< 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         }

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 

 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.lang.reflect.ClassFileFormatVersion;
 41 import java.util.AbstractList;
 42 import java.util.Collection;
 43 import java.util.List;
 44 import java.util.function.Consumer;
 45 import java.util.function.Function;
 46 
 47 import jdk.internal.access.SharedSecrets;
 48 import jdk.internal.constant.ClassOrInterfaceDescImpl;
 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         }

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

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

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