use of org.jikesrvm.compilers.opt.ir.operand.MethodOperand 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.compilers.opt.ir.operand.MethodOperand in project JikesRVM by JikesRVM.
the class SimpleEscape method checkEscapesThread.
/**
* Checks a single use, to see if this use may cause the object
* referenced to escape from this thread.
*
* @param use the use to check
* @param ir the governing IR
* @param visited visited registers
* @return {@code true} if it may escape, {@code false} otherwise
*/
private static boolean checkEscapesThread(RegisterOperand use, IR ir, Set<Register> visited) {
Instruction inst = use.instruction;
switch(inst.getOpcode()) {
case INT_ASTORE_opcode:
case LONG_ASTORE_opcode:
case FLOAT_ASTORE_opcode:
case DOUBLE_ASTORE_opcode:
case BYTE_ASTORE_opcode:
case SHORT_ASTORE_opcode:
case REF_ASTORE_opcode:
// as long as we don't store this operand elsewhere, all
// is OK
Operand value = AStore.getValue(inst);
return value == use;
case GETFIELD_opcode:
case GETSTATIC_opcode:
case INT_ALOAD_opcode:
case LONG_ALOAD_opcode:
case FLOAT_ALOAD_opcode:
case DOUBLE_ALOAD_opcode:
case BYTE_ALOAD_opcode:
case UBYTE_ALOAD_opcode:
case BYTE_LOAD_opcode:
case UBYTE_LOAD_opcode:
case SHORT_ALOAD_opcode:
case USHORT_ALOAD_opcode:
case SHORT_LOAD_opcode:
case USHORT_LOAD_opcode:
case REF_ALOAD_opcode:
case INT_LOAD_opcode:
case LONG_LOAD_opcode:
case FLOAT_LOAD_opcode:
case DOUBLE_LOAD_opcode:
case REF_LOAD_opcode:
// all is OK, unless we load this register from memory
Operand result = ResultCarrier.getResult(inst);
return result == use;
case PUTFIELD_opcode:
// as long as we don't store this operand elsewhere, all
// is OK. TODO: add more smarts.
value = PutField.getValue(inst);
return value == use;
case PUTSTATIC_opcode:
// as long as we don't store this operand elsewhere, all
// is OK. TODO: add more smarts.
value = PutStatic.getValue(inst);
return value == use;
case BYTE_STORE_opcode:
case SHORT_STORE_opcode:
case REF_STORE_opcode:
case INT_STORE_opcode:
case LONG_STORE_opcode:
case FLOAT_STORE_opcode:
case DOUBLE_STORE_opcode:
// as long as we don't store this operand elsewhere, all
// is OK. TODO: add more smarts.
value = Store.getValue(inst);
return value == use;
// escape
case BOUNDS_CHECK_opcode:
case MONITORENTER_opcode:
case MONITOREXIT_opcode:
case NULL_CHECK_opcode:
case ARRAYLENGTH_opcode:
case REF_IFCMP_opcode:
case INT_IFCMP_opcode:
case IG_PATCH_POINT_opcode:
case IG_CLASS_TEST_opcode:
case IG_METHOD_TEST_opcode:
case BOOLEAN_CMP_INT_opcode:
case BOOLEAN_CMP_ADDR_opcode:
case OBJARRAY_STORE_CHECK_opcode:
case OBJARRAY_STORE_CHECK_NOTNULL_opcode:
case GET_OBJ_TIB_opcode:
case GET_TYPE_FROM_TIB_opcode:
case NEW_opcode:
case NEWARRAY_opcode:
case NEWOBJMULTIARRAY_opcode:
case NEW_UNRESOLVED_opcode:
case NEWARRAY_UNRESOLVED_opcode:
case INSTANCEOF_opcode:
case INSTANCEOF_NOTNULL_opcode:
case INSTANCEOF_UNRESOLVED_opcode:
case MUST_IMPLEMENT_INTERFACE_opcode:
case GET_CAUGHT_EXCEPTION_opcode:
case IR_PROLOGUE_opcode:
return false;
case RETURN_opcode:
// by caller)
return !ir.isParameter(use);
case CALL_opcode:
MethodOperand mop = Call.getMethod(inst);
if (mop == null) {
return true;
}
if (!mop.hasPreciseTarget()) {
// if we're not sure of the dynamic target, give up
return true;
}
// pure methods don't let object escape
if (mop.getTarget().isPure()) {
return false;
}
// Assume non-annotated native methods let object escape
if (mop.getTarget().isNative()) {
return true;
}
// try to get a method summary for the called method
MethodSummary summ = getMethodSummaryIfAvailable(mop.getTarget(), ir.options);
if (summ == null) {
// couldn't get one. assume the object escapes
return true;
}
// if use is result of the call...
if (use == Call.getResult(inst)) {
return summ.resultMayEscapeThread();
}
// use is a parameter to the call. Find out which one.
int p = getParameterIndex(use, inst);
return summ.parameterMayEscapeThread(p);
case CHECKCAST_opcode:
case CHECKCAST_NOTNULL_opcode:
case CHECKCAST_UNRESOLVED_opcode:
case REF_MOVE_opcode:
{
Register copy = ResultCarrier.getResult(inst).getRegister();
if (!copy.isSSA()) {
return true;
} else {
if (visited == null) {
visited = new HashSet<Register>();
}
visited.add(use.getRegister());
if (visited.contains(copy)) {
return false;
} else {
return checkIfUseEscapesThread(copy, ir, visited);
}
}
}
case ATHROW_opcode:
case PREPARE_INT_opcode:
case PREPARE_ADDR_opcode:
case PREPARE_LONG_opcode:
case ATTEMPT_LONG_opcode:
case ATTEMPT_INT_opcode:
case ATTEMPT_ADDR_opcode:
case INT_MOVE_opcode:
case INT_ADD_opcode:
case REF_ADD_opcode:
case INT_MUL_opcode:
case INT_DIV_opcode:
case INT_REM_opcode:
case INT_NEG_opcode:
case INT_ZERO_CHECK_opcode:
case INT_OR_opcode:
case INT_AND_opcode:
case INT_XOR_opcode:
case REF_OR_opcode:
case REF_AND_opcode:
case REF_XOR_opcode:
case INT_SUB_opcode:
case REF_SUB_opcode:
case INT_SHL_opcode:
case INT_SHR_opcode:
case INT_USHR_opcode:
case SYSCALL_opcode:
case REF_SHL_opcode:
case REF_SHR_opcode:
case REF_USHR_opcode:
case SET_CAUGHT_EXCEPTION_opcode:
case PHI_opcode:
case INT_2LONG_opcode:
case REF_COND_MOVE_opcode:
case INT_COND_MOVE_opcode:
case INT_2ADDRSigExt_opcode:
case INT_2ADDRZerExt_opcode:
case ADDR_2INT_opcode:
case ADDR_2LONG_opcode:
case LONG_OR_opcode:
case LONG_AND_opcode:
case LONG_XOR_opcode:
case LONG_SUB_opcode:
case LONG_SHL_opcode:
case LONG_ADD_opcode:
case LONG_SHR_opcode:
case LONG_USHR_opcode:
case LONG_NEG_opcode:
case LONG_MOVE_opcode:
case LONG_2ADDR_opcode:
// TODO: add more smarts
case YIELDPOINT_OSR_opcode:
// we do not know exactly, so be conservative
return true;
default:
if (VM.BuildForPowerPC) {
switch(inst.getOpcode()) {
case DCBST_opcode:
case DCBT_opcode:
case DCBTST_opcode:
case DCBZ_opcode:
case DCBZL_opcode:
case ICBI_opcode:
return false;
}
} else {
switch(inst.getOpcode()) {
case PREFETCH_opcode:
return false;
}
}
throw new OptimizingCompilerException("SimpleEscapge: Unexpected " + inst);
}
}
use of org.jikesrvm.compilers.opt.ir.operand.MethodOperand in project JikesRVM by JikesRVM.
the class Instruction method isNonPureCall.
/**
* Is the instruction a call but not a pure call (one kind of interprocedural branch)?
*
* @return <code>true</code> if the instruction is a nonpure call
* or <code>false</code> if it is not.
*/
public boolean isNonPureCall() {
if (operator.isCall()) {
MethodOperand methOp = Call.getMethod(this);
boolean isPure = methOp != null && methOp.hasPreciseTarget() && methOp.getTarget().isPure();
return !isPure;
}
return false;
}
use of org.jikesrvm.compilers.opt.ir.operand.MethodOperand in project JikesRVM by JikesRVM.
the class BURS_Helpers method mutateTrapToCall.
private void mutateTrapToCall(Instruction s, RVMMethod target) {
Offset offset = target.getOffset();
RegisterOperand tmp = regpool.makeTemp(TypeReference.JavaLangObjectArray);
Register JTOC = regpool.getPhysicalRegisterSet().asPPC().getJTOC();
MethodOperand meth = MethodOperand.STATIC(target);
meth.setIsNonReturningCall(true);
int valueLow = PPCMaskLower16(offset);
if (fits(offset, 16)) {
EMIT(MIR_Load.create(PPC_LAddr, tmp, A(JTOC), IC(valueLow)));
} else {
int valueHigh = PPCMaskUpper16(offset);
if (VM.VerifyAssertions)
VM._assert(fits(offset, 32));
Register reg = regpool.getAddress();
EMIT(MIR_Binary.create(PPC_ADDIS, A(reg), A(JTOC), IC(valueHigh)));
EMIT(MIR_Load.create(PPC_LAddr, tmp, A(reg), IC(valueLow)));
}
EMIT(MIR_Move.create(PPC_MTSPR, A(CTR), tmp.copyD2U()));
EMIT(MIR_Call.mutate0(s, PPC_BCTRL, null, null, meth));
}
use of org.jikesrvm.compilers.opt.ir.operand.MethodOperand in project JikesRVM by JikesRVM.
the class GenerationContextTest method childContextsQueryOSRBarrierInformationViaOutermostParent.
@Test
public void childContextsQueryOSRBarrierInformationViaOutermostParent() throws Exception {
NormalMethod nm = getNormalMethodForTest("methodForInliningTests");
CompiledMethod cm = new OptCompiledMethod(-1, nm);
OptOptions opts = new OptOptions();
InlineOracle io = new DefaultInlineOracle();
GenerationContext outermost = new GenerationContext(nm, null, cm, opts, io);
Class<?>[] classArgs = { Object.class };
NormalMethod callee = getNormalMethodForTest("emptyStaticMethodWithObjectParamAndReturnValue", classArgs);
MethodOperand methOp = MethodOperand.STATIC(callee);
RegisterOperand result = createMockRegisterOperand(TypeReference.JavaLangObject);
Instruction callInstr = Call.create(CALL, result, null, methOp, 1);
RegisterOperand objectParam = createMockRegisterOperand(TypeReference.JavaLangObject);
Call.setParam(callInstr, 0, objectParam);
callInstr.setPosition(new InlineSequence(nm));
ExceptionHandlerBasicBlockBag ebag = getMockEbag();
GenerationContext child = outermost.createChildContext(ebag, callee, callInstr);
Instruction osrBarrier = createMockOSRBarrier();
Instruction call = createMockCall();
child.saveOSRBarrierForInst(osrBarrier, call);
assertThat(outermost.getOSRBarrierFromInst(call), is(osrBarrier));
assertThat(child.getOSRBarrierFromInst(call), is(osrBarrier));
GenerationContext child2 = outermost.createChildContext(ebag, callee, callInstr);
assertThat(child2.getOSRBarrierFromInst(call), is(osrBarrier));
}
Aggregations