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;
}
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;
}
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;
}
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;
}
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);
}
Aggregations