8198492: Bootstrapping java.lang.invoke can cause deadlock after JDK-8198418
authorredestad
Mon, 26 Feb 2018 12:43:53 +0100
changeset 48989 0b65c64c9db9
parent 48988 c2cd23e1d9cb
child 48990 9c006936068b
child 49101 206a6f728ce5
child 49258 be0ec3cc0c2a
child 56191 ad61409cdb6c
8198492: Bootstrapping java.lang.invoke can cause deadlock after JDK-8198418 8198490: java/util/logging/TestLogConfigurationDeadLock.java timed out. Reviewed-by: alanb
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: