1 /*
   2  * Copyright (c) 1994, 2013, 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 sun.tools.java;
  27 
  28 import java.io.IOException;
  29 import java.io.DataInputStream;
  30 import java.io.DataOutputStream;
  31 import java.util.Vector;
  32 import java.util.Hashtable;
  33 
  34 /**
  35  * This class is used to represent a constant table once
  36  * it is read from a class file.
  37  *
  38  * WARNING: The contents of this source file are not part of any
  39  * supported API.  Code that depends on them does so at its own risk:
  40  * they are subject to change or removal without notice.
  41  */
  42 public final
  43 class BinaryConstantPool implements Constants {
  44     private byte types[];
  45     private Object cpool[];
  46 
  47     /**
  48      * Constructor
  49      */
  50     BinaryConstantPool(DataInputStream in) throws IOException {
  51         // JVM 4.1 ClassFile.constant_pool_count
  52         types = new byte[in.readUnsignedShort()];
  53         cpool = new Object[types.length];
  54         for (int i = 1 ; i < cpool.length ; i++) {
  55             int j = i;
  56             // JVM 4.4 cp_info.tag
  57             switch(types[i] = in.readByte()) {
  58               case CONSTANT_UTF8:
  59                 cpool[i] = in.readUTF();
  60                 break;
  61 
  62               case CONSTANT_INTEGER:
  63                 cpool[i] = new Integer(in.readInt());
  64                 break;
  65               case CONSTANT_FLOAT:
  66                 cpool[i] = new Float(in.readFloat());
  67                 break;
  68               case CONSTANT_LONG:
  69                 cpool[i++] = in.readLong();
  70                 break;
  71               case CONSTANT_DOUBLE:
  72                 cpool[i++] = new Double(in.readDouble());
  73                 break;
  74 
  75               case CONSTANT_CLASS:
  76               case CONSTANT_STRING:
  77                 // JVM 4.4.3 CONSTANT_String_info.string_index
  78                 // or JVM 4.4.1 CONSTANT_Class_info.name_index
  79                 cpool[i] = new Integer(in.readUnsignedShort());
  80                 break;
  81 
  82               case CONSTANT_FIELD:
  83               case CONSTANT_METHOD:
  84               case CONSTANT_INTERFACEMETHOD:
  85               case CONSTANT_NAMEANDTYPE:
  86                 // JVM 4.4.2 CONSTANT_*ref_info.class_index & name_and_type_index
  87                 cpool[i] = new Integer((in.readUnsignedShort() << 16) | in.readUnsignedShort());
  88                 break;
  89 
  90               case CONSTANT_METHODHANDLE:
  91                 cpool[i] = readBytes(in, 3);
  92                 break;
  93               case CONSTANT_METHODTYPE:
  94                 cpool[i] = readBytes(in, 2);
  95                 break;
  96               case CONSTANT_INVOKEDYNAMIC:
  97                 cpool[i] = readBytes(in, 4);
  98                 break;
  99 
 100               case 0:
 101               default:
 102                 throw new ClassFormatError("invalid constant type: " + (int)types[i]);
 103             }
 104         }
 105     }
 106 
 107     private byte[] readBytes(DataInputStream in, int cnt) throws IOException {
 108         byte[] b = new byte[cnt];
 109         in.readFully(b);
 110         return b;
 111     }
 112 
 113     /**
 114      * get a integer
 115      */
 116     public int getInteger(int n) {
 117         return (n == 0) ? 0 : ((Number)cpool[n]).intValue();
 118     }
 119 
 120     /**
 121      * get a value
 122      */
 123     public Object getValue(int n) {
 124         return (n == 0) ? null : cpool[n];
 125     }
 126 
 127     /**
 128      * get a string
 129      */
 130     public String getString(int n) {
 131         return (n == 0) ? null : (String)cpool[n];
 132     }
 133 
 134     /**
 135      * get an identifier
 136      */
 137     public Identifier getIdentifier(int n) {
 138         return (n == 0) ? null : Identifier.lookup(getString(n));
 139     }
 140 
 141     /**
 142      * get class declaration
 143      */
 144     public ClassDeclaration getDeclarationFromName(Environment env, int n) {
 145         return (n == 0) ? null : env.getClassDeclaration(Identifier.lookup(getString(n).replace('/','.')));
 146     }
 147 
 148     /**
 149      * get class declaration
 150      */
 151     public ClassDeclaration getDeclaration(Environment env, int n) {
 152         return (n == 0) ? null : getDeclarationFromName(env, getInteger(n));
 153     }
 154 
 155     /**
 156      * get a type from a type signature
 157      */
 158     public Type getType(int n) {
 159         return Type.tType(getString(n));
 160     }
 161 
 162     /**
 163      * get the type of constant given an index
 164      */
 165     public int getConstantType(int n) {
 166         return types[n];
 167     }
 168 
 169     /**
 170      * get the n-th constant from the constant pool
 171      */
 172     public Object getConstant(int n, Environment env) {
 173         int constant_type = getConstantType(n);
 174         switch (constant_type) {
 175             case CONSTANT_INTEGER:
 176             case CONSTANT_FLOAT:
 177             case CONSTANT_LONG:
 178             case CONSTANT_DOUBLE:
 179             case CONSTANT_METHODHANDLE:
 180             case CONSTANT_METHODTYPE:
 181             case CONSTANT_INVOKEDYNAMIC:
 182                 return getValue(n);
 183 
 184             case CONSTANT_CLASS:
 185                 return getDeclaration(env, n);
 186 
 187             case CONSTANT_STRING:
 188                 return getString(getInteger(n));
 189 
 190             case CONSTANT_FIELD:
 191             case CONSTANT_METHOD:
 192             case CONSTANT_INTERFACEMETHOD:
 193                 try {
 194                     int key = getInteger(n);
 195                     ClassDefinition clazz =
 196                         getDeclaration(env, key >> 16).getClassDefinition(env);
 197                     int name_and_type = getInteger(key & 0xFFFF);
 198                     Identifier id = getIdentifier(name_and_type >> 16);
 199                     Type type = getType(name_and_type & 0xFFFF);
 200 
 201                     for (MemberDefinition field = clazz.getFirstMatch(id);
 202                          field != null;
 203                          field = field.getNextMatch()) {
 204                         Type field_type = field.getType();
 205                         if ((constant_type == CONSTANT_FIELD)
 206                             ? (field_type == type)
 207                             : (field_type.equalArguments(type)))
 208                             return field;
 209                     }
 210                 } catch (ClassNotFound e) {
 211                 }
 212                 return null;
 213 
 214             default:
 215                 throw new ClassFormatError("invalid constant type: " +
 216                                               constant_type);
 217         }
 218     }
 219 
 220 
 221     /**
 222      * Get a list of dependencies, ie: all the classes referenced in this
 223      * constant pool.
 224      */
 225     public Vector getDependencies(Environment env) {
 226         Vector v = new Vector();
 227         for (int i = 1 ; i < cpool.length ; i++) {
 228             switch(types[i]) {
 229               case CONSTANT_CLASS:
 230                 v.addElement(getDeclarationFromName(env, getInteger(i)));
 231                 break;
 232             }
 233         }
 234         return v;
 235     }
 236 
 237     Hashtable indexHashObject, indexHashAscii;
 238     Vector MoreStuff;
 239 
 240     /**
 241      * Find the index of an Object in the constant pool
 242      */
 243     public int indexObject(Object obj, Environment env) {
 244         if (indexHashObject == null)
 245             createIndexHash(env);
 246         Integer result = (Integer)indexHashObject.get(obj);
 247         if (result == null)
 248             throw new IndexOutOfBoundsException("Cannot find object " + obj + " of type " +
 249                                 obj.getClass() + " in constant pool");
 250         return result.intValue();
 251     }
 252 
 253     /**
 254      * Find the index of an ascii string in the constant pool.  If it's not in
 255      * the constant pool, then add it at the end.
 256      */
 257     public int indexString(String string, Environment env) {
 258         if (indexHashObject == null)
 259             createIndexHash(env);
 260         Integer result = (Integer)indexHashAscii.get(string);
 261         if (result == null) {
 262             if (MoreStuff == null) MoreStuff = new Vector();
 263             result = new Integer(cpool.length + MoreStuff.size());
 264             MoreStuff.addElement(string);
 265             indexHashAscii.put(string, result);
 266         }
 267         return result.intValue();
 268     }
 269 
 270     /**
 271      * Create a hash table of all the items in the constant pool that could
 272      * possibly be referenced from the outside.
 273      */
 274 
 275     public void createIndexHash(Environment env) {
 276         indexHashObject = new Hashtable();
 277         indexHashAscii = new Hashtable();
 278         for (int i = 1; i < cpool.length; i++) {
 279             if (types[i] == CONSTANT_UTF8) {
 280                 indexHashAscii.put(cpool[i], new Integer(i));
 281             } else {
 282                 try {
 283                     indexHashObject.put(getConstant(i, env), new Integer(i));
 284                 } catch (ClassFormatError e) { }
 285             }
 286         }
 287     }
 288 
 289 
 290     /**
 291      * Write out the contents of the constant pool, including any additions
 292      * that have been added.
 293      */
 294     public void write(DataOutputStream out, Environment env) throws IOException {
 295         int length = cpool.length;
 296         if (MoreStuff != null)
 297             length += MoreStuff.size();
 298         out.writeShort(length);
 299         for (int i = 1 ; i < cpool.length; i++) {
 300             int type = types[i];
 301             Object x = cpool[i];
 302             out.writeByte(type);
 303             switch (type) {
 304                 case CONSTANT_UTF8:
 305                     out.writeUTF((String) x);
 306                     break;
 307                 case CONSTANT_INTEGER:
 308                     out.writeInt(((Number)x).intValue());
 309                     break;
 310                 case CONSTANT_FLOAT:
 311                     out.writeFloat(((Number)x).floatValue());
 312                     break;
 313                 case CONSTANT_LONG:
 314                     out.writeLong(((Number)x).longValue());
 315                     i++;
 316                     break;
 317                 case CONSTANT_DOUBLE:
 318                     out.writeDouble(((Number)x).doubleValue());
 319                     i++;
 320                     break;
 321                 case CONSTANT_CLASS:
 322                 case CONSTANT_STRING:
 323                     out.writeShort(((Number)x).intValue());
 324                     break;
 325                 case CONSTANT_FIELD:
 326                 case CONSTANT_METHOD:
 327                 case CONSTANT_INTERFACEMETHOD:
 328                 case CONSTANT_NAMEANDTYPE: {
 329                     int value = ((Number)x).intValue();
 330                     out.writeShort(value >> 16);
 331                     out.writeShort(value & 0xFFFF);
 332                     break;
 333                 }
 334                 case CONSTANT_METHODHANDLE:
 335                 case CONSTANT_METHODTYPE:
 336                 case CONSTANT_INVOKEDYNAMIC:
 337                     out.write((byte[])x, 0, ((byte[])x).length);
 338                     break;
 339                 default:
 340                      throw new ClassFormatError("invalid constant type: "
 341                                                    + (int)types[i]);
 342             }
 343         }
 344         for (int i = cpool.length; i < length; i++) {
 345             String string = (String)(MoreStuff.elementAt(i - cpool.length));
 346             out.writeByte(CONSTANT_UTF8);
 347             out.writeUTF(string);
 348         }
 349     }
 350 
 351 }