提交 c2204994 编写于 作者: P plevart

8131129: Attempt to define a duplicate BMH$Species class

Reviewed-by: mhaupt, redestad, vlivanov
上级 2deb6469
...@@ -34,14 +34,16 @@ import java.lang.invoke.LambdaForm.NamedFunction; ...@@ -34,14 +34,16 @@ import java.lang.invoke.LambdaForm.NamedFunction;
import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.function.Function;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentHashMap;
import jdk.internal.org.objectweb.asm.FieldVisitor;
import sun.invoke.util.ValueConversions; import sun.invoke.util.ValueConversions;
import sun.invoke.util.Wrapper; import sun.invoke.util.Wrapper;
import jdk.internal.org.objectweb.asm.ClassWriter; import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Type;
/** /**
* The flavor of method handle which emulates an invoke instruction * The flavor of method handle which emulates an invoke instruction
...@@ -217,7 +219,7 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -217,7 +219,7 @@ import jdk.internal.org.objectweb.asm.Type;
/*non-public*/ int fieldCount() { /*non-public*/ int fieldCount() {
return 1; return 1;
} }
/*non-public*/ static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("L", Species_L.class); /*non-public*/ static final SpeciesData SPECIES_DATA = new SpeciesData("L", Species_L.class);
/*non-public*/ static BoundMethodHandle make(MethodType mt, LambdaForm lf, Object argL0) { /*non-public*/ static BoundMethodHandle make(MethodType mt, LambdaForm lf, Object argL0) {
return new Species_L(mt, lf, argL0); return new Species_L(mt, lf, argL0);
} }
...@@ -335,7 +337,7 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -335,7 +337,7 @@ import jdk.internal.org.objectweb.asm.Type;
static final SpeciesData EMPTY = new SpeciesData("", BoundMethodHandle.class); static final SpeciesData EMPTY = new SpeciesData("", BoundMethodHandle.class);
private SpeciesData(String types, Class<? extends BoundMethodHandle> clazz) { SpeciesData(String types, Class<? extends BoundMethodHandle> clazz) {
this.typeChars = types; this.typeChars = types;
this.typeCodes = basicTypes(types); this.typeCodes = basicTypes(types);
this.clazz = clazz; this.clazz = clazz;
...@@ -355,26 +357,14 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -355,26 +357,14 @@ import jdk.internal.org.objectweb.asm.Type;
assert(!INIT_DONE); assert(!INIT_DONE);
if (constructor() == null) { if (constructor() == null) {
String types = typeChars; String types = typeChars;
CACHE.put(types, this);
Factory.makeCtors(clazz, types, this.constructor); Factory.makeCtors(clazz, types, this.constructor);
Factory.makeGetters(clazz, types, this.getters); Factory.makeGetters(clazz, types, this.getters);
Factory.makeNominalGetters(types, this.nominalGetters, this.getters); Factory.makeNominalGetters(types, this.nominalGetters, this.getters);
} }
} }
private SpeciesData(String typeChars) { private static final ConcurrentMap<String, SpeciesData> CACHE = new ConcurrentHashMap<>();
// Placeholder only.
this.typeChars = typeChars;
this.typeCodes = basicTypes(typeChars);
this.clazz = null;
this.constructor = null;
this.getters = null;
this.nominalGetters = null;
this.extensions = null;
}
private boolean isPlaceholder() { return clazz == null; }
private static final HashMap<String, SpeciesData> CACHE = new HashMap<>();
static { CACHE.put("", EMPTY); } // make bootstrap predictable
private static final boolean INIT_DONE; // set after <clinit> finishes... private static final boolean INIT_DONE; // set after <clinit> finishes...
SpeciesData extendWith(byte type) { SpeciesData extendWith(byte type) {
...@@ -390,62 +380,52 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -390,62 +380,52 @@ import jdk.internal.org.objectweb.asm.Type;
} }
private static SpeciesData get(String types) { private static SpeciesData get(String types) {
// Acquire cache lock for query. return CACHE.computeIfAbsent(types, new Function<String, SpeciesData>() {
SpeciesData d = lookupCache(types); @Override
if (!d.isPlaceholder()) public SpeciesData apply(String types) {
return d; Class<? extends BoundMethodHandle> bmhcl = Factory.getConcreteBMHClass(types);
synchronized (d) { // SpeciesData instantiation may throw VirtualMachineError because of
// Use synch. on the placeholder to prevent multiple instantiation of one species. // code cache overflow...
// Creating this class forces a recursive call to getForClass. SpeciesData speciesData = new SpeciesData(types, bmhcl);
if (lookupCache(types).isPlaceholder()) // CHM.computeIfAbsent ensures only one SpeciesData will be set
Factory.generateConcreteBMHClass(types); // successfully on the concrete BMH class if ever
} Factory.setSpeciesDataToConcreteBMHClass(bmhcl, speciesData);
// Reacquire cache lock. // the concrete BMH class is published via SpeciesData instance
d = lookupCache(types); // returned here only after it's SPECIES_DATA field is set
// Class loading must have upgraded the cache. return speciesData;
assert(d != null && !d.isPlaceholder());
return d;
}
static SpeciesData getForClass(String types, Class<? extends BoundMethodHandle> clazz) {
// clazz is a new class which is initializing its SPECIES_DATA field
return updateCache(types, new SpeciesData(types, clazz));
}
private static synchronized SpeciesData lookupCache(String types) {
SpeciesData d = CACHE.get(types);
if (d != null) return d;
d = new SpeciesData(types);
assert(d.isPlaceholder());
CACHE.put(types, d);
return d;
} }
private static synchronized SpeciesData updateCache(String types, SpeciesData d) { });
SpeciesData d2;
assert((d2 = CACHE.get(types)) == null || d2.isPlaceholder());
assert(!d.isPlaceholder());
CACHE.put(types, d);
return d;
} }
static { /**
// pre-fill the BMH speciesdata cache with BMH's inner classes * This is to be called when assertions are enabled. It checks whether SpeciesData for all of the statically
final Class<BoundMethodHandle> rootCls = BoundMethodHandle.class; * defined species subclasses of BoundMethodHandle has been added to the SpeciesData cache. See below in the
* static initializer for
*/
static boolean speciesDataCachePopulated() {
Class<BoundMethodHandle> rootCls = BoundMethodHandle.class;
try { try {
for (Class<?> c : rootCls.getDeclaredClasses()) { for (Class<?> c : rootCls.getDeclaredClasses()) {
if (rootCls.isAssignableFrom(c)) { if (rootCls.isAssignableFrom(c)) {
final Class<? extends BoundMethodHandle> cbmh = c.asSubclass(BoundMethodHandle.class); final Class<? extends BoundMethodHandle> cbmh = c.asSubclass(BoundMethodHandle.class);
SpeciesData d = Factory.speciesDataFromConcreteBMHClass(cbmh); SpeciesData d = Factory.getSpeciesDataFromConcreteBMHClass(cbmh);
assert(d != null) : cbmh.getName(); assert(d != null) : cbmh.getName();
assert(d.clazz == cbmh); assert(d.clazz == cbmh);
assert(d == lookupCache(d.typeChars)); assert(CACHE.get(d.typeChars) == d);
} }
} }
} catch (Throwable e) { } catch (Throwable e) {
throw newInternalError(e); throw newInternalError(e);
} }
return true;
for (SpeciesData d : CACHE.values()) {
d.initForBootstrap();
} }
static {
// Pre-fill the BMH species-data cache with EMPTY and all BMH's inner subclasses.
EMPTY.initForBootstrap();
Species_L.SPECIES_DATA.initForBootstrap();
// check that all static SpeciesData instances have been initialized
assert speciesDataCachePopulated();
// Note: Do not simplify this, because INIT_DONE must not be // Note: Do not simplify this, because INIT_DONE must not be
// a compile-time constant during bootstrapping. // a compile-time constant during bootstrapping.
INIT_DONE = Boolean.TRUE; INIT_DONE = Boolean.TRUE;
...@@ -479,6 +459,7 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -479,6 +459,7 @@ import jdk.internal.org.objectweb.asm.Type;
static final String BMH_SIG = "L"+BMH+";"; static final String BMH_SIG = "L"+BMH+";";
static final String SPECIES_DATA = "java/lang/invoke/BoundMethodHandle$SpeciesData"; static final String SPECIES_DATA = "java/lang/invoke/BoundMethodHandle$SpeciesData";
static final String SPECIES_DATA_SIG = "L"+SPECIES_DATA+";"; static final String SPECIES_DATA_SIG = "L"+SPECIES_DATA+";";
static final String STABLE_SIG = "Ljava/lang/invoke/Stable;";
static final String SPECIES_PREFIX_NAME = "Species_"; static final String SPECIES_PREFIX_NAME = "Species_";
static final String SPECIES_PREFIX_PATH = BMH + "$" + SPECIES_PREFIX_NAME; static final String SPECIES_PREFIX_PATH = BMH + "$" + SPECIES_PREFIX_NAME;
...@@ -493,6 +474,26 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -493,6 +474,26 @@ import jdk.internal.org.objectweb.asm.Type;
static final String[] E_THROWABLE = new String[] { "java/lang/Throwable" }; static final String[] E_THROWABLE = new String[] { "java/lang/Throwable" };
static final ConcurrentMap<String, Class<? extends BoundMethodHandle>> CLASS_CACHE = new ConcurrentHashMap<>();
/**
* Get a concrete subclass of BMH for a given combination of bound types.
*
* @param types the type signature, wherein reference types are erased to 'L'
* @return the concrete BMH class
*/
static Class<? extends BoundMethodHandle> getConcreteBMHClass(String types) {
// CHM.computeIfAbsent ensures generateConcreteBMHClass is called
// only once per key.
return CLASS_CACHE.computeIfAbsent(
types, new Function<String, Class<? extends BoundMethodHandle>>() {
@Override
public Class<? extends BoundMethodHandle> apply(String types) {
return generateConcreteBMHClass(types);
}
});
}
/** /**
* Generate a concrete subclass of BMH for a given combination of bound types. * Generate a concrete subclass of BMH for a given combination of bound types.
* *
...@@ -529,7 +530,7 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -529,7 +530,7 @@ import jdk.internal.org.objectweb.asm.Type;
* } * }
* final SpeciesData speciesData() { return SPECIES_DATA; } * final SpeciesData speciesData() { return SPECIES_DATA; }
* final int fieldCount() { return 3; } * final int fieldCount() { return 3; }
* static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("LLI", Species_LLI.class); * &#64;Stable static SpeciesData SPECIES_DATA; // injected afterwards
* static BoundMethodHandle make(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) { * static BoundMethodHandle make(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
* return new Species_LLI(mt, lf, argL0, argL1, argI2); * return new Species_LLI(mt, lf, argL0, argL1, argI2);
* } * }
...@@ -568,7 +569,9 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -568,7 +569,9 @@ import jdk.internal.org.objectweb.asm.Type;
cw.visitSource(sourceFile, null); cw.visitSource(sourceFile, null);
// emit static types and SPECIES_DATA fields // emit static types and SPECIES_DATA fields
cw.visitField(NOT_ACC_PUBLIC + ACC_STATIC, "SPECIES_DATA", SPECIES_DATA_SIG, null, null).visitEnd(); FieldVisitor fw = cw.visitField(NOT_ACC_PUBLIC + ACC_STATIC, "SPECIES_DATA", SPECIES_DATA_SIG, null, null);
fw.visitAnnotation(STABLE_SIG, true);
fw.visitEnd();
// emit bound argument fields // emit bound argument fields
for (int i = 0; i < types.length(); ++i) { for (int i = 0; i < types.length(); ++i) {
...@@ -694,17 +697,6 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -694,17 +697,6 @@ import jdk.internal.org.objectweb.asm.Type;
mv.visitEnd(); mv.visitEnd();
} }
// emit class initializer
mv = cw.visitMethod(NOT_ACC_PUBLIC | ACC_STATIC, "<clinit>", VOID_SIG, null, null);
mv.visitCode();
mv.visitLdcInsn(types);
mv.visitLdcInsn(Type.getObjectType(className));
mv.visitMethodInsn(INVOKESTATIC, SPECIES_DATA, "getForClass", BMHSPECIES_DATA_GFC_SIG, false);
mv.visitFieldInsn(PUTSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
cw.visitEnd(); cw.visitEnd();
// load class // load class
...@@ -715,7 +707,6 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -715,7 +707,6 @@ import jdk.internal.org.objectweb.asm.Type;
UNSAFE.defineClass(className, classFile, 0, classFile.length, UNSAFE.defineClass(className, classFile, 0, classFile.length,
BoundMethodHandle.class.getClassLoader(), null) BoundMethodHandle.class.getClassLoader(), null)
.asSubclass(BoundMethodHandle.class); .asSubclass(BoundMethodHandle.class);
UNSAFE.ensureClassInitialized(bmhClass);
return bmhClass; return bmhClass;
} }
...@@ -785,7 +776,7 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -785,7 +776,7 @@ import jdk.internal.org.objectweb.asm.Type;
// Auxiliary methods. // Auxiliary methods.
// //
static SpeciesData speciesDataFromConcreteBMHClass(Class<? extends BoundMethodHandle> cbmh) { static SpeciesData getSpeciesDataFromConcreteBMHClass(Class<? extends BoundMethodHandle> cbmh) {
try { try {
Field F_SPECIES_DATA = cbmh.getDeclaredField("SPECIES_DATA"); Field F_SPECIES_DATA = cbmh.getDeclaredField("SPECIES_DATA");
return (SpeciesData) F_SPECIES_DATA.get(null); return (SpeciesData) F_SPECIES_DATA.get(null);
...@@ -794,6 +785,16 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -794,6 +785,16 @@ import jdk.internal.org.objectweb.asm.Type;
} }
} }
static void setSpeciesDataToConcreteBMHClass(Class<? extends BoundMethodHandle> cbmh, SpeciesData speciesData) {
try {
Field F_SPECIES_DATA = cbmh.getDeclaredField("SPECIES_DATA");
assert F_SPECIES_DATA.getDeclaredAnnotation(Stable.class) != null;
F_SPECIES_DATA.set(null, speciesData);
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
}
}
/** /**
* Field names in concrete BMHs adhere to this pattern: * Field names in concrete BMHs adhere to this pattern:
* arg + type + index * arg + type + index
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册