1 /* 2 * Copyright (c) 1996, 2020, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.openjdk.asmtools.jdis; 24 25 import org.openjdk.asmtools.asmutils.HexUtils; 26 import org.openjdk.asmtools.asmutils.StringUtils; 27 28 import java.io.DataInputStream; 29 import java.io.IOException; 30 import java.io.PrintWriter; 31 import java.util.ArrayList; 32 import java.util.Collections; 33 import java.util.Hashtable; 34 import java.util.stream.Collectors; 35 36 import static java.lang.String.format; 37 import static org.openjdk.asmtools.jdis.Utils.commentString; 38 39 /** 40 * 41 * ConstantPool 42 * 43 * Class representing the ConstantPool 44 */ 45 public class ConstantPool { 46 47 private static final Hashtable<Byte, TAG> taghash = new Hashtable<>(); 48 private static final Hashtable<Byte, SUBTAG> subtaghash = new Hashtable<>(); 49 50 private boolean printTAG = false; 51 52 public void setPrintTAG(boolean value) { 53 this.printTAG = value; 54 } 55 56 public String getPrintedTAG(TAG tag) { 57 return (this.printTAG) ? tag.tagname + " " : "" ; 58 } 59 60 class Indent { 61 private int length, offset, step; 62 63 void inc() { length+=step; } 64 65 void dec() { length-=step; } 66 67 Indent(int offset, int step) { 68 this.length = 0; 69 this.step = step; 70 this.offset = offset; 71 } 72 73 int size() { return offset + length; } 74 75 /** 76 * Creates indent string based on current indent size. 77 */ 78 private String get() { 79 return Collections.nCopies(size(), "\t").stream().collect(Collectors.joining()); 80 } 81 } 82 83 private final Indent indent = new Indent(2, 1); 84 85 /** 86 * TAG 87 * 88 * A Tag descriptor of constants in the constant pool 89 * 90 */ 91 public enum TAG { 92 CONSTANT_UTF8 ((byte) 1, "Asciz", "CONSTANT_UTF8"), 93 CONSTANT_UNICODE ((byte) 2, "unicorn", "CONSTANT_UNICODE"), 94 CONSTANT_INTEGER ((byte) 3, "int", "CONSTANT_INTEGER"), 95 CONSTANT_FLOAT ((byte) 4, "float", "CONSTANT_FLOAT"), 96 CONSTANT_LONG ((byte) 5, "long", "CONSTANT_LONG"), 97 CONSTANT_DOUBLE ((byte) 6, "double", "CONSTANT_DOUBLE"), 98 CONSTANT_CLASS ((byte) 7, "class", "CONSTANT_CLASS"), 99 CONSTANT_STRING ((byte) 8, "String", "CONSTANT_STRING"), 100 CONSTANT_FIELD ((byte) 9, "Field", "CONSTANT_FIELD"), 101 CONSTANT_METHOD ((byte) 10, "Method", "CONSTANT_METHOD"), 102 CONSTANT_INTERFACEMETHOD ((byte) 11, "InterfaceMethod", "CONSTANT_INTERFACEMETHOD"), 103 CONSTANT_NAMEANDTYPE ((byte) 12, "NameAndType", "CONSTANT_NAMEANDTYPE"), 104 CONSTANT_METHODHANDLE ((byte) 15, "MethodHandle", "CONSTANT_METHODHANDLE"), 105 CONSTANT_METHODTYPE ((byte) 16, "MethodType", "CONSTANT_METHODTYPE"), 106 CONSTANT_DYNAMIC ((byte) 17, "Dynamic", "CONSTANT_DYNAMIC"), 107 CONSTANT_INVOKEDYNAMIC ((byte) 18, "InvokeDynamic", "CONSTANT_INVOKEDYNAMIC"), 108 CONSTANT_MODULE ((byte) 19, "Module", "CONSTANT_MODULE"), 109 CONSTANT_PACKAGE ((byte) 20, "Package", "CONSTANT_PACKAGE"); 110 111 private final Byte value; 112 private final String tagname; 113 private final String printval; 114 115 TAG(byte val, String tgname, String print) { 116 value = val; 117 tagname = tgname; 118 printval = print; 119 } 120 121 public byte value() { 122 return value; 123 } 124 125 public String tagname() { 126 return tagname; 127 } 128 129 public String description() { 130 return printval; 131 } 132 133 @Override 134 public String toString() { 135 return "<" + tagname + "> "; 136 } 137 138 }; 139 140 141 /** 142 * SUBTAG 143 * 144 * A Tag descriptor of form method-handle constants 145 * 146 */ 147 static public enum SUBTAG { 148 REF_GETFIELD ((byte) 1, "REF_getField", "REF_GETFIELD"), 149 REF_GETSTATIC ((byte) 2, "REF_getStatic", "REF_GETSTATIC"), 150 REF_PUTFIELD ((byte) 3, "REF_putField", "REF_PUTFIELD"), 151 REF_PUTSTATIC ((byte) 4, "REF_putStatic", "REF_PUTSTATIC"), 152 REF_INVOKEVIRTUAL ((byte) 5, "REF_invokeVirtual", "REF_INVOKEVIRTUAL"), 153 REF_INVOKESTATIC ((byte) 6, "REF_invokeStatic", "REF_INVOKESTATIC"), 154 REF_INVOKESPECIAL ((byte) 7, "REF_invokeSpecial", "REF_INVOKESPECIAL"), 155 REF_NEWINVOKESPECIAL ((byte) 8, "REF_newInvokeSpecial", "REF_NEWINVOKESPECIAL"), 156 REF_INVOKEINTERFACE ((byte) 9, "REF_invokeInterface", "REF_INVOKEINTERFACE"); 157 158 private final Byte value; 159 private final String tagname; 160 private final String printval; 161 162 SUBTAG(byte val, String tgname, String print) { 163 value = val; 164 tagname = tgname; 165 printval = print; 166 // subtaghash.put(new Byte(val), this); 167 } 168 169 public byte value() { 170 return value; 171 } 172 173 public String tagname() { 174 return tagname; 175 } 176 177 public String description() { 178 return printval; 179 } 180 181 @Override 182 public String toString() { 183 return "<" + tagname + "> "; 184 } 185 }; 186 187 static { 188 189 // Class initializer Code 190 // 191 // Make sure all of the tags get initialized before being used. 192 taghash.put(TAG.CONSTANT_UTF8.value(), TAG.CONSTANT_UTF8); 193 taghash.put(TAG.CONSTANT_UNICODE.value(), TAG.CONSTANT_UNICODE); 194 taghash.put(TAG.CONSTANT_INTEGER.value(), TAG.CONSTANT_INTEGER); 195 taghash.put(TAG.CONSTANT_FLOAT.value(), TAG.CONSTANT_FLOAT); 196 taghash.put(TAG.CONSTANT_LONG.value(), TAG.CONSTANT_LONG); 197 taghash.put(TAG.CONSTANT_DOUBLE.value(), TAG.CONSTANT_DOUBLE); 198 taghash.put(TAG.CONSTANT_CLASS.value(), TAG.CONSTANT_CLASS); 199 taghash.put(TAG.CONSTANT_STRING.value(), TAG.CONSTANT_STRING); 200 taghash.put(TAG.CONSTANT_FIELD.value(), TAG.CONSTANT_FIELD); 201 taghash.put(TAG.CONSTANT_METHOD.value(), TAG.CONSTANT_METHOD); 202 taghash.put(TAG.CONSTANT_INTERFACEMETHOD.value(), TAG.CONSTANT_INTERFACEMETHOD); 203 taghash.put(TAG.CONSTANT_NAMEANDTYPE.value(), TAG.CONSTANT_NAMEANDTYPE); 204 taghash.put(TAG.CONSTANT_METHODHANDLE.value(), TAG.CONSTANT_METHODHANDLE); 205 taghash.put(TAG.CONSTANT_METHODTYPE.value(), TAG.CONSTANT_METHODTYPE); 206 taghash.put(TAG.CONSTANT_DYNAMIC.value(), TAG.CONSTANT_DYNAMIC); 207 taghash.put(TAG.CONSTANT_INVOKEDYNAMIC.value(), TAG.CONSTANT_INVOKEDYNAMIC); 208 taghash.put(TAG.CONSTANT_MODULE.value(), TAG.CONSTANT_MODULE); 209 taghash.put(TAG.CONSTANT_PACKAGE.value(), TAG.CONSTANT_PACKAGE); 210 211 subtaghash.put(SUBTAG.REF_GETFIELD.value(), SUBTAG.REF_GETFIELD); 212 subtaghash.put(SUBTAG.REF_GETSTATIC.value(), SUBTAG.REF_GETSTATIC); 213 subtaghash.put(SUBTAG.REF_PUTFIELD.value(), SUBTAG.REF_PUTFIELD); 214 subtaghash.put(SUBTAG.REF_PUTSTATIC.value(), SUBTAG.REF_PUTSTATIC); 215 subtaghash.put(SUBTAG.REF_INVOKEVIRTUAL.value(), SUBTAG.REF_INVOKEVIRTUAL); 216 subtaghash.put(SUBTAG.REF_INVOKESTATIC.value(), SUBTAG.REF_INVOKESTATIC); 217 subtaghash.put(SUBTAG.REF_INVOKESPECIAL.value(), SUBTAG.REF_INVOKESPECIAL); 218 subtaghash.put(SUBTAG.REF_NEWINVOKESPECIAL.value(), SUBTAG.REF_NEWINVOKESPECIAL); 219 subtaghash.put(SUBTAG.REF_INVOKEINTERFACE.value(), SUBTAG.REF_INVOKEINTERFACE); 220 221 } 222 223 /** 224 * 225 * Constant 226 * 227 * Base class of all constant entries 228 * 229 */ 230 public class Constant { 231 232 /** 233 * tag the descriptor for the constant 234 */ 235 public TAG tag; 236 237 public Constant(TAG tagval) { 238 tag = tagval; 239 } 240 241 public String stringVal() { 242 return ""; 243 } 244 245 public void print(PrintWriter out) { 246 out.print(tag.tagname + "\t"); 247 } 248 249 public int size() { 250 return 1; 251 } 252 253 @Override 254 public String toString() { 255 return "<CONSTANT " + tag.toString() + " " + stringVal() + ">"; 256 } 257 258 private IOException issue; 259 260 public IOException getIssue() { 261 return issue; 262 } 263 264 public void setIssue(IOException value) { 265 issue = value; 266 } 267 268 } 269 270 /* -------------------------------------------------------- */ 271 /* Constant Sub-classes */ 272 /** 273 * 274 * CP_Str 275 * 276 * Constant entries that contain String data. usually is a CONSTANT_UTF8 277 * 278 */ 279 class CP_Str extends Constant { 280 281 String value; 282 283 CP_Str(TAG tagval, String str) { 284 super(tagval); 285 this.value = str; 286 } 287 288 @Override 289 public String stringVal() { 290 return StringUtils.Utf8ToString(value); 291 } 292 293 @Override 294 public void print(PrintWriter out) { 295 super.print(out); 296 out.println(stringVal() + ";"); 297 } 298 } 299 300 /** 301 * 302 * CP_Int 303 * 304 * Constant entries that contain Integer data. usually is a CONSTANT_INTEGER 305 * 306 */ 307 class CP_Int extends Constant { 308 309 Integer value; 310 311 CP_Int(TAG tagval, int intval) { 312 super(tagval); 313 this.value = intval; 314 } 315 316 @Override 317 public String stringVal() { 318 if (cd.options.contains(Options.PR.HEX)) { 319 return HexUtils.toHex(value.intValue()); 320 } 321 return value.toString(); 322 } 323 324 @Override 325 public void print(PrintWriter out) { 326 super.print(out); 327 out.println(stringVal() + ";"); 328 } 329 } 330 331 /** 332 * 333 * CP_Long 334 * 335 * Constant entries that contain LongInteger data. usually is a CONSTANT_LONG 336 * 337 * These take up 2 slots in the constant pool. 338 * 339 */ 340 class CP_Long extends Constant { 341 342 Long value; 343 344 CP_Long(TAG tagval, long intval) { 345 super(tagval); 346 this.value = intval; 347 } 348 349 @Override 350 public String stringVal() { 351 if (cd.options.contains(Options.PR.HEX)) { 352 return HexUtils.toHex(value.longValue()) + 'l'; 353 } 354 return value.toString() + 'l'; 355 } 356 357 @Override 358 public void print(PrintWriter out) { 359 super.print(out); 360 out.println(stringVal() + ";"); 361 } 362 363 @Override 364 public int size() { 365 return 2; 366 } 367 } 368 369 /** 370 * 371 * CP_Float 372 * 373 * Constant entries that contain Float data. usually is a CONSTANT_FLOAT 374 * 375 */ 376 class CP_Float extends Constant { 377 378 Float value; 379 380 CP_Float(TAG tagval, float fltvl) { 381 super(tagval); 382 this.value = fltvl; 383 } 384 385 @Override 386 public String stringVal() { 387 if (cd.options.contains(Options.PR.HEX)) { 388 return "bits " + HexUtils.toHex(Float.floatToIntBits(value.floatValue())); 389 } 390 String sf = (value).toString(); 391 if (value.isNaN() || value.isInfinite()) { 392 return sf; 393 } 394 return sf + "f"; 395 } 396 397 @Override 398 public void print(PrintWriter out) { 399 super.print(out); 400 out.println(stringVal() + ";"); 401 } 402 } 403 404 /** 405 * 406 * CP_Double 407 * 408 * Constant entries that contain double-precision float data. usually is a 409 * CONSTANT_DOUBLE 410 * 411 * These take up 2 slots in the constant pool. 412 * 413 */ 414 class CP_Double extends Constant { 415 416 Double value; 417 418 CP_Double(TAG tagval, double fltvl) { 419 super(tagval); 420 this.value = fltvl; 421 } 422 423 @Override 424 public String stringVal() { 425 if (cd.options.contains(Options.PR.HEX)) { 426 return "bits " + HexUtils.toHex(Double.doubleToLongBits(value.doubleValue())) + 'l'; 427 } 428 String sd = value.toString(); 429 if (value.isNaN() || value.isInfinite()) { 430 return sd; 431 } 432 return sd + "d"; 433 } 434 435 @Override 436 public void print(PrintWriter out) { 437 super.print(out); 438 out.println(stringVal() + ";"); 439 } 440 441 @Override 442 public int size() { 443 return 2; 444 } 445 } 446 447 /** 448 * 449 * CPX 450 * 451 * Constant entries that contain a single constant-pool index. Usually, this includes: 452 * CONSTANT_CLASS CONSTANT_METHODTYPE CONSTANT_STRING CONSTANT_MODULE CONSTANT_PACKAGE 453 * 454 */ 455 class CPX extends Constant { 456 457 int value; 458 459 CPX(TAG tagval, int cpx) { 460 super(tagval); 461 this.value = cpx; 462 } 463 464 @Override 465 public String stringVal() { 466 String str = "UnknownTag"; 467 switch (tag) { 468 case CONSTANT_CLASS: 469 str = getShortClassName(getClassName(this), cd.pkgPrefix); 470 break; 471 case CONSTANT_PACKAGE: 472 case CONSTANT_MODULE: 473 str = getString(value); 474 break; 475 case CONSTANT_METHODTYPE: 476 case CONSTANT_STRING: 477 str = StringValue(value); 478 break; 479 default: 480 break; 481 } 482 return str; 483 } 484 485 @Override 486 public void print(PrintWriter out) { 487 super.print(out); 488 switch (tag) { 489 case CONSTANT_CLASS: 490 case CONSTANT_STRING: 491 case CONSTANT_METHODTYPE: 492 case CONSTANT_PACKAGE: 493 case CONSTANT_MODULE: 494 out.println("#" + (value) + ";\t// " + stringVal()); 495 break; 496 } 497 } 498 } 499 500 /** 501 * 502 * CPX2 503 * 504 * Constant entries that contain two constant-pool indices. Usually, this includes: 505 * CONSTANT_FIELD CONSTANT_METHOD CONSTANT_INTERFACEMETHOD CONSTANT_NAMEANDTYPE 506 * CONSTANT_METHODHANDLE CONSTANT_DYNAMIC CONSTANT_INVOKEDYNAMIC 507 * 508 */ 509 class CPX2 extends Constant { 510 511 int value1, value2; 512 513 CPX2(TAG tagval, int cpx1, int cpx2) { 514 super(tagval); 515 this.value1 = cpx1; 516 this.value2 = cpx2; 517 } 518 519 @Override 520 public String stringVal() { 521 522 String str = "UnknownTag"; 523 switch (tag) { 524 case CONSTANT_FIELD: 525 // CODETOOLS-7902660: the tag Field is not necessary while printing static parameters of a bsm 526 // Example: MethodHandle REF_getField:ClassName.FieldName:"I" 527 str = getShortClassName(getClassName(value1), cd.pkgPrefix) + "." + StringValue(value2); 528 break; 529 case CONSTANT_METHOD: 530 case CONSTANT_INTERFACEMETHOD: 531 // CODETOOLS-7902648: added printing of the tag: Method/Interface to clarify 532 // interpreting CONSTANT_MethodHandle_info:reference_kind 533 // Example: invokedynamic InvokeDynamic REF_invokeStatic:Method java/lang/runtime/ObjectMethods.bootstrap 534 str = getPrintedTAG(tag) + getShortClassName(getClassName(value1), cd.pkgPrefix) + "." + StringValue(value2); 535 break; 536 case CONSTANT_NAMEANDTYPE: 537 str = getName(value1) + ":" + StringValue(value2); 538 break; 539 case CONSTANT_METHODHANDLE: 540 str = subtagToString(value1) + ":" + StringValue(value2); 541 break; 542 case CONSTANT_DYNAMIC: 543 case CONSTANT_INVOKEDYNAMIC: 544 int bsm_attr_idx = value1; 545 int nape_idx = value2; 546 BootstrapMethodData bsmData; 547 try { 548 bsmData = cd.bootstrapMethods.get(bsm_attr_idx); 549 } catch (NullPointerException npe) { 550 return "<Missing BootstrapMethods attribute>"; 551 } catch (IndexOutOfBoundsException ioob) { 552 return "<Invalid bootstrap method index:" + bsm_attr_idx + ">"; 553 } 554 StringBuilder bsm_args_str = new StringBuilder(); 555 String offsetParm,offsetBrace; 556 int bsm_ref = bsmData.bsm_index; 557 int bsm_args_len = bsmData.bsm_args_indexes.size(); 558 if (bsm_args_len > 0) { 559 bsm_args_str.append(" {\n"); 560 offsetBrace = indent.get(); 561 indent.inc(); 562 offsetParm = indent.get(); 563 for (int i = 0; i < bsm_args_len; i++) { 564 int bsm_arg_idx = bsmData.bsm_args_indexes.get(i); 565 Constant cnt = pool.get(bsm_arg_idx); 566 if (cnt.equals(this)) { 567 String s = "circular reference to " + cnt.tag.tagname() + " #" + bsm_arg_idx; 568 bsm_args_str.append(offsetParm).append(" <").append(s).append(">"); 569 cnt.setIssue(new IOException(s)); 570 } else { 571 bsm_args_str.append(offsetParm).append(ConstantStrValue(bsm_arg_idx)); 572 if (i + 1 < bsm_args_len) { 573 bsm_args_str.append(","); 574 } 575 } 576 bsm_args_str.append('\n'); 577 } 578 indent.dec(); 579 bsm_args_str.append(offsetBrace).append("}"); 580 } 581 str = StringValue(bsm_ref) + ":" + StringValue(nape_idx) + bsm_args_str.toString(); 582 default: 583 break; 584 } 585 return str; 586 } 587 588 589 590 @Override 591 public void print(PrintWriter out) { 592 super.print(out); 593 switch (tag) { 594 case CONSTANT_FIELD: 595 case CONSTANT_METHOD: 596 case CONSTANT_INTERFACEMETHOD: 597 out.println("#" + value1 + ".#" + value2 + ";\t// " + stringVal()); 598 break; 599 case CONSTANT_METHODHANDLE: 600 out.println(value1 + ":#" + value2 + ";\t// " + stringVal()); 601 break; 602 case CONSTANT_NAMEANDTYPE: 603 out.println("#" + value1 + ":#" + value2 + ";\t// " + stringVal()); 604 break; 605 case CONSTANT_DYNAMIC: 606 case CONSTANT_INVOKEDYNAMIC: 607 out.println(value1 + ":#" + value2 + ";\t" + commentString(stringVal())); 608 break; 609 default: 610 break; 611 } 612 } 613 614 public boolean refersClassMember() { 615 return tag == TAG.CONSTANT_FIELD || tag == TAG.CONSTANT_METHOD || tag == TAG.CONSTANT_INTERFACEMETHOD; 616 } 617 } 618 619 /* -------------------------------------------------------- */ 620 /* ConstantPool Fields */ 621 /** 622 * The actual pool of Constants 623 */ 624 public ArrayList<Constant> pool; 625 /** 626 * Reference to the class data 627 */ 628 private ClassData cd; 629 630 631 /* -------------------------------------------------------- */ 632 /* ConstantPool Methods */ 633 634 /* ConstantPool Constructors */ 635 public ConstantPool(ClassData cd) { 636 pool = null; 637 this.cd = cd; 638 } 639 640 public ConstantPool(ClassData cd, int size) { 641 pool = new ArrayList<>(size); 642 this.cd = cd; 643 } 644 645 /** 646 * 647 * read 648 * 649 * decodes a ConstantPool and it's constants from a data stream. 650 * 651 */ 652 void read(DataInputStream in) throws IOException { 653 int length = in.readUnsignedShort(); 654 pool = new ArrayList<>(length); 655 pool.add(0, null); 656 TraceUtils.traceln("CP len=" + length); 657 for (int i = 1; i < length; i++) { 658 byte tag = in.readByte(); 659 TAG tagobj = taghash.get(tag); 660 TraceUtils.traceln("CP entry #" + i + " + tagindex=" + tag + " tag=" + tagobj); 661 switch (tagobj) { 662 case CONSTANT_UTF8: 663 pool.add(i, new CP_Str(tagobj, in.readUTF())); 664 break; 665 case CONSTANT_INTEGER: 666 pool.add(i, new CP_Int(tagobj, in.readInt())); 667 break; 668 case CONSTANT_LONG: 669 pool.add(i, new CP_Long(tagobj, in.readLong())); 670 // handle null entry to account for Longs taking up 2 CP slots 671 i += 1; 672 pool.add(null); 673 break; 674 case CONSTANT_FLOAT: 675 pool.add(i, new CP_Float(tagobj, in.readFloat())); 676 break; 677 case CONSTANT_DOUBLE: 678 pool.add(i, new CP_Double(tagobj, in.readDouble())); 679 // handle null entry to account for Doubles taking up 2 CP slots 680 i += 1; 681 pool.add(null); 682 break; 683 case CONSTANT_CLASS: 684 case CONSTANT_STRING: 685 case CONSTANT_METHODTYPE: 686 case CONSTANT_PACKAGE: 687 case CONSTANT_MODULE: 688 pool.add(i, new CPX(tagobj, in.readUnsignedShort())); 689 break; 690 case CONSTANT_FIELD: 691 case CONSTANT_METHOD: 692 case CONSTANT_INTERFACEMETHOD: 693 case CONSTANT_NAMEANDTYPE: 694 case CONSTANT_DYNAMIC: 695 case CONSTANT_INVOKEDYNAMIC: 696 pool.add(i, new CPX2(tagobj, in.readUnsignedShort(), in.readUnsignedShort())); 697 break; 698 case CONSTANT_METHODHANDLE: 699 pool.add(i, new CPX2(tagobj, in.readUnsignedByte(), in.readUnsignedShort())); 700 break; 701 702 default: 703 throw new ClassFormatError("invalid constant type: " + (int) tag); 704 } 705 } 706 } 707 708 /** 709 * 710 * inbounds 711 * 712 * bounds-check a CP index. 713 * 714 */ 715 private boolean inbounds(int cpx) { 716 return !(cpx == 0 || cpx >= pool.size()); 717 } 718 719 /** 720 * 721 * getConst 722 * 723 * Public getter - Safely gets a Constant from the CP at a given index. 724 * 725 */ 726 public Constant getConst(int cpx) { 727 if (inbounds(cpx)) { 728 return pool.get(cpx); 729 } else { 730 return null; 731 } 732 } 733 734 /** 735 * 736 * StringTag 737 * 738 * Public string val - Safely gets the string-rep of a Constant from the CP at a given 739 * index. 740 * 741 */ 742 public String StringTag(int cpx) { 743 String str = "Incorrect CP index:" + cpx; 744 if (inbounds(cpx)) { 745 Constant cns = pool.get(cpx); 746 if (cns != null) { 747 str = cns.tag.tagname; 748 } 749 } 750 return str; 751 } 752 753 /** 754 * 755 * getString 756 * 757 * Public string val - Safely gets the string-rep of a ConstantUTF8 from the CP at a 758 * given index. 759 * 760 * Returns either null (if invalid), or the string value of the UTF8 761 * 762 */ 763 public String getString(int cpx) { 764 String str = null; 765 if (inbounds(cpx)) { 766 Constant cns = pool.get(cpx); 767 if (cns != null && cns.tag == TAG.CONSTANT_UTF8) { 768 CP_Str cns1 = (CP_Str) cns; 769 str = cns1.value; 770 } 771 } 772 return str; 773 } 774 775 /** 776 * 777 * getModule 778 * 779 * Public string val - Safely gets the string-rep of a ConstantModule from the CP at a 780 * given index. 781 * 782 * Returns either null (if invalid), or the string value of the ConstantModule 783 * 784 */ 785 public String getModule(int cpx) { 786 String str = null; 787 if (inbounds(cpx)) { 788 Constant cns = pool.get(cpx); 789 if (cns != null && cns.tag == TAG.CONSTANT_MODULE) { 790 str = cns.stringVal(); 791 } 792 } 793 return str; 794 } 795 796 /** 797 * 798 * getPackage 799 * 800 * Public string val - Safely gets the string-rep of a ConstantPackage from the CP at a 801 * given index. 802 * 803 * Returns either null (if invalid), or the string value of the ConstantPackage 804 * 805 */ 806 public String getPackage(int cpx) { 807 String str = null; 808 if (inbounds(cpx)) { 809 Constant cns = pool.get(cpx); 810 if (cns != null && cns.tag == TAG.CONSTANT_PACKAGE) { 811 str = cns.stringVal(); 812 } 813 } 814 return str; 815 } 816 817 /** 818 * 819 * getTypeName 820 * 821 * Safely gets a Java name from a ConstantUTF8 from the CP at a given index. 822 * 823 * Returns either null (if invalid), or the Java name value of the UTF8 824 * 825 */ 826 public String getName(int cpx) { 827 String str = getString(cpx); 828 if (str == null) { 829 return "<invalid constant pool index:" + cpx + ">"; 830 } 831 832 return Utils.javaName(str); 833 } 834 835 /** 836 * 837 * getClassName 838 * 839 * Safely gets a Java class name from a ConstantClass from the CP at a given index. 840 * 841 * Returns either the Java class name, or a CP index reference string. 842 * 843 */ 844 public String getClassName(int cpx) { 845 String res = "#" + cpx; 846 if (cpx == 0) { 847 return res; 848 } 849 if (!inbounds(cpx)) { 850 return res; 851 } 852 Constant cns = pool.get(cpx); 853 if (cns == null || cns.tag != TAG.CONSTANT_CLASS) { 854 return res; 855 } 856 857 return getClassName((CPX) cns); 858 } 859 860 /** 861 * 862 * getClassName 863 * 864 * Safely gets a Java class name from a ConstantClass from a CPX2 constant pool 865 * object. (eg. Method/Field/Interface Ref) 866 * 867 * Returns either the Java class name, or a CP index reference string. 868 * 869 */ 870 public String getClassName(CPX2 classConst) { 871 return _getClassName(classConst.value1); 872 } 873 874 /** 875 * 876 * getClassName 877 * 878 * Safely gets a Java class name from a ConstantClass from a CPX constant pool object. 879 * (eg. Class Ref) 880 * 881 * Returns either the Java class name, or a CP index reference string. 882 * 883 */ 884 public String getClassName(CPX classConst) { 885 return _getClassName(classConst.value); 886 } 887 888 /** 889 * 890 * _getClassName 891 * 892 * Helper for getting class name. Checks bounds, does name conversion. 893 * 894 */ 895 private String _getClassName(int nameIndex) { 896 String res = "#" + nameIndex; 897 if (!inbounds(nameIndex)) { 898 return res; 899 } 900 Constant nameconst = pool.get(nameIndex); 901 if (nameconst == null || nameconst.tag != TAG.CONSTANT_UTF8) { 902 return res; 903 } 904 CP_Str name = (CP_Str) nameconst; 905 906 String classname = name.value; 907 908 if (Utils.isClassArrayDescriptor(classname)) { 909 classname = "\"" + classname + "\""; 910 } 911 return classname; 912 } 913 914 /** 915 * 916 * getShortClassName 917 * 918 * shortens a class name (if the class is in the given package). works with a 919 * string-encoded classname. 920 * 921 */ 922 public String getShortClassName(String className, String pkgPrefix) { 923 if (className.startsWith(pkgPrefix)) { 924 return className.substring(pkgPrefix.length()); 925 } 926 return className; 927 } 928 929 /** 930 * 931 * getShortClassName 932 * 933 * shortens a class name (if the class is in the given package). works with a CP index 934 * to a ConstantClass. 935 * 936 */ 937 public String getShortClassName(int cpx, String pkgPrefix) { 938 String name = Utils.javaName(getClassName(cpx)); 939 return getShortClassName(name, pkgPrefix); 940 } 941 942 /** 943 * 944 * decodeClassDescriptor 945 * 946 * Pulls the class name out of a string (at the CP index). (drops any array 947 * descriptors, and the class descriptors ("L" and ";") 948 * 949 */ 950 public String decodeClassDescriptor(int cpx) { 951 // enum type is encoded as a descriptor 952 // need to remove '"'s and L (class descriptor) 953 954 // TODO: might have to count '['s at the beginning for Arrays 955 String rawEnumName = getName(cpx); 956 int len = rawEnumName.length(); 957 int begin = (rawEnumName.startsWith("\"L")) ? 2 : 0; 958 int end = (begin > 0) ? len - 2 : len; 959 return rawEnumName.substring(begin, end); 960 } 961 962 /** 963 * 964 * subtagToString 965 * 966 * Getter that safely gets the string descriptor of a subtag 967 * 968 */ 969 private String subtagToString(int subtag) { 970 SUBTAG st = subtaghash.get((byte) subtag); 971 if (st == null) { 972 return "BOGUS_SUBTAG:" + subtag; 973 } 974 return st.tagname; 975 } 976 977 /** 978 * 979 * StringValue 980 * 981 * Safely gets the string value of any Constant at any CP index. 982 * 983 */ 984 public String StringValue(int cpx) { 985 if (cpx == 0) { 986 return "#0"; 987 } 988 if (!inbounds(cpx)) { 989 return "<Incorrect CP index:" + cpx + ">"; 990 } 991 Constant cnst = pool.get(cpx); 992 if (cnst == null) { 993 return "<NULL>"; 994 } 995 return cnst.stringVal(); 996 } 997 998 /** 999 * ConstantStrValue 1000 * 1001 * Safely gets the string value of any Constant at any CP index. This string is either 1002 * a Constant's String value, or a CP index reference string. The Constant string has 1003 * a tag descriptor in the beginning. 1004 * 1005 */ 1006 public String ConstantStrValue(int cpx) { 1007 if (cpx == 0) { 1008 return "#0"; 1009 } 1010 if (!inbounds(cpx)) { 1011 return "#" + cpx; 1012 } 1013 Constant cns = pool.get(cpx); 1014 if (cns == null) { 1015 return "#" + cpx; 1016 } 1017 if (cns instanceof CPX2) { 1018 CPX2 cns2 = (CPX2) cns; 1019 if (cns2.value1 == cd.this_cpx && cns2.refersClassMember()) { 1020 cpx = cns2.value2; 1021 } 1022 } 1023 return cns.tag.tagname + " " + StringValue(cpx); 1024 } 1025 1026 /** 1027 * prints the entire constant pool. 1028 */ 1029 public void print(PrintWriter out) throws IOException { 1030 int cpx = 0; 1031 for (Constant cns : pool) { 1032 if (cpx == 0) { 1033 cpx += 1; 1034 continue; 1035 } 1036 1037 out.print("\tconst #" + cpx + " = "); 1038 1039 if (cns == null) { 1040 // do something 1041 out.println("null"); 1042 cpx += 1; 1043 } else { 1044 cns.print(out); 1045 cpx += cns.size(); 1046 } 1047 } 1048 } 1049 1050 /** 1051 * prints the Constant value at a given CP index. 1052 */ 1053 void PrintConstant(PrintWriter out, int cpx) { 1054 out.print(ConstantStrValue(cpx)); 1055 } 1056 1057 /** 1058 * prints a constant value, with the print format based on the print options. 1059 */ 1060 public void printlnClassId(PrintWriter out, int cpx) throws IOException { 1061 printlnClassId(out, cpx, false); 1062 } 1063 1064 public void printlnClassId(PrintWriter out, int cpx, boolean addComma) throws IOException { 1065 if (!cd.options.contains(Options.PR.CPX)) { 1066 out.print(getShortClassName(cpx, cd.pkgPrefix) + (addComma ? "," : "")); 1067 } else { 1068 out.print("\t#" + cpx + (addComma ? "," : "") + " //"); 1069 PrintConstant(out, cpx); 1070 } 1071 } 1072 1073 }