Methods Summary |
---|
static java.util.BitSet | bitSetFromLabelList(com.android.dx.rop.code.BasicBlockList blocks, com.android.dx.util.IntList labelList)Builds a BitSet of block indices from a basic block list and a list
of labels taken from Rop form.
BitSet result = new BitSet(blocks.size());
for (int i = 0, sz = labelList.size(); i < sz; i++) {
result.set(blocks.indexOfLabel(labelList.get(i)));
}
return result;
|
public int | blockIndexToRopLabel(int bi)
if (bi < 0) {
return -1;
}
return blocks.get(bi).getRopLabel();
|
public int | borrowSpareRegister(int category)Borrows a register to use as a temp. Used in the phi removal process.
Call returnSpareRegisters() when done.
int result = spareRegisterBase + borrowedSpareRegisters;
borrowedSpareRegisters += category;
registerCount = Math.max(registerCount, result + category);
return result;
|
private void | buildUseList()Builds useList and unmodifiableUseList.
if (backMode) {
throw new RuntimeException("No use list in back mode");
}
useList = new ArrayList[registerCount];
for (int i = 0; i < registerCount; i++) {
useList[i] = new ArrayList();
}
forEachInsn(new SsaInsn.Visitor() {
/** {@inheritDoc} */
public void visitMoveInsn (NormalSsaInsn insn) {
addToUses(insn);
}
/** {@inheritDoc} */
public void visitPhiInsn (PhiInsn phi) {
addToUses(phi);
}
/** {@inheritDoc} */
public void visitNonMoveInsn (NormalSsaInsn insn) {
addToUses(insn);
}
/**
* Adds specified insn to the uses list for all of its sources.
* @param insn {@code non-null;} insn to process
*/
private void addToUses(SsaInsn insn) {
RegisterSpecList rl = insn.getSources();
int sz = rl.size();
for (int i = 0; i < sz; i++) {
useList[rl.get(i).getReg()].add(insn);
}
}
});
unmodifiableUseList = new List[registerCount];
for (int i = 0; i < registerCount; i++) {
unmodifiableUseList[i] = Collections.unmodifiableList(useList[i]);
}
|
public void | computeReachability()Computes reachability for all blocks in the method. First clears old
values from all blocks, then starts with the entry block and walks down
the control flow graph, marking all blocks it finds as reachable.
for (SsaBasicBlock block : blocks) {
block.setReachable(0);
}
ArrayList<SsaBasicBlock> blockList = new ArrayList<SsaBasicBlock>();
blockList.add(this.getEntryBlock());
while (!blockList.isEmpty()) {
SsaBasicBlock block = blockList.remove(0);
if (block.isReachable()) continue;
block.setReachable(1);
BitSet succs = block.getSuccessors();
for (int i = succs.nextSetBit(0); i >= 0;
i = succs.nextSetBit(i + 1)) {
blockList.add(blocks.get(i));
}
}
|
private void | convertRopToSsaBlocks(com.android.dx.rop.code.RopMethod rmeth)
BasicBlockList ropBlocks = rmeth.getBlocks();
int sz = ropBlocks.size();
blocks = new ArrayList<SsaBasicBlock>(sz + 2);
for (int i = 0; i < sz; i++) {
SsaBasicBlock sbb = SsaBasicBlock.newFromRop(rmeth, i, this);
blocks.add(sbb);
}
// Add an no-op entry block.
int origEntryBlockIndex = rmeth.getBlocks()
.indexOfLabel(rmeth.getFirstLabel());
SsaBasicBlock entryBlock
= blocks.get(origEntryBlockIndex).insertNewPredecessor();
entryBlockIndex = entryBlock.getIndex();
exitBlockIndex = -1; // This gets made later.
|
public void | deleteInsns(java.util.Set deletedInsns)Deletes all insns in the set from this method.
for (SsaBasicBlock block : getBlocks()) {
ArrayList<SsaInsn> insns = block.getInsns();
for (int i = insns.size() - 1; i >= 0; i--) {
SsaInsn insn = insns.get(i);
if (deletedInsns.contains(insn)) {
onInsnRemoved(insn);
insns.remove(i);
}
}
// Check to see if we need to add a GOTO
int insnsSz = insns.size();
SsaInsn lastInsn = (insnsSz == 0) ? null : insns.get(insnsSz - 1);
if (block != getExitBlock() && (insnsSz == 0
|| lastInsn.getOriginalRopInsn() == null
|| lastInsn.getOriginalRopInsn().getOpcode()
.getBranchingness() == Rop.BRANCH_NONE)) {
// We managed to eat a throwable insn
Insn gotoInsn = new PlainInsn(Rops.GOTO,
SourcePosition.NO_INFO, null, RegisterSpecList.EMPTY);
insns.add(SsaInsn.makeFromRop(gotoInsn, block));
// Remove secondary successors from this block
BitSet succs = block.getSuccessors();
for (int i = succs.nextSetBit(0); i >= 0;
i = succs.nextSetBit(i + 1)) {
if (i != block.getPrimarySuccessorIndex()) {
block.removeSuccessor(i);
}
}
}
}
|
public void | forEachBlockDepthFirst(boolean reverse, SsaBasicBlock.Visitor v)Walks the basic block tree in depth-first order, calling the visitor
method once for every block. This depth-first walk may be run forward
from the method entry point or backwards from the method exit points.
BitSet visited = new BitSet(blocks.size());
// We push the parent first, then the child on the stack.
Stack<SsaBasicBlock> stack = new Stack<SsaBasicBlock>();
SsaBasicBlock rootBlock = reverse ? getExitBlock() : getEntryBlock();
if (rootBlock == null) {
// in the case there's no exit block
return;
}
stack.add(null); // Start with null parent.
stack.add(rootBlock);
while (stack.size() > 0) {
SsaBasicBlock cur = stack.pop();
SsaBasicBlock parent = stack.pop();
if (!visited.get(cur.getIndex())) {
BitSet children
= reverse ? cur.getPredecessors() : cur.getSuccessors();
for (int i = children.nextSetBit(0); i >= 0
; i = children.nextSetBit(i + 1)) {
stack.add(cur);
stack.add(blocks.get(i));
}
visited.set(cur.getIndex());
v.visitBlock(cur, parent);
}
}
|
public void | forEachBlockDepthFirstDom(SsaBasicBlock.Visitor v)Visits blocks in dom-tree order, starting at the current node.
The {@code parent} parameter of the Visitor.visitBlock callback
is currently always set to null.
BitSet visited = new BitSet(getBlocks().size());
Stack<SsaBasicBlock> stack = new Stack<SsaBasicBlock>();
stack.add(getEntryBlock());
while (stack.size() > 0) {
SsaBasicBlock cur = stack.pop();
ArrayList<SsaBasicBlock> curDomChildren = cur.getDomChildren();
if (!visited.get(cur.getIndex())) {
// We walk the tree this way for historical reasons...
for (int i = curDomChildren.size() - 1; i >= 0; i--) {
SsaBasicBlock child = curDomChildren.get(i);
stack.add(child);
}
visited.set(cur.getIndex());
v.visitBlock(cur, null);
}
}
|
public void | forEachInsn(SsaInsn.Visitor visitor)Visits all insns in this method.
for (SsaBasicBlock block : blocks) {
block.forEachInsn(visitor);
}
|
public void | forEachPhiInsn(PhiInsn.Visitor v)Visits each phi insn in this method
for (SsaBasicBlock block : blocks) {
block.forEachPhiInsn(v);
}
|
public java.util.ArrayList | getBlocks()
return blocks;
|
public int | getCountReachableBlocks()Returns the count of reachable blocks in this method: blocks that have
predecessors (or are the start block)
int ret = 0;
for (SsaBasicBlock b : blocks) {
// Blocks that have been disconnected don't count.
if (b.isReachable()) {
ret++;
}
}
return ret;
|
public SsaInsn | getDefinitionForRegister(int reg)Returns the insn that defines the given register
if (backMode) {
throw new RuntimeException("No def list in back mode");
}
if (definitionList != null) {
return definitionList[reg];
}
definitionList = new SsaInsn[getRegCount()];
forEachInsn(new SsaInsn.Visitor() {
public void visitMoveInsn (NormalSsaInsn insn) {
definitionList[insn.getResult().getReg()] = insn;
}
public void visitPhiInsn (PhiInsn phi) {
definitionList[phi.getResult().getReg()] = phi;
}
public void visitNonMoveInsn (NormalSsaInsn insn) {
RegisterSpec result = insn.getResult();
if (result != null) {
definitionList[insn.getResult().getReg()] = insn;
}
}
});
return definitionList[reg];
|
public SsaBasicBlock | getEntryBlock()
return blocks.get(entryBlockIndex);
|
public int | getEntryBlockIndex()
return entryBlockIndex;
|
public SsaBasicBlock | getExitBlock()
return exitBlockIndex < 0 ? null : blocks.get(exitBlockIndex);
|
public int | getExitBlockIndex()
return exitBlockIndex;
|
private static SsaInsn | getGoto(SsaBasicBlock block)Gets a new {@code GOTO} insn.
return new NormalSsaInsn (
new PlainInsn(Rops.GOTO, SourcePosition.NO_INFO,
null, RegisterSpecList.EMPTY), block);
|
public int | getParamWidth()
return paramWidth;
|
public int | getRegCount()
return registerCount;
|
public java.util.ArrayList[] | getUseListCopy()Returns a modifiable copy of the register use list.
if (useList == null) {
buildUseList();
}
ArrayList<SsaInsn>[] useListCopy
= (ArrayList<SsaInsn>[])(new ArrayList[registerCount]);
for (int i = 0; i < registerCount; i++) {
useListCopy[i] = (ArrayList<SsaInsn>)(new ArrayList(useList[i]));
}
return useListCopy;
|
public java.util.List | getUseListForRegister(int reg)Returns the list of all source uses (not results) for a register.
if (unmodifiableUseList == null) {
buildUseList();
}
return unmodifiableUseList[reg];
|
public static com.android.dx.util.IntList | indexListFromLabelList(com.android.dx.rop.code.BasicBlockList ropBlocks, com.android.dx.util.IntList labelList)Builds an IntList of block indices from a basic block list and a list
of labels taken from Rop form.
IntList result = new IntList(labelList.size());
for (int i = 0, sz = labelList.size(); i < sz; i++) {
result.add(ropBlocks.indexOfLabel(labelList.get(i)));
}
return result;
|
public boolean | isRegALocal(com.android.dx.rop.code.RegisterSpec spec)Checks to see if the given SSA reg is ever associated with a local
local variable. Each SSA reg may be associated with at most one
local var.
SsaInsn defn = getDefinitionForRegister(spec.getReg());
if (defn == null) {
// version 0 registers are never used as locals
return false;
}
// Does the definition have a local associated with it?
if (defn.getLocalAssignment() != null) return true;
// If not, is there a mark-local insn?
for (SsaInsn use : getUseListForRegister(spec.getReg())) {
Insn insn = use.getOriginalRopInsn();
if (insn != null
&& insn.getOpcode().getOpcode() == RegOps.MARK_LOCAL) {
return true;
}
}
return false;
|
public boolean | isStatic()Returns {@code true} if this is a static method.
return isStatic;
|
void | makeExitBlock()Creates an exit block and attaches it to the CFG if this method
exits. Methods that never exit will not have an exit block. This
is called after edge-splitting and phi insertion, since the edges
going into the exit block should not be considered in those steps.
if (exitBlockIndex >= 0) {
throw new RuntimeException("must be called at most once");
}
exitBlockIndex = blocks.size();
SsaBasicBlock exitBlock
= new SsaBasicBlock(exitBlockIndex, maxLabel++, this);
blocks.add(exitBlock);
for (SsaBasicBlock block : blocks) {
block.exitBlockFixup(exitBlock);
}
if (exitBlock.getPredecessors().cardinality() == 0) {
// In cases where there is no exit...
blocks.remove(exitBlockIndex);
exitBlockIndex = -1;
maxLabel--;
}
|
public SsaBasicBlock | makeNewGotoBlock()Makes a new basic block for this method, which is empty besides
a single {@code GOTO}. Successors and predecessors are not yet
set.
int newIndex = blocks.size();
SsaBasicBlock newBlock = new SsaBasicBlock(newIndex, maxLabel++, this);
newBlock.getInsns().add(getGoto(newBlock));
blocks.add(newBlock);
return newBlock;
|
public int | makeNewSsaReg()Makes a new SSA register. For use after renaming has completed.
int reg = registerCount++;
spareRegisterBase = registerCount;
onInsnsChanged();
return reg;
|
public void | mapRegisters(RegisterMapper mapper)Remaps unversioned registers.
for (SsaBasicBlock block : getBlocks()) {
for (SsaInsn insn : block.getInsns()) {
insn.mapRegisters(mapper);
}
}
registerCount = mapper.getNewRegisterCount();
spareRegisterBase = registerCount;
|
public static com.android.dx.ssa.SsaMethod | newFromRopMethod(com.android.dx.rop.code.RopMethod ropMethod, int paramWidth, boolean isStatic)
SsaMethod result = new SsaMethod(ropMethod, paramWidth, isStatic);
result.convertRopToSsaBlocks(ropMethod);
return result;
|
void | onInsnAdded(SsaInsn insn)Adds an insn to both the use and def lists. For use when adding
a new insn to the method.
onSourcesChanged(insn, null);
updateOneDefinition(insn, null);
|
void | onInsnRemoved(SsaInsn insn)Removes an instruction from use and def lists. For use during
instruction removal.
if (useList != null) {
removeFromUseList(insn, insn.getSources());
}
RegisterSpec resultReg = insn.getResult();
if (definitionList != null && resultReg != null) {
definitionList[resultReg.getReg()] = null;
}
|
public void | onInsnsChanged()Indicates that the instruction list has changed or the SSA register
count has increased, so that internal datastructures that rely on
it should be rebuild. In general, the various other on* methods
should be called in preference when changes occur if they are
applicable.
// Definition list will need to be recomputed
definitionList = null;
// Use list will need to be recomputed
useList = null;
unmodifiableUseList = null;
|
void | onSourceChanged(SsaInsn insn, com.android.dx.rop.code.RegisterSpec oldSource, com.android.dx.rop.code.RegisterSpec newSource)Updates the use list for a single change in source register.
if (useList == null) return;
if (oldSource != null) {
int reg = oldSource.getReg();
useList[reg].remove(insn);
}
int reg = newSource.getReg();
if (useList.length <= reg) {
useList = null;
return;
}
useList[reg].add(insn);
|
void | onSourcesChanged(SsaInsn insn, com.android.dx.rop.code.RegisterSpecList oldSources)Updates the use list for a source list change.
if (useList == null) return;
if (oldSources != null) {
removeFromUseList(insn, oldSources);
}
RegisterSpecList sources = insn.getSources();
int szNew = sources.size();
for (int i = 0; i < szNew; i++) {
int reg = sources.get(i).getReg();
useList[reg].add(insn);
}
|
private void | removeFromUseList(SsaInsn insn, com.android.dx.rop.code.RegisterSpecList oldSources)Removes a given {@code insn} from the use lists for the given
{@code oldSources} (rather than the sources currently
returned by insn.getSources()).
if (oldSources == null) {
return;
}
int szNew = oldSources.size();
for (int i = 0; i < szNew; i++) {
if (!useList[oldSources.get(i).getReg()].remove(insn)) {
throw new RuntimeException("use not found");
}
}
|
public void | returnSpareRegisters()Returns all borrowed registers.
borrowedSpareRegisters = 0;
|
public void | setBackMode()Sets "back-convert mode". Set during back-conversion when registers
are about to be mapped into a non-SSA namespace. When true,
use and def lists are unavailable.
backMode = true;
useList = null;
definitionList = null;
|
void | setNewRegCount(int newRegCount)Sets the new register count after renaming.
registerCount = newRegCount;
spareRegisterBase = registerCount;
onInsnsChanged();
|
void | updateOneDefinition(SsaInsn insn, com.android.dx.rop.code.RegisterSpec oldResult)Updates a single definition.
if (definitionList == null) return;
if (oldResult != null) {
int reg = oldResult.getReg();
definitionList[reg] = null;
}
RegisterSpec resultReg = insn.getResult();
if (resultReg != null) {
int reg = resultReg.getReg();
if (definitionList[reg] != null) {
throw new RuntimeException("Duplicate add of insn");
} else {
definitionList[resultReg.getReg()] = insn;
}
}
|