use of org.jikesrvm.compilers.opt.ir.ExceptionHandlerBasicBlockBag in project JikesRVM by JikesRVM.
the class GenerationContextTest method invalidReceiverCausesException.
@Test(expected = OptimizingCompilerException.class)
public void invalidReceiverCausesException() 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);
NormalMethod callee = getNormalMethodForTest("emptyInstanceMethodWithoutAnnotations");
MethodOperand methOp = MethodOperand.VIRTUAL(callee.getMemberRef().asMethodReference(), callee);
Instruction callInstr = Call.create(CALL, null, null, methOp, 1);
Operand receiver = new InvalidReceiverOperand();
Call.setParam(callInstr, 0, receiver);
callInstr.setPosition(new InlineSequence(nm));
ExceptionHandlerBasicBlockBag ebag = getMockEbag();
gc.createChildContext(ebag, callee, callInstr);
}
use of org.jikesrvm.compilers.opt.ir.ExceptionHandlerBasicBlockBag in project JikesRVM by JikesRVM.
the class GenerationContextTest method inliningInstanceMethodWithNarrowingOfReferenceParam.
@Test
public void inliningInstanceMethodWithNarrowingOfReferenceParam() 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 = { MethodsForTests.class };
NormalMethod callee = getNormalMethodForTest("emptyStaticMethodWithReferenceParam", argumentTypes);
MethodOperand methOp = MethodOperand.VIRTUAL(callee.getMemberRef().asMethodReference(), callee);
Instruction callInstr = Call.create(CALL, null, null, methOp, 1);
RegisterOperand objectParam = createMockRegisterOperand(TypeReference.JavaLangObject);
assertFalse(objectParam.isPreciseType());
assertFalse(objectParam.isDeclaredType());
objectParam.setPreciseType();
Call.setParam(callInstr, 0, objectParam);
RegisterOperand objectParamCopy = objectParam.copy().asRegister();
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 objectParamArg = child.getArguments()[0].asRegister();
TypeReference calleeClass = callee.getDeclaringClass().getTypeRef();
assertThatRegOpWasNarrowedToCalleeClass(objectParamArg, calleeClass);
RegisterOperand expectedLocalForObjectParam = child.makeLocal(0, objectParamArg);
assertTrue(objectParamArg.sameRegisterPropertiesAs(expectedLocalForObjectParam));
InlineSequence expectedInlineSequence = new InlineSequence(callee, callInstr.position(), callInstr);
assertEquals(expectedInlineSequence, child.getInlineSequence());
assertThatPrologueAndEpilogueAreWiredCorrectlyForChildContext(ebag, nodeNumber, child);
Enumeration<Instruction> prologueRealInstr = child.getPrologue().forwardRealInstrEnumerator();
Instruction objectMove = prologueRealInstr.nextElement();
narrowRegOpToCalleeClass(objectParamCopy, calleeClass);
assertMoveOperationIsCorrect(callInstr, REF_MOVE, expectedLocalForObjectParam, objectParamCopy, objectMove);
assertThatNoMoreInstructionsExist(prologueRealInstr);
BasicBlock epilogue = child.getEpilogue();
assertThatEpilogueLabelIsCorrectForInlinedMethod(child, expectedInlineSequence, epilogue);
assertThatEpilogueIsEmpty(epilogue);
assertThatNoRethrowBlockExists(child);
assertThatChecksWontBeSkipped(gc);
}
use of org.jikesrvm.compilers.opt.ir.ExceptionHandlerBasicBlockBag in project JikesRVM by JikesRVM.
the class GenerationContextTest method inliningInstanceMethodWithRegisterReceiverNoNarrowing.
@Test
public void inliningInstanceMethodWithRegisterReceiverNoNarrowing() 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(callee.getDeclaringClass().getTypeRef());
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();
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();
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);
}
use of org.jikesrvm.compilers.opt.ir.ExceptionHandlerBasicBlockBag in project JikesRVM by JikesRVM.
the class GenerationContext method completeExceptionHandlers.
/**
* If the method is synchronized then we wrap it in a
* synthetic exception handler that unlocks & rethrows
* PRECONDITION: cfg, arguments & temps have been setup/initialized.
*
* @param isOutermost is this the outermost context (i.e. not an inlined context)
*/
private void completeExceptionHandlers(boolean isOutermost) {
if (method.isSynchronized() && !options.ESCAPE_INVOKEE_THREAD_LOCAL) {
ExceptionHandlerBasicBlock rethrow = new ExceptionHandlerBasicBlock(SYNTH_CATCH_BCI, inlineSequence, new TypeOperand(RVMType.JavaLangThrowableType), cfg);
rethrow.setExceptionHandlers(enclosingHandlers);
RegisterOperand ceo = temps.makeTemp(TypeReference.JavaLangThrowable);
Instruction s = Nullary.create(GET_CAUGHT_EXCEPTION, ceo);
appendInstruction(rethrow, s, SYNTH_CATCH_BCI);
Operand lockObject = getLockObject();
RVMMethod target = Entrypoints.unlockAndThrowMethod;
MethodOperand methodOp = MethodOperand.STATIC(target);
// Used to keep cfg correct
methodOp.setIsNonReturningCall(true);
s = Call.create2(CALL, null, new AddressConstantOperand(target.getOffset()), methodOp, lockObject, ceo.copyD2U());
appendInstruction(rethrow, s, RUNTIME_SERVICES_BCI);
cfg.insertBeforeInCodeOrder(epilogue, rethrow);
// (if enclosed by another catch of Throwable...)
if (enclosingHandlers != null) {
for (Enumeration<BasicBlock> e = enclosingHandlers.enumerator(); e.hasMoreElements(); ) {
BasicBlock eh = e.nextElement();
rethrow.insertOut(eh);
}
}
rethrow.setCanThrowExceptions();
rethrow.setMayThrowUncaughtException();
rethrow.insertOut(exit);
// save a reference to this block so we can discard it if unused.
unlockAndRethrow = rethrow;
ExceptionHandlerBasicBlock[] sh = new ExceptionHandlerBasicBlock[1];
sh[0] = rethrow;
enclosingHandlers = new ExceptionHandlerBasicBlockBag(sh, enclosingHandlers);
generatedExceptionHandlers = true;
}
}
use of org.jikesrvm.compilers.opt.ir.ExceptionHandlerBasicBlockBag in project JikesRVM by JikesRVM.
the class BBSet method finalPass.
/**
* Do a final pass over the generated basic blocks to create
* the initial code ordering. All blocks generated for the method
* will be inserted after gc.prologue.
* <p>
* NOTE: Only some CFG edges are created here.....
* we're mainly just patching together a code linearization.
*
* @param inlinedSomething was a normal method (i.e. non-magic) inlined?
*/
void finalPass(boolean inlinedSomething) {
BBSet.TreeEnumerator e = TreeEnumerator.enumFromRoot(root);
BasicBlock cop = gc.getPrologue();
BasicBlockLE curr = getEntry();
BasicBlockLE next = null;
top: while (true) {
// inject synthetic entry block too.
if (curr instanceof HandlerBlockLE) {
// tell our caller that we actually put a handler in the final CFG.
gc.markExceptionHandlersAsGenerated();
HandlerBlockLE hcurr = (HandlerBlockLE) curr;
if (DBG_FLATTEN) {
db("injecting handler entry block " + hcurr.entryBlock + " before " + hcurr);
}
gc.getCfg().insertAfterInCodeOrder(cop, hcurr.entryBlock);
cop = hcurr.entryBlock;
}
// Step 1: Insert curr in the code order (after cop, updating cop).
if (DBG_FLATTEN)
db("flattening: " + curr + " (" + curr.block + ")");
curr.setInCodeOrder();
gc.getCfg().insertAfterInCodeOrder(cop, curr.block);
cop = curr.block;
if (DBG_FLATTEN) {
db("Current Code order for " + gc.getMethod() + "\n");
for (BasicBlock bb = gc.getPrologue(); bb != null; bb = (BasicBlock) bb.getNext()) {
VM.sysWriteln(bb.toString());
}
}
// make a new, filtered EHBBB to avoid later confusion.
if (curr.handlers != null) {
int notGenerated = 0;
for (HandlerBlockLE handler : curr.handlers) {
if (!handler.isGenerated()) {
if (DBG_EX || DBG_FLATTEN) {
db("Will remove unreachable handler " + handler + " from " + curr);
}
notGenerated++;
}
}
if (notGenerated > 0) {
if (notGenerated == curr.handlers.length) {
if (DBG_EX || DBG_FLATTEN) {
db("No (local) handlers were actually reachable for " + curr + "; setting to caller");
}
curr.block.setExceptionHandlers(curr.block.exceptionHandlers().getCaller());
} else {
ExceptionHandlerBasicBlock[] nlh = new ExceptionHandlerBasicBlock[curr.handlers.length - notGenerated];
for (int i = 0, j = 0; i < curr.handlers.length; i++) {
if (curr.handlers[i].isGenerated()) {
nlh[j++] = curr.handlers[i].entryBlock;
} else {
if (VM.VerifyAssertions) {
VM._assert(curr.handlers[i].entryBlock.hasZeroIn(), "Non-generated handler with CFG edges");
}
}
}
curr.block.setExceptionHandlers(new ExceptionHandlerBasicBlockBag(nlh, curr.block.exceptionHandlers().getCaller()));
}
}
}
// all fits together....--dave
if (curr.fallThrough != null && curr.fallThrough instanceof InliningBlockLE) {
InliningBlockLE icurr = (InliningBlockLE) curr.fallThrough;
BasicBlock forw = cop.nextBasicBlockInCodeOrder();
BasicBlock calleeEntry = icurr.gc.getCfg().firstInCodeOrder();
BasicBlock calleeExit = icurr.gc.getCfg().lastInCodeOrder();
gc.getCfg().breakCodeOrder(cop, forw);
gc.getCfg().linkInCodeOrder(cop, icurr.gc.getCfg().firstInCodeOrder());
gc.getCfg().linkInCodeOrder(icurr.gc.getCfg().lastInCodeOrder(), forw);
if (DBG_CFG || BC2IR.DBG_SELECTED) {
db("Added CFG edge from " + cop + " to " + calleeEntry);
}
if (icurr.epilogueBBLE != null) {
if (DBG_FLATTEN) {
db("injected " + icurr + " between " + curr + " and " + icurr.epilogueBBLE.fallThrough);
}
if (VM.VerifyAssertions) {
VM._assert(icurr.epilogueBBLE.block == icurr.gc.getCfg().lastInCodeOrder());
}
curr = icurr.epilogueBBLE;
cop = curr.block;
} else {
if (DBG_FLATTEN)
db("injected " + icurr + " after " + curr);
curr = icurr;
cop = calleeExit;
}
}
next = curr.fallThrough;
if (DBG_FLATTEN && next == null) {
db(curr + " has no fallthrough case, getting next block");
}
if (next != null) {
if (DBG_CFG || BC2IR.DBG_SELECTED) {
db("Added CFG edge from " + curr.block + " to " + next.block);
}
if (next.isInCodeOrder()) {
if (DBG_FLATTEN) {
db("fallthrough " + next + " is already flattened, adding goto");
}
curr.block.appendInstruction(next.block.makeGOTO());
// set next to null to indicate no "real" fall through
next = null;
}
}
if (next == null) {
// Can't process fallthroughblock, so get next BBLE from enumeration
while (true) {
if (!e.hasMoreElements()) {
// all done.
if (DBG_FLATTEN)
db("no more blocks! all done");
break top;
}
next = e.next();
if (DBG_FLATTEN)
db("looking at " + next);
if (!next.isGenerated()) {
if (DBG_FLATTEN)
db("block " + next + " was not generated");
continue;
}
if (!next.isInCodeOrder()) {
break;
}
}
if (DBG_FLATTEN)
db("found unflattened block: " + next);
}
curr = next;
}
// If the epilogue was unreachable, remove it from the code order and cfg
// and set gc.epilogue to null.
boolean removedSomethingFromCodeOrdering = inlinedSomething;
if (gc.getEpilogue().hasZeroIn()) {
if (DBG_FLATTEN || DBG_CFG) {
db("Deleting unreachable epilogue " + gc.getEpilogue());
}
gc.getCfg().removeFromCodeOrder(gc.getEpilogue());
removedSomethingFromCodeOrdering = true;
// remove the node from the graph AND adjust its edge info
gc.getEpilogue().remove();
gc.getEpilogue().deleteIn();
gc.getEpilogue().deleteOut();
if (VM.VerifyAssertions)
VM._assert(gc.getEpilogue().hasZeroOut());
gc.setEpilogue(null);
}
// if gc has an unlockAndRethrow block that was not used, then remove it
if (gc.getUnlockAndRethrow() != null && gc.getUnlockAndRethrow().hasZeroIn()) {
gc.getCfg().removeFromCFGAndCodeOrder(gc.getUnlockAndRethrow());
removedSomethingFromCodeOrdering = true;
gc.getEnclosingHandlers().remove(gc.getUnlockAndRethrow());
}
// if we removed a basic block then we should compact the node numbering
if (removedSomethingFromCodeOrdering) {
gc.getCfg().compactNodeNumbering();
}
if (DBG_FLATTEN) {
db("Current Code order for " + gc.getMethod() + "\n");
for (BasicBlock bb = gc.getPrologue(); bb != null; bb = (BasicBlock) bb.getNext()) {
bb.printExtended();
}
}
if (DBG_FLATTEN) {
db("Final CFG for " + gc.getMethod() + "\n");
gc.getCfg().printDepthFirst();
}
}
Aggregations