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 */
21package proguard.classfile.editor;
22
23import proguard.classfile.*;
24import proguard.classfile.attribute.*;
25import proguard.classfile.constant.*;
26import 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 */
37public class ConstantAdder
38implements   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