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