001    /*
002     * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
003     * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004     *
005     * This code is free software; you can redistribute it and/or modify it
006     * under the terms of the GNU General Public License version 2 only, as
007     * published by the Free Software Foundation.  Sun designates this
008     * particular file as subject to the "Classpath" exception as provided
009     * by Sun in the LICENSE file that accompanied this code.
010     *
011     * This code is distributed in the hope that it will be useful, but WITHOUT
012     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013     * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014     * version 2 for more details (a copy is included in the LICENSE file that
015     * accompanied this code).
016     *
017     * You should have received a copy of the GNU General Public License version
018     * 2 along with this work; if not, write to the Free Software Foundation,
019     * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020     *
021     * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022     * CA 95054 USA or visit www.sun.com if you need additional information or
023     * have any questions.
024     */
025    
026    package com.sun.tools.classfile;
027    
028    import java.io.IOException;
029    
030    /**
031     * See JVMS3, section 4.5.
032     *
033     *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
034     *  you write code that depends on this, you do so at your own risk.
035     *  This code and its internal interfaces are subject to change or
036     *  deletion without notice.</b>
037     */
038    public class ConstantPool {
039    
040        public class InvalidIndex extends ConstantPoolException {
041            private static final long serialVersionUID = -4350294289300939730L;
042            InvalidIndex(int index) {
043                super(index);
044            }
045    
046            @Override
047            public String getMessage() {
048                // i18n
049                return "invalid index #" + index;
050            }
051        }
052    
053        public class UnexpectedEntry extends ConstantPoolException {
054            private static final long serialVersionUID = 6986335935377933211L;
055            UnexpectedEntry(int index, int expected_tag, int found_tag) {
056                super(index);
057                this.expected_tag = expected_tag;
058                this.found_tag = found_tag;
059            }
060    
061            @Override
062            public String getMessage() {
063                // i18n?
064                return "unexpected entry at #" + index + " -- expected tag " + expected_tag + ", found " + found_tag;
065            }
066    
067            public final int expected_tag;
068            public final int found_tag;
069        }
070    
071        public class InvalidEntry extends ConstantPoolException {
072            private static final long serialVersionUID = 1000087545585204447L;
073            InvalidEntry(int index, int tag) {
074                super(index);
075                this.tag = tag;
076            }
077    
078            @Override
079            public String getMessage() {
080                // i18n?
081                return "unexpected tag at #" + index + ": " + tag;
082            }
083    
084            public final int tag;
085        }
086    
087        public class EntryNotFound extends ConstantPoolException {
088            private static final long serialVersionUID = 2885537606468581850L;
089            EntryNotFound(Object value) {
090                super(-1);
091                this.value = value;
092            }
093    
094            @Override
095            public String getMessage() {
096                // i18n?
097                return "value not found: " + value;
098            }
099    
100            public final Object value;
101        }
102    
103        public static final int CONSTANT_Utf8 = 1;
104        public static final int CONSTANT_Integer = 3;
105        public static final int CONSTANT_Float = 4;
106        public static final int CONSTANT_Long = 5;
107        public static final int CONSTANT_Double = 6;
108        public static final int CONSTANT_Class = 7;
109        public static final int CONSTANT_String = 8;
110        public static final int CONSTANT_Fieldref = 9;
111        public static final int CONSTANT_Methodref = 10;
112        public static final int CONSTANT_InterfaceMethodref = 11;
113        public static final int CONSTANT_NameAndType = 12;
114    
115        ConstantPool(ClassReader cr) throws IOException, InvalidEntry {
116            int count = cr.readUnsignedShort();
117            pool = new CPInfo[count];
118            for (int i = 1; i < count; i++) {
119                int tag = cr.readUnsignedByte();
120                switch (tag) {
121                case CONSTANT_Class:
122                    pool[i] = new CONSTANT_Class_info(this, cr);
123                    break;
124    
125                case CONSTANT_Double:
126                    pool[i] = new CONSTANT_Double_info(cr);
127                    i++;
128                    break;
129    
130                case CONSTANT_Fieldref:
131                    pool[i] = new CONSTANT_Fieldref_info(this, cr);
132                    break;
133    
134                case CONSTANT_Float:
135                    pool[i] = new CONSTANT_Float_info(cr);
136                    break;
137    
138                case CONSTANT_Integer:
139                    pool[i] = new CONSTANT_Integer_info(cr);
140                    break;
141    
142                case CONSTANT_InterfaceMethodref:
143                    pool[i] = new CONSTANT_InterfaceMethodref_info(this, cr);
144                    break;
145    
146                case CONSTANT_Long:
147                    pool[i] = new CONSTANT_Long_info(cr);
148                    i++;
149                    break;
150    
151                case CONSTANT_Methodref:
152                    pool[i] = new CONSTANT_Methodref_info(this, cr);
153                    break;
154    
155                case CONSTANT_NameAndType:
156                    pool[i] = new CONSTANT_NameAndType_info(this, cr);
157                    break;
158    
159                case CONSTANT_String:
160                    pool[i] = new CONSTANT_String_info(this, cr);
161                    break;
162    
163                case CONSTANT_Utf8:
164                    pool[i] = new CONSTANT_Utf8_info(cr);
165                    break;
166    
167                default:
168                    throw new InvalidEntry(i, tag);
169                }
170            }
171        }
172    
173        public ConstantPool(CPInfo[] pool) {
174            this.pool = pool;
175        }
176    
177        public int size() {
178            return pool.length;
179        }
180    
181        public CPInfo get(int index) throws InvalidIndex {
182            if (index <= 0 || index >= pool.length)
183                throw new InvalidIndex(index);
184            CPInfo info = pool[index];
185            if (info == null) {
186                // this occurs for indices referencing the "second half" of an
187                // 8 byte constant, such as CONSTANT_Double or CONSTANT_Long
188                throw new InvalidIndex(index);
189            }
190            return pool[index];
191        }
192    
193        private CPInfo get(int index, int expected_type) throws InvalidIndex, UnexpectedEntry {
194            CPInfo info = get(index);
195            if (info.getTag() != expected_type)
196                throw new UnexpectedEntry(index, expected_type, info.getTag());
197            return info;
198        }
199    
200        public CONSTANT_Utf8_info getUTF8Info(int index) throws InvalidIndex, UnexpectedEntry {
201            return ((CONSTANT_Utf8_info) get(index, CONSTANT_Utf8));
202        }
203    
204        public CONSTANT_Class_info getClassInfo(int index) throws InvalidIndex, UnexpectedEntry {
205            return ((CONSTANT_Class_info) get(index, CONSTANT_Class));
206        }
207    
208        public CONSTANT_NameAndType_info getNameAndTypeInfo(int index) throws InvalidIndex, UnexpectedEntry {
209            return ((CONSTANT_NameAndType_info) get(index, CONSTANT_NameAndType));
210        }
211    
212        public String getUTF8Value(int index) throws InvalidIndex, UnexpectedEntry {
213            return getUTF8Info(index).value;
214        }
215    
216        public int getUTF8Index(String value) throws EntryNotFound {
217            for (int i = 1; i < pool.length; i++) {
218                CPInfo info = pool[i];
219                if (info instanceof CONSTANT_Utf8_info &&
220                        ((CONSTANT_Utf8_info) info).value.equals(value))
221                    return i;
222            }
223            throw new EntryNotFound(value);
224        }
225    
226        private CPInfo[] pool;
227    
228        public interface Visitor<R,P> {
229            R visitClass(CONSTANT_Class_info info, P p);
230            R visitDouble(CONSTANT_Double_info info, P p);
231            R visitFieldref(CONSTANT_Fieldref_info info, P p);
232            R visitFloat(CONSTANT_Float_info info, P p);
233            R visitInteger(CONSTANT_Integer_info info, P p);
234            R visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, P p);
235            R visitLong(CONSTANT_Long_info info, P p);
236            R visitNameAndType(CONSTANT_NameAndType_info info, P p);
237            R visitMethodref(CONSTANT_Methodref_info info, P p);
238            R visitString(CONSTANT_String_info info, P p);
239            R visitUtf8(CONSTANT_Utf8_info info, P p);
240        }
241    
242        public static abstract class CPInfo {
243            CPInfo() {
244                this.cp = null;
245            }
246    
247            CPInfo(ConstantPool cp) {
248                this.cp = cp;
249            }
250    
251            public abstract int getTag();
252    
253            public abstract <R,D> R accept(Visitor<R,D> visitor, D data);
254    
255            protected final ConstantPool cp;
256        }
257    
258        public static abstract class CPRefInfo extends CPInfo {
259            protected CPRefInfo(ConstantPool cp, ClassReader cr, int tag) throws IOException {
260                super(cp);
261                this.tag = tag;
262                class_index = cr.readUnsignedShort();
263                name_and_type_index = cr.readUnsignedShort();
264            }
265    
266            protected CPRefInfo(ConstantPool cp, int tag, int class_index, int name_and_type_index) {
267                super(cp);
268                this.tag = tag;
269                this.class_index = class_index;
270                this.name_and_type_index = name_and_type_index;
271            }
272    
273            public int getTag() {
274                return tag;
275            }
276    
277            public CONSTANT_Class_info getClassInfo() throws ConstantPoolException {
278                return cp.getClassInfo(class_index);
279            }
280    
281            public String getClassName() throws ConstantPoolException {
282                return cp.getClassInfo(class_index).getName();
283            }
284    
285            public CONSTANT_NameAndType_info getNameAndTypeInfo() throws ConstantPoolException {
286                return cp.getNameAndTypeInfo(name_and_type_index);
287            }
288    
289            public final int tag;
290            public final int class_index;
291            public final int name_and_type_index;
292        }
293    
294        public static class CONSTANT_Class_info extends CPInfo {
295            CONSTANT_Class_info(ConstantPool cp, ClassReader cr) throws IOException {
296                super(cp);
297                name_index = cr.readUnsignedShort();
298            }
299    
300            public CONSTANT_Class_info(ConstantPool cp, int name_index) {
301                super(cp);
302                this.name_index = name_index;
303            }
304    
305            public int getTag() {
306                return CONSTANT_Class;
307            }
308    
309            public String getName() throws ConstantPoolException {
310                return cp.getUTF8Value(name_index);
311            }
312    
313            @Override
314            public String toString() {
315                return "CONSTANT_Class_info[name_index: " + name_index + "]";
316            }
317    
318            public <R, D> R accept(Visitor<R, D> visitor, D data) {
319                return visitor.visitClass(this, data);
320            }
321    
322            public final int name_index;
323        }
324    
325        public static class CONSTANT_Double_info extends CPInfo {
326            CONSTANT_Double_info(ClassReader cr) throws IOException {
327                value = cr.readDouble();
328            }
329    
330            public CONSTANT_Double_info(double value) {
331                this.value = value;
332            }
333    
334            public int getTag() {
335                return CONSTANT_Double;
336            }
337    
338            @Override
339            public String toString() {
340                return "CONSTANT_Double_info[value: " + value + "]";
341            }
342    
343            public <R, D> R accept(Visitor<R, D> visitor, D data) {
344                return visitor.visitDouble(this, data);
345            }
346    
347            public final double value;
348        }
349    
350        public static class CONSTANT_Fieldref_info extends CPRefInfo {
351            CONSTANT_Fieldref_info(ConstantPool cp, ClassReader cr) throws IOException {
352                super(cp, cr, CONSTANT_Fieldref);
353            }
354    
355            public CONSTANT_Fieldref_info(ConstantPool cp, int class_index, int name_and_type_index) {
356                super(cp, CONSTANT_Fieldref, class_index, name_and_type_index);
357            }
358    
359            @Override
360            public String toString() {
361                return "CONSTANT_Fieldref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]";
362            }
363    
364            public <R, D> R accept(Visitor<R, D> visitor, D data) {
365                return visitor.visitFieldref(this, data);
366            }
367        }
368    
369        public static class CONSTANT_Float_info extends CPInfo {
370            CONSTANT_Float_info(ClassReader cr) throws IOException {
371                value = cr.readFloat();
372            }
373    
374            public CONSTANT_Float_info(float value) {
375                this.value = value;
376            }
377    
378            public int getTag() {
379                return CONSTANT_Float;
380            }
381    
382            @Override
383            public String toString() {
384                return "CONSTANT_Float_info[value: " + value + "]";
385            }
386    
387            public <R, D> R accept(Visitor<R, D> visitor, D data) {
388                return visitor.visitFloat(this, data);
389            }
390    
391            public final float value;
392        }
393    
394        public static class CONSTANT_Integer_info extends CPInfo {
395            CONSTANT_Integer_info(ClassReader cr) throws IOException {
396                value = cr.readInt();
397            }
398    
399            public CONSTANT_Integer_info(int value) {
400                this.value = value;
401            }
402    
403            public int getTag() {
404                return CONSTANT_Integer;
405            }
406    
407            @Override
408            public String toString() {
409                return "CONSTANT_Integer_info[value: " + value + "]";
410            }
411    
412            public <R, D> R accept(Visitor<R, D> visitor, D data) {
413                return visitor.visitInteger(this, data);
414            }
415    
416            public final int value;
417        }
418    
419        public static class CONSTANT_InterfaceMethodref_info extends CPRefInfo {
420            CONSTANT_InterfaceMethodref_info(ConstantPool cp, ClassReader cr) throws IOException {
421                super(cp, cr, CONSTANT_InterfaceMethodref);
422            }
423    
424            public CONSTANT_InterfaceMethodref_info(ConstantPool cp, int class_index, int name_and_type_index) {
425                super(cp, CONSTANT_InterfaceMethodref, class_index, name_and_type_index);
426            }
427    
428            @Override
429            public String toString() {
430                return "CONSTANT_InterfaceMethodref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]";
431            }
432    
433            public <R, D> R accept(Visitor<R, D> visitor, D data) {
434                return visitor.visitInterfaceMethodref(this, data);
435            }
436        }
437    
438        public static class CONSTANT_Long_info extends CPInfo {
439            CONSTANT_Long_info(ClassReader cr) throws IOException {
440                value = cr.readLong();
441            }
442    
443            public CONSTANT_Long_info(long value) {
444                this.value = value;
445            }
446    
447            public int getTag() {
448                return CONSTANT_Long;
449            }
450    
451            @Override
452            public String toString() {
453                return "CONSTANT_Long_info[value: " + value + "]";
454            }
455    
456            public <R, D> R accept(Visitor<R, D> visitor, D data) {
457                return visitor.visitLong(this, data);
458            }
459    
460            public final long value;
461        }
462    
463        public static class CONSTANT_Methodref_info extends CPRefInfo {
464            CONSTANT_Methodref_info(ConstantPool cp, ClassReader cr) throws IOException {
465                super(cp, cr, CONSTANT_Methodref);
466            }
467    
468            public CONSTANT_Methodref_info(ConstantPool cp, int class_index, int name_and_type_index) {
469                super(cp, CONSTANT_Methodref, class_index, name_and_type_index);
470            }
471    
472            @Override
473            public String toString() {
474                return "CONSTANT_Methodref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]";
475            }
476    
477            public <R, D> R accept(Visitor<R, D> visitor, D data) {
478                return visitor.visitMethodref(this, data);
479            }
480        }
481    
482        public static class CONSTANT_NameAndType_info extends CPInfo {
483            CONSTANT_NameAndType_info(ConstantPool cp, ClassReader cr) throws IOException {
484                super(cp);
485                name_index = cr.readUnsignedShort();
486                type_index = cr.readUnsignedShort();
487            }
488    
489            public CONSTANT_NameAndType_info(ConstantPool cp, int name_index, int type_index) {
490                super(cp);
491                this.name_index = name_index;
492                this.type_index = type_index;
493            }
494    
495            public int getTag() {
496                return CONSTANT_NameAndType;
497            }
498    
499            public String getName() throws ConstantPoolException {
500                return cp.getUTF8Value(name_index);
501            }
502    
503            public String getType() throws ConstantPoolException {
504                return cp.getUTF8Value(type_index);
505            }
506    
507            public <R, D> R accept(Visitor<R, D> visitor, D data) {
508                return visitor.visitNameAndType(this, data);
509            }
510    
511            public final int name_index;
512            public final int type_index;
513        }
514    
515        public static class CONSTANT_String_info extends CPInfo {
516            CONSTANT_String_info(ConstantPool cp, ClassReader cr) throws IOException {
517                super(cp);
518                string_index = cr.readUnsignedShort();
519            }
520    
521            public CONSTANT_String_info(ConstantPool cp, int string_index) {
522                super(cp);
523                this.string_index = string_index;
524            }
525    
526            public int getTag() {
527                return CONSTANT_String;
528            }
529    
530            public String getString() throws ConstantPoolException {
531                return cp.getUTF8Value(string_index);
532            }
533    
534            public <R, D> R accept(Visitor<R, D> visitor, D data) {
535                return visitor.visitString(this, data);
536            }
537    
538            public final int string_index;
539        }
540    
541        public static class CONSTANT_Utf8_info extends CPInfo {
542            CONSTANT_Utf8_info(ClassReader cr) throws IOException {
543                value = cr.readUTF();
544            }
545    
546            public CONSTANT_Utf8_info(String value) {
547                this.value = value;
548            }
549    
550            public int getTag() {
551                return CONSTANT_Utf8;
552            }
553    
554            @Override
555            public String toString() {
556                return "CONSTANT_Utf8_info[value: " + value + "]";
557            }
558    
559            public <R, D> R accept(Visitor<R, D> visitor, D data) {
560                return visitor.visitUtf8(this, data);
561            }
562    
563            public final String value;
564        }
565    
566    
567    }