use of org.jikesrvm.classloader.RVMField in project JikesRVM by JikesRVM.
the class GenerateMagic method generateMagic.
/**
* "Semantic inlining" of methods of the Magic class.
* Based on the methodName, generate a sequence of opt instructions
* that implement the magic, updating the expression stack as necessary.
*
* @param bc2ir the bc2ir object that is generating the
* ir containing this magic
* @param gc must be bc2ir.gc
* @param meth the RVMMethod that is the magic method
* @return {@code true} if and only if magic was generated
*/
static boolean generateMagic(BC2IR bc2ir, GenerationContext gc, MethodReference meth) throws MagicNotImplementedException {
if (gc.getMethod().hasNoInlinePragma())
gc.forceFrameAllocation();
Atom methodName = meth.getName();
boolean address = (meth.getType() == TypeReference.Address);
// Address magic
TypeReference[] types = meth.getParameterTypes();
TypeReference returnType = meth.getReturnType();
if (address && isLoad(methodName)) {
// LOAD
Operand offset = (types.length == 0) ? AC(Address.zero()) : bc2ir.popAddress();
Operand base = bc2ir.popAddress();
RegisterOperand result = gc.getTemps().makeTemp(returnType);
bc2ir.appendInstruction(Load.create(getOperator(returnType, LOAD_OP), result, base, offset, null));
bc2ir.push(result.copyD2U(), returnType);
} else if (address && isPrepare(methodName)) {
// PREPARE
Operand offset = (types.length == 0) ? AC(Address.zero()) : bc2ir.popAddress();
Operand base = bc2ir.popAddress();
RegisterOperand result = gc.getTemps().makeTemp(returnType);
bc2ir.appendInstruction(Prepare.create(getOperator(returnType, PREPARE_OP), result, base, offset, null));
bc2ir.push(result.copyD2U(), returnType);
} else if (address && methodName == MagicNames.attempt) {
// ATTEMPT
TypeReference attemptType = types[0];
Operand offset = (types.length == 2) ? AC(Address.zero()) : bc2ir.popAddress();
Operand newVal = bc2ir.pop();
Operand oldVal = bc2ir.pop();
Operand base = bc2ir.popAddress();
RegisterOperand test = gc.getTemps().makeTempInt();
bc2ir.appendInstruction(Attempt.create(getOperator(attemptType, ATTEMPT_OP), test, base, offset, oldVal, newVal, null));
bc2ir.push(test.copyD2U(), returnType);
} else if (address && methodName == MagicNames.store) {
// STORE
TypeReference storeType = types[0];
Operand offset = (types.length == 1) ? AC(Address.zero()) : bc2ir.popAddress();
Operand val = bc2ir.pop(storeType);
Operand base = bc2ir.popAddress();
bc2ir.appendInstruction(Store.create(getOperator(storeType, STORE_OP), val, base, offset, null));
} else if (methodName == MagicNames.getThreadRegister) {
RegisterOperand rop = gc.getTemps().makeTROp();
bc2ir.markGuardlessNonNull(rop);
bc2ir.push(rop);
} else if (methodName == MagicNames.setThreadRegister) {
Operand val = bc2ir.popRef();
if (val instanceof RegisterOperand) {
bc2ir.appendInstruction(Move.create(REF_MOVE, gc.getTemps().makeTROp(), val));
} else {
String msg = " Unexpected operand Magic.setThreadRegister";
throw MagicNotImplementedException.UNEXPECTED(msg);
}
} else if (methodName == MagicNames.addressArrayCreate) {
Instruction s = bc2ir.generateAnewarray(null, meth.getType().getArrayElementType());
bc2ir.appendInstruction(s);
} else if (methodName == MagicNames.addressArrayLength) {
Operand op1 = bc2ir.pop();
bc2ir.clearCurrentGuard();
if (bc2ir.do_NullCheck(op1)) {
return true;
}
RegisterOperand t = gc.getTemps().makeTempInt();
Instruction s = GuardedUnary.create(ARRAYLENGTH, t, op1, bc2ir.getCurrentGuard());
bc2ir.push(t.copyD2U());
bc2ir.appendInstruction(s);
} else if (methodName == MagicNames.addressArrayGet) {
TypeReference elementType = meth.getReturnType();
Operand index = bc2ir.popInt();
Operand ref = bc2ir.popRef();
RegisterOperand offsetI = gc.getTemps().makeTempInt();
RegisterOperand offset = gc.getTemps().makeTempOffset();
RegisterOperand result;
if (meth.getType().isCodeArrayType()) {
if (VM.BuildForIA32) {
result = gc.getTemps().makeTemp(TypeReference.Byte);
bc2ir.appendInstruction(Load.create(BYTE_LOAD, result, ref, index, new LocationOperand(elementType), new TrueGuardOperand()));
} else if (VM.BuildForPowerPC) {
result = gc.getTemps().makeTemp(TypeReference.Int);
bc2ir.appendInstruction(Binary.create(INT_SHL, offsetI, index, new IntConstantOperand(LOG_BYTES_IN_INT)));
bc2ir.appendInstruction(Unary.create(INT_2ADDRZerExt, offset, offsetI.copy()));
bc2ir.appendInstruction(Load.create(INT_LOAD, result, ref, offset.copy(), new LocationOperand(elementType), new TrueGuardOperand()));
}
} else {
result = gc.getTemps().makeTemp(elementType);
bc2ir.appendInstruction(Binary.create(INT_SHL, offsetI, index, new IntConstantOperand(LOG_BYTES_IN_ADDRESS)));
bc2ir.appendInstruction(Unary.create(INT_2ADDRZerExt, offset, offsetI.copy()));
bc2ir.appendInstruction(Load.create(REF_LOAD, result, ref, offset.copy(), new LocationOperand(elementType), new TrueGuardOperand()));
}
bc2ir.push(result.copyD2U());
} else if (methodName == MagicNames.addressArraySet) {
TypeReference elementType = meth.getParameterTypes()[1];
Operand val = bc2ir.pop();
Operand index = bc2ir.popInt();
Operand ref = bc2ir.popRef();
RegisterOperand offsetI = gc.getTemps().makeTempInt();
RegisterOperand offset = gc.getTemps().makeTempOffset();
if (meth.getType().isCodeArrayType()) {
if (VM.BuildForIA32) {
bc2ir.appendInstruction(Store.create(BYTE_STORE, val, ref, index, new LocationOperand(elementType), new TrueGuardOperand()));
} else if (VM.BuildForPowerPC) {
bc2ir.appendInstruction(Binary.create(INT_SHL, offsetI, index, new IntConstantOperand(LOG_BYTES_IN_INT)));
bc2ir.appendInstruction(Unary.create(INT_2ADDRZerExt, offset, offsetI.copy()));
bc2ir.appendInstruction(Store.create(INT_STORE, val, ref, offset.copy(), new LocationOperand(elementType), new TrueGuardOperand()));
}
} else {
bc2ir.appendInstruction(Binary.create(INT_SHL, offsetI, index, new IntConstantOperand(LOG_BYTES_IN_ADDRESS)));
bc2ir.appendInstruction(Unary.create(INT_2ADDRZerExt, offset, offsetI.copy()));
bc2ir.appendInstruction(Store.create(REF_STORE, val, ref, offset.copy(), new LocationOperand(elementType), new TrueGuardOperand()));
}
} else if (methodName == MagicNames.getIntAtOffset) {
Operand offset = bc2ir.popAddress();
Operand object = bc2ir.popRef();
RegisterOperand val = gc.getTemps().makeTempInt();
bc2ir.appendInstruction(Load.create(INT_LOAD, val, object, offset, null));
bc2ir.push(val.copyD2U());
} else if (methodName == MagicNames.setIntAtOffset) {
LocationOperand loc = null;
if (meth.getParameterTypes().length == 4) {
loc = mapToMetadata(bc2ir.popInt());
}
Operand val = bc2ir.popInt();
Operand offset = bc2ir.popAddress();
Operand object = bc2ir.popRef();
bc2ir.appendInstruction(Store.create(INT_STORE, val, object, offset, loc));
} else if (methodName == MagicNames.getFloatAtOffset) {
Operand offset = bc2ir.popAddress();
Operand object = bc2ir.popRef();
RegisterOperand val = gc.getTemps().makeTempFloat();
bc2ir.appendInstruction(Load.create(FLOAT_LOAD, val, object, offset, null));
bc2ir.push(val.copyD2U());
} else if (methodName == MagicNames.setFloatAtOffset) {
LocationOperand loc = null;
if (meth.getParameterTypes().length == 4) {
loc = mapToMetadata(bc2ir.popInt());
}
Operand val = bc2ir.popFloat();
Operand offset = bc2ir.popAddress();
Operand object = bc2ir.popRef();
bc2ir.appendInstruction(Store.create(FLOAT_STORE, val, object, offset, loc));
} else if (methodName == MagicNames.getWordAtOffset) {
LocationOperand loc = null;
if (meth.getParameterTypes().length == 3) {
loc = mapToMetadata(bc2ir.popInt());
}
Operand offset = bc2ir.popAddress();
Operand object = bc2ir.popRef();
RegisterOperand val = gc.getTemps().makeTemp(TypeReference.Word);
bc2ir.appendInstruction(Load.create(REF_LOAD, val, object, offset, loc));
bc2ir.push(val.copyD2U());
} else if (methodName == MagicNames.getAddressAtOffset) {
LocationOperand loc = null;
if (meth.getParameterTypes().length == 3) {
loc = mapToMetadata(bc2ir.popInt());
}
Operand offset = bc2ir.popAddress();
Operand object = bc2ir.popRef();
RegisterOperand val = gc.getTemps().makeTemp(TypeReference.Address);
bc2ir.appendInstruction(Load.create(REF_LOAD, val, object, offset, loc));
bc2ir.push(val.copyD2U());
} else if (methodName == MagicNames.getExtentAtOffset) {
LocationOperand loc = null;
if (meth.getParameterTypes().length == 3) {
loc = mapToMetadata(bc2ir.popInt());
}
Operand offset = bc2ir.popAddress();
Operand object = bc2ir.popRef();
RegisterOperand val = gc.getTemps().makeTemp(TypeReference.Extent);
bc2ir.appendInstruction(Load.create(REF_LOAD, val, object, offset, loc));
bc2ir.push(val.copyD2U());
} else if (methodName == MagicNames.getOffsetAtOffset) {
LocationOperand loc = null;
if (meth.getParameterTypes().length == 3) {
loc = mapToMetadata(bc2ir.popInt());
}
Operand offset = bc2ir.popAddress();
Operand object = bc2ir.popRef();
RegisterOperand val = gc.getTemps().makeTemp(TypeReference.Offset);
bc2ir.appendInstruction(Load.create(REF_LOAD, val, object, offset, loc));
bc2ir.push(val.copyD2U());
} else if (methodName == MagicNames.setWordAtOffset || methodName == MagicNames.setAddressAtOffset || methodName == MagicNames.setOffsetAtOffset || methodName == MagicNames.setExtentAtOffset) {
LocationOperand loc = null;
if (meth.getParameterTypes().length == 4) {
loc = mapToMetadata(bc2ir.popInt());
}
Operand val = bc2ir.popRef();
Operand offset = bc2ir.popAddress();
Operand object = bc2ir.popRef();
bc2ir.appendInstruction(Store.create(REF_STORE, val, object, offset, loc));
} else if (methodName == MagicNames.getLongAtOffset) {
Operand offset = bc2ir.popAddress();
Operand object = bc2ir.popRef();
RegisterOperand val = gc.getTemps().makeTempLong();
bc2ir.appendInstruction(Load.create(LONG_LOAD, val, object, offset, null));
bc2ir.pushDual(val.copyD2U());
} else if (methodName == MagicNames.setLongAtOffset) {
LocationOperand loc = null;
if (meth.getParameterTypes().length == 4) {
loc = mapToMetadata(bc2ir.popInt());
}
Operand val = bc2ir.popLong();
Operand offset = bc2ir.popAddress();
Operand object = bc2ir.popRef();
bc2ir.appendInstruction(Store.create(LONG_STORE, val, object, offset, loc));
} else if (methodName == MagicNames.getDoubleAtOffset) {
Operand offset = bc2ir.popAddress();
Operand object = bc2ir.popRef();
RegisterOperand val = gc.getTemps().makeTempDouble();
bc2ir.appendInstruction(Load.create(DOUBLE_LOAD, val, object, offset, null));
bc2ir.pushDual(val.copyD2U());
} else if (methodName == MagicNames.setDoubleAtOffset) {
LocationOperand loc = null;
if (meth.getParameterTypes().length == 4) {
loc = mapToMetadata(bc2ir.popInt());
}
Operand val = bc2ir.popDouble();
Operand offset = bc2ir.popAddress();
Operand object = bc2ir.popRef();
bc2ir.appendInstruction(Store.create(DOUBLE_STORE, val, object, offset, loc));
} else if (methodName == MagicNames.getObjectAtOffset) {
LocationOperand loc = null;
if (meth.getParameterTypes().length == 3) {
loc = mapToMetadata(bc2ir.popInt());
}
Operand offset = bc2ir.popAddress();
Operand object = bc2ir.popRef();
RegisterOperand val = gc.getTemps().makeTemp(TypeReference.JavaLangObject);
bc2ir.appendInstruction(Load.create(REF_LOAD, val, object, offset, loc));
bc2ir.push(val.copyD2U());
} else if (methodName == MagicNames.getTIBAtOffset) {
Operand offset = bc2ir.popAddress();
Operand object = bc2ir.popRef();
RegisterOperand val = gc.getTemps().makeTemp(TypeReference.TIB);
bc2ir.appendInstruction(Load.create(REF_LOAD, val, object, offset, null));
bc2ir.push(val.copyD2U());
} else if (methodName == MagicNames.setObjectAtOffset) {
LocationOperand loc = null;
if (meth.getParameterTypes().length == 4) {
loc = mapToMetadata(bc2ir.popInt());
}
Operand val = bc2ir.popRef();
Operand offset = bc2ir.popAddress();
Operand object = bc2ir.popRef();
bc2ir.appendInstruction(Store.create(REF_STORE, val, object, offset, loc));
} else if (methodName == MagicNames.getByteAtOffset) {
Operand offset = bc2ir.popAddress();
Operand object = bc2ir.popRef();
RegisterOperand val = gc.getTemps().makeTemp(TypeReference.Byte);
bc2ir.appendInstruction(Load.create(BYTE_LOAD, val, object, offset, null));
bc2ir.push(val.copyD2U());
} else if (methodName == MagicNames.getUnsignedByteAtOffset) {
Operand offset = bc2ir.popAddress();
Operand object = bc2ir.popRef();
RegisterOperand val = gc.getTemps().makeTemp(TypeReference.Byte);
bc2ir.appendInstruction(Load.create(UBYTE_LOAD, val, object, offset, null));
bc2ir.push(val.copyD2U());
} else if (methodName == MagicNames.setByteAtOffset || methodName == MagicNames.setBooleanAtOffset) {
LocationOperand loc = null;
if (meth.getParameterTypes().length == 4) {
loc = mapToMetadata(bc2ir.popInt());
}
Operand val = bc2ir.popInt();
Operand offset = bc2ir.popAddress();
Operand object = bc2ir.popRef();
bc2ir.appendInstruction(Store.create(BYTE_STORE, val, object, offset, loc));
} else if (methodName == MagicNames.getShortAtOffset) {
Operand offset = bc2ir.popAddress();
Operand object = bc2ir.popRef();
RegisterOperand val = gc.getTemps().makeTemp(TypeReference.Char);
bc2ir.appendInstruction(Load.create(SHORT_LOAD, val, object, offset, null));
bc2ir.push(val.copyD2U());
} else if (methodName == MagicNames.getCharAtOffset) {
Operand offset = bc2ir.popAddress();
Operand object = bc2ir.popRef();
RegisterOperand val = gc.getTemps().makeTemp(TypeReference.Char);
bc2ir.appendInstruction(Load.create(USHORT_LOAD, val, object, offset, null));
bc2ir.push(val.copyD2U());
} else if (methodName == MagicNames.setCharAtOffset || methodName == MagicNames.setShortAtOffset) {
LocationOperand loc = null;
if (meth.getParameterTypes().length == 4) {
loc = mapToMetadata(bc2ir.popInt());
}
Operand val = bc2ir.popInt();
Operand offset = bc2ir.popAddress();
Operand object = bc2ir.popRef();
bc2ir.appendInstruction(Store.create(SHORT_STORE, val, object, offset, loc));
} else if (methodName == MagicNames.getMemoryInt) {
Operand memAddr = bc2ir.popAddress();
RegisterOperand val = gc.getTemps().makeTempInt();
bc2ir.appendInstruction(Load.create(INT_LOAD, val, memAddr, AC(Offset.zero()), null));
bc2ir.push(val.copyD2U());
} else if (methodName == MagicNames.getMemoryWord) {
Operand memAddr = bc2ir.popAddress();
RegisterOperand val = gc.getTemps().makeTemp(TypeReference.Word);
bc2ir.appendInstruction(Load.create(REF_LOAD, val, memAddr, AC(Offset.zero()), null));
bc2ir.push(val.copyD2U());
} else if (methodName == MagicNames.getMemoryAddress) {
Operand memAddr = bc2ir.popAddress();
RegisterOperand val = gc.getTemps().makeTemp(TypeReference.Address);
bc2ir.appendInstruction(Load.create(REF_LOAD, val, memAddr, AC(Offset.zero()), null));
bc2ir.push(val.copyD2U());
} else if (methodName == MagicNames.setMemoryInt) {
Operand val = bc2ir.popInt();
Operand memAddr = bc2ir.popAddress();
bc2ir.appendInstruction(Store.create(INT_STORE, val, memAddr, AC(Offset.zero()), null));
} else if (methodName == MagicNames.setMemoryWord) {
Operand val = bc2ir.popRef();
Operand memAddr = bc2ir.popAddress();
bc2ir.appendInstruction(Store.create(REF_STORE, val, memAddr, AC(Offset.zero()), null));
} else if (meth.isSysCall()) {
// All methods of SysCall have the following signature:
// callNAME(Address functionAddress, <var args to pass via native calling convention>)
// With 64 bit PowerPC ELF ABI, functionAddress points to the function descriptor
TypeReference[] args = meth.getParameterTypes();
Instruction call = Call.create(SYSCALL, null, null, null, null, args.length - 1);
for (int i = args.length - 1; i >= 1; i--) {
Call.setParam(call, i - 1, bc2ir.pop(args[i]));
}
Operand functionAddress = bc2ir.pop(args[0]);
Call.setAddress(call, functionAddress);
if (!returnType.isVoidType()) {
RegisterOperand op0 = gc.getTemps().makeTemp(returnType);
Call.setResult(call, op0);
bc2ir.push(op0.copyD2U(), returnType);
}
Call.setMethod(call, MethodOperand.STATIC(meth, meth.peekResolvedMethod()));
bc2ir.appendInstruction(call);
} else if (meth.isSpecializedInvoke()) {
// The callsite looks like RETURN = INVOKE (ID, OBJECT, P0, P1 .. PN)
// And the actual method will look like RETURN = INVOKE (OBJECT, P0, P1 .. PN)
// Create the call instruction
Instruction call = Call.create(CALL, null, null, null, null, types.length - 1);
// Plumb all of the normal parameters into the call
for (int i = types.length - 1; i >= 2; i--) {
Call.setParam(call, i - 1, bc2ir.pop(types[i]));
}
// The object being specialized
Operand objectOperand = bc2ir.pop(types[1]);
Call.setParam(call, 0, objectOperand);
Operand guard = BC2IR.copyGuardFromOperand(objectOperand);
if (guard == null) {
// it's magic, so assume that it's OK....
guard = new TrueGuardOperand();
}
Call.setGuard(call, guard);
// Load the tib of this object
RegisterOperand tibObject = gc.getTemps().makeTemp(TypeReference.TIB);
bc2ir.appendInstruction(GuardedUnary.create(GET_OBJ_TIB, tibObject, objectOperand.copy(), guard.copy()));
// The index of the specialized method
Operand methodId = bc2ir.popInt();
// Add the base offset for specialized methods and convert from index to address
RegisterOperand tibOffset = gc.getTemps().makeTemp(TypeReference.Int);
bc2ir.appendInstruction(Binary.create(INT_ADD, tibOffset, methodId, new IntConstantOperand(TIB_FIRST_SPECIALIZED_METHOD_INDEX)));
bc2ir.appendInstruction(Binary.create(INT_SHL, tibOffset.copyRO(), tibOffset.copyD2U(), new IntConstantOperand(LOG_BYTES_IN_ADDRESS)));
// Load the code address from the TIB
RegisterOperand codeAddress = gc.getTemps().makeTemp(TypeReference.Address);
bc2ir.appendInstruction(Load.create(REF_LOAD, codeAddress, tibObject.copyD2U(), tibOffset.copyD2U(), null));
Call.setAddress(call, codeAddress.copyD2U());
if (!returnType.isVoidType()) {
RegisterOperand op0 = gc.getTemps().makeTemp(returnType);
Call.setResult(call, op0);
bc2ir.push(op0.copyD2U(), returnType);
}
bc2ir.appendInstruction(call);
} else if (methodName == MagicNames.objectAsType) {
RegisterOperand reg = gc.getTemps().makeTemp(TypeReference.Type);
bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popRef()));
bc2ir.push(reg.copyD2U());
} else if (methodName == MagicNames.objectAsThread) {
RegisterOperand reg = gc.getTemps().makeTemp(TypeReference.Thread);
bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popRef()));
bc2ir.push(reg.copyD2U());
} else if (methodName == MagicNames.objectAsAddress) {
RegisterOperand reg = gc.getTemps().makeTemp(TypeReference.Address);
bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popRef()));
bc2ir.push(reg.copyD2U());
} else if (methodName == MagicNames.addressAsObject) {
RegisterOperand reg = gc.getTemps().makeTemp(TypeReference.JavaLangObject);
bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popAddress()));
bc2ir.push(reg.copyD2U());
} else if (methodName == MagicNames.addressAsTIB) {
RegisterOperand reg = gc.getTemps().makeTemp(TypeReference.TIB);
bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popAddress()));
bc2ir.push(reg.copyD2U());
} else if (methodName == MagicNames.addressAsByteArray) {
RegisterOperand reg = gc.getTemps().makeTemp(TypeReference.ByteArray);
bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popAddress()));
bc2ir.push(reg.copyD2U());
} else if (methodName == MagicNames.objectAsShortArray) {
RegisterOperand reg = gc.getTemps().makeTemp(TypeReference.ShortArray);
bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popRef()));
bc2ir.push(reg.copyD2U());
} else if (methodName == MagicNames.objectAsIntArray) {
RegisterOperand reg = gc.getTemps().makeTemp(TypeReference.IntArray);
bc2ir.appendInstruction(Move.create(REF_MOVE, reg, bc2ir.popRef()));
bc2ir.push(reg.copyD2U());
} else if (methodName == MagicNames.floatAsIntBits) {
Operand val = bc2ir.popFloat();
RegisterOperand op0 = gc.getTemps().makeTempInt();
bc2ir.appendInstruction(Unary.create(FLOAT_AS_INT_BITS, op0, val));
bc2ir.push(op0.copyD2U());
} else if (methodName == MagicNames.intBitsAsFloat) {
Operand val = bc2ir.popInt();
RegisterOperand op0 = gc.getTemps().makeTempFloat();
bc2ir.appendInstruction(Unary.create(INT_BITS_AS_FLOAT, op0, val));
bc2ir.push(op0.copyD2U());
} else if (methodName == MagicNames.doubleAsLongBits) {
Operand val = bc2ir.popDouble();
RegisterOperand op0 = gc.getTemps().makeTempLong();
bc2ir.appendInstruction(Unary.create(DOUBLE_AS_LONG_BITS, op0, val));
bc2ir.pushDual(op0.copyD2U());
} else if (methodName == MagicNames.longBitsAsDouble) {
Operand val = bc2ir.popLong();
RegisterOperand op0 = gc.getTemps().makeTempDouble();
bc2ir.appendInstruction(Unary.create(LONG_BITS_AS_DOUBLE, op0, val));
bc2ir.pushDual(op0.copyD2U());
} else if (methodName == MagicNames.sqrt) {
TypeReference[] args = meth.getParameterTypes();
if (args[0] == TypeReference.Float) {
Operand val = bc2ir.popFloat();
RegisterOperand op0 = gc.getTemps().makeTempFloat();
bc2ir.appendInstruction(Unary.create(FLOAT_SQRT, op0, val));
bc2ir.push(op0.copyD2U());
} else if (args[0] == TypeReference.Double) {
Operand val = bc2ir.popDouble();
RegisterOperand op0 = gc.getTemps().makeTempDouble();
bc2ir.appendInstruction(Unary.create(DOUBLE_SQRT, op0, val));
bc2ir.pushDual(op0.copyD2U());
} else {
if (VM.VerifyAssertions)
VM._assert(VM.NOT_REACHED, "SQRT only handles Double or Float operands");
}
} else if (methodName == MagicNames.getObjectType) {
Operand val = bc2ir.popRef();
if (val.isObjectConstant()) {
bc2ir.push(new ObjectConstantOperand(val.getType().peekType(), Offset.zero()));
} else {
Operand guard = BC2IR.copyGuardFromOperand(val);
if (guard == null) {
// it's magic, so assume that it's OK....
guard = new TrueGuardOperand();
}
RegisterOperand tibPtr = gc.getTemps().makeTemp(TypeReference.TIB);
bc2ir.appendInstruction(GuardedUnary.create(GET_OBJ_TIB, tibPtr, val, guard));
RegisterOperand op0;
TypeReference argType = val.getType();
if (argType.isArrayType()) {
op0 = gc.getTemps().makeTemp(TypeReference.RVMArray);
} else {
if (argType == TypeReference.JavaLangObject || argType == TypeReference.JavaLangCloneable || argType == TypeReference.JavaIoSerializable) {
// could be an array or a class, so make op0 be a RVMType
op0 = gc.getTemps().makeTemp(TypeReference.Type);
} else {
op0 = gc.getTemps().makeTemp(TypeReference.Class);
}
}
bc2ir.markGuardlessNonNull(op0);
bc2ir.appendInstruction(Unary.create(GET_TYPE_FROM_TIB, op0, tibPtr.copyD2U()));
bc2ir.push(op0.copyD2U());
}
} else if (methodName == MagicNames.getArrayLength) {
Operand val = bc2ir.popRef();
RegisterOperand op0 = gc.getTemps().makeTempInt();
bc2ir.appendInstruction(GuardedUnary.create(ARRAYLENGTH, op0, val, new TrueGuardOperand()));
bc2ir.push(op0.copyD2U());
} else if (methodName == MagicNames.invokeClassInitializer) {
Instruction s = Call.create0(CALL, null, bc2ir.popRef(), null);
bc2ir.appendInstruction(s);
} else if ((methodName == MagicNames.invokeMethodReturningObject) || (methodName == MagicNames.invokeMethodReturningVoid) || (methodName == MagicNames.invokeMethodReturningLong) || (methodName == MagicNames.invokeMethodReturningDouble) || (methodName == MagicNames.invokeMethodReturningFloat) || (methodName == MagicNames.invokeMethodReturningInt)) {
Operand spills = bc2ir.popRef();
Operand fprmeta = bc2ir.popRef();
Operand fprs = bc2ir.popRef();
Operand gprs = bc2ir.popRef();
Operand code = bc2ir.popRef();
RegisterOperand res = null;
if (methodName == MagicNames.invokeMethodReturningObject) {
res = gc.getTemps().makeTemp(TypeReference.JavaLangObject);
bc2ir.push(res.copyD2U());
} else if (methodName == MagicNames.invokeMethodReturningLong) {
res = gc.getTemps().makeTemp(TypeReference.Long);
bc2ir.push(res.copyD2U(), TypeReference.Long);
} else if (methodName == MagicNames.invokeMethodReturningDouble) {
res = gc.getTemps().makeTempDouble();
bc2ir.push(res.copyD2U(), TypeReference.Double);
} else if (methodName == MagicNames.invokeMethodReturningFloat) {
res = gc.getTemps().makeTempFloat();
bc2ir.push(res.copyD2U(), TypeReference.Float);
} else if (methodName == MagicNames.invokeMethodReturningInt) {
res = gc.getTemps().makeTempInt();
bc2ir.push(res.copyD2U());
}
RVMField target = ArchEntrypoints.reflectiveMethodInvokerInstructionsField;
MethodOperand met = MethodOperand.STATIC(target);
Instruction s = Call.create5(CALL, res, AC(target.getOffset()), met, code, gprs, fprs, fprmeta, spills);
bc2ir.appendInstruction(s);
} else if (methodName == MagicNames.saveThreadState) {
Operand p1 = bc2ir.popRef();
RVMField target = ArchEntrypoints.saveThreadStateInstructionsField;
MethodOperand mo = MethodOperand.STATIC(target);
bc2ir.appendInstruction(Call.create1(CALL, null, AC(target.getOffset()), mo, p1));
} else if (methodName == MagicNames.threadSwitch) {
Operand p2 = bc2ir.popRef();
Operand p1 = bc2ir.popRef();
RVMField target = ArchEntrypoints.threadSwitchInstructionsField;
MethodOperand mo = MethodOperand.STATIC(target);
bc2ir.appendInstruction(Call.create2(CALL, null, AC(target.getOffset()), mo, p1, p2));
} else if (methodName == MagicNames.restoreHardwareExceptionState) {
RVMField target = ArchEntrypoints.restoreHardwareExceptionStateInstructionsField;
MethodOperand mo = MethodOperand.STATIC(target);
bc2ir.appendInstruction(Call.create1(CALL, null, AC(target.getOffset()), mo, bc2ir.popRef()));
} else if (methodName == MagicNames.prepareInt) {
Operand offset = bc2ir.popAddress();
Operand base = bc2ir.popRef();
RegisterOperand val = gc.getTemps().makeTempInt();
bc2ir.appendInstruction(Prepare.create(PREPARE_INT, val, base, offset, null));
bc2ir.push(val.copyD2U());
} else if (methodName == MagicNames.prepareLong) {
Operand offset = bc2ir.popAddress();
Operand base = bc2ir.popRef();
RegisterOperand val = gc.getTemps().makeTempLong();
bc2ir.appendInstruction(Prepare.create(PREPARE_LONG, val, base, offset, null));
bc2ir.pushDual(val.copyD2U());
} else if (methodName == MagicNames.prepareObject) {
Operand offset = bc2ir.popAddress();
Operand base = bc2ir.popRef();
RegisterOperand val = gc.getTemps().makeTemp(TypeReference.JavaLangObject);
bc2ir.appendInstruction(Prepare.create(PREPARE_ADDR, val, base, offset, null));
bc2ir.push(val.copyD2U());
} else if (methodName == MagicNames.prepareAddress) {
Operand offset = bc2ir.popAddress();
Operand base = bc2ir.popRef();
RegisterOperand val = gc.getTemps().makeTemp(TypeReference.Address);
bc2ir.appendInstruction(Prepare.create(PREPARE_ADDR, val, base, offset, null));
bc2ir.push(val.copyD2U());
} else if (methodName == MagicNames.prepareWord) {
Operand offset = bc2ir.popAddress();
Operand base = bc2ir.popRef();
RegisterOperand val = gc.getTemps().makeTemp(TypeReference.Word);
bc2ir.appendInstruction(Prepare.create(PREPARE_ADDR, val, base, offset, null));
bc2ir.push(val.copyD2U());
} else if (methodName == MagicNames.attemptInt) {
Operand newVal = bc2ir.popInt();
Operand oldVal = bc2ir.popInt();
Operand offset = bc2ir.popAddress();
Operand base = bc2ir.popRef();
RegisterOperand test = gc.getTemps().makeTempBoolean();
bc2ir.appendInstruction(Attempt.create(ATTEMPT_INT, test, base, offset, oldVal, newVal, null));
bc2ir.push(test.copyD2U());
} else if (methodName == MagicNames.attemptLong) {
Operand newVal = bc2ir.popLong();
Operand oldVal = bc2ir.popLong();
Operand offset = bc2ir.popAddress();
Operand base = bc2ir.popRef();
RegisterOperand test = gc.getTemps().makeTempBoolean();
bc2ir.appendInstruction(Attempt.create(ATTEMPT_LONG, test, base, offset, oldVal, newVal, null));
bc2ir.push(test.copyD2U());
} else if (methodName == MagicNames.attemptObject) {
Operand newVal = bc2ir.popRef();
Operand oldVal = bc2ir.popRef();
Operand offset = bc2ir.popAddress();
Operand base = bc2ir.popRef();
RegisterOperand test = gc.getTemps().makeTempBoolean();
bc2ir.appendInstruction(Attempt.create(ATTEMPT_ADDR, test, base, offset, oldVal, newVal, null));
bc2ir.push(test.copyD2U());
} else if (methodName == MagicNames.attemptAddress) {
Operand newVal = bc2ir.popAddress();
Operand oldVal = bc2ir.popAddress();
Operand offset = bc2ir.popAddress();
Operand base = bc2ir.popRef();
RegisterOperand test = gc.getTemps().makeTempBoolean();
bc2ir.appendInstruction(Attempt.create(ATTEMPT_ADDR, test, base, offset, oldVal, newVal, null));
bc2ir.push(test.copyD2U());
} else if (methodName == MagicNames.attemptWord) {
Operand newVal = bc2ir.pop();
Operand oldVal = bc2ir.pop();
Operand offset = bc2ir.popAddress();
Operand base = bc2ir.popRef();
RegisterOperand test = gc.getTemps().makeTempBoolean();
bc2ir.appendInstruction(Attempt.create(ATTEMPT_ADDR, test, base, offset, oldVal, newVal, null));
bc2ir.push(test.copyD2U());
} else if (methodName == MagicNames.fence) {
bc2ir.appendInstruction(Empty.create(FENCE));
} else if (methodName == MagicNames.combinedLoadBarrier) {
bc2ir.appendInstruction(Empty.create(READ_CEILING));
} else if (methodName == MagicNames.storeStoreBarrier) {
bc2ir.appendInstruction(Empty.create(WRITE_FLOOR));
} else if (generatePolymorphicMagic(bc2ir, gc, meth, methodName)) {
return true;
} else if (methodName == MagicNames.getTimeBase) {
RegisterOperand op0 = gc.getTemps().makeTempLong();
bc2ir.appendInstruction(Nullary.create(GET_TIME_BASE, op0));
bc2ir.pushDual(op0.copyD2U());
} else if (methodName == MagicNames.getInlineDepth) {
bc2ir.push(new IntConstantOperand(gc.getInlineSequence().getInlineDepth()));
} else if (methodName == MagicNames.getCompilerLevel) {
bc2ir.push(new IntConstantOperand(gc.getOptions().getOptLevel()));
} else if (methodName == MagicNames.isConstantParameter) {
Operand requestedOperand = bc2ir.pop();
if (!(requestedOperand instanceof IntConstantOperand)) {
throw new OptimizingCompilerException("Must supply constant to Magic.isConstantParameter");
}
int requested = ((IntConstantOperand) (requestedOperand)).value;
boolean isConstant = gc.getArguments()[requested].isConstant();
bc2ir.push(new IntConstantOperand(isConstant ? 1 : 0));
} else if (methodName == MagicNames.getFrameSize) {
RegisterOperand res = gc.getTemps().makeTempInt();
gc.forceFrameAllocation();
bc2ir.appendInstruction(Nullary.create(FRAMESIZE, res));
bc2ir.push(res.copyD2U());
} else {
// Wasn't machine-independent, so try the machine-dependent magics next.
if (VM.BuildForIA32) {
return org.jikesrvm.compilers.opt.bc2ir.ia32.GenerateMachineSpecificMagic.generateMagic(bc2ir, gc, meth);
} else {
if (VM.VerifyAssertions)
VM._assert(VM.BuildForPowerPC);
return org.jikesrvm.compilers.opt.bc2ir.ppc.GenerateMachineSpecificMagic.generateMagic(bc2ir, gc, meth);
}
}
return true;
}
use of org.jikesrvm.classloader.RVMField in project JikesRVM by JikesRVM.
the class BaselineCompilerImpl method emit_resolved_putstatic.
@Override
protected void emit_resolved_putstatic(FieldReference fieldRef) {
RVMField field = fieldRef.peekResolvedField();
Offset fieldOffset = field.getOffset();
if (field.isVolatile()) {
// JMM: (pre-barrier when second operation)
// StoreStore barrier.
asm.emitSYNC();
}
if (NEEDS_OBJECT_PUTSTATIC_BARRIER && !fieldRef.getFieldContentsType().isPrimitiveType() && !field.isUntraced()) {
Barriers.compilePutstaticBarrierImm(this, fieldOffset, fieldRef.getId());
discardSlots(1);
} else if (fieldRef.getSize() <= BYTES_IN_INT) {
// field is one word
popInt(T0);
asm.emitSTWtoc(T0, fieldOffset, T1);
} else {
// field is two words (double or long (or address on PPC64))
if (VM.VerifyAssertions)
VM._assert(fieldRef.getSize() == BYTES_IN_LONG);
if (VM.BuildFor64Addr && fieldRef.getNumberOfStackSlots() == 1) {
// address only 1 stackslot!!!
popAddr(T0);
asm.emitSTDtoc(T0, fieldOffset, T1);
} else {
popDouble(F0);
asm.emitSTFDtoc(F0, fieldOffset, T0);
}
}
if (field.isVolatile()) {
// JMM: post-barrier when first operation
// StoreLoad barrier.
asm.emitHWSYNC();
}
}
use of org.jikesrvm.classloader.RVMField in project JikesRVM by JikesRVM.
the class BaselineCompilerImpl method emit_resolved_putfield.
@Override
protected void emit_resolved_putfield(FieldReference fieldRef) {
RVMField field = fieldRef.peekResolvedField();
Offset fieldOffset = field.getOffset();
TypeReference fieldType = fieldRef.getFieldContentsType();
if (field.isVolatile()) {
// JMM: pre-barrier when second operation
// StoreStore barrier.
asm.emitSYNC();
}
if (fieldType.isReferenceType()) {
// 32/64bit reference store
if (NEEDS_OBJECT_PUTFIELD_BARRIER && !field.isUntraced()) {
Barriers.compilePutfieldBarrierImm(this, fieldOffset, fieldRef.getId());
discardSlots(2);
} else {
// T0 = address value
popAddr(T0);
// T1 = object reference
popAddr(T1);
asm.emitSTAddrOffset(T0, T1, fieldOffset);
}
} else if (NEEDS_BOOLEAN_PUTFIELD_BARRIER && fieldType.isBooleanType()) {
Barriers.compilePutfieldBarrierBooleanImm(this, fieldOffset, fieldRef.getId());
} else if (NEEDS_BYTE_PUTFIELD_BARRIER && fieldType.isByteType()) {
Barriers.compilePutfieldBarrierByteImm(this, fieldOffset, fieldRef.getId());
} else if (NEEDS_CHAR_PUTFIELD_BARRIER && fieldType.isCharType()) {
Barriers.compilePutfieldBarrierCharImm(this, fieldOffset, fieldRef.getId());
} else if (NEEDS_DOUBLE_PUTFIELD_BARRIER && fieldType.isDoubleType()) {
Barriers.compilePutfieldBarrierDoubleImm(this, fieldOffset, fieldRef.getId());
} else if (NEEDS_FLOAT_PUTFIELD_BARRIER && fieldType.isFloatType()) {
Barriers.compilePutfieldBarrierFloatImm(this, fieldOffset, fieldRef.getId());
} else if (NEEDS_INT_PUTFIELD_BARRIER && fieldType.isIntType()) {
Barriers.compilePutfieldBarrierIntImm(this, fieldOffset, fieldRef.getId());
} else if (NEEDS_LONG_PUTFIELD_BARRIER && fieldType.isLongType()) {
Barriers.compilePutfieldBarrierLongImm(this, fieldOffset, fieldRef.getId());
} else if (NEEDS_SHORT_PUTFIELD_BARRIER && fieldType.isShortType()) {
Barriers.compilePutfieldBarrierShortImm(this, fieldOffset, fieldRef.getId());
} else if (NEEDS_WORD_PUTFIELD_BARRIER && fieldType.isWordType()) {
Barriers.compilePutfieldBarrierWordImm(this, fieldOffset, fieldRef.getId());
} else if (NEEDS_ADDRESS_PUTFIELD_BARRIER && fieldType.isAddressType()) {
Barriers.compilePutfieldBarrierAddressImm(this, fieldOffset, fieldRef.getId());
} else if (NEEDS_OFFSET_PUTFIELD_BARRIER && fieldType.isOffsetType()) {
Barriers.compilePutfieldBarrierOffsetImm(this, fieldOffset, fieldRef.getId());
} else if (NEEDS_EXTENT_PUTFIELD_BARRIER && fieldType.isExtentType()) {
Barriers.compilePutfieldBarrierExtentImm(this, fieldOffset, fieldRef.getId());
} else if (fieldType.isWordLikeType()) {
// 32/64bit word store
// T0 = value
popAddr(T0);
// T1 = object reference
popAddr(T1);
asm.emitSTAddrOffset(T0, T1, fieldOffset);
} else if (fieldType.isBooleanType() || fieldType.isByteType()) {
// 8bit store
// T0 = value
popInt(T0);
// T1 = object reference
popAddr(T1);
asm.emitSTBoffset(T0, T1, fieldOffset);
} else if (fieldType.isShortType() || fieldType.isCharType()) {
// 16bit store
// T0 = value
popInt(T0);
// T1 = object reference
popAddr(T1);
asm.emitSTHoffset(T0, T1, fieldOffset);
} else if (fieldType.isIntType() || fieldType.isFloatType()) {
// 32bit store
// T0 = value
popInt(T0);
// T1 = object reference
popAddr(T1);
asm.emitSTWoffset(T0, T1, fieldOffset);
} else {
// 64bit store
if (VM.VerifyAssertions)
VM._assert(fieldType.isLongType() || fieldType.isDoubleType());
// F0 = doubleword value
popDouble(F0);
// T1 = object reference
popAddr(T1);
asm.emitSTFDoffset(F0, T1, fieldOffset);
}
if (field.isVolatile()) {
// JMM: post-barrier when first operation
// StoreLoad barrier.
asm.emitHWSYNC();
}
}
use of org.jikesrvm.classloader.RVMField in project JikesRVM by JikesRVM.
the class BaselineCompilerImpl method emit_resolved_putfield.
@Override
protected void emit_resolved_putfield(FieldReference fieldRef) {
Barriers.compileModifyCheck(asm, fieldRef.getNumberOfStackSlots() * WORDSIZE);
RVMField field = fieldRef.peekResolvedField();
TypeReference fieldType = fieldRef.getFieldContentsType();
Offset fieldOffset = field.getOffset();
if (field.isReferenceType()) {
// 32/64bit reference store
if (NEEDS_OBJECT_PUTFIELD_BARRIER && !field.isUntraced()) {
Barriers.compilePutfieldBarrierImm(asm, fieldOffset, fieldRef.getId());
} else {
// T0 is the value to be stored
asm.emitPOP_Reg(T0);
// S0 is the object reference
asm.emitPOP_Reg(S0);
// [S0+fieldOffset] <- T0
if (VM.BuildFor32Addr) {
asm.emitMOV_RegDisp_Reg(S0, fieldOffset, T0);
} else {
asm.emitMOV_RegDisp_Reg_Quad(S0, fieldOffset, T0);
}
}
} else if (NEEDS_BOOLEAN_PUTFIELD_BARRIER && fieldType.isBooleanType()) {
Barriers.compilePutfieldBarrierBooleanImm(asm, fieldOffset, fieldRef.getId(), this);
} else if (NEEDS_BYTE_PUTFIELD_BARRIER && fieldType.isByteType()) {
Barriers.compilePutfieldBarrierByteImm(asm, fieldOffset, fieldRef.getId(), this);
} else if (NEEDS_CHAR_PUTFIELD_BARRIER && fieldType.isCharType()) {
Barriers.compilePutfieldBarrierCharImm(asm, fieldOffset, fieldRef.getId(), this);
} else if (NEEDS_DOUBLE_PUTFIELD_BARRIER && fieldType.isDoubleType()) {
Barriers.compilePutfieldBarrierDoubleImm(asm, fieldOffset, fieldRef.getId(), this);
} else if (NEEDS_FLOAT_PUTFIELD_BARRIER && fieldType.isFloatType()) {
Barriers.compilePutfieldBarrierFloatImm(asm, fieldOffset, fieldRef.getId(), this);
} else if (NEEDS_INT_PUTFIELD_BARRIER && fieldType.isIntType()) {
Barriers.compilePutfieldBarrierIntImm(asm, fieldOffset, fieldRef.getId(), this);
} else if (NEEDS_LONG_PUTFIELD_BARRIER && fieldType.isLongType()) {
Barriers.compilePutfieldBarrierLongImm(asm, fieldOffset, fieldRef.getId(), this);
} else if (NEEDS_SHORT_PUTFIELD_BARRIER && fieldType.isShortType()) {
Barriers.compilePutfieldBarrierShortImm(asm, fieldOffset, fieldRef.getId(), this);
} else if (NEEDS_WORD_PUTFIELD_BARRIER && fieldType.isWordType()) {
Barriers.compilePutfieldBarrierWordImm(asm, fieldOffset, fieldRef.getId(), this);
} else if (NEEDS_ADDRESS_PUTFIELD_BARRIER && fieldType.isAddressType()) {
Barriers.compilePutfieldBarrierAddressImm(asm, fieldOffset, fieldRef.getId(), this);
} else if (NEEDS_OFFSET_PUTFIELD_BARRIER && fieldType.isOffsetType()) {
Barriers.compilePutfieldBarrierOffsetImm(asm, fieldOffset, fieldRef.getId(), this);
} else if (NEEDS_EXTENT_PUTFIELD_BARRIER && fieldType.isExtentType()) {
Barriers.compilePutfieldBarrierExtentImm(asm, fieldOffset, fieldRef.getId(), this);
} else if (field.getSize() == BYTES_IN_BYTE) {
// no need for primitive write barriers
// 8bit store
// T0 is the value to be stored
asm.emitPOP_Reg(T0);
// S0 is the object reference
asm.emitPOP_Reg(S0);
// [S0+fieldOffset] <- T0
asm.emitMOV_RegDisp_Reg_Byte(S0, fieldOffset, T0);
} else if (field.getSize() == BYTES_IN_SHORT) {
// 16bit store
// T0 is the value to be stored
asm.emitPOP_Reg(T0);
// S0 is the object reference
asm.emitPOP_Reg(S0);
// [S0+fieldOffset] <- T0
asm.emitMOV_RegDisp_Reg_Word(S0, fieldOffset, T0);
} else if (field.getSize() == BYTES_IN_INT) {
// 32bit store
// T0 is the value to be stored
asm.emitPOP_Reg(T0);
// S0 is the object reference
asm.emitPOP_Reg(S0);
// [S0+fieldOffset] <- T0
asm.emitMOV_RegDisp_Reg(S0, fieldOffset, T0);
} else {
// 64bit store
if (VM.VerifyAssertions) {
VM._assert(field.getSize() == BYTES_IN_LONG);
}
if (VM.BuildFor32Addr) {
// NB this is a 64bit copy from the stack to memory so implement
// as a slightly optimized Intel memory copy using the FPU
// S0 is the object reference
asm.emitMOV_Reg_RegDisp(S0, SP, TWO_SLOTS);
if (SSE2_BASE) {
// XMM0 is the value to be stored
asm.emitMOVQ_Reg_RegInd(XMM0, SP);
// [S0+fieldOffset] <- XMM0
asm.emitMOVQ_RegDisp_Reg(S0, fieldOffset, XMM0);
} else {
// FP0 is the value to be stored
asm.emitFLD_Reg_RegInd_Quad(FP0, SP);
asm.emitFSTP_RegDisp_Reg_Quad(S0, fieldOffset, FP0);
}
// complete popping the values and reference
adjustStack(WORDSIZE * 3, true);
} else {
// T1 is the value to be stored
asm.emitPOP_Reg(T1);
if (!field.getType().isWordLikeType()) {
// throw away slot
adjustStack(WORDSIZE, true);
}
// S0 is the object reference
asm.emitPOP_Reg(S0);
// [S0+fieldOffset] <- T1
asm.emitMOV_RegDisp_Reg_Quad(S0, fieldOffset, T1);
}
}
if (field.isVolatile()) {
asm.emitMFENCE();
}
}
use of org.jikesrvm.classloader.RVMField in project JikesRVM by JikesRVM.
the class Class method getFieldInternal.
// --- Fields ---
@Pure
private RVMField getFieldInternal(Atom name) {
RVMClass ctype = type.asClass();
// (1) Check my public declared fields
RVMField[] fields = ctype.getDeclaredFields();
for (RVMField field : fields) {
if (field.isPublic() && field.getName() == name) {
return field;
}
}
// (2) Check superinterfaces
RVMClass[] interfaces = ctype.getDeclaredInterfaces();
for (RVMClass anInterface : interfaces) {
RVMField ans = anInterface.getClassForType().getFieldInternal(name);
if (ans != null)
return ans;
}
// (3) Check superclass (if I have one).
if (ctype.getSuperClass() != null) {
return ctype.getSuperClass().getClassForType().getFieldInternal(name);
}
return null;
}
Aggregations