diff options
author | Joe Onorato <joeo@android.com> | 2009-08-31 10:12:00 -0700 |
---|---|---|
committer | Joe Onorato <joeo@android.com> | 2009-08-31 10:12:00 -0700 |
commit | b72c5c2e5482cf10117b2b25f642f7616b2326c3 (patch) | |
tree | f02ba1bc29f4fe6853d9b7008eed37cdcfb96e81 /src/proguard/classfile/instruction | |
parent | a23344a828357fe4b6596f8af5fed467d72757ab (diff) | |
download | external_proguard-b72c5c2e5482cf10117b2b25f642f7616b2326c3.tar.gz external_proguard-b72c5c2e5482cf10117b2b25f642f7616b2326c3.tar.bz2 external_proguard-b72c5c2e5482cf10117b2b25f642f7616b2326c3.zip |
ProGuard 4.4android-2.1_r2.1sandroid-2.1_r2.1p2android-2.1_r2.1pandroid-2.1_r2android-2.1_r1android-2.0_r1android-2.0.1_r1
Diffstat (limited to 'src/proguard/classfile/instruction')
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> |