# HG changeset patch # User redestad # Date 1519645433 -3600 # Node ID 0b65c64c9db990a2fb56a8d8e37e9077014ee36b # Parent c2cd23e1d9cb5e334b9745bd85e2796b5b2c6bf5 8198492: Bootstrapping java.lang.invoke can cause deadlock after JDK-8198418 8198490: java/util/logging/TestLogConfigurationDeadLock.java timed out. Reviewed-by: alanb diff -r c2cd23e1d9cb -r 0b65c64c9db9 src/java.base/share/classes/java/lang/invoke/LambdaForm.java --- a/src/java.base/share/classes/java/lang/invoke/LambdaForm.java Fri Feb 16 11:33:13 2018 +0100 +++ b/src/java.base/share/classes/java/lang/invoke/LambdaForm.java Mon Feb 26 12:43:53 2018 +0100 @@ -1734,70 +1734,75 @@ 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); + 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; + } + 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); + // 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); } - } catch (IllegalAccessException|NoSuchMethodException ex) { - throw newInternalError(ex); - } - NamedFunction idFun; - LambdaForm zeForm; - NamedFunction zeFun; + 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)); + // 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); + 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); - } + 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; + 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()); + assert(idFun.isIdentity()); + assert(zeFun.isConstantZero()); + assert(new Name(zeFun).isConstantZero()); + } } // Avoid appealing to ValueConversions at bootstrap time: