Home | History | Annotate | Download | only in editor
      1 /*
      2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
      3  *             of Java bytecode.
      4  *
      5  * Copyright (c) 2002-2014 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.editor;
     22 
     23 import proguard.classfile.*;
     24 import proguard.classfile.attribute.*;
     25 import proguard.classfile.constant.*;
     26 import proguard.classfile.constant.visitor.ConstantVisitor;
     27 
     28 /**
     29  * This ConstantVisitor adds all constants that it visits to the constant pool
     30  * of a given target class.
     31  *
     32  * Bootstrap methods attributes are automatically updated for invokedynamic
     33  * constants.
     34  *
     35  * @author Eric Lafortune
     36  */
     37 public class ConstantAdder
     38 implements   ConstantVisitor
     39 {
     40     private final ConstantPoolEditor             constantPoolEditor;
     41     private final BootstrapMethodsAttributeAdder bootstrapMethodsAttributeAdder;
     42 
     43     private int constantIndex;
     44 
     45 
     46     /**
     47      * Creates a new ConstantAdder that will copy constants into the given
     48      * target class.
     49      */
     50     public ConstantAdder(ProgramClass targetClass)
     51     {
     52         constantPoolEditor             = new ConstantPoolEditor(targetClass);
     53         bootstrapMethodsAttributeAdder = new BootstrapMethodsAttributeAdder(targetClass);
     54     }
     55 
     56 
     57     /**
     58      * Adds a copy of the specified constant in the given class and returns
     59      * its index. If the specified index is 0, the returned value is 0 too.
     60      */
     61     public int addConstant(Clazz clazz, int constantIndex)
     62     {
     63         clazz.constantPoolEntryAccept(constantIndex, this);
     64 
     65         return this.constantIndex;
     66     }
     67 
     68 
     69     /**
     70      * Adds a copy of the given constant in the given class and returns
     71      * its index.
     72      */
     73     public int addConstant(Clazz clazz, Constant constant)
     74     {
     75         constant.accept(clazz, this);
     76 
     77         return this.constantIndex;
     78     }
     79 
     80 
     81     /**
     82      * Returns the index of the most recently created constant in the constant
     83      * pool of the target class.
     84      */
     85     public int getConstantIndex()
     86     {
     87         return constantIndex;
     88     }
     89 
     90 
     91     // Implementations for ConstantVisitor.
     92 
     93     public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant)
     94     {
     95         constantIndex =
     96             constantPoolEditor.addIntegerConstant(integerConstant.getValue());
     97     }
     98 
     99 
    100     public void visitLongConstant(Clazz clazz, LongConstant longConstant)
    101     {
    102         constantIndex =
    103             constantPoolEditor.addLongConstant(longConstant.getValue());
    104     }
    105 
    106 
    107     public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant)
    108     {
    109         constantIndex =
    110             constantPoolEditor.addFloatConstant(floatConstant.getValue());
    111     }
    112 
    113 
    114     public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)
    115     {
    116         constantIndex =
    117             constantPoolEditor.addDoubleConstant(doubleConstant.getValue());
    118     }
    119 
    120 
    121     public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
    122     {
    123         constantIndex =
    124             constantPoolEditor.addStringConstant(stringConstant.getString(clazz),
    125                                                  stringConstant.referencedClass,
    126                                                  stringConstant.referencedMember);
    127     }
    128 
    129 
    130     public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant)
    131     {
    132         constantIndex =
    133             constantPoolEditor.addUtf8Constant(utf8Constant.getString());
    134     }
    135 
    136 
    137     public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)
    138     {
    139         // Find the bootstrap methods attribute.
    140         AttributesEditor attributesEditor =
    141             new AttributesEditor((ProgramClass)clazz, false);
    142 
    143         BootstrapMethodsAttribute bootstrapMethodsAttribute =
    144             (BootstrapMethodsAttribute)attributesEditor.findAttribute(ClassConstants.ATTR_BootstrapMethods);
    145 
    146         // Add the name and type constant.
    147         clazz.constantPoolEntryAccept(invokeDynamicConstant.u2nameAndTypeIndex, this);
    148 
    149         // Copy the referenced classes.
    150         Clazz[] referencedClasses     = invokeDynamicConstant.referencedClasses;
    151         Clazz[] referencedClassesCopy = null;
    152         if (referencedClasses != null)
    153         {
    154             referencedClassesCopy = new Clazz[referencedClasses.length];
    155             System.arraycopy(referencedClasses, 0,
    156                              referencedClassesCopy, 0,
    157                              referencedClasses.length);
    158         }
    159 
    160         bootstrapMethodsAttribute.bootstrapMethodEntryAccept(clazz,
    161                                                              invokeDynamicConstant.getBootstrapMethodAttributeIndex(),
    162                                                              bootstrapMethodsAttributeAdder);
    163 
    164         // Then add the actual invoke dynamic constant.
    165         constantIndex =
    166             constantPoolEditor.addInvokeDynamicConstant(bootstrapMethodsAttributeAdder.getBootstrapMethodIndex(),
    167                                                         constantIndex,
    168                                                         referencedClassesCopy);
    169     }
    170 
    171 
    172     public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant)
    173     {
    174         // First add the field ref, interface method ref, or method ref
    175         // constant.
    176         clazz.constantPoolEntryAccept(methodHandleConstant.u2referenceIndex, this);
    177 
    178         // Then add the actual method handle constant.
    179         constantIndex =
    180             constantPoolEditor.addMethodHandleConstant(methodHandleConstant.getReferenceKind(),
    181                                                        constantIndex);
    182     }
    183 
    184 
    185     public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)
    186     {
    187         // First add the referenced class constant, with its own referenced class.
    188         clazz.constantPoolEntryAccept(fieldrefConstant.u2classIndex, this);
    189 
    190         // Then add the actual field reference constant, with its referenced
    191         // class and class member.
    192         constantIndex =
    193             constantPoolEditor.addFieldrefConstant(constantIndex,
    194                                                    fieldrefConstant.getName(clazz),
    195                                                    fieldrefConstant.getType(clazz),
    196                                                    fieldrefConstant.referencedClass,
    197                                                    fieldrefConstant.referencedMember);
    198     }
    199 
    200 
    201     public void visitInterfaceMethodrefConstant(Clazz clazz, InterfaceMethodrefConstant interfaceMethodrefConstant)
    202     {
    203         // First add the referenced class constant, with its own referenced class.
    204         clazz.constantPoolEntryAccept(interfaceMethodrefConstant.u2classIndex, this);
    205 
    206         // Then add the actual interface method reference constant, with its
    207         // referenced class and class member.
    208         constantIndex =
    209             constantPoolEditor.addInterfaceMethodrefConstant(constantIndex,
    210                                                              interfaceMethodrefConstant.getName(clazz),
    211                                                              interfaceMethodrefConstant.getType(clazz),
    212                                                              interfaceMethodrefConstant.referencedClass,
    213                                                              interfaceMethodrefConstant.referencedMember);
    214     }
    215 
    216 
    217     public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant)
    218     {
    219         // First add the referenced class constant, with its own referenced class.
    220         clazz.constantPoolEntryAccept(methodrefConstant.u2classIndex, this);
    221 
    222         // Then add the actual method reference constant, with its referenced
    223         // class and class member.
    224         constantIndex =
    225             constantPoolEditor.addMethodrefConstant(constantIndex,
    226                                                     methodrefConstant.getName(clazz),
    227                                                     methodrefConstant.getType(clazz),
    228                                                     methodrefConstant.referencedClass,
    229                                                     methodrefConstant.referencedMember);
    230     }
    231 
    232 
    233     public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
    234     {
    235         // Add the class constant, with its referenced class..
    236         constantIndex =
    237             constantPoolEditor.addClassConstant(classConstant.getName(clazz),
    238                                                 classConstant.referencedClass);
    239     }
    240 
    241 
    242     public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant)
    243     {
    244         constantIndex =
    245             constantPoolEditor.addMethodTypeConstant(methodTypeConstant.getType(clazz));
    246     }
    247 
    248 
    249     public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)
    250     {
    251         constantIndex =
    252             constantPoolEditor.addNameAndTypeConstant(nameAndTypeConstant.getName(clazz),
    253                                                       nameAndTypeConstant.getType(clazz));
    254     }
    255 }
    256