* Merge the frame into each possible non-exceptional
* successor.
*/
int catchSz = catches.size();
IntList successors = block.getSuccessors();
int startSuccessorIndex;
Subroutine calledSubroutine = null;
if (machine.hasJsr()) {
/*
* If this frame ends in a JSR, only merge our frame with
* the subroutine start, not the subroutine's return target.
*/
startSuccessorIndex = 1;
int subroutineLabel = successors.get(1);
if (subroutines[subroutineLabel] == null) {
subroutines[subroutineLabel] = new Subroutine (subroutineLabel);
}
subroutines[subroutineLabel].addCallerBlock(block.getLabel());
calledSubroutine = subroutines[subroutineLabel];
} else if (machine.hasRet()) {
/*
* This block ends in a ret, which means it's the final block
* in some subroutine. Ultimately, this block will be copied
* and inlined for each call and then disposed of.
*/
ReturnAddress ra = machine.getReturnAddress();
int subroutineLabel = ra.getSubroutineAddress();
if (subroutines[subroutineLabel] == null) {
subroutines[subroutineLabel]
= new Subroutine (subroutineLabel, block.getLabel());
} else {
subroutines[subroutineLabel].addRetBlock(block.getLabel());
}
successors = subroutines[subroutineLabel].getSuccessors();
subroutines[subroutineLabel]
.mergeToSuccessors(frame, workSet);
// Skip processing below since we just did it.
startSuccessorIndex = successors.size();
} else if (machine.wereCatchesUsed()) {
/*
* If there are catches, then the first successors
* (which will either be all of them or all but the last one)
* are catch targets.
*/
startSuccessorIndex = catchSz;
} else {
startSuccessorIndex = 0;
}
int succSz = successors.size();
for (int i = startSuccessorIndex; i < succSz;
i++) {
int succ = successors.get(i);
try {
mergeAndWorkAsNecessary(succ, block.getLabel(),
calledSubroutine, frame, workSet);
} catch (SimException ex) {
ex.addContext("...while merging to block " + Hex.u2(succ));
throw ex;
}
}
if ((succSz == 0) && machine.returns()) {
/*
* The block originally contained a return, but it has
* been made to instead end with a goto, and we need to
* tell it at this point that its sole successor is the
* return block. This has to happen after the merge loop
* above, since, at this point, the return block doesn't
* actually exist; it gets synthesized at the end of
* processing the original blocks.
*/
successors = IntList.makeImmutable(getSpecialLabel(RETURN));
succSz = 1;
}
int primarySucc;
if (succSz == 0) {
primarySucc = -1;
} else {
primarySucc = machine.getPrimarySuccessorIndex();
if (primarySucc >= 0) {
primarySucc = successors.get(primarySucc);
}
}
/*
* This variable is true only when the method is synchronized and
* the block being processed can possibly throw an exception.
*/
boolean synch = isSynchronized() && machine.canThrow();
if (synch || (catchSz != 0)) {
/*
* Deal with exception handlers: Merge an exception-catch
* frame into each possible exception handler, and
* construct a new set of successors to point at the
* exception handler setup blocks (which get synthesized
* at the very end of processing).
*/
boolean catchesAny = false;
IntList newSucc = new IntList(succSz);
for (int i = 0; i < catchSz; i++) {
ByteCatchList.Item one = catches.get(i);
CstType exceptionClass = one.getExceptionClass();
int targ = one.getHandlerPc();
catchesAny |= (exceptionClass == CstType.OBJECT);
Frame f = frame.makeExceptionHandlerStartFrame(exceptionClass);
try {
mergeAndWorkAsNecessary(targ, block.getLabel(),
null, f, workSet);
} catch (SimException ex) {
ex.addContext("...while merging exception to block " +
Hex.u2(targ));
throw ex;
}
/*
* Set up the exception handler type, by setting it if
* the given handler has yet to be encountered, or by
* conservatively unioning if it has.
*/
Type already = catchTypes[targ];
if (already == null) {
catchTypes[targ] = exceptionClass.getClassType();
} else if (already != exceptionClass.getClassType()) {
catchTypes[targ] = Type.OBJECT;
}
/*
* The synthesized exception setup block will have the
* label getExceptionSetupLabel(targ).
*/
newSucc.add(getExceptionSetupLabel(targ));
}
if (synch && !catchesAny) {
/*
* The method is synchronized and this block doesn't
* already have a catch-all handler, so add one to the
* end, both in the successors and in the throwing
* instruction(s) at the end of the block (which is where
* the caught classes live).
*/
newSucc.add(getSpecialLabel(SYNCH_CATCH_1));
synchNeedsExceptionHandler = true;
for (int i = insnSz - extraBlockCount - 1; i < insnSz; i++) {
Insn insn = insns.get(i);
if (insn.canThrow()) {
insn = insn.withAddedCatch(Type.OBJECT);
insns.set(i, insn);
}
}
}
if (primarySucc >= 0) {
newSucc.add(primarySucc);
}
newSucc.setImmutable();
successors = newSucc;
}
// Construct the final resulting block(s), and store it (them).
int primarySuccListIndex = successors.indexOf(primarySucc);
/*
* If there are any extra blocks, work backwards through the
* list of instructions, adding single-instruction blocks, and
* resetting the successors variables as appropriate.
*/
for (/*extraBlockCount*/; extraBlockCount > 0; extraBlockCount--) {
/*
* Some of the blocks that the RopperMachine wants added
* are for move-result insns, and these need goto insns as well.
*/
Insn extraInsn = insns.get(--insnSz);
boolean needsGoto
= extraInsn.getOpcode().getBranchingness()
== Rop.BRANCH_NONE;
InsnList il = new InsnList(needsGoto ? 2 : 1);
IntList extraBlockSuccessors = successors;
il.set(0, extraInsn);
if (needsGoto) {
il.set(1, new PlainInsn(Rops.GOTO,