Search in sources :

Example 1 with InterfaceMethodSignature

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);
    }
}
Also used : InterfaceMethodSignature(org.jikesrvm.classloader.InterfaceMethodSignature) MemoryOperand(org.jikesrvm.compilers.opt.ir.operand.MemoryOperand) Instruction(org.jikesrvm.compilers.opt.ir.Instruction) MethodOperand(org.jikesrvm.compilers.opt.ir.operand.MethodOperand)

Example 2 with InterfaceMethodSignature

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);
}
Also used : ForwardReference(org.jikesrvm.compilers.common.assembler.ForwardReference) InterfaceMethodSignature(org.jikesrvm.classloader.InterfaceMethodSignature) RVMMethod(org.jikesrvm.classloader.RVMMethod) RVMClass(org.jikesrvm.classloader.RVMClass)

Example 3 with InterfaceMethodSignature

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;
}
Also used : InterfaceMethodSignature(org.jikesrvm.classloader.InterfaceMethodSignature) RegisterOperand(org.jikesrvm.compilers.opt.ir.operand.RegisterOperand) Register(org.jikesrvm.compilers.opt.ir.Register) PhysicalRegisterSet(org.jikesrvm.compilers.opt.ir.ppc.PhysicalRegisterSet) BasicBlock(org.jikesrvm.compilers.opt.ir.BasicBlock) MachineCodeOffsets(org.jikesrvm.compilers.opt.mir2mc.MachineCodeOffsets) OptimizingCompilerException(org.jikesrvm.compilers.opt.OptimizingCompilerException) Instruction(org.jikesrvm.compilers.opt.ir.Instruction) MethodOperand(org.jikesrvm.compilers.opt.ir.operand.MethodOperand) Offset(org.vmmagic.unboxed.Offset)

Example 4 with InterfaceMethodSignature

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;
}
Also used : InterfaceMethodSignature(org.jikesrvm.classloader.InterfaceMethodSignature) RVMMethod(org.jikesrvm.classloader.RVMMethod) RegisterOperand(org.jikesrvm.compilers.opt.ir.operand.RegisterOperand) SpecializedMethod(org.jikesrvm.compilers.opt.specialization.SpecializedMethod) TypeOperand(org.jikesrvm.compilers.opt.ir.operand.TypeOperand) RegisterOperand(org.jikesrvm.compilers.opt.ir.operand.RegisterOperand) TIBConstantOperand(org.jikesrvm.compilers.opt.ir.operand.TIBConstantOperand) LocationOperand(org.jikesrvm.compilers.opt.ir.operand.LocationOperand) IntConstantOperand(org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand) AddressConstantOperand(org.jikesrvm.compilers.opt.ir.operand.AddressConstantOperand) MethodOperand(org.jikesrvm.compilers.opt.ir.operand.MethodOperand) ConditionOperand(org.jikesrvm.compilers.opt.ir.operand.ConditionOperand) Operand(org.jikesrvm.compilers.opt.ir.operand.Operand) BranchProfileOperand(org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand) TrapCodeOperand(org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand) BranchOperand(org.jikesrvm.compilers.opt.ir.operand.BranchOperand) Instruction(org.jikesrvm.compilers.opt.ir.Instruction) BranchOperand(org.jikesrvm.compilers.opt.ir.operand.BranchOperand) MethodOperand(org.jikesrvm.compilers.opt.ir.operand.MethodOperand) Offset(org.vmmagic.unboxed.Offset) RVMClass(org.jikesrvm.classloader.RVMClass)

Example 5 with InterfaceMethodSignature

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);
}
Also used : ForwardReference(org.jikesrvm.compilers.common.assembler.ForwardReference) InterfaceMethodSignature(org.jikesrvm.classloader.InterfaceMethodSignature) RVMMethod(org.jikesrvm.classloader.RVMMethod) RVMClass(org.jikesrvm.classloader.RVMClass) Offset(org.vmmagic.unboxed.Offset)

Aggregations

InterfaceMethodSignature (org.jikesrvm.classloader.InterfaceMethodSignature)5 RVMClass (org.jikesrvm.classloader.RVMClass)3 RVMMethod (org.jikesrvm.classloader.RVMMethod)3 Instruction (org.jikesrvm.compilers.opt.ir.Instruction)3 MethodOperand (org.jikesrvm.compilers.opt.ir.operand.MethodOperand)3 Offset (org.vmmagic.unboxed.Offset)3 ForwardReference (org.jikesrvm.compilers.common.assembler.ForwardReference)2 RegisterOperand (org.jikesrvm.compilers.opt.ir.operand.RegisterOperand)2 OptimizingCompilerException (org.jikesrvm.compilers.opt.OptimizingCompilerException)1 BasicBlock (org.jikesrvm.compilers.opt.ir.BasicBlock)1 Register (org.jikesrvm.compilers.opt.ir.Register)1 AddressConstantOperand (org.jikesrvm.compilers.opt.ir.operand.AddressConstantOperand)1 BranchOperand (org.jikesrvm.compilers.opt.ir.operand.BranchOperand)1 BranchProfileOperand (org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand)1 ConditionOperand (org.jikesrvm.compilers.opt.ir.operand.ConditionOperand)1 IntConstantOperand (org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand)1 LocationOperand (org.jikesrvm.compilers.opt.ir.operand.LocationOperand)1 MemoryOperand (org.jikesrvm.compilers.opt.ir.operand.MemoryOperand)1 Operand (org.jikesrvm.compilers.opt.ir.operand.Operand)1 TIBConstantOperand (org.jikesrvm.compilers.opt.ir.operand.TIBConstantOperand)1