8198492: Bootstrapping java.lang.invoke can cause deadlock after JDK-8198418

8198490: java/util/logging/TestLogConfigurationDeadLock.java timed out

Reviewed-by: alanb
This commit is contained in:
Claes Redestad 2018-02-26 12:43:53 +01:00
parent e1f8cacc0b
commit 703621f15f

@ -1734,70 +1734,75 @@ class LambdaForm {
private static final @Stable NamedFunction[] NF_identity = new NamedFunction[TYPE_LIMIT];
private static final @Stable NamedFunction[] NF_zero = new NamedFunction[TYPE_LIMIT];
private static synchronized void createFormsFor(BasicType type) {
final int ord = type.ordinal();
LambdaForm idForm = LF_identity[ord];
if (idForm != null) {
return;
}
char btChar = type.basicTypeChar();
boolean isVoid = (type == V_TYPE);
Class<?> btClass = type.btClass;
MethodType zeType = MethodType.methodType(btClass);
MethodType idType = (isVoid) ? zeType : MethodType.methodType(btClass, btClass);
// Look up symbolic names. It might not be necessary to have these,
// but if we need to emit direct references to bytecodes, it helps.
// Zero is built from a call to an identity function with a constant zero input.
MemberName idMem = new MemberName(LambdaForm.class, "identity_"+btChar, idType, REF_invokeStatic);
MemberName zeMem = null;
try {
idMem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, idMem, null, NoSuchMethodException.class);
if (!isVoid) {
zeMem = new MemberName(LambdaForm.class, "zero_"+btChar, zeType, REF_invokeStatic);
zeMem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, zeMem, null, NoSuchMethodException.class);
private static final Object createFormsLock = new Object();
private static void createFormsFor(BasicType type) {
// Avoid racy initialization during bootstrap
UNSAFE.ensureClassInitialized(BoundMethodHandle.class);
synchronized (createFormsLock) {
final int ord = type.ordinal();
LambdaForm idForm = LF_identity[ord];
if (idForm != null) {
return;
}
} catch (IllegalAccessException|NoSuchMethodException ex) {
throw newInternalError(ex);
char btChar = type.basicTypeChar();
boolean isVoid = (type == V_TYPE);
Class<?> btClass = type.btClass;
MethodType zeType = MethodType.methodType(btClass);
MethodType idType = (isVoid) ? zeType : MethodType.methodType(btClass, btClass);
// Look up symbolic names. It might not be necessary to have these,
// but if we need to emit direct references to bytecodes, it helps.
// Zero is built from a call to an identity function with a constant zero input.
MemberName idMem = new MemberName(LambdaForm.class, "identity_"+btChar, idType, REF_invokeStatic);
MemberName zeMem = null;
try {
idMem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, idMem, null, NoSuchMethodException.class);
if (!isVoid) {
zeMem = new MemberName(LambdaForm.class, "zero_"+btChar, zeType, REF_invokeStatic);
zeMem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, zeMem, null, NoSuchMethodException.class);
}
} catch (IllegalAccessException|NoSuchMethodException ex) {
throw newInternalError(ex);
}
NamedFunction idFun;
LambdaForm zeForm;
NamedFunction zeFun;
// Create the LFs and NamedFunctions. Precompiling LFs to byte code is needed to break circular
// bootstrap dependency on this method in case we're interpreting LFs
if (isVoid) {
Name[] idNames = new Name[] { argument(0, L_TYPE) };
idForm = new LambdaForm(1, idNames, VOID_RESULT, Kind.IDENTITY);
idForm.compileToBytecode();
idFun = new NamedFunction(idMem, SimpleMethodHandle.make(idMem.getInvocationType(), idForm));
zeForm = idForm;
zeFun = idFun;
} else {
Name[] idNames = new Name[] { argument(0, L_TYPE), argument(1, type) };
idForm = new LambdaForm(2, idNames, 1, Kind.IDENTITY);
idForm.compileToBytecode();
idFun = new NamedFunction(idMem, SimpleMethodHandle.make(idMem.getInvocationType(), idForm),
MethodHandleImpl.Intrinsic.IDENTITY);
Object zeValue = Wrapper.forBasicType(btChar).zero();
Name[] zeNames = new Name[] { argument(0, L_TYPE), new Name(idFun, zeValue) };
zeForm = new LambdaForm(1, zeNames, 1, Kind.ZERO);
zeForm.compileToBytecode();
zeFun = new NamedFunction(zeMem, SimpleMethodHandle.make(zeMem.getInvocationType(), zeForm),
MethodHandleImpl.Intrinsic.ZERO);
}
LF_zero[ord] = zeForm;
NF_zero[ord] = zeFun;
LF_identity[ord] = idForm;
NF_identity[ord] = idFun;
assert(idFun.isIdentity());
assert(zeFun.isConstantZero());
assert(new Name(zeFun).isConstantZero());
}
NamedFunction idFun;
LambdaForm zeForm;
NamedFunction zeFun;
// Create the LFs and NamedFunctions. Precompiling LFs to byte code is needed to break circular
// bootstrap dependency on this method in case we're interpreting LFs
if (isVoid) {
Name[] idNames = new Name[] { argument(0, L_TYPE) };
idForm = new LambdaForm(1, idNames, VOID_RESULT, Kind.IDENTITY);
idForm.compileToBytecode();
idFun = new NamedFunction(idMem, SimpleMethodHandle.make(idMem.getInvocationType(), idForm));
zeForm = idForm;
zeFun = idFun;
} else {
Name[] idNames = new Name[] { argument(0, L_TYPE), argument(1, type) };
idForm = new LambdaForm(2, idNames, 1, Kind.IDENTITY);
idForm.compileToBytecode();
idFun = new NamedFunction(idMem, SimpleMethodHandle.make(idMem.getInvocationType(), idForm),
MethodHandleImpl.Intrinsic.IDENTITY);
Object zeValue = Wrapper.forBasicType(btChar).zero();
Name[] zeNames = new Name[] { argument(0, L_TYPE), new Name(idFun, zeValue) };
zeForm = new LambdaForm(1, zeNames, 1, Kind.ZERO);
zeForm.compileToBytecode();
zeFun = new NamedFunction(zeMem, SimpleMethodHandle.make(zeMem.getInvocationType(), zeForm),
MethodHandleImpl.Intrinsic.ZERO);
}
LF_zero[ord] = zeForm;
NF_zero[ord] = zeFun;
LF_identity[ord] = idForm;
NF_identity[ord] = idFun;
assert(idFun.isIdentity());
assert(zeFun.isConstantZero());
assert(new Name(zeFun).isConstantZero());
}
// Avoid appealing to ValueConversions at bootstrap time: