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