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 }