use of com.android.dx.rop.type.TypeBearer in project buck by facebook.
the class ExecutionStack method change.
/**
* Changes an element already on a stack. This method is useful in limited
* contexts, particularly when merging two instances. As such, it places
* the following restriction on its behavior: You may only replace
* values with other values of the same category.
*
* @param n {@code >= 0;} which element to change, where {@code 0} is
* the top element of the stack
* @param type {@code non-null;} type of the new value
* @throws SimException thrown if {@code n >= size()} or
* the action is otherwise prohibited
*/
public void change(int n, TypeBearer type) {
throwIfImmutable();
try {
type = type.getFrameType();
} catch (NullPointerException ex) {
// Elucidate the exception.
throw new NullPointerException("type == null");
}
int idx = stackPtr - n - 1;
TypeBearer orig = stack[idx];
if ((orig == null) || (orig.getType().getCategory() != type.getType().getCategory())) {
throwSimException("incompatible substitution: " + stackElementString(orig) + " -> " + stackElementString(type));
}
stack[idx] = type;
}
use of com.android.dx.rop.type.TypeBearer in project buck by facebook.
the class Merger method mergeStack.
/**
* Merges two stacks. If the merged result is the same as the first
* argument, then return the first argument (not a copy).
*
* @param stack1 {@code non-null;} a stack
* @param stack2 {@code non-null;} another stack
* @return {@code non-null;} the result of merging the two stacks
*/
public static ExecutionStack mergeStack(ExecutionStack stack1, ExecutionStack stack2) {
if (stack1 == stack2) {
// Easy out.
return stack1;
}
int sz = stack1.size();
ExecutionStack result = null;
if (stack2.size() != sz) {
throw new SimException("mismatched stack depths");
}
for (int i = 0; i < sz; i++) {
TypeBearer tb1 = stack1.peek(i);
TypeBearer tb2 = stack2.peek(i);
TypeBearer resultType = mergeType(tb1, tb2);
if (resultType != tb1) {
/*
* We only need to do anything when the result differs
* from what is in the first stack, since that's what the
* result gets initialized to.
*/
if (result == null) {
result = stack1.copy();
}
try {
if (resultType == null) {
throw new SimException("incompatible: " + tb1 + ", " + tb2);
} else {
result.change(i, resultType);
}
} catch (SimException ex) {
ex.addContext("...while merging stack[" + Hex.u2(i) + "]");
throw ex;
}
}
}
if (result == null) {
return stack1;
}
result.setImmutable();
return result;
}
use of com.android.dx.rop.type.TypeBearer in project buck by facebook.
the class EscapeAnalysis method replaceUse.
/**
* Replaces the use for a scalar replaceable array. Gets and puts become
* move instructions, and array lengths and fills are handled. Can also
* identify ArrayIndexOutOfBounds exceptions and throw them if detected.
*
* @param use {@code non-null;} move result instruction for array
* @param prev {@code non-null;} instruction for instantiating new array
* @param newRegs {@code non-null;} mapping of array indices to new
* registers
* @param deletedInsns {@code non-null;} set of instructions marked for
* deletion
*/
private void replaceUse(SsaInsn use, SsaInsn prev, ArrayList<RegisterSpec> newRegs, HashSet<SsaInsn> deletedInsns) {
int index;
int length = newRegs.size();
SsaInsn next;
RegisterSpecList sources;
RegisterSpec source, result;
CstLiteralBits indexReg;
switch(use.getOpcode().getOpcode()) {
case RegOps.AGET:
// Replace array gets with moves
next = getMoveForInsn(use);
sources = use.getSources();
indexReg = ((CstLiteralBits) sources.get(1).getTypeBearer());
index = indexReg.getIntBits();
if (index < length) {
source = newRegs.get(index);
result = source.withReg(next.getResult().getReg());
insertPlainInsnBefore(next, RegisterSpecList.make(source), result, RegOps.MOVE, null);
} else {
// Throw an exception if the index is out of bounds
insertExceptionThrow(next, sources.get(1), deletedInsns);
deletedInsns.add(next.getBlock().getInsns().get(2));
}
deletedInsns.add(next);
break;
case RegOps.APUT:
// Replace array puts with moves
sources = use.getSources();
indexReg = ((CstLiteralBits) sources.get(2).getTypeBearer());
index = indexReg.getIntBits();
if (index < length) {
source = sources.get(0);
result = source.withReg(newRegs.get(index).getReg());
insertPlainInsnBefore(use, RegisterSpecList.make(source), result, RegOps.MOVE, null);
// Update the newReg entry to mark value as unknown now
newRegs.set(index, result.withSimpleType());
} else {
// Throw an exception if the index is out of bounds
insertExceptionThrow(use, sources.get(2), deletedInsns);
}
break;
case RegOps.ARRAY_LENGTH:
// Replace array lengths with const instructions
TypeBearer lengthReg = prev.getSources().get(0).getTypeBearer();
//CstInteger lengthReg = CstInteger.make(length);
next = getMoveForInsn(use);
insertPlainInsnBefore(next, RegisterSpecList.EMPTY, next.getResult(), RegOps.CONST, (Constant) lengthReg);
deletedInsns.add(next);
break;
case RegOps.MARK_LOCAL:
// Remove mark local instructions
break;
case RegOps.FILL_ARRAY_DATA:
// Create const instructions for each fill value
Insn ropUse = use.getOriginalRopInsn();
FillArrayDataInsn fill = (FillArrayDataInsn) ropUse;
ArrayList<Constant> constList = fill.getInitValues();
for (int i = 0; i < length; i++) {
RegisterSpec newFill = RegisterSpec.make(newRegs.get(i).getReg(), (TypeBearer) constList.get(i));
insertPlainInsnBefore(use, RegisterSpecList.EMPTY, newFill, RegOps.CONST, constList.get(i));
// Update the newRegs to hold the new const value
newRegs.set(i, newFill);
}
break;
default:
}
}
use of com.android.dx.rop.type.TypeBearer in project buck by facebook.
the class PlainInsn method withSourceLiteral.
/** {@inheritDoc} */
@Override
public Insn withSourceLiteral() {
RegisterSpecList sources = getSources();
int szSources = sources.size();
if (szSources == 0) {
return this;
}
TypeBearer lastType = sources.get(szSources - 1).getTypeBearer();
if (!lastType.isConstant()) {
// Check for reverse subtraction, where first source is constant
TypeBearer firstType = sources.get(0).getTypeBearer();
if (szSources == 2 && firstType.isConstant()) {
Constant cst = (Constant) firstType;
RegisterSpecList newSources = sources.withoutFirst();
Rop newRop = Rops.ropFor(getOpcode().getOpcode(), getResult(), newSources, cst);
return new PlainCstInsn(newRop, getPosition(), getResult(), newSources, cst);
}
return this;
} else {
Constant cst = (Constant) lastType;
RegisterSpecList newSources = sources.withoutLast();
Rop newRop;
try {
// Check for constant subtraction and flip it to be addition
int opcode = getOpcode().getOpcode();
if (opcode == RegOps.SUB && cst instanceof CstInteger) {
opcode = RegOps.ADD;
cst = CstInteger.make(-((CstInteger) cst).getValue());
}
newRop = Rops.ropFor(opcode, getResult(), newSources, cst);
} catch (IllegalArgumentException ex) {
// There's no rop for this case
return this;
}
return new PlainCstInsn(newRop, getPosition(), getResult(), newSources, cst);
}
}
use of com.android.dx.rop.type.TypeBearer in project buck by facebook.
the class RegisterSpec method intersect.
/**
* Returns an instance that is the intersection between this instance
* and the given one, if any. The intersection is defined as follows:
*
* <ul>
* <li>If {@code other} is {@code null}, then the result
* is {@code null}.
* <li>If the register numbers don't match, then the intersection
* is {@code null}. Otherwise, the register number of the
* intersection is the same as the one in the two instances.</li>
* <li>If the types returned by {@code getType()} are not
* {@code equals()}, then the intersection is null.</li>
* <li>If the type bearers returned by {@code getTypeBearer()}
* are {@code equals()}, then the intersection's type bearer
* is the one from this instance. Otherwise, the intersection's
* type bearer is the {@code getType()} of this instance.</li>
* <li>If the locals are {@code equals()}, then the local info
* of the intersection is the local info of this instance. Otherwise,
* the local info of the intersection is {@code null}.</li>
* </ul>
*
* @param other {@code null-ok;} instance to intersect with (or {@code null})
* @param localPrimary whether local variables are primary to the
* intersection; if {@code true}, then the only non-null
* results occur when registers being intersected have equal local
* infos (or both have {@code null} local infos)
* @return {@code null-ok;} the intersection
*/
public RegisterSpec intersect(RegisterSpec other, boolean localPrimary) {
if (this == other) {
// Easy out.
return this;
}
if ((other == null) || (reg != other.getReg())) {
return null;
}
LocalItem resultLocal = ((local == null) || !local.equals(other.getLocalItem())) ? null : local;
boolean sameName = (resultLocal == local);
if (localPrimary && !sameName) {
return null;
}
Type thisType = getType();
Type otherType = other.getType();
// Note: Types are always interned.
if (thisType != otherType) {
return null;
}
TypeBearer resultTypeBearer = type.equals(other.getTypeBearer()) ? type : thisType;
if ((resultTypeBearer == type) && sameName) {
// It turns out that the intersection is "this" after all.
return this;
}
return (resultLocal == null) ? make(reg, resultTypeBearer) : make(reg, resultTypeBearer, resultLocal);
}
Aggregations