jdk/src/share/classes/java/lang/invoke/LambdaForm.java
changeset 24572 5c9e5961d21c
parent 23038 bb8b3b23af3a
child 24696 00479fa7c27f
--- a/jdk/src/share/classes/java/lang/invoke/LambdaForm.java	Mon May 26 19:59:28 2014 +0400
+++ b/jdk/src/share/classes/java/lang/invoke/LambdaForm.java	Mon Feb 24 18:11:55 2014 +0400
@@ -30,14 +30,14 @@
 import java.util.Map;
 import java.util.List;
 import java.util.Arrays;
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.concurrent.ConcurrentHashMap;
 import sun.invoke.util.Wrapper;
+import java.lang.reflect.Field;
+
+import static java.lang.invoke.LambdaForm.BasicType.*;
 import static java.lang.invoke.MethodHandleStatics.*;
 import static java.lang.invoke.MethodHandleNatives.Constants.*;
-import java.lang.reflect.Field;
-import java.util.Objects;
 
 /**
  * The symbolic, non-executable form of a method handle's invocation semantics.
@@ -130,13 +130,119 @@
 
     public static final int VOID_RESULT = -1, LAST_RESULT = -2;
 
+    enum BasicType {
+        L_TYPE('L', Object.class, Wrapper.OBJECT),  // all reference types
+        I_TYPE('I', int.class,    Wrapper.INT),
+        J_TYPE('J', long.class,   Wrapper.LONG),
+        F_TYPE('F', float.class,  Wrapper.FLOAT),
+        D_TYPE('D', double.class, Wrapper.DOUBLE),  // all primitive types
+        V_TYPE('V', void.class,   Wrapper.VOID);    // not valid in all contexts
+
+        static final BasicType[] ALL_TYPES = BasicType.values();
+        static final BasicType[] ARG_TYPES = Arrays.copyOf(ALL_TYPES, ALL_TYPES.length-1);
+
+        static final int ARG_TYPE_LIMIT = ARG_TYPES.length;
+        static final int TYPE_LIMIT = ALL_TYPES.length;
+
+        private final char btChar;
+        private final Class<?> btClass;
+        private final Wrapper btWrapper;
+
+        private BasicType(char btChar, Class<?> btClass, Wrapper wrapper) {
+            this.btChar = btChar;
+            this.btClass = btClass;
+            this.btWrapper = wrapper;
+        }
+
+        char basicTypeChar() {
+            return btChar;
+        }
+        Class<?> basicTypeClass() {
+            return btClass;
+        }
+        Wrapper basicTypeWrapper() {
+            return btWrapper;
+        }
+        int basicTypeSlots() {
+            return btWrapper.stackSlots();
+        }
+
+        static BasicType basicType(byte type) {
+            return ALL_TYPES[type];
+        }
+        static BasicType basicType(char type) {
+            switch (type) {
+                case 'L': return L_TYPE;
+                case 'I': return I_TYPE;
+                case 'J': return J_TYPE;
+                case 'F': return F_TYPE;
+                case 'D': return D_TYPE;
+                case 'V': return V_TYPE;
+                // all subword types are represented as ints
+                case 'Z':
+                case 'B':
+                case 'S':
+                case 'C':
+                    return I_TYPE;
+                default:
+                    throw newInternalError("Unknown type char: '"+type+"'");
+            }
+        }
+        static BasicType basicType(Wrapper type) {
+            char c = type.basicTypeChar();
+            return basicType(c);
+        }
+        static BasicType basicType(Class<?> type) {
+            if (!type.isPrimitive())  return L_TYPE;
+            return basicType(Wrapper.forPrimitiveType(type));
+        }
+
+        static char basicTypeChar(Class<?> type) {
+            return basicType(type).btChar;
+        }
+        static BasicType[] basicTypes(List<Class<?>> types) {
+            BasicType[] btypes = new BasicType[types.size()];
+            for (int i = 0; i < btypes.length; i++) {
+                btypes[i] = basicType(types.get(i));
+            }
+            return btypes;
+        }
+        static BasicType[] basicTypes(String types) {
+            BasicType[] btypes = new BasicType[types.length()];
+            for (int i = 0; i < btypes.length; i++) {
+                btypes[i] = basicType(types.charAt(i));
+            }
+            return btypes;
+        }
+        static boolean isBasicTypeChar(char c) {
+            return "LIJFDV".indexOf(c) >= 0;
+        }
+        static boolean isArgBasicTypeChar(char c) {
+            return "LIJFD".indexOf(c) >= 0;
+        }
+
+        static { assert(checkBasicType()); }
+        private static boolean checkBasicType() {
+            for (int i = 0; i < ARG_TYPE_LIMIT; i++) {
+                assert ARG_TYPES[i].ordinal() == i;
+                assert ARG_TYPES[i] == ALL_TYPES[i];
+            }
+            for (int i = 0; i < TYPE_LIMIT; i++) {
+                assert ALL_TYPES[i].ordinal() == i;
+            }
+            assert ALL_TYPES[TYPE_LIMIT - 1] == V_TYPE;
+            assert !Arrays.asList(ARG_TYPES).contains(V_TYPE);
+            return true;
+        }
+    }
+
     LambdaForm(String debugName,
                int arity, Name[] names, int result) {
         assert(namesOK(arity, names));
         this.arity = arity;
         this.result = fixResult(result, names);
         this.names = names.clone();
-        this.debugName = debugName;
+        this.debugName = fixDebugName(debugName);
         normalize();
     }
 
@@ -168,12 +274,12 @@
         // Called only from getPreparedForm.
         assert(isValidSignature(sig));
         this.arity = signatureArity(sig);
-        this.result = (signatureReturn(sig) == 'V' ? -1 : arity);
+        this.result = (signatureReturn(sig) == V_TYPE ? -1 : arity);
         this.names = buildEmptyNames(arity, sig);
         this.debugName = "LF.zero";
         assert(nameRefsAreLegal());
         assert(isEmpty());
-        assert(sig.equals(basicTypeSignature()));
+        assert(sig.equals(basicTypeSignature())) : sig + " != " + basicTypeSignature();
     }
 
     private static Name[] buildEmptyNames(int arity, String basicTypeSignature) {
@@ -181,22 +287,53 @@
         int resultPos = arity + 1;  // skip '_'
         if (arity < 0 || basicTypeSignature.length() != resultPos+1)
             throw new IllegalArgumentException("bad arity for "+basicTypeSignature);
-        int numRes = (basicTypeSignature.charAt(resultPos) == 'V' ? 0 : 1);
+        int numRes = (basicType(basicTypeSignature.charAt(resultPos)) == V_TYPE ? 0 : 1);
         Name[] names = arguments(numRes, basicTypeSignature.substring(0, arity));
         for (int i = 0; i < numRes; i++) {
-            names[arity + i] = constantZero(arity + i, basicTypeSignature.charAt(resultPos + i));
+            Name zero = new Name(constantZero(basicType(basicTypeSignature.charAt(resultPos + i))));
+            names[arity + i] = zero.newIndex(arity + i);
         }
         return names;
     }
 
     private static int fixResult(int result, Name[] names) {
-        if (result >= 0) {
-            if (names[result].type == 'V')
-                return -1;
-        } else if (result == LAST_RESULT) {
-            return names.length - 1;
+        if (result == LAST_RESULT)
+            result = names.length - 1;  // might still be void
+        if (result >= 0 && names[result].type == V_TYPE)
+            result = VOID_RESULT;
+        return result;
+    }
+
+    private static String fixDebugName(String debugName) {
+        if (DEBUG_NAME_COUNTERS != null) {
+            int under = debugName.indexOf('_');
+            int length = debugName.length();
+            if (under < 0)  under = length;
+            String debugNameStem = debugName.substring(0, under);
+            Integer ctr;
+            synchronized (DEBUG_NAME_COUNTERS) {
+                ctr = DEBUG_NAME_COUNTERS.get(debugNameStem);
+                if (ctr == null)  ctr = 0;
+                DEBUG_NAME_COUNTERS.put(debugNameStem, ctr+1);
+            }
+            StringBuilder buf = new StringBuilder(debugNameStem);
+            buf.append('_');
+            int leadingZero = buf.length();
+            buf.append((int) ctr);
+            for (int i = buf.length() - leadingZero; i < 3; i++)
+                buf.insert(leadingZero, '0');
+            if (under < length) {
+                ++under;    // skip "_"
+                while (under < length && Character.isDigit(debugName.charAt(under))) {
+                    ++under;
+                }
+                if (under < length && debugName.charAt(under) == '_')  ++under;
+                if (under < length)
+                    buf.append('_').append(debugName, under, length);
+            }
+            return buf.toString();
         }
-        return result;
+        return debugName;
     }
 
     private static boolean namesOK(int arity, Name[] names) {
@@ -294,14 +431,14 @@
     // }
 
     /** Report the return type. */
-    char returnType() {
-        if (result < 0)  return 'V';
+    BasicType returnType() {
+        if (result < 0)  return V_TYPE;
         Name n = names[result];
         return n.type;
     }
 
     /** Report the N-th argument type. */
-    char parameterType(int n) {
+    BasicType parameterType(int n) {
         assert(n < arity);
         return names[n].type;
     }
@@ -319,15 +456,15 @@
     final String basicTypeSignature() {
         StringBuilder buf = new StringBuilder(arity() + 3);
         for (int i = 0, a = arity(); i < a; i++)
-            buf.append(parameterType(i));
-        return buf.append('_').append(returnType()).toString();
+            buf.append(parameterType(i).basicTypeChar());
+        return buf.append('_').append(returnType().basicTypeChar()).toString();
     }
     static int signatureArity(String sig) {
         assert(isValidSignature(sig));
         return sig.indexOf('_');
     }
-    static char signatureReturn(String sig) {
-        return sig.charAt(signatureArity(sig)+1);
+    static BasicType signatureReturn(String sig) {
+        return basicType(sig.charAt(signatureArity(sig)+1));
     }
     static boolean isValidSignature(String sig) {
         int arity = sig.indexOf('_');
@@ -339,27 +476,15 @@
             char c = sig.charAt(i);
             if (c == 'V')
                 return (i == siglen - 1 && arity == siglen - 2);
-            if (ALL_TYPES.indexOf(c) < 0)  return false; // must be [LIJFD]
+            if (!isArgBasicTypeChar(c))  return false; // must be [LIJFD]
         }
         return true;  // [LIJFD]*_[LIJFDV]
     }
-    static Class<?> typeClass(char t) {
-        switch (t) {
-        case 'I': return int.class;
-        case 'J': return long.class;
-        case 'F': return float.class;
-        case 'D': return double.class;
-        case 'L': return Object.class;
-        case 'V': return void.class;
-        default: assert false;
-        }
-        return null;
-    }
     static MethodType signatureType(String sig) {
         Class<?>[] ptypes = new Class<?>[signatureArity(sig)];
         for (int i = 0; i < ptypes.length; i++)
-            ptypes[i] = typeClass(sig.charAt(i));
-        Class<?> rtype = typeClass(signatureReturn(sig));
+            ptypes[i] = basicType(sig.charAt(i)).btClass;
+        Class<?> rtype = signatureReturn(sig).btClass;
         return MethodType.methodType(rtype, ptypes);
     }
 
@@ -543,21 +668,21 @@
         assert(mt.parameterCount() == arity-1);
         for (int i = 0; i < av.length; i++) {
             Class<?> pt = (i == 0 ? MethodHandle.class : mt.parameterType(i-1));
-            assert(valueMatches(sig.charAt(i), pt, av[i]));
+            assert(valueMatches(basicType(sig.charAt(i)), pt, av[i]));
         }
         return true;
     }
-    private static boolean valueMatches(char tc, Class<?> type, Object x) {
+    private static boolean valueMatches(BasicType tc, Class<?> type, Object x) {
         // The following line is needed because (...)void method handles can use non-void invokers
-        if (type == void.class)  tc = 'V';   // can drop any kind of value
+        if (type == void.class)  tc = V_TYPE;   // can drop any kind of value
         assert tc == basicType(type) : tc + " == basicType(" + type + ")=" + basicType(type);
         switch (tc) {
-        case 'I': assert checkInt(type, x)   : "checkInt(" + type + "," + x +")";   break;
-        case 'J': assert x instanceof Long   : "instanceof Long: " + x;             break;
-        case 'F': assert x instanceof Float  : "instanceof Float: " + x;            break;
-        case 'D': assert x instanceof Double : "instanceof Double: " + x;           break;
-        case 'L': assert checkRef(type, x)   : "checkRef(" + type + "," + x + ")";  break;
-        case 'V': break;  // allow anything here; will be dropped
+        case I_TYPE: assert checkInt(type, x)   : "checkInt(" + type + "," + x +")";   break;
+        case J_TYPE: assert x instanceof Long   : "instanceof Long: " + x;             break;
+        case F_TYPE: assert x instanceof Float  : "instanceof Float: " + x;            break;
+        case D_TYPE: assert x instanceof Double : "instanceof Double: " + x;           break;
+        case L_TYPE: assert checkRef(type, x)   : "checkRef(" + type + "," + x + ")";  break;
+        case V_TYPE: break;  // allow anything here; will be dropped
         default:  assert(false);
         }
         return true;
@@ -736,7 +861,7 @@
      * The first parameter to a LambdaForm, a0:L, always represents the form's method handle, so 0 is not
      * accepted as valid.
      */
-    LambdaForm bindImmediate(int pos, char basicType, Object value) {
+    LambdaForm bindImmediate(int pos, BasicType basicType, Object value) {
         // must be an argument, and the types must match
         assert pos > 0 && pos < arity && names[pos].type == basicType && Name.typesMatch(basicType, value);
 
@@ -782,8 +907,8 @@
 
     LambdaForm bind(int namePos, BoundMethodHandle.SpeciesData oldData) {
         Name name = names[namePos];
-        BoundMethodHandle.SpeciesData newData = oldData.extendWithType(name.type);
-        return bind(name, newData.getterName(names[0], oldData.fieldCount()), oldData, newData);
+        BoundMethodHandle.SpeciesData newData = oldData.extendWith(name.type);
+        return bind(name, new Name(newData.getterFunction(oldData.fieldCount()), names[0]), oldData, newData);
     }
     LambdaForm bind(Name name, Name binding,
                     BoundMethodHandle.SpeciesData oldData,
@@ -874,7 +999,7 @@
         return false;
     }
 
-    LambdaForm addArguments(int pos, char... types) {
+    LambdaForm addArguments(int pos, BasicType... types) {
         assert(pos <= arity);
         int length = names.length;
         int inTypes = types.length;
@@ -895,13 +1020,10 @@
     }
 
     LambdaForm addArguments(int pos, List<Class<?>> types) {
-        char[] basicTypes = new char[types.size()];
-        for (int i = 0; i < basicTypes.length; i++)
-            basicTypes[i] = basicType(types.get(i));
-        return addArguments(pos, basicTypes);
+        return addArguments(pos, basicTypes(types));
     }
 
-    LambdaForm permuteArguments(int skip, int[] reorder, char[] types) {
+    LambdaForm permuteArguments(int skip, int[] reorder, BasicType[] types) {
         // Note:  When inArg = reorder[outArg], outArg is fed by a copy of inArg.
         // The types are the types of the new (incoming) arguments.
         int length = names.length;
@@ -960,7 +1082,7 @@
         return new LambdaForm(debugName, arity2, names2, result2);
     }
 
-    static boolean permutedTypesMatch(int[] reorder, char[] types, Name[] names, int skip) {
+    static boolean permutedTypesMatch(int[] reorder, BasicType[] types, Name[] names, int skip) {
         int inTypes = types.length;
         int outArgs = reorder.length;
         for (int i = 0; i < outArgs; i++) {
@@ -1044,7 +1166,7 @@
                     String sig = m.getName().substring("invoke_".length());
                     int arity = LambdaForm.signatureArity(sig);
                     MethodType srcType = MethodType.genericMethodType(arity);
-                    if (LambdaForm.signatureReturn(sig) == 'V')
+                    if (LambdaForm.signatureReturn(sig) == V_TYPE)
                         srcType = srcType.changeReturnType(void.class);
                     MethodTypeForm typeForm = srcType.form();
                     typeForm.namedFunctionInvoker = DirectMethodHandle.make(m);
@@ -1134,7 +1256,7 @@
             MethodHandle mh2 = typeForm.namedFunctionInvoker;
             if (mh2 != null)  return mh2;  // benign race
             if (!mh.type().equals(INVOKER_METHOD_TYPE))
-                throw new InternalError(mh.debugString());
+                throw newInternalError(mh.debugString());
             return typeForm.namedFunctionInvoker = mh;
         }
 
@@ -1193,11 +1315,6 @@
             return true;
         }
 
-        String basicTypeSignature() {
-            //return LambdaForm.basicTypeSignature(resolvedHandle.type());
-            return LambdaForm.basicTypeSignature(methodType());
-        }
-
         MethodType methodType() {
             if (resolvedHandle != null)
                 return resolvedHandle.type();
@@ -1224,18 +1341,15 @@
             return (member == null) ? null : member.getDeclaringClass();
         }
 
-        char returnType() {
+        BasicType returnType() {
             return basicType(methodType().returnType());
         }
 
-        char parameterType(int n) {
+        BasicType parameterType(int n) {
             return basicType(methodType().parameterType(n));
         }
 
         int arity() {
-            //int siglen = member.getMethodType().parameterCount();
-            //if (!member.isStatic())  siglen += 1;
-            //return siglen;
             return methodType().parameterCount();
         }
 
@@ -1243,44 +1357,63 @@
             if (member == null)  return String.valueOf(resolvedHandle);
             return member.getDeclaringClass().getSimpleName()+"."+member.getName();
         }
-    }
 
-    void resolve() {
-        for (Name n : names) n.resolve();
+        public boolean isIdentity() {
+            return this.equals(identity(returnType()));
+        }
+
+        public boolean isConstantZero() {
+            return this.equals(constantZero(returnType()));
+        }
     }
 
-    public static char basicType(Class<?> type) {
-        char c = Wrapper.basicTypeChar(type);
-        if ("ZBSC".indexOf(c) >= 0)  c = 'I';
-        assert("LIJFDV".indexOf(c) >= 0);
-        return c;
-    }
-    public static char[] basicTypes(List<Class<?>> types) {
-        char[] btypes = new char[types.size()];
-        for (int i = 0; i < btypes.length; i++) {
-            btypes[i] = basicType(types.get(i));
-        }
-        return btypes;
-    }
     public static String basicTypeSignature(MethodType type) {
         char[] sig = new char[type.parameterCount() + 2];
         int sigp = 0;
         for (Class<?> pt : type.parameterList()) {
-            sig[sigp++] = basicType(pt);
+            sig[sigp++] = basicTypeChar(pt);
         }
         sig[sigp++] = '_';
-        sig[sigp++] = basicType(type.returnType());
+        sig[sigp++] = basicTypeChar(type.returnType());
         assert(sigp == sig.length);
         return String.valueOf(sig);
     }
+    public static String shortenSignature(String signature) {
+        // Hack to make signatures more readable when they show up in method names.
+        final int NO_CHAR = -1, MIN_RUN = 3;
+        int c0, c1 = NO_CHAR, c1reps = 0;
+        StringBuilder buf = null;
+        int len = signature.length();
+        if (len < MIN_RUN)  return signature;
+        for (int i = 0; i <= len; i++) {
+            // shift in the next char:
+            c0 = c1; c1 = (i == len ? NO_CHAR : signature.charAt(i));
+            if (c1 == c0) { ++c1reps; continue; }
+            // shift in the next count:
+            int c0reps = c1reps; c1reps = 1;
+            // end of a  character run
+            if (c0reps < MIN_RUN) {
+                if (buf != null) {
+                    while (--c0reps >= 0)
+                        buf.append((char)c0);
+                }
+                continue;
+            }
+            // found three or more in a row
+            if (buf == null)
+                buf = new StringBuilder().append(signature, 0, i - c0reps);
+            buf.append((char)c0).append(c0reps);
+        }
+        return (buf == null) ? signature : buf.toString();
+    }
 
     static final class Name {
-        final char type;
+        final BasicType type;
         private short index;
         final NamedFunction function;
         @Stable final Object[] arguments;
 
-        private Name(int index, char type, NamedFunction function, Object[] arguments) {
+        private Name(int index, BasicType type, NamedFunction function, Object[] arguments) {
             this.index = (short)index;
             this.type = type;
             this.function = function;
@@ -1292,7 +1425,7 @@
         }
         Name(MethodType functionType, Object... arguments) {
             this(new NamedFunction(functionType), arguments);
-            assert(arguments[0] instanceof Name && ((Name)arguments[0]).type == 'L');
+            assert(arguments[0] instanceof Name && ((Name)arguments[0]).type == L_TYPE);
         }
         Name(MemberName function, Object... arguments) {
             this(new NamedFunction(function), arguments);
@@ -1303,14 +1436,14 @@
             for (int i = 0; i < arguments.length; i++)
                 assert(typesMatch(function.parameterType(i), arguments[i])) : "types don't match: function.parameterType(" + i + ")=" + function.parameterType(i) + ", arguments[" + i + "]=" + arguments[i] + " in " + debugString();
         }
-        Name(int index, char type) {
+        /** Create a raw parameter of the given type, with an expected index. */
+        Name(int index, BasicType type) {
             this(index, type, null, null);
         }
-        Name(char type) {
-            this(-1, type);
-        }
+        /** Create a raw parameter of the given type. */
+        Name(BasicType type) { this(-1, type); }
 
-        char type() { return type; }
+        BasicType type() { return type; }
         int index() { return index; }
         boolean initIndex(int i) {
             if (index != i) {
@@ -1319,7 +1452,9 @@
             }
             return true;
         }
-
+        char typeChar() {
+            return type.btChar;
+        }
 
         void resolve() {
             if (function != null)
@@ -1397,18 +1532,18 @@
             return function == null;
         }
         boolean isConstantZero() {
-            return !isParam() && arguments.length == 0 && function.equals(constantZero(0, type).function);
+            return !isParam() && arguments.length == 0 && function.isConstantZero();
         }
 
         public String toString() {
-            return (isParam()?"a":"t")+(index >= 0 ? index : System.identityHashCode(this))+":"+type;
+            return (isParam()?"a":"t")+(index >= 0 ? index : System.identityHashCode(this))+":"+typeChar();
         }
         public String debugString() {
             String s = toString();
             return (function == null) ? s : s + "=" + exprString();
         }
         public String exprString() {
-            if (function == null)  return "null";
+            if (function == null)  return toString();
             StringBuilder buf = new StringBuilder(function.toString());
             buf.append("(");
             String cma = "";
@@ -1423,17 +1558,17 @@
             return buf.toString();
         }
 
-        private static boolean typesMatch(char parameterType, Object object) {
+        static boolean typesMatch(BasicType parameterType, Object object) {
             if (object instanceof Name) {
                 return ((Name)object).type == parameterType;
             }
             switch (parameterType) {
-                case 'I':  return object instanceof Integer;
-                case 'J':  return object instanceof Long;
-                case 'F':  return object instanceof Float;
-                case 'D':  return object instanceof Double;
+                case I_TYPE:  return object instanceof Integer;
+                case J_TYPE:  return object instanceof Long;
+                case F_TYPE:  return object instanceof Float;
+                case D_TYPE:  return object instanceof Double;
             }
-            assert(parameterType == 'L');
+            assert(parameterType == L_TYPE);
             return true;
         }
 
@@ -1510,7 +1645,7 @@
         @Override
         public int hashCode() {
             if (isParam())
-                return index | (type << 8);
+                return index | (type.ordinal() << 8);
             return function.hashCode() ^ Arrays.hashCode(arguments);
         }
     }
@@ -1545,10 +1680,12 @@
     }
 
     static Name argument(int which, char type) {
-        int tn = ALL_TYPES.indexOf(type);
-        if (tn < 0 || which >= INTERNED_ARGUMENT_LIMIT)
+        return argument(which, basicType(type));
+    }
+    static Name argument(int which, BasicType type) {
+        if (which >= INTERNED_ARGUMENT_LIMIT)
             return new Name(which, type);
-        return INTERNED_ARGUMENTS[tn][which];
+        return INTERNED_ARGUMENTS[type.ordinal()][which];
     }
     static Name internArgument(Name n) {
         assert(n.isParam()) : "not param: " + n;
@@ -1590,56 +1727,118 @@
             names[i] = argument(i, basicType(types.parameterType(i)));
         return names;
     }
-    static final String ALL_TYPES = "LIJFD";  // omit V, not an argument type
     static final int INTERNED_ARGUMENT_LIMIT = 10;
     private static final Name[][] INTERNED_ARGUMENTS
-            = new Name[ALL_TYPES.length()][INTERNED_ARGUMENT_LIMIT];
+            = new Name[ARG_TYPE_LIMIT][INTERNED_ARGUMENT_LIMIT];
     static {
-        for (int tn = 0; tn < ALL_TYPES.length(); tn++) {
-            for (int i = 0; i < INTERNED_ARGUMENTS[tn].length; i++) {
-                char type = ALL_TYPES.charAt(tn);
-                INTERNED_ARGUMENTS[tn][i] = new Name(i, type);
+        for (BasicType type : BasicType.ARG_TYPES) {
+            int ord = type.ordinal();
+            for (int i = 0; i < INTERNED_ARGUMENTS[ord].length; i++) {
+                INTERNED_ARGUMENTS[ord][i] = new Name(i, type);
             }
         }
     }
 
     private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
 
-    static Name constantZero(int which, char type) {
-        return CONSTANT_ZERO[ALL_TYPES.indexOf(type)].newIndex(which);
+    static LambdaForm identityForm(BasicType type) {
+        return LF_identityForm[type.ordinal()];
+    }
+    static LambdaForm zeroForm(BasicType type) {
+        return LF_zeroForm[type.ordinal()];
+    }
+    static NamedFunction identity(BasicType type) {
+        return NF_identity[type.ordinal()];
+    }
+    static NamedFunction constantZero(BasicType type) {
+        return NF_zero[type.ordinal()];
     }
-    private static final Name[] CONSTANT_ZERO
-            = new Name[ALL_TYPES.length()];
-    static {
-        for (int tn = 0; tn < ALL_TYPES.length(); tn++) {
-            char bt = ALL_TYPES.charAt(tn);
-            Wrapper wrap = Wrapper.forBasicType(bt);
-            MemberName zmem = new MemberName(LambdaForm.class, "zero"+bt, MethodType.methodType(wrap.primitiveType()), REF_invokeStatic);
+    private static final LambdaForm[] LF_identityForm = new LambdaForm[TYPE_LIMIT];
+    private static final LambdaForm[] LF_zeroForm = new LambdaForm[TYPE_LIMIT];
+    private static final NamedFunction[] NF_identity = new NamedFunction[TYPE_LIMIT];
+    private static final NamedFunction[] NF_zero = new NamedFunction[TYPE_LIMIT];
+    private static void createIdentityForms() {
+        for (BasicType type : BasicType.ALL_TYPES) {
+            int ord = type.ordinal();
+            char btChar = type.basicTypeChar();
+            boolean isVoid = (type == V_TYPE);
+            Class<?> btClass = type.btClass;
+            MethodType zeType = MethodType.methodType(btClass);
+            MethodType idType = isVoid ? zeType : zeType.appendParameterTypes(btClass);
+
+            // Look up some 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 = new MemberName(LambdaForm.class, "zero_"+btChar, zeType, REF_invokeStatic);
             try {
-                zmem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, zmem, null, NoSuchMethodException.class);
+                zeMem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, zeMem, null, NoSuchMethodException.class);
+                idMem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, idMem, null, NoSuchMethodException.class);
             } catch (IllegalAccessException|NoSuchMethodException ex) {
                 throw newInternalError(ex);
             }
-            NamedFunction zcon = new NamedFunction(zmem);
-            Name n = new Name(zcon).newIndex(0);
-            assert(n.type == ALL_TYPES.charAt(tn));
-            CONSTANT_ZERO[tn] = n;
-            assert(n.isConstantZero());
+
+            NamedFunction idFun = new NamedFunction(idMem);
+            LambdaForm idForm;
+            if (isVoid) {
+                Name[] idNames = new Name[] { argument(0, L_TYPE) };
+                idForm = new LambdaForm(idMem.getName(), 1, idNames, VOID_RESULT);
+            } else {
+                Name[] idNames = new Name[] { argument(0, L_TYPE), argument(1, type) };
+                idForm = new LambdaForm(idMem.getName(), 2, idNames, 1);
+            }
+            LF_identityForm[ord] = idForm;
+            NF_identity[ord] = idFun;
+
+            NamedFunction zeFun = new NamedFunction(zeMem);
+            LambdaForm zeForm;
+            if (isVoid) {
+                zeForm = idForm;
+            } else {
+                Object zeValue = Wrapper.forBasicType(btChar).zero();
+                Name[] zeNames = new Name[] { argument(0, L_TYPE), new Name(idFun, zeValue) };
+                zeForm = new LambdaForm(zeMem.getName(), 1, zeNames, 1);
+            }
+            LF_zeroForm[ord] = zeForm;
+            NF_zero[ord] = zeFun;
+
+            assert(idFun.isIdentity());
+            assert(zeFun.isConstantZero());
+            assert(new Name(zeFun).isConstantZero());
+        }
+
+        // Do this in a separate pass, so that SimpleMethodHandle.make can see the tables.
+        for (BasicType type : BasicType.ALL_TYPES) {
+            int ord = type.ordinal();
+            NamedFunction idFun = NF_identity[ord];
+            LambdaForm idForm = LF_identityForm[ord];
+            MemberName idMem = idFun.member;
+            idFun.resolvedHandle = SimpleMethodHandle.make(idMem.getInvocationType(), idForm);
+
+            NamedFunction zeFun = NF_zero[ord];
+            LambdaForm zeForm = LF_zeroForm[ord];
+            MemberName zeMem = zeFun.member;
+            zeFun.resolvedHandle = SimpleMethodHandle.make(zeMem.getInvocationType(), zeForm);
+
+            assert(idFun.isIdentity());
+            assert(zeFun.isConstantZero());
+            assert(new Name(zeFun).isConstantZero());
         }
     }
 
     // Avoid appealing to ValueConversions at bootstrap time:
-    private static int zeroI() { return 0; }
-    private static long zeroJ() { return 0; }
-    private static float zeroF() { return 0; }
-    private static double zeroD() { return 0; }
-    private static Object zeroL() { return null; }
-
-    // Put this last, so that previous static inits can run before.
-    static {
-        if (USE_PREDEFINED_INTERPRET_METHODS)
-            PREPARED_FORMS.putAll(computeInitialPreparedForms());
-    }
+    private static int identity_I(int x) { return x; }
+    private static long identity_J(long x) { return x; }
+    private static float identity_F(float x) { return x; }
+    private static double identity_D(double x) { return x; }
+    private static Object identity_L(Object x) { return x; }
+    private static void identity_V() { return; }  // same as zeroV, but that's OK
+    private static int zero_I() { return 0; }
+    private static long zero_J() { return 0; }
+    private static float zero_F() { return 0; }
+    private static double zero_D() { return 0; }
+    private static Object zero_L() { return null; }
+    private static void zero_V() { return; }
 
     /**
      * Internal marker for byte-compiled LambdaForms.
@@ -1690,7 +1889,21 @@
     static final native Object linkToInterface(Object x1, MemberName mn) throws Throwable;
  */
 
-    static { NamedFunction.initializeInvokers(); }
+    private static final HashMap<String,Integer> DEBUG_NAME_COUNTERS;
+    static {
+        if (debugEnabled())
+            DEBUG_NAME_COUNTERS = new HashMap<>();
+        else
+            DEBUG_NAME_COUNTERS = null;
+    }
+
+    // Put this last, so that previous static inits can run before.
+    static {
+        createIdentityForms();
+        if (USE_PREDEFINED_INTERPRET_METHODS)
+            PREPARED_FORMS.putAll(computeInitialPreparedForms());
+        NamedFunction.initializeInvokers();
+    }
 
     // The following hack is necessary in order to suppress TRACE_INTERPRETER
     // during execution of the static initializes of this class.