use of com.android.dx.rop.code.RegisterSpec in project buck by facebook.
the class Ropper method addSetupBlocks.
/**
* Constructs and adds the blocks that perform setup for the rest of
* the method. This includes a first block which merely contains
* assignments from parameters to the same-numbered registers and
* a possible second block which deals with synchronization.
*/
private void addSetupBlocks() {
LocalVariableList localVariables = method.getLocalVariables();
SourcePosition pos = method.makeSourcePosistion(0);
Prototype desc = method.getEffectiveDescriptor();
StdTypeList params = desc.getParameterTypes();
int sz = params.size();
InsnList insns = new InsnList(sz + 1);
int at = 0;
for (int i = 0; i < sz; i++) {
Type one = params.get(i);
LocalVariableList.Item local = localVariables.pcAndIndexToLocal(0, at);
RegisterSpec result = (local == null) ? RegisterSpec.make(at, one) : RegisterSpec.makeLocalOptional(at, one, local.getLocalItem());
Insn insn = new PlainCstInsn(Rops.opMoveParam(one), pos, result, RegisterSpecList.EMPTY, CstInteger.make(at));
insns.set(i, insn);
at += one.getCategory();
}
insns.set(sz, new PlainInsn(Rops.GOTO, pos, null, RegisterSpecList.EMPTY));
insns.setImmutable();
boolean synch = isSynchronized();
int label = synch ? getSpecialLabel(SYNCH_SETUP_1) : 0;
BasicBlock bb = new BasicBlock(getSpecialLabel(PARAM_ASSIGNMENT), insns, IntList.makeImmutable(label), label);
addBlock(bb, IntList.EMPTY);
if (synch) {
RegisterSpec synchReg = getSynchReg();
Insn insn;
if (isStatic()) {
insn = new ThrowingCstInsn(Rops.CONST_OBJECT, pos, RegisterSpecList.EMPTY, StdTypeList.EMPTY, method.getDefiningClass());
insns = new InsnList(1);
insns.set(0, insn);
} else {
insns = new InsnList(2);
insn = new PlainCstInsn(Rops.MOVE_PARAM_OBJECT, pos, synchReg, RegisterSpecList.EMPTY, CstInteger.VALUE_0);
insns.set(0, insn);
insns.set(1, new PlainInsn(Rops.GOTO, pos, null, RegisterSpecList.EMPTY));
}
int label2 = getSpecialLabel(SYNCH_SETUP_2);
insns.setImmutable();
bb = new BasicBlock(label, insns, IntList.makeImmutable(label2), label2);
addBlock(bb, IntList.EMPTY);
insns = new InsnList(isStatic() ? 2 : 1);
if (isStatic()) {
insns.set(0, new PlainInsn(Rops.opMoveResultPseudo(synchReg), pos, synchReg, RegisterSpecList.EMPTY));
}
insn = new ThrowingInsn(Rops.MONITOR_ENTER, pos, RegisterSpecList.make(synchReg), StdTypeList.EMPTY);
insns.set(isStatic() ? 1 : 0, insn);
insns.setImmutable();
bb = new BasicBlock(label2, insns, IntList.makeImmutable(0), 0);
addBlock(bb, IntList.EMPTY);
}
}
use of com.android.dx.rop.code.RegisterSpec in project buck by facebook.
the class Ropper method addSynchExceptionHandlerBlock.
/**
* Constructs and adds, if necessary, the catch-all exception handler
* block to deal with unwinding the lock taken on entry to a synchronized
* method.
*/
private void addSynchExceptionHandlerBlock() {
if (!synchNeedsExceptionHandler) {
/*
* The method being converted either isn't synchronized or
* can't possibly throw exceptions in its main body, so
* there's no need for a synchronized method exception
* handler.
*/
return;
}
SourcePosition pos = method.makeSourcePosistion(0);
RegisterSpec exReg = RegisterSpec.make(0, Type.THROWABLE);
BasicBlock bb;
Insn insn;
InsnList insns = new InsnList(2);
insn = new PlainInsn(Rops.opMoveException(Type.THROWABLE), pos, exReg, RegisterSpecList.EMPTY);
insns.set(0, insn);
insn = new ThrowingInsn(Rops.MONITOR_EXIT, pos, RegisterSpecList.make(getSynchReg()), StdTypeList.EMPTY);
insns.set(1, insn);
insns.setImmutable();
int label2 = getSpecialLabel(SYNCH_CATCH_2);
bb = new BasicBlock(getSpecialLabel(SYNCH_CATCH_1), insns, IntList.makeImmutable(label2), label2);
addBlock(bb, IntList.EMPTY);
insns = new InsnList(1);
insn = new ThrowingInsn(Rops.THROW, pos, RegisterSpecList.make(exReg), StdTypeList.EMPTY);
insns.set(0, insn);
insns.setImmutable();
bb = new BasicBlock(label2, insns, IntList.EMPTY, -1);
addBlock(bb, IntList.EMPTY);
}
use of com.android.dx.rop.code.RegisterSpec in project buck by facebook.
the class RegisterAllocator method insertMoveBefore.
/**
* Inserts a move instruction for a specified SSA register before a
* specified instruction, creating a new SSA register and adjusting the
* interference graph in the process. The insn currently must be the
* last insn in a block.
*
* @param insn {@code non-null;} insn to insert move before, must
* be last insn in block
* @param reg {@code non-null;} SSA register to duplicate
* @return {@code non-null;} spec of new SSA register created by move
*/
protected final RegisterSpec insertMoveBefore(SsaInsn insn, RegisterSpec reg) {
SsaBasicBlock block = insn.getBlock();
ArrayList<SsaInsn> insns = block.getInsns();
int insnIndex = insns.indexOf(insn);
if (insnIndex < 0) {
throw new IllegalArgumentException("specified insn is not in this block");
}
if (insnIndex != insns.size() - 1) {
/*
* Presently, the interference updater only works when
* adding before the last insn, and the last insn must have no
* result
*/
throw new IllegalArgumentException("Adding move here not supported:" + insn.toHuman());
}
/*
* Get new register and make new move instruction.
*/
// The new result must not have an associated local variable.
RegisterSpec newRegSpec = RegisterSpec.make(ssaMeth.makeNewSsaReg(), reg.getTypeBearer());
SsaInsn toAdd = SsaInsn.makeFromRop(new PlainInsn(Rops.opMove(newRegSpec.getType()), SourcePosition.NO_INFO, newRegSpec, RegisterSpecList.make(reg)), block);
insns.add(insnIndex, toAdd);
int newReg = newRegSpec.getReg();
/*
* Adjust interference graph based on what's live out of the current
* block and what's used by the final instruction.
*/
IntSet liveOut = block.getLiveOutRegs();
IntIterator liveOutIter = liveOut.iterator();
while (liveOutIter.hasNext()) {
interference.add(newReg, liveOutIter.next());
}
// Everything that's a source in the last insn interferes.
RegisterSpecList sources = insn.getSources();
int szSources = sources.size();
for (int i = 0; i < szSources; i++) {
interference.add(newReg, sources.get(i).getReg());
}
ssaMeth.onInsnsChanged();
return newRegSpec;
}
use of com.android.dx.rop.code.RegisterSpec in project buck by facebook.
the class SsaConverter method placePhiFunctions.
/**
* See Appel algorithm 19.6:
*
* Place Phi functions in appropriate locations.
*
* @param ssaMeth {@code non-null;} method to process.
* Modifications are made in-place.
* @param localInfo {@code non-null;} local variable info, used
* when placing phis
* @param threshold registers below this number are ignored
*/
private static void placePhiFunctions(SsaMethod ssaMeth, LocalVariableInfo localInfo, int threshold) {
ArrayList<SsaBasicBlock> ssaBlocks;
int regCount;
int blockCount;
ssaBlocks = ssaMeth.getBlocks();
blockCount = ssaBlocks.size();
regCount = ssaMeth.getRegCount() - threshold;
DomFront df = new DomFront(ssaMeth);
DomFront.DomInfo[] domInfos = df.run();
// Bit set of registers vs block index "definition sites"
BitSet[] defsites = new BitSet[regCount];
// Bit set of registers vs block index "phi placement sites"
BitSet[] phisites = new BitSet[regCount];
for (int i = 0; i < regCount; i++) {
defsites[i] = new BitSet(blockCount);
phisites[i] = new BitSet(blockCount);
}
/*
* For each register, build a set of all basic blocks where
* containing an assignment to that register.
*/
for (int bi = 0, s = ssaBlocks.size(); bi < s; bi++) {
SsaBasicBlock b = ssaBlocks.get(bi);
for (SsaInsn insn : b.getInsns()) {
RegisterSpec rs = insn.getResult();
if (rs != null && rs.getReg() - threshold >= 0) {
defsites[rs.getReg() - threshold].set(bi);
}
}
}
if (DEBUG) {
System.out.println("defsites");
for (int i = 0; i < regCount; i++) {
StringBuilder sb = new StringBuilder();
sb.append('v').append(i).append(": ");
sb.append(defsites[i].toString());
System.out.println(sb);
}
}
BitSet worklist;
/*
* For each register, compute all locations for phi placement
* based on dominance-frontier algorithm.
*/
for (int reg = 0, s = regCount; reg < s; reg++) {
int workBlockIndex;
/* Worklist set starts out with each node where reg is assigned. */
worklist = (BitSet) (defsites[reg].clone());
while (0 <= (workBlockIndex = worklist.nextSetBit(0))) {
worklist.clear(workBlockIndex);
IntIterator dfIterator = domInfos[workBlockIndex].dominanceFrontiers.iterator();
while (dfIterator.hasNext()) {
int dfBlockIndex = dfIterator.next();
if (!phisites[reg].get(dfBlockIndex)) {
phisites[reg].set(dfBlockIndex);
int tReg = reg + threshold;
RegisterSpec rs = localInfo.getStarts(dfBlockIndex).get(tReg);
if (rs == null) {
ssaBlocks.get(dfBlockIndex).addPhiInsnForReg(tReg);
} else {
ssaBlocks.get(dfBlockIndex).addPhiInsnForReg(rs);
}
if (!defsites[reg].get(dfBlockIndex)) {
worklist.set(dfBlockIndex);
}
}
}
}
}
if (DEBUG) {
System.out.println("phisites");
for (int i = 0; i < regCount; i++) {
StringBuilder sb = new StringBuilder();
sb.append('v').append(i).append(": ");
sb.append(phisites[i].toString());
System.out.println(sb);
}
}
}
use of com.android.dx.rop.code.RegisterSpec in project buck by facebook.
the class SsaMethod method updateOneDefinition.
/**
* Updates a single definition.
*
* @param insn {@code non-null;} insn who's result should be recorded as
* a definition
* @param oldResult {@code null-ok;} a previous result that should
* be no longer considered a definition by this insn
*/
/*package*/
void updateOneDefinition(SsaInsn insn, RegisterSpec oldResult) {
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;
}
}
}
Aggregations