ConstantPool.java revision 2942:08092deced3f
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
26package com.sun.tools.classfile;
27
28import java.io.DataOutputStream;
29import java.io.IOException;
30import java.io.OutputStream;
31import 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 */
41public class ConstantPool {
42
43    public static class InvalidIndex extends ConstantPoolException {
44        private static final long serialVersionUID = -4350294289300939730L;
45        InvalidIndex(int index) {
46            super(index);
47        }
48
49        @Override
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;
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
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;
76        InvalidEntry(int index, int tag) {
77            super(index);
78            this.tag = tag;
79        }
80
81        @Override
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;
92        EntryNotFound(Object value) {
93            super(-1);
94            this.value = value;
95        }
96
97        @Override
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
135        RefKind(int tag, String name) {
136            this.tag = tag;
137            this.name = name;
138        }
139
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
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
236    public ConstantPool(CPInfo[] pool) {
237        this.pool = pool;
238    }
239
240    public int size() {
241        return pool.length;
242    }
243
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
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
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
273    public CONSTANT_Utf8_info getUTF8Info(int index) throws InvalidIndex, UnexpectedEntry {
274        return ((CONSTANT_Utf8_info) get(index, CONSTANT_Utf8));
275    }
276
277    public CONSTANT_Class_info getClassInfo(int index) throws InvalidIndex, UnexpectedEntry {
278        return ((CONSTANT_Class_info) get(index, CONSTANT_Class));
279    }
280
281    public CONSTANT_NameAndType_info getNameAndTypeInfo(int index) throws InvalidIndex, UnexpectedEntry {
282        return ((CONSTANT_NameAndType_info) get(index, CONSTANT_NameAndType));
283    }
284
285    public String getUTF8Value(int index) throws InvalidIndex, UnexpectedEntry {
286        return getUTF8Info(index).value;
287    }
288
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
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