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