< prev index next >

src/java.base/share/classes/jdk/internal/classfile/impl/Util.java

Print this page

 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 package jdk.internal.classfile.impl;
 26 
 27 import java.lang.classfile.*;
 28 import java.lang.classfile.attribute.CodeAttribute;
 29 import jdk.internal.classfile.components.ClassPrinter;
 30 import java.lang.classfile.constantpool.ClassEntry;


 31 import java.lang.classfile.constantpool.ModuleEntry;
 32 import java.lang.classfile.constantpool.PoolEntry;
 33 import java.lang.classfile.constantpool.Utf8Entry;
 34 import java.lang.constant.ClassDesc;
 35 import java.lang.constant.MethodTypeDesc;
 36 import java.lang.constant.ModuleDesc;
 37 import java.lang.reflect.AccessFlag;
 38 import java.util.AbstractList;
 39 import java.util.Collection;
 40 import java.util.List;
 41 import java.util.function.Consumer;
 42 import java.util.function.Function;
 43 
 44 import jdk.internal.access.SharedSecrets;
 45 import jdk.internal.constant.ClassOrInterfaceDescImpl;

 46 import jdk.internal.vm.annotation.ForceInline;
 47 import jdk.internal.vm.annotation.Stable;
 48 
 49 import static java.lang.classfile.ClassFile.ACC_STATIC;

 50 import static jdk.internal.constant.PrimitiveClassDescImpl.CD_double;
 51 import static jdk.internal.constant.PrimitiveClassDescImpl.CD_long;
 52 import static jdk.internal.constant.PrimitiveClassDescImpl.CD_void;
 53 
 54 /**
 55  * Helper to create and manipulate type descriptors, where type descriptors are
 56  * represented as JVM type descriptor strings and symbols are represented as
 57  * name strings
 58  */
 59 public final class Util {
 60 


 61     private Util() {
 62     }
 63 
 64     public static <T> Consumer<Consumer<T>> writingAll(Iterable<T> container) {
 65         record ForEachConsumer<T>(Iterable<T> container) implements Consumer<Consumer<T>> {
 66             @Override
 67             public void accept(Consumer<T> consumer) {
 68                 container.forEach(consumer);
 69             }
 70         }
 71         return new ForEachConsumer<>(container);
 72     }
 73 
 74     public static Consumer<MethodBuilder> buildingCode(Consumer<? super CodeBuilder> codeHandler) {
 75         record WithCodeMethodHandler(Consumer<? super CodeBuilder> codeHandler) implements Consumer<MethodBuilder> {
 76             @Override
 77             public void accept(MethodBuilder builder) {
 78                 builder.withCode(codeHandler);
 79             }
 80         }

179             public U get(int index) {
180                 return mapper.apply(list.get(index));
181             }
182 
183             @Override
184             public int size() {
185                 return list.size();
186             }
187         };
188     }
189 
190     public static List<ClassEntry> entryList(List<? extends ClassDesc> list) {
191         var result = new Object[list.size()]; // null check
192         int i = 0;
193         for (var entry : list) {
194             result[i++] = TemporaryConstantPool.INSTANCE.classEntry(entry);
195         }
196         return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(result);
197     }
198 









199     public static List<ModuleEntry> moduleEntryList(List<? extends ModuleDesc> list) {
200         var result = new Object[list.size()]; // null check
201         int i = 0;
202         for (var entry : list) {
203             result[i++] = TemporaryConstantPool.INSTANCE.moduleEntry(entry);
204         }
205         return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(result);
206     }
207 
208     public static void checkKind(Opcode op, Opcode.Kind k) {
209         if (op.kind() != k)
210             throw badOpcodeKindException(op, k);
211     }
212 
213     public static IllegalArgumentException badOpcodeKindException(Opcode op, Opcode.Kind k) {
214         return new IllegalArgumentException(
215                 String.format("Wrong opcode kind specified; found %s(%s), expected %s", op, op.kind(), k));
216     }
217 
218     /// Ensures the given value won't be truncated when written as a u1

237 
238     /// Ensures the given mask won't be truncated when written as an access flag
239     public static char checkFlags(int mask) {
240         return checkU2(mask, "access flags");
241     }
242 
243     public static int flagsToBits(AccessFlag.Location location, Collection<AccessFlag> flags) {
244         int i = 0;
245         for (AccessFlag f : flags) {
246             if (!f.locations().contains(location)) {
247                 throw new IllegalArgumentException("unexpected flag: " + f + " use in target location: " + location);
248             }
249             i |= f.mask();
250         }
251         return i;
252     }
253 
254     public static int flagsToBits(AccessFlag.Location location, AccessFlag... flags) {
255         int i = 0;
256         for (AccessFlag f : flags) {
257             if (!f.locations().contains(location)) {
258                 throw new IllegalArgumentException("unexpected flag: " + f + " use in target location: " + location);
259             }
260             i |= f.mask();
261         }
262         return i;
263     }
264 
265     public static boolean has(AccessFlag.Location location, int flagsMask, AccessFlag flag) {
266         return (flag.mask() & flagsMask) == flag.mask() && flag.locations().contains(location);

267     }
268 
269     public static ClassDesc fieldTypeSymbol(Utf8Entry utf8) {
270         return ((AbstractPoolEntry.Utf8EntryImpl) utf8).fieldTypeSymbol();
271     }
272 
273     public static MethodTypeDesc methodTypeSymbol(Utf8Entry utf8) {
274         return ((AbstractPoolEntry.Utf8EntryImpl) utf8).methodTypeSymbol();
275     }
276 
277     @SuppressWarnings("unchecked")
278     public static <T extends Attribute<T>> void writeAttribute(BufWriterImpl writer, Attribute<?> attr) {
279         if (attr instanceof CustomAttribute<?> ca) {
280             var mapper = (AttributeMapper<T>) ca.attributeMapper();
281             mapper.writeAttribute(writer, (T) ca);
282         } else {
283             assert attr instanceof BoundAttribute || attr instanceof UnboundAttribute;
284             ((Writable) attr).writeTo(writer);
285         }
286     }

299     static void writeList(BufWriterImpl buf, Writable[] array, int size) {
300         Util.checkU2(size, "member count");
301         buf.writeU2(size);
302         for (int i = 0; i < size; i++) {
303             array[i].writeTo(buf);
304         }
305     }
306 
307     public static int slotSize(ClassDesc desc) {
308         return desc == CD_void ? 0 : isDoubleSlot(desc) ? 2 : 1;
309     }
310 
311     public static int paramSlotSize(ClassDesc desc) {
312         return isDoubleSlot(desc) ? 2 : 1;
313     }
314 
315     public static boolean isDoubleSlot(ClassDesc desc) {
316         return desc == CD_double || desc == CD_long;
317     }
318 








319     public static void dumpMethod(SplitConstantPool cp,
320                                   ClassDesc cls,
321                                   String methodName,
322                                   MethodTypeDesc methodDesc,
323                                   int acc,
324                                   RawBytecodeHelper.CodeRange bytecode,
325                                   Consumer<String> dump) {
326 
327         // try to dump debug info about corrupted bytecode
328         try {
329             var cc = ClassFile.of();
330             var clm = cc.parse(cc.build(cp.classEntry(cls), cp, clb ->
331                     clb.withMethod(methodName, methodDesc, acc, mb ->
332                             ((DirectMethodBuilder)mb).writeAttribute(new UnboundAttribute.AdHocAttribute<CodeAttribute>(Attributes.code()) {
333                                 @Override
334                                 public void writeBody(BufWriterImpl b) {
335                                     b.writeU2U2(-1, -1);//max stack & locals
336                                     b.writeInt(bytecode.length());
337                                     b.writeBytes(bytecode.array(), 0, bytecode.length());
338                                     b.writeU2U2(0, 0);//exception handlers & attributes

342                                 public Utf8Entry attributeName() {
343                                     return cp.utf8Entry(Attributes.NAME_CODE);
344                                 }
345                     }))));
346             ClassPrinter.toYaml(clm.methods().get(0).code().get(), ClassPrinter.Verbosity.TRACE_ALL, dump);
347         } catch (Error | Exception _) {
348             // fallback to bytecode hex dump
349             dumpBytesHex(dump, bytecode.array(), bytecode.length());
350         }
351     }
352 
353     public static void dumpBytesHex(Consumer<String> dump, byte[] bytes, int length) {
354         for (int i = 0; i < length; i++) {
355             if (i % 16 == 0) {
356                 dump.accept("%n%04x:".formatted(i));
357             }
358             dump.accept(" %02x".formatted(bytes[i]));
359         }
360     }
361 











362     public static void writeListIndices(BufWriter writer, List<? extends PoolEntry> list) {
363         writer.writeU2(list.size());
364         for (PoolEntry info : list) {
365             writer.writeIndex(info);
366         }
367     }
368 
369     public static boolean writeLocalVariable(BufWriterImpl buf, PseudoInstruction lvOrLvt) {
370         return ((WritableLocalVariable) lvOrLvt).writeLocalTo(buf);
371     }
372 
373     /**
374      * A generic interface for objects to write to a
375      * buf writer. Do not implement unless necessary,
376      * as this writeTo is public, which can be troublesome.
377      */
378     interface Writable {
379         void writeTo(BufWriterImpl writer);
380     }
381 

 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 package jdk.internal.classfile.impl;
 26 
 27 import java.lang.classfile.*;
 28 import java.lang.classfile.attribute.CodeAttribute;
 29 import jdk.internal.classfile.components.ClassPrinter;
 30 import java.lang.classfile.constantpool.ClassEntry;
 31 import java.lang.classfile.constantpool.ConstantPool;
 32 import java.lang.classfile.constantpool.ConstantPoolBuilder;
 33 import java.lang.classfile.constantpool.ModuleEntry;
 34 import java.lang.classfile.constantpool.PoolEntry;
 35 import java.lang.classfile.constantpool.Utf8Entry;
 36 import java.lang.constant.ClassDesc;
 37 import java.lang.constant.MethodTypeDesc;
 38 import java.lang.constant.ModuleDesc;
 39 import java.lang.reflect.AccessFlag;
 40 import java.util.AbstractList;
 41 import java.util.Collection;
 42 import java.util.List;
 43 import java.util.function.Consumer;
 44 import java.util.function.Function;
 45 
 46 import jdk.internal.access.SharedSecrets;
 47 import jdk.internal.constant.ClassOrInterfaceDescImpl;
 48 import jdk.internal.reflect.PreviewAccessFlags;
 49 import jdk.internal.vm.annotation.ForceInline;
 50 import jdk.internal.vm.annotation.Stable;
 51 
 52 import static java.lang.classfile.ClassFile.ACC_STATIC;
 53 import static java.lang.constant.ConstantDescs.INIT_NAME;
 54 import static jdk.internal.constant.PrimitiveClassDescImpl.CD_double;
 55 import static jdk.internal.constant.PrimitiveClassDescImpl.CD_long;
 56 import static jdk.internal.constant.PrimitiveClassDescImpl.CD_void;
 57 
 58 /**
 59  * Helper to create and manipulate type descriptors, where type descriptors are
 60  * represented as JVM type descriptor strings and symbols are represented as
 61  * name strings
 62  */
 63 public final class Util {
 64 
 65     public static final int VALUE_OBJECTS_MAJOR = ClassFile.latestMajorVersion();
 66 
 67     private Util() {
 68     }
 69 
 70     public static <T> Consumer<Consumer<T>> writingAll(Iterable<T> container) {
 71         record ForEachConsumer<T>(Iterable<T> container) implements Consumer<Consumer<T>> {
 72             @Override
 73             public void accept(Consumer<T> consumer) {
 74                 container.forEach(consumer);
 75             }
 76         }
 77         return new ForEachConsumer<>(container);
 78     }
 79 
 80     public static Consumer<MethodBuilder> buildingCode(Consumer<? super CodeBuilder> codeHandler) {
 81         record WithCodeMethodHandler(Consumer<? super CodeBuilder> codeHandler) implements Consumer<MethodBuilder> {
 82             @Override
 83             public void accept(MethodBuilder builder) {
 84                 builder.withCode(codeHandler);
 85             }
 86         }

185             public U get(int index) {
186                 return mapper.apply(list.get(index));
187             }
188 
189             @Override
190             public int size() {
191                 return list.size();
192             }
193         };
194     }
195 
196     public static List<ClassEntry> entryList(List<? extends ClassDesc> list) {
197         var result = new Object[list.size()]; // null check
198         int i = 0;
199         for (var entry : list) {
200             result[i++] = TemporaryConstantPool.INSTANCE.classEntry(entry);
201         }
202         return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(result);
203     }
204 
205     public static List<Utf8Entry> fieldDescriptorList(List<? extends ClassDesc> list) {
206         var result = new Object[list.size()]; // null check
207         int i = 0;
208         for (var entry : list) {
209             result[i++] = TemporaryConstantPool.INSTANCE.utf8Entry(entry);
210         }
211         return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(result);
212     }
213 
214     public static List<ModuleEntry> moduleEntryList(List<? extends ModuleDesc> list) {
215         var result = new Object[list.size()]; // null check
216         int i = 0;
217         for (var entry : list) {
218             result[i++] = TemporaryConstantPool.INSTANCE.moduleEntry(entry);
219         }
220         return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(result);
221     }
222 
223     public static void checkKind(Opcode op, Opcode.Kind k) {
224         if (op.kind() != k)
225             throw badOpcodeKindException(op, k);
226     }
227 
228     public static IllegalArgumentException badOpcodeKindException(Opcode op, Opcode.Kind k) {
229         return new IllegalArgumentException(
230                 String.format("Wrong opcode kind specified; found %s(%s), expected %s", op, op.kind(), k));
231     }
232 
233     /// Ensures the given value won't be truncated when written as a u1

252 
253     /// Ensures the given mask won't be truncated when written as an access flag
254     public static char checkFlags(int mask) {
255         return checkU2(mask, "access flags");
256     }
257 
258     public static int flagsToBits(AccessFlag.Location location, Collection<AccessFlag> flags) {
259         int i = 0;
260         for (AccessFlag f : flags) {
261             if (!f.locations().contains(location)) {
262                 throw new IllegalArgumentException("unexpected flag: " + f + " use in target location: " + location);
263             }
264             i |= f.mask();
265         }
266         return i;
267     }
268 
269     public static int flagsToBits(AccessFlag.Location location, AccessFlag... flags) {
270         int i = 0;
271         for (AccessFlag f : flags) {
272             if (!f.locations().contains(location) && !PreviewAccessFlags.locations(f).contains(location)) {
273                 throw new IllegalArgumentException("unexpected flag: " + f + " use in target location: " + location);
274             }
275             i |= f.mask();
276         }
277         return i;
278     }
279 
280     public static boolean has(AccessFlag.Location location, int flagsMask, AccessFlag flag) {
281         return (flag.mask() & flagsMask) == flag.mask() && (flag.locations().contains(location)
282                 || PreviewAccessFlags.locations(flag).contains(location));
283     }
284 
285     public static ClassDesc fieldTypeSymbol(Utf8Entry utf8) {
286         return ((AbstractPoolEntry.Utf8EntryImpl) utf8).fieldTypeSymbol();
287     }
288 
289     public static MethodTypeDesc methodTypeSymbol(Utf8Entry utf8) {
290         return ((AbstractPoolEntry.Utf8EntryImpl) utf8).methodTypeSymbol();
291     }
292 
293     @SuppressWarnings("unchecked")
294     public static <T extends Attribute<T>> void writeAttribute(BufWriterImpl writer, Attribute<?> attr) {
295         if (attr instanceof CustomAttribute<?> ca) {
296             var mapper = (AttributeMapper<T>) ca.attributeMapper();
297             mapper.writeAttribute(writer, (T) ca);
298         } else {
299             assert attr instanceof BoundAttribute || attr instanceof UnboundAttribute;
300             ((Writable) attr).writeTo(writer);
301         }
302     }

315     static void writeList(BufWriterImpl buf, Writable[] array, int size) {
316         Util.checkU2(size, "member count");
317         buf.writeU2(size);
318         for (int i = 0; i < size; i++) {
319             array[i].writeTo(buf);
320         }
321     }
322 
323     public static int slotSize(ClassDesc desc) {
324         return desc == CD_void ? 0 : isDoubleSlot(desc) ? 2 : 1;
325     }
326 
327     public static int paramSlotSize(ClassDesc desc) {
328         return isDoubleSlot(desc) ? 2 : 1;
329     }
330 
331     public static boolean isDoubleSlot(ClassDesc desc) {
332         return desc == CD_double || desc == CD_long;
333     }
334 
335     public static boolean checkConstantPoolsCompatible(ConstantPool one, ConstantPool two) {
336         if (one.equals(two))
337             return true;
338         if (one instanceof ConstantPoolBuilder cpb && cpb.canWriteDirect(two))
339             return true;
340         return two instanceof ConstantPoolBuilder cpb && cpb.canWriteDirect(one);
341     }
342 
343     public static void dumpMethod(SplitConstantPool cp,
344                                   ClassDesc cls,
345                                   String methodName,
346                                   MethodTypeDesc methodDesc,
347                                   int acc,
348                                   RawBytecodeHelper.CodeRange bytecode,
349                                   Consumer<String> dump) {
350 
351         // try to dump debug info about corrupted bytecode
352         try {
353             var cc = ClassFile.of();
354             var clm = cc.parse(cc.build(cp.classEntry(cls), cp, clb ->
355                     clb.withMethod(methodName, methodDesc, acc, mb ->
356                             ((DirectMethodBuilder)mb).writeAttribute(new UnboundAttribute.AdHocAttribute<CodeAttribute>(Attributes.code()) {
357                                 @Override
358                                 public void writeBody(BufWriterImpl b) {
359                                     b.writeU2U2(-1, -1);//max stack & locals
360                                     b.writeInt(bytecode.length());
361                                     b.writeBytes(bytecode.array(), 0, bytecode.length());
362                                     b.writeU2U2(0, 0);//exception handlers & attributes

366                                 public Utf8Entry attributeName() {
367                                     return cp.utf8Entry(Attributes.NAME_CODE);
368                                 }
369                     }))));
370             ClassPrinter.toYaml(clm.methods().get(0).code().get(), ClassPrinter.Verbosity.TRACE_ALL, dump);
371         } catch (Error | Exception _) {
372             // fallback to bytecode hex dump
373             dumpBytesHex(dump, bytecode.array(), bytecode.length());
374         }
375     }
376 
377     public static void dumpBytesHex(Consumer<String> dump, byte[] bytes, int length) {
378         for (int i = 0; i < length; i++) {
379             if (i % 16 == 0) {
380                 dump.accept("%n%04x:".formatted(i));
381             }
382             dump.accept(" %02x".formatted(bytes[i]));
383         }
384     }
385 
386     public static boolean canSkipMethodInflation(ClassReader cr, MethodInfo method, BufWriterImpl buf) {
387         if (!buf.canWriteDirect(cr)) {
388             return false;
389         }
390         if (method.methodName().equalsString(INIT_NAME) &&
391                 !buf.strictFieldsMatch(((ClassReaderImpl) cr).getContainedClass())) {
392             return false;
393         }
394         return true;
395     }
396 
397     public static void writeListIndices(BufWriter writer, List<? extends PoolEntry> list) {
398         writer.writeU2(list.size());
399         for (PoolEntry info : list) {
400             writer.writeIndex(info);
401         }
402     }
403 
404     public static boolean writeLocalVariable(BufWriterImpl buf, PseudoInstruction lvOrLvt) {
405         return ((WritableLocalVariable) lvOrLvt).writeLocalTo(buf);
406     }
407 
408     /**
409      * A generic interface for objects to write to a
410      * buf writer. Do not implement unless necessary,
411      * as this writeTo is public, which can be troublesome.
412      */
413     interface Writable {
414         void writeTo(BufWriterImpl writer);
415     }
416 
< prev index next >