8050052: Small cleanups in java.lang.invoke code
authorvlivanov
Wed, 10 Sep 2014 19:19:47 +0400
changeset 26467 d69abed3a07d
parent 26466 3bbb6a284bd4
child 26468 2d57604f9299
8050052: Small cleanups in java.lang.invoke code Reviewed-by: vlivanov, psandoz Contributed-by: john.r.rose@oracle.com
jdk/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java
jdk/src/java.base/share/classes/java/lang/invoke/CallSite.java
jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java
jdk/src/java.base/share/classes/java/lang/invoke/Invokers.java
jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java
jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java
jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java
jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java
jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java
jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleStatics.java
jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java
jdk/src/java.base/share/classes/java/lang/invoke/MethodTypeForm.java
jdk/test/java/lang/invoke/MethodHandlesTest.java
--- a/jdk/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java	Wed Sep 10 19:19:47 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java	Wed Sep 10 19:19:47 2014 +0400
@@ -50,9 +50,9 @@
  *
  * All bound arguments are encapsulated in dedicated species.
  */
-/* non-public */ abstract class BoundMethodHandle extends MethodHandle {
+/*non-public*/ abstract class BoundMethodHandle extends MethodHandle {
 
-    /* non-public */ BoundMethodHandle(MethodType type, LambdaForm form) {
+    /*non-public*/ BoundMethodHandle(MethodType type, LambdaForm form) {
         super(type, form);
     }
 
@@ -66,15 +66,15 @@
             switch (xtype) {
             case L_TYPE:
                 if (true)  return bindSingle(type, form, x);  // Use known fast path.
-                return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(L_TYPE).constructor[0].invokeBasic(type, form, x);
+                return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(L_TYPE).constructor().invokeBasic(type, form, x);
             case I_TYPE:
-                return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(I_TYPE).constructor[0].invokeBasic(type, form, ValueConversions.widenSubword(x));
+                return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(I_TYPE).constructor().invokeBasic(type, form, ValueConversions.widenSubword(x));
             case J_TYPE:
-                return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(J_TYPE).constructor[0].invokeBasic(type, form, (long) x);
+                return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(J_TYPE).constructor().invokeBasic(type, form, (long) x);
             case F_TYPE:
-                return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(F_TYPE).constructor[0].invokeBasic(type, form, (float) x);
+                return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(F_TYPE).constructor().invokeBasic(type, form, (float) x);
             case D_TYPE:
-                return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(D_TYPE).constructor[0].invokeBasic(type, form, (double) x);
+                return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(D_TYPE).constructor().invokeBasic(type, form, (double) x);
             default : throw newInternalError("unexpected xtype: " + xtype);
             }
         } catch (Throwable t) {
@@ -139,8 +139,8 @@
     /*non-public*/ abstract int fieldCount();
 
     @Override
-    final Object internalProperties() {
-        return "/BMH="+internalValues();
+    Object internalProperties() {
+        return "\n& BMH="+internalValues();
     }
 
     @Override
@@ -219,7 +219,7 @@
         @Override
         /*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);
+                return (BoundMethodHandle) SPECIES_DATA.extendWith(L_TYPE).constructor().invokeBasic(mt, lf, argL0, narg);
             } catch (Throwable ex) {
                 throw uncaughtException(ex);
             }
@@ -227,7 +227,7 @@
         @Override
         /*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);
+                return (BoundMethodHandle) SPECIES_DATA.extendWith(I_TYPE).constructor().invokeBasic(mt, lf, argL0, narg);
             } catch (Throwable ex) {
                 throw uncaughtException(ex);
             }
@@ -235,7 +235,7 @@
         @Override
         /*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);
+                return (BoundMethodHandle) SPECIES_DATA.extendWith(J_TYPE).constructor().invokeBasic(mt, lf, argL0, narg);
             } catch (Throwable ex) {
                 throw uncaughtException(ex);
             }
@@ -243,7 +243,7 @@
         @Override
         /*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);
+                return (BoundMethodHandle) SPECIES_DATA.extendWith(F_TYPE).constructor().invokeBasic(mt, lf, argL0, narg);
             } catch (Throwable ex) {
                 throw uncaughtException(ex);
             }
@@ -251,7 +251,7 @@
         @Override
         /*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);
+                return (BoundMethodHandle) SPECIES_DATA.extendWith(D_TYPE).constructor().invokeBasic(mt, lf, argL0, narg);
             } catch (Throwable ex) {
                 throw uncaughtException(ex);
             }
@@ -268,18 +268,20 @@
      * 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.
+     * The shortest possible BMH has zero fields; its class is SimpleMethodHandle.
+     * BMH species are not interrelated by subtyping, even though it would appear that
+     * a shorter BMH could serve as a supertype of a longer one which extends it.
      */
     static class SpeciesData {
-        final String                             typeChars;
-        final BasicType[]                        typeCodes;
-        final Class<? extends BoundMethodHandle> clazz;
+        private final String                             typeChars;
+        private final BasicType[]                        typeCodes;
+        private 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;
+        @Stable private final MethodHandle[]             constructor;
+        @Stable private final MethodHandle[]             getters;
+        @Stable private final NamedFunction[]            nominalGetters;
+        @Stable private final SpeciesData[]              extensions;
 
         /*non-public*/ int fieldCount() {
             return typeCodes.length;
@@ -290,9 +292,14 @@
         /*non-public*/ char fieldTypeChar(int i) {
             return typeChars.charAt(i);
         }
-
+        Object fieldSignature() {
+            return typeChars;
+        }
+        public Class<? extends BoundMethodHandle> fieldHolder() {
+            return clazz;
+        }
         public String toString() {
-            return "SpeciesData["+(isPlaceholder() ? "<placeholder>" : clazz.getSimpleName())+":"+typeChars+"]";
+            return "SpeciesData<"+fieldSignature()+">";
         }
 
         /**
@@ -301,7 +308,20 @@
          * getter.
          */
         NamedFunction getterFunction(int i) {
-            return nominalGetters[i];
+            NamedFunction nf = nominalGetters[i];
+            assert(nf.memberDeclaringClassOrNull() == fieldHolder());
+            assert(nf.returnType() == fieldType(i));
+            return nf;
+        }
+
+        NamedFunction[] getterFunctions() {
+            return nominalGetters;
+        }
+
+        MethodHandle[] getterHandles() { return getters; }
+
+        MethodHandle constructor() {
+            return constructor[0];
         }
 
         static final SpeciesData EMPTY = new SpeciesData("", BoundMethodHandle.class);
@@ -324,7 +344,7 @@
 
         private void initForBootstrap() {
             assert(!INIT_DONE);
-            if (constructor[0] == null) {
+            if (constructor() == null) {
                 String types = typeChars;
                 Factory.makeCtors(clazz, types, this.constructor);
                 Factory.makeGetters(clazz, types, this.getters);
@@ -508,19 +528,19 @@
          *         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);
+         *         return SPECIES_DATA.extendWith(L_TYPE).constructor().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);
+         *         return SPECIES_DATA.extendWith(I_TYPE).constructor().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);
+         *         return SPECIES_DATA.extendWith(J_TYPE).constructor().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);
+         *         return SPECIES_DATA.extendWith(F_TYPE).constructor().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);
+         *         return SPECIES_DATA.extendWith(D_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
          *     }
          * }
          * </pre>
@@ -653,16 +673,14 @@
                 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.extendWith(t).constructor[0].invokeBasic(mt, lf, argL0, ..., narg)
+                // return SPECIES_DATA.extendWith(t).constructor().invokeBasic(mt, lf, argL0, ..., narg)
                 // obtain constructor
                 mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
                 int iconstInsn = ICONST_0 + ord;
                 assert(iconstInsn <= ICONST_5);
                 mv.visitInsn(iconstInsn);
                 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);
+                mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "constructor", "()" + MH_SIG, false);
                 // load mt, lf
                 mv.visitVarInsn(ALOAD, 1);
                 mv.visitVarInsn(ALOAD, 2);
--- a/jdk/src/java.base/share/classes/java/lang/invoke/CallSite.java	Wed Sep 10 19:19:47 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/CallSite.java	Wed Sep 10 19:19:47 2014 +0400
@@ -319,7 +319,7 @@
                 throw new ClassCastException("bootstrap method failed to produce a CallSite");
             }
             if (!site.getTarget().type().equals(type))
-                throw new WrongMethodTypeException("wrong type: "+site.getTarget());
+                throw wrongTargetType(site.getTarget(), type);
         } catch (Throwable ex) {
             BootstrapMethodError bex;
             if (ex instanceof BootstrapMethodError)
--- a/jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java	Wed Sep 10 19:19:47 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java	Wed Sep 10 19:19:47 2014 +0400
@@ -59,6 +59,7 @@
             MemberName m = new MemberName(Object.class, member.getName(), member.getMethodType(), member.getReferenceKind());
             m = MemberName.getFactory().resolveOrNull(m.getReferenceKind(), m, null);
             if (m != null && m.isPublic()) {
+                assert(member.getReferenceKind() == m.getReferenceKind());  // else this.form is wrong
                 member = m;
             }
         }
@@ -127,7 +128,7 @@
 
     @Override
     String internalProperties() {
-        return "/DMH="+member.toString();
+        return "\n& DMH.MN="+internalMemberName();
     }
 
     //// Implementation methods.
--- a/jdk/src/java.base/share/classes/java/lang/invoke/Invokers.java	Wed Sep 10 19:19:47 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/Invokers.java	Wed Sep 10 19:19:47 2014 +0400
@@ -308,7 +308,7 @@
                 : Arrays.asList(mtype, customized, which, nameCursor, names.length);
         if (MTYPE_ARG >= INARG_LIMIT) {
             assert(names[MTYPE_ARG] == null);
-            NamedFunction getter = BoundMethodHandle.getSpeciesData("L").getterFunction(0);
+            NamedFunction getter = BoundMethodHandle.speciesData_L().getterFunction(0);
             names[MTYPE_ARG] = new Name(getter, names[THIS_MH]);
             // else if isLinker, then MTYPE is passed in from the caller (e.g., the JVM)
         }
@@ -360,9 +360,6 @@
     Object checkGenericType(Object mhObj, Object expectedObj) {
         MethodHandle mh = (MethodHandle) mhObj;
         MethodType expected = (MethodType) expectedObj;
-        if (mh.type() == expected)  return mh;
-        MethodHandle atc = mh.asTypeCache;
-        if (atc != null && atc.type() == expected)  return atc;
         return mh.asType(expected);
         /* Maybe add more paths here.  Possible optimizations:
          * for (R)MH.invoke(a*),
@@ -436,24 +433,25 @@
     }
 
     // Local constant functions:
-    private static final NamedFunction NF_checkExactType;
-    private static final NamedFunction NF_checkGenericType;
-    private static final NamedFunction NF_asType;
-    private static final NamedFunction NF_getCallSiteTarget;
+    private static final NamedFunction
+        NF_checkExactType,
+        NF_checkGenericType,
+        NF_getCallSiteTarget;
     static {
         try {
-            NF_checkExactType = new NamedFunction(Invokers.class
-                    .getDeclaredMethod("checkExactType", Object.class, Object.class));
-            NF_checkGenericType = new NamedFunction(Invokers.class
-                    .getDeclaredMethod("checkGenericType", Object.class, Object.class));
-            NF_asType = new NamedFunction(MethodHandle.class
-                    .getDeclaredMethod("asType", MethodType.class));
-            NF_getCallSiteTarget = new NamedFunction(Invokers.class
-                    .getDeclaredMethod("getCallSiteTarget", Object.class));
-            NF_checkExactType.resolve();
-            NF_checkGenericType.resolve();
-            NF_getCallSiteTarget.resolve();
-            // bound
+            NamedFunction nfs[] = {
+                NF_checkExactType = new NamedFunction(Invokers.class
+                        .getDeclaredMethod("checkExactType", Object.class, Object.class)),
+                NF_checkGenericType = new NamedFunction(Invokers.class
+                        .getDeclaredMethod("checkGenericType", Object.class, Object.class)),
+                NF_getCallSiteTarget = new NamedFunction(Invokers.class
+                        .getDeclaredMethod("getCallSiteTarget", Object.class))
+            };
+            for (NamedFunction nf : nfs) {
+                // Each nf must be statically invocable or we get tied up in our bootstraps.
+                assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf.member)) : nf;
+                nf.resolve();
+            }
         } catch (ReflectiveOperationException ex) {
             throw newInternalError(ex);
         }
--- a/jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java	Wed Sep 10 19:19:47 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java	Wed Sep 10 19:19:47 2014 +0400
@@ -243,7 +243,12 @@
         this.result = fixResult(result, names);
         this.names = names.clone();
         this.debugName = fixDebugName(debugName);
-        normalize();
+        int maxOutArity = normalize();
+        if (maxOutArity > MethodType.MAX_MH_INVOKER_ARITY) {
+            // Cannot use LF interpreter on very high arity expressions.
+            assert(maxOutArity <= MethodType.MAX_JVM_ARITY);
+            compileToBytecode();
+        }
     }
 
     LambdaForm(String debugName,
@@ -348,9 +353,12 @@
         return true;
     }
 
-    /** Renumber and/or replace params so that they are interned and canonically numbered. */
-    private void normalize() {
+    /** Renumber and/or replace params so that they are interned and canonically numbered.
+     *  @return maximum argument list length among the names (since we have to pass over them anyway)
+     */
+    private int normalize() {
         Name[] oldNames = null;
+        int maxOutArity = 0;
         int changesStart = 0;
         for (int i = 0; i < names.length; i++) {
             Name n = names[i];
@@ -361,6 +369,8 @@
                 }
                 names[i] = n.cloneWithIndex(i);
             }
+            if (n.arguments != null && maxOutArity < n.arguments.length)
+                maxOutArity = n.arguments.length;
         }
         if (oldNames != null) {
             int startFixing = arity;
@@ -387,6 +397,7 @@
             }
             assert(nameRefsAreLegal());
         }
+        return maxOutArity;
     }
 
     /**
@@ -439,8 +450,15 @@
 
     /** Report the N-th argument type. */
     BasicType parameterType(int n) {
+        return parameter(n).type;
+    }
+
+    /** Report the N-th argument name. */
+    Name parameter(int n) {
         assert(n < arity);
-        return names[n].type;
+        Name param = names[n];
+        assert(param.isParam());
+        return param;
     }
 
     /** Report the arity. */
@@ -582,21 +600,12 @@
             isCompiled = true;
             return vmentry;
         } catch (Error | Exception ex) {
-            throw newInternalError("compileToBytecode: " + this, ex);
+            throw newInternalError(this.toString(), ex);
         }
     }
 
-    private static final ConcurrentHashMap<String,LambdaForm> PREPARED_FORMS;
-    static {
-        int   capacity   = 512;    // expect many distinct signatures over time
-        float loadFactor = 0.75f;  // normal default
-        int   writers    = 1;
-        PREPARED_FORMS = new ConcurrentHashMap<>(capacity, loadFactor, writers);
-    }
-
-    private static Map<String,LambdaForm> computeInitialPreparedForms() {
+    private static void computeInitialPreparedForms() {
         // Find all predefined invokers and associate them with canonical empty lambda forms.
-        HashMap<String,LambdaForm> forms = new HashMap<>();
         for (MemberName m : MemberName.getFactory().getMethods(LambdaForm.class, false, null, null, null)) {
             if (!m.isStatic() || !m.isPackage())  continue;
             MethodType mt = m.getMethodType();
@@ -607,13 +616,9 @@
                 assert(m.getName().equals("interpret" + sig.substring(sig.indexOf('_'))));
                 LambdaForm form = new LambdaForm(sig);
                 form.vmentry = m;
-                form = mt.form().setCachedLambdaForm(MethodTypeForm.LF_COUNTER, form);
-                // FIXME: get rid of PREPARED_FORMS; use MethodTypeForm cache only
-                forms.put(sig, form);
+                form = mt.form().setCachedLambdaForm(MethodTypeForm.LF_INTERPRET, form);
             }
         }
-        //System.out.println("computeInitialPreparedForms => "+forms);
-        return forms;
     }
 
     // Set this false to disable use of the interpret_L methods defined in this file.
@@ -647,13 +652,11 @@
     }
     private static LambdaForm getPreparedForm(String sig) {
         MethodType mtype = signatureType(sig);
-        //LambdaForm prep = PREPARED_FORMS.get(sig);
         LambdaForm prep =  mtype.form().cachedLambdaForm(MethodTypeForm.LF_INTERPRET);
         if (prep != null)  return prep;
         assert(isValidSignature(sig));
         prep = new LambdaForm(sig);
         prep.vmentry = InvokerBytecodeGenerator.generateLambdaFormInterpreterEntryPoint(sig);
-        //LambdaForm prep2 = PREPARED_FORMS.putIfAbsent(sig.intern(), prep);
         return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_INTERPRET, prep);
     }
 
@@ -709,10 +712,7 @@
     /** If the invocation count hits the threshold we spin bytecodes and call that subsequently. */
     private static final int COMPILE_THRESHOLD;
     static {
-        if (MethodHandleStatics.COMPILE_THRESHOLD != null)
-            COMPILE_THRESHOLD = MethodHandleStatics.COMPILE_THRESHOLD;
-        else
-            COMPILE_THRESHOLD = 30;  // default value
+        COMPILE_THRESHOLD = Math.max(-1, MethodHandleStatics.COMPILE_THRESHOLD);
     }
     private int invocationCounter = 0;
 
@@ -728,7 +728,9 @@
         for (int i = argumentValues.length; i < values.length; i++) {
             values[i] = interpretName(names[i], values);
         }
-        return (result < 0) ? null : values[result];
+        Object rv = (result < 0) ? null : values[result];
+        assert(resultCheck(argumentValues, rv));
+        return rv;
     }
 
     @Hidden
@@ -819,8 +821,16 @@
         assert(argumentValues.length == arity) : arity+"!="+Arrays.asList(argumentValues)+".length";
         // also check that the leading (receiver) argument is somehow bound to this LF:
         assert(argumentValues[0] instanceof MethodHandle) : "not MH: " + argumentValues[0];
-        assert(((MethodHandle)argumentValues[0]).internalForm() == this);
+        MethodHandle mh = (MethodHandle) argumentValues[0];
+        assert(mh.internalForm() == this);
         // note:  argument #0 could also be an interface wrapper, in the future
+        argumentTypesMatch(basicTypeSignature(), argumentValues);
+        return true;
+    }
+    private boolean resultCheck(Object[] argumentValues, Object result) {
+        MethodHandle mh = (MethodHandle) argumentValues[0];
+        MethodType mt = mh.type();
+        assert(valueMatches(returnType(), mt.returnType(), result));
         return true;
     }
 
@@ -839,7 +849,7 @@
             if (i == arity)  buf.append(")=>{");
             Name n = names[i];
             if (i >= arity)  buf.append("\n    ");
-            buf.append(n);
+            buf.append(n.paramString());
             if (i < arity) {
                 if (i+1 < arity)  buf.append(",");
                 continue;
@@ -847,6 +857,7 @@
             buf.append("=").append(n.exprString());
             buf.append(";");
         }
+        if (arity == names.length)  buf.append(")=>{");
         buf.append(result < 0 ? "void" : names[result]).append("}");
         if (TRACE_INTERPRETER) {
             // Extra verbosity:
@@ -856,53 +867,16 @@
         return buf.toString();
     }
 
-    /**
-     * Apply immediate binding for a Name in this form indicated by its position relative to the form.
-     * 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, 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);
-
-        int arity2 = arity - 1;
-        Name[] names2 = new Name[names.length - 1];
-        for (int r = 0, w = 0; r < names.length; ++r, ++w) { // (r)ead from names, (w)rite to names2
-            Name n = names[r];
-            if (n.isParam()) {
-                if (n.index == pos) {
-                    // do not copy over the argument that is to be replaced with a literal,
-                    // but adjust the write index
-                    --w;
-                } else {
-                    names2[w] = new Name(w, n.type);
-                }
-            } else {
-                Object[] arguments2 = new Object[n.arguments.length];
-                for (int i = 0; i < n.arguments.length; ++i) {
-                    Object arg = n.arguments[i];
-                    if (arg instanceof Name) {
-                        int ni = ((Name) arg).index;
-                        if (ni == pos) {
-                            arguments2[i] = value;
-                        } else if (ni < pos) {
-                            // replacement position not yet passed
-                            arguments2[i] = names2[ni];
-                        } else {
-                            // replacement position passed
-                            arguments2[i] = names2[ni - 1];
-                        }
-                    } else {
-                        arguments2[i] = arg;
-                    }
-                }
-                names2[w] = new Name(n.function, arguments2);
-                names2[w].initIndex(w);
-            }
-        }
-
-        int result2 = result == -1 ? -1 : result - 1;
-        return new LambdaForm(debugName, arity2, names2, result2);
+    @Override
+    public boolean equals(Object obj) {
+        return obj instanceof LambdaForm && equals((LambdaForm)obj);
+    }
+    public boolean equals(LambdaForm that) {
+        if (this.result != that.result)  return false;
+        return Arrays.equals(this.names, that.names);
+    }
+    public int hashCode() {
+        return result + 31 * Arrays.hashCode(names);
     }
 
     LambdaForm bind(int namePos, BoundMethodHandle.SpeciesData oldData) {
@@ -918,8 +892,8 @@
         assert(!binding.isParam());
         assert(name.type == binding.type);
         assert(0 <= pos && pos < arity && names[pos] == name);
-        assert(binding.function.memberDeclaringClassOrNull() == newData.clazz);
-        assert(oldData.getters.length == newData.getters.length-1);
+        assert(binding.function.memberDeclaringClassOrNull() == newData.fieldHolder());
+        assert(oldData.getterFunctions().length == newData.getterFunctions().length-1);
         if (bindCache != null) {
             LambdaForm form = bindCache[pos];
             if (form != null) {
@@ -940,12 +914,12 @@
         for (int i = 0; i < names2.length; i++) {
             Name n = names[i];
             if (n.function != null &&
-                n.function.memberDeclaringClassOrNull() == oldData.clazz) {
+                n.function.memberDeclaringClassOrNull() == oldData.fieldHolder()) {
                 MethodHandle oldGetter = n.function.resolvedHandle;
                 MethodHandle newGetter = null;
-                for (int j = 0; j < oldData.getters.length; j++) {
-                    if (oldGetter == oldData.getters[j])
-                        newGetter =  newData.getters[j];
+                for (int j = 0; j < oldData.getterHandles().length; j++) {
+                    if (oldGetter == oldData.getterHandles()[j])
+                        newGetter =  newData.getterHandles()[j];
                 }
                 if (newGetter != null) {
                     if (firstOldRef < 0)  firstOldRef = i;
@@ -969,7 +943,7 @@
         int insPos = pos;
         for (; insPos+1 < names2.length; insPos++) {
             Name n = names2[insPos+1];
-            if (n.isSiblingBindingBefore(binding)) {
+            if (n.isParam()) {
                 names2[insPos] = n;
             } else {
                 break;
@@ -1000,16 +974,16 @@
     }
 
     LambdaForm addArguments(int pos, BasicType... types) {
-        assert(pos <= arity);
+        // names array has MH in slot 0; skip it.
+        int argpos = pos + 1;
+        assert(argpos <= arity);
         int length = names.length;
         int inTypes = types.length;
         Name[] names2 = Arrays.copyOf(names, length + inTypes);
         int arity2 = arity + inTypes;
         int result2 = result;
-        if (result2 >= arity)
+        if (result2 >= argpos)
             result2 += inTypes;
-        // names array has MH in slot 0; skip it.
-        int argpos = pos + 1;
         // Note:  The LF constructor will rename names2[argpos...].
         // Make space for new arguments (shift temporaries).
         System.arraycopy(names, argpos, names2, argpos + inTypes, length - argpos);
@@ -1102,8 +1076,9 @@
         }
         NamedFunction(MemberName member, MethodHandle resolvedHandle) {
             this.member = member;
-            //resolvedHandle = eraseSubwordTypes(resolvedHandle);
             this.resolvedHandle = resolvedHandle;
+             // The following assert is almost always correct, but will fail for corner cases, such as PrivateInvokeTest.
+             //assert(!isInvokeBasic());
         }
         NamedFunction(MethodType basicInvokerType) {
             assert(basicInvokerType == basicInvokerType.basicType()) : basicInvokerType;
@@ -1114,6 +1089,13 @@
                 // necessary to pass BigArityTest
                 this.member = Invokers.invokeBasicMethod(basicInvokerType);
             }
+            assert(isInvokeBasic());
+        }
+
+        private boolean isInvokeBasic() {
+            return member != null &&
+                   member.isMethodHandleInvoke() &&
+                   "invokeBasic".equals(member.getName());
         }
 
         // The next 3 constructors are used to break circular dependencies on MH.invokeStatic, etc.
@@ -1179,71 +1161,89 @@
         /** void return type invokers. */
         @Hidden
         static Object invoke__V(MethodHandle mh, Object[] a) throws Throwable {
-            assert(a.length == 0);
+            assert(arityCheck(0, void.class, mh, a));
             mh.invokeBasic();
             return null;
         }
         @Hidden
         static Object invoke_L_V(MethodHandle mh, Object[] a) throws Throwable {
-            assert(a.length == 1);
+            assert(arityCheck(1, void.class, mh, a));
             mh.invokeBasic(a[0]);
             return null;
         }
         @Hidden
         static Object invoke_LL_V(MethodHandle mh, Object[] a) throws Throwable {
-            assert(a.length == 2);
+            assert(arityCheck(2, void.class, mh, a));
             mh.invokeBasic(a[0], a[1]);
             return null;
         }
         @Hidden
         static Object invoke_LLL_V(MethodHandle mh, Object[] a) throws Throwable {
-            assert(a.length == 3);
+            assert(arityCheck(3, void.class, mh, a));
             mh.invokeBasic(a[0], a[1], a[2]);
             return null;
         }
         @Hidden
         static Object invoke_LLLL_V(MethodHandle mh, Object[] a) throws Throwable {
-            assert(a.length == 4);
+            assert(arityCheck(4, void.class, mh, a));
             mh.invokeBasic(a[0], a[1], a[2], a[3]);
             return null;
         }
         @Hidden
         static Object invoke_LLLLL_V(MethodHandle mh, Object[] a) throws Throwable {
-            assert(a.length == 5);
+            assert(arityCheck(5, void.class, mh, a));
             mh.invokeBasic(a[0], a[1], a[2], a[3], a[4]);
             return null;
         }
         /** Object return type invokers. */
         @Hidden
         static Object invoke__L(MethodHandle mh, Object[] a) throws Throwable {
-            assert(a.length == 0);
+            assert(arityCheck(0, mh, a));
             return mh.invokeBasic();
         }
         @Hidden
         static Object invoke_L_L(MethodHandle mh, Object[] a) throws Throwable {
-            assert(a.length == 1);
+            assert(arityCheck(1, mh, a));
             return mh.invokeBasic(a[0]);
         }
         @Hidden
         static Object invoke_LL_L(MethodHandle mh, Object[] a) throws Throwable {
-            assert(a.length == 2);
+            assert(arityCheck(2, mh, a));
             return mh.invokeBasic(a[0], a[1]);
         }
         @Hidden
         static Object invoke_LLL_L(MethodHandle mh, Object[] a) throws Throwable {
-            assert(a.length == 3);
+            assert(arityCheck(3, mh, a));
             return mh.invokeBasic(a[0], a[1], a[2]);
         }
         @Hidden
         static Object invoke_LLLL_L(MethodHandle mh, Object[] a) throws Throwable {
-            assert(a.length == 4);
+            assert(arityCheck(4, mh, a));
             return mh.invokeBasic(a[0], a[1], a[2], a[3]);
         }
         @Hidden
         static Object invoke_LLLLL_L(MethodHandle mh, Object[] a) throws Throwable {
-            assert(a.length == 5);
+            assert(arityCheck(5, mh, a));
             return mh.invokeBasic(a[0], a[1], a[2], a[3], a[4]);
         }
+        private static boolean arityCheck(int arity, MethodHandle mh, Object[] a) {
+            return arityCheck(arity, Object.class, mh, a);
+        }
+        private static boolean arityCheck(int arity, Class<?> rtype, MethodHandle mh, Object[] a) {
+            assert(a.length == arity)
+                    : Arrays.asList(a.length, arity);
+            assert(mh.type().basicType() == MethodType.genericMethodType(arity).changeReturnType(rtype))
+                    : Arrays.asList(mh, rtype, arity);
+            MemberName member = mh.internalMemberName();
+            if (member != null && member.getName().equals("invokeBasic") && member.isMethodHandleInvoke()) {
+                assert(arity > 0);
+                assert(a[0] instanceof MethodHandle);
+                MethodHandle mh2 = (MethodHandle) a[0];
+                assert(mh2.type().basicType() == MethodType.genericMethodType(arity-1).changeReturnType(rtype))
+                        : Arrays.asList(member, mh2, rtype, arity);
+            }
+            return true;
+        }
 
         static final MethodType INVOKER_METHOD_TYPE =
             MethodType.methodType(Object.class, MethodHandle.class, Object[].class);
@@ -1431,7 +1431,7 @@
             this(new NamedFunction(function), arguments);
         }
         Name(NamedFunction function, Object... arguments) {
-            this(-1, function.returnType(), function, arguments = arguments.clone());
+            this(-1, function.returnType(), function, arguments = Arrays.copyOf(arguments, arguments.length, Object[].class));
             assert(arguments.length == function.arity()) : "arity mismatch: arguments.length=" + arguments.length + " == function.arity()=" + function.arity() + " in " + debugString();
             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();
@@ -1487,7 +1487,11 @@
             if (!replaced)  return this;
             return new Name(function, arguments);
         }
+        /** In the arguments of this Name, replace oldNames[i] pairwise by newNames[i].
+         *  Limit such replacements to {@code start<=i<end}.  Return possibly changed self.
+         */
         Name replaceNames(Name[] oldNames, Name[] newNames, int start, int end) {
+            if (start >= end)  return this;
             @SuppressWarnings("LocalVariableHidesMemberVariable")
             Object[] arguments = this.arguments;
             boolean replaced = false;
@@ -1539,9 +1543,12 @@
             return (isParam()?"a":"t")+(index >= 0 ? index : System.identityHashCode(this))+":"+typeChar();
         }
         public String debugString() {
-            String s = toString();
+            String s = paramString();
             return (function == null) ? s : s + "=" + exprString();
         }
+        public String paramString() {
+            return toString();
+        }
         public String exprString() {
             if (function == null)  return toString();
             StringBuilder buf = new StringBuilder(function.toString());
@@ -1572,34 +1579,6 @@
             return true;
         }
 
-        /**
-         * Does this Name precede the given binding node in some canonical order?
-         * This predicate is used to order data bindings (via insertion sort)
-         * with some stability.
-         */
-        boolean isSiblingBindingBefore(Name binding) {
-            assert(!binding.isParam());
-            if (isParam())  return true;
-            if (function.equals(binding.function) &&
-                arguments.length == binding.arguments.length) {
-                boolean sawInt = false;
-                for (int i = 0; i < arguments.length; i++) {
-                    Object a1 = arguments[i];
-                    Object a2 = binding.arguments[i];
-                    if (!a1.equals(a2)) {
-                        if (a1 instanceof Integer && a2 instanceof Integer) {
-                            if (sawInt)  continue;
-                            sawInt = true;
-                            if ((int)a1 < (int)a2)  continue;  // still might be true
-                        }
-                        return false;
-                    }
-                }
-                return sawInt;
-            }
-            return false;
-        }
-
         /** Return the index of the last occurrence of n in the argument array.
          *  Return -1 if the name is not used.
          */
@@ -1858,37 +1837,6 @@
     @interface Hidden {
     }
 
-
-/*
-    // Smoke-test for the invokers used in this file.
-    static void testMethodHandleLinkers() throws Throwable {
-        MemberName.Factory lookup = MemberName.getFactory();
-        MemberName asList_MN = new MemberName(Arrays.class, "asList",
-                                              MethodType.methodType(List.class, Object[].class),
-                                              REF_invokeStatic);
-        //MethodHandleNatives.resolve(asList_MN, null);
-        asList_MN = lookup.resolveOrFail(asList_MN, REF_invokeStatic, null, NoSuchMethodException.class);
-        System.out.println("about to call "+asList_MN);
-        Object[] abc = { "a", "bc" };
-        List<?> lst = (List<?>) MethodHandle.linkToStatic(abc, asList_MN);
-        System.out.println("lst="+lst);
-        MemberName toString_MN = new MemberName(Object.class.getMethod("toString"));
-        String s1 = (String) MethodHandle.linkToVirtual(lst, toString_MN);
-        toString_MN = new MemberName(Object.class.getMethod("toString"), true);
-        String s2 = (String) MethodHandle.linkToSpecial(lst, toString_MN);
-        System.out.println("[s1,s2,lst]="+Arrays.asList(s1, s2, lst.toString()));
-        MemberName toArray_MN = new MemberName(List.class.getMethod("toArray"));
-        Object[] arr = (Object[]) MethodHandle.linkToInterface(lst, toArray_MN);
-        System.out.println("toArray="+Arrays.toString(arr));
-    }
-    static { try { testMethodHandleLinkers(); } catch (Throwable ex) { throw new RuntimeException(ex); } }
-    // Requires these definitions in MethodHandle:
-    static final native Object linkToStatic(Object x1, MemberName mn) throws Throwable;
-    static final native Object linkToVirtual(Object x1, MemberName mn) throws Throwable;
-    static final native Object linkToSpecial(Object x1, MemberName mn) throws Throwable;
-    static final native Object linkToInterface(Object x1, MemberName mn) throws Throwable;
- */
-
     private static final HashMap<String,Integer> DEBUG_NAME_COUNTERS;
     static {
         if (debugEnabled())
@@ -1901,7 +1849,7 @@
     static {
         createIdentityForms();
         if (USE_PREDEFINED_INTERPRET_METHODS)
-            PREPARED_FORMS.putAll(computeInitialPreparedForms());
+            computeInitialPreparedForms();
         NamedFunction.initializeInvokers();
     }
 
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java	Wed Sep 10 19:19:47 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java	Wed Sep 10 19:19:47 2014 +0400
@@ -327,10 +327,6 @@
         assert(getReferenceKind() == oldKind);
         assert(MethodHandleNatives.refKindIsValid(refKind));
         flags += (((int)refKind - oldKind) << MN_REFERENCE_KIND_SHIFT);
-//        if (isConstructor() && refKind != REF_newInvokeSpecial)
-//            flags += (IS_METHOD - IS_CONSTRUCTOR);
-//        else if (refKind == REF_newInvokeSpecial && isMethod())
-//            flags += (IS_CONSTRUCTOR - IS_METHOD);
         return this;
     }
 
@@ -344,9 +340,11 @@
         return !testFlags(mask, 0);
     }
 
-    /** Utility method to query if this member is a method handle invocation (invoke or invokeExact). */
+    /** Utility method to query if this member is a method handle invocation (invoke or invokeExact).
+     *  Also returns true for the non-public MH.invokeBasic.
+     */
     public boolean isMethodHandleInvoke() {
-        final int bits = MH_INVOKE_MODS;
+        final int bits = MH_INVOKE_MODS &~ Modifier.PUBLIC;
         final int negs = Modifier.STATIC;
         if (testFlags(bits | negs, bits) &&
             clazz == MethodHandle.class) {
@@ -355,7 +353,14 @@
         return false;
     }
     public static boolean isMethodHandleInvokeName(String name) {
-        return name.equals("invoke") || name.equals("invokeExact");
+        switch (name) {
+        case "invoke":
+        case "invokeExact":
+        case "invokeBasic":  // internal sig-poly method
+            return true;
+        default:
+            return false;
+        }
     }
     private static final int MH_INVOKE_MODS = Modifier.NATIVE | Modifier.FINAL | Modifier.PUBLIC;
 
@@ -720,16 +725,8 @@
         init(defClass, name, type, flagsMods(IS_FIELD, 0, refKind));
         initResolved(false);
     }
-    /** Create a field or type name from the given components:  Declaring class, name, type.
-     *  The declaring class may be supplied as null if this is to be a bare name and type.
-     *  The modifier flags default to zero.
-     *  The resulting name will in an unresolved state.
-     */
-    public MemberName(Class<?> defClass, String name, Class<?> type, Void unused) {
-        this(defClass, name, type, REF_NONE);
-        initResolved(false);
-    }
-    /** Create a method or constructor name from the given components:  Declaring class, name, type, modifiers.
+    /** Create a method or constructor name from the given components:
+     *  Declaring class, name, type, reference kind.
      *  It will be a constructor if and only if the name is {@code "&lt;init&gt;"}.
      *  The declaring class may be supplied as null if this is to be a bare name and type.
      *  The last argument is optional, a boolean which requests REF_invokeSpecial.
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java	Wed Sep 10 19:19:47 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java	Wed Sep 10 19:19:47 2014 +0400
@@ -762,11 +762,19 @@
             return this;
         }
         // Return 'this.asTypeCache' if the conversion is already memoized.
+        MethodHandle atc = asTypeCached(newType);
+        if (atc != null) {
+            return atc;
+        }
+        return asTypeUncached(newType);
+    }
+
+    private MethodHandle asTypeCached(MethodType newType) {
         MethodHandle atc = asTypeCache;
         if (atc != null && newType == atc.type) {
             return atc;
         }
-        return asTypeUncached(newType);
+        return null;
     }
 
     /** Override this to change asType behavior. */
@@ -991,8 +999,11 @@
         return MethodHandles.collectArguments(target, collectArgPos, collector);
     }
 
-    // private API: return true if last param exactly matches arrayType
-    private boolean asCollectorChecks(Class<?> arrayType, int arrayLength) {
+    /**
+     * See if {@code asCollector} can be validly called with the given arguments.
+     * Return false if the last parameter is not an exact match to arrayType.
+     */
+    /*non-public*/ boolean asCollectorChecks(Class<?> arrayType, int arrayLength) {
         spreadArrayChecks(arrayType, arrayLength);
         int nargs = type().parameterCount();
         if (nargs != 0) {
@@ -1154,7 +1165,7 @@
      * @see #asFixedArity
      */
     public MethodHandle asVarargsCollector(Class<?> arrayType) {
-        Class<?> arrayElement = arrayType.getComponentType();
+        arrayType.getClass(); // explicit NPE
         boolean lastMatch = asCollectorChecks(arrayType, 0);
         if (isVarargsCollector() && lastMatch)
             return this;
@@ -1283,14 +1294,17 @@
      */
     @Override
     public String toString() {
-        if (DEBUG_METHOD_HANDLE_NAMES)  return debugString();
+        if (DEBUG_METHOD_HANDLE_NAMES)  return "MethodHandle"+debugString();
         return standardString();
     }
     String standardString() {
         return "MethodHandle"+type;
     }
+    /** Return a string with a several lines describing the method handle structure.
+     *  This string would be suitable for display in an IDE debugger.
+     */
     String debugString() {
-        return standardString()+"/LF="+internalForm()+internalProperties();
+        return type+" : "+internalForm()+internalProperties();
     }
 
     //// Implementation methods.
@@ -1302,15 +1316,13 @@
     /*non-public*/
     MethodHandle setVarargs(MemberName member) throws IllegalAccessException {
         if (!member.isVarargs())  return this;
-        int argc = type().parameterCount();
-        if (argc != 0) {
-            Class<?> arrayType = type().parameterType(argc-1);
-            if (arrayType.isArray()) {
-                return MethodHandleImpl.makeVarargsCollector(this, arrayType);
-            }
+        Class<?> arrayType = type().lastParameterType();
+        if (arrayType.isArray()) {
+            return MethodHandleImpl.makeVarargsCollector(this, arrayType);
         }
         throw member.makeAccessException("cannot make variable arity", null);
     }
+
     /*non-public*/
     MethodHandle viewAsType(MethodType newType) {
         // No actual conversions, just a new view of the same method.
@@ -1361,7 +1373,7 @@
 
     /*non-public*/
     Object internalProperties() {
-        // Override to something like "/FOO=bar"
+        // Override to something to follow this.form, like "\n& FOO=bar"
         return "";
     }
 
@@ -1469,6 +1481,7 @@
     /*non-public*/
     void updateForm(LambdaForm newForm) {
         if (form == newForm)  return;
+        assert(this instanceof DirectMethodHandle && this.internalMemberName().isStatic());
         // ISSUE: Should we have a memory fence here?
         UNSAFE.putObject(this, FORM_OFFSET, newForm);
         this.form.prepare();  // as in MethodHandle.<init>
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java	Wed Sep 10 19:19:47 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java	Wed Sep 10 19:19:47 2014 +0400
@@ -357,7 +357,7 @@
     static class AsVarargsCollector extends MethodHandle {
         private final MethodHandle target;
         private final Class<?> arrayType;
-        private /*@Stable*/ MethodHandle asCollectorCache;
+        private @Stable MethodHandle asCollectorCache;
 
         AsVarargsCollector(MethodHandle target, MethodType type, Class<?> arrayType) {
             super(type, reinvokerForm(target));
@@ -534,7 +534,6 @@
 
         static final MethodHandle MH_castReference;
         static final MethodHandle MH_copyAsPrimitiveArray;
-        static final MethodHandle MH_copyAsReferenceArray;
         static final MethodHandle MH_fillNewTypedArray;
         static final MethodHandle MH_fillNewArray;
         static final MethodHandle MH_arrayIdentity;
@@ -557,8 +556,6 @@
                                             MethodType.methodType(Object.class, Class.class, Object.class));
                 MH_copyAsPrimitiveArray = IMPL_LOOKUP.findStatic(MHI, "copyAsPrimitiveArray",
                                             MethodType.methodType(Object.class, Wrapper.class, Object[].class));
-                MH_copyAsReferenceArray = IMPL_LOOKUP.findStatic(MHI, "copyAsReferenceArray",
-                                            MethodType.methodType(Object[].class, Class.class, Object[].class));
                 MH_arrayIdentity        = IMPL_LOOKUP.findStatic(MHI, "identity",
                                             MethodType.methodType(Object[].class, Object[].class));
                 MH_fillNewArray         = IMPL_LOOKUP.findStatic(MHI, "fillNewArray",
@@ -758,8 +755,8 @@
         BoundMethodHandle mh;
         try {
             mh = (BoundMethodHandle)
-                    data.constructor[0].invokeBasic(type, form, (Object) target, (Object) exType, (Object) catcher,
-                                                    (Object) collectArgs, (Object) unboxResult);
+                    data.constructor().invokeBasic(type, form, (Object) target, (Object) exType, (Object) catcher,
+                                                   (Object) collectArgs, (Object) unboxResult);
         } catch (Throwable ex) {
             throw uncaughtException(ex);
         }
@@ -1095,6 +1092,7 @@
     }
     private static Object[] fillNewTypedArray(Object[] example, Integer len, Object[] /*not ...*/ args) {
         Object[] a = Arrays.copyOf(example, len);
+        assert(a.getClass() != Object[].class);
         fillWithArguments(a, 0, args);
         return a;
     }
@@ -1143,9 +1141,6 @@
     }
     private static final MethodHandle[] FILL_ARRAYS = makeFillArrays();
 
-    private static Object[] copyAsReferenceArray(Class<? extends Object[]> arrayType, Object... a) {
-        return Arrays.copyOf(a, a.length, arrayType);
-    }
     private static Object copyAsPrimitiveArray(Wrapper w, Object... boxes) {
         Object a = w.makeArray(boxes.length);
         w.copyArrayUnboxing(boxes, 0, a, 0, boxes.length);
@@ -1265,8 +1260,8 @@
         if (nargs >= MAX_JVM_ARITY/2 - 1) {
             int slots = nargs;
             final int MAX_ARRAY_SLOTS = MAX_JVM_ARITY - 1;  // 1 for receiver MH
-            if (arrayType == double[].class || arrayType == long[].class)
-                slots *= 2;
+            if (slots <= MAX_ARRAY_SLOTS && elemType.isPrimitive())
+                slots *= Wrapper.forPrimitiveType(elemType).stackSlots();
             if (slots > MAX_ARRAY_SLOTS)
                 throw new IllegalArgumentException("too many arguments: "+arrayType.getSimpleName()+", length "+nargs);
         }
@@ -1276,16 +1271,18 @@
         MethodHandle cache[] = TYPED_COLLECTORS.get(elemType);
         MethodHandle mh = nargs < cache.length ? cache[nargs] : null;
         if (mh != null)  return mh;
-        if (elemType.isPrimitive()) {
+        if (nargs == 0) {
+            Object example = java.lang.reflect.Array.newInstance(arrayType.getComponentType(), 0);
+            mh = MethodHandles.constant(arrayType, example);
+        } else if (elemType.isPrimitive()) {
             MethodHandle builder = Lazy.MH_fillNewArray;
             MethodHandle producer = buildArrayProducer(arrayType);
             mh = buildVarargsArray(builder, producer, nargs);
         } else {
-            @SuppressWarnings("unchecked")
-            Class<? extends Object[]> objArrayType = (Class<? extends Object[]>) arrayType;
+            Class<? extends Object[]> objArrayType = arrayType.asSubclass(Object[].class);
             Object[] example = Arrays.copyOf(NO_ARGS_ARRAY, 0, objArrayType);
             MethodHandle builder = Lazy.MH_fillNewTypedArray.bindTo(example);
-            MethodHandle producer = Lazy.MH_arrayIdentity;
+            MethodHandle producer = Lazy.MH_arrayIdentity; // must be weakly typed
             mh = buildVarargsArray(builder, producer, nargs);
         }
         mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)));
@@ -1297,9 +1294,7 @@
 
     private static MethodHandle buildArrayProducer(Class<?> arrayType) {
         Class<?> elemType = arrayType.getComponentType();
-        if (elemType.isPrimitive())
-            return Lazy.MH_copyAsPrimitiveArray.bindTo(Wrapper.forPrimitiveType(elemType));
-        else
-            return Lazy.MH_copyAsReferenceArray.bindTo(arrayType);
+        assert(elemType.isPrimitive());
+        return Lazy.MH_copyAsPrimitiveArray.bindTo(Wrapper.forPrimitiveType(elemType));
     }
 }
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java	Wed Sep 10 19:19:47 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java	Wed Sep 10 19:19:47 2014 +0400
@@ -33,6 +33,7 @@
 import sun.reflect.CallerSensitive;
 import sun.reflect.Reflection;
 import sun.reflect.misc.ReflectUtil;
+import static java.lang.invoke.MethodHandleStatics.*;
 
 /**
  * This class consists exclusively of static methods that help adapt
@@ -148,7 +149,7 @@
     public static
     <T> T asInterfaceInstance(final Class<T> intfc, final MethodHandle target) {
         if (!intfc.isInterface() || !Modifier.isPublic(intfc.getModifiers()))
-            throw new IllegalArgumentException("not a public interface: "+intfc.getName());
+            throw newIllegalArgumentException("not a public interface", intfc.getName());
         final MethodHandle mh;
         if (System.getSecurityManager() != null) {
             final Class<?> caller = Reflection.getCallerClass();
@@ -165,7 +166,7 @@
         }
         final Method[] methods = getSingleNameMethods(intfc);
         if (methods == null)
-            throw new IllegalArgumentException("not a single-method interface: "+intfc.getName());
+            throw newIllegalArgumentException("not a single-method interface", intfc.getName());
         final MethodHandle[] vaTargets = new MethodHandle[methods.length];
         for (int i = 0; i < methods.length; i++) {
             Method sm = methods[i];
@@ -189,7 +190,7 @@
                         return getArg(method.getName());
                     if (isObjectMethod(method))
                         return callObjectMethod(proxy, method, args);
-                    throw new InternalError("bad proxy method: "+method);
+                    throw newInternalError("bad proxy method: "+method);
                 }
             };
 
@@ -240,7 +241,7 @@
                 return (WrapperInstance) x;
         } catch (ClassCastException ex) {
         }
-        throw new IllegalArgumentException("not a wrapper instance");
+        throw newIllegalArgumentException("not a wrapper instance");
     }
 
     /**
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleStatics.java	Wed Sep 10 19:19:47 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleStatics.java	Wed Sep 10 19:19:47 2014 +0400
@@ -45,7 +45,7 @@
     static final boolean DUMP_CLASS_FILES;
     static final boolean TRACE_INTERPRETER;
     static final boolean TRACE_METHOD_LINKAGE;
-    static final Integer COMPILE_THRESHOLD;
+    static final int COMPILE_THRESHOLD;
     static final int PROFILE_LEVEL;
 
     static {
@@ -56,7 +56,7 @@
                     values[1] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DUMP_CLASS_FILES");
                     values[2] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_INTERPRETER");
                     values[3] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE");
-                    values[4] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD");
+                    values[4] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD", 30);
                     values[5] = Integer.getInteger("java.lang.invoke.MethodHandle.PROFILE_LEVEL", 0);
                     return null;
                 }
@@ -131,7 +131,10 @@
     /*non-public*/ static RuntimeException newIllegalArgumentException(String message, Object obj, Object obj2) {
         return new IllegalArgumentException(message(message, obj, obj2));
     }
+    /** Propagate unchecked exceptions and errors, but wrap anything checked and throw that instead. */
     /*non-public*/ static Error uncaughtException(Throwable ex) {
+        if (ex instanceof Error)  throw (Error) ex;
+        if (ex instanceof RuntimeException)  throw (RuntimeException) ex;
         throw newInternalError("uncaught exception", ex);
     }
     static Error NYI() {
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Wed Sep 10 19:19:47 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Wed Sep 10 19:19:47 2014 +0400
@@ -862,6 +862,8 @@
                 return invoker(type);
             if ("invokeExact".equals(name))
                 return exactInvoker(type);
+            if ("invokeBasic".equals(name))
+                return basicInvoker(type);
             assert(!MemberName.isMethodHandleInvokeName(name));
             return null;
         }
@@ -1879,7 +1881,7 @@
     static public
     MethodHandle spreadInvoker(MethodType type, int leadingArgCount) {
         if (leadingArgCount < 0 || leadingArgCount > type.parameterCount())
-            throw new IllegalArgumentException("bad argument count "+leadingArgCount);
+            throw newIllegalArgumentException("bad argument count", leadingArgCount);
         return type.invokers().spreadInvoker(leadingArgCount);
     }
 
@@ -1964,7 +1966,7 @@
 
     static /*non-public*/
     MethodHandle basicInvoker(MethodType type) {
-        return type.form().basicInvoker();
+        return type.invokers().basicInvoker();
     }
 
      /// method handle modification (creation from other method handles)
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java	Wed Sep 10 19:19:47 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java	Wed Sep 10 19:19:47 2014 +0400
@@ -905,7 +905,7 @@
         if (!descriptor.startsWith("(") ||  // also generates NPE if needed
             descriptor.indexOf(')') < 0 ||
             descriptor.indexOf('.') >= 0)
-            throw new IllegalArgumentException("not a method descriptor: "+descriptor);
+            throw newIllegalArgumentException("not a method descriptor: "+descriptor);
         List<Class<?>> types = BytecodeDescriptor.parseMethod(descriptor, loader);
         Class<?> rtype = types.remove(types.size() - 1);
         checkSlotCount(types.size());
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodTypeForm.java	Wed Sep 10 19:19:47 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodTypeForm.java	Wed Sep 10 19:19:47 2014 +0400
@@ -47,14 +47,10 @@
     final int[] argToSlotTable, slotToArgTable;
     final long argCounts;               // packed slot & value counts
     final long primCounts;              // packed prim & double counts
-    final int vmslots;                  // total number of parameter slots
     final MethodType erasedType;        // the canonical erasure
     final MethodType basicType;         // the canonical erasure, with primitives simplified
 
     // Cached adapter information:
-    @Stable String typeString;           // argument type signature characters
-    @Stable MethodHandle genericInvoker; // JVM hook for inexact invoke
-    @Stable MethodHandle basicInvoker;   // cached instance of MH.invokeBasic
     @Stable MethodHandle namedFunctionInvoker; // cached helper for LF.NamedFunction
 
     // Cached lambda form information, for basic types only:
@@ -70,24 +66,40 @@
             LF_INTERPRET      =  6,  // LF interpreter
             LF_COUNTER        =  7,  // CMH wrapper
             LF_REINVOKE       =  8,  // other wrapper
-            LF_EX_LINKER      =  9,  // invokeExact_MT
-            LF_EX_INVOKER     = 10,  // invokeExact MH
-            LF_GEN_LINKER     = 11,
-            LF_GEN_INVOKER    = 12,
+            LF_EX_LINKER      =  9,  // invokeExact_MT (for invokehandle)
+            LF_EX_INVOKER     = 10,  // MHs.invokeExact
+            LF_GEN_LINKER     = 11,  // generic invoke_MT (for invokehandle)
+            LF_GEN_INVOKER    = 12,  // generic MHs.invoke
             LF_CS_LINKER      = 13,  // linkToCallSite_CS
             LF_MH_LINKER      = 14,  // linkToCallSite_MH
-            LF_GWC            = 15,
+            LF_GWC            = 15,  // guardWithCatch (catchException)
             LF_LIMIT          = 16;
 
+    /** Return the type corresponding uniquely (1-1) to this MT-form.
+     *  It might have any primitive returns or arguments, but will have no references except Object.
+     */
     public MethodType erasedType() {
         return erasedType;
     }
 
+    /** Return the basic type derived from the erased type of this MT-form.
+     *  A basic type is erased (all references Object) and also has all primitive
+     *  types (except int, long, float, double, void) normalized to int.
+     *  Such basic types correspond to low-level JVM calling sequences.
+     */
     public MethodType basicType() {
         return basicType;
     }
 
+    private boolean assertIsBasicType() {
+        // primitives must be flattened also
+        assert(erasedType == basicType)
+                : "erasedType: " + erasedType + " != basicType: " + basicType;
+        return true;
+    }
+
     public LambdaForm cachedLambdaForm(int which) {
+        assert(assertIsBasicType());
         return lambdaForms[which];
     }
 
@@ -98,28 +110,6 @@
         return lambdaForms[which] = form;
     }
 
-    public MethodHandle basicInvoker() {
-        assert(erasedType == basicType) : "erasedType: " + erasedType + " != basicType: " + basicType;  // primitives must be flattened also
-        MethodHandle invoker = basicInvoker;
-        if (invoker != null)  return invoker;
-        invoker = DirectMethodHandle.make(invokeBasicMethod(basicType));
-        basicInvoker = invoker;
-        return invoker;
-    }
-
-    // This next one is called from LambdaForm.NamedFunction.<init>.
-    /*non-public*/ static MemberName invokeBasicMethod(MethodType basicType) {
-        assert(basicType == basicType.basicType());
-        try {
-            // Do approximately the same as this public API call:
-            //   Lookup.findVirtual(MethodHandle.class, name, type);
-            // But bypass access and corner case checks, since we know exactly what we need.
-            return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, "invokeBasic", basicType);
-         } catch (ReflectiveOperationException ex) {
-            throw newInternalError("JVM cannot find invoker for "+basicType, ex);
-        }
-    }
-
     /**
      * Build an MTF for a given type, which must have all references erased to Object.
      * This MTF will stand for that type and all un-erased variations.
@@ -172,6 +162,15 @@
             this.basicType = erasedType;
         } else {
             this.basicType = MethodType.makeImpl(bt, bpts, true);
+            // fill in rest of data from the basic type:
+            MethodTypeForm that = this.basicType.form();
+            assert(this != that);
+            this.primCounts = that.primCounts;
+            this.argCounts = that.argCounts;
+            this.argToSlotTable = that.argToSlotTable;
+            this.slotToArgTable = that.slotToArgTable;
+            this.lambdaForms = null;
+            return;
         }
         if (lac != 0) {
             int slot = ptypeCount + lac;
@@ -187,10 +186,14 @@
                 argToSlotTab[1+i]  = slot;
             }
             assert(slot == 0);  // filled the table
-        }
-        this.primCounts = pack(lrc, prc, lac, pac);
-        this.argCounts = pack(rslotCount, rtypeCount, pslotCount, ptypeCount);
-        if (slotToArgTab == null) {
+        } else if (pac != 0) {
+            // have primitives but no long primitives; share slot counts with generic
+            assert(ptypeCount == pslotCount);
+            MethodTypeForm that = MethodType.genericMethodType(ptypeCount).form();
+            assert(this != that);
+            slotToArgTab = that.slotToArgTable;
+            argToSlotTab = that.argToSlotTable;
+        } else {
             int slot = ptypeCount; // first arg is deepest in stack
             slotToArgTab = new int[slot+1];
             argToSlotTab = new int[1+ptypeCount];
@@ -201,19 +204,16 @@
                 argToSlotTab[1+i]  = slot;
             }
         }
+        this.primCounts = pack(lrc, prc, lac, pac);
+        this.argCounts = pack(rslotCount, rtypeCount, pslotCount, ptypeCount);
         this.argToSlotTable = argToSlotTab;
         this.slotToArgTable = slotToArgTab;
 
         if (pslotCount >= 256)  throw newIllegalArgumentException("too many arguments");
 
-        // send a few bits down to the JVM:
-        this.vmslots = parameterSlotCount();
-
-        if (basicType == erasedType) {
-            lambdaForms = new LambdaForm[LF_LIMIT];
-        } else {
-            lambdaForms = null;  // could be basicType.form().lambdaForms;
-        }
+        // Initialize caches, but only for basic types
+        assert(basicType == erasedType);
+        this.lambdaForms = new LambdaForm[LF_LIMIT];
     }
 
     private static long pack(int a, int b, int c, int d) {
@@ -300,7 +300,7 @@
      */
     public static MethodType canonicalize(MethodType mt, int howRet, int howArgs) {
         Class<?>[] ptypes = mt.ptypes();
-        Class<?>[] ptc = MethodTypeForm.canonicalizes(ptypes, howArgs);
+        Class<?>[] ptc = MethodTypeForm.canonicalizeAll(ptypes, howArgs);
         Class<?> rtype = mt.returnType();
         Class<?> rtc = MethodTypeForm.canonicalize(rtype, howRet);
         if (ptc == null && rtc == null) {
@@ -368,7 +368,7 @@
     /** Canonicalize each param type in the given array.
      *  Return null if all types are already canonicalized.
      */
-    static Class<?>[] canonicalizes(Class<?>[] ts, int how) {
+    static Class<?>[] canonicalizeAll(Class<?>[] ts, int how) {
         Class<?>[] cs = null;
         for (int imax = ts.length, i = 0; i < imax; i++) {
             Class<?> c = canonicalize(ts[i], how);
--- a/jdk/test/java/lang/invoke/MethodHandlesTest.java	Wed Sep 10 19:19:47 2014 +0400
+++ b/jdk/test/java/lang/invoke/MethodHandlesTest.java	Wed Sep 10 19:19:47 2014 +0400
@@ -2160,15 +2160,23 @@
                     else
                         type = type.changeParameterType(j, argType);
                     if (done.add(type))
-                        testInvokers(type);
+                        testInvokersWithCatch(type);
                     MethodType vtype = type.changeReturnType(void.class);
                     if (done.add(vtype))
-                        testInvokers(vtype);
+                        testInvokersWithCatch(vtype);
                 }
             }
         }
     }
 
+    public void testInvokersWithCatch(MethodType type) throws Throwable {
+        try {
+            testInvokers(type);
+        } catch (Throwable ex) {
+            System.out.println("*** testInvokers on "+type+" => ");
+            ex.printStackTrace(System.out);
+        }
+    }
     public void testInvokers(MethodType type) throws Throwable {
         if (verbosity >= 3)
             System.out.println("test invokers for "+type);