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 }