use of org.jikesrvm.compilers.opt.ir.ExceptionHandlerBasicBlock in project JikesRVM by JikesRVM.
the class GenerationContextTest method assertThatUnlockAndRethrowBlockIsCorrectForInlinedMethod.
private void assertThatUnlockAndRethrowBlockIsCorrectForInlinedMethod(GenerationContext parentContext, GenerationContext childContext, InlineSequence inlineSequence, BasicBlock prologue, Operand lockObject, BasicBlock epilogue) {
ExceptionHandlerBasicBlockBag ehbb = childContext.getEnclosingHandlers();
Enumeration<BasicBlock> enumerator = ehbb.enumerator();
assertThat(childContext.getUnlockAndRethrow().exceptionHandlers(), is(parentContext.getEnclosingHandlers()));
ExceptionHandlerBasicBlock rethrow = (ExceptionHandlerBasicBlock) enumerator.nextElement();
assertSame(rethrow, childContext.getUnlockAndRethrow());
assertThatRethrowBlockIsCorrect(inlineSequence, lockObject, rethrow);
checkCodeOrderForRethrowBlock(childContext, prologue, epilogue, rethrow);
ExceptionHandlerBasicBlockBag parentHandlers = parentContext.getEnclosingHandlers();
Enumeration<BasicBlock> parentHandlerBBEnum = parentHandlers.enumerator();
HashSet<BasicBlock> parentHandlerBBs = new HashSet<BasicBlock>();
while (parentHandlerBBEnum.hasMoreElements()) {
parentHandlerBBs.add(parentHandlerBBEnum.nextElement());
}
BasicBlock childRethrow = childContext.getUnlockAndRethrow();
OutEdgeEnumeration outEdges = childRethrow.outEdges();
boolean linkedToAllBlocksFromParentHandler = true;
while (outEdges.hasMoreElements()) {
BasicBlock target = (BasicBlock) outEdges.nextElement().to();
if (!parentHandlerBBs.contains(target) && target != childContext.getExit()) {
linkedToAllBlocksFromParentHandler = false;
break;
}
}
assertTrue(linkedToAllBlocksFromParentHandler);
ExceptionHandlerBasicBlockBag ehbbb = childContext.getEnclosingHandlers();
assertSame(parentContext.getEnclosingHandlers(), ehbbb.getCaller());
assertThatEnclosingHandlersContainRethrow(rethrow, ehbbb);
}
use of org.jikesrvm.compilers.opt.ir.ExceptionHandlerBasicBlock 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.ExceptionHandlerBasicBlock 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();
}
}
use of org.jikesrvm.compilers.opt.ir.ExceptionHandlerBasicBlock in project JikesRVM by JikesRVM.
the class BBSet method initializeExceptionHandlers.
/**
* Initialize bble's handlers array based on startPCs/endPCs.
* In the process, new HandlerBlockLE's may be created
* (by the call to getOrCreateBlock). <p>
* PRECONDITION: bble.low and bble.max have already been correctly
* set to reflect the invariant that a basic block is in exactly one
* "handler range."<p>
* Also initializes bble.block.exceptionHandlers.
*
* @param bble the block whose handlers are to be initialized
* @param simLocals local variables
*/
private void initializeExceptionHandlers(BasicBlockLE bble, Operand[] simLocals) {
if (startPCs != null) {
HashSet<TypeReference> caughtTypes = new HashSet<TypeReference>();
for (int i = 0; i < startPCs.length; i++) {
TypeReference caughtType = exceptionTypes[i].getTypeRef();
if (bble.low >= startPCs[i] && bble.max <= endPCs[i] && !caughtTypes.contains(caughtType)) {
// bble's basic block is contained within this handler's range.
HandlerBlockLE eh = (HandlerBlockLE) getOrCreateBlock(handlerPCs[i], bble, null, simLocals);
if (DBG_EX)
db("Adding handler " + eh + " to " + bble);
caughtTypes.add(caughtType);
bble.addHandler(eh);
}
}
}
if (bble.handlers != null) {
ExceptionHandlerBasicBlock[] ehbbs = new ExceptionHandlerBasicBlock[bble.handlers.length];
for (int i = 0; i < bble.handlers.length; i++) {
ehbbs[i] = bble.handlers[i].entryBlock;
}
bble.block.setExceptionHandlers(new ExceptionHandlerBasicBlockBag(ehbbs, gc.getEnclosingHandlers()));
} else {
bble.block.setExceptionHandlers(gc.getEnclosingHandlers());
}
}
use of org.jikesrvm.compilers.opt.ir.ExceptionHandlerBasicBlock in project JikesRVM by JikesRVM.
the class BC2IR method rectifyStateWithExceptionHandlers.
/*
* Very similar to the above, but since we aren't told what might be thrown,
* we are forced to connect to every in scope handler and can't
* identify a definite target.
*
*/
private void rectifyStateWithExceptionHandlers(boolean linkToExitIfUncaught) {
currentBBLE.block.setCanThrowExceptions();
currentBBLE.block.setMayThrowUncaughtException();
if (linkToExitIfUncaught) {
if (DBG_EX) {
db("PEI of unknown type caused edge from " + currentBBLE + " to outermost exit");
}
currentBBLE.block.insertOut(gc.getExit());
if (DBG_CFG || DBG_SELECTED) {
db("Added CFG edge from " + currentBBLE.block + " to exit");
}
}
if (currentBBLE.handlers != null) {
for (HandlerBlockLE xbble : currentBBLE.handlers) {
if (DBG_EX) {
db("PEI of unknown type could be caught by " + xbble + " rectifying locals");
}
blocks.rectifyLocals(_localState, xbble);
currentBBLE.block.insertOut(xbble.entryBlock);
if (DBG_CFG || DBG_SELECTED) {
db("Added CFG edge from " + currentBBLE.block + " to " + xbble.entryBlock);
}
}
}
// Now, consider the enclosing exception context; ditto NOTE above.
if (gc.getEnclosingHandlers() != null) {
for (Enumeration<BasicBlock> e = gc.getEnclosingHandlers().enumerator(); e.hasMoreElements(); ) {
ExceptionHandlerBasicBlock xbb = (ExceptionHandlerBasicBlock) e.nextElement();
if (DBG_EX) {
db("PEI of unknown type could be caught by enclosing handler " + xbb);
}
currentBBLE.block.insertOut(xbb);
if (DBG_CFG || DBG_SELECTED) {
db("Added CFG edge from " + currentBBLE.block + " to " + xbb);
}
}
}
}
Aggregations