use of com.android.dx.rop.cst.CstInteger in project buck by facebook.
the class SCCP method simulateBranch.
/**
* Simulates branch insns, if possible. Adds reachable successor blocks
* to the CFG worklists.
* @param insn branch to simulate
*/
private void simulateBranch(SsaInsn insn) {
Rop opcode = insn.getOpcode();
RegisterSpecList sources = insn.getSources();
boolean constantBranch = false;
boolean constantSuccessor = false;
// Check if the insn is a branch with a constant condition
if (opcode.getBranchingness() == Rop.BRANCH_IF) {
Constant cA = null;
Constant cB = null;
RegisterSpec specA = sources.get(0);
int regA = specA.getReg();
if (!ssaMeth.isRegALocal(specA) && latticeValues[regA] == CONSTANT) {
cA = latticeConstants[regA];
}
if (sources.size() == 2) {
RegisterSpec specB = sources.get(1);
int regB = specB.getReg();
if (!ssaMeth.isRegALocal(specB) && latticeValues[regB] == CONSTANT) {
cB = latticeConstants[regB];
}
}
// Calculate the result of the condition
if (cA != null && sources.size() == 1) {
switch(((TypedConstant) cA).getBasicType()) {
case Type.BT_INT:
constantBranch = true;
int vA = ((CstInteger) cA).getValue();
switch(opcode.getOpcode()) {
case RegOps.IF_EQ:
constantSuccessor = (vA == 0);
break;
case RegOps.IF_NE:
constantSuccessor = (vA != 0);
break;
case RegOps.IF_LT:
constantSuccessor = (vA < 0);
break;
case RegOps.IF_GE:
constantSuccessor = (vA >= 0);
break;
case RegOps.IF_LE:
constantSuccessor = (vA <= 0);
break;
case RegOps.IF_GT:
constantSuccessor = (vA > 0);
break;
default:
throw new RuntimeException("Unexpected op");
}
break;
default:
}
} else if (cA != null && cB != null) {
switch(((TypedConstant) cA).getBasicType()) {
case Type.BT_INT:
constantBranch = true;
int vA = ((CstInteger) cA).getValue();
int vB = ((CstInteger) cB).getValue();
switch(opcode.getOpcode()) {
case RegOps.IF_EQ:
constantSuccessor = (vA == vB);
break;
case RegOps.IF_NE:
constantSuccessor = (vA != vB);
break;
case RegOps.IF_LT:
constantSuccessor = (vA < vB);
break;
case RegOps.IF_GE:
constantSuccessor = (vA >= vB);
break;
case RegOps.IF_LE:
constantSuccessor = (vA <= vB);
break;
case RegOps.IF_GT:
constantSuccessor = (vA > vB);
break;
default:
throw new RuntimeException("Unexpected op");
}
break;
default:
}
}
}
/*
* If condition is constant, add only the target block to the
* worklist. Otherwise, add all successors to the worklist.
*/
SsaBasicBlock block = insn.getBlock();
if (constantBranch) {
int successorBlock;
if (constantSuccessor) {
successorBlock = block.getSuccessorList().get(1);
} else {
successorBlock = block.getSuccessorList().get(0);
}
addBlockToWorklist(ssaMeth.getBlocks().get(successorBlock));
branchWorklist.add(insn);
} else {
for (int i = 0; i < block.getSuccessorList().size(); i++) {
int successorBlock = block.getSuccessorList().get(i);
addBlockToWorklist(ssaMeth.getBlocks().get(successorBlock));
}
}
}
use of com.android.dx.rop.cst.CstInteger in project buck by facebook.
the class MoveParamCombiner method getParamIndex.
/**
* Returns the parameter index associated with a move-param insn. Does
* not verify that the insn is a move-param insn.
*
* @param insn {@code non-null;} a move-param insn
* @return {@code >=0;} parameter index
*/
private int getParamIndex(NormalSsaInsn insn) {
CstInsn cstInsn = (CstInsn) (insn.getOriginalRopInsn());
int param = ((CstInteger) cstInsn.getConstant()).getValue();
return param;
}
use of com.android.dx.rop.cst.CstInteger in project J2ME-Loader by nikita36078.
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 J2ME-Loader by nikita36078.
the class BytecodeArray method parseInstruction.
/**
* Parses the instruction at the indicated offset. Indicate the
* result by calling the visitor if supplied and by returning the
* number of bytes consumed by the instruction.
*
* <p>In order to simplify further processing, the opcodes passed
* to the visitor are canonicalized, altering the opcode to a more
* universal one and making formerly implicit arguments
* explicit. In particular:</p>
*
* <ul>
* <li>The opcodes to push literal constants of primitive types all become
* {@code ldc}.
* E.g., {@code fconst_0}, {@code sipush}, and
* {@code lconst_0} qualify for this treatment.</li>
* <li>{@code aconst_null} becomes {@code ldc} of a
* "known null."</li>
* <li>Shorthand local variable accessors become the corresponding
* longhand. E.g. {@code aload_2} becomes {@code aload}.</li>
* <li>{@code goto_w} and {@code jsr_w} become {@code goto}
* and {@code jsr} (respectively).</li>
* <li>{@code ldc_w} becomes {@code ldc}.</li>
* <li>{@code tableswitch} becomes {@code lookupswitch}.
* <li>Arithmetic, array, and value-returning ops are collapsed
* to the {@code int} variant opcode, with the {@code type}
* argument set to indicate the actual type. E.g.,
* {@code fadd} becomes {@code iadd}, but
* {@code type} is passed as {@code Type.FLOAT} in that
* case. Similarly, {@code areturn} becomes
* {@code ireturn}. (However, {@code return} remains
* unchanged.</li>
* <li>Local variable access ops are collapsed to the {@code int}
* variant opcode, with the {@code type} argument set to indicate
* the actual type. E.g., {@code aload} becomes {@code iload},
* but {@code type} is passed as {@code Type.OBJECT} in
* that case.</li>
* <li>Numeric conversion ops ({@code i2l}, etc.) are left alone
* to avoid too much confustion, but their {@code type} is
* the pushed type. E.g., {@code i2b} gets type
* {@code Type.INT}, and {@code f2d} gets type
* {@code Type.DOUBLE}. Other unaltered opcodes also get
* their pushed type. E.g., {@code arraylength} gets type
* {@code Type.INT}.</li>
* </ul>
*
* @param offset {@code >= 0, < bytes.size();} offset to the start of the
* instruction
* @param visitor {@code null-ok;} visitor to call back to
* @return the length of the instruction, in bytes
*/
public int parseInstruction(int offset, Visitor visitor) {
if (visitor == null) {
visitor = EMPTY_VISITOR;
}
try {
int opcode = bytes.getUnsignedByte(offset);
int info = ByteOps.opInfo(opcode);
int fmt = info & ByteOps.FMT_MASK;
switch(opcode) {
case ByteOps.NOP:
{
visitor.visitNoArgs(opcode, offset, 1, Type.VOID);
return 1;
}
case ByteOps.ACONST_NULL:
{
visitor.visitConstant(ByteOps.LDC, offset, 1, CstKnownNull.THE_ONE, 0);
return 1;
}
case ByteOps.ICONST_M1:
{
visitor.visitConstant(ByteOps.LDC, offset, 1, CstInteger.VALUE_M1, -1);
return 1;
}
case ByteOps.ICONST_0:
{
visitor.visitConstant(ByteOps.LDC, offset, 1, CstInteger.VALUE_0, 0);
return 1;
}
case ByteOps.ICONST_1:
{
visitor.visitConstant(ByteOps.LDC, offset, 1, CstInteger.VALUE_1, 1);
return 1;
}
case ByteOps.ICONST_2:
{
visitor.visitConstant(ByteOps.LDC, offset, 1, CstInteger.VALUE_2, 2);
return 1;
}
case ByteOps.ICONST_3:
{
visitor.visitConstant(ByteOps.LDC, offset, 1, CstInteger.VALUE_3, 3);
return 1;
}
case ByteOps.ICONST_4:
{
visitor.visitConstant(ByteOps.LDC, offset, 1, CstInteger.VALUE_4, 4);
return 1;
}
case ByteOps.ICONST_5:
{
visitor.visitConstant(ByteOps.LDC, offset, 1, CstInteger.VALUE_5, 5);
return 1;
}
case ByteOps.LCONST_0:
{
visitor.visitConstant(ByteOps.LDC, offset, 1, CstLong.VALUE_0, 0);
return 1;
}
case ByteOps.LCONST_1:
{
visitor.visitConstant(ByteOps.LDC, offset, 1, CstLong.VALUE_1, 0);
return 1;
}
case ByteOps.FCONST_0:
{
visitor.visitConstant(ByteOps.LDC, offset, 1, CstFloat.VALUE_0, 0);
return 1;
}
case ByteOps.FCONST_1:
{
visitor.visitConstant(ByteOps.LDC, offset, 1, CstFloat.VALUE_1, 0);
return 1;
}
case ByteOps.FCONST_2:
{
visitor.visitConstant(ByteOps.LDC, offset, 1, CstFloat.VALUE_2, 0);
return 1;
}
case ByteOps.DCONST_0:
{
visitor.visitConstant(ByteOps.LDC, offset, 1, CstDouble.VALUE_0, 0);
return 1;
}
case ByteOps.DCONST_1:
{
visitor.visitConstant(ByteOps.LDC, offset, 1, CstDouble.VALUE_1, 0);
return 1;
}
case ByteOps.BIPUSH:
{
int value = bytes.getByte(offset + 1);
visitor.visitConstant(ByteOps.LDC, offset, 2, CstInteger.make(value), value);
return 2;
}
case ByteOps.SIPUSH:
{
int value = bytes.getShort(offset + 1);
visitor.visitConstant(ByteOps.LDC, offset, 3, CstInteger.make(value), value);
return 3;
}
case ByteOps.LDC:
{
int idx = bytes.getUnsignedByte(offset + 1);
Constant cst = pool.get(idx);
int value = (cst instanceof CstInteger) ? ((CstInteger) cst).getValue() : 0;
visitor.visitConstant(ByteOps.LDC, offset, 2, cst, value);
return 2;
}
case ByteOps.LDC_W:
{
int idx = bytes.getUnsignedShort(offset + 1);
Constant cst = pool.get(idx);
int value = (cst instanceof CstInteger) ? ((CstInteger) cst).getValue() : 0;
visitor.visitConstant(ByteOps.LDC, offset, 3, cst, value);
return 3;
}
case ByteOps.LDC2_W:
{
int idx = bytes.getUnsignedShort(offset + 1);
Constant cst = pool.get(idx);
visitor.visitConstant(ByteOps.LDC2_W, offset, 3, cst, 0);
return 3;
}
case ByteOps.ILOAD:
{
int idx = bytes.getUnsignedByte(offset + 1);
visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx, Type.INT, 0);
return 2;
}
case ByteOps.LLOAD:
{
int idx = bytes.getUnsignedByte(offset + 1);
visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx, Type.LONG, 0);
return 2;
}
case ByteOps.FLOAD:
{
int idx = bytes.getUnsignedByte(offset + 1);
visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx, Type.FLOAT, 0);
return 2;
}
case ByteOps.DLOAD:
{
int idx = bytes.getUnsignedByte(offset + 1);
visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx, Type.DOUBLE, 0);
return 2;
}
case ByteOps.ALOAD:
{
int idx = bytes.getUnsignedByte(offset + 1);
visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx, Type.OBJECT, 0);
return 2;
}
case ByteOps.ILOAD_0:
case ByteOps.ILOAD_1:
case ByteOps.ILOAD_2:
case ByteOps.ILOAD_3:
{
int idx = opcode - ByteOps.ILOAD_0;
visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx, Type.INT, 0);
return 1;
}
case ByteOps.LLOAD_0:
case ByteOps.LLOAD_1:
case ByteOps.LLOAD_2:
case ByteOps.LLOAD_3:
{
int idx = opcode - ByteOps.LLOAD_0;
visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx, Type.LONG, 0);
return 1;
}
case ByteOps.FLOAD_0:
case ByteOps.FLOAD_1:
case ByteOps.FLOAD_2:
case ByteOps.FLOAD_3:
{
int idx = opcode - ByteOps.FLOAD_0;
visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx, Type.FLOAT, 0);
return 1;
}
case ByteOps.DLOAD_0:
case ByteOps.DLOAD_1:
case ByteOps.DLOAD_2:
case ByteOps.DLOAD_3:
{
int idx = opcode - ByteOps.DLOAD_0;
visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx, Type.DOUBLE, 0);
return 1;
}
case ByteOps.ALOAD_0:
case ByteOps.ALOAD_1:
case ByteOps.ALOAD_2:
case ByteOps.ALOAD_3:
{
int idx = opcode - ByteOps.ALOAD_0;
visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx, Type.OBJECT, 0);
return 1;
}
case ByteOps.IALOAD:
{
visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.INT);
return 1;
}
case ByteOps.LALOAD:
{
visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.LONG);
return 1;
}
case ByteOps.FALOAD:
{
visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.FLOAT);
return 1;
}
case ByteOps.DALOAD:
{
visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.DOUBLE);
return 1;
}
case ByteOps.AALOAD:
{
visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.OBJECT);
return 1;
}
case ByteOps.BALOAD:
{
/*
* Note: This is a load from either a byte[] or a
* boolean[].
*/
visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.BYTE);
return 1;
}
case ByteOps.CALOAD:
{
visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.CHAR);
return 1;
}
case ByteOps.SALOAD:
{
visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.SHORT);
return 1;
}
case ByteOps.ISTORE:
{
int idx = bytes.getUnsignedByte(offset + 1);
visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx, Type.INT, 0);
return 2;
}
case ByteOps.LSTORE:
{
int idx = bytes.getUnsignedByte(offset + 1);
visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx, Type.LONG, 0);
return 2;
}
case ByteOps.FSTORE:
{
int idx = bytes.getUnsignedByte(offset + 1);
visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx, Type.FLOAT, 0);
return 2;
}
case ByteOps.DSTORE:
{
int idx = bytes.getUnsignedByte(offset + 1);
visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx, Type.DOUBLE, 0);
return 2;
}
case ByteOps.ASTORE:
{
int idx = bytes.getUnsignedByte(offset + 1);
visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx, Type.OBJECT, 0);
return 2;
}
case ByteOps.ISTORE_0:
case ByteOps.ISTORE_1:
case ByteOps.ISTORE_2:
case ByteOps.ISTORE_3:
{
int idx = opcode - ByteOps.ISTORE_0;
visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx, Type.INT, 0);
return 1;
}
case ByteOps.LSTORE_0:
case ByteOps.LSTORE_1:
case ByteOps.LSTORE_2:
case ByteOps.LSTORE_3:
{
int idx = opcode - ByteOps.LSTORE_0;
visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx, Type.LONG, 0);
return 1;
}
case ByteOps.FSTORE_0:
case ByteOps.FSTORE_1:
case ByteOps.FSTORE_2:
case ByteOps.FSTORE_3:
{
int idx = opcode - ByteOps.FSTORE_0;
visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx, Type.FLOAT, 0);
return 1;
}
case ByteOps.DSTORE_0:
case ByteOps.DSTORE_1:
case ByteOps.DSTORE_2:
case ByteOps.DSTORE_3:
{
int idx = opcode - ByteOps.DSTORE_0;
visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx, Type.DOUBLE, 0);
return 1;
}
case ByteOps.ASTORE_0:
case ByteOps.ASTORE_1:
case ByteOps.ASTORE_2:
case ByteOps.ASTORE_3:
{
int idx = opcode - ByteOps.ASTORE_0;
visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx, Type.OBJECT, 0);
return 1;
}
case ByteOps.IASTORE:
{
visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, Type.INT);
return 1;
}
case ByteOps.LASTORE:
{
visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, Type.LONG);
return 1;
}
case ByteOps.FASTORE:
{
visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, Type.FLOAT);
return 1;
}
case ByteOps.DASTORE:
{
visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, Type.DOUBLE);
return 1;
}
case ByteOps.AASTORE:
{
visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, Type.OBJECT);
return 1;
}
case ByteOps.BASTORE:
{
/*
* Note: This is a load from either a byte[] or a
* boolean[].
*/
visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, Type.BYTE);
return 1;
}
case ByteOps.CASTORE:
{
visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, Type.CHAR);
return 1;
}
case ByteOps.SASTORE:
{
visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, Type.SHORT);
return 1;
}
case ByteOps.POP:
case ByteOps.POP2:
case ByteOps.DUP:
case ByteOps.DUP_X1:
case ByteOps.DUP_X2:
case ByteOps.DUP2:
case ByteOps.DUP2_X1:
case ByteOps.DUP2_X2:
case ByteOps.SWAP:
{
visitor.visitNoArgs(opcode, offset, 1, Type.VOID);
return 1;
}
case ByteOps.IADD:
case ByteOps.ISUB:
case ByteOps.IMUL:
case ByteOps.IDIV:
case ByteOps.IREM:
case ByteOps.INEG:
case ByteOps.ISHL:
case ByteOps.ISHR:
case ByteOps.IUSHR:
case ByteOps.IAND:
case ByteOps.IOR:
case ByteOps.IXOR:
{
visitor.visitNoArgs(opcode, offset, 1, Type.INT);
return 1;
}
case ByteOps.LADD:
case ByteOps.LSUB:
case ByteOps.LMUL:
case ByteOps.LDIV:
case ByteOps.LREM:
case ByteOps.LNEG:
case ByteOps.LSHL:
case ByteOps.LSHR:
case ByteOps.LUSHR:
case ByteOps.LAND:
case ByteOps.LOR:
case ByteOps.LXOR:
{
/*
* It's "opcode - 1" because, conveniently enough, all
* these long ops are one past the int variants.
*/
visitor.visitNoArgs(opcode - 1, offset, 1, Type.LONG);
return 1;
}
case ByteOps.FADD:
case ByteOps.FSUB:
case ByteOps.FMUL:
case ByteOps.FDIV:
case ByteOps.FREM:
case ByteOps.FNEG:
{
/*
* It's "opcode - 2" because, conveniently enough, all
* these float ops are two past the int variants.
*/
visitor.visitNoArgs(opcode - 2, offset, 1, Type.FLOAT);
return 1;
}
case ByteOps.DADD:
case ByteOps.DSUB:
case ByteOps.DMUL:
case ByteOps.DDIV:
case ByteOps.DREM:
case ByteOps.DNEG:
{
/*
* It's "opcode - 3" because, conveniently enough, all
* these double ops are three past the int variants.
*/
visitor.visitNoArgs(opcode - 3, offset, 1, Type.DOUBLE);
return 1;
}
case ByteOps.IINC:
{
int idx = bytes.getUnsignedByte(offset + 1);
int value = bytes.getByte(offset + 2);
visitor.visitLocal(opcode, offset, 3, idx, Type.INT, value);
return 3;
}
case ByteOps.I2L:
case ByteOps.F2L:
case ByteOps.D2L:
{
visitor.visitNoArgs(opcode, offset, 1, Type.LONG);
return 1;
}
case ByteOps.I2F:
case ByteOps.L2F:
case ByteOps.D2F:
{
visitor.visitNoArgs(opcode, offset, 1, Type.FLOAT);
return 1;
}
case ByteOps.I2D:
case ByteOps.L2D:
case ByteOps.F2D:
{
visitor.visitNoArgs(opcode, offset, 1, Type.DOUBLE);
return 1;
}
case ByteOps.L2I:
case ByteOps.F2I:
case ByteOps.D2I:
case ByteOps.I2B:
case ByteOps.I2C:
case ByteOps.I2S:
case ByteOps.LCMP:
case ByteOps.FCMPL:
case ByteOps.FCMPG:
case ByteOps.DCMPL:
case ByteOps.DCMPG:
case ByteOps.ARRAYLENGTH:
{
visitor.visitNoArgs(opcode, offset, 1, Type.INT);
return 1;
}
case ByteOps.IFEQ:
case ByteOps.IFNE:
case ByteOps.IFLT:
case ByteOps.IFGE:
case ByteOps.IFGT:
case ByteOps.IFLE:
case ByteOps.IF_ICMPEQ:
case ByteOps.IF_ICMPNE:
case ByteOps.IF_ICMPLT:
case ByteOps.IF_ICMPGE:
case ByteOps.IF_ICMPGT:
case ByteOps.IF_ICMPLE:
case ByteOps.IF_ACMPEQ:
case ByteOps.IF_ACMPNE:
case ByteOps.GOTO:
case ByteOps.JSR:
case ByteOps.IFNULL:
case ByteOps.IFNONNULL:
{
int target = offset + bytes.getShort(offset + 1);
visitor.visitBranch(opcode, offset, 3, target);
return 3;
}
case ByteOps.RET:
{
int idx = bytes.getUnsignedByte(offset + 1);
visitor.visitLocal(opcode, offset, 2, idx, Type.RETURN_ADDRESS, 0);
return 2;
}
case ByteOps.TABLESWITCH:
{
return parseTableswitch(offset, visitor);
}
case ByteOps.LOOKUPSWITCH:
{
return parseLookupswitch(offset, visitor);
}
case ByteOps.IRETURN:
{
visitor.visitNoArgs(ByteOps.IRETURN, offset, 1, Type.INT);
return 1;
}
case ByteOps.LRETURN:
{
visitor.visitNoArgs(ByteOps.IRETURN, offset, 1, Type.LONG);
return 1;
}
case ByteOps.FRETURN:
{
visitor.visitNoArgs(ByteOps.IRETURN, offset, 1, Type.FLOAT);
return 1;
}
case ByteOps.DRETURN:
{
visitor.visitNoArgs(ByteOps.IRETURN, offset, 1, Type.DOUBLE);
return 1;
}
case ByteOps.ARETURN:
{
visitor.visitNoArgs(ByteOps.IRETURN, offset, 1, Type.OBJECT);
return 1;
}
case ByteOps.RETURN:
case ByteOps.ATHROW:
case ByteOps.MONITORENTER:
case ByteOps.MONITOREXIT:
{
visitor.visitNoArgs(opcode, offset, 1, Type.VOID);
return 1;
}
case ByteOps.GETSTATIC:
case ByteOps.PUTSTATIC:
case ByteOps.GETFIELD:
case ByteOps.PUTFIELD:
case ByteOps.INVOKEVIRTUAL:
case ByteOps.INVOKESPECIAL:
case ByteOps.INVOKESTATIC:
case ByteOps.NEW:
case ByteOps.ANEWARRAY:
case ByteOps.CHECKCAST:
case ByteOps.INSTANCEOF:
{
int idx = bytes.getUnsignedShort(offset + 1);
Constant cst = pool.get(idx);
visitor.visitConstant(opcode, offset, 3, cst, 0);
return 3;
}
case ByteOps.INVOKEINTERFACE:
{
int idx = bytes.getUnsignedShort(offset + 1);
int count = bytes.getUnsignedByte(offset + 3);
int expectZero = bytes.getUnsignedByte(offset + 4);
Constant cst = pool.get(idx);
visitor.visitConstant(opcode, offset, 5, cst, count | (expectZero << 8));
return 5;
}
case ByteOps.INVOKEDYNAMIC:
{
throw new ParseException("invokedynamic not supported");
}
case ByteOps.NEWARRAY:
{
return parseNewarray(offset, visitor);
}
case ByteOps.WIDE:
{
return parseWide(offset, visitor);
}
case ByteOps.MULTIANEWARRAY:
{
int idx = bytes.getUnsignedShort(offset + 1);
int dimensions = bytes.getUnsignedByte(offset + 3);
Constant cst = pool.get(idx);
visitor.visitConstant(opcode, offset, 4, cst, dimensions);
return 4;
}
case ByteOps.GOTO_W:
case ByteOps.JSR_W:
{
int target = offset + bytes.getInt(offset + 1);
int newop = (opcode == ByteOps.GOTO_W) ? ByteOps.GOTO : ByteOps.JSR;
visitor.visitBranch(newop, offset, 5, target);
return 5;
}
default:
{
visitor.visitInvalid(opcode, offset, 1);
return 1;
}
}
} catch (SimException ex) {
ex.addContext("...at bytecode offset " + Hex.u4(offset));
throw ex;
} catch (RuntimeException ex) {
SimException se = new SimException(ex);
se.addContext("...at bytecode offset " + Hex.u4(offset));
throw se;
}
}
use of com.android.dx.rop.cst.CstInteger in project J2ME-Loader by nikita36078.
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