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