use of org.jikesrvm.compilers.opt.inlining.InlineSequence in project JikesRVM by JikesRVM.
the class GenerationContextTest method constructorCreatesOperandsForStaticMethodWithParameters.
@Test
public void constructorCreatesOperandsForStaticMethodWithParameters() throws Exception {
Class<?>[] argumentTypes = { long.class, int.class, Object.class, double.class };
NormalMethod nm = getNormalMethodForTest("emptyStaticMethodWithParams", argumentTypes);
CompiledMethod cm = new OptCompiledMethod(-1, nm);
OptOptions opts = new OptOptions();
InlineOracle io = new DefaultInlineOracle();
GenerationContext gc = new GenerationContext(nm, null, cm, opts, io);
InlineSequence inlineSequence = new InlineSequence(nm);
assertThatInlineSequenceWasSetCorrectly(gc, inlineSequence);
assertThatNumberOfParametersIs(gc, 4);
RegisterOperand longRegOp = getThisOperand(gc);
assertThat(longRegOp.isLong(), is(true));
assertThatRegOpHasDeclaredType(longRegOp);
RegisterOperand intRegOp = gc.getArguments()[1].asRegister();
assertThat(intRegOp.isInt(), is(true));
assertThatRegOpHasDeclaredType(intRegOp);
RegisterOperand objectRegOp = gc.getArguments()[2].asRegister();
assertThatRegOpHoldsClassType(objectRegOp);
assertThatRegOpHasDeclaredType(objectRegOp);
RegisterOperand doubleRegOp = gc.getArguments()[3].asRegister();
assertThat(doubleRegOp.isDouble(), is(true));
assertThatRegOpHasDeclaredType(doubleRegOp);
Register longReg = gc.localReg(0, TypeReference.Long);
assertThatRegOpIsLocalRegOfRegister(longRegOp, longReg);
Register intReg = gc.localReg(2, TypeReference.Int);
assertThatRegOpIsLocalRegOfRegister(intRegOp, intReg);
Register objectReg = gc.localReg(3, TypeReference.JavaLangObject);
assertThatRegOpIsLocalRegOfRegister(objectRegOp, objectReg);
Register doubleReg = gc.localReg(4, TypeReference.Double);
assertThatRegOpIsLocalRegOfRegister(doubleRegOp, doubleReg);
BasicBlock prologue = gc.getPrologue();
assertThatPrologueBlockIsSetupCorrectly(gc, inlineSequence, prologue);
assertThatFirstInstructionInPrologueIsPrologue(inlineSequence, prologue);
assertThatBlockOnlyHasOneRealInstruction(prologue);
assertThatPrologueOperandIsRegOpFromLocalNr(prologue, longRegOp, 0);
assertThatPrologueOperandIsRegOpFromLocalNr(prologue, intRegOp, 1);
assertThatPrologueOperandIsRegOpFromLocalNr(prologue, objectRegOp, 2);
assertThatPrologueOperandIsRegOpFromLocalNr(prologue, doubleRegOp, 3);
assertThatEpilogueIsForVoidReturnMethod(gc, inlineSequence);
assertThatExitBlockIsSetCorrectly(gc);
assertThatDataIsSavedCorrectly(nm, cm, io, gc);
assertThatReturnValueIsVoid(gc);
assertThatGCHasNoExceptionHandlers(gc);
assertThatRegisterPoolExists(gc);
assertThatChecksWontBeSkipped(gc);
assertThatNoRethrowBlockExists(gc);
}
use of org.jikesrvm.compilers.opt.inlining.InlineSequence in project JikesRVM by JikesRVM.
the class GenerationContext method createChildContext.
/**
* Creates a child generation context from this context
* and callerBB to generate IR for callsite.
*
* @param ebag the enclosing exception handlers (null if none)
* @param callee the callee method to be inlined
* (may _not_ be equal to Call.getMethod(callSite).method)
* @param callSite the Call instruction to be inlined.
* @return the child context
*/
public GenerationContext createChildContext(ExceptionHandlerBasicBlockBag ebag, NormalMethod callee, Instruction callSite) {
// Note: In this method, use "this" explicitly to refer to parent fields in order
// to avoid confusing parent/child fields.
GenerationContext child = new GenerationContext();
child.method = callee;
if (this.options.frequencyCounters() || this.options.inverseFrequencyCounters()) {
child.branchProfiles = EdgeCounts.getBranchProfiles(callee);
}
child.parent = this;
child.original_cm = this.original_cm;
// Some state gets directly copied to the child
child.options = this.options;
child.temps = this.temps;
child._ncGuards = this._ncGuards;
child.exit = this.exit;
child.inlinePlan = this.inlinePlan;
// Now inherit state based on callSite
child.inlineSequence = new InlineSequence(child.method, callSite.position(), callSite);
child.enclosingHandlers = ebag;
child.arguments = new Operand[Call.getNumberOfParams(callSite)];
for (int i = 0; i < child.arguments.length; i++) {
// copy instead
child.arguments[i] = Call.getParam(callSite, i).copy();
// of clearing in case inlining aborts.
}
if (Call.hasResult(callSite)) {
child.resultReg = Call.getResult(callSite).copyD2D().getRegister();
// it will...
child.resultReg.setSpansBasicBlock();
}
// Initialize the child CFG, prologue, and epilogue blocks
child.cfg = new ControlFlowGraph(this.cfg.numberOfNodes());
child.prologue = new BasicBlock(PROLOGUE_BCI, child.inlineSequence, child.cfg);
child.prologue.setExceptionHandlers(ebag);
child.epilogue = new BasicBlock(EPILOGUE_BCI, child.inlineSequence, child.cfg);
child.epilogue.setExceptionHandlers(ebag);
child.cfg.addLastInCodeOrder(child.prologue);
child.cfg.addLastInCodeOrder(child.epilogue);
// Set up the local pool
child.initLocalPool();
// Insert moves from child.arguments to child's locals in prologue
TypeReference[] params = child.method.getParameterTypes();
int numParams = params.length;
int argIdx = 0;
int localNum = 0;
if (!child.method.isStatic()) {
Operand receiver = child.arguments[argIdx];
argIdx++;
RegisterOperand local = null;
if (receiver.isRegister()) {
RegisterOperand objPtr = receiver.asRegister();
if (ClassLoaderProxy.includesType(child.method.getDeclaringClass().getTypeRef(), objPtr.getType()) != YES) {
// narrow type of actual to match formal static type implied by method
// Can be precise but not assignable if enough classes aren't loaded
objPtr.clearPreciseType();
objPtr.setDeclaredType();
objPtr.setType(child.method.getDeclaringClass().getTypeRef());
}
local = child.makeLocal(localNum, objPtr);
localNum++;
// Avoid confusion in BC2IR of callee
child.arguments[0] = local;
// when objPtr is a local in the caller.
} else if (receiver.isConstant()) {
local = child.makeLocal(localNum, receiver.getType());
localNum++;
local.setPreciseType();
// Constants trivially non-null
RegisterOperand guard = child.makeNullCheckGuard(local.getRegister());
BC2IR.setGuardForRegOp(local, guard);
child.prologue.appendInstruction(Move.create(GUARD_MOVE, guard.copyRO(), new TrueGuardOperand()));
} else {
OptimizingCompilerException.UNREACHABLE("Unexpected receiver operand");
}
Instruction s = Move.create(REF_MOVE, local, receiver);
s.setSourcePosition(PROLOGUE_BCI, callSite.position());
child.prologue.appendInstruction(s);
}
for (int paramIdx = 0; paramIdx < numParams; paramIdx++, argIdx++) {
TypeReference argType = params[paramIdx];
RegisterOperand formal;
Operand actual = child.arguments[argIdx];
if (actual.isRegister()) {
RegisterOperand rActual = actual.asRegister();
if (ClassLoaderProxy.includesType(argType, rActual.getType()) != YES) {
// narrow type of actual to match formal static type implied by method
// Can be precise but not
rActual.clearPreciseType();
// assignable if enough classes aren't loaded
rActual.setDeclaredType();
rActual.setType(argType);
}
formal = child.makeLocal(localNum, rActual);
localNum++;
// Avoid confusion in BC2IR of
child.arguments[argIdx] = formal;
// callee when arg is a local in the caller.
} else {
formal = child.makeLocal(localNum, argType);
localNum++;
}
Instruction s = Move.create(IRTools.getMoveOp(argType), formal, actual);
s.setSourcePosition(PROLOGUE_BCI, callSite.position());
child.prologue.appendInstruction(s);
if (argType.isLongType() || argType.isDoubleType()) {
// longs and doubles take two local words
localNum++;
}
}
child.completePrologue(false);
child.completeEpilogue(false);
child.completeExceptionHandlers(false);
return child;
}
use of org.jikesrvm.compilers.opt.inlining.InlineSequence in project JikesRVM by JikesRVM.
the class GenerationContextTest method prologueAndEpilogueForSynchronizedStaticMethodHaveMonitorEnterAndExit.
@Test
public void prologueAndEpilogueForSynchronizedStaticMethodHaveMonitorEnterAndExit() throws Exception {
NormalMethod nm = getNormalMethodForTest("emptySynchronizedStaticMethod");
CompiledMethod cm = new OptCompiledMethod(-1, nm);
OptOptions opts = new OptOptions();
InlineOracle io = new DefaultInlineOracle();
GenerationContext gc = new GenerationContext(nm, null, cm, opts, io);
InlineSequence inlineSequence = new InlineSequence(nm);
assertThatInlineSequenceWasSetCorrectly(gc, inlineSequence);
assertThatNumberOfParametersIs(gc, 0);
BasicBlock prologue = gc.getPrologue();
assertThatPrologueBlockIsSetupCorrectly(gc, inlineSequence, prologue);
assertThatFirstInstructionInPrologueIsPrologue(inlineSequence, prologue);
Enumeration<Instruction> prologueInstructions = prologue.forwardRealInstrEnumerator();
prologueInstructions.nextElement();
Instruction secondInstruction = prologueInstructions.nextElement();
assertInstructionIsMonitorEnterInPrologue(secondInstruction, inlineSequence);
assertThatGuardIsCorrectForMonitorEnter(secondInstruction);
Operand lockObject = MonitorOp.getRef(secondInstruction);
Operand expectedLockObject = buildLockObjectForStaticMethod(nm);
assertTrue(expectedLockObject.similar(lockObject));
assertThatNumberOfRealInstructionsMatches(prologue, 2);
BasicBlock epilogue = gc.getEpilogue();
assertThatEpilogueBlockIsSetupCorrectly(gc, inlineSequence, epilogue);
assertThatFirstInstructionEpilogueIsMonitorExit(inlineSequence, epilogue);
assertThatLastInstructionInEpilogueIsReturn(gc, epilogue);
assertThatReturnInstructionReturnsVoid(epilogue);
assertThatNumberOfRealInstructionsMatches(epilogue, 2);
assertThatExitBlockIsSetCorrectly(gc);
assertThatRegisterPoolExists(gc);
assertThatDataIsSavedCorrectly(nm, cm, io, gc);
assertThatReturnValueIsVoid(gc);
assertThatExceptionHandlersWereGenerated(gc);
assertThatUnlockAndRethrowBlockIsCorrect(gc, inlineSequence, prologue, expectedLockObject, epilogue);
assertThatChecksWontBeSkipped(gc);
}
use of org.jikesrvm.compilers.opt.inlining.InlineSequence in project JikesRVM by JikesRVM.
the class GenerationContextTest method unintBeginAndUnintEndAreAddedWhenNecessary.
@Test
public void unintBeginAndUnintEndAreAddedWhenNecessary() throws Exception {
NormalMethod nm = getNormalMethodForTest("emptyStaticMethodWithoutAnnotations");
CompiledMethod cm = new OptCompiledMethod(-1, nm);
OptOptions opts = new OptOptions();
InlineOracle io = new DefaultInlineOracle();
GenerationContext gc = new GenerationContext(nm, null, cm, opts, io);
assertThatStateIsCorrectForUnsynchronizedEmptyStaticMethod(nm, cm, io, gc);
NormalMethod callee = getNormalMethodForTest("emptyStaticUninterruptibleMethod");
Instruction callInstr = buildCallInstructionForStaticMethodWithoutReturn(callee, nm);
ExceptionHandlerBasicBlockBag ebag = getMockEbag();
int nodeNumber = 23456;
gc.getCfg().setNumberOfNodes(nodeNumber);
GenerationContext child = gc.createChildContext(ebag, callee, callInstr);
assertThatStateIsCopiedFromParentToChild(gc, callee, child, ebag);
InlineSequence expectedInlineSequence = new InlineSequence(callee, callInstr.position(), callInstr);
assertEquals(expectedInlineSequence, child.getInlineSequence());
assertThatPrologueAndEpilogueAreWiredCorrectlyForChildContext(ebag, nodeNumber, child);
Enumeration<Instruction> prologueRealInstr = child.getPrologue().forwardRealInstrEnumerator();
Instruction unintBegin = prologueRealInstr.nextElement();
assertThatInstructionIsUnintMarker(unintBegin, UNINT_BEGIN);
assertThatNoMoreInstructionsExist(prologueRealInstr);
Enumeration<Instruction> epilogueRealInstr = child.getEpilogue().forwardRealInstrEnumerator();
Instruction unintEnd = epilogueRealInstr.nextElement();
assertThatInstructionIsUnintMarker(unintEnd, UNINT_END);
assertThatNoMoreInstructionsExist(epilogueRealInstr);
}
use of org.jikesrvm.compilers.opt.inlining.InlineSequence in project JikesRVM by JikesRVM.
the class GenerationContextTest method inliningInstanceMethodWithRegisterReceiver.
@Test
public void inliningInstanceMethodWithRegisterReceiver() throws Exception {
NormalMethod nm = getNormalMethodForTest("methodForInliningTests");
CompiledMethod cm = new OptCompiledMethod(-1, nm);
OptOptions opts = new OptOptions();
InlineOracle io = new DefaultInlineOracle();
GenerationContext gc = new GenerationContext(nm, null, cm, opts, io);
Class<?>[] argumentTypes = { Object.class, double.class, int.class, long.class };
NormalMethod callee = getNormalMethodForTest("emptyInstanceMethodWithParams", argumentTypes);
MethodOperand methOp = MethodOperand.VIRTUAL(callee.getMemberRef().asMethodReference(), callee);
Instruction callInstr = Call.create(CALL, null, null, methOp, 5);
RegisterOperand receiver = createMockRegisterOperand(TypeReference.JavaLangObject);
assertFalse(receiver.isPreciseType());
assertFalse(receiver.isDeclaredType());
receiver.setPreciseType();
Call.setParam(callInstr, 0, receiver);
RegisterOperand objectParam = prepareCallWithObjectParam(callInstr);
RegisterOperand doubleParam = prepareCallWithDoubleParam(callInstr);
RegisterOperand intParam = prepareCallWithIntParam(callInstr);
RegisterOperand longParam = prepareCallWithLongParam(callInstr);
callInstr.setPosition(new InlineSequence(nm));
ExceptionHandlerBasicBlockBag ebag = getMockEbag();
int nodeNumber = 12345;
gc.getCfg().setNumberOfNodes(nodeNumber);
GenerationContext child = gc.createChildContext(ebag, callee, callInstr);
assertThatStateIsCopiedFromParentToChild(gc, callee, child, ebag);
assertThatReturnValueIsVoid(child);
RegisterOperand thisArg = child.getArguments()[0].asRegister();
assertFalse(thisArg.isPreciseType());
assertTrue(thisArg.isDeclaredType());
TypeReference calleeClass = callee.getDeclaringClass().getTypeRef();
assertSame(thisArg.getType(), calleeClass);
RegisterOperand expectedLocalForReceiverParam = child.makeLocal(0, thisArg);
assertTrue(thisArg.sameRegisterPropertiesAs(expectedLocalForReceiverParam));
RegisterOperand firstArg = child.getArguments()[1].asRegister();
RegisterOperand expectedLocalForObjectParam = child.makeLocal(1, firstArg);
assertTrue(firstArg.sameRegisterPropertiesAs(expectedLocalForObjectParam));
RegisterOperand secondArg = child.getArguments()[2].asRegister();
RegisterOperand expectedLocalForDoubleParam = child.makeLocal(2, secondArg);
assertTrue(secondArg.sameRegisterPropertiesAs(expectedLocalForDoubleParam));
RegisterOperand thirdArg = child.getArguments()[3].asRegister();
RegisterOperand expectedLocalForIntParam = child.makeLocal(4, thirdArg);
assertTrue(thirdArg.sameRegisterPropertiesAs(expectedLocalForIntParam));
RegisterOperand fourthArg = child.getArguments()[4].asRegister();
RegisterOperand expectedLocalForLongParam = child.makeLocal(5, fourthArg);
assertTrue(fourthArg.sameRegisterPropertiesAs(expectedLocalForLongParam));
InlineSequence expectedInlineSequence = new InlineSequence(callee, callInstr.position(), callInstr);
assertEquals(expectedInlineSequence, child.getInlineSequence());
assertThatPrologueAndEpilogueAreWiredCorrectlyForChildContext(ebag, nodeNumber, child);
Enumeration<Instruction> prologueRealInstr = child.getPrologue().forwardRealInstrEnumerator();
Instruction receiverMove = prologueRealInstr.nextElement();
RegisterOperand expectedReceiver = receiver.copy().asRegister();
narrowRegOpToCalleeClass(expectedReceiver, calleeClass);
assertMoveOperationIsCorrect(callInstr, REF_MOVE, expectedLocalForReceiverParam, expectedReceiver, receiverMove);
Instruction objectMove = prologueRealInstr.nextElement();
RegisterOperand objectParamCopy = objectParam.copy().asRegister();
assertMoveOperationIsCorrect(callInstr, REF_MOVE, expectedLocalForObjectParam, objectParamCopy, objectMove);
Instruction doubleMove = prologueRealInstr.nextElement();
RegisterOperand doubleParamCopy = doubleParam.copy().asRegister();
assertMoveOperationIsCorrect(callInstr, DOUBLE_MOVE, expectedLocalForDoubleParam, doubleParamCopy, doubleMove);
Instruction intMove = prologueRealInstr.nextElement();
RegisterOperand intParamCopy = intParam.copy().asRegister();
assertMoveOperationIsCorrect(callInstr, INT_MOVE, expectedLocalForIntParam, intParamCopy, intMove);
Instruction longMove = prologueRealInstr.nextElement();
RegisterOperand longParamCopy = longParam.copy().asRegister();
assertMoveOperationIsCorrect(callInstr, LONG_MOVE, expectedLocalForLongParam, longParamCopy, longMove);
assertThatNoMoreInstructionsExist(prologueRealInstr);
BasicBlock epilogue = child.getEpilogue();
assertThatEpilogueLabelIsCorrectForInlinedMethod(child, expectedInlineSequence, epilogue);
assertThatEpilogueIsEmpty(epilogue);
assertThatNoRethrowBlockExists(child);
assertThatChecksWontBeSkipped(gc);
}
Aggregations