< prev index next >

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

Print this page

  1 /*
  2  * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 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         }

178             @Override
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         for (int i = 0; i < result.length; i++) {
193             result[i] = TemporaryConstantPool.INSTANCE.classEntry(list.get(i));
194         }
195         return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(result);
196     }
197 








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

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

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

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








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

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











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

  1 /*
  2  * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 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         }

184             @Override
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         for (int i = 0; i < result.length; i++) {
199             result[i] = TemporaryConstantPool.INSTANCE.classEntry(list.get(i));
200         }
201         return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(result);
202     }
203 
204     public static List<Utf8Entry> fieldDescriptorList(List<? extends ClassDesc> list) {
205         var result = new Object[list.size()]; // null check
206         for (int i = 0; i < result.length; i++) {
207             result[i] = TemporaryConstantPool.INSTANCE.utf8Entry(list.get(i));
208         }
209         return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(result);
210     }
211 
212     public static List<ModuleEntry> moduleEntryList(List<? extends ModuleDesc> list) {
213         var result = new Object[list.size()]; // null check
214         for (int i = 0; i < result.length; i++) {
215             result[i] = TemporaryConstantPool.INSTANCE.moduleEntry(TemporaryConstantPool.INSTANCE.utf8Entry(list.get(i).name()));
216         }
217         return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(result);
218     }
219 
220     public static void checkKind(Opcode op, Opcode.Kind k) {
221         if (op.kind() != k)
222             throw badOpcodeKindException(op, k);
223     }
224 
225     public static IllegalArgumentException badOpcodeKindException(Opcode op, Opcode.Kind k) {
226         return new IllegalArgumentException(
227                 String.format("Wrong opcode kind specified; found %s(%s), expected %s", op, op.kind(), k));
228     }
229 
230     /// Ensures the given value won't be truncated when written as a u1
231     public static int checkU1(int incoming, String valueName) {

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

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

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