| /* |
| * 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.Kinds; |
| 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.*; |
| |
| /** 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); |
| } |
| 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); |
| } |
| 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 |
| public boolean equals(Object any) { |
| if (!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 |
| public int hashCode() { |
| int hash = super.hashCode(); |
| 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 Variable extends DelegatedSymbol<VarSymbol> { |
| UniqueType uniqueType; |
| Variable(VarSymbol v, Types types) { |
| super(v); |
| this.uniqueType = new UniqueType(v.type, types); |
| } |
| 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); |
| } |
| 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; |
| int expectedKind = -1; |
| 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 = Kinds.VAR; |
| break; |
| case ClassFile.REF_newInvokeSpecial: |
| nameFilter = initFilter; |
| expectedKind = Kinds.MTH; |
| break; |
| case ClassFile.REF_invokeInterface: |
| interfaceOwner = true; |
| expectedKind = Kinds.MTH; |
| break; |
| case ClassFile.REF_invokeStatic: |
| interfaceOwner = true; |
| staticOk = true; |
| case ClassFile.REF_invokeVirtual: |
| expectedKind = Kinds.MTH; |
| break; |
| case ClassFile.REF_invokeSpecial: |
| interfaceOwner = true; |
| expectedKind = Kinds.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 = new Filter<Name>() { |
| public boolean accepts(Name n) { |
| return n != n.table.names.init && n != n.table.names.clinit; |
| } |
| }; |
| |
| Filter<Name> initFilter = new Filter<Name>() { |
| public boolean accepts(Name n) { |
| return n == n.table.names.init; |
| } |
| }; |
| } |
| } |