use of com.android.dx.rop.cst.CstInteger in project buck by facebook.
the class BytecodeArray method parseNewarray.
/**
* Helper to deal with {@code newarray}.
*
* @param offset the offset to the {@code newarray} opcode itself
* @param visitor {@code non-null;} visitor to use
* @return instruction length, in bytes
*/
private int parseNewarray(int offset, Visitor visitor) {
int value = bytes.getUnsignedByte(offset + 1);
CstType type;
switch(value) {
case ByteOps.NEWARRAY_BOOLEAN:
{
type = CstType.BOOLEAN_ARRAY;
break;
}
case ByteOps.NEWARRAY_CHAR:
{
type = CstType.CHAR_ARRAY;
break;
}
case ByteOps.NEWARRAY_DOUBLE:
{
type = CstType.DOUBLE_ARRAY;
break;
}
case ByteOps.NEWARRAY_FLOAT:
{
type = CstType.FLOAT_ARRAY;
break;
}
case ByteOps.NEWARRAY_BYTE:
{
type = CstType.BYTE_ARRAY;
break;
}
case ByteOps.NEWARRAY_SHORT:
{
type = CstType.SHORT_ARRAY;
break;
}
case ByteOps.NEWARRAY_INT:
{
type = CstType.INT_ARRAY;
break;
}
case ByteOps.NEWARRAY_LONG:
{
type = CstType.LONG_ARRAY;
break;
}
default:
{
throw new SimException("bad newarray code " + Hex.u1(value));
}
}
// Revisit the previous bytecode to find out the length of the array
int previousOffset = visitor.getPreviousOffset();
ConstantParserVisitor constantVisitor = new ConstantParserVisitor();
int arrayLength = 0;
/*
* For visitors that don't record the previous offset, -1 will be
* seen here
*/
if (previousOffset >= 0) {
parseInstruction(previousOffset, constantVisitor);
if (constantVisitor.cst instanceof CstInteger && constantVisitor.length + previousOffset == offset) {
arrayLength = constantVisitor.value;
}
}
/*
* Try to match the array initialization idiom. For example, if the
* subsequent code is initializing an int array, we are expecting the
* following pattern repeatedly:
* dup
* push index
* push value
* *astore
*
* where the index value will be incrimented sequentially from 0 up.
*/
int nInit = 0;
int curOffset = offset + 2;
int lastOffset = curOffset;
ArrayList<Constant> initVals = new ArrayList<Constant>();
if (arrayLength != 0) {
while (true) {
boolean punt = false;
// First, check if the next bytecode is dup.
int nextByte = bytes.getUnsignedByte(curOffset++);
if (nextByte != ByteOps.DUP)
break;
/*
* Next, check if the expected array index is pushed to
* the stack.
*/
parseInstruction(curOffset, constantVisitor);
if (constantVisitor.length == 0 || !(constantVisitor.cst instanceof CstInteger) || constantVisitor.value != nInit)
break;
// Next, fetch the init value and record it.
curOffset += constantVisitor.length;
/*
* Next, find out what kind of constant is pushed onto
* the stack.
*/
parseInstruction(curOffset, constantVisitor);
if (constantVisitor.length == 0 || !(constantVisitor.cst instanceof CstLiteralBits))
break;
curOffset += constantVisitor.length;
initVals.add(constantVisitor.cst);
nextByte = bytes.getUnsignedByte(curOffset++);
// Now, check if the value is stored to the array properly.
switch(value) {
case ByteOps.NEWARRAY_BYTE:
case ByteOps.NEWARRAY_BOOLEAN:
{
if (nextByte != ByteOps.BASTORE) {
punt = true;
}
break;
}
case ByteOps.NEWARRAY_CHAR:
{
if (nextByte != ByteOps.CASTORE) {
punt = true;
}
break;
}
case ByteOps.NEWARRAY_DOUBLE:
{
if (nextByte != ByteOps.DASTORE) {
punt = true;
}
break;
}
case ByteOps.NEWARRAY_FLOAT:
{
if (nextByte != ByteOps.FASTORE) {
punt = true;
}
break;
}
case ByteOps.NEWARRAY_SHORT:
{
if (nextByte != ByteOps.SASTORE) {
punt = true;
}
break;
}
case ByteOps.NEWARRAY_INT:
{
if (nextByte != ByteOps.IASTORE) {
punt = true;
}
break;
}
case ByteOps.NEWARRAY_LONG:
{
if (nextByte != ByteOps.LASTORE) {
punt = true;
}
break;
}
default:
punt = true;
break;
}
if (punt) {
break;
}
lastOffset = curOffset;
nInit++;
}
}
/*
* For singleton arrays it is still more economical to
* generate the aput.
*/
if (nInit < 2 || nInit != arrayLength) {
visitor.visitNewarray(offset, 2, type, null);
return 2;
} else {
visitor.visitNewarray(offset, lastOffset - offset, type, initVals);
return lastOffset - offset;
}
}
use of com.android.dx.rop.cst.CstInteger in project buck by facebook.
the class FirstFitLocalCombiningAllocator method getParameterIndexForReg.
/**
* Gets the parameter index for SSA registers that are method parameters.
* {@code -1} is returned for non-parameter registers.
*
* @param ssaReg {@code >=0;} SSA register to look up
* @return parameter index or {@code -1} if not a parameter
*/
private int getParameterIndexForReg(int ssaReg) {
SsaInsn defInsn = ssaMeth.getDefinitionForRegister(ssaReg);
if (defInsn == null) {
return -1;
}
Rop opcode = defInsn.getOpcode();
// opcode == null for phi insns.
if (opcode != null && opcode.getOpcode() == RegOps.MOVE_PARAM) {
CstInsn origInsn = (CstInsn) defInsn.getOriginalRopInsn();
return ((CstInteger) origInsn.getConstant()).getValue();
}
return -1;
}
use of com.android.dx.rop.cst.CstInteger in project buck by facebook.
the class RopperMachine method run.
/** {@inheritDoc} */
@Override
public void run(Frame frame, int offset, int opcode) {
/*
* This is the stack pointer after the opcode's arguments have been
* popped.
*/
int stackPointer = maxLocals + frame.getStack().size();
// The sources have to be retrieved before super.run() gets called.
RegisterSpecList sources = getSources(opcode, stackPointer);
int sourceCount = sources.size();
super.run(frame, offset, opcode);
SourcePosition pos = method.makeSourcePosistion(offset);
RegisterSpec localTarget = getLocalTarget(opcode == ByteOps.ISTORE);
int destCount = resultCount();
RegisterSpec dest;
if (destCount == 0) {
dest = null;
switch(opcode) {
case ByteOps.POP:
case ByteOps.POP2:
{
// These simply don't appear in the rop form.
return;
}
}
} else if (localTarget != null) {
dest = localTarget;
} else if (destCount == 1) {
dest = RegisterSpec.make(stackPointer, result(0));
} else {
/*
* This clause only ever applies to the stack manipulation
* ops that have results (that is, dup* and swap but not
* pop*).
*
* What we do is first move all the source registers into
* the "temporary stack" area defined for the method, and
* then move stuff back down onto the main "stack" in the
* arrangement specified by the stack op pattern.
*
* Note: This code ends up emitting a lot of what will
* turn out to be superfluous moves (e.g., moving back and
* forth to the same local when doing a dup); however,
* that makes this code a bit easier (and goodness knows
* it doesn't need any extra complexity), and all the SSA
* stuff is going to want to deal with this sort of
* superfluous assignment anyway, so it should be a wash
* in the end.
*/
int scratchAt = ropper.getFirstTempStackReg();
RegisterSpec[] scratchRegs = new RegisterSpec[sourceCount];
for (int i = 0; i < sourceCount; i++) {
RegisterSpec src = sources.get(i);
TypeBearer type = src.getTypeBearer();
RegisterSpec scratch = src.withReg(scratchAt);
insns.add(new PlainInsn(Rops.opMove(type), pos, scratch, src));
scratchRegs[i] = scratch;
scratchAt += src.getCategory();
}
for (int pattern = getAuxInt(); pattern != 0; pattern >>= 4) {
int which = (pattern & 0x0f) - 1;
RegisterSpec scratch = scratchRegs[which];
TypeBearer type = scratch.getTypeBearer();
insns.add(new PlainInsn(Rops.opMove(type), pos, scratch.withReg(stackPointer), scratch));
stackPointer += type.getType().getCategory();
}
return;
}
TypeBearer destType = (dest != null) ? dest : Type.VOID;
Constant cst = getAuxCst();
int ropOpcode;
Rop rop;
Insn insn;
if (opcode == ByteOps.MULTIANEWARRAY) {
blockCanThrow = true;
// Add the extra instructions for handling multianewarray.
extraBlockCount = 6;
/*
* Add an array constructor for the int[] containing all the
* dimensions.
*/
RegisterSpec dimsReg = RegisterSpec.make(dest.getNextReg(), Type.INT_ARRAY);
rop = Rops.opFilledNewArray(Type.INT_ARRAY, sourceCount);
insn = new ThrowingCstInsn(rop, pos, sources, catches, CstType.INT_ARRAY);
insns.add(insn);
// Add a move-result for the new-filled-array
rop = Rops.opMoveResult(Type.INT_ARRAY);
insn = new PlainInsn(rop, pos, dimsReg, RegisterSpecList.EMPTY);
insns.add(insn);
/*
* Add a const-class instruction for the specified array
* class.
*/
/*
* Remove as many dimensions from the originally specified
* class as are given in the explicit list of dimensions,
* so as to pass the right component class to the standard
* Java library array constructor.
*/
Type componentType = ((CstType) cst).getClassType();
for (int i = 0; i < sourceCount; i++) {
componentType = componentType.getComponentType();
}
RegisterSpec classReg = RegisterSpec.make(dest.getReg(), Type.CLASS);
if (componentType.isPrimitive()) {
/*
* The component type is primitive (e.g., int as opposed
* to Integer), so we have to fetch the corresponding
* TYPE class.
*/
CstFieldRef typeField = CstFieldRef.forPrimitiveType(componentType);
insn = new ThrowingCstInsn(Rops.GET_STATIC_OBJECT, pos, RegisterSpecList.EMPTY, catches, typeField);
} else {
/*
* The component type is an object type, so just make a
* normal class reference.
*/
insn = new ThrowingCstInsn(Rops.CONST_OBJECT, pos, RegisterSpecList.EMPTY, catches, new CstType(componentType));
}
insns.add(insn);
// Add a move-result-pseudo for the get-static or const
rop = Rops.opMoveResultPseudo(classReg.getType());
insn = new PlainInsn(rop, pos, classReg, RegisterSpecList.EMPTY);
insns.add(insn);
/*
* Add a call to the "multianewarray method," that is,
* Array.newInstance(class, dims). Note: The result type
* of newInstance() is Object, which is why the last
* instruction in this sequence is a cast to the right
* type for the original instruction.
*/
RegisterSpec objectReg = RegisterSpec.make(dest.getReg(), Type.OBJECT);
insn = new ThrowingCstInsn(Rops.opInvokeStatic(MULTIANEWARRAY_METHOD.getPrototype()), pos, RegisterSpecList.make(classReg, dimsReg), catches, MULTIANEWARRAY_METHOD);
insns.add(insn);
// Add a move-result.
rop = Rops.opMoveResult(MULTIANEWARRAY_METHOD.getPrototype().getReturnType());
insn = new PlainInsn(rop, pos, objectReg, RegisterSpecList.EMPTY);
insns.add(insn);
/*
* And finally, set up for the remainder of this method to
* add an appropriate cast.
*/
opcode = ByteOps.CHECKCAST;
sources = RegisterSpecList.make(objectReg);
} else if (opcode == ByteOps.JSR) {
// JSR has no Rop instruction
hasJsr = true;
return;
} else if (opcode == ByteOps.RET) {
try {
returnAddress = (ReturnAddress) arg(0);
} catch (ClassCastException ex) {
throw new RuntimeException("Argument to RET was not a ReturnAddress", ex);
}
// RET has no Rop instruction.
return;
}
ropOpcode = jopToRopOpcode(opcode, cst);
rop = Rops.ropFor(ropOpcode, destType, sources, cst);
Insn moveResult = null;
if (dest != null && rop.isCallLike()) {
/*
* We're going to want to have a move-result in the next
* basic block.
*/
extraBlockCount++;
moveResult = new PlainInsn(Rops.opMoveResult(((CstMethodRef) cst).getPrototype().getReturnType()), pos, dest, RegisterSpecList.EMPTY);
dest = null;
} else if (dest != null && rop.canThrow()) {
/*
* We're going to want to have a move-result-pseudo in the
* next basic block.
*/
extraBlockCount++;
moveResult = new PlainInsn(Rops.opMoveResultPseudo(dest.getTypeBearer()), pos, dest, RegisterSpecList.EMPTY);
dest = null;
}
if (ropOpcode == RegOps.NEW_ARRAY) {
/*
* In the original bytecode, this was either a primitive
* array constructor "newarray" or an object array
* constructor "anewarray". In the former case, there is
* no explicit constant, and in the latter, the constant
* is for the element type and not the array type. The rop
* instruction form for both of these is supposed to be
* the resulting array type, so we initialize / alter
* "cst" here, accordingly. Conveniently enough, the rop
* opcode already gets constructed with the proper array
* type.
*/
cst = CstType.intern(rop.getResult());
} else if ((cst == null) && (sourceCount == 2)) {
TypeBearer firstType = sources.get(0).getTypeBearer();
TypeBearer lastType = sources.get(1).getTypeBearer();
if ((lastType.isConstant() || firstType.isConstant()) && advice.hasConstantOperation(rop, sources.get(0), sources.get(1))) {
if (lastType.isConstant()) {
/*
* The target architecture has an instruction that can
* build in the constant found in the second argument,
* so pull it out of the sources and just use it as a
* constant here.
*/
cst = (Constant) lastType;
sources = sources.withoutLast();
// For subtraction, change to addition and invert constant
if (rop.getOpcode() == RegOps.SUB) {
ropOpcode = RegOps.ADD;
CstInteger cstInt = (CstInteger) lastType;
cst = CstInteger.make(-cstInt.getValue());
}
} else {
/*
* The target architecture has an instruction that can
* build in the constant found in the first argument,
* so pull it out of the sources and just use it as a
* constant here.
*/
cst = (Constant) firstType;
sources = sources.withoutFirst();
}
rop = Rops.ropFor(ropOpcode, destType, sources, cst);
}
}
SwitchList cases = getAuxCases();
ArrayList<Constant> initValues = getInitValues();
boolean canThrow = rop.canThrow();
blockCanThrow |= canThrow;
if (cases != null) {
if (cases.size() == 0) {
// It's a default-only switch statement. It can happen!
insn = new PlainInsn(Rops.GOTO, pos, null, RegisterSpecList.EMPTY);
primarySuccessorIndex = 0;
} else {
IntList values = cases.getValues();
insn = new SwitchInsn(rop, pos, dest, sources, values);
primarySuccessorIndex = values.size();
}
} else if (ropOpcode == RegOps.RETURN) {
/*
* Returns get turned into the combination of a move (if
* non-void and if the return doesn't already mention
* register 0) and a goto (to the return block).
*/
if (sources.size() != 0) {
RegisterSpec source = sources.get(0);
TypeBearer type = source.getTypeBearer();
if (source.getReg() != 0) {
insns.add(new PlainInsn(Rops.opMove(type), pos, RegisterSpec.make(0, type), source));
}
}
insn = new PlainInsn(Rops.GOTO, pos, null, RegisterSpecList.EMPTY);
primarySuccessorIndex = 0;
updateReturnOp(rop, pos);
returns = true;
} else if (cst != null) {
if (canThrow) {
insn = new ThrowingCstInsn(rop, pos, sources, catches, cst);
catchesUsed = true;
primarySuccessorIndex = catches.size();
} else {
insn = new PlainCstInsn(rop, pos, dest, sources, cst);
}
} else if (canThrow) {
insn = new ThrowingInsn(rop, pos, sources, catches);
catchesUsed = true;
if (opcode == ByteOps.ATHROW) {
/*
* The op athrow is the only one where it's possible
* to have non-empty successors and yet not have a
* primary successor.
*/
primarySuccessorIndex = -1;
} else {
primarySuccessorIndex = catches.size();
}
} else {
insn = new PlainInsn(rop, pos, dest, sources);
}
insns.add(insn);
if (moveResult != null) {
insns.add(moveResult);
}
/*
* If initValues is non-null, it means that the parser has
* seen a group of compatible constant initialization
* bytecodes that are applied to the current newarray. The
* action we take here is to convert these initialization
* bytecodes into a single fill-array-data ROP which lays out
* all the constant values in a table.
*/
if (initValues != null) {
extraBlockCount++;
insn = new FillArrayDataInsn(Rops.FILL_ARRAY_DATA, pos, RegisterSpecList.make(moveResult.getResult()), initValues, cst);
insns.add(insn);
}
}
use of com.android.dx.rop.cst.CstInteger in project buck by facebook.
the class AnnotationParser method parseValue.
/**
* Parses an annotation value.
*
* @return {@code non-null;} the parsed value
*/
private Constant parseValue() throws IOException {
int tag = input.readUnsignedByte();
if (observer != null) {
CstString humanTag = new CstString(Character.toString((char) tag));
parsed(1, "tag: " + humanTag.toQuoted());
}
switch(tag) {
case 'B':
{
CstInteger value = (CstInteger) parseConstant();
return CstByte.make(value.getValue());
}
case 'C':
{
CstInteger value = (CstInteger) parseConstant();
int intValue = value.getValue();
return CstChar.make(value.getValue());
}
case 'D':
{
CstDouble value = (CstDouble) parseConstant();
return value;
}
case 'F':
{
CstFloat value = (CstFloat) parseConstant();
return value;
}
case 'I':
{
CstInteger value = (CstInteger) parseConstant();
return value;
}
case 'J':
{
CstLong value = (CstLong) parseConstant();
return value;
}
case 'S':
{
CstInteger value = (CstInteger) parseConstant();
return CstShort.make(value.getValue());
}
case 'Z':
{
CstInteger value = (CstInteger) parseConstant();
return CstBoolean.make(value.getValue());
}
case 'c':
{
int classInfoIndex = input.readUnsignedShort();
CstString value = (CstString) pool.get(classInfoIndex);
Type type = Type.internReturnType(value.getString());
if (observer != null) {
parsed(2, "class_info: " + type.toHuman());
}
return new CstType(type);
}
case 's':
{
return parseConstant();
}
case 'e':
{
requireLength(4);
int typeNameIndex = input.readUnsignedShort();
int constNameIndex = input.readUnsignedShort();
CstString typeName = (CstString) pool.get(typeNameIndex);
CstString constName = (CstString) pool.get(constNameIndex);
if (observer != null) {
parsed(2, "type_name: " + typeName.toHuman());
parsed(2, "const_name: " + constName.toHuman());
}
return new CstEnumRef(new CstNat(constName, typeName));
}
case '@':
{
Annotation annotation = parseAnnotation(AnnotationVisibility.EMBEDDED);
return new CstAnnotation(annotation);
}
case '[':
{
requireLength(2);
int numValues = input.readUnsignedShort();
CstArray.List list = new CstArray.List(numValues);
if (observer != null) {
parsed(2, "num_values: " + numValues);
changeIndent(1);
}
for (int i = 0; i < numValues; i++) {
if (observer != null) {
changeIndent(-1);
parsed(0, "element_value[" + i + "]:");
changeIndent(1);
}
list.set(i, parseValue());
}
if (observer != null) {
changeIndent(-1);
}
list.setImmutable();
return new CstArray(list);
}
default:
{
throw new ParseException("unknown annotation tag: " + Hex.u1(tag));
}
}
}
use of com.android.dx.rop.cst.CstInteger in project buck by facebook.
the class SCCP method simulateMath.
/**
* Simulates math insns, if possible.
*
* @param insn non-null insn to simulate
* @param resultType basic type of the result
* @return constant result or null if not simulatable.
*/
private Constant simulateMath(SsaInsn insn, int resultType) {
Insn ropInsn = insn.getOriginalRopInsn();
int opcode = insn.getOpcode().getOpcode();
RegisterSpecList sources = insn.getSources();
int regA = sources.get(0).getReg();
Constant cA;
Constant cB;
if (latticeValues[regA] != CONSTANT) {
cA = null;
} else {
cA = latticeConstants[regA];
}
if (sources.size() == 1) {
CstInsn cstInsn = (CstInsn) ropInsn;
cB = cstInsn.getConstant();
} else {
/* sources.size() == 2 */
int regB = sources.get(1).getReg();
if (latticeValues[regB] != CONSTANT) {
cB = null;
} else {
cB = latticeConstants[regB];
}
}
if (cA == null || cB == null) {
//TODO handle a constant of 0 with MUL or AND
return null;
}
switch(resultType) {
case Type.BT_INT:
int vR;
boolean skip = false;
int vA = ((CstInteger) cA).getValue();
int vB = ((CstInteger) cB).getValue();
switch(opcode) {
case RegOps.ADD:
vR = vA + vB;
break;
case RegOps.SUB:
// 1 source for reverse sub, 2 sources for regular sub
if (sources.size() == 1) {
vR = vB - vA;
} else {
vR = vA - vB;
}
break;
case RegOps.MUL:
vR = vA * vB;
break;
case RegOps.DIV:
if (vB == 0) {
skip = true;
// just to hide a warning
vR = 0;
} else {
vR = vA / vB;
}
break;
case RegOps.AND:
vR = vA & vB;
break;
case RegOps.OR:
vR = vA | vB;
break;
case RegOps.XOR:
vR = vA ^ vB;
break;
case RegOps.SHL:
vR = vA << vB;
break;
case RegOps.SHR:
vR = vA >> vB;
break;
case RegOps.USHR:
vR = vA >>> vB;
break;
case RegOps.REM:
if (vB == 0) {
skip = true;
// just to hide a warning
vR = 0;
} else {
vR = vA % vB;
}
break;
default:
throw new RuntimeException("Unexpected op");
}
return skip ? null : CstInteger.make(vR);
default:
// not yet supported
return null;
}
}
Aggregations