src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Pool.java
changeset 47216 71c04702a3d5
parent 42827 36468b5fa7f4
child 49577 faf02d65df7d
--- /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.
+ *
+ *  <p><b>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.</b>
+ */
+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<Object,Integer> 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<MethodSymbol> {
+        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<VarSymbol> {
+        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<Name> 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<Name> nonInitFilter = n -> (n != n.table.names.init && n != n.table.names.clinit);
+
+                Filter<Name> initFilter = n -> n == n.table.names.init;
+    }
+}