< prev index next >

src/java.base/share/classes/java/lang/invoke/Invokers.java

Print this page
rev 13050 : 8142334: Improve lazy initialization of java.lang.invoke
Reviewed-by: psandoz, vlivanov, mhaupt

@@ -271,19 +271,19 @@
         // Make the final call.  If isGeneric, then prepend the result of type checking.
         MethodType outCallType = mtype.basicType();
         Object[] outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT, Object[].class);
         Object mtypeArg = (customized ? mtype : names[MTYPE_ARG]);
         if (!isGeneric) {
-            names[CHECK_TYPE] = new Name(NF_checkExactType, names[CALL_MH], mtypeArg);
+            names[CHECK_TYPE] = new Name(getConstantFunction(NF_checkExactType), names[CALL_MH], mtypeArg);
             // mh.invokeExact(a*):R => checkExactType(mh, TYPEOF(a*:R)); mh.invokeBasic(a*)
         } else {
-            names[CHECK_TYPE] = new Name(NF_checkGenericType, names[CALL_MH], mtypeArg);
+            names[CHECK_TYPE] = new Name(getConstantFunction(NF_checkGenericType), names[CALL_MH], mtypeArg);
             // mh.invokeGeneric(a*):R => checkGenericType(mh, TYPEOF(a*:R)).invokeBasic(a*)
             outArgs[0] = names[CHECK_TYPE];
         }
         if (CHECK_CUSTOM != -1) {
-            names[CHECK_CUSTOM] = new Name(NF_checkCustomized, outArgs[0]);
+            names[CHECK_CUSTOM] = new Name(getConstantFunction(NF_checkCustomized), outArgs[0]);
         }
         names[LINKER_CALL] = new Name(outCallType, outArgs);
         lform = new LambdaForm(debugName, INARG_LIMIT, names);
         if (isLinker)
             lform.compileToBytecode();  // JVM needs a real methodOop

@@ -367,11 +367,11 @@
         MethodType invokerFormType = mtype.appendParameterTypes(skipCallSite ? MethodHandle.class : CallSite.class);
         Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType);
         assert(names.length == nameCursor);
         assert(names[APPENDIX_ARG] != null);
         if (!skipCallSite)
-            names[CALL_MH] = new Name(NF_getCallSiteTarget, names[CSITE_ARG]);
+            names[CALL_MH] = new Name(getConstantFunction(NF_getCallSiteTarget), names[CSITE_ARG]);
         // (site.)invokedynamic(a*):R => mh = site.getTarget(); mh.invokeBasic(a*)
         final int PREPEND_MH = 0, PREPEND_COUNT = 1;
         Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, OUTARG_LIMIT + PREPEND_COUNT, Object[].class);
         // prepend MH argument:
         System.arraycopy(outArgs, 0, outArgs, PREPEND_COUNT, outArgs.length - PREPEND_COUNT);

@@ -409,36 +409,61 @@
         } else {
             mh.customizationCount = (byte)(count+1);
         }
     }
 
+    private static NamedFunction getConstantFunction(int idx) {
+        NamedFunction function = FUNCTIONS[idx];
+        if (function != null) {
+            return function;
+        }
+        return setCachedFunction(idx, makeConstantFunction(idx));
+    }
+
+    private static synchronized NamedFunction setCachedFunction(int idx, final NamedFunction function) {
+        // Simulate a CAS, to avoid racy duplication of results.
+        NamedFunction prev = FUNCTIONS[idx];
+        if (prev != null) {
+            return prev;
+        }
+        function.resolve();
+        UNSAFE.storeFence();
+        FUNCTIONS[idx] = function;
+        return function;
+    }
+
+    // Indexes into constant functions:
+    private static final int
+            NF_checkExactType    =  0,
+            NF_checkGenericType  =  1,
+            NF_getCallSiteTarget =  2,
+            NF_checkCustomized   =  3,
+            NF_LIMIT             =  4;
+
     // Local constant functions:
-    private static final NamedFunction
-        NF_checkExactType,
-        NF_checkGenericType,
-        NF_getCallSiteTarget,
-        NF_checkCustomized;
-    static {
+    private static final @Stable NamedFunction[] FUNCTIONS = new NamedFunction[NF_LIMIT];
+
+    private static NamedFunction makeConstantFunction(int idx) {
         try {
-            NamedFunction nfs[] = {
-                NF_checkExactType = new NamedFunction(Invokers.class
-                        .getDeclaredMethod("checkExactType", Object.class, Object.class)),
-                NF_checkGenericType = new NamedFunction(Invokers.class
-                        .getDeclaredMethod("checkGenericType", Object.class, Object.class)),
-                NF_getCallSiteTarget = new NamedFunction(Invokers.class
-                        .getDeclaredMethod("getCallSiteTarget", Object.class)),
-                NF_checkCustomized = new NamedFunction(Invokers.class
-                        .getDeclaredMethod("checkCustomized", Object.class))
-            };
-            for (NamedFunction nf : nfs) {
-                // Each nf must be statically invocable or we get tied up in our bootstraps.
-                assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf.member)) : nf;
-                nf.resolve();
+            switch (idx) {
+                case NF_checkExactType:
+                    return new NamedFunction(Invokers.class
+                            .getDeclaredMethod("checkExactType", Object.class, Object.class));
+                case NF_checkGenericType:
+                    return new NamedFunction(Invokers.class
+                            .getDeclaredMethod("checkGenericType", Object.class, Object.class));
+                case NF_getCallSiteTarget:
+                    return new NamedFunction(Invokers.class
+                            .getDeclaredMethod("getCallSiteTarget", Object.class));
+                case NF_checkCustomized:
+                    return new NamedFunction(Invokers.class
+                            .getDeclaredMethod("checkCustomized", Object.class));
             }
         } catch (ReflectiveOperationException ex) {
             throw newInternalError(ex);
         }
+        throw newInternalError("Unknown function index: " + idx);
     }
 
     private static class Lazy {
         private static final MethodHandle MH_asSpreader;
 
< prev index next >