Pool.java revision 3827:44bdefe64114
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 = n -> (n != n.table.names.init && n != n.table.names.clinit);
369
370                Filter<Name> initFilter = n -> n == n.table.names.init;
371    }
372}
373