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