/*
* 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.
/** 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.
/** Index of next constant to be entered.
*/
int pp;
The initial pool buffer.
/** The initial pool buffer.
*/
Object[] pool;
A hashtable containing all constants in the 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.
/** 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.
/** Construct an empty pool.
*/
public Pool(Types types) {
this(1, new Object[64], types);
}
Return the number of entries in the constant pool.
/** Return the number of entries in the constant pool.
*/
public int numEntries() {
return pp;
}
Remove everything from this pool.
/** 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.
/** 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.
/** 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 /** Reference kind - see ClassFile */
int refKind;
Reference symbol /** 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)
/**
* 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;
}
}