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