src/share/classes/com/sun/tools/classfile/ConstantPool.java

Thu, 30 Jul 2009 07:48:24 -0700

author
jjg
date
Thu, 30 Jul 2009 07:48:24 -0700
changeset 345
23505e6ea22d
parent 300
ed989c347b3c
child 422
e526e39579ae
permissions
-rw-r--r--

6866657: add byteLength method to primary classfile types
Reviewed-by: mchung

     1 /*
     2  * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
    23  * have any 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 JVMS3, section 4.5.
    35  *
    36  *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
    37  *  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 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 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 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 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;
   118     ConstantPool(ClassReader cr) throws IOException, InvalidEntry {
   119         int count = cr.readUnsignedShort();
   120         pool = new CPInfo[count];
   121         for (int i = 1; i < count; i++) {
   122             int tag = cr.readUnsignedByte();
   123             switch (tag) {
   124             case CONSTANT_Class:
   125                 pool[i] = new CONSTANT_Class_info(this, cr);
   126                 break;
   128             case CONSTANT_Double:
   129                 pool[i] = new CONSTANT_Double_info(cr);
   130                 i++;
   131                 break;
   133             case CONSTANT_Fieldref:
   134                 pool[i] = new CONSTANT_Fieldref_info(this, cr);
   135                 break;
   137             case CONSTANT_Float:
   138                 pool[i] = new CONSTANT_Float_info(cr);
   139                 break;
   141             case CONSTANT_Integer:
   142                 pool[i] = new CONSTANT_Integer_info(cr);
   143                 break;
   145             case CONSTANT_InterfaceMethodref:
   146                 pool[i] = new CONSTANT_InterfaceMethodref_info(this, cr);
   147                 break;
   149             case CONSTANT_Long:
   150                 pool[i] = new CONSTANT_Long_info(cr);
   151                 i++;
   152                 break;
   154             case CONSTANT_Methodref:
   155                 pool[i] = new CONSTANT_Methodref_info(this, cr);
   156                 break;
   158             case CONSTANT_NameAndType:
   159                 pool[i] = new CONSTANT_NameAndType_info(this, cr);
   160                 break;
   162             case CONSTANT_String:
   163                 pool[i] = new CONSTANT_String_info(this, cr);
   164                 break;
   166             case CONSTANT_Utf8:
   167                 pool[i] = new CONSTANT_Utf8_info(cr);
   168                 break;
   170             default:
   171                 throw new InvalidEntry(i, tag);
   172             }
   173         }
   174     }
   176     public ConstantPool(CPInfo[] pool) {
   177         this.pool = pool;
   178     }
   180     public int size() {
   181         return pool.length;
   182     }
   184     public int byteLength() {
   185         int length = 2;
   186         for (int i = 1; i < size(); ) {
   187             CPInfo cpInfo = pool[i];
   188             length += cpInfo.byteLength();
   189             i += cpInfo.size();
   190         }
   191         return length;
   192     }
   194     public CPInfo get(int index) throws InvalidIndex {
   195         if (index <= 0 || index >= pool.length)
   196             throw new InvalidIndex(index);
   197         CPInfo info = pool[index];
   198         if (info == null) {
   199             // this occurs for indices referencing the "second half" of an
   200             // 8 byte constant, such as CONSTANT_Double or CONSTANT_Long
   201             throw new InvalidIndex(index);
   202         }
   203         return pool[index];
   204     }
   206     private CPInfo get(int index, int expected_type) throws InvalidIndex, UnexpectedEntry {
   207         CPInfo info = get(index);
   208         if (info.getTag() != expected_type)
   209             throw new UnexpectedEntry(index, expected_type, info.getTag());
   210         return info;
   211     }
   213     public CONSTANT_Utf8_info getUTF8Info(int index) throws InvalidIndex, UnexpectedEntry {
   214         return ((CONSTANT_Utf8_info) get(index, CONSTANT_Utf8));
   215     }
   217     public CONSTANT_Class_info getClassInfo(int index) throws InvalidIndex, UnexpectedEntry {
   218         return ((CONSTANT_Class_info) get(index, CONSTANT_Class));
   219     }
   221     public CONSTANT_NameAndType_info getNameAndTypeInfo(int index) throws InvalidIndex, UnexpectedEntry {
   222         return ((CONSTANT_NameAndType_info) get(index, CONSTANT_NameAndType));
   223     }
   225     public String getUTF8Value(int index) throws InvalidIndex, UnexpectedEntry {
   226         return getUTF8Info(index).value;
   227     }
   229     public int getUTF8Index(String value) throws EntryNotFound {
   230         for (int i = 1; i < pool.length; i++) {
   231             CPInfo info = pool[i];
   232             if (info instanceof CONSTANT_Utf8_info &&
   233                     ((CONSTANT_Utf8_info) info).value.equals(value))
   234                 return i;
   235         }
   236         throw new EntryNotFound(value);
   237     }
   239     public Iterable<CPInfo> entries() {
   240         return new Iterable<CPInfo>() {
   241             public Iterator<CPInfo> iterator() {
   242                 return new Iterator<CPInfo>() {
   244                     public boolean hasNext() {
   245                         return next < pool.length;
   246                     }
   248                     public CPInfo next() {
   249                         current = pool[next];
   250                         switch (current.getTag()) {
   251                             case CONSTANT_Double:
   252                             case CONSTANT_Long:
   253                                 next += 2;
   254                                 break;
   255                             default:
   256                                 next += 1;
   257                         }
   258                         return current;
   259                     }
   261                     public void remove() {
   262                         throw new UnsupportedOperationException();
   263                     }
   265                     private CPInfo current;
   266                     private int next = 1;
   268                 };
   269             }
   270         };
   271     }
   273     private CPInfo[] pool;
   275     public interface Visitor<R,P> {
   276         R visitClass(CONSTANT_Class_info info, P p);
   277         R visitDouble(CONSTANT_Double_info info, P p);
   278         R visitFieldref(CONSTANT_Fieldref_info info, P p);
   279         R visitFloat(CONSTANT_Float_info info, P p);
   280         R visitInteger(CONSTANT_Integer_info info, P p);
   281         R visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, P p);
   282         R visitLong(CONSTANT_Long_info info, P p);
   283         R visitNameAndType(CONSTANT_NameAndType_info info, P p);
   284         R visitMethodref(CONSTANT_Methodref_info info, P p);
   285         R visitString(CONSTANT_String_info info, P p);
   286         R visitUtf8(CONSTANT_Utf8_info info, P p);
   287     }
   289     public static abstract class CPInfo {
   290         CPInfo() {
   291             this.cp = null;
   292         }
   294         CPInfo(ConstantPool cp) {
   295             this.cp = cp;
   296         }
   298         public abstract int getTag();
   300         /** The number of slots in the constant pool used by this entry.
   301          * 2 for CONSTANT_Double and CONSTANT_Long; 1 for everything else. */
   302         public int size() {
   303             return 1;
   304         }
   306         public abstract int byteLength();
   308         public abstract <R,D> R accept(Visitor<R,D> visitor, D data);
   310         protected final ConstantPool cp;
   311     }
   313     public static abstract class CPRefInfo extends CPInfo {
   314         protected CPRefInfo(ConstantPool cp, ClassReader cr, int tag) throws IOException {
   315             super(cp);
   316             this.tag = tag;
   317             class_index = cr.readUnsignedShort();
   318             name_and_type_index = cr.readUnsignedShort();
   319         }
   321         protected CPRefInfo(ConstantPool cp, int tag, int class_index, int name_and_type_index) {
   322             super(cp);
   323             this.tag = tag;
   324             this.class_index = class_index;
   325             this.name_and_type_index = name_and_type_index;
   326         }
   328         public int getTag() {
   329             return tag;
   330         }
   332         public int byteLength() {
   333             return 5;
   334         }
   336         public CONSTANT_Class_info getClassInfo() throws ConstantPoolException {
   337             return cp.getClassInfo(class_index);
   338         }
   340         public String getClassName() throws ConstantPoolException {
   341             return cp.getClassInfo(class_index).getName();
   342         }
   344         public CONSTANT_NameAndType_info getNameAndTypeInfo() throws ConstantPoolException {
   345             return cp.getNameAndTypeInfo(name_and_type_index);
   346         }
   348         public final int tag;
   349         public final int class_index;
   350         public final int name_and_type_index;
   351     }
   353     public static class CONSTANT_Class_info extends CPInfo {
   354         CONSTANT_Class_info(ConstantPool cp, ClassReader cr) throws IOException {
   355             super(cp);
   356             name_index = cr.readUnsignedShort();
   357         }
   359         public CONSTANT_Class_info(ConstantPool cp, int name_index) {
   360             super(cp);
   361             this.name_index = name_index;
   362         }
   364         public int getTag() {
   365             return CONSTANT_Class;
   366         }
   368         public int  byteLength() {
   369             return 3;
   370         }
   372         public String getName() throws ConstantPoolException {
   373             return cp.getUTF8Value(name_index);
   374         }
   376         public String getBaseName() throws ConstantPoolException {
   377             String name = getName();
   378             int index = name.indexOf("[L") + 1;
   379             return name.substring(index);
   380         }
   382         public int getDimensionCount() throws ConstantPoolException {
   383             String name = getName();
   384             int count = 0;
   385             while (name.charAt(count) == '[')
   386                 count++;
   387             return count;
   388         }
   390         @Override
   391         public String toString() {
   392             return "CONSTANT_Class_info[name_index: " + name_index + "]";
   393         }
   395         public <R, D> R accept(Visitor<R, D> visitor, D data) {
   396             return visitor.visitClass(this, data);
   397         }
   399         public final int name_index;
   400     }
   402     public static class CONSTANT_Double_info extends CPInfo {
   403         CONSTANT_Double_info(ClassReader cr) throws IOException {
   404             value = cr.readDouble();
   405         }
   407         public CONSTANT_Double_info(double value) {
   408             this.value = value;
   409         }
   411         public int getTag() {
   412             return CONSTANT_Double;
   413         }
   415         public int  byteLength() {
   416             return 9;
   417         }
   419         @Override
   420         public int size() {
   421             return 2;
   422         }
   424         @Override
   425         public String toString() {
   426             return "CONSTANT_Double_info[value: " + value + "]";
   427         }
   429         public <R, D> R accept(Visitor<R, D> visitor, D data) {
   430             return visitor.visitDouble(this, data);
   431         }
   433         public final double value;
   434     }
   436     public static class CONSTANT_Fieldref_info extends CPRefInfo {
   437         CONSTANT_Fieldref_info(ConstantPool cp, ClassReader cr) throws IOException {
   438             super(cp, cr, CONSTANT_Fieldref);
   439         }
   441         public CONSTANT_Fieldref_info(ConstantPool cp, int class_index, int name_and_type_index) {
   442             super(cp, CONSTANT_Fieldref, class_index, name_and_type_index);
   443         }
   445         @Override
   446         public String toString() {
   447             return "CONSTANT_Fieldref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]";
   448         }
   450         public <R, D> R accept(Visitor<R, D> visitor, D data) {
   451             return visitor.visitFieldref(this, data);
   452         }
   453     }
   455     public static class CONSTANT_Float_info extends CPInfo {
   456         CONSTANT_Float_info(ClassReader cr) throws IOException {
   457             value = cr.readFloat();
   458         }
   460         public CONSTANT_Float_info(float value) {
   461             this.value = value;
   462         }
   464         public int getTag() {
   465             return CONSTANT_Float;
   466         }
   468         public int byteLength() {
   469             return 5;
   470         }
   472         @Override
   473         public String toString() {
   474             return "CONSTANT_Float_info[value: " + value + "]";
   475         }
   477         public <R, D> R accept(Visitor<R, D> visitor, D data) {
   478             return visitor.visitFloat(this, data);
   479         }
   481         public final float value;
   482     }
   484     public static class CONSTANT_Integer_info extends CPInfo {
   485         CONSTANT_Integer_info(ClassReader cr) throws IOException {
   486             value = cr.readInt();
   487         }
   489         public CONSTANT_Integer_info(int value) {
   490             this.value = value;
   491         }
   493         public int getTag() {
   494             return CONSTANT_Integer;
   495         }
   497         public int byteLength() {
   498             return 5;
   499         }
   501         @Override
   502         public String toString() {
   503             return "CONSTANT_Integer_info[value: " + value + "]";
   504         }
   506         public <R, D> R accept(Visitor<R, D> visitor, D data) {
   507             return visitor.visitInteger(this, data);
   508         }
   510         public final int value;
   511     }
   513     public static class CONSTANT_InterfaceMethodref_info extends CPRefInfo {
   514         CONSTANT_InterfaceMethodref_info(ConstantPool cp, ClassReader cr) throws IOException {
   515             super(cp, cr, CONSTANT_InterfaceMethodref);
   516         }
   518         public CONSTANT_InterfaceMethodref_info(ConstantPool cp, int class_index, int name_and_type_index) {
   519             super(cp, CONSTANT_InterfaceMethodref, class_index, name_and_type_index);
   520         }
   522         @Override
   523         public String toString() {
   524             return "CONSTANT_InterfaceMethodref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]";
   525         }
   527         public <R, D> R accept(Visitor<R, D> visitor, D data) {
   528             return visitor.visitInterfaceMethodref(this, data);
   529         }
   530     }
   532     public static class CONSTANT_Long_info extends CPInfo {
   533         CONSTANT_Long_info(ClassReader cr) throws IOException {
   534             value = cr.readLong();
   535         }
   537         public CONSTANT_Long_info(long value) {
   538             this.value = value;
   539         }
   541         public int getTag() {
   542             return CONSTANT_Long;
   543         }
   545         @Override
   546         public int size() {
   547             return 2;
   548         }
   550         public int byteLength() {
   551             return 9;
   552         }
   554         @Override
   555         public String toString() {
   556             return "CONSTANT_Long_info[value: " + value + "]";
   557         }
   559         public <R, D> R accept(Visitor<R, D> visitor, D data) {
   560             return visitor.visitLong(this, data);
   561         }
   563         public final long value;
   564     }
   566     public static class CONSTANT_Methodref_info extends CPRefInfo {
   567         CONSTANT_Methodref_info(ConstantPool cp, ClassReader cr) throws IOException {
   568             super(cp, cr, CONSTANT_Methodref);
   569         }
   571         public CONSTANT_Methodref_info(ConstantPool cp, int class_index, int name_and_type_index) {
   572             super(cp, CONSTANT_Methodref, class_index, name_and_type_index);
   573         }
   575         @Override
   576         public String toString() {
   577             return "CONSTANT_Methodref_info[class_index: " + class_index + ", name_and_type_index: " + name_and_type_index + "]";
   578         }
   580         public <R, D> R accept(Visitor<R, D> visitor, D data) {
   581             return visitor.visitMethodref(this, data);
   582         }
   583     }
   585     public static class CONSTANT_NameAndType_info extends CPInfo {
   586         CONSTANT_NameAndType_info(ConstantPool cp, ClassReader cr) throws IOException {
   587             super(cp);
   588             name_index = cr.readUnsignedShort();
   589             type_index = cr.readUnsignedShort();
   590         }
   592         public CONSTANT_NameAndType_info(ConstantPool cp, int name_index, int type_index) {
   593             super(cp);
   594             this.name_index = name_index;
   595             this.type_index = type_index;
   596         }
   598         public int getTag() {
   599             return CONSTANT_NameAndType;
   600         }
   602         public int byteLength() {
   603             return 5;
   604         }
   606         public String getName() throws ConstantPoolException {
   607             return cp.getUTF8Value(name_index);
   608         }
   610         public String getType() throws ConstantPoolException {
   611             return cp.getUTF8Value(type_index);
   612         }
   614         public <R, D> R accept(Visitor<R, D> visitor, D data) {
   615             return visitor.visitNameAndType(this, data);
   616         }
   618         @Override
   619         public String toString() {
   620             return "CONSTANT_NameAndType_info[name_index: " + name_index + ", type_index: " + type_index + "]";
   621         }
   623         public final int name_index;
   624         public final int type_index;
   625     }
   627     public static class CONSTANT_String_info extends CPInfo {
   628         CONSTANT_String_info(ConstantPool cp, ClassReader cr) throws IOException {
   629             super(cp);
   630             string_index = cr.readUnsignedShort();
   631         }
   633         public CONSTANT_String_info(ConstantPool cp, int string_index) {
   634             super(cp);
   635             this.string_index = string_index;
   636         }
   638         public int getTag() {
   639             return CONSTANT_String;
   640         }
   642         public int byteLength() {
   643             return 3;
   644         }
   646         public String getString() throws ConstantPoolException {
   647             return cp.getUTF8Value(string_index);
   648         }
   650         public <R, D> R accept(Visitor<R, D> visitor, D data) {
   651             return visitor.visitString(this, data);
   652         }
   654         @Override
   655         public String toString() {
   656             return "CONSTANT_String_info[class_index: " + string_index + "]";
   657         }
   659         public final int string_index;
   660     }
   662     public static class CONSTANT_Utf8_info extends CPInfo {
   663         CONSTANT_Utf8_info(ClassReader cr) throws IOException {
   664             value = cr.readUTF();
   665         }
   667         public CONSTANT_Utf8_info(String value) {
   668             this.value = value;
   669         }
   671         public int getTag() {
   672             return CONSTANT_Utf8;
   673         }
   675         public int byteLength() {
   676             class SizeOutputStream extends OutputStream {
   677                 @Override
   678                 public void write(int b) throws IOException {
   679                     size++;
   680                 }
   681                 int size;
   682             }
   683             SizeOutputStream sizeOut = new SizeOutputStream();
   684             DataOutputStream out = new DataOutputStream(sizeOut);
   685             try { out.writeUTF(value); } catch (IOException ignore) { }
   686             return 1 + sizeOut.size;
   687         }
   689         @Override
   690         public String toString() {
   691             if (value.length() < 32 && isPrintableAscii(value))
   692                 return "CONSTANT_Utf8_info[value: \"" + value + "\"]";
   693             else
   694                 return "CONSTANT_Utf8_info[value: (" + value.length() + " chars)]";
   695         }
   697         static boolean isPrintableAscii(String s) {
   698             for (int i = 0; i < s.length(); i++) {
   699                 char c = s.charAt(i);
   700                 if (c < 32 || c >= 127)
   701                     return false;
   702             }
   703             return true;
   704         }
   706         public <R, D> R accept(Visitor<R, D> visitor, D data) {
   707             return visitor.visitUtf8(this, data);
   708         }
   710         public final String value;
   711     }
   714 }

mercurial