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 }