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
|