use of com.android.dx.util.IntList in project J2ME-Loader by nikita36078.
the class Ropper method isSubroutineCaller.
/**
* Checks to see if the basic block is a subroutine caller block.
*
* @param bb {@code non-null;} the basic block in question
* @return true if this block calls a subroutine
*/
private boolean isSubroutineCaller(BasicBlock bb) {
IntList successors = bb.getSuccessors();
if (successors.size() < 2)
return false;
int subLabel = successors.get(1);
return (subLabel < subroutines.length) && (subroutines[subLabel] != null);
}
use of com.android.dx.util.IntList in project J2ME-Loader by nikita36078.
the class Ropper method processBlock.
/**
* Processes the given block.
*
* @param block {@code non-null;} block to process
* @param frame {@code non-null;} start frame for the block
* @param workSet {@code non-null;} bits representing work to do,
* which this method may add to
*/
private void processBlock(ByteBlock block, Frame frame, int[] workSet) {
// Prepare the list of caught exceptions for this block.
ByteCatchList catches = block.getCatches();
machine.startBlock(catches.toRopCatchList());
/*
* Using a copy of the given frame, simulate each instruction,
* calling into machine for each.
*/
frame = frame.copy();
sim.simulate(block, frame);
frame.setImmutable();
int extraBlockCount = machine.getExtraBlockCount();
ArrayList<Insn> insns = machine.getInsns();
int insnSz = insns.size();
/*
* 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.
*/
CatchInfo handlers = catchInfos[targ];
if (handlers == null) {
handlers = new CatchInfo();
catchInfos[targ] = handlers;
}
ExceptionHandlerSetup handler = handlers.getSetup(exceptionClass.getClassType());
/*
* The synthesized exception setup block will have the label given by handler.
*/
newSucc.add(handler.getLabel());
}
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, extraInsn.getPosition(), null, RegisterSpecList.EMPTY));
/*
* Obviously, this block won't be throwing an exception
* so it should only have one successor.
*/
extraBlockSuccessors = IntList.makeImmutable(primarySucc);
}
il.setImmutable();
int label = getAvailableLabel();
BasicBlock bb = new BasicBlock(label, il, extraBlockSuccessors, primarySucc);
// All of these extra blocks will be in the same subroutine
addBlock(bb, frame.getSubroutines());
successors = successors.mutableCopy();
successors.set(primarySuccListIndex, label);
successors.setImmutable();
primarySucc = label;
}
Insn lastInsn = (insnSz == 0) ? null : insns.get(insnSz - 1);
/*
* Add a goto to the end of the block if it doesn't already
* end with a branch, to maintain the invariant that all
* blocks end with a branch of some sort or other. Note that
* it is possible for there to be blocks for which no
* instructions were ever output (e.g., only consist of pop*
* in the original Java bytecode).
*/
if ((lastInsn == null) || (lastInsn.getOpcode().getBranchingness() == Rop.BRANCH_NONE)) {
SourcePosition pos = (lastInsn == null) ? SourcePosition.NO_INFO : lastInsn.getPosition();
insns.add(new PlainInsn(Rops.GOTO, pos, null, RegisterSpecList.EMPTY));
insnSz++;
}
/*
* Construct a block for the remaining instructions (which in
* the usual case is all of them).
*/
InsnList il = new InsnList(insnSz);
for (int i = 0; i < insnSz; i++) {
il.set(i, insns.get(i));
}
il.setImmutable();
BasicBlock bb = new BasicBlock(block.getLabel(), il, successors, primarySucc);
addOrReplaceBlock(bb, frame.getSubroutines());
}
use of com.android.dx.util.IntList in project J2ME-Loader by nikita36078.
the class Ropper method removeBlockAndSpecialSuccessors.
/**
* Helper for {@link #addOrReplaceBlock} which recursively removes
* the given block and all blocks that are (direct and indirect)
* successors of it whose labels indicate that they are not in the
* normally-translated range.
*
* @param idx {@code non-null;} block to remove (etc.)
*/
private void removeBlockAndSpecialSuccessors(int idx) {
int minLabel = getMinimumUnreservedLabel();
BasicBlock block = result.get(idx);
IntList successors = block.getSuccessors();
int sz = successors.size();
result.remove(idx);
resultSubroutines.remove(idx);
for (int i = 0; i < sz; i++) {
int label = successors.get(i);
if (label >= minLabel) {
idx = labelToResultIndex(label);
if (idx < 0) {
throw new RuntimeException("Invalid label " + Hex.u2(label));
}
removeBlockAndSpecialSuccessors(idx);
}
}
}
use of com.android.dx.util.IntList in project J2ME-Loader by nikita36078.
the class LocalVariableExtractor method processBlock.
/**
* Processes a single block.
*
* @param blockIndex {@code >= 0;} block index of the block to process
*/
private void processBlock(int blockIndex) {
RegisterSpecSet primaryState = resultInfo.mutableCopyOfStarts(blockIndex);
SsaBasicBlock block = blocks.get(blockIndex);
List<SsaInsn> insns = block.getInsns();
int insnSz = insns.size();
// The exit block has no insns and no successors
if (blockIndex == method.getExitBlockIndex()) {
return;
}
/*
* We may have to treat the last instruction specially: If it
* can (but doesn't always) throw, and the exception can be
* caught within the same method, then we need to use the
* state *before* executing it to be what is merged into
* exception targets.
*/
SsaInsn lastInsn = insns.get(insnSz - 1);
boolean hasExceptionHandlers = lastInsn.getOriginalRopInsn().getCatches().size() != 0;
boolean canThrowDuringLastInsn = hasExceptionHandlers && (lastInsn.getResult() != null);
int freezeSecondaryStateAt = insnSz - 1;
RegisterSpecSet secondaryState = primaryState;
for (int i = 0; i < insnSz; i++) {
if (canThrowDuringLastInsn && (i == freezeSecondaryStateAt)) {
// Until this point, primaryState == secondaryState.
primaryState.setImmutable();
primaryState = primaryState.mutableCopy();
}
SsaInsn insn = insns.get(i);
RegisterSpec result;
result = insn.getLocalAssignment();
if (result == null) {
// We may be nuking an existing local
result = insn.getResult();
if (result != null && primaryState.get(result.getReg()) != null) {
primaryState.remove(primaryState.get(result.getReg()));
}
continue;
}
result = result.withSimpleType();
RegisterSpec already = primaryState.get(result);
/*
* The equals() check ensures we only add new info if
* the instruction causes a change to the set of
* active variables.
*/
if (!result.equals(already)) {
/*
* If this insn represents a local moving from one register
* to another, remove the association between the old register
* and the local.
*/
RegisterSpec previous = primaryState.localItemToSpec(result.getLocalItem());
if (previous != null && (previous.getReg() != result.getReg())) {
primaryState.remove(previous);
}
resultInfo.addAssignment(insn, result);
primaryState.put(result);
}
}
primaryState.setImmutable();
/*
* Merge this state into the start state for each successor,
* and update the work set where required (that is, in cases
* where the start state for a block changes).
*/
IntList successors = block.getSuccessorList();
int succSz = successors.size();
int primarySuccessor = block.getPrimarySuccessorIndex();
for (int i = 0; i < succSz; i++) {
int succ = successors.get(i);
RegisterSpecSet state = (succ == primarySuccessor) ? primaryState : secondaryState;
if (resultInfo.mergeStarts(succ, state)) {
workSet.set(succ);
}
}
}
use of com.android.dx.util.IntList in project J2ME-Loader by nikita36078.
the class IdenticalBlockCombiner method process.
/**
* Runs algorithm. TODO: This is n^2, and could be made linear-ish with
* a hash. In particular, hash the contents of each block and only
* compare blocks with the same hash.
*
* @return {@code non-null;} new method that has been processed
*/
public RopMethod process() {
int szBlocks = blocks.size();
// indexed by label
BitSet toDelete = new BitSet(blocks.getMaxLabel());
// For each non-deleted block...
for (int bindex = 0; bindex < szBlocks; bindex++) {
BasicBlock b = blocks.get(bindex);
if (toDelete.get(b.getLabel())) {
// doomed block
continue;
}
IntList preds = ropMethod.labelToPredecessors(b.getLabel());
// ...look at all of it's predecessors that have only one succ...
int szPreds = preds.size();
for (int i = 0; i < szPreds; i++) {
int iLabel = preds.get(i);
BasicBlock iBlock = blocks.labelToBlock(iLabel);
if (toDelete.get(iLabel) || iBlock.getSuccessors().size() > 1 || iBlock.getFirstInsn().getOpcode().getOpcode() == RegOps.MOVE_RESULT) {
continue;
}
IntList toCombine = new IntList();
// ...and see if they can be combined with any other preds...
for (int j = i + 1; j < szPreds; j++) {
int jLabel = preds.get(j);
BasicBlock jBlock = blocks.labelToBlock(jLabel);
if (jBlock.getSuccessors().size() == 1 && compareInsns(iBlock, jBlock)) {
toCombine.add(jLabel);
toDelete.set(jLabel);
}
}
combineBlocks(iLabel, toCombine);
}
}
for (int i = szBlocks - 1; i >= 0; i--) {
if (toDelete.get(newBlocks.get(i).getLabel())) {
newBlocks.set(i, null);
}
}
newBlocks.shrinkToFit();
newBlocks.setImmutable();
return new RopMethod(newBlocks, ropMethod.getFirstLabel());
}
Aggregations