Search in sources :

Example 21 with RVMMethod

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

the class Inliner method execute.

/**
 * Return a generation context that represents the
 * execution of inlDec in the context <code>&lt;parent,ebag&gt;</code> for
 * the call instruction callSite.
 * <p> PRECONDITION: inlDec.isYes()
 * <p> POSTCONDITIONS:
 * Let gc be the returned generation context.
 * <ul>
 *  <li> gc.cfg.firstInCodeOrder is the entry to the inlined context
 *  <li>gc.cfg.lastInCodeOrder is the exit from the inlined context
 *  <li> GenerationContext.transferState(parent, child) has been called.
 * </ul>
 *
 * @param inlDec the inlining decision to execute
 * @param parent the caller generation context
 * @param ebag exception handler scope for the caller
 * @param callSite the callsite to execute
 * @return a generation context that represents the execution of the
 *         inline decision in the given context
 */
public static GenerationContext execute(InlineDecision inlDec, GenerationContext parent, ExceptionHandlerBasicBlockBag ebag, Instruction callSite) {
    if (inlDec.needsGuard()) {
        // Step 1: create the synthetic generation context we'll
        // return to our caller.
        GenerationContext container = GenerationContext.createSynthetic(parent, ebag);
        container.getCfg().breakCodeOrder(container.getPrologue(), container.getEpilogue());
        // Step 2: (a) Print a message (optional)
        // (b) Generate the child GC for each target
        RVMMethod[] targets = inlDec.getTargets();
        byte[] guards = inlDec.getGuards();
        GenerationContext[] children = new GenerationContext[targets.length];
        for (int i = 0; i < targets.length; i++) {
            NormalMethod callee = (NormalMethod) targets[i];
            // (a)
            if (parent.getOptions().PRINT_INLINE_REPORT) {
                String guard = guards[i] == OptOptions.INLINE_GUARD_CLASS_TEST ? " (class test) " : " (method test) ";
                VM.sysWriteln("\tGuarded inline" + guard + " " + callee + " into " + callSite.position().getMethod() + " at bytecode " + callSite.getBytecodeIndex());
            }
            // (b)
            children[i] = parent.createChildContext(ebag, callee, callSite);
            BC2IR.generateHIR(children[i]);
            children[i].transferStateToParent();
        }
        // special purpose coding wrapping the calls to Operand.meet.
        if (Call.hasResult(callSite)) {
            Register reg = Call.getResult(callSite).getRegister();
            container.setResult(children[0].getResult());
            for (int i = 1; i < targets.length; i++) {
                if (children[i].getResult() != null) {
                    container.setResult((container.getResult() == null) ? children[i].getResult() : Operand.meet(container.getResult(), children[i].getResult(), reg));
                }
            }
            if (!inlDec.OSRTestFailed()) {
                // Account for the non-predicted case as well...
                RegisterOperand failureCaseResult = Call.getResult(callSite).copyRO();
                container.setResult((container.getResult() == null) ? failureCaseResult : Operand.meet(container.getResult(), failureCaseResult, reg));
            }
        }
        // Step 4: Create a block to contain a copy of the original call or an OSR_Yieldpoint
        // to cover the case that all predictions fail.
        BasicBlock testFailed = new BasicBlock(callSite.getBytecodeIndex(), callSite.position(), parent.getCfg());
        testFailed.setExceptionHandlers(ebag);
        if (COUNT_FAILED_GUARDS && Controller.options.INSERT_DEBUGGING_COUNTERS) {
            // Get a dynamic count of how many times guards fail at runtime.
            // Need a name for the event to count.  In this example, a
            // separate counter for each method by using the method name
            // as the event name.  You could also have used just the string
            // "Guarded inline failed" to keep only one counter.
            String eventName = "Guarded inline failed: " + callSite.position().getMethod().toString();
            // Create instruction that will increment the counter
            // corresponding to the named event.
            Instruction counterInst = AOSDatabase.debuggingCounterData.getCounterInstructionForEvent(eventName);
            testFailed.appendInstruction(counterInst);
        }
        if (inlDec.OSRTestFailed()) {
            // note where we're storing the osr barrier instruction
            Instruction lastOsrBarrier = parent.getOSRBarrierFromInst(callSite);
            Instruction s = BC2IR._osrHelper(lastOsrBarrier, parent);
            s.copyPosition(callSite);
            testFailed.appendInstruction(s);
            testFailed.insertOut(parent.getExit());
        } else {
            Instruction call = callSite.copyWithoutLinks();
            Call.getMethod(call).setIsGuardedInlineOffBranch(true);
            call.copyPosition(callSite);
            testFailed.appendInstruction(call);
            testFailed.insertOut(container.getEpilogue());
            // BC2IR.maybeInlineMethod).
            if (ebag != null) {
                for (Enumeration<BasicBlock> e = ebag.enumerator(); e.hasMoreElements(); ) {
                    BasicBlock handler = e.nextElement();
                    testFailed.insertOut(handler);
                }
            }
            testFailed.setCanThrowExceptions();
            testFailed.setMayThrowUncaughtException();
        }
        container.getCfg().linkInCodeOrder(testFailed, container.getEpilogue());
        testFailed.setInfrequent();
        // Step 5: Patch together all the callees by generating guard blocks
        BasicBlock firstIfBlock = testFailed;
        // Note: We know that receiver must be a register
        // operand (and not a string constant) because we are doing a
        // guarded inlining....if it was a string constant we'd have
        // been able to inline without a guard.
        Operand receiver = Call.getParam(callSite, 0);
        MethodOperand mo = Call.getMethod(callSite);
        boolean isInterface = mo.isInterface();
        if (isInterface) {
            if (VM.BuildForIMTInterfaceInvocation) {
                RVMType interfaceType = mo.getTarget().getDeclaringClass();
                TypeReference recTypeRef = receiver.getType();
                RVMClass recType = (RVMClass) recTypeRef.peekType();
                // Attempt to avoid inserting the check by seeing if the
                // known static type of the receiver implements the interface.
                boolean requiresImplementsTest = true;
                if (recType != null && recType.isResolved() && !recType.isInterface()) {
                    byte doesImplement = ClassLoaderProxy.includesType(interfaceType.getTypeRef(), recTypeRef);
                    requiresImplementsTest = doesImplement != YES;
                }
                if (requiresImplementsTest) {
                    RegisterOperand checkedReceiver = parent.getTemps().makeTemp(receiver);
                    Instruction dtc = TypeCheck.create(MUST_IMPLEMENT_INTERFACE, checkedReceiver, receiver.copy(), new TypeOperand(interfaceType), Call.getGuard(callSite).copy());
                    dtc.copyPosition(callSite);
                    checkedReceiver.refine(interfaceType.getTypeRef());
                    Call.setParam(callSite, 0, checkedReceiver.copyRO());
                    testFailed.prependInstruction(dtc);
                }
            }
        }
        // "logical" test and to share test insertion for interfaces/virtuals.
        for (int i = children.length - 1; i >= 0; i--, testFailed = firstIfBlock) {
            firstIfBlock = new BasicBlock(callSite.getBytecodeIndex(), callSite.position(), parent.getCfg());
            firstIfBlock.setExceptionHandlers(ebag);
            BasicBlock lastIfBlock = firstIfBlock;
            RVMMethod target = children[i].getMethod();
            Instruction tmp;
            if (isInterface) {
                RVMClass callDeclClass = mo.getTarget().getDeclaringClass();
                if (!callDeclClass.isInterface()) {
                    // the entire compilation.
                    throw new OptimizingCompilerException("Attempted guarded inline of invoke interface when decl class of target method may not be an interface");
                }
                // We potentially have to generate IR to perform two tests here:
                // (1) Does the receiver object implement callDeclClass?
                // (2) Given that it does, is target the method that would
                // be invoked for this receiver?
                // It is quite common to be able to answer (1) "YES" at compile
                // time, in which case we only have to generate IR to establish
                // (2) at runtime.
                byte doesImplement = ClassLoaderProxy.includesType(callDeclClass.getTypeRef(), target.getDeclaringClass().getTypeRef());
                if (doesImplement != YES) {
                    // implements the interface).
                    if (parent.getOptions().PRINT_INLINE_REPORT) {
                        VM.sysWriteln("\t\tRequired additional instanceof " + callDeclClass + " test");
                    }
                    firstIfBlock = new BasicBlock(callSite.getBytecodeIndex(), callSite.position(), parent.getCfg());
                    firstIfBlock.setExceptionHandlers(ebag);
                    RegisterOperand instanceOfResult = parent.getTemps().makeTempInt();
                    tmp = InstanceOf.create(INSTANCEOF_NOTNULL, instanceOfResult, new TypeOperand(callDeclClass), receiver.copy(), Call.getGuard(callSite));
                    tmp.copyPosition(callSite);
                    firstIfBlock.appendInstruction(tmp);
                    tmp = IfCmp.create(INT_IFCMP, parent.getTemps().makeTempValidation(), instanceOfResult.copyD2U(), new IntConstantOperand(0), ConditionOperand.EQUAL(), testFailed.makeJumpTarget(), BranchProfileOperand.unlikely());
                    tmp.copyPosition(callSite);
                    firstIfBlock.appendInstruction(tmp);
                    firstIfBlock.insertOut(testFailed);
                    firstIfBlock.insertOut(lastIfBlock);
                    container.getCfg().linkInCodeOrder(firstIfBlock, lastIfBlock);
                }
            }
            if (guards[i] == OptOptions.INLINE_GUARD_CLASS_TEST) {
                tmp = InlineGuard.create(IG_CLASS_TEST, receiver.copy(), Call.getGuard(callSite).copy(), new TypeOperand(target.getDeclaringClass()), testFailed.makeJumpTarget(), BranchProfileOperand.unlikely());
            } else if (guards[i] == OptOptions.INLINE_GUARD_METHOD_TEST) {
                // declaring class.
                if (isInterface) {
                    RegisterOperand t = parent.getTemps().makeTempInt();
                    Instruction test = InstanceOf.create(INSTANCEOF_NOTNULL, t, new TypeOperand(target.getDeclaringClass().getTypeRef()), receiver.copy());
                    test.copyPosition(callSite);
                    lastIfBlock.appendInstruction(test);
                    Instruction cmp = IfCmp.create(INT_IFCMP, parent.getTemps().makeTempValidation(), t.copyD2U(), new IntConstantOperand(0), ConditionOperand.EQUAL(), testFailed.makeJumpTarget(), BranchProfileOperand.unlikely());
                    cmp.copyPosition(callSite);
                    lastIfBlock.appendInstruction(cmp);
                    BasicBlock subclassTest = new BasicBlock(callSite.getBytecodeIndex(), callSite.position(), parent.getCfg());
                    lastIfBlock.insertOut(testFailed);
                    lastIfBlock.insertOut(subclassTest);
                    container.getCfg().linkInCodeOrder(lastIfBlock, subclassTest);
                    lastIfBlock = subclassTest;
                }
                tmp = InlineGuard.create(IG_METHOD_TEST, receiver.copy(), Call.getGuard(callSite).copy(), MethodOperand.VIRTUAL(target.getMemberRef().asMethodReference(), target), testFailed.makeJumpTarget(), BranchProfileOperand.unlikely());
            } else {
                tmp = InlineGuard.create(IG_PATCH_POINT, receiver.copy(), Call.getGuard(callSite).copy(), MethodOperand.VIRTUAL(target.getMemberRef().asMethodReference(), target), testFailed.makeJumpTarget(), inlDec.OSRTestFailed() ? BranchProfileOperand.never() : BranchProfileOperand.unlikely());
            }
            tmp.copyPosition(callSite);
            lastIfBlock.appendInstruction(tmp);
            lastIfBlock.insertOut(testFailed);
            lastIfBlock.insertOut(children[i].getPrologue());
            container.getCfg().linkInCodeOrder(lastIfBlock, children[i].getCfg().firstInCodeOrder());
            if (children[i].getEpilogue() != null) {
                children[i].getEpilogue().appendInstruction(container.getEpilogue().makeGOTO());
                children[i].getEpilogue().insertOut(container.getEpilogue());
            }
            container.getCfg().linkInCodeOrder(children[i].getCfg().lastInCodeOrder(), testFailed);
        }
        // Step 6: finish by linking container.prologue & testFailed
        container.getPrologue().insertOut(testFailed);
        container.getCfg().linkInCodeOrder(container.getPrologue(), testFailed);
        return container;
    } else {
        if (VM.VerifyAssertions)
            VM._assert(inlDec.getNumberOfTargets() == 1);
        NormalMethod callee = (NormalMethod) inlDec.getTargets()[0];
        if (parent.getOptions().PRINT_INLINE_REPORT) {
            VM.sysWriteln("\tInline " + callee + " into " + callSite.position().getMethod() + " at bytecode " + callSite.getBytecodeIndex());
        }
        GenerationContext child = parent.createChildContext(ebag, callee, callSite);
        BC2IR.generateHIR(child);
        child.transferStateToParent();
        return child;
    }
}
Also used : GenerationContext(org.jikesrvm.compilers.opt.bc2ir.GenerationContext) IntConstantOperand(org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand) BranchProfileOperand(org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand) MethodOperand(org.jikesrvm.compilers.opt.ir.operand.MethodOperand) TypeOperand(org.jikesrvm.compilers.opt.ir.operand.TypeOperand) RegisterOperand(org.jikesrvm.compilers.opt.ir.operand.RegisterOperand) ConditionOperand(org.jikesrvm.compilers.opt.ir.operand.ConditionOperand) Operand(org.jikesrvm.compilers.opt.ir.operand.Operand) IntConstantOperand(org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand) RVMType(org.jikesrvm.classloader.RVMType) ExceptionHandlerBasicBlock(org.jikesrvm.compilers.opt.ir.ExceptionHandlerBasicBlock) BasicBlock(org.jikesrvm.compilers.opt.ir.BasicBlock) Instruction(org.jikesrvm.compilers.opt.ir.Instruction) MethodOperand(org.jikesrvm.compilers.opt.ir.operand.MethodOperand) RVMClass(org.jikesrvm.classloader.RVMClass) RVMMethod(org.jikesrvm.classloader.RVMMethod) RegisterOperand(org.jikesrvm.compilers.opt.ir.operand.RegisterOperand) Register(org.jikesrvm.compilers.opt.ir.Register) NormalMethod(org.jikesrvm.classloader.NormalMethod) TypeOperand(org.jikesrvm.compilers.opt.ir.operand.TypeOperand) TypeReference(org.jikesrvm.classloader.TypeReference) OptimizingCompilerException(org.jikesrvm.compilers.opt.OptimizingCompilerException)

Example 22 with RVMMethod

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

the class InterfaceHierarchy method getUniqueImplementation.

/**
 * If, in the current class hierarchy, there is exactly one method that
 * defines the interface method foo, then return the unique
 * implementation.  If there is not a unique implementation, return
 * null.
 *
 * @param foo an interface method
 * @return the unique implementation if it exists, {@code null} otherwise
 */
public static synchronized RVMMethod getUniqueImplementation(RVMMethod foo) {
    RVMClass I = foo.getDeclaringClass();
    ImmutableEntryHashSetRVM<RVMClass> classes = allImplementors(I);
    RVMMethod firstMethod = null;
    Atom name = foo.getName();
    Atom desc = foo.getDescriptor();
    for (RVMClass klass : classes) {
        RVMMethod m = klass.findDeclaredMethod(name, desc);
        if (firstMethod == null) {
            firstMethod = m;
        }
        if (m != firstMethod) {
            return null;
        }
    }
    return firstMethod;
}
Also used : RVMMethod(org.jikesrvm.classloader.RVMMethod) Atom(org.jikesrvm.classloader.Atom) RVMClass(org.jikesrvm.classloader.RVMClass)

Example 23 with RVMMethod

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

the class SimpleEscape method simpleEscapeAnalysis.

/**
 * Performs the escape analysis for a method.
 *
 * <p> Side effect: updates method summary database to hold
 *                escape analysis result for parameters
 *
 * @param ir IR for the target method
 * @return an object holding the result of the analysis
 */
public FI_EscapeSummary simpleEscapeAnalysis(IR ir) {
    final boolean DEBUG = false;
    if (DEBUG) {
        VM.sysWriteln("ENTER Simple Escape Analysis " + ir.method);
    }
    if (DEBUG) {
        ir.printInstructions();
    }
    // create a method summary object for this method
    RVMMethod m = ir.method;
    MethodSummary summ = SummaryDatabase.findOrCreateMethodSummary(m);
    summ.setInProgress(true);
    FI_EscapeSummary result = new FI_EscapeSummary();
    // set up register lists, SSA flags
    DefUse.computeDU(ir);
    DefUse.recomputeSSA(ir);
    // pass through registers, and mark escape information
    for (Register reg = ir.regpool.getFirstSymbolicRegister(); reg != null; reg = reg.getNext()) {
        // skip the following types of registers:
        if (reg.isFloatingPoint()) {
            continue;
        }
        if (reg.isInteger()) {
            continue;
        }
        if (reg.isLong()) {
            continue;
        }
        if (reg.isCondition()) {
            continue;
        }
        if (reg.isValidation()) {
            continue;
        }
        if (reg.isPhysical()) {
            continue;
        }
        if (!reg.isSSA()) {
            continue;
        }
        AnalysisResult escapes = checkAllAppearances(reg, ir);
        if (escapes.threadLocal) {
            result.setThreadLocal(reg, true);
        }
        if (escapes.methodLocal) {
            result.setMethodLocal(reg, true);
        }
    }
    // update the method summary database to note whether
    // parameters may escape
    int numParam = 0;
    for (Enumeration<Operand> e = ir.getParameters(); e.hasMoreElements(); numParam++) {
        Register p = ((RegisterOperand) e.nextElement()).getRegister();
        if (result.isThreadLocal(p)) {
            summ.setParameterMayEscapeThread(numParam, false);
        } else {
            summ.setParameterMayEscapeThread(numParam, true);
        }
    }
    // update the method summary to note whether the return value
    // may escape
    boolean foundEscapingReturn = false;
    for (Iterator<Operand> itr = iterateReturnValues(ir); itr.hasNext(); ) {
        Operand op = itr.next();
        if (op == null) {
            continue;
        }
        if (op.isRegister()) {
            Register r = op.asRegister().getRegister();
            if (!result.isThreadLocal(r)) {
                foundEscapingReturn = true;
            }
        }
    }
    if (!foundEscapingReturn) {
        summ.setResultMayEscapeThread(false);
    }
    // record that we're done with analysis
    summ.setInProgress(false);
    if (DEBUG) {
        VM.sysWriteln("LEAVE Simple Escape Analysis " + ir.method);
    }
    return result;
}
Also used : RVMMethod(org.jikesrvm.classloader.RVMMethod) RegisterOperand(org.jikesrvm.compilers.opt.ir.operand.RegisterOperand) Register(org.jikesrvm.compilers.opt.ir.Register) MethodOperand(org.jikesrvm.compilers.opt.ir.operand.MethodOperand) RegisterOperand(org.jikesrvm.compilers.opt.ir.operand.RegisterOperand) Operand(org.jikesrvm.compilers.opt.ir.operand.Operand)

Example 24 with RVMMethod

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

the class PartialCallGraph method report.

/**
 * Dump out set of edges in sorted order.
 */
@Override
public synchronized void report() {
    System.out.println("Partial Call Graph");
    System.out.println("  Number of callsites " + callGraph.size() + ", total weight: " + totalEdgeWeights);
    System.out.println();
    TreeSet<CallSite> tmp = new TreeSet<CallSite>(new OrderByTotalWeight());
    tmp.addAll(callGraph.keySet());
    for (final CallSite cs : tmp) {
        WeightedCallTargets ct = callGraph.get(cs);
        ct.visitTargets(new WeightedCallTargets.Visitor() {

            @Override
            public void visit(RVMMethod callee, double weight) {
                System.out.println(weight + " <" + cs.getMethod() + ", " + cs.getBytecodeIndex() + ", " + callee + ">");
            }
        });
        System.out.println();
    }
}
Also used : RVMMethod(org.jikesrvm.classloader.RVMMethod) UnResolvedWeightedCallTargets(org.jikesrvm.adaptive.util.UnResolvedWeightedCallTargets) TreeSet(java.util.TreeSet) UnResolvedCallSite(org.jikesrvm.adaptive.util.UnResolvedCallSite)

Example 25 with RVMMethod

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

the class PartialCallGraph method dumpGraph.

/**
 * Dump all profile data to the given file
 * @param fn output file name
 */
public synchronized void dumpGraph(String fn) {
    final BufferedWriter f;
    try {
        f = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fn), "ISO-8859-1"));
    } catch (IOException e) {
        VM.sysWriteln();
        VM.sysWriteln();
        VM.sysWrite("PartialCallGraph.dumpGraph: Error opening output file!!");
        VM.sysWriteln();
        VM.sysWriteln();
        return;
    }
    TreeSet<CallSite> tmp = new TreeSet<CallSite>(new OrderByTotalWeight());
    tmp.addAll(callGraph.keySet());
    for (final CallSite cs : tmp) {
        WeightedCallTargets ct = callGraph.get(cs);
        ct.visitTargets(new WeightedCallTargets.Visitor() {

            @Override
            public void visit(RVMMethod callee, double weight) {
                CodeArray callerArray = cs.getMethod().getCurrentEntryCodeArray();
                CodeArray calleeArray = callee.getCurrentEntryCodeArray();
                try {
                    f.write("CallSite " + cs.getMethod().getMemberRef() + " " + callerArray.length() + " " + +cs.getBytecodeIndex() + " " + callee.getMemberRef() + " " + +calleeArray.length() + " weight: " + weight + "\n");
                    f.flush();
                } catch (IOException exc) {
                    System.err.println("I/O error writing to dynamic call graph profile.");
                }
            }
        });
    }
}
Also used : UnResolvedCallSite(org.jikesrvm.adaptive.util.UnResolvedCallSite) IOException(java.io.IOException) BufferedWriter(java.io.BufferedWriter) RVMMethod(org.jikesrvm.classloader.RVMMethod) CodeArray(org.jikesrvm.compilers.common.CodeArray) UnResolvedWeightedCallTargets(org.jikesrvm.adaptive.util.UnResolvedWeightedCallTargets) TreeSet(java.util.TreeSet) FileOutputStream(java.io.FileOutputStream) OutputStreamWriter(java.io.OutputStreamWriter)

Aggregations

RVMMethod (org.jikesrvm.classloader.RVMMethod)86 RVMClass (org.jikesrvm.classloader.RVMClass)29 TypeReference (org.jikesrvm.classloader.TypeReference)17 RVMType (org.jikesrvm.classloader.RVMType)15 CompiledMethod (org.jikesrvm.compilers.common.CompiledMethod)14 MethodOperand (org.jikesrvm.compilers.opt.ir.operand.MethodOperand)13 Atom (org.jikesrvm.classloader.Atom)11 RegisterOperand (org.jikesrvm.compilers.opt.ir.operand.RegisterOperand)11 Offset (org.vmmagic.unboxed.Offset)11 Instruction (org.jikesrvm.compilers.opt.ir.Instruction)10 Operand (org.jikesrvm.compilers.opt.ir.operand.Operand)10 Address (org.vmmagic.unboxed.Address)9 MethodReference (org.jikesrvm.classloader.MethodReference)8 NormalMethod (org.jikesrvm.classloader.NormalMethod)8 BranchProfileOperand (org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand)8 IntConstantOperand (org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand)8 Method (java.lang.reflect.Method)7 ConditionOperand (org.jikesrvm.compilers.opt.ir.operand.ConditionOperand)7 TrapCodeOperand (org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand)7 OptCompiledMethod (org.jikesrvm.compilers.opt.runtimesupport.OptCompiledMethod)7