8178384: Reduce work in java.lang.invoke initializers
authorredestad
Tue, 11 Apr 2017 11:24:12 +0200
changeset 44590 15a77e5b7612
parent 44589 64d9270bd24c
child 44591 b9bf065070fe
8178384: Reduce work in java.lang.invoke initializers Reviewed-by: vlivanov, psandoz
jdk/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java
jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java
jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
jdk/src/java.base/share/classes/java/lang/invoke/Invokers.java
jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java
jdk/src/java.base/share/classes/java/lang/invoke/LambdaFormEditor.java
jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java
jdk/src/java.base/share/classes/sun/invoke/util/Wrapper.java
--- a/jdk/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java	Mon Apr 10 13:46:19 2017 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java	Tue Apr 11 11:24:12 2017 +0200
@@ -450,32 +450,29 @@
      */
     static class Factory {
 
-        static final String JLO_SIG  = "Ljava/lang/Object;";
-        static final String JLS_SIG  = "Ljava/lang/String;";
-        static final String JLC_SIG  = "Ljava/lang/Class;";
-        static final String MH       = "java/lang/invoke/MethodHandle";
-        static final String MH_SIG   = "L"+MH+";";
-        static final String BMH      = "java/lang/invoke/BoundMethodHandle";
-        static final String BMH_SIG  = "L"+BMH+";";
-        static final String SPECIES_DATA     = "java/lang/invoke/BoundMethodHandle$SpeciesData";
-        static final String SPECIES_DATA_SIG = "L"+SPECIES_DATA+";";
-        static final String STABLE_SIG       = "Ljdk/internal/vm/annotation/Stable;";
+        private static final String JLO_SIG  = "Ljava/lang/Object;";
+        private static final String MH       = "java/lang/invoke/MethodHandle";
+        private static final String MH_SIG   = "L"+MH+";";
+        private static final String BMH      = "java/lang/invoke/BoundMethodHandle";
+        private static final String BMH_NAME = "java.lang.invoke.BoundMethodHandle";
+        private static final String BMH_SIG  = "L"+BMH+";";
+        private static final String SPECIES_DATA     = "java/lang/invoke/BoundMethodHandle$SpeciesData";
+        private static final String SPECIES_DATA_SIG = "L"+SPECIES_DATA+";";
+        private static final String STABLE_SIG       = "Ljdk/internal/vm/annotation/Stable;";
 
-        static final String SPECIES_PREFIX_NAME = "Species_";
-        static final String SPECIES_PREFIX_PATH = BMH + "$" + SPECIES_PREFIX_NAME;
-        static final String SPECIES_CLASS_PREFIX = SPECIES_PREFIX_PATH.replace('/', '.');
+        private static final String SPECIES_PREFIX_NAME = "Species_";
+        private static final String SPECIES_PREFIX_PATH = BMH + "$" + SPECIES_PREFIX_NAME;
+        private static final String SPECIES_CLASS_PREFIX = BMH_NAME + "$" + SPECIES_PREFIX_NAME;
 
-        static final String BMHSPECIES_DATA_EWI_SIG = "(B)" + SPECIES_DATA_SIG;
-        static final String BMHSPECIES_DATA_GFC_SIG = "(" + JLS_SIG + JLC_SIG + ")" + SPECIES_DATA_SIG;
-        static final String MYSPECIES_DATA_SIG = "()" + SPECIES_DATA_SIG;
-        static final String VOID_SIG   = "()V";
-        static final String INT_SIG    = "()I";
+        private static final String BMHSPECIES_DATA_EWI_SIG = "(B)" + SPECIES_DATA_SIG;
+        private static final String MYSPECIES_DATA_SIG = "()" + SPECIES_DATA_SIG;
+        private static final String INT_SIG    = "()I";
 
-        static final String SIG_INCIPIT = "(Ljava/lang/invoke/MethodType;Ljava/lang/invoke/LambdaForm;";
+        private static final String SIG_INCIPIT = "(Ljava/lang/invoke/MethodType;Ljava/lang/invoke/LambdaForm;";
 
-        static final String[] E_THROWABLE = new String[] { "java/lang/Throwable" };
+        private static final String[] E_THROWABLE = new String[] { "java/lang/Throwable" };
 
-        static final ConcurrentMap<String, Class<? extends BoundMethodHandle>> CLASS_CACHE = new ConcurrentHashMap<>();
+        private static final ConcurrentMap<String, Class<? extends BoundMethodHandle>> CLASS_CACHE = new ConcurrentHashMap<>();
 
         /**
          * Get a concrete subclass of BMH for a given combination of bound types.
--- a/jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java	Mon Apr 10 13:46:19 2017 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java	Tue Apr 11 11:24:12 2017 +0200
@@ -224,12 +224,12 @@
         assert(names.length == nameCursor);
         if (doesAlloc) {
             // names = { argx,y,z,... new C, init method }
-            names[NEW_OBJ] = new Name(NF_allocateInstance, names[DMH_THIS]);
-            names[GET_MEMBER] = new Name(NF_constructorMethod, names[DMH_THIS]);
+            names[NEW_OBJ] = new Name(getFunction(NF_allocateInstance), names[DMH_THIS]);
+            names[GET_MEMBER] = new Name(getFunction(NF_constructorMethod), names[DMH_THIS]);
         } else if (needsInit) {
-            names[GET_MEMBER] = new Name(NF_internalMemberNameEnsureInit, names[DMH_THIS]);
+            names[GET_MEMBER] = new Name(getFunction(NF_internalMemberNameEnsureInit), names[DMH_THIS]);
         } else {
-            names[GET_MEMBER] = new Name(NF_internalMemberName, names[DMH_THIS]);
+            names[GET_MEMBER] = new Name(getFunction(NF_internalMemberName), names[DMH_THIS]);
         }
         assert(findDirectMethodHandle(names[GET_MEMBER]) == names[DMH_THIS]);
         Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, GET_MEMBER+1, Object[].class);
@@ -249,10 +249,10 @@
         return lform;
     }
 
-    static Object findDirectMethodHandle(Name name) {
-        if (name.function == NF_internalMemberName ||
-            name.function == NF_internalMemberNameEnsureInit ||
-            name.function == NF_constructorMethod) {
+    /* assert */ static Object findDirectMethodHandle(Name name) {
+        if (name.function.equals(getFunction(NF_internalMemberName)) ||
+            name.function.equals(getFunction(NF_internalMemberNameEnsureInit)) ||
+            name.function.equals(getFunction(NF_constructorMethod))) {
             assert(name.arguments.length == 1);
             return name.arguments[0];
         }
@@ -674,18 +674,18 @@
         final int RESULT    = nameCursor-1;  // either the call or the cast
         Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
         if (needsInit)
-            names[INIT_BAR] = new Name(NF_ensureInitialized, names[DMH_THIS]);
+            names[INIT_BAR] = new Name(getFunction(NF_ensureInitialized), names[DMH_THIS]);
         if (needsCast && !isGetter)
-            names[PRE_CAST] = new Name(NF_checkCast, names[DMH_THIS], names[SET_VALUE]);
+            names[PRE_CAST] = new Name(getFunction(NF_checkCast), names[DMH_THIS], names[SET_VALUE]);
         Object[] outArgs = new Object[1 + linkerType.parameterCount()];
         assert(outArgs.length == (isGetter ? 3 : 4));
-        outArgs[0] = names[U_HOLDER] = new Name(NF_UNSAFE);
+        outArgs[0] = names[U_HOLDER] = new Name(getFunction(NF_UNSAFE));
         if (isStatic) {
-            outArgs[1] = names[F_HOLDER]  = new Name(NF_staticBase, names[DMH_THIS]);
-            outArgs[2] = names[F_OFFSET]  = new Name(NF_staticOffset, names[DMH_THIS]);
+            outArgs[1] = names[F_HOLDER]  = new Name(getFunction(NF_staticBase), names[DMH_THIS]);
+            outArgs[2] = names[F_OFFSET]  = new Name(getFunction(NF_staticOffset), names[DMH_THIS]);
         } else {
-            outArgs[1] = names[OBJ_CHECK] = new Name(NF_checkBase, names[OBJ_BASE]);
-            outArgs[2] = names[F_OFFSET]  = new Name(NF_fieldOffset, names[DMH_THIS]);
+            outArgs[1] = names[OBJ_CHECK] = new Name(getFunction(NF_checkBase), names[OBJ_BASE]);
+            outArgs[2] = names[F_OFFSET]  = new Name(getFunction(NF_fieldOffset), names[DMH_THIS]);
         }
         if (!isGetter) {
             outArgs[3] = (needsCast ? names[PRE_CAST] : names[SET_VALUE]);
@@ -693,7 +693,7 @@
         for (Object a : outArgs)  assert(a != null);
         names[LINKER_CALL] = new Name(linker, outArgs);
         if (needsCast && isGetter)
-            names[POST_CAST] = new Name(NF_checkCast, names[DMH_THIS], names[LINKER_CALL]);
+            names[POST_CAST] = new Name(getFunction(NF_checkCast), names[DMH_THIS], names[LINKER_CALL]);
         for (Name n : names)  assert(n != null);
 
         LambdaForm form;
@@ -726,48 +726,72 @@
 
     /**
      * Pre-initialized NamedFunctions for bootstrapping purposes.
-     * Factored in an inner class to delay initialization until first usage.
      */
-    static final NamedFunction
-            NF_internalMemberName,
-            NF_internalMemberNameEnsureInit,
-            NF_ensureInitialized,
-            NF_fieldOffset,
-            NF_checkBase,
-            NF_staticBase,
-            NF_staticOffset,
-            NF_checkCast,
-            NF_allocateInstance,
-            NF_constructorMethod,
-            NF_UNSAFE;
-    static {
+    static final byte NF_internalMemberName = 0,
+            NF_internalMemberNameEnsureInit = 1,
+            NF_ensureInitialized = 2,
+            NF_fieldOffset = 3,
+            NF_checkBase = 4,
+            NF_staticBase = 5,
+            NF_staticOffset = 6,
+            NF_checkCast = 7,
+            NF_allocateInstance = 8,
+            NF_constructorMethod = 9,
+            NF_UNSAFE = 10,
+            NF_LIMIT = 11;
+
+    private static final @Stable NamedFunction[] NFS = new NamedFunction[NF_LIMIT];
+
+    private static NamedFunction getFunction(byte func) {
+        NamedFunction nf = NFS[func];
+        if (nf != null) {
+            return nf;
+        }
+        // Each nf must be statically invocable or we get tied up in our bootstraps.
+        nf = NFS[func] = createFunction(func);
+        assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf));
+        return nf;
+    }
+
+    private static NamedFunction createFunction(byte func) {
         try {
-            NamedFunction nfs[] = {
-                    NF_internalMemberName = new NamedFunction(DirectMethodHandle.class
-                            .getDeclaredMethod("internalMemberName", Object.class)),
-                    NF_internalMemberNameEnsureInit = new NamedFunction(DirectMethodHandle.class
-                            .getDeclaredMethod("internalMemberNameEnsureInit", Object.class)),
-                    NF_ensureInitialized = new NamedFunction(DirectMethodHandle.class
-                            .getDeclaredMethod("ensureInitialized", Object.class)),
-                    NF_fieldOffset = new NamedFunction(DirectMethodHandle.class
-                            .getDeclaredMethod("fieldOffset", Object.class)),
-                    NF_checkBase = new NamedFunction(DirectMethodHandle.class
-                            .getDeclaredMethod("checkBase", Object.class)),
-                    NF_staticBase = new NamedFunction(DirectMethodHandle.class
-                            .getDeclaredMethod("staticBase", Object.class)),
-                    NF_staticOffset = new NamedFunction(DirectMethodHandle.class
-                            .getDeclaredMethod("staticOffset", Object.class)),
-                    NF_checkCast = new NamedFunction(DirectMethodHandle.class
-                            .getDeclaredMethod("checkCast", Object.class, Object.class)),
-                    NF_allocateInstance = new NamedFunction(DirectMethodHandle.class
-                            .getDeclaredMethod("allocateInstance", Object.class)),
-                    NF_constructorMethod = new NamedFunction(DirectMethodHandle.class
-                            .getDeclaredMethod("constructorMethod", Object.class)),
-                    NF_UNSAFE = new NamedFunction(new MemberName(MethodHandleStatics.class
-                            .getDeclaredField("UNSAFE")))
-            };
-            // Each nf must be statically invocable or we get tied up in our bootstraps.
-            assert(InvokerBytecodeGenerator.isStaticallyInvocable(nfs));
+            switch (func) {
+                case NF_internalMemberName:
+                    return new NamedFunction(DirectMethodHandle.class
+                            .getDeclaredMethod("internalMemberName", Object.class));
+                case NF_internalMemberNameEnsureInit:
+                    return new NamedFunction(DirectMethodHandle.class
+                            .getDeclaredMethod("internalMemberNameEnsureInit", Object.class));
+                case NF_ensureInitialized:
+                    return new NamedFunction(DirectMethodHandle.class
+                            .getDeclaredMethod("ensureInitialized", Object.class));
+                case NF_fieldOffset:
+                    return new NamedFunction(DirectMethodHandle.class
+                            .getDeclaredMethod("fieldOffset", Object.class));
+                case NF_checkBase:
+                    return new NamedFunction(DirectMethodHandle.class
+                            .getDeclaredMethod("checkBase", Object.class));
+                case NF_staticBase:
+                    return new NamedFunction(DirectMethodHandle.class
+                            .getDeclaredMethod("staticBase", Object.class));
+                case NF_staticOffset:
+                    return new NamedFunction(DirectMethodHandle.class
+                            .getDeclaredMethod("staticOffset", Object.class));
+                case NF_checkCast:
+                    return new NamedFunction(DirectMethodHandle.class
+                            .getDeclaredMethod("checkCast", Object.class, Object.class));
+                case NF_allocateInstance:
+                    return new NamedFunction(DirectMethodHandle.class
+                            .getDeclaredMethod("allocateInstance", Object.class));
+                case NF_constructorMethod:
+                    return new NamedFunction(DirectMethodHandle.class
+                            .getDeclaredMethod("constructorMethod", Object.class));
+                case NF_UNSAFE:
+                    return new NamedFunction(new MemberName(MethodHandleStatics.class
+                            .getDeclaredField("UNSAFE")));
+                default:
+                    throw newInternalError("Unknown function: " + func);
+            }
         } catch (ReflectiveOperationException ex) {
             throw newInternalError(ex);
         }
--- a/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java	Mon Apr 10 13:46:19 2017 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java	Tue Apr 11 11:24:12 2017 +0200
@@ -908,7 +908,7 @@
         //MethodHandle.class already covered
     };
 
-    static boolean isStaticallyInvocable(NamedFunction[] functions) {
+    static boolean isStaticallyInvocable(NamedFunction ... functions) {
         for (NamedFunction nf : functions) {
             if (!isStaticallyInvocable(nf.member())) {
                 return false;
--- a/jdk/src/java.base/share/classes/java/lang/invoke/Invokers.java	Mon Apr 10 13:46:19 2017 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/Invokers.java	Tue Apr 11 11:24:12 2017 +0200
@@ -313,15 +313,15 @@
         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(getFunction(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(getFunction(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(getFunction(NF_checkCustomized), outArgs[0]);
         }
         names[LINKER_CALL] = new Name(outCallType, outArgs);
         if (customized) {
@@ -368,7 +368,7 @@
         }
         names[VAD_ARG] = new Name(ARG_LIMIT, BasicType.basicType(Object.class));
 
-        names[CHECK_TYPE] = new Name(NF_checkVarHandleGenericType, names[THIS_VH], names[VAD_ARG]);
+        names[CHECK_TYPE] = new Name(getFunction(NF_checkVarHandleGenericType), names[THIS_VH], names[VAD_ARG]);
 
         Object[] outArgs = new Object[ARG_LIMIT + 1];
         outArgs[0] = names[CHECK_TYPE];
@@ -377,7 +377,7 @@
         }
 
         if (CHECK_CUSTOM != -1) {
-            names[CHECK_CUSTOM] = new Name(NF_checkCustomized, outArgs[0]);
+            names[CHECK_CUSTOM] = new Name(getFunction(NF_checkCustomized), outArgs[0]);
         }
 
         MethodType outCallType = mtype.insertParameterTypes(0, VarHandle.class)
@@ -420,9 +420,9 @@
         names[VAD_ARG] = new Name(getter, names[THIS_MH]);
 
         if (isExact) {
-            names[CHECK_TYPE] = new Name(NF_checkVarHandleExactType, names[CALL_VH], names[VAD_ARG]);
+            names[CHECK_TYPE] = new Name(getFunction(NF_checkVarHandleExactType), names[CALL_VH], names[VAD_ARG]);
         } else {
-            names[CHECK_TYPE] = new Name(NF_checkVarHandleGenericType, names[CALL_VH], names[VAD_ARG]);
+            names[CHECK_TYPE] = new Name(getFunction(NF_checkVarHandleGenericType), names[CALL_VH], names[VAD_ARG]);
         }
         Object[] outArgs = new Object[ARG_LIMIT];
         outArgs[0] = names[CHECK_TYPE];
@@ -543,7 +543,7 @@
         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(getFunction(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);
@@ -586,31 +586,51 @@
     }
 
     // Local constant functions:
-    private static final NamedFunction
-        NF_checkExactType,
-        NF_checkGenericType,
-        NF_getCallSiteTarget,
-        NF_checkCustomized,
-        NF_checkVarHandleGenericType,
-        NF_checkVarHandleExactType;
-    static {
+    private static final byte NF_checkExactType = 0,
+        NF_checkGenericType = 1,
+        NF_getCallSiteTarget = 2,
+        NF_checkCustomized = 3,
+        NF_checkVarHandleGenericType = 4,
+        NF_checkVarHandleExactType = 5,
+        NF_LIMIT = 6;
+
+    private static final @Stable NamedFunction[] NFS = new NamedFunction[NF_LIMIT];
+
+    private static NamedFunction getFunction(byte func) {
+        NamedFunction nf = NFS[func];
+        if (nf != null) {
+            return nf;
+        }
+        NFS[func] = nf = createFunction(func);
+        // Each nf must be statically invocable or we get tied up in our bootstraps.
+        assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf));
+        return nf;
+    }
+
+    private static NamedFunction createFunction(byte func) {
         try {
-            NamedFunction nfs[] = {
-                NF_checkExactType = new NamedFunction(Invokers.class
-                        .getDeclaredMethod("checkExactType", MethodHandle.class,  MethodType.class)),
-                NF_checkGenericType = new NamedFunction(Invokers.class
-                        .getDeclaredMethod("checkGenericType", MethodHandle.class,  MethodType.class)),
-                NF_getCallSiteTarget = new NamedFunction(Invokers.class
-                        .getDeclaredMethod("getCallSiteTarget", CallSite.class)),
-                NF_checkCustomized = new NamedFunction(Invokers.class
-                        .getDeclaredMethod("checkCustomized", MethodHandle.class)),
-                NF_checkVarHandleGenericType = new NamedFunction(Invokers.class
-                        .getDeclaredMethod("checkVarHandleGenericType", VarHandle.class, VarHandle.AccessDescriptor.class)),
-                NF_checkVarHandleExactType = new NamedFunction(Invokers.class
-                        .getDeclaredMethod("checkVarHandleExactType", VarHandle.class, VarHandle.AccessDescriptor.class)),
-            };
-            // Each nf must be statically invocable or we get tied up in our bootstraps.
-            assert(InvokerBytecodeGenerator.isStaticallyInvocable(nfs));
+            switch (func) {
+                case NF_checkExactType:
+                    return new NamedFunction(Invokers.class
+                        .getDeclaredMethod("checkExactType", MethodHandle.class,  MethodType.class));
+                case NF_checkGenericType:
+                    return new NamedFunction(Invokers.class
+                        .getDeclaredMethod("checkGenericType", MethodHandle.class,  MethodType.class));
+                case NF_getCallSiteTarget:
+                    return new NamedFunction(Invokers.class
+                        .getDeclaredMethod("getCallSiteTarget", CallSite.class));
+                case NF_checkCustomized:
+                    return new NamedFunction(Invokers.class
+                        .getDeclaredMethod("checkCustomized", MethodHandle.class));
+                case NF_checkVarHandleGenericType:
+                    return new NamedFunction(Invokers.class
+                        .getDeclaredMethod("checkVarHandleGenericType", VarHandle.class, VarHandle.AccessDescriptor.class));
+                case NF_checkVarHandleExactType:
+                    return new NamedFunction(Invokers.class
+                        .getDeclaredMethod("checkVarHandleExactType", VarHandle.class, VarHandle.AccessDescriptor.class));
+                default:
+                    throw newInternalError("Unknown function: " + func);
+            }
         } catch (ReflectiveOperationException ex) {
             throw newInternalError(ex);
         }
--- a/jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java	Mon Apr 10 13:46:19 2017 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java	Tue Apr 11 11:24:12 2017 +0200
@@ -270,21 +270,21 @@
         GENERIC("invoke"),
         ZERO("zero"),
         IDENTITY("identity"),
-        BOUND_REINVOKER("BMH.reinvoke"),
-        REINVOKER("MH.reinvoke"),
-        DELEGATE("MH.delegate"),
-        EXACT_LINKER("MH.invokeExact_MT"),
-        EXACT_INVOKER("MH.exactInvoker"),
-        GENERIC_LINKER("MH.invoke_MT"),
-        GENERIC_INVOKER("MH.invoker"),
+        BOUND_REINVOKER("BMH.reinvoke", "reinvoke"),
+        REINVOKER("MH.reinvoke", "reinvoke"),
+        DELEGATE("MH.delegate", "delegate"),
+        EXACT_LINKER("MH.invokeExact_MT", "invokeExact_MT"),
+        EXACT_INVOKER("MH.exactInvoker", "exactInvoker"),
+        GENERIC_LINKER("MH.invoke_MT", "invoke_MT"),
+        GENERIC_INVOKER("MH.invoker", "invoker"),
         LINK_TO_TARGET_METHOD("linkToTargetMethod"),
         LINK_TO_CALL_SITE("linkToCallSite"),
-        DIRECT_INVOKE_VIRTUAL("DMH.invokeVirtual"),
-        DIRECT_INVOKE_SPECIAL("DMH.invokeSpecial"),
-        DIRECT_INVOKE_STATIC("DMH.invokeStatic"),
-        DIRECT_NEW_INVOKE_SPECIAL("DMH.newInvokeSpecial"),
-        DIRECT_INVOKE_INTERFACE("DMH.invokeInterface"),
-        DIRECT_INVOKE_STATIC_INIT("DMH.invokeStaticInit"),
+        DIRECT_INVOKE_VIRTUAL("DMH.invokeVirtual", "invokeVirtual"),
+        DIRECT_INVOKE_SPECIAL("DMH.invokeSpecial", "invokeSpecial"),
+        DIRECT_INVOKE_STATIC("DMH.invokeStatic", "invokeStatic"),
+        DIRECT_NEW_INVOKE_SPECIAL("DMH.newInvokeSpecial", "newInvokeSpecial"),
+        DIRECT_INVOKE_INTERFACE("DMH.invokeInterface", "invokeInterface"),
+        DIRECT_INVOKE_STATIC_INIT("DMH.invokeStaticInit", "invokeStaticInit"),
         GET_OBJECT("getObject"),
         PUT_OBJECT("putObject"),
         GET_OBJECT_VOLATILE("getObjectVolatile"),
@@ -330,20 +330,19 @@
         GUARD("guard"),
         GUARD_WITH_CATCH("guardWithCatch"),
         VARHANDLE_EXACT_INVOKER("VH.exactInvoker"),
-        VARHANDLE_INVOKER("VH.invoker"),
-        VARHANDLE_LINKER("VH.invoke_MT");
+        VARHANDLE_INVOKER("VH.invoker", "invoker"),
+        VARHANDLE_LINKER("VH.invoke_MT", "invoke_MT");
 
         final String defaultLambdaName;
         final String methodName;
 
         private Kind(String defaultLambdaName) {
+            this(defaultLambdaName, defaultLambdaName);
+        }
+
+        private Kind(String defaultLambdaName, String methodName) {
             this.defaultLambdaName = defaultLambdaName;
-            int p = defaultLambdaName.indexOf('.');
-            if (p > -1) {
-                this.methodName = defaultLambdaName.substring(p + 1);
-            } else {
-                this.methodName = defaultLambdaName;
-            }
+            this.methodName = methodName;
         }
     }
 
--- a/jdk/src/java.base/share/classes/java/lang/invoke/LambdaFormEditor.java	Mon Apr 10 13:46:19 2017 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/LambdaFormEditor.java	Tue Apr 11 11:24:12 2017 +0200
@@ -532,7 +532,8 @@
         assert(pos > 0);  // cannot spread the MH arg itself
 
         Name spreadParam = new Name(L_TYPE);
-        Name checkSpread = new Name(MethodHandleImpl.NF_checkSpreadArgument, spreadParam, arrayLength);
+        Name checkSpread = new Name(MethodHandleImpl.getFunction(MethodHandleImpl.NF_checkSpreadArgument),
+                spreadParam, arrayLength);
 
         // insert the new expressions
         int exprPos = lambdaForm.arity();
@@ -932,14 +933,14 @@
 
         // replace the null entry in the MHImpl.loop invocation with localTypes
         Name invokeLoop = lambdaForm.names[pos + 1];
-        assert(invokeLoop.function == NF_loop);
+        assert(invokeLoop.function.equals(MethodHandleImpl.getFunction(NF_loop)));
         Object[] args = Arrays.copyOf(invokeLoop.arguments, invokeLoop.arguments.length);
         assert(args[0] == null);
         args[0] = localTypes;
 
         LambdaFormBuffer buf = buffer();
         buf.startEdit();
-        buf.changeName(pos + 1, new Name(NF_loop, args));
+        buf.changeName(pos + 1, new Name(MethodHandleImpl.getFunction(NF_loop), args));
         form = buf.endEdit();
 
         return putInCache(key, form);
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java	Mon Apr 10 13:46:19 2017 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java	Tue Apr 11 11:24:12 2017 +0200
@@ -589,7 +589,7 @@
                 // Spread the array.
                 MethodHandle aload = MethodHandles.arrayElementGetter(spreadArgType);
                 Name array = names[argIndex];
-                names[nameCursor++] = new Name(NF_checkSpreadArgument, array, spreadArgCount);
+                names[nameCursor++] = new Name(getFunction(NF_checkSpreadArgument), array, spreadArgCount);
                 for (int j = 0; j < spreadArgCount; i++, j++) {
                     indexes[i] = nameCursor;
                     names[nameCursor++] = new Name(aload, array, j);
@@ -934,7 +934,7 @@
 
         // profile branch
         if (PROFILE != -1) {
-            names[PROFILE] = new Name(NF_profileBoolean, names[CALL_TEST], names[GET_COUNTERS]);
+            names[PROFILE] = new Name(getFunction(NF_profileBoolean), names[CALL_TEST], names[GET_COUNTERS]);
         }
         // call selectAlternative
         names[SELECT_ALT] = new Name(getConstantHandle(MH_selectAlternative), names[TEST], names[GET_TARGET], names[GET_FALLBACK]);
@@ -1012,7 +1012,7 @@
 
         // t_{i+1}:L=MethodHandleImpl.guardWithCatch(target:L,exType:L,catcher:L,t_{i}:L);
         Object[] gwcArgs = new Object[] {names[GET_TARGET], names[GET_CLASS], names[GET_CATCHER], names[BOXED_ARGS]};
-        names[TRY_CATCH] = new Name(NF_guardWithCatch, gwcArgs);
+        names[TRY_CATCH] = new Name(getFunction(NF_guardWithCatch), gwcArgs);
 
         // t_{i+2}:I=MethodHandle.invokeBasic(unbox:L,t_{i+1}:L);
         MethodHandle invokeBasicUnbox = MethodHandles.basicInvoker(MethodType.methodType(basicType.rtype(), Object.class));
@@ -1085,7 +1085,7 @@
             mh = MethodHandles.dropArguments(mh, 1, Arrays.copyOfRange(type.parameterArray(), 1, arity));
             return mh;
         }
-        return makePairwiseConvert(NF_throwException.resolvedHandle(), type, false, true);
+        return makePairwiseConvert(getFunction(NF_throwException).resolvedHandle(), type, false, true);
     }
 
     static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
@@ -1673,33 +1673,57 @@
     }
 
     // Local constant functions:
-    /*non-public*/ static final NamedFunction
-        NF_checkSpreadArgument,
-        NF_guardWithCatch,
-        NF_throwException,
-        NF_tryFinally,
-        NF_loop,
-        NF_profileBoolean;
+
+    static final byte NF_checkSpreadArgument = 0,
+            NF_guardWithCatch = 1,
+            NF_throwException = 2,
+            NF_tryFinally = 3,
+            NF_loop = 4,
+            NF_profileBoolean = 5,
+            NF_LIMIT = 6;
 
-    static {
+    /*non-public*/
+    private static final @Stable NamedFunction[] NFS = new NamedFunction[NF_LIMIT];
+
+    static NamedFunction getFunction(byte func) {
+        NamedFunction nf = NFS[func];
+        if (nf != null) {
+            return nf;
+        }
+        return NFS[func] = createFunction(func);
+    }
+
+    private static NamedFunction createFunction(byte func) {
         try {
-            NF_checkSpreadArgument = new NamedFunction(MethodHandleImpl.class
-                    .getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
-            NF_guardWithCatch = new NamedFunction(MethodHandleImpl.class
-                    .getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class,
-                            MethodHandle.class, Object[].class));
-            NF_tryFinally = new NamedFunction(MethodHandleImpl.class
-                    .getDeclaredMethod("tryFinally", MethodHandle.class, MethodHandle.class, Object[].class));
-            NF_loop = new NamedFunction(MethodHandleImpl.class
-                    .getDeclaredMethod("loop", BasicType[].class, LoopClauses.class, Object[].class));
-            NF_throwException = new NamedFunction(MethodHandleImpl.class
-                    .getDeclaredMethod("throwException", Throwable.class));
-            NF_profileBoolean = new NamedFunction(MethodHandleImpl.class
-                    .getDeclaredMethod("profileBoolean", boolean.class, int[].class));
+            switch (func) {
+                case NF_checkSpreadArgument:
+                    return new NamedFunction(MethodHandleImpl.class
+                            .getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
+                case NF_guardWithCatch:
+                    return new NamedFunction(MethodHandleImpl.class
+                            .getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class,
+                                    MethodHandle.class, Object[].class));
+                case NF_tryFinally:
+                    return new NamedFunction(MethodHandleImpl.class
+                            .getDeclaredMethod("tryFinally", MethodHandle.class, MethodHandle.class, Object[].class));
+                case NF_loop:
+                    return new NamedFunction(MethodHandleImpl.class
+                            .getDeclaredMethod("loop", BasicType[].class, LoopClauses.class, Object[].class));
+                case NF_throwException:
+                    return new NamedFunction(MethodHandleImpl.class
+                            .getDeclaredMethod("throwException", Throwable.class));
+                case NF_profileBoolean:
+                    return new NamedFunction(MethodHandleImpl.class
+                            .getDeclaredMethod("profileBoolean", boolean.class, int[].class));
+                default:
+                    throw new InternalError("Undefined function: " + func);
+            }
         } catch (ReflectiveOperationException ex) {
             throw newInternalError(ex);
         }
+    }
 
+    static {
         SharedSecrets.setJavaLangInvokeAccess(new JavaLangInvokeAccess() {
             @Override
             public Object newMemberName() {
@@ -1878,7 +1902,7 @@
             Object[] lArgs =
                     new Object[]{null, // placeholder for BasicType[] localTypes - will be added by LambdaFormEditor
                             names[GET_CLAUSE_DATA], names[BOXED_ARGS]};
-            names[LOOP] = new Name(NF_loop, lArgs);
+            names[LOOP] = new Name(getFunction(NF_loop), lArgs);
 
             // t_{i+2}:I=MethodHandle.invokeBasic(unbox:L,t_{i+1}:L);
             MethodHandle invokeBasicUnbox = MethodHandles.basicInvoker(MethodType.methodType(basicType.rtype(), Object.class));
@@ -2113,7 +2137,7 @@
 
         // t_{i+1}:L=MethodHandleImpl.tryFinally(target:L,exType:L,catcher:L,t_{i}:L);
         Object[] tfArgs = new Object[] {names[GET_TARGET], names[GET_CLEANUP], names[BOXED_ARGS]};
-        names[TRY_FINALLY] = new Name(NF_tryFinally, tfArgs);
+        names[TRY_FINALLY] = new Name(getFunction(NF_tryFinally), tfArgs);
 
         // t_{i+2}:I=MethodHandle.invokeBasic(unbox:L,t_{i+1}:L);
         MethodHandle invokeBasicUnbox = MethodHandles.basicInvoker(MethodType.methodType(basicType.rtype(), Object.class));
--- a/jdk/src/java.base/share/classes/sun/invoke/util/Wrapper.java	Mon Apr 10 13:46:19 2017 -0700
+++ b/jdk/src/java.base/share/classes/sun/invoke/util/Wrapper.java	Tue Apr 11 11:24:12 2017 +0200
@@ -26,20 +26,20 @@
 package sun.invoke.util;
 
 public enum Wrapper {
-    //        wrapperType    primitiveType  char     emptyArray          format
-    BOOLEAN(  Boolean.class, boolean.class, 'Z', new boolean[0], Format.unsigned( 1)),
+    //        wrapperType      simple     primitiveType  simple     char  emptyArray     format
+    BOOLEAN(  Boolean.class,   "Boolean", boolean.class, "boolean", 'Z', new boolean[0], Format.unsigned( 1)),
     // These must be in the order defined for widening primitive conversions in JLS 5.1.2
     // Avoid boxing integral types here to defer initialization of internal caches
-    BYTE   (     Byte.class,    byte.class, 'B', new    byte[0], Format.signed(   8)),
-    SHORT  (    Short.class,   short.class, 'S', new   short[0], Format.signed(  16)),
-    CHAR   (Character.class,    char.class, 'C', new    char[0], Format.unsigned(16)),
-    INT    (  Integer.class,     int.class, 'I', new     int[0], Format.signed(  32)),
-    LONG   (     Long.class,    long.class, 'J', new    long[0], Format.signed(  64)),
-    FLOAT  (    Float.class,   float.class, 'F', new   float[0], Format.floating(32)),
-    DOUBLE (   Double.class,  double.class, 'D', new  double[0], Format.floating(64)),
-    OBJECT (   Object.class,  Object.class, 'L', new  Object[0], Format.other(    1)),
+    BYTE   (     Byte.class,      "Byte",    byte.class,    "byte", 'B', new    byte[0], Format.signed(   8)),
+    SHORT  (    Short.class,     "Short",   short.class,   "short", 'S', new   short[0], Format.signed(  16)),
+    CHAR   (Character.class, "Character",    char.class,    "char", 'C', new    char[0], Format.unsigned(16)),
+    INT    (  Integer.class,   "Integer",     int.class,     "int", 'I', new     int[0], Format.signed(  32)),
+    LONG   (     Long.class,      "Long",    long.class,    "long", 'J', new    long[0], Format.signed(  64)),
+    FLOAT  (    Float.class,     "Float",   float.class,   "float", 'F', new   float[0], Format.floating(32)),
+    DOUBLE (   Double.class,    "Double",  double.class,  "double", 'D', new  double[0], Format.floating(64)),
+    OBJECT (   Object.class,    "Object",  Object.class,  "Object", 'L', new  Object[0], Format.other(    1)),
     // VOID must be the last type, since it is "assignable" from any other type:
-    VOID   (     Void.class,    void.class, 'V',           null, Format.other(    0)),
+    VOID   (     Void.class,      "Void",    void.class,    "void", 'V',           null, Format.other(    0)),
     ;
 
     public static final int COUNT = 10;
@@ -52,14 +52,14 @@
     private final String   wrapperSimpleName;
     private final String   primitiveSimpleName;
 
-    private Wrapper(Class<?> wtype, Class<?> ptype, char tchar, Object emptyArray, int format) {
+    private Wrapper(Class<?> wtype, String wtypeName, Class<?> ptype, String ptypeName, char tchar, Object emptyArray, int format) {
         this.wrapperType = wtype;
         this.primitiveType = ptype;
         this.basicTypeChar = tchar;
         this.emptyArray = emptyArray;
         this.format = format;
-        this.wrapperSimpleName = wtype.getSimpleName();
-        this.primitiveSimpleName = ptype.getSimpleName();
+        this.wrapperSimpleName = wtypeName;
+        this.primitiveSimpleName = ptypeName;
     }
 
     /** For debugging, give the details of this wrapper. */