Home | History | Annotate | Download | only in instruction
      1 /*
      2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
      3  *             of Java bytecode.
      4  *
      5  * Copyright (c) 2002-2009 Eric Lafortune (eric (at) graphics.cornell.edu)
      6  *
      7  * This program is free software; you can redistribute it and/or modify it
      8  * under the terms of the GNU General Public License as published by the Free
      9  * Software Foundation; either version 2 of the License, or (at your option)
     10  * any later version.
     11  *
     12  * This program is distributed in the hope that it will be useful, but WITHOUT
     13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
     15  * more details.
     16  *
     17  * You should have received a copy of the GNU General Public License along
     18  * with this program; if not, write to the Free Software Foundation, Inc.,
     19  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
     20  */
     21 package proguard.classfile.instruction;
     22 
     23 import proguard.classfile.*;
     24 import proguard.classfile.attribute.CodeAttribute;
     25 import proguard.classfile.constant.*;
     26 import proguard.classfile.constant.visitor.ConstantVisitor;
     27 import proguard.classfile.instruction.visitor.InstructionVisitor;
     28 import proguard.classfile.util.ClassUtil;
     29 
     30 /**
     31  * This Instruction represents an instruction that refers to an entry in the
     32  * constant pool.
     33  *
     34  * @author Eric Lafortune
     35  */
     36 public class ConstantInstruction extends Instruction
     37 implements   ConstantVisitor
     38 {
     39     public int constantIndex;
     40     public int constant;
     41 
     42 
     43     // Fields acting as return parameters for the ConstantVisitor methods.
     44     private int parameterStackDelta;
     45     private int typeStackDelta;
     46 
     47 
     48     /**
     49      * Creates an uninitialized ConstantInstruction.
     50      */
     51     public ConstantInstruction() {}
     52 
     53 
     54     /**
     55      * Creates a new ConstantInstruction with the given opcode and constant pool
     56      * index.
     57      */
     58     public ConstantInstruction(byte opcode, int constantIndex)
     59     {
     60         this(opcode, constantIndex, 0);
     61     }
     62 
     63 
     64     /**
     65      * Creates a new ConstantInstruction with the given opcode, constant pool
     66      * index, and constant.
     67      */
     68     public ConstantInstruction(byte opcode, int constantIndex, int constant)
     69     {
     70         this.opcode        = opcode;
     71         this.constantIndex = constantIndex;
     72         this.constant      = constant;
     73     }
     74 
     75 
     76     /**
     77      * Copies the given instruction into this instruction.
     78      * @param constantInstruction the instruction to be copied.
     79      * @return this instruction.
     80      */
     81     public ConstantInstruction copy(ConstantInstruction constantInstruction)
     82     {
     83         this.opcode        = constantInstruction.opcode;
     84         this.constantIndex = constantInstruction.constantIndex;
     85         this.constant      = constantInstruction.constant;
     86 
     87         return this;
     88     }
     89 
     90 
     91     // Implementations for Instruction.
     92 
     93     public byte canonicalOpcode()
     94     {
     95         // Remove the _w extension, if any.
     96         switch (opcode)
     97         {
     98             case InstructionConstants.OP_LDC_W:
     99             case InstructionConstants.OP_LDC2_W: return InstructionConstants.OP_LDC;
    100 
    101             default: return opcode;
    102         }
    103     }
    104 
    105     public Instruction shrink()
    106     {
    107         // Do we need a short index or a long index?
    108         if (requiredConstantIndexSize() == 1)
    109         {
    110             // Can we replace the long instruction by a short instruction?
    111             if (opcode == InstructionConstants.OP_LDC_W)
    112             {
    113                 opcode = InstructionConstants.OP_LDC;
    114             }
    115         }
    116         else
    117         {
    118             // Should we replace the short instruction by a long instruction?
    119             if (opcode == InstructionConstants.OP_LDC)
    120             {
    121                 opcode = InstructionConstants.OP_LDC_W;
    122             }
    123         }
    124 
    125         return this;
    126     }
    127 
    128     protected void readInfo(byte[] code, int offset)
    129     {
    130         int constantIndexSize = constantIndexSize();
    131         int constantSize      = constantSize();
    132 
    133         constantIndex = readValue(code, offset, constantIndexSize);  offset += constantIndexSize;
    134         constant      = readValue(code, offset, constantSize);
    135     }
    136 
    137 
    138     protected void writeInfo(byte[] code, int offset)
    139     {
    140         int constantIndexSize = constantIndexSize();
    141         int constantSize      = constantSize();
    142 
    143         if (requiredConstantIndexSize() > constantIndexSize)
    144         {
    145             throw new IllegalArgumentException("Instruction has invalid constant index size ("+this.toString(offset)+")");
    146         }
    147 
    148         writeValue(code, offset, constantIndex, constantIndexSize); offset += constantIndexSize;
    149         writeValue(code, offset, constant,      constantSize);
    150     }
    151 
    152 
    153     public int length(int offset)
    154     {
    155         return 1 + constantIndexSize() + constantSize();
    156     }
    157 
    158 
    159     public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, InstructionVisitor instructionVisitor)
    160     {
    161         instructionVisitor.visitConstantInstruction(clazz, method, codeAttribute, offset, this);
    162     }
    163 
    164 
    165     public int stackPopCount(Clazz clazz)
    166     {
    167         int stackPopCount = super.stackPopCount(clazz);
    168 
    169         // Some special cases.
    170         switch (opcode)
    171         {
    172             case InstructionConstants.OP_MULTIANEWARRAY:
    173                 // For each dimension, an integer size is popped from the stack.
    174                 stackPopCount += constant;
    175                 break;
    176 
    177             case InstructionConstants.OP_PUTSTATIC:
    178             case InstructionConstants.OP_PUTFIELD:
    179                 // The field value is be popped from the stack.
    180                 clazz.constantPoolEntryAccept(constantIndex, this);
    181                 stackPopCount += typeStackDelta;
    182                 break;
    183 
    184             case InstructionConstants.OP_INVOKEVIRTUAL:
    185             case InstructionConstants.OP_INVOKESPECIAL:
    186             case InstructionConstants.OP_INVOKESTATIC:
    187             case InstructionConstants.OP_INVOKEINTERFACE:
    188                 // The some parameters may be popped from the stack.
    189                 clazz.constantPoolEntryAccept(constantIndex, this);
    190                 stackPopCount += parameterStackDelta;
    191                 break;
    192         }
    193 
    194         return stackPopCount;
    195     }
    196 
    197 
    198     public int stackPushCount(Clazz clazz)
    199     {
    200         int stackPushCount = super.stackPushCount(clazz);
    201 
    202         // Some special cases.
    203         switch (opcode)
    204         {
    205             case InstructionConstants.OP_GETSTATIC:
    206             case InstructionConstants.OP_GETFIELD:
    207             case InstructionConstants.OP_INVOKEVIRTUAL:
    208             case InstructionConstants.OP_INVOKESPECIAL:
    209             case InstructionConstants.OP_INVOKESTATIC:
    210             case InstructionConstants.OP_INVOKEINTERFACE:
    211                 // The field value or a return value may be pushed onto the stack.
    212                 clazz.constantPoolEntryAccept(constantIndex, this);
    213                 stackPushCount += typeStackDelta;
    214                 break;
    215         }
    216 
    217         return stackPushCount;
    218     }
    219 
    220 
    221     // Implementations for ConstantVisitor.
    222 
    223     public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant) {}
    224     public void visitLongConstant(Clazz clazz, LongConstant longConstant) {}
    225     public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant) {}
    226     public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant) {}
    227     public void visitStringConstant(Clazz clazz, StringConstant stringConstant) {}
    228     public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) {}
    229     public void visitClassConstant(Clazz clazz, ClassConstant classConstant) {}
    230     public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) {}
    231 
    232 
    233     public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)
    234     {
    235         String type = fieldrefConstant.getType(clazz);
    236 
    237         typeStackDelta = ClassUtil.internalTypeSize(ClassUtil.internalMethodReturnType(type));
    238     }
    239 
    240 
    241     public void visitInterfaceMethodrefConstant(Clazz clazz, InterfaceMethodrefConstant interfaceMethodrefConstant)
    242     {
    243         visitRefConstant(clazz, interfaceMethodrefConstant);
    244     }
    245 
    246 
    247     public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant)
    248     {
    249         visitRefConstant(clazz, methodrefConstant);
    250     }
    251 
    252 
    253     private void visitRefConstant(Clazz clazz, RefConstant methodrefConstant)
    254     {
    255         String type = methodrefConstant.getType(clazz);
    256 
    257         parameterStackDelta = ClassUtil.internalMethodParameterSize(type);
    258         typeStackDelta      = ClassUtil.internalTypeSize(ClassUtil.internalMethodReturnType(type));
    259     }
    260 
    261 
    262     // Implementations for Object.
    263 
    264     public String toString()
    265     {
    266         return getName()+" #"+constantIndex;
    267     }
    268 
    269 
    270     // Small utility methods.
    271 
    272     /**
    273      * Returns the constant pool index size for this instruction.
    274      */
    275     private int constantIndexSize()
    276     {
    277         return opcode == InstructionConstants.OP_LDC ? 1 :
    278                                                        2;
    279     }
    280 
    281 
    282     /**
    283      * Returns the constant size for this instruction.
    284      */
    285     private int constantSize()
    286     {
    287         return opcode == InstructionConstants.OP_MULTIANEWARRAY  ? 1 :
    288                opcode == InstructionConstants.OP_INVOKEINTERFACE ? 2 :
    289                                                                    0;
    290     }
    291 
    292 
    293     /**
    294      * Computes the required constant pool index size for this instruction's
    295      * constant pool index.
    296      */
    297     private int requiredConstantIndexSize()
    298     {
    299         return (constantIndex &   0xff) == constantIndex ? 1 :
    300                (constantIndex & 0xffff) == constantIndex ? 2 :
    301                                                            4;
    302     }
    303 }
    304