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><parent,ebag></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;
}
}
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;
}
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;
}
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();
}
}
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.");
}
}
});
}
}
Aggregations