/* * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package org.openjdk.asmtools.jdis; import org.openjdk.asmtools.asmutils.HexUtils; import org.openjdk.asmtools.asmutils.StringUtils; import java.io.DataInputStream; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.Hashtable; import java.util.stream.Collectors; import static java.lang.String.format; import static org.openjdk.asmtools.jdis.Utils.commentString; /** * * ConstantPool * * Class representing the ConstantPool */ public class ConstantPool { private static final Hashtable taghash = new Hashtable<>(); private static final Hashtable subtaghash = new Hashtable<>(); private boolean printTAG = false; public void setPrintTAG(boolean value) { this.printTAG = value; } public String getPrintedTAG(TAG tag) { return (this.printTAG) ? tag.tagname + " " : "" ; } class Indent { private int length, offset, step; void inc() { length+=step; } void dec() { length-=step; } Indent(int offset, int step) { this.length = 0; this.step = step; this.offset = offset; } int size() { return offset + length; } /** * Creates indent string based on current indent size. */ private String get() { return Collections.nCopies(size(), "\t").stream().collect(Collectors.joining()); } } private final Indent indent = new Indent(2, 1); /** * TAG * * A Tag descriptor of constants in the constant pool * */ public enum TAG { CONSTANT_UTF8 ((byte) 1, "Asciz", "CONSTANT_UTF8"), CONSTANT_UNICODE ((byte) 2, "unicorn", "CONSTANT_UNICODE"), CONSTANT_INTEGER ((byte) 3, "int", "CONSTANT_INTEGER"), CONSTANT_FLOAT ((byte) 4, "float", "CONSTANT_FLOAT"), CONSTANT_LONG ((byte) 5, "long", "CONSTANT_LONG"), CONSTANT_DOUBLE ((byte) 6, "double", "CONSTANT_DOUBLE"), CONSTANT_CLASS ((byte) 7, "class", "CONSTANT_CLASS"), CONSTANT_STRING ((byte) 8, "String", "CONSTANT_STRING"), CONSTANT_FIELD ((byte) 9, "Field", "CONSTANT_FIELD"), CONSTANT_METHOD ((byte) 10, "Method", "CONSTANT_METHOD"), CONSTANT_INTERFACEMETHOD ((byte) 11, "InterfaceMethod", "CONSTANT_INTERFACEMETHOD"), CONSTANT_NAMEANDTYPE ((byte) 12, "NameAndType", "CONSTANT_NAMEANDTYPE"), CONSTANT_METHODHANDLE ((byte) 15, "MethodHandle", "CONSTANT_METHODHANDLE"), CONSTANT_METHODTYPE ((byte) 16, "MethodType", "CONSTANT_METHODTYPE"), CONSTANT_DYNAMIC ((byte) 17, "Dynamic", "CONSTANT_DYNAMIC"), CONSTANT_INVOKEDYNAMIC ((byte) 18, "InvokeDynamic", "CONSTANT_INVOKEDYNAMIC"), CONSTANT_MODULE ((byte) 19, "Module", "CONSTANT_MODULE"), CONSTANT_PACKAGE ((byte) 20, "Package", "CONSTANT_PACKAGE"); private final Byte value; private final String tagname; private final String printval; TAG(byte val, String tgname, String print) { value = val; tagname = tgname; printval = print; } public byte value() { return value; } public String tagname() { return tagname; } public String description() { return printval; } @Override public String toString() { return "<" + tagname + "> "; } }; /** * SUBTAG * * A Tag descriptor of form method-handle constants * */ static public enum SUBTAG { REF_GETFIELD ((byte) 1, "REF_getField", "REF_GETFIELD"), REF_GETSTATIC ((byte) 2, "REF_getStatic", "REF_GETSTATIC"), REF_PUTFIELD ((byte) 3, "REF_putField", "REF_PUTFIELD"), REF_PUTSTATIC ((byte) 4, "REF_putStatic", "REF_PUTSTATIC"), REF_INVOKEVIRTUAL ((byte) 5, "REF_invokeVirtual", "REF_INVOKEVIRTUAL"), REF_INVOKESTATIC ((byte) 6, "REF_invokeStatic", "REF_INVOKESTATIC"), REF_INVOKESPECIAL ((byte) 7, "REF_invokeSpecial", "REF_INVOKESPECIAL"), REF_NEWINVOKESPECIAL ((byte) 8, "REF_newInvokeSpecial", "REF_NEWINVOKESPECIAL"), REF_INVOKEINTERFACE ((byte) 9, "REF_invokeInterface", "REF_INVOKEINTERFACE"); private final Byte value; private final String tagname; private final String printval; SUBTAG(byte val, String tgname, String print) { value = val; tagname = tgname; printval = print; // subtaghash.put(new Byte(val), this); } public byte value() { return value; } public String tagname() { return tagname; } public String description() { return printval; } @Override public String toString() { return "<" + tagname + "> "; } }; static { // Class initializer Code // // Make sure all of the tags get initialized before being used. taghash.put(TAG.CONSTANT_UTF8.value(), TAG.CONSTANT_UTF8); taghash.put(TAG.CONSTANT_UNICODE.value(), TAG.CONSTANT_UNICODE); taghash.put(TAG.CONSTANT_INTEGER.value(), TAG.CONSTANT_INTEGER); taghash.put(TAG.CONSTANT_FLOAT.value(), TAG.CONSTANT_FLOAT); taghash.put(TAG.CONSTANT_LONG.value(), TAG.CONSTANT_LONG); taghash.put(TAG.CONSTANT_DOUBLE.value(), TAG.CONSTANT_DOUBLE); taghash.put(TAG.CONSTANT_CLASS.value(), TAG.CONSTANT_CLASS); taghash.put(TAG.CONSTANT_STRING.value(), TAG.CONSTANT_STRING); taghash.put(TAG.CONSTANT_FIELD.value(), TAG.CONSTANT_FIELD); taghash.put(TAG.CONSTANT_METHOD.value(), TAG.CONSTANT_METHOD); taghash.put(TAG.CONSTANT_INTERFACEMETHOD.value(), TAG.CONSTANT_INTERFACEMETHOD); taghash.put(TAG.CONSTANT_NAMEANDTYPE.value(), TAG.CONSTANT_NAMEANDTYPE); taghash.put(TAG.CONSTANT_METHODHANDLE.value(), TAG.CONSTANT_METHODHANDLE); taghash.put(TAG.CONSTANT_METHODTYPE.value(), TAG.CONSTANT_METHODTYPE); taghash.put(TAG.CONSTANT_DYNAMIC.value(), TAG.CONSTANT_DYNAMIC); taghash.put(TAG.CONSTANT_INVOKEDYNAMIC.value(), TAG.CONSTANT_INVOKEDYNAMIC); taghash.put(TAG.CONSTANT_MODULE.value(), TAG.CONSTANT_MODULE); taghash.put(TAG.CONSTANT_PACKAGE.value(), TAG.CONSTANT_PACKAGE); subtaghash.put(SUBTAG.REF_GETFIELD.value(), SUBTAG.REF_GETFIELD); subtaghash.put(SUBTAG.REF_GETSTATIC.value(), SUBTAG.REF_GETSTATIC); subtaghash.put(SUBTAG.REF_PUTFIELD.value(), SUBTAG.REF_PUTFIELD); subtaghash.put(SUBTAG.REF_PUTSTATIC.value(), SUBTAG.REF_PUTSTATIC); subtaghash.put(SUBTAG.REF_INVOKEVIRTUAL.value(), SUBTAG.REF_INVOKEVIRTUAL); subtaghash.put(SUBTAG.REF_INVOKESTATIC.value(), SUBTAG.REF_INVOKESTATIC); subtaghash.put(SUBTAG.REF_INVOKESPECIAL.value(), SUBTAG.REF_INVOKESPECIAL); subtaghash.put(SUBTAG.REF_NEWINVOKESPECIAL.value(), SUBTAG.REF_NEWINVOKESPECIAL); subtaghash.put(SUBTAG.REF_INVOKEINTERFACE.value(), SUBTAG.REF_INVOKEINTERFACE); } /** * * Constant * * Base class of all constant entries * */ public class Constant { /** * tag the descriptor for the constant */ public TAG tag; public Constant(TAG tagval) { tag = tagval; } public String stringVal() { return ""; } public void print(PrintWriter out) { out.print(tag.tagname + "\t"); } public int size() { return 1; } @Override public String toString() { return ""; } private IOException issue; public IOException getIssue() { return issue; } public void setIssue(IOException value) { issue = value; } } /* -------------------------------------------------------- */ /* Constant Sub-classes */ /** * * CP_Str * * Constant entries that contain String data. usually is a CONSTANT_UTF8 * */ class CP_Str extends Constant { String value; CP_Str(TAG tagval, String str) { super(tagval); this.value = str; } @Override public String stringVal() { return StringUtils.Utf8ToString(value); } @Override public void print(PrintWriter out) { super.print(out); out.println(stringVal() + ";"); } } /** * * CP_Int * * Constant entries that contain Integer data. usually is a CONSTANT_INTEGER * */ class CP_Int extends Constant { Integer value; CP_Int(TAG tagval, int intval) { super(tagval); this.value = intval; } @Override public String stringVal() { if (cd.options.contains(Options.PR.HEX)) { return HexUtils.toHex(value.intValue()); } return value.toString(); } @Override public void print(PrintWriter out) { super.print(out); out.println(stringVal() + ";"); } } /** * * CP_Long * * Constant entries that contain LongInteger data. usually is a CONSTANT_LONG * * These take up 2 slots in the constant pool. * */ class CP_Long extends Constant { Long value; CP_Long(TAG tagval, long intval) { super(tagval); this.value = intval; } @Override public String stringVal() { if (cd.options.contains(Options.PR.HEX)) { return HexUtils.toHex(value.longValue()) + 'l'; } return value.toString() + 'l'; } @Override public void print(PrintWriter out) { super.print(out); out.println(stringVal() + ";"); } @Override public int size() { return 2; } } /** * * CP_Float * * Constant entries that contain Float data. usually is a CONSTANT_FLOAT * */ class CP_Float extends Constant { Float value; CP_Float(TAG tagval, float fltvl) { super(tagval); this.value = fltvl; } @Override public String stringVal() { if (cd.options.contains(Options.PR.HEX)) { return "bits " + HexUtils.toHex(Float.floatToIntBits(value.floatValue())); } String sf = (value).toString(); if (value.isNaN() || value.isInfinite()) { return sf; } return sf + "f"; } @Override public void print(PrintWriter out) { super.print(out); out.println(stringVal() + ";"); } } /** * * CP_Double * * Constant entries that contain double-precision float data. usually is a * CONSTANT_DOUBLE * * These take up 2 slots in the constant pool. * */ class CP_Double extends Constant { Double value; CP_Double(TAG tagval, double fltvl) { super(tagval); this.value = fltvl; } @Override public String stringVal() { if (cd.options.contains(Options.PR.HEX)) { return "bits " + HexUtils.toHex(Double.doubleToLongBits(value.doubleValue())) + 'l'; } String sd = value.toString(); if (value.isNaN() || value.isInfinite()) { return sd; } return sd + "d"; } @Override public void print(PrintWriter out) { super.print(out); out.println(stringVal() + ";"); } @Override public int size() { return 2; } } /** * * CPX * * Constant entries that contain a single constant-pool index. Usually, this includes: * CONSTANT_CLASS CONSTANT_METHODTYPE CONSTANT_STRING CONSTANT_MODULE CONSTANT_PACKAGE * */ class CPX extends Constant { int value; CPX(TAG tagval, int cpx) { super(tagval); this.value = cpx; } @Override public String stringVal() { String str = "UnknownTag"; switch (tag) { case CONSTANT_CLASS: str = getShortClassName(getClassName(this), cd.pkgPrefix); break; case CONSTANT_PACKAGE: case CONSTANT_MODULE: str = getString(value); break; case CONSTANT_METHODTYPE: case CONSTANT_STRING: str = StringValue(value); break; default: break; } return str; } @Override public void print(PrintWriter out) { super.print(out); switch (tag) { case CONSTANT_CLASS: case CONSTANT_STRING: case CONSTANT_METHODTYPE: case CONSTANT_PACKAGE: case CONSTANT_MODULE: out.println("#" + (value) + ";\t// " + stringVal()); break; } } } /** * * CPX2 * * Constant entries that contain two constant-pool indices. Usually, this includes: * CONSTANT_FIELD CONSTANT_METHOD CONSTANT_INTERFACEMETHOD CONSTANT_NAMEANDTYPE * CONSTANT_METHODHANDLE CONSTANT_DYNAMIC CONSTANT_INVOKEDYNAMIC * */ class CPX2 extends Constant { int value1, value2; CPX2(TAG tagval, int cpx1, int cpx2) { super(tagval); this.value1 = cpx1; this.value2 = cpx2; } @Override public String stringVal() { String str = "UnknownTag"; switch (tag) { case CONSTANT_FIELD: case CONSTANT_METHOD: case CONSTANT_INTERFACEMETHOD: str = getPrintedTAG(tag) + getShortClassName(getClassName(value1), cd.pkgPrefix) + "." + StringValue(value2); break; case CONSTANT_NAMEANDTYPE: str = getName(value1) + ":" + StringValue(value2); break; case CONSTANT_METHODHANDLE: str = subtagToString(value1) + ":" + StringValue(value2); break; case CONSTANT_DYNAMIC: case CONSTANT_INVOKEDYNAMIC: int bsm_attr_idx = value1; int nape_idx = value2; BootstrapMethodData bsmData; try { bsmData = cd.bootstrapMethods.get(bsm_attr_idx); } catch (NullPointerException npe) { return ""; } catch (IndexOutOfBoundsException ioob) { return ""; } StringBuilder bsm_args_str = new StringBuilder(); String offsetParm,offsetBrace; int bsm_ref = bsmData.bsm_index; int bsm_args_len = bsmData.bsm_args_indexes.size(); if (bsm_args_len > 0) { bsm_args_str.append(" {\n"); offsetBrace = indent.get(); indent.inc(); offsetParm = indent.get(); for (int i = 0; i < bsm_args_len; i++) { int bsm_arg_idx = bsmData.bsm_args_indexes.get(i); Constant cnt = pool.get(bsm_arg_idx); if (cnt.equals(this)) { String s = "circular reference to " + cnt.tag.tagname() + " #" + bsm_arg_idx; bsm_args_str.append(offsetParm).append(" <").append(s).append(">"); cnt.setIssue(new IOException(s)); } else { bsm_args_str.append(offsetParm).append(ConstantStrValue(bsm_arg_idx)); if (i + 1 < bsm_args_len) { bsm_args_str.append(","); } } bsm_args_str.append('\n'); } indent.dec(); bsm_args_str.append(offsetBrace).append("}"); } str = StringValue(bsm_ref) + ":" + StringValue(nape_idx) + bsm_args_str.toString(); default: break; } return str; } @Override public void print(PrintWriter out) { super.print(out); switch (tag) { case CONSTANT_FIELD: case CONSTANT_METHOD: case CONSTANT_INTERFACEMETHOD: out.println("#" + value1 + ".#" + value2 + ";\t// " + stringVal()); break; case CONSTANT_METHODHANDLE: out.println(value1 + ":#" + value2 + ";\t// " + stringVal()); break; case CONSTANT_NAMEANDTYPE: out.println("#" + value1 + ":#" + value2 + ";\t// " + stringVal()); break; case CONSTANT_DYNAMIC: case CONSTANT_INVOKEDYNAMIC: out.println(value1 + ":#" + value2 + ";\t" + commentString(stringVal())); break; default: break; } } public boolean refersClassMember() { return tag == TAG.CONSTANT_FIELD || tag == TAG.CONSTANT_METHOD || tag == TAG.CONSTANT_INTERFACEMETHOD; } } /* -------------------------------------------------------- */ /* ConstantPool Fields */ /** * The actual pool of Constants */ public ArrayList pool; /** * Reference to the class data */ private ClassData cd; /* -------------------------------------------------------- */ /* ConstantPool Methods */ /* ConstantPool Constructors */ public ConstantPool(ClassData cd) { pool = null; this.cd = cd; } public ConstantPool(ClassData cd, int size) { pool = new ArrayList<>(size); this.cd = cd; } /** * * read * * decodes a ConstantPool and it's constants from a data stream. * */ void read(DataInputStream in) throws IOException { int length = in.readUnsignedShort(); pool = new ArrayList<>(length); pool.add(0, null); TraceUtils.traceln("CP len=" + length); for (int i = 1; i < length; i++) { byte tag = in.readByte(); TAG tagobj = taghash.get(tag); TraceUtils.traceln("CP entry #" + i + " + tagindex=" + tag + " tag=" + tagobj); switch (tagobj) { case CONSTANT_UTF8: pool.add(i, new CP_Str(tagobj, in.readUTF())); break; case CONSTANT_INTEGER: pool.add(i, new CP_Int(tagobj, in.readInt())); break; case CONSTANT_LONG: pool.add(i, new CP_Long(tagobj, in.readLong())); // handle null entry to account for Longs taking up 2 CP slots i += 1; pool.add(null); break; case CONSTANT_FLOAT: pool.add(i, new CP_Float(tagobj, in.readFloat())); break; case CONSTANT_DOUBLE: pool.add(i, new CP_Double(tagobj, in.readDouble())); // handle null entry to account for Doubles taking up 2 CP slots i += 1; pool.add(null); break; case CONSTANT_CLASS: case CONSTANT_STRING: case CONSTANT_METHODTYPE: case CONSTANT_PACKAGE: case CONSTANT_MODULE: pool.add(i, new CPX(tagobj, in.readUnsignedShort())); break; case CONSTANT_FIELD: case CONSTANT_METHOD: case CONSTANT_INTERFACEMETHOD: case CONSTANT_NAMEANDTYPE: case CONSTANT_DYNAMIC: case CONSTANT_INVOKEDYNAMIC: pool.add(i, new CPX2(tagobj, in.readUnsignedShort(), in.readUnsignedShort())); break; case CONSTANT_METHODHANDLE: pool.add(i, new CPX2(tagobj, in.readUnsignedByte(), in.readUnsignedShort())); break; default: throw new ClassFormatError("invalid constant type: " + (int) tag); } } } /** * * inbounds * * bounds-check a CP index. * */ private boolean inbounds(int cpx) { return !(cpx == 0 || cpx >= pool.size()); } /** * * getConst * * Public getter - Safely gets a Constant from the CP at a given index. * */ public Constant getConst(int cpx) { if (inbounds(cpx)) { return pool.get(cpx); } else { return null; } } /** * * StringTag * * Public string val - Safely gets the string-rep of a Constant from the CP at a given * index. * */ public String StringTag(int cpx) { String str = "Incorrect CP index:" + cpx; if (inbounds(cpx)) { Constant cns = pool.get(cpx); if (cns != null) { str = cns.tag.tagname; } } return str; } /** * * getString * * Public string val - Safely gets the string-rep of a ConstantUTF8 from the CP at a * given index. * * Returns either null (if invalid), or the string value of the UTF8 * */ public String getString(int cpx) { String str = null; if (inbounds(cpx)) { Constant cns = pool.get(cpx); if (cns != null && cns.tag == TAG.CONSTANT_UTF8) { CP_Str cns1 = (CP_Str) cns; str = cns1.value; } } return str; } /** * * getModule * * Public string val - Safely gets the string-rep of a ConstantModule from the CP at a * given index. * * Returns either null (if invalid), or the string value of the ConstantModule * */ public String getModule(int cpx) { String str = null; if (inbounds(cpx)) { Constant cns = pool.get(cpx); if (cns != null && cns.tag == TAG.CONSTANT_MODULE) { str = cns.stringVal(); } } return str; } /** * * getPackage * * Public string val - Safely gets the string-rep of a ConstantPackage from the CP at a * given index. * * Returns either null (if invalid), or the string value of the ConstantPackage * */ public String getPackage(int cpx) { String str = null; if (inbounds(cpx)) { Constant cns = pool.get(cpx); if (cns != null && cns.tag == TAG.CONSTANT_PACKAGE) { str = cns.stringVal(); } } return str; } /** * * getTypeName * * Safely gets a Java name from a ConstantUTF8 from the CP at a given index. * * Returns either null (if invalid), or the Java name value of the UTF8 * */ public String getName(int cpx) { String str = getString(cpx); if (str == null) { return ""; } return Utils.javaName(str); } /** * * getClassName * * Safely gets a Java class name from a ConstantClass from the CP at a given index. * * Returns either the Java class name, or a CP index reference string. * */ public String getClassName(int cpx) { String res = "#" + cpx; if (cpx == 0) { return res; } if (!inbounds(cpx)) { return res; } Constant cns = pool.get(cpx); if (cns == null || cns.tag != TAG.CONSTANT_CLASS) { return res; } return getClassName((CPX) cns); } /** * * getClassName * * Safely gets a Java class name from a ConstantClass from a CPX2 constant pool * object. (eg. Method/Field/Interface Ref) * * Returns either the Java class name, or a CP index reference string. * */ public String getClassName(CPX2 classConst) { return _getClassName(classConst.value1); } /** * * getClassName * * Safely gets a Java class name from a ConstantClass from a CPX constant pool object. * (eg. Class Ref) * * Returns either the Java class name, or a CP index reference string. * */ public String getClassName(CPX classConst) { return _getClassName(classConst.value); } /** * * _getClassName * * Helper for getting class name. Checks bounds, does name conversion. * */ private String _getClassName(int nameIndex) { String res = "#" + nameIndex; if (!inbounds(nameIndex)) { return res; } Constant nameconst = pool.get(nameIndex); if (nameconst == null || nameconst.tag != TAG.CONSTANT_UTF8) { return res; } CP_Str name = (CP_Str) nameconst; String classname = name.value; if (Utils.isClassArrayDescriptor(classname)) { classname = "\"" + classname + "\""; } return classname; } /** * * getShortClassName * * shortens a class name (if the class is in the given package). works with a * string-encoded classname. * */ public String getShortClassName(String className, String pkgPrefix) { if (className.startsWith(pkgPrefix)) { return className.substring(pkgPrefix.length()); } return className; } /** * * getShortClassName * * shortens a class name (if the class is in the given package). works with a CP index * to a ConstantClass. * */ public String getShortClassName(int cpx, String pkgPrefix) { String name = Utils.javaName(getClassName(cpx)); return getShortClassName(name, pkgPrefix); } /** * * decodeClassDescriptor * * Pulls the class name out of a string (at the CP index). (drops any array * descriptors, and the class descriptors ("L" and ";") * */ public String decodeClassDescriptor(int cpx) { // enum type is encoded as a descriptor // need to remove '"'s and L (class descriptor) // TODO: might have to count '['s at the beginning for Arrays String rawEnumName = getName(cpx); int len = rawEnumName.length(); int begin = (rawEnumName.startsWith("\"L")) ? 2 : 0; int end = (begin > 0) ? len - 2 : len; return rawEnumName.substring(begin, end); } /** * * subtagToString * * Getter that safely gets the string descriptor of a subtag * */ private String subtagToString(int subtag) { SUBTAG st = subtaghash.get((byte) subtag); if (st == null) { return "BOGUS_SUBTAG:" + subtag; } return st.tagname; } /** * * StringValue * * Safely gets the string value of any Constant at any CP index. * */ public String StringValue(int cpx) { if (cpx == 0) { return "#0"; } if (!inbounds(cpx)) { return ""; } Constant cnst = pool.get(cpx); if (cnst == null) { return ""; } return cnst.stringVal(); } /** * ConstantStrValue * * Safely gets the string value of any Constant at any CP index. This string is either * a Constant's String value, or a CP index reference string. The Constant string has * a tag descriptor in the beginning. * */ public String ConstantStrValue(int cpx) { if (cpx == 0) { return "#0"; } if (!inbounds(cpx)) { return "#" + cpx; } Constant cns = pool.get(cpx); if (cns == null) { return "#" + cpx; } if (cns instanceof CPX2) { CPX2 cns2 = (CPX2) cns; if (cns2.value1 == cd.this_cpx && cns2.refersClassMember()) { cpx = cns2.value2; } } return cns.tag.tagname + " " + StringValue(cpx); } /** * prints the entire constant pool. */ public void print(PrintWriter out) throws IOException { int cpx = 0; for (Constant cns : pool) { if (cpx == 0) { cpx += 1; continue; } out.print("\tconst #" + cpx + " = "); if (cns == null) { // do something out.println("null"); cpx += 1; } else { cns.print(out); cpx += cns.size(); } } } /** * prints the Constant value at a given CP index. */ void PrintConstant(PrintWriter out, int cpx) { out.print(ConstantStrValue(cpx)); } /** * prints a constant value, with the print format based on the print options. */ public void printlnClassId(PrintWriter out, int cpx) throws IOException { printlnClassId(out, cpx, false); } public void printlnClassId(PrintWriter out, int cpx, boolean addComma) throws IOException { if (!cd.options.contains(Options.PR.CPX)) { out.print(getShortClassName(cpx, cd.pkgPrefix) + (addComma ? "," : "")); } else { out.print("\t#" + cpx + (addComma ? "," : "") + " //"); PrintConstant(out, cpx); } } }