Thu, 12 Jan 2012 15:28:34 +0000
7123100: javac fails with java.lang.StackOverflowError
Summary: Inference of under-constrained type-variables creates erroneous recursive wildcard types
Reviewed-by: jjg
1 /*
2 * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
26 package com.sun.tools.classfile;
28 import java.io.DataOutputStream;
29 import java.io.IOException;
30 import java.io.OutputStream;
31 import java.util.Iterator;
33 /**
34 * See JVMS, section 4.5.
35 *
36 * <p><b>This is NOT part of any supported API.
37 * If you write code that depends on this, you do so at your own risk.
38 * This code and its internal interfaces are subject to change or
39 * deletion without notice.</b>
40 */
41 public class ConstantPool {
43 public static class InvalidIndex extends ConstantPoolException {
44 private static final long serialVersionUID = -4350294289300939730L;
45 InvalidIndex(int index) {
46 super(index);
47 }
49 @Override
50 public String getMessage() {
51 // i18n
52 return "invalid index #" + index;
53 }
54 }
56 public static class UnexpectedEntry extends ConstantPoolException {
57 private static final long serialVersionUID = 6986335935377933211L;
58 UnexpectedEntry(int index, int expected_tag, int found_tag) {
59 super(index);
60 this.expected_tag = expected_tag;
61 this.found_tag = found_tag;
62 }
64 @Override
65 public String getMessage() {
66 // i18n?
67 return "unexpected entry at #" + index + " -- expected tag " + expected_tag + ", found " + found_tag;
68 }
70 public final int expected_tag;
71 public final int found_tag;
72 }
74 public static class InvalidEntry extends ConstantPoolException {
75 private static final long serialVersionUID = 1000087545585204447L;
76 InvalidEntry(int index, int tag) {
77 super(index);
78 this.tag = tag;
79 }
81 @Override
82 public String getMessage() {
83 // i18n?
84 return "unexpected tag at #" + index + ": " + tag;
85 }
87 public final int tag;
88 }
90 public static class EntryNotFound extends ConstantPoolException {
91 private static final long serialVersionUID = 2885537606468581850L;
92 EntryNotFound(Object value) {
93 super(-1);
94 this.value = value;
95 }
97 @Override
98 public String getMessage() {
99 // i18n?
100 return "value not found: " + value;
101 }
103 public final Object value;
104 }
106 public static final int CONSTANT_Utf8 = 1;
107 public static final int CONSTANT_Integer = 3;
108 public static final int CONSTANT_Float = 4;
109 public static final int CONSTANT_Long = 5;
110 public static final int CONSTANT_Double = 6;
111 public static final int CONSTANT_Class = 7;
112 public static final int CONSTANT_String = 8;
113 public static final int CONSTANT_Fieldref = 9;
114 public static final int CONSTANT_Methodref = 10;
115 public static final int CONSTANT_InterfaceMethodref = 11;
116 public static final int CONSTANT_NameAndType = 12;
117 public static final int CONSTANT_MethodHandle = 15;
118 public static final int CONSTANT_MethodType = 16;
119 public static final int CONSTANT_InvokeDynamic = 18;
121 public static enum RefKind {
122 REF_getField(1, "getfield"),
123 REF_getStatic(2, "getstatic"),
124 REF_putField(3, "putfield"),
125 REF_putStatic(4, "putstatic"),
126 REF_invokeVirtual(5, "invokevirtual"),
127 REF_invokeStatic(6, "invokestatic"),
128 REF_invokeSpecial(7, "invokespecial"),
129 REF_newInvokeSpecial(8, "newinvokespecial"),
130 REF_invokeInterface(9, "invokeinterface");
132 public final int tag;
133 public final String name;
135 RefKind(int tag, String name) {
136 this.tag = tag;
137 this.name = name;
138 }
140 static RefKind getRefkind(int tag) {
141 switch(tag) {
142 case 1:
143 return REF_getField;
144 case 2:
145 return REF_getStatic;
146 case 3:
147 return REF_putField;
148 case 4:
149 return REF_putStatic;
150 case 5:
151 return REF_invokeVirtual;
152 case 6:
153 return REF_invokeStatic;
154 case 7:
155 return REF_invokeSpecial;
156 case 8:
157 return REF_newInvokeSpecial;
158 case 9:
159 return REF_invokeInterface;
160 default:
161 return null;
162 }
163 }
164 }
166 ConstantPool(ClassReader cr) throws IOException, InvalidEntry {
167 int count = cr.readUnsignedShort();
168 pool = new CPInfo[count];
169 for (int i = 1; i < count; i++) {
170 int tag = cr.readUnsignedByte();
171 switch (tag) {
172 case CONSTANT_Class:
173 pool[i] = new CONSTANT_Class_info(this, cr);
174 break;
176 case CONSTANT_Double:
177 pool[i] = new CONSTANT_Double_info(cr);
178 i++;
179 break;
181 case CONSTANT_Fieldref:
182 pool[i] = new CONSTANT_Fieldref_info(this, cr);
183 break;
185 case CONSTANT_Float:
186 pool[i] = new CONSTANT_Float_info(cr);
187 break;
189 case CONSTANT_Integer:
190 pool[i] = new CONSTANT_Integer_info(cr);
191 break;
193 case CONSTANT_InterfaceMethodref:
194 pool[i] = new CONSTANT_InterfaceMethodref_info(this, cr);
195 break;
197 case CONSTANT_InvokeDynamic:
198 pool[i] = new CONSTANT_InvokeDynamic_info(this, cr);
199 break;
201 case CONSTANT_Long:
202 pool[i] = new CONSTANT_Long_info(cr);
203 i++;
204 break;
206 case CONSTANT_MethodHandle:
207 pool[i] = new CONSTANT_MethodHandle_info(this, cr);
208 break;
210 case CONSTANT_MethodType:
211 pool[i] = new CONSTANT_MethodType_info(this, cr);
212 break;
214 case CONSTANT_Methodref:
215 pool[i] = new CONSTANT_Methodref_info(this, cr);
216 break;
218 case CONSTANT_NameAndType:
219 pool[i] = new CONSTANT_NameAndType_info(this, cr);
220 break;
222 case CONSTANT_String:
223 pool[i] = new CONSTANT_String_info(this, cr);
224 break;
226 case CONSTANT_Utf8:
227 pool[i] = new CONSTANT_Utf8_info(cr);
228 break;
230 default:
231 throw new InvalidEntry(i, tag);
232 }
233 }
234 }
236 public ConstantPool(CPInfo[] pool) {
237 this.pool = pool;
238 }
240 public int size() {
241 return pool.length;
242 }
244 public int byteLength() {
245 int length = 2;
246 for (int i = 1; i < size(); ) {
247 CPInfo cpInfo = pool[i];
248 length += cpInfo.byteLength();
249 i += cpInfo.size();
250 }
251 return length;
252 }
254 public CPInfo get(int index) throws InvalidIndex {
255 if (index <= 0 || index >= pool.length)
256 throw new InvalidIndex(index);
257 CPInfo info = pool[index];
258 if (info == null) {
259 // this occurs for indices referencing the "second half" of an
260 // 8 byte constant, such as CONSTANT_Double or CONSTANT_Long
261 throw new InvalidIndex(index);
262 }
263 return pool[index];
264 }
266 private CPInfo get(int index, int expected_type) throws InvalidIndex, UnexpectedEntry {
267 CPInfo info = get(index);
268 if (info.getTag() != expected_type)
269 throw new UnexpectedEntry(index, expected_type, info.getTag());
270 return info;
271 }
273 public CONSTANT_Utf8_info getUTF8Info(int index) throws InvalidIndex, UnexpectedEntry {
274 return ((CONSTANT_Utf8_info) get(index, CONSTANT_Utf8));
275 }
277 public CONSTANT_Class_info getClassInfo(int index) throws InvalidIndex, UnexpectedEntry {
278 return ((CONSTANT_Class_info) get(index, CONSTANT_Class));
279 }
281 public CONSTANT_NameAndType_info getNameAndTypeInfo(int index) throws InvalidIndex, UnexpectedEntry {
282 return ((CONSTANT_NameAndType_info) get(index, CONSTANT_NameAndType));
283 }
285 public String getUTF8Value(int index) throws InvalidIndex, UnexpectedEntry {
286 return getUTF8Info(index).value;
287 }
289 public int getUTF8Index(String value) throws EntryNotFound {
290 for (int i = 1; i < pool.length; i++) {
291 CPInfo info = pool[i];
292 if (info instanceof CONSTANT_Utf8_info &&
293 ((CONSTANT_Utf8_info) info).value.equals(value))
294 return i;
295 }
296 throw new EntryNotFound(value);
297 }
299 public Iterable<CPInfo> entries() {
300 return new Iterable<CPInfo>() {
301 public Iterator<CPInfo> iterator() {
302 return new Iterator<CPInfo>() {
304 public boolean hasNext() {
305 return next < pool.length;
306 }
308 public CPInfo next() {
309 current = pool[next];
310 switch (current.getTag()) {
311 case CONSTANT_Double:
312 case CONSTANT_Long:
313 next += 2;
314 break;
315 default:
316 next += 1;
317 }
318 return current;
319 }
321 public void remove() {
322 throw new UnsupportedOperationException();
323 }
325 private CPInfo current;
326 private int next = 1;
328 };
329 }
330 };
331 }
333 private CPInfo[] pool;
335 public interface Visitor<R,P> {
336 R visitClass(CONSTANT_Class_info info, P p);
337 R visitDouble(CONSTANT_Double_info info, P p);
338 R visitFieldref(CONSTANT_Fieldref_info info, P p);
339 R visitFloat(CONSTANT_Float_info info, P p);
340 R visitInteger(CONSTANT_Integer_info info, P p);
341 R visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, P p);
342 R visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, P p);
343 R visitLong(CONSTANT_Long_info info, P p);
344 R visitNameAndType(CONSTANT_NameAndType_info info, P p);
345 R visitMethodref(CONSTANT_Methodref_info info, P p);
346 R visitMethodHandle(CONSTANT_MethodHandle_info info, P p);
347 R visitMethodType(CONSTANT_MethodType_info info, P p);
348 R visitString(CONSTANT_String_info info, P p);
349 R visitUtf8(CONSTANT_Utf8_info info, P p);
350 }
352 public static abstract class CPInfo {
353 CPInfo() {
354 this.cp = null;
355 }
357 CPInfo(ConstantPool cp) {
358 this.cp = cp;
359 }
361 public abstract int getTag();
363 /** The number of slots in the constant pool used by this entry.
364 * 2 for CONSTANT_Double and CONSTANT_Long; 1 for everything else. */
365 public int size() {
366 return 1;
367 }
369 public abstract int byteLength();
371 public abstract <R,D> R accept(Visitor<R,D> visitor, D data);
373 protected final ConstantPool cp;
374 }
376 public static abstract class CPRefInfo extends CPInfo {
377 protected CPRefInfo(ConstantPool cp, ClassReader cr, int tag) throws IOException {
378 super(cp);
379 this.tag = tag;
380 class_index = cr.readUnsignedShort();
381 name_and_type_index = cr.readUnsignedShort();
382 }
384 protected CPRefInfo(ConstantPool cp, int tag, int class_index, int name_and_type_index) {
385 super(cp);
386 this.tag = tag;
387 this.class_index = class_index;
388 this.name_and_type_index = name_and_type_index;
389 }
391 public int getTag() {
392 return tag;
393 }
395 public int byteLength() {
396 return 5;
397 }
399 public CONSTANT_Class_info getClassInfo() throws ConstantPoolException {
400 return cp.getClassInfo(class_index);
401 }
403 public String getClassName() throws ConstantPoolException {
404 return cp.getClassInfo(class_index).getName();
405 }
407 public CONSTANT_NameAndType_info getNameAndTypeInfo() throws ConstantPoolException {
408 return cp.getNameAndTypeInfo(name_and_type_index);
409 }
411 public final int tag;
412 public final int class_index;
413 public final int name_and_type_index;
414 }
416 public static class CONSTANT_Class_info extends CPInfo {
417 CONSTANT_Class_info(ConstantPool cp, ClassReader cr) throws IOException {
418 super(cp);
419 name_index = cr.readUnsignedShort();
420 }
422 public CONSTANT_Class_info(ConstantPool cp, int name_index) {
423 super(cp);
424 this.name_index = name_index;
425 }
427 public int getTag() {
428 return CONSTANT_Class;
429 }
431 public int byteLength() {
432 return 3;
433 }
435 /**
436 * Get the raw value of the class referenced by this constant pool entry.
437 * This will either be the name of the class, in internal form, or a
438 * descriptor for an array class.
439 * @return the raw value of the class
440 */
441 public String getName() throws ConstantPoolException {
442 return cp.getUTF8Value(name_index);
443 }
445 /**
446 * If this constant pool entry identifies either a class or interface type,
447 * or a possibly multi-dimensional array of a class of interface type,
448 * return the name of the class or interface in internal form. Otherwise,
449 * (i.e. if this is a possibly multi-dimensional array of a primitive type),
450 * return null.
451 * @return the base class or interface name
452 */
453 public String getBaseName() throws ConstantPoolException {
454 String name = getName();
455 if (name.startsWith("[")) {
456 int index = name.indexOf("[L");
457 if (index == -1)
458 return null;
459 return name.substring(index + 2, name.length() - 1);
460 } else
461 return name;
462 }
464 public int getDimensionCount() throws ConstantPoolException {
465 String name = getName();
466 int count = 0;
467 while (name.charAt(count) == '[')
468 count++;
469 return count;
470 }
472 @Override
473 public String toString() {
474 return "CONSTANT_Class_info[name_index: " + name_index + "]";
475 }
477 public <R, D> R accept(Visitor<R, D> visitor, D data) {
478 return visitor.visitClass(this, data);
479 }
481 public final int name_index;
482 }
484 public static class CONSTANT_Double_info extends CPInfo {
485 CONSTANT_Double_info(ClassReader cr) throws IOException {
486 value = cr.readDouble();
487 }
489 public CONSTANT_Double_info(double value) {
490 this.value = value;
491 }
493 public int getTag() {
494 return CONSTANT_Double;
495 }
497 public int byteLength() {
498 return 9;
499 }
501 @Override
502 public int size() {
503 return 2;
504 }
506 @Override
507 public String toString() {
508 return "CONSTANT_Double_info[value: " + value + "]";
509 }
511 public <R, D> R accept(Visitor<R, D> visitor, D data) {
512 return visitor.visitDouble(this, data);
513 }
515 public final double value;
516 }
518 public static class CONSTANT_Fieldref_info extends CPRefInfo {
519 CONSTANT_Fieldref_info(ConstantPool cp, ClassReader cr) throws IOException {
520 super(cp, cr, CONSTANT_Fieldref);
521 }
523 public CONSTANT_Fieldref_info(ConstantPool cp, int class_index, int name_and_type_index) {
524 super(cp, CONSTANT_Fieldref, class_index, name_and_type_index);
525 }
527 @Override
528 public String toString() {
529 return "CONSTANT_Fieldref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]";
530 }
532 public <R, D> R accept(Visitor<R, D> visitor, D data) {
533 return visitor.visitFieldref(this, data);
534 }
535 }
537 public static class CONSTANT_Float_info extends CPInfo {
538 CONSTANT_Float_info(ClassReader cr) throws IOException {
539 value = cr.readFloat();
540 }
542 public CONSTANT_Float_info(float value) {
543 this.value = value;
544 }
546 public int getTag() {
547 return CONSTANT_Float;
548 }
550 public int byteLength() {
551 return 5;
552 }
554 @Override
555 public String toString() {
556 return "CONSTANT_Float_info[value: " + value + "]";
557 }
559 public <R, D> R accept(Visitor<R, D> visitor, D data) {
560 return visitor.visitFloat(this, data);
561 }
563 public final float value;
564 }
566 public static class CONSTANT_Integer_info extends CPInfo {
567 CONSTANT_Integer_info(ClassReader cr) throws IOException {
568 value = cr.readInt();
569 }
571 public CONSTANT_Integer_info(int value) {
572 this.value = value;
573 }
575 public int getTag() {
576 return CONSTANT_Integer;
577 }
579 public int byteLength() {
580 return 5;
581 }
583 @Override
584 public String toString() {
585 return "CONSTANT_Integer_info[value: " + value + "]";
586 }
588 public <R, D> R accept(Visitor<R, D> visitor, D data) {
589 return visitor.visitInteger(this, data);
590 }
592 public final int value;
593 }
595 public static class CONSTANT_InterfaceMethodref_info extends CPRefInfo {
596 CONSTANT_InterfaceMethodref_info(ConstantPool cp, ClassReader cr) throws IOException {
597 super(cp, cr, CONSTANT_InterfaceMethodref);
598 }
600 public CONSTANT_InterfaceMethodref_info(ConstantPool cp, int class_index, int name_and_type_index) {
601 super(cp, CONSTANT_InterfaceMethodref, class_index, name_and_type_index);
602 }
604 @Override
605 public String toString() {
606 return "CONSTANT_InterfaceMethodref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]";
607 }
609 public <R, D> R accept(Visitor<R, D> visitor, D data) {
610 return visitor.visitInterfaceMethodref(this, data);
611 }
612 }
614 public static class CONSTANT_InvokeDynamic_info extends CPInfo {
615 CONSTANT_InvokeDynamic_info(ConstantPool cp, ClassReader cr) throws IOException {
616 super(cp);
617 bootstrap_method_attr_index = cr.readUnsignedShort();
618 name_and_type_index = cr.readUnsignedShort();
619 }
621 public CONSTANT_InvokeDynamic_info(ConstantPool cp, int bootstrap_method_index, int name_and_type_index) {
622 super(cp);
623 this.bootstrap_method_attr_index = bootstrap_method_index;
624 this.name_and_type_index = name_and_type_index;
625 }
627 public int getTag() {
628 return CONSTANT_InvokeDynamic;
629 }
631 public int byteLength() {
632 return 5;
633 }
635 @Override
636 public String toString() {
637 return "CONSTANT_InvokeDynamic_info[bootstrap_method_index: " + bootstrap_method_attr_index + ", name_and_type_index: " + name_and_type_index + "]";
638 }
640 public <R, D> R accept(Visitor<R, D> visitor, D data) {
641 return visitor.visitInvokeDynamic(this, data);
642 }
644 public CONSTANT_NameAndType_info getNameAndTypeInfo() throws ConstantPoolException {
645 return cp.getNameAndTypeInfo(name_and_type_index);
646 }
648 public final int bootstrap_method_attr_index;
649 public final int name_and_type_index;
650 }
652 public static class CONSTANT_Long_info extends CPInfo {
653 CONSTANT_Long_info(ClassReader cr) throws IOException {
654 value = cr.readLong();
655 }
657 public CONSTANT_Long_info(long value) {
658 this.value = value;
659 }
661 public int getTag() {
662 return CONSTANT_Long;
663 }
665 @Override
666 public int size() {
667 return 2;
668 }
670 public int byteLength() {
671 return 9;
672 }
674 @Override
675 public String toString() {
676 return "CONSTANT_Long_info[value: " + value + "]";
677 }
679 public <R, D> R accept(Visitor<R, D> visitor, D data) {
680 return visitor.visitLong(this, data);
681 }
683 public final long value;
684 }
686 public static class CONSTANT_MethodHandle_info extends CPInfo {
687 CONSTANT_MethodHandle_info(ConstantPool cp, ClassReader cr) throws IOException {
688 super(cp);
689 reference_kind = RefKind.getRefkind(cr.readUnsignedByte());
690 reference_index = cr.readUnsignedShort();
691 }
693 public CONSTANT_MethodHandle_info(ConstantPool cp, RefKind ref_kind, int member_index) {
694 super(cp);
695 this.reference_kind = ref_kind;
696 this.reference_index = member_index;
697 }
699 public int getTag() {
700 return CONSTANT_MethodHandle;
701 }
703 public int byteLength() {
704 return 4;
705 }
707 @Override
708 public String toString() {
709 return "CONSTANT_MethodHandle_info[ref_kind: " + reference_kind + ", member_index: " + reference_index + "]";
710 }
712 public <R, D> R accept(Visitor<R, D> visitor, D data) {
713 return visitor.visitMethodHandle(this, data);
714 }
716 public CPRefInfo getCPRefInfo() throws ConstantPoolException {
717 int expected = CONSTANT_Methodref;
718 int actual = cp.get(reference_index).getTag();
719 // allow these tag types also:
720 switch (actual) {
721 case CONSTANT_Fieldref:
722 case CONSTANT_InterfaceMethodref:
723 expected = actual;
724 }
725 return (CPRefInfo) cp.get(reference_index, expected);
726 }
728 public final RefKind reference_kind;
729 public final int reference_index;
730 }
732 public static class CONSTANT_MethodType_info extends CPInfo {
733 CONSTANT_MethodType_info(ConstantPool cp, ClassReader cr) throws IOException {
734 super(cp);
735 descriptor_index = cr.readUnsignedShort();
736 }
738 public CONSTANT_MethodType_info(ConstantPool cp, int signature_index) {
739 super(cp);
740 this.descriptor_index = signature_index;
741 }
743 public int getTag() {
744 return CONSTANT_MethodType;
745 }
747 public int byteLength() {
748 return 3;
749 }
751 @Override
752 public String toString() {
753 return "CONSTANT_MethodType_info[signature_index: " + descriptor_index + "]";
754 }
756 public <R, D> R accept(Visitor<R, D> visitor, D data) {
757 return visitor.visitMethodType(this, data);
758 }
760 public String getType() throws ConstantPoolException {
761 return cp.getUTF8Value(descriptor_index);
762 }
764 public final int descriptor_index;
765 }
767 public static class CONSTANT_Methodref_info extends CPRefInfo {
768 CONSTANT_Methodref_info(ConstantPool cp, ClassReader cr) throws IOException {
769 super(cp, cr, CONSTANT_Methodref);
770 }
772 public CONSTANT_Methodref_info(ConstantPool cp, int class_index, int name_and_type_index) {
773 super(cp, CONSTANT_Methodref, class_index, name_and_type_index);
774 }
776 @Override
777 public String toString() {
778 return "CONSTANT_Methodref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]";
779 }
781 public <R, D> R accept(Visitor<R, D> visitor, D data) {
782 return visitor.visitMethodref(this, data);
783 }
784 }
786 public static class CONSTANT_NameAndType_info extends CPInfo {
787 CONSTANT_NameAndType_info(ConstantPool cp, ClassReader cr) throws IOException {
788 super(cp);
789 name_index = cr.readUnsignedShort();
790 type_index = cr.readUnsignedShort();
791 }
793 public CONSTANT_NameAndType_info(ConstantPool cp, int name_index, int type_index) {
794 super(cp);
795 this.name_index = name_index;
796 this.type_index = type_index;
797 }
799 public int getTag() {
800 return CONSTANT_NameAndType;
801 }
803 public int byteLength() {
804 return 5;
805 }
807 public String getName() throws ConstantPoolException {
808 return cp.getUTF8Value(name_index);
809 }
811 public String getType() throws ConstantPoolException {
812 return cp.getUTF8Value(type_index);
813 }
815 public <R, D> R accept(Visitor<R, D> visitor, D data) {
816 return visitor.visitNameAndType(this, data);
817 }
819 @Override
820 public String toString() {
821 return "CONSTANT_NameAndType_info[name_index: " + name_index + ", type_index: " + type_index + "]";
822 }
824 public final int name_index;
825 public final int type_index;
826 }
828 public static class CONSTANT_String_info extends CPInfo {
829 CONSTANT_String_info(ConstantPool cp, ClassReader cr) throws IOException {
830 super(cp);
831 string_index = cr.readUnsignedShort();
832 }
834 public CONSTANT_String_info(ConstantPool cp, int string_index) {
835 super(cp);
836 this.string_index = string_index;
837 }
839 public int getTag() {
840 return CONSTANT_String;
841 }
843 public int byteLength() {
844 return 3;
845 }
847 public String getString() throws ConstantPoolException {
848 return cp.getUTF8Value(string_index);
849 }
851 public <R, D> R accept(Visitor<R, D> visitor, D data) {
852 return visitor.visitString(this, data);
853 }
855 @Override
856 public String toString() {
857 return "CONSTANT_String_info[class_index: " + string_index + "]";
858 }
860 public final int string_index;
861 }
863 public static class CONSTANT_Utf8_info extends CPInfo {
864 CONSTANT_Utf8_info(ClassReader cr) throws IOException {
865 value = cr.readUTF();
866 }
868 public CONSTANT_Utf8_info(String value) {
869 this.value = value;
870 }
872 public int getTag() {
873 return CONSTANT_Utf8;
874 }
876 public int byteLength() {
877 class SizeOutputStream extends OutputStream {
878 @Override
879 public void write(int b) {
880 size++;
881 }
882 int size;
883 }
884 SizeOutputStream sizeOut = new SizeOutputStream();
885 DataOutputStream out = new DataOutputStream(sizeOut);
886 try { out.writeUTF(value); } catch (IOException ignore) { }
887 return 1 + sizeOut.size;
888 }
890 @Override
891 public String toString() {
892 if (value.length() < 32 && isPrintableAscii(value))
893 return "CONSTANT_Utf8_info[value: \"" + value + "\"]";
894 else
895 return "CONSTANT_Utf8_info[value: (" + value.length() + " chars)]";
896 }
898 static boolean isPrintableAscii(String s) {
899 for (int i = 0; i < s.length(); i++) {
900 char c = s.charAt(i);
901 if (c < 32 || c >= 127)
902 return false;
903 }
904 return true;
905 }
907 public <R, D> R accept(Visitor<R, D> visitor, D data) {
908 return visitor.visitUtf8(this, data);
909 }
911 public final String value;
912 }
914 }