• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  *             of Java bytecode.
4  *
5  * Copyright (c) 2002-2014 Eric Lafortune (eric@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      */
ConstantAdder(ProgramClass targetClass)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      */
addConstant(Clazz clazz, int constantIndex)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      */
addConstant(Clazz clazz, Constant constant)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      */
getConstantIndex()85     public int getConstantIndex()
86     {
87         return constantIndex;
88     }
89 
90 
91     // Implementations for ConstantVisitor.
92 
visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant)93     public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant)
94     {
95         constantIndex =
96             constantPoolEditor.addIntegerConstant(integerConstant.getValue());
97     }
98 
99 
visitLongConstant(Clazz clazz, LongConstant longConstant)100     public void visitLongConstant(Clazz clazz, LongConstant longConstant)
101     {
102         constantIndex =
103             constantPoolEditor.addLongConstant(longConstant.getValue());
104     }
105 
106 
visitFloatConstant(Clazz clazz, FloatConstant floatConstant)107     public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant)
108     {
109         constantIndex =
110             constantPoolEditor.addFloatConstant(floatConstant.getValue());
111     }
112 
113 
visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)114     public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)
115     {
116         constantIndex =
117             constantPoolEditor.addDoubleConstant(doubleConstant.getValue());
118     }
119 
120 
visitStringConstant(Clazz clazz, StringConstant stringConstant)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 
visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant)130     public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant)
131     {
132         constantIndex =
133             constantPoolEditor.addUtf8Constant(utf8Constant.getString());
134     }
135 
136 
visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)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 
visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant)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 
visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)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 
visitInterfaceMethodrefConstant(Clazz clazz, InterfaceMethodrefConstant interfaceMethodrefConstant)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 
visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant)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 
visitClassConstant(Clazz clazz, ClassConstant classConstant)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 
visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant)242     public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant)
243     {
244         constantIndex =
245             constantPoolEditor.addMethodTypeConstant(methodTypeConstant.getType(clazz));
246     }
247 
248 
visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)249     public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)
250     {
251         constantIndex =
252             constantPoolEditor.addNameAndTypeConstant(nameAndTypeConstant.getName(clazz),
253                                                       nameAndTypeConstant.getType(clazz));
254     }
255 }
256