diff -r 4ebc2e2fb97c -r 71c04702a3d5 src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Pool.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Pool.java Tue Sep 12 19:03:39 2017 +0200 @@ -0,0 +1,372 @@ +/* + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.tools.javac.jvm; + +import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.code.Symbol.*; +import com.sun.tools.javac.code.TypeTag; +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.code.Types; +import com.sun.tools.javac.code.Types.UniqueType; + +import com.sun.tools.javac.util.ArrayUtils; +import com.sun.tools.javac.util.Assert; +import com.sun.tools.javac.util.Filter; +import com.sun.tools.javac.util.Name; + +import java.util.*; + +import com.sun.tools.javac.util.DefinedBy; +import com.sun.tools.javac.util.DefinedBy.Api; + +import static com.sun.tools.javac.code.Kinds.*; +import static com.sun.tools.javac.code.Kinds.Kind.*; + +/** An internal structure that corresponds to the constant pool of a classfile. + * + *

This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + */ +public class Pool { + + public static final int MAX_ENTRIES = 0xFFFF; + public static final int MAX_STRING_LENGTH = 0xFFFF; + + /** Index of next constant to be entered. + */ + int pp; + + /** The initial pool buffer. + */ + Object[] pool; + + /** A hashtable containing all constants in the pool. + */ + Map indices; + + Types types; + + /** Construct a pool with given number of elements and element array. + */ + public Pool(int pp, Object[] pool, Types types) { + this.pp = pp; + this.pool = pool; + this.types = types; + this.indices = new HashMap<>(pool.length); + for (int i = 1; i < pp; i++) { + if (pool[i] != null) indices.put(pool[i], i); + } + } + + /** Construct an empty pool. + */ + public Pool(Types types) { + this(1, new Object[64], types); + } + + /** Return the number of entries in the constant pool. + */ + public int numEntries() { + return pp; + } + + /** Remove everything from this pool. + */ + public void reset() { + pp = 1; + indices.clear(); + } + + /** Place an object in the pool, unless it is already there. + * If object is a symbol also enter its owner unless the owner is a + * package. Return the object's index in the pool. + */ + public int put(Object value) { + value = makePoolValue(value); + Assert.check(!(value instanceof Type.TypeVar)); + Assert.check(!(value instanceof Types.UniqueType && + ((UniqueType) value).type instanceof Type.TypeVar)); + Integer index = indices.get(value); + if (index == null) { + index = pp; + indices.put(value, index); + pool = ArrayUtils.ensureCapacity(pool, pp); + pool[pp++] = value; + if (value instanceof Long || value instanceof Double) { + pool = ArrayUtils.ensureCapacity(pool, pp); + pool[pp++] = null; + } + } + return index.intValue(); + } + + Object makePoolValue(Object o) { + if (o instanceof DynamicMethodSymbol) { + return new DynamicMethod((DynamicMethodSymbol)o, types); + } else if (o instanceof MethodSymbol) { + return new Method((MethodSymbol)o, types); + } else if (o instanceof VarSymbol) { + return new Variable((VarSymbol)o, types); + } else if (o instanceof Type) { + Type t = (Type)o; + // ClassRefs can come from ClassSymbols or from Types. + // Return the symbol for these types to avoid duplicates + // in the constant pool + if (t.hasTag(TypeTag.CLASS)) + return t.tsym; + else + return new UniqueType(t, types); + } else { + return o; + } + } + + /** Return the given object's index in the pool, + * or -1 if object is not in there. + */ + public int get(Object o) { + Integer n = indices.get(o); + return n == null ? -1 : n.intValue(); + } + + static class Method extends DelegatedSymbol { + UniqueType uniqueType; + Method(MethodSymbol m, Types types) { + super(m); + this.uniqueType = new UniqueType(m.type, types); + } + @DefinedBy(Api.LANGUAGE_MODEL) + public boolean equals(Object any) { + if (!(any instanceof Method)) return false; + MethodSymbol o = ((Method)any).other; + MethodSymbol m = this.other; + return + o.name == m.name && + o.owner == m.owner && + ((Method)any).uniqueType.equals(uniqueType); + } + @DefinedBy(Api.LANGUAGE_MODEL) + public int hashCode() { + MethodSymbol m = this.other; + return + m.name.hashCode() * 33 + + m.owner.hashCode() * 9 + + uniqueType.hashCode(); + } + } + + static class DynamicMethod extends Method { + public Object[] uniqueStaticArgs; + + DynamicMethod(DynamicMethodSymbol m, Types types) { + super(m, types); + uniqueStaticArgs = getUniqueTypeArray(m.staticArgs, types); + } + + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public boolean equals(Object any) { + return equalsImpl(any, true); + } + + protected boolean equalsImpl(Object any, boolean includeDynamicArgs) { + if (includeDynamicArgs && !super.equals(any)) return false; + if (!(any instanceof DynamicMethod)) return false; + DynamicMethodSymbol dm1 = (DynamicMethodSymbol)other; + DynamicMethodSymbol dm2 = (DynamicMethodSymbol)((DynamicMethod)any).other; + return dm1.bsm == dm2.bsm && + dm1.bsmKind == dm2.bsmKind && + Arrays.equals(uniqueStaticArgs, + ((DynamicMethod)any).uniqueStaticArgs); + } + + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public int hashCode() { + return hashCodeImpl(true); + } + + protected int hashCodeImpl(boolean includeDynamicArgs) { + int hash = includeDynamicArgs ? super.hashCode() : 0; + DynamicMethodSymbol dm = (DynamicMethodSymbol)other; + hash += dm.bsmKind * 7 + + dm.bsm.hashCode() * 11; + for (int i = 0; i < dm.staticArgs.length; i++) { + hash += (uniqueStaticArgs[i].hashCode() * 23); + } + return hash; + } + + private Object[] getUniqueTypeArray(Object[] objects, Types types) { + Object[] result = new Object[objects.length]; + for (int i = 0; i < objects.length; i++) { + if (objects[i] instanceof Type) { + result[i] = new UniqueType((Type)objects[i], types); + } else { + result[i] = objects[i]; + } + } + return result; + } + + static class BootstrapMethodsKey extends DynamicMethod { + BootstrapMethodsKey(DynamicMethodSymbol m, Types types) { + super(m, types); + } + + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public boolean equals(Object any) { + return equalsImpl(any, false); + } + + @Override @DefinedBy(Api.LANGUAGE_MODEL) + public int hashCode() { + return hashCodeImpl(false); + } + + Object[] getUniqueArgs() { + return uniqueStaticArgs; + } + } + + static class BootstrapMethodsValue { + final MethodHandle mh; + final int index; + + public BootstrapMethodsValue(MethodHandle mh, int index) { + this.mh = mh; + this.index = index; + } + } + } + + static class Variable extends DelegatedSymbol { + UniqueType uniqueType; + Variable(VarSymbol v, Types types) { + super(v); + this.uniqueType = new UniqueType(v.type, types); + } + @DefinedBy(Api.LANGUAGE_MODEL) + public boolean equals(Object any) { + if (!(any instanceof Variable)) return false; + VarSymbol o = ((Variable)any).other; + VarSymbol v = other; + return + o.name == v.name && + o.owner == v.owner && + ((Variable)any).uniqueType.equals(uniqueType); + } + @DefinedBy(Api.LANGUAGE_MODEL) + public int hashCode() { + VarSymbol v = other; + return + v.name.hashCode() * 33 + + v.owner.hashCode() * 9 + + uniqueType.hashCode(); + } + } + + public static class MethodHandle { + + /** Reference kind - see ClassFile */ + int refKind; + + /** Reference symbol */ + Symbol refSym; + + UniqueType uniqueType; + + public MethodHandle(int refKind, Symbol refSym, Types types) { + this.refKind = refKind; + this.refSym = refSym; + this.uniqueType = new UniqueType(this.refSym.type, types); + checkConsistent(); + } + public boolean equals(Object other) { + if (!(other instanceof MethodHandle)) return false; + MethodHandle mr = (MethodHandle) other; + if (mr.refKind != refKind) return false; + Symbol o = mr.refSym; + return + o.name == refSym.name && + o.owner == refSym.owner && + ((MethodHandle)other).uniqueType.equals(uniqueType); + } + public int hashCode() { + return + refKind * 65 + + refSym.name.hashCode() * 33 + + refSym.owner.hashCode() * 9 + + uniqueType.hashCode(); + } + + /** + * Check consistency of reference kind and symbol (see JVMS 4.4.8) + */ + @SuppressWarnings("fallthrough") + private void checkConsistent() { + boolean staticOk = false; + Kind expectedKind = null; + Filter nameFilter = nonInitFilter; + boolean interfaceOwner = false; + switch (refKind) { + case ClassFile.REF_getStatic: + case ClassFile.REF_putStatic: + staticOk = true; + case ClassFile.REF_getField: + case ClassFile.REF_putField: + expectedKind = VAR; + break; + case ClassFile.REF_newInvokeSpecial: + nameFilter = initFilter; + expectedKind = MTH; + break; + case ClassFile.REF_invokeInterface: + interfaceOwner = true; + expectedKind = MTH; + break; + case ClassFile.REF_invokeStatic: + interfaceOwner = true; + staticOk = true; + case ClassFile.REF_invokeVirtual: + expectedKind = MTH; + break; + case ClassFile.REF_invokeSpecial: + interfaceOwner = true; + expectedKind = MTH; + break; + } + Assert.check(!refSym.isStatic() || staticOk); + Assert.check(refSym.kind == expectedKind); + Assert.check(nameFilter.accepts(refSym.name)); + Assert.check(!refSym.owner.isInterface() || interfaceOwner); + } + //where + Filter nonInitFilter = n -> (n != n.table.names.init && n != n.table.names.clinit); + + Filter initFilter = n -> n == n.table.names.init; + } +}