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 }