Search in sources :

Example 26 with RVMClass

use of org.jikesrvm.classloader.RVMClass in project JikesRVM by JikesRVM.

the class DynamicTypeCheckExpansion method generateBranchingTypeCheck.

/**
 * Generate a branching dynamic type check.
 * This routine assumes that the CFG and code order are already
 * correctly established.
 * This routine must either remove s or mutate it.
 *
 * @param s          The Instruction that is to be replaced by a
 *                   branching type check
 * @param ir         The IR containing the instruction to be expanded.
 * @param RHSobj     The RegisterOperand containing the rhs object.
 * @param LHStype    The TypeReference to be tested against.
 * @param RHStib     The Operand containing the TIB of the rhs.
 * @param trueBlock  The BasicBlock to continue at if the typecheck
 *                   evaluates to true
 * @param falseBlock The BasicBlock to continue at if the typecheck
 *                   evaluates to false.
 * @param oldGuard   A suitable guard operand (not necessarily related
 *                   the instruction that is to be replaced).
 * @param falseProb   The probability that typecheck will branch to the falseBlock
 * @return the opt instruction immediately before the instruction to
 *         continue expansion.
 */
private static Instruction generateBranchingTypeCheck(Instruction s, IR ir, Operand RHSobj, TypeReference LHStype, Operand RHStib, BasicBlock trueBlock, BasicBlock falseBlock, RegisterOperand oldGuard, BranchProfileOperand falseProb) {
    Instruction continueAt = Goto.create(GOTO, trueBlock.makeJumpTarget());
    continueAt.copyPosition(s);
    s.insertBefore(continueAt);
    s.remove();
    if (LHStype.isClassType()) {
        RVMClass LHSclass = (RVMClass) LHStype.peekType();
        if (LHSclass != null && LHSclass.isResolved()) {
            // class or interface
            if (LHSclass.isInterface()) {
                // A resolved interface (case 4)
                int interfaceIndex = LHSclass.getDoesImplementIndex();
                int interfaceMask = LHSclass.getDoesImplementBitMask();
                RegisterOperand doesImpl = InsertUnary(continueAt, ir, GET_DOES_IMPLEMENT_FROM_TIB, TypeReference.IntArray, RHStib);
                if (DynamicTypeCheck.MIN_DOES_IMPLEMENT_SIZE <= interfaceIndex) {
                    RegisterOperand doesImplLength = InsertGuardedUnary(continueAt, ir, ARRAYLENGTH, TypeReference.Int, doesImpl.copyD2U(), TG());
                    Instruction lengthCheck = IfCmp.create(INT_IFCMP, oldGuard, doesImplLength, IC(interfaceIndex), ConditionOperand.LESS_EQUAL(), falseBlock.makeJumpTarget(), BranchProfileOperand.unlikely());
                    if (oldGuard != null) {
                        oldGuard = oldGuard.copyD2D();
                    }
                    continueAt.insertBefore(lengthCheck);
                    BasicBlock oldBlock = continueAt.getBasicBlock();
                    oldBlock.splitNodeWithLinksAt(lengthCheck, ir);
                    // required due to splitNode!
                    oldBlock.insertOut(falseBlock);
                }
                RegisterOperand entry = InsertLoadOffset(continueAt, ir, INT_LOAD, TypeReference.Int, doesImpl, Offset.fromIntZeroExtend(interfaceIndex << 2), new LocationOperand(TypeReference.Int), TG());
                RegisterOperand bit = insertBinary(continueAt, ir, INT_AND, TypeReference.Int, entry, IC(interfaceMask));
                continueAt.insertBefore(IfCmp.create(INT_IFCMP, oldGuard, bit, IC(0), ConditionOperand.EQUAL(), falseBlock.makeJumpTarget(), falseProb));
                return continueAt;
            } else {
                // A resolved class (cases 5 and 6 in DynamicTypeCheck)
                if (LHSclass.isFinal()) {
                    // For a final class, we can do a PTR compare of
                    // rhsTIB and the TIB of the class
                    Operand classTIB = getTIB(continueAt, ir, LHSclass);
                    continueAt.insertBefore(IfCmp.create(REF_IFCMP, oldGuard, RHStib, classTIB, ConditionOperand.NOT_EQUAL(), falseBlock.makeJumpTarget(), falseProb));
                    return continueAt;
                } else {
                    // Do the full blown case 5 or 6 typecheck.
                    int LHSDepth = LHSclass.getTypeDepth();
                    int LHSId = LHSclass.getId();
                    RegisterOperand superclassIds = InsertUnary(continueAt, ir, GET_SUPERCLASS_IDS_FROM_TIB, TypeReference.ShortArray, RHStib);
                    if (DynamicTypeCheck.MIN_SUPERCLASS_IDS_SIZE <= LHSDepth) {
                        RegisterOperand superclassIdsLength = InsertGuardedUnary(continueAt, ir, ARRAYLENGTH, TypeReference.Int, superclassIds.copyD2U(), TG());
                        Instruction lengthCheck = IfCmp.create(INT_IFCMP, oldGuard, superclassIdsLength, IC(LHSDepth), ConditionOperand.LESS(), falseBlock.makeJumpTarget(), BranchProfileOperand.unlikely());
                        if (oldGuard != null) {
                            oldGuard = oldGuard.copyD2D();
                        }
                        continueAt.insertBefore(lengthCheck);
                        BasicBlock oldBlock = continueAt.getBasicBlock();
                        oldBlock.splitNodeWithLinksAt(lengthCheck, ir);
                        // required due to splitNode!
                        oldBlock.insertOut(falseBlock);
                    }
                    RegisterOperand refCandidate = InsertLoadOffset(continueAt, ir, USHORT_LOAD, TypeReference.Short, superclassIds, Offset.fromIntZeroExtend(LHSDepth << 1), new LocationOperand(TypeReference.Short), TG());
                    continueAt.insertBefore(IfCmp.create(INT_IFCMP, oldGuard, refCandidate, IC(LHSId), ConditionOperand.NOT_EQUAL(), falseBlock.makeJumpTarget(), falseProb));
                    return continueAt;
                }
            }
        } else {
            // A non-resolved class or interface. Case 3 of DynamicTypeCheck
            // Branch on the result of a call to
            // RuntimeEntrypoints.instance
            RegisterOperand result = ir.regpool.makeTempInt();
            RVMMethod target = Entrypoints.instanceOfMethod;
            Instruction call = Call.create2(CALL, result, AC(target.getOffset()), MethodOperand.STATIC(target), RHSobj, IC(LHStype.getId()));
            call.copyPosition(continueAt);
            continueAt.insertBefore(call);
            call = callHelper(call, ir);
            continueAt.insertBefore(IfCmp.create(INT_IFCMP, oldGuard, result.copyD2U(), IC(0), ConditionOperand.EQUAL(), falseBlock.makeJumpTarget(), falseProb));
            return continueAt;
        }
    }
    if (LHStype.isArrayType()) {
        // Case 2 of DynamicTypeCheck: LHS is an array.
        RVMArray LHSArray = (RVMArray) LHStype.peekType();
        if (LHSArray != null) {
            Operand classTIB = getTIB(continueAt, ir, LHSArray);
            RVMType innermostElementType = LHSArray.getInnermostElementType();
            if (innermostElementType.isPrimitiveType() || innermostElementType.isUnboxedType() || (innermostElementType.asClass().isResolved() && innermostElementType.asClass().isFinal())) {
                // [^k of primitive or [^k of final class. Just like final classes,
                // a PTR compare of rhsTIB and the TIB of the class gives the answer.
                continueAt.insertBefore(IfCmp.create(REF_IFCMP, oldGuard, RHStib, classTIB, ConditionOperand.NOT_EQUAL(), falseBlock.makeJumpTarget(), falseProb));
                return continueAt;
            }
            // TODO: branch probability calculation is somewhat bogus for this case.
            Instruction shortcircuit = IfCmp.create(REF_IFCMP, oldGuard, RHStib, classTIB, ConditionOperand.EQUAL(), trueBlock.makeJumpTarget(), new BranchProfileOperand());
            if (oldGuard != null) {
                oldGuard = oldGuard.copyD2D();
            }
            continueAt.insertBefore(shortcircuit);
            BasicBlock myBlock = shortcircuit.getBasicBlock();
            BasicBlock mainBlock = myBlock.splitNodeWithLinksAt(shortcircuit, ir);
            // must come after the splitNodeAt
            myBlock.insertOut(trueBlock);
            RegisterOperand rhsType = InsertUnary(continueAt, ir, GET_TYPE_FROM_TIB, TypeReference.Type, RHStib.copy());
            if (innermostElementType.isJavaLangObjectType()) {
                IntConstantOperand lhsDimension = IC(LHStype.getDimensionality());
                RegisterOperand rhsDimension = getField(continueAt, ir, rhsType, Entrypoints.dimensionField);
                Instruction dimTest = IfCmp2.create(INT_IFCMP2, oldGuard, rhsDimension, lhsDimension, ConditionOperand.GREATER(), trueBlock.makeJumpTarget(), ((BranchProfileOperand) falseProb.copy()).flip(), ConditionOperand.LESS(), falseBlock.makeJumpTarget(), (BranchProfileOperand) falseProb.copy());
                if (oldGuard != null) {
                    oldGuard = oldGuard.copyD2D();
                }
                continueAt.insertBefore(dimTest);
                // BasicBlock testBlock =
                mainBlock.splitNodeWithLinksAt(dimTest, ir);
                mainBlock.insertOut(trueBlock);
                mainBlock.insertOut(falseBlock);
                RegisterOperand rhsInnermostElementTypeDimension = getField(continueAt, ir, rhsType.copyU2U(), Entrypoints.innermostElementTypeDimensionField);
                continueAt.insertBefore(IfCmp.create(INT_IFCMP, oldGuard, rhsInnermostElementTypeDimension, IC(0), ConditionOperand.NOT_EQUAL(), falseBlock.makeJumpTarget(), falseProb));
                return continueAt;
            }
        }
        // Not a case we want to handle inline
        RVMMethod target = Entrypoints.instanceOfMethod;
        RegisterOperand callResult = ir.regpool.makeTempInt();
        Instruction call = Call.create2(CALL, callResult, AC(target.getOffset()), MethodOperand.STATIC(target), RHSobj, IC(LHStype.getId()));
        call.copyPosition(continueAt);
        continueAt.insertBefore(call);
        call = callHelper(call, ir);
        continueAt.insertBefore(IfCmp.create(INT_IFCMP, oldGuard, callResult.copyD2U(), IC(0), ConditionOperand.EQUAL(), falseBlock.makeJumpTarget(), falseProb));
        return continueAt;
    }
    OptimizingCompilerException.UNREACHABLE();
    return null;
}
Also used : RVMMethod(org.jikesrvm.classloader.RVMMethod) LocationOperand(org.jikesrvm.compilers.opt.ir.operand.LocationOperand) RegisterOperand(org.jikesrvm.compilers.opt.ir.operand.RegisterOperand) IntConstantOperand(org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand) MethodOperand(org.jikesrvm.compilers.opt.ir.operand.MethodOperand) RegisterOperand(org.jikesrvm.compilers.opt.ir.operand.RegisterOperand) TrueGuardOperand(org.jikesrvm.compilers.opt.ir.operand.TrueGuardOperand) ConditionOperand(org.jikesrvm.compilers.opt.ir.operand.ConditionOperand) Operand(org.jikesrvm.compilers.opt.ir.operand.Operand) NullConstantOperand(org.jikesrvm.compilers.opt.ir.operand.NullConstantOperand) BranchProfileOperand(org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand) TrapCodeOperand(org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand) LocationOperand(org.jikesrvm.compilers.opt.ir.operand.LocationOperand) IntConstantOperand(org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand) RVMArray(org.jikesrvm.classloader.RVMArray) RVMType(org.jikesrvm.classloader.RVMType) BasicBlock(org.jikesrvm.compilers.opt.ir.BasicBlock) BranchProfileOperand(org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand) Instruction(org.jikesrvm.compilers.opt.ir.Instruction) RVMClass(org.jikesrvm.classloader.RVMClass)

Example 27 with RVMClass

use of org.jikesrvm.classloader.RVMClass in project JikesRVM by JikesRVM.

the class ExpandRuntimeServices method perform.

/**
 * Given an HIR, expand operators that are implemented as calls to
 * runtime service methods. This method should be called as one of the
 * first steps in lowering HIR into LIR.
 *
 * @param ir  The HIR to expand
 */
@Override
public void perform(IR ir) {
    // resync generation context -- yuck...
    ir.getGc().resync();
    for (Instruction inst = ir.firstInstructionInCodeOrder(); inst != null; inst = next) {
        next = inst.nextInstructionInCodeOrder();
        int opcode = inst.getOpcode();
        switch(opcode) {
            case NEW_opcode:
                {
                    TypeOperand Type = New.getClearType(inst);
                    RVMClass cls = (RVMClass) Type.getVMType();
                    IntConstantOperand hasFinalizer = IRTools.IC(cls.hasFinalizer() ? 1 : 0);
                    RVMMethod callSite = inst.position().getMethod();
                    IntConstantOperand allocator = IRTools.IC(MemoryManager.pickAllocator(cls, callSite));
                    IntConstantOperand align = IRTools.IC(ObjectModel.getAlignment(cls));
                    IntConstantOperand offset = IRTools.IC(ObjectModel.getOffsetForAlignment(cls, false));
                    Operand tib = ConvertToLowLevelIR.getTIB(inst, ir, Type);
                    if (VM.BuildForIA32 && VM.runningVM) {
                        // shield BC2IR from address constants
                        RegisterOperand tmp = ir.regpool.makeTemp(TypeReference.TIB);
                        inst.insertBefore(Move.create(REF_MOVE, tmp, tib));
                        tib = tmp.copyRO();
                    }
                    IntConstantOperand site = IRTools.IC(MemoryManager.getAllocationSite(true));
                    RVMMethod target = Entrypoints.resolvedNewScalarMethod;
                    Call.mutate7(inst, CALL, New.getClearResult(inst), IRTools.AC(target.getOffset()), MethodOperand.STATIC(target), IRTools.IC(cls.getInstanceSize()), tib, hasFinalizer, allocator, align, offset, site);
                    next = inst.prevInstructionInCodeOrder();
                    if (ir.options.H2L_INLINE_NEW) {
                        if (inst.getBasicBlock().getInfrequent())
                            container.counter1++;
                        container.counter2++;
                        if (!ir.options.FREQ_FOCUS_EFFORT || !inst.getBasicBlock().getInfrequent()) {
                            inline(inst, ir);
                        }
                    }
                }
                break;
            case NEW_UNRESOLVED_opcode:
                {
                    int typeRefId = New.getType(inst).getTypeRef().getId();
                    RVMMethod target = Entrypoints.unresolvedNewScalarMethod;
                    IntConstantOperand site = IRTools.IC(MemoryManager.getAllocationSite(true));
                    Call.mutate2(inst, CALL, New.getClearResult(inst), IRTools.AC(target.getOffset()), MethodOperand.STATIC(target), IRTools.IC(typeRefId), site);
                }
                break;
            case NEWARRAY_opcode:
                {
                    TypeOperand Array = NewArray.getClearType(inst);
                    RVMArray array = (RVMArray) Array.getVMType();
                    Operand numberElements = NewArray.getClearSize(inst);
                    boolean inline = numberElements instanceof IntConstantOperand;
                    Operand width = IRTools.IC(array.getLogElementSize());
                    Operand headerSize = IRTools.IC(ObjectModel.computeArrayHeaderSize(array));
                    RVMMethod callSite = inst.position().getMethod();
                    IntConstantOperand allocator = IRTools.IC(MemoryManager.pickAllocator(array, callSite));
                    IntConstantOperand align = IRTools.IC(ObjectModel.getAlignment(array));
                    IntConstantOperand offset = IRTools.IC(ObjectModel.getOffsetForAlignment(array, false));
                    Operand tib = ConvertToLowLevelIR.getTIB(inst, ir, Array);
                    if (VM.BuildForIA32 && VM.runningVM) {
                        // shield BC2IR from address constants
                        RegisterOperand tmp = ir.regpool.makeTemp(TypeReference.TIB);
                        inst.insertBefore(Move.create(REF_MOVE, tmp, tib));
                        tib = tmp.copyRO();
                    }
                    IntConstantOperand site = IRTools.IC(MemoryManager.getAllocationSite(true));
                    RVMMethod target = Entrypoints.resolvedNewArrayMethod;
                    Call.mutate8(inst, CALL, NewArray.getClearResult(inst), IRTools.AC(target.getOffset()), MethodOperand.STATIC(target), numberElements, width, headerSize, tib, allocator, align, offset, site);
                    next = inst.prevInstructionInCodeOrder();
                    if (inline && ir.options.H2L_INLINE_NEW) {
                        if (inst.getBasicBlock().getInfrequent())
                            container.counter1++;
                        container.counter2++;
                        if (!ir.options.FREQ_FOCUS_EFFORT || !inst.getBasicBlock().getInfrequent()) {
                            inline(inst, ir);
                        }
                    }
                }
                break;
            case NEWARRAY_UNRESOLVED_opcode:
                {
                    int typeRefId = NewArray.getType(inst).getTypeRef().getId();
                    Operand numberElements = NewArray.getClearSize(inst);
                    RVMMethod target = Entrypoints.unresolvedNewArrayMethod;
                    IntConstantOperand site = IRTools.IC(MemoryManager.getAllocationSite(true));
                    Call.mutate3(inst, CALL, NewArray.getClearResult(inst), IRTools.AC(target.getOffset()), MethodOperand.STATIC(target), numberElements, IRTools.IC(typeRefId), site);
                }
                break;
            case NEWOBJMULTIARRAY_opcode:
                {
                    int dimensions = Multianewarray.getNumberOfDimensions(inst);
                    RVMMethod callSite = inst.position().getMethod();
                    int typeRefId = Multianewarray.getType(inst).getTypeRef().getId();
                    if (dimensions == 2) {
                        RVMMethod target = Entrypoints.optNew2DArrayMethod;
                        Call.mutate4(inst, CALL, Multianewarray.getClearResult(inst), IRTools.AC(target.getOffset()), MethodOperand.STATIC(target), IRTools.IC(callSite.getId()), Multianewarray.getClearDimension(inst, 0), Multianewarray.getClearDimension(inst, 1), IRTools.IC(typeRefId));
                    } else {
                        // Step 1: Create an int array to hold the dimensions.
                        TypeOperand dimArrayType = new TypeOperand(RVMArray.IntArray);
                        RegisterOperand dimArray = ir.regpool.makeTemp(TypeReference.IntArray);
                        dimArray.setPreciseType();
                        next = NewArray.create(NEWARRAY, dimArray, dimArrayType, new IntConstantOperand(dimensions));
                        inst.insertBefore(next);
                        // Step 2: Assign the dimension values to dimArray
                        for (int i = 0; i < dimensions; i++) {
                            LocationOperand loc = new LocationOperand(TypeReference.Int);
                            inst.insertBefore(AStore.create(INT_ASTORE, Multianewarray.getClearDimension(inst, i), dimArray.copyD2U(), IRTools.IC(i), loc, IRTools.TG()));
                        }
                        // Step 3. Plant call to OptLinker.newArrayArray
                        RVMMethod target = Entrypoints.optNewArrayArrayMethod;
                        Call.mutate3(inst, CALL, Multianewarray.getClearResult(inst), IRTools.AC(target.getOffset()), MethodOperand.STATIC(target), IRTools.IC(callSite.getId()), dimArray.copyD2U(), IRTools.IC(typeRefId));
                    }
                }
                break;
            case ATHROW_opcode:
                {
                    RVMMethod target = Entrypoints.athrowMethod;
                    MethodOperand methodOp = MethodOperand.STATIC(target);
                    // Record the fact that this is a non-returning call.
                    methodOp.setIsNonReturningCall(true);
                    Call.mutate1(inst, CALL, null, IRTools.AC(target.getOffset()), methodOp, Athrow.getClearValue(inst));
                }
                break;
            case MONITORENTER_opcode:
                {
                    Operand ref = MonitorOp.getClearRef(inst);
                    RVMType refType = ref.getType().peekType();
                    if (refType != null && !refType.getThinLockOffset().isMax()) {
                        RVMMethod target = Entrypoints.inlineLockMethod;
                        Call.mutate2(inst, CALL, null, IRTools.AC(target.getOffset()), MethodOperand.STATIC(target), MonitorOp.getClearGuard(inst), ref, IRTools.AC(refType.getThinLockOffset()));
                        next = inst.prevInstructionInCodeOrder();
                        if (inst.getBasicBlock().getInfrequent())
                            container.counter1++;
                        container.counter2++;
                        if (!ir.options.FREQ_FOCUS_EFFORT || !inst.getBasicBlock().getInfrequent()) {
                            inline(inst, ir);
                        }
                    } else {
                        RVMMethod target = Entrypoints.lockMethod;
                        Call.mutate1(inst, CALL, null, IRTools.AC(target.getOffset()), MethodOperand.STATIC(target), MonitorOp.getClearGuard(inst), ref);
                    }
                }
                break;
            case MONITOREXIT_opcode:
                {
                    Operand ref = MonitorOp.getClearRef(inst);
                    RVMType refType = ref.getType().peekType();
                    if (refType != null && !refType.getThinLockOffset().isMax()) {
                        RVMMethod target = Entrypoints.inlineUnlockMethod;
                        Call.mutate2(inst, CALL, null, IRTools.AC(target.getOffset()), MethodOperand.STATIC(target), MonitorOp.getClearGuard(inst), ref, IRTools.AC(refType.getThinLockOffset()));
                        next = inst.prevInstructionInCodeOrder();
                        if (inst.getBasicBlock().getInfrequent())
                            container.counter1++;
                        container.counter2++;
                        if (!ir.options.FREQ_FOCUS_EFFORT || !inst.getBasicBlock().getInfrequent()) {
                            inline(inst, ir);
                        }
                    } else {
                        RVMMethod target = Entrypoints.unlockMethod;
                        Call.mutate1(inst, CALL, null, IRTools.AC(target.getOffset()), MethodOperand.STATIC(target), MonitorOp.getClearGuard(inst), ref);
                    }
                }
                break;
            case REF_ASTORE_opcode:
                {
                    if (NEEDS_OBJECT_ASTORE_BARRIER) {
                        RVMMethod target = Entrypoints.objectArrayWriteBarrierMethod;
                        Instruction wb = Call.create3(CALL, null, IRTools.AC(target.getOffset()), MethodOperand.STATIC(target), AStore.getClearGuard(inst), AStore.getArray(inst).copy(), AStore.getIndex(inst).copy(), AStore.getValue(inst).copy());
                        replaceInstructionWithBarrier(inst, wb);
                        if (ir.options.H2L_INLINE_WRITE_BARRIER) {
                            inline(wb, ir, true);
                        }
                    }
                }
                break;
            case BYTE_ASTORE_opcode:
                {
                    if (NEEDS_BYTE_ASTORE_BARRIER) {
                        primitiveArrayStoreHelper(Entrypoints.byteArrayWriteBarrierMethod, inst, ir);
                    }
                }
                break;
            case DOUBLE_ASTORE_opcode:
                {
                    if (NEEDS_DOUBLE_ASTORE_BARRIER) {
                        primitiveArrayStoreHelper(Entrypoints.doubleArrayWriteBarrierMethod, inst, ir);
                    }
                }
                break;
            case FLOAT_ASTORE_opcode:
                {
                    if (NEEDS_FLOAT_ASTORE_BARRIER) {
                        primitiveArrayStoreHelper(Entrypoints.floatArrayWriteBarrierMethod, inst, ir);
                    }
                }
                break;
            case INT_ASTORE_opcode:
                {
                    if (NEEDS_INT_ASTORE_BARRIER) {
                        primitiveArrayStoreHelper(Entrypoints.intArrayWriteBarrierMethod, inst, ir);
                    }
                }
                break;
            case LONG_ASTORE_opcode:
                {
                    if (NEEDS_LONG_ASTORE_BARRIER) {
                        primitiveArrayStoreHelper(Entrypoints.longArrayWriteBarrierMethod, inst, ir);
                    }
                }
                break;
            case SHORT_ASTORE_opcode:
                {
                    TypeReference type = AStore.getLocation(inst).getElementType();
                    if (NEEDS_SHORT_ASTORE_BARRIER && type.isShortType()) {
                        primitiveArrayStoreHelper(Entrypoints.shortArrayWriteBarrierMethod, inst, ir);
                    } else if (NEEDS_CHAR_ASTORE_BARRIER) {
                        if (VM.VerifyAssertions)
                            VM._assert(type.isCharType());
                        primitiveArrayStoreHelper(Entrypoints.charArrayWriteBarrierMethod, inst, ir);
                    }
                }
                break;
            case REF_ALOAD_opcode:
                {
                    if (NEEDS_OBJECT_ALOAD_BARRIER) {
                        RVMMethod target = Entrypoints.objectArrayReadBarrierMethod;
                        Instruction rb = Call.create2(CALL, ALoad.getClearResult(inst), IRTools.AC(target.getOffset()), MethodOperand.STATIC(target), ALoad.getClearGuard(inst), ALoad.getArray(inst).copy(), ALoad.getIndex(inst).copy());
                        replaceInstructionWithBarrier(inst, rb);
                        inline(rb, ir, true);
                    }
                }
                break;
            case PUTFIELD_opcode:
                {
                    if (NEEDS_OBJECT_PUTFIELD_BARRIER) {
                        LocationOperand loc = PutField.getLocation(inst);
                        FieldReference fieldRef = loc.getFieldRef();
                        if (!fieldRef.getFieldContentsType().isPrimitiveType()) {
                            // reference PUTFIELD
                            RVMField field = fieldRef.peekResolvedField();
                            if (field == null || !field.isUntraced()) {
                                RVMMethod target = Entrypoints.objectFieldWriteBarrierMethod;
                                Instruction wb = Call.create4(CALL, null, IRTools.AC(target.getOffset()), MethodOperand.STATIC(target), PutField.getClearGuard(inst), PutField.getRef(inst).copy(), PutField.getValue(inst).copy(), PutField.getOffset(inst).copy(), IRTools.IC(fieldRef.getId()));
                                replaceInstructionWithBarrier(inst, wb);
                                if (ir.options.H2L_INLINE_WRITE_BARRIER) {
                                    inline(wb, ir, true);
                                }
                            }
                        } else {
                            // primitive PUTFIELD
                            if (NEEDS_BOOLEAN_PUTFIELD_BARRIER && fieldRef.getFieldContentsType().isBooleanType()) {
                                primitiveObjectFieldStoreHelper(Entrypoints.booleanFieldWriteBarrierMethod, inst, ir, fieldRef);
                            } else if (NEEDS_BYTE_PUTFIELD_BARRIER && fieldRef.getFieldContentsType().isByteType()) {
                                primitiveObjectFieldStoreHelper(Entrypoints.byteFieldWriteBarrierMethod, inst, ir, fieldRef);
                            } else if (NEEDS_CHAR_PUTFIELD_BARRIER && fieldRef.getFieldContentsType().isCharType()) {
                                primitiveObjectFieldStoreHelper(Entrypoints.charFieldWriteBarrierMethod, inst, ir, fieldRef);
                            } else if (NEEDS_DOUBLE_PUTFIELD_BARRIER && fieldRef.getFieldContentsType().isDoubleType()) {
                                primitiveObjectFieldStoreHelper(Entrypoints.doubleFieldWriteBarrierMethod, inst, ir, fieldRef);
                            } else if (NEEDS_FLOAT_PUTFIELD_BARRIER && fieldRef.getFieldContentsType().isFloatType()) {
                                primitiveObjectFieldStoreHelper(Entrypoints.floatFieldWriteBarrierMethod, inst, ir, fieldRef);
                            } else if (NEEDS_INT_PUTFIELD_BARRIER && fieldRef.getFieldContentsType().isIntType()) {
                                primitiveObjectFieldStoreHelper(Entrypoints.intFieldWriteBarrierMethod, inst, ir, fieldRef);
                            } else if (NEEDS_LONG_PUTFIELD_BARRIER && fieldRef.getFieldContentsType().isLongType()) {
                                primitiveObjectFieldStoreHelper(Entrypoints.longFieldWriteBarrierMethod, inst, ir, fieldRef);
                            } else if (NEEDS_SHORT_PUTFIELD_BARRIER && fieldRef.getFieldContentsType().isShortType()) {
                                primitiveObjectFieldStoreHelper(Entrypoints.shortFieldWriteBarrierMethod, inst, ir, fieldRef);
                            } else if (NEEDS_WORD_PUTFIELD_BARRIER && fieldRef.getFieldContentsType().isWordType()) {
                                primitiveObjectFieldStoreHelper(Entrypoints.wordFieldWriteBarrierMethod, inst, ir, fieldRef);
                            } else if (NEEDS_ADDRESS_PUTFIELD_BARRIER && fieldRef.getFieldContentsType().isAddressType()) {
                                primitiveObjectFieldStoreHelper(Entrypoints.addressFieldWriteBarrierMethod, inst, ir, fieldRef);
                            } else if (NEEDS_EXTENT_PUTFIELD_BARRIER && fieldRef.getFieldContentsType().isExtentType()) {
                                primitiveObjectFieldStoreHelper(Entrypoints.extentFieldWriteBarrierMethod, inst, ir, fieldRef);
                            } else if (NEEDS_OFFSET_PUTFIELD_BARRIER && fieldRef.getFieldContentsType().isOffsetType()) {
                                primitiveObjectFieldStoreHelper(Entrypoints.offsetFieldWriteBarrierMethod, inst, ir, fieldRef);
                            }
                        }
                    }
                }
                break;
            case GETFIELD_opcode:
                {
                    if (NEEDS_OBJECT_GETFIELD_BARRIER) {
                        LocationOperand loc = GetField.getLocation(inst);
                        FieldReference fieldRef = loc.getFieldRef();
                        if (GetField.getResult(inst).getType().isReferenceType()) {
                            RVMField field = fieldRef.peekResolvedField();
                            if (field == null || !field.isUntraced()) {
                                RVMMethod target = Entrypoints.objectFieldReadBarrierMethod;
                                Instruction rb = Call.create3(CALL, GetField.getClearResult(inst), IRTools.AC(target.getOffset()), MethodOperand.STATIC(target), GetField.getClearGuard(inst), GetField.getRef(inst).copy(), GetField.getOffset(inst).copy(), IRTools.IC(fieldRef.getId()));
                                replaceInstructionWithBarrier(inst, rb);
                                inline(rb, ir, true);
                            }
                        }
                    }
                }
                break;
            case PUTSTATIC_opcode:
                {
                    if (NEEDS_OBJECT_PUTSTATIC_BARRIER) {
                        LocationOperand loc = PutStatic.getLocation(inst);
                        FieldReference field = loc.getFieldRef();
                        if (!field.getFieldContentsType().isPrimitiveType()) {
                            RVMMethod target = Entrypoints.objectStaticWriteBarrierMethod;
                            Instruction wb = Call.create3(CALL, null, IRTools.AC(target.getOffset()), MethodOperand.STATIC(target), PutStatic.getValue(inst).copy(), PutStatic.getOffset(inst).copy(), IRTools.IC(field.getId()));
                            replaceInstructionWithBarrier(inst, wb);
                            if (ir.options.H2L_INLINE_WRITE_BARRIER) {
                                inline(wb, ir, true);
                            }
                        }
                    }
                }
                break;
            case GETSTATIC_opcode:
                {
                    if (NEEDS_OBJECT_GETSTATIC_BARRIER) {
                        LocationOperand loc = GetStatic.getLocation(inst);
                        FieldReference field = loc.getFieldRef();
                        if (!field.getFieldContentsType().isPrimitiveType()) {
                            RVMMethod target = Entrypoints.objectStaticReadBarrierMethod;
                            Instruction rb = Call.create2(CALL, GetStatic.getClearResult(inst), IRTools.AC(target.getOffset()), MethodOperand.STATIC(target), GetStatic.getOffset(inst).copy(), IRTools.IC(field.getId()));
                            replaceInstructionWithBarrier(inst, rb);
                            inline(rb, ir, true);
                        }
                    }
                }
                break;
            default:
                break;
        }
    }
    // If we actually inlined anything, clean up the mess
    if (didSomething) {
        if (branchOpts == null) {
            branchOpts = new BranchOptimizations(-1, true, true);
        }
        branchOpts.perform(ir, true);
        if (_os == null) {
            _os = new Simple(1, false, false, false, false);
        }
        _os.perform(ir);
    }
    // signal that we do not intend to use the gc in other phases anymore.
    ir.getGc().close();
}
Also used : IntConstantOperand(org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand) FieldReference(org.jikesrvm.classloader.FieldReference) MethodOperand(org.jikesrvm.compilers.opt.ir.operand.MethodOperand) TypeOperand(org.jikesrvm.compilers.opt.ir.operand.TypeOperand) RegisterOperand(org.jikesrvm.compilers.opt.ir.operand.RegisterOperand) Operand(org.jikesrvm.compilers.opt.ir.operand.Operand) LocationOperand(org.jikesrvm.compilers.opt.ir.operand.LocationOperand) IntConstantOperand(org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand) RVMType(org.jikesrvm.classloader.RVMType) Instruction(org.jikesrvm.compilers.opt.ir.Instruction) RVMClass(org.jikesrvm.classloader.RVMClass) MethodOperand(org.jikesrvm.compilers.opt.ir.operand.MethodOperand) Simple(org.jikesrvm.compilers.opt.Simple) RVMMethod(org.jikesrvm.classloader.RVMMethod) LocationOperand(org.jikesrvm.compilers.opt.ir.operand.LocationOperand) RegisterOperand(org.jikesrvm.compilers.opt.ir.operand.RegisterOperand) RVMArray(org.jikesrvm.classloader.RVMArray) TypeOperand(org.jikesrvm.compilers.opt.ir.operand.TypeOperand) RVMField(org.jikesrvm.classloader.RVMField) TypeReference(org.jikesrvm.classloader.TypeReference) BranchOptimizations(org.jikesrvm.compilers.opt.controlflow.BranchOptimizations)

Example 28 with RVMClass

use of org.jikesrvm.classloader.RVMClass in project JikesRVM by JikesRVM.

the class ClassLoadingDependencyManager method handleOverriddenMethods.

// //////////////////////
// Implementation
// //////////////////////
/**
 * Takes action when a method is overridden.
 * @param c a class that has just been loaded.
 */
private void handleOverriddenMethods(RVMClass c) {
    // nothing to do.
    if (c.isJavaLangObjectType() || c.isInterface())
        return;
    RVMClass sc = c.getSuperClass();
    // for each virtual method of sc, if it is overriden by
    // a virtual method declared by c, then handle any required invalidations.
    RVMMethod[] sc_methods = sc.getVirtualMethods();
    RVMMethod[] c_methods = c.getVirtualMethods();
    for (int i = 0; i < sc_methods.length; i++) {
        if (sc_methods[i] != c_methods[i]) {
            processOverride(sc_methods[i]);
        }
    }
    // implementation
    for (RVMClass intf : c.getAllImplementedInterfaces()) {
        for (RVMMethod m : intf.getVirtualMethods()) {
            processOverride(m);
        }
    }
}
Also used : RVMMethod(org.jikesrvm.classloader.RVMMethod) RVMClass(org.jikesrvm.classloader.RVMClass)

Example 29 with RVMClass

use of org.jikesrvm.classloader.RVMClass in project JikesRVM by JikesRVM.

the class DefaultInlineOracle method shouldInline.

@Override
public InlineDecision shouldInline(final CompilationState state) {
    final OptOptions opts = state.getOptions();
    final boolean verbose = opts.PRINT_DETAILED_INLINE_REPORT;
    if (!opts.INLINE) {
        return NO("inlining not enabled");
    }
    final RVMMethod staticCallee = state.obtainTarget();
    final NormalMethod rootMethod = state.getRootMethod();
    final RVMMethod caller = state.getMethod();
    final int bcIndex = state.getRealBytecodeIndex();
    if (verbose)
        VM.sysWriteln("Begin inline decision for " + "<" + caller + "," + bcIndex + "," + staticCallee + ">");
    // Stage 1: We definitely don't inline certain methods
    if (!state.isInvokeInterface()) {
        if (staticCallee.isNative()) {
            reportUnguardedDecisionIfVerbose("NO: native method", verbose);
            return NO("native method");
        }
        if (hasNoInlinePragma(staticCallee, state)) {
            reportUnguardedDecisionIfVerbose("NO: pragmaNoInline", verbose);
            return NO("pragmaNoInline");
        }
        // traces (see StackTrace).
        if (staticCallee.isObjectInitializer() && staticCallee.getDeclaringClass().isAssignableToThrowable()) {
            reportUnguardedDecisionIfVerbose("NO: constructor of class assignable to throwable", verbose);
            return NO("constructor of class assignable to throwable");
        }
    }
    // at worse replace one call instruction with another one).
    if (!state.isInvokeInterface() && !staticCallee.isAbstract()) {
        // above test passes
        if (state.getHasPreciseTarget() || !needsGuard(staticCallee)) {
            // call is guardless
            int inlinedSizeEstimate = inlinedSizeEstimate((NormalMethod) staticCallee, state);
            if (inlinedSizeEstimate < opts.INLINE_MAX_ALWAYS_INLINE_TARGET_SIZE) {
                // inlining is desirable
                if (!state.getSequence().containsMethod(staticCallee)) {
                    // not recursive
                    reportUnguardedDecisionIfVerbose("YES: trivial guardless inline", verbose);
                    return YES(staticCallee, "trivial inline");
                }
            }
            if (hasInlinePragma(staticCallee, state)) {
                // inlining is desirable
                if (!state.getSequence().containsMethod(staticCallee)) {
                    // not recursive
                    reportUnguardedDecisionIfVerbose("YES: pragma inline", verbose);
                    return YES(staticCallee, "pragma inline");
                }
            }
        }
    }
    if (opts.getOptLevel() == 0) {
        // at opt level 0, trivial unguarded inlines are the only kind we consider
        reportUnguardedDecisionIfVerbose("NO: only do trivial inlines at O0", verbose);
        return NO("Only do trivial inlines at O0");
    }
    // than faster boot image compilation.
    if (VM.runningVM && rootMethod.inlinedSizeEstimate() > opts.INLINE_MASSIVE_METHOD_SIZE) {
        reportUnguardedDecisionIfVerbose("NO: only do trivial inlines into massive methods when the VM is running", verbose);
        return NO("Root method is massive; no non-trivial inlines");
    }
    // Stage 3: Determine based on profile data and static information
    // what are the possible targets of this call.
    WeightedCallTargets targets = null;
    boolean purelyStatic = true;
    if (Controller.dcgAvailable() && Controller.options.ADAPTIVE_INLINING) {
        targets = Controller.dcg.getCallTargets(caller, bcIndex);
        if (targets != null) {
            reportProfilingIfVerbose("Found profile data", verbose);
            purelyStatic = false;
            WeightedCallTargets filteredTargets = targets.filter(staticCallee, state.getHasPreciseTarget());
            if (targets != filteredTargets) {
                reportProfilingIfVerbose("Profiled callees filtered based on static information", verbose);
                targets = filteredTargets;
                if (targets == null) {
                    reportProfilingIfVerbose("After filterting no profile data...", verbose);
                    // After filtering, no matching profile data, fall back to
                    // static information to avoid degradations
                    targets = WeightedCallTargets.create(staticCallee, 0);
                    purelyStatic = true;
                }
            }
        }
    }
    // we are inspecting it to determine how/whether to do the inline guard.
    synchronized (RVMClass.classLoadListener) {
        boolean guardOverrideOnStaticCallee = false;
        if (targets == null) {
            reportUnguardedDecisionIfVerbose("no profile data", verbose);
            // be able to share all the decision making logic.
            if (state.isInvokeInterface()) {
                if (opts.INLINE_GUARDED_INTERFACES) {
                    RVMMethod singleImpl = InterfaceHierarchy.getUniqueImplementation(staticCallee);
                    if (singleImpl != null && hasBody(singleImpl)) {
                        if (verbose) {
                            VM.sysWriteln("\tFound a single implementation " + singleImpl + " of an interface method " + staticCallee);
                        }
                        targets = WeightedCallTargets.create(singleImpl, 0);
                        guardOverrideOnStaticCallee = true;
                    }
                }
            } else {
                // invokestatic, invokevirtual, invokespecial
                if (staticCallee.isAbstract()) {
                    // look for single non-abstract implementation of the abstract method
                    RVMClass klass = staticCallee.getDeclaringClass();
                    while (true) {
                        RVMClass[] subClasses = klass.getSubClasses();
                        // multiple subclasses => multiple targets
                        if (subClasses.length != 1)
                            break;
                        RVMMethod singleImpl = subClasses[0].findDeclaredMethod(staticCallee.getName(), staticCallee.getDescriptor());
                        if (singleImpl != null && !singleImpl.isAbstract()) {
                            // found something
                            reportProfilingIfVerbose("single impl of abstract method", verbose);
                            targets = WeightedCallTargets.create(singleImpl, 0);
                            guardOverrideOnStaticCallee = true;
                            break;
                        }
                        // keep crawling down the hierarchy
                        klass = subClasses[0];
                    }
                } else {
                    targets = WeightedCallTargets.create(staticCallee, 0);
                }
            }
        }
        // If there is a precise target, then targets contains exactly that target method.
        if (targets == null)
            return NO("No potential targets identified");
        // Stage 4: We have one or more targets.  Determine what if anything should be done with them.
        final ArrayList<RVMMethod> methodsToInline = new ArrayList<RVMMethod>();
        final ArrayList<Boolean> methodsNeedGuard = new ArrayList<Boolean>();
        final double callSiteWeight = targets.totalWeight();
        // real closures anyone?
        final boolean goosc = guardOverrideOnStaticCallee;
        // real closures anyone?
        final boolean ps = purelyStatic;
        targets.visitTargets(new WeightedCallTargets.Visitor() {

            @Override
            public void visit(RVMMethod callee, double weight) {
                if (hasBody(callee)) {
                    reportInitialProfileState(verbose, callee, weight);
                    // Don't inline recursively and respect no inline pragmas
                    InlineSequence seq = state.getSequence();
                    if (seq.containsMethod(callee)) {
                        reportSelectionIfVerbose("Reject: recursive", verbose);
                        return;
                    }
                    if (hasNoInlinePragma(callee, state)) {
                        reportSelectionIfVerbose("Reject: noinline pragma", verbose);
                        return;
                    }
                    // more or less figure out the guard situation early -- impacts size estimate.
                    boolean needsGuard = !state.getHasPreciseTarget() && (staticCallee != callee || needsGuard(staticCallee));
                    if (needsGuard && isForbiddenSpeculation(state.getRootMethod(), callee)) {
                        reportSelectionIfVerbose("Reject: forbidden speculation", verbose);
                        return;
                    }
                    boolean currentlyFinal = (goosc || (staticCallee == callee)) && isCurrentlyFinal(callee, !opts.guardWithClassTest());
                    boolean preEx = needsGuard && state.getIsExtant() && opts.INLINE_PREEX && currentlyFinal;
                    if (needsGuard && !preEx) {
                        if (!opts.INLINE_GUARDED) {
                            reportSelectionIfVerbose("Reject: guarded inlining disabled", verbose);
                            return;
                        }
                        if (!currentlyFinal && ps) {
                            reportSelectionIfVerbose("Reject: multiple targets and no profile data", verbose);
                            return;
                        }
                    }
                    // Estimate cost of performing this inlining action.
                    // Includes cost of guard & off-branch call if they are going to be generated.
                    boolean decideYes = false;
                    if (hasInlinePragma(callee, state)) {
                        reportSelectionIfVerbose("Select: pragma inline", verbose);
                        decideYes = true;
                    } else {
                        // Preserve previous inlining decisions
                        // Not the best thing in the world due to phase shifts, but
                        // it does buy some degree of stability. So, it is probably the lesser
                        // of two evils.
                        CompiledMethod prev = state.getRootMethod().getCurrentCompiledMethod();
                        if (prev != null && prev.getCompilerType() == CompiledMethod.OPT) {
                            if (((OptCompiledMethod) prev).getMCMap().hasInlinedEdge(caller, bcIndex, callee)) {
                                reportSelectionIfVerbose("Select: Previously inlined", verbose);
                                decideYes = true;
                            }
                        }
                        if (!decideYes) {
                            int inlinedSizeEstimate = inlinedSizeEstimate((NormalMethod) callee, state);
                            int cost = inliningActionCost(inlinedSizeEstimate, needsGuard, preEx, opts);
                            int maxCost = opts.INLINE_MAX_TARGET_SIZE;
                            if (callSiteWeight > Controller.options.INLINE_AI_SEED_MULTIPLIER) {
                                // real profile data with enough samples for us to trust it.
                                // Use weight and shape of call site distribution to compute
                                // a higher maxCost.
                                double fractionOfSample = weight / callSiteWeight;
                                if (needsGuard && fractionOfSample < opts.INLINE_AI_MIN_CALLSITE_FRACTION) {
                                    // This call accounts for less than INLINE_AI_MIN_CALLSITE_FRACTION
                                    // of the profiled targets at this call site.
                                    // It is highly unlikely to be profitable to inline it.
                                    reportSelectionIfVerbose("Reject: less than INLINE_AI_MIN_CALLSITE_FRACTION of distribution", verbose);
                                    maxCost = 0;
                                } else {
                                    if (cost > maxCost) {
                                        /* We're going to increase the maximum callee size (maxCost) we're willing
                       * to inline based on how "hot" (what % of the total weight in the
                       * dynamic call graph) the edge is.
                       */
                                        double adjustedWeight = AdaptiveInlining.adjustedWeight(weight);
                                        if (adjustedWeight > Controller.options.INLINE_AI_HOT_CALLSITE_THRESHOLD) {
                                            /* A truly hot edge; use the max allowable callee size */
                                            maxCost = opts.INLINE_AI_MAX_TARGET_SIZE;
                                        } else {
                                            /* A warm edge, we will use a value between the static default and the max allowable.
                         * The code below simply does a linear interpolation between 2x static default
                         * and max allowable.
                         * Other alternatives would be to do a log interpolation or some other step function.
                         */
                                            int range = opts.INLINE_AI_MAX_TARGET_SIZE - 2 * opts.INLINE_MAX_TARGET_SIZE;
                                            double slope = (range) / Controller.options.INLINE_AI_HOT_CALLSITE_THRESHOLD;
                                            int scaledAdj = (int) (slope * adjustedWeight);
                                            maxCost += opts.INLINE_MAX_TARGET_SIZE + scaledAdj;
                                        }
                                    }
                                }
                            }
                            // Somewhat bogus, but if we get really deeply inlined we start backing off.
                            int curDepth = state.getInlineDepth();
                            if (curDepth > opts.INLINE_MAX_INLINE_DEPTH) {
                                maxCost /= (curDepth - opts.INLINE_MAX_INLINE_DEPTH + 1);
                            }
                            decideYes = cost <= maxCost;
                            if (decideYes) {
                                reportSelectionIfVerbose("Accept: cost of " + cost + " was below threshold " + maxCost, verbose);
                            } else {
                                reportSelectionIfVerbose("Reject: cost of " + cost + " was above threshold " + maxCost, verbose);
                            }
                        }
                    }
                    if (decideYes) {
                        // Ok, we're going to inline it.
                        // Record that and also whether or not we think it needs a guard.
                        methodsToInline.add(callee);
                        if (preEx) {
                            ClassLoadingDependencyManager cldm = (ClassLoadingDependencyManager) RVMClass.classLoadListener;
                            if (ClassLoadingDependencyManager.TRACE || ClassLoadingDependencyManager.DEBUG) {
                                cldm.report("PREEX_INLINE: Inlined " + callee + " into " + caller);
                            }
                            cldm.addNotOverriddenDependency(callee, state.getCompiledMethod());
                            if (goosc) {
                                cldm.addNotOverriddenDependency(staticCallee, state.getCompiledMethod());
                            }
                            methodsNeedGuard.add(Boolean.FALSE);
                        } else {
                            methodsNeedGuard.add(needsGuard);
                        }
                    }
                }
            }

            private void reportInitialProfileState(final boolean verbose, RVMMethod callee, double weight) {
                double adjustedWeight = AdaptiveInlining.adjustedWeight(weight);
                String sampleString = " samples (";
                if (Double.isNaN(adjustedWeight)) {
                    sampleString += "no DCG available)";
                } else {
                    sampleString += (100 * adjustedWeight) + "%)";
                }
                reportProfilingIfVerbose("Evaluating target " + callee + " with " + weight + sampleString, verbose);
            }
        });
        // Stage 5: Choose guards and package up the results in an InlineDecision object
        if (methodsToInline.isEmpty()) {
            InlineDecision d = NO("No desirable targets");
            reportGuardedDecisionIfVerbose(d, verbose);
            return d;
        } else if (methodsToInline.size() == 1) {
            RVMMethod target = methodsToInline.get(0);
            boolean needsGuard = methodsNeedGuard.get(0);
            if (needsGuard) {
                if ((guardOverrideOnStaticCallee || target == staticCallee) && isCurrentlyFinal(target, !opts.guardWithClassTest())) {
                    InlineDecision d = guardedYES(target, chooseGuard(caller, target, staticCallee, state, true), "Guarded inline of single static target");
                    /*
             * Determine if it is allowable to put an OSR point in the failed case of
             * the guarded inline instead of generating a real call instruction.
             * There are several conditions that must be met for this to be allowable:
             *   (1) OSR guarded inlining and recompilation must both be enabled
             *   (2) The current context must be an interruptible method
             *   (3) The application must be started.  This is a rough proxy for the VM
             *       being fully booted so we can actually get through the OSR process.
             *       Note: One implication of this requirement is that we will
             *       never put an OSR on an off-branch of a guarded inline in bootimage
             *       code.
             */
                    if (opts.OSR_GUARDED_INLINING && Controller.options.ENABLE_RECOMPILATION && caller.isInterruptible() && OptimizingCompiler.getAppStarted()) {
                        if (VM.VerifyAssertions)
                            VM._assert(VM.runningVM);
                        d.setOSRTestFailed();
                    }
                    if (verbose)
                        VM.sysWriteln("\tDecide: " + d);
                    return d;
                } else {
                    InlineDecision d = guardedYES(target, chooseGuard(caller, target, staticCallee, state, false), "Guarded inlining of one potential target");
                    reportGuardedDecisionIfVerbose(d, verbose);
                    return d;
                }
            } else {
                InlineDecision d = YES(target, "Unique and desirable target");
                reportGuardedDecisionIfVerbose(d, verbose);
                return d;
            }
        } else {
            RVMMethod[] methods = new RVMMethod[methodsNeedGuard.size()];
            byte[] guards = new byte[methods.length];
            int idx = 0;
            Iterator<RVMMethod> methodIterator = methodsToInline.iterator();
            Iterator<Boolean> guardIterator = methodsNeedGuard.iterator();
            while (methodIterator.hasNext()) {
                RVMMethod target = methodIterator.next();
                boolean needsGuard = guardIterator.next();
                if (VM.VerifyAssertions) {
                    if (!needsGuard) {
                        VM.sysWriteln("Error, inlining for " + methodsToInline.size() + " targets");
                        VM.sysWriteln("Inlining into " + rootMethod + " at bytecode index " + bcIndex);
                        VM.sysWriteln("Method: " + target + " doesn't need a guard");
                        for (int i = 0; i < methodsToInline.size(); i++) {
                            VM.sysWriteln("  Method " + i + ": " + methodsToInline.get(i));
                            VM.sysWriteln("  NeedsGuard: " + methodsNeedGuard.get(i));
                        }
                        VM._assert(VM.NOT_REACHED);
                    }
                }
                methods[idx] = target;
                guards[idx] = chooseGuard(caller, target, staticCallee, state, false);
                idx++;
            }
            InlineDecision d = guardedYES(methods, guards, "Inline multiple targets");
            reportGuardedDecisionIfVerbose(d, verbose);
            return d;
        }
    }
}
Also used : OptCompiledMethod(org.jikesrvm.compilers.opt.runtimesupport.OptCompiledMethod) ArrayList(java.util.ArrayList) OptOptions(org.jikesrvm.compilers.opt.OptOptions) OptCompiledMethod(org.jikesrvm.compilers.opt.runtimesupport.OptCompiledMethod) CompiledMethod(org.jikesrvm.compilers.common.CompiledMethod) RVMClass(org.jikesrvm.classloader.RVMClass) RVMMethod(org.jikesrvm.classloader.RVMMethod) WeightedCallTargets(org.jikesrvm.adaptive.database.callgraph.WeightedCallTargets) NormalMethod(org.jikesrvm.classloader.NormalMethod) Iterator(java.util.Iterator)

Example 30 with RVMClass

use of org.jikesrvm.classloader.RVMClass in project JikesRVM by JikesRVM.

the class Reflection method outOfLineInvoke.

private static Object outOfLineInvoke(RVMMethod method, Object thisArg, Object[] otherArgs, boolean isNonvirtual) {
    // the class must be initialized before we can invoke a method
    // 
    RVMClass klass = method.getDeclaringClass();
    if (!klass.isInitialized()) {
        RuntimeEntrypoints.initializeClassForDynamicLink(klass);
    }
    // remember return type
    // Determine primitive type-ness early to avoid call (possible yield)
    // later while refs are possibly being held in int arrays.
    // 
    TypeReference returnType = method.getReturnType();
    boolean returnIsPrimitive = returnType.isPrimitiveType();
    // decide how to pass parameters
    // 
    int triple = 0;
    if (VM.BuildForIA32) {
        triple = org.jikesrvm.ia32.MachineReflection.countParameters(method);
    } else {
        if (VM.VerifyAssertions)
            VM._assert(VM.BuildForPowerPC);
        triple = org.jikesrvm.ppc.MachineReflection.countParameters(method);
    }
    int gprs = triple & REFLECTION_GPRS_MASK;
    WordArray GPRs = (gprs > 0) ? WordArray.create(gprs) : emptyWordArray;
    int fprs = (triple >> REFLECTION_GPRS_BITS) & 0x1F;
    double[] FPRs = (fprs > 0) ? new double[fprs] : emptyDoubleArray;
    byte[] FPRmeta;
    if (BuildForSSE2Full) {
        FPRmeta = (fprs > 0) ? new byte[fprs] : emptyByteArray;
    } else {
        FPRmeta = null;
    }
    int spillCount = triple >> (REFLECTION_GPRS_BITS + REFLECTION_FPRS_BITS);
    WordArray Spills = (spillCount > 0) ? WordArray.create(spillCount) : emptyWordArray;
    if (firstUse) {
        // force dynamic link sites in unwrappers to get resolved,
        // before disabling gc.
        // this is a bit silly, but I can't think of another way to do it [--DL]
        unwrapBoolean(wrapBoolean(0));
        unwrapByte(wrapByte((byte) 0));
        unwrapChar(wrapChar((char) 0));
        unwrapShort(wrapShort((short) 0));
        unwrapInt(wrapInt(0));
        unwrapLong(wrapLong(0));
        unwrapFloat(wrapFloat(0));
        unwrapDouble(wrapDouble(0));
        firstUse = false;
    }
    // choose actual method to be called
    // 
    RVMMethod targetMethod;
    if (isNonvirtual || method.isStatic() || method.isObjectInitializer()) {
        targetMethod = method;
    } else {
        RVMClass C = Magic.getObjectType(thisArg).asClass();
        if (!method.getDeclaringClass().isInterface()) {
            int tibIndex = method.getOffset().toInt() >>> LOG_BYTES_IN_ADDRESS;
            targetMethod = C.getVirtualMethods()[tibIndex - TIB_FIRST_VIRTUAL_METHOD_INDEX];
        } else {
            RVMClass I = method.getDeclaringClass();
            if (!RuntimeEntrypoints.isAssignableWith(I, C))
                throw new IncompatibleClassChangeError();
            targetMethod = C.findVirtualMethod(method.getName(), method.getDescriptor());
            if (targetMethod == null)
                throw new IncompatibleClassChangeError();
        }
    }
    // getCurrentCompiledMethod is synchronized but Unpreemptible.
    // Therefore there are no possible yieldpoints from the time
    // the compiledMethod is loaded in getCurrentCompiledMethod
    // to when we disable GC below.
    // We can't allow any yieldpoints between these points because of the way in which
    // we GC compiled code.  Once a method is marked as obsolete, if it is not
    // executing on the stack of some thread, then the process of collecting the
    // code and meta-data might be initiated.
    targetMethod.compile();
    CompiledMethod cm = targetMethod.getCurrentCompiledMethod();
    while (cm == null) {
        targetMethod.compile();
        cm = targetMethod.getCurrentCompiledMethod();
    }
    RVMThread.getCurrentThread().disableYieldpoints();
    CodeArray code = cm.getEntryCodeArray();
    if (VM.BuildForIA32) {
        org.jikesrvm.ia32.MachineReflection.packageParameters(method, thisArg, otherArgs, GPRs, FPRs, FPRmeta, Spills);
    } else {
        if (VM.VerifyAssertions)
            VM._assert(VM.BuildForPowerPC);
        org.jikesrvm.ppc.MachineReflection.packageParameters(method, thisArg, otherArgs, GPRs, FPRs, FPRmeta, Spills);
    }
    // critical: no yieldpoints/GCpoints between here and the invoke of code!
    // We may have references hidden in the GPRs and Spills arrays!!!
    RVMThread.getCurrentThread().enableYieldpoints();
    if (!returnIsPrimitive) {
        return Magic.invokeMethodReturningObject(code, GPRs, FPRs, FPRmeta, Spills);
    }
    if (returnType.isVoidType()) {
        Magic.invokeMethodReturningVoid(code, GPRs, FPRs, FPRmeta, Spills);
        return null;
    }
    if (returnType.isBooleanType()) {
        int x = Magic.invokeMethodReturningInt(code, GPRs, FPRs, FPRmeta, Spills);
        return x == 1;
    }
    if (returnType.isByteType()) {
        int x = Magic.invokeMethodReturningInt(code, GPRs, FPRs, FPRmeta, Spills);
        return (byte) x;
    }
    if (returnType.isShortType()) {
        int x = Magic.invokeMethodReturningInt(code, GPRs, FPRs, FPRmeta, Spills);
        return (short) x;
    }
    if (returnType.isCharType()) {
        int x = Magic.invokeMethodReturningInt(code, GPRs, FPRs, FPRmeta, Spills);
        return (char) x;
    }
    if (returnType.isIntType()) {
        return Magic.invokeMethodReturningInt(code, GPRs, FPRs, FPRmeta, Spills);
    }
    if (returnType.isLongType()) {
        return Magic.invokeMethodReturningLong(code, GPRs, FPRs, FPRmeta, Spills);
    }
    if (returnType.isFloatType()) {
        return Magic.invokeMethodReturningFloat(code, GPRs, FPRs, FPRmeta, Spills);
    }
    if (returnType.isDoubleType()) {
        return Magic.invokeMethodReturningDouble(code, GPRs, FPRs, FPRmeta, Spills);
    }
    if (VM.VerifyAssertions)
        VM._assert(NOT_REACHED);
    return null;
}
Also used : RVMMethod(org.jikesrvm.classloader.RVMMethod) CodeArray(org.jikesrvm.compilers.common.CodeArray) WordArray(org.vmmagic.unboxed.WordArray) TypeReference(org.jikesrvm.classloader.TypeReference) CompiledMethod(org.jikesrvm.compilers.common.CompiledMethod) RVMClass(org.jikesrvm.classloader.RVMClass)

Aggregations

RVMClass (org.jikesrvm.classloader.RVMClass)69 RVMMethod (org.jikesrvm.classloader.RVMMethod)28 TypeReference (org.jikesrvm.classloader.TypeReference)22 RVMType (org.jikesrvm.classloader.RVMType)20 Atom (org.jikesrvm.classloader.Atom)14 RVMField (org.jikesrvm.classloader.RVMField)11 RVMArray (org.jikesrvm.classloader.RVMArray)8 Instruction (org.jikesrvm.compilers.opt.ir.Instruction)8 IntConstantOperand (org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand)8 MethodOperand (org.jikesrvm.compilers.opt.ir.operand.MethodOperand)8 Operand (org.jikesrvm.compilers.opt.ir.operand.Operand)8 RegisterOperand (org.jikesrvm.compilers.opt.ir.operand.RegisterOperand)8 BranchProfileOperand (org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand)7 ConditionOperand (org.jikesrvm.compilers.opt.ir.operand.ConditionOperand)7 LocationOperand (org.jikesrvm.compilers.opt.ir.operand.LocationOperand)7 Address (org.vmmagic.unboxed.Address)7 NormalMethod (org.jikesrvm.classloader.NormalMethod)6 CompiledMethod (org.jikesrvm.compilers.common.CompiledMethod)6 TrapCodeOperand (org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand)6 BasicBlock (org.jikesrvm.compilers.opt.ir.BasicBlock)5