use of org.jikesrvm.classloader.InterfaceMethodSignature in project JikesRVM by JikesRVM.
the class CallingConvention method callExpand.
/**
* Expands the calling convention for a particular call instruction.
*
* @param call the call instruction
* @param ir the IR that contains the call instruction
*/
private static void callExpand(Instruction call, IR ir) {
boolean isSysCall = call.operator() == IA32_SYSCALL;
// 0. Handle the parameters
int parameterBytes = isSysCall ? expandParametersToSysCall(call, ir) : expandParametersToCall(call, ir);
// 1. Clear the floating-point stack if dirty.
if (!SSE2_FULL) {
if (!call.operator().isCallSaveVolatile()) {
int FPRRegisterParams = countFPRParams(call);
FPRRegisterParams = Math.min(FPRRegisterParams, PhysicalRegisterSet.getNumberOfFPRParams());
call.insertBefore(MIR_UnaryNoRes.create(IA32_FCLEAR, IC(FPRRegisterParams)));
}
}
// 2. Move the return value into a register
expandResultOfCall(call, isSysCall, ir);
// in the processor object to hold the interface signature id.
if (VM.BuildForIMTInterfaceInvocation) {
if (MIR_Call.hasMethod(call)) {
MethodOperand mo = MIR_Call.getMethod(call);
if (mo.isInterface()) {
InterfaceMethodSignature sig = InterfaceMethodSignature.findOrCreate(mo.getMemberRef());
MemoryOperand M = MemoryOperand.BD(ir.regpool.makeTROp(), ArchEntrypoints.hiddenSignatureIdField.getOffset(), (byte) WORDSIZE, null, null);
call.insertBefore(MIR_Move.create(IA32_MOV, M, IC(sig.getId())));
}
}
}
// 4. ESP must be parameterBytes before call, will be at either parameterBytes
// or 0 afterwards depending on whether or it is an RVM method or a sysCall.
Instruction requireESP = MIR_UnaryNoRes.create(REQUIRE_ESP, IC(parameterBytes));
call.insertBefore(requireESP);
Instruction adviseESP = MIR_UnaryNoRes.create(ADVISE_ESP, IC(isSysCall ? parameterBytes : 0));
call.insertAfter(adviseESP);
// by 16 at the call.
if (VM.BuildFor64Addr && isSysCall) {
alignStackForX64SysCall(call, ir, parameterBytes, requireESP, adviseESP);
}
}
use of org.jikesrvm.classloader.InterfaceMethodSignature in project JikesRVM by JikesRVM.
the class BaselineCompilerImpl method emit_invokeinterface.
@Override
protected void emit_invokeinterface(MethodReference methodRef) {
// +1 for "this" parameter
int count = methodRef.getParameterWords() + 1;
RVMMethod resolvedMethod = null;
resolvedMethod = methodRef.peekInterfaceMethod();
// do so inline.
if (VM.BuildForIMTInterfaceInvocation) {
if (methodRef.isMiranda()) {
// TODO: It's not entirely clear that we can just assume that
// the class actually implements the interface.
// However, we don't know what interface we need to be checking
// so there doesn't appear to be much else we can do here.
} else {
if (resolvedMethod == null) {
// Can't successfully resolve it at compile time.
// Call uncommon case typechecking routine to do the right thing when this code actually executes.
asm.emitLAddrToc(T0, Entrypoints.unresolvedInvokeinterfaceImplementsTestMethod.getOffset());
asm.emitMTCTR(T0);
// id of method reference we are trying to call
asm.emitLVAL(T0, methodRef.getId());
// the "this" object
peekAddr(T1, count - 1);
// throw exception, if link error
asm.emitBCCTRL();
} else {
RVMClass interfaceClass = resolvedMethod.getDeclaringClass();
int interfaceIndex = interfaceClass.getDoesImplementIndex();
int interfaceMask = interfaceClass.getDoesImplementBitMask();
// the "this" object
peekAddr(T0, count - 1);
// TIB of "this" object
asm.baselineEmitLoadTIB(T0, T0);
// implements bit vector
asm.emitLAddr(T0, TIB_DOES_IMPLEMENT_INDEX << LOG_BYTES_IN_ADDRESS, T0);
if (DynamicTypeCheck.MIN_DOES_IMPLEMENT_SIZE <= interfaceIndex) {
// must do arraybounds check of implements bit vector
// T1 gets array length
asm.emitLIntOffset(T1, T0, ObjectModel.getArrayLengthOffset());
asm.emitLVAL(T2, interfaceIndex);
asm.emitCMPL(T2, T1);
// if in bounds, jump around trap. TODO: would like to encode "y" bit that this branch is expected to be takem.
ForwardReference fr1 = asm.emitForwardBC(LT);
// encoding of TRAP_ALWAYS MUST_IMPLEMENT_INTERFACE
asm.emitTWI(31, GPR.R12, MUST_IMPLEMENT_TRAP);
fr1.resolve(asm);
}
// Test the appropriate bit and if set, branch around another trap imm
asm.emitLInt(T1, interfaceIndex << LOG_BYTES_IN_INT, T0);
if ((interfaceMask & 0xffff) == interfaceMask) {
asm.emitANDI(S0, T1, interfaceMask);
} else {
if (VM.VerifyAssertions)
VM._assert((interfaceMask & 0xffff0000) == interfaceMask);
asm.emitANDIS(S0, T1, interfaceMask);
}
// TODO: encode "y" bit that branch is likely taken.
ForwardReference fr2 = asm.emitForwardBC(NE);
// encoding of TRAP_ALWAYS MUST_IMPLEMENT_INTERFACE
asm.emitTWI(31, GPR.R12, MUST_IMPLEMENT_TRAP);
fr2.resolve(asm);
}
}
}
// (2) Emit interface invocation sequence.
if (VM.BuildForIMTInterfaceInvocation) {
InterfaceMethodSignature sig = InterfaceMethodSignature.findOrCreate(methodRef);
// T0 is "this"
genMoveParametersToRegisters(true, methodRef);
asm.baselineEmitLoadTIB(S0, T0);
// Load the IMT base into S0
asm.emitLAddr(S0, TIB_INTERFACE_DISPATCH_TABLE_INDEX << LOG_BYTES_IN_ADDRESS, S0);
// the method address
asm.emitLAddrOffset(S0, S0, sig.getIMTOffset());
asm.emitMTCTR(S0);
// pass "hidden" parameter in S1 scratch register
asm.emitLVAL(S1, sig.getId());
asm.emitBCCTRL();
} else {
int itableIndex = -1;
if (VM.BuildForITableInterfaceInvocation && resolvedMethod != null) {
// get the index of the method in the Itable
itableIndex = InterfaceInvocation.getITableIndex(resolvedMethod.getDeclaringClass(), methodRef.getName(), methodRef.getDescriptor());
}
if (itableIndex == -1) {
// itable index is not known at compile-time.
// call "invokeInterface" to resolve object + method id into method address
int methodRefId = methodRef.getId();
asm.emitLAddrToc(T0, Entrypoints.invokeInterfaceMethod.getOffset());
asm.emitMTCTR(T0);
// object
peekAddr(T0, count - 1);
// method id
asm.emitLVAL(T1, methodRefId);
// T0 := resolved method address
asm.emitBCCTRL();
asm.emitMTCTR(T0);
genMoveParametersToRegisters(true, methodRef);
asm.emitBCCTRL();
} else {
// itable index is known at compile-time.
// call "findITable" to resolve object + interface id into
// itable address
asm.emitLAddrToc(T0, Entrypoints.findItableMethod.getOffset());
asm.emitMTCTR(T0);
// object
peekAddr(T0, count - 1);
asm.baselineEmitLoadTIB(T0, T0);
// interface id
asm.emitLVAL(T1, resolvedMethod.getDeclaringClass().getInterfaceId());
// T0 := itable reference
asm.emitBCCTRL();
// T0 := the method to call
asm.emitLAddr(T0, itableIndex << LOG_BYTES_IN_ADDRESS, T0);
asm.emitMTCTR(T0);
// T0 is "this"
genMoveParametersToRegisters(true, methodRef);
asm.emitBCCTRL();
}
}
genPopParametersAndPushReturnValue(true, methodRef);
}
use of org.jikesrvm.classloader.InterfaceMethodSignature in project JikesRVM by JikesRVM.
the class FinalMIRExpansion method expand.
/**
* @param ir the IR to expand
* @return upperbound on number of machine code instructions
* that will be generated for this IR
*/
public static int expand(IR ir) {
int instructionCount = 0;
int conditionalBranchCount = 0;
int machinecodeLength = 0;
PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet().asPPC();
MachineCodeOffsets mcOffsets = ir.MIRInfo.mcOffsets;
for (Instruction p = ir.firstInstructionInCodeOrder(); p != null; p = p.nextInstructionInCodeOrder()) {
mcOffsets.setMachineCodeOffset(p, -1);
switch(p.getOpcode()) {
case MIR_LOWTABLESWITCH_opcode:
{
BasicBlock tableBlock = p.getBasicBlock();
BasicBlock nextBlock = tableBlock.splitNodeWithLinksAt(p.prevInstructionInCodeOrder(), ir);
mcOffsets.setMachineCodeOffset(nextBlock.firstInstruction(), -1);
Register regI = MIR_LowTableSwitch.getIndex(p).getRegister();
int NumTargets = MIR_LowTableSwitch.getNumberOfTargets(p);
tableBlock.appendInstruction(MIR_Call.create0(PPC_BL, null, null, nextBlock.makeJumpTarget()));
for (int i = 0; i < NumTargets; i++) {
tableBlock.appendInstruction(MIR_DataLabel.create(PPC_DATA_LABEL, MIR_LowTableSwitch.getClearTarget(p, i)));
}
Register temp = phys.getGPR(0);
p.insertBefore(MIR_Move.create(PPC_MFSPR, A(temp), A(phys.getLR())));
p.insertBefore(MIR_Binary.create(PPC_SLWI, I(regI), I(regI), IC(2)));
p.insertBefore(MIR_LoadUpdate.create(PPC_LIntUX, I(temp), I(regI), A(temp)));
p.insertBefore(MIR_Binary.create(PPC_ADD, A(regI), A(regI), I(temp)));
p.insertBefore(MIR_Move.create(PPC_MTSPR, A(phys.getCTR()), A(regI)));
MIR_Branch.mutate(p, PPC_BCTR);
instructionCount += NumTargets + 7;
}
break;
case PPC_BCOND2_opcode:
{
RegisterOperand cond = MIR_CondBranch2.getClearValue(p);
p.insertAfter(MIR_CondBranch.create(PPC_BCOND, cond.copyU2U(), MIR_CondBranch2.getClearCond2(p), MIR_CondBranch2.getClearTarget2(p), MIR_CondBranch2.getClearBranchProfile2(p)));
MIR_CondBranch.mutate(p, PPC_BCOND, cond, MIR_CondBranch2.getClearCond1(p), MIR_CondBranch2.getClearTarget1(p), MIR_CondBranch2.getClearBranchProfile1(p));
conditionalBranchCount++;
}
break;
case PPC_BLRL_opcode:
case PPC_BCTRL_opcode:
{
// See also ConvertToLowlevelIR.java
if (VM.BuildForIMTInterfaceInvocation) {
if (MIR_Call.hasMethod(p)) {
MethodOperand mo = MIR_Call.getMethod(p);
if (mo.isInterface()) {
InterfaceMethodSignature sig = InterfaceMethodSignature.findOrCreate(mo.getMemberRef());
int signatureId = sig.getId();
Instruction s;
if (fits(signatureId, 16)) {
s = MIR_Unary.create(PPC_LDI, I(phys.getGPR(LAST_SCRATCH_GPR)), IC(signatureId));
p.insertBefore(s);
instructionCount++;
} else {
s = MIR_Unary.create(PPC_LDIS, I(phys.getGPR(LAST_SCRATCH_GPR)), IC(PPCMaskUpper16(signatureId)));
p.insertBefore(s);
s = MIR_Binary.create(PPC_ADDI, I(phys.getGPR(LAST_SCRATCH_GPR)), I(phys.getGPR(LAST_SCRATCH_GPR)), IC(PPCMaskLower16(signatureId)));
p.insertBefore(s);
instructionCount += 2;
}
}
}
}
instructionCount++;
}
break;
case LABEL_opcode:
case BBEND_opcode:
case UNINT_BEGIN_opcode:
case UNINT_END_opcode:
// These generate no code, so don't count them.
break;
case RESOLVE_opcode:
{
Register zero = phys.getGPR(0);
Register JTOC = phys.getJTOC();
Register CTR = phys.getCTR();
if (VM.VerifyAssertions)
VM._assert(p.getBytecodeIndex() >= 0 && p.position() != null);
Offset offset = Entrypoints.optResolveMethod.getOffset();
if (fits(offset, 16)) {
p.insertBefore(MIR_Load.create(PPC_LAddr, A(zero), A(JTOC), IC(PPCMaskLower16(offset))));
} else {
// not implemented
if (VM.VerifyAssertions)
VM._assert(fits(offset, 32));
p.insertBefore(MIR_Binary.create(PPC_ADDIS, A(zero), A(JTOC), IC(PPCMaskUpper16(offset))));
p.insertBefore(MIR_Load.create(PPC_LAddr, A(zero), A(zero), IC(PPCMaskLower16(offset))));
instructionCount += 1;
}
p.insertBefore(MIR_Move.create(PPC_MTSPR, A(CTR), A(zero)));
instructionCount += 3;
// Because the GC Map code holds a reference to the original
// instruction, it is important that we mutate the last instruction
// because this will be the GC point.
MIR_Call.mutate0(p, PPC_BCTRL, null, null);
break;
}
case YIELDPOINT_PROLOGUE_opcode:
{
Register TSR = phys.getTSR();
BasicBlock yieldpoint = findOrCreateYieldpointBlock(ir, RVMThread.PROLOGUE);
// Because the GC Map code holds a reference to the original
// instruction, it is important that we mutate the last instruction
// because this will be the GC point.
MIR_CondCall.mutate0(p, PPC_BCL, null, null, I(TSR), PowerPCConditionOperand.NOT_EQUAL(), yieldpoint.makeJumpTarget());
p.getBasicBlock().insertOut(yieldpoint);
conditionalBranchCount++;
}
break;
case YIELDPOINT_BACKEDGE_opcode:
{
BasicBlock yieldpoint = findOrCreateYieldpointBlock(ir, RVMThread.BACKEDGE);
Register zero = phys.getGPR(0);
Register TSR = phys.getTSR();
Register TR = phys.getTR();
Offset offset = Entrypoints.takeYieldpointField.getOffset();
if (VM.VerifyAssertions)
VM._assert(fits(offset, 16));
p.insertBefore(MIR_Load.create(PPC_LInt, I(zero), A(TR), IC(PPCMaskLower16(offset))));
p.insertBefore(MIR_Binary.create(PPC_CMPI, I(TSR), I(zero), IC(0)));
instructionCount += 2;
// Because the GC Map code holds a reference to the original
// instruction, it is important that we mutate the last instruction
// because this will be the GC point.
MIR_CondCall.mutate0(p, PPC_BCL, null, null, I(TSR), PowerPCConditionOperand.GREATER(), yieldpoint.makeJumpTarget());
p.getBasicBlock().insertOut(yieldpoint);
conditionalBranchCount++;
}
break;
case YIELDPOINT_EPILOGUE_opcode:
{
BasicBlock yieldpoint = findOrCreateYieldpointBlock(ir, RVMThread.EPILOGUE);
Register zero = phys.getGPR(0);
Register TSR = phys.getTSR();
Register TR = phys.getTR();
Offset offset = Entrypoints.takeYieldpointField.getOffset();
if (VM.VerifyAssertions)
VM._assert(fits(offset, 16));
p.insertBefore(MIR_Load.create(PPC_LInt, I(zero), A(TR), IC(PPCMaskLower16(offset))));
p.insertBefore(MIR_Binary.create(PPC_CMPI, I(TSR), I(zero), IC(0)));
instructionCount += 2;
// Because the GC Map code holds a reference to the original
// instruction, it is important that we mutate the last instruction
// because this will be the GC point.
MIR_CondCall.mutate0(p, PPC_BCL, null, null, I(TSR), PowerPCConditionOperand.NOT_EQUAL(), yieldpoint.makeJumpTarget());
p.getBasicBlock().insertOut(yieldpoint);
conditionalBranchCount++;
}
break;
case YIELDPOINT_OSR_opcode:
{
// unconditionally branch to yield point.
BasicBlock yieldpoint = findOrCreateYieldpointBlock(ir, RVMThread.OSROPT);
// Because the GC Map code holds a reference to the original
// instruction, it is important that we mutate the last instruction
// because this will be the GC point.
MIR_Call.mutate0(p, PPC_BL, null, null, yieldpoint.makeJumpTarget());
p.getBasicBlock().insertOut(yieldpoint);
}
instructionCount++;
break;
default:
if (p.operator().isConditionalBranch()) {
conditionalBranchCount++;
} else {
instructionCount++;
}
break;
}
}
// reasonably sized methods
if ((instructionCount + conditionalBranchCount) > AssemblerOpt.MAX_COND_DISPL) {
machinecodeLength = instructionCount + 2 * conditionalBranchCount;
} else {
machinecodeLength = instructionCount + conditionalBranchCount;
}
if ((machinecodeLength & ~AssemblerOpt.MAX_24_BITS) != 0) {
throw new OptimizingCompilerException("CodeGen", "method too large to compile:", AssemblerOpt.MAX_24_BITS);
}
return machinecodeLength;
}
use of org.jikesrvm.classloader.InterfaceMethodSignature in project JikesRVM by JikesRVM.
the class ConvertToLowLevelIR method callHelper.
/**
* Helper method for call expansion.
* @param v the call instruction
* @param ir the containing IR
* @return the last expanded instruction
*/
static Instruction callHelper(Instruction v, IR ir) {
if (!Call.hasMethod(v)) {
if (VM.VerifyAssertions)
VM._assert(Call.getAddress(v) instanceof RegisterOperand);
// nothing to do....very low level call to address already in the register.
return v;
}
MethodOperand methOp = Call.getMethod(v);
// Handle recursive invocations.
if (methOp.hasPreciseTarget() && methOp.getTarget() == ir.method) {
Call.setAddress(v, new BranchOperand(ir.firstInstructionInCodeOrder()));
return v;
}
// has been marked as a specialized call.
if (VM.runningVM) {
SpecializedMethod spMethod = methOp.spMethod;
if (spMethod != null) {
int smid = spMethod.getSpecializedMethodIndex();
Call.setAddress(v, getSpecialMethod(v, ir, smid));
return v;
}
}
// Used mainly (only?) by OSR
if (methOp.hasDesignatedTarget()) {
Call.setAddress(v, InsertLoadOffsetJTOC(v, ir, REF_LOAD, TypeReference.CodeArray, methOp.jtocOffset));
return v;
}
if (methOp.isStatic()) {
if (VM.VerifyAssertions)
VM._assert(Call.hasAddress(v));
Call.setAddress(v, InsertLoadOffsetJTOC(v, ir, REF_LOAD, TypeReference.CodeArray, Call.getClearAddress(v)));
} else if (methOp.isVirtual()) {
if (VM.VerifyAssertions)
VM._assert(Call.hasAddress(v));
if (ir.options.H2L_CALL_VIA_JTOC && methOp.hasPreciseTarget()) {
// Call to precise type can go via JTOC
RVMMethod target = methOp.getTarget();
Call.setAddress(v, InsertLoadOffsetJTOC(v, ir, REF_LOAD, TypeReference.CodeArray, target.findOrCreateJtocOffset()));
} else {
Operand tib = getTIB(v, ir, Call.getParam(v, 0).copy(), Call.getGuard(v).copy());
Call.setAddress(v, InsertLoadOffset(v, ir, REF_LOAD, TypeReference.CodeArray, tib, Call.getClearAddress(v), null, TG()));
}
} else if (methOp.isSpecial()) {
RVMMethod target = methOp.getTarget();
if (target == null || target.isObjectInitializer() || target.isStatic()) {
// target == null => we are calling an unresolved <init> method.
Call.setAddress(v, InsertLoadOffsetJTOC(v, ir, REF_LOAD, TypeReference.CodeArray, Call.getClearAddress(v)));
} else {
if (ir.options.H2L_CALL_VIA_JTOC) {
Call.setAddress(v, InsertLoadOffsetJTOC(v, ir, REF_LOAD, TypeReference.CodeArray, target.findOrCreateJtocOffset()));
} else {
// invoking a virtual method; do it via TIB of target's declaring class.
Operand tib = getTIB(v, ir, target.getDeclaringClass());
Call.setAddress(v, InsertLoadOffset(v, ir, REF_LOAD, TypeReference.CodeArray, tib, Call.getClearAddress(v), null, TG()));
}
}
} else {
if (VM.VerifyAssertions)
VM._assert(methOp.isInterface());
if (VM.VerifyAssertions)
VM._assert(!Call.hasAddress(v));
if (VM.BuildForIMTInterfaceInvocation) {
// SEE ALSO: FinalMIRExpansion (for hidden parameter)
Operand RHStib = getTIB(v, ir, Call.getParam(v, 0).copy(), Call.getGuard(v).copy());
InterfaceMethodSignature sig = InterfaceMethodSignature.findOrCreate(methOp.getMemberRef());
Offset offset = sig.getIMTOffset();
RegisterOperand address = null;
RegisterOperand IMT = InsertLoadOffset(v, ir, REF_LOAD, TypeReference.IMT, RHStib.copy(), Offset.fromIntZeroExtend(TIB_INTERFACE_DISPATCH_TABLE_INDEX << LOG_BYTES_IN_ADDRESS));
address = InsertLoadOffset(v, ir, REF_LOAD, TypeReference.CodeArray, IMT.copyD2U(), offset);
Call.setAddress(v, address);
} else {
int itableIndex = -1;
if (VM.BuildForITableInterfaceInvocation && methOp.hasTarget()) {
RVMClass I = methOp.getTarget().getDeclaringClass();
// search ITable variant
itableIndex = InterfaceInvocation.getITableIndex(I, methOp.getMemberRef().getName(), methOp.getMemberRef().getDescriptor());
}
if (itableIndex == -1) {
// itable index is not known at compile-time.
// call "invokeinterface" to resolve the object and method id
// into a method address
RegisterOperand realAddrReg = ir.regpool.makeTemp(TypeReference.CodeArray);
RVMMethod target = Entrypoints.invokeInterfaceMethod;
Instruction vp = Call.create2(CALL, realAddrReg, AC(target.getOffset()), MethodOperand.STATIC(target), Call.getParam(v, 0).asRegister().copyU2U(), IC(methOp.getMemberRef().getId()));
vp.setSourcePosition(RUNTIME_SERVICES_BCI, v.position());
v.insertBefore(vp);
callHelper(vp, ir);
Call.setAddress(v, realAddrReg.copyD2U());
return v;
} else {
// itable index is known at compile-time.
// call "findITable" to resolve object + interface id into
// itable address
RegisterOperand iTable = ir.regpool.makeTemp(TypeReference.ITable);
Operand RHStib = getTIB(v, ir, Call.getParam(v, 0).copy(), Call.getGuard(v).copy());
RVMMethod target = Entrypoints.findItableMethod;
Instruction fi = Call.create2(CALL, iTable, AC(target.getOffset()), MethodOperand.STATIC(target), RHStib, IC(methOp.getTarget().getDeclaringClass().getInterfaceId()));
fi.setSourcePosition(RUNTIME_SERVICES_BCI, v.position());
v.insertBefore(fi);
callHelper(fi, ir);
RegisterOperand address = InsertLoadOffset(v, ir, REF_LOAD, TypeReference.CodeArray, iTable.copyD2U(), Offset.fromIntZeroExtend(itableIndex << LOG_BYTES_IN_ADDRESS));
Call.setAddress(v, address);
return v;
}
}
}
return v;
}
use of org.jikesrvm.classloader.InterfaceMethodSignature in project JikesRVM by JikesRVM.
the class BaselineCompilerImpl method emit_invokeinterface.
@Override
protected void emit_invokeinterface(MethodReference methodRef) {
// +1 for "this" parameter
final int count = methodRef.getParameterWords() + 1;
RVMMethod resolvedMethod = null;
resolvedMethod = methodRef.peekInterfaceMethod();
// (1) Emit dynamic type checking sequence if required to do so inline.
if (VM.BuildForIMTInterfaceInvocation) {
if (methodRef.isMiranda()) {
// TODO: It's not entirely clear that we can just assume that
// the class actually implements the interface.
// However, we don't know what interface we need to be checking
// so there doesn't appear to be much else we can do here.
} else {
if (resolvedMethod == null) {
// Can't successfully resolve it at compile time.
// Call uncommon case typechecking routine to do the right thing when this code actually executes.
// T1 = "this" object
stackMoveHelper(T1, Offset.fromIntZeroExtend((count - 1) << LG_WORDSIZE));
// push dict id of target
asm.emitPUSH_Imm(methodRef.getId());
// push "this"
asm.emitPUSH_Reg(T1);
// pass 2 parameter word
genParameterRegisterLoad(asm, 2);
// check that "this" class implements the interface
asm.generateJTOCcall(Entrypoints.unresolvedInvokeinterfaceImplementsTestMethod.getOffset());
} else {
RVMClass interfaceClass = resolvedMethod.getDeclaringClass();
int interfaceIndex = interfaceClass.getDoesImplementIndex();
int interfaceMask = interfaceClass.getDoesImplementBitMask();
// T1 = "this" object
stackMoveHelper(T1, Offset.fromIntZeroExtend((count - 1) << LG_WORDSIZE));
// S0 = tib of "this" object
asm.baselineEmitLoadTIB(S0, T1);
if (VM.BuildFor32Addr) {
// implements bit vector
asm.emitMOV_Reg_RegDisp(S0, S0, Offset.fromIntZeroExtend(TIB_DOES_IMPLEMENT_INDEX << LG_WORDSIZE));
} else {
// implements bit vector
asm.emitMOV_Reg_RegDisp_Quad(S0, S0, Offset.fromIntZeroExtend(TIB_DOES_IMPLEMENT_INDEX << LG_WORDSIZE));
}
if (DynamicTypeCheck.MIN_DOES_IMPLEMENT_SIZE <= interfaceIndex) {
// must do arraybounds check of implements bit vector
if (ARRAY_LENGTH_BYTES == 4) {
asm.emitCMP_RegDisp_Imm(S0, ObjectModel.getArrayLengthOffset(), interfaceIndex);
} else {
asm.emitCMP_RegDisp_Imm_Quad(S0, ObjectModel.getArrayLengthOffset(), interfaceIndex);
}
asm.emitBranchLikelyNextInstruction();
ForwardReference fr = asm.forwardJcc(LGT);
asm.emitINT_Imm(RuntimeEntrypoints.TRAP_MUST_IMPLEMENT + RVM_TRAP_BASE);
fr.resolve(asm);
}
// Test the appropriate bit and if set, branch around another trap imm
if (interfaceIndex == 0) {
asm.emitTEST_RegInd_Imm(S0, interfaceMask);
} else {
asm.emitTEST_RegDisp_Imm(S0, Offset.fromIntZeroExtend(interfaceIndex << LOG_BYTES_IN_INT), interfaceMask);
}
asm.emitBranchLikelyNextInstruction();
ForwardReference fr = asm.forwardJcc(NE);
asm.emitINT_Imm(RuntimeEntrypoints.TRAP_MUST_IMPLEMENT + RVM_TRAP_BASE);
fr.resolve(asm);
}
}
}
// (2) Emit interface invocation sequence.
if (VM.BuildForIMTInterfaceInvocation) {
InterfaceMethodSignature sig = InterfaceMethodSignature.findOrCreate(methodRef);
// squirrel away signature ID
Offset offset = ArchEntrypoints.hiddenSignatureIdField.getOffset();
asm.emitMOV_RegDisp_Imm(THREAD_REGISTER, offset, sig.getId());
// T1 = "this" object
stackMoveHelper(T1, Offset.fromIntZeroExtend((count - 1) << LG_WORDSIZE));
asm.baselineEmitLoadTIB(S0, T1);
// Load the IMT Base into S0
if (VM.BuildFor32Addr) {
asm.emitMOV_Reg_RegDisp(S0, S0, Offset.fromIntZeroExtend(TIB_INTERFACE_DISPATCH_TABLE_INDEX << LG_WORDSIZE));
} else {
asm.emitMOV_Reg_RegDisp_Quad(S0, S0, Offset.fromIntZeroExtend(TIB_INTERFACE_DISPATCH_TABLE_INDEX << LG_WORDSIZE));
}
genParameterRegisterLoad(methodRef, true);
// the interface call
asm.emitCALL_RegDisp(S0, sig.getIMTOffset());
} else {
int itableIndex = -1;
if (VM.BuildForITableInterfaceInvocation && resolvedMethod != null) {
// get the index of the method in the Itable
itableIndex = InterfaceInvocation.getITableIndex(resolvedMethod.getDeclaringClass(), methodRef.getName(), methodRef.getDescriptor());
}
if (itableIndex == -1) {
// itable index is not known at compile-time.
// call "invokeInterface" to resolve object + method id into
// method address
int methodRefId = methodRef.getId();
// "this" parameter is obj
if (count == 1) {
asm.emitPUSH_RegInd(SP);
} else {
asm.emitPUSH_RegDisp(SP, Offset.fromIntZeroExtend((count - 1) << LG_WORDSIZE));
}
// id of method to call
asm.emitPUSH_Imm(methodRefId);
// pass 2 parameter words
genParameterRegisterLoad(asm, 2);
// invokeinterface(obj, id) returns address to call
asm.generateJTOCcall(Entrypoints.invokeInterfaceMethod.getOffset());
if (VM.BuildFor32Addr) {
// S0 has address of method
asm.emitMOV_Reg_Reg(S0, T0);
} else {
// S0 has address of method
asm.emitMOV_Reg_Reg_Quad(S0, T0);
}
genParameterRegisterLoad(methodRef, true);
// the interface method (its parameters are on stack)
asm.emitCALL_Reg(S0);
} else {
// itable index is known at compile-time.
// call "findITable" to resolve object + interface id into
// itable address
// T0 = "this" object
stackMoveHelper(T0, Offset.fromIntZeroExtend((count - 1) << LG_WORDSIZE));
asm.baselineEmitLoadTIB(S0, T0);
asm.emitPUSH_Reg(S0);
// interface id
asm.emitPUSH_Imm(resolvedMethod.getDeclaringClass().getInterfaceId());
// pass 2 parameter words
genParameterRegisterLoad(asm, 2);
// findItableOffset(tib, id) returns iTable
asm.generateJTOCcall(Entrypoints.findItableMethod.getOffset());
if (VM.BuildFor32Addr) {
// S0 has iTable
asm.emitMOV_Reg_Reg(S0, T0);
} else {
// S0 has iTable
asm.emitMOV_Reg_Reg_Quad(S0, T0);
}
genParameterRegisterLoad(methodRef, true);
// the interface call
asm.emitCALL_RegDisp(S0, Offset.fromIntZeroExtend(itableIndex << LG_WORDSIZE));
}
}
genResultRegisterUnload(methodRef);
}
Aggregations