8037210: Get rid of char-based descriptions 'J' of basic types
authorvlivanov
Mon, 24 Feb 2014 18:11:55 +0400
changeset 24572 5c9e5961d21c
parent 24571 e1cabb2a72ed
child 24573 fc2756f8dfef
8037210: Get rid of char-based descriptions 'J' of basic types Reviewed-by: jrose, psandoz, twisti
jdk/src/share/classes/java/lang/invoke/BoundMethodHandle.java
jdk/src/share/classes/java/lang/invoke/DirectMethodHandle.java
jdk/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
jdk/src/share/classes/java/lang/invoke/LambdaForm.java
jdk/src/share/classes/java/lang/invoke/MethodHandle.java
jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java
jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java
jdk/src/share/classes/java/lang/invoke/MethodHandleStatics.java
jdk/src/share/classes/java/lang/invoke/MethodHandles.java
jdk/src/share/classes/java/lang/invoke/SimpleMethodHandle.java
jdk/test/java/lang/invoke/LambdaFormTest.java
--- a/jdk/src/share/classes/java/lang/invoke/BoundMethodHandle.java	Mon May 26 19:59:28 2014 +0400
+++ b/jdk/src/share/classes/java/lang/invoke/BoundMethodHandle.java	Mon Feb 24 18:11:55 2014 +0400
@@ -26,11 +26,10 @@
 package java.lang.invoke;
 
 import static jdk.internal.org.objectweb.asm.Opcodes.*;
-import static java.lang.invoke.LambdaForm.basicTypes;
-import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;
+import static java.lang.invoke.LambdaForm.*;
+import static java.lang.invoke.LambdaForm.BasicType.*;
 import static java.lang.invoke.MethodHandleStatics.*;
 
-import java.lang.invoke.LambdaForm.Name;
 import java.lang.invoke.LambdaForm.NamedFunction;
 import java.lang.invoke.MethodHandles.Lookup;
 import java.lang.reflect.Field;
@@ -61,22 +60,22 @@
     // BMH API and internals
     //
 
-    static MethodHandle bindSingle(MethodType type, LambdaForm form, char xtype, Object x) {
+    static MethodHandle bindSingle(MethodType type, LambdaForm form, BasicType xtype, Object x) {
         // for some type signatures, there exist pre-defined concrete BMH classes
         try {
             switch (xtype) {
-            case 'L':
+            case L_TYPE:
                 if (true)  return bindSingle(type, form, x);  // Use known fast path.
-                return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('L').constructor[0].invokeBasic(type, form, x);
-            case 'I':
-                return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('I').constructor[0].invokeBasic(type, form, ValueConversions.widenSubword(x));
-            case 'J':
-                return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('J').constructor[0].invokeBasic(type, form, (long) x);
-            case 'F':
-                return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('F').constructor[0].invokeBasic(type, form, (float) x);
-            case 'D':
-                return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('D').constructor[0].invokeBasic(type, form, (double) x);
-            default : throw new InternalError("unexpected xtype: " + xtype);
+                return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(L_TYPE).constructor[0].invokeBasic(type, form, x);
+            case I_TYPE:
+                return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(I_TYPE).constructor[0].invokeBasic(type, form, ValueConversions.widenSubword(x));
+            case J_TYPE:
+                return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(J_TYPE).constructor[0].invokeBasic(type, form, (long) x);
+            case F_TYPE:
+                return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(F_TYPE).constructor[0].invokeBasic(type, form, (float) x);
+            case D_TYPE:
+                return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(D_TYPE).constructor[0].invokeBasic(type, form, (double) x);
+            default : throw newInternalError("unexpected xtype: " + xtype);
             }
         } catch (Throwable t) {
             throw newInternalError(t);
@@ -87,23 +86,23 @@
             return new Species_L(type, form, x);
     }
 
-    MethodHandle cloneExtend(MethodType type, LambdaForm form, char xtype, Object x) {
+    MethodHandle cloneExtend(MethodType type, LambdaForm form, BasicType xtype, Object x) {
         try {
             switch (xtype) {
-            case 'L': return cloneExtendL(type, form, x);
-            case 'I': return cloneExtendI(type, form, ValueConversions.widenSubword(x));
-            case 'J': return cloneExtendJ(type, form, (long) x);
-            case 'F': return cloneExtendF(type, form, (float) x);
-            case 'D': return cloneExtendD(type, form, (double) x);
+            case L_TYPE: return copyWithExtendL(type, form, x);
+            case I_TYPE: return copyWithExtendI(type, form, ValueConversions.widenSubword(x));
+            case J_TYPE: return copyWithExtendJ(type, form, (long) x);
+            case F_TYPE: return copyWithExtendF(type, form, (float) x);
+            case D_TYPE: return copyWithExtendD(type, form, (double) x);
             }
         } catch (Throwable t) {
             throw newInternalError(t);
         }
-        throw new InternalError("unexpected type: " + xtype);
+        throw newInternalError("unexpected type: " + xtype);
     }
 
     @Override
-    MethodHandle bindArgument(int pos, char basicType, Object value) {
+    MethodHandle bindArgument(int pos, BasicType basicType, Object value) {
         MethodType type = type().dropParameterTypes(pos, pos+1);
         LambdaForm form = internalForm().bind(1+pos, speciesData());
         return cloneExtend(type, form, basicType, value);
@@ -111,9 +110,9 @@
 
     @Override
     MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
-        LambdaForm form = internalForm().addArguments(pos, srcType.parameterList().subList(pos, pos+drops));
+        LambdaForm form = internalForm().addArguments(pos, srcType.parameterList().subList(pos, pos + drops));
         try {
-             return clone(srcType, form);
+             return copyWith(srcType, form);
          } catch (Throwable t) {
              throw newInternalError(t);
          }
@@ -122,26 +121,23 @@
     @Override
     MethodHandle permuteArguments(MethodType newType, int[] reorder) {
         try {
-             return clone(newType, form.permuteArguments(1, reorder, basicTypes(newType.parameterList())));
+             return copyWith(newType, form.permuteArguments(1, reorder, basicTypes(newType.parameterList())));
          } catch (Throwable t) {
              throw newInternalError(t);
          }
     }
 
-    static final String EXTENSION_TYPES = "LIJFD";
-    static final byte INDEX_L = 0, INDEX_I = 1, INDEX_J = 2, INDEX_F = 3, INDEX_D = 4;
-    static byte extensionIndex(char type) {
-        int i = EXTENSION_TYPES.indexOf(type);
-        if (i < 0)  throw new InternalError();
-        return (byte) i;
-    }
-
     /**
      * Return the {@link SpeciesData} instance representing this BMH species. All subclasses must provide a
      * static field containing this value, and they must accordingly implement this method.
      */
     /*non-public*/ abstract SpeciesData speciesData();
 
+    /**
+     * Return the number of fields in this BMH.  Equivalent to speciesData().fieldCount().
+     */
+    /*non-public*/ abstract int fieldCount();
+
     @Override
     final Object internalProperties() {
         return "/BMH="+internalValues();
@@ -159,38 +155,33 @@
     /*non-public*/ final Object arg(int i) {
         try {
             switch (speciesData().fieldType(i)) {
-            case 'L': return argL(i);
-            case 'I': return argI(i);
-            case 'F': return argF(i);
-            case 'D': return argD(i);
-            case 'J': return argJ(i);
+            case L_TYPE: return          speciesData().getters[i].invokeBasic(this);
+            case I_TYPE: return (int)    speciesData().getters[i].invokeBasic(this);
+            case J_TYPE: return (long)   speciesData().getters[i].invokeBasic(this);
+            case F_TYPE: return (float)  speciesData().getters[i].invokeBasic(this);
+            case D_TYPE: return (double) speciesData().getters[i].invokeBasic(this);
             }
         } catch (Throwable ex) {
             throw newInternalError(ex);
         }
-        throw new InternalError("unexpected type: " + speciesData().types+"."+i);
+        throw new InternalError("unexpected type: " + speciesData().typeChars+"."+i);
     }
-    /*non-public*/ final Object argL(int i) throws Throwable { return          speciesData().getters[i].invokeBasic(this); }
-    /*non-public*/ final int    argI(int i) throws Throwable { return (int)    speciesData().getters[i].invokeBasic(this); }
-    /*non-public*/ final float  argF(int i) throws Throwable { return (float)  speciesData().getters[i].invokeBasic(this); }
-    /*non-public*/ final double argD(int i) throws Throwable { return (double) speciesData().getters[i].invokeBasic(this); }
-    /*non-public*/ final long   argJ(int i) throws Throwable { return (long)   speciesData().getters[i].invokeBasic(this); }
 
     //
     // cloning API
     //
 
-    /*non-public*/ abstract BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable;
-    /*non-public*/ abstract BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable;
-    /*non-public*/ abstract BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int    narg) throws Throwable;
-    /*non-public*/ abstract BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long   narg) throws Throwable;
-    /*non-public*/ abstract BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float  narg) throws Throwable;
-    /*non-public*/ abstract BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable;
+    /*non-public*/ abstract BoundMethodHandle copyWith(MethodType mt, LambdaForm lf);
+    /*non-public*/ abstract BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg);
+    /*non-public*/ abstract BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int    narg);
+    /*non-public*/ abstract BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long   narg);
+    /*non-public*/ abstract BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float  narg);
+    /*non-public*/ abstract BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg);
 
     // The following is a grossly irregular hack:
     @Override MethodHandle reinvokerTarget() {
         try {
-            return (MethodHandle) argL(0);
+            return (MethodHandle) arg(0);
         } catch (Throwable ex) {
             throw newInternalError(ex);
         }
@@ -203,7 +194,7 @@
     private  // make it private to force users to access the enclosing class first
     static final class Species_L extends BoundMethodHandle {
         final Object argL0;
-        /*non-public*/ Species_L(MethodType mt, LambdaForm lf, Object argL0) {
+        private Species_L(MethodType mt, LambdaForm lf, Object argL0) {
             super(mt, lf);
             this.argL0 = argL0;
         }
@@ -213,140 +204,95 @@
         /*non-public*/ SpeciesData speciesData() {
             return SPECIES_DATA;
         }
-        /*non-public*/ static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("L", Species_L.class);
         @Override
-        /*non-public*/ final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
+        /*non-public*/ int fieldCount() {
+            return 1;
+        }
+        /*non-public*/ static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("L", Species_L.class);
+        /*non-public*/ static BoundMethodHandle make(MethodType mt, LambdaForm lf, Object argL0) {
+            return new Species_L(mt, lf, argL0);
+        }
+        @Override
+        /*non-public*/ final BoundMethodHandle copyWith(MethodType mt, LambdaForm lf) {
             return new Species_L(mt, lf, argL0);
         }
         @Override
-        /*non-public*/ final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, narg);
-        }
-        @Override
-        /*non-public*/ final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, narg);
-        }
-        @Override
-        /*non-public*/ final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, narg);
-        }
-        @Override
-        /*non-public*/ final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, narg);
+        /*non-public*/ final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) {
+            try {
+                return (BoundMethodHandle) SPECIES_DATA.extendWith(L_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
+            } catch (Throwable ex) {
+                throw uncaughtException(ex);
+            }
         }
         @Override
-        /*non-public*/ final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, narg);
-        }
-    }
-
-/*
-    static final class Species_LL extends BoundMethodHandle {
-        final Object argL0;
-        final Object argL1;
-        public Species_LL(MethodType mt, LambdaForm lf, Object argL0, Object argL1) {
-            super(mt, lf);
-            this.argL0 = argL0;
-            this.argL1 = argL1;
-        }
-        @Override
-        public SpeciesData speciesData() {
-            return SPECIES_DATA;
-        }
-        public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("LL", Species_LL.class);
-        @Override
-        public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
-            return new Species_LL(mt, lf, argL0, argL1);
-        }
-        @Override
-        public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
-        }
-        @Override
-        public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
+        /*non-public*/ final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) {
+            try {
+                return (BoundMethodHandle) SPECIES_DATA.extendWith(I_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
+            } catch (Throwable ex) {
+                throw uncaughtException(ex);
+            }
         }
         @Override
-        public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
-        }
-        @Override
-        public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
-        }
-        @Override
-        public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
-        }
-    }
-
-    static final class Species_JL extends BoundMethodHandle {
-        final long argJ0;
-        final Object argL1;
-        public Species_JL(MethodType mt, LambdaForm lf, long argJ0, Object argL1) {
-            super(mt, lf);
-            this.argJ0 = argJ0;
-            this.argL1 = argL1;
+        /*non-public*/ final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) {
+            try {
+                return (BoundMethodHandle) SPECIES_DATA.extendWith(J_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
+            } catch (Throwable ex) {
+                throw uncaughtException(ex);
+            }
         }
         @Override
-        public SpeciesData speciesData() {
-            return SPECIES_DATA;
-        }
-        public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("JL", Species_JL.class);
-        @Override public final long   argJ0() { return argJ0; }
-        @Override public final Object argL1() { return argL1; }
-        @Override
-        public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
-            return new Species_JL(mt, lf, argJ0, argL1);
-        }
-        @Override
-        public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
+        /*non-public*/ final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) {
+            try {
+                return (BoundMethodHandle) SPECIES_DATA.extendWith(F_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
+            } catch (Throwable ex) {
+                throw uncaughtException(ex);
+            }
         }
         @Override
-        public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
-        }
-        @Override
-        public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
-        }
-        @Override
-        public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
-        }
-        @Override
-        public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
+        /*non-public*/ final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) {
+            try {
+                return (BoundMethodHandle) SPECIES_DATA.extendWith(D_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
+            } catch (Throwable ex) {
+                throw uncaughtException(ex);
+            }
         }
     }
-*/
 
     //
     // BMH species meta-data
     //
 
     /**
-     * Meta-data wrapper for concrete BMH classes.
+     * Meta-data wrapper for concrete BMH types.
+     * Each BMH type corresponds to a given sequence of basic field types (LIJFD).
+     * The fields are immutable; their values are fully specified at object construction.
+     * Each BMH type supplies an array of getter functions which may be used in lambda forms.
+     * A BMH is constructed by cloning a shorter BMH and adding one or more new field values.
+     * As a degenerate and common case, the "shorter BMH" can be missing, and contributes zero prior fields.
      */
     static class SpeciesData {
-        final String                             types;
+        final String                             typeChars;
+        final BasicType[]                        typeCodes;
         final Class<? extends BoundMethodHandle> clazz;
         // Bootstrapping requires circular relations MH -> BMH -> SpeciesData -> MH
         // Therefore, we need a non-final link in the chain.  Use array elements.
         final MethodHandle[]                     constructor;
         final MethodHandle[]                     getters;
+        final NamedFunction[]                    nominalGetters;
         final SpeciesData[]                      extensions;
 
         /*non-public*/ int fieldCount() {
-            return types.length();
+            return typeCodes.length;
         }
-        /*non-public*/ char fieldType(int i) {
-            return types.charAt(i);
+        /*non-public*/ BasicType fieldType(int i) {
+            return typeCodes[i];
+        }
+        /*non-public*/ char fieldTypeChar(int i) {
+            return typeChars.charAt(i);
         }
 
         public String toString() {
-            return "SpeciesData["+(isPlaceholder() ? "<placeholder>" : clazz.getSimpleName())+":"+types+"]";
+            return "SpeciesData["+(isPlaceholder() ? "<placeholder>" : clazz.getSimpleName())+":"+typeChars+"]";
         }
 
         /**
@@ -354,45 +300,46 @@
          * represents a MH bound to a generic invoker, which in turn forwards to the corresponding
          * getter.
          */
-        Name getterName(Name mhName, int i) {
-            MethodHandle mh = getters[i];
-            assert(mh != null) : this+"."+i;
-            return new Name(mh, mhName);
-        }
-
         NamedFunction getterFunction(int i) {
-            return new NamedFunction(getters[i]);
+            return nominalGetters[i];
         }
 
         static final SpeciesData EMPTY = new SpeciesData("", BoundMethodHandle.class);
 
         private SpeciesData(String types, Class<? extends BoundMethodHandle> clazz) {
-            this.types = types;
+            this.typeChars = types;
+            this.typeCodes = basicTypes(types);
             this.clazz = clazz;
             if (!INIT_DONE) {
-                this.constructor = new MethodHandle[1];
+                this.constructor = new MethodHandle[1];  // only one ctor
                 this.getters = new MethodHandle[types.length()];
+                this.nominalGetters = new NamedFunction[types.length()];
             } else {
                 this.constructor = Factory.makeCtors(clazz, types, null);
                 this.getters = Factory.makeGetters(clazz, types, null);
+                this.nominalGetters = Factory.makeNominalGetters(types, null, this.getters);
             }
-            this.extensions = new SpeciesData[EXTENSION_TYPES.length()];
+            this.extensions = new SpeciesData[ARG_TYPE_LIMIT];
         }
 
         private void initForBootstrap() {
             assert(!INIT_DONE);
             if (constructor[0] == null) {
+                String types = typeChars;
                 Factory.makeCtors(clazz, types, this.constructor);
                 Factory.makeGetters(clazz, types, this.getters);
+                Factory.makeNominalGetters(types, this.nominalGetters, this.getters);
             }
         }
 
-        private SpeciesData(String types) {
+        private SpeciesData(String typeChars) {
             // Placeholder only.
-            this.types = types;
+            this.typeChars = typeChars;
+            this.typeCodes = basicTypes(typeChars);
             this.clazz = null;
             this.constructor = null;
             this.getters = null;
+            this.nominalGetters = null;
             this.extensions = null;
         }
         private boolean isPlaceholder() { return clazz == null; }
@@ -401,18 +348,15 @@
         static { CACHE.put("", EMPTY); }  // make bootstrap predictable
         private static final boolean INIT_DONE;  // set after <clinit> finishes...
 
-        SpeciesData extendWithType(char type) {
-            int i = extensionIndex(type);
-            SpeciesData d = extensions[i];
-            if (d != null)  return d;
-            extensions[i] = d = get(types+type);
-            return d;
+        SpeciesData extendWith(byte type) {
+            return extendWith(BasicType.basicType(type));
         }
 
-        SpeciesData extendWithIndex(byte index) {
-            SpeciesData d = extensions[index];
+        SpeciesData extendWith(BasicType type) {
+            int ord = type.ordinal();
+            SpeciesData d = extensions[ord];
             if (d != null)  return d;
-            extensions[index] = d = get(types+EXTENSION_TYPES.charAt(index));
+            extensions[ord] = d = get(typeChars+type.basicTypeChar());
             return d;
         }
 
@@ -456,8 +400,6 @@
         static {
             // pre-fill the BMH speciesdata cache with BMH's inner classes
             final Class<BoundMethodHandle> rootCls = BoundMethodHandle.class;
-            SpeciesData d0 = BoundMethodHandle.SPECIES_DATA;  // trigger class init
-            assert(d0 == null || d0 == lookupCache("")) : d0;
             try {
                 for (Class<?> c : rootCls.getDeclaredClasses()) {
                     if (rootCls.isAssignableFrom(c)) {
@@ -465,7 +407,7 @@
                         SpeciesData d = Factory.speciesDataFromConcreteBMHClass(cbmh);
                         assert(d != null) : cbmh.getName();
                         assert(d.clazz == cbmh);
-                        assert(d == lookupCache(d.types));
+                        assert(d == lookupCache(d.typeChars));
                     }
                 }
             } catch (Throwable e) {
@@ -516,11 +458,10 @@
         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";
 
         static final String SIG_INCIPIT = "(Ljava/lang/invoke/MethodType;Ljava/lang/invoke/LambdaForm;";
 
-        static final Class<?>[] TYPES = new Class<?>[] { Object.class, int.class, long.class, float.class, double.class };
-
         static final String[] E_THROWABLE = new String[] { "java/lang/Throwable" };
 
         /**
@@ -551,31 +492,35 @@
          *     final Object argL0;
          *     final Object argL1;
          *     final int argI2;
-         *     Species_LLI(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
+         *     private Species_LLI(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
          *         super(mt, lf);
          *         this.argL0 = argL0;
          *         this.argL1 = argL1;
          *         this.argI2 = argI2;
          *     }
          *     final SpeciesData speciesData() { return SPECIES_DATA; }
+         *     final int fieldCount() { return 3; }
          *     static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("LLI", Species_LLI.class);
-         *     final BoundMethodHandle clone(MethodType mt, LambdaForm lf) {
-         *         return SPECIES_DATA.constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2);
+         *     static BoundMethodHandle make(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
+         *         return new Species_LLI(mt, lf, argL0, argL1, argI2);
          *     }
-         *     final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) {
-         *         return SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
+         *     final BoundMethodHandle copyWith(MethodType mt, LambdaForm lf) {
+         *         return new Species_LLI(mt, lf, argL0, argL1, argI2);
+         *     }
+         *     final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) {
+         *         return SPECIES_DATA.extendWith(L_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
          *     }
-         *     final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) {
-         *         return SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
+         *     final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) {
+         *         return SPECIES_DATA.extendWith(I_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
          *     }
-         *     final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) {
-         *         return SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
+         *     final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) {
+         *         return SPECIES_DATA.extendWith(J_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
          *     }
-         *     final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) {
-         *         return SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
+         *     final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) {
+         *         return SPECIES_DATA.extendWith(F_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
          *     }
-         *     final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) {
-         *         return SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
+         *     public final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) {
+         *         return SPECIES_DATA.extendWith(D_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
          *     }
          * }
          * </pre>
@@ -586,8 +531,9 @@
         static Class<? extends BoundMethodHandle> generateConcreteBMHClass(String types) {
             final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
 
-            final String className  = SPECIES_PREFIX_PATH + types;
-            final String sourceFile = SPECIES_PREFIX_NAME + types;
+            String shortTypes = LambdaForm.shortenSignature(types);
+            final String className  = SPECIES_PREFIX_PATH + shortTypes;
+            final String sourceFile = SPECIES_PREFIX_NAME + shortTypes;
             final int NOT_ACC_PUBLIC = 0;  // not ACC_PUBLIC
             cw.visit(V1_6, NOT_ACC_PUBLIC + ACC_FINAL + ACC_SUPER, className, null, BMH, null);
             cw.visitSource(sourceFile, null);
@@ -606,11 +552,11 @@
             MethodVisitor mv;
 
             // emit constructor
-            mv = cw.visitMethod(NOT_ACC_PUBLIC, "<init>", makeSignature(types, true), null, null);
+            mv = cw.visitMethod(ACC_PRIVATE, "<init>", makeSignature(types, true), null, null);
             mv.visitCode();
-            mv.visitVarInsn(ALOAD, 0);
-            mv.visitVarInsn(ALOAD, 1);
-            mv.visitVarInsn(ALOAD, 2);
+            mv.visitVarInsn(ALOAD, 0); // this
+            mv.visitVarInsn(ALOAD, 1); // type
+            mv.visitVarInsn(ALOAD, 2); // form
 
             mv.visitMethodInsn(INVOKESPECIAL, BMH, "<init>", makeSignature("", true), false);
 
@@ -647,39 +593,73 @@
             mv.visitMaxs(0, 0);
             mv.visitEnd();
 
-            // emit clone()
-            mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "clone", makeSignature("", false), null, E_THROWABLE);
+            // emit implementation of fieldCount()
+            mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "fieldCount", INT_SIG, null, null);
+            mv.visitCode();
+            int fc = types.length();
+            if (fc <= (ICONST_5 - ICONST_0)) {
+                mv.visitInsn(ICONST_0 + fc);
+            } else {
+                mv.visitIntInsn(SIPUSH, fc);
+            }
+            mv.visitInsn(IRETURN);
+            mv.visitMaxs(0, 0);
+            mv.visitEnd();
+            // emit make()  ...factory method wrapping constructor
+            mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_STATIC, "make", makeSignature(types, false), null, null);
             mv.visitCode();
-            // return speciesData().constructor[0].invokeBasic(mt, lf, argL0, ...)
-            // obtain constructor
-            mv.visitVarInsn(ALOAD, 0);
-            mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
-            mv.visitFieldInsn(GETFIELD, SPECIES_DATA, "constructor", "[" + MH_SIG);
-            mv.visitInsn(ICONST_0);
-            mv.visitInsn(AALOAD);
+            // make instance
+            mv.visitTypeInsn(NEW, className);
+            mv.visitInsn(DUP);
+            // load mt, lf
+            mv.visitVarInsn(ALOAD, 0);  // type
+            mv.visitVarInsn(ALOAD, 1);  // form
+            // load factory method arguments
+            for (int i = 0, j = 0; i < types.length(); ++i, ++j) {
+                // i counts the arguments, j counts corresponding argument slots
+                char t = types.charAt(i);
+                mv.visitVarInsn(typeLoadOp(t), j + 2); // parameters start at 3
+                if (t == 'J' || t == 'D') {
+                    ++j; // adjust argument register access
+                }
+            }
+
+            // finally, invoke the constructor and return
+            mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", makeSignature(types, true), false);
+            mv.visitInsn(ARETURN);
+            mv.visitMaxs(0, 0);
+            mv.visitEnd();
+
+            // emit copyWith()
+            mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "copyWith", makeSignature("", false), null, null);
+            mv.visitCode();
+            // make instance
+            mv.visitTypeInsn(NEW, className);
+            mv.visitInsn(DUP);
             // load mt, lf
             mv.visitVarInsn(ALOAD, 1);
             mv.visitVarInsn(ALOAD, 2);
             // put fields on the stack
             emitPushFields(types, className, mv);
             // finally, invoke the constructor and return
-            mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types, false), false);
+            mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", makeSignature(types, true), false);
             mv.visitInsn(ARETURN);
             mv.visitMaxs(0, 0);
             mv.visitEnd();
 
-            // for each type, emit cloneExtendT()
-            for (Class<?> c : TYPES) {
-                char t = Wrapper.basicTypeChar(c);
-                mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "cloneExtend" + t, makeSignature(String.valueOf(t), false), null, E_THROWABLE);
+            // for each type, emit copyWithExtendT()
+            for (BasicType type : BasicType.ARG_TYPES) {
+                int ord = type.ordinal();
+                char btChar = type.basicTypeChar();
+                mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "copyWithExtend" + btChar, makeSignature(String.valueOf(btChar), false), null, E_THROWABLE);
                 mv.visitCode();
-                // return SPECIES_DATA.extendWithIndex(extensionIndex(t)).constructor[0].invokeBasic(mt, lf, argL0, ..., narg)
+                // return SPECIES_DATA.extendWith(t).constructor[0].invokeBasic(mt, lf, argL0, ..., narg)
                 // obtain constructor
                 mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
-                int iconstInsn = ICONST_0 + extensionIndex(t);
+                int iconstInsn = ICONST_0 + ord;
                 assert(iconstInsn <= ICONST_5);
                 mv.visitInsn(iconstInsn);
-                mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "extendWithIndex", BMHSPECIES_DATA_EWI_SIG, false);
+                mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "extendWith", BMHSPECIES_DATA_EWI_SIG, false);
                 mv.visitFieldInsn(GETFIELD, SPECIES_DATA, "constructor", "[" + MH_SIG);
                 mv.visitInsn(ICONST_0);
                 mv.visitInsn(AALOAD);
@@ -689,9 +669,9 @@
                 // put fields on the stack
                 emitPushFields(types, className, mv);
                 // put narg on stack
-                mv.visitVarInsn(typeLoadOp(t), 3);
+                mv.visitVarInsn(typeLoadOp(btChar), 3);
                 // finally, invoke the constructor and return
-                mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types + t, false), false);
+                mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types + btChar, false), false);
                 mv.visitInsn(ARETURN);
                 mv.visitMaxs(0, 0);
                 mv.visitEnd();
@@ -730,7 +710,7 @@
             case 'J': return LLOAD;
             case 'F': return FLOAD;
             case 'D': return DLOAD;
-            default : throw new InternalError("unrecognized type " + t);
+            default : throw newInternalError("unrecognized type " + t);
             }
         }
 
@@ -771,10 +751,19 @@
 
         static MethodHandle[] makeCtors(Class<? extends BoundMethodHandle> cbmh, String types, MethodHandle mhs[]) {
             if (mhs == null)  mhs = new MethodHandle[1];
+            if (types.equals(""))  return mhs;  // hack for empty BMH species
             mhs[0] = makeCbmhCtor(cbmh, types);
             return mhs;
         }
 
+        static NamedFunction[] makeNominalGetters(String types, NamedFunction[] nfs, MethodHandle[] getters) {
+            if (nfs == null)  nfs = new NamedFunction[types.length()];
+            for (int i = 0; i < nfs.length; ++i) {
+                nfs[i] = new NamedFunction(getters[i]);
+            }
+            return nfs;
+        }
+
         //
         // Auxiliary methods.
         //
@@ -808,52 +797,11 @@
 
         static MethodHandle makeCbmhCtor(Class<? extends BoundMethodHandle> cbmh, String types) {
             try {
-                return linkConstructor(LOOKUP.findConstructor(cbmh, MethodType.fromMethodDescriptorString(makeSignature(types, true), null)));
+                return LOOKUP.findStatic(cbmh, "make", MethodType.fromMethodDescriptorString(makeSignature(types, false), null));
             } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | TypeNotPresentException e) {
                 throw newInternalError(e);
             }
         }
-
-        /**
-         * Wrap a constructor call in a {@link LambdaForm}.
-         *
-         * If constructors ({@code <init>} methods) are called in LFs, problems might arise if the LFs
-         * are turned into bytecode, because the call to the allocator is routed through an MH, and the
-         * verifier cannot find a {@code NEW} instruction preceding the {@code INVOKESPECIAL} to
-         * {@code <init>}. To avoid this, we add an indirection by invoking {@code <init>} through
-         * {@link MethodHandle#linkToSpecial}.
-         *
-         * The last {@link LambdaForm.Name Name} in the argument's form is expected to be the {@code void}
-         * result of the {@code <init>} invocation. This entry is replaced.
-         */
-        private static MethodHandle linkConstructor(MethodHandle cmh) {
-            final LambdaForm lf = cmh.form;
-            final int initNameIndex = lf.names.length - 1;
-            final Name initName = lf.names[initNameIndex];
-            final MemberName ctorMN = initName.function.member;
-            final MethodType ctorMT = ctorMN.getInvocationType();
-
-            // obtain function member (call target)
-            // linker method type replaces initial parameter (BMH species) with BMH to avoid naming a species (anonymous class!)
-            final MethodType linkerMT = ctorMT.changeParameterType(0, BoundMethodHandle.class).appendParameterTypes(MemberName.class);
-            MemberName linkerMN = new MemberName(MethodHandle.class, "linkToSpecial", linkerMT, REF_invokeStatic);
-            try {
-                linkerMN = MemberName.getFactory().resolveOrFail(REF_invokeStatic, linkerMN, null, NoSuchMethodException.class);
-                assert(linkerMN.isStatic());
-            } catch (ReflectiveOperationException ex) {
-                throw newInternalError(ex);
-            }
-            // extend arguments array
-            Object[] newArgs = Arrays.copyOf(initName.arguments, initName.arguments.length + 1);
-            newArgs[newArgs.length - 1] = ctorMN;
-            // replace function
-            final NamedFunction nf = new NamedFunction(linkerMN);
-            final Name linkedCtor = new Name(nf, newArgs);
-            linkedCtor.initIndex(initNameIndex);
-            lf.names[initNameIndex] = linkedCtor;
-            return cmh;
-        }
-
     }
 
     private static final Lookup LOOKUP = Lookup.IMPL_LOOKUP;
--- a/jdk/src/share/classes/java/lang/invoke/DirectMethodHandle.java	Mon May 26 19:59:28 2014 +0400
+++ b/jdk/src/share/classes/java/lang/invoke/DirectMethodHandle.java	Mon Feb 24 18:11:55 2014 +0400
@@ -31,6 +31,7 @@
 import sun.invoke.util.VerifyAccess;
 import static java.lang.invoke.MethodHandleNatives.Constants.*;
 import static java.lang.invoke.LambdaForm.*;
+import static java.lang.invoke.LambdaForm.BasicType.*;
 import static java.lang.invoke.MethodTypeForm.*;
 import static java.lang.invoke.MethodHandleStatics.*;
 import java.lang.ref.WeakReference;
@@ -125,11 +126,6 @@
     }
 
     @Override
-    MethodHandle copyWith(MethodType mt, LambdaForm lf) {
-        return new DirectMethodHandle(mt, lf, member);
-    }
-
-    @Override
     String internalProperties() {
         return "/DMH="+member.toString();
     }
@@ -146,9 +142,9 @@
     }
 
     @Override
-    MethodHandle bindArgument(int pos, char basicType, Object value) {
+    MethodHandle bindArgument(int pos, BasicType basicType, Object value) {
         // If the member needs dispatching, do so.
-        if (pos == 0 && basicType == 'L') {
+        if (pos == 0 && basicType == L_TYPE) {
             DirectMethodHandle concrete = maybeRebind(value);
             if (concrete != null)
                 return concrete.bindReceiver(value);
@@ -274,7 +270,7 @@
             result = NEW_OBJ;
         }
         names[LINKER_CALL] = new Name(linker, outArgs);
-        lambdaName += "_" + LambdaForm.basicTypeSignature(mtype);
+        lambdaName += "_" + shortenSignature(basicTypeSignature(mtype));
         LambdaForm lform = new LambdaForm(lambdaName, ARG_LIMIT, names, result);
         // This is a tricky bit of code.  Don't send it through the LF interpreter.
         lform.compileToBytecode();
--- a/jdk/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java	Mon May 26 19:59:28 2014 +0400
+++ b/jdk/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java	Mon Feb 24 18:11:55 2014 +0400
@@ -26,7 +26,7 @@
 package java.lang.invoke;
 
 import sun.invoke.util.VerifyAccess;
-import java.lang.invoke.LambdaForm.Name;
+import static java.lang.invoke.LambdaForm.*;
 
 import sun.invoke.util.Wrapper;
 
@@ -38,6 +38,7 @@
 import java.lang.reflect.*;
 import static java.lang.invoke.MethodHandleStatics.*;
 import static java.lang.invoke.MethodHandleNatives.Constants.*;
+import static java.lang.invoke.LambdaForm.BasicType.*;
 import sun.invoke.util.VerifyType;
 
 /**
@@ -115,7 +116,7 @@
         Name[] names = form.names;
         for (int i = 0, index = 0; i < localsMap.length; i++) {
             localsMap[i] = index;
-            index += Wrapper.forBasicType(names[i].type).stackSlots();
+            index += names[i].type.basicTypeSlots();
         }
     }
 
@@ -358,47 +359,52 @@
     /*
      * NOTE: These load/store methods use the localsMap to find the correct index!
      */
-    private void emitLoadInsn(char type, int index) {
-        int opcode;
+    private void emitLoadInsn(BasicType type, int index) {
+        int opcode = loadInsnOpcode(type);
+        mv.visitVarInsn(opcode, localsMap[index]);
+    }
+
+    private int loadInsnOpcode(BasicType type) throws InternalError {
         switch (type) {
-        case 'I':  opcode = Opcodes.ILOAD;  break;
-        case 'J':  opcode = Opcodes.LLOAD;  break;
-        case 'F':  opcode = Opcodes.FLOAD;  break;
-        case 'D':  opcode = Opcodes.DLOAD;  break;
-        case 'L':  opcode = Opcodes.ALOAD;  break;
-        default:
-            throw new InternalError("unknown type: " + type);
+            case I_TYPE: return Opcodes.ILOAD;
+            case J_TYPE: return Opcodes.LLOAD;
+            case F_TYPE: return Opcodes.FLOAD;
+            case D_TYPE: return Opcodes.DLOAD;
+            case L_TYPE: return Opcodes.ALOAD;
+            default:
+                throw new InternalError("unknown type: " + type);
         }
-        mv.visitVarInsn(opcode, localsMap[index]);
     }
     private void emitAloadInsn(int index) {
-        emitLoadInsn('L', index);
+        emitLoadInsn(L_TYPE, index);
+    }
+
+    private void emitStoreInsn(BasicType type, int index) {
+        int opcode = storeInsnOpcode(type);
+        mv.visitVarInsn(opcode, localsMap[index]);
     }
 
-    private void emitStoreInsn(char type, int index) {
-        int opcode;
+    private int storeInsnOpcode(BasicType type) throws InternalError {
         switch (type) {
-        case 'I':  opcode = Opcodes.ISTORE;  break;
-        case 'J':  opcode = Opcodes.LSTORE;  break;
-        case 'F':  opcode = Opcodes.FSTORE;  break;
-        case 'D':  opcode = Opcodes.DSTORE;  break;
-        case 'L':  opcode = Opcodes.ASTORE;  break;
-        default:
-            throw new InternalError("unknown type: " + type);
+            case I_TYPE: return Opcodes.ISTORE;
+            case J_TYPE: return Opcodes.LSTORE;
+            case F_TYPE: return Opcodes.FSTORE;
+            case D_TYPE: return Opcodes.DSTORE;
+            case L_TYPE: return Opcodes.ASTORE;
+            default:
+                throw new InternalError("unknown type: " + type);
         }
-        mv.visitVarInsn(opcode, localsMap[index]);
     }
     private void emitAstoreInsn(int index) {
-        emitStoreInsn('L', index);
+        emitStoreInsn(L_TYPE, index);
     }
 
     /**
      * Emit a boxing call.
      *
-     * @param type primitive type class to box.
+     * @param wrapper primitive type class to box.
      */
-    private void emitBoxing(Class<?> type) {
-        Wrapper wrapper = Wrapper.forPrimitiveType(type);
+    private void emitBoxing(Wrapper wrapper) {
         String owner = "java/lang/" + wrapper.wrapperType().getSimpleName();
         String name  = "valueOf";
         String desc  = "(" + wrapper.basicTypeChar() + ")L" + owner + ";";
@@ -408,10 +414,9 @@
     /**
      * Emit an unboxing call (plus preceding checkcast).
      *
-     * @param type wrapper type class to unbox.
+     * @param wrapper wrapper type class to unbox.
      */
-    private void emitUnboxing(Class<?> type) {
-        Wrapper wrapper = Wrapper.forWrapperType(type);
+    private void emitUnboxing(Wrapper wrapper) {
         String owner = "java/lang/" + wrapper.wrapperType().getSimpleName();
         String name  = wrapper.primitiveSimpleName() + "Value";
         String desc  = "()" + wrapper.basicTypeChar();
@@ -425,9 +430,12 @@
      * @param ptype type of value present on stack
      * @param pclass type of value required on stack
      */
-    private void emitImplicitConversion(char ptype, Class<?> pclass) {
+    private void emitImplicitConversion(BasicType ptype, Class<?> pclass) {
+        assert(basicType(pclass) == ptype);  // boxing/unboxing handled by caller
+        if (pclass == ptype.basicTypeClass() && ptype != L_TYPE)
+            return;   // nothing to do
         switch (ptype) {
-        case 'L':
+        case L_TYPE:
             if (VerifyType.isNullConversion(Object.class, pclass))
                 return;
             if (isStaticallyNameable(pclass)) {
@@ -441,18 +449,9 @@
                     mv.visitTypeInsn(Opcodes.CHECKCAST, OBJARY);
             }
             return;
-        case 'I':
+        case I_TYPE:
             if (!VerifyType.isNullConversion(int.class, pclass))
-                emitPrimCast(ptype, Wrapper.basicTypeChar(pclass));
-            return;
-        case 'J':
-            assert(pclass == long.class);
-            return;
-        case 'F':
-            assert(pclass == float.class);
-            return;
-        case 'D':
-            assert(pclass == double.class);
+                emitPrimCast(ptype.basicTypeWrapper(), Wrapper.forPrimitiveType(pclass));
             return;
         }
         throw new InternalError("bad implicit conversion: tc="+ptype+": "+pclass);
@@ -461,15 +460,15 @@
     /**
      * Emits an actual return instruction conforming to the given return type.
      */
-    private void emitReturnInsn(Class<?> type) {
+    private void emitReturnInsn(BasicType type) {
         int opcode;
-        switch (Wrapper.basicTypeChar(type)) {
-        case 'I':  opcode = Opcodes.IRETURN;  break;
-        case 'J':  opcode = Opcodes.LRETURN;  break;
-        case 'F':  opcode = Opcodes.FRETURN;  break;
-        case 'D':  opcode = Opcodes.DRETURN;  break;
-        case 'L':  opcode = Opcodes.ARETURN;  break;
-        case 'V':  opcode = Opcodes.RETURN;   break;
+        switch (type) {
+        case I_TYPE:  opcode = Opcodes.IRETURN;  break;
+        case J_TYPE:  opcode = Opcodes.LRETURN;  break;
+        case F_TYPE:  opcode = Opcodes.FRETURN;  break;
+        case D_TYPE:  opcode = Opcodes.DRETURN;  break;
+        case L_TYPE:  opcode = Opcodes.ARETURN;  break;
+        case V_TYPE:  opcode = Opcodes.RETURN;   break;
         default:
             throw new InternalError("unknown return type: " + type);
         }
@@ -531,7 +530,7 @@
             // avoid store/load/return and just return)
             if (i == lambdaForm.names.length - 1 && i == lambdaForm.result) {
                 // return value - do nothing
-            } else if (name.type != 'V') {
+            } else if (name.type != V_TYPE) {
                 // non-void: actually assign
                 emitStoreInsn(name.type, name.index());
             }
@@ -865,20 +864,24 @@
 
     private void emitPushArgument(Name name, int paramIndex) {
         Object arg = name.arguments[paramIndex];
-        char ptype = name.function.parameterType(paramIndex);
-        MethodType mtype = name.function.methodType();
+        Class<?> ptype = name.function.methodType().parameterType(paramIndex);
+        emitPushArgument(ptype, arg);
+    }
+
+    private void emitPushArgument(Class<?> ptype, Object arg) {
+        BasicType bptype = basicType(ptype);
         if (arg instanceof Name) {
             Name n = (Name) arg;
             emitLoadInsn(n.type, n.index());
-            emitImplicitConversion(n.type, mtype.parameterType(paramIndex));
-        } else if ((arg == null || arg instanceof String) && ptype == 'L') {
+            emitImplicitConversion(n.type, ptype);
+        } else if ((arg == null || arg instanceof String) && bptype == L_TYPE) {
             emitConst(arg);
         } else {
-            if (Wrapper.isWrapperType(arg.getClass()) && ptype != 'L') {
+            if (Wrapper.isWrapperType(arg.getClass()) && bptype != L_TYPE) {
                 emitConst(arg);
             } else {
                 mv.visitLdcInsn(constantPlaceholder(arg));
-                emitImplicitConversion('L', mtype.parameterType(paramIndex));
+                emitImplicitConversion(L_TYPE, ptype);
             }
         }
     }
@@ -888,52 +891,33 @@
      */
     private void emitReturn() {
         // return statement
-        if (lambdaForm.result == -1) {
+        Class<?> rclass = invokerType.returnType();
+        BasicType rtype = lambdaForm.returnType();
+        assert(rtype == basicType(rclass));  // must agree
+        if (rtype == V_TYPE) {
             // void
             mv.visitInsn(Opcodes.RETURN);
+            // it doesn't matter what rclass is; the JVM will discard any value
         } else {
             LambdaForm.Name rn = lambdaForm.names[lambdaForm.result];
-            char rtype = Wrapper.basicTypeChar(invokerType.returnType());
 
             // put return value on the stack if it is not already there
-            if (lambdaForm.result != lambdaForm.names.length - 1) {
+            if (lambdaForm.result != lambdaForm.names.length - 1 ||
+                    lambdaForm.result < lambdaForm.arity) {
                 emitLoadInsn(rn.type, lambdaForm.result);
             }
 
-            // potentially generate cast
-            // rtype is the return type of the invoker - generated code must conform to this
-            // rn.type is the type of the result Name in the LF
-            if (rtype != rn.type) {
-                // need cast
-                if (rtype == 'L') {
-                    // possibly cast the primitive to the correct type for boxing
-                    char boxedType = Wrapper.forWrapperType(invokerType.returnType()).basicTypeChar();
-                    if (boxedType != rn.type) {
-                        emitPrimCast(rn.type, boxedType);
-                    }
-                    // cast primitive to reference ("boxing")
-                    emitBoxing(invokerType.returnType());
-                } else {
-                    // to-primitive cast
-                    if (rn.type != 'L') {
-                        // prim-to-prim cast
-                        emitPrimCast(rn.type, rtype);
-                    } else {
-                        // ref-to-prim cast ("unboxing")
-                        throw new InternalError("no ref-to-prim (unboxing) casts supported right now");
-                    }
-                }
-            }
+            emitImplicitConversion(rtype, rclass);
 
             // generate actual return statement
-            emitReturnInsn(invokerType.returnType());
+            emitReturnInsn(rtype);
         }
     }
 
     /**
      * Emit a type conversion bytecode casting from "from" to "to".
      */
-    private void emitPrimCast(char from, char to) {
+    private void emitPrimCast(Wrapper from, Wrapper to) {
         // Here's how.
         // -   indicates forbidden
         // <-> indicates implicit
@@ -950,17 +934,15 @@
             // no cast required, should be dead code anyway
             return;
         }
-        Wrapper wfrom = Wrapper.forBasicType(from);
-        Wrapper wto   = Wrapper.forBasicType(to);
-        if (wfrom.isSubwordOrInt()) {
+        if (from.isSubwordOrInt()) {
             // cast from {byte,short,char,int} to anything
             emitI2X(to);
         } else {
             // cast from {long,float,double} to anything
-            if (wto.isSubwordOrInt()) {
+            if (to.isSubwordOrInt()) {
                 // cast to {byte,short,char,int}
                 emitX2I(from);
-                if (wto.bitWidth() < 32) {
+                if (to.bitWidth() < 32) {
                     // targets other than int require another conversion
                     emitI2X(to);
                 }
@@ -968,20 +950,26 @@
                 // cast to {long,float,double} - this is verbose
                 boolean error = false;
                 switch (from) {
-                case 'J':
-                         if (to == 'F') { mv.visitInsn(Opcodes.L2F); }
-                    else if (to == 'D') { mv.visitInsn(Opcodes.L2D); }
-                    else error = true;
+                case LONG:
+                    switch (to) {
+                    case FLOAT:   mv.visitInsn(Opcodes.L2F);  break;
+                    case DOUBLE:  mv.visitInsn(Opcodes.L2D);  break;
+                    default:      error = true;               break;
+                    }
                     break;
-                case 'F':
-                         if (to == 'J') { mv.visitInsn(Opcodes.F2L); }
-                    else if (to == 'D') { mv.visitInsn(Opcodes.F2D); }
-                    else error = true;
+                case FLOAT:
+                    switch (to) {
+                    case LONG :   mv.visitInsn(Opcodes.F2L);  break;
+                    case DOUBLE:  mv.visitInsn(Opcodes.F2D);  break;
+                    default:      error = true;               break;
+                    }
                     break;
-                case 'D':
-                         if (to == 'J') { mv.visitInsn(Opcodes.D2L); }
-                    else if (to == 'F') { mv.visitInsn(Opcodes.D2F); }
-                    else error = true;
+                case DOUBLE:
+                    switch (to) {
+                    case LONG :   mv.visitInsn(Opcodes.D2L);  break;
+                    case FLOAT:   mv.visitInsn(Opcodes.D2F);  break;
+                    default:      error = true;               break;
+                    }
                     break;
                 default:
                     error = true;
@@ -994,16 +982,16 @@
         }
     }
 
-    private void emitI2X(char type) {
+    private void emitI2X(Wrapper type) {
         switch (type) {
-        case 'B':  mv.visitInsn(Opcodes.I2B);  break;
-        case 'S':  mv.visitInsn(Opcodes.I2S);  break;
-        case 'C':  mv.visitInsn(Opcodes.I2C);  break;
-        case 'I':  /* naught */                break;
-        case 'J':  mv.visitInsn(Opcodes.I2L);  break;
-        case 'F':  mv.visitInsn(Opcodes.I2F);  break;
-        case 'D':  mv.visitInsn(Opcodes.I2D);  break;
-        case 'Z':
+        case BYTE:    mv.visitInsn(Opcodes.I2B);  break;
+        case SHORT:   mv.visitInsn(Opcodes.I2S);  break;
+        case CHAR:    mv.visitInsn(Opcodes.I2C);  break;
+        case INT:     /* naught */                break;
+        case LONG:    mv.visitInsn(Opcodes.I2L);  break;
+        case FLOAT:   mv.visitInsn(Opcodes.I2F);  break;
+        case DOUBLE:  mv.visitInsn(Opcodes.I2D);  break;
+        case BOOLEAN:
             // For compatibility with ValueConversions and explicitCastArguments:
             mv.visitInsn(Opcodes.ICONST_1);
             mv.visitInsn(Opcodes.IAND);
@@ -1012,39 +1000,24 @@
         }
     }
 
-    private void emitX2I(char type) {
+    private void emitX2I(Wrapper type) {
         switch (type) {
-        case 'J':  mv.visitInsn(Opcodes.L2I);  break;
-        case 'F':  mv.visitInsn(Opcodes.F2I);  break;
-        case 'D':  mv.visitInsn(Opcodes.D2I);  break;
-        default:   throw new InternalError("unknown type: " + type);
+        case LONG:    mv.visitInsn(Opcodes.L2I);  break;
+        case FLOAT:   mv.visitInsn(Opcodes.F2I);  break;
+        case DOUBLE:  mv.visitInsn(Opcodes.D2I);  break;
+        default:      throw new InternalError("unknown type: " + type);
         }
     }
 
-    private static String basicTypeCharSignature(String prefix, MethodType type) {
-        StringBuilder buf = new StringBuilder(prefix);
-        for (Class<?> ptype : type.parameterList())
-            buf.append(Wrapper.forBasicType(ptype).basicTypeChar());
-        buf.append('_').append(Wrapper.forBasicType(type.returnType()).basicTypeChar());
-        return buf.toString();
-    }
-
     /**
      * Generate bytecode for a LambdaForm.vmentry which calls interpretWithArguments.
      */
     static MemberName generateLambdaFormInterpreterEntryPoint(String sig) {
-        assert(LambdaForm.isValidSignature(sig));
-        //System.out.println("generateExactInvoker "+sig);
-        // compute method type
-        // first parameter and return type
-        char tret = LambdaForm.signatureReturn(sig);
-        MethodType type = MethodType.methodType(LambdaForm.typeClass(tret), MethodHandle.class);
-        // other parameter types
-        int arity = LambdaForm.signatureArity(sig);
-        for (int i = 1; i < arity; i++) {
-            type = type.appendParameterTypes(LambdaForm.typeClass(sig.charAt(i)));
-        }
-        InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("LFI", "interpret_"+tret, type);
+        assert(isValidSignature(sig));
+        String name = "interpret_"+signatureReturn(sig).basicTypeChar();
+        MethodType type = signatureType(sig);  // sig includes leading argument
+        type = type.changeParameterType(0, MethodHandle.class);
+        InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("LFI", name, type);
         return g.loadMethod(g.generateLambdaFormInterpreterEntryPointBytes());
     }
 
@@ -1066,10 +1039,10 @@
             Class<?> ptype = invokerType.parameterType(i);
             mv.visitInsn(Opcodes.DUP);
             emitIconstInsn(i);
-            emitLoadInsn(Wrapper.basicTypeChar(ptype), i);
+            emitLoadInsn(basicType(ptype), i);
             // box if primitive type
             if (ptype.isPrimitive()) {
-                emitBoxing(ptype);
+                emitBoxing(Wrapper.forPrimitiveType(ptype));
             }
             mv.visitInsn(Opcodes.AASTORE);
         }
@@ -1082,11 +1055,11 @@
         // maybe unbox
         Class<?> rtype = invokerType.returnType();
         if (rtype.isPrimitive() && rtype != void.class) {
-            emitUnboxing(Wrapper.asWrapperType(rtype));
+            emitUnboxing(Wrapper.forPrimitiveType(rtype));
         }
 
         // return statement
-        emitReturnInsn(rtype);
+        emitReturnInsn(basicType(rtype));
 
         classFileEpilogue();
         bogusMethod(invokerType);
@@ -1100,14 +1073,12 @@
      * Generate bytecode for a NamedFunction invoker.
      */
     static MemberName generateNamedFunctionInvoker(MethodTypeForm typeForm) {
-        MethodType invokerType = LambdaForm.NamedFunction.INVOKER_METHOD_TYPE;
-        String invokerName = basicTypeCharSignature("invoke_", typeForm.erasedType());
+        MethodType invokerType = NamedFunction.INVOKER_METHOD_TYPE;
+        String invokerName = "invoke_" + shortenSignature(basicTypeSignature(typeForm.erasedType()));
         InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("NFI", invokerName, invokerType);
         return g.loadMethod(g.generateNamedFunctionInvokerImpl(typeForm));
     }
 
-    static int nfi = 0;
-
     private byte[] generateNamedFunctionInvokerImpl(MethodTypeForm typeForm) {
         MethodType dstType = typeForm.erasedType();
         classFilePrologue();
@@ -1133,8 +1104,8 @@
                 Class<?> sptype = dstType.basicType().wrap().parameterType(i);
                 Wrapper dstWrapper = Wrapper.forBasicType(dptype);
                 Wrapper srcWrapper = dstWrapper.isSubwordOrInt() ? Wrapper.INT : dstWrapper;  // narrow subword from int
-                emitUnboxing(srcWrapper.wrapperType());
-                emitPrimCast(srcWrapper.basicTypeChar(), dstWrapper.basicTypeChar());
+                emitUnboxing(srcWrapper);
+                emitPrimCast(srcWrapper, dstWrapper);
             }
         }
 
@@ -1148,15 +1119,15 @@
             Wrapper srcWrapper = Wrapper.forBasicType(rtype);
             Wrapper dstWrapper = srcWrapper.isSubwordOrInt() ? Wrapper.INT : srcWrapper;  // widen subword to int
             // boolean casts not allowed
-            emitPrimCast(srcWrapper.basicTypeChar(), dstWrapper.basicTypeChar());
-            emitBoxing(dstWrapper.primitiveType());
+            emitPrimCast(srcWrapper, dstWrapper);
+            emitBoxing(dstWrapper);
         }
 
         // If the return type is void we return a null reference.
         if (rtype == void.class) {
             mv.visitInsn(Opcodes.ACONST_NULL);
         }
-        emitReturnInsn(Object.class);  // NOTE: NamedFunction invokers always return a reference value.
+        emitReturnInsn(L_TYPE);  // NOTE: NamedFunction invokers always return a reference value.
 
         classFileEpilogue();
         bogusMethod(dstType);
--- 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.
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandle.java	Mon May 26 19:59:28 2014 +0400
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandle.java	Mon Feb 24 18:11:55 2014 +0400
@@ -27,10 +27,12 @@
 
 
 import java.util.*;
+import java.lang.invoke.LambdaForm.BasicType;
 import sun.invoke.util.*;
 import sun.misc.Unsafe;
 
 import static java.lang.invoke.MethodHandleStatics.*;
+import static java.lang.invoke.LambdaForm.BasicType.*;
 
 /**
  * A method handle is a typed, directly executable reference to an underlying method,
@@ -729,7 +731,7 @@
      * <li>If the return type <em>T0</em> is void and <em>T1</em> a primitive,
      *     a zero value is introduced.
      * </ul>
-    * (<em>Note:</em> Both <em>T0</em> and <em>T1</em> may be regarded as static types,
+     * (<em>Note:</em> Both <em>T0</em> and <em>T1</em> may be regarded as static types,
      * because neither corresponds specifically to the <em>dynamic type</em> of any
      * actual argument or return value.)
      * <p>
@@ -1374,7 +1376,7 @@
     }
 
     /*non-public*/
-    MethodHandle bindArgument(int pos, char basicType, Object value) {
+    MethodHandle bindArgument(int pos, BasicType basicType, Object value) {
         // Override this if it can be improved.
         return rebind().bindArgument(pos, basicType, value);
     }
@@ -1382,26 +1384,7 @@
     /*non-public*/
     MethodHandle bindReceiver(Object receiver) {
         // Override this if it can be improved.
-        return bindArgument(0, 'L', receiver);
-    }
-
-    /*non-public*/
-    MethodHandle bindImmediate(int pos, char basicType, Object value) {
-        // Bind an immediate value to a position in the arguments.
-        // This means, elide the respective argument,
-        // and replace all references to it in NamedFunction args with the specified value.
-
-        // CURRENT RESTRICTIONS
-        // * only for pos 0 and UNSAFE (position is adjusted in MHImpl to make API usable for others)
-        assert pos == 0 && basicType == 'L' && value instanceof Unsafe;
-        MethodType type2 = type.dropParameterTypes(pos, pos + 1); // adjustment: ignore receiver!
-        LambdaForm form2 = form.bindImmediate(pos + 1, basicType, value); // adjust pos to form-relative pos
-        return copyWith(type2, form2);
-    }
-
-    /*non-public*/
-    MethodHandle copyWith(MethodType mt, LambdaForm lf) {
-        throw new InternalError("copyWith: " + this.getClass());
+        return bindArgument(0, L_TYPE, receiver);
     }
 
     /*non-public*/
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Mon May 26 19:59:28 2014 +0400
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Mon Feb 24 18:11:55 2014 +0400
@@ -412,7 +412,7 @@
 
 
         @Override
-        MethodHandle bindArgument(int pos, char basicType, Object value) {
+        MethodHandle bindArgument(int pos, BasicType basicType, Object value) {
             return asFixedArity().bindArgument(pos, basicType, value);
         }
 
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java	Mon May 26 19:59:28 2014 +0400
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java	Mon Feb 24 18:11:55 2014 +0400
@@ -78,7 +78,7 @@
 
         // The JVM calls MethodHandleNatives.<clinit>.  Cascade the <clinit> calls as needed:
         MethodHandleImpl.initStatics();
-}
+    }
 
     // All compile-time constants go here.
     // There is an opportunity to check them against the JVM's idea of them.
@@ -293,6 +293,17 @@
         Class<?> caller = (Class<?>)callerObj;
         String name = nameObj.toString().intern();
         MethodType type = (MethodType)typeObj;
+        if (!TRACE_METHOD_LINKAGE)
+            return linkCallSiteImpl(caller, bootstrapMethod, name, type,
+                                    staticArguments, appendixResult);
+        return linkCallSiteTracing(caller, bootstrapMethod, name, type,
+                                   staticArguments, appendixResult);
+    }
+    static MemberName linkCallSiteImpl(Class<?> caller,
+                                       MethodHandle bootstrapMethod,
+                                       String name, MethodType type,
+                                       Object staticArguments,
+                                       Object[] appendixResult) {
         CallSite callSite = CallSite.makeSite(bootstrapMethod,
                                               name,
                                               type,
@@ -306,6 +317,30 @@
             return Invokers.linkToCallSiteMethod(type);
         }
     }
+    // Tracing logic:
+    static MemberName linkCallSiteTracing(Class<?> caller,
+                                          MethodHandle bootstrapMethod,
+                                          String name, MethodType type,
+                                          Object staticArguments,
+                                          Object[] appendixResult) {
+        Object bsmReference = bootstrapMethod.internalMemberName();
+        if (bsmReference == null)  bsmReference = bootstrapMethod;
+        Object staticArglist = (staticArguments instanceof Object[] ?
+                                java.util.Arrays.asList((Object[]) staticArguments) :
+                                staticArguments);
+        System.out.println("linkCallSite "+caller.getName()+" "+
+                           bsmReference+" "+
+                           name+type+"/"+staticArglist);
+        try {
+            MemberName res = linkCallSiteImpl(caller, bootstrapMethod, name, type,
+                                              staticArguments, appendixResult);
+            System.out.println("linkCallSite => "+res+" + "+appendixResult[0]);
+            return res;
+        } catch (Throwable ex) {
+            System.out.println("linkCallSite => throw "+ex);
+            throw ex;
+        }
+    }
 
     /**
      * The JVM wants a pointer to a MethodType.  Oblige it by finding or creating one.
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleStatics.java	Mon May 26 19:59:28 2014 +0400
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleStatics.java	Mon Feb 24 18:11:55 2014 +0400
@@ -65,6 +65,16 @@
         COMPILE_THRESHOLD         = (Integer) values[4];
     }
 
+    /** Tell if any of the debugging switches are turned on.
+     *  If this is the case, it is reasonable to perform extra checks or save extra information.
+     */
+    /*non-public*/ static boolean debugEnabled() {
+        return (DEBUG_METHOD_HANDLE_NAMES |
+                DUMP_CLASS_FILES |
+                TRACE_INTERPRETER |
+                TRACE_METHOD_LINKAGE);
+    }
+
     /*non-public*/ static String getNameString(MethodHandle target, MethodType type) {
         if (type == null)
             type = target.type();
@@ -93,6 +103,9 @@
     }
 
     // handy shared exception makers (they simplify the common case code)
+    /*non-public*/ static InternalError newInternalError(String message) {
+        return new InternalError(message);
+    }
     /*non-public*/ static InternalError newInternalError(String message, Throwable cause) {
         return new InternalError(message, cause);
     }
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java	Mon May 26 19:59:28 2014 +0400
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java	Mon Feb 24 18:11:55 2014 +0400
@@ -37,10 +37,11 @@
 import sun.reflect.Reflection;
 import sun.reflect.misc.ReflectUtil;
 import sun.security.util.SecurityConstants;
+import java.lang.invoke.LambdaForm.BasicType;
+import static java.lang.invoke.LambdaForm.BasicType.*;
 import static java.lang.invoke.MethodHandleStatics.*;
 import static java.lang.invoke.MethodHandleNatives.Constants.*;
 import java.util.concurrent.ConcurrentHashMap;
-import sun.security.util.SecurityConstants;
 
 /**
  * This class consists exclusively of static methods that operate on or return
@@ -2189,12 +2190,12 @@
             Object value = values[i];
             Class<?> ptype = oldType.parameterType(pos+i);
             if (ptype.isPrimitive()) {
-                char btype = 'I';
+                BasicType btype = I_TYPE;
                 Wrapper w = Wrapper.forPrimitiveType(ptype);
                 switch (w) {
-                case LONG:    btype = 'J'; break;
-                case FLOAT:   btype = 'F'; break;
-                case DOUBLE:  btype = 'D'; break;
+                case LONG:    btype = J_TYPE; break;
+                case FLOAT:   btype = F_TYPE; break;
+                case DOUBLE:  btype = D_TYPE; break;
                 }
                 // perform unboxing and/or primitive conversion
                 value = w.convert(value, ptype);
@@ -2205,7 +2206,7 @@
             if (pos == 0) {
                 result = result.bindReceiver(value);
             } else {
-                result = result.bindArgument(pos, 'L', value);
+                result = result.bindArgument(pos, L_TYPE, value);
             }
         }
         return result;
--- a/jdk/src/share/classes/java/lang/invoke/SimpleMethodHandle.java	Mon May 26 19:59:28 2014 +0400
+++ b/jdk/src/share/classes/java/lang/invoke/SimpleMethodHandle.java	Mon Feb 24 18:11:55 2014 +0400
@@ -26,7 +26,7 @@
 package java.lang.invoke;
 
 import static java.lang.invoke.LambdaForm.*;
-import static java.lang.invoke.MethodHandleNatives.Constants.*;
+import static java.lang.invoke.LambdaForm.BasicType.*;
 
 /**
  * A method handle whose behavior is determined only by its LambdaForm.
@@ -42,7 +42,7 @@
     }
 
     @Override
-    MethodHandle bindArgument(int pos, char basicType, Object value) {
+    MethodHandle bindArgument(int pos, BasicType basicType, Object value) {
         MethodType type2 = type().dropParameterTypes(pos, pos+1);
         LambdaForm form2 = internalForm().bind(1+pos, BoundMethodHandle.SpeciesData.EMPTY);
         return BoundMethodHandle.bindSingle(type2, form2, basicType, value);
@@ -59,10 +59,4 @@
         LambdaForm form2 = internalForm().permuteArguments(1, reorder, basicTypes(newType.parameterList()));
         return new SimpleMethodHandle(newType, form2);
     }
-
-    @Override
-    MethodHandle copyWith(MethodType mt, LambdaForm lf) {
-        return new SimpleMethodHandle(mt, lf);
-    }
-
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/LambdaFormTest.java	Mon Feb 24 18:11:55 2014 +0400
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @summary unit tests for java.lang.invoke.LambdaForm
+ * @run junit/othervm test.java.lang.invoke.LambdaFormTest
+ */
+package test.java.lang.invoke;
+
+import org.junit.Test;
+import java.lang.reflect.Method;
+import static org.junit.Assert.*;
+
+public class LambdaFormTest {
+    static final Method M_shortenSignature;
+    static {
+        try {
+            Class<?> impl = Class.forName("java.lang.invoke.LambdaForm", false, null);
+            Method m = impl.getDeclaredMethod("shortenSignature", String.class);
+            m.setAccessible(true);
+            M_shortenSignature = m;
+        } catch(Exception e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    public static String shortenSignature(String signature) throws ReflectiveOperationException {
+        return (String)M_shortenSignature.invoke(null, signature);
+    }
+
+    @Test
+    public void testShortenSignature() throws ReflectiveOperationException {
+        for (String s : new String[] {
+                // invariant strings:
+                "L", "LL", "ILL", "LIL", "LLI", "IILL", "ILIL", "ILLI",
+                // a few mappings:
+                "LLL=L3", "LLLL=L4", "LLLLLLLLLL=L10",
+                "IIIDDD=I3D3", "IDDD=ID3", "IIDDD=IID3", "IIID=I3D", "IIIDD=I3DD"
+            }) {
+            String s2 = s.substring(s.indexOf('=')+1);
+            String s1 = s.equals(s2) ? s : s.substring(0, s.length() - s2.length() - 1);
+            // mix the above cases with before and after reps of Z*
+            for (int k = -3; k <= 3; k++) {
+                String beg = (k < 0 ? "ZZZZ".substring(-k) : "");
+                String end = (k > 0 ? "ZZZZ".substring(+k) : "");
+                String ks1 = beg+s1+end;
+                String ks2 = shortenSignature(beg)+s2+shortenSignature(end);
+                String ks3 = shortenSignature(ks1);
+                assertEquals(ks2, ks3);
+            }
+        }
+    }
+
+    public static void main(String[] args) throws ReflectiveOperationException {
+        LambdaFormTest test = new LambdaFormTest();
+        test.testShortenSignature();
+    }
+}