summaryrefslogtreecommitdiffstats
path: root/src/proguard/evaluation/Processor.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/proguard/evaluation/Processor.java')
-rw-r--r--src/proguard/evaluation/Processor.java979
1 files changed, 979 insertions, 0 deletions
diff --git a/src/proguard/evaluation/Processor.java b/src/proguard/evaluation/Processor.java
new file mode 100644
index 0000000..74afd0b
--- /dev/null
+++ b/src/proguard/evaluation/Processor.java
@@ -0,0 +1,979 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.evaluation;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.CodeAttribute;
+import proguard.classfile.constant.*;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+import proguard.classfile.instruction.*;
+import proguard.classfile.instruction.visitor.InstructionVisitor;
+import proguard.classfile.util.SimplifiedVisitor;
+import proguard.evaluation.value.*;
+
+/**
+ * This InstructionVisitor executes the instructions that it visits on a given
+ * local variable frame and stack.
+ *
+ * @author Eric Lafortune
+ */
+public class Processor
+extends SimplifiedVisitor
+implements InstructionVisitor,
+ ConstantVisitor
+{
+ private final Variables variables;
+ private final Stack stack;
+ private final ValueFactory valueFactory;
+ private final BranchUnit branchUnit;
+ private final InvocationUnit invocationUnit;
+
+ // Fields acting as parameters for the ConstantVisitor methods.
+ private boolean handleClassConstantAsClassValue;
+ private Value cpValue;
+
+
+ /**
+ * Creates a new processor that operates on the given environment.
+ * @param variables the local variable frame.
+ * @param stack the local stack.
+ * @param branchUnit the class that can affect the program counter.
+ * @param invocationUnit the class that can access other program members.
+ */
+ public Processor(Variables variables,
+ Stack stack,
+ ValueFactory valueFactory,
+ BranchUnit branchUnit,
+ InvocationUnit invocationUnit)
+ {
+ this.variables = variables;
+ this.stack = stack;
+ this.valueFactory = valueFactory;
+ this.branchUnit = branchUnit;
+ this.invocationUnit = invocationUnit;
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
+ {
+ switch (simpleInstruction.opcode)
+ {
+ case InstructionConstants.OP_NOP:
+ break;
+
+ case InstructionConstants.OP_ACONST_NULL:
+ stack.push(valueFactory.createReferenceValueNull());
+ break;
+
+ case InstructionConstants.OP_ICONST_M1:
+ case InstructionConstants.OP_ICONST_0:
+ case InstructionConstants.OP_ICONST_1:
+ case InstructionConstants.OP_ICONST_2:
+ case InstructionConstants.OP_ICONST_3:
+ case InstructionConstants.OP_ICONST_4:
+ case InstructionConstants.OP_ICONST_5:
+ case InstructionConstants.OP_BIPUSH:
+ case InstructionConstants.OP_SIPUSH:
+ stack.push(valueFactory.createIntegerValue(simpleInstruction.constant));
+ break;
+
+ case InstructionConstants.OP_LCONST_0:
+ case InstructionConstants.OP_LCONST_1:
+ stack.push(valueFactory.createLongValue(simpleInstruction.constant));
+ break;
+
+ case InstructionConstants.OP_FCONST_0:
+ case InstructionConstants.OP_FCONST_1:
+ case InstructionConstants.OP_FCONST_2:
+ stack.push(valueFactory.createFloatValue((float)simpleInstruction.constant));
+ break;
+
+ case InstructionConstants.OP_DCONST_0:
+ case InstructionConstants.OP_DCONST_1:
+ stack.push(valueFactory.createDoubleValue((double)simpleInstruction.constant));
+ break;
+
+ case InstructionConstants.OP_IALOAD:
+ case InstructionConstants.OP_BALOAD:
+ case InstructionConstants.OP_CALOAD:
+ case InstructionConstants.OP_SALOAD:
+ stack.ipop();
+ stack.apop();
+ stack.push(valueFactory.createIntegerValue());
+ break;
+
+ case InstructionConstants.OP_LALOAD:
+ stack.ipop();
+ stack.apop();
+ stack.push(valueFactory.createLongValue());
+ break;
+
+ case InstructionConstants.OP_FALOAD:
+ stack.ipop();
+ stack.apop();
+ stack.push(valueFactory.createFloatValue());
+ break;
+
+ case InstructionConstants.OP_DALOAD:
+ stack.ipop();
+ stack.apop();
+ stack.push(valueFactory.createDoubleValue());
+ break;
+
+ case InstructionConstants.OP_AALOAD:
+ {
+ IntegerValue arrayIndex = stack.ipop();
+ ReferenceValue arrayReference = stack.apop();
+ stack.push(arrayReference.arrayLoad(arrayIndex, valueFactory));
+ break;
+ }
+
+ case InstructionConstants.OP_IASTORE:
+ case InstructionConstants.OP_BASTORE:
+ case InstructionConstants.OP_CASTORE:
+ case InstructionConstants.OP_SASTORE:
+ stack.ipop();
+ stack.ipop();
+ stack.apop();
+ break;
+
+ case InstructionConstants.OP_LASTORE:
+ stack.lpop();
+ stack.ipop();
+ stack.apop();
+ break;
+
+ case InstructionConstants.OP_FASTORE:
+ stack.fpop();
+ stack.ipop();
+ stack.apop();
+ break;
+
+ case InstructionConstants.OP_DASTORE:
+ stack.dpop();
+ stack.ipop();
+ stack.apop();
+ break;
+
+ case InstructionConstants.OP_AASTORE:
+ stack.apop();
+ stack.ipop();
+ stack.apop();
+ break;
+
+ case InstructionConstants.OP_POP:
+ stack.pop1();
+ break;
+
+ case InstructionConstants.OP_POP2:
+ stack.pop2();
+ break;
+
+ case InstructionConstants.OP_DUP:
+ stack.dup();
+ break;
+
+ case InstructionConstants.OP_DUP_X1:
+ stack.dup_x1();
+ break;
+
+ case InstructionConstants.OP_DUP_X2:
+ stack.dup_x2();
+ break;
+
+ case InstructionConstants.OP_DUP2:
+ stack.dup2();
+ break;
+
+ case InstructionConstants.OP_DUP2_X1:
+ stack.dup2_x1();
+ break;
+
+ case InstructionConstants.OP_DUP2_X2:
+ stack.dup2_x2();
+ break;
+
+ case InstructionConstants.OP_SWAP:
+ stack.swap();
+ break;
+
+ case InstructionConstants.OP_IADD:
+ stack.push(stack.ipop().add(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_LADD:
+ stack.push(stack.lpop().add(stack.lpop()));
+ break;
+
+ case InstructionConstants.OP_FADD:
+ stack.push(stack.fpop().add(stack.fpop()));
+ break;
+
+ case InstructionConstants.OP_DADD:
+ stack.push(stack.dpop().add(stack.dpop()));
+ break;
+
+ case InstructionConstants.OP_ISUB:
+ stack.push(stack.ipop().subtractFrom(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_LSUB:
+ stack.push(stack.lpop().subtractFrom(stack.lpop()));
+ break;
+
+ case InstructionConstants.OP_FSUB:
+ stack.push(stack.fpop().subtractFrom(stack.fpop()));
+ break;
+
+ case InstructionConstants.OP_DSUB:
+ stack.push(stack.dpop().subtractFrom(stack.dpop()));
+ break;
+
+ case InstructionConstants.OP_IMUL:
+ stack.push(stack.ipop().multiply(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_LMUL:
+ stack.push(stack.lpop().multiply(stack.lpop()));
+ break;
+
+ case InstructionConstants.OP_FMUL:
+ stack.push(stack.fpop().multiply(stack.fpop()));
+ break;
+
+ case InstructionConstants.OP_DMUL:
+ stack.push(stack.dpop().multiply(stack.dpop()));
+ break;
+
+ case InstructionConstants.OP_IDIV:
+ try
+ {
+ stack.push(stack.ipop().divideOf(stack.ipop()));
+ }
+ catch (ArithmeticException ex)
+ {
+ stack.push(valueFactory.createIntegerValue());
+ // TODO: Forward ArithmeticExceptions.
+ //stack.clear();
+ //stack.push(valueFactory.createReference(false));
+ //branchUnit.throwException();
+ }
+ break;
+
+ case InstructionConstants.OP_LDIV:
+ try
+ {
+ stack.push(stack.lpop().divideOf(stack.lpop()));
+ }
+ catch (ArithmeticException ex)
+ {
+ stack.push(valueFactory.createLongValue());
+ // TODO: Forward ArithmeticExceptions.
+ //stack.clear();
+ //stack.push(valueFactory.createReference(false));
+ //branchUnit.throwException();
+ }
+ break;
+
+ case InstructionConstants.OP_FDIV:
+ stack.push(stack.fpop().divideOf(stack.fpop()));
+ break;
+
+ case InstructionConstants.OP_DDIV:
+ stack.push(stack.dpop().divideOf(stack.dpop()));
+ break;
+
+ case InstructionConstants.OP_IREM:
+ try
+ {
+ stack.push(stack.ipop().remainderOf(stack.ipop()));
+ }
+ catch (ArithmeticException ex)
+ {
+ stack.push(valueFactory.createIntegerValue());
+ // TODO: Forward ArithmeticExceptions.
+ //stack.clear();
+ //stack.push(valueFactory.createReference(false));
+ //branchUnit.throwException();
+ }
+ break;
+
+ case InstructionConstants.OP_LREM:
+ try
+ {
+ stack.push(stack.lpop().remainderOf(stack.lpop()));
+ }
+ catch (ArithmeticException ex)
+ {
+ stack.push(valueFactory.createLongValue());
+ // TODO: Forward ArithmeticExceptions.
+ //stack.clear();
+ //stack.push(valueFactory.createReference(false));
+ //branchUnit.throwException();
+ }
+ break;
+
+ case InstructionConstants.OP_FREM:
+ stack.push(stack.fpop().remainderOf(stack.fpop()));
+ break;
+
+ case InstructionConstants.OP_DREM:
+ stack.push(stack.dpop().remainderOf(stack.dpop()));
+ break;
+
+ case InstructionConstants.OP_INEG:
+ stack.push(stack.ipop().negate());
+ break;
+
+ case InstructionConstants.OP_LNEG:
+ stack.push(stack.lpop().negate());
+ break;
+
+ case InstructionConstants.OP_FNEG:
+ stack.push(stack.fpop().negate());
+ break;
+
+ case InstructionConstants.OP_DNEG:
+ stack.push(stack.dpop().negate());
+ break;
+
+ case InstructionConstants.OP_ISHL:
+ stack.push(stack.ipop().shiftLeftOf(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_LSHL:
+ stack.push(stack.ipop().shiftLeftOf(stack.lpop()));
+ break;
+
+ case InstructionConstants.OP_ISHR:
+ stack.push(stack.ipop().shiftRightOf(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_LSHR:
+ stack.push(stack.ipop().shiftRightOf(stack.lpop()));
+ break;
+
+ case InstructionConstants.OP_IUSHR:
+ stack.push(stack.ipop().unsignedShiftRightOf(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_LUSHR:
+ stack.push(stack.ipop().unsignedShiftRightOf(stack.lpop()));
+ break;
+
+ case InstructionConstants.OP_IAND:
+ stack.push(stack.ipop().and(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_LAND:
+ stack.push(stack.lpop().and(stack.lpop()));
+ break;
+
+ case InstructionConstants.OP_IOR:
+ stack.push(stack.ipop().or(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_LOR:
+ stack.push(stack.lpop().or(stack.lpop()));
+ break;
+
+ case InstructionConstants.OP_IXOR:
+ stack.push(stack.ipop().xor(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_LXOR:
+ stack.push(stack.lpop().xor(stack.lpop()));
+ break;
+
+ case InstructionConstants.OP_I2L:
+ stack.push(stack.ipop().convertToLong());
+ break;
+
+ case InstructionConstants.OP_I2F:
+ stack.push(stack.ipop().convertToFloat());
+ break;
+
+ case InstructionConstants.OP_I2D:
+ stack.push(stack.ipop().convertToDouble());
+ break;
+
+ case InstructionConstants.OP_L2I:
+ stack.push(stack.lpop().convertToInteger());
+ break;
+
+ case InstructionConstants.OP_L2F:
+ stack.push(stack.lpop().convertToFloat());
+ break;
+
+ case InstructionConstants.OP_L2D:
+ stack.push(stack.lpop().convertToDouble());
+ break;
+
+ case InstructionConstants.OP_F2I:
+ stack.push(stack.fpop().convertToInteger());
+ break;
+
+ case InstructionConstants.OP_F2L:
+ stack.push(stack.fpop().convertToLong());
+ break;
+
+ case InstructionConstants.OP_F2D:
+ stack.push(stack.fpop().convertToDouble());
+ break;
+
+ case InstructionConstants.OP_D2I:
+ stack.push(stack.dpop().convertToInteger());
+ break;
+
+ case InstructionConstants.OP_D2L:
+ stack.push(stack.dpop().convertToLong());
+ break;
+
+ case InstructionConstants.OP_D2F:
+ stack.push(stack.dpop().convertToFloat());
+ break;
+
+ case InstructionConstants.OP_I2B:
+ stack.push(stack.ipop().convertToByte());
+ break;
+
+ case InstructionConstants.OP_I2C:
+ stack.push(stack.ipop().convertToCharacter());
+ break;
+
+ case InstructionConstants.OP_I2S:
+ stack.push(stack.ipop().convertToShort());
+ break;
+
+ case InstructionConstants.OP_LCMP:
+// stack.push(stack.lpop().compareReverse(stack.lpop()));
+
+ LongValue longValue1 = stack.lpop();
+ LongValue longValue2 = stack.lpop();
+ stack.push(longValue2.compare(longValue1));
+ break;
+
+ case InstructionConstants.OP_FCMPL:
+ FloatValue floatValue1 = stack.fpop();
+ FloatValue floatValue2 = stack.fpop();
+ stack.push(floatValue2.compare(floatValue1));
+ break;
+
+ case InstructionConstants.OP_FCMPG:
+ stack.push(stack.fpop().compareReverse(stack.fpop()));
+ break;
+
+ case InstructionConstants.OP_DCMPL:
+ DoubleValue doubleValue1 = stack.dpop();
+ DoubleValue doubleValue2 = stack.dpop();
+ stack.push(doubleValue2.compare(doubleValue1));
+ break;
+
+ case InstructionConstants.OP_DCMPG:
+ stack.push(stack.dpop().compareReverse(stack.dpop()));
+ break;
+
+ case InstructionConstants.OP_IRETURN:
+ invocationUnit.exitMethod(clazz, method, stack.ipop());
+ branchUnit.returnFromMethod();
+ break;
+
+ case InstructionConstants.OP_LRETURN:
+ invocationUnit.exitMethod(clazz, method, stack.lpop());
+ branchUnit.returnFromMethod();
+ break;
+
+ case InstructionConstants.OP_FRETURN:
+ invocationUnit.exitMethod(clazz, method, stack.fpop());
+ branchUnit.returnFromMethod();
+ break;
+
+ case InstructionConstants.OP_DRETURN:
+ invocationUnit.exitMethod(clazz, method, stack.dpop());
+ branchUnit.returnFromMethod();
+ break;
+
+ case InstructionConstants.OP_ARETURN:
+ invocationUnit.exitMethod(clazz, method, stack.apop());
+ branchUnit.returnFromMethod();
+ break;
+
+ case InstructionConstants.OP_RETURN:
+ branchUnit.returnFromMethod();
+ break;
+
+ case InstructionConstants.OP_NEWARRAY:
+ IntegerValue arrayLength = stack.ipop();
+ stack.push(valueFactory.createArrayReferenceValue(String.valueOf(InstructionUtil.internalTypeFromArrayType((byte)simpleInstruction.constant)),
+ null,
+ arrayLength));
+ break;
+
+ case InstructionConstants.OP_ARRAYLENGTH:
+ stack.apop();
+ stack.push(valueFactory.createIntegerValue());
+ break;
+
+ case InstructionConstants.OP_ATHROW:
+ ReferenceValue exceptionReferenceValue = stack.apop();
+ stack.clear();
+ stack.push(exceptionReferenceValue);
+ branchUnit.throwException();
+ break;
+
+ case InstructionConstants.OP_MONITORENTER:
+ case InstructionConstants.OP_MONITOREXIT:
+ stack.apop();
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unknown simple instruction ["+simpleInstruction.opcode+"]");
+ }
+ }
+
+
+ public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
+ {
+ int constantIndex = constantInstruction.constantIndex;
+
+ switch (constantInstruction.opcode)
+ {
+ case InstructionConstants.OP_LDC:
+ case InstructionConstants.OP_LDC_W:
+ case InstructionConstants.OP_LDC2_W:
+ stack.push(cpValue(clazz, constantIndex, true));
+ break;
+
+ case InstructionConstants.OP_GETSTATIC:
+ case InstructionConstants.OP_PUTSTATIC:
+ case InstructionConstants.OP_GETFIELD:
+ case InstructionConstants.OP_PUTFIELD:
+ case InstructionConstants.OP_INVOKEVIRTUAL:
+ case InstructionConstants.OP_INVOKESPECIAL:
+ case InstructionConstants.OP_INVOKESTATIC:
+ case InstructionConstants.OP_INVOKEINTERFACE:
+ invocationUnit.invokeMember(clazz, method, codeAttribute, offset, constantInstruction, stack);
+ break;
+
+ case InstructionConstants.OP_NEW:
+ stack.push(cpValue(clazz, constantIndex).referenceValue());
+ break;
+
+ case InstructionConstants.OP_ANEWARRAY:
+ {
+ ReferenceValue referenceValue = cpValue(clazz, constantIndex).referenceValue();
+
+ stack.push(valueFactory.createArrayReferenceValue(referenceValue.internalType(),
+ referenceValue.getReferencedClass(),
+ stack.ipop()));
+ break;
+ }
+
+ case InstructionConstants.OP_CHECKCAST:
+ // TODO: Check cast.
+ ReferenceValue castValue = stack.apop();
+ ReferenceValue castResultValue =
+ castValue.isNull() == Value.ALWAYS ? castValue :
+ castValue.isNull() == Value.NEVER ? cpValue(clazz, constantIndex).referenceValue() :
+ cpValue(clazz, constantIndex).referenceValue().generalize(valueFactory.createReferenceValueNull());
+ stack.push(castResultValue);
+ break;
+
+ case InstructionConstants.OP_INSTANCEOF:
+ {
+ ReferenceValue referenceValue = cpValue(clazz, constantIndex).referenceValue();
+
+ int instanceOf = stack.apop().instanceOf(referenceValue.getType(),
+ referenceValue.getReferencedClass());
+
+ stack.push(instanceOf == Value.NEVER ? valueFactory.createIntegerValue(0) :
+ instanceOf == Value.ALWAYS ? valueFactory.createIntegerValue(1) :
+ valueFactory.createIntegerValue());
+ break;
+ }
+
+ case InstructionConstants.OP_MULTIANEWARRAY:
+ {
+ int dimensionCount = constantInstruction.constant;
+ for (int dimension = 0; dimension < dimensionCount; dimension++)
+ {
+ // TODO: Use array lengths.
+ IntegerValue arrayLength = stack.ipop();
+ }
+
+ stack.push(cpValue(clazz, constantIndex).referenceValue());
+ break;
+ }
+
+ default:
+ throw new IllegalArgumentException("Unknown constant pool instruction ["+constantInstruction.opcode+"]");
+ }
+ }
+
+
+ public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction)
+ {
+ int variableIndex = variableInstruction.variableIndex;
+
+ switch (variableInstruction.opcode)
+ {
+ case InstructionConstants.OP_ILOAD:
+ case InstructionConstants.OP_ILOAD_0:
+ case InstructionConstants.OP_ILOAD_1:
+ case InstructionConstants.OP_ILOAD_2:
+ case InstructionConstants.OP_ILOAD_3:
+ stack.push(variables.iload(variableIndex));
+ break;
+
+ case InstructionConstants.OP_LLOAD:
+ case InstructionConstants.OP_LLOAD_0:
+ case InstructionConstants.OP_LLOAD_1:
+ case InstructionConstants.OP_LLOAD_2:
+ case InstructionConstants.OP_LLOAD_3:
+ stack.push(variables.lload(variableIndex));
+ break;
+
+ case InstructionConstants.OP_FLOAD:
+ case InstructionConstants.OP_FLOAD_0:
+ case InstructionConstants.OP_FLOAD_1:
+ case InstructionConstants.OP_FLOAD_2:
+ case InstructionConstants.OP_FLOAD_3:
+ stack.push(variables.fload(variableIndex));
+ break;
+
+ case InstructionConstants.OP_DLOAD:
+ case InstructionConstants.OP_DLOAD_0:
+ case InstructionConstants.OP_DLOAD_1:
+ case InstructionConstants.OP_DLOAD_2:
+ case InstructionConstants.OP_DLOAD_3:
+ stack.push(variables.dload(variableIndex));
+ break;
+
+ case InstructionConstants.OP_ALOAD:
+ case InstructionConstants.OP_ALOAD_0:
+ case InstructionConstants.OP_ALOAD_1:
+ case InstructionConstants.OP_ALOAD_2:
+ case InstructionConstants.OP_ALOAD_3:
+ stack.push(variables.aload(variableIndex));
+ break;
+
+ case InstructionConstants.OP_ISTORE:
+ case InstructionConstants.OP_ISTORE_0:
+ case InstructionConstants.OP_ISTORE_1:
+ case InstructionConstants.OP_ISTORE_2:
+ case InstructionConstants.OP_ISTORE_3:
+ variables.store(variableIndex, stack.ipop());
+ break;
+
+ case InstructionConstants.OP_LSTORE:
+ case InstructionConstants.OP_LSTORE_0:
+ case InstructionConstants.OP_LSTORE_1:
+ case InstructionConstants.OP_LSTORE_2:
+ case InstructionConstants.OP_LSTORE_3:
+ variables.store(variableIndex, stack.lpop());
+ break;
+
+ case InstructionConstants.OP_FSTORE:
+ case InstructionConstants.OP_FSTORE_0:
+ case InstructionConstants.OP_FSTORE_1:
+ case InstructionConstants.OP_FSTORE_2:
+ case InstructionConstants.OP_FSTORE_3:
+ variables.store(variableIndex, stack.fpop());
+ break;
+
+ case InstructionConstants.OP_DSTORE:
+ case InstructionConstants.OP_DSTORE_0:
+ case InstructionConstants.OP_DSTORE_1:
+ case InstructionConstants.OP_DSTORE_2:
+ case InstructionConstants.OP_DSTORE_3:
+ variables.store(variableIndex, stack.dpop());
+ break;
+
+ case InstructionConstants.OP_ASTORE:
+ case InstructionConstants.OP_ASTORE_0:
+ case InstructionConstants.OP_ASTORE_1:
+ case InstructionConstants.OP_ASTORE_2:
+ case InstructionConstants.OP_ASTORE_3:
+ // The operand on the stack can be a reference or a return
+ // address, so we'll relax the pop operation.
+ //variables.store(variableIndex, stack.apop());
+ variables.store(variableIndex, stack.pop());
+ break;
+
+ case InstructionConstants.OP_IINC:
+ variables.store(variableIndex,
+ variables.iload(variableIndex).add(
+ valueFactory.createIntegerValue(variableInstruction.constant)));
+ break;
+
+ case InstructionConstants.OP_RET:
+ // The return address should be in the last offset of the
+ // given instruction offset variable (even though there may
+ // be other offsets).
+ InstructionOffsetValue instructionOffsetValue = variables.oload(variableIndex);
+ branchUnit.branch(clazz,
+ codeAttribute,
+ offset,
+ instructionOffsetValue.instructionOffset(instructionOffsetValue.instructionOffsetCount()-1));
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unknown variable instruction ["+variableInstruction.opcode+"]");
+ }
+ }
+
+
+ public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)
+ {
+ int branchTarget = offset + branchInstruction.branchOffset;
+
+ switch (branchInstruction.opcode)
+ {
+ case InstructionConstants.OP_IFEQ:
+ branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
+ stack.ipop().equal(valueFactory.createIntegerValue(0)));
+ break;
+
+ case InstructionConstants.OP_IFNE:
+ branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
+ stack.ipop().notEqual(valueFactory.createIntegerValue(0)));
+ break;
+
+ case InstructionConstants.OP_IFLT:
+ branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
+ stack.ipop().lessThan(valueFactory.createIntegerValue(0)));
+ break;
+
+ case InstructionConstants.OP_IFGE:
+ branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
+ stack.ipop().greaterThanOrEqual(valueFactory.createIntegerValue(0)));
+ break;
+
+ case InstructionConstants.OP_IFGT:
+ branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
+ stack.ipop().greaterThan(valueFactory.createIntegerValue(0)));
+ break;
+
+ case InstructionConstants.OP_IFLE:
+ branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
+ stack.ipop().lessThanOrEqual(valueFactory.createIntegerValue(0)));
+ break;
+
+
+ case InstructionConstants.OP_IFICMPEQ:
+ branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
+ stack.ipop().equal(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_IFICMPNE:
+ branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
+ stack.ipop().notEqual(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_IFICMPLT:
+ // Note that the stack entries are popped in reverse order.
+ branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
+ stack.ipop().greaterThan(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_IFICMPGE:
+ // Note that the stack entries are popped in reverse order.
+ branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
+ stack.ipop().lessThanOrEqual(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_IFICMPGT:
+ // Note that the stack entries are popped in reverse order.
+ branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
+ stack.ipop().lessThan(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_IFICMPLE:
+ // Note that the stack entries are popped in reverse order.
+ branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
+ stack.ipop().greaterThanOrEqual(stack.ipop()));
+ break;
+
+ case InstructionConstants.OP_IFACMPEQ:
+ branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
+ stack.apop().equal(stack.apop()));
+ break;
+
+ case InstructionConstants.OP_IFACMPNE:
+ branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
+ stack.apop().notEqual(stack.apop()));
+ break;
+
+ case InstructionConstants.OP_GOTO:
+ case InstructionConstants.OP_GOTO_W:
+ branchUnit.branch(clazz, codeAttribute, offset, branchTarget);
+ break;
+
+
+ case InstructionConstants.OP_JSR:
+ case InstructionConstants.OP_JSR_W:
+ stack.push(new InstructionOffsetValue(offset +
+ branchInstruction.length(offset)));
+ branchUnit.branch(clazz, codeAttribute, offset, branchTarget);
+ break;
+
+ case InstructionConstants.OP_IFNULL:
+ branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
+ stack.apop().isNull());
+ break;
+
+ case InstructionConstants.OP_IFNONNULL:
+ branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
+ stack.apop().isNotNull());
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unknown branch instruction ["+branchInstruction.opcode+"]");
+ }
+ }
+
+
+ public void visitTableSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction)
+ {
+ IntegerValue indexValue = stack.ipop();
+
+ // If there is no definite branch in any of the cases below,
+ // branch to the default offset.
+ branchUnit.branch(clazz, codeAttribute,
+ offset,
+ offset + tableSwitchInstruction.defaultOffset);
+
+ for (int index = 0; index < tableSwitchInstruction.jumpOffsets.length; index++)
+ {
+ int conditional = indexValue.equal(valueFactory.createIntegerValue(
+ tableSwitchInstruction.lowCase + index));
+ branchUnit.branchConditionally(clazz, codeAttribute,
+ offset,
+ offset + tableSwitchInstruction.jumpOffsets[index],
+ conditional);
+
+ // If this branch is always taken, we can skip the rest.
+ if (conditional == Value.ALWAYS)
+ {
+ break;
+ }
+ }
+ }
+
+
+ public void visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction)
+ {
+ IntegerValue indexValue = stack.ipop();
+
+ // If there is no definite branch in any of the cases below,
+ // branch to the default offset.
+ branchUnit.branch(clazz, codeAttribute,
+ offset,
+ offset + lookUpSwitchInstruction.defaultOffset);
+
+ for (int index = 0; index < lookUpSwitchInstruction.jumpOffsets.length; index++)
+ {
+ int conditional = indexValue.equal(valueFactory.createIntegerValue(
+ lookUpSwitchInstruction.cases[index]));
+ branchUnit.branchConditionally(clazz, codeAttribute,
+ offset,
+ offset + lookUpSwitchInstruction.jumpOffsets[index],
+ conditional);
+
+ // If this branch is always taken, we can skip the rest.
+ if (conditional == Value.ALWAYS)
+ {
+ break;
+ }
+ }
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant)
+ {
+ cpValue = valueFactory.createIntegerValue(integerConstant.getValue());
+ }
+
+ public void visitLongConstant(Clazz clazz, LongConstant longConstant)
+ {
+ cpValue = valueFactory.createLongValue(longConstant.getValue());
+ }
+
+ public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant)
+ {
+ cpValue = valueFactory.createFloatValue(floatConstant.getValue());
+ }
+
+ public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)
+ {
+ cpValue = valueFactory.createDoubleValue(doubleConstant.getValue());
+ }
+
+ public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
+ {
+ cpValue = valueFactory.createReferenceValue(ClassConstants.INTERNAL_NAME_JAVA_LANG_STRING,
+ stringConstant.javaLangStringClass,
+ false);
+ }
+
+ public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
+ {
+ cpValue = handleClassConstantAsClassValue ?
+ valueFactory.createReferenceValue(ClassConstants.INTERNAL_NAME_JAVA_LANG_CLASS,
+ classConstant.javaLangClassClass,
+ false) :
+ valueFactory.createReferenceValue(classConstant.getName(clazz),
+ classConstant.referencedClass,
+ false);
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Returns the Value of the constant pool element at the given index.
+ */
+ private Value cpValue(Clazz clazz,
+ int constantIndex)
+ {
+ return cpValue(clazz, constantIndex, false);
+ }
+
+
+ /**
+ * Returns the Value of the constant pool element at the given index.
+ */
+ private Value cpValue(Clazz clazz,
+ int constantIndex,
+ boolean handleClassConstantAsClassValue)
+ {
+ this.handleClassConstantAsClassValue = handleClassConstantAsClassValue;
+
+ // Visit the constant pool entry to get its return value.
+ clazz.constantPoolEntryAccept(constantIndex, this);
+
+ return cpValue;
+ }
+}