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  */
25 
26 package com.sun.tools.classfile;
27 
28 import java.io.DataOutputStream;
29 import java.io.IOException;
30 import java.io.OutputStream;
31 import java.util.Iterator;
32 
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 {
42 
43     public static class InvalidIndex extends ConstantPoolException {
44         private static final long serialVersionUID = -4350294289300939730L;
InvalidIndex(int index)45         InvalidIndex(int index) {
46             super(index);
47         }
48 
49         @Override
getMessage()50         public String getMessage() {
51             // i18n
52             return "invalid index #" + index;
53         }
54     }
55 
56     public static class UnexpectedEntry extends ConstantPoolException {
57         private static final long serialVersionUID = 6986335935377933211L;
UnexpectedEntry(int index, int expected_tag, int found_tag)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         }
63 
64         @Override
getMessage()65         public String getMessage() {
66             // i18n?
67             return "unexpected entry at #" + index + " -- expected tag " + expected_tag + ", found " + found_tag;
68         }
69 
70         public final int expected_tag;
71         public final int found_tag;
72     }
73 
74     public static class InvalidEntry extends ConstantPoolException {
75         private static final long serialVersionUID = 1000087545585204447L;
InvalidEntry(int index, int tag)76         InvalidEntry(int index, int tag) {
77             super(index);
78             this.tag = tag;
79         }
80 
81         @Override
getMessage()82         public String getMessage() {
83             // i18n?
84             return "unexpected tag at #" + index + ": " + tag;
85         }
86 
87         public final int tag;
88     }
89 
90     public static class EntryNotFound extends ConstantPoolException {
91         private static final long serialVersionUID = 2885537606468581850L;
EntryNotFound(Object value)92         EntryNotFound(Object value) {
93             super(-1);
94             this.value = value;
95         }
96 
97         @Override
getMessage()98         public String getMessage() {
99             // i18n?
100             return "value not found: " + value;
101         }
102 
103         public final Object value;
104     }
105 
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;
120 
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");
131 
132         public final int tag;
133         public final String name;
134 
RefKind(int tag, String name)135         RefKind(int tag, String name) {
136             this.tag = tag;
137             this.name = name;
138         }
139 
getRefkind(int tag)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     }
165 
ConstantPool(ClassReader cr)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;
175 
176             case CONSTANT_Double:
177                 pool[i] = new CONSTANT_Double_info(cr);
178                 i++;
179                 break;
180 
181             case CONSTANT_Fieldref:
182                 pool[i] = new CONSTANT_Fieldref_info(this, cr);
183                 break;
184 
185             case CONSTANT_Float:
186                 pool[i] = new CONSTANT_Float_info(cr);
187                 break;
188 
189             case CONSTANT_Integer:
190                 pool[i] = new CONSTANT_Integer_info(cr);
191                 break;
192 
193             case CONSTANT_InterfaceMethodref:
194                 pool[i] = new CONSTANT_InterfaceMethodref_info(this, cr);
195                 break;
196 
197             case CONSTANT_InvokeDynamic:
198                 pool[i] = new CONSTANT_InvokeDynamic_info(this, cr);
199                 break;
200 
201             case CONSTANT_Long:
202                 pool[i] = new CONSTANT_Long_info(cr);
203                 i++;
204                 break;
205 
206             case CONSTANT_MethodHandle:
207                 pool[i] = new CONSTANT_MethodHandle_info(this, cr);
208                 break;
209 
210             case CONSTANT_MethodType:
211                 pool[i] = new CONSTANT_MethodType_info(this, cr);
212                 break;
213 
214             case CONSTANT_Methodref:
215                 pool[i] = new CONSTANT_Methodref_info(this, cr);
216                 break;
217 
218             case CONSTANT_NameAndType:
219                 pool[i] = new CONSTANT_NameAndType_info(this, cr);
220                 break;
221 
222             case CONSTANT_String:
223                 pool[i] = new CONSTANT_String_info(this, cr);
224                 break;
225 
226             case CONSTANT_Utf8:
227                 pool[i] = new CONSTANT_Utf8_info(cr);
228                 break;
229 
230             default:
231                 throw new InvalidEntry(i, tag);
232             }
233         }
234     }
235 
ConstantPool(CPInfo[] pool)236     public ConstantPool(CPInfo[] pool) {
237         this.pool = pool;
238     }
239 
size()240     public int size() {
241         return pool.length;
242     }
243 
byteLength()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     }
253 
get(int index)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     }
265 
get(int index, int expected_type)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     }
272 
getUTF8Info(int index)273     public CONSTANT_Utf8_info getUTF8Info(int index) throws InvalidIndex, UnexpectedEntry {
274         return ((CONSTANT_Utf8_info) get(index, CONSTANT_Utf8));
275     }
276 
getClassInfo(int index)277     public CONSTANT_Class_info getClassInfo(int index) throws InvalidIndex, UnexpectedEntry {
278         return ((CONSTANT_Class_info) get(index, CONSTANT_Class));
279     }
280 
getNameAndTypeInfo(int index)281     public CONSTANT_NameAndType_info getNameAndTypeInfo(int index) throws InvalidIndex, UnexpectedEntry {
282         return ((CONSTANT_NameAndType_info) get(index, CONSTANT_NameAndType));
283     }
284 
getUTF8Value(int index)285     public String getUTF8Value(int index) throws InvalidIndex, UnexpectedEntry {
286         return getUTF8Info(index).value;
287     }
288 
getUTF8Index(String value)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     }
298 
entries()299     public Iterable<CPInfo> entries() {
300         return new Iterable<CPInfo>() {
301             public Iterator<CPInfo> iterator() {
302                 return new Iterator<CPInfo>() {
303 
304                     public boolean hasNext() {
305                         return next < pool.length;
306                     }
307 
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                     }
320 
321                     public void remove() {
322                         throw new UnsupportedOperationException();
323                     }
324 
325                     private CPInfo current;
326                     private int next = 1;
327 
328                 };
329             }
330         };
331     }
332 
333     private CPInfo[] pool;
334 
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     }
351 
352     public static abstract class CPInfo {
353         CPInfo() {
354             this.cp = null;
355         }
356 
357         CPInfo(ConstantPool cp) {
358             this.cp = cp;
359         }
360 
361         public abstract int getTag();
362 
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         }
368 
369         public abstract int byteLength();
370 
371         public abstract <R,D> R accept(Visitor<R,D> visitor, D data);
372 
373         protected final ConstantPool cp;
374     }
375 
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         }
383 
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         }
390 
391         public int getTag() {
392             return tag;
393         }
394 
395         public int byteLength() {
396             return 5;
397         }
398 
399         public CONSTANT_Class_info getClassInfo() throws ConstantPoolException {
400             return cp.getClassInfo(class_index);
401         }
402 
403         public String getClassName() throws ConstantPoolException {
404             return cp.getClassInfo(class_index).getName();
405         }
406 
407         public CONSTANT_NameAndType_info getNameAndTypeInfo() throws ConstantPoolException {
408             return cp.getNameAndTypeInfo(name_and_type_index);
409         }
410 
411         public final int tag;
412         public final int class_index;
413         public final int name_and_type_index;
414     }
415 
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         }
421 
422         public CONSTANT_Class_info(ConstantPool cp, int name_index) {
423             super(cp);
424             this.name_index = name_index;
425         }
426 
427         public int getTag() {
428             return CONSTANT_Class;
429         }
430 
431         public int  byteLength() {
432             return 3;
433         }
434 
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         }
444 
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         }
463 
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         }
471 
472         @Override
473         public String toString() {
474             return "CONSTANT_Class_info[name_index: " + name_index + "]";
475         }
476 
477         public <R, D> R accept(Visitor<R, D> visitor, D data) {
478             return visitor.visitClass(this, data);
479         }
480 
481         public final int name_index;
482     }
483 
484     public static class CONSTANT_Double_info extends CPInfo {
485         CONSTANT_Double_info(ClassReader cr) throws IOException {
486             value = cr.readDouble();
487         }
488 
489         public CONSTANT_Double_info(double value) {
490             this.value = value;
491         }
492 
493         public int getTag() {
494             return CONSTANT_Double;
495         }
496 
497         public int  byteLength() {
498             return 9;
499         }
500 
501         @Override
502         public int size() {
503             return 2;
504         }
505 
506         @Override
507         public String toString() {
508             return "CONSTANT_Double_info[value: " + value + "]";
509         }
510 
511         public <R, D> R accept(Visitor<R, D> visitor, D data) {
512             return visitor.visitDouble(this, data);
513         }
514 
515         public final double value;
516     }
517 
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         }
522 
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         }
526 
527         @Override
528         public String toString() {
529             return "CONSTANT_Fieldref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]";
530         }
531 
532         public <R, D> R accept(Visitor<R, D> visitor, D data) {
533             return visitor.visitFieldref(this, data);
534         }
535     }
536 
537     public static class CONSTANT_Float_info extends CPInfo {
538         CONSTANT_Float_info(ClassReader cr) throws IOException {
539             value = cr.readFloat();
540         }
541 
542         public CONSTANT_Float_info(float value) {
543             this.value = value;
544         }
545 
546         public int getTag() {
547             return CONSTANT_Float;
548         }
549 
550         public int byteLength() {
551             return 5;
552         }
553 
554         @Override
555         public String toString() {
556             return "CONSTANT_Float_info[value: " + value + "]";
557         }
558 
559         public <R, D> R accept(Visitor<R, D> visitor, D data) {
560             return visitor.visitFloat(this, data);
561         }
562 
563         public final float value;
564     }
565 
566     public static class CONSTANT_Integer_info extends CPInfo {
567         CONSTANT_Integer_info(ClassReader cr) throws IOException {
568             value = cr.readInt();
569         }
570 
571         public CONSTANT_Integer_info(int value) {
572             this.value = value;
573         }
574 
575         public int getTag() {
576             return CONSTANT_Integer;
577         }
578 
579         public int byteLength() {
580             return 5;
581         }
582 
583         @Override
584         public String toString() {
585             return "CONSTANT_Integer_info[value: " + value + "]";
586         }
587 
588         public <R, D> R accept(Visitor<R, D> visitor, D data) {
589             return visitor.visitInteger(this, data);
590         }
591 
592         public final int value;
593     }
594 
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         }
599 
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         }
603 
604         @Override
605         public String toString() {
606             return "CONSTANT_InterfaceMethodref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]";
607         }
608 
609         public <R, D> R accept(Visitor<R, D> visitor, D data) {
610             return visitor.visitInterfaceMethodref(this, data);
611         }
612     }
613 
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         }
620 
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         }
626 
627         public int getTag() {
628             return CONSTANT_InvokeDynamic;
629         }
630 
631         public int byteLength() {
632             return 5;
633         }
634 
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         }
639 
640         public <R, D> R accept(Visitor<R, D> visitor, D data) {
641             return visitor.visitInvokeDynamic(this, data);
642         }
643 
644         public CONSTANT_NameAndType_info getNameAndTypeInfo() throws ConstantPoolException {
645             return cp.getNameAndTypeInfo(name_and_type_index);
646         }
647 
648         public final int bootstrap_method_attr_index;
649         public final int name_and_type_index;
650     }
651 
652     public static class CONSTANT_Long_info extends CPInfo {
653         CONSTANT_Long_info(ClassReader cr) throws IOException {
654             value = cr.readLong();
655         }
656 
657         public CONSTANT_Long_info(long value) {
658             this.value = value;
659         }
660 
661         public int getTag() {
662             return CONSTANT_Long;
663         }
664 
665         @Override
666         public int size() {
667             return 2;
668         }
669 
670         public int byteLength() {
671             return 9;
672         }
673 
674         @Override
675         public String toString() {
676             return "CONSTANT_Long_info[value: " + value + "]";
677         }
678 
679         public <R, D> R accept(Visitor<R, D> visitor, D data) {
680             return visitor.visitLong(this, data);
681         }
682 
683         public final long value;
684     }
685 
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         }
692 
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         }
698 
699         public int getTag() {
700             return CONSTANT_MethodHandle;
701         }
702 
703         public int byteLength() {
704             return 4;
705         }
706 
707         @Override
708         public String toString() {
709             return "CONSTANT_MethodHandle_info[ref_kind: " + reference_kind + ", member_index: " + reference_index + "]";
710         }
711 
712         public <R, D> R accept(Visitor<R, D> visitor, D data) {
713             return visitor.visitMethodHandle(this, data);
714         }
715 
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         }
727 
728         public final RefKind reference_kind;
729         public final int reference_index;
730     }
731 
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         }
737 
738         public CONSTANT_MethodType_info(ConstantPool cp, int signature_index) {
739             super(cp);
740             this.descriptor_index = signature_index;
741         }
742 
743         public int getTag() {
744             return CONSTANT_MethodType;
745         }
746 
747         public int byteLength() {
748             return 3;
749         }
750 
751         @Override
752         public String toString() {
753             return "CONSTANT_MethodType_info[signature_index: " + descriptor_index + "]";
754         }
755 
756         public <R, D> R accept(Visitor<R, D> visitor, D data) {
757             return visitor.visitMethodType(this, data);
758         }
759 
760         public String getType() throws ConstantPoolException {
761             return cp.getUTF8Value(descriptor_index);
762         }
763 
764         public final int descriptor_index;
765     }
766 
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         }
771 
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         }
775 
776         @Override
777         public String toString() {
778             return "CONSTANT_Methodref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]";
779         }
780 
781         public <R, D> R accept(Visitor<R, D> visitor, D data) {
782             return visitor.visitMethodref(this, data);
783         }
784     }
785 
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         }
792 
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         }
798 
799         public int getTag() {
800             return CONSTANT_NameAndType;
801         }
802 
803         public int byteLength() {
804             return 5;
805         }
806 
807         public String getName() throws ConstantPoolException {
808             return cp.getUTF8Value(name_index);
809         }
810 
811         public String getType() throws ConstantPoolException {
812             return cp.getUTF8Value(type_index);
813         }
814 
815         public <R, D> R accept(Visitor<R, D> visitor, D data) {
816             return visitor.visitNameAndType(this, data);
817         }
818 
819         @Override
820         public String toString() {
821             return "CONSTANT_NameAndType_info[name_index: " + name_index + ", type_index: " + type_index + "]";
822         }
823 
824         public final int name_index;
825         public final int type_index;
826     }
827 
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         }
833 
834         public CONSTANT_String_info(ConstantPool cp, int string_index) {
835             super(cp);
836             this.string_index = string_index;
837         }
838 
839         public int getTag() {
840             return CONSTANT_String;
841         }
842 
843         public int byteLength() {
844             return 3;
845         }
846 
847         public String getString() throws ConstantPoolException {
848             return cp.getUTF8Value(string_index);
849         }
850 
851         public <R, D> R accept(Visitor<R, D> visitor, D data) {
852             return visitor.visitString(this, data);
853         }
854 
855         @Override
856         public String toString() {
857             return "CONSTANT_String_info[class_index: " + string_index + "]";
858         }
859 
860         public final int string_index;
861     }
862 
863     public static class CONSTANT_Utf8_info extends CPInfo {
864         CONSTANT_Utf8_info(ClassReader cr) throws IOException {
865             value = cr.readUTF();
866         }
867 
868         public CONSTANT_Utf8_info(String value) {
869             this.value = value;
870         }
871 
872         public int getTag() {
873             return CONSTANT_Utf8;
874         }
875 
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         }
889 
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         }
897 
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         }
906 
907         public <R, D> R accept(Visitor<R, D> visitor, D data) {
908             return visitor.visitUtf8(this, data);
909         }
910 
911         public final String value;
912     }
913 
914 }
915