summaryrefslogtreecommitdiffstats
path: root/src/proguard/classfile/instruction
diff options
context:
space:
mode:
authorJoe Onorato <joeo@android.com>2009-08-31 10:12:00 -0700
committerJoe Onorato <joeo@android.com>2009-08-31 10:12:00 -0700
commitb72c5c2e5482cf10117b2b25f642f7616b2326c3 (patch)
treef02ba1bc29f4fe6853d9b7008eed37cdcfb96e81 /src/proguard/classfile/instruction
parenta23344a828357fe4b6596f8af5fed467d72757ab (diff)
downloadexternal_proguard-b72c5c2e5482cf10117b2b25f642f7616b2326c3.tar.gz
external_proguard-b72c5c2e5482cf10117b2b25f642f7616b2326c3.tar.bz2
external_proguard-b72c5c2e5482cf10117b2b25f642f7616b2326c3.zip
Diffstat (limited to 'src/proguard/classfile/instruction')
-rw-r--r--src/proguard/classfile/instruction/BranchInstruction.java180
-rw-r--r--src/proguard/classfile/instruction/ConstantInstruction.java303
-rw-r--r--src/proguard/classfile/instruction/Instruction.java920
-rw-r--r--src/proguard/classfile/instruction/InstructionConstants.java449
-rw-r--r--src/proguard/classfile/instruction/InstructionFactory.java299
-rw-r--r--src/proguard/classfile/instruction/InstructionUtil.java67
-rw-r--r--src/proguard/classfile/instruction/LookUpSwitchInstruction.java135
-rw-r--r--src/proguard/classfile/instruction/SimpleInstruction.java255
-rw-r--r--src/proguard/classfile/instruction/SwitchInstruction.java83
-rw-r--r--src/proguard/classfile/instruction/TableSwitchInstruction.java139
-rw-r--r--src/proguard/classfile/instruction/VariableInstruction.java372
-rw-r--r--src/proguard/classfile/instruction/package.html9
-rw-r--r--src/proguard/classfile/instruction/visitor/AllInstructionVisitor.java56
-rw-r--r--src/proguard/classfile/instruction/visitor/InstructionCounter.java59
-rw-r--r--src/proguard/classfile/instruction/visitor/InstructionVisitor.java42
-rw-r--r--src/proguard/classfile/instruction/visitor/MultiInstructionVisitor.java131
-rw-r--r--src/proguard/classfile/instruction/visitor/package.html3
17 files changed, 3502 insertions, 0 deletions
diff --git a/src/proguard/classfile/instruction/BranchInstruction.java b/src/proguard/classfile/instruction/BranchInstruction.java
new file mode 100644
index 0000000..2baa917
--- /dev/null
+++ b/src/proguard/classfile/instruction/BranchInstruction.java
@@ -0,0 +1,180 @@
+/*
+ * 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.classfile.instruction;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.CodeAttribute;
+import proguard.classfile.instruction.visitor.InstructionVisitor;
+
+/**
+ * This interface describes an instruction that branches to a given offset in
+ * the code.
+ *
+ * @author Eric Lafortune
+ */
+public class BranchInstruction extends Instruction
+{
+ public int branchOffset;
+
+
+ /**
+ * Creates an uninitialized BranchInstruction.
+ */
+ public BranchInstruction() {}
+
+
+ public BranchInstruction(byte opcode, int branchOffset)
+ {
+ this.opcode = opcode;
+ this.branchOffset = branchOffset;
+ }
+
+
+ /**
+ * Copies the given instruction into this instruction.
+ * @param branchInstruction the instruction to be copied.
+ * @return this instruction.
+ */
+ public BranchInstruction copy(BranchInstruction branchInstruction)
+ {
+ this.opcode = branchInstruction.opcode;
+ this.branchOffset = branchInstruction.branchOffset;
+
+ return this;
+ }
+
+
+ // Implementations for Instruction.
+
+ public byte canonicalOpcode()
+ {
+ // Remove the _w extension, if any.
+ switch (opcode)
+ {
+ case InstructionConstants.OP_GOTO_W: return InstructionConstants.OP_GOTO;
+
+ case InstructionConstants.OP_JSR_W: return InstructionConstants.OP_JSR;
+
+ default: return opcode;
+ }
+ }
+
+ public Instruction shrink()
+ {
+ // Do we need an ordinary branch or a wide branch?
+ if (requiredBranchOffsetSize() == 2)
+ {
+ // Can we replace the wide branch by an ordinary branch?
+ if (opcode == InstructionConstants.OP_GOTO_W)
+ {
+ opcode = InstructionConstants.OP_GOTO;
+ }
+ else if (opcode == InstructionConstants.OP_JSR_W)
+ {
+ opcode = InstructionConstants.OP_JSR;
+ }
+ }
+ else
+ {
+ // Should we replace the ordinary branch by a wide branch?
+ if (opcode == InstructionConstants.OP_GOTO)
+ {
+ opcode = InstructionConstants.OP_GOTO_W;
+ }
+ else if (opcode == InstructionConstants.OP_JSR)
+ {
+ opcode = InstructionConstants.OP_JSR_W;
+ }
+ else
+ {
+ throw new IllegalArgumentException("Branch instruction can't be widened ("+this.toString()+")");
+ }
+ }
+
+ return this;
+ }
+
+ protected void readInfo(byte[] code, int offset)
+ {
+ branchOffset = readSignedValue(code, offset, branchOffsetSize());
+ }
+
+
+ protected void writeInfo(byte[] code, int offset)
+ {
+ if (requiredBranchOffsetSize() > branchOffsetSize())
+ {
+ throw new IllegalArgumentException("Instruction has invalid branch offset size ("+this.toString(offset)+")");
+ }
+
+ writeSignedValue(code, offset, branchOffset, branchOffsetSize());
+ }
+
+
+ public int length(int offset)
+ {
+ return 1 + branchOffsetSize();
+ }
+
+
+ public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, InstructionVisitor instructionVisitor)
+ {
+ instructionVisitor.visitBranchInstruction(clazz, method, codeAttribute, offset, this);
+ }
+
+
+ public String toString(int offset)
+ {
+ return "["+offset+"] "+toString()+" (target="+(offset+branchOffset)+")";
+ }
+
+
+ // Implementations for Object.
+
+ public String toString()
+ {
+ return getName()+" "+(branchOffset >= 0 ? "+" : "")+branchOffset;
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Returns the branch offset size for this instruction.
+ */
+ private int branchOffsetSize()
+ {
+ return opcode == InstructionConstants.OP_GOTO_W ||
+ opcode == InstructionConstants.OP_JSR_W ? 4 :
+ 2;
+ }
+
+
+ /**
+ * Computes the required branch offset size for this instruction's branch
+ * offset.
+ */
+ private int requiredBranchOffsetSize()
+ {
+ return branchOffset << 16 >> 16 == branchOffset ? 2 :
+ 4;
+ }
+}
diff --git a/src/proguard/classfile/instruction/ConstantInstruction.java b/src/proguard/classfile/instruction/ConstantInstruction.java
new file mode 100644
index 0000000..6c2d1a3
--- /dev/null
+++ b/src/proguard/classfile/instruction/ConstantInstruction.java
@@ -0,0 +1,303 @@
+/*
+ * 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.classfile.instruction;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.CodeAttribute;
+import proguard.classfile.constant.*;
+import proguard.classfile.constant.visitor.ConstantVisitor;
+import proguard.classfile.instruction.visitor.InstructionVisitor;
+import proguard.classfile.util.ClassUtil;
+
+/**
+ * This Instruction represents an instruction that refers to an entry in the
+ * constant pool.
+ *
+ * @author Eric Lafortune
+ */
+public class ConstantInstruction extends Instruction
+implements ConstantVisitor
+{
+ public int constantIndex;
+ public int constant;
+
+
+ // Fields acting as return parameters for the ConstantVisitor methods.
+ private int parameterStackDelta;
+ private int typeStackDelta;
+
+
+ /**
+ * Creates an uninitialized ConstantInstruction.
+ */
+ public ConstantInstruction() {}
+
+
+ /**
+ * Creates a new ConstantInstruction with the given opcode and constant pool
+ * index.
+ */
+ public ConstantInstruction(byte opcode, int constantIndex)
+ {
+ this(opcode, constantIndex, 0);
+ }
+
+
+ /**
+ * Creates a new ConstantInstruction with the given opcode, constant pool
+ * index, and constant.
+ */
+ public ConstantInstruction(byte opcode, int constantIndex, int constant)
+ {
+ this.opcode = opcode;
+ this.constantIndex = constantIndex;
+ this.constant = constant;
+ }
+
+
+ /**
+ * Copies the given instruction into this instruction.
+ * @param constantInstruction the instruction to be copied.
+ * @return this instruction.
+ */
+ public ConstantInstruction copy(ConstantInstruction constantInstruction)
+ {
+ this.opcode = constantInstruction.opcode;
+ this.constantIndex = constantInstruction.constantIndex;
+ this.constant = constantInstruction.constant;
+
+ return this;
+ }
+
+
+ // Implementations for Instruction.
+
+ public byte canonicalOpcode()
+ {
+ // Remove the _w extension, if any.
+ switch (opcode)
+ {
+ case InstructionConstants.OP_LDC_W:
+ case InstructionConstants.OP_LDC2_W: return InstructionConstants.OP_LDC;
+
+ default: return opcode;
+ }
+ }
+
+ public Instruction shrink()
+ {
+ // Do we need a short index or a long index?
+ if (requiredConstantIndexSize() == 1)
+ {
+ // Can we replace the long instruction by a short instruction?
+ if (opcode == InstructionConstants.OP_LDC_W)
+ {
+ opcode = InstructionConstants.OP_LDC;
+ }
+ }
+ else
+ {
+ // Should we replace the short instruction by a long instruction?
+ if (opcode == InstructionConstants.OP_LDC)
+ {
+ opcode = InstructionConstants.OP_LDC_W;
+ }
+ }
+
+ return this;
+ }
+
+ protected void readInfo(byte[] code, int offset)
+ {
+ int constantIndexSize = constantIndexSize();
+ int constantSize = constantSize();
+
+ constantIndex = readValue(code, offset, constantIndexSize); offset += constantIndexSize;
+ constant = readValue(code, offset, constantSize);
+ }
+
+
+ protected void writeInfo(byte[] code, int offset)
+ {
+ int constantIndexSize = constantIndexSize();
+ int constantSize = constantSize();
+
+ if (requiredConstantIndexSize() > constantIndexSize)
+ {
+ throw new IllegalArgumentException("Instruction has invalid constant index size ("+this.toString(offset)+")");
+ }
+
+ writeValue(code, offset, constantIndex, constantIndexSize); offset += constantIndexSize;
+ writeValue(code, offset, constant, constantSize);
+ }
+
+
+ public int length(int offset)
+ {
+ return 1 + constantIndexSize() + constantSize();
+ }
+
+
+ public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, InstructionVisitor instructionVisitor)
+ {
+ instructionVisitor.visitConstantInstruction(clazz, method, codeAttribute, offset, this);
+ }
+
+
+ public int stackPopCount(Clazz clazz)
+ {
+ int stackPopCount = super.stackPopCount(clazz);
+
+ // Some special cases.
+ switch (opcode)
+ {
+ case InstructionConstants.OP_MULTIANEWARRAY:
+ // For each dimension, an integer size is popped from the stack.
+ stackPopCount += constant;
+ break;
+
+ case InstructionConstants.OP_PUTSTATIC:
+ case InstructionConstants.OP_PUTFIELD:
+ // The field value is be popped from the stack.
+ clazz.constantPoolEntryAccept(constantIndex, this);
+ stackPopCount += typeStackDelta;
+ break;
+
+ case InstructionConstants.OP_INVOKEVIRTUAL:
+ case InstructionConstants.OP_INVOKESPECIAL:
+ case InstructionConstants.OP_INVOKESTATIC:
+ case InstructionConstants.OP_INVOKEINTERFACE:
+ // The some parameters may be popped from the stack.
+ clazz.constantPoolEntryAccept(constantIndex, this);
+ stackPopCount += parameterStackDelta;
+ break;
+ }
+
+ return stackPopCount;
+ }
+
+
+ public int stackPushCount(Clazz clazz)
+ {
+ int stackPushCount = super.stackPushCount(clazz);
+
+ // Some special cases.
+ switch (opcode)
+ {
+ case InstructionConstants.OP_GETSTATIC:
+ case InstructionConstants.OP_GETFIELD:
+ case InstructionConstants.OP_INVOKEVIRTUAL:
+ case InstructionConstants.OP_INVOKESPECIAL:
+ case InstructionConstants.OP_INVOKESTATIC:
+ case InstructionConstants.OP_INVOKEINTERFACE:
+ // The field value or a return value may be pushed onto the stack.
+ clazz.constantPoolEntryAccept(constantIndex, this);
+ stackPushCount += typeStackDelta;
+ break;
+ }
+
+ return stackPushCount;
+ }
+
+
+ // Implementations for ConstantVisitor.
+
+ public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant) {}
+ public void visitLongConstant(Clazz clazz, LongConstant longConstant) {}
+ public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant) {}
+ public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant) {}
+ public void visitStringConstant(Clazz clazz, StringConstant stringConstant) {}
+ public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) {}
+ public void visitClassConstant(Clazz clazz, ClassConstant classConstant) {}
+ public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) {}
+
+
+ public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)
+ {
+ String type = fieldrefConstant.getType(clazz);
+
+ typeStackDelta = ClassUtil.internalTypeSize(ClassUtil.internalMethodReturnType(type));
+ }
+
+
+ public void visitInterfaceMethodrefConstant(Clazz clazz, InterfaceMethodrefConstant interfaceMethodrefConstant)
+ {
+ visitRefConstant(clazz, interfaceMethodrefConstant);
+ }
+
+
+ public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant)
+ {
+ visitRefConstant(clazz, methodrefConstant);
+ }
+
+
+ private void visitRefConstant(Clazz clazz, RefConstant methodrefConstant)
+ {
+ String type = methodrefConstant.getType(clazz);
+
+ parameterStackDelta = ClassUtil.internalMethodParameterSize(type);
+ typeStackDelta = ClassUtil.internalTypeSize(ClassUtil.internalMethodReturnType(type));
+ }
+
+
+ // Implementations for Object.
+
+ public String toString()
+ {
+ return getName()+" #"+constantIndex;
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Returns the constant pool index size for this instruction.
+ */
+ private int constantIndexSize()
+ {
+ return opcode == InstructionConstants.OP_LDC ? 1 :
+ 2;
+ }
+
+
+ /**
+ * Returns the constant size for this instruction.
+ */
+ private int constantSize()
+ {
+ return opcode == InstructionConstants.OP_MULTIANEWARRAY ? 1 :
+ opcode == InstructionConstants.OP_INVOKEINTERFACE ? 2 :
+ 0;
+ }
+
+
+ /**
+ * Computes the required constant pool index size for this instruction's
+ * constant pool index.
+ */
+ private int requiredConstantIndexSize()
+ {
+ return (constantIndex & 0xff) == constantIndex ? 1 :
+ (constantIndex & 0xffff) == constantIndex ? 2 :
+ 4;
+ }
+}
diff --git a/src/proguard/classfile/instruction/Instruction.java b/src/proguard/classfile/instruction/Instruction.java
new file mode 100644
index 0000000..8437495
--- /dev/null
+++ b/src/proguard/classfile/instruction/Instruction.java
@@ -0,0 +1,920 @@
+/*
+ * 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.classfile.instruction;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.CodeAttribute;
+import proguard.classfile.instruction.visitor.InstructionVisitor;
+
+/**
+ * Base class for representing instructions.
+ *
+ * @author Eric Lafortune
+ */
+public abstract class Instruction
+{
+ // An array for marking Category 2 instructions.
+ private static final boolean[] IS_CATEGORY2 = new boolean[]
+ {
+ false, // nop
+ false, // aconst_null
+ false, // iconst_m1
+ false, // iconst_0
+ false, // iconst_1
+ false, // iconst_2
+ false, // iconst_3
+ false, // iconst_4
+ false, // iconst_5
+ true, // lconst_0
+ true, // lconst_1
+ false, // fconst_0
+ false, // fconst_1
+ false, // fconst_2
+ true, // dconst_0
+ true, // dconst_1
+ false, // bipush
+ false, // sipush
+ false, // ldc
+ false, // ldc_w
+ true, // ldc2_w
+ false, // iload
+ true, // lload
+ false, // fload
+ true, // dload
+ false, // aload
+ false, // iload_0
+ false, // iload_1
+ false, // iload_2
+ false, // iload_3
+ true, // lload_0
+ true, // lload_1
+ true, // lload_2
+ true, // lload_3
+ false, // fload_0
+ false, // fload_1
+ false, // fload_2
+ false, // fload_3
+ true, // dload_0
+ true, // dload_1
+ true, // dload_2
+ true, // dload_3
+ false, // aload_0
+ false, // aload_1
+ false, // aload_2
+ false, // aload_3
+ false, // iaload
+ true, // laload
+ false, // faload
+ true, // daload
+ false, // aaload
+ false, // baload
+ false, // caload
+ false, // saload
+ false, // istore
+ true, // lstore
+ false, // fstore
+ true, // dstore
+ false, // astore
+ false, // istore_0
+ false, // istore_1
+ false, // istore_2
+ false, // istore_3
+ true, // lstore_0
+ true, // lstore_1
+ true, // lstore_2
+ true, // lstore_3
+ false, // fstore_0
+ false, // fstore_1
+ false, // fstore_2
+ false, // fstore_3
+ true, // dstore_0
+ true, // dstore_1
+ true, // dstore_2
+ true, // dstore_3
+ false, // astore_0
+ false, // astore_1
+ false, // astore_2
+ false, // astore_3
+ false, // iastore
+ true, // lastore
+ false, // fastore
+ true, // dastore
+ false, // aastore
+ false, // bastore
+ false, // castore
+ false, // sastore
+ false, // pop
+ true, // pop2
+ false, // dup
+ false, // dup_x1
+ false, // dup_x2
+ true, // dup2
+ true, // dup2_x1
+ true, // dup2_x2
+ false, // swap
+ false, // iadd
+ true, // ladd
+ false, // fadd
+ true, // dadd
+ false, // isub
+ true, // lsub
+ false, // fsub
+ true, // dsub
+ false, // imul
+ true, // lmul
+ false, // fmul
+ true, // dmul
+ false, // idiv
+ true, // ldiv
+ false, // fdiv
+ true, // ddiv
+ false, // irem
+ true, // lrem
+ false, // frem
+ true, // drem
+ false, // ineg
+ true, // lneg
+ false, // fneg
+ true, // dneg
+ false, // ishl
+ true, // lshl
+ false, // ishr
+ true, // lshr
+ false, // iushr
+ true, // lushr
+ false, // iand
+ true, // land
+ false, // ior
+ true, // lor
+ false, // ixor
+ true, // lxor
+ false, // iinc
+ false, // i2l
+ false, // i2f
+ false, // i2d
+ true, // l2i
+ true, // l2f
+ true, // l2d
+ false, // f2i
+ false, // f2l
+ false, // f2d
+ true, // d2i
+ true, // d2l
+ true, // d2f
+ false, // i2b
+ false, // i2c
+ false, // i2s
+ true, // lcmp
+ false, // fcmpl
+ false, // fcmpg
+ true, // dcmpl
+ true, // dcmpg
+ false, // ifeq
+ false, // ifne
+ false, // iflt
+ false, // ifge
+ false, // ifgt
+ false, // ifle
+ false, // ificmpeq
+ false, // ificmpne
+ false, // ificmplt
+ false, // ificmpge
+ false, // ificmpgt
+ false, // ificmple
+ false, // ifacmpeq
+ false, // ifacmpne
+ false, // goto
+ false, // jsr
+ false, // ret
+ false, // tableswitch
+ false, // lookupswitch
+ false, // ireturn
+ true, // lreturn
+ false, // freturn
+ true, // dreturn
+ false, // areturn
+ false, // return
+ false, // getstatic
+ false, // putstatic
+ false, // getfield
+ false, // putfield
+ false, // invokevirtual
+ false, // invokespecial
+ false, // invokestatic
+ false, // invokeinterface
+ false, // unused
+ false, // new
+ false, // newarray
+ false, // anewarray
+ false, // arraylength
+ false, // athrow
+ false, // checkcast
+ false, // instanceof
+ false, // monitorenter
+ false, // monitorexit
+ false, // wide
+ false, // multianewarray
+ false, // ifnull
+ false, // ifnonnull
+ false, // goto_w
+ false, // jsr_w
+ };
+
+
+ // An array containing the fixed number of entries popped from the stack,
+ // for all instructions.
+ private static final int[] STACK_POP_COUNTS = new int[]
+ {
+ 0, // nop
+ 0, // aconst_null
+ 0, // iconst_m1
+ 0, // iconst_0
+ 0, // iconst_1
+ 0, // iconst_2
+ 0, // iconst_3
+ 0, // iconst_4
+ 0, // iconst_5
+ 0, // lconst_0
+ 0, // lconst_1
+ 0, // fconst_0
+ 0, // fconst_1
+ 0, // fconst_2
+ 0, // dconst_0
+ 0, // dconst_1
+ 0, // bipush
+ 0, // sipush
+ 0, // ldc
+ 0, // ldc_w
+ 0, // ldc2_w
+ 0, // iload
+ 0, // lload
+ 0, // fload
+ 0, // dload
+ 0, // aload
+ 0, // iload_0
+ 0, // iload_1
+ 0, // iload_2
+ 0, // iload_3
+ 0, // lload_0
+ 0, // lload_1
+ 0, // lload_2
+ 0, // lload_3
+ 0, // fload_0
+ 0, // fload_1
+ 0, // fload_2
+ 0, // fload_3
+ 0, // dload_0
+ 0, // dload_1
+ 0, // dload_2
+ 0, // dload_3
+ 0, // aload_0
+ 0, // aload_1
+ 0, // aload_2
+ 0, // aload_3
+ 2, // iaload
+ 2, // laload
+ 2, // faload
+ 2, // daload
+ 2, // aaload
+ 2, // baload
+ 2, // caload
+ 2, // saload
+ 1, // istore
+ 2, // lstore
+ 1, // fstore
+ 2, // dstore
+ 1, // astore
+ 1, // istore_0
+ 1, // istore_1
+ 1, // istore_2
+ 1, // istore_3
+ 2, // lstore_0
+ 2, // lstore_1
+ 2, // lstore_2
+ 2, // lstore_3
+ 1, // fstore_0
+ 1, // fstore_1
+ 1, // fstore_2
+ 1, // fstore_3
+ 2, // dstore_0
+ 2, // dstore_1
+ 2, // dstore_2
+ 2, // dstore_3
+ 1, // astore_0
+ 1, // astore_1
+ 1, // astore_2
+ 1, // astore_3
+ 3, // iastore
+ 4, // lastore
+ 3, // fastore
+ 4, // dastore
+ 3, // aastore
+ 3, // bastore
+ 3, // castore
+ 3, // sastore
+ 1, // pop
+ 2, // pop2
+ 1, // dup
+ 2, // dup_x1
+ 3, // dup_x2
+ 2, // dup2
+ 3, // dup2_x1
+ 4, // dup2_x2
+ 2, // swap
+ 2, // iadd
+ 4, // ladd
+ 2, // fadd
+ 4, // dadd
+ 2, // isub
+ 4, // lsub
+ 2, // fsub
+ 4, // dsub
+ 2, // imul
+ 4, // lmul
+ 2, // fmul
+ 4, // dmul
+ 2, // idiv
+ 4, // ldiv
+ 2, // fdiv
+ 4, // ddiv
+ 2, // irem
+ 4, // lrem
+ 2, // frem
+ 4, // drem
+ 1, // ineg
+ 2, // lneg
+ 1, // fneg
+ 2, // dneg
+ 2, // ishl
+ 3, // lshl
+ 2, // ishr
+ 3, // lshr
+ 2, // iushr
+ 3, // lushr
+ 2, // iand
+ 4, // land
+ 2, // ior
+ 4, // lor
+ 2, // ixor
+ 4, // lxor
+ 0, // iinc
+ 1, // i2l
+ 1, // i2f
+ 1, // i2d
+ 2, // l2i
+ 2, // l2f
+ 2, // l2d
+ 1, // f2i
+ 1, // f2l
+ 1, // f2d
+ 2, // d2i
+ 2, // d2l
+ 2, // d2f
+ 1, // i2b
+ 1, // i2c
+ 1, // i2s
+ 4, // lcmp
+ 2, // fcmpl
+ 2, // fcmpg
+ 4, // dcmpl
+ 4, // dcmpg
+ 1, // ifeq
+ 1, // ifne
+ 1, // iflt
+ 1, // ifge
+ 1, // ifgt
+ 1, // ifle
+ 2, // ificmpeq
+ 2, // ificmpne
+ 2, // ificmplt
+ 2, // ificmpge
+ 2, // ificmpgt
+ 2, // ificmple
+ 2, // ifacmpeq
+ 2, // ifacmpne
+ 0, // goto
+ 0, // jsr
+ 0, // ret
+ 1, // tableswitch
+ 1, // lookupswitch
+ 1, // ireturn
+ 2, // lreturn
+ 1, // freturn
+ 2, // dreturn
+ 1, // areturn
+ 0, // return
+ 0, // getstatic
+ 0, // putstatic
+ 1, // getfield
+ 1, // putfield
+ 1, // invokevirtual
+ 1, // invokespecial
+ 0, // invokestatic
+ 1, // invokeinterface
+ 0, // unused
+ 0, // new
+ 1, // newarray
+ 1, // anewarray
+ 1, // arraylength
+ 1, // athrow
+ 1, // checkcast
+ 1, // instanceof
+ 1, // monitorenter
+ 1, // monitorexit
+ 0, // wide
+ 0, // multianewarray
+ 1, // ifnull
+ 1, // ifnonnull
+ 0, // goto_w
+ 0, // jsr_w
+ };
+
+
+ // An array containing the fixed number of entries pushed onto the stack,
+ // for all instructions.
+ private static final int[] STACK_PUSH_COUNTS = new int[]
+ {
+ 0, // nop
+ 1, // aconst_null
+ 1, // iconst_m1
+ 1, // iconst_0
+ 1, // iconst_1
+ 1, // iconst_2
+ 1, // iconst_3
+ 1, // iconst_4
+ 1, // iconst_5
+ 2, // lconst_0
+ 2, // lconst_1
+ 1, // fconst_0
+ 1, // fconst_1
+ 1, // fconst_2
+ 2, // dconst_0
+ 2, // dconst_1
+ 1, // bipush
+ 1, // sipush
+ 1, // ldc
+ 1, // ldc_w
+ 2, // ldc2_w
+ 1, // iload
+ 2, // lload
+ 1, // fload
+ 2, // dload
+ 1, // aload
+ 1, // iload_0
+ 1, // iload_1
+ 1, // iload_2
+ 1, // iload_3
+ 2, // lload_0
+ 2, // lload_1
+ 2, // lload_2
+ 2, // lload_3
+ 1, // fload_0
+ 1, // fload_1
+ 1, // fload_2
+ 1, // fload_3
+ 2, // dload_0
+ 2, // dload_1
+ 2, // dload_2
+ 2, // dload_3
+ 1, // aload_0
+ 1, // aload_1
+ 1, // aload_2
+ 1, // aload_3
+ 1, // iaload
+ 2, // laload
+ 1, // faload
+ 2, // daload
+ 1, // aaload
+ 1, // baload
+ 1, // caload
+ 1, // saload
+ 0, // istore
+ 0, // lstore
+ 0, // fstore
+ 0, // dstore
+ 0, // astore
+ 0, // istore_0
+ 0, // istore_1
+ 0, // istore_2
+ 0, // istore_3
+ 0, // lstore_0
+ 0, // lstore_1
+ 0, // lstore_2
+ 0, // lstore_3
+ 0, // fstore_0
+ 0, // fstore_1
+ 0, // fstore_2
+ 0, // fstore_3
+ 0, // dstore_0
+ 0, // dstore_1
+ 0, // dstore_2
+ 0, // dstore_3
+ 0, // astore_0
+ 0, // astore_1
+ 0, // astore_2
+ 0, // astore_3
+ 0, // iastore
+ 0, // lastore
+ 0, // fastore
+ 0, // dastore
+ 0, // aastore
+ 0, // bastore
+ 0, // castore
+ 0, // sastore
+ 0, // pop
+ 0, // pop2
+ 2, // dup
+ 3, // dup_x1
+ 4, // dup_x2
+ 4, // dup2
+ 5, // dup2_x1
+ 6, // dup2_x2
+ 2, // swap
+ 1, // iadd
+ 2, // ladd
+ 1, // fadd
+ 2, // dadd
+ 1, // isub
+ 2, // lsub
+ 1, // fsub
+ 2, // dsub
+ 1, // imul
+ 2, // lmul
+ 1, // fmul
+ 2, // dmul
+ 1, // idiv
+ 2, // ldiv
+ 1, // fdiv
+ 2, // ddiv
+ 1, // irem
+ 2, // lrem
+ 1, // frem
+ 2, // drem
+ 1, // ineg
+ 2, // lneg
+ 1, // fneg
+ 2, // dneg
+ 1, // ishl
+ 2, // lshl
+ 1, // ishr
+ 2, // lshr
+ 1, // iushr
+ 2, // lushr
+ 1, // iand
+ 2, // land
+ 1, // ior
+ 2, // lor
+ 1, // ixor
+ 2, // lxor
+ 0, // iinc
+ 2, // i2l
+ 1, // i2f
+ 2, // i2d
+ 1, // l2i
+ 1, // l2f
+ 2, // l2d
+ 1, // f2i
+ 2, // f2l
+ 2, // f2d
+ 1, // d2i
+ 2, // d2l
+ 1, // d2f
+ 1, // i2b
+ 1, // i2c
+ 1, // i2s
+ 1, // lcmp
+ 1, // fcmpl
+ 1, // fcmpg
+ 1, // dcmpl
+ 1, // dcmpg
+ 0, // ifeq
+ 0, // ifne
+ 0, // iflt
+ 0, // ifge
+ 0, // ifgt
+ 0, // ifle
+ 0, // ificmpeq
+ 0, // ificmpne
+ 0, // ificmplt
+ 0, // ificmpge
+ 0, // ificmpgt
+ 0, // ificmple
+ 0, // ifacmpeq
+ 0, // ifacmpne
+ 0, // goto
+ 1, // jsr
+ 0, // ret
+ 0, // tableswitch
+ 0, // lookupswitch
+ 0, // ireturn
+ 0, // lreturn
+ 0, // freturn
+ 0, // dreturn
+ 0, // areturn
+ 0, // return
+ 0, // getstatic
+ 0, // putstatic
+ 0, // getfield
+ 0, // putfield
+ 0, // invokevirtual
+ 0, // invokespecial
+ 0, // invokestatic
+ 0, // invokeinterface
+ 0, // unused
+ 1, // new
+ 1, // newarray
+ 1, // anewarray
+ 1, // arraylength
+ 0, // athrow
+ 1, // checkcast
+ 1, // instanceof
+ 0, // monitorenter
+ 0, // monitorexit
+ 0, // wide
+ 1, // multianewarray
+ 0, // ifnull
+ 0, // ifnonnull
+ 0, // goto_w
+ 1, // jsr_w
+ };
+
+
+ public byte opcode;
+
+
+ /**
+ * Returns the canonical opcode of this instruction, i.e. typically the
+ * opcode whose extension has been removed.
+ */
+ public byte canonicalOpcode()
+ {
+ return opcode;
+ }
+
+
+ /**
+ * Shrinks this instruction to its shortest possible form.
+ * @return this instruction.
+ */
+ public abstract Instruction shrink();
+
+
+
+ /**
+ * Writes the Instruction at the given offset in the given code attribute.
+ */
+ public final void write(CodeAttribute codeAttribute, int offset)
+ {
+ write(codeAttribute.code, offset);
+ }
+
+
+ /**
+ * Writes the Instruction at the given offset in the given code array.
+ */
+ public void write(byte[] code, int offset)
+ {
+ // Write the wide opcode, if necessary.
+ if (isWide())
+ {
+ code[offset++] = InstructionConstants.OP_WIDE;
+ }
+
+ // Write the opcode.
+ code[offset++] = opcode;
+
+ // Write any additional arguments.
+ writeInfo(code, offset);
+ }
+
+
+ /**
+ * Returns whether the instruction is wide, i.e. preceded by a wide opcode.
+ * With the current specifications, only variable instructions can be wide.
+ */
+ protected boolean isWide()
+ {
+ return false;
+ }
+
+
+ /**
+ * Reads the data following the instruction opcode.
+ */
+ protected abstract void readInfo(byte[] code, int offset);
+
+
+ /**
+ * Writes data following the instruction opcode.
+ */
+ protected abstract void writeInfo(byte[] code, int offset);
+
+
+ /**
+ * Returns the length in bytes of the instruction.
+ */
+ public abstract int length(int offset);
+
+
+ /**
+ * Accepts the given visitor.
+ */
+ public abstract void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, InstructionVisitor instructionVisitor);
+
+
+ /**
+ * Returns a description of the instruction, at the given offset.
+ */
+ public String toString(int offset)
+ {
+ return "["+offset+"] "+ this.toString();
+ }
+
+
+ /**
+ * Returns the name of the instruction.
+ */
+ public String getName()
+ {
+ return InstructionConstants.NAMES[opcode & 0xff];
+ }
+
+
+ /**
+ * Returns whether the instruction is a Category 2 instruction. This means
+ * that it operates on long or double arguments.
+ */
+ public boolean isCategory2()
+ {
+ return IS_CATEGORY2[opcode & 0xff];
+ }
+
+
+ /**
+ * Returns the number of entries popped from the stack during the execution
+ * of the instruction.
+ */
+ public int stackPopCount(Clazz clazz)
+ {
+ return STACK_POP_COUNTS[opcode & 0xff];
+ }
+
+
+ /**
+ * Returns the number of entries pushed onto the stack during the execution
+ * of the instruction.
+ */
+ public int stackPushCount(Clazz clazz)
+ {
+ return STACK_PUSH_COUNTS[opcode & 0xff];
+ }
+
+
+ // Small utility methods.
+
+ protected static int readByte(byte[] code, int offset)
+ {
+ return code[offset] & 0xff;
+ }
+
+ protected static int readShort(byte[] code, int offset)
+ {
+ return ((code[offset++] & 0xff) << 8) |
+ ( code[offset ] & 0xff );
+ }
+
+ protected static int readInt(byte[] code, int offset)
+ {
+ return ( code[offset++] << 24) |
+ ((code[offset++] & 0xff) << 16) |
+ ((code[offset++] & 0xff) << 8) |
+ ( code[offset ] & 0xff );
+ }
+
+ protected static int readValue(byte[] code, int offset, int valueSize)
+ {
+ switch (valueSize)
+ {
+ case 0: return 0;
+ case 1: return readByte( code, offset);
+ case 2: return readShort(code, offset);
+ case 4: return readInt( code, offset);
+ default: throw new IllegalArgumentException("Unsupported value size ["+valueSize+"]");
+ }
+ }
+
+ protected static int readSignedByte(byte[] code, int offset)
+ {
+ return code[offset];
+ }
+
+ protected static int readSignedShort(byte[] code, int offset)
+ {
+ return (code[offset++] << 8) |
+ (code[offset ] & 0xff);
+ }
+
+ protected static int readSignedValue(byte[] code, int offset, int valueSize)
+ {
+ switch (valueSize)
+ {
+ case 0: return 0;
+ case 1: return readSignedByte( code, offset);
+ case 2: return readSignedShort(code, offset);
+ case 4: return readInt( code, offset);
+ default: throw new IllegalArgumentException("Unsupported value size ["+valueSize+"]");
+ }
+ }
+
+ protected static void writeByte(byte[] code, int offset, int value)
+ {
+ if (value > 0xff)
+ {
+ throw new IllegalArgumentException("Unsigned byte value larger than 0xff ["+value+"]");
+ }
+
+ code[offset] = (byte)value;
+ }
+
+ protected static void writeShort(byte[] code, int offset, int value)
+ {
+ if (value > 0xffff)
+ {
+ throw new IllegalArgumentException("Unsigned short value larger than 0xffff ["+value+"]");
+ }
+
+ code[offset++] = (byte)(value >> 8);
+ code[offset ] = (byte)(value );
+ }
+
+ protected static void writeInt(byte[] code, int offset, int value)
+ {
+ code[offset++] = (byte)(value >> 24);
+ code[offset++] = (byte)(value >> 16);
+ code[offset++] = (byte)(value >> 8);
+ code[offset ] = (byte)(value );
+ }
+
+ protected static void writeValue(byte[] code, int offset, int value, int valueSize)
+ {
+ switch (valueSize)
+ {
+ case 0: break;
+ case 1: writeByte( code, offset, value); break;
+ case 2: writeShort(code, offset, value); break;
+ case 4: writeInt( code, offset, value); break;
+ default: throw new IllegalArgumentException("Unsupported value size ["+valueSize+"]");
+ }
+ }
+
+ protected static void writeSignedByte(byte[] code, int offset, int value)
+ {
+ if (value << 24 >> 24 != value)
+ {
+ throw new IllegalArgumentException("Signed byte value out of range ["+value+"]");
+ }
+
+ code[offset] = (byte)value;
+ }
+
+ protected static void writeSignedShort(byte[] code, int offset, int value)
+ {
+ if (value << 16 >> 16 != value)
+ {
+ throw new IllegalArgumentException("Signed short value out of range ["+value+"]");
+ }
+
+ code[offset++] = (byte)(value >> 8);
+ code[offset ] = (byte)(value );
+ }
+
+ protected static void writeSignedValue(byte[] code, int offset, int value, int valueSize)
+ {
+ switch (valueSize)
+ {
+ case 0: break;
+ case 1: writeSignedByte( code, offset, value); break;
+ case 2: writeSignedShort(code, offset, value); break;
+ case 4: writeInt( code, offset, value); break;
+ default: throw new IllegalArgumentException("Unsupported value size ["+valueSize+"]");
+ }
+ }
+}
diff --git a/src/proguard/classfile/instruction/InstructionConstants.java b/src/proguard/classfile/instruction/InstructionConstants.java
new file mode 100644
index 0000000..78730b3
--- /dev/null
+++ b/src/proguard/classfile/instruction/InstructionConstants.java
@@ -0,0 +1,449 @@
+/*
+ * 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.classfile.instruction;
+
+/**
+ * Representation of an instruction.
+ *
+ * @author Eric Lafortune
+ */
+public interface InstructionConstants
+{
+ public static final byte OP_NOP = 0;
+ public static final byte OP_ACONST_NULL = 1;
+ public static final byte OP_ICONST_M1 = 2;
+ public static final byte OP_ICONST_0 = 3;
+ public static final byte OP_ICONST_1 = 4;
+ public static final byte OP_ICONST_2 = 5;
+ public static final byte OP_ICONST_3 = 6;
+ public static final byte OP_ICONST_4 = 7;
+ public static final byte OP_ICONST_5 = 8;
+ public static final byte OP_LCONST_0 = 9;
+ public static final byte OP_LCONST_1 = 10;
+ public static final byte OP_FCONST_0 = 11;
+ public static final byte OP_FCONST_1 = 12;
+ public static final byte OP_FCONST_2 = 13;
+ public static final byte OP_DCONST_0 = 14;
+ public static final byte OP_DCONST_1 = 15;
+ public static final byte OP_BIPUSH = 16;
+ public static final byte OP_SIPUSH = 17;
+ public static final byte OP_LDC = 18;
+ public static final byte OP_LDC_W = 19;
+ public static final byte OP_LDC2_W = 20;
+ public static final byte OP_ILOAD = 21;
+ public static final byte OP_LLOAD = 22;
+ public static final byte OP_FLOAD = 23;
+ public static final byte OP_DLOAD = 24;
+ public static final byte OP_ALOAD = 25;
+ public static final byte OP_ILOAD_0 = 26;
+ public static final byte OP_ILOAD_1 = 27;
+ public static final byte OP_ILOAD_2 = 28;
+ public static final byte OP_ILOAD_3 = 29;
+ public static final byte OP_LLOAD_0 = 30;
+ public static final byte OP_LLOAD_1 = 31;
+ public static final byte OP_LLOAD_2 = 32;
+ public static final byte OP_LLOAD_3 = 33;
+ public static final byte OP_FLOAD_0 = 34;
+ public static final byte OP_FLOAD_1 = 35;
+ public static final byte OP_FLOAD_2 = 36;
+ public static final byte OP_FLOAD_3 = 37;
+ public static final byte OP_DLOAD_0 = 38;
+ public static final byte OP_DLOAD_1 = 39;
+ public static final byte OP_DLOAD_2 = 40;
+ public static final byte OP_DLOAD_3 = 41;
+ public static final byte OP_ALOAD_0 = 42;
+ public static final byte OP_ALOAD_1 = 43;
+ public static final byte OP_ALOAD_2 = 44;
+ public static final byte OP_ALOAD_3 = 45;
+ public static final byte OP_IALOAD = 46;
+ public static final byte OP_LALOAD = 47;
+ public static final byte OP_FALOAD = 48;
+ public static final byte OP_DALOAD = 49;
+ public static final byte OP_AALOAD = 50;
+ public static final byte OP_BALOAD = 51;
+ public static final byte OP_CALOAD = 52;
+ public static final byte OP_SALOAD = 53;
+ public static final byte OP_ISTORE = 54;
+ public static final byte OP_LSTORE = 55;
+ public static final byte OP_FSTORE = 56;
+ public static final byte OP_DSTORE = 57;
+ public static final byte OP_ASTORE = 58;
+ public static final byte OP_ISTORE_0 = 59;
+ public static final byte OP_ISTORE_1 = 60;
+ public static final byte OP_ISTORE_2 = 61;
+ public static final byte OP_ISTORE_3 = 62;
+ public static final byte OP_LSTORE_0 = 63;
+ public static final byte OP_LSTORE_1 = 64;
+ public static final byte OP_LSTORE_2 = 65;
+ public static final byte OP_LSTORE_3 = 66;
+ public static final byte OP_FSTORE_0 = 67;
+ public static final byte OP_FSTORE_1 = 68;
+ public static final byte OP_FSTORE_2 = 69;
+ public static final byte OP_FSTORE_3 = 70;
+ public static final byte OP_DSTORE_0 = 71;
+ public static final byte OP_DSTORE_1 = 72;
+ public static final byte OP_DSTORE_2 = 73;
+ public static final byte OP_DSTORE_3 = 74;
+ public static final byte OP_ASTORE_0 = 75;
+ public static final byte OP_ASTORE_1 = 76;
+ public static final byte OP_ASTORE_2 = 77;
+ public static final byte OP_ASTORE_3 = 78;
+ public static final byte OP_IASTORE = 79;
+ public static final byte OP_LASTORE = 80;
+ public static final byte OP_FASTORE = 81;
+ public static final byte OP_DASTORE = 82;
+ public static final byte OP_AASTORE = 83;
+ public static final byte OP_BASTORE = 84;
+ public static final byte OP_CASTORE = 85;
+ public static final byte OP_SASTORE = 86;
+ public static final byte OP_POP = 87;
+ public static final byte OP_POP2 = 88;
+ public static final byte OP_DUP = 89;
+ public static final byte OP_DUP_X1 = 90;
+ public static final byte OP_DUP_X2 = 91;
+ public static final byte OP_DUP2 = 92;
+ public static final byte OP_DUP2_X1 = 93;
+ public static final byte OP_DUP2_X2 = 94;
+ public static final byte OP_SWAP = 95;
+ public static final byte OP_IADD = 96;
+ public static final byte OP_LADD = 97;
+ public static final byte OP_FADD = 98;
+ public static final byte OP_DADD = 99;
+ public static final byte OP_ISUB = 100;
+ public static final byte OP_LSUB = 101;
+ public static final byte OP_FSUB = 102;
+ public static final byte OP_DSUB = 103;
+ public static final byte OP_IMUL = 104;
+ public static final byte OP_LMUL = 105;
+ public static final byte OP_FMUL = 106;
+ public static final byte OP_DMUL = 107;
+ public static final byte OP_IDIV = 108;
+ public static final byte OP_LDIV = 109;
+ public static final byte OP_FDIV = 110;
+ public static final byte OP_DDIV = 111;
+ public static final byte OP_IREM = 112;
+ public static final byte OP_LREM = 113;
+ public static final byte OP_FREM = 114;
+ public static final byte OP_DREM = 115;
+ public static final byte OP_INEG = 116;
+ public static final byte OP_LNEG = 117;
+ public static final byte OP_FNEG = 118;
+ public static final byte OP_DNEG = 119;
+ public static final byte OP_ISHL = 120;
+ public static final byte OP_LSHL = 121;
+ public static final byte OP_ISHR = 122;
+ public static final byte OP_LSHR = 123;
+ public static final byte OP_IUSHR = 124;
+ public static final byte OP_LUSHR = 125;
+ public static final byte OP_IAND = 126;
+ public static final byte OP_LAND = 127;
+ public static final byte OP_IOR = -128;
+ public static final byte OP_LOR = -127;
+ public static final byte OP_IXOR = -126;
+ public static final byte OP_LXOR = -125;
+ public static final byte OP_IINC = -124;
+ public static final byte OP_I2L = -123;
+ public static final byte OP_I2F = -122;
+ public static final byte OP_I2D = -121;
+ public static final byte OP_L2I = -120;
+ public static final byte OP_L2F = -119;
+ public static final byte OP_L2D = -118;
+ public static final byte OP_F2I = -117;
+ public static final byte OP_F2L = -116;
+ public static final byte OP_F2D = -115;
+ public static final byte OP_D2I = -114;
+ public static final byte OP_D2L = -113;
+ public static final byte OP_D2F = -112;
+ public static final byte OP_I2B = -111;
+ public static final byte OP_I2C = -110;
+ public static final byte OP_I2S = -109;
+ public static final byte OP_LCMP = -108;
+ public static final byte OP_FCMPL = -107;
+ public static final byte OP_FCMPG = -106;
+ public static final byte OP_DCMPL = -105;
+ public static final byte OP_DCMPG = -104;
+ public static final byte OP_IFEQ = -103;
+ public static final byte OP_IFNE = -102;
+ public static final byte OP_IFLT = -101;
+ public static final byte OP_IFGE = -100;
+ public static final byte OP_IFGT = -99;
+ public static final byte OP_IFLE = -98;
+ public static final byte OP_IFICMPEQ = -97;
+ public static final byte OP_IFICMPNE = -96;
+ public static final byte OP_IFICMPLT = -95;
+ public static final byte OP_IFICMPGE = -94;
+ public static final byte OP_IFICMPGT = -93;
+ public static final byte OP_IFICMPLE = -92;
+ public static final byte OP_IFACMPEQ = -91;
+ public static final byte OP_IFACMPNE = -90;
+ public static final byte OP_GOTO = -89;
+ public static final byte OP_JSR = -88;
+ public static final byte OP_RET = -87;
+ public static final byte OP_TABLESWITCH = -86;
+ public static final byte OP_LOOKUPSWITCH = -85;
+ public static final byte OP_IRETURN = -84;
+ public static final byte OP_LRETURN = -83;
+ public static final byte OP_FRETURN = -82;
+ public static final byte OP_DRETURN = -81;
+ public static final byte OP_ARETURN = -80;
+ public static final byte OP_RETURN = -79;
+ public static final byte OP_GETSTATIC = -78;
+ public static final byte OP_PUTSTATIC = -77;
+ public static final byte OP_GETFIELD = -76;
+ public static final byte OP_PUTFIELD = -75;
+ public static final byte OP_INVOKEVIRTUAL = -74;
+ public static final byte OP_INVOKESPECIAL = -73;
+ public static final byte OP_INVOKESTATIC = -72;
+ public static final byte OP_INVOKEINTERFACE = -71;
+// public static final byte OP_UNUSED = -70;
+ public static final byte OP_NEW = -69;
+ public static final byte OP_NEWARRAY = -68;
+ public static final byte OP_ANEWARRAY = -67;
+ public static final byte OP_ARRAYLENGTH = -66;
+ public static final byte OP_ATHROW = -65;
+ public static final byte OP_CHECKCAST = -64;
+ public static final byte OP_INSTANCEOF = -63;
+ public static final byte OP_MONITORENTER = -62;
+ public static final byte OP_MONITOREXIT = -61;
+ public static final byte OP_WIDE = -60;
+ public static final byte OP_MULTIANEWARRAY = -59;
+ public static final byte OP_IFNULL = -58;
+ public static final byte OP_IFNONNULL = -57;
+ public static final byte OP_GOTO_W = -56;
+ public static final byte OP_JSR_W = -55;
+
+
+ public static final String[] NAMES =
+ {
+ "nop",
+ "aconst_null",
+ "iconst_m1",
+ "iconst_0",
+ "iconst_1",
+ "iconst_2",
+ "iconst_3",
+ "iconst_4",
+ "iconst_5",
+ "lconst_0",
+ "lconst_1",
+ "fconst_0",
+ "fconst_1",
+ "fconst_2",
+ "dconst_0",
+ "dconst_1",
+ "bipush",
+ "sipush",
+ "ldc",
+ "ldc_w",
+ "ldc2_w",
+ "iload",
+ "lload",
+ "fload",
+ "dload",
+ "aload",
+ "iload_0",
+ "iload_1",
+ "iload_2",
+ "iload_3",
+ "lload_0",
+ "lload_1",
+ "lload_2",
+ "lload_3",
+ "fload_0",
+ "fload_1",
+ "fload_2",
+ "fload_3",
+ "dload_0",
+ "dload_1",
+ "dload_2",
+ "dload_3",
+ "aload_0",
+ "aload_1",
+ "aload_2",
+ "aload_3",
+ "iaload",
+ "laload",
+ "faload",
+ "daload",
+ "aaload",
+ "baload",
+ "caload",
+ "saload",
+ "istore",
+ "lstore",
+ "fstore",
+ "dstore",
+ "astore",
+ "istore_0",
+ "istore_1",
+ "istore_2",
+ "istore_3",
+ "lstore_0",
+ "lstore_1",
+ "lstore_2",
+ "lstore_3",
+ "fstore_0",
+ "fstore_1",
+ "fstore_2",
+ "fstore_3",
+ "dstore_0",
+ "dstore_1",
+ "dstore_2",
+ "dstore_3",
+ "astore_0",
+ "astore_1",
+ "astore_2",
+ "astore_3",
+ "iastore",
+ "lastore",
+ "fastore",
+ "dastore",
+ "aastore",
+ "bastore",
+ "castore",
+ "sastore",
+ "pop",
+ "pop2",
+ "dup",
+ "dup_x1",
+ "dup_x2",
+ "dup2",
+ "dup2_x1",
+ "dup2_x2",
+ "swap",
+ "iadd",
+ "ladd",
+ "fadd",
+ "dadd",
+ "isub",
+ "lsub",
+ "fsub",
+ "dsub",
+ "imul",
+ "lmul",
+ "fmul",
+ "dmul",
+ "idiv",
+ "ldiv",
+ "fdiv",
+ "ddiv",
+ "irem",
+ "lrem",
+ "frem",
+ "drem",
+ "ineg",
+ "lneg",
+ "fneg",
+ "dneg",
+ "ishl",
+ "lshl",
+ "ishr",
+ "lshr",
+ "iushr",
+ "lushr",
+ "iand",
+ "land",
+ "ior",
+ "lor",
+ "ixor",
+ "lxor",
+ "iinc",
+ "i2l",
+ "i2f",
+ "i2d",
+ "l2i",
+ "l2f",
+ "l2d",
+ "f2i",
+ "f2l",
+ "f2d",
+ "d2i",
+ "d2l",
+ "d2f",
+ "i2b",
+ "i2c",
+ "i2s",
+ "lcmp",
+ "fcmpl",
+ "fcmpg",
+ "dcmpl",
+ "dcmpg",
+ "ifeq",
+ "ifne",
+ "iflt",
+ "ifge",
+ "ifgt",
+ "ifle",
+ "ificmpeq",
+ "ificmpne",
+ "ificmplt",
+ "ificmpge",
+ "ificmpgt",
+ "ificmple",
+ "ifacmpeq",
+ "ifacmpne",
+ "goto",
+ "jsr",
+ "ret",
+ "tableswitch",
+ "lookupswitch",
+ "ireturn",
+ "lreturn",
+ "freturn",
+ "dreturn",
+ "areturn",
+ "return",
+ "getstatic",
+ "putstatic",
+ "getfield",
+ "putfield",
+ "invokevirtual",
+ "invokespecial",
+ "invokestatic",
+ "invokeinterface",
+ "unused",
+ "new",
+ "newarray",
+ "anewarray",
+ "arraylength",
+ "athrow",
+ "checkcast",
+ "instanceof",
+ "monitorenter",
+ "monitorexit",
+ "wide",
+ "multianewarray",
+ "ifnull",
+ "ifnonnull",
+ "goto_w",
+ "jsr_w",
+ };
+
+
+ public static final byte ARRAY_T_BOOLEAN = 4;
+ public static final byte ARRAY_T_CHAR = 5;
+ public static final byte ARRAY_T_FLOAT = 6;
+ public static final byte ARRAY_T_DOUBLE = 7;
+ public static final byte ARRAY_T_BYTE = 8;
+ public static final byte ARRAY_T_SHORT = 9;
+ public static final byte ARRAY_T_INT = 10;
+ public static final byte ARRAY_T_LONG = 11;
+}
diff --git a/src/proguard/classfile/instruction/InstructionFactory.java b/src/proguard/classfile/instruction/InstructionFactory.java
new file mode 100644
index 0000000..f898471
--- /dev/null
+++ b/src/proguard/classfile/instruction/InstructionFactory.java
@@ -0,0 +1,299 @@
+/*
+ * 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.classfile.instruction;
+
+/**
+ * This class provides methods to create and reuse Instruction objects.
+ *
+ * @author Eric Lafortune
+ */
+public class InstructionFactory
+{
+ /**
+ * Creates a new Instruction from the data in the byte array, starting
+ * at the given index.
+ */
+ public static Instruction create(byte[] code, int offset)
+ {
+ Instruction instruction;
+
+ int index = offset;
+ byte opcode = code[index++];
+
+ boolean wide = false;
+ if (opcode == InstructionConstants.OP_WIDE)
+ {
+ opcode = code[index++];
+ wide = true;
+ }
+
+ switch (opcode)
+ {
+ // Simple instructions.
+ case InstructionConstants.OP_NOP:
+ case InstructionConstants.OP_ACONST_NULL:
+ 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_LCONST_0:
+ case InstructionConstants.OP_LCONST_1:
+ case InstructionConstants.OP_FCONST_0:
+ case InstructionConstants.OP_FCONST_1:
+ case InstructionConstants.OP_FCONST_2:
+ case InstructionConstants.OP_DCONST_0:
+ case InstructionConstants.OP_DCONST_1:
+
+ case InstructionConstants.OP_BIPUSH:
+ case InstructionConstants.OP_SIPUSH:
+
+ case InstructionConstants.OP_IALOAD:
+ case InstructionConstants.OP_LALOAD:
+ case InstructionConstants.OP_FALOAD:
+ case InstructionConstants.OP_DALOAD:
+ case InstructionConstants.OP_AALOAD:
+ case InstructionConstants.OP_BALOAD:
+ case InstructionConstants.OP_CALOAD:
+ case InstructionConstants.OP_SALOAD:
+
+ case InstructionConstants.OP_IASTORE:
+ case InstructionConstants.OP_LASTORE:
+ case InstructionConstants.OP_FASTORE:
+ case InstructionConstants.OP_DASTORE:
+ case InstructionConstants.OP_AASTORE:
+ case InstructionConstants.OP_BASTORE:
+ case InstructionConstants.OP_CASTORE:
+ case InstructionConstants.OP_SASTORE:
+ case InstructionConstants.OP_POP:
+ case InstructionConstants.OP_POP2:
+ case InstructionConstants.OP_DUP:
+ case InstructionConstants.OP_DUP_X1:
+ case InstructionConstants.OP_DUP_X2:
+ case InstructionConstants.OP_DUP2:
+ case InstructionConstants.OP_DUP2_X1:
+ case InstructionConstants.OP_DUP2_X2:
+ case InstructionConstants.OP_SWAP:
+ case InstructionConstants.OP_IADD:
+ case InstructionConstants.OP_LADD:
+ case InstructionConstants.OP_FADD:
+ case InstructionConstants.OP_DADD:
+ case InstructionConstants.OP_ISUB:
+ case InstructionConstants.OP_LSUB:
+ case InstructionConstants.OP_FSUB:
+ case InstructionConstants.OP_DSUB:
+ case InstructionConstants.OP_IMUL:
+ case InstructionConstants.OP_LMUL:
+ case InstructionConstants.OP_FMUL:
+ case InstructionConstants.OP_DMUL:
+ case InstructionConstants.OP_IDIV:
+ case InstructionConstants.OP_LDIV:
+ case InstructionConstants.OP_FDIV:
+ case InstructionConstants.OP_DDIV:
+ case InstructionConstants.OP_IREM:
+ case InstructionConstants.OP_LREM:
+ case InstructionConstants.OP_FREM:
+ case InstructionConstants.OP_DREM:
+ case InstructionConstants.OP_INEG:
+ case InstructionConstants.OP_LNEG:
+ case InstructionConstants.OP_FNEG:
+ case InstructionConstants.OP_DNEG:
+ case InstructionConstants.OP_ISHL:
+ case InstructionConstants.OP_LSHL:
+ case InstructionConstants.OP_ISHR:
+ case InstructionConstants.OP_LSHR:
+ case InstructionConstants.OP_IUSHR:
+ case InstructionConstants.OP_LUSHR:
+ case InstructionConstants.OP_IAND:
+ case InstructionConstants.OP_LAND:
+ case InstructionConstants.OP_IOR:
+ case InstructionConstants.OP_LOR:
+ case InstructionConstants.OP_IXOR:
+ case InstructionConstants.OP_LXOR:
+
+ case InstructionConstants.OP_I2L:
+ case InstructionConstants.OP_I2F:
+ case InstructionConstants.OP_I2D:
+ case InstructionConstants.OP_L2I:
+ case InstructionConstants.OP_L2F:
+ case InstructionConstants.OP_L2D:
+ case InstructionConstants.OP_F2I:
+ case InstructionConstants.OP_F2L:
+ case InstructionConstants.OP_F2D:
+ case InstructionConstants.OP_D2I:
+ case InstructionConstants.OP_D2L:
+ case InstructionConstants.OP_D2F:
+ case InstructionConstants.OP_I2B:
+ case InstructionConstants.OP_I2C:
+ case InstructionConstants.OP_I2S:
+ case InstructionConstants.OP_LCMP:
+ case InstructionConstants.OP_FCMPL:
+ case InstructionConstants.OP_FCMPG:
+ case InstructionConstants.OP_DCMPL:
+ case InstructionConstants.OP_DCMPG:
+
+ case InstructionConstants.OP_IRETURN:
+ case InstructionConstants.OP_LRETURN:
+ case InstructionConstants.OP_FRETURN:
+ case InstructionConstants.OP_DRETURN:
+ case InstructionConstants.OP_ARETURN:
+ case InstructionConstants.OP_RETURN:
+
+ case InstructionConstants.OP_NEWARRAY:
+ case InstructionConstants.OP_ARRAYLENGTH:
+ case InstructionConstants.OP_ATHROW:
+
+ case InstructionConstants.OP_MONITORENTER:
+ case InstructionConstants.OP_MONITOREXIT:
+ instruction = new SimpleInstruction();
+ break;
+
+ // Instructions with a contant pool index.
+ case InstructionConstants.OP_LDC:
+ case InstructionConstants.OP_LDC_W:
+ case InstructionConstants.OP_LDC2_W:
+
+ 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:
+
+ case InstructionConstants.OP_NEW:
+ case InstructionConstants.OP_ANEWARRAY:
+ case InstructionConstants.OP_CHECKCAST:
+ case InstructionConstants.OP_INSTANCEOF:
+ case InstructionConstants.OP_MULTIANEWARRAY:
+ instruction = new ConstantInstruction();
+ break;
+
+ // Instructions with a local variable index.
+ case InstructionConstants.OP_ILOAD:
+ case InstructionConstants.OP_LLOAD:
+ case InstructionConstants.OP_FLOAD:
+ case InstructionConstants.OP_DLOAD:
+ case InstructionConstants.OP_ALOAD:
+ case InstructionConstants.OP_ILOAD_0:
+ case InstructionConstants.OP_ILOAD_1:
+ case InstructionConstants.OP_ILOAD_2:
+ case InstructionConstants.OP_ILOAD_3:
+ case InstructionConstants.OP_LLOAD_0:
+ case InstructionConstants.OP_LLOAD_1:
+ case InstructionConstants.OP_LLOAD_2:
+ case InstructionConstants.OP_LLOAD_3:
+ case InstructionConstants.OP_FLOAD_0:
+ case InstructionConstants.OP_FLOAD_1:
+ case InstructionConstants.OP_FLOAD_2:
+ case InstructionConstants.OP_FLOAD_3:
+ case InstructionConstants.OP_DLOAD_0:
+ case InstructionConstants.OP_DLOAD_1:
+ case InstructionConstants.OP_DLOAD_2:
+ case InstructionConstants.OP_DLOAD_3:
+ case InstructionConstants.OP_ALOAD_0:
+ case InstructionConstants.OP_ALOAD_1:
+ case InstructionConstants.OP_ALOAD_2:
+ case InstructionConstants.OP_ALOAD_3:
+
+ case InstructionConstants.OP_ISTORE:
+ case InstructionConstants.OP_LSTORE:
+ case InstructionConstants.OP_FSTORE:
+ case InstructionConstants.OP_DSTORE:
+ case InstructionConstants.OP_ASTORE:
+ case InstructionConstants.OP_ISTORE_0:
+ case InstructionConstants.OP_ISTORE_1:
+ case InstructionConstants.OP_ISTORE_2:
+ case InstructionConstants.OP_ISTORE_3:
+ case InstructionConstants.OP_LSTORE_0:
+ case InstructionConstants.OP_LSTORE_1:
+ case InstructionConstants.OP_LSTORE_2:
+ case InstructionConstants.OP_LSTORE_3:
+ case InstructionConstants.OP_FSTORE_0:
+ case InstructionConstants.OP_FSTORE_1:
+ case InstructionConstants.OP_FSTORE_2:
+ case InstructionConstants.OP_FSTORE_3:
+ case InstructionConstants.OP_DSTORE_0:
+ case InstructionConstants.OP_DSTORE_1:
+ case InstructionConstants.OP_DSTORE_2:
+ case InstructionConstants.OP_DSTORE_3:
+ case InstructionConstants.OP_ASTORE_0:
+ case InstructionConstants.OP_ASTORE_1:
+ case InstructionConstants.OP_ASTORE_2:
+ case InstructionConstants.OP_ASTORE_3:
+
+ case InstructionConstants.OP_IINC:
+
+ case InstructionConstants.OP_RET:
+ instruction = new VariableInstruction(wide);
+ break;
+
+ // Instructions with a branch offset operand.
+ case InstructionConstants.OP_IFEQ:
+ case InstructionConstants.OP_IFNE:
+ case InstructionConstants.OP_IFLT:
+ case InstructionConstants.OP_IFGE:
+ case InstructionConstants.OP_IFGT:
+ case InstructionConstants.OP_IFLE:
+ case InstructionConstants.OP_IFICMPEQ:
+ case InstructionConstants.OP_IFICMPNE:
+ case InstructionConstants.OP_IFICMPLT:
+ case InstructionConstants.OP_IFICMPGE:
+ case InstructionConstants.OP_IFICMPGT:
+ case InstructionConstants.OP_IFICMPLE:
+ case InstructionConstants.OP_IFACMPEQ:
+ case InstructionConstants.OP_IFACMPNE:
+ case InstructionConstants.OP_GOTO:
+ case InstructionConstants.OP_JSR:
+
+ case InstructionConstants.OP_IFNULL:
+ case InstructionConstants.OP_IFNONNULL:
+
+ case InstructionConstants.OP_GOTO_W:
+ case InstructionConstants.OP_JSR_W:
+ instruction = new BranchInstruction();
+ break;
+
+ // The tableswitch instruction.
+ case InstructionConstants.OP_TABLESWITCH:
+ instruction = new TableSwitchInstruction();
+ break;
+
+ // The lookupswitch instruction.
+ case InstructionConstants.OP_LOOKUPSWITCH:
+ instruction = new LookUpSwitchInstruction();
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unknown instruction opcode ["+opcode+"] at offset "+offset);
+ }
+
+ instruction.opcode = opcode;
+
+ instruction.readInfo(code, index);
+
+ return instruction;
+ }
+}
diff --git a/src/proguard/classfile/instruction/InstructionUtil.java b/src/proguard/classfile/instruction/InstructionUtil.java
new file mode 100644
index 0000000..a3a328a
--- /dev/null
+++ b/src/proguard/classfile/instruction/InstructionUtil.java
@@ -0,0 +1,67 @@
+/*
+ * 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.classfile.instruction;
+
+import proguard.classfile.ClassConstants;
+
+/**
+ * Utility methods for converting between representations of names and
+ * descriptions.
+ *
+ * @author Eric Lafortune
+ */
+public class InstructionUtil
+{
+ /**
+ * Returns the internal type corresponding to the given 'newarray' type.
+ * @param arrayType <code>InstructionConstants.ARRAY_T_BOOLEAN</code>,
+ * <code>InstructionConstants.ARRAY_T_BYTE</code>,
+ * <code>InstructionConstants.ARRAY_T_CHAR</code>,
+ * <code>InstructionConstants.ARRAY_T_SHORT</code>,
+ * <code>InstructionConstants.ARRAY_T_INT</code>,
+ * <code>InstructionConstants.ARRAY_T_LONG</code>,
+ * <code>InstructionConstants.ARRAY_T_FLOAT</code>, or
+ * <code>InstructionConstants.ARRAY_T_DOUBLE</code>.
+ * @return <code>ClassConstants.INTERNAL_TYPE_BOOLEAN</code>,
+ * <code>ClassConstants.INTERNAL_TYPE_BYTE</code>,
+ * <code>ClassConstants.INTERNAL_TYPE_CHAR</code>,
+ * <code>ClassConstants.INTERNAL_TYPE_SHORT</code>,
+ * <code>ClassConstants.INTERNAL_TYPE_INT</code>,
+ * <code>ClassConstants.INTERNAL_TYPE_LONG</code>,
+ * <code>ClassConstants.INTERNAL_TYPE_FLOAT</code>, or
+ * <code>ClassConstants.INTERNAL_TYPE_DOUBLE</code>.
+ */
+ public static char internalTypeFromArrayType(byte arrayType)
+ {
+ switch (arrayType)
+ {
+ case InstructionConstants.ARRAY_T_BOOLEAN: return ClassConstants.INTERNAL_TYPE_BOOLEAN;
+ case InstructionConstants.ARRAY_T_CHAR: return ClassConstants.INTERNAL_TYPE_CHAR;
+ case InstructionConstants.ARRAY_T_FLOAT: return ClassConstants.INTERNAL_TYPE_FLOAT;
+ case InstructionConstants.ARRAY_T_DOUBLE: return ClassConstants.INTERNAL_TYPE_DOUBLE;
+ case InstructionConstants.ARRAY_T_BYTE: return ClassConstants.INTERNAL_TYPE_BYTE;
+ case InstructionConstants.ARRAY_T_SHORT: return ClassConstants.INTERNAL_TYPE_SHORT;
+ case InstructionConstants.ARRAY_T_INT: return ClassConstants.INTERNAL_TYPE_INT;
+ case InstructionConstants.ARRAY_T_LONG: return ClassConstants.INTERNAL_TYPE_LONG;
+ default: throw new IllegalArgumentException("Unknown array type ["+arrayType+"]");
+ }
+ }
+}
diff --git a/src/proguard/classfile/instruction/LookUpSwitchInstruction.java b/src/proguard/classfile/instruction/LookUpSwitchInstruction.java
new file mode 100644
index 0000000..178cce5
--- /dev/null
+++ b/src/proguard/classfile/instruction/LookUpSwitchInstruction.java
@@ -0,0 +1,135 @@
+/*
+ * 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.classfile.instruction;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.CodeAttribute;
+import proguard.classfile.instruction.visitor.InstructionVisitor;
+
+/**
+ * This Instruction represents a simple instruction without variable arguments
+ * or constant pool references.
+ *
+ * @author Eric Lafortune
+ */
+public class LookUpSwitchInstruction extends SwitchInstruction
+{
+ public int[] cases;
+
+
+ /**
+ * Creates an uninitialized LookUpSwitchInstruction.
+ */
+ public LookUpSwitchInstruction() {}
+
+
+ /**
+ * Creates a new LookUpSwitchInstruction with the given arguments.
+ */
+ public LookUpSwitchInstruction(byte opcode,
+ int defaultOffset,
+ int[] cases,
+ int[] jumpOffsets)
+ {
+ this.opcode = opcode;
+ this.defaultOffset = defaultOffset;
+ this.cases = cases;
+ this.jumpOffsets = jumpOffsets;
+ }
+
+
+ /**
+ * Copies the given instruction into this instruction.
+ * @param lookUpSwitchInstruction the instruction to be copied.
+ * @return this instruction.
+ */
+ public LookUpSwitchInstruction copy(LookUpSwitchInstruction lookUpSwitchInstruction)
+ {
+ this.opcode = lookUpSwitchInstruction.opcode;
+ this.defaultOffset = lookUpSwitchInstruction.defaultOffset;
+ this.cases = lookUpSwitchInstruction.cases;
+ this.jumpOffsets = lookUpSwitchInstruction.jumpOffsets;
+
+ return this;
+ }
+
+
+ // Implementations for Instruction.
+
+ public Instruction shrink()
+ {
+ // There aren't any ways to shrink this instruction.
+ return this;
+ }
+
+ protected void readInfo(byte[] code, int offset)
+ {
+ // Skip up to three padding bytes.
+ offset += -offset & 3;
+
+ // Read the two 32-bit arguments.
+ defaultOffset = readInt(code, offset); offset += 4;
+ int jumpOffsetCount = readInt(code, offset); offset += 4;
+
+ // Read the matches-offset pairs.
+ cases = new int[jumpOffsetCount];
+ jumpOffsets = new int[jumpOffsetCount];
+
+ for (int index = 0; index < jumpOffsetCount; index++)
+ {
+ cases[index] = readInt(code, offset); offset += 4;
+ jumpOffsets[index] = readInt(code, offset); offset += 4;
+ }
+ }
+
+
+ protected void writeInfo(byte[] code, int offset)
+ {
+ // Write up to three padding bytes.
+ while ((offset & 3) != 0)
+ {
+ writeByte(code, offset++, 0);
+ }
+
+ // Write the two 32-bit arguments.
+ writeInt(code, offset, defaultOffset); offset += 4;
+ writeInt(code, offset, cases.length); offset += 4;
+
+ // Write the matches-offset pairs.
+ for (int index = 0; index < cases.length; index++)
+ {
+ writeInt(code, offset, cases[index]); offset += 4;
+ writeInt(code, offset, jumpOffsets[index]); offset += 4;
+ }
+ }
+
+
+ public int length(int offset)
+ {
+ return 1 + (-(offset+1) & 3) + 8 + cases.length * 8;
+ }
+
+
+ public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, InstructionVisitor instructionVisitor)
+ {
+ instructionVisitor.visitLookUpSwitchInstruction(clazz, method, codeAttribute, offset, this);
+ }
+}
diff --git a/src/proguard/classfile/instruction/SimpleInstruction.java b/src/proguard/classfile/instruction/SimpleInstruction.java
new file mode 100644
index 0000000..84e6344
--- /dev/null
+++ b/src/proguard/classfile/instruction/SimpleInstruction.java
@@ -0,0 +1,255 @@
+/*
+ * 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.classfile.instruction;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.CodeAttribute;
+import proguard.classfile.instruction.visitor.InstructionVisitor;
+
+/**
+ * This Instruction represents a simple instruction without variable arguments
+ * or constant pool references.
+ *
+ * @author Eric Lafortune
+ */
+public class SimpleInstruction extends Instruction
+{
+ public int constant;
+
+
+ /**
+ * Creates an uninitialized SimpleInstruction.
+ */
+ public SimpleInstruction() {}
+
+
+ /**
+ * Creates a new SimpleInstruction with the given opcode.
+ */
+ public SimpleInstruction(byte opcode)
+ {
+ this(opcode, embeddedConstant(opcode));
+ }
+
+
+ /**
+ * Creates a new SimpleInstruction with the given opcode and constant.
+ */
+ public SimpleInstruction(byte opcode, int constant)
+ {
+ this.opcode = opcode;
+ this.constant = constant;
+ }
+
+
+ /**
+ * Copies the given instruction into this instruction.
+ * @param simpleInstruction the instruction to be copied.
+ * @return this instruction.
+ */
+ public SimpleInstruction copy(SimpleInstruction simpleInstruction)
+ {
+ this.opcode = simpleInstruction.opcode;
+ this.constant = simpleInstruction.constant;
+
+ return this;
+ }
+
+
+ /**
+ * Return the embedded constant of the given opcode, or 0 if the opcode
+ * doesn't have one.
+ */
+ private static int embeddedConstant(byte opcode)
+ {
+ switch (opcode)
+ {
+ case InstructionConstants.OP_ICONST_M1: return -1;
+
+ case InstructionConstants.OP_ICONST_1:
+ case InstructionConstants.OP_LCONST_1:
+ case InstructionConstants.OP_FCONST_1:
+ case InstructionConstants.OP_DCONST_1: return 1;
+
+ case InstructionConstants.OP_ICONST_2:
+ case InstructionConstants.OP_FCONST_2: return 2;
+
+ case InstructionConstants.OP_ICONST_3: return 3;
+
+ case InstructionConstants.OP_ICONST_4: return 4;
+
+ case InstructionConstants.OP_ICONST_5: return 5;
+
+ default: return 0;
+ }
+ }
+
+
+ // Implementations for Instruction.
+
+ public byte canonicalOpcode()
+ {
+ // Replace any _1, _2, _3,... extension by _0.
+ switch (opcode)
+ {
+ 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: return InstructionConstants.OP_ICONST_0;
+
+ case InstructionConstants.OP_LCONST_0:
+ case InstructionConstants.OP_LCONST_1: return InstructionConstants.OP_LCONST_0;
+
+ case InstructionConstants.OP_FCONST_0:
+ case InstructionConstants.OP_FCONST_1:
+ case InstructionConstants.OP_FCONST_2: return InstructionConstants.OP_FCONST_0;
+
+ case InstructionConstants.OP_DCONST_0:
+ case InstructionConstants.OP_DCONST_1: return InstructionConstants.OP_DCONST_0;
+
+ default: return opcode;
+ }
+ }
+
+ public Instruction shrink()
+ {
+ // Reconstruct the opcode of the shortest instruction, if there are
+ // any alternatives.
+ switch (opcode)
+ {
+ 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:
+ switch (requiredConstantSize())
+ {
+ case 0:
+ opcode = (byte)(InstructionConstants.OP_ICONST_0 + constant);
+ break;
+ case 1:
+ opcode = InstructionConstants.OP_BIPUSH;
+ break;
+ case 2:
+ opcode = InstructionConstants.OP_SIPUSH;
+ break;
+ }
+ break;
+
+ case InstructionConstants.OP_LCONST_0:
+ case InstructionConstants.OP_LCONST_1:
+ opcode = (byte)(InstructionConstants.OP_LCONST_0 + constant);
+ break;
+
+ case InstructionConstants.OP_FCONST_0:
+ case InstructionConstants.OP_FCONST_1:
+ case InstructionConstants.OP_FCONST_2:
+ opcode = (byte)(InstructionConstants.OP_FCONST_0 + constant);
+ break;
+
+ case InstructionConstants.OP_DCONST_0:
+ case InstructionConstants.OP_DCONST_1:
+ opcode = (byte)(InstructionConstants.OP_DCONST_0 + constant);
+ break;
+ }
+
+ return this;
+ }
+
+ protected void readInfo(byte[] code, int offset)
+ {
+ int constantSize = constantSize();
+
+ // Also initialize embedded constants that are different from 0.
+ constant = constantSize == 0 ?
+ embeddedConstant(opcode) :
+ readSignedValue(code, offset, constantSize);
+ }
+
+
+ protected void writeInfo(byte[] code, int offset)
+ {
+ int constantSize = constantSize();
+
+ if (requiredConstantSize() > constantSize)
+ {
+ throw new IllegalArgumentException("Instruction has invalid constant size ("+this.toString(offset)+")");
+ }
+
+ writeSignedValue(code, offset, constant, constantSize);
+ }
+
+
+ public int length(int offset)
+ {
+ return 1 + constantSize();
+ }
+
+
+ public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, InstructionVisitor instructionVisitor)
+ {
+ instructionVisitor.visitSimpleInstruction(clazz, method, codeAttribute, offset, this);
+ }
+
+
+ // Implementations for Object.
+
+ public String toString()
+ {
+ return getName() +
+ (constantSize() > 0 ? " "+constant : "");
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Returns the constant size for this instruction.
+ */
+ private int constantSize()
+ {
+ return opcode == InstructionConstants.OP_BIPUSH ||
+ opcode == InstructionConstants.OP_NEWARRAY ? 1 :
+ opcode == InstructionConstants.OP_SIPUSH ? 2 :
+ 0;
+ }
+
+
+ /**
+ * Computes the required constant size for this instruction.
+ */
+ private int requiredConstantSize()
+ {
+ return constant >= -1 && constant <= 5 ? 0 :
+ constant << 24 >> 24 == constant ? 1 :
+ constant << 16 >> 16 == constant ? 2 :
+ 4;
+ }
+}
diff --git a/src/proguard/classfile/instruction/SwitchInstruction.java b/src/proguard/classfile/instruction/SwitchInstruction.java
new file mode 100644
index 0000000..b98c2fb
--- /dev/null
+++ b/src/proguard/classfile/instruction/SwitchInstruction.java
@@ -0,0 +1,83 @@
+/*
+ * 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.classfile.instruction;
+
+/**
+ * This Instruction represents a simple instruction without variable arguments
+ * or constant pool references.
+ *
+ * @author Eric Lafortune
+ */
+public abstract class SwitchInstruction extends Instruction
+{
+ public int defaultOffset;
+ public int[] jumpOffsets;
+
+
+ /**
+ * Creates an uninitialized SwitchInstruction.
+ */
+ public SwitchInstruction() {}
+
+
+ /**
+ * Creates a new SwitchInstruction with the given arguments.
+ */
+ public SwitchInstruction(byte opcode,
+ int defaultOffset,
+ int[] jumpOffsets)
+ {
+ this.opcode = opcode;
+ this.defaultOffset = defaultOffset;
+ this.jumpOffsets = jumpOffsets;
+ }
+
+
+ /**
+ * Copies the given instruction into this instruction.
+ * @param switchInstruction the instruction to be copied.
+ * @return this instruction.
+ */
+ public SwitchInstruction copy(SwitchInstruction switchInstruction)
+ {
+ this.opcode = switchInstruction.opcode;
+ this.defaultOffset = switchInstruction.defaultOffset;
+ this.jumpOffsets = switchInstruction.jumpOffsets;
+
+ return this;
+ }
+
+
+ // Implementations for Instruction.
+
+ public String toString(int offset)
+ {
+ return "["+offset+"] "+toString()+" (target="+(offset+defaultOffset)+")";
+ }
+
+
+ // Implementations for Object.
+
+ public String toString()
+ {
+ return getName()+" ("+jumpOffsets.length+" offsets, default="+defaultOffset+")";
+ }
+}
diff --git a/src/proguard/classfile/instruction/TableSwitchInstruction.java b/src/proguard/classfile/instruction/TableSwitchInstruction.java
new file mode 100644
index 0000000..ee81af5
--- /dev/null
+++ b/src/proguard/classfile/instruction/TableSwitchInstruction.java
@@ -0,0 +1,139 @@
+/*
+ * 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.classfile.instruction;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.CodeAttribute;
+import proguard.classfile.instruction.visitor.InstructionVisitor;
+
+/**
+ * This Instruction represents a simple instruction without variable arguments
+ * or constant pool references.
+ *
+ * @author Eric Lafortune
+ */
+public class TableSwitchInstruction extends SwitchInstruction
+{
+ public int lowCase;
+ public int highCase;
+
+
+ /**
+ * Creates an uninitialized TableSwitchInstruction.
+ */
+ public TableSwitchInstruction() {}
+
+
+ /**
+ * Creates a new TableSwitchInstruction with the given arguments.
+ */
+ public TableSwitchInstruction(byte opcode,
+ int defaultOffset,
+ int lowCase,
+ int highCase,
+ int[] jumpOffsets)
+ {
+ this.opcode = opcode;
+ this.defaultOffset = defaultOffset;
+ this.lowCase = lowCase;
+ this.highCase = highCase;
+ this.jumpOffsets = jumpOffsets;
+ }
+
+
+ /**
+ * Copies the given instruction into this instruction.
+ * @param tableSwitchInstruction the instruction to be copied.
+ * @return this instruction.
+ */
+ public TableSwitchInstruction copy(TableSwitchInstruction tableSwitchInstruction)
+ {
+ this.opcode = tableSwitchInstruction.opcode;
+ this.defaultOffset = tableSwitchInstruction.defaultOffset;
+ this.lowCase = tableSwitchInstruction.lowCase;
+ this.highCase = tableSwitchInstruction.highCase;
+ this.jumpOffsets = tableSwitchInstruction.jumpOffsets;
+
+ return this;
+ }
+
+
+ // Implementations for Instruction.
+
+ public Instruction shrink()
+ {
+ // There aren't any ways to shrink this instruction.
+ return this;
+ }
+
+ protected void readInfo(byte[] code, int offset)
+ {
+ // Skip up to three padding bytes.
+ offset += -offset & 3;
+
+ // Read the three 32-bit arguments.
+ defaultOffset = readInt(code, offset); offset += 4;
+ lowCase = readInt(code, offset); offset += 4;
+ highCase = readInt(code, offset); offset += 4;
+
+ // Read the jump offsets.
+ jumpOffsets = new int[highCase - lowCase + 1];
+
+ for (int index = 0; index < jumpOffsets.length; index++)
+ {
+ jumpOffsets[index] = readInt(code, offset); offset += 4;
+ }
+ }
+
+
+ protected void writeInfo(byte[] code, int offset)
+ {
+ // Write up to three padding bytes.
+ while ((offset & 3) != 0)
+ {
+ writeByte(code, offset++, 0);
+ }
+
+ // Write the three 32-bit arguments.
+ writeInt(code, offset, defaultOffset); offset += 4;
+ writeInt(code, offset, lowCase); offset += 4;
+ writeInt(code, offset, highCase); offset += 4;
+
+ // Write the jump offsets.
+ int length = highCase - lowCase + 1;
+ for (int index = 0; index < length; index++)
+ {
+ writeInt(code, offset, jumpOffsets[index]); offset += 4;
+ }
+ }
+
+
+ public int length(int offset)
+ {
+ return 1 + (-(offset+1) & 3) + 12 + (highCase - lowCase + 1) * 4;
+ }
+
+
+ public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, InstructionVisitor instructionVisitor)
+ {
+ instructionVisitor.visitTableSwitchInstruction(clazz, method, codeAttribute, offset, this);
+ }
+}
diff --git a/src/proguard/classfile/instruction/VariableInstruction.java b/src/proguard/classfile/instruction/VariableInstruction.java
new file mode 100644
index 0000000..309f802
--- /dev/null
+++ b/src/proguard/classfile/instruction/VariableInstruction.java
@@ -0,0 +1,372 @@
+/*
+ * 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.classfile.instruction;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.CodeAttribute;
+import proguard.classfile.instruction.visitor.InstructionVisitor;
+
+/**
+ * This Instruction represents an instruction that refers to a variable on the
+ * local variable stack.
+ *
+ * @author Eric Lafortune
+ */
+public class VariableInstruction extends Instruction
+{
+ public boolean wide;
+ public int variableIndex;
+ public int constant;
+
+
+ /**
+ * Creates an uninitialized VariableInstruction.
+ */
+ public VariableInstruction() {}
+
+
+ public VariableInstruction(boolean wide)
+ {
+ this.wide = wide;
+ }
+
+
+ public VariableInstruction(byte opcode)
+ {
+ this(opcode, embeddedVariable(opcode), 0);
+ }
+
+
+ public VariableInstruction(byte opcode,
+ int variableIndex)
+ {
+ this(opcode, variableIndex, 0);
+ }
+
+
+ public VariableInstruction(byte opcode,
+ int variableIndex,
+ int constant)
+ {
+ this.opcode = opcode;
+ this.variableIndex = variableIndex;
+ this.constant = constant;
+ this.wide = requiredVariableIndexSize() > 1 ||
+ requiredConstantSize() > 1;
+ }
+
+
+ /**
+ * Copies the given instruction into this instruction.
+ * @param variableInstruction the instruction to be copied.
+ * @return this instruction.
+ */
+ public VariableInstruction copy(VariableInstruction variableInstruction)
+ {
+ this.opcode = variableInstruction.opcode;
+ this.variableIndex = variableInstruction.variableIndex;
+ this.constant = variableInstruction.constant;
+ this.wide = variableInstruction.wide;
+
+ return this;
+ }
+
+
+ /**
+ * Return the embedded variable of the given opcode, or 0 if the opcode
+ * doesn't have one.
+ */
+ private static int embeddedVariable(byte opcode)
+ {
+ switch (opcode)
+ {
+ case InstructionConstants.OP_ILOAD_1:
+ case InstructionConstants.OP_LLOAD_1:
+ case InstructionConstants.OP_FLOAD_1:
+ case InstructionConstants.OP_DLOAD_1:
+ case InstructionConstants.OP_ALOAD_1:
+ case InstructionConstants.OP_ISTORE_1:
+ case InstructionConstants.OP_LSTORE_1:
+ case InstructionConstants.OP_FSTORE_1:
+ case InstructionConstants.OP_DSTORE_1:
+ case InstructionConstants.OP_ASTORE_1: return 1;
+
+ case InstructionConstants.OP_ILOAD_2:
+ case InstructionConstants.OP_LLOAD_2:
+ case InstructionConstants.OP_FLOAD_2:
+ case InstructionConstants.OP_DLOAD_2:
+ case InstructionConstants.OP_ALOAD_2:
+ case InstructionConstants.OP_ISTORE_2:
+ case InstructionConstants.OP_LSTORE_2:
+ case InstructionConstants.OP_FSTORE_2:
+ case InstructionConstants.OP_DSTORE_2:
+ case InstructionConstants.OP_ASTORE_2: return 2;
+
+ case InstructionConstants.OP_ILOAD_3:
+ case InstructionConstants.OP_LLOAD_3:
+ case InstructionConstants.OP_FLOAD_3:
+ case InstructionConstants.OP_DLOAD_3:
+ case InstructionConstants.OP_ALOAD_3:
+ case InstructionConstants.OP_ISTORE_3:
+ case InstructionConstants.OP_LSTORE_3:
+ case InstructionConstants.OP_FSTORE_3:
+ case InstructionConstants.OP_DSTORE_3:
+ case InstructionConstants.OP_ASTORE_3: return 3;
+
+ default: return 0;
+ }
+ }
+
+
+ /**
+ * Returns whether this instruction stores the value of a variable.
+ * The value is false for the ret instruction, but true for the iinc
+ * instruction.
+ */
+ public boolean isStore()
+ {
+ // A store instruction can be recognized as follows. Note that this
+ // excludes the ret instruction, which has a negative opcode.
+ return opcode >= InstructionConstants.OP_ISTORE ||
+ opcode == InstructionConstants.OP_IINC;
+ }
+
+
+ /**
+ * Returns whether this instruction loads the value of a variable.
+ * The value is true for the ret instruction and for the iinc
+ * instruction.
+ */
+ public boolean isLoad()
+ {
+ // A load instruction can be recognized as follows. Note that this
+ // includes the ret instruction, which has a negative opcode.
+ return opcode < InstructionConstants.OP_ISTORE;
+ }
+
+
+ // Implementations for Instruction.
+
+ public byte canonicalOpcode()
+ {
+ // Remove the _0, _1, _2, _3 extension, if any.
+ switch (opcode)
+ {
+ case InstructionConstants.OP_ILOAD_0:
+ case InstructionConstants.OP_ILOAD_1:
+ case InstructionConstants.OP_ILOAD_2:
+ case InstructionConstants.OP_ILOAD_3: return InstructionConstants.OP_ILOAD;
+ case InstructionConstants.OP_LLOAD_0:
+ case InstructionConstants.OP_LLOAD_1:
+ case InstructionConstants.OP_LLOAD_2:
+ case InstructionConstants.OP_LLOAD_3: return InstructionConstants.OP_LLOAD;
+ case InstructionConstants.OP_FLOAD_0:
+ case InstructionConstants.OP_FLOAD_1:
+ case InstructionConstants.OP_FLOAD_2:
+ case InstructionConstants.OP_FLOAD_3: return InstructionConstants.OP_FLOAD;
+ case InstructionConstants.OP_DLOAD_0:
+ case InstructionConstants.OP_DLOAD_1:
+ case InstructionConstants.OP_DLOAD_2:
+ case InstructionConstants.OP_DLOAD_3: return InstructionConstants.OP_DLOAD;
+ case InstructionConstants.OP_ALOAD_0:
+ case InstructionConstants.OP_ALOAD_1:
+ case InstructionConstants.OP_ALOAD_2:
+ case InstructionConstants.OP_ALOAD_3: return InstructionConstants.OP_ALOAD;
+
+ case InstructionConstants.OP_ISTORE_0:
+ case InstructionConstants.OP_ISTORE_1:
+ case InstructionConstants.OP_ISTORE_2:
+ case InstructionConstants.OP_ISTORE_3: return InstructionConstants.OP_ISTORE;
+ case InstructionConstants.OP_LSTORE_0:
+ case InstructionConstants.OP_LSTORE_1:
+ case InstructionConstants.OP_LSTORE_2:
+ case InstructionConstants.OP_LSTORE_3: return InstructionConstants.OP_LSTORE;
+ case InstructionConstants.OP_FSTORE_0:
+ case InstructionConstants.OP_FSTORE_1:
+ case InstructionConstants.OP_FSTORE_2:
+ case InstructionConstants.OP_FSTORE_3: return InstructionConstants.OP_FSTORE;
+ case InstructionConstants.OP_DSTORE_0:
+ case InstructionConstants.OP_DSTORE_1:
+ case InstructionConstants.OP_DSTORE_2:
+ case InstructionConstants.OP_DSTORE_3: return InstructionConstants.OP_DSTORE;
+ case InstructionConstants.OP_ASTORE_0:
+ case InstructionConstants.OP_ASTORE_1:
+ case InstructionConstants.OP_ASTORE_2:
+ case InstructionConstants.OP_ASTORE_3: return InstructionConstants.OP_ASTORE;
+
+ default: return opcode;
+ }
+ }
+
+ public Instruction shrink()
+ {
+ opcode = canonicalOpcode();
+
+ // Is this instruction pointing to a variable with index from 0 to 3?
+ if (variableIndex <= 3)
+ {
+ switch (opcode)
+ {
+ case InstructionConstants.OP_ILOAD: opcode = (byte)(InstructionConstants.OP_ILOAD_0 + variableIndex); break;
+ case InstructionConstants.OP_LLOAD: opcode = (byte)(InstructionConstants.OP_LLOAD_0 + variableIndex); break;
+ case InstructionConstants.OP_FLOAD: opcode = (byte)(InstructionConstants.OP_FLOAD_0 + variableIndex); break;
+ case InstructionConstants.OP_DLOAD: opcode = (byte)(InstructionConstants.OP_DLOAD_0 + variableIndex); break;
+ case InstructionConstants.OP_ALOAD: opcode = (byte)(InstructionConstants.OP_ALOAD_0 + variableIndex); break;
+
+ case InstructionConstants.OP_ISTORE: opcode = (byte)(InstructionConstants.OP_ISTORE_0 + variableIndex); break;
+ case InstructionConstants.OP_LSTORE: opcode = (byte)(InstructionConstants.OP_LSTORE_0 + variableIndex); break;
+ case InstructionConstants.OP_FSTORE: opcode = (byte)(InstructionConstants.OP_FSTORE_0 + variableIndex); break;
+ case InstructionConstants.OP_DSTORE: opcode = (byte)(InstructionConstants.OP_DSTORE_0 + variableIndex); break;
+ case InstructionConstants.OP_ASTORE: opcode = (byte)(InstructionConstants.OP_ASTORE_0 + variableIndex); break;
+ }
+ }
+
+ // Only make the instruction wide if necessary.
+ wide = requiredVariableIndexSize() > 1 ||
+ requiredConstantSize() > 1;
+
+ return this;
+ }
+
+
+ protected boolean isWide()
+ {
+ return wide;
+ }
+
+
+ protected void readInfo(byte[] code, int offset)
+ {
+ int variableIndexSize = variableIndexSize();
+ int constantSize = constantSize();
+
+ // Also initialize embedded variable indexes.
+ if (variableIndexSize == 0)
+ {
+ // An embedded variable index can be decoded as follows.
+ variableIndex = opcode < InstructionConstants.OP_ISTORE_0 ?
+ (opcode - InstructionConstants.OP_ILOAD_0 ) & 3 :
+ (opcode - InstructionConstants.OP_ISTORE_0) & 3;
+ }
+ else
+ {
+ variableIndex = readValue(code, offset, variableIndexSize); offset += variableIndexSize;
+ }
+
+ constant = readSignedValue(code, offset, constantSize);
+ }
+
+
+ protected void writeInfo(byte[] code, int offset)
+ {
+ int variableIndexSize = variableIndexSize();
+ int constantSize = constantSize();
+
+ if (requiredVariableIndexSize() > variableIndexSize)
+ {
+ throw new IllegalArgumentException("Instruction has invalid variable index size ("+this.toString(offset)+")");
+ }
+
+ if (requiredConstantSize() > constantSize)
+ {
+ throw new IllegalArgumentException("Instruction has invalid constant size ("+this.toString(offset)+")");
+ }
+
+ writeValue(code, offset, variableIndex, variableIndexSize); offset += variableIndexSize;
+ writeSignedValue(code, offset, constant, constantSize);
+ }
+
+
+ public int length(int offset)
+ {
+ return (wide ? 2 : 1) + variableIndexSize() + constantSize();
+ }
+
+
+ public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, InstructionVisitor instructionVisitor)
+ {
+ instructionVisitor.visitVariableInstruction(clazz, method, codeAttribute, offset, this);
+ }
+
+
+ // Implementations for Object.
+
+ public String toString()
+ {
+ return getName() +
+ (wide ? "_w" : "") +
+ " v"+variableIndex +
+ (constantSize() > 0 ? ", "+constant : "");
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Returns the variable index size for this instruction.
+ */
+ private int variableIndexSize()
+ {
+ return (opcode >= InstructionConstants.OP_ILOAD_0 &&
+ opcode <= InstructionConstants.OP_ALOAD_3) ||
+ (opcode >= InstructionConstants.OP_ISTORE_0 &&
+ opcode <= InstructionConstants.OP_ASTORE_3) ? 0 :
+ wide ? 2 :
+ 1;
+ }
+
+
+ /**
+ * Computes the required variable index size for this instruction's variable
+ * index.
+ */
+ private int requiredVariableIndexSize()
+ {
+ return (variableIndex & 0x3) == variableIndex ? 0 :
+ (variableIndex & 0xff) == variableIndex ? 1 :
+ (variableIndex & 0xffff) == variableIndex ? 2 :
+ 4;
+
+ }
+
+
+ /**
+ * Returns the constant size for this instruction.
+ */
+ private int constantSize()
+ {
+ return opcode != InstructionConstants.OP_IINC ? 0 :
+ wide ? 2 :
+ 1;
+ }
+
+
+ /**
+ * Computes the required constant size for this instruction's constant.
+ */
+ private int requiredConstantSize()
+ {
+ return opcode != InstructionConstants.OP_IINC ? 0 :
+ constant << 24 >> 24 == constant ? 1 :
+ constant << 16 >> 16 == constant ? 2 :
+ 4;
+ }
+}
diff --git a/src/proguard/classfile/instruction/package.html b/src/proguard/classfile/instruction/package.html
new file mode 100644
index 0000000..48c234e
--- /dev/null
+++ b/src/proguard/classfile/instruction/package.html
@@ -0,0 +1,9 @@
+<body>
+This package contains classes to represent Java bytecode instructions.
+<p>
+Not every instruction currently has its own class. Only groups of instructions
+that refer to the constant pool get their own representations.
+<p>
+While the package is sufficient for the current needs of the ProGuard
+application, it may very well be reorganised and extended in the future.
+</body>
diff --git a/src/proguard/classfile/instruction/visitor/AllInstructionVisitor.java b/src/proguard/classfile/instruction/visitor/AllInstructionVisitor.java
new file mode 100644
index 0000000..71b2cde
--- /dev/null
+++ b/src/proguard/classfile/instruction/visitor/AllInstructionVisitor.java
@@ -0,0 +1,56 @@
+/*
+ * 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.classfile.instruction.visitor;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.visitor.AttributeVisitor;
+import proguard.classfile.util.SimplifiedVisitor;
+
+/**
+ * This AttributeVisitor lets a given InstructionVisitor visit all Instruction
+ * objects of the CodeAttribute objects it visits.
+ *
+ * @author Eric Lafortune
+ */
+public class AllInstructionVisitor
+extends SimplifiedVisitor
+implements AttributeVisitor
+{
+ private final InstructionVisitor instructionVisitor;
+
+
+ public AllInstructionVisitor(InstructionVisitor instructionVisitor)
+ {
+ this.instructionVisitor = instructionVisitor;
+ }
+
+
+ // Implementations for AttributeVisitor.
+
+ public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
+
+
+ public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
+ {
+ codeAttribute.instructionsAccept(clazz, method, instructionVisitor);
+ }
+}
diff --git a/src/proguard/classfile/instruction/visitor/InstructionCounter.java b/src/proguard/classfile/instruction/visitor/InstructionCounter.java
new file mode 100644
index 0000000..1d10980
--- /dev/null
+++ b/src/proguard/classfile/instruction/visitor/InstructionCounter.java
@@ -0,0 +1,59 @@
+/*
+ * 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.classfile.instruction.visitor;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.CodeAttribute;
+import proguard.classfile.instruction.Instruction;
+import proguard.classfile.util.SimplifiedVisitor;
+
+/**
+ * This InstructionVisitor counts the number of instructions that has been visited.
+ *
+ * @author Eric Lafortune
+ */
+public class InstructionCounter
+extends SimplifiedVisitor
+implements InstructionVisitor
+{
+ private int count;
+
+
+ /**
+ * Returns the number of instructions that has been visited so far.
+ */
+ public int getCount()
+ {
+ return count;
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitAnyInstruction(Clazz clazz,
+ Method method,
+ CodeAttribute codeAttribute,
+ int offset,
+ Instruction instruction)
+ {
+ count++;
+ }
+}
diff --git a/src/proguard/classfile/instruction/visitor/InstructionVisitor.java b/src/proguard/classfile/instruction/visitor/InstructionVisitor.java
new file mode 100644
index 0000000..11af131
--- /dev/null
+++ b/src/proguard/classfile/instruction/visitor/InstructionVisitor.java
@@ -0,0 +1,42 @@
+/*
+ * 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.classfile.instruction.visitor;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.CodeAttribute;
+import proguard.classfile.instruction.*;
+
+
+/**
+ * This interface specifies the methods for a visitor of
+ * <code>Instruction</code> objects.
+ *
+ * @author Eric Lafortune
+ */
+public interface InstructionVisitor
+{
+ public void visitSimpleInstruction( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction);
+ public void visitVariableInstruction( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction);
+ public void visitConstantInstruction( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction);
+ public void visitBranchInstruction( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction);
+ public void visitTableSwitchInstruction( Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction);
+ public void visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction);
+}
diff --git a/src/proguard/classfile/instruction/visitor/MultiInstructionVisitor.java b/src/proguard/classfile/instruction/visitor/MultiInstructionVisitor.java
new file mode 100644
index 0000000..aada455
--- /dev/null
+++ b/src/proguard/classfile/instruction/visitor/MultiInstructionVisitor.java
@@ -0,0 +1,131 @@
+/*
+ * 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.classfile.instruction.visitor;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.CodeAttribute;
+import proguard.classfile.instruction.*;
+
+
+/**
+ * This InstructionVisitor delegates all visits to each InstructionVisitor
+ * in a given list.
+ *
+ * @author Eric Lafortune
+ */
+public class MultiInstructionVisitor implements InstructionVisitor
+{
+ private static final int ARRAY_SIZE_INCREMENT = 5;
+
+
+ private InstructionVisitor[] instructionVisitors;
+ private int instructionVisitorCount;
+
+
+ public MultiInstructionVisitor()
+ {
+ }
+
+
+ public MultiInstructionVisitor(InstructionVisitor[] instructionVisitors)
+ {
+ this.instructionVisitors = instructionVisitors;
+ this.instructionVisitorCount = instructionVisitors.length;
+ }
+
+
+ public void addInstructionVisitor(InstructionVisitor instructionVisitor)
+ {
+ ensureArraySize();
+
+ instructionVisitors[instructionVisitorCount++] = instructionVisitor;
+ }
+
+
+ private void ensureArraySize()
+ {
+ if (instructionVisitors == null)
+ {
+ instructionVisitors = new InstructionVisitor[ARRAY_SIZE_INCREMENT];
+ }
+ else if (instructionVisitors.length == instructionVisitorCount)
+ {
+ InstructionVisitor[] newInstructionVisitors =
+ new InstructionVisitor[instructionVisitorCount +
+ ARRAY_SIZE_INCREMENT];
+ System.arraycopy(instructionVisitors, 0,
+ newInstructionVisitors, 0,
+ instructionVisitorCount);
+ instructionVisitors = newInstructionVisitors;
+ }
+ }
+
+
+ // Implementations for InstructionVisitor.
+
+ public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
+ {
+ for (int index = 0; index < instructionVisitorCount; index++)
+ {
+ instructionVisitors[index].visitSimpleInstruction(clazz, method, codeAttribute, offset, simpleInstruction);
+ }
+ }
+
+ public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction)
+ {
+ for (int index = 0; index < instructionVisitorCount; index++)
+ {
+ instructionVisitors[index].visitVariableInstruction(clazz, method, codeAttribute, offset, variableInstruction);
+ }
+ }
+
+ public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
+ {
+ for (int index = 0; index < instructionVisitorCount; index++)
+ {
+ instructionVisitors[index].visitConstantInstruction(clazz, method, codeAttribute, offset, constantInstruction);
+ }
+ }
+
+ public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)
+ {
+ for (int index = 0; index < instructionVisitorCount; index++)
+ {
+ instructionVisitors[index].visitBranchInstruction(clazz, method, codeAttribute, offset, branchInstruction);
+ }
+ }
+
+ public void visitTableSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction)
+ {
+ for (int index = 0; index < instructionVisitorCount; index++)
+ {
+ instructionVisitors[index].visitTableSwitchInstruction(clazz, method, codeAttribute, offset, tableSwitchInstruction);
+ }
+ }
+
+ public void visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction)
+ {
+ for (int index = 0; index < instructionVisitorCount; index++)
+ {
+ instructionVisitors[index].visitLookUpSwitchInstruction(clazz, method, codeAttribute, offset, lookUpSwitchInstruction);
+ }
+ }
+}
diff --git a/src/proguard/classfile/instruction/visitor/package.html b/src/proguard/classfile/instruction/visitor/package.html
new file mode 100644
index 0000000..a31a408
--- /dev/null
+++ b/src/proguard/classfile/instruction/visitor/package.html
@@ -0,0 +1,3 @@
+<body>
+This package contains visitors for instructions.
+</body>