Search in sources :

Example 1 with InvokeSite

use of com.jopdesign.common.code.InvokeSite in project jop by jop-devel.

the class InlineHelper method checkCode.

/**
     * check the code of the invoked method if it contains instructions which prevent inlining.
     *
     * @param invoker the method into which the invokee will be inlined.
     * @param invokee the invoked method.
     * @return true if the code can be inlined and {@link #prepareInlining(MethodInfo, MethodInfo)} will succeed.
     */
private boolean checkCode(MethodInfo invoker, MethodInfo invokee) {
    MethodCode code = invokee.getCode();
    // Go through code, check for access to fields and invocations
    for (InstructionHandle ih : code.getInstructionList(true, false).getInstructionHandles()) {
        Instruction instr = ih.getInstruction();
        if (instr instanceof InvokeInstruction) {
            InvokeSite invokeSite = code.getInvokeSite(ih);
            MethodRef ref = invokeSite.getInvokeeRef();
            MethodInfo method = ref.getMethodInfo();
            if (method == null) {
                // TODO perform basic check on classnames if invoked method must already be public?
                return false;
            }
            // invokespecial is somewhat, well, special..
            if (invokeSite.isInvokeSpecial()) {
                if (checkInvokeSpecial(invoker, invokee, invokeSite, ref.getClassInfo(), method) == CheckResult.SKIP) {
                    return false;
                }
            } else {
                // check if fields need to be set to public
                if (checkNeedsPublic(invoker, invokee, ref.getClassInfo(), method) == CheckResult.SKIP) {
                    return false;
                }
            }
        } else if (instr instanceof FieldInstruction) {
            FieldRef ref = code.getFieldRef(ih);
            FieldInfo field = ref.getFieldInfo();
            if (field == null) {
                // TODO perform basic check on classnames if field is already public?
                return false;
            }
            // check if fields need to be set to public
            if (checkNeedsPublic(invoker, invokee, ref.getClassInfo(), field) == CheckResult.SKIP) {
                return false;
            }
        }
    }
    return true;
}
Also used : InvokeInstruction(org.apache.bcel.generic.InvokeInstruction) MethodRef(com.jopdesign.common.type.MethodRef) FieldRef(com.jopdesign.common.type.FieldRef) MethodInfo(com.jopdesign.common.MethodInfo) InvokeSite(com.jopdesign.common.code.InvokeSite) FieldInstruction(org.apache.bcel.generic.FieldInstruction) MethodCode(com.jopdesign.common.MethodCode) InvokeInstruction(org.apache.bcel.generic.InvokeInstruction) ConstantPushInstruction(org.apache.bcel.generic.ConstantPushInstruction) Instruction(org.apache.bcel.generic.Instruction) FieldInstruction(org.apache.bcel.generic.FieldInstruction) LocalVariableInstruction(org.apache.bcel.generic.LocalVariableInstruction) InstructionHandle(org.apache.bcel.generic.InstructionHandle) FieldInfo(com.jopdesign.common.FieldInfo)

Example 2 with InvokeSite

use of com.jopdesign.common.code.InvokeSite in project jop by jop-devel.

the class InlineHelper method prepareInlining.

/**
     * Prepare the invokee for inlining into the invokesite, by widening access restrictions or renaming
     * methods to prevent incorrect method resolving.
     * <p>
     * This may change the code of the invokee, so this needs to be done before inlining the code.
     * The CFG of the invokee will be removed.
     * </p><p>
     * This code assumes that {@link #canInline(CallString, InvokeSite, MethodInfo)} returned true for this invoke.
     * </p>
     *
     * @param invoker the method where the code will be inlined to.
     * @param invokee the method to inline.
     */
public void prepareInlining(MethodInfo invoker, MethodInfo invokee) {
    MethodCode code = invokee.getCode();
    InstructionList il = code.getInstructionList();
    for (InstructionHandle ih : il.getInstructionHandles()) {
        Instruction instr = ih.getInstruction();
        if (instr instanceof InvokeInstruction) {
            InvokeSite invokeSite = code.getInvokeSite(ih);
            MethodRef ref = invokeSite.getInvokeeRef();
            MethodInfo method = ref.getMethodInfo();
            // we already checked that everything can be resolved
            // nothing special to do for invokespecial here (checkInvokeSpecial only skips, no special return codes)
            // check what we need to do
            CheckResult rs = checkNeedsPublic(invoker, invokee, ref.getClassInfo(), method);
            if (rs == CheckResult.NEEDS_PUBLIC) {
                makePublic(method);
            }
            if (rs == CheckResult.NEEDS_PUBLIC_RENAME) {
                if (method.isPrivate()) {
                // TODO check the class for invokers, change to invokevirtual
                } else {
                // if the method is package visible, we need to rename all overriding methods
                // too (but not methods from subclasses in different packages which do not override this)
                // TODO update overriding methods
                // TODO need to update all possible call sites
                }
                makePublic(method);
                throw new AppInfoError("Implement me!");
            }
        } else if (instr instanceof FieldInstruction) {
            FieldRef ref = code.getFieldRef(ih);
            FieldInfo field = ref.getFieldInfo();
            // we already checked that everything can be resolved
            // check if fields need to be set to public
            CheckResult rs = checkNeedsPublic(invoker, invokee, ref.getClassInfo(), field);
            if (rs == CheckResult.NEEDS_PUBLIC) {
                makePublic(field);
            }
            if (rs == CheckResult.NEEDS_PUBLIC_RENAME) {
                throw new AppInfoError("Invalid returncode: renaming of fields not required");
            }
        }
    }
}
Also used : FieldRef(com.jopdesign.common.type.FieldRef) InstructionList(org.apache.bcel.generic.InstructionList) InvokeInstruction(org.apache.bcel.generic.InvokeInstruction) ConstantPushInstruction(org.apache.bcel.generic.ConstantPushInstruction) Instruction(org.apache.bcel.generic.Instruction) FieldInstruction(org.apache.bcel.generic.FieldInstruction) LocalVariableInstruction(org.apache.bcel.generic.LocalVariableInstruction) InstructionHandle(org.apache.bcel.generic.InstructionHandle) AppInfoError(com.jopdesign.common.misc.AppInfoError) InvokeInstruction(org.apache.bcel.generic.InvokeInstruction) MethodRef(com.jopdesign.common.type.MethodRef) MethodInfo(com.jopdesign.common.MethodInfo) InvokeSite(com.jopdesign.common.code.InvokeSite) FieldInstruction(org.apache.bcel.generic.FieldInstruction) MethodCode(com.jopdesign.common.MethodCode) FieldInfo(com.jopdesign.common.FieldInfo)

Example 3 with InvokeSite

use of com.jopdesign.common.code.InvokeSite in project jop by jop-devel.

the class InlineHelper method needsNullpointerCheck.

/**
     * Check if an exception must be generated if the 'this' reference is null.
     * This test can return false if
     * <ul><li>There is no 'this' reference</li>
     * <li>The DFA analysis showed that the reference is never null</li>
     * <li>The inlined code will always generate an exception anyway</li>
     * <li>Generating checks has been disabled by configuration</li>
     * </ul>
     * <p>
     * The callstring does not need to start or to end at the method to optimize. However since the callstring is
     * used to check the DFA results if available, the callstring must match what the DFA expects, i.e. if
     * the DFA-results and -callstrings are updated during inlining, this callstring must not include inlined
     * invokes. Contrariwise if the DFA results are not updated during inline, the callstring must contain already
     * inlined invokes.
     * </p>
     *
     * @param callString The callstring including the invokesite of the invokee. The top invokesite does not need to
     *                   refer to an invoke instruction, and the referenced invoker method does not need to
     *                   be the method containing the invoke to inline (e.g. if the invoke to inline has
     *                   been inlined itself). However the callstring needs to match what the DFA expects.
     * @param invokee the devirtualized invokee.
     * @param analyzeCode if false, skip checking the code of the invokee.
     * @return true if a nullpointer check code should be generated.
     */
public boolean needsNullpointerCheck(CallString callString, MethodInfo invokee, boolean analyzeCode) {
    if (inlineConfig.skipNullpointerChecks())
        return false;
    InvokeSite invokeSite = callString.top();
    // check if we have a 'this' reference anyway
    if (invokeSite.isInvokeStatic() || invokeSite.isJVMCall()) {
        return false;
    }
    // TODO check the DFA results if available
    if (jcopter.useDFA()) {
    } else if ("<init>".equals(invokee.getShortName())) {
        // the NP check in this case (and hope that compilers for languages other than Java do the same..)
        return false;
    }
    if (!analyzeCode) {
        return true;
    }
    // check if the code will always throw an exception anyway (without producing any side effects before throwing)
    ValueMapAnalysis analysis = new ValueMapAnalysis(invokee);
    analysis.loadParameters();
    InstructionList list = invokee.getCode().getInstructionList(true, false);
    for (InstructionHandle ih : list.getInstructionHandles()) {
        Instruction instr = ih.getInstruction();
        if (instr instanceof ConstantPushInstruction || instr instanceof LocalVariableInstruction) {
            analysis.transfer(instr);
        } else if (instr instanceof GETFIELD || instr instanceof PUTFIELD || instr instanceof INVOKEVIRTUAL || instr instanceof INVOKEINTERFACE || instr instanceof INVOKESPECIAL) {
            int down = instr.consumeStack(invokee.getConstantPoolGen());
            ValueInfo value = analysis.getValueTable().top(down);
            // the same way as the inlined invoke
            if (value.isThisReference()) {
                return false;
            }
            break;
        } else {
            // we ignore all other instructions (for now..)
            break;
        }
    }
    return true;
}
Also used : ValueMapAnalysis(com.jopdesign.jcopter.analysis.ValueMapAnalysis) InstructionList(org.apache.bcel.generic.InstructionList) PUTFIELD(org.apache.bcel.generic.PUTFIELD) InvokeInstruction(org.apache.bcel.generic.InvokeInstruction) ConstantPushInstruction(org.apache.bcel.generic.ConstantPushInstruction) Instruction(org.apache.bcel.generic.Instruction) FieldInstruction(org.apache.bcel.generic.FieldInstruction) LocalVariableInstruction(org.apache.bcel.generic.LocalVariableInstruction) INVOKESPECIAL(org.apache.bcel.generic.INVOKESPECIAL) InstructionHandle(org.apache.bcel.generic.InstructionHandle) GETFIELD(org.apache.bcel.generic.GETFIELD) INVOKEINTERFACE(org.apache.bcel.generic.INVOKEINTERFACE) ValueInfo(com.jopdesign.common.type.ValueInfo) LocalVariableInstruction(org.apache.bcel.generic.LocalVariableInstruction) InvokeSite(com.jopdesign.common.code.InvokeSite) ConstantPushInstruction(org.apache.bcel.generic.ConstantPushInstruction) INVOKEVIRTUAL(org.apache.bcel.generic.INVOKEVIRTUAL)

Example 4 with InvokeSite

use of com.jopdesign.common.code.InvokeSite in project jop by jop-devel.

the class SimpleInliner method optimizeMethod.

@Override
public void optimizeMethod(MethodInfo method) {
    InlineData inlineData = new InlineData();
    List<InvokeSite> invokes = new ArrayList<InvokeSite>(method.getCode().getInvokeSites());
    // we iterate over the invoke sites in a sorted order for the single reason that the DFA cache hack works
    // (else the order of the entries in the constantpool can differ)
    Collections.sort(invokes, new Comparator<InvokeSite>() {

        @Override
        public int compare(InvokeSite o1, InvokeSite o2) {
            return o1.getInstructionHandle().getPosition() - o2.getInstructionHandle().getPosition();
        }
    });
    for (InvokeSite invoke : invokes) {
        // The callstring contains 'original' invokesites from the unmodified callgraph,
        // 'invoke' refers to the new invokesite in the modified code
        CallString cs = new CallString(invoke);
        while (invoke != null) {
            countInvokeSites++;
            MethodInfo invokee = helper.devirtualize(cs);
            if (invokee == null)
                break;
            countDevirtualized++;
            // Preliminary checks
            if (checkInvoke(invoke, cs, invokee, inlineData)) {
                invoke = performSimpleInline(invoke, invokee, inlineData);
                inlineCounter++;
                if (inlineData.getInvokeSite() != null) {
                    cs.push(inlineData.getInvokeSite());
                } else {
                    break;
                }
            } else {
                break;
            }
        }
    }
// update callgraph (?) If we update the callgraph, the callstrings become invalid!
// -> update callgraph only after we finished inlining of a toplevel invokesite;
//    collect all invokesites to collapse into toplevel invokesite;
//    replace old invokesite with invokesites from inlined code, add edges to not inlined methods
// We could collect all nodes to merge and call callgraph.merge(), but this is not yet implemented.
// Instead we simply rebuild the whole callgraph and all results which use callstrings.
}
Also used : ArrayList(java.util.ArrayList) MethodInfo(com.jopdesign.common.MethodInfo) InvokeSite(com.jopdesign.common.code.InvokeSite) CallString(com.jopdesign.common.code.CallString)

Example 5 with InvokeSite

use of com.jopdesign.common.code.InvokeSite in project jop by jop-devel.

the class ExecFrequencyProvider method getExecCount.

public long getExecCount(ExecutionContext context) {
    CallString cs = context.getCallString();
    if (cs.isEmpty()) {
        return getExecCount(context.getMethodInfo());
    }
    // if we have a callstring, we need to start at the beginning of the callstring, then multiply the
    // frequencies up to the invoked method along the callstring
    long count = getExecCount(cs.first().getInvoker());
    for (int i = 0; i < cs.length(); i++) {
        InvokeSite is = cs.get(i);
        MethodInfo invokee = i + 1 < cs.length() ? cs.get(i + 1).getInvoker() : context.getMethodInfo();
        count *= getExecFrequency(is, invokee);
    }
    return count;
}
Also used : MethodInfo(com.jopdesign.common.MethodInfo) InvokeSite(com.jopdesign.common.code.InvokeSite) CallString(com.jopdesign.common.code.CallString)

Aggregations

InvokeSite (com.jopdesign.common.code.InvokeSite)13 MethodInfo (com.jopdesign.common.MethodInfo)7 InstructionHandle (org.apache.bcel.generic.InstructionHandle)6 FieldInstruction (org.apache.bcel.generic.FieldInstruction)4 Instruction (org.apache.bcel.generic.Instruction)4 InvokeInstruction (org.apache.bcel.generic.InvokeInstruction)4 FieldInfo (com.jopdesign.common.FieldInfo)3 MethodCode (com.jopdesign.common.MethodCode)3 CallString (com.jopdesign.common.code.CallString)3 LinkedHashSet (java.util.LinkedHashSet)3 ConstantPushInstruction (org.apache.bcel.generic.ConstantPushInstruction)3 InstructionList (org.apache.bcel.generic.InstructionList)3 LocalVariableInstruction (org.apache.bcel.generic.LocalVariableInstruction)3 ExecutionContext (com.jopdesign.common.code.ExecutionContext)2 AppInfoError (com.jopdesign.common.misc.AppInfoError)2 FieldRef (com.jopdesign.common.type.FieldRef)2 MethodRef (com.jopdesign.common.type.MethodRef)2 ValueInfo (com.jopdesign.common.type.ValueInfo)2 ValueMapAnalysis (com.jopdesign.jcopter.analysis.ValueMapAnalysis)2 ArrayList (java.util.ArrayList)2