Search in sources :

Example 86 with MethodInfo

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

the class MethodCacheAnalysis method findClassificationChanges.

private Set<MethodInfo> findClassificationChanges(MethodInfo method, final int deltaBlocks, Collection<MethodInfo> removed, final boolean update) {
    if (analysisType == AnalysisType.ALWAYS_HIT || analysisType == AnalysisType.ALWAYS_MISS || (deltaBlocks == 0 && removed.isEmpty())) {
        return Collections.emptySet();
    }
    Set<ExecutionContext> roots = callGraph.getNodes(method);
    // First, go up and find all nodes where one or more methods need to be removed from the reachable methods set
    final Map<ExecutionContext, Set<MethodInfo>> removeMethods = findRemovedMethods(roots, removed);
    // next, calculate blocks of removed methods
    final Map<MethodInfo, Integer> blocks = new LinkedHashMap<MethodInfo, Integer>(removed.size());
    for (MethodInfo m : removed) {
        int size = MiscUtils.bytesToWords(getMethodSize(m));
        blocks.put(m, cache.requiredNumberOfBlocks(size));
    }
    // finally, go up all invokers, sum up reachable method set changes and deltaBlocks per node, check all-fit
    final Set<MethodInfo> changeSet = new LinkedHashSet<MethodInfo>();
    DFSVisitor<ExecutionContext, ContextEdge> visitor = new EmptyDFSVisitor<ExecutionContext, ContextEdge>() {

        @Override
        public void preorder(ExecutionContext node) {
            Set<MethodInfo> remove = removeMethods.get(node);
            int oldBlocks = cacheBlocks.get(node);
            int newBlocks = oldBlocks;
            if (remove != null) {
                if (update) {
                    reachableMethods.get(node).removeAll(remove);
                }
                for (MethodInfo r : remove) {
                    newBlocks -= blocks.get(r);
                }
            }
            newBlocks += deltaBlocks;
            if (update) {
                cacheBlocks.put(node, newBlocks);
            }
            boolean oldFit = cache.allFit(oldBlocks);
            boolean newFit = cache.allFit(newBlocks);
            if (oldFit != newFit) {
                changeSet.add(node.getMethodInfo());
                if (update) {
                    classifyChanges.add(node.getMethodInfo());
                }
            }
        }
    };
    DFSTraverser<ExecutionContext, ContextEdge> traverser = new DFSTraverser<ExecutionContext, ContextEdge>(visitor);
    traverser.traverse(callGraph.getReversedGraph(), roots);
    return changeSet;
}
Also used : LinkedHashSet(java.util.LinkedHashSet) LinkedHashSet(java.util.LinkedHashSet) Set(java.util.Set) EmptyDFSVisitor(com.jopdesign.common.graphutils.DFSTraverser.EmptyDFSVisitor) ContextEdge(com.jopdesign.common.code.CallGraph.ContextEdge) LinkedHashMap(java.util.LinkedHashMap) DFSTraverser(com.jopdesign.common.graphutils.DFSTraverser) ExecutionContext(com.jopdesign.common.code.ExecutionContext) MethodInfo(com.jopdesign.common.MethodInfo)

Example 87 with MethodInfo

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

the class MethodCacheAnalysis method getAllFitChangeCosts.

private long getAllFitChangeCosts(ExecFrequencyProvider ecp, CodeModification modification, int deltaBlocks) {
    if (analysisType == AnalysisType.ALWAYS_HIT || analysisType == AnalysisType.ALWAYS_MISS) {
        return 0;
    }
    int deltaBytes = modification.getDeltaLocalCodesize();
    MethodInfo method = modification.getMethod();
    // for ALWAYS_MISS_HIT oder MOST_ONCE we need to find out what has changed for all-fit
    Set<MethodInfo> changes = findClassificationChanges(method, deltaBlocks, modification.getRemovedInvokees(), false);
    AppInfo appInfo = AppInfo.getSingleton();
    // In all nodes where we have changes, we need to sum up the new costs
    long deltaCosts = 0;
    for (MethodInfo node : changes) {
        // but all invokes in the method are now no longer always-hit/-miss
        for (InvokeSite invokeSite : node.getCode().getInvokeSites()) {
            // Note: this is very similar to getInvokeReturnCacheCosts(invokeSite), but we cannot use
            // this here, because that method uses allFit and does not honor our 'virtual' codesize change
            int size = 0;
            for (MethodInfo impl : appInfo.findImplementations(invokeSite)) {
                size = Math.max(size, getMethodSize(impl));
            }
            size = MiscUtils.bytesToWords(size);
            int sizeInvoker = getMethodSize(invokeSite.getInvoker());
            sizeInvoker = MiscUtils.bytesToWords(sizeInvoker);
            long invokeCosts = cache.getMissPenaltyOnInvoke(size, invokeSite.getInvokeInstruction());
            long returnCosts = cache.getMissPenaltyOnReturn(sizeInvoker, invokeSite.getInvokeeRef().getDescriptor().getType());
            long count = ecp.getExecCount(invokeSite);
            if (analysisType == AnalysisType.ALL_FIT_REGIONS) {
                // for this analysis we already have one miss in the original cost estimation
                count--;
            }
            deltaCosts += count * (invokeCosts + returnCosts);
        }
    }
    // if the code increased, the classification changed from always-hit to always-miss ..
    long costs = deltaBytes > 0 ? deltaCosts : -deltaCosts;
    if (analysisType == AnalysisType.ALL_FIT_REGIONS) {
        // find out how many additional persistent cache misses we have
        // find out border of new all-fit region
        Map<MethodInfo, Integer> deltaExec = new LinkedHashMap<MethodInfo, Integer>();
        int deltaCount = 0;
        Set<ExecutionContext> border = new LinkedHashSet<ExecutionContext>();
        if (deltaBlocks < 0) {
            throw new AppInfoError("Not implemented");
        } else {
            for (MethodInfo miss : changes) {
                for (ExecutionContext context : callGraph.getNodes(miss)) {
                    for (ExecutionContext invokee : callGraph.getChildren(context)) {
                        // not all-fit if in changeset
                        if (changes.contains(invokee.getMethodInfo()))
                            continue;
                        // we ignore native stuff
                        if (invokee.getMethodInfo().isNative())
                            continue;
                        // invokee is all-fit
                        if (border.add(invokee)) {
                            deltaCount += ecp.getExecCount(invokee);
                        }
                    }
                }
            }
            // remove old miss count
            deltaCount -= getPersistentMisses(ecp, border);
        }
        // TODO this is not quite correct: instead of joining the reachable sets and multiplying
        // with the delta count for the whole region, we should:
        // - for every node in the reachable sets of the new border, sum up exec-counts of border nodes
        // which contain that node in the reachable set
        // - for every node in the reachable sets of the old border, subtract the exec counts of those border nodes
        // - sum up invoke miss costs times calculates delta counts per node
        // find out cache miss costs of new all-fit region
        int regionCosts = 0;
        Set<MethodInfo> visited = new LinkedHashSet<MethodInfo>();
        for (ExecutionContext context : border) {
            for (MethodInfo reachable : reachableMethods.get(context)) {
                if (visited.add(reachable)) {
                    regionCosts += cache.getMissPenalty(reachable.getCode().getNumberOfWords(), cache.isLRU());
                }
            }
        }
        costs += deltaCount * regionCosts;
    }
    return costs;
}
Also used : LinkedHashSet(java.util.LinkedHashSet) AppInfoError(com.jopdesign.common.misc.AppInfoError) AppInfo(com.jopdesign.common.AppInfo) LinkedHashMap(java.util.LinkedHashMap) ExecutionContext(com.jopdesign.common.code.ExecutionContext) MethodInfo(com.jopdesign.common.MethodInfo) InvokeSite(com.jopdesign.common.code.InvokeSite)

Example 88 with MethodInfo

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

the class MethodCacheAnalysis method getDeltaCacheMissCosts.

/**
 * @param ecp execution counts to use
 * @param modification the modifications which will be done
 * @return the number of cache miss cycles due to the code size change, excluding the effects on the modified code
 */
public long getDeltaCacheMissCosts(ExecFrequencyProvider ecp, CodeModification modification) {
    if (analysisType == AnalysisType.ALWAYS_HIT)
        return 0;
    int deltaBytes = modification.getDeltaLocalCodesize();
    if (deltaBytes == 0)
        return 0;
    MethodInfo method = modification.getMethod();
    int size = getMethodSize(method);
    int oldWords = MiscUtils.bytesToWords(size);
    int newWords = MiscUtils.bytesToWords(size + deltaBytes);
    int deltaBlocks = cache.requiredNumberOfBlocks(newWords) - cache.requiredNumberOfBlocks(oldWords);
    // int newBlocks = getRequiredBlocks(method) + deltaBlocks;
    // calc various cache miss cost deltas
    long deltaInvokeCacheMissCosts = cache.getMissPenalty(newWords, true) - cache.getMissPenalty(oldWords, true);
    long deltaReturnCacheMissCosts = cache.getMissPenalty(newWords, false) - cache.getMissPenalty(oldWords, false);
    long costs = 0;
    // we have cache costs due to invokes of the modified method
    costs += getInvokeMissCount(ecp, modification.getMethod()) * deltaInvokeCacheMissCosts;
    // .. and due to returns from invokees to the modified method
    costs += getReturnMissCount(ecp, modification) * deltaReturnCacheMissCosts;
    // .. and because other methods may not fit into the cache anymore
    costs += getAllFitChangeCosts(ecp, modification, deltaBlocks);
    return costs;
}
Also used : MethodInfo(com.jopdesign.common.MethodInfo)

Example 89 with MethodInfo

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

the class SimpleInliner method analyzeInvokeSite.

/**
 * Check if the invokesite can be modified in a way so that the parameters are passed in the correct order
 * @param invokeSite the invokesite to inline.
 * @param invokee the invoked method.
 * @param inlineData the map to store the analyzer results
 * @return true if the prologue can be changed to match the expected behaviour
 */
private boolean analyzeInvokeSite(InvokeSite invokeSite, MethodInfo invokee, InlineData inlineData) {
    MethodInfo invoker = invokeSite.getInvoker();
    ConstantPoolGen invokerCpg = invoker.getConstantPoolGen();
    InstructionHandle invoke = invokeSite.getInstructionHandle();
    // Check epilogue
    Type[] ret = StackHelper.produceStack(invokerCpg, invoke.getInstruction());
    // works if the invoked method returns the same (single) type as the replaced instruction..
    boolean match = (ret.length == 1 && TypeHelper.canAssign(invokee.getType(), ret[0]));
    // return something but doesn't then it is a JVM call and throws an exception.
    if (!match && !invokee.getType().equals(Type.VOID)) {
        return false;
    }
    // Check and build prologue
    Type[] args = StackHelper.consumeStack(invokerCpg, invoke.getInstruction());
    List<Instruction> oldPrologue = new LinkedList<Instruction>();
    int cnt = 0;
    InstructionHandle current = invoke;
    while (cnt < args.length) {
        if (current.hasTargeters()) {
            // stay within the basic block
            break;
        }
        current = current.getPrev();
        Instruction instr = current.getInstruction();
        // we only rearrange push-instructions
        if (!(instr instanceof PushInstruction) || (instr instanceof DUP) || (instr instanceof DUP2)) {
            break;
        }
        // we add this instruction to the old prologue to replace
        cnt++;
        oldPrologue.add(0, instr);
    }
    inlineData.setOldPrologueLength(cnt);
    List<ValueInfo> params = inlineData.getParams();
    // other parameters must be used in the order they are pushed on the stack, we do not rearrange them
    int offset = args.length - cnt;
    for (int i = 0; i < offset; i++) {
        if (i >= params.size()) {
            Type t = args[i];
            // unused argument, we cannot remove the push instruction so we pop it
            inlineData.addPrologue(t.getSize() == 2 ? new POP2() : new POP());
        } else {
            ValueInfo value = params.get(i);
            int argNum = value.getParamNr();
            if (!invokee.isStatic()) {
                argNum++;
            }
            if (argNum != i) {
                return false;
            }
        }
    }
    // Now, we create a new prologue using the expected argument values and the old push instructions
    for (int i = offset; i < params.size(); i++) {
        ValueInfo value = params.get(i);
        if (value.isThisReference() || value.isParamReference()) {
            int argNum = value.getParamNr();
            if (!invokee.isStatic()) {
                argNum++;
            }
            if (argNum < offset) {
                // loading a param a second time which we do not duplicate, cannot inline this
                return false;
            }
            // To be on the safe side, copy the instruction in case a param is used more than once
            Instruction instr = oldPrologue.get(argNum - offset).copy();
            inlineData.addPrologue(instr);
        } else if (value.isNullReference()) {
            inlineData.addPrologue(InstructionConstants.ACONST_NULL);
        } else if (value.isConstantValue() || value.isStaticFieldReference()) {
            // We need to push a constant on the stack
            Instruction instr = value.getConstantValue().createPushInstruction(invoker.getConstantPoolGen());
            inlineData.addPrologue(instr);
        } else if (!value.isContinued()) {
            throw new AssertionError("Unhandled value type");
        }
    }
    return true;
}
Also used : POP2(org.apache.bcel.generic.POP2) InvokeInstruction(org.apache.bcel.generic.InvokeInstruction) StackInstruction(org.apache.bcel.generic.StackInstruction) Instruction(org.apache.bcel.generic.Instruction) FieldInstruction(org.apache.bcel.generic.FieldInstruction) ArithmeticInstruction(org.apache.bcel.generic.ArithmeticInstruction) ConversionInstruction(org.apache.bcel.generic.ConversionInstruction) ReturnInstruction(org.apache.bcel.generic.ReturnInstruction) PushInstruction(org.apache.bcel.generic.PushInstruction) PushInstruction(org.apache.bcel.generic.PushInstruction) InstructionHandle(org.apache.bcel.generic.InstructionHandle) LinkedList(java.util.LinkedList) POP(org.apache.bcel.generic.POP) ConstantPoolGen(org.apache.bcel.generic.ConstantPoolGen) Type(org.apache.bcel.generic.Type) DUP2(org.apache.bcel.generic.DUP2) ValueInfo(com.jopdesign.common.type.ValueInfo) MethodInfo(com.jopdesign.common.MethodInfo) DUP(org.apache.bcel.generic.DUP)

Example 90 with MethodInfo

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

the class RelinkInvokesuper method relinkInvokeSuper.

private void relinkInvokeSuper(InvokeSite is) {
    // this already resolves to the correct method..
    MethodRef invokee = is.getInvokeeRef();
    MethodInfo target = invokee.getMethodInfo();
    if (target == null) {
        // .. or not (class or method excluded or unknown)
        logger.warn("Cannot try to relink invokespecial to unknown super method " + invokee);
        return;
    }
    // now simply relink instruction (no need to check if it changes)
    int index = is.getInvoker().getClassInfo().addConstantInfo(new ConstantMethodInfo(invokee));
    if (!(is.getInvokeInstruction() instanceof INVOKESPECIAL)) {
        throw new JavaClassFormatError("Invokesuper is not an invokespecial instruction!");
    }
    is.getInvokeInstruction().setIndex(index);
}
Also used : ConstantMethodInfo(com.jopdesign.common.type.ConstantMethodInfo) MethodRef(com.jopdesign.common.type.MethodRef) JavaClassFormatError(com.jopdesign.common.misc.JavaClassFormatError) MethodInfo(com.jopdesign.common.MethodInfo) ConstantMethodInfo(com.jopdesign.common.type.ConstantMethodInfo) INVOKESPECIAL(org.apache.bcel.generic.INVOKESPECIAL)

Aggregations

MethodInfo (com.jopdesign.common.MethodInfo)108 LinkedHashSet (java.util.LinkedHashSet)21 InstructionHandle (org.apache.bcel.generic.InstructionHandle)20 ClassInfo (com.jopdesign.common.ClassInfo)19 ExecutionContext (com.jopdesign.common.code.ExecutionContext)16 CFGNode (com.jopdesign.common.code.ControlFlowGraph.CFGNode)13 ArrayList (java.util.ArrayList)13 CallString (com.jopdesign.common.code.CallString)12 ControlFlowGraph (com.jopdesign.common.code.ControlFlowGraph)12 HashMap (java.util.HashMap)10 Set (java.util.Set)10 LinkedHashMap (java.util.LinkedHashMap)9 Instruction (org.apache.bcel.generic.Instruction)9 FieldInfo (com.jopdesign.common.FieldInfo)8 MethodCode (com.jopdesign.common.MethodCode)8 AppInfo (com.jopdesign.common.AppInfo)7 ContextEdge (com.jopdesign.common.code.CallGraph.ContextEdge)7 InvokeSite (com.jopdesign.common.code.InvokeSite)7 MemberID (com.jopdesign.common.type.MemberID)7 Context (com.jopdesign.dfa.framework.Context)7