View Javadoc
1   /*
2    * MIT License
3    * Copyright (c) 2006-2025 JMockit developers
4    * See LICENSE file for full license text.
5    */
6   package mockit.asm.classes;
7   
8   import static mockit.asm.jvmConstants.ConstantPoolTypes.CLASS;
9   import static mockit.asm.jvmConstants.ConstantPoolTypes.DOUBLE;
10  import static mockit.asm.jvmConstants.ConstantPoolTypes.DYNAMIC;
11  import static mockit.asm.jvmConstants.ConstantPoolTypes.FIELD_REF;
12  import static mockit.asm.jvmConstants.ConstantPoolTypes.FLOAT;
13  import static mockit.asm.jvmConstants.ConstantPoolTypes.IMETHOD_REF;
14  import static mockit.asm.jvmConstants.ConstantPoolTypes.INTEGER;
15  import static mockit.asm.jvmConstants.ConstantPoolTypes.INVOKE_DYNAMIC;
16  import static mockit.asm.jvmConstants.ConstantPoolTypes.LONG;
17  import static mockit.asm.jvmConstants.ConstantPoolTypes.METHOD_HANDLE;
18  import static mockit.asm.jvmConstants.ConstantPoolTypes.METHOD_REF;
19  import static mockit.asm.jvmConstants.ConstantPoolTypes.METHOD_TYPE;
20  import static mockit.asm.jvmConstants.ConstantPoolTypes.MODULE;
21  import static mockit.asm.jvmConstants.ConstantPoolTypes.NAME_TYPE;
22  import static mockit.asm.jvmConstants.ConstantPoolTypes.PACKAGE;
23  import static mockit.asm.jvmConstants.ConstantPoolTypes.STRING;
24  import static mockit.asm.jvmConstants.ConstantPoolTypes.UTF8;
25  
26  import edu.umd.cs.findbugs.annotations.NonNull;
27  import edu.umd.cs.findbugs.annotations.Nullable;
28  
29  import mockit.asm.constantPool.ClassMemberItem;
30  import mockit.asm.constantPool.DoubleItem;
31  import mockit.asm.constantPool.DynamicItem;
32  import mockit.asm.constantPool.FloatItem;
33  import mockit.asm.constantPool.IntItem;
34  import mockit.asm.constantPool.Item;
35  import mockit.asm.constantPool.LongItem;
36  import mockit.asm.constantPool.MethodHandleItem;
37  import mockit.asm.constantPool.ModuleItem;
38  import mockit.asm.constantPool.NameAndTypeItem;
39  import mockit.asm.constantPool.PackageItem;
40  import mockit.asm.constantPool.StringItem;
41  import mockit.asm.util.MethodHandle;
42  
43  import org.checkerframework.checker.index.qual.NonNegative;
44  
45  /**
46   * Copies the constant pool data from a {@link ClassReader} into a {@link ClassWriter}.
47   */
48  final class ConstantPoolCopying {
49      @NonNull
50      private final ClassReader source;
51      @NonNull
52      private final ClassWriter destination;
53      @NonNull
54      private final Item[] newItems;
55      @NonNegative
56      private int itemIndex;
57  
58      ConstantPoolCopying(@NonNull ClassReader source, @NonNull ClassWriter destination) {
59          this.source = source;
60          this.destination = destination;
61          newItems = new Item[source.items.length];
62      }
63  
64      void copyPool(@Nullable BootstrapMethodsWriter bootstrapMethods) {
65          if (bootstrapMethods != null) {
66              bootstrapMethods.copyBootstrapMethods(source, newItems);
67          }
68  
69          int[] items = source.items;
70          int itemCount = items.length;
71  
72          for (itemIndex = 1; itemIndex < itemCount; itemIndex++) {
73              source.codeIndex = items[itemIndex] - 1;
74              int itemType = source.readSignedByte();
75  
76              Item newItem = copyItem(itemType);
77              newItem.setNext(newItems);
78          }
79  
80          int off = items[1] - 1;
81          destination.getConstantPoolGeneration().copy(source.code, off, source.header, newItems);
82      }
83  
84      @NonNull
85      @SuppressWarnings("OverlyComplexMethod")
86      private Item copyItem(int itemType) {
87          switch (itemType) {
88              case UTF8:
89                  return copyUTF8Item();
90              case INTEGER:
91                  return copyIntItem();
92              case FLOAT:
93                  return copyFloatItem();
94              case LONG:
95                  return copyLongItem();
96              case DOUBLE:
97                  return copyDoubleItem();
98              case FIELD_REF:
99              case METHOD_REF:
100             case IMETHOD_REF:
101                 return copyFieldOrMethodReferenceItem(itemType);
102             case NAME_TYPE:
103                 return copyNameAndTypeItem();
104             case METHOD_HANDLE:
105                 return copyHandleItem();
106             case DYNAMIC:
107             case INVOKE_DYNAMIC:
108                 return copyDynamicItem(itemType);
109             case STRING:
110             case CLASS:
111             case METHOD_TYPE:
112                 return copyNameReferenceItem(itemType);
113             case MODULE:
114                 return copyModule();
115             case PACKAGE:
116                 return copyPackage();
117             default:
118                 throw new IllegalArgumentException("Unknown CP type, cannot copy: " + itemType);
119         }
120     }
121 
122     @NonNull
123     private Item copyIntItem() {
124         int itemValue = source.readInt();
125         IntItem item = new IntItem(itemIndex);
126         item.setValue(itemValue);
127         return item;
128     }
129 
130     @NonNull
131     private Item copyLongItem() {
132         long itemValue = source.readLong();
133         LongItem item = new LongItem(itemIndex);
134         item.setValue(itemValue);
135         itemIndex++;
136         return item;
137     }
138 
139     @NonNull
140     private Item copyFloatItem() {
141         float itemValue = source.readFloat();
142         FloatItem item = new FloatItem(itemIndex);
143         item.set(itemValue);
144         return item;
145     }
146 
147     @NonNull
148     private Item copyDoubleItem() {
149         double itemValue = source.readDouble();
150         DoubleItem item = new DoubleItem(itemIndex);
151         item.set(itemValue);
152         itemIndex++;
153         return item;
154     }
155 
156     @NonNull
157     private Item copyUTF8Item() {
158         String strVal = source.readString(itemIndex);
159         return new StringItem(itemIndex, UTF8, strVal);
160     }
161 
162     @NonNull
163     private Item copyNameReferenceItem(int type) {
164         String strVal = source.readNonnullUTF8();
165         return new StringItem(itemIndex, type, strVal);
166     }
167 
168     @NonNull
169     private Item copyNameAndTypeItem() {
170         String name = source.readNonnullUTF8();
171         String type = source.readNonnullUTF8();
172 
173         NameAndTypeItem item = new NameAndTypeItem(itemIndex);
174         item.set(name, type);
175         return item;
176     }
177 
178     @NonNull
179     private Item copyFieldOrMethodReferenceItem(int type) {
180         String classDesc = source.readNonnullClass();
181         int nameCodeIndex = source.readItem();
182         String methodName = source.readNonnullUTF8(nameCodeIndex);
183         String methodDesc = source.readNonnullUTF8(nameCodeIndex + 2);
184 
185         ClassMemberItem item = new ClassMemberItem(itemIndex);
186         item.set(type, classDesc, methodName, methodDesc);
187         return item;
188     }
189 
190     @NonNull
191     private Item copyHandleItem() {
192         int tag = source.readUnsignedByte();
193 
194         int fieldOrMethodRef = source.readItem();
195         int nameCodeIndex = source.readItem(fieldOrMethodRef + 2);
196 
197         String classDesc = source.readNonnullClass(fieldOrMethodRef);
198         String name = source.readNonnullUTF8(nameCodeIndex);
199         String desc = source.readNonnullUTF8(nameCodeIndex + 2);
200 
201         MethodHandle handle = new MethodHandle(tag, classDesc, name, desc);
202         MethodHandleItem item = new MethodHandleItem(itemIndex);
203         item.set(handle);
204         return item;
205     }
206 
207     @NonNull
208     private Item copyDynamicItem(int type) {
209         int bsmIndex = source.readUnsignedShort();
210         int nameCodeIndex = source.readItem();
211         String name = source.readNonnullUTF8(nameCodeIndex);
212         String desc = source.readNonnullUTF8(nameCodeIndex + 2);
213 
214         DynamicItem item = new DynamicItem(itemIndex);
215         item.set(type, name, desc, bsmIndex);
216         return item;
217     }
218 
219     @NonNull
220     private Item copyModule() {
221         int nameIndex = source.readItem();
222         String name = source.readNonnullUTF8(nameIndex);
223         return new ModuleItem(itemIndex, MODULE, name);
224     }
225 
226     @NonNull
227     private Item copyPackage() {
228         int nameIndex = source.readItem();
229         String name = source.readNonnullUTF8(nameIndex);
230         return new PackageItem(itemIndex, PACKAGE, name);
231     }
232 }