Methods Summary |
---|
private com.android.dx.rop.code.RopMethod | convert()Performs the conversion.
if (DEBUG) {
interference.dumpToStdout();
}
// These are other allocators for debugging or historical comparison:
// allocator = new NullRegisterAllocator(ssaMeth, interference);
// allocator = new FirstFitAllocator(ssaMeth, interference);
RegisterAllocator allocator =
new FirstFitLocalCombiningAllocator(ssaMeth, interference,
minimizeRegisters);
RegisterMapper mapper = allocator.allocateRegisters();
if (DEBUG) {
System.out.println("Printing reg map");
System.out.println(((BasicRegisterMapper)mapper).toHuman());
}
ssaMeth.setBackMode();
ssaMeth.mapRegisters(mapper);
removePhiFunctions();
if (allocator.wantsParamsMovedHigh()) {
moveParametersToHighRegisters();
}
removeEmptyGotos();
RopMethod ropMethod = new RopMethod(convertBasicBlocks(),
ssaMeth.blockIndexToRopLabel(ssaMeth.getEntryBlockIndex()));
ropMethod = new IdenticalBlockCombiner(ropMethod).process();
return ropMethod;
|
private com.android.dx.rop.code.BasicBlock | convertBasicBlock(com.android.dx.ssa.SsaBasicBlock block)Converts a single basic block to rop form.
IntList successorList = block.getRopLabelSuccessorList();
int primarySuccessorLabel = block.getPrimarySuccessorRopLabel();
// Filter out any reference to the SSA form's exit block.
// Exit block may be null.
SsaBasicBlock exitBlock = ssaMeth.getExitBlock();
int exitRopLabel = (exitBlock == null) ? -1 : exitBlock.getRopLabel();
if (successorList.contains(exitRopLabel)) {
if (successorList.size() > 1) {
throw new RuntimeException(
"Exit predecessor must have no other successors"
+ Hex.u2(block.getRopLabel()));
} else {
successorList = IntList.EMPTY;
primarySuccessorLabel = -1;
verifyValidExitPredecessor(block);
}
}
successorList.setImmutable();
BasicBlock result = new BasicBlock(
block.getRopLabel(), convertInsns(block.getInsns()),
successorList,
primarySuccessorLabel);
return result;
|
private com.android.dx.rop.code.BasicBlockList | convertBasicBlocks()
ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks();
// Exit block may be null.
SsaBasicBlock exitBlock = ssaMeth.getExitBlock();
ssaMeth.computeReachability();
int ropBlockCount = ssaMeth.getCountReachableBlocks();
// Don't count the exit block, if it exists and is reachable.
ropBlockCount -= (exitBlock != null && exitBlock.isReachable()) ? 1 : 0;
BasicBlockList result = new BasicBlockList(ropBlockCount);
// Convert all the reachable blocks except the exit block.
int ropBlockIndex = 0;
for (SsaBasicBlock b : blocks) {
if (b.isReachable() && b != exitBlock) {
result.set(ropBlockIndex++, convertBasicBlock(b));
}
}
// The exit block, which is discarded, must do nothing.
if (exitBlock != null && exitBlock.getInsns().size() != 0) {
throw new RuntimeException(
"Exit block must have no insns when leaving SSA form");
}
return result;
|
private com.android.dx.rop.code.InsnList | convertInsns(java.util.ArrayList ssaInsns)Converts an insn list to rop form.
int insnCount = ssaInsns.size();
InsnList result = new InsnList(insnCount);
for (int i = 0; i < insnCount; i++) {
result.set(i, ssaInsns.get(i).toRopInsn());
}
result.setImmutable();
return result;
|
public static com.android.dx.rop.code.RopMethod | convertToRopMethod(com.android.dx.ssa.SsaMethod ssaMeth, boolean minimizeRegisters)Converts a method in SSA form to ROP form.
return new SsaToRop(ssaMeth, minimizeRegisters).convert();
|
public int[] | getRegistersByFrequency()Note: This method is not presently used.
int regCount = ssaMeth.getRegCount();
Integer[] ret = new Integer[regCount];
for (int i = 0; i < regCount; i++) {
ret[i] = i;
}
Arrays.sort(ret, new Comparator<Integer>() {
public int compare(Integer o1, Integer o2) {
return ssaMeth.getUseListForRegister(o2).size()
- ssaMeth.getUseListForRegister(o1).size();
}
});
int result[] = new int[regCount];
for (int i = 0; i < regCount; i++) {
result[i] = ret[i];
}
return result;
|
private void | moveParametersToHighRegisters()Moves the parameter registers, which allocateRegisters() places
at the bottom of the frame, up to the top of the frame to match
Dalvik calling convention.
int paramWidth = ssaMeth.getParamWidth();
BasicRegisterMapper mapper
= new BasicRegisterMapper(ssaMeth.getRegCount());
int regCount = ssaMeth.getRegCount();
for (int i = 0; i < regCount; i++) {
if (i < paramWidth) {
mapper.addMapping(i, regCount - paramWidth + i, 1);
} else {
mapper.addMapping(i, i - paramWidth, 1);
}
}
if (DEBUG) {
System.out.printf("Moving %d registers from 0 to %d\n",
paramWidth, regCount - paramWidth);
}
ssaMeth.mapRegisters(mapper);
|
private void | removeEmptyGotos()Removes all blocks containing only GOTOs from the control flow.
Although much of this work will be done later when converting
from rop to dex, not all simplification cases can be handled
there. Furthermore, any no-op block between the exit block and
blocks containing the real return or throw statements must be
removed.
final ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks();
ssaMeth.forEachBlockDepthFirst(false, new SsaBasicBlock.Visitor() {
public void visitBlock(SsaBasicBlock b, SsaBasicBlock parent) {
ArrayList<SsaInsn> insns = b.getInsns();
if ((insns.size() == 1)
&& (insns.get(0).getOpcode() == Rops.GOTO)) {
BitSet preds = (BitSet) b.getPredecessors().clone();
for (int i = preds.nextSetBit(0); i >= 0;
i = preds.nextSetBit(i + 1)) {
SsaBasicBlock pb = blocks.get(i);
pb.replaceSuccessor(b.getIndex(),
b.getPrimarySuccessorIndex());
}
}
}
});
|
private void | removePhiFunctions()See Appel 19.6. To remove the phi instructions in an edge-split
SSA representation we know we can always insert a move in a
predecessor block.
ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks();
for (SsaBasicBlock block : blocks) {
// Add moves in all the pred blocks for each phi insn.
block.forEachPhiInsn(new PhiVisitor(blocks));
// Delete the phi insns.
block.removeAllPhiInsns();
}
/*
* After all move insns have been added, sort them so they don't
* destructively interfere.
*/
for (SsaBasicBlock block : blocks) {
block.scheduleMovesFromPhis();
}
|
private void | verifyValidExitPredecessor(com.android.dx.ssa.SsaBasicBlock b)Validates that a basic block is a valid end predecessor. It must
end in a RETURN or a THROW. Throws a runtime exception on error.
ArrayList<SsaInsn> insns = b.getInsns();
SsaInsn lastInsn = insns.get(insns.size() - 1);
Rop opcode = lastInsn.getOpcode();
if (opcode.getBranchingness() != Rop.BRANCH_RETURN
&& opcode != Rops.THROW) {
throw new RuntimeException("Exit predecessor must end"
+ " in valid exit statement.");
}
|