use of com.taobao.android.dx.rop.code.RegisterSpec in project atlas by alibaba.
the class DeadCodeRemover method run.
/**
* Runs the dead code remover.
*/
private void run() {
pruneDeadInstructions();
HashSet<SsaInsn> deletedInsns = new HashSet<SsaInsn>();
ssaMeth.forEachInsn(new NoSideEffectVisitor(worklist));
int regV;
while (0 <= (regV = worklist.nextSetBit(0))) {
worklist.clear(regV);
if (useList[regV].size() == 0 || isCircularNoSideEffect(regV, null)) {
SsaInsn insnS = ssaMeth.getDefinitionForRegister(regV);
// This insn has already been deleted.
if (deletedInsns.contains(insnS)) {
continue;
}
RegisterSpecList sources = insnS.getSources();
int sz = sources.size();
for (int i = 0; i < sz; i++) {
// Delete this insn from all usage lists.
RegisterSpec source = sources.get(i);
useList[source.getReg()].remove(insnS);
if (!hasSideEffect(ssaMeth.getDefinitionForRegister(source.getReg()))) {
/*
* Only registers whose definition has no side effect
* should be added back to the worklist.
*/
worklist.set(source.getReg());
}
}
// Schedule this insn for later deletion.
deletedInsns.add(insnS);
}
}
ssaMeth.deleteInsns(deletedInsns);
}
use of com.taobao.android.dx.rop.code.RegisterSpec in project atlas by alibaba.
the class EscapeAnalysis method replaceDef.
/**
* Replaces the instructions that define an array with equivalent registers.
* For each entry in the array, a register is created, initialized to zero.
* A mapping between this register and the corresponding array index is
* added.
*
* @param def {@code non-null;} move result instruction for array
* @param prev {@code non-null;} instruction for instantiating new array
* @param length size of the new array
* @param newRegs {@code non-null;} mapping of array indices to new
* registers to be populated
*/
private void replaceDef(SsaInsn def, SsaInsn prev, int length, ArrayList<RegisterSpec> newRegs) {
Type resultType = def.getResult().getType();
// Create new zeroed out registers for each element in the array
for (int i = 0; i < length; i++) {
Constant newZero = Zeroes.zeroFor(resultType.getComponentType());
TypedConstant typedZero = (TypedConstant) newZero;
RegisterSpec newReg = RegisterSpec.make(ssaMeth.makeNewSsaReg(), typedZero);
newRegs.add(newReg);
insertPlainInsnBefore(def, RegisterSpecList.EMPTY, newReg, RegOps.CONST, newZero);
}
}
use of com.taobao.android.dx.rop.code.RegisterSpec in project atlas by alibaba.
the class EscapeAnalysis method movePropagate.
/**
* Identifies extra moves added by scalar replacement and propagates the
* source of the move to any users of the result.
*/
private void movePropagate() {
for (int i = 0; i < ssaMeth.getRegCount(); i++) {
SsaInsn insn = ssaMeth.getDefinitionForRegister(i);
// Look for move instructions only
if (insn == null || insn.getOpcode() == null || insn.getOpcode().getOpcode() != RegOps.MOVE) {
continue;
}
final ArrayList<SsaInsn>[] useList = ssaMeth.getUseListCopy();
final RegisterSpec source = insn.getSources().get(0);
final RegisterSpec result = insn.getResult();
// Ignore moves that weren't added due to scalar replacement
if (source.getReg() < regCount && result.getReg() < regCount) {
continue;
}
// Create a mapping from source to result
RegisterMapper mapper = new RegisterMapper() {
@Override
public int getNewRegisterCount() {
return ssaMeth.getRegCount();
}
@Override
public RegisterSpec map(RegisterSpec registerSpec) {
if (registerSpec.getReg() == result.getReg()) {
return source;
}
return registerSpec;
}
};
// Modify all uses of the move to use the source of the move instead
for (SsaInsn use : useList[result.getReg()]) {
use.mapSourceRegisters(mapper);
}
}
}
use of com.taobao.android.dx.rop.code.RegisterSpec in project atlas by alibaba.
the class EscapeAnalysis method processRegister.
/**
* Iterate through all the uses of a new object.
*
* @param result {@code non-null;} register where new object is stored
* @param escSet {@code non-null;} EscapeSet for the new object
*/
private void processRegister(RegisterSpec result, EscapeSet escSet) {
ArrayList<RegisterSpec> regWorklist = new ArrayList<RegisterSpec>();
regWorklist.add(result);
// Go through the worklist
while (!regWorklist.isEmpty()) {
int listSize = regWorklist.size() - 1;
RegisterSpec def = regWorklist.remove(listSize);
List<SsaInsn> useList = ssaMeth.getUseListForRegister(def.getReg());
// Handle all the uses of this register
for (SsaInsn use : useList) {
Rop useOpcode = use.getOpcode();
if (useOpcode == null) {
// Handle phis
processPhiUse(use, escSet, regWorklist);
} else {
// Handle other opcodes
processUse(def, use, escSet, regWorklist);
}
}
}
}
use of com.taobao.android.dx.rop.code.RegisterSpec in project atlas by alibaba.
the class EscapeAnalysis method processUse.
/**
* Handles non-phi uses of new objects. Checks to see how instruction is
* used and updates the escape state accordingly.
*
* @param def {@code non-null;} register holding definition of new object
* @param use {@code non-null;} use of object being processed
* @param escSet {@code non-null;} EscapeSet for the object
* @param regWorklist {@code non-null;} worklist of instructions left to
* process for this object
*/
private void processUse(RegisterSpec def, SsaInsn use, EscapeSet escSet, ArrayList<RegisterSpec> regWorklist) {
int useOpcode = use.getOpcode().getOpcode();
switch(useOpcode) {
case RegOps.MOVE:
// Follow uses of the move by adding it to the worklist
escSet.regSet.set(use.getResult().getReg());
regWorklist.add(use.getResult());
break;
case RegOps.IF_EQ:
case RegOps.IF_NE:
case RegOps.CHECK_CAST:
// Compared objects can't be replaced, so promote if necessary
if (escSet.escape.compareTo(EscapeState.METHOD) < 0) {
escSet.escape = EscapeState.METHOD;
}
break;
case RegOps.APUT:
// For array puts, check for a constant array index
RegisterSpec putIndex = use.getSources().get(2);
if (!putIndex.getTypeBearer().isConstant()) {
// If not constant, array can't be replaced
escSet.replaceableArray = false;
}
// Intentional fallthrough
case RegOps.PUT_FIELD:
// Skip non-object puts
RegisterSpec putValue = use.getSources().get(0);
if (putValue.getTypeBearer().getBasicType() != Type.BT_OBJECT) {
break;
}
escSet.replaceableArray = false;
// Raise 1st object's escape state to 2nd if 2nd is higher
RegisterSpecList sources = use.getSources();
if (sources.get(0).getReg() == def.getReg()) {
int setIndex = findSetIndex(sources.get(1));
if (setIndex != latticeValues.size()) {
EscapeSet parentSet = latticeValues.get(setIndex);
addEdge(parentSet, escSet);
if (escSet.escape.compareTo(parentSet.escape) < 0) {
escSet.escape = parentSet.escape;
}
}
} else {
int setIndex = findSetIndex(sources.get(0));
if (setIndex != latticeValues.size()) {
EscapeSet childSet = latticeValues.get(setIndex);
addEdge(escSet, childSet);
if (childSet.escape.compareTo(escSet.escape) < 0) {
childSet.escape = escSet.escape;
}
}
}
break;
case RegOps.AGET:
// For array gets, check for a constant array index
RegisterSpec getIndex = use.getSources().get(1);
if (!getIndex.getTypeBearer().isConstant()) {
// If not constant, array can't be replaced
escSet.replaceableArray = false;
}
break;
case RegOps.PUT_STATIC:
// Static puts cause an object to escape globally
escSet.escape = EscapeState.GLOBAL;
break;
case RegOps.INVOKE_STATIC:
case RegOps.INVOKE_VIRTUAL:
case RegOps.INVOKE_SUPER:
case RegOps.INVOKE_DIRECT:
case RegOps.INVOKE_INTERFACE:
case RegOps.RETURN:
case RegOps.THROW:
// These operations cause an object to escape interprocedurally
escSet.escape = EscapeState.INTER;
break;
default:
break;
}
}
Aggregations