Pool.java revision 2571:10fc81ac75b4
1/* 2 * Copyright (c) 1999, 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 26package com.sun.tools.javac.jvm; 27 28import com.sun.tools.javac.code.Kinds; 29import com.sun.tools.javac.code.Symbol; 30import com.sun.tools.javac.code.Symbol.*; 31import com.sun.tools.javac.code.TypeTag; 32import com.sun.tools.javac.code.Type; 33import com.sun.tools.javac.code.Types; 34import com.sun.tools.javac.code.Types.UniqueType; 35 36import com.sun.tools.javac.util.ArrayUtils; 37import com.sun.tools.javac.util.Assert; 38import com.sun.tools.javac.util.Filter; 39import com.sun.tools.javac.util.Name; 40 41import java.util.*; 42 43/** An internal structure that corresponds to the constant pool of a classfile. 44 * 45 * <p><b>This is NOT part of any supported API. 46 * If you write code that depends on this, you do so at your own risk. 47 * This code and its internal interfaces are subject to change or 48 * deletion without notice.</b> 49 */ 50public class Pool { 51 52 public static final int MAX_ENTRIES = 0xFFFF; 53 public static final int MAX_STRING_LENGTH = 0xFFFF; 54 55 /** Index of next constant to be entered. 56 */ 57 int pp; 58 59 /** The initial pool buffer. 60 */ 61 Object[] pool; 62 63 /** A hashtable containing all constants in the pool. 64 */ 65 Map<Object,Integer> indices; 66 67 Types types; 68 69 /** Construct a pool with given number of elements and element array. 70 */ 71 public Pool(int pp, Object[] pool, Types types) { 72 this.pp = pp; 73 this.pool = pool; 74 this.types = types; 75 this.indices = new HashMap<>(pool.length); 76 for (int i = 1; i < pp; i++) { 77 if (pool[i] != null) indices.put(pool[i], i); 78 } 79 } 80 81 /** Construct an empty pool. 82 */ 83 public Pool(Types types) { 84 this(1, new Object[64], types); 85 } 86 87 /** Return the number of entries in the constant pool. 88 */ 89 public int numEntries() { 90 return pp; 91 } 92 93 /** Remove everything from this pool. 94 */ 95 public void reset() { 96 pp = 1; 97 indices.clear(); 98 } 99 100 /** Place an object in the pool, unless it is already there. 101 * If object is a symbol also enter its owner unless the owner is a 102 * package. Return the object's index in the pool. 103 */ 104 public int put(Object value) { 105 value = makePoolValue(value); 106 Assert.check(!(value instanceof Type.TypeVar)); 107 Assert.check(!(value instanceof Types.UniqueType && 108 ((UniqueType) value).type instanceof Type.TypeVar)); 109 Integer index = indices.get(value); 110 if (index == null) { 111 index = pp; 112 indices.put(value, index); 113 pool = ArrayUtils.ensureCapacity(pool, pp); 114 pool[pp++] = value; 115 if (value instanceof Long || value instanceof Double) { 116 pool = ArrayUtils.ensureCapacity(pool, pp); 117 pool[pp++] = null; 118 } 119 } 120 return index.intValue(); 121 } 122 123 Object makePoolValue(Object o) { 124 if (o instanceof DynamicMethodSymbol) { 125 return new DynamicMethod((DynamicMethodSymbol)o, types); 126 } else if (o instanceof MethodSymbol) { 127 return new Method((MethodSymbol)o, types); 128 } else if (o instanceof VarSymbol) { 129 return new Variable((VarSymbol)o, types); 130 } else if (o instanceof Type) { 131 Type t = (Type)o; 132 // ClassRefs can come from ClassSymbols or from Types. 133 // Return the symbol for these types to avoid duplicates 134 // in the constant pool 135 if (t.hasTag(TypeTag.CLASS)) 136 return t.tsym; 137 else 138 return new UniqueType(t, types); 139 } else { 140 return o; 141 } 142 } 143 144 /** Return the given object's index in the pool, 145 * or -1 if object is not in there. 146 */ 147 public int get(Object o) { 148 Integer n = indices.get(o); 149 return n == null ? -1 : n.intValue(); 150 } 151 152 static class Method extends DelegatedSymbol<MethodSymbol> { 153 UniqueType uniqueType; 154 Method(MethodSymbol m, Types types) { 155 super(m); 156 this.uniqueType = new UniqueType(m.type, types); 157 } 158 public boolean equals(Object any) { 159 if (!(any instanceof Method)) return false; 160 MethodSymbol o = ((Method)any).other; 161 MethodSymbol m = this.other; 162 return 163 o.name == m.name && 164 o.owner == m.owner && 165 ((Method)any).uniqueType.equals(uniqueType); 166 } 167 public int hashCode() { 168 MethodSymbol m = this.other; 169 return 170 m.name.hashCode() * 33 + 171 m.owner.hashCode() * 9 + 172 uniqueType.hashCode(); 173 } 174 } 175 176 static class DynamicMethod extends Method { 177 public Object[] uniqueStaticArgs; 178 179 DynamicMethod(DynamicMethodSymbol m, Types types) { 180 super(m, types); 181 uniqueStaticArgs = getUniqueTypeArray(m.staticArgs, types); 182 } 183 184 @Override 185 public boolean equals(Object any) { 186 if (!super.equals(any)) return false; 187 if (!(any instanceof DynamicMethod)) return false; 188 DynamicMethodSymbol dm1 = (DynamicMethodSymbol)other; 189 DynamicMethodSymbol dm2 = (DynamicMethodSymbol)((DynamicMethod)any).other; 190 return dm1.bsm == dm2.bsm && 191 dm1.bsmKind == dm2.bsmKind && 192 Arrays.equals(uniqueStaticArgs, 193 ((DynamicMethod)any).uniqueStaticArgs); 194 } 195 196 @Override 197 public int hashCode() { 198 int hash = super.hashCode(); 199 DynamicMethodSymbol dm = (DynamicMethodSymbol)other; 200 hash += dm.bsmKind * 7 + 201 dm.bsm.hashCode() * 11; 202 for (int i = 0; i < dm.staticArgs.length; i++) { 203 hash += (uniqueStaticArgs[i].hashCode() * 23); 204 } 205 return hash; 206 } 207 208 private Object[] getUniqueTypeArray(Object[] objects, Types types) { 209 Object[] result = new Object[objects.length]; 210 for (int i = 0; i < objects.length; i++) { 211 if (objects[i] instanceof Type) { 212 result[i] = new UniqueType((Type)objects[i], types); 213 } else { 214 result[i] = objects[i]; 215 } 216 } 217 return result; 218 } 219 } 220 221 static class Variable extends DelegatedSymbol<VarSymbol> { 222 UniqueType uniqueType; 223 Variable(VarSymbol v, Types types) { 224 super(v); 225 this.uniqueType = new UniqueType(v.type, types); 226 } 227 public boolean equals(Object any) { 228 if (!(any instanceof Variable)) return false; 229 VarSymbol o = ((Variable)any).other; 230 VarSymbol v = other; 231 return 232 o.name == v.name && 233 o.owner == v.owner && 234 ((Variable)any).uniqueType.equals(uniqueType); 235 } 236 public int hashCode() { 237 VarSymbol v = other; 238 return 239 v.name.hashCode() * 33 + 240 v.owner.hashCode() * 9 + 241 uniqueType.hashCode(); 242 } 243 } 244 245 public static class MethodHandle { 246 247 /** Reference kind - see ClassFile */ 248 int refKind; 249 250 /** Reference symbol */ 251 Symbol refSym; 252 253 UniqueType uniqueType; 254 255 public MethodHandle(int refKind, Symbol refSym, Types types) { 256 this.refKind = refKind; 257 this.refSym = refSym; 258 this.uniqueType = new UniqueType(this.refSym.type, types); 259 checkConsistent(); 260 } 261 public boolean equals(Object other) { 262 if (!(other instanceof MethodHandle)) return false; 263 MethodHandle mr = (MethodHandle) other; 264 if (mr.refKind != refKind) return false; 265 Symbol o = mr.refSym; 266 return 267 o.name == refSym.name && 268 o.owner == refSym.owner && 269 ((MethodHandle)other).uniqueType.equals(uniqueType); 270 } 271 public int hashCode() { 272 return 273 refKind * 65 + 274 refSym.name.hashCode() * 33 + 275 refSym.owner.hashCode() * 9 + 276 uniqueType.hashCode(); 277 } 278 279 /** 280 * Check consistency of reference kind and symbol (see JVMS 4.4.8) 281 */ 282 @SuppressWarnings("fallthrough") 283 private void checkConsistent() { 284 boolean staticOk = false; 285 int expectedKind = -1; 286 Filter<Name> nameFilter = nonInitFilter; 287 boolean interfaceOwner = false; 288 switch (refKind) { 289 case ClassFile.REF_getStatic: 290 case ClassFile.REF_putStatic: 291 staticOk = true; 292 case ClassFile.REF_getField: 293 case ClassFile.REF_putField: 294 expectedKind = Kinds.VAR; 295 break; 296 case ClassFile.REF_newInvokeSpecial: 297 nameFilter = initFilter; 298 expectedKind = Kinds.MTH; 299 break; 300 case ClassFile.REF_invokeInterface: 301 interfaceOwner = true; 302 expectedKind = Kinds.MTH; 303 break; 304 case ClassFile.REF_invokeStatic: 305 interfaceOwner = true; 306 staticOk = true; 307 case ClassFile.REF_invokeVirtual: 308 expectedKind = Kinds.MTH; 309 break; 310 case ClassFile.REF_invokeSpecial: 311 interfaceOwner = true; 312 expectedKind = Kinds.MTH; 313 break; 314 } 315 Assert.check(!refSym.isStatic() || staticOk); 316 Assert.check(refSym.kind == expectedKind); 317 Assert.check(nameFilter.accepts(refSym.name)); 318 Assert.check(!refSym.owner.isInterface() || interfaceOwner); 319 } 320 //where 321 Filter<Name> nonInitFilter = new Filter<Name>() { 322 public boolean accepts(Name n) { 323 return n != n.table.names.init && n != n.table.names.clinit; 324 } 325 }; 326 327 Filter<Name> initFilter = new Filter<Name>() { 328 public boolean accepts(Name n) { 329 return n == n.table.names.init; 330 } 331 }; 332 } 333} 334