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