1 /*
2 * Copyright (c) 2007, 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
26 package com.sun.tools.javap;
27
28 import java.lang.classfile.Annotation;
29 import java.lang.classfile.Attribute;
30 import java.lang.classfile.Attributes;
31 import java.lang.classfile.Signature;
32 import java.lang.classfile.TypeAnnotation;
33 import java.lang.classfile.attribute.*;
34 import java.lang.classfile.constantpool.ModuleEntry;
35 import java.lang.classfile.constantpool.PoolEntry;
36 import java.lang.classfile.constantpool.Utf8Entry;
37 import java.lang.reflect.AccessFlag;
38 import java.lang.reflect.ClassFileFormatVersion;
39 import java.lang.reflect.Modifier;
40 import java.nio.charset.StandardCharsets;
41 import java.util.List;
42 import java.util.Locale;
43
44 import static java.lang.classfile.ClassFile.ACC_MANDATED;
45 import static java.lang.classfile.ClassFile.ACC_SYNTHETIC;
46 import static java.lang.classfile.attribute.StackMapFrameInfo.*;
47 import static java.lang.classfile.instruction.CharacterRange.*;
48
49 /*
50 * A writer for writing Attributes as text.
51 *
52 * <p><b>This is NOT part of any supported API.
53 * If you write code that depends on this, you do so at your own risk.
54 * This code and its internal interfaces are subject to change or
55 * deletion without notice.</b>
56 */
57 public class AttributeWriter extends BasicWriter {
58
59 public static AttributeWriter instance(Context context) {
60 AttributeWriter instance = context.get(AttributeWriter.class);
61 if (instance == null)
62 instance = new AttributeWriter(context);
63 return instance;
64 }
65
66 protected AttributeWriter(Context context) {
67 super(context);
68 context.put(AttributeWriter.class, this);
69 annotationWriter = AnnotationWriter.instance(context);
70 codeWriter = CodeWriter.instance(context);
71 constantWriter = ConstantWriter.instance(context);
72 options = Options.instance(context);
73 }
74
75 public void write(List<Attribute<?>> attrs, ClassFileFormatVersion cffv) {
76 write(attrs, null, cffv);
77 }
78
79 public void write(List<Attribute<?>> attrs, CodeAttribute lr, ClassFileFormatVersion cffv) {
80 if (attrs != null) {
81 for (var attr : attrs) try {
82 write(attr, lr, cffv);
83 } catch (IllegalArgumentException e) {
84 report(e);
85 }
86 }
87 }
88
89 public void write(Attribute<?> a, CodeAttribute lr, ClassFileFormatVersion cffv) {
90 switch (a) {
91 case UnknownAttribute attr -> {
92 byte[] data = attr.contents();
93 int i = 0;
94 int j = 0;
95 print(" ");
96 print(attr.attributeName().stringValue());
97 print(": ");
98 print("length = 0x" + toHex(data.length));
99 print(" (unknown attribute)");
100 println();
101 print(" ");
102 while (i < data.length) {
103 print(toHex(data[i], 2));
104
105 j++;
106 if (j == 16) {
107 println();
108 print(" ");
109 j = 0;
110 } else {
111 print(" ");
112 }
113 i++;
114 }
115 println();
116 }
117 case AnnotationDefaultAttribute attr -> {
118 println("AnnotationDefault:");
119 indent(+1);
120 print("default_value: ");
121 annotationWriter.write(attr.defaultValue());
122 indent(-1);
123 println();
124 }
125 case BootstrapMethodsAttribute attr -> {
126 println("BootstrapMethods:");
127 for (int i = 0; i < attr.bootstrapMethodsSize() ; i++) {
128 var bsm = attr.bootstrapMethods().get(i);
129 indent(+1);
130 print(i + ": #" + bsm.bootstrapMethod().index() + " ");
131 println(constantWriter.stringValue(bsm.bootstrapMethod()));
132 indent(+1);
133 println("Method arguments:");
134 indent(+1);
135 for (var arg : bsm.arguments()) {
136 print("#" + arg.index() + " ");
137 println(constantWriter.stringValue(arg));
138 }
139 indent(-3);
140 }
141 }
142 case CharacterRangeTableAttribute attr -> {
143 println("CharacterRangeTable:");
144 indent(+1);
145 for (var e : attr.characterRangeTable()) {
146 print(String.format(" %2d, %2d, %6x, %6x, %4x",
147 e.startPc(), e.endPc(),
148 e.characterRangeStart(), e.characterRangeEnd(),
149 e.flags()));
150 tab();
151 print(String.format("// %2d, %2d, %4d:%02d, %4d:%02d",
152 e.startPc(), e.endPc(),
153 (e.characterRangeStart() >> 10),
154 (e.characterRangeStart() & 0x3ff),
155 (e.characterRangeEnd() >> 10),
156 (e.characterRangeEnd() & 0x3ff)));
157 if ((e.flags() & FLAG_STATEMENT) != 0)
158 print(", statement");
159 if ((e.flags() & FLAG_BLOCK) != 0)
160 print(", block");
161 if ((e.flags() & FLAG_ASSIGNMENT) != 0)
162 print(", assignment");
163 if ((e.flags() & FLAG_FLOW_CONTROLLER) != 0)
164 print(", flow-controller");
165 if ((e.flags() & FLAG_FLOW_TARGET) != 0)
166 print(", flow-target");
167 if ((e.flags() & FLAG_INVOKE) != 0)
168 print(", invoke");
169 if ((e.flags() & FLAG_CREATE) != 0)
170 print(", create");
171 if ((e.flags() & FLAG_BRANCH_TRUE) != 0)
172 print(", branch-true");
173 if ((e.flags() & FLAG_BRANCH_FALSE) != 0)
174 print(", branch-false");
175 println();
176 }
177 indent(-1);
178 }
179 case CodeAttribute attr -> codeWriter.write(attr);
180 case CompilationIDAttribute attr ->
181 constantWriter.write(attr.compilationId().index());
182 case ConstantValueAttribute attr -> {
183 print("ConstantValue: ");
184 constantWriter.write(attr.constant().index());
185 println();
186 }
187 case DeprecatedAttribute attr -> println("Deprecated: true");
188 case EnclosingMethodAttribute attr -> {
189 print("EnclosingMethod: #" + attr.enclosingClass().index() + ".#"
190 + attr.enclosingMethod().map(PoolEntry::index).orElse(0));
191 tab();
192 print("// " + getJavaName(attr.enclosingClass().asInternalName()));
193 if (attr.enclosingMethod().isPresent())
194 print("." + attr.enclosingMethod().get().name().stringValue());
195 println();
196 }
197 case ExceptionsAttribute attr -> {
198 println("Exceptions:");
199 indent(+1);
200 print("throws ");
201 var exc = attr.exceptions();
202 for (int i = 0; i < exc.size(); i++) {
203 if (i > 0)
204 print(", ");
205 print(getJavaName(exc.get(i).asInternalName()));
206 }
207 println();
208 indent(-1);
209 }
210 case InnerClassesAttribute attr -> {
211 boolean first = true;
212 for (var info : attr.classes()) {
213 //access
214 int access_flags = info.flagsMask();
215 if (options.checkAccess(access_flags)) {
216 if (first) {
217 println("InnerClasses:");
218 indent(+1);
219 first = false;
220 }
221 for (var flag : maskToAccessFlagsReportUnknown(access_flags, AccessFlag.Location.INNER_CLASS, cffv)) {
222 if (flag.sourceModifier() && (flag != AccessFlag.ABSTRACT
223 || !info.has(AccessFlag.INTERFACE))) {
224 print(Modifier.toString(flag.mask()) + " ");
225 }
226 }
227 if (info.innerName().isPresent()) {
228 print("#" + info.innerName().get().index() + "= ");
229 }
230 print("#" + info.innerClass().index());
231 if (info.outerClass().isPresent()) {
232 print(" of #" + info.outerClass().get().index());
233 }
234 print(";");
235 tab();
236 print("// ");
237 if (info.innerName().isPresent()) {
238 print(info.innerName().get().stringValue() + "=");
239 }
240 constantWriter.write(info.innerClass().index());
241 if (info.outerClass().isPresent()) {
242 print(" of ");
243 constantWriter.write(info.outerClass().get().index());
244 }
245 println();
246 }
247 }
248 if (!first)
249 indent(-1);
250 }
251 case LineNumberTableAttribute attr -> {
252 println("LineNumberTable:");
253 indent(+1);
254 for (var entry: attr.lineNumbers()) {
255 println("line " + entry.lineNumber() + ": " + entry.startPc());
256 }
257 indent(-1);
258 }
259 case LocalVariableTableAttribute attr -> {
260 println("LocalVariableTable:");
261 indent(+1);
262 println("Start Length Slot Name Signature");
263 for (var entry : attr.localVariables()) {
264 println(String.format("%5d %7d %5d %5s %s",
265 entry.startPc(), entry.length(), entry.slot(),
266 constantWriter.stringValue(entry.name()),
267 constantWriter.stringValue(entry.type())));
268 }
269 indent(-1);
270 }
271 case LocalVariableTypeTableAttribute attr -> {
272 println("LocalVariableTypeTable:");
273 indent(+1);
274 println("Start Length Slot Name Signature");
275 for (var entry : attr.localVariableTypes()) {
276 println(String.format("%5d %7d %5d %5s %s",
277 entry.startPc(), entry.length(), entry.slot(),
278 constantWriter.stringValue(entry.name()),
279 constantWriter.stringValue(entry.signature())));
280 }
281 indent(-1);
282 }
283 case NestHostAttribute attr -> {
284 print("NestHost: ");
285 constantWriter.write(attr.nestHost().index());
286 println();
287 }
288 case MethodParametersAttribute attr -> {
289 final String header = String.format(format, "Name", "Flags");
290 println("MethodParameters:");
291 indent(+1);
292 println(header);
293 for (var entry : attr.parameters()) {
294 String namestr =
295 entry.name().isPresent() ?
296 constantWriter.stringValue(entry.name().get()) : "<no name>";
297 String flagstr =
298 (entry.has(AccessFlag.FINAL) ? "final " : "") +
299 (entry.has(AccessFlag.MANDATED) ? "mandated " : "") +
300 (entry.has(AccessFlag.SYNTHETIC) ? "synthetic" : "");
301 println(String.format(format, namestr, flagstr));
302 }
303 indent(-1);
304 }
305 case ModuleAttribute attr -> {
306 println("Module:");
307 indent(+1);
308
309 print("#" + attr.moduleName().index());
310 print(",");
311 print(String.format("%x", attr.moduleFlagsMask()));
312 tab();
313 print("// " + constantWriter.stringValue(attr.moduleName()));
314 if (attr.has(AccessFlag.OPEN))
315 print(" ACC_OPEN");
316 if (attr.has(AccessFlag.MANDATED))
317 print(" ACC_MANDATED");
318 if (attr.has(AccessFlag.SYNTHETIC))
319 print(" ACC_SYNTHETIC");
320 println();
321 var ver = attr.moduleVersion();
322 print("#" + ver.map(Utf8Entry::index).orElse(0));
323 if (ver.isPresent()) {
324 tab();
325 print("// " + constantWriter.stringValue(ver.get()));
326 }
327 println();
328 {
329 var entries = attr.requires();
330 print(entries.size());
331 tab();
332 println("// " + "requires");
333 indent(+1);
334 for (var e: entries) {
335 print("#" + e.requires().index() + ","
336 + String.format("%x", e.requiresFlagsMask()));
337 tab();
338 print("// " + constantWriter.stringValue(e.requires()));
339 if (e.has(AccessFlag.TRANSITIVE))
340 print(" ACC_TRANSITIVE");
341 if (e.has(AccessFlag.STATIC_PHASE))
342 print(" ACC_STATIC_PHASE");
343 if (e.has(AccessFlag.SYNTHETIC))
344 print(" ACC_SYNTHETIC");
345 if (e.has(AccessFlag.MANDATED))
346 print(" ACC_MANDATED");
347 println();
348 var reqVer = e.requiresVersion();
349 print("#" + reqVer.map(Utf8Entry::index).orElse(0));
350 if (reqVer.isPresent()) {
351 tab();
352 print("// " + constantWriter.stringValue(reqVer.get()));
353 }
354 println();
355 }
356 indent(-1);
357 }
358 {
359 var entries = attr.exports();
360 print(entries.size());
361 tab();
362 println("// exports");
363 indent(+1);
364 for (var e: entries) {
365 printExportOpenEntry(e.exportedPackage().index(),
366 e.exportsFlagsMask(), e.exportsTo());
367 }
368 indent(-1);
369 }
370 {
371 var entries = attr.opens();
372 print(entries.size());
373 tab();
374 println("// opens");
375 indent(+1);
376 for (var e: entries) {
377 printExportOpenEntry(e.openedPackage().index(),
378 e.opensFlagsMask(), e.opensTo());
379 }
380 indent(-1);
381 }
382 {
383 var entries = attr.uses();
384 print(entries.size());
385 tab();
386 println("// " + "uses");
387 indent(+1);
388 for (var e: entries) {
389 print("#" + e.index());
390 tab();
391 println("// " + constantWriter.stringValue(e));
392 }
393 indent(-1);
394 }
395 {
396 var entries = attr.provides();
397 print(entries.size());
398 tab();
399 println("// " + "provides");
400 indent(+1);
401 for (var e: entries) {
402 print("#" + e.provides().index());
403 tab();
404 print("// ");
405 print(constantWriter.stringValue(e.provides()));
406 println(" with ... " + e.providesWith().size());
407 indent(+1);
408 for (var with : e.providesWith()) {
409 print("#" + with.index());
410 tab();
411 println("// ... with " + constantWriter.stringValue(with));
412 }
413 indent(-1);
414 }
415 indent(-1);
416 }
417 indent(-1);
418 }
419 case ModuleHashesAttribute attr -> {
420 println("ModuleHashes:");
421 indent(+1);
422 print("algorithm: #" + attr.algorithm().index());
423 tab();
424 println("// " + attr.algorithm().stringValue());
425 print(attr.hashes().size());
426 tab();
427 println("// hashes");
428 for (var e : attr.hashes()) {
429 print("#" + e.moduleName().index());
430 tab();
431 println("// " + e.moduleName().name().stringValue());
432 println("hash_length: " + e.hash().length);
433 println("hash: [" + toHex(e.hash()) + "]");
434 }
435 indent(-1);
436 }
437 case ModuleMainClassAttribute attr -> {
438 print("ModuleMainClass: #" + attr.mainClass().index());
439 tab();
440 print("// " + getJavaName(attr.mainClass().asInternalName()));
441 println();
442 }
443 case ModulePackagesAttribute attr -> {
444 println("ModulePackages: ");
445 indent(+1);
446 for (var p : attr.packages()) {
447 print("#" + p.index());
448 tab();
449 println("// " + getJavaName(p.name().stringValue()));
450 }
451 indent(-1);
452 }
453 case ModuleResolutionAttribute attr -> {
454 println("ModuleResolution:");
455 indent(+1);
456 print(String.format("%x", attr.resolutionFlags()));
457 tab();
458 print("// ");
459 int flags = attr.resolutionFlags();
460 if ((flags & DO_NOT_RESOLVE_BY_DEFAULT) != 0)
461 print(" DO_NOT_RESOLVE_BY_DEFAULT");
462 if ((flags & WARN_DEPRECATED) != 0)
463 print(" WARN_DEPRECATED");
464 if ((flags & WARN_DEPRECATED_FOR_REMOVAL) != 0)
465 print(" WARN_DEPRECATED_FOR_REMOVAL");
466 if ((flags & WARN_INCUBATING) != 0)
467 print(" WARN_INCUBATING");
468 println();
469 indent(-1);
470 }
471 case ModuleTargetAttribute attr -> {
472 println("ModuleTarget:");
473 indent(+1);
474 print("target_platform: #" + attr.targetPlatform().index());
475 tab();
476 println("// " + attr.targetPlatform().stringValue());
477 indent(-1);
478 }
479 case NestMembersAttribute attr -> {
480 println("NestMembers:");
481 indent(+1);
482 for (var m : attr.nestMembers()) {
483 println(constantWriter.stringValue(m));
484 }
485 indent(-1);
486 }
487 case RecordAttribute attr -> {
488 println("Record:");
489 indent(+1);
490 for (var componentInfo : attr.components()) {
491 var sigAttr = componentInfo.findAttribute(Attributes.signature());
492 print(getJavaName(
493 new ClassWriter.SignaturePrinter(options.verbose).print(
494 sigAttr.map(SignatureAttribute::asTypeSignature)
495 .orElse(Signature.of(
496 componentInfo.descriptorSymbol())))));
497 print(" ");
498 print(componentInfo.name().stringValue());
499 print(";");
500 println();
501 indent(+1);
502 if (options.showDescriptors) {
503 println("descriptor: " + componentInfo.descriptor().stringValue());
504 }
505 if (options.showAllAttrs) {
506 write(componentInfo.attributes(), cffv);
507 println();
508 }
509 indent(-1);
510 }
511 indent(-1);
512 }
513 case RuntimeVisibleAnnotationsAttribute attr ->
514 printAnnotations("RuntimeVisibleAnnotations:", attr.annotations());
515 case RuntimeInvisibleAnnotationsAttribute attr ->
516 printAnnotations("RuntimeInvisibleAnnotations:", attr.annotations());
517 case RuntimeVisibleTypeAnnotationsAttribute attr ->
518 printTypeAnnotations("RuntimeVisibleTypeAnnotations:",
519 attr.annotations(), lr);
520 case RuntimeInvisibleTypeAnnotationsAttribute attr ->
521 printTypeAnnotations("RuntimeInvisibleTypeAnnotations:",
522 attr.annotations(), lr);
523 case RuntimeVisibleParameterAnnotationsAttribute attr ->
524 printParameterAnnotations("RuntimeVisibleParameterAnnotations:",
525 attr.parameterAnnotations());
526 case RuntimeInvisibleParameterAnnotationsAttribute attr ->
527 printParameterAnnotations("RuntimeInvisibleParameterAnnotations:",
528 attr.parameterAnnotations());
529 case PermittedSubclassesAttribute attr -> {
530 println("PermittedSubclasses:");
531 indent(+1);
532 for (var sc : attr.permittedSubclasses()) {
533 println(constantWriter.stringValue(sc));
534 }
535 indent(-1);
536 }
537 case SignatureAttribute attr -> {
538 print("Signature: #" + attr.signature().index());
539 tab();
540 println("// " + attr.signature().stringValue());
541 }
542 case SourceDebugExtensionAttribute attr -> {
543 println("SourceDebugExtension:");
544 indent(+1);
545 for (String s: new String(attr.contents(), StandardCharsets.UTF_8)
546 .split("[\r\n]+")) {
547 println(s);
548 }
549 indent(-1);
550 }
551 case SourceFileAttribute attr ->
552 println("SourceFile: \"" + attr.sourceFile().stringValue() + "\"");
553 case SourceIDAttribute attr ->
554 constantWriter.write(attr.sourceId().index());
555 case StackMapTableAttribute attr -> {
556 var entries = attr.entries();
557 println("StackMapTable: number_of_entries = " + entries.size());
558 indent(+1);
559 int lastOffset = -1;
560 for (var frame : entries) {
561 int frameType = frame.frameType();
562 if (frameType < 64) {
563 printHeader(frameType, "/* same */");
564 } else if (frameType < 128) {
565 printHeader(frameType, "/* same_locals_1_stack_item */");
566 indent(+1);
567 printMap("stack", frame.stack(), lr);
568 indent(-1);
569 } else {
570 int offsetDelta = lr.labelToBci(frame.target()) - lastOffset - 1;
571 switch (frameType) {
572 case 247 -> {
573 printHeader(frameType, "/* same_locals_1_stack_item_frame_extended */");
574 indent(+1);
575 println("offset_delta = " + offsetDelta);
576 printMap("stack", frame.stack(), lr);
577 indent(-1);
578 }
579 case 248, 249, 250 -> {
580 printHeader(frameType, "/* chop */");
581 indent(+1);
582 println("offset_delta = " + offsetDelta);
583 indent(-1);
584 }
585 case 251 -> {
586 printHeader(frameType, "/* same_frame_extended */");
587 indent(+1);
588 println("offset_delta = " + offsetDelta);
589 indent(-1);
590 }
591 case 252, 253, 254 -> {
592 printHeader(frameType, "/* append */");
593 indent(+1);
594 println("offset_delta = " + offsetDelta);
595 var locals = frame.locals();
596 printMap("locals", locals.subList(locals.size()
597 - frameType + 251, locals.size()), lr);
598 indent(-1);
599 }
600 case 255 -> {
601 printHeader(frameType, "/* full_frame */");
602 indent(+1);
603 println("offset_delta = " + offsetDelta);
604 printMap("locals", frame.locals(), lr);
605 printMap("stack", frame.stack(), lr);
606 indent(-1);
607 }
608 }
609 }
610 lastOffset = lr.labelToBci(frame.target());
611 }
612 indent(-1);
613 }
614 case SyntheticAttribute attr ->
615 println("Synthetic: true");
616 default -> {}
617 }
618 }
619
620 //ToDo move somewhere to Bytecode API
621 public static final int DO_NOT_RESOLVE_BY_DEFAULT = 0x0001;
622 public static final int WARN_DEPRECATED = 0x0002;
623 public static final int WARN_DEPRECATED_FOR_REMOVAL = 0x0004;
624 public static final int WARN_INCUBATING = 0x0008;
625
626 private static final String format = "%-31s%s";
627
628 protected void printExportOpenEntry(int index, int flags, List<ModuleEntry> to_index) {
629 print("#" + index + "," + String.format("%x", flags));
630 tab();
631 print("// ");
632 print(constantWriter.stringValue(index));
633 if ((flags & ACC_MANDATED) != 0)
634 print(" ACC_MANDATED");
635 if ((flags & ACC_SYNTHETIC) != 0)
636 print(" ACC_SYNTHETIC");
637 if (to_index.size() == 0) {
638 println();
639 } else {
640 println(" to ... " + to_index.size());
641 indent(+1);
642 for (var to: to_index) {
643 print("#" + to.index());
644 tab();
645 println("// ... to " + constantWriter.stringValue(to));
646 }
647 indent(-1);
648 }
649 }
650
651 private void printAnnotations(String message, List<? extends Annotation> anno) {
652 println(message);
653 indent(+1);
654 for (int i = 0; i < anno.size(); i++) {
655 print(i + ": ");
656 annotationWriter.write(anno.get(i));
657 println();
658 }
659 indent(-1);
660 }
661
662 private void printTypeAnnotations(String message,
663 List<? extends TypeAnnotation> anno, CodeAttribute lr) {
664 println(message);
665 indent(+1);
666 for (int i = 0; i < anno.size(); i++) {
667 print(i + ": ");
668 annotationWriter.write(anno.get(i), lr);
669 println();
670 }
671 indent(-1);
672 }
673
674 private void printParameterAnnotations(String message, List<List<Annotation>> paramsAnno) {
675 println(message);
676 indent(+1);
677 for (int param = 0; param < paramsAnno.size(); param++) {
678 println("parameter " + param + ": ");
679 indent(+1);
680 var annos = paramsAnno.get(param);
681 for (int i = 0; i < annos.size(); i++) {
682 print(i + ": ");
683 annotationWriter.write(annos.get(i));
684 println();
685 }
686 indent(-1);
687 }
688 indent(-1);
689 }
690
691 void printHeader(int frameType, String extra) {
692 print("frame_type = " + frameType + " ");
693 println(extra);
694 }
695
696 void printMap(String name, List<VerificationTypeInfo> map, CodeAttribute lr) {
697 print(name + " = [");
698 for (int i = 0; i < map.size(); i++) {
699 var info = map.get(i);
700 switch (info) {
701 case ObjectVerificationTypeInfo obj -> {
702 print(" ");
703 constantWriter.write(obj.className().index());
704 }
705 case UninitializedVerificationTypeInfo u -> {
706 print(" uninitialized " + lr.labelToBci(u.newTarget()));
707 }
708 case SimpleVerificationTypeInfo s ->
709 print(" " + mapTypeName(s));
710 }
711 print(i == (map.size() - 1) ? " " : ",");
712 }
713 println("]");
714 }
715
716 String mapTypeName(SimpleVerificationTypeInfo type) {
717 return switch (type) {
718 case TOP -> "top";
719 case INTEGER -> "int";
720 case FLOAT -> "float";
721 case LONG -> "long";
722 case DOUBLE -> "double";
723 case NULL -> "null";
724 case UNINITIALIZED_THIS -> "this";
725 };
726 }
727
728 static String getJavaName(String name) {
729 return name.replace('/', '.');
730 }
731
732 String toHex(byte b, int w) {
733 return toHex(b & 0xff, w);
734 }
735
736 static String toHex(int i) {
737 return Integer.toString(i, 16).toUpperCase(Locale.US);
738 }
739
740 static String toHex(int i, int w) {
741 String s = Integer.toHexString(i).toUpperCase(Locale.US);
742 while (s.length() < w)
743 s = "0" + s;
744 return s;
745 }
746
747 static String toHex(byte[] ba) {
748 StringBuilder sb = new StringBuilder(ba.length);
749 for (byte b: ba) {
750 sb.append(String.format("%02x", b & 0xff));
751 }
752 return sb.toString();
753 }
754
755 private final AnnotationWriter annotationWriter;
756 private final CodeWriter codeWriter;
757 private final ConstantWriter constantWriter;
758 private final Options options;
759 }