changeset 10664:4a5637160724

Merge
author prr
date Fri, 12 Sep 2014 10:33:32 -0700
parents acfb397df680 267950e85a3b
children fb6b143641fd
files src/java.base/share/conf/security/sunpkcs11-solaris.cfg
diffstat 106 files changed, 5813 insertions(+), 3355 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Mon Sep 08 10:24:45 2014 -0700
+++ b/.hgignore	Fri Sep 12 10:33:32 2014 -0700
@@ -1,5 +1,6 @@
 ^build/
 ^dist/
+^webrev
 ^testoutput/
 /nbproject/private/
 ^make/netbeans/.*/build/
--- a/.hgtags	Mon Sep 08 10:24:45 2014 -0700
+++ b/.hgtags	Fri Sep 12 10:33:32 2014 -0700
@@ -269,3 +269,7 @@
 875450e7ef8dde8f59db662ec1351ea30b8cb35d jdk9-b24
 a31efe49556a7c12f9ea2c9ee8b4fae8aa67723a jdk9-b25
 dde9f5cfde5f46e62ceb5fab81151578e5277aef jdk9-b26
+f0870554049807d3392bd7976ab114f7f2b7bafa jdk9-b27
+1828f73b35cfe35e460e41fd6e087ab1f83e0621 jdk9-b28
+2da27e8e2c865e154f0c2eb9009f011a44649b11 jdk9-b29
+8d24fb4493f13d380a2adf62d444e1e5a4451f37 jdk9-b30
--- a/make/copy/Copy-java.base.gmk	Mon Sep 08 10:24:45 2014 -0700
+++ b/make/copy/Copy-java.base.gmk	Fri Sep 12 10:33:32 2014 -0700
@@ -208,20 +208,6 @@
 
 ################################################################################
 
-ifeq ($(OPENJDK_TARGET_OS), solaris)
-
-  SUNPKCS11_CFG_SRC := $(JDK_TOPDIR)/src/java.base/share/conf/security/sunpkcs11-solaris.cfg
-  SUNPKCS11_CFG_DST := $(JDK_OUTPUTDIR)/lib/security/sunpkcs11-solaris.cfg
-
-  $(SUNPKCS11_CFG_DST): $(SUNPKCS11_CFG_SRC)
-	$(call install-file)
-
-  BASE_CONF_FILES += $(SUNPKCS11_CFG_DST)
-
-endif
-
-################################################################################
-
 $(JDK_OUTPUTDIR)/lib/net.properties: $(JDK_TOPDIR)/src/java.base/share/conf/net.properties
 	$(ECHO) $(LOG_INFO) Copying $(@F)
 	$(call install-file)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/copy/Copy-jdk.crypto.pkcs11.gmk	Fri Sep 12 10:33:32 2014 -0700
@@ -0,0 +1,50 @@
+#
+# 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.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# 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.
+#
+
+include CopyCommon.gmk
+
+################################################################################
+
+ifeq ($(OPENJDK_TARGET_OS), solaris)
+
+  SUNPKCS11_CFG_SRC := \
+      $(JDK_TOPDIR)/src/jdk.crypto.pkcs11/solaris/conf/security/sunpkcs11-solaris.cfg
+  SUNPKCS11_CFG_DST := $(JDK_OUTPUTDIR)/lib/security/sunpkcs11-solaris.cfg
+
+  $(SUNPKCS11_CFG_DST): $(SUNPKCS11_CFG_SRC)
+	$(call install-file)
+
+  SECURITY_PKCS11_CONF_FILES += $(SUNPKCS11_CFG_DST)
+
+endif
+
+################################################################################
+
+jdk.crypto.pkcs11: $(SECURITY_PKCS11_CONF_FILES)
+
+all: jdk.crypto.pkcs11
+
+.PHONY: all jdk.crypto.pkcs11
+
--- a/src/java.base/share/classes/java/lang/Integer.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/java/lang/Integer.java	Fri Sep 12 10:33:32 2014 -0700
@@ -595,37 +595,6 @@
     /**
      * Parses the {@link CharSequence} argument as a signed {@code int} in the
      * specified {@code radix}, beginning at the specified {@code beginIndex}
-     * and extending to the end of the sequence.
-     *
-     * <p>The method does not take steps to guard against the
-     * {@code CharSequence} being mutated while parsing.
-     *
-     * @param      s   the {@code CharSequence} containing the {@code int}
-     *                  representation to be parsed
-     * @param      radix   the radix to be used while parsing {@code s}.
-     * @param      beginIndex   the beginning index, inclusive.
-     * @return     the signed {@code int} represented by the subsequence in
-     *             the specified radix.
-     * @throws     NullPointerException  if {@code s} is null.
-     * @throws     IndexOutOfBoundsException  if {@code beginIndex} is
-     *             negative, or if {@code beginIndex} is greater than
-     *             {@code s.length()}.
-     * @throws     NumberFormatException  if the {@code CharSequence} does not
-     *             contain a parsable {@code int} in the specified
-     *             {@code radix}, or if {@code radix} is either smaller than
-     *             {@link java.lang.Character#MIN_RADIX} or larger than
-     *             {@link java.lang.Character#MAX_RADIX}.
-     * @since  1.9
-     */
-    public static int parseInt(CharSequence s, int radix, int beginIndex)
-                throws NumberFormatException {
-        // forces an implicit null check of s
-        return parseInt(s, radix, beginIndex, s.length());
-    }
-
-    /**
-     * Parses the {@link CharSequence} argument as a signed {@code int} in the
-     * specified {@code radix}, beginning at the specified {@code beginIndex}
      * and extending to {@code endIndex - 1}.
      *
      * <p>The method does not take steps to guard against the
@@ -633,9 +602,9 @@
      *
      * @param      s   the {@code CharSequence} containing the {@code int}
      *                  representation to be parsed
-     * @param      radix   the radix to be used while parsing {@code s}.
      * @param      beginIndex   the beginning index, inclusive.
      * @param      endIndex     the ending index, exclusive.
+     * @param      radix   the radix to be used while parsing {@code s}.
      * @return     the signed {@code int} represented by the subsequence in
      *             the specified radix.
      * @throws     NullPointerException  if {@code s} is null.
@@ -650,7 +619,7 @@
      *             {@link java.lang.Character#MAX_RADIX}.
      * @since  1.9
      */
-    public static int parseInt(CharSequence s, int radix, int beginIndex, int endIndex)
+    public static int parseInt(CharSequence s, int beginIndex, int endIndex, int radix)
                 throws NumberFormatException {
         s = Objects.requireNonNull(s);
 
@@ -690,7 +659,7 @@
             int result = 0;
             while (i < endIndex) {
                 // Accumulating negatively avoids surprises near MAX_VALUE
-                int digit = Character.digit(s.charAt(i++), radix);
+                int digit = Character.digit(s.charAt(i), radix);
                 if (digit < 0 || result < multmin) {
                     throw NumberFormatException.forCharSequence(s, beginIndex,
                             endIndex, i);
@@ -700,6 +669,7 @@
                     throw NumberFormatException.forCharSequence(s, beginIndex,
                             endIndex, i);
                 }
+                i++;
                 result -= digit;
             }
             return negative ? result : -result;
@@ -808,37 +778,6 @@
     /**
      * Parses the {@link CharSequence} argument as an unsigned {@code int} in
      * the specified {@code radix}, beginning at the specified
-     * {@code beginIndex} and extending to the end of the sequence.
-     *
-     * <p>The method does not take steps to guard against the
-     * {@code CharSequence} being mutated while parsing.
-     *
-     * @param      s   the {@code CharSequence} containing the unsigned
-     *                 {@code int} representation to be parsed
-     * @param      radix   the radix to be used while parsing {@code s}.
-     * @param      beginIndex   the beginning index, inclusive.
-     * @return     the unsigned {@code int} represented by the subsequence in
-     *             the specified radix.
-     * @throws     NullPointerException  if {@code s} is null.
-     * @throws     IndexOutOfBoundsException  if {@code beginIndex} is
-     *             negative, or if {@code beginIndex} is greater than
-     *             {@code s.length()}.
-     * @throws     NumberFormatException  if the {@code CharSequence} does not
-     *             contain a parsable unsigned {@code int} in the specified
-     *             {@code radix}, or if {@code radix} is either smaller than
-     *             {@link java.lang.Character#MIN_RADIX} or larger than
-     *             {@link java.lang.Character#MAX_RADIX}.
-     * @since  1.9
-     */
-    public static int parseUnsignedInt(CharSequence s, int radix, int beginIndex)
-                throws NumberFormatException {
-        // forces an implicit null check of s
-        return parseUnsignedInt(s, radix, beginIndex, s.length());
-    }
-
-    /**
-     * Parses the {@link CharSequence} argument as an unsigned {@code int} in
-     * the specified {@code radix}, beginning at the specified
      * {@code beginIndex} and extending to {@code endIndex - 1}.
      *
      * <p>The method does not take steps to guard against the
@@ -846,9 +785,9 @@
      *
      * @param      s   the {@code CharSequence} containing the unsigned
      *                 {@code int} representation to be parsed
-     * @param      radix   the radix to be used while parsing {@code s}.
      * @param      beginIndex   the beginning index, inclusive.
      * @param      endIndex     the ending index, exclusive.
+     * @param      radix   the radix to be used while parsing {@code s}.
      * @return     the unsigned {@code int} represented by the subsequence in
      *             the specified radix.
      * @throws     NullPointerException  if {@code s} is null.
@@ -863,7 +802,7 @@
      *             {@link java.lang.Character#MAX_RADIX}.
      * @since  1.9
      */
-    public static int parseUnsignedInt(CharSequence s, int radix, int beginIndex, int endIndex)
+    public static int parseUnsignedInt(CharSequence s, int beginIndex, int endIndex, int radix)
                 throws NumberFormatException {
         s = Objects.requireNonNull(s);
 
@@ -881,9 +820,9 @@
             } else {
                 if (len <= 5 || // Integer.MAX_VALUE in Character.MAX_RADIX is 6 digits
                         (radix == 10 && len <= 9)) { // Integer.MAX_VALUE in base 10 is 10 digits
-                    return parseInt(s, radix, start, start + len);
+                    return parseInt(s, start, start + len, radix);
                 } else {
-                    long ell = Long.parseLong(s, radix, start, start + len);
+                    long ell = Long.parseLong(s, start, start + len, radix);
                     if ((ell & 0xffff_ffff_0000_0000L) == 0) {
                         return (int) ell;
                     } else {
--- a/src/java.base/share/classes/java/lang/Long.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/java/lang/Long.java	Fri Sep 12 10:33:32 2014 -0700
@@ -606,37 +606,6 @@
 
     /**
      * Parses the {@link CharSequence} argument as a signed {@code long} in
-     * the specified {@code radix}, beginning at the specified {@code beginIndex}
-     * and extending to the end of the sequence.
-     *
-     * <p>The method does not take steps to guard against the
-     * {@code CharSequence} being mutated while parsing.
-     *
-     * @param      s   the {@code CharSequence} containing the {@code long}
-     *                  representation to be parsed
-     * @param      radix   the radix to be used while parsing {@code s}.
-     * @param      beginIndex   the beginning index, inclusive.
-     * @return     the signed {@code long} represented by the subsequence in
-     *             the specified radix.
-     * @throws     NullPointerException  if {@code s} is null.
-     * @throws     IndexOutOfBoundsException  if {@code beginIndex} is
-     *             negative, or if {@code beginIndex} is greater than
-     *             {@code s.length()}.
-     * @throws     NumberFormatException  if the {@code CharSequence} does not
-     *             contain a parsable {@code long} in the specified
-     *             {@code radix}, or if {@code radix} is either smaller than
-     *             {@link java.lang.Character#MIN_RADIX} or larger than
-     *             {@link java.lang.Character#MAX_RADIX}.
-     * @since  1.9
-     */
-    public static long parseLong(CharSequence s, int radix, int beginIndex)
-            throws NumberFormatException {
-        // forces a null check of s
-        return parseLong(s, radix, beginIndex, s.length());
-    }
-
-    /**
-     * Parses the {@link CharSequence} argument as a signed {@code long} in
      * the specified {@code radix}, beginning at the specified
      * {@code beginIndex} and extending to {@code endIndex - 1}.
      *
@@ -645,9 +614,9 @@
      *
      * @param      s   the {@code CharSequence} containing the {@code long}
      *                  representation to be parsed
-     * @param      radix   the radix to be used while parsing {@code s}.
      * @param      beginIndex   the beginning index, inclusive.
      * @param      endIndex     the ending index, exclusive.
+     * @param      radix   the radix to be used while parsing {@code s}.
      * @return     the signed {@code long} represented by the subsequence in
      *             the specified radix.
      * @throws     NullPointerException  if {@code s} is null.
@@ -662,7 +631,7 @@
      *             {@link java.lang.Character#MAX_RADIX}.
      * @since  1.9
      */
-    public static long parseLong(CharSequence s, int radix, int beginIndex, int endIndex)
+    public static long parseLong(CharSequence s, int beginIndex, int endIndex, int radix)
                 throws NumberFormatException {
         s = Objects.requireNonNull(s);
 
@@ -702,7 +671,7 @@
             long result = 0;
             while (i < endIndex) {
                 // Accumulating negatively avoids surprises near MAX_VALUE
-                int digit = Character.digit(s.charAt(i++), radix);
+                int digit = Character.digit(s.charAt(i), radix);
                 if (digit < 0 || result < multmin) {
                     throw NumberFormatException.forCharSequence(s, beginIndex,
                             endIndex, i);
@@ -712,6 +681,7 @@
                     throw NumberFormatException.forCharSequence(s, beginIndex,
                             endIndex, i);
                 }
+                i++;
                 result -= digit;
             }
             return negative ? result : -result;
@@ -811,7 +781,7 @@
                 }
 
                 // No need for range checks on len due to testing above.
-                long first = parseLong(s, radix, 0, len - 1);
+                long first = parseLong(s, 0, len - 1, radix);
                 int second = Character.digit(s.charAt(len - 1), radix);
                 if (second < 0) {
                     throw new NumberFormatException("Bad digit at end of " + s);
@@ -883,37 +853,6 @@
     /**
      * Parses the {@link CharSequence} argument as an unsigned {@code long} in
      * the specified {@code radix}, beginning at the specified
-     * {@code beginIndex} and extending to the end of the sequence.
-     *
-     * <p>The method does not take steps to guard against the
-     * {@code CharSequence} being mutated while parsing.
-     *
-     * @param      s   the {@code CharSequence} containing the unsigned
-     *                 {@code long} representation to be parsed
-     * @param      radix   the radix to be used while parsing {@code s}.
-     * @param      beginIndex   the beginning index, inclusive.
-     * @return     the unsigned {@code long} represented by the subsequence in
-     *             the specified radix.
-     * @throws     NullPointerException  if {@code s} is null.
-     * @throws     IndexOutOfBoundsException  if {@code beginIndex} is
-     *             negative, or if {@code beginIndex} is greater than
-     *             {@code s.length()}.
-     * @throws     NumberFormatException  if the {@code CharSequence} does not
-     *             contain a parsable unsigned {@code long} in the specified
-     *             {@code radix}, or if {@code radix} is either smaller than
-     *             {@link java.lang.Character#MIN_RADIX} or larger than
-     *             {@link java.lang.Character#MAX_RADIX}.
-     * @since  1.9
-     */
-    public static long parseUnsignedLong(CharSequence s, int radix, int beginIndex)
-                throws NumberFormatException {
-        // forces a null check of s
-        return parseUnsignedLong(s, radix, beginIndex, s.length());
-    }
-
-    /**
-     * Parses the {@link CharSequence} argument as an unsigned {@code long} in
-     * the specified {@code radix}, beginning at the specified
      * {@code beginIndex} and extending to {@code endIndex - 1}.
      *
      * <p>The method does not take steps to guard against the
@@ -921,9 +860,9 @@
      *
      * @param      s   the {@code CharSequence} containing the unsigned
      *                 {@code long} representation to be parsed
-     * @param      radix   the radix to be used while parsing {@code s}.
      * @param      beginIndex   the beginning index, inclusive.
      * @param      endIndex     the ending index, exclusive.
+     * @param      radix   the radix to be used while parsing {@code s}.
      * @return     the unsigned {@code long} represented by the subsequence in
      *             the specified radix.
      * @throws     NullPointerException  if {@code s} is null.
@@ -938,7 +877,7 @@
      *             {@link java.lang.Character#MAX_RADIX}.
      * @since  1.9
      */
-    public static long parseUnsignedLong(CharSequence s, int radix, int beginIndex, int endIndex)
+    public static long parseUnsignedLong(CharSequence s, int beginIndex, int endIndex, int radix)
                 throws NumberFormatException {
         s = Objects.requireNonNull(s);
 
@@ -955,11 +894,11 @@
             } else {
                 if (len <= 12 || // Long.MAX_VALUE in Character.MAX_RADIX is 13 digits
                     (radix == 10 && len <= 18) ) { // Long.MAX_VALUE in base 10 is 19 digits
-                    return parseLong(s, radix, start, start + len);
+                    return parseLong(s, start, start + len, radix);
                 }
 
                 // No need for range checks on end due to testing above.
-                long first = parseLong(s, radix, start, start + len - 1);
+                long first = parseLong(s, start, start + len - 1, radix);
                 int second = Character.digit(s.charAt(start + len - 1), radix);
                 if (second < 0) {
                     throw new NumberFormatException("Bad digit at end of " +
--- a/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java	Fri Sep 12 10:33:32 2014 -0700
@@ -50,31 +50,31 @@
  *
  * 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);
+        assert(speciesData() == speciesData(form));
     }
 
     //
     // BMH API and internals
     //
 
-    static MethodHandle bindSingle(MethodType type, LambdaForm form, BasicType xtype, Object x) {
+    static BoundMethodHandle 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_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 bindSingle(type, form, x);  // Use known fast path.
             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) {
@@ -82,49 +82,61 @@
         }
     }
 
-    static MethodHandle bindSingle(MethodType type, LambdaForm form, Object x) {
-            return new Species_L(type, form, x);
+    /*non-public*/
+    LambdaFormEditor editor() {
+        return form.editor();
     }
 
-    MethodHandle cloneExtend(MethodType type, LambdaForm form, BasicType xtype, Object x) {
-        try {
-            switch (xtype) {
-            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 newInternalError("unexpected type: " + xtype);
+    static BoundMethodHandle bindSingle(MethodType type, LambdaForm form, Object x) {
+        return Species_L.make(type, form, x);
+    }
+
+    @Override // there is a default binder in the super class, for 'L' types only
+    /*non-public*/
+    BoundMethodHandle bindArgumentL(int pos, Object value) {
+        return editor().bindArgumentL(this, pos, value);
+    }
+    /*non-public*/
+    BoundMethodHandle bindArgumentI(int pos, int value) {
+        return editor().bindArgumentI(this, pos, value);
+    }
+    /*non-public*/
+    BoundMethodHandle bindArgumentJ(int pos, long value) {
+        return editor().bindArgumentJ(this, pos, value);
+    }
+    /*non-public*/
+    BoundMethodHandle bindArgumentF(int pos, float value) {
+        return editor().bindArgumentF(this, pos, value);
+    }
+    /*non-public*/
+    BoundMethodHandle bindArgumentD(int pos, double value) {
+        return editor().bindArgumentD(this, pos, value);
     }
 
     @Override
-    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);
+    BoundMethodHandle rebind() {
+        if (!tooComplex()) {
+            return this;
+        }
+        return makeReinvoker(this);
     }
 
-    @Override
-    MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
-        LambdaForm form = internalForm().addArguments(pos, srcType.parameterList().subList(pos, pos + drops));
-        try {
-             return copyWith(srcType, form);
-         } catch (Throwable t) {
-             throw newInternalError(t);
-         }
+    private boolean tooComplex() {
+        return (fieldCount() > FIELD_COUNT_THRESHOLD ||
+                form.expressionCount() > FORM_EXPRESSION_THRESHOLD);
     }
+    private static final int FIELD_COUNT_THRESHOLD = 12;      // largest convenient BMH field count
+    private static final int FORM_EXPRESSION_THRESHOLD = 24;  // largest convenient BMH expression count
 
-    @Override
-    MethodHandle permuteArguments(MethodType newType, int[] reorder) {
-        try {
-             return copyWith(newType, form.permuteArguments(1, reorder, basicTypes(newType.parameterList())));
-         } catch (Throwable t) {
-             throw newInternalError(t);
-         }
+    /**
+     * A reinvoker MH has this form:
+     * {@code lambda (bmh, arg*) { thismh = bmh[0]; invokeBasic(thismh, arg*) }}
+     */
+    static BoundMethodHandle makeReinvoker(MethodHandle target) {
+        LambdaForm form = DelegatingMethodHandle.makeReinvokerForm(
+                target, MethodTypeForm.LF_REBIND,
+                Species_L.SPECIES_DATA, Species_L.SPECIES_DATA.getterFunction(0));
+        return Species_L.make(target.type(), form, target);
     }
 
     /**
@@ -133,14 +145,22 @@
      */
     /*non-public*/ abstract SpeciesData speciesData();
 
+    /*non-public*/ static SpeciesData speciesData(LambdaForm form) {
+        Object c = form.names[0].constraint;
+        if (c instanceof SpeciesData)
+            return (SpeciesData) c;
+        // if there is no BMH constraint, then use the null constraint
+        return SpeciesData.EMPTY;
+    }
+
     /**
      * Return the number of fields in this BMH.  Equivalent to speciesData().fieldCount().
      */
     /*non-public*/ abstract int fieldCount();
 
     @Override
-    final Object internalProperties() {
-        return "/BMH="+internalValues();
+    Object internalProperties() {
+        return "\n& BMH="+internalValues();
     }
 
     @Override
@@ -178,15 +198,6 @@
     /*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) arg(0);
-        } catch (Throwable ex) {
-            throw newInternalError(ex);
-        }
-    }
-
     //
     // concrete BMH classes required to close bootstrap loops
     //
@@ -198,8 +209,6 @@
             super(mt, lf);
             this.argL0 = argL0;
         }
-        // The following is a grossly irregular hack:
-        @Override MethodHandle reinvokerTarget() { return (MethodHandle) argL0; }
         @Override
         /*non-public*/ SpeciesData speciesData() {
             return SPECIES_DATA;
@@ -219,7 +228,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 +236,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 +244,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 +252,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 +260,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 +277,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 +301,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 +317,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 +353,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 +537,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>
@@ -575,16 +604,6 @@
             mv.visitMaxs(0, 0);
             mv.visitEnd();
 
-            // emit implementation of reinvokerTarget()
-            mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "reinvokerTarget", "()" + MH_SIG, null, null);
-            mv.visitCode();
-            mv.visitVarInsn(ALOAD, 0);
-            mv.visitFieldInsn(GETFIELD, className, "argL0", JLO_SIG);
-            mv.visitTypeInsn(CHECKCAST, MH);
-            mv.visitInsn(ARETURN);
-            mv.visitMaxs(0, 0);
-            mv.visitEnd();
-
             // emit implementation of speciesData()
             mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "speciesData", MYSPECIES_DATA_SIG, null, null);
             mv.visitCode();
@@ -653,16 +672,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/src/java.base/share/classes/java/lang/invoke/CallSite.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/CallSite.java	Fri Sep 12 10:33:32 2014 -0700
@@ -102,7 +102,7 @@
      */
     /*package-private*/
     CallSite(MethodType type) {
-        target = type.invokers().uninitializedCallSite();
+        target = makeUninitializedCallSite(type);
     }
 
     /**
@@ -211,27 +211,40 @@
     public abstract MethodHandle dynamicInvoker();
 
     /*non-public*/ MethodHandle makeDynamicInvoker() {
-        MethodHandle getTarget = GET_TARGET.bindReceiver(this);
+        MethodHandle getTarget = GET_TARGET.bindArgumentL(0, this);
         MethodHandle invoker = MethodHandles.exactInvoker(this.type());
         return MethodHandles.foldArguments(invoker, getTarget);
     }
 
     private static final MethodHandle GET_TARGET;
+    private static final MethodHandle THROW_UCS;
     static {
         try {
             GET_TARGET = IMPL_LOOKUP.
                 findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class));
+            THROW_UCS = IMPL_LOOKUP.
+                findStatic(CallSite.class, "uninitializedCallSite", MethodType.methodType(Object.class, Object[].class));
         } catch (ReflectiveOperationException e) {
             throw newInternalError(e);
         }
     }
 
     /** This guy is rolled into the default target if a MethodType is supplied to the constructor. */
-    /*package-private*/
-    static Empty uninitializedCallSite() {
+    private static Object uninitializedCallSite(Object... ignore) {
         throw new IllegalStateException("uninitialized call site");
     }
 
+    private MethodHandle makeUninitializedCallSite(MethodType targetType) {
+        MethodType basicType = targetType.basicType();
+        MethodHandle invoker = basicType.form().cachedMethodHandle(MethodTypeForm.MH_UNINIT_CS);
+        if (invoker == null) {
+            invoker = THROW_UCS.asType(basicType);
+            invoker = basicType.form().setCachedMethodHandle(MethodTypeForm.MH_UNINIT_CS, invoker);
+        }
+        // unchecked view is OK since no values will be received or returned
+        return invoker.viewAsType(targetType, false);
+    }
+
     // unsafe stuff:
     private static final long TARGET_OFFSET;
     static {
@@ -319,7 +332,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)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java	Fri Sep 12 10:33:32 2014 -0700
@@ -0,0 +1,145 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package java.lang.invoke;
+
+import java.util.Arrays;
+import static java.lang.invoke.LambdaForm.*;
+import static java.lang.invoke.MethodHandleStatics.*;
+
+/**
+ * A method handle whose invocation behavior is determined by a target.
+ * The delegating MH itself can hold extra "intentions" beyond the simple behavior.
+ * @author jrose
+ */
+/*non-public*/
+abstract class DelegatingMethodHandle extends MethodHandle {
+    protected DelegatingMethodHandle(MethodHandle target) {
+        this(target.type(), target);
+    }
+
+    protected DelegatingMethodHandle(MethodType type, MethodHandle target) {
+        super(type, chooseDelegatingForm(target));
+    }
+
+    /** Define this to extract the delegated target which supplies the invocation behavior. */
+    abstract protected MethodHandle getTarget();
+
+    @Override
+    abstract MethodHandle asTypeUncached(MethodType newType);
+
+    @Override
+    MemberName internalMemberName() {
+        return getTarget().internalMemberName();
+    }
+
+    @Override
+    boolean isInvokeSpecial() {
+        return getTarget().isInvokeSpecial();
+    }
+
+    @Override
+    Class<?> internalCallerClass() {
+        return getTarget().internalCallerClass();
+    }
+
+    @Override
+    MethodHandle copyWith(MethodType mt, LambdaForm lf) {
+        // FIXME: rethink 'copyWith' protocol; it is too low-level for use on all MHs
+        throw newIllegalArgumentException("do not use this");
+    }
+
+    @Override
+    String internalProperties() {
+        return "\n& Class="+getClass().getSimpleName()+
+               "\n& Target="+getTarget().debugString();
+    }
+
+    @Override
+    BoundMethodHandle rebind() {
+        return getTarget().rebind();
+    }
+
+    private static LambdaForm chooseDelegatingForm(MethodHandle target) {
+        if (target instanceof SimpleMethodHandle)
+            return target.internalForm();  // no need for an indirection
+        return makeReinvokerForm(target, MethodTypeForm.LF_DELEGATE, DelegatingMethodHandle.class, NF_getTarget);
+    }
+
+    /** Create a LF which simply reinvokes a target of the given basic type. */
+    static LambdaForm makeReinvokerForm(MethodHandle target,
+                                        int whichCache,
+                                        Object constraint,
+                                        NamedFunction getTargetFn) {
+        MethodType mtype = target.type().basicType();
+        boolean customized = (whichCache < 0 ||
+                mtype.parameterSlotCount() > MethodType.MAX_MH_INVOKER_ARITY);
+        LambdaForm form;
+        if (!customized) {
+            form = mtype.form().cachedLambdaForm(whichCache);
+            if (form != null)  return form;
+        }
+        final int THIS_DMH    = 0;
+        final int ARG_BASE    = 1;
+        final int ARG_LIMIT   = ARG_BASE + mtype.parameterCount();
+        int nameCursor = ARG_LIMIT;
+        final int NEXT_MH     = customized ? -1 : nameCursor++;
+        final int REINVOKE    = nameCursor++;
+        LambdaForm.Name[] names = LambdaForm.arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
+        assert(names.length == nameCursor);
+        names[THIS_DMH] = names[THIS_DMH].withConstraint(constraint);
+        Object[] targetArgs;
+        if (customized) {
+            targetArgs = Arrays.copyOfRange(names, ARG_BASE, ARG_LIMIT, Object[].class);
+            names[REINVOKE] = new LambdaForm.Name(target, targetArgs);  // the invoker is the target itself
+        } else {
+            names[NEXT_MH] = new LambdaForm.Name(getTargetFn, names[THIS_DMH]);
+            targetArgs = Arrays.copyOfRange(names, THIS_DMH, ARG_LIMIT, Object[].class);
+            targetArgs[0] = names[NEXT_MH];  // overwrite this MH with next MH
+            names[REINVOKE] = new LambdaForm.Name(mtype, targetArgs);
+        }
+        String debugString;
+        switch(whichCache) {
+            case MethodTypeForm.LF_REBIND:   debugString = "BMH.reinvoke"; break;
+            case MethodTypeForm.LF_DELEGATE: debugString = "MH.delegate";  break;
+            default:                         debugString = "MH.reinvoke";  break;
+        }
+        form = new LambdaForm(debugString, ARG_LIMIT, names);
+        if (!customized) {
+            form = mtype.form().setCachedLambdaForm(whichCache, form);
+        }
+        return form;
+    }
+
+    private static final NamedFunction NF_getTarget;
+    static {
+        try {
+            NF_getTarget = new NamedFunction(DelegatingMethodHandle.class
+                                             .getDeclaredMethod("getTarget"));
+        } catch (ReflectiveOperationException ex) {
+            throw newInternalError(ex);
+        }
+    }
+}
--- a/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java	Fri Sep 12 10:33:32 2014 -0700
@@ -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;
             }
         }
@@ -126,60 +127,30 @@
     }
 
     @Override
+    BoundMethodHandle rebind() {
+        return BoundMethodHandle.makeReinvoker(this);
+    }
+
+    @Override
+    MethodHandle copyWith(MethodType mt, LambdaForm lf) {
+        assert(this.getClass() == DirectMethodHandle.class);  // must override in subclasses
+        return new DirectMethodHandle(mt, lf, member);
+    }
+
+    @Override
     String internalProperties() {
-        return "/DMH="+member.toString();
+        return "\n& DMH.MN="+internalMemberName();
     }
 
     //// Implementation methods.
     @Override
-    MethodHandle viewAsType(MethodType newType) {
-        return new DirectMethodHandle(newType, form, member);
-    }
-    @Override
     @ForceInline
     MemberName internalMemberName() {
         return member;
     }
 
-    @Override
-    MethodHandle bindArgument(int pos, BasicType basicType, Object value) {
-        // If the member needs dispatching, do so.
-        if (pos == 0 && basicType == L_TYPE) {
-            DirectMethodHandle concrete = maybeRebind(value);
-            if (concrete != null)
-                return concrete.bindReceiver(value);
-        }
-        return super.bindArgument(pos, basicType, value);
-    }
-
-    @Override
-    MethodHandle bindReceiver(Object receiver) {
-        // If the member needs dispatching, do so.
-        DirectMethodHandle concrete = maybeRebind(receiver);
-        if (concrete != null)
-            return concrete.bindReceiver(receiver);
-        return super.bindReceiver(receiver);
-    }
-
     private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
 
-    private DirectMethodHandle maybeRebind(Object receiver) {
-        if (receiver != null) {
-            switch (member.getReferenceKind()) {
-            case REF_invokeInterface:
-            case REF_invokeVirtual:
-                // Pre-dispatch the member.
-                Class<?> concreteClass = receiver.getClass();
-                MemberName concrete = new MemberName(concreteClass, member.getName(), member.getMethodType(), REF_invokeSpecial);
-                concrete = IMPL_NAMES.resolveOrNull(REF_invokeSpecial, concrete, concreteClass);
-                if (concrete != null)
-                    return new DirectMethodHandle(type(), preparedLambdaForm(concrete), concrete);
-                break;
-            }
-        }
-        return null;
-    }
-
     /**
      * Create a LF which can invoke the given method.
      * Cache and share this structure among all methods with
@@ -260,9 +231,10 @@
         } else {
             names[GET_MEMBER] = new Name(Lazy.NF_internalMemberName, names[DMH_THIS]);
         }
+        assert(findDirectMethodHandle(names[GET_MEMBER]) == names[DMH_THIS]);
         Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, GET_MEMBER+1, Object[].class);
         assert(outArgs[outArgs.length-1] == names[GET_MEMBER]);  // look, shifted args!
-        int result = LambdaForm.LAST_RESULT;
+        int result = LAST_RESULT;
         if (doesAlloc) {
             assert(outArgs[outArgs.length-2] == names[NEW_OBJ]);  // got to move this one
             System.arraycopy(outArgs, 0, outArgs, 1, outArgs.length-2);
@@ -277,6 +249,16 @@
         return lform;
     }
 
+    static Object findDirectMethodHandle(Name name) {
+        if (name.function == Lazy.NF_internalMemberName ||
+            name.function == Lazy.NF_internalMemberNameEnsureInit ||
+            name.function == Lazy.NF_constructorMethod) {
+            assert(name.arguments.length == 1);
+            return name.arguments[0];
+        }
+        return null;
+    }
+
     private static void maybeCompile(LambdaForm lform, MemberName m) {
         if (VerifyAccess.isSamePackage(m.getDeclaringClass(), MethodHandle.class))
             // Help along bootstrapping...
@@ -389,8 +371,8 @@
             return true;
         }
         @Override
-        MethodHandle viewAsType(MethodType newType) {
-            return new Special(newType, form, member);
+        MethodHandle copyWith(MethodType mt, LambdaForm lf) {
+            return new Special(mt, lf, member);
         }
     }
 
@@ -407,8 +389,8 @@
             assert(initMethod.isResolved());
         }
         @Override
-        MethodHandle viewAsType(MethodType newType) {
-            return new Constructor(newType, form, member, initMethod, instanceClass);
+        MethodHandle copyWith(MethodType mt, LambdaForm lf) {
+            return new Constructor(mt, lf, member, initMethod, instanceClass);
         }
     }
 
@@ -437,8 +419,8 @@
             return fieldType.cast(obj);
         }
         @Override
-        MethodHandle viewAsType(MethodType newType) {
-            return new Accessor(newType, form, member, fieldOffset);
+        MethodHandle copyWith(MethodType mt, LambdaForm lf) {
+            return new Accessor(mt, lf, member, fieldOffset);
         }
     }
 
@@ -480,8 +462,8 @@
             return fieldType.cast(obj);
         }
         @Override
-        MethodHandle viewAsType(MethodType newType) {
-            return new StaticAccessor(newType, form, member, staticBase, staticOffset);
+        MethodHandle copyWith(MethodType mt, LambdaForm lf) {
+            return new StaticAccessor(mt, lf, member, staticBase, staticOffset);
         }
     }
 
--- a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java	Fri Sep 12 10:33:32 2014 -0700
@@ -25,21 +25,20 @@
 
 package java.lang.invoke;
 
-import sun.invoke.util.VerifyAccess;
-import static java.lang.invoke.LambdaForm.*;
-
-import sun.invoke.util.Wrapper;
-
 import java.io.*;
 import java.util.*;
+import java.lang.reflect.Modifier;
 
 import jdk.internal.org.objectweb.asm.*;
 
-import java.lang.reflect.*;
+import static java.lang.invoke.LambdaForm.*;
+import static java.lang.invoke.LambdaForm.BasicType.*;
 import static java.lang.invoke.MethodHandleStatics.*;
 import static java.lang.invoke.MethodHandleNatives.Constants.*;
-import static java.lang.invoke.LambdaForm.BasicType.*;
+
+import sun.invoke.util.VerifyAccess;
 import sun.invoke.util.VerifyType;
+import sun.invoke.util.Wrapper;
 import sun.reflect.misc.ReflectUtil;
 
 /**
@@ -74,7 +73,11 @@
     private final LambdaForm lambdaForm;
     private final String     invokerName;
     private final MethodType invokerType;
-    private final int[] localsMap;
+
+    /** Info about local variables in compiled lambda form */
+    private final int[]       localsMap;    // index
+    private final BasicType[] localTypes;   // basic type
+    private final Class<?>[]  localClasses; // type
 
     /** ASM bytecode generation. */
     private ClassWriter cw;
@@ -83,6 +86,7 @@
     private static final MemberName.Factory MEMBERNAME_FACTORY = MemberName.getFactory();
     private static final Class<?> HOST_CLASS = LambdaForm.class;
 
+    /** Main constructor; other constructors delegate to this one. */
     private InvokerBytecodeGenerator(LambdaForm lambdaForm, int localsMapSize,
                                      String className, String invokerName, MethodType invokerType) {
         if (invokerName.contains(".")) {
@@ -98,18 +102,26 @@
         this.lambdaForm = lambdaForm;
         this.invokerName = invokerName;
         this.invokerType = invokerType;
-        this.localsMap = new int[localsMapSize];
+        this.localsMap = new int[localsMapSize+1];
+        // last entry of localsMap is count of allocated local slots
+        this.localTypes = new BasicType[localsMapSize+1];
+        this.localClasses = new Class<?>[localsMapSize+1];
     }
 
+    /** For generating LambdaForm interpreter entry points. */
     private InvokerBytecodeGenerator(String className, String invokerName, MethodType invokerType) {
         this(null, invokerType.parameterCount(),
              className, invokerName, invokerType);
         // Create an array to map name indexes to locals indexes.
+        localTypes[localTypes.length - 1] = V_TYPE;
         for (int i = 0; i < localsMap.length; i++) {
             localsMap[i] = invokerType.parameterSlotCount() - invokerType.parameterSlotDepth(i);
+            if (i < invokerType.parameterCount())
+                localTypes[i] = basicType(invokerType.parameterType(i));
         }
     }
 
+    /** For generating customized code for a single LambdaForm. */
     private InvokerBytecodeGenerator(String className, LambdaForm form, MethodType invokerType) {
         this(form, form.names.length,
              className, form.debugName, invokerType);
@@ -117,7 +129,11 @@
         Name[] names = form.names;
         for (int i = 0, index = 0; i < localsMap.length; i++) {
             localsMap[i] = index;
-            index += names[i].type.basicTypeSlots();
+            if (i < names.length) {
+                BasicType type = names[i].type();
+                index += type.basicTypeSlots();
+                localTypes[i] = type;
+            }
         }
     }
 
@@ -148,7 +164,6 @@
 
     static void maybeDump(final String className, final byte[] classFile) {
         if (DUMP_CLASS_FILES) {
-            System.out.println("dump: " + className);
             java.security.AccessController.doPrivileged(
             new java.security.PrivilegedAction<Void>() {
                 public Void run() {
@@ -156,6 +171,7 @@
                         String dumpName = className;
                         //dumpName = dumpName.replace('/', '-');
                         File dumpFile = new File(DUMP_CLASS_FILES_DIR, dumpName+".class");
+                        System.out.println("dump: " + dumpFile);
                         dumpFile.getParentFile().mkdirs();
                         FileOutputStream file = new FileOutputStream(dumpFile);
                         file.write(classFile);
@@ -204,7 +220,7 @@
 
     String constantPlaceholder(Object arg) {
         String cpPlaceholder = "CONSTANT_PLACEHOLDER_" + cph++;
-        if (DUMP_CLASS_FILES) cpPlaceholder += " <<" + arg.toString() + ">>";  // debugging aid
+        if (DUMP_CLASS_FILES) cpPlaceholder += " <<" + debugString(arg) + ">>";  // debugging aid
         if (cpPatches.containsKey(cpPlaceholder)) {
             throw new InternalError("observed CP placeholder twice: " + cpPlaceholder);
         }
@@ -225,6 +241,17 @@
         return res;
     }
 
+    private static String debugString(Object arg) {
+        if (arg instanceof MethodHandle) {
+            MethodHandle mh = (MethodHandle) arg;
+            MemberName member = mh.internalMemberName();
+            if (member != null)
+                return member.toString();
+            return mh.debugString();
+        }
+        return arg.toString();
+    }
+
     /**
      * Extract the number of constant pool entries from a given class file.
      *
@@ -400,6 +427,64 @@
         emitStoreInsn(L_TYPE, index);
     }
 
+    private byte arrayTypeCode(Wrapper elementType) {
+        switch (elementType) {
+            case BOOLEAN: return Opcodes.T_BOOLEAN;
+            case BYTE:    return Opcodes.T_BYTE;
+            case CHAR:    return Opcodes.T_CHAR;
+            case SHORT:   return Opcodes.T_SHORT;
+            case INT:     return Opcodes.T_INT;
+            case LONG:    return Opcodes.T_LONG;
+            case FLOAT:   return Opcodes.T_FLOAT;
+            case DOUBLE:  return Opcodes.T_DOUBLE;
+            case OBJECT:  return 0; // in place of Opcodes.T_OBJECT
+            default:      throw new InternalError();
+        }
+    }
+
+    private int arrayInsnOpcode(byte tcode, int aaop) throws InternalError {
+        assert(aaop == Opcodes.AASTORE || aaop == Opcodes.AALOAD);
+        int xas;
+        switch (tcode) {
+            case Opcodes.T_BOOLEAN: xas = Opcodes.BASTORE; break;
+            case Opcodes.T_BYTE:    xas = Opcodes.BASTORE; break;
+            case Opcodes.T_CHAR:    xas = Opcodes.CASTORE; break;
+            case Opcodes.T_SHORT:   xas = Opcodes.SASTORE; break;
+            case Opcodes.T_INT:     xas = Opcodes.IASTORE; break;
+            case Opcodes.T_LONG:    xas = Opcodes.LASTORE; break;
+            case Opcodes.T_FLOAT:   xas = Opcodes.FASTORE; break;
+            case Opcodes.T_DOUBLE:  xas = Opcodes.DASTORE; break;
+            case 0:                 xas = Opcodes.AASTORE; break;
+            default:      throw new InternalError();
+        }
+        return xas - Opcodes.AASTORE + aaop;
+    }
+
+
+    private void freeFrameLocal(int oldFrameLocal) {
+        int i = indexForFrameLocal(oldFrameLocal);
+        if (i < 0)  return;
+        BasicType type = localTypes[i];
+        int newFrameLocal = makeLocalTemp(type);
+        mv.visitVarInsn(loadInsnOpcode(type), oldFrameLocal);
+        mv.visitVarInsn(storeInsnOpcode(type), newFrameLocal);
+        assert(localsMap[i] == oldFrameLocal);
+        localsMap[i] = newFrameLocal;
+        assert(indexForFrameLocal(oldFrameLocal) < 0);
+    }
+    private int indexForFrameLocal(int frameLocal) {
+        for (int i = 0; i < localsMap.length; i++) {
+            if (localsMap[i] == frameLocal && localTypes[i] != V_TYPE)
+                return i;
+        }
+        return -1;
+    }
+    private int makeLocalTemp(BasicType type) {
+        int frameLocal = localsMap[localsMap.length - 1];
+        localsMap[localsMap.length - 1] = frameLocal + type.basicTypeSlots();
+        return frameLocal;
+    }
+
     /**
      * Emit a boxing call.
      *
@@ -421,41 +506,79 @@
         String owner = "java/lang/" + wrapper.wrapperType().getSimpleName();
         String name  = wrapper.primitiveSimpleName() + "Value";
         String desc  = "()" + wrapper.basicTypeChar();
-        mv.visitTypeInsn(Opcodes.CHECKCAST, owner);
+        emitReferenceCast(wrapper.wrapperType(), null);
         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc, false);
     }
 
     /**
-     * Emit an implicit conversion.
+     * Emit an implicit conversion for an argument which must be of the given pclass.
+     * This is usually a no-op, except when pclass is a subword type or a reference other than Object or an interface.
      *
      * @param ptype type of value present on stack
      * @param pclass type of value required on stack
+     * @param arg compile-time representation of value on stack (Node, constant) or null if none
      */
-    private void emitImplicitConversion(BasicType ptype, Class<?> pclass) {
+    private void emitImplicitConversion(BasicType ptype, Class<?> pclass, Object arg) {
         assert(basicType(pclass) == ptype);  // boxing/unboxing handled by caller
         if (pclass == ptype.basicTypeClass() && ptype != L_TYPE)
             return;   // nothing to do
         switch (ptype) {
-        case L_TYPE:
-            if (VerifyType.isNullConversion(Object.class, pclass))
+            case L_TYPE:
+                if (VerifyType.isNullConversion(Object.class, pclass, false)) {
+                    if (PROFILE_LEVEL > 0)
+                        emitReferenceCast(Object.class, arg);
+                    return;
+                }
+                emitReferenceCast(pclass, arg);
                 return;
-            if (isStaticallyNameable(pclass)) {
-                mv.visitTypeInsn(Opcodes.CHECKCAST, getInternalName(pclass));
-            } else {
-                mv.visitLdcInsn(constantPlaceholder(pclass));
-                mv.visitTypeInsn(Opcodes.CHECKCAST, CLS);
-                mv.visitInsn(Opcodes.SWAP);
-                mv.visitMethodInsn(Opcodes.INVOKESTATIC, MHI, "castReference", CLL_SIG, false);
-                if (pclass.isArray())
-                    mv.visitTypeInsn(Opcodes.CHECKCAST, OBJARY);
+            case I_TYPE:
+                if (!VerifyType.isNullConversion(int.class, pclass, false))
+                    emitPrimCast(ptype.basicTypeWrapper(), Wrapper.forPrimitiveType(pclass));
+                return;
+        }
+        throw newInternalError("bad implicit conversion: tc="+ptype+": "+pclass);
+    }
+
+    /** Update localClasses type map.  Return true if the information is already present. */
+    private boolean assertStaticType(Class<?> cls, Name n) {
+        int local = n.index();
+        Class<?> aclass = localClasses[local];
+        if (aclass != null && (aclass == cls || cls.isAssignableFrom(aclass))) {
+            return true;  // type info is already present
+        } else if (aclass == null || aclass.isAssignableFrom(cls)) {
+            localClasses[local] = cls;  // type info can be improved
+        }
+        return false;
+    }
+
+    private void emitReferenceCast(Class<?> cls, Object arg) {
+        Name writeBack = null;  // local to write back result
+        if (arg instanceof Name) {
+            Name n = (Name) arg;
+            if (assertStaticType(cls, n))
+                return;  // this cast was already performed
+            if (lambdaForm.useCount(n) > 1) {
+                // This guy gets used more than once.
+                writeBack = n;
             }
-            return;
-        case I_TYPE:
-            if (!VerifyType.isNullConversion(int.class, pclass))
-                emitPrimCast(ptype.basicTypeWrapper(), Wrapper.forPrimitiveType(pclass));
-            return;
         }
-        throw new InternalError("bad implicit conversion: tc="+ptype+": "+pclass);
+        if (isStaticallyNameable(cls)) {
+            String sig = getInternalName(cls);
+            mv.visitTypeInsn(Opcodes.CHECKCAST, sig);
+        } else {
+            mv.visitLdcInsn(constantPlaceholder(cls));
+            mv.visitTypeInsn(Opcodes.CHECKCAST, CLS);
+            mv.visitInsn(Opcodes.SWAP);
+            mv.visitMethodInsn(Opcodes.INVOKESTATIC, MHI, "castReference", CLL_SIG, false);
+            if (Object[].class.isAssignableFrom(cls))
+                mv.visitTypeInsn(Opcodes.CHECKCAST, OBJARY);
+            else if (PROFILE_LEVEL > 0)
+                mv.visitTypeInsn(Opcodes.CHECKCAST, OBJ);
+        }
+        if (writeBack != null) {
+            mv.visitInsn(Opcodes.DUP);
+            emitAstoreInsn(writeBack.index());
+        }
     }
 
     /**
@@ -477,7 +600,11 @@
     }
 
     private static String getInternalName(Class<?> c) {
-        assert(VerifyAccess.isTypeVisible(c, Object.class));
+        if (c == Object.class)             return OBJ;
+        else if (c == Object[].class)      return OBJARY;
+        else if (c == Class.class)         return CLS;
+        else if (c == MethodHandle.class)  return MH;
+        assert(VerifyAccess.isTypeVisible(c, Object.class)) : c.getName();
         return c.getName().replace('.', '/');
     }
 
@@ -506,39 +633,62 @@
 
         // iterate over the form's names, generating bytecode instructions for each
         // start iterating at the first name following the arguments
+        Name onStack = null;
         for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
             Name name = lambdaForm.names[i];
+
+            emitStoreResult(onStack);
+            onStack = name;  // unless otherwise modified below
+            MethodHandleImpl.Intrinsic intr = name.function.intrinsicName();
+            switch (intr) {
+                case SELECT_ALTERNATIVE:
+                    assert isSelectAlternative(i);
+                    onStack = emitSelectAlternative(name, lambdaForm.names[i+1]);
+                    i++;  // skip MH.invokeBasic of the selectAlternative result
+                    continue;
+                case GUARD_WITH_CATCH:
+                    assert isGuardWithCatch(i);
+                    onStack = emitGuardWithCatch(i);
+                    i = i+2; // Jump to the end of GWC idiom
+                    continue;
+                case NEW_ARRAY:
+                    Class<?> rtype = name.function.methodType().returnType();
+                    if (isStaticallyNameable(rtype)) {
+                        emitNewArray(name);
+                        continue;
+                    }
+                    break;
+                case ARRAY_LOAD:
+                    emitArrayLoad(name);
+                    continue;
+                case ARRAY_STORE:
+                    emitArrayStore(name);
+                    continue;
+                case IDENTITY:
+                    assert(name.arguments.length == 1);
+                    emitPushArguments(name);
+                    continue;
+                case ZERO:
+                    assert(name.arguments.length == 0);
+                    emitConst(name.type.basicTypeWrapper().zero());
+                    continue;
+                case NONE:
+                    // no intrinsic associated
+                    break;
+                default:
+                    throw newInternalError("Unknown intrinsic: "+intr);
+            }
+
             MemberName member = name.function.member();
-
-            if (isSelectAlternative(i)) {
-                emitSelectAlternative(name, lambdaForm.names[i + 1]);
-                i++;  // skip MH.invokeBasic of the selectAlternative result
-            } else if (isGuardWithCatch(i)) {
-                emitGuardWithCatch(i);
-                i = i+2; // Jump to the end of GWC idiom
-            } else if (isStaticallyInvocable(member)) {
+            if (isStaticallyInvocable(member)) {
                 emitStaticInvoke(member, name);
             } else {
                 emitInvoke(name);
             }
-
-            // Update cached form name's info in case an intrinsic spanning multiple names was encountered.
-            name = lambdaForm.names[i];
-            member = name.function.member();
-
-            // store the result from evaluating to the target name in a local if required
-            // (if this is the last value, i.e., the one that is going to be returned,
-            // 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_TYPE) {
-                // non-void: actually assign
-                emitStoreInsn(name.type, name.index());
-            }
         }
 
         // return statement
-        emitReturn();
+        emitReturn(onStack);
 
         classFileEpilogue();
         bogusMethod(lambdaForm);
@@ -548,29 +698,43 @@
         return classFile;
     }
 
+    void emitArrayLoad(Name name)  { emitArrayOp(name, Opcodes.AALOAD);  }
+    void emitArrayStore(Name name) { emitArrayOp(name, Opcodes.AASTORE); }
+
+    void emitArrayOp(Name name, int arrayOpcode) {
+        assert arrayOpcode == Opcodes.AALOAD || arrayOpcode == Opcodes.AASTORE;
+        Class<?> elementType = name.function.methodType().parameterType(0).getComponentType();
+        assert elementType != null;
+        emitPushArguments(name);
+        if (elementType.isPrimitive()) {
+            Wrapper w = Wrapper.forPrimitiveType(elementType);
+            arrayOpcode = arrayInsnOpcode(arrayTypeCode(w), arrayOpcode);
+        }
+        mv.visitInsn(arrayOpcode);
+    }
+
     /**
      * Emit an invoke for the given name.
      */
     void emitInvoke(Name name) {
+        assert(!isLinkerMethodInvoke(name));  // should use the static path for these
         if (true) {
             // push receiver
             MethodHandle target = name.function.resolvedHandle;
             assert(target != null) : name.exprString();
             mv.visitLdcInsn(constantPlaceholder(target));
-            mv.visitTypeInsn(Opcodes.CHECKCAST, MH);
+            emitReferenceCast(MethodHandle.class, target);
         } else {
             // load receiver
             emitAloadInsn(0);
-            mv.visitTypeInsn(Opcodes.CHECKCAST, MH);
+            emitReferenceCast(MethodHandle.class, null);
             mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", LF_SIG);
             mv.visitFieldInsn(Opcodes.GETFIELD, LF, "names", LFN_SIG);
             // TODO more to come
         }
 
         // push arguments
-        for (int i = 0; i < name.arguments.length; i++) {
-            emitPushArgument(name, i);
-        }
+        emitPushArguments(name);
 
         // invocation
         MethodType type = name.function.methodType();
@@ -585,6 +749,10 @@
         //MethodHandle.class already covered
     };
 
+    static boolean isStaticallyInvocable(Name name) {
+        return isStaticallyInvocable(name.function.member());
+    }
+
     static boolean isStaticallyInvocable(MemberName member) {
         if (member == null)  return false;
         if (member.isConstructor())  return false;
@@ -611,6 +779,8 @@
     }
 
     static boolean isStaticallyNameable(Class<?> cls) {
+        if (cls == Object.class)
+            return true;
         while (cls.isArray())
             cls = cls.getComponentType();
         if (cls.isPrimitive())
@@ -631,12 +801,17 @@
         return false;
     }
 
+    void emitStaticInvoke(Name name) {
+        emitStaticInvoke(name.function.member(), name);
+    }
+
     /**
      * Emit an invoke for the given name, using the MemberName directly.
      */
     void emitStaticInvoke(MemberName member, Name name) {
         assert(member.equals(name.function.member()));
-        String cname = getInternalName(member.getDeclaringClass());
+        Class<?> defc = member.getDeclaringClass();
+        String cname = getInternalName(defc);
         String mname = member.getName();
         String mtype;
         byte refKind = member.getReferenceKind();
@@ -653,9 +828,7 @@
         }
 
         // push arguments
-        for (int i = 0; i < name.arguments.length; i++) {
-            emitPushArgument(name, i);
-        }
+        emitPushArguments(name);
 
         // invocation
         if (member.isMethod()) {
@@ -666,6 +839,52 @@
             mtype = MethodType.toFieldDescriptorString(member.getFieldType());
             mv.visitFieldInsn(refKindOpcode(refKind), cname, mname, mtype);
         }
+        // Issue a type assertion for the result, so we can avoid casts later.
+        if (name.type == L_TYPE) {
+            Class<?> rtype = member.getInvocationType().returnType();
+            assert(!rtype.isPrimitive());
+            if (rtype != Object.class && !rtype.isInterface()) {
+                assertStaticType(rtype, name);
+            }
+        }
+    }
+
+    void emitNewArray(Name name) throws InternalError {
+        Class<?> rtype = name.function.methodType().returnType();
+        if (name.arguments.length == 0) {
+            // The array will be a constant.
+            Object emptyArray;
+            try {
+                emptyArray = name.function.resolvedHandle.invoke();
+            } catch (Throwable ex) {
+                throw newInternalError(ex);
+            }
+            assert(java.lang.reflect.Array.getLength(emptyArray) == 0);
+            assert(emptyArray.getClass() == rtype);  // exact typing
+            mv.visitLdcInsn(constantPlaceholder(emptyArray));
+            emitReferenceCast(rtype, emptyArray);
+            return;
+        }
+        Class<?> arrayElementType = rtype.getComponentType();
+        assert(arrayElementType != null);
+        emitIconstInsn(name.arguments.length);
+        int xas = Opcodes.AASTORE;
+        if (!arrayElementType.isPrimitive()) {
+            mv.visitTypeInsn(Opcodes.ANEWARRAY, getInternalName(arrayElementType));
+        } else {
+            byte tc = arrayTypeCode(Wrapper.forPrimitiveType(arrayElementType));
+            xas = arrayInsnOpcode(tc, xas);
+            mv.visitIntInsn(Opcodes.NEWARRAY, tc);
+        }
+        // store arguments
+        for (int i = 0; i < name.arguments.length; i++) {
+            mv.visitInsn(Opcodes.DUP);
+            emitIconstInsn(i);
+            emitPushArgument(name, i);
+            mv.visitInsn(xas);
+        }
+        // the array is left on the stack
+        assertStaticType(rtype, name);
     }
     int refKindOpcode(byte refKind) {
         switch (refKind) {
@@ -708,6 +927,21 @@
     }
 
     /**
+     * Check if MemberName is a call to MethodHandle.linkToStatic, etc.
+     */
+    private boolean isLinkerMethodInvoke(Name name) {
+        if (name.function == null)
+            return false;
+        if (name.arguments.length < 1)
+            return false;  // must have MH argument
+        MemberName member = name.function.member();
+        return member != null &&
+               member.getDeclaringClass() == MethodHandle.class &&
+               !member.isPublic() && member.isStatic() &&
+               member.getName().startsWith("linkTo");
+    }
+
+    /**
      * Check if i-th name is a call to MethodHandleImpl.selectAlternative.
      */
     private boolean isSelectAlternative(int pos) {
@@ -755,7 +989,9 @@
      *     t4:I=MethodHandle.invokeBasic(t3:L,a1:I);t4:I}
      * }</pre></blockquote>
      */
-    private void emitSelectAlternative(Name selectAlternativeName, Name invokeBasicName) {
+    private Name emitSelectAlternative(Name selectAlternativeName, Name invokeBasicName) {
+        assert isStaticallyInvocable(invokeBasicName);
+
         Name receiver = (Name) invokeBasicName.arguments[0];
 
         Label L_fallback = new Label();
@@ -763,15 +999,15 @@
 
         // load test result
         emitPushArgument(selectAlternativeName, 0);
-        mv.visitInsn(Opcodes.ICONST_1);
 
         // if_icmpne L_fallback
-        mv.visitJumpInsn(Opcodes.IF_ICMPNE, L_fallback);
+        mv.visitJumpInsn(Opcodes.IFEQ, L_fallback);
 
         // invoke selectAlternativeName.arguments[1]
+        Class<?>[] preForkClasses = localClasses.clone();
         emitPushArgument(selectAlternativeName, 1);  // get 2nd argument of selectAlternative
         emitAstoreInsn(receiver.index());  // store the MH in the receiver slot
-        emitInvoke(invokeBasicName);
+        emitStaticInvoke(invokeBasicName);
 
         // goto L_done
         mv.visitJumpInsn(Opcodes.GOTO, L_done);
@@ -780,12 +1016,17 @@
         mv.visitLabel(L_fallback);
 
         // invoke selectAlternativeName.arguments[2]
+        System.arraycopy(preForkClasses, 0, localClasses, 0, preForkClasses.length);
         emitPushArgument(selectAlternativeName, 2);  // get 3rd argument of selectAlternative
         emitAstoreInsn(receiver.index());  // store the MH in the receiver slot
-        emitInvoke(invokeBasicName);
+        emitStaticInvoke(invokeBasicName);
 
         // L_done:
         mv.visitLabel(L_done);
+        // for now do not bother to merge typestate; just reset to the dominator state
+        System.arraycopy(preForkClasses, 0, localClasses, 0, preForkClasses.length);
+
+        return invokeBasicName;  // return what's on stack
     }
 
     /**
@@ -808,7 +1049,7 @@
       *      return a3.invokeBasic(ex, a6, a7);
       *  }}
       */
-    private void emitGuardWithCatch(int pos) {
+    private Name emitGuardWithCatch(int pos) {
         Name args    = lambdaForm.names[pos];
         Name invoker = lambdaForm.names[pos+1];
         Name result  = lambdaForm.names[pos+2];
@@ -859,6 +1100,12 @@
         mv.visitInsn(Opcodes.ATHROW);
 
         mv.visitLabel(L_done);
+
+        return result;
+    }
+
+    private void emitPushArguments(Name args) {
+        emitPushArguments(args, 0);
     }
 
     private void emitPushArguments(Name args, int start) {
@@ -878,7 +1125,7 @@
         if (arg instanceof Name) {
             Name n = (Name) arg;
             emitLoadInsn(n.type, n.index());
-            emitImplicitConversion(n.type, ptype);
+            emitImplicitConversion(n.type, ptype, n);
         } else if ((arg == null || arg instanceof String) && bptype == L_TYPE) {
             emitConst(arg);
         } else {
@@ -886,15 +1133,25 @@
                 emitConst(arg);
             } else {
                 mv.visitLdcInsn(constantPlaceholder(arg));
-                emitImplicitConversion(L_TYPE, ptype);
+                emitImplicitConversion(L_TYPE, ptype, arg);
             }
         }
     }
 
     /**
+     * Store the name to its local, if necessary.
+     */
+    private void emitStoreResult(Name name) {
+        if (name != null && name.type != V_TYPE) {
+            // non-void: actually assign
+            emitStoreInsn(name.type, name.index());
+        }
+    }
+
+    /**
      * Emits a return statement from a LF invoker. If required, the result type is cast to the correct return type.
      */
-    private void emitReturn() {
+    private void emitReturn(Name onStack) {
         // return statement
         Class<?> rclass = invokerType.returnType();
         BasicType rtype = lambdaForm.returnType();
@@ -907,12 +1164,11 @@
             LambdaForm.Name rn = lambdaForm.names[lambdaForm.result];
 
             // put return value on the stack if it is not already there
-            if (lambdaForm.result != lambdaForm.names.length - 1 ||
-                    lambdaForm.result < lambdaForm.arity) {
-                emitLoadInsn(rn.type, lambdaForm.result);
+            if (rn != onStack) {
+                emitLoadInsn(rtype, lambdaForm.result);
             }
 
-            emitImplicitConversion(rtype, rclass);
+            emitImplicitConversion(rtype, rclass, rn);
 
             // generate actual return statement
             emitReturnInsn(rtype);
--- a/src/java.base/share/classes/java/lang/invoke/Invokers.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/Invokers.java	Fri Sep 12 10:33:32 2014 -0700
@@ -25,8 +25,9 @@
 
 package java.lang.invoke;
 
+import java.lang.reflect.Array;
 import java.util.Arrays;
-import sun.invoke.empty.Empty;
+
 import static java.lang.invoke.MethodHandleStatics.*;
 import static java.lang.invoke.MethodHandleNatives.Constants.*;
 import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
@@ -40,52 +41,63 @@
     // exact type (sans leading target MH) for the outgoing call
     private final MethodType targetType;
 
-    // FIXME: Get rid of the invokers that are not useful.
-
-    // exact invoker for the outgoing call
-    private /*lazy*/ MethodHandle exactInvoker;
-    private /*lazy*/ MethodHandle basicInvoker;  // invokeBasic (unchecked exact)
-
-    // erased (partially untyped but with primitives) invoker for the outgoing call
-    // FIXME: get rid of
-    private /*lazy*/ MethodHandle erasedInvoker;
-    // FIXME: get rid of
-    /*lazy*/ MethodHandle erasedInvokerWithDrops;  // for InvokeGeneric
-
-    // general invoker for the outgoing call
-    private /*lazy*/ MethodHandle generalInvoker;
-
-    // general invoker for the outgoing call, uses varargs
-    private /*lazy*/ MethodHandle varargsInvoker;
-
-    // general invoker for the outgoing call; accepts a trailing Object[]
-    private final /*lazy*/ MethodHandle[] spreadInvokers;
-
-    // invoker for an unbound callsite
-    private /*lazy*/ MethodHandle uninitializedCallSite;
+    // Cached adapter information:
+    private final @Stable MethodHandle[] invokers = new MethodHandle[INV_LIMIT];
+    // Indexes into invokers:
+    static final int
+            INV_EXACT          =  0,  // MethodHandles.exactInvoker
+            INV_GENERIC        =  1,  // MethodHandles.invoker (generic invocation)
+            INV_BASIC          =  2,  // MethodHandles.basicInvoker
+            INV_LIMIT          =  3;
 
     /** Compute and cache information common to all collecting adapters
      *  that implement members of the erasure-family of the given erased type.
      */
     /*non-public*/ Invokers(MethodType targetType) {
         this.targetType = targetType;
-        this.spreadInvokers = new MethodHandle[targetType.parameterCount()+1];
     }
 
     /*non-public*/ MethodHandle exactInvoker() {
-        MethodHandle invoker = exactInvoker;
+        MethodHandle invoker = cachedInvoker(INV_EXACT);
         if (invoker != null)  return invoker;
         invoker = makeExactOrGeneralInvoker(true);
-        exactInvoker = invoker;
-        return invoker;
+        return setCachedInvoker(INV_EXACT, invoker);
     }
 
-    /*non-public*/ MethodHandle generalInvoker() {
-        MethodHandle invoker = generalInvoker;
+    /*non-public*/ MethodHandle genericInvoker() {
+        MethodHandle invoker = cachedInvoker(INV_GENERIC);
         if (invoker != null)  return invoker;
         invoker = makeExactOrGeneralInvoker(false);
-        generalInvoker = invoker;
-        return invoker;
+        return setCachedInvoker(INV_GENERIC, invoker);
+    }
+
+    /*non-public*/ MethodHandle basicInvoker() {
+        MethodHandle invoker = cachedInvoker(INV_BASIC);
+        if (invoker != null)  return invoker;
+        MethodType basicType = targetType.basicType();
+        if (basicType != targetType) {
+            // double cache; not used significantly
+            return setCachedInvoker(INV_BASIC, basicType.invokers().basicInvoker());
+        }
+        invoker = basicType.form().cachedMethodHandle(MethodTypeForm.MH_BASIC_INV);
+        if (invoker == null) {
+            MemberName method = invokeBasicMethod(basicType);
+            invoker = DirectMethodHandle.make(method);
+            assert(checkInvoker(invoker));
+            invoker = basicType.form().setCachedMethodHandle(MethodTypeForm.MH_BASIC_INV, invoker);
+        }
+        return setCachedInvoker(INV_BASIC, invoker);
+    }
+
+    private MethodHandle cachedInvoker(int idx) {
+        return invokers[idx];
+    }
+
+    private synchronized MethodHandle setCachedInvoker(int idx, final MethodHandle invoker) {
+        // Simulate a CAS, to avoid racy duplication of results.
+        MethodHandle prev = invokers[idx];
+        if (prev != null)  return prev;
+        return invokers[idx] = invoker;
     }
 
     private MethodHandle makeExactOrGeneralInvoker(boolean isExact) {
@@ -95,7 +107,7 @@
         LambdaForm lform = invokeHandleForm(mtype, false, which);
         MethodHandle invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype);
         String whichName = (isExact ? "invokeExact" : "invoke");
-        invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke(whichName, mtype));
+        invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke(whichName, mtype), false);
         assert(checkInvoker(invoker));
         maybeCompileToBytecode(invoker);
         return invoker;
@@ -110,21 +122,6 @@
         }
     }
 
-    /*non-public*/ MethodHandle basicInvoker() {
-        MethodHandle invoker = basicInvoker;
-        if (invoker != null)  return invoker;
-        MethodType basicType = targetType.basicType();
-        if (basicType != targetType) {
-            // double cache; not used significantly
-            return basicInvoker = basicType.invokers().basicInvoker();
-        }
-        MemberName method = invokeBasicMethod(basicType);
-        invoker = DirectMethodHandle.make(method);
-        assert(checkInvoker(invoker));
-        basicInvoker = invoker;
-        return invoker;
-    }
-
     // This next one is called from LambdaForm.NamedFunction.<init>.
     /*non-public*/ static MemberName invokeBasicMethod(MethodType basicType) {
         assert(basicType == basicType.basicType());
@@ -145,87 +142,42 @@
         return true;
     }
 
-    // FIXME: get rid of
-    /*non-public*/ MethodHandle erasedInvoker() {
-        MethodHandle xinvoker = exactInvoker();
-        MethodHandle invoker = erasedInvoker;
-        if (invoker != null)  return invoker;
-        MethodType erasedType = targetType.erase();
-        invoker = xinvoker.asType(erasedType.invokerType());
-        erasedInvoker = invoker;
-        return invoker;
+    /**
+     * Find or create an invoker which passes unchanged a given number of arguments
+     * and spreads the rest from a trailing array argument.
+     * The invoker target type is the post-spread type {@code (TYPEOF(uarg*), TYPEOF(sarg*))=>RT}.
+     * All the {@code sarg}s must have a common type {@code C}.  (If there are none, {@code Object} is assumed.}
+     * @param leadingArgCount the number of unchanged (non-spread) arguments
+     * @return {@code invoker.invokeExact(mh, uarg*, C[]{sarg*}) := (RT)mh.invoke(uarg*, sarg*)}
+     */
+    /*non-public*/ MethodHandle spreadInvoker(int leadingArgCount) {
+        int spreadArgCount = targetType.parameterCount() - leadingArgCount;
+        MethodType postSpreadType = targetType;
+        Class<?> argArrayType = impliedRestargType(postSpreadType, leadingArgCount);
+        if (postSpreadType.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY) {
+            return genericInvoker().asSpreader(argArrayType, spreadArgCount);
+        }
+        // Cannot build a generic invoker here of type ginvoker.invoke(mh, a*[254]).
+        // Instead, factor sinvoker.invoke(mh, a) into ainvoker.invoke(filter(mh), a)
+        // where filter(mh) == mh.asSpreader(Object[], spreadArgCount)
+        MethodType preSpreadType = postSpreadType
+            .replaceParameterTypes(leadingArgCount, postSpreadType.parameterCount(), argArrayType);
+        MethodHandle arrayInvoker = MethodHandles.invoker(preSpreadType);
+        MethodHandle makeSpreader = MethodHandles.insertArguments(Lazy.MH_asSpreader, 1, argArrayType, spreadArgCount);
+        return MethodHandles.filterArgument(arrayInvoker, 0, makeSpreader);
     }
 
-    /*non-public*/ MethodHandle spreadInvoker(int leadingArgCount) {
-        MethodHandle vaInvoker = spreadInvokers[leadingArgCount];
-        if (vaInvoker != null)  return vaInvoker;
-        int spreadArgCount = targetType.parameterCount() - leadingArgCount;
-        MethodType spreadInvokerType = targetType
-            .replaceParameterTypes(leadingArgCount, targetType.parameterCount(), Object[].class);
-        if (targetType.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY) {
-            // Factor sinvoker.invoke(mh, a) into ginvoker.asSpreader().invoke(mh, a)
-            // where ginvoker.invoke(mh, a*) => mh.invoke(a*).
-            MethodHandle genInvoker = generalInvoker();
-            vaInvoker = genInvoker.asSpreader(Object[].class, spreadArgCount);
-        } else {
-            // Cannot build a general invoker here of type ginvoker.invoke(mh, a*[254]).
-            // Instead, factor sinvoker.invoke(mh, a) into ainvoker.invoke(filter(mh), a)
-            // where filter(mh) == mh.asSpreader(Object[], spreadArgCount)
-            MethodHandle arrayInvoker = MethodHandles.exactInvoker(spreadInvokerType);
-            MethodHandle makeSpreader;
-            try {
-                makeSpreader = IMPL_LOOKUP
-                    .findVirtual(MethodHandle.class, "asSpreader",
-                        MethodType.methodType(MethodHandle.class, Class.class, int.class));
-            } catch (ReflectiveOperationException ex) {
-                throw newInternalError(ex);
-            }
-            makeSpreader = MethodHandles.insertArguments(makeSpreader, 1, Object[].class, spreadArgCount);
-            vaInvoker = MethodHandles.filterArgument(arrayInvoker, 0, makeSpreader);
+    private static Class<?> impliedRestargType(MethodType restargType, int fromPos) {
+        if (restargType.isGeneric())  return Object[].class;  // can be nothing else
+        int maxPos = restargType.parameterCount();
+        if (fromPos >= maxPos)  return Object[].class;  // reasonable default
+        Class<?> argType = restargType.parameterType(fromPos);
+        for (int i = fromPos+1; i < maxPos; i++) {
+            if (argType != restargType.parameterType(i))
+                throw newIllegalArgumentException("need homogeneous rest arguments", restargType);
         }
-        assert(vaInvoker.type().equals(spreadInvokerType.invokerType()));
-        maybeCompileToBytecode(vaInvoker);
-        spreadInvokers[leadingArgCount] = vaInvoker;
-        return vaInvoker;
-    }
-
-    /*non-public*/ MethodHandle varargsInvoker() {
-        MethodHandle vaInvoker = varargsInvoker;
-        if (vaInvoker != null)  return vaInvoker;
-        vaInvoker = spreadInvoker(0).asType(MethodType.genericMethodType(0, true).invokerType());
-        varargsInvoker = vaInvoker;
-        return vaInvoker;
-    }
-
-    private static MethodHandle THROW_UCS = null;
-
-    /*non-public*/ MethodHandle uninitializedCallSite() {
-        MethodHandle invoker = uninitializedCallSite;
-        if (invoker != null)  return invoker;
-        if (targetType.parameterCount() > 0) {
-            MethodType type0 = targetType.dropParameterTypes(0, targetType.parameterCount());
-            Invokers invokers0 = type0.invokers();
-            invoker = MethodHandles.dropArguments(invokers0.uninitializedCallSite(),
-                                                  0, targetType.parameterList());
-            assert(invoker.type().equals(targetType));
-            uninitializedCallSite = invoker;
-            return invoker;
-        }
-        invoker = THROW_UCS;
-        if (invoker == null) {
-            try {
-                THROW_UCS = invoker = IMPL_LOOKUP
-                    .findStatic(CallSite.class, "uninitializedCallSite",
-                                MethodType.methodType(Empty.class));
-            } catch (ReflectiveOperationException ex) {
-                throw newInternalError(ex);
-            }
-        }
-        invoker = MethodHandles.explicitCastArguments(invoker, MethodType.methodType(targetType.returnType()));
-        invoker = invoker.dropArguments(targetType, 0, targetType.parameterCount());
-        assert(invoker.type().equals(targetType));
-        uninitializedCallSite = invoker;
-        return invoker;
+        if (argType == Object.class)  return Object[].class;
+        return Array.newInstance(argType, 0).getClass();
     }
 
     public String toString() {
@@ -308,7 +260,9 @@
                 : 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);
+            BoundMethodHandle.SpeciesData speciesData = BoundMethodHandle.speciesData_L();
+            names[THIS_MH] = names[THIS_MH].withConstraint(speciesData);
+            NamedFunction getter = speciesData.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 +314,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,27 +387,40 @@
     }
 
     // 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);
         }
     }
 
+    private static class Lazy {
+        private static final MethodHandle MH_asSpreader;
+
+        static {
+            try {
+                MH_asSpreader = IMPL_LOOKUP.findVirtual(MethodHandle.class, "asSpreader",
+                        MethodType.methodType(MethodHandle.class, Class.class, int.class));
+            } catch (ReflectiveOperationException ex) {
+                throw newInternalError(ex);
+            }
+        }
+    }
 }
--- a/src/java.base/share/classes/java/lang/invoke/LambdaForm.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/LambdaForm.java	Fri Sep 12 10:33:32 2014 -0700
@@ -27,11 +27,10 @@
 
 import java.lang.annotation.*;
 import java.lang.reflect.Method;
-import java.util.Map;
 import java.util.List;
 import java.util.Arrays;
 import java.util.HashMap;
-import java.util.concurrent.ConcurrentHashMap;
+
 import sun.invoke.util.Wrapper;
 import java.lang.reflect.Field;
 
@@ -125,8 +124,7 @@
     MemberName vmentry;   // low-level behavior, or null if not yet prepared
     private boolean isCompiled;
 
-    // Caches for common structural transforms:
-    LambdaForm[] bindCache;
+    Object transformCache;  // managed by LambdaFormEditor
 
     public static final int VOID_RESULT = -1, LAST_RESULT = -2;
 
@@ -214,6 +212,13 @@
             }
             return btypes;
         }
+        static byte[] basicTypesOrd(BasicType[] btypes) {
+            byte[] ords = new byte[btypes.length];
+            for (int i = 0; i < btypes.length; i++) {
+                ords[i] = (byte)btypes[i].ordinal();
+            }
+            return ords;
+        }
         static boolean isBasicTypeChar(char c) {
             return "LIJFDV".indexOf(c) >= 0;
         }
@@ -243,7 +248,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 +358,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 +374,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 +402,7 @@
             }
             assert(nameRefsAreLegal());
         }
+        return maxOutArity;
     }
 
     /**
@@ -398,7 +414,7 @@
      * This allows Name references to be freely reused to construct
      * fresh lambdas, without confusion.
      */
-    private boolean nameRefsAreLegal() {
+    boolean nameRefsAreLegal() {
         assert(arity >= 0 && arity <= names.length);
         assert(result >= -1 && result < names.length);
         // Do all names possess an index consistent with their local definition order?
@@ -439,8 +455,20 @@
 
     /** 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 N-th argument type constraint. */
+    Object parameterConstraint(int n) {
+        return parameter(n).constraint;
     }
 
     /** Report the arity. */
@@ -448,6 +476,11 @@
         return arity;
     }
 
+    /** Report the number of expressions (non-parameter names). */
+    int expressionCount() {
+        return names.length - arity;
+    }
+
     /** Return the method type corresponding to my basic type signature. */
     MethodType methodType() {
         return signatureType(basicTypeSignature());
@@ -464,7 +497,7 @@
         return sig.indexOf('_');
     }
     static BasicType signatureReturn(String sig) {
-        return basicType(sig.charAt(signatureArity(sig)+1));
+        return basicType(sig.charAt(signatureArity(sig) + 1));
     }
     static boolean isValidSignature(String sig) {
         int arity = sig.indexOf('_');
@@ -582,21 +615,12 @@
             isCompiled = true;
             return vmentry;
         } catch (Error | Exception ex) {
-            throw newInternalError("compileToBytecode", 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 +631,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 +667,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 +727,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 +743,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
@@ -785,28 +802,6 @@
         return rval;
     }
 
-    //** This transform is applied (statically) to every name.function. */
-    /*
-    private static MethodHandle eraseSubwordTypes(MethodHandle mh) {
-        MethodType mt = mh.type();
-        if (mt.hasPrimitives()) {
-            mt = mt.changeReturnType(eraseSubwordType(mt.returnType()));
-            for (int i = 0; i < mt.parameterCount(); i++) {
-                mt = mt.changeParameterType(i, eraseSubwordType(mt.parameterType(i)));
-            }
-            mh = MethodHandles.explicitCastArguments(mh, mt);
-        }
-        return mh;
-    }
-    private static Class<?> eraseSubwordType(Class<?> type) {
-        if (!type.isPrimitive())  return type;
-        if (type == int.class)  return type;
-        Wrapper w = Wrapper.forPrimitiveType(type);
-        if (w.isSubwordOrInt())  return int.class;
-        return type;
-    }
-    */
-
     static void traceInterpreter(String event, Object obj, Object... args) {
         if (TRACE_INTERPRETER) {
             System.out.println("LFI: "+event+" "+(obj != null ? obj : "")+(args != null && args.length != 0 ? Arrays.asList(args) : ""));
@@ -819,8 +814,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 +842,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 +850,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,135 +860,19 @@
         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);
     }
-
-    LambdaForm bind(int namePos, BoundMethodHandle.SpeciesData oldData) {
-        Name name = names[namePos];
-        BoundMethodHandle.SpeciesData newData = oldData.extendWith(name.type);
-        return bind(name, new Name(newData.getterFunction(oldData.fieldCount()), names[0]), oldData, newData);
+    public boolean equals(LambdaForm that) {
+        if (this.result != that.result)  return false;
+        return Arrays.equals(this.names, that.names);
     }
-    LambdaForm bind(Name name, Name binding,
-                    BoundMethodHandle.SpeciesData oldData,
-                    BoundMethodHandle.SpeciesData newData) {
-        int pos = name.index;
-        assert(name.isParam());
-        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);
-        if (bindCache != null) {
-            LambdaForm form = bindCache[pos];
-            if (form != null) {
-                assert(form.contains(binding)) : "form << " + form + " >> does not contain binding << " + binding + " >>";
-                return form;
-            }
-        } else {
-            bindCache = new LambdaForm[arity];
-        }
-        assert(nameRefsAreLegal());
-        int arity2 = arity-1;
-        Name[] names2 = names.clone();
-        names2[pos] = binding;  // we might move this in a moment
-
-        // The newly created LF will run with a different BMH.
-        // Switch over any pre-existing BMH field references to the new BMH class.
-        int firstOldRef = -1;
-        for (int i = 0; i < names2.length; i++) {
-            Name n = names[i];
-            if (n.function != null &&
-                n.function.memberDeclaringClassOrNull() == oldData.clazz) {
-                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];
-                }
-                if (newGetter != null) {
-                    if (firstOldRef < 0)  firstOldRef = i;
-                    Name n2 = new Name(newGetter, n.arguments);
-                    names2[i] = n2;
-                }
-            }
-        }
-
-        // Walk over the new list of names once, in forward order.
-        // Replace references to 'name' with 'binding'.
-        // Replace data structure references to the old BMH species with the new.
-        // This might cause a ripple effect, but it will settle in one pass.
-        assert(firstOldRef < 0 || firstOldRef > pos);
-        for (int i = pos+1; i < names2.length; i++) {
-            if (i <= arity2)  continue;
-            names2[i] = names2[i].replaceNames(names, names2, pos, i);
-        }
-
-        //  (a0, a1, name=a2, a3, a4)  =>  (a0, a1, a3, a4, binding)
-        int insPos = pos;
-        for (; insPos+1 < names2.length; insPos++) {
-            Name n = names2[insPos+1];
-            if (n.isSiblingBindingBefore(binding)) {
-                names2[insPos] = n;
-            } else {
-                break;
-            }
-        }
-        names2[insPos] = binding;
-
-        // Since we moved some stuff, maybe update the result reference:
-        int result2 = result;
-        if (result2 == pos)
-            result2 = insPos;
-        else if (result2 > pos && result2 <= insPos)
-            result2 -= 1;
-
-        return bindCache[pos] = new LambdaForm(debugName, arity2, names2, result2);
+    public int hashCode() {
+        return result + 31 * Arrays.hashCode(names);
+    }
+    LambdaFormEditor editor() {
+        return LambdaFormEditor.lambdaFormEditor(this);
     }
 
     boolean contains(Name name) {
@@ -1000,16 +888,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 +990,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 +1003,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.
@@ -1169,7 +1065,7 @@
                     if (LambdaForm.signatureReturn(sig) == V_TYPE)
                         srcType = srcType.changeReturnType(void.class);
                     MethodTypeForm typeForm = srcType.form();
-                    typeForm.namedFunctionInvoker = DirectMethodHandle.make(m);
+                    typeForm.setCachedMethodHandle(MethodTypeForm.MH_NF_INV, DirectMethodHandle.make(m));
                 }
             }
         }
@@ -1179,85 +1075,104 @@
         /** 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);
 
         private static MethodHandle computeInvoker(MethodTypeForm typeForm) {
-            MethodHandle mh = typeForm.namedFunctionInvoker;
+            typeForm = typeForm.basicType().form();  // normalize to basic type
+            MethodHandle mh = typeForm.cachedMethodHandle(MethodTypeForm.MH_NF_INV);
             if (mh != null)  return mh;
             MemberName invoker = InvokerBytecodeGenerator.generateNamedFunctionInvoker(typeForm);  // this could take a while
             mh = DirectMethodHandle.make(invoker);
-            MethodHandle mh2 = typeForm.namedFunctionInvoker;
+            MethodHandle mh2 = typeForm.cachedMethodHandle(MethodTypeForm.MH_NF_INV);
             if (mh2 != null)  return mh2;  // benign race
             if (!mh.type().equals(INVOKER_METHOD_TYPE))
                 throw newInternalError(mh.debugString());
-            return typeForm.namedFunctionInvoker = mh;
+            return typeForm.setCachedMethodHandle(MethodTypeForm.MH_NF_INV, mh);
         }
 
         @Hidden
@@ -1365,6 +1280,11 @@
         public boolean isConstantZero() {
             return this.equals(constantZero(returnType()));
         }
+
+        public MethodHandleImpl.Intrinsic intrinsicName() {
+            return resolvedHandle == null ? MethodHandleImpl.Intrinsic.NONE
+                                          : resolvedHandle.intrinsicName();
+        }
     }
 
     public static String basicTypeSignature(MethodType type) {
@@ -1411,6 +1331,7 @@
         final BasicType type;
         private short index;
         final NamedFunction function;
+        final Object constraint;  // additional type information, if not null
         @Stable final Object[] arguments;
 
         private Name(int index, BasicType type, NamedFunction function, Object[] arguments) {
@@ -1418,8 +1339,18 @@
             this.type = type;
             this.function = function;
             this.arguments = arguments;
+            this.constraint = null;
             assert(this.index == index);
         }
+        private Name(Name that, Object constraint) {
+            this.index = that.index;
+            this.type = that.type;
+            this.function = that.function;
+            this.arguments = that.arguments;
+            this.constraint = constraint;
+            assert(constraint == null || isParam());  // only params have constraints
+            assert(constraint == null || constraint instanceof BoundMethodHandle.SpeciesData || constraint instanceof Class);
+        }
         Name(MethodHandle function, Object... arguments) {
             this(new NamedFunction(function), arguments);
         }
@@ -1431,7 +1362,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();
@@ -1467,7 +1398,11 @@
         }
         Name cloneWithIndex(int i) {
             Object[] newArguments = (arguments == null) ? null : arguments.clone();
-            return new Name(i, type, function, newArguments);
+            return new Name(i, type, function, newArguments).withConstraint(constraint);
+        }
+        Name withConstraint(Object constraint) {
+            if (constraint == this.constraint)  return this;
+            return new Name(this, constraint);
         }
         Name replaceName(Name oldName, Name newName) {  // FIXME: use replaceNames uniformly
             if (oldName == newName)  return this;
@@ -1487,7 +1422,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,8 +1478,16 @@
             return (isParam()?"a":"t")+(index >= 0 ? index : System.identityHashCode(this))+":"+typeChar();
         }
         public String debugString() {
+            String s = paramString();
+            return (function == null) ? s : s + "=" + exprString();
+        }
+        public String paramString() {
             String s = toString();
-            return (function == null) ? s : s + "=" + exprString();
+            Object c = constraint;
+            if (c == null)
+                return s;
+            if (c instanceof Class)  c = ((Class<?>)c).getSimpleName();
+            return s + "/" + c;
         }
         public String exprString() {
             if (function == null)  return toString();
@@ -1572,34 +1519,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.
          */
@@ -1690,6 +1609,7 @@
     static Name internArgument(Name n) {
         assert(n.isParam()) : "not param: " + n;
         assert(n.index < INTERNED_ARGUMENT_LIMIT);
+        if (n.constraint != null)  return n;
         return argument(n.index, n.type);
     }
     static Name[] arguments(int extra, String types) {
@@ -1858,37 +1778,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 +1790,7 @@
     static {
         createIdentityForms();
         if (USE_PREDEFINED_INTERPRET_METHODS)
-            PREPARED_FORMS.putAll(computeInitialPreparedForms());
+            computeInitialPreparedForms();
         NamedFunction.initializeInvokers();
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/invoke/LambdaFormBuffer.java	Fri Sep 12 10:33:32 2014 -0700
@@ -0,0 +1,401 @@
+/*
+ * Copyright (c) 2013, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package java.lang.invoke;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import static java.lang.invoke.LambdaForm.*;
+import static java.lang.invoke.LambdaForm.BasicType.*;
+
+/** Working storage for an LF that is being transformed.
+ *  Similarly to a StringBuffer, the editing can take place in multiple steps.
+ */
+final class LambdaFormBuffer {
+    private int arity, length;
+    private Name[] names;
+    private Name[] originalNames;  // snapshot of pre-transaction names
+    private byte flags;
+    private int firstChange;
+    private Name resultName;
+    private String debugName;
+    private ArrayList<Name> dups;
+
+    private static final int F_TRANS = 0x10, F_OWNED = 0x03;
+
+    LambdaFormBuffer(LambdaForm lf) {
+        this(lf.arity, lf.names, lf.result);
+        debugName = lf.debugName;
+        assert(lf.nameRefsAreLegal());
+    }
+
+    private LambdaFormBuffer(int arity, Name[] names, int result) {
+        this.arity = arity;
+        setNames(names);
+        if (result == LAST_RESULT)  result = length - 1;
+        if (result >= 0 && names[result].type != V_TYPE)
+            resultName = names[result];
+    }
+
+    private LambdaForm lambdaForm() {
+        assert(!inTrans());  // need endEdit call to tidy things up
+        return new LambdaForm(debugName, arity, nameArray(), resultIndex());
+    }
+
+    Name name(int i) {
+        assert(i < length);
+        return names[i];
+    }
+
+    Name[] nameArray() {
+        return Arrays.copyOf(names, length);
+    }
+
+    int resultIndex() {
+        if (resultName == null)  return VOID_RESULT;
+        int index = indexOf(resultName, names);
+        assert(index >= 0);
+        return index;
+    }
+
+    void setNames(Name[] names2) {
+        names = originalNames = names2;  // keep a record of where everything was to start with
+        length = names2.length;
+        flags = 0;
+    }
+
+    private boolean verifyArity() {
+        for (int i = 0; i < arity && i < firstChange; i++) {
+            assert(names[i].isParam()) : "#" + i + "=" + names[i];
+        }
+        for (int i = arity; i < length; i++) {
+            assert(!names[i].isParam()) : "#" + i + "=" + names[i];
+        }
+        for (int i = length; i < names.length; i++) {
+            assert(names[i] == null) : "#" + i + "=" + names[i];
+        }
+        // check resultName also
+        if (resultName != null) {
+            int resultIndex = indexOf(resultName, names);
+            assert(resultIndex >= 0) : "not found: " + resultName.exprString() + Arrays.asList(names);
+            assert(names[resultIndex] == resultName);
+        }
+        return true;
+    }
+
+    private boolean verifyFirstChange() {
+        assert(inTrans());
+        for (int i = 0; i < length; i++) {
+            if (names[i] != originalNames[i]) {
+                assert(firstChange == i) : Arrays.asList(firstChange, i, originalNames[i].exprString(), Arrays.asList(names));
+                return true;
+            }
+        }
+        assert(firstChange == length) : Arrays.asList(firstChange, Arrays.asList(names));
+        return true;
+    }
+
+    private static int indexOf(NamedFunction fn, NamedFunction[] fns) {
+        for (int i = 0; i < fns.length; i++) {
+            if (fns[i] == fn)  return i;
+        }
+        return -1;
+    }
+
+    private static int indexOf(Name n, Name[] ns) {
+        for (int i = 0; i < ns.length; i++) {
+            if (ns[i] == n)  return i;
+        }
+        return -1;
+    }
+
+    boolean inTrans() {
+        return (flags & F_TRANS) != 0;
+    }
+
+    int ownedCount() {
+        return flags & F_OWNED;
+    }
+
+    void growNames(int insertPos, int growLength) {
+        int oldLength = length;
+        int newLength = oldLength + growLength;
+        int oc = ownedCount();
+        if (oc == 0 || newLength > names.length) {
+            names = Arrays.copyOf(names, (names.length + growLength) * 5 / 4);
+            if (oc == 0) {
+                flags++;
+                oc++;
+                assert(ownedCount() == oc);
+            }
+        }
+        if (originalNames != null && originalNames.length < names.length) {
+            originalNames = Arrays.copyOf(originalNames, names.length);
+            if (oc == 1) {
+                flags++;
+                oc++;
+                assert(ownedCount() == oc);
+            }
+        }
+        if (growLength == 0)  return;
+        int insertEnd = insertPos + growLength;
+        int tailLength = oldLength - insertPos;
+        System.arraycopy(names, insertPos, names, insertEnd, tailLength);
+        Arrays.fill(names, insertPos, insertEnd, null);
+        if (originalNames != null) {
+            System.arraycopy(originalNames, insertPos, originalNames, insertEnd, tailLength);
+            Arrays.fill(originalNames, insertPos, insertEnd, null);
+        }
+        length = newLength;
+        if (firstChange >= insertPos) {
+            firstChange += growLength;
+        }
+    }
+
+    int lastIndexOf(Name n) {
+        int result = -1;
+        for (int i = 0; i < length; i++) {
+            if (names[i] == n)  result = i;
+        }
+        return result;
+    }
+
+    /** We have just overwritten the name at pos1 with the name at pos2.
+     *  This means that there are two copies of the name, which we will have to fix later.
+     */
+    private void noteDuplicate(int pos1, int pos2) {
+        Name n = names[pos1];
+        assert(n == names[pos2]);
+        assert(originalNames[pos1] != null);  // something was replaced at pos1
+        assert(originalNames[pos2] == null || originalNames[pos2] == n);
+        if (dups == null) {
+            dups = new ArrayList<>();
+        }
+        dups.add(n);
+    }
+
+    /** Replace duplicate names by nulls, and remove all nulls. */
+    private void clearDuplicatesAndNulls() {
+        if (dups != null) {
+            // Remove duplicates.
+            assert(ownedCount() >= 1);
+            for (Name dup : dups) {
+                for (int i = firstChange; i < length; i++) {
+                    if (names[i] == dup && originalNames[i] != dup) {
+                        names[i] = null;
+                        assert(Arrays.asList(names).contains(dup));
+                        break;  // kill only one dup
+                    }
+                }
+            }
+            dups.clear();
+        }
+        // Now that we are done with originalNames, remove "killed" names.
+        int oldLength = length;
+        for (int i = firstChange; i < length; i++) {
+            if (names[i] == null) {
+                System.arraycopy(names, i + 1, names, i, (--length - i));
+                --i;  // restart loop at this position
+            }
+        }
+        if (length < oldLength) {
+            Arrays.fill(names, length, oldLength, null);
+        }
+        assert(!Arrays.asList(names).subList(0, length).contains(null));
+    }
+
+    /** Create a private, writable copy of names.
+     *  Preserve the original copy, for reference.
+     */
+    void startEdit() {
+        assert(verifyArity());
+        int oc = ownedCount();
+        assert(!inTrans());  // no nested transactions
+        flags |= F_TRANS;
+        Name[] oldNames = names;
+        Name[] ownBuffer = (oc == 2 ? originalNames : null);
+        assert(ownBuffer != oldNames);
+        if (ownBuffer != null && ownBuffer.length >= length) {
+            names = copyNamesInto(ownBuffer);
+        } else {
+            // make a new buffer to hold the names
+            final int SLOP = 2;
+            names = Arrays.copyOf(oldNames, Math.max(length + SLOP, oldNames.length));
+            if (oc < 2)  ++flags;
+            assert(ownedCount() == oc + 1);
+        }
+        originalNames = oldNames;
+        assert(originalNames != names);
+        firstChange = length;
+        assert(inTrans());
+    }
+
+    private void changeName(int i, Name name) {
+        assert(inTrans());
+        assert(i < length);
+        Name oldName = names[i];
+        assert(oldName == originalNames[i]);  // no multiple changes
+        assert(verifyFirstChange());
+        if (ownedCount() == 0)
+            growNames(0, 0);
+        names[i] = name;
+        if (firstChange > i) {
+            firstChange = i;
+        }
+        if (resultName != null && resultName == oldName) {
+            resultName = name;
+        }
+    }
+
+    /** Change the result name.  Null means a void result. */
+    void setResult(Name name) {
+        assert(name == null || lastIndexOf(name) >= 0);
+        resultName = name;
+    }
+
+    /** Finish a transaction. */
+    LambdaForm endEdit() {
+        assert(verifyFirstChange());
+        // Assuming names have been changed pairwise from originalNames[i] to names[i],
+        // update arguments to ensure referential integrity.
+        for (int i = Math.max(firstChange, arity); i < length; i++) {
+            Name name = names[i];
+            if (name == null)  continue;  // space for removed duplicate
+            Name newName = name.replaceNames(originalNames, names, firstChange, i);
+            if (newName != name) {
+                names[i] = newName;
+                if (resultName == name) {
+                    resultName = newName;
+                }
+            }
+        }
+        assert(inTrans());
+        flags &= ~F_TRANS;
+        clearDuplicatesAndNulls();
+        originalNames = null;
+        // If any parameters have been changed, then reorder them as needed.
+        // This is a "sheep-and-goats" stable sort, pushing all non-parameters
+        // to the right of all parameters.
+        if (firstChange < arity) {
+            Name[] exprs = new Name[arity - firstChange];
+            int argp = firstChange, exprp = 0;
+            for (int i = firstChange; i < arity; i++) {
+                Name name = names[i];
+                if (name.isParam()) {
+                    names[argp++] = name;
+                } else {
+                    exprs[exprp++] = name;
+                }
+            }
+            assert(exprp == (arity - argp));
+            // copy the exprs just after the last remaining param
+            System.arraycopy(exprs, 0, names, argp, exprp);
+            // adjust arity
+            arity -= exprp;
+        }
+        assert(verifyArity());
+        return lambdaForm();
+    }
+
+    private Name[] copyNamesInto(Name[] buffer) {
+        System.arraycopy(names, 0, buffer, 0, length);
+        Arrays.fill(buffer, length, buffer.length, null);
+        return buffer;
+    }
+
+    /** Replace any Name whose function is in oldFns with a copy
+     *  whose function is in the corresponding position in newFns.
+     *  Only do this if the arguments are exactly equal to the given.
+     */
+    LambdaFormBuffer replaceFunctions(NamedFunction[] oldFns, NamedFunction[] newFns,
+                                      Object... forArguments) {
+        assert(inTrans());
+        if (oldFns.length == 0)  return this;
+        for (int i = arity; i < length; i++) {
+            Name n = names[i];
+            int nfi = indexOf(n.function, oldFns);
+            if (nfi >= 0 && Arrays.equals(n.arguments, forArguments)) {
+                changeName(i, new Name(newFns[nfi], n.arguments));
+            }
+        }
+        return this;
+    }
+
+    private void replaceName(int pos, Name binding) {
+        assert(inTrans());
+        assert(verifyArity());
+        assert(pos < arity);
+        Name param = names[pos];
+        assert(param.isParam());
+        assert(param.type == binding.type);
+        changeName(pos, binding);
+    }
+
+    /** Replace a parameter by a fresh parameter. */
+    LambdaFormBuffer renameParameter(int pos, Name newParam) {
+        assert(newParam.isParam());
+        replaceName(pos, newParam);
+        return this;
+    }
+
+    /** Replace a parameter by a fresh expression. */
+    LambdaFormBuffer replaceParameterByNewExpression(int pos, Name binding) {
+        assert(!binding.isParam());
+        assert(lastIndexOf(binding) < 0);  // else use replaceParameterByCopy
+        replaceName(pos, binding);
+        return this;
+    }
+
+    /** Replace a parameter by another parameter or expression already in the form. */
+    LambdaFormBuffer replaceParameterByCopy(int pos, int valuePos) {
+        assert(pos != valuePos);
+        replaceName(pos, names[valuePos]);
+        noteDuplicate(pos, valuePos);  // temporarily, will occur twice in the names array
+        return this;
+    }
+
+    private void insertName(int pos, Name expr, boolean isParameter) {
+        assert(inTrans());
+        assert(verifyArity());
+        assert(isParameter ? pos <= arity : pos >= arity);
+        growNames(pos, 1);
+        if (isParameter)  arity += 1;
+        changeName(pos, expr);
+    }
+
+    /** Insert a fresh expression. */
+    LambdaFormBuffer insertExpression(int pos, Name expr) {
+        assert(!expr.isParam());
+        insertName(pos, expr, false);
+        return this;
+    }
+
+    /** Insert a fresh parameter. */
+    LambdaFormBuffer insertParameter(int pos, Name param) {
+        assert(param.isParam());
+        insertName(pos, param, true);
+        return this;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/invoke/LambdaFormEditor.java	Fri Sep 12 10:33:32 2014 -0700
@@ -0,0 +1,825 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package java.lang.invoke;
+
+import java.util.Arrays;
+import static java.lang.invoke.LambdaForm.*;
+import static java.lang.invoke.LambdaForm.BasicType.*;
+import static java.lang.invoke.MethodHandleImpl.Intrinsic;
+import java.util.Collections;
+import java.util.concurrent.ConcurrentHashMap;
+
+import sun.invoke.util.Wrapper;
+
+/** Transforms on LFs.
+ *  A lambda-form editor can derive new LFs from its base LF.
+ *  The editor can cache derived LFs, which simplifies the reuse of their underlying bytecodes.
+ *  To support this caching, a LF has an optional pointer to its editor.
+ */
+class LambdaFormEditor {
+    final LambdaForm lambdaForm;
+
+    private LambdaFormEditor(LambdaForm lambdaForm) {
+        this.lambdaForm = lambdaForm;
+    }
+
+    // Factory method.
+    static LambdaFormEditor lambdaFormEditor(LambdaForm lambdaForm) {
+        // TO DO:  Consider placing intern logic here, to cut down on duplication.
+        // lambdaForm = findPreexistingEquivalent(lambdaForm)
+        return new LambdaFormEditor(lambdaForm);
+    }
+
+    /** A description of a cached transform, possibly associated with the result of the transform.
+     *  The logical content is a sequence of byte values, starting with a Kind.ordinal value.
+     *  The sequence is unterminated, ending with an indefinite number of zero bytes.
+     *  Sequences that are simple (short enough and with small enough values) pack into a 64-bit long.
+     */
+    private static final class Transform {
+        final long packedBytes;
+        final byte[] fullBytes;
+        final LambdaForm result;  // result of transform, or null, if there is none available
+
+        private enum Kind {
+            NO_KIND,  // necessary because ordinal must be greater than zero
+            BIND_ARG, ADD_ARG, DUP_ARG,
+            SPREAD_ARGS,
+            FILTER_ARG, FILTER_RETURN, FILTER_RETURN_TO_ZERO,
+            COLLECT_ARGS, COLLECT_ARGS_TO_VOID, COLLECT_ARGS_TO_ARRAY,
+            FOLD_ARGS, FOLD_ARGS_TO_VOID,
+            PERMUTE_ARGS
+            //maybe add more for guard with test, catch exception, pointwise type conversions
+        }
+
+        private static final boolean STRESS_TEST = false; // turn on to disable most packing
+        private static final int
+                PACKED_BYTE_SIZE = (STRESS_TEST ? 2 : 4),
+                PACKED_BYTE_MASK = (1 << PACKED_BYTE_SIZE) - 1,
+                PACKED_BYTE_MAX_LENGTH = (STRESS_TEST ? 3 : 64 / PACKED_BYTE_SIZE);
+
+        private static long packedBytes(byte[] bytes) {
+            if (bytes.length > PACKED_BYTE_MAX_LENGTH)  return 0;
+            long pb = 0;
+            int bitset = 0;
+            for (int i = 0; i < bytes.length; i++) {
+                int b = bytes[i] & 0xFF;
+                bitset |= b;
+                pb |= (long)b << (i * PACKED_BYTE_SIZE);
+            }
+            if (!inRange(bitset))
+                return 0;
+            return pb;
+        }
+        private static long packedBytes(int b0, int b1) {
+            assert(inRange(b0 | b1));
+            return (  (b0 << 0*PACKED_BYTE_SIZE)
+                    | (b1 << 1*PACKED_BYTE_SIZE));
+        }
+        private static long packedBytes(int b0, int b1, int b2) {
+            assert(inRange(b0 | b1 | b2));
+            return (  (b0 << 0*PACKED_BYTE_SIZE)
+                    | (b1 << 1*PACKED_BYTE_SIZE)
+                    | (b2 << 2*PACKED_BYTE_SIZE));
+        }
+        private static long packedBytes(int b0, int b1, int b2, int b3) {
+            assert(inRange(b0 | b1 | b2 | b3));
+            return (  (b0 << 0*PACKED_BYTE_SIZE)
+                    | (b1 << 1*PACKED_BYTE_SIZE)
+                    | (b2 << 2*PACKED_BYTE_SIZE)
+                    | (b3 << 3*PACKED_BYTE_SIZE));
+        }
+        private static boolean inRange(int bitset) {
+            assert((bitset & 0xFF) == bitset);  // incoming values must fit in *unsigned* byte
+            return ((bitset & ~PACKED_BYTE_MASK) == 0);
+        }
+        private static byte[] fullBytes(int... byteValues) {
+            byte[] bytes = new byte[byteValues.length];
+            int i = 0;
+            for (int bv : byteValues) {
+                bytes[i++] = bval(bv);
+            }
+            assert(packedBytes(bytes) == 0);
+            return bytes;
+        }
+
+        private byte byteAt(int i) {
+            long pb = packedBytes;
+            if (pb == 0) {
+                if (i >= fullBytes.length)  return 0;
+                return fullBytes[i];
+            }
+            assert(fullBytes == null);
+            if (i > PACKED_BYTE_MAX_LENGTH)  return 0;
+            int pos = (i * PACKED_BYTE_SIZE);
+            return (byte)((pb >>> pos) & PACKED_BYTE_MASK);
+        }
+
+        Kind kind() { return Kind.values()[byteAt(0)]; }
+
+        private Transform(long packedBytes, byte[] fullBytes, LambdaForm result) {
+            this.packedBytes = packedBytes;
+            this.fullBytes = fullBytes;
+            this.result = result;
+        }
+        private Transform(long packedBytes) {
+            this(packedBytes, null, null);
+            assert(packedBytes != 0);
+        }
+        private Transform(byte[] fullBytes) {
+            this(0, fullBytes, null);
+        }
+
+        private static byte bval(int b) {
+            assert((b & 0xFF) == b);  // incoming value must fit in *unsigned* byte
+            return (byte)b;
+        }
+        private static byte bval(Kind k) {
+            return bval(k.ordinal());
+        }
+        static Transform of(Kind k, int b1) {
+            byte b0 = bval(k);
+            if (inRange(b0 | b1))
+                return new Transform(packedBytes(b0, b1));
+            else
+                return new Transform(fullBytes(b0, b1));
+        }
+        static Transform of(Kind k, int b1, int b2) {
+            byte b0 = (byte) k.ordinal();
+            if (inRange(b0 | b1 | b2))
+                return new Transform(packedBytes(b0, b1, b2));
+            else
+                return new Transform(fullBytes(b0, b1, b2));
+        }
+        static Transform of(Kind k, int b1, int b2, int b3) {
+            byte b0 = (byte) k.ordinal();
+            if (inRange(b0 | b1 | b2 | b3))
+                return new Transform(packedBytes(b0, b1, b2, b3));
+            else
+                return new Transform(fullBytes(b0, b1, b2, b3));
+        }
+        private static final byte[] NO_BYTES = {};
+        static Transform of(Kind k, int... b123) {
+            return ofBothArrays(k, b123, NO_BYTES);
+        }
+        static Transform of(Kind k, int b1, byte[] b234) {
+            return ofBothArrays(k, new int[]{ b1 }, b234);
+        }
+        static Transform of(Kind k, int b1, int b2, byte[] b345) {
+            return ofBothArrays(k, new int[]{ b1, b2 }, b345);
+        }
+        private static Transform ofBothArrays(Kind k, int[] b123, byte[] b456) {
+            byte[] fullBytes = new byte[1 + b123.length + b456.length];
+            int i = 0;
+            fullBytes[i++] = bval(k);
+            for (int bv : b123) {
+                fullBytes[i++] = bval(bv);
+            }
+            for (byte bv : b456) {
+                fullBytes[i++] = bv;
+            }
+            long packedBytes = packedBytes(fullBytes);
+            if (packedBytes != 0)
+                return new Transform(packedBytes);
+            else
+                return new Transform(fullBytes);
+        }
+
+        Transform withResult(LambdaForm result) {
+            return new Transform(this.packedBytes, this.fullBytes, result);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            return obj instanceof Transform && equals((Transform)obj);
+        }
+        public boolean equals(Transform that) {
+            return this.packedBytes == that.packedBytes && Arrays.equals(this.fullBytes, that.fullBytes);
+        }
+        @Override
+        public int hashCode() {
+            if (packedBytes != 0) {
+                assert(fullBytes == null);
+                return Long.hashCode(packedBytes);
+            }
+            return Arrays.hashCode(fullBytes);
+        }
+        @Override
+        public String toString() {
+            StringBuilder buf = new StringBuilder();
+            long bits = packedBytes;
+            if (bits != 0) {
+                buf.append("(");
+                while (bits != 0) {
+                    buf.append(bits & PACKED_BYTE_MASK);
+                    bits >>>= PACKED_BYTE_SIZE;
+                    if (bits != 0)  buf.append(",");
+                }
+                buf.append(")");
+            }
+            if (fullBytes != null) {
+                buf.append("unpacked");
+                buf.append(Arrays.toString(fullBytes));
+            }
+            if (result != null) {
+                buf.append(" result=");
+                buf.append(result);
+            }
+            return buf.toString();
+        }
+    }
+
+    /** Find a previously cached transform equivalent to the given one, and return its result. */
+    private LambdaForm getInCache(Transform key) {
+        assert(key.result == null);
+        // The transformCache is one of null, Transform, Transform[], or ConcurrentHashMap.
+        Object c = lambdaForm.transformCache;
+        Transform k = null;
+        if (c instanceof ConcurrentHashMap) {
+            @SuppressWarnings("unchecked")
+            ConcurrentHashMap<Transform,Transform> m = (ConcurrentHashMap<Transform,Transform>) c;
+            k = m.get(key);
+        } else if (c == null) {
+            return null;
+        } else if (c instanceof Transform) {
+            // one-element cache avoids overhead of an array
+            Transform t = (Transform)c;
+            if (t.equals(key))  k = t;
+        } else {
+            Transform[] ta = (Transform[])c;
+            for (int i = 0; i < ta.length; i++) {
+                Transform t = ta[i];
+                if (t == null)  break;
+                if (t.equals(key)) { k = t; break; }
+            }
+        }
+        assert(k == null || key.equals(k));
+        return k == null ? null : k.result;
+    }
+
+    /** Arbitrary but reasonable limits on Transform[] size for cache. */
+    private static final int MIN_CACHE_ARRAY_SIZE = 4, MAX_CACHE_ARRAY_SIZE = 16;
+
+    /** Cache a transform with its result, and return that result.
+     *  But if an equivalent transform has already been cached, return its result instead.
+     */
+    private LambdaForm putInCache(Transform key, LambdaForm form) {
+        key = key.withResult(form);
+        for (int pass = 0; ; pass++) {
+            Object c = lambdaForm.transformCache;
+            if (c instanceof ConcurrentHashMap) {
+                @SuppressWarnings("unchecked")
+                ConcurrentHashMap<Transform,Transform> m = (ConcurrentHashMap<Transform,Transform>) c;
+                Transform k = m.putIfAbsent(key, key);
+                return k != null ? k.result : form;
+            }
+            assert(pass == 0);
+            synchronized (lambdaForm) {
+                c = lambdaForm.transformCache;
+                if (c instanceof ConcurrentHashMap)
+                    continue;
+                if (c == null) {
+                    lambdaForm.transformCache = key;
+                    return form;
+                }
+                Transform[] ta;
+                if (c instanceof Transform) {
+                    Transform k = (Transform)c;
+                    if (k.equals(key)) {
+                        return k.result;
+                    }
+                    // expand one-element cache to small array
+                    ta = new Transform[MIN_CACHE_ARRAY_SIZE];
+                    ta[0] = k;
+                    lambdaForm.transformCache = c = ta;
+                } else {
+                    // it is already expanded
+                    ta = (Transform[])c;
+                }
+                int len = ta.length;
+                int i;
+                for (i = 0; i < len; i++) {
+                    Transform k = ta[i];
+                    if (k == null) {
+                        break;
+                    }
+                    if (k.equals(key)) {
+                        return k.result;
+                    }
+                }
+                if (i < len) {
+                    // just fall through to cache update
+                } else if (len < MAX_CACHE_ARRAY_SIZE) {
+                    len = Math.min(len * 2, MAX_CACHE_ARRAY_SIZE);
+                    ta = Arrays.copyOf(ta, len);
+                    lambdaForm.transformCache = ta;
+                } else {
+                    ConcurrentHashMap<Transform, Transform> m = new ConcurrentHashMap<>(MAX_CACHE_ARRAY_SIZE * 2);
+                    for (Transform k : ta) {
+                        m.put(k, k);
+                    }
+                    lambdaForm.transformCache = m;
+                    // The second iteration will update for this query, concurrently.
+                    continue;
+                }
+                ta[i] = key;
+                return form;
+            }
+        }
+    }
+
+    private LambdaFormBuffer buffer() {
+        return new LambdaFormBuffer(lambdaForm);
+    }
+
+    /// Editing methods for method handles.  These need to have fast paths.
+
+    private BoundMethodHandle.SpeciesData oldSpeciesData() {
+        return BoundMethodHandle.speciesData(lambdaForm);
+    }
+    private BoundMethodHandle.SpeciesData newSpeciesData(BasicType type) {
+        return oldSpeciesData().extendWith(type);
+    }
+
+    BoundMethodHandle bindArgumentL(BoundMethodHandle mh, int pos, Object value) {
+        assert(mh.speciesData() == oldSpeciesData());
+        BasicType bt = L_TYPE;
+        MethodType type2 = bindArgumentType(mh, pos, bt);
+        LambdaForm form2 = bindArgumentForm(1+pos);
+        return mh.copyWithExtendL(type2, form2, value);
+    }
+    BoundMethodHandle bindArgumentI(BoundMethodHandle mh, int pos, int value) {
+        assert(mh.speciesData() == oldSpeciesData());
+        BasicType bt = I_TYPE;
+        MethodType type2 = bindArgumentType(mh, pos, bt);
+        LambdaForm form2 = bindArgumentForm(1+pos);
+        return mh.copyWithExtendI(type2, form2, value);
+    }
+
+    BoundMethodHandle bindArgumentJ(BoundMethodHandle mh, int pos, long value) {
+        assert(mh.speciesData() == oldSpeciesData());
+        BasicType bt = J_TYPE;
+        MethodType type2 = bindArgumentType(mh, pos, bt);
+        LambdaForm form2 = bindArgumentForm(1+pos);
+        return mh.copyWithExtendJ(type2, form2, value);
+    }
+
+    BoundMethodHandle bindArgumentF(BoundMethodHandle mh, int pos, float value) {
+        assert(mh.speciesData() == oldSpeciesData());
+        BasicType bt = F_TYPE;
+        MethodType type2 = bindArgumentType(mh, pos, bt);
+        LambdaForm form2 = bindArgumentForm(1+pos);
+        return mh.copyWithExtendF(type2, form2, value);
+    }
+
+    BoundMethodHandle bindArgumentD(BoundMethodHandle mh, int pos, double value) {
+        assert(mh.speciesData() == oldSpeciesData());
+        BasicType bt = D_TYPE;
+        MethodType type2 = bindArgumentType(mh, pos, bt);
+        LambdaForm form2 = bindArgumentForm(1+pos);
+        return mh.copyWithExtendD(type2, form2, value);
+    }
+
+    private MethodType bindArgumentType(BoundMethodHandle mh, int pos, BasicType bt) {
+        assert(mh.form == lambdaForm);
+        assert(mh.form.names[1+pos].type == bt);
+        assert(BasicType.basicType(mh.type().parameterType(pos)) == bt);
+        return mh.type().dropParameterTypes(pos, pos+1);
+    }
+
+    /// Editing methods for lambda forms.
+    // Each editing method can (potentially) cache the edited LF so that it can be reused later.
+
+    LambdaForm bindArgumentForm(int pos) {
+        Transform key = Transform.of(Transform.Kind.BIND_ARG, pos);
+        LambdaForm form = getInCache(key);
+        if (form != null) {
+            assert(form.parameterConstraint(0) == newSpeciesData(lambdaForm.parameterType(pos)));
+            return form;
+        }
+        LambdaFormBuffer buf = buffer();
+        buf.startEdit();
+
+        BoundMethodHandle.SpeciesData oldData = oldSpeciesData();
+        BoundMethodHandle.SpeciesData newData = newSpeciesData(lambdaForm.parameterType(pos));
+        Name oldBaseAddress = lambdaForm.parameter(0);  // BMH holding the values
+        Name newBaseAddress;
+        NamedFunction getter = newData.getterFunction(oldData.fieldCount());
+
+        if (pos != 0) {
+            // The newly created LF will run with a different BMH.
+            // Switch over any pre-existing BMH field references to the new BMH class.
+            buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress);
+            newBaseAddress = oldBaseAddress.withConstraint(newData);
+            buf.renameParameter(0, newBaseAddress);
+            buf.replaceParameterByNewExpression(pos, new Name(getter, newBaseAddress));
+        } else {
+            // cannot bind the MH arg itself, unless oldData is empty
+            assert(oldData == BoundMethodHandle.SpeciesData.EMPTY);
+            newBaseAddress = new Name(L_TYPE).withConstraint(newData);
+            buf.replaceParameterByNewExpression(0, new Name(getter, newBaseAddress));
+            buf.insertParameter(0, newBaseAddress);
+        }
+
+        form = buf.endEdit();
+        return putInCache(key, form);
+    }
+
+    LambdaForm addArgumentForm(int pos, BasicType type) {
+        Transform key = Transform.of(Transform.Kind.ADD_ARG, pos, type.ordinal());
+        LambdaForm form = getInCache(key);
+        if (form != null) {
+            assert(form.arity == lambdaForm.arity+1);
+            assert(form.parameterType(pos) == type);
+            return form;
+        }
+        LambdaFormBuffer buf = buffer();
+        buf.startEdit();
+
+        buf.insertParameter(pos, new Name(type));
+
+        form = buf.endEdit();
+        return putInCache(key, form);
+    }
+
+    LambdaForm dupArgumentForm(int srcPos, int dstPos) {
+        Transform key = Transform.of(Transform.Kind.DUP_ARG, srcPos, dstPos);
+        LambdaForm form = getInCache(key);
+        if (form != null) {
+            assert(form.arity == lambdaForm.arity-1);
+            return form;
+        }
+        LambdaFormBuffer buf = buffer();
+        buf.startEdit();
+
+        assert(lambdaForm.parameter(srcPos).constraint == null);
+        assert(lambdaForm.parameter(dstPos).constraint == null);
+        buf.replaceParameterByCopy(dstPos, srcPos);
+
+        form = buf.endEdit();
+        return putInCache(key, form);
+    }
+
+    LambdaForm spreadArgumentsForm(int pos, Class<?> arrayType, int arrayLength) {
+        Class<?> elementType = arrayType.getComponentType();
+        Class<?> erasedArrayType = arrayType;
+        if (!elementType.isPrimitive())
+            erasedArrayType = Object[].class;
+        BasicType bt = basicType(elementType);
+        int elementTypeKey = bt.ordinal();
+        if (bt.basicTypeClass() != elementType) {
+            if (elementType.isPrimitive()) {
+                elementTypeKey = TYPE_LIMIT + Wrapper.forPrimitiveType(elementType).ordinal();
+            }
+        }
+        Transform key = Transform.of(Transform.Kind.SPREAD_ARGS, pos, elementTypeKey, arrayLength);
+        LambdaForm form = getInCache(key);
+        if (form != null) {
+            assert(form.arity == lambdaForm.arity - arrayLength + 1);
+            return form;
+        }
+        LambdaFormBuffer buf = buffer();
+        buf.startEdit();
+
+        assert(pos <= MethodType.MAX_JVM_ARITY);
+        assert(pos + arrayLength <= lambdaForm.arity);
+        assert(pos > 0);  // cannot spread the MH arg itself
+
+        Name spreadParam = new Name(L_TYPE);
+        Name checkSpread = new Name(MethodHandleImpl.Lazy.NF_checkSpreadArgument, spreadParam, arrayLength);
+
+        // insert the new expressions
+        int exprPos = lambdaForm.arity();
+        buf.insertExpression(exprPos++, checkSpread);
+        // adjust the arguments
+        MethodHandle aload = MethodHandles.arrayElementGetter(erasedArrayType);
+        for (int i = 0; i < arrayLength; i++) {
+            Name loadArgument = new Name(aload, spreadParam, i);
+            buf.insertExpression(exprPos + i, loadArgument);
+            buf.replaceParameterByCopy(pos + i, exprPos + i);
+        }
+        buf.insertParameter(pos, spreadParam);
+
+        form = buf.endEdit();
+        return putInCache(key, form);
+    }
+
+    LambdaForm collectArgumentsForm(int pos, MethodType collectorType) {
+        int collectorArity = collectorType.parameterCount();
+        boolean dropResult = (collectorType.returnType() == void.class);
+        if (collectorArity == 1 && !dropResult) {
+            return filterArgumentForm(pos, basicType(collectorType.parameterType(0)));
+        }
+        BasicType[] newTypes = BasicType.basicTypes(collectorType.parameterList());
+        Transform.Kind kind = (dropResult
+                ? Transform.Kind.COLLECT_ARGS_TO_VOID
+                : Transform.Kind.COLLECT_ARGS);
+        if (dropResult && collectorArity == 0)  pos = 1;  // pure side effect
+        Transform key = Transform.of(kind, pos, collectorArity, BasicType.basicTypesOrd(newTypes));
+        LambdaForm form = getInCache(key);
+        if (form != null) {
+            assert(form.arity == lambdaForm.arity - (dropResult ? 0 : 1) + collectorArity);
+            return form;
+        }
+        form = makeArgumentCombinationForm(pos, collectorType, false, dropResult);
+        return putInCache(key, form);
+    }
+
+    LambdaForm collectArgumentArrayForm(int pos, MethodHandle arrayCollector) {
+        MethodType collectorType = arrayCollector.type();
+        int collectorArity = collectorType.parameterCount();
+        assert(arrayCollector.intrinsicName() == Intrinsic.NEW_ARRAY);
+        Class<?> arrayType = collectorType.returnType();
+        Class<?> elementType = arrayType.getComponentType();
+        BasicType argType = basicType(elementType);
+        int argTypeKey = argType.ordinal();
+        if (argType.basicTypeClass() != elementType) {
+            // return null if it requires more metadata (like String[].class)
+            if (!elementType.isPrimitive())
+                return null;
+            argTypeKey = TYPE_LIMIT + Wrapper.forPrimitiveType(elementType).ordinal();
+        }
+        assert(collectorType.parameterList().equals(Collections.nCopies(collectorArity, elementType)));
+        Transform.Kind kind = Transform.Kind.COLLECT_ARGS_TO_ARRAY;
+        Transform key = Transform.of(kind, pos, collectorArity, argTypeKey);
+        LambdaForm form = getInCache(key);
+        if (form != null) {
+            assert(form.arity == lambdaForm.arity - 1 + collectorArity);
+            return form;
+        }
+        LambdaFormBuffer buf = buffer();
+        buf.startEdit();
+
+        assert(pos + 1 <= lambdaForm.arity);
+        assert(pos > 0);  // cannot filter the MH arg itself
+
+        Name[] newParams = new Name[collectorArity];
+        for (int i = 0; i < collectorArity; i++) {
+            newParams[i] = new Name(pos + i, argType);
+        }
+        Name callCombiner = new Name(arrayCollector, (Object[]) /*...*/ newParams);
+
+        // insert the new expression
+        int exprPos = lambdaForm.arity();
+        buf.insertExpression(exprPos, callCombiner);
+
+        // insert new arguments
+        int argPos = pos + 1;  // skip result parameter
+        for (Name newParam : newParams) {
+            buf.insertParameter(argPos++, newParam);
+        }
+        assert(buf.lastIndexOf(callCombiner) == exprPos+newParams.length);
+        buf.replaceParameterByCopy(pos, exprPos+newParams.length);
+
+        form = buf.endEdit();
+        return putInCache(key, form);
+    }
+
+    LambdaForm filterArgumentForm(int pos, BasicType newType) {
+        Transform key = Transform.of(Transform.Kind.FILTER_ARG, pos, newType.ordinal());
+        LambdaForm form = getInCache(key);
+        if (form != null) {
+            assert(form.arity == lambdaForm.arity);
+            assert(form.parameterType(pos) == newType);
+            return form;
+        }
+
+        BasicType oldType = lambdaForm.parameterType(pos);
+        MethodType filterType = MethodType.methodType(oldType.basicTypeClass(),
+                newType.basicTypeClass());
+        form = makeArgumentCombinationForm(pos, filterType, false, false);
+        return putInCache(key, form);
+    }
+
+    private LambdaForm makeArgumentCombinationForm(int pos,
+                                                   MethodType combinerType,
+                                                   boolean keepArguments, boolean dropResult) {
+        LambdaFormBuffer buf = buffer();
+        buf.startEdit();
+        int combinerArity = combinerType.parameterCount();
+        int resultArity = (dropResult ? 0 : 1);
+
+        assert(pos <= MethodType.MAX_JVM_ARITY);
+        assert(pos + resultArity + (keepArguments ? combinerArity : 0) <= lambdaForm.arity);
+        assert(pos > 0);  // cannot filter the MH arg itself
+        assert(combinerType == combinerType.basicType());
+        assert(combinerType.returnType() != void.class || dropResult);
+
+        BoundMethodHandle.SpeciesData oldData = oldSpeciesData();
+        BoundMethodHandle.SpeciesData newData = newSpeciesData(L_TYPE);
+
+        // The newly created LF will run with a different BMH.
+        // Switch over any pre-existing BMH field references to the new BMH class.
+        Name oldBaseAddress = lambdaForm.parameter(0);  // BMH holding the values
+        buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress);
+        Name newBaseAddress = oldBaseAddress.withConstraint(newData);
+        buf.renameParameter(0, newBaseAddress);
+
+        Name getCombiner = new Name(newData.getterFunction(oldData.fieldCount()), newBaseAddress);
+        Object[] combinerArgs = new Object[1 + combinerArity];
+        combinerArgs[0] = getCombiner;
+        Name[] newParams;
+        if (keepArguments) {
+            newParams = new Name[0];
+            System.arraycopy(lambdaForm.names, pos + resultArity,
+                             combinerArgs, 1, combinerArity);
+        } else {
+            newParams = new Name[combinerArity];
+            BasicType[] newTypes = basicTypes(combinerType.parameterList());
+            for (int i = 0; i < newTypes.length; i++) {
+                newParams[i] = new Name(pos + i, newTypes[i]);
+            }
+            System.arraycopy(newParams, 0,
+                             combinerArgs, 1, combinerArity);
+        }
+        Name callCombiner = new Name(combinerType, combinerArgs);
+
+        // insert the two new expressions
+        int exprPos = lambdaForm.arity();
+        buf.insertExpression(exprPos+0, getCombiner);
+        buf.insertExpression(exprPos+1, callCombiner);
+
+        // insert new arguments, if needed
+        int argPos = pos + resultArity;  // skip result parameter
+        for (Name newParam : newParams) {
+            buf.insertParameter(argPos++, newParam);
+        }
+        assert(buf.lastIndexOf(callCombiner) == exprPos+1+newParams.length);
+        if (!dropResult) {
+            buf.replaceParameterByCopy(pos, exprPos+1+newParams.length);
+        }
+
+        return buf.endEdit();
+    }
+
+    LambdaForm filterReturnForm(BasicType newType, boolean constantZero) {
+        Transform.Kind kind = (constantZero ? Transform.Kind.FILTER_RETURN_TO_ZERO : Transform.Kind.FILTER_RETURN);
+        Transform key = Transform.of(kind, newType.ordinal());
+        LambdaForm form = getInCache(key);
+        if (form != null) {
+            assert(form.arity == lambdaForm.arity);
+            assert(form.returnType() == newType);
+            return form;
+        }
+        LambdaFormBuffer buf = buffer();
+        buf.startEdit();
+
+        int insPos = lambdaForm.names.length;
+        Name callFilter;
+        if (constantZero) {
+            // Synthesize a constant zero value for the given type.
+            if (newType == V_TYPE)
+                callFilter = null;
+            else
+                callFilter = new Name(constantZero(newType));
+        } else {
+            BoundMethodHandle.SpeciesData oldData = oldSpeciesData();
+            BoundMethodHandle.SpeciesData newData = newSpeciesData(L_TYPE);
+
+            // The newly created LF will run with a different BMH.
+            // Switch over any pre-existing BMH field references to the new BMH class.
+            Name oldBaseAddress = lambdaForm.parameter(0);  // BMH holding the values
+            buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress);
+            Name newBaseAddress = oldBaseAddress.withConstraint(newData);
+            buf.renameParameter(0, newBaseAddress);
+
+            Name getFilter = new Name(newData.getterFunction(oldData.fieldCount()), newBaseAddress);
+            buf.insertExpression(insPos++, getFilter);
+            BasicType oldType = lambdaForm.returnType();
+            if (oldType == V_TYPE) {
+                MethodType filterType = MethodType.methodType(newType.basicTypeClass());
+                callFilter = new Name(filterType, getFilter);
+            } else {
+                MethodType filterType = MethodType.methodType(newType.basicTypeClass(), oldType.basicTypeClass());
+                callFilter = new Name(filterType, getFilter, lambdaForm.names[lambdaForm.result]);
+            }
+        }
+
+        if (callFilter != null)
+            buf.insertExpression(insPos++, callFilter);
+        buf.setResult(callFilter);
+
+        form = buf.endEdit();
+        return putInCache(key, form);
+    }
+
+    LambdaForm foldArgumentsForm(int foldPos, boolean dropResult, MethodType combinerType) {
+        int combinerArity = combinerType.parameterCount();
+        Transform.Kind kind = (dropResult ? Transform.Kind.FOLD_ARGS_TO_VOID : Transform.Kind.FOLD_ARGS);
+        Transform key = Transform.of(kind, foldPos, combinerArity);
+        LambdaForm form = getInCache(key);
+        if (form != null) {
+            assert(form.arity == lambdaForm.arity - (kind == Transform.Kind.FOLD_ARGS ? 1 : 0));
+            return form;
+        }
+        form = makeArgumentCombinationForm(foldPos, combinerType, true, dropResult);
+        return putInCache(key, form);
+    }
+
+    LambdaForm permuteArgumentsForm(int skip, int[] reorder) {
+        assert(skip == 1);  // skip only the leading MH argument, names[0]
+        int length = lambdaForm.names.length;
+        int outArgs = reorder.length;
+        int inTypes = 0;
+        boolean nullPerm = true;
+        for (int i = 0; i < reorder.length; i++) {
+            int inArg = reorder[i];
+            if (inArg != i)  nullPerm = false;
+            inTypes = Math.max(inTypes, inArg+1);
+        }
+        assert(skip + reorder.length == lambdaForm.arity);
+        if (nullPerm)  return lambdaForm;  // do not bother to cache
+        Transform key = Transform.of(Transform.Kind.PERMUTE_ARGS, reorder);
+        LambdaForm form = getInCache(key);
+        if (form != null) {
+            assert(form.arity == skip+inTypes) : form;
+            return form;
+        }
+
+        BasicType[] types = new BasicType[inTypes];
+        for (int i = 0; i < outArgs; i++) {
+            int inArg = reorder[i];
+            types[inArg] = lambdaForm.names[skip + i].type;
+        }
+        assert (skip + outArgs == lambdaForm.arity);
+        assert (permutedTypesMatch(reorder, types, lambdaForm.names, skip));
+        int pos = 0;
+        while (pos < outArgs && reorder[pos] == pos) {
+            pos += 1;
+        }
+        Name[] names2 = new Name[length - outArgs + inTypes];
+        System.arraycopy(lambdaForm.names, 0, names2, 0, skip + pos);
+        int bodyLength = length - lambdaForm.arity;
+        System.arraycopy(lambdaForm.names, skip + outArgs, names2, skip + inTypes, bodyLength);
+        int arity2 = names2.length - bodyLength;
+        int result2 = lambdaForm.result;
+        if (result2 >= 0) {
+            if (result2 < skip + outArgs) {
+                result2 = reorder[result2 - skip];
+            } else {
+                result2 = result2 - outArgs + inTypes;
+            }
+        }
+        for (int j = pos; j < outArgs; j++) {
+            Name n = lambdaForm.names[skip + j];
+            int i = reorder[j];
+            Name n2 = names2[skip + i];
+            if (n2 == null) {
+                names2[skip + i] = n2 = new Name(types[i]);
+            } else {
+                assert (n2.type == types[i]);
+            }
+            for (int k = arity2; k < names2.length; k++) {
+                names2[k] = names2[k].replaceName(n, n2);
+            }
+        }
+        for (int i = skip + pos; i < arity2; i++) {
+            if (names2[i] == null) {
+                names2[i] = argument(i, types[i - skip]);
+            }
+        }
+        for (int j = lambdaForm.arity; j < lambdaForm.names.length; j++) {
+            int i = j - lambdaForm.arity + arity2;
+            Name n = lambdaForm.names[j];
+            Name n2 = names2[i];
+            if (n != n2) {
+                for (int k = i + 1; k < names2.length; k++) {
+                    names2[k] = names2[k].replaceName(n, n2);
+                }
+            }
+        }
+
+        form = new LambdaForm(lambdaForm.debugName, arity2, names2, result2);
+        return putInCache(key, form);
+    }
+
+    static boolean permutedTypesMatch(int[] reorder, BasicType[] types, Name[] names, int skip) {
+        for (int i = 0; i < reorder.length; i++) {
+            assert (names[skip + i].isParam());
+            assert (names[skip + i].type == types[reorder[i]]);
+        }
+        return true;
+    }
+}
--- a/src/java.base/share/classes/java/lang/invoke/MemberName.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/MemberName.java	Fri Sep 12 10:33:32 2014 -0700
@@ -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/src/java.base/share/classes/java/lang/invoke/MethodHandle.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandle.java	Fri Sep 12 10:33:32 2014 -0700
@@ -27,12 +27,8 @@
 
 
 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,
@@ -625,15 +621,8 @@
      * @see MethodHandles#spreadInvoker
      */
     public Object invokeWithArguments(Object... arguments) throws Throwable {
-        int argc = arguments == null ? 0 : arguments.length;
-        @SuppressWarnings("LocalVariableHidesMemberVariable")
-        MethodType type = type();
-        if (type.parameterCount() != argc || isVarargsCollector()) {
-            // simulate invoke
-            return asType(MethodType.genericMethodType(argc)).invokeWithArguments(arguments);
-        }
-        MethodHandle invoker = type.invokers().varargsInvoker();
-        return invoker.invokeExact(this, arguments);
+        MethodType invocationType = MethodType.genericMethodType(arguments == null ? 0 : arguments.length);
+        return invocationType.invokers().spreadInvoker(0).invokeExact(asType(invocationType), arguments);
     }
 
     /**
@@ -763,18 +752,26 @@
             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. */
     /*non-public*/ MethodHandle asTypeUncached(MethodType newType) {
         if (!type.isConvertibleTo(newType))
             throw new WrongMethodTypeException("cannot convert "+this+" to "+newType);
-        return asTypeCache = convertArguments(newType);
+        return asTypeCache = MethodHandleImpl.makePairwiseConvert(this, newType, true);
     }
 
     /**
@@ -867,34 +864,48 @@
      * @see #asCollector
      */
     public MethodHandle asSpreader(Class<?> arrayType, int arrayLength) {
-        asSpreaderChecks(arrayType, arrayLength);
-        int spreadArgPos = type.parameterCount() - arrayLength;
-        return MethodHandleImpl.makeSpreadArguments(this, arrayType, spreadArgPos, arrayLength);
+        MethodType postSpreadType = asSpreaderChecks(arrayType, arrayLength);
+        int arity = type().parameterCount();
+        int spreadArgPos = arity - arrayLength;
+        if (USE_LAMBDA_FORM_EDITOR) {
+            MethodHandle afterSpread = this.asType(postSpreadType);
+            BoundMethodHandle mh = afterSpread.rebind();
+            LambdaForm lform = mh.editor().spreadArgumentsForm(1 + spreadArgPos, arrayType, arrayLength);
+            MethodType preSpreadType = postSpreadType.replaceParameterTypes(spreadArgPos, arity, arrayType);
+            return mh.copyWith(preSpreadType, lform);
+        } else {
+            return MethodHandleImpl.makeSpreadArguments(this, arrayType, spreadArgPos, arrayLength);
+        }
     }
 
-    private void asSpreaderChecks(Class<?> arrayType, int arrayLength) {
+    /**
+     * See if {@code asSpreader} can be validly called with the given arguments.
+     * Return the type of the method handle call after spreading but before conversions.
+     */
+    private MethodType asSpreaderChecks(Class<?> arrayType, int arrayLength) {
         spreadArrayChecks(arrayType, arrayLength);
         int nargs = type().parameterCount();
         if (nargs < arrayLength || arrayLength < 0)
             throw newIllegalArgumentException("bad spread array length");
-        if (arrayType != Object[].class && arrayLength != 0) {
-            boolean sawProblem = false;
-            Class<?> arrayElement = arrayType.getComponentType();
-            for (int i = nargs - arrayLength; i < nargs; i++) {
-                if (!MethodType.canConvert(arrayElement, type().parameterType(i))) {
-                    sawProblem = true;
+        Class<?> arrayElement = arrayType.getComponentType();
+        MethodType mtype = type();
+        boolean match = true, fail = false;
+        for (int i = nargs - arrayLength; i < nargs; i++) {
+            Class<?> ptype = mtype.parameterType(i);
+            if (ptype != arrayElement) {
+                match = false;
+                if (!MethodType.canConvert(arrayElement, ptype)) {
+                    fail = true;
                     break;
                 }
             }
-            if (sawProblem) {
-                ArrayList<Class<?>> ptypes = new ArrayList<>(type().parameterList());
-                for (int i = nargs - arrayLength; i < nargs; i++) {
-                    ptypes.set(i, arrayElement);
-                }
-                // elicit an error:
-                this.asType(MethodType.methodType(type().returnType(), ptypes));
-            }
         }
+        if (match)  return mtype;
+        MethodType needType = mtype.asSpreaderType(arrayType, arrayLength);
+        if (!fail)  return needType;
+        // elicit an error:
+        this.asType(needType);
+        throw newInternalError("should not return", null);
     }
 
     private void spreadArrayChecks(Class<?> arrayType, int arrayLength) {
@@ -984,16 +995,31 @@
      */
     public MethodHandle asCollector(Class<?> arrayType, int arrayLength) {
         asCollectorChecks(arrayType, arrayLength);
-        int collectArgPos = type().parameterCount()-1;
-        MethodHandle target = this;
-        if (arrayType != type().parameterType(collectArgPos))
-            target = convertArguments(type().changeParameterType(collectArgPos, arrayType));
-        MethodHandle collector = ValueConversions.varargsArray(arrayType, arrayLength);
-        return MethodHandles.collectArguments(target, collectArgPos, collector);
+        int collectArgPos = type().parameterCount() - 1;
+        if (USE_LAMBDA_FORM_EDITOR) {
+            BoundMethodHandle mh = rebind();
+            MethodType resultType = type().asCollectorType(arrayType, arrayLength);
+            MethodHandle newArray = MethodHandleImpl.varargsArray(arrayType, arrayLength);
+            LambdaForm lform = mh.editor().collectArgumentArrayForm(1 + collectArgPos, newArray);
+            if (lform != null) {
+                return mh.copyWith(resultType, lform);
+            }
+            lform = mh.editor().collectArgumentsForm(1 + collectArgPos, newArray.type().basicType());
+            return mh.copyWithExtendL(resultType, lform, newArray);
+        } else {
+            MethodHandle target = this;
+            if (arrayType != type().parameterType(collectArgPos))
+                target = MethodHandleImpl.makePairwiseConvert(this, type().changeParameterType(collectArgPos, arrayType), true);
+            MethodHandle collector = MethodHandleImpl.varargsArray(arrayType, arrayLength);
+            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) {
@@ -1155,7 +1181,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;
@@ -1257,14 +1283,8 @@
      * @see MethodHandles#insertArguments
      */
     public MethodHandle bindTo(Object x) {
-        Class<?> ptype;
-        @SuppressWarnings("LocalVariableHidesMemberVariable")
-        MethodType type = type();
-        if (type.parameterCount() == 0 ||
-            (ptype = type.parameterType(0)).isPrimitive())
-            throw newIllegalArgumentException("no leading reference parameter", x);
-        x = ptype.cast(x);  // throw CCE if needed
-        return bindReceiver(x);
+        x = type.leadingReferenceParameter().cast(x);  // throw CCE if needed
+        return bindArgumentL(0, x);
     }
 
     /**
@@ -1284,14 +1304,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.
@@ -1300,22 +1323,42 @@
 
     // Other transforms to do:  convert, explicitCast, permute, drop, filter, fold, GWT, catch
 
+    BoundMethodHandle bindArgumentL(int pos, Object value) {
+        return rebind().bindArgumentL(pos, value);
+    }
+
     /*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) {
+    MethodHandle viewAsType(MethodType newType, boolean strict) {
         // No actual conversions, just a new view of the same method.
-        return MethodHandleImpl.makePairwiseConvert(this, newType, 0);
+        // Note that this operation must not produce a DirectMethodHandle,
+        // because retyped DMHs, like any transformed MHs,
+        // cannot be cracked into MethodHandleInfo.
+        assert viewAsTypeChecks(newType, strict);
+        BoundMethodHandle mh = rebind();
+        assert(!((MethodHandle)mh instanceof DirectMethodHandle));
+        return mh.copyWith(newType, mh.form);
+    }
+
+    /*non-public*/
+    boolean viewAsTypeChecks(MethodType newType, boolean strict) {
+        if (strict) {
+            assert(type().isViewableAs(newType, true))
+                : Arrays.asList(this, newType);
+        } else {
+            assert(type().basicType().isViewableAs(newType.basicType(), true))
+                : Arrays.asList(this, newType);
+        }
+        return true;
     }
 
     // Decoding
@@ -1336,9 +1379,15 @@
     }
 
     /*non-public*/
-    MethodHandle withInternalMemberName(MemberName member) {
+    MethodHandleImpl.Intrinsic intrinsicName() {
+        // no special intrinsic meaning to most MHs
+        return MethodHandleImpl.Intrinsic.NONE;
+    }
+
+    /*non-public*/
+    MethodHandle withInternalMemberName(MemberName member, boolean isInvokeSpecial) {
         if (member != null) {
-            return MethodHandleImpl.makeWrappedMember(this, member);
+            return MethodHandleImpl.makeWrappedMember(this, member, isInvokeSpecial);
         } else if (internalMemberName() == null) {
             // The required internaMemberName is null, and this MH (like most) doesn't have one.
             return this;
@@ -1362,7 +1411,7 @@
 
     /*non-public*/
     Object internalProperties() {
-        // Override to something like "/FOO=bar"
+        // Override to something to follow this.form, like "\n& FOO=bar"
         return "";
     }
 
@@ -1370,95 +1419,14 @@
     //// Sub-classes can override these default implementations.
     //// All these methods assume arguments are already validated.
 
-    /*non-public*/ MethodHandle convertArguments(MethodType newType) {
-        // Override this if it can be improved.
-        return MethodHandleImpl.makePairwiseConvert(this, newType, 1);
-    }
+    /*non-public*/
+    abstract MethodHandle copyWith(MethodType mt, LambdaForm lf);
 
-    /*non-public*/
-    MethodHandle bindArgument(int pos, BasicType basicType, Object value) {
-        // Override this if it can be improved.
-        return rebind().bindArgument(pos, basicType, value);
-    }
-
-    /*non-public*/
-    MethodHandle bindReceiver(Object receiver) {
-        // Override this if it can be improved.
-        return bindArgument(0, L_TYPE, receiver);
-    }
-
-    /*non-public*/
-    MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
-        // Override this if it can be improved.
-        return rebind().dropArguments(srcType, pos, drops);
-    }
-
-    /*non-public*/
-    MethodHandle permuteArguments(MethodType newType, int[] reorder) {
-        // Override this if it can be improved.
-        return rebind().permuteArguments(newType, reorder);
-    }
-
-    /*non-public*/
-    MethodHandle rebind() {
-        // Bind 'this' into a new invoker, of the known class BMH.
-        MethodType type2 = type();
-        LambdaForm form2 = reinvokerForm(this);
-        // form2 = lambda (bmh, arg*) { thismh = bmh[0]; invokeBasic(thismh, arg*) }
-        return BoundMethodHandle.bindSingle(type2, form2, this);
-    }
-
-    /*non-public*/
-    MethodHandle reinvokerTarget() {
-        throw new InternalError("not a reinvoker MH: "+this.getClass().getName()+": "+this);
-    }
-
-    /** Create a LF which simply reinvokes a target of the given basic type.
-     *  The target MH must override {@link #reinvokerTarget} to provide the target.
+    /** Require this method handle to be a BMH, or else replace it with a "wrapper" BMH.
+     *  Many transforms are implemented only for BMHs.
+     *  @return a behaviorally equivalent BMH
      */
-    static LambdaForm reinvokerForm(MethodHandle target) {
-        MethodType mtype = target.type().basicType();
-        LambdaForm reinvoker = mtype.form().cachedLambdaForm(MethodTypeForm.LF_REINVOKE);
-        if (reinvoker != null)  return reinvoker;
-        if (mtype.parameterSlotCount() >= MethodType.MAX_MH_ARITY)
-            return makeReinvokerForm(target.type(), target);  // cannot cache this
-        reinvoker = makeReinvokerForm(mtype, null);
-        return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_REINVOKE, reinvoker);
-    }
-    private static LambdaForm makeReinvokerForm(MethodType mtype, MethodHandle customTargetOrNull) {
-        boolean customized = (customTargetOrNull != null);
-        MethodHandle MH_invokeBasic = customized ? null : MethodHandles.basicInvoker(mtype);
-        final int THIS_BMH    = 0;
-        final int ARG_BASE    = 1;
-        final int ARG_LIMIT   = ARG_BASE + mtype.parameterCount();
-        int nameCursor = ARG_LIMIT;
-        final int NEXT_MH     = customized ? -1 : nameCursor++;
-        final int REINVOKE    = nameCursor++;
-        LambdaForm.Name[] names = LambdaForm.arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
-        Object[] targetArgs;
-        MethodHandle targetMH;
-        if (customized) {
-            targetArgs = Arrays.copyOfRange(names, ARG_BASE, ARG_LIMIT, Object[].class);
-            targetMH = customTargetOrNull;
-        } else {
-            names[NEXT_MH] = new LambdaForm.Name(NF_reinvokerTarget, names[THIS_BMH]);
-            targetArgs = Arrays.copyOfRange(names, THIS_BMH, ARG_LIMIT, Object[].class);
-            targetArgs[0] = names[NEXT_MH];  // overwrite this MH with next MH
-            targetMH = MethodHandles.basicInvoker(mtype);
-        }
-        names[REINVOKE] = new LambdaForm.Name(targetMH, targetArgs);
-        return new LambdaForm("BMH.reinvoke", ARG_LIMIT, names);
-    }
-
-    private static final LambdaForm.NamedFunction NF_reinvokerTarget;
-    static {
-        try {
-            NF_reinvokerTarget = new LambdaForm.NamedFunction(MethodHandle.class
-                .getDeclaredMethod("reinvokerTarget"));
-        } catch (ReflectiveOperationException ex) {
-            throw newInternalError(ex);
-        }
-    }
+    abstract BoundMethodHandle rebind();
 
     /**
      * Replace the old lambda form of this method handle with a new one.
@@ -1470,6 +1438,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/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -27,8 +27,10 @@
 
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashMap;
+import java.util.Collections;
+
 import sun.invoke.empty.Empty;
 import sun.invoke.util.ValueConversions;
 import sun.invoke.util.VerifyType;
@@ -44,6 +46,20 @@
  * @author jrose
  */
 /*non-public*/ abstract class MethodHandleImpl {
+    // Do not adjust this except for special platforms:
+    private static final int MAX_ARITY;
+    static {
+        final Object[] values = { 255 };
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            @Override
+            public Void run() {
+                values[0] = Integer.getInteger(MethodHandleImpl.class.getName()+".MAX_ARITY", 255);
+                return null;
+            }
+        });
+        MAX_ARITY = (Integer) values[0];
+    }
+
     /// Factory methods to create method handles:
 
     static void initStatics() {
@@ -52,27 +68,55 @@
     }
 
     static MethodHandle makeArrayElementAccessor(Class<?> arrayClass, boolean isSetter) {
+        if (arrayClass == Object[].class)
+            return (isSetter ? ArrayAccessor.OBJECT_ARRAY_SETTER : ArrayAccessor.OBJECT_ARRAY_GETTER);
         if (!arrayClass.isArray())
             throw newIllegalArgumentException("not an array: "+arrayClass);
-        MethodHandle accessor = ArrayAccessor.getAccessor(arrayClass, isSetter);
-        MethodType srcType = accessor.type().erase();
-        MethodType lambdaType = srcType.invokerType();
-        Name[] names = arguments(1, lambdaType);
-        Name[] args  = Arrays.copyOfRange(names, 1, 1 + srcType.parameterCount());
-        names[names.length - 1] = new Name(accessor.asType(srcType), (Object[]) args);
-        LambdaForm form = new LambdaForm("getElement", lambdaType.parameterCount(), names);
-        MethodHandle mh = SimpleMethodHandle.make(srcType, form);
-        if (ArrayAccessor.needCast(arrayClass)) {
-            mh = mh.bindTo(arrayClass);
+        MethodHandle[] cache = ArrayAccessor.TYPED_ACCESSORS.get(arrayClass);
+        int cacheIndex = (isSetter ? ArrayAccessor.SETTER_INDEX : ArrayAccessor.GETTER_INDEX);
+        MethodHandle mh = cache[cacheIndex];
+        if (mh != null)  return mh;
+        mh = ArrayAccessor.getAccessor(arrayClass, isSetter);
+        MethodType correctType = ArrayAccessor.correctType(arrayClass, isSetter);
+        if (mh.type() != correctType) {
+            assert(mh.type().parameterType(0) == Object[].class);
+            assert((isSetter ? mh.type().parameterType(2) : mh.type().returnType()) == Object.class);
+            assert(isSetter || correctType.parameterType(0).getComponentType() == correctType.returnType());
+            // safe to view non-strictly, because element type follows from array type
+            mh = mh.viewAsType(correctType, false);
         }
-        mh = mh.asType(ArrayAccessor.correctType(arrayClass, isSetter));
+        mh = makeIntrinsic(mh, (isSetter ? Intrinsic.ARRAY_STORE : Intrinsic.ARRAY_LOAD));
+        // Atomically update accessor cache.
+        synchronized(cache) {
+            if (cache[cacheIndex] == null) {
+                cache[cacheIndex] = mh;
+            } else {
+                // Throw away newly constructed accessor and use cached version.
+                mh = cache[cacheIndex];
+            }
+        }
         return mh;
     }
 
     static final class ArrayAccessor {
         /// Support for array element access
-        static final HashMap<Class<?>, MethodHandle> GETTER_CACHE = new HashMap<>();  // TODO use it
-        static final HashMap<Class<?>, MethodHandle> SETTER_CACHE = new HashMap<>();  // TODO use it
+        static final int GETTER_INDEX = 0, SETTER_INDEX = 1, INDEX_LIMIT = 2;
+        static final ClassValue<MethodHandle[]> TYPED_ACCESSORS
+                = new ClassValue<MethodHandle[]>() {
+                    @Override
+                    protected MethodHandle[] computeValue(Class<?> type) {
+                        return new MethodHandle[INDEX_LIMIT];
+                    }
+                };
+        static final MethodHandle OBJECT_ARRAY_GETTER, OBJECT_ARRAY_SETTER;
+        static {
+            MethodHandle[] cache = TYPED_ACCESSORS.get(Object[].class);
+            cache[GETTER_INDEX] = OBJECT_ARRAY_GETTER = makeIntrinsic(getAccessor(Object[].class, false), Intrinsic.ARRAY_LOAD);
+            cache[SETTER_INDEX] = OBJECT_ARRAY_SETTER = makeIntrinsic(getAccessor(Object[].class, true),  Intrinsic.ARRAY_STORE);
+
+            assert(InvokerBytecodeGenerator.isStaticallyInvocable(ArrayAccessor.OBJECT_ARRAY_GETTER.internalMemberName()));
+            assert(InvokerBytecodeGenerator.isStaticallyInvocable(ArrayAccessor.OBJECT_ARRAY_SETTER.internalMemberName()));
+        }
 
         static int     getElementI(int[]     a, int i)            { return              a[i]; }
         static long    getElementJ(long[]    a, int i)            { return              a[i]; }
@@ -94,45 +138,21 @@
         static void    setElementC(char[]    a, int i, char    x) {              a[i] = x; }
         static void    setElementL(Object[]  a, int i, Object  x) {              a[i] = x; }
 
-        static Object  getElementL(Class<?> arrayClass, Object[] a, int i)           { arrayClass.cast(a); return a[i]; }
-        static void    setElementL(Class<?> arrayClass, Object[] a, int i, Object x) { arrayClass.cast(a); a[i] = x; }
-
-        // Weakly typed wrappers of Object[] accessors:
-        static Object  getElementL(Object    a, int i)            { return getElementL((Object[])a, i); }
-        static void    setElementL(Object    a, int i, Object  x) {        setElementL((Object[]) a, i, x); }
-        static Object  getElementL(Object   arrayClass, Object a, int i)             { return getElementL((Class<?>) arrayClass, (Object[])a, i); }
-        static void    setElementL(Object   arrayClass, Object a, int i, Object x)   {        setElementL((Class<?>) arrayClass, (Object[])a, i, x); }
-
-        static boolean needCast(Class<?> arrayClass) {
-            Class<?> elemClass = arrayClass.getComponentType();
-            return !elemClass.isPrimitive() && elemClass != Object.class;
-        }
         static String name(Class<?> arrayClass, boolean isSetter) {
             Class<?> elemClass = arrayClass.getComponentType();
-            if (elemClass == null)  throw new IllegalArgumentException();
+            if (elemClass == null)  throw newIllegalArgumentException("not an array", arrayClass);
             return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(elemClass);
         }
-        static final boolean USE_WEAKLY_TYPED_ARRAY_ACCESSORS = false;  // FIXME: decide
         static MethodType type(Class<?> arrayClass, boolean isSetter) {
             Class<?> elemClass = arrayClass.getComponentType();
             Class<?> arrayArgClass = arrayClass;
             if (!elemClass.isPrimitive()) {
                 arrayArgClass = Object[].class;
-                if (USE_WEAKLY_TYPED_ARRAY_ACCESSORS)
-                    arrayArgClass = Object.class;
+                elemClass = Object.class;
             }
-            if (!needCast(arrayClass)) {
-                return !isSetter ?
+            return !isSetter ?
                     MethodType.methodType(elemClass,  arrayArgClass, int.class) :
                     MethodType.methodType(void.class, arrayArgClass, int.class, elemClass);
-            } else {
-                Class<?> classArgClass = Class.class;
-                if (USE_WEAKLY_TYPED_ARRAY_ACCESSORS)
-                    classArgClass = Object.class;
-                return !isSetter ?
-                    MethodType.methodType(Object.class, classArgClass, arrayArgClass, int.class) :
-                    MethodType.methodType(void.class,   classArgClass, arrayArgClass, int.class, Object.class);
-            }
         }
         static MethodType correctType(Class<?> arrayClass, boolean isSetter) {
             Class<?> elemClass = arrayClass.getComponentType();
@@ -159,40 +179,110 @@
      * integral widening or narrowing, and floating point widening or narrowing.
      * @param srcType required call type
      * @param target original method handle
-     * @param level which strength of conversion is allowed
+     * @param strict if true, only asType conversions are allowed; if false, explicitCastArguments conversions allowed
+     * @param monobox if true, unboxing conversions are assumed to be exactly typed (Integer to int only, not long or double)
      * @return an adapter to the original handle with the desired new type,
      *          or the original target if the types are already identical
      *          or null if the adaptation cannot be made
      */
-    static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType, int level) {
-        assert(level >= 0 && level <= 2);
+    static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType,
+                                            boolean strict, boolean monobox) {
         MethodType dstType = target.type();
         assert(dstType.parameterCount() == target.type().parameterCount());
         if (srcType == dstType)
             return target;
+        if (USE_LAMBDA_FORM_EDITOR) {
+            return makePairwiseConvertByEditor(target, srcType, strict, monobox);
+        } else {
+            return makePairwiseConvertIndirect(target, srcType, strict, monobox);
+        }
+    }
 
-        // Calculate extra arguments (temporaries) required in the names array.
-        // FIXME: Use an ArrayList<Name>.  Some arguments require more than one conversion step.
-        final int INARG_COUNT = srcType.parameterCount();
-        int conversions = 0;
-        boolean[] needConv = new boolean[1+INARG_COUNT];
-        for (int i = 0; i <= INARG_COUNT; i++) {
-            Class<?> src = (i == INARG_COUNT) ? dstType.returnType() : srcType.parameterType(i);
-            Class<?> dst = (i == INARG_COUNT) ? srcType.returnType() : dstType.parameterType(i);
-            if (!VerifyType.isNullConversion(src, dst) ||
-                level <= 1 && dst.isInterface() && !dst.isAssignableFrom(src)) {
-                needConv[i] = true;
-                conversions++;
+    private static int countNonNull(Object[] array) {
+        int count = 0;
+        for (Object x : array) {
+            if (x != null)  ++count;
+        }
+        return count;
+    }
+
+    static MethodHandle makePairwiseConvertByEditor(MethodHandle target, MethodType srcType,
+                                                    boolean strict, boolean monobox) {
+        Object[] convSpecs = computeValueConversions(srcType, target.type(), strict, monobox);
+        int convCount = countNonNull(convSpecs);
+        if (convCount == 0)
+            return target.viewAsType(srcType, strict);
+        MethodType basicSrcType = srcType.basicType();
+        MethodType midType = target.type().basicType();
+        BoundMethodHandle mh = target.rebind();
+        // FIXME: Reduce number of bindings when there is more than one Class conversion.
+        // FIXME: Reduce number of bindings when there are repeated conversions.
+        for (int i = 0; i < convSpecs.length-1; i++) {
+            Object convSpec = convSpecs[i];
+            if (convSpec == null)  continue;
+            MethodHandle fn;
+            if (convSpec instanceof Class) {
+                fn = Lazy.MH_castReference.bindTo(convSpec);
+            } else {
+                fn = (MethodHandle) convSpec;
+            }
+            Class<?> newType = basicSrcType.parameterType(i);
+            if (--convCount == 0)
+                midType = srcType;
+            else
+                midType = midType.changeParameterType(i, newType);
+            LambdaForm form2 = mh.editor().filterArgumentForm(1+i, BasicType.basicType(newType));
+            mh = mh.copyWithExtendL(midType, form2, fn);
+            mh = mh.rebind();
+        }
+        Object convSpec = convSpecs[convSpecs.length-1];
+        if (convSpec != null) {
+            MethodHandle fn;
+            if (convSpec instanceof Class) {
+                if (convSpec == void.class)
+                    fn = null;
+                else
+                    fn = Lazy.MH_castReference.bindTo(convSpec);
+            } else {
+                fn = (MethodHandle) convSpec;
+            }
+            Class<?> newType = basicSrcType.returnType();
+            assert(--convCount == 0);
+            midType = srcType;
+            if (fn != null) {
+                mh = mh.rebind();  // rebind if too complex
+                LambdaForm form2 = mh.editor().filterReturnForm(BasicType.basicType(newType), false);
+                mh = mh.copyWithExtendL(midType, form2, fn);
+            } else {
+                LambdaForm form2 = mh.editor().filterReturnForm(BasicType.basicType(newType), true);
+                mh = mh.copyWith(midType, form2);
             }
         }
-        boolean retConv = needConv[INARG_COUNT];
+        assert(convCount == 0);
+        assert(mh.type().equals(srcType));
+        return mh;
+    }
+
+    static MethodHandle makePairwiseConvertIndirect(MethodHandle target, MethodType srcType,
+                                                    boolean strict, boolean monobox) {
+        // Calculate extra arguments (temporaries) required in the names array.
+        Object[] convSpecs = computeValueConversions(srcType, target.type(), strict, monobox);
+        final int INARG_COUNT = srcType.parameterCount();
+        int convCount = countNonNull(convSpecs);
+        boolean retConv = (convSpecs[INARG_COUNT] != null);
+        boolean retVoid = srcType.returnType() == void.class;
+        if (retConv && retVoid) {
+            convCount -= 1;
+            retConv = false;
+        }
 
         final int IN_MH         = 0;
         final int INARG_BASE    = 1;
         final int INARG_LIMIT   = INARG_BASE + INARG_COUNT;
-        final int NAME_LIMIT    = INARG_LIMIT + conversions + 1;
+        final int NAME_LIMIT    = INARG_LIMIT + convCount + 1;
         final int RETURN_CONV   = (!retConv ? -1         : NAME_LIMIT - 1);
         final int OUT_CALL      = (!retConv ? NAME_LIMIT : RETURN_CONV) - 1;
+        final int RESULT        = (retVoid ? -1 : NAME_LIMIT - 1);
 
         // Now build a LambdaForm.
         MethodType lambdaType = srcType.basicType().invokerType();
@@ -204,59 +294,21 @@
 
         int nameCursor = INARG_LIMIT;
         for (int i = 0; i < INARG_COUNT; i++) {
-            Class<?> src = srcType.parameterType(i);
-            Class<?> dst = dstType.parameterType(i);
-
-            if (!needConv[i]) {
+            Object convSpec = convSpecs[i];
+            if (convSpec == null) {
                 // do nothing: difference is trivial
                 outArgs[OUTARG_BASE + i] = names[INARG_BASE + i];
                 continue;
             }
 
-            // Tricky case analysis follows.
-            MethodHandle fn = null;
-            if (src.isPrimitive()) {
-                if (dst.isPrimitive()) {
-                    fn = ValueConversions.convertPrimitive(src, dst);
-                } else {
-                    Wrapper w = Wrapper.forPrimitiveType(src);
-                    MethodHandle boxMethod = ValueConversions.box(w);
-                    if (dst == w.wrapperType())
-                        fn = boxMethod;
-                    else
-                        fn = boxMethod.asType(MethodType.methodType(dst, src));
-                }
+            Name conv;
+            if (convSpec instanceof Class) {
+                Class<?> convClass = (Class<?>) convSpec;
+                conv = new Name(Lazy.MH_castReference, convClass, names[INARG_BASE + i]);
             } else {
-                if (dst.isPrimitive()) {
-                    // Caller has boxed a primitive.  Unbox it for the target.
-                    Wrapper w = Wrapper.forPrimitiveType(dst);
-                    if (level == 0 || VerifyType.isNullConversion(src, w.wrapperType())) {
-                        fn = ValueConversions.unbox(dst);
-                    } else if (src == Object.class || !Wrapper.isWrapperType(src)) {
-                        // Examples:  Object->int, Number->int, Comparable->int; Byte->int, Character->int
-                        // must include additional conversions
-                        // src must be examined at runtime, to detect Byte, Character, etc.
-                        MethodHandle unboxMethod = (level == 1
-                                                    ? ValueConversions.unbox(dst)
-                                                    : ValueConversions.unboxCast(dst));
-                        fn = unboxMethod;
-                    } else {
-                        // Example: Byte->int
-                        // Do this by reformulating the problem to Byte->byte.
-                        Class<?> srcPrim = Wrapper.forWrapperType(src).primitiveType();
-                        MethodHandle unbox = ValueConversions.unbox(srcPrim);
-                        // Compose the two conversions.  FIXME:  should make two Names for this job
-                        fn = unbox.asType(MethodType.methodType(dst, src));
-                    }
-                } else {
-                    // Simple reference conversion.
-                    // Note:  Do not check for a class hierarchy relation
-                    // between src and dst.  In all cases a 'null' argument
-                    // will pass the cast conversion.
-                    fn = ValueConversions.cast(dst, Lazy.MH_castReference);
-                }
+                MethodHandle fn = (MethodHandle) convSpec;
+                conv = new Name(fn, names[INARG_BASE + i]);
             }
-            Name conv = new Name(fn, names[INARG_BASE + i]);
             assert(names[nameCursor] == null);
             names[nameCursor++] = conv;
             assert(outArgs[OUTARG_BASE + i] == null);
@@ -267,29 +319,29 @@
         assert(nameCursor == OUT_CALL);
         names[OUT_CALL] = new Name(target, outArgs);
 
-        if (RETURN_CONV < 0) {
+        Object convSpec = convSpecs[INARG_COUNT];
+        if (!retConv) {
             assert(OUT_CALL == names.length-1);
         } else {
-            Class<?> needReturn = srcType.returnType();
-            Class<?> haveReturn = dstType.returnType();
-            MethodHandle fn;
-            Object[] arg = { names[OUT_CALL] };
-            if (haveReturn == void.class) {
-                // synthesize a zero value for the given void
-                Object zero = Wrapper.forBasicType(needReturn).zero();
-                fn = MethodHandles.constant(needReturn, zero);
-                arg = new Object[0];  // don't pass names[OUT_CALL] to conversion
+            Name conv;
+            if (convSpec == void.class) {
+                conv = new Name(LambdaForm.constantZero(BasicType.basicType(srcType.returnType())));
+            } else if (convSpec instanceof Class) {
+                Class<?> convClass = (Class<?>) convSpec;
+                conv = new Name(Lazy.MH_castReference, convClass, names[OUT_CALL]);
             } else {
-                MethodHandle identity = MethodHandles.identity(needReturn);
-                MethodType needConversion = identity.type().changeParameterType(0, haveReturn);
-                fn = makePairwiseConvert(identity, needConversion, level);
+                MethodHandle fn = (MethodHandle) convSpec;
+                if (fn.type().parameterCount() == 0)
+                    conv = new Name(fn);  // don't pass retval to void conversion
+                else
+                    conv = new Name(fn, names[OUT_CALL]);
             }
             assert(names[RETURN_CONV] == null);
-            names[RETURN_CONV] = new Name(fn, arg);
+            names[RETURN_CONV] = conv;
             assert(RETURN_CONV == names.length-1);
         }
 
-        LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names);
+        LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names, RESULT);
         return SimpleMethodHandle.make(srcType, form);
     }
 
@@ -312,12 +364,79 @@
         return new ClassCastException("Cannot cast " + obj.getClass().getName() + " to " + t.getName());
     }
 
-    static MethodHandle makeReferenceIdentity(Class<?> refType) {
-        MethodType lambdaType = MethodType.genericMethodType(1).invokerType();
-        Name[] names = arguments(1, lambdaType);
-        names[names.length - 1] = new Name(ValueConversions.identity(), names[1]);
-        LambdaForm form = new LambdaForm("identity", lambdaType.parameterCount(), names);
-        return SimpleMethodHandle.make(MethodType.methodType(refType, refType), form);
+    static Object[] computeValueConversions(MethodType srcType, MethodType dstType,
+                                            boolean strict, boolean monobox) {
+        final int INARG_COUNT = srcType.parameterCount();
+        Object[] convSpecs = new Object[INARG_COUNT+1];
+        for (int i = 0; i <= INARG_COUNT; i++) {
+            boolean isRet = (i == INARG_COUNT);
+            Class<?> src = isRet ? dstType.returnType() : srcType.parameterType(i);
+            Class<?> dst = isRet ? srcType.returnType() : dstType.parameterType(i);
+            if (!VerifyType.isNullConversion(src, dst, /*keepInterfaces=*/ strict)) {
+                convSpecs[i] = valueConversion(src, dst, strict, monobox);
+            }
+        }
+        return convSpecs;
+    }
+    static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType,
+                                            boolean strict) {
+        return makePairwiseConvert(target, srcType, strict, /*monobox=*/ false);
+    }
+
+    /**
+     * Find a conversion function from the given source to the given destination.
+     * This conversion function will be used as a LF NamedFunction.
+     * Return a Class object if a simple cast is needed.
+     * Return void.class if void is involved.
+     */
+    static Object valueConversion(Class<?> src, Class<?> dst, boolean strict, boolean monobox) {
+        assert(!VerifyType.isNullConversion(src, dst, /*keepInterfaces=*/ strict));  // caller responsibility
+        if (dst == void.class)
+            return dst;
+        MethodHandle fn;
+        if (src.isPrimitive()) {
+            if (src == void.class) {
+                return void.class;  // caller must recognize this specially
+            } else if (dst.isPrimitive()) {
+                // Examples: int->byte, byte->int, boolean->int (!strict)
+                fn = ValueConversions.convertPrimitive(src, dst);
+            } else {
+                // Examples: int->Integer, boolean->Object, float->Number
+                Wrapper wsrc = Wrapper.forPrimitiveType(src);
+                fn = ValueConversions.boxExact(wsrc);
+                assert(fn.type().parameterType(0) == wsrc.primitiveType());
+                assert(fn.type().returnType() == wsrc.wrapperType());
+                if (!VerifyType.isNullConversion(wsrc.wrapperType(), dst, strict)) {
+                    // Corner case, such as int->Long, which will probably fail.
+                    MethodType mt = MethodType.methodType(dst, src);
+                    if (strict)
+                        fn = fn.asType(mt);
+                    else
+                        fn = MethodHandleImpl.makePairwiseConvert(fn, mt, /*strict=*/ false);
+                }
+            }
+        } else if (dst.isPrimitive()) {
+            Wrapper wdst = Wrapper.forPrimitiveType(dst);
+            if (monobox || src == wdst.wrapperType()) {
+                // Use a strongly-typed unboxer, if possible.
+                fn = ValueConversions.unboxExact(wdst, strict);
+            } else {
+                // Examples:  Object->int, Number->int, Comparable->int, Byte->int
+                // must include additional conversions
+                // src must be examined at runtime, to detect Byte, Character, etc.
+                fn = (strict
+                        ? ValueConversions.unboxWiden(wdst)
+                        : ValueConversions.unboxCast(wdst));
+            }
+        } else {
+            // Simple reference conversion.
+            // Note:  Do not check for a class hierarchy relation
+            // between src and dst.  In all cases a 'null' argument
+            // will pass the cast conversion.
+            return dst;
+        }
+        assert(fn.type().parameterCount() <= 1) : "pc"+Arrays.asList(src.getSimpleName(), dst.getSimpleName(), fn);
+        return fn;
     }
 
     static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) {
@@ -326,34 +445,46 @@
         if (type.parameterType(last) != arrayType)
             target = target.asType(type.changeParameterType(last, arrayType));
         target = target.asFixedArity();  // make sure this attribute is turned off
-        return new AsVarargsCollector(target, target.type(), arrayType);
+        return new AsVarargsCollector(target, arrayType);
     }
 
-    static class AsVarargsCollector extends MethodHandle {
+    private static final class AsVarargsCollector extends DelegatingMethodHandle {
         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));
+        AsVarargsCollector(MethodHandle target, Class<?> arrayType) {
+            this(target.type(), target, arrayType);
+        }
+        AsVarargsCollector(MethodType type, MethodHandle target, Class<?> arrayType) {
+            super(type, target);
             this.target = target;
             this.arrayType = arrayType;
             this.asCollectorCache = target.asCollector(arrayType, 0);
         }
 
-        @Override MethodHandle reinvokerTarget() { return target; }
-
         @Override
         public boolean isVarargsCollector() {
             return true;
         }
 
         @Override
+        protected MethodHandle getTarget() {
+            return target;
+        }
+
+        @Override
         public MethodHandle asFixedArity() {
             return target;
         }
 
         @Override
+        MethodHandle setVarargs(MemberName member) {
+            if (member.isVarargs())  return this;
+            return asFixedArity();
+        }
+
+        @Override
         public MethodHandle asTypeUncached(MethodType newType) {
             MethodType type = this.type();
             int collectArg = type.parameterCount() - 1;
@@ -381,54 +512,15 @@
         }
 
         @Override
-        MethodHandle setVarargs(MemberName member) {
-            if (member.isVarargs())  return this;
-            return asFixedArity();
-        }
-
-        @Override
-        MethodHandle viewAsType(MethodType newType) {
-            if (newType.lastParameterType() != type().lastParameterType())
-                throw new InternalError();
-            MethodHandle newTarget = asFixedArity().viewAsType(newType);
-            // put back the varargs bit:
-            return new AsVarargsCollector(newTarget, newType, arrayType);
-        }
-
-        @Override
-        MemberName internalMemberName() {
-            return asFixedArity().internalMemberName();
-        }
-        @Override
-        Class<?> internalCallerClass() {
-            return asFixedArity().internalCallerClass();
-        }
-
-        /*non-public*/
-        @Override
-        boolean isInvokeSpecial() {
-            return asFixedArity().isInvokeSpecial();
-        }
-
-
-        @Override
-        MethodHandle bindArgument(int pos, BasicType basicType, Object value) {
-            return asFixedArity().bindArgument(pos, basicType, value);
-        }
-
-        @Override
-        MethodHandle bindReceiver(Object receiver) {
-            return asFixedArity().bindReceiver(receiver);
-        }
-
-        @Override
-        MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
-            return asFixedArity().dropArguments(srcType, pos, drops);
-        }
-
-        @Override
-        MethodHandle permuteArguments(MethodType newType, int[] reorder) {
-            return asFixedArity().permuteArguments(newType, reorder);
+        boolean viewAsTypeChecks(MethodType newType, boolean strict) {
+            super.viewAsTypeChecks(newType, true);
+            if (strict) return true;
+            // extra assertion for non-strict checks:
+            assert (type().lastParameterType().getComponentType()
+                    .isAssignableFrom(
+                            newType.lastParameterType().getComponentType()))
+                    : Arrays.asList(this, newType);
+            return true;
         }
     }
 
@@ -499,32 +591,46 @@
      * Pre-initialized NamedFunctions for bootstrapping purposes.
      * Factored in an inner class to delay initialization until first usage.
      */
-    private static class Lazy {
+    static class Lazy {
         private static final Class<?> MHI = MethodHandleImpl.class;
 
         static final NamedFunction NF_checkSpreadArgument;
         static final NamedFunction NF_guardWithCatch;
-        static final NamedFunction NF_selectAlternative;
         static final NamedFunction NF_throwException;
 
         static final MethodHandle MH_castReference;
+        static final MethodHandle MH_selectAlternative;
+        static final MethodHandle MH_copyAsPrimitiveArray;
+        static final MethodHandle MH_fillNewTypedArray;
+        static final MethodHandle MH_fillNewArray;
+        static final MethodHandle MH_arrayIdentity;
 
         static {
             try {
                 NF_checkSpreadArgument = new NamedFunction(MHI.getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
                 NF_guardWithCatch      = new NamedFunction(MHI.getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class,
                                                                                  MethodHandle.class, Object[].class));
-                NF_selectAlternative   = new NamedFunction(MHI.getDeclaredMethod("selectAlternative", boolean.class, MethodHandle.class,
-                                                                                 MethodHandle.class));
                 NF_throwException      = new NamedFunction(MHI.getDeclaredMethod("throwException", Throwable.class));
 
                 NF_checkSpreadArgument.resolve();
                 NF_guardWithCatch.resolve();
-                NF_selectAlternative.resolve();
                 NF_throwException.resolve();
 
-                MethodType mt = MethodType.methodType(Object.class, Class.class, Object.class);
-                MH_castReference = IMPL_LOOKUP.findStatic(MHI, "castReference", mt);
+                MH_castReference        = IMPL_LOOKUP.findStatic(MHI, "castReference",
+                                            MethodType.methodType(Object.class, Class.class, Object.class));
+                MH_copyAsPrimitiveArray = IMPL_LOOKUP.findStatic(MHI, "copyAsPrimitiveArray",
+                                            MethodType.methodType(Object.class, Wrapper.class, Object[].class));
+                MH_arrayIdentity        = IMPL_LOOKUP.findStatic(MHI, "identity",
+                                            MethodType.methodType(Object[].class, Object[].class));
+                MH_fillNewArray         = IMPL_LOOKUP.findStatic(MHI, "fillNewArray",
+                                            MethodType.methodType(Object[].class, Integer.class, Object[].class));
+                MH_fillNewTypedArray    = IMPL_LOOKUP.findStatic(MHI, "fillNewTypedArray",
+                                            MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class));
+
+                MH_selectAlternative    = makeIntrinsic(
+                        IMPL_LOOKUP.findStatic(MHI, "selectAlternative",
+                                MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class)),
+                        Intrinsic.SELECT_ALTERNATIVE);
             } catch (ReflectiveOperationException ex) {
                 throw newInternalError(ex);
             }
@@ -595,29 +701,66 @@
     MethodHandle makeGuardWithTest(MethodHandle test,
                                    MethodHandle target,
                                    MethodHandle fallback) {
-        MethodType basicType = target.type().basicType();
-        MethodHandle invokeBasic = MethodHandles.basicInvoker(basicType);
-        int arity = basicType.parameterCount();
-        int extraNames = 3;
+        MethodType type = target.type();
+        assert(test.type().equals(type.changeReturnType(boolean.class)) && fallback.type().equals(type));
+        MethodType basicType = type.basicType();
+        LambdaForm form = makeGuardWithTestForm(basicType);
+        BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLL();
+        BoundMethodHandle mh;
+        try {
+            mh = (BoundMethodHandle)
+                    data.constructor().invokeBasic(type, form,
+                        (Object) test, (Object) target, (Object) fallback);
+        } catch (Throwable ex) {
+            throw uncaughtException(ex);
+        }
+        assert(mh.type() == type);
+        return mh;
+    }
+
+    static
+    LambdaForm makeGuardWithTestForm(MethodType basicType) {
+        LambdaForm lform = basicType.form().cachedLambdaForm(MethodTypeForm.LF_GWT);
+        if (lform != null)  return lform;
+        final int THIS_MH      = 0;  // the BMH_LLL
+        final int ARG_BASE     = 1;  // start of incoming arguments
+        final int ARG_LIMIT    = ARG_BASE + basicType.parameterCount();
+        int nameCursor = ARG_LIMIT;
+        final int GET_TEST     = nameCursor++;
+        final int GET_TARGET   = nameCursor++;
+        final int GET_FALLBACK = nameCursor++;
+        final int CALL_TEST    = nameCursor++;
+        final int SELECT_ALT   = nameCursor++;
+        final int CALL_TARGET  = nameCursor++;
+        assert(CALL_TARGET == SELECT_ALT+1);  // must be true to trigger IBG.emitSelectAlternative
+
         MethodType lambdaType = basicType.invokerType();
-        Name[] names = arguments(extraNames, lambdaType);
+        Name[] names = arguments(nameCursor - ARG_LIMIT, lambdaType);
 
-        Object[] testArgs   = Arrays.copyOfRange(names, 1, 1 + arity, Object[].class);
-        Object[] targetArgs = Arrays.copyOfRange(names, 0, 1 + arity, Object[].class);
+        BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLL();
+        names[THIS_MH] = names[THIS_MH].withConstraint(data);
+        names[GET_TEST]     = new Name(data.getterFunction(0), names[THIS_MH]);
+        names[GET_TARGET]   = new Name(data.getterFunction(1), names[THIS_MH]);
+        names[GET_FALLBACK] = new Name(data.getterFunction(2), names[THIS_MH]);
+
+        Object[] invokeArgs = Arrays.copyOfRange(names, 0, ARG_LIMIT, Object[].class);
 
         // call test
-        names[arity + 1] = new Name(test, testArgs);
+        MethodType testType = basicType.changeReturnType(boolean.class).basicType();
+        invokeArgs[0] = names[GET_TEST];
+        names[CALL_TEST] = new Name(testType, invokeArgs);
 
         // call selectAlternative
-        Object[] selectArgs = { names[arity + 1], target, fallback };
-        names[arity + 2] = new Name(Lazy.NF_selectAlternative, selectArgs);
-        targetArgs[0] = names[arity + 2];
+        names[SELECT_ALT] = new Name(Lazy.MH_selectAlternative, names[CALL_TEST],
+                                     names[GET_TARGET], names[GET_FALLBACK]);
 
         // call target or fallback
-        names[arity + 3] = new Name(new NamedFunction(invokeBasic), targetArgs);
+        invokeArgs[0] = names[SELECT_ALT];
+        names[CALL_TARGET] = new Name(basicType, invokeArgs);
 
-        LambdaForm form = new LambdaForm("guard", lambdaType.parameterCount(), names);
-        return SimpleMethodHandle.make(target.type(), form);
+        lform = new LambdaForm("guard", lambdaType.parameterCount(), names);
+
+        return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWT, lform);
     }
 
     /**
@@ -665,6 +808,7 @@
         Name[] names = arguments(nameCursor - ARG_LIMIT, lambdaType);
 
         BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLLL();
+        names[THIS_MH]          = names[THIS_MH].withConstraint(data);
         names[GET_TARGET]       = new Name(data.getterFunction(0), names[THIS_MH]);
         names[GET_CLASS]        = new Name(data.getterFunction(1), names[THIS_MH]);
         names[GET_CATCHER]      = new Name(data.getterFunction(2), names[THIS_MH]);
@@ -679,7 +823,7 @@
         Object[] args = new Object[invokeBasic.type().parameterCount()];
         args[0] = names[GET_COLLECT_ARGS];
         System.arraycopy(names, ARG_BASE, args, 1, ARG_LIMIT-ARG_BASE);
-        names[BOXED_ARGS] = new Name(new NamedFunction(invokeBasic), args);
+        names[BOXED_ARGS] = new Name(makeIntrinsic(invokeBasic, Intrinsic.GUARD_WITH_CATCH), args);
 
         // t_{i+1}:L=MethodHandleImpl.guardWithCatch(target:L,exType:L,catcher:L,t_{i}:L);
         Object[] gwcArgs = new Object[] {names[GET_TARGET], names[GET_CLASS], names[GET_CATCHER], names[BOXED_ARGS]};
@@ -688,7 +832,7 @@
         // t_{i+2}:I=MethodHandle.invokeBasic(unbox:L,t_{i+1}:L);
         MethodHandle invokeBasicUnbox = MethodHandles.basicInvoker(MethodType.methodType(basicType.rtype(), Object.class));
         Object[] unboxArgs  = new Object[] {names[GET_UNBOX_RESULT], names[TRY_CATCH]};
-        names[UNBOX_RESULT] = new Name(new NamedFunction(invokeBasicUnbox), unboxArgs);
+        names[UNBOX_RESULT] = new Name(invokeBasicUnbox, unboxArgs);
 
         lform = new LambdaForm("guardWithCatch", lambdaType.parameterCount(), names);
 
@@ -705,22 +849,27 @@
         // Prepare auxiliary method handles used during LambdaForm interpretation.
         // Box arguments and wrap them into Object[]: ValueConversions.array().
         MethodType varargsType = type.changeReturnType(Object[].class);
-        MethodHandle collectArgs = ValueConversions.varargsArray(type.parameterCount())
-                                                   .asType(varargsType);
+        MethodHandle collectArgs = varargsArray(type.parameterCount()).asType(varargsType);
         // Result unboxing: ValueConversions.unbox() OR ValueConversions.identity() OR ValueConversions.ignore().
         MethodHandle unboxResult;
-        if (type.returnType().isPrimitive()) {
-            unboxResult = ValueConversions.unbox(type.returnType());
+        Class<?> rtype = type.returnType();
+        if (rtype.isPrimitive()) {
+            if (rtype == void.class) {
+                unboxResult = ValueConversions.ignore();
+            } else {
+                Wrapper w = Wrapper.forPrimitiveType(type.returnType());
+                unboxResult = ValueConversions.unboxExact(w);
+            }
         } else {
-            unboxResult = ValueConversions.identity();
+            unboxResult = MethodHandles.identity(Object.class);
         }
 
         BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLLL();
         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);
         }
@@ -758,9 +907,11 @@
         assert(Throwable.class.isAssignableFrom(type.parameterType(0)));
         int arity = type.parameterCount();
         if (arity > 1) {
-            return throwException(type.dropParameterTypes(1, arity)).dropArguments(type, 1, arity-1);
+            MethodHandle mh = throwException(type.dropParameterTypes(1, arity));
+            mh = MethodHandles.dropArguments(mh, 1, type.parameterList().subList(1, arity));
+            return mh;
         }
-        return makePairwiseConvert(Lazy.NF_throwException.resolvedHandle(), type, 2);
+        return makePairwiseConvert(Lazy.NF_throwException.resolvedHandle(), type, false, true);
     }
 
     static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
@@ -782,7 +933,7 @@
         mh = mh.bindTo(new UnsupportedOperationException("cannot reflectively invoke MethodHandle"));
         if (!method.getInvocationType().equals(mh.type()))
             throw new InternalError(method.toString());
-        mh = mh.withInternalMemberName(method);
+        mh = mh.withInternalMemberName(method, false);
         mh = mh.asVarargsCollector(Object[].class);
         assert(method.isVarargs());
         FAKE_METHOD_HANDLE_INVOKE[idx] = mh;
@@ -819,7 +970,7 @@
             MethodHandle vamh = prepareForInvoker(mh);
             // Cache the result of makeInjectedInvoker once per argument class.
             MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass);
-            return restoreToType(bccInvoker.bindTo(vamh), mh.type(), mh.internalMemberName(), hostClass);
+            return restoreToType(bccInvoker.bindTo(vamh), mh, hostClass);
         }
 
         private static MethodHandle makeInjectedInvoker(Class<?> hostClass) {
@@ -874,12 +1025,14 @@
         }
 
         // Undo the adapter effect of prepareForInvoker:
-        private static MethodHandle restoreToType(MethodHandle vamh, MethodType type,
-                                                  MemberName member,
+        private static MethodHandle restoreToType(MethodHandle vamh,
+                                                  MethodHandle original,
                                                   Class<?> hostClass) {
+            MethodType type = original.type();
             MethodHandle mh = vamh.asCollector(Object[].class, type.parameterCount());
+            MemberName member = original.internalMemberName();
             mh = mh.asType(type);
-            mh = new WrappedMember(mh, type, member, hostClass);
+            mh = new WrappedMember(mh, type, member, original.isInvokeSpecial(), hostClass);
             return mh;
         }
 
@@ -945,29 +1098,23 @@
 
 
     /** This subclass allows a wrapped method handle to be re-associated with an arbitrary member name. */
-    static class WrappedMember extends MethodHandle {
+    private static final class WrappedMember extends DelegatingMethodHandle {
         private final MethodHandle target;
         private final MemberName member;
         private final Class<?> callerClass;
+        private final boolean isInvokeSpecial;
 
-        private WrappedMember(MethodHandle target, MethodType type, MemberName member, Class<?> callerClass) {
-            super(type, reinvokerForm(target));
+        private WrappedMember(MethodHandle target, MethodType type,
+                              MemberName member, boolean isInvokeSpecial,
+                              Class<?> callerClass) {
+            super(type, target);
             this.target = target;
             this.member = member;
             this.callerClass = callerClass;
+            this.isInvokeSpecial = isInvokeSpecial;
         }
 
         @Override
-        MethodHandle reinvokerTarget() {
-            return target;
-        }
-        @Override
-        public MethodHandle asTypeUncached(MethodType newType) {
-            // This MH is an alias for target, except for the MemberName
-            // Drop the MemberName if there is any conversion.
-            return asTypeCache = target.asType(newType);
-        }
-        @Override
         MemberName internalMemberName() {
             return member;
         }
@@ -977,18 +1124,367 @@
         }
         @Override
         boolean isInvokeSpecial() {
-            return target.isInvokeSpecial();
+            return isInvokeSpecial;
         }
         @Override
-        MethodHandle viewAsType(MethodType newType) {
-            return new WrappedMember(target, newType, member, callerClass);
+        protected MethodHandle getTarget() {
+            return target;
+        }
+        @Override
+        public MethodHandle asTypeUncached(MethodType newType) {
+            // This MH is an alias for target, except for the MemberName
+            // Drop the MemberName if there is any conversion.
+            return asTypeCache = target.asType(newType);
         }
     }
 
-    static MethodHandle makeWrappedMember(MethodHandle target, MemberName member) {
-        if (member.equals(target.internalMemberName()))
+    static MethodHandle makeWrappedMember(MethodHandle target, MemberName member, boolean isInvokeSpecial) {
+        if (member.equals(target.internalMemberName()) && isInvokeSpecial == target.isInvokeSpecial())
             return target;
-        return new WrappedMember(target, target.type(), member, null);
+        return new WrappedMember(target, target.type(), member, isInvokeSpecial, null);
     }
 
+    /** Intrinsic IDs */
+    /*non-public*/
+    enum Intrinsic {
+        SELECT_ALTERNATIVE,
+        GUARD_WITH_CATCH,
+        NEW_ARRAY,
+        ARRAY_LOAD,
+        ARRAY_STORE,
+        IDENTITY,
+        ZERO,
+        NONE // no intrinsic associated
+    }
+
+    /** Mark arbitrary method handle as intrinsic.
+     * InvokerBytecodeGenerator uses this info to produce more efficient bytecode shape. */
+    private static final class IntrinsicMethodHandle extends DelegatingMethodHandle {
+        private final MethodHandle target;
+        private final Intrinsic intrinsicName;
+
+        IntrinsicMethodHandle(MethodHandle target, Intrinsic intrinsicName) {
+            super(target.type(), target);
+            this.target = target;
+            this.intrinsicName = intrinsicName;
+        }
+
+        @Override
+        protected MethodHandle getTarget() {
+            return target;
+        }
+
+        @Override
+        Intrinsic intrinsicName() {
+            return intrinsicName;
+        }
+
+        @Override
+        public MethodHandle asTypeUncached(MethodType newType) {
+            // This MH is an alias for target, except for the intrinsic name
+            // Drop the name if there is any conversion.
+            return asTypeCache = target.asType(newType);
+        }
+
+        @Override
+        String internalProperties() {
+            return super.internalProperties() +
+                    "\n& Intrinsic="+intrinsicName;
+        }
+
+        @Override
+        public MethodHandle asCollector(Class<?> arrayType, int arrayLength) {
+            if (intrinsicName == Intrinsic.IDENTITY) {
+                MethodType resultType = type().asCollectorType(arrayType, arrayLength);
+                MethodHandle newArray = MethodHandleImpl.varargsArray(arrayType, arrayLength);
+                return newArray.asType(resultType);
+            }
+            return super.asCollector(arrayType, arrayLength);
+        }
+    }
+
+    static MethodHandle makeIntrinsic(MethodHandle target, Intrinsic intrinsicName) {
+        if (intrinsicName == target.intrinsicName())
+            return target;
+        return new IntrinsicMethodHandle(target, intrinsicName);
+    }
+
+    static MethodHandle makeIntrinsic(MethodType type, LambdaForm form, Intrinsic intrinsicName) {
+        return new IntrinsicMethodHandle(SimpleMethodHandle.make(type, form), intrinsicName);
+    }
+
+    /// Collection of multiple arguments.
+
+    private static MethodHandle findCollector(String name, int nargs, Class<?> rtype, Class<?>... ptypes) {
+        MethodType type = MethodType.genericMethodType(nargs)
+                .changeReturnType(rtype)
+                .insertParameterTypes(0, ptypes);
+        try {
+            return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, name, type);
+        } catch (ReflectiveOperationException ex) {
+            return null;
+        }
+    }
+
+    private static final Object[] NO_ARGS_ARRAY = {};
+    private static Object[] makeArray(Object... args) { return args; }
+    private static Object[] array() { return NO_ARGS_ARRAY; }
+    private static Object[] array(Object a0)
+                { return makeArray(a0); }
+    private static Object[] array(Object a0, Object a1)
+                { return makeArray(a0, a1); }
+    private static Object[] array(Object a0, Object a1, Object a2)
+                { return makeArray(a0, a1, a2); }
+    private static Object[] array(Object a0, Object a1, Object a2, Object a3)
+                { return makeArray(a0, a1, a2, a3); }
+    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
+                                  Object a4)
+                { return makeArray(a0, a1, a2, a3, a4); }
+    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
+                                  Object a4, Object a5)
+                { return makeArray(a0, a1, a2, a3, a4, a5); }
+    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
+                                  Object a4, Object a5, Object a6)
+                { return makeArray(a0, a1, a2, a3, a4, a5, a6); }
+    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
+                                  Object a4, Object a5, Object a6, Object a7)
+                { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); }
+    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
+                                  Object a4, Object a5, Object a6, Object a7,
+                                  Object a8)
+                { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
+    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
+                                  Object a4, Object a5, Object a6, Object a7,
+                                  Object a8, Object a9)
+                { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
+    private static MethodHandle[] makeArrays() {
+        ArrayList<MethodHandle> mhs = new ArrayList<>();
+        for (;;) {
+            MethodHandle mh = findCollector("array", mhs.size(), Object[].class);
+            if (mh == null)  break;
+            mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY);
+            mhs.add(mh);
+        }
+        assert(mhs.size() == 11);  // current number of methods
+        return mhs.toArray(new MethodHandle[MAX_ARITY+1]);
+    }
+    private static final MethodHandle[] ARRAYS = makeArrays();
+
+    // filling versions of the above:
+    // using Integer len instead of int len and no varargs to avoid bootstrapping problems
+    private static Object[] fillNewArray(Integer len, Object[] /*not ...*/ args) {
+        Object[] a = new Object[len];
+        fillWithArguments(a, 0, args);
+        return a;
+    }
+    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;
+    }
+    private static void fillWithArguments(Object[] a, int pos, Object... args) {
+        System.arraycopy(args, 0, a, pos, args.length);
+    }
+    // using Integer pos instead of int pos to avoid bootstrapping problems
+    private static Object[] fillArray(Integer pos, Object[] a, Object a0)
+                { fillWithArguments(a, pos, a0); return a; }
+    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1)
+                { fillWithArguments(a, pos, a0, a1); return a; }
+    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2)
+                { fillWithArguments(a, pos, a0, a1, a2); return a; }
+    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3)
+                { fillWithArguments(a, pos, a0, a1, a2, a3); return a; }
+    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
+                                  Object a4)
+                { fillWithArguments(a, pos, a0, a1, a2, a3, a4); return a; }
+    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
+                                  Object a4, Object a5)
+                { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5); return a; }
+    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
+                                  Object a4, Object a5, Object a6)
+                { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6); return a; }
+    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
+                                  Object a4, Object a5, Object a6, Object a7)
+                { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7); return a; }
+    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
+                                  Object a4, Object a5, Object a6, Object a7,
+                                  Object a8)
+                { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8); return a; }
+    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
+                                  Object a4, Object a5, Object a6, Object a7,
+                                  Object a8, Object a9)
+                { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); return a; }
+    private static MethodHandle[] makeFillArrays() {
+        ArrayList<MethodHandle> mhs = new ArrayList<>();
+        mhs.add(null);  // there is no empty fill; at least a0 is required
+        for (;;) {
+            MethodHandle mh = findCollector("fillArray", mhs.size(), Object[].class, Integer.class, Object[].class);
+            if (mh == null)  break;
+            mhs.add(mh);
+        }
+        assert(mhs.size() == 11);  // current number of methods
+        return mhs.toArray(new MethodHandle[0]);
+    }
+    private static final MethodHandle[] FILL_ARRAYS = makeFillArrays();
+
+    private static Object copyAsPrimitiveArray(Wrapper w, Object... boxes) {
+        Object a = w.makeArray(boxes.length);
+        w.copyArrayUnboxing(boxes, 0, a, 0, boxes.length);
+        return a;
+    }
+
+    /** Return a method handle that takes the indicated number of Object
+     *  arguments and returns an Object array of them, as if for varargs.
+     */
+    static MethodHandle varargsArray(int nargs) {
+        MethodHandle mh = ARRAYS[nargs];
+        if (mh != null)  return mh;
+        mh = findCollector("array", nargs, Object[].class);
+        if (mh != null)  mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY);
+        if (mh != null)  return ARRAYS[nargs] = mh;
+        mh = buildVarargsArray(Lazy.MH_fillNewArray, Lazy.MH_arrayIdentity, nargs);
+        assert(assertCorrectArity(mh, nargs));
+        mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY);
+        return ARRAYS[nargs] = mh;
+    }
+
+    private static boolean assertCorrectArity(MethodHandle mh, int arity) {
+        assert(mh.type().parameterCount() == arity) : "arity != "+arity+": "+mh;
+        return true;
+    }
+
+    // Array identity function (used as Lazy.MH_arrayIdentity).
+    static <T> T[] identity(T[] x) {
+        return x;
+    }
+
+    private static MethodHandle buildVarargsArray(MethodHandle newArray, MethodHandle finisher, int nargs) {
+        // Build up the result mh as a sequence of fills like this:
+        //   finisher(fill(fill(newArrayWA(23,x1..x10),10,x11..x20),20,x21..x23))
+        // The various fill(_,10*I,___*[J]) are reusable.
+        int leftLen = Math.min(nargs, LEFT_ARGS);  // absorb some arguments immediately
+        int rightLen = nargs - leftLen;
+        MethodHandle leftCollector = newArray.bindTo(nargs);
+        leftCollector = leftCollector.asCollector(Object[].class, leftLen);
+        MethodHandle mh = finisher;
+        if (rightLen > 0) {
+            MethodHandle rightFiller = fillToRight(LEFT_ARGS + rightLen);
+            if (mh == Lazy.MH_arrayIdentity)
+                mh = rightFiller;
+            else
+                mh = MethodHandles.collectArguments(mh, 0, rightFiller);
+        }
+        if (mh == Lazy.MH_arrayIdentity)
+            mh = leftCollector;
+        else
+            mh = MethodHandles.collectArguments(mh, 0, leftCollector);
+        return mh;
+    }
+
+    private static final int LEFT_ARGS = (FILL_ARRAYS.length - 1);
+    private static final MethodHandle[] FILL_ARRAY_TO_RIGHT = new MethodHandle[MAX_ARITY+1];
+    /** fill_array_to_right(N).invoke(a, argL..arg[N-1])
+     *  fills a[L]..a[N-1] with corresponding arguments,
+     *  and then returns a.  The value L is a global constant (LEFT_ARGS).
+     */
+    private static MethodHandle fillToRight(int nargs) {
+        MethodHandle filler = FILL_ARRAY_TO_RIGHT[nargs];
+        if (filler != null)  return filler;
+        filler = buildFiller(nargs);
+        assert(assertCorrectArity(filler, nargs - LEFT_ARGS + 1));
+        return FILL_ARRAY_TO_RIGHT[nargs] = filler;
+    }
+    private static MethodHandle buildFiller(int nargs) {
+        if (nargs <= LEFT_ARGS)
+            return Lazy.MH_arrayIdentity;  // no args to fill; return the array unchanged
+        // we need room for both mh and a in mh.invoke(a, arg*[nargs])
+        final int CHUNK = LEFT_ARGS;
+        int rightLen = nargs % CHUNK;
+        int midLen = nargs - rightLen;
+        if (rightLen == 0) {
+            midLen = nargs - (rightLen = CHUNK);
+            if (FILL_ARRAY_TO_RIGHT[midLen] == null) {
+                // build some precursors from left to right
+                for (int j = LEFT_ARGS % CHUNK; j < midLen; j += CHUNK)
+                    if (j > LEFT_ARGS)  fillToRight(j);
+            }
+        }
+        if (midLen < LEFT_ARGS) rightLen = nargs - (midLen = LEFT_ARGS);
+        assert(rightLen > 0);
+        MethodHandle midFill = fillToRight(midLen);  // recursive fill
+        MethodHandle rightFill = FILL_ARRAYS[rightLen].bindTo(midLen);  // [midLen..nargs-1]
+        assert(midFill.type().parameterCount()   == 1 + midLen - LEFT_ARGS);
+        assert(rightFill.type().parameterCount() == 1 + rightLen);
+
+        // Combine the two fills:
+        //   right(mid(a, x10..x19), x20..x23)
+        // The final product will look like this:
+        //   right(mid(newArrayLeft(24, x0..x9), x10..x19), x20..x23)
+        if (midLen == LEFT_ARGS)
+            return rightFill;
+        else
+            return MethodHandles.collectArguments(rightFill, 0, midFill);
+    }
+
+    // Type-polymorphic version of varargs maker.
+    private static final ClassValue<MethodHandle[]> TYPED_COLLECTORS
+        = new ClassValue<MethodHandle[]>() {
+            @Override
+            protected MethodHandle[] computeValue(Class<?> type) {
+                return new MethodHandle[256];
+            }
+    };
+
+    static final int MAX_JVM_ARITY = 255;  // limit imposed by the JVM
+
+    /** Return a method handle that takes the indicated number of
+     *  typed arguments and returns an array of them.
+     *  The type argument is the array type.
+     */
+    static MethodHandle varargsArray(Class<?> arrayType, int nargs) {
+        Class<?> elemType = arrayType.getComponentType();
+        if (elemType == null)  throw new IllegalArgumentException("not an array: "+arrayType);
+        // FIXME: Need more special casing and caching here.
+        if (nargs >= MAX_JVM_ARITY/2 - 1) {
+            int slots = nargs;
+            final int MAX_ARRAY_SLOTS = MAX_JVM_ARITY - 1;  // 1 for receiver MH
+            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);
+        }
+        if (elemType == Object.class)
+            return varargsArray(nargs);
+        // other cases:  primitive arrays, subtypes of Object[]
+        MethodHandle cache[] = TYPED_COLLECTORS.get(elemType);
+        MethodHandle mh = nargs < cache.length ? cache[nargs] : null;
+        if (mh != null)  return mh;
+        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 {
+            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; // must be weakly typed
+            mh = buildVarargsArray(builder, producer, nargs);
+        }
+        mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)));
+        mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY);
+        assert(assertCorrectArity(mh, nargs));
+        if (nargs < cache.length)
+            cache[nargs] = mh;
+        return mh;
+    }
+
+    private static MethodHandle buildArrayProducer(Class<?> arrayType) {
+        Class<?> elemType = arrayType.getComponentType();
+        assert(elemType.isPrimitive());
+        return Lazy.MH_copyAsPrimitiveArray.bindTo(Wrapper.forPrimitiveType(elemType));
+    }
 }
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java	Fri Sep 12 10:33:32 2014 -0700
@@ -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/src/java.base/share/classes/java/lang/invoke/MethodHandleStatics.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleStatics.java	Fri Sep 12 10:33:32 2014 -0700
@@ -45,16 +45,21 @@
     static final boolean DUMP_CLASS_FILES;
     static final boolean TRACE_INTERPRETER;
     static final boolean TRACE_METHOD_LINKAGE;
-    static final Integer COMPILE_THRESHOLD;
+    static final boolean USE_LAMBDA_FORM_EDITOR;
+    static final int COMPILE_THRESHOLD;
+    static final int PROFILE_LEVEL;
+
     static {
-        final Object[] values = { false, false, false, false, null };
+        final Object[] values = { false, false, false, false, false, null, null };
         AccessController.doPrivileged(new PrivilegedAction<Void>() {
                 public Void run() {
                     values[0] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
                     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] = Boolean.getBoolean("java.lang.invoke.MethodHandle.USE_LF_EDITOR");
+                    values[5] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD", 30);
+                    values[6] = Integer.getInteger("java.lang.invoke.MethodHandle.PROFILE_LEVEL", 0);
                     return null;
                 }
             });
@@ -62,7 +67,9 @@
         DUMP_CLASS_FILES          = (Boolean) values[1];
         TRACE_INTERPRETER         = (Boolean) values[2];
         TRACE_METHOD_LINKAGE      = (Boolean) values[3];
-        COMPILE_THRESHOLD         = (Integer) values[4];
+        USE_LAMBDA_FORM_EDITOR    = (Boolean) values[4];
+        COMPILE_THRESHOLD         = (Integer) values[5];
+        PROFILE_LEVEL             = (Integer) values[6];
     }
 
     /** Tell if any of the debugging switches are turned on.
@@ -127,7 +134,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/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Fri Sep 12 10:33:32 2014 -0700
@@ -26,8 +26,8 @@
 package java.lang.invoke;
 
 import java.lang.reflect.*;
+import java.util.BitSet;
 import java.util.List;
-import java.util.ArrayList;
 import java.util.Arrays;
 
 import sun.invoke.util.ValueConversions;
@@ -40,6 +40,7 @@
 import java.lang.invoke.LambdaForm.BasicType;
 import static java.lang.invoke.LambdaForm.BasicType.*;
 import static java.lang.invoke.MethodHandleStatics.*;
+import static java.lang.invoke.MethodHandleImpl.Intrinsic;
 import static java.lang.invoke.MethodHandleNatives.Constants.*;
 import java.util.concurrent.ConcurrentHashMap;
 
@@ -862,6 +863,8 @@
                 return invoker(type);
             if ("invokeExact".equals(name))
                 return exactInvoker(type);
+            if ("invokeBasic".equals(name))
+                return basicInvoker(type);
             assert(!MemberName.isMethodHandleInvokeName(name));
             return null;
         }
@@ -1141,7 +1144,7 @@
             Class<? extends Object> refc = receiver.getClass(); // may get NPE
             MemberName method = resolveOrFail(REF_invokeSpecial, refc, name, type);
             MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method, findBoundCallerClass(method));
-            return mh.bindReceiver(receiver).setVarargs(method);
+            return mh.bindArgumentL(0, receiver).setVarargs(method);
         }
 
         /**
@@ -1576,7 +1579,7 @@
                 return false;
             return true;
         }
-        private MethodHandle restrictReceiver(MemberName method, MethodHandle mh, Class<?> caller) throws IllegalAccessException {
+        private MethodHandle restrictReceiver(MemberName method, DirectMethodHandle mh, Class<?> caller) throws IllegalAccessException {
             assert(!method.isStatic());
             // receiver type of mh is too wide; narrow to caller
             if (!method.getDeclaringClass().isAssignableFrom(caller)) {
@@ -1585,7 +1588,9 @@
             MethodType rawType = mh.type();
             if (rawType.parameterType(0) == caller)  return mh;
             MethodType narrowType = rawType.changeParameterType(0, caller);
-            return mh.viewAsType(narrowType);
+            assert(!mh.isVarargsCollector());  // viewAsType will lose varargs-ness
+            assert(mh.viewAsTypeChecks(narrowType, true));
+            return mh.copyWith(narrowType, mh.form);
         }
 
         /** Check access and get the requested method. */
@@ -1647,15 +1652,17 @@
                 checkMethod(refKind, refc, method);
             }
 
-            MethodHandle mh = DirectMethodHandle.make(refKind, refc, method);
-            mh = maybeBindCaller(method, mh, callerClass);
-            mh = mh.setVarargs(method);
+            DirectMethodHandle dmh = DirectMethodHandle.make(refKind, refc, method);
+            MethodHandle mh = dmh;
             // Optionally narrow the receiver argument to refc using restrictReceiver.
             if (doRestrict &&
                    (refKind == REF_invokeSpecial ||
                        (MethodHandleNatives.refKindHasReceiver(refKind) &&
-                           restrictProtectedReceiver(method))))
-                mh = restrictReceiver(method, mh, lookupClass());
+                           restrictProtectedReceiver(method)))) {
+                mh = restrictReceiver(method, dmh, lookupClass());
+            }
+            mh = maybeBindCaller(method, mh, callerClass);
+            mh = mh.setVarargs(method);
             return mh;
         }
         private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh,
@@ -1687,12 +1694,12 @@
             // Optionally check with the security manager; this isn't needed for unreflect* calls.
             if (checkSecurity)
                 checkSecurityManager(refc, field);
-            MethodHandle mh = DirectMethodHandle.make(refc, field);
+            DirectMethodHandle dmh = DirectMethodHandle.make(refc, field);
             boolean doRestrict = (MethodHandleNatives.refKindHasReceiver(refKind) &&
                                     restrictProtectedReceiver(field));
             if (doRestrict)
-                mh = restrictReceiver(field, mh, lookupClass());
-            return mh;
+                return restrictReceiver(field, dmh, lookupClass());
+            return dmh;
         }
         /** Check access and get the requested constructor. */
         private MethodHandle getDirectConstructor(Class<?> refc, MemberName ctor) throws IllegalAccessException {
@@ -1879,7 +1886,8 @@
     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);
+        type = type.asSpreaderType(Object[].class, type.parameterCount() - leadingArgCount);
         return type.invokers().spreadInvoker(leadingArgCount);
     }
 
@@ -1959,12 +1967,12 @@
      */
     static public
     MethodHandle invoker(MethodType type) {
-        return type.invokers().generalInvoker();
+        return type.invokers().genericInvoker();
     }
 
     static /*non-public*/
     MethodHandle basicInvoker(MethodType type) {
-        return type.form().basicInvoker();
+        return type.invokers().basicInvoker();
     }
 
      /// method handle modification (creation from other method handles)
@@ -2015,10 +2023,13 @@
      */
     public static
     MethodHandle explicitCastArguments(MethodHandle target, MethodType newType) {
-        if (!target.type().isCastableTo(newType)) {
-            throw new WrongMethodTypeException("cannot explicitly cast "+target+" to "+newType);
+        MethodType oldType = target.type();
+        // use the asTypeCache when possible:
+        if (oldType == newType)  return target;
+        if (oldType.explicitCastEquivalentToAsType(newType)) {
+            return target.asType(newType);
         }
-        return MethodHandleImpl.makePairwiseConvert(target, newType, 2);
+        return MethodHandleImpl.makePairwiseConvert(target, newType, false);
     }
 
     /**
@@ -2082,12 +2093,165 @@
      */
     public static
     MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder) {
-        reorder = reorder.clone();
-        checkReorder(reorder, newType, target.type());
-        return target.permuteArguments(newType, reorder);
+        reorder = reorder.clone();  // get a private copy
+        MethodType oldType = target.type();
+        permuteArgumentChecks(reorder, newType, oldType);
+        if (USE_LAMBDA_FORM_EDITOR) {
+            // first detect dropped arguments and handle them separately
+            int[] originalReorder = reorder;
+            BoundMethodHandle result = target.rebind();
+            LambdaForm form = result.form;
+            int newArity = newType.parameterCount();
+            // Normalize the reordering into a real permutation,
+            // by removing duplicates and adding dropped elements.
+            // This somewhat improves lambda form caching, as well
+            // as simplifying the transform by breaking it up into steps.
+            for (int ddIdx; (ddIdx = findFirstDupOrDrop(reorder, newArity)) != 0; ) {
+                if (ddIdx > 0) {
+                    // We found a duplicated entry at reorder[ddIdx].
+                    // Example:  (x,y,z)->asList(x,y,z)
+                    // permuted by [1*,0,1] => (a0,a1)=>asList(a1,a0,a1)
+                    // permuted by [0,1,0*] => (a0,a1)=>asList(a0,a1,a0)
+                    // The starred element corresponds to the argument
+                    // deleted by the dupArgumentForm transform.
+                    int srcPos = ddIdx, dstPos = srcPos, dupVal = reorder[srcPos];
+                    boolean killFirst = false;
+                    for (int val; (val = reorder[--dstPos]) != dupVal; ) {
+                        // Set killFirst if the dup is larger than an intervening position.
+                        // This will remove at least one inversion from the permutation.
+                        if (dupVal > val) killFirst = true;
+                    }
+                    if (!killFirst) {
+                        srcPos = dstPos;
+                        dstPos = ddIdx;
+                    }
+                    form = form.editor().dupArgumentForm(1 + srcPos, 1 + dstPos);
+                    assert (reorder[srcPos] == reorder[dstPos]);
+                    oldType = oldType.dropParameterTypes(dstPos, dstPos + 1);
+                    // contract the reordering by removing the element at dstPos
+                    int tailPos = dstPos + 1;
+                    System.arraycopy(reorder, tailPos, reorder, dstPos, reorder.length - tailPos);
+                    reorder = Arrays.copyOf(reorder, reorder.length - 1);
+                } else {
+                    int dropVal = ~ddIdx, insPos = 0;
+                    while (insPos < reorder.length && reorder[insPos] < dropVal) {
+                        // Find first element of reorder larger than dropVal.
+                        // This is where we will insert the dropVal.
+                        insPos += 1;
+                    }
+                    Class<?> ptype = newType.parameterType(dropVal);
+                    form = form.editor().addArgumentForm(1 + insPos, BasicType.basicType(ptype));
+                    oldType = oldType.insertParameterTypes(insPos, ptype);
+                    // expand the reordering by inserting an element at insPos
+                    int tailPos = insPos + 1;
+                    reorder = Arrays.copyOf(reorder, reorder.length + 1);
+                    System.arraycopy(reorder, insPos, reorder, tailPos, reorder.length - tailPos);
+                    reorder[insPos] = dropVal;
+                }
+                assert (permuteArgumentChecks(reorder, newType, oldType));
+            }
+            assert (reorder.length == newArity);  // a perfect permutation
+            // Note:  This may cache too many distinct LFs. Consider backing off to varargs code.
+            form = form.editor().permuteArgumentsForm(1, reorder);
+            if (newType == result.type() && form == result.internalForm())
+                return result;
+            return result.copyWith(newType, form);
+        } else {
+            // first detect dropped arguments and handle them separately
+            MethodHandle originalTarget = target;
+            int newArity = newType.parameterCount();
+            for (int dropIdx; (dropIdx = findFirstDrop(reorder, newArity)) >= 0; ) {
+                // dropIdx is missing from reorder; add it in at the end
+                int oldArity = reorder.length;
+                target = dropArguments(target, oldArity, newType.parameterType(dropIdx));
+                reorder = Arrays.copyOf(reorder, oldArity+1);
+                reorder[oldArity] = dropIdx;
+            }
+            assert(target == originalTarget || permuteArgumentChecks(reorder, newType, target.type()));
+            // Note:  This may cache too many distinct LFs. Consider backing off to varargs code.
+            BoundMethodHandle result = target.rebind();
+            LambdaForm form = result.form.permuteArguments(1, reorder, basicTypes(newType.parameterList()));
+            return result.copyWith(newType, form);
+        }
     }
 
-    private static void checkReorder(int[] reorder, MethodType newType, MethodType oldType) {
+    /** Return the first value in [0..newArity-1] that is not present in reorder. */
+    private static int findFirstDrop(int[] reorder, int newArity) {
+        final int BIT_LIMIT = 63;  // max number of bits in bit mask
+        if (newArity < BIT_LIMIT) {
+            long mask = 0;
+            for (int arg : reorder) {
+                assert(arg < newArity);
+                mask |= (1 << arg);
+            }
+            if (mask == (1 << newArity) - 1) {
+                assert(Long.numberOfTrailingZeros(Long.lowestOneBit(~mask)) == newArity);
+                return -1;
+            }
+            // find first zero
+            long zeroBit = Long.lowestOneBit(~mask);
+            int zeroPos = Long.numberOfTrailingZeros(zeroBit);
+            assert(zeroPos < newArity);
+            return zeroPos;
+        }
+        BitSet mask = new BitSet(newArity);
+        for (int arg : reorder) {
+            assert(arg < newArity);
+            mask.set(arg);
+        }
+        int zeroPos = mask.nextClearBit(0);
+        if (zeroPos == newArity)
+            return -1;
+        return zeroPos;
+    }
+
+    /**
+     * Return an indication of any duplicate or omission in reorder.
+     * If the reorder contains a duplicate entry, return the index of the second occurrence.
+     * Otherwise, return ~(n), for the first n in [0..newArity-1] that is not present in reorder.
+     * Otherwise, return zero.
+     * If an element not in [0..newArity-1] is encountered, return reorder.length.
+     */
+    private static int findFirstDupOrDrop(int[] reorder, int newArity) {
+        final int BIT_LIMIT = 63;  // max number of bits in bit mask
+        if (newArity < BIT_LIMIT) {
+            long mask = 0;
+            for (int i = 0; i < reorder.length; i++) {
+                int arg = reorder[i];
+                if (arg >= newArity)  return reorder.length;
+                int bit = 1 << arg;
+                if ((mask & bit) != 0)
+                    return i;  // >0 indicates a dup
+                mask |= bit;
+            }
+            if (mask == (1 << newArity) - 1) {
+                assert(Long.numberOfTrailingZeros(Long.lowestOneBit(~mask)) == newArity);
+                return 0;
+            }
+            // find first zero
+            long zeroBit = Long.lowestOneBit(~mask);
+            int zeroPos = Long.numberOfTrailingZeros(zeroBit);
+            assert(zeroPos < newArity);
+            return ~zeroPos;
+        } else {
+            // same algorithm, different bit set
+            BitSet mask = new BitSet(newArity);
+            for (int i = 0; i < reorder.length; i++) {
+                int arg = reorder[i];
+                if (arg >= newArity)  return reorder.length;
+                if (mask.get(arg))
+                    return i;  // >0 indicates a dup
+                mask.set(arg);
+            }
+            int zeroPos = mask.nextClearBit(0);
+            if (zeroPos == newArity) {
+                return 0;
+            }
+            return ~zeroPos;
+        }
+    }
+
+    private static boolean permuteArgumentChecks(int[] reorder, MethodType newType, MethodType oldType) {
         if (newType.returnType() != oldType.returnType())
             throw newIllegalArgumentException("return types do not match",
                     oldType, newType);
@@ -2105,7 +2269,7 @@
                     throw newIllegalArgumentException("parameter types do not match after reorder",
                             oldType, newType);
             }
-            if (!bad)  return;
+            if (!bad)  return true;
         }
         throw newIllegalArgumentException("bad reorder array: "+Arrays.toString(reorder));
     }
@@ -2131,9 +2295,14 @@
             if (type == void.class)
                 throw newIllegalArgumentException("void type");
             Wrapper w = Wrapper.forPrimitiveType(type);
-            return insertArguments(identity(type), 0, w.convert(value, type));
+            value = w.convert(value, type);
+            if (w.zero().equals(value))
+                return zero(w, type);
+            return insertArguments(identity(type), 0, value);
         } else {
-            return identity(type).bindTo(type.cast(value));
+            if (value == null)
+                return zero(Wrapper.OBJECT, type);
+            return identity(type).bindTo(value);
         }
     }
 
@@ -2146,14 +2315,48 @@
      */
     public static
     MethodHandle identity(Class<?> type) {
-        if (type == void.class)
-            throw newIllegalArgumentException("void type");
-        else if (type == Object.class)
-            return ValueConversions.identity();
-        else if (type.isPrimitive())
-            return ValueConversions.identity(Wrapper.forPrimitiveType(type));
-        else
-            return MethodHandleImpl.makeReferenceIdentity(type);
+        Wrapper btw = (type.isPrimitive() ? Wrapper.forPrimitiveType(type) : Wrapper.OBJECT);
+        int pos = btw.ordinal();
+        MethodHandle ident = IDENTITY_MHS[pos];
+        if (ident == null) {
+            ident = setCachedMethodHandle(IDENTITY_MHS, pos, makeIdentity(btw.primitiveType()));
+        }
+        if (ident.type().returnType() == type)
+            return ident;
+        // something like identity(Foo.class); do not bother to intern these
+        assert(btw == Wrapper.OBJECT);
+        return makeIdentity(type);
+    }
+    private static final MethodHandle[] IDENTITY_MHS = new MethodHandle[Wrapper.values().length];
+    private static MethodHandle makeIdentity(Class<?> ptype) {
+        MethodType mtype = MethodType.methodType(ptype, ptype);
+        LambdaForm lform = LambdaForm.identityForm(BasicType.basicType(ptype));
+        return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.IDENTITY);
+    }
+
+    private static MethodHandle zero(Wrapper btw, Class<?> rtype) {
+        int pos = btw.ordinal();
+        MethodHandle zero = ZERO_MHS[pos];
+        if (zero == null) {
+            zero = setCachedMethodHandle(ZERO_MHS, pos, makeZero(btw.primitiveType()));
+        }
+        if (zero.type().returnType() == rtype)
+            return zero;
+        assert(btw == Wrapper.OBJECT);
+        return makeZero(rtype);
+    }
+    private static final MethodHandle[] ZERO_MHS = new MethodHandle[Wrapper.values().length];
+    private static MethodHandle makeZero(Class<?> rtype) {
+        MethodType mtype = MethodType.methodType(rtype);
+        LambdaForm lform = LambdaForm.zeroForm(BasicType.basicType(rtype));
+        return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.ZERO);
+    }
+
+    synchronized private static MethodHandle setCachedMethodHandle(MethodHandle[] cache, int pos, MethodHandle value) {
+        // Simulate a CAS, to avoid racy duplication of results.
+        MethodHandle prev = cache[pos];
+        if (prev != null) return prev;
+        return cache[pos] = value;
     }
 
     /**
@@ -2189,6 +2392,37 @@
     public static
     MethodHandle insertArguments(MethodHandle target, int pos, Object... values) {
         int insCount = values.length;
+        Class<?>[] ptypes = insertArgumentsChecks(target, insCount, pos);
+        if (insCount == 0)  return target;
+        BoundMethodHandle result = target.rebind();
+        for (int i = 0; i < insCount; i++) {
+            Object value = values[i];
+            Class<?> ptype = ptypes[pos+i];
+            if (ptype.isPrimitive()) {
+                result = insertArgumentPrimitive(result, pos, ptype, value);
+            } else {
+                value = ptype.cast(value);  // throw CCE if needed
+                result = result.bindArgumentL(pos, value);
+            }
+        }
+        return result;
+    }
+
+    private static BoundMethodHandle insertArgumentPrimitive(BoundMethodHandle result, int pos,
+                                                             Class<?> ptype, Object value) {
+        Wrapper w = Wrapper.forPrimitiveType(ptype);
+        // perform unboxing and/or primitive conversion
+        value = w.convert(value, ptype);
+        switch (w) {
+        case INT:     return result.bindArgumentI(pos, (int)value);
+        case LONG:    return result.bindArgumentJ(pos, (long)value);
+        case FLOAT:   return result.bindArgumentF(pos, (float)value);
+        case DOUBLE:  return result.bindArgumentD(pos, (double)value);
+        default:      return result.bindArgumentI(pos, ValueConversions.widenSubword(value));
+        }
+    }
+
+    private static Class<?>[] insertArgumentsChecks(MethodHandle target, int insCount, int pos) throws RuntimeException {
         MethodType oldType = target.type();
         int outargs = oldType.parameterCount();
         int inargs  = outargs - insCount;
@@ -2196,31 +2430,7 @@
             throw newIllegalArgumentException("too many values to insert");
         if (pos < 0 || pos > inargs)
             throw newIllegalArgumentException("no argument type to append");
-        MethodHandle result = target;
-        for (int i = 0; i < insCount; i++) {
-            Object value = values[i];
-            Class<?> ptype = oldType.parameterType(pos+i);
-            if (ptype.isPrimitive()) {
-                BasicType btype = I_TYPE;
-                Wrapper w = Wrapper.forPrimitiveType(ptype);
-                switch (w) {
-                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);
-                result = result.bindArgument(pos, btype, value);
-                continue;
-            }
-            value = ptype.cast(value);  // throw CCE if needed
-            if (pos == 0) {
-                result = result.bindReceiver(value);
-            } else {
-                result = result.bindArgument(pos, L_TYPE, value);
-            }
-        }
-        return result;
+        return oldType.ptypes();
     }
 
     /**
@@ -2268,18 +2478,33 @@
     public static
     MethodHandle dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes) {
         MethodType oldType = target.type();  // get NPE
+        int dropped = dropArgumentChecks(oldType, pos, valueTypes);
+        if (dropped == 0)  return target;
+        BoundMethodHandle result = target.rebind();
+        LambdaForm lform = result.form;
+        if (USE_LAMBDA_FORM_EDITOR) {
+            int insertFormArg = 1 + pos;
+            for (Class<?> ptype : valueTypes) {
+                lform = lform.editor().addArgumentForm(insertFormArg++, BasicType.basicType(ptype));
+            }
+        } else {
+            lform = lform.addArguments(pos, valueTypes);
+        }
+        MethodType newType = oldType.insertParameterTypes(pos, valueTypes);
+        result = result.copyWith(newType, lform);
+        return result;
+    }
+
+    private static int dropArgumentChecks(MethodType oldType, int pos, List<Class<?>> valueTypes) {
         int dropped = valueTypes.size();
         MethodType.checkSlotCount(dropped);
-        if (dropped == 0)  return target;
         int outargs = oldType.parameterCount();
         int inargs  = outargs + dropped;
-        if (pos < 0 || pos >= inargs)
-            throw newIllegalArgumentException("no argument type to remove");
-        ArrayList<Class<?>> ptypes = new ArrayList<>(oldType.parameterList());
-        ptypes.addAll(pos, valueTypes);
-        if (ptypes.size() != inargs)  throw newIllegalArgumentException("valueTypes");
-        MethodType newType = MethodType.methodType(oldType.returnType(), ptypes);
-        return target.dropArguments(newType, pos, dropped);
+        if (pos < 0 || pos > outargs)
+            throw newIllegalArgumentException("no argument type to remove"
+                    + Arrays.asList(oldType, pos, valueTypes, inargs, outargs)
+                    );
+        return dropped;
     }
 
     /**
@@ -2401,32 +2626,47 @@
      */
     public static
     MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters) {
-        MethodType targetType = target.type();
+        filterArgumentsCheckArity(target, pos, filters);
         MethodHandle adapter = target;
-        MethodType adapterType = null;
-        assert((adapterType = targetType) != null);
-        int maxPos = targetType.parameterCount();
-        if (pos + filters.length > maxPos)
-            throw newIllegalArgumentException("too many filters");
         int curPos = pos-1;  // pre-incremented
         for (MethodHandle filter : filters) {
             curPos += 1;
             if (filter == null)  continue;  // ignore null elements of filters
             adapter = filterArgument(adapter, curPos, filter);
-            assert((adapterType = adapterType.changeParameterType(curPos, filter.type().parameterType(0))) != null);
         }
-        assert(adapterType.equals(adapter.type()));
         return adapter;
     }
 
     /*non-public*/ static
     MethodHandle filterArgument(MethodHandle target, int pos, MethodHandle filter) {
+        filterArgumentChecks(target, pos, filter);
+        if (USE_LAMBDA_FORM_EDITOR) {
+            MethodType targetType = target.type();
+            MethodType filterType = filter.type();
+            BoundMethodHandle result = target.rebind();
+            Class<?> newParamType = filterType.parameterType(0);
+            LambdaForm lform = result.editor().filterArgumentForm(1 + pos, BasicType.basicType(newParamType));
+            MethodType newType = targetType.changeParameterType(pos, newParamType);
+            result = result.copyWithExtendL(newType, lform, filter);
+            return result;
+        } else {
+            return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
+        }
+    }
+
+    private static void filterArgumentsCheckArity(MethodHandle target, int pos, MethodHandle[] filters) {
+        MethodType targetType = target.type();
+        int maxPos = targetType.parameterCount();
+        if (pos + filters.length > maxPos)
+            throw newIllegalArgumentException("too many filters");
+    }
+
+    private static void filterArgumentChecks(MethodHandle target, int pos, MethodHandle filter) throws RuntimeException {
         MethodType targetType = target.type();
         MethodType filterType = filter.type();
         if (filterType.parameterCount() != 1
             || filterType.returnType() != targetType.parameterType(pos))
             throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
-        return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
     }
 
     /**
@@ -2537,12 +2777,36 @@
      */
     public static
     MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle filter) {
+        MethodType newType = collectArgumentsChecks(target, pos, filter);
+        if (USE_LAMBDA_FORM_EDITOR) {
+            MethodType collectorType = filter.type();
+            BoundMethodHandle result = target.rebind();
+            LambdaForm lform;
+            if (collectorType.returnType().isArray() && filter.intrinsicName() == Intrinsic.NEW_ARRAY) {
+                lform = result.editor().collectArgumentArrayForm(1 + pos, filter);
+                if (lform != null) {
+                    return result.copyWith(newType, lform);
+                }
+            }
+            lform = result.editor().collectArgumentsForm(1 + pos, collectorType.basicType());
+            return result.copyWithExtendL(newType, lform, filter);
+        } else {
+            return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
+        }
+    }
+
+    private static MethodType collectArgumentsChecks(MethodHandle target, int pos, MethodHandle filter) throws RuntimeException {
         MethodType targetType = target.type();
         MethodType filterType = filter.type();
-        if (filterType.returnType() != void.class &&
-            filterType.returnType() != targetType.parameterType(pos))
+        Class<?> rtype = filterType.returnType();
+        List<Class<?>> filterArgs = filterType.parameterList();
+        if (rtype == void.class) {
+            return targetType.insertParameterTypes(pos, filterArgs);
+        }
+        if (rtype != targetType.parameterType(pos)) {
             throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
-        return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
+        }
+        return targetType.dropParameterTypes(pos, pos+1).insertParameterTypes(pos, filterArgs);
     }
 
     /**
@@ -2606,15 +2870,26 @@
     MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter) {
         MethodType targetType = target.type();
         MethodType filterType = filter.type();
+        filterReturnValueChecks(targetType, filterType);
+        if (USE_LAMBDA_FORM_EDITOR) {
+            BoundMethodHandle result = target.rebind();
+            BasicType rtype = BasicType.basicType(filterType.returnType());
+            LambdaForm lform = result.editor().filterReturnForm(rtype, false);
+            MethodType newType = targetType.changeReturnType(filterType.returnType());
+            result = result.copyWithExtendL(newType, lform, filter);
+            return result;
+        } else {
+            return MethodHandleImpl.makeCollectArguments(filter, target, 0, false);
+        }
+    }
+
+    private static void filterReturnValueChecks(MethodType targetType, MethodType filterType) throws RuntimeException {
         Class<?> rtype = targetType.returnType();
         int filterValues = filterType.parameterCount();
         if (filterValues == 0
                 ? (rtype != void.class)
                 : (rtype != filterType.parameterType(0)))
-            throw newIllegalArgumentException("target and filter types do not match", target, filter);
-        // result = fold( lambda(retval, arg...) { filter(retval) },
-        //                lambda(        arg...) { target(arg...) } )
-        return MethodHandleImpl.makeCollectArguments(filter, target, 0, false);
+            throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
     }
 
     /**
@@ -2695,24 +2970,40 @@
      */
     public static
     MethodHandle foldArguments(MethodHandle target, MethodHandle combiner) {
-        int pos = 0;
+        int foldPos = 0;
         MethodType targetType = target.type();
         MethodType combinerType = combiner.type();
-        int foldPos = pos;
-        int foldArgs = combinerType.parameterCount();
-        int foldVals = combinerType.returnType() == void.class ? 0 : 1;
+        Class<?> rtype = foldArgumentChecks(foldPos, targetType, combinerType);
+        if (USE_LAMBDA_FORM_EDITOR) {
+            BoundMethodHandle result = target.rebind();
+            boolean dropResult = (rtype == void.class);
+            // Note:  This may cache too many distinct LFs. Consider backing off to varargs code.
+            LambdaForm lform = result.editor().foldArgumentsForm(1 + foldPos, dropResult, combinerType.basicType());
+            MethodType newType = targetType;
+            if (!dropResult)
+                newType = newType.dropParameterTypes(foldPos, foldPos + 1);
+            result = result.copyWithExtendL(newType, lform, combiner);
+            return result;
+        } else {
+            return MethodHandleImpl.makeCollectArguments(target, combiner, foldPos, true);
+        }
+    }
+
+    private static Class<?> foldArgumentChecks(int foldPos, MethodType targetType, MethodType combinerType) {
+        int foldArgs   = combinerType.parameterCount();
+        Class<?> rtype = combinerType.returnType();
+        int foldVals = rtype == void.class ? 0 : 1;
         int afterInsertPos = foldPos + foldVals;
         boolean ok = (targetType.parameterCount() >= afterInsertPos + foldArgs);
         if (ok && !(combinerType.parameterList()
                     .equals(targetType.parameterList().subList(afterInsertPos,
                                                                afterInsertPos + foldArgs))))
             ok = false;
-        if (ok && foldVals != 0 && !combinerType.returnType().equals(targetType.parameterType(0)))
+        if (ok && foldVals != 0 && combinerType.returnType() != targetType.parameterType(0))
             ok = false;
         if (!ok)
             throw misMatchedTypes("target and combiner types", targetType, combinerType);
-        MethodType newType = targetType.dropParameterTypes(foldPos, afterInsertPos);
-        return MethodHandleImpl.makeCollectArguments(target, combiner, foldPos, true);
+        return rtype;
     }
 
     /**
--- a/src/java.base/share/classes/java/lang/invoke/MethodType.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/MethodType.java	Fri Sep 12 10:33:32 2014 -0700
@@ -467,6 +467,75 @@
         return dropParameterTypes(start, end).insertParameterTypes(start, ptypesToInsert);
     }
 
+    /** Replace the last arrayLength parameter types with the component type of arrayType.
+     * @param arrayType any array type
+     * @param arrayLength the number of parameter types to change
+     * @return the resulting type
+     */
+    /*non-public*/ MethodType asSpreaderType(Class<?> arrayType, int arrayLength) {
+        assert(parameterCount() >= arrayLength);
+        int spreadPos = ptypes.length - arrayLength;
+        if (arrayLength == 0)  return this;  // nothing to change
+        if (arrayType == Object[].class) {
+            if (isGeneric())  return this;  // nothing to change
+            if (spreadPos == 0) {
+                // no leading arguments to preserve; go generic
+                MethodType res = genericMethodType(arrayLength);
+                if (rtype != Object.class) {
+                    res = res.changeReturnType(rtype);
+                }
+                return res;
+            }
+        }
+        Class<?> elemType = arrayType.getComponentType();
+        assert(elemType != null);
+        for (int i = spreadPos; i < ptypes.length; i++) {
+            if (ptypes[i] != elemType) {
+                Class<?>[] fixedPtypes = ptypes.clone();
+                Arrays.fill(fixedPtypes, i, ptypes.length, elemType);
+                return methodType(rtype, fixedPtypes);
+            }
+        }
+        return this;  // arguments check out; no change
+    }
+
+    /** Return the leading parameter type, which must exist and be a reference.
+     *  @return the leading parameter type, after error checks
+     */
+    /*non-public*/ Class<?> leadingReferenceParameter() {
+        Class<?> ptype;
+        if (ptypes.length == 0 ||
+            (ptype = ptypes[0]).isPrimitive())
+            throw newIllegalArgumentException("no leading reference parameter");
+        return ptype;
+    }
+
+    /** Delete the last parameter type and replace it with arrayLength copies of the component type of arrayType.
+     * @param arrayType any array type
+     * @param arrayLength the number of parameter types to insert
+     * @return the resulting type
+     */
+    /*non-public*/ MethodType asCollectorType(Class<?> arrayType, int arrayLength) {
+        assert(parameterCount() >= 1);
+        assert(lastParameterType().isAssignableFrom(arrayType));
+        MethodType res;
+        if (arrayType == Object[].class) {
+            res = genericMethodType(arrayLength);
+            if (rtype != Object.class) {
+                res = res.changeReturnType(rtype);
+            }
+        } else {
+            Class<?> elemType = arrayType.getComponentType();
+            assert(elemType != null);
+            res = methodType(rtype, Collections.nCopies(arrayLength, elemType));
+        }
+        if (ptypes.length == 1) {
+            return res;
+        } else {
+            return res.insertParameterTypes(0, parameterList().subList(0, ptypes.length-1));
+        }
+    }
+
     /**
      * Finds or creates a method type with some parameter types omitted.
      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
@@ -574,6 +643,10 @@
         return genericMethodType(parameterCount());
     }
 
+    /*non-public*/ boolean isGeneric() {
+        return this == erase() && !hasPrimitives();
+    }
+
     /**
      * Converts all primitive types to their corresponding wrapper types.
      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
@@ -726,44 +799,137 @@
         return sj.toString();
     }
 
-
+    /** True if the old return type can always be viewed (w/o casting) under new return type,
+     *  and the new parameters can be viewed (w/o casting) under the old parameter types.
+     */
     /*non-public*/
-    boolean isViewableAs(MethodType newType) {
-        if (!VerifyType.isNullConversion(returnType(), newType.returnType()))
+    boolean isViewableAs(MethodType newType, boolean keepInterfaces) {
+        if (!VerifyType.isNullConversion(returnType(), newType.returnType(), keepInterfaces))
             return false;
+        return parametersAreViewableAs(newType, keepInterfaces);
+    }
+    /** True if the new parameters can be viewed (w/o casting) under the old parameter types. */
+    /*non-public*/
+    boolean parametersAreViewableAs(MethodType newType, boolean keepInterfaces) {
+        if (form == newType.form && form.erasedType == this)
+            return true;  // my reference parameters are all Object
+        if (ptypes == newType.ptypes)
+            return true;
         int argc = parameterCount();
         if (argc != newType.parameterCount())
             return false;
         for (int i = 0; i < argc; i++) {
-            if (!VerifyType.isNullConversion(newType.parameterType(i), parameterType(i)))
+            if (!VerifyType.isNullConversion(newType.parameterType(i), parameterType(i), keepInterfaces))
                 return false;
         }
         return true;
     }
     /*non-public*/
-    boolean isCastableTo(MethodType newType) {
-        int argc = parameterCount();
-        if (argc != newType.parameterCount())
-            return false;
-        return true;
-    }
-    /*non-public*/
     boolean isConvertibleTo(MethodType newType) {
+        MethodTypeForm oldForm = this.form();
+        MethodTypeForm newForm = newType.form();
+        if (oldForm == newForm)
+            // same parameter count, same primitive/object mix
+            return true;
         if (!canConvert(returnType(), newType.returnType()))
             return false;
-        int argc = parameterCount();
-        if (argc != newType.parameterCount())
+        Class<?>[] srcTypes = newType.ptypes;
+        Class<?>[] dstTypes = ptypes;
+        if (srcTypes == dstTypes)
+            return true;
+        int argc;
+        if ((argc = srcTypes.length) != dstTypes.length)
             return false;
-        for (int i = 0; i < argc; i++) {
-            if (!canConvert(newType.parameterType(i), parameterType(i)))
+        if (argc <= 1) {
+            if (argc == 1 && !canConvert(srcTypes[0], dstTypes[0]))
                 return false;
+            return true;
+        }
+        if ((oldForm.primitiveParameterCount() == 0 && oldForm.erasedType == this) ||
+            (newForm.primitiveParameterCount() == 0 && newForm.erasedType == newType)) {
+            // Somewhat complicated test to avoid a loop of 2 or more trips.
+            // If either type has only Object parameters, we know we can convert.
+            assert(canConvertParameters(srcTypes, dstTypes));
+            return true;
+        }
+        return canConvertParameters(srcTypes, dstTypes);
+    }
+
+    /** Returns true if MHs.explicitCastArguments produces the same result as MH.asType.
+     *  If the type conversion is impossible for either, the result should be false.
+     */
+    /*non-public*/
+    boolean explicitCastEquivalentToAsType(MethodType newType) {
+        if (this == newType)  return true;
+        if (!explicitCastEquivalentToAsType(rtype, newType.rtype)) {
+            return false;
+        }
+        Class<?>[] srcTypes = newType.ptypes;
+        Class<?>[] dstTypes = ptypes;
+        if (dstTypes == srcTypes) {
+            return true;
+        }
+        if (dstTypes.length != srcTypes.length) {
+            return false;
+        }
+        for (int i = 0; i < dstTypes.length; i++) {
+            if (!explicitCastEquivalentToAsType(srcTypes[i], dstTypes[i])) {
+                return false;
+            }
         }
         return true;
     }
+
+    /** Reports true if the src can be converted to the dst, by both asType and MHs.eCE,
+     *  and with the same effect.
+     *  MHs.eCA has the following "upgrades" to MH.asType:
+     *  1. interfaces are unchecked (that is, treated as if aliased to Object)
+     *     Therefore, {@code Object->CharSequence} is possible in both cases but has different semantics
+     *  2. the full matrix of primitive-to-primitive conversions is supported
+     *     Narrowing like {@code long->byte} and basic-typing like {@code boolean->int}
+     *     are not supported by asType, but anything supported by asType is equivalent
+     *     with MHs.eCE.
+     *  3a. unboxing conversions can be followed by the full matrix of primitive conversions
+     *  3b. unboxing of null is permitted (creates a zero primitive value)
+     *     Most unboxing conversions, like {@code Object->int}, has potentially
+     *     different behaviors for asType vs. MHs.eCE, because the dynamic value
+     *     might be a wrapper of a type that requires narrowing, like {@code (Object)1L->byte}.
+     *     The equivalence is only certain if the static src type is a wrapper,
+     *     and the conversion will be a widening one.
+     * Other than interfaces, reference-to-reference conversions are the same.
+     * Boxing primitives to references is the same for both operators.
+     */
+    private static boolean explicitCastEquivalentToAsType(Class<?> src, Class<?> dst) {
+        if (src == dst || dst == Object.class || dst == void.class)  return true;
+        if (src.isPrimitive()) {
+            // Could be a prim/prim conversion, where casting is a strict superset.
+            // Or a boxing conversion, which is always to an exact wrapper class.
+            return canConvert(src, dst);
+        } else if (dst.isPrimitive()) {
+            Wrapper dw = Wrapper.forPrimitiveType(dst);
+            // Watch out:  If src is Number or Object, we could get dynamic narrowing conversion.
+            // The conversion is known to be widening only if the wrapper type is statically visible.
+            return (Wrapper.isWrapperType(src) &&
+                    dw.isConvertibleFrom(Wrapper.forWrapperType(src)));
+        } else {
+            // R->R always works, but we have to avoid a check-cast to an interface.
+            return !dst.isInterface() || dst.isAssignableFrom(src);
+        }
+    }
+
+    private boolean canConvertParameters(Class<?>[] srcTypes, Class<?>[] dstTypes) {
+        for (int i = 0; i < srcTypes.length; i++) {
+            if (!canConvert(srcTypes[i], dstTypes[i])) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     /*non-public*/
     static boolean canConvert(Class<?> src, Class<?> dst) {
         // short-circuit a few cases:
-        if (src == dst || dst == Object.class)  return true;
+        if (src == dst || src == Object.class || dst == Object.class)  return true;
         // the remainder of this logic is documented in MethodHandle.asType
         if (src.isPrimitive()) {
             // can force void to an explicit null, a la reflect.Method.invoke
@@ -905,7 +1071,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/src/java.base/share/classes/java/lang/invoke/MethodTypeForm.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/MethodTypeForm.java	Fri Sep 12 10:33:32 2014 -0700
@@ -47,15 +47,17 @@
     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
+    @Stable final MethodHandle[] methodHandles;
+    // Indexes into methodHandles:
+    static final int
+            MH_BASIC_INV      =  0,  // cached instance of MH.invokeBasic
+            MH_NF_INV         =  1,  // cached helper for LF.NamedFunction
+            MH_UNINIT_CS      =  2,  // uninitialized call site
+            MH_LIMIT          =  3;
 
     // Cached lambda form information, for basic types only:
     final @Stable LambdaForm[] lambdaForms;
@@ -68,26 +70,55 @@
             LF_INVINTERFACE   =  4,
             LF_INVSTATIC_INIT =  5,  // DMH invokeStatic with <clinit> barrier
             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_REBIND         =  7,  // BoundMethodHandle
+            LF_DELEGATE       =  8,  // DelegatingMethodHandle
+            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_LIMIT          = 16;
+            LF_GWC            = 15,  // guardWithCatch (catchException)
+            LF_GWT            = 16,  // guardWithTest
+            LF_LIMIT          = 17;
 
+    /** 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 MethodHandle cachedMethodHandle(int which) {
+        assert(assertIsBasicType());
+        return methodHandles[which];
+    }
+
+    synchronized public MethodHandle setCachedMethodHandle(int which, MethodHandle mh) {
+        // Simulate a CAS, to avoid racy duplication of results.
+        MethodHandle prev = methodHandles[which];
+        if (prev != null)  return prev;
+        return methodHandles[which] = mh;
+    }
+
     public LambdaForm cachedLambdaForm(int which) {
+        assert(assertIsBasicType());
         return lambdaForms[which];
     }
 
@@ -98,28 +129,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 +181,16 @@
             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.methodHandles = null;
+            this.lambdaForms = null;
+            return;
         }
         if (lac != 0) {
             int slot = ptypeCount + lac;
@@ -187,10 +206,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 +224,17 @@
                 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];
+        this.methodHandles = new MethodHandle[MH_LIMIT];
     }
 
     private static long pack(int a, int b, int c, int d) {
@@ -300,7 +321,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 +389,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/src/java.base/share/classes/java/lang/invoke/SimpleMethodHandle.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/SimpleMethodHandle.java	Fri Sep 12 10:33:32 2014 -0700
@@ -25,38 +25,77 @@
 
 package java.lang.invoke;
 
-import static java.lang.invoke.LambdaForm.*;
 import static java.lang.invoke.LambdaForm.BasicType.*;
+import static java.lang.invoke.MethodHandleStatics.*;
 
 /**
  * A method handle whose behavior is determined only by its LambdaForm.
  * @author jrose
  */
-final class SimpleMethodHandle extends MethodHandle {
+final class SimpleMethodHandle extends BoundMethodHandle {
     private SimpleMethodHandle(MethodType type, LambdaForm form) {
         super(type, form);
     }
 
-    /*non-public*/ static SimpleMethodHandle make(MethodType type, LambdaForm form) {
+    /*non-public*/ static BoundMethodHandle make(MethodType type, LambdaForm form) {
         return new SimpleMethodHandle(type, form);
     }
 
-    @Override
-    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);
+    /*non-public*/ static final SpeciesData SPECIES_DATA = SpeciesData.EMPTY;
+
+    /*non-public*/ public SpeciesData speciesData() {
+            return SPECIES_DATA;
     }
 
     @Override
-    MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
-        LambdaForm newForm = internalForm().addArguments(pos, srcType.parameterList().subList(pos, pos+drops));
-        return new SimpleMethodHandle(srcType, newForm);
+    /*non-public*/ BoundMethodHandle copyWith(MethodType mt, LambdaForm lf) {
+        return make(mt, lf);
     }
 
     @Override
-    MethodHandle permuteArguments(MethodType newType, int[] reorder) {
-        LambdaForm form2 = internalForm().permuteArguments(1, reorder, basicTypes(newType.parameterList()));
-        return new SimpleMethodHandle(newType, form2);
+    String internalProperties() {
+        return "\n& Class="+getClass().getSimpleName();
+    }
+
+    @Override
+    /*non-public*/ public int fieldCount() {
+        return 0;
+    }
+
+    @Override
+    /*non-public*/ final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) {
+        return BoundMethodHandle.bindSingle(mt, lf, narg); // Use known fast path.
+    }
+    @Override
+    /*non-public*/ final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) {
+        try {
+            return (BoundMethodHandle) SPECIES_DATA.extendWith(I_TYPE).constructor().invokeBasic(mt, lf, narg);
+        } catch (Throwable ex) {
+            throw uncaughtException(ex);
+        }
+    }
+    @Override
+    /*non-public*/ final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) {
+        try {
+            return (BoundMethodHandle) SPECIES_DATA.extendWith(J_TYPE).constructor().invokeBasic(mt, lf, narg);
+        } catch (Throwable ex) {
+            throw uncaughtException(ex);
+        }
+    }
+    @Override
+    /*non-public*/ final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) {
+        try {
+            return (BoundMethodHandle) SPECIES_DATA.extendWith(F_TYPE).constructor().invokeBasic(mt, lf, narg);
+        } catch (Throwable ex) {
+            throw uncaughtException(ex);
+        }
+    }
+    @Override
+    /*non-public*/ final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) {
+        try {
+            return (BoundMethodHandle) SPECIES_DATA.extendWith(D_TYPE).constructor().invokeBasic(mt, lf, narg);
+        } catch (Throwable ex) {
+            throw uncaughtException(ex);
+        }
     }
 }
--- a/src/java.base/share/classes/java/lang/reflect/Constructor.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/java/lang/reflect/Constructor.java	Fri Sep 12 10:33:32 2014 -0700
@@ -94,9 +94,20 @@
     // For sharing of ConstructorAccessors. This branching structure
     // is currently only two levels deep (i.e., one root Constructor
     // and potentially many Constructor objects pointing to it.)
+    //
+    // If this branching structure would ever contain cycles, deadlocks can
+    // occur in annotation code.
     private Constructor<T>      root;
 
     /**
+     * Used by Excecutable for annotation sharing.
+     */
+    @Override
+    Executable getRoot() {
+        return root;
+    }
+
+    /**
      * Package-private constructor used by ReflectAccess to enable
      * instantiation of these objects in Java code from the java.lang
      * package via sun.reflect.LangReflectAccess.
@@ -132,6 +143,9 @@
         // which implicitly requires that new java.lang.reflect
         // objects be fabricated for each reflective call on Class
         // objects.)
+        if (this.root != null)
+            throw new IllegalArgumentException("Can not copy a non-root Constructor");
+
         Constructor<T> res = new Constructor<>(clazz,
                                                parameterTypes,
                                                exceptionTypes, modifiers, slot,
--- a/src/java.base/share/classes/java/lang/reflect/Executable.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/java/lang/reflect/Executable.java	Fri Sep 12 10:33:32 2014 -0700
@@ -53,6 +53,11 @@
     abstract byte[] getAnnotationBytes();
 
     /**
+     * Accessor method to allow code sharing
+     */
+    abstract Executable getRoot();
+
+    /**
      * Does the Executable have generic information.
      */
     abstract boolean hasGenericInformation();
@@ -540,11 +545,16 @@
 
     private synchronized  Map<Class<? extends Annotation>, Annotation> declaredAnnotations() {
         if (declaredAnnotations == null) {
-            declaredAnnotations = AnnotationParser.parseAnnotations(
-                getAnnotationBytes(),
-                sun.misc.SharedSecrets.getJavaLangAccess().
-                getConstantPool(getDeclaringClass()),
-                getDeclaringClass());
+            Executable root = getRoot();
+            if (root != null) {
+                declaredAnnotations = root.declaredAnnotations();
+            } else {
+                declaredAnnotations = AnnotationParser.parseAnnotations(
+                    getAnnotationBytes(),
+                    sun.misc.SharedSecrets.getJavaLangAccess().
+                    getConstantPool(getDeclaringClass()),
+                    getDeclaringClass());
+            }
         }
         return declaredAnnotations;
     }
--- a/src/java.base/share/classes/java/lang/reflect/Field.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/java/lang/reflect/Field.java	Fri Sep 12 10:33:32 2014 -0700
@@ -81,6 +81,9 @@
     // For sharing of FieldAccessors. This branching structure is
     // currently only two levels deep (i.e., one root Field and
     // potentially many Field objects pointing to it.)
+    //
+    // If this branching structure would ever contain cycles, deadlocks can
+    // occur in annotation code.
     private Field               root;
 
     // Generics infrastructure
@@ -141,6 +144,9 @@
         // which implicitly requires that new java.lang.reflect
         // objects be fabricated for each reflective call on Class
         // objects.)
+        if (this.root != null)
+            throw new IllegalArgumentException("Can not copy a non-root Field");
+
         Field res = new Field(clazz, name, type, modifiers, slot, signature, annotations);
         res.root = this;
         // Might as well eagerly propagate this if already present
@@ -1137,10 +1143,15 @@
 
     private synchronized  Map<Class<? extends Annotation>, Annotation> declaredAnnotations() {
         if (declaredAnnotations == null) {
-            declaredAnnotations = AnnotationParser.parseAnnotations(
-                annotations, sun.misc.SharedSecrets.getJavaLangAccess().
-                getConstantPool(getDeclaringClass()),
-                getDeclaringClass());
+            Field root = this.root;
+            if (root != null) {
+                declaredAnnotations = root.declaredAnnotations();
+            } else {
+                declaredAnnotations = AnnotationParser.parseAnnotations(
+                        annotations,
+                        sun.misc.SharedSecrets.getJavaLangAccess().getConstantPool(getDeclaringClass()),
+                        getDeclaringClass());
+            }
         }
         return declaredAnnotations;
     }
--- a/src/java.base/share/classes/java/lang/reflect/Method.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/java/lang/reflect/Method.java	Fri Sep 12 10:33:32 2014 -0700
@@ -79,6 +79,9 @@
     // For sharing of MethodAccessors. This branching structure is
     // currently only two levels deep (i.e., one root Method and
     // potentially many Method objects pointing to it.)
+    //
+    // If this branching structure would ever contain cycles, deadlocks can
+    // occur in annotation code.
     private Method              root;
 
     // Generics infrastructure
@@ -144,6 +147,9 @@
         // which implicitly requires that new java.lang.reflect
         // objects be fabricated for each reflective call on Class
         // objects.)
+        if (this.root != null)
+            throw new IllegalArgumentException("Can not copy a non-root Method");
+
         Method res = new Method(clazz, name, parameterTypes, returnType,
                                 exceptionTypes, modifiers, slot, signature,
                                 annotations, parameterAnnotations, annotationDefault);
@@ -153,6 +159,14 @@
         return res;
     }
 
+    /**
+     * Used by Excecutable for annotation sharing.
+     */
+    @Override
+    Executable getRoot() {
+        return root;
+    }
+
     @Override
     boolean hasGenericInformation() {
         return (getGenericSignature() != null);
--- a/src/java.base/share/classes/java/net/URLClassLoader.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/java/net/URLClassLoader.java	Fri Sep 12 10:33:32 2014 -0700
@@ -354,10 +354,11 @@
      * @exception NullPointerException if {@code name} is {@code null}.
      */
     protected Class<?> findClass(final String name)
-         throws ClassNotFoundException
+        throws ClassNotFoundException
     {
+        final Class<?> result;
         try {
-            return AccessController.doPrivileged(
+            result = AccessController.doPrivileged(
                 new PrivilegedExceptionAction<Class<?>>() {
                     public Class<?> run() throws ClassNotFoundException {
                         String path = name.replace('.', '/').concat(".class");
@@ -369,13 +370,17 @@
                                 throw new ClassNotFoundException(name, e);
                             }
                         } else {
-                            throw new ClassNotFoundException(name);
+                            return null;
                         }
                     }
                 }, acc);
         } catch (java.security.PrivilegedActionException pae) {
             throw (ClassNotFoundException) pae.getException();
         }
+        if (result == null) {
+            throw new ClassNotFoundException(name);
+        }
+        return result;
     }
 
     /*
--- a/src/java.base/share/classes/java/time/Duration.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/java/time/Duration.java	Fri Sep 12 10:33:32 2014 -0700
@@ -424,7 +424,7 @@
             return 0;
         }
         try {
-            long val = Long.parseLong(text, 10, start, end);
+            long val = Long.parseLong(text, start, end, 10);
             return Math.multiplyExact(val, multiplier);
         } catch (NumberFormatException | ArithmeticException ex) {
             throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: " + errorText, text, 0).initCause(ex);
@@ -437,7 +437,7 @@
             return 0;
         }
         try {
-            int fraction = Integer.parseInt(text, 10, start, end);
+            int fraction = Integer.parseInt(text, start, end, 10);
 
             // for number strings smaller than 9 digits, interpret as if there
             // were trailing zeros
--- a/src/java.base/share/classes/java/time/Period.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/java/time/Period.java	Fri Sep 12 10:33:32 2014 -0700
@@ -358,7 +358,7 @@
         if (start < 0 || end < 0) {
             return 0;
         }
-        int val = Integer.parseInt(text, 10, start, end);
+        int val = Integer.parseInt(text, start, end, 10);
         try {
             return Math.multiplyExact(val, negate);
         } catch (ArithmeticException ex) {
--- a/src/java.base/share/classes/java/util/UUID.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/java/util/UUID.java	Fri Sep 12 10:33:32 2014 -0700
@@ -194,7 +194,8 @@
      *
      */
     public static UUID fromString(String name) {
-        if (name.length() > 36) {
+        int len = name.length();
+        if (len > 36) {
             throw new IllegalArgumentException("UUID string too large");
         }
 
@@ -214,15 +215,14 @@
             throw new IllegalArgumentException("Invalid UUID string: " + name);
         }
 
-        long mostSigBits = Long.parseLong(name, 16, 0, dash1) & 0xffffffffL;
+        long mostSigBits = Long.parseLong(name, 0, dash1, 16) & 0xffffffffL;
         mostSigBits <<= 16;
-        mostSigBits |= Long.parseLong(name, 16, dash1 + 1, dash2) & 0xffffL;
+        mostSigBits |= Long.parseLong(name, dash1 + 1, dash2, 16) & 0xffffL;
         mostSigBits <<= 16;
-        mostSigBits |= Long.parseLong(name, 16, dash2 + 1, dash3) & 0xffffL;
-
-        long leastSigBits = Long.parseLong(name, 16, dash3 + 1, dash4) & 0xffffL;
+        mostSigBits |= Long.parseLong(name, dash2 + 1, dash3, 16) & 0xffffL;
+        long leastSigBits = Long.parseLong(name, dash3 + 1, dash4, 16) & 0xffffL;
         leastSigBits <<= 48;
-        leastSigBits |= Long.parseLong(name, 16, dash4 + 1) & 0xffffffffffffL;
+        leastSigBits |= Long.parseLong(name, dash4 + 1, len, 16) & 0xffffffffffffL;
 
         return new UUID(mostSigBits, leastSigBits);
     }
--- a/src/java.base/share/classes/sun/invoke/util/ValueConversions.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/invoke/util/ValueConversions.java	Fri Sep 12 10:33:32 2014 -0700
@@ -29,38 +29,34 @@
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodHandles.Lookup;
 import java.lang.invoke.MethodType;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
 import java.util.EnumMap;
-import java.util.List;
 
 public class ValueConversions {
     private static final Class<?> THIS_CLASS = ValueConversions.class;
-    // Do not adjust this except for special platforms:
-    private static final int MAX_ARITY;
-    static {
-        final Object[] values = { 255 };
-        AccessController.doPrivileged(new PrivilegedAction<Void>() {
-                @Override
-                public Void run() {
-                    values[0] = Integer.getInteger(THIS_CLASS.getName()+".MAX_ARITY", 255);
-                    return null;
-                }
-            });
-        MAX_ARITY = (Integer) values[0];
+    private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();
+
+    /** Thread-safe canonicalized mapping from Wrapper to MethodHandle
+     * with unsynchronized reads and synchronized writes.
+     * It's safe to publish MethodHandles by data race because they are immutable. */
+    private static class WrapperCache {
+        /** EnumMap uses preconstructed array internally, which is constant during it's lifetime. */
+        private final EnumMap<Wrapper, MethodHandle> map = new EnumMap<>(Wrapper.class);
+
+        public MethodHandle get(Wrapper w) {
+            return map.get(w);
+        }
+        public synchronized MethodHandle put(final Wrapper w, final MethodHandle mh) {
+            // Simulate CAS to avoid racy duplication
+            MethodHandle prev = map.putIfAbsent(w, mh);
+            if (prev != null)  return prev;
+            return mh;
+        }
     }
 
-    private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();
-
-    private static EnumMap<Wrapper, MethodHandle>[] newWrapperCaches(int n) {
-        @SuppressWarnings("unchecked")  // generic array creation
-        EnumMap<Wrapper, MethodHandle>[] caches
-                = (EnumMap<Wrapper, MethodHandle>[]) new EnumMap<?,?>[n];
+    private static WrapperCache[] newWrapperCaches(int n) {
+        WrapperCache[] caches = new WrapperCache[n];
         for (int i = 0; i < n; i++)
-            caches[i] = new EnumMap<>(Wrapper.class);
+            caches[i] = new WrapperCache();
         return caches;
     }
 
@@ -71,63 +67,92 @@
     //   implicit conversions sanctioned by JLS 5.1.2, etc.
     //   explicit conversions as allowed by explicitCastArguments
 
+    static int unboxInteger(Integer x) {
+        return x;
+    }
     static int unboxInteger(Object x, boolean cast) {
         if (x instanceof Integer)
-            return ((Integer) x).intValue();
+            return (Integer) x;
         return primitiveConversion(Wrapper.INT, x, cast).intValue();
     }
 
+    static byte unboxByte(Byte x) {
+        return x;
+    }
     static byte unboxByte(Object x, boolean cast) {
         if (x instanceof Byte)
-            return ((Byte) x).byteValue();
+            return (Byte) x;
         return primitiveConversion(Wrapper.BYTE, x, cast).byteValue();
     }
 
+    static short unboxShort(Short x) {
+        return x;
+    }
     static short unboxShort(Object x, boolean cast) {
         if (x instanceof Short)
-            return ((Short) x).shortValue();
+            return (Short) x;
         return primitiveConversion(Wrapper.SHORT, x, cast).shortValue();
     }
 
+    static boolean unboxBoolean(Boolean x) {
+        return x;
+    }
     static boolean unboxBoolean(Object x, boolean cast) {
         if (x instanceof Boolean)
-            return ((Boolean) x).booleanValue();
+            return (Boolean) x;
         return (primitiveConversion(Wrapper.BOOLEAN, x, cast).intValue() & 1) != 0;
     }
 
+    static char unboxCharacter(Character x) {
+        return x;
+    }
     static char unboxCharacter(Object x, boolean cast) {
         if (x instanceof Character)
-            return ((Character) x).charValue();
+            return (Character) x;
         return (char) primitiveConversion(Wrapper.CHAR, x, cast).intValue();
     }
 
+    static long unboxLong(Long x) {
+        return x;
+    }
     static long unboxLong(Object x, boolean cast) {
         if (x instanceof Long)
-            return ((Long) x).longValue();
+            return (Long) x;
         return primitiveConversion(Wrapper.LONG, x, cast).longValue();
     }
 
+    static float unboxFloat(Float x) {
+        return x;
+    }
     static float unboxFloat(Object x, boolean cast) {
         if (x instanceof Float)
-            return ((Float) x).floatValue();
+            return (Float) x;
         return primitiveConversion(Wrapper.FLOAT, x, cast).floatValue();
     }
 
+    static double unboxDouble(Double x) {
+        return x;
+    }
     static double unboxDouble(Object x, boolean cast) {
         if (x instanceof Double)
-            return ((Double) x).doubleValue();
+            return (Double) x;
         return primitiveConversion(Wrapper.DOUBLE, x, cast).doubleValue();
     }
 
-    private static MethodType unboxType(Wrapper wrap) {
+    private static MethodType unboxType(Wrapper wrap, int kind) {
+        if (kind == 0)
+            return MethodType.methodType(wrap.primitiveType(), wrap.wrapperType());
         return MethodType.methodType(wrap.primitiveType(), Object.class, boolean.class);
     }
 
-    private static final EnumMap<Wrapper, MethodHandle>[]
-            UNBOX_CONVERSIONS = newWrapperCaches(2);
+    private static final WrapperCache[] UNBOX_CONVERSIONS = newWrapperCaches(4);
 
-    private static MethodHandle unbox(Wrapper wrap, boolean cast) {
-        EnumMap<Wrapper, MethodHandle> cache = UNBOX_CONVERSIONS[(cast?1:0)];
+    private static MethodHandle unbox(Wrapper wrap, int kind) {
+        // kind 0 -> strongly typed with NPE
+        // kind 1 -> strongly typed but zero for null,
+        // kind 2 -> asType rules: accept multiple box types but only widening conversions with NPE
+        // kind 3 -> explicitCastArguments rules: allow narrowing conversions, zero for null
+        WrapperCache cache = UNBOX_CONVERSIONS[kind];
         MethodHandle mh = cache.get(wrap);
         if (mh != null) {
             return mh;
@@ -135,41 +160,59 @@
         // slow path
         switch (wrap) {
             case OBJECT:
-                mh = IDENTITY; break;
             case VOID:
-                mh = IGNORE; break;
-        }
-        if (mh != null) {
-            cache.put(wrap, mh);
-            return mh;
+                throw new IllegalArgumentException("unbox "+wrap);
         }
         // look up the method
         String name = "unbox" + wrap.wrapperSimpleName();
-        MethodType type = unboxType(wrap);
+        MethodType type = unboxType(wrap, kind);
         try {
             mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
         } catch (ReflectiveOperationException ex) {
             mh = null;
         }
         if (mh != null) {
-            mh = MethodHandles.insertArguments(mh, 1, cast);
-            cache.put(wrap, mh);
-            return mh;
+            if (kind > 0) {
+                boolean cast = (kind != 2);
+                mh = MethodHandles.insertArguments(mh, 1, cast);
+            }
+            if (kind == 1) {  // casting but exact (null -> zero)
+                mh = mh.asType(unboxType(wrap, 0));
+            }
+            return cache.put(wrap, mh);
         }
         throw new IllegalArgumentException("cannot find unbox adapter for " + wrap
-                + (cast ? " (cast)" : ""));
+                + (kind <= 1 ? " (exact)" : kind == 3 ? " (cast)" : ""));
     }
 
-    public static MethodHandle unboxCast(Wrapper type) {
-        return unbox(type, true);
+    /** Return an exact unboxer for the given primitive type. */
+    public static MethodHandle unboxExact(Wrapper type) {
+        return unbox(type, 0);
     }
 
-    public static MethodHandle unbox(Class<?> type) {
-        return unbox(Wrapper.forPrimitiveType(type), false);
+    /** Return an exact unboxer for the given primitive type, with optional null-to-zero conversion.
+     *  The boolean says whether to throw an NPE on a null value (false means unbox a zero).
+     *  The type of the unboxer is of a form like (Integer)int.
+     */
+    public static MethodHandle unboxExact(Wrapper type, boolean throwNPE) {
+        return unbox(type, throwNPE ? 0 : 1);
     }
 
-    public static MethodHandle unboxCast(Class<?> type) {
-        return unbox(Wrapper.forPrimitiveType(type), true);
+    /** Return a widening unboxer for the given primitive type.
+     *  Widen narrower primitive boxes to the given type.
+     *  Do not narrow any primitive values or convert null to zero.
+     *  The type of the unboxer is of a form like (Object)int.
+     */
+    public static MethodHandle unboxWiden(Wrapper type) {
+        return unbox(type, 2);
+    }
+
+    /** Return a casting unboxer for the given primitive type.
+     *  Widen or narrow primitive values to the given type, or convert null to zero, as needed.
+     *  The type of the unboxer is of a form like (Object)int.
+     */
+    public static MethodHandle unboxCast(Wrapper type) {
+        return unbox(type, 3);
     }
 
     static private final Integer ZERO_INT = 0, ONE_INT = 1;
@@ -266,57 +309,26 @@
         return MethodType.methodType(boxType, wrap.primitiveType());
     }
 
-    private static final EnumMap<Wrapper, MethodHandle>[]
-            BOX_CONVERSIONS = newWrapperCaches(2);
+    private static final WrapperCache[] BOX_CONVERSIONS = newWrapperCaches(1);
 
-    private static MethodHandle box(Wrapper wrap, boolean exact) {
-        EnumMap<Wrapper, MethodHandle> cache = BOX_CONVERSIONS[(exact?1:0)];
+    public static MethodHandle boxExact(Wrapper wrap) {
+        WrapperCache cache = BOX_CONVERSIONS[0];
         MethodHandle mh = cache.get(wrap);
         if (mh != null) {
             return mh;
         }
-        // slow path
-        switch (wrap) {
-            case OBJECT:
-                mh = IDENTITY; break;
-            case VOID:
-                mh = ZERO_OBJECT;
-                break;
-        }
-        if (mh != null) {
-            cache.put(wrap, mh);
-            return mh;
-        }
         // look up the method
         String name = "box" + wrap.wrapperSimpleName();
         MethodType type = boxType(wrap);
-        if (exact) {
-            try {
-                mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
-            } catch (ReflectiveOperationException ex) {
-                mh = null;
-            }
-        } else {
-            mh = box(wrap, !exact).asType(type.erase());
+        try {
+            mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
+        } catch (ReflectiveOperationException ex) {
+            mh = null;
         }
         if (mh != null) {
-            cache.put(wrap, mh);
-            return mh;
+            return cache.put(wrap, mh);
         }
-        throw new IllegalArgumentException("cannot find box adapter for "
-                + wrap + (exact ? " (exact)" : ""));
-    }
-
-    public static MethodHandle box(Class<?> type) {
-        boolean exact = false;
-        // e.g., boxShort(short)Short if exact,
-        // e.g., boxShort(short)Object if !exact
-        return box(Wrapper.forPrimitiveType(type), exact);
-    }
-
-    public static MethodHandle box(Wrapper type) {
-        boolean exact = false;
-        return box(type, exact);
+        throw new IllegalArgumentException("cannot find box adapter for " + wrap);
     }
 
     /// Constant functions
@@ -348,11 +360,10 @@
         return 0;
     }
 
-    private static final EnumMap<Wrapper, MethodHandle>[]
-            CONSTANT_FUNCTIONS = newWrapperCaches(2);
+    private static final WrapperCache[] CONSTANT_FUNCTIONS = newWrapperCaches(2);
 
     public static MethodHandle zeroConstantFunction(Wrapper wrap) {
-        EnumMap<Wrapper, MethodHandle> cache = CONSTANT_FUNCTIONS[0];
+        WrapperCache cache = CONSTANT_FUNCTIONS[0];
         MethodHandle mh = cache.get(wrap);
         if (mh != null) {
             return mh;
@@ -373,184 +384,37 @@
                 break;
         }
         if (mh != null) {
-            cache.put(wrap, mh);
-            return mh;
+            return cache.put(wrap, mh);
         }
 
         // use zeroInt and cast the result
         if (wrap.isSubwordOrInt() && wrap != Wrapper.INT) {
             mh = MethodHandles.explicitCastArguments(zeroConstantFunction(Wrapper.INT), type);
-            cache.put(wrap, mh);
-            return mh;
+            return cache.put(wrap, mh);
         }
         throw new IllegalArgumentException("cannot find zero constant for " + wrap);
     }
 
-    /// Converting references to references.
-
-    /**
-     * Identity function.
-     * @param x an arbitrary reference value
-     * @return the same value x
-     */
-    static <T> T identity(T x) {
-        return x;
-    }
-
-    static <T> T[] identity(T[] x) {
-        return x;
-    }
-
-    /**
-     * Identity function on ints.
-     * @param x an arbitrary int value
-     * @return the same value x
-     */
-    static int identity(int x) {
-        return x;
-    }
-
-    static byte identity(byte x) {
-        return x;
-    }
-
-    static short identity(short x) {
-        return x;
-    }
-
-    static boolean identity(boolean x) {
-        return x;
-    }
-
-    static char identity(char x) {
-        return x;
-    }
-
-    /**
-     * Identity function on longs.
-     * @param x an arbitrary long value
-     * @return the same value x
-     */
-    static long identity(long x) {
-        return x;
-    }
-
-    static float identity(float x) {
-        return x;
-    }
-
-    static double identity(double x) {
-        return x;
-    }
-
-    private static ClassCastException newClassCastException(Class<?> t, Object obj) {
-        return new ClassCastException("Cannot cast " + obj.getClass().getName() + " to " + t.getName());
-    }
-
-    private static final MethodHandle IDENTITY, CAST_REFERENCE, ZERO_OBJECT, IGNORE, EMPTY,
-            ARRAY_IDENTITY, FILL_NEW_TYPED_ARRAY, FILL_NEW_ARRAY;
+    private static final MethodHandle CAST_REFERENCE, IGNORE, EMPTY;
     static {
         try {
             MethodType idType = MethodType.genericMethodType(1);
             MethodType ignoreType = idType.changeReturnType(void.class);
-            MethodType zeroObjectType = MethodType.genericMethodType(0);
-            IDENTITY = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", idType);
             CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType);
-            ZERO_OBJECT = IMPL_LOOKUP.findStatic(THIS_CLASS, "zeroObject", zeroObjectType);
             IGNORE = IMPL_LOOKUP.findStatic(THIS_CLASS, "ignore", ignoreType);
             EMPTY = IMPL_LOOKUP.findStatic(THIS_CLASS, "empty", ignoreType.dropParameterTypes(0, 1));
-            ARRAY_IDENTITY = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", MethodType.methodType(Object[].class, Object[].class));
-            FILL_NEW_ARRAY = IMPL_LOOKUP
-                    .findStatic(THIS_CLASS, "fillNewArray",
-                          MethodType.methodType(Object[].class, Integer.class, Object[].class));
-            FILL_NEW_TYPED_ARRAY = IMPL_LOOKUP
-                    .findStatic(THIS_CLASS, "fillNewTypedArray",
-                          MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class));
         } catch (NoSuchMethodException | IllegalAccessException ex) {
             throw newInternalError("uncaught exception", ex);
         }
     }
 
-    // Varargs methods need to be in a separately initialized class, to avoid bootstrapping problems.
-    static class LazyStatics {
-        private static final MethodHandle COPY_AS_REFERENCE_ARRAY, COPY_AS_PRIMITIVE_ARRAY, MAKE_LIST;
-        static {
-            try {
-                //MAKE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "makeArray", MethodType.methodType(Object[].class, Object[].class));
-                COPY_AS_REFERENCE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "copyAsReferenceArray", MethodType.methodType(Object[].class, Class.class, Object[].class));
-                COPY_AS_PRIMITIVE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "copyAsPrimitiveArray", MethodType.methodType(Object.class, Wrapper.class, Object[].class));
-                MAKE_LIST = IMPL_LOOKUP.findStatic(THIS_CLASS, "makeList", MethodType.methodType(List.class, Object[].class));
-            } catch (ReflectiveOperationException ex) {
-                throw newInternalError("uncaught exception", ex);
-            }
-        }
+    public static MethodHandle ignore() {
+        return IGNORE;
     }
 
-    private static final EnumMap<Wrapper, MethodHandle>[] WRAPPER_CASTS
-            = newWrapperCaches(1);
-
-    /** Return a method that casts its sole argument (an Object) to the given type
-     *  and returns it as the given type.
-     */
-    public static MethodHandle cast(Class<?> type) {
-        return cast(type, CAST_REFERENCE);
-    }
-    public static MethodHandle cast(Class<?> type, MethodHandle castReference) {
-        if (type.isPrimitive())  throw new IllegalArgumentException("cannot cast primitive type "+type);
-        MethodHandle mh;
-        Wrapper wrap = null;
-        EnumMap<Wrapper, MethodHandle> cache = null;
-        if (Wrapper.isWrapperType(type)) {
-            wrap = Wrapper.forWrapperType(type);
-            cache = WRAPPER_CASTS[0];
-            mh = cache.get(wrap);
-            if (mh != null)  return mh;
-        }
-        mh = MethodHandles.insertArguments(castReference, 0, type);
-        if (cache != null)
-            cache.put(wrap, mh);
-        return mh;
-    }
-
-    public static MethodHandle identity() {
-        return IDENTITY;
-    }
-
-    public static MethodHandle identity(Class<?> type) {
-        if (!type.isPrimitive())
-            // Reference identity has been moved into MethodHandles:
-            return MethodHandles.identity(type);
-        return identity(Wrapper.findPrimitiveType(type));
-    }
-
-    public static MethodHandle identity(Wrapper wrap) {
-        EnumMap<Wrapper, MethodHandle> cache = CONSTANT_FUNCTIONS[1];
-        MethodHandle mh = cache.get(wrap);
-        if (mh != null) {
-            return mh;
-        }
-        // slow path
-        MethodType type = MethodType.methodType(wrap.primitiveType());
-        if (wrap != Wrapper.VOID)
-            type = type.appendParameterTypes(wrap.primitiveType());
-        try {
-            mh = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", type);
-        } catch (ReflectiveOperationException ex) {
-            mh = null;
-        }
-        if (mh == null && wrap == Wrapper.VOID) {
-            mh = EMPTY;  // #(){} : #()void
-        }
-        if (mh != null) {
-            cache.put(wrap, mh);
-            return mh;
-        }
-
-        if (mh != null) {
-            cache.put(wrap, mh);
-            return mh;
-        }
-        throw new IllegalArgumentException("cannot find identity for " + wrap);
+    /** Return a method that casts its second argument (an Object) to the given type (a Class). */
+    public static MethodHandle cast() {
+        return CAST_REFERENCE;
     }
 
     /// Primitive conversions.
@@ -759,11 +623,10 @@
         return (x ? (byte)1 : (byte)0);
     }
 
-    private static final EnumMap<Wrapper, MethodHandle>[]
-            CONVERT_PRIMITIVE_FUNCTIONS = newWrapperCaches(Wrapper.values().length);
+    private static final WrapperCache[] CONVERT_PRIMITIVE_FUNCTIONS = newWrapperCaches(Wrapper.values().length);
 
     public static MethodHandle convertPrimitive(Wrapper wsrc, Wrapper wdst) {
-        EnumMap<Wrapper, MethodHandle> cache = CONVERT_PRIMITIVE_FUNCTIONS[wsrc.ordinal()];
+        WrapperCache cache = CONVERT_PRIMITIVE_FUNCTIONS[wsrc.ordinal()];
         MethodHandle mh = cache.get(wdst);
         if (mh != null) {
             return mh;
@@ -771,17 +634,9 @@
         // slow path
         Class<?> src = wsrc.primitiveType();
         Class<?> dst = wdst.primitiveType();
-        MethodType type = src == void.class ? MethodType.methodType(dst) : MethodType.methodType(dst, src);
+        MethodType type = MethodType.methodType(dst, src);
         if (wsrc == wdst) {
-            mh = identity(src);
-        } else if (wsrc == Wrapper.VOID) {
-            mh = zeroConstantFunction(wdst);
-        } else if (wdst == Wrapper.VOID) {
-            mh = MethodHandles.dropArguments(EMPTY, 0, src);  // Defer back to MethodHandles.
-        } else if (wsrc == Wrapper.OBJECT) {
-            mh = unboxCast(dst);
-        } else if (wdst == Wrapper.OBJECT) {
-            mh = box(src);
+            mh = MethodHandles.identity(src);
         } else {
             assert(src.isPrimitive() && dst.isPrimitive());
             try {
@@ -792,8 +647,7 @@
         }
         if (mh != null) {
             assert(mh.type() == type) : mh;
-            cache.put(wdst, mh);
-            return mh;
+            return cache.put(wdst, mh);
         }
 
         throw new IllegalArgumentException("cannot find primitive conversion function for " +
@@ -808,363 +662,6 @@
         return Character.toUpperCase(x.charAt(0))+x.substring(1);
     }
 
-    /// Collection of multiple arguments.
-
-    public static Object convertArrayElements(Class<?> arrayType, Object array) {
-        Class<?> src = array.getClass().getComponentType();
-        Class<?> dst = arrayType.getComponentType();
-        if (src == null || dst == null)  throw new IllegalArgumentException("not array type");
-        Wrapper sw = (src.isPrimitive() ? Wrapper.forPrimitiveType(src) : null);
-        Wrapper dw = (dst.isPrimitive() ? Wrapper.forPrimitiveType(dst) : null);
-        int length;
-        if (sw == null) {
-            Object[] a = (Object[]) array;
-            length = a.length;
-            if (dw == null)
-                return Arrays.copyOf(a, length, arrayType.asSubclass(Object[].class));
-            Object res = dw.makeArray(length);
-            dw.copyArrayUnboxing(a, 0, res, 0, length);
-            return res;
-        }
-        length = java.lang.reflect.Array.getLength(array);
-        Object[] res;
-        if (dw == null) {
-            res = Arrays.copyOf(NO_ARGS_ARRAY, length, arrayType.asSubclass(Object[].class));
-        } else {
-            res = new Object[length];
-        }
-        sw.copyArrayBoxing(array, 0, res, 0, length);
-        if (dw == null)  return res;
-        Object a = dw.makeArray(length);
-        dw.copyArrayUnboxing(res, 0, a, 0, length);
-        return a;
-    }
-
-    private static MethodHandle findCollector(String name, int nargs, Class<?> rtype, Class<?>... ptypes) {
-        MethodType type = MethodType.genericMethodType(nargs)
-                .changeReturnType(rtype)
-                .insertParameterTypes(0, ptypes);
-        try {
-            return IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
-        } catch (ReflectiveOperationException ex) {
-            return null;
-        }
-    }
-
-    private static final Object[] NO_ARGS_ARRAY = {};
-    private static Object[] makeArray(Object... args) { return args; }
-    private static Object[] array() { return NO_ARGS_ARRAY; }
-    private static Object[] array(Object a0)
-                { return makeArray(a0); }
-    private static Object[] array(Object a0, Object a1)
-                { return makeArray(a0, a1); }
-    private static Object[] array(Object a0, Object a1, Object a2)
-                { return makeArray(a0, a1, a2); }
-    private static Object[] array(Object a0, Object a1, Object a2, Object a3)
-                { return makeArray(a0, a1, a2, a3); }
-    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
-                                  Object a4)
-                { return makeArray(a0, a1, a2, a3, a4); }
-    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
-                                  Object a4, Object a5)
-                { return makeArray(a0, a1, a2, a3, a4, a5); }
-    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
-                                  Object a4, Object a5, Object a6)
-                { return makeArray(a0, a1, a2, a3, a4, a5, a6); }
-    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
-                                  Object a4, Object a5, Object a6, Object a7)
-                { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); }
-    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
-                                  Object a4, Object a5, Object a6, Object a7,
-                                  Object a8)
-                { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
-    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
-                                  Object a4, Object a5, Object a6, Object a7,
-                                  Object a8, Object a9)
-                { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
-    private static MethodHandle[] makeArrays() {
-        ArrayList<MethodHandle> mhs = new ArrayList<>();
-        for (;;) {
-            MethodHandle mh = findCollector("array", mhs.size(), Object[].class);
-            if (mh == null)  break;
-            mhs.add(mh);
-        }
-        assert(mhs.size() == 11);  // current number of methods
-        return mhs.toArray(new MethodHandle[MAX_ARITY+1]);
-    }
-    private static final MethodHandle[] ARRAYS = makeArrays();
-
-    // filling versions of the above:
-    // using Integer len instead of int len and no varargs to avoid bootstrapping problems
-    private static Object[] fillNewArray(Integer len, Object[] /*not ...*/ args) {
-        Object[] a = new Object[len];
-        fillWithArguments(a, 0, args);
-        return a;
-    }
-    private static Object[] fillNewTypedArray(Object[] example, Integer len, Object[] /*not ...*/ args) {
-        Object[] a = Arrays.copyOf(example, len);
-        fillWithArguments(a, 0, args);
-        return a;
-    }
-    private static void fillWithArguments(Object[] a, int pos, Object... args) {
-        System.arraycopy(args, 0, a, pos, args.length);
-    }
-    // using Integer pos instead of int pos to avoid bootstrapping problems
-    private static Object[] fillArray(Integer pos, Object[] a, Object a0)
-                { fillWithArguments(a, pos, a0); return a; }
-    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1)
-                { fillWithArguments(a, pos, a0, a1); return a; }
-    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2)
-                { fillWithArguments(a, pos, a0, a1, a2); return a; }
-    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3)
-                { fillWithArguments(a, pos, a0, a1, a2, a3); return a; }
-    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
-                                  Object a4)
-                { fillWithArguments(a, pos, a0, a1, a2, a3, a4); return a; }
-    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
-                                  Object a4, Object a5)
-                { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5); return a; }
-    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
-                                  Object a4, Object a5, Object a6)
-                { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6); return a; }
-    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
-                                  Object a4, Object a5, Object a6, Object a7)
-                { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7); return a; }
-    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
-                                  Object a4, Object a5, Object a6, Object a7,
-                                  Object a8)
-                { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8); return a; }
-    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
-                                  Object a4, Object a5, Object a6, Object a7,
-                                  Object a8, Object a9)
-                { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); return a; }
-    private static MethodHandle[] makeFillArrays() {
-        ArrayList<MethodHandle> mhs = new ArrayList<>();
-        mhs.add(null);  // there is no empty fill; at least a0 is required
-        for (;;) {
-            MethodHandle mh = findCollector("fillArray", mhs.size(), Object[].class, Integer.class, Object[].class);
-            if (mh == null)  break;
-            mhs.add(mh);
-        }
-        assert(mhs.size() == 11);  // current number of methods
-        return mhs.toArray(new MethodHandle[0]);
-    }
-    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);
-        return a;
-    }
-
-    /** Return a method handle that takes the indicated number of Object
-     *  arguments and returns an Object array of them, as if for varargs.
-     */
-    public static MethodHandle varargsArray(int nargs) {
-        MethodHandle mh = ARRAYS[nargs];
-        if (mh != null)  return mh;
-        mh = findCollector("array", nargs, Object[].class);
-        if (mh != null)  return ARRAYS[nargs] = mh;
-        mh = buildVarargsArray(FILL_NEW_ARRAY, ARRAY_IDENTITY, nargs);
-        assert(assertCorrectArity(mh, nargs));
-        return ARRAYS[nargs] = mh;
-    }
-
-    private static boolean assertCorrectArity(MethodHandle mh, int arity) {
-        assert(mh.type().parameterCount() == arity) : "arity != "+arity+": "+mh;
-        return true;
-    }
-
-    private static MethodHandle buildVarargsArray(MethodHandle newArray, MethodHandle finisher, int nargs) {
-        // Build up the result mh as a sequence of fills like this:
-        //   finisher(fill(fill(newArrayWA(23,x1..x10),10,x11..x20),20,x21..x23))
-        // The various fill(_,10*I,___*[J]) are reusable.
-        int leftLen = Math.min(nargs, LEFT_ARGS);  // absorb some arguments immediately
-        int rightLen = nargs - leftLen;
-        MethodHandle leftCollector = newArray.bindTo(nargs);
-        leftCollector = leftCollector.asCollector(Object[].class, leftLen);
-        MethodHandle mh = finisher;
-        if (rightLen > 0) {
-            MethodHandle rightFiller = fillToRight(LEFT_ARGS + rightLen);
-            if (mh == ARRAY_IDENTITY)
-                mh = rightFiller;
-            else
-                mh = MethodHandles.collectArguments(mh, 0, rightFiller);
-        }
-        if (mh == ARRAY_IDENTITY)
-            mh = leftCollector;
-        else
-            mh = MethodHandles.collectArguments(mh, 0, leftCollector);
-        return mh;
-    }
-
-    private static final int LEFT_ARGS = (FILL_ARRAYS.length - 1);
-    private static final MethodHandle[] FILL_ARRAY_TO_RIGHT = new MethodHandle[MAX_ARITY+1];
-    /** fill_array_to_right(N).invoke(a, argL..arg[N-1])
-     *  fills a[L]..a[N-1] with corresponding arguments,
-     *  and then returns a.  The value L is a global constant (LEFT_ARGS).
-     */
-    private static MethodHandle fillToRight(int nargs) {
-        MethodHandle filler = FILL_ARRAY_TO_RIGHT[nargs];
-        if (filler != null)  return filler;
-        filler = buildFiller(nargs);
-        assert(assertCorrectArity(filler, nargs - LEFT_ARGS + 1));
-        return FILL_ARRAY_TO_RIGHT[nargs] = filler;
-    }
-    private static MethodHandle buildFiller(int nargs) {
-        if (nargs <= LEFT_ARGS)
-            return ARRAY_IDENTITY;  // no args to fill; return the array unchanged
-        // we need room for both mh and a in mh.invoke(a, arg*[nargs])
-        final int CHUNK = LEFT_ARGS;
-        int rightLen = nargs % CHUNK;
-        int midLen = nargs - rightLen;
-        if (rightLen == 0) {
-            midLen = nargs - (rightLen = CHUNK);
-            if (FILL_ARRAY_TO_RIGHT[midLen] == null) {
-                // build some precursors from left to right
-                for (int j = LEFT_ARGS % CHUNK; j < midLen; j += CHUNK)
-                    if (j > LEFT_ARGS)  fillToRight(j);
-            }
-        }
-        if (midLen < LEFT_ARGS) rightLen = nargs - (midLen = LEFT_ARGS);
-        assert(rightLen > 0);
-        MethodHandle midFill = fillToRight(midLen);  // recursive fill
-        MethodHandle rightFill = FILL_ARRAYS[rightLen].bindTo(midLen);  // [midLen..nargs-1]
-        assert(midFill.type().parameterCount()   == 1 + midLen - LEFT_ARGS);
-        assert(rightFill.type().parameterCount() == 1 + rightLen);
-
-        // Combine the two fills:
-        //   right(mid(a, x10..x19), x20..x23)
-        // The final product will look like this:
-        //   right(mid(newArrayLeft(24, x0..x9), x10..x19), x20..x23)
-        if (midLen == LEFT_ARGS)
-            return rightFill;
-        else
-            return MethodHandles.collectArguments(rightFill, 0, midFill);
-    }
-
-    // Type-polymorphic version of varargs maker.
-    private static final ClassValue<MethodHandle[]> TYPED_COLLECTORS
-        = new ClassValue<MethodHandle[]>() {
-            @Override
-            protected MethodHandle[] computeValue(Class<?> type) {
-                return new MethodHandle[256];
-            }
-    };
-
-    static final int MAX_JVM_ARITY = 255;  // limit imposed by the JVM
-
-    /** Return a method handle that takes the indicated number of
-     *  typed arguments and returns an array of them.
-     *  The type argument is the array type.
-     */
-    public static MethodHandle varargsArray(Class<?> arrayType, int nargs) {
-        Class<?> elemType = arrayType.getComponentType();
-        if (elemType == null)  throw new IllegalArgumentException("not an array: "+arrayType);
-        // FIXME: Need more special casing and caching here.
-        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)
-                throw new IllegalArgumentException("too many arguments: "+arrayType.getSimpleName()+", length "+nargs);
-        }
-        if (elemType == Object.class)
-            return varargsArray(nargs);
-        // other cases:  primitive arrays, subtypes of Object[]
-        MethodHandle cache[] = TYPED_COLLECTORS.get(elemType);
-        MethodHandle mh = nargs < cache.length ? cache[nargs] : null;
-        if (mh != null)  return mh;
-        if (elemType.isPrimitive()) {
-            MethodHandle builder = FILL_NEW_ARRAY;
-            MethodHandle producer = buildArrayProducer(arrayType);
-            mh = buildVarargsArray(builder, producer, nargs);
-        } else {
-            @SuppressWarnings("unchecked")
-            Class<? extends Object[]> objArrayType = (Class<? extends Object[]>) arrayType;
-            Object[] example = Arrays.copyOf(NO_ARGS_ARRAY, 0, objArrayType);
-            MethodHandle builder = FILL_NEW_TYPED_ARRAY.bindTo(example);
-            MethodHandle producer = ARRAY_IDENTITY;
-            mh = buildVarargsArray(builder, producer, nargs);
-        }
-        mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)));
-        assert(assertCorrectArity(mh, nargs));
-        if (nargs < cache.length)
-            cache[nargs] = mh;
-        return mh;
-    }
-
-    private static MethodHandle buildArrayProducer(Class<?> arrayType) {
-        Class<?> elemType = arrayType.getComponentType();
-        if (elemType.isPrimitive())
-            return LazyStatics.COPY_AS_PRIMITIVE_ARRAY.bindTo(Wrapper.forPrimitiveType(elemType));
-        else
-            return LazyStatics.COPY_AS_REFERENCE_ARRAY.bindTo(arrayType);
-    }
-
-    // List version of varargs maker.
-
-    private static final List<Object> NO_ARGS_LIST = Arrays.asList(NO_ARGS_ARRAY);
-    private static List<Object> makeList(Object... args) { return Arrays.asList(args); }
-    private static List<Object> list() { return NO_ARGS_LIST; }
-    private static List<Object> list(Object a0)
-                { return makeList(a0); }
-    private static List<Object> list(Object a0, Object a1)
-                { return makeList(a0, a1); }
-    private static List<Object> list(Object a0, Object a1, Object a2)
-                { return makeList(a0, a1, a2); }
-    private static List<Object> list(Object a0, Object a1, Object a2, Object a3)
-                { return makeList(a0, a1, a2, a3); }
-    private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
-                                     Object a4)
-                { return makeList(a0, a1, a2, a3, a4); }
-    private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
-                                     Object a4, Object a5)
-                { return makeList(a0, a1, a2, a3, a4, a5); }
-    private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
-                                     Object a4, Object a5, Object a6)
-                { return makeList(a0, a1, a2, a3, a4, a5, a6); }
-    private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
-                                     Object a4, Object a5, Object a6, Object a7)
-                { return makeList(a0, a1, a2, a3, a4, a5, a6, a7); }
-    private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
-                                     Object a4, Object a5, Object a6, Object a7,
-                                     Object a8)
-                { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
-    private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
-                                     Object a4, Object a5, Object a6, Object a7,
-                                     Object a8, Object a9)
-                { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
-    private static MethodHandle[] makeLists() {
-        ArrayList<MethodHandle> mhs = new ArrayList<>();
-        for (;;) {
-            MethodHandle mh = findCollector("list", mhs.size(), List.class);
-            if (mh == null)  break;
-            mhs.add(mh);
-        }
-        assert(mhs.size() == 11);  // current number of methods
-        return mhs.toArray(new MethodHandle[MAX_ARITY+1]);
-    }
-    private static final MethodHandle[] LISTS = makeLists();
-
-    /** Return a method handle that takes the indicated number of Object
-     *  arguments and returns a List.
-     */
-    public static MethodHandle varargsList(int nargs) {
-        MethodHandle mh = LISTS[nargs];
-        if (mh != null)  return mh;
-        mh = findCollector("list", nargs, List.class);
-        if (mh != null)  return LISTS[nargs] = mh;
-        return LISTS[nargs] = buildVarargsList(nargs);
-    }
-    private static MethodHandle buildVarargsList(int nargs) {
-        return MethodHandles.filterReturnValue(varargsArray(nargs), LazyStatics.MAKE_LIST);
-    }
-
     // handy shared exception makers (they simplify the common case code)
     private static InternalError newInternalError(String message, Throwable cause) {
         return new InternalError(message, cause);
--- a/src/java.base/share/classes/sun/invoke/util/VerifyType.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/invoke/util/VerifyType.java	Fri Sep 12 10:33:32 2014 -0700
@@ -40,18 +40,38 @@
     /**
      * True if a value can be stacked as the source type and unstacked as the
      * destination type, without violating the JVM's type consistency.
+     * <p>
+     * If both types are references, we apply the verifier's subclass check
+     * (or subtyping, if keepInterfaces).
+     * If the src type is a type guaranteed to be null (Void) it can be converted
+     * to any other reference type.
+     * <p>
+     * If both types are primitives, we apply the verifier's primitive conversions.
+     * These do not include Java conversions such as long to double, since those
+     * require computation and (in general) stack depth changes.
+     * But very simple 32-bit viewing changes, such as byte to int,
+     * are null conversions, because they do not require any computation.
+     * These conversions are from any type to a wider type up to 32 bits,
+     * as long as the conversion is not signed to unsigned (byte to char).
+     * <p>
+     * The primitive type 'void' does not interconvert with any other type,
+     * even though it is legal to drop any type from the stack and "return void".
+     * The stack effects, though are different between void and any other type,
+     * so it is safer to report a non-trivial conversion.
      *
      * @param src the type of a stacked value
      * @param dst the type by which we'd like to treat it
+     * @param keepInterfaces if false, we treat any interface as if it were Object
      * @return whether the retyping can be done without motion or reformatting
      */
-    public static boolean isNullConversion(Class<?> src, Class<?> dst) {
+    public static boolean isNullConversion(Class<?> src, Class<?> dst, boolean keepInterfaces) {
         if (src == dst)            return true;
         // Verifier allows any interface to be treated as Object:
-        if (dst.isInterface())     dst = Object.class;
-        if (src.isInterface())     src = Object.class;
-        if (src == dst)            return true;  // check again
-        if (dst == void.class)     return true;  // drop any return value
+        if (!keepInterfaces) {
+            if (dst.isInterface())  dst = Object.class;
+            if (src.isInterface())  src = Object.class;
+            if (src == dst)         return true;  // check again
+        }
         if (isNullType(src))       return !dst.isPrimitive();
         if (!src.isPrimitive())    return dst.isAssignableFrom(src);
         if (!dst.isPrimitive())    return false;
@@ -82,25 +102,13 @@
      * Is the given type java.lang.Null or an equivalent null-only type?
      */
     public static boolean isNullType(Class<?> type) {
-        if (type == null)  return false;
-        return type == NULL_CLASS
-            // This one may also be used as a null type.
-            // TO DO: Decide if we really want to legitimize it here.
-            // Probably we do, unless java.lang.Null really makes it into Java 7
-            //|| type == Void.class
-            // Locally known null-only class:
-            || type == Empty.class
-            ;
-    }
-    private static final Class<?> NULL_CLASS;
-    static {
-        Class<?> nullClass = null;
-        try {
-            nullClass = Class.forName("java.lang.Null");
-        } catch (ClassNotFoundException ex) {
-            // OK, we'll cope
-        }
-        NULL_CLASS = nullClass;
+        // Any reference statically typed as Void is guaranteed to be null.
+        // Therefore, it can be safely treated as a value of any
+        // other type that admits null, i.e., a reference type.
+        if (type == Void.class)  return true;
+        // Locally known null-only class:
+        if (type == Empty.class)  return true;
+        return false;
     }
 
     /**
@@ -111,14 +119,14 @@
      * @param recv the type of the method handle receiving the call
      * @return whether the retyping can be done without motion or reformatting
      */
-    public static boolean isNullConversion(MethodType call, MethodType recv) {
+    public static boolean isNullConversion(MethodType call, MethodType recv, boolean keepInterfaces) {
         if (call == recv)  return true;
         int len = call.parameterCount();
         if (len != recv.parameterCount())  return false;
         for (int i = 0; i < len; i++)
-            if (!isNullConversion(call.parameterType(i), recv.parameterType(i)))
+            if (!isNullConversion(call.parameterType(i), recv.parameterType(i), keepInterfaces))
                 return false;
-        return isNullConversion(recv.returnType(), call.returnType());
+        return isNullConversion(recv.returnType(), call.returnType(), keepInterfaces);
     }
 
     /**
--- a/src/java.base/share/classes/sun/invoke/util/Wrapper.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/invoke/util/Wrapper.java	Fri Sep 12 10:33:32 2014 -0700
@@ -230,14 +230,6 @@
      */
     public <T> T zero(Class<T> type) { return convert(zero, type); }
 
-//    /** Produce a wrapper for the given wrapper or primitive type. */
-//    public static Wrapper valueOf(Class<?> type) {
-//        if (isPrimitiveType(type))
-//            return forPrimitiveType(type);
-//        else
-//            return forWrapperType(type);
-//    }
-
     /** Return the wrapper that wraps values of the given type.
      *  The type may be {@code Object}, meaning the {@code OBJECT} wrapper.
      *  Otherwise, the type must be a primitive.
--- a/src/java.base/share/classes/sun/reflect/AccessorGenerator.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/AccessorGenerator.java	Fri Sep 12 10:33:32 2014 -0700
@@ -69,33 +69,34 @@
     protected short codeIdx;
     protected short exceptionsIdx;
     // Boxing
+    protected short valueOfIdx;
     protected short booleanIdx;
-    protected short booleanCtorIdx;
+    protected short booleanBoxIdx;
     protected short booleanUnboxIdx;
     protected short byteIdx;
-    protected short byteCtorIdx;
+    protected short byteBoxIdx;
     protected short byteUnboxIdx;
     protected short characterIdx;
-    protected short characterCtorIdx;
+    protected short characterBoxIdx;
     protected short characterUnboxIdx;
     protected short doubleIdx;
-    protected short doubleCtorIdx;
+    protected short doubleBoxIdx;
     protected short doubleUnboxIdx;
     protected short floatIdx;
-    protected short floatCtorIdx;
+    protected short floatBoxIdx;
     protected short floatUnboxIdx;
     protected short integerIdx;
-    protected short integerCtorIdx;
+    protected short integerBoxIdx;
     protected short integerUnboxIdx;
     protected short longIdx;
-    protected short longCtorIdx;
+    protected short longBoxIdx;
     protected short longUnboxIdx;
     protected short shortIdx;
-    protected short shortCtorIdx;
+    protected short shortBoxIdx;
     protected short shortUnboxIdx;
 
     protected final short NUM_COMMON_CPOOL_ENTRIES = (short) 30;
-    protected final short NUM_BOXING_CPOOL_ENTRIES = (short) 72;
+    protected final short NUM_BOXING_CPOOL_ENTRIES = (short) 73;
 
     // Requires that superClass has been set up
     protected void emitCommonConstantPoolEntries() {
@@ -181,9 +182,10 @@
     /** Constant pool entries required to be able to box/unbox primitive
         types. Note that we don't emit these if we don't need them. */
     protected void emitBoxingContantPoolEntries() {
+        //  *  [UTF-8] "valueOf"
         //  *  [UTF-8] "java/lang/Boolean"
         //  *  [CONSTANT_Class_info] for above
-        //  *  [UTF-8] "(Z)V"
+        //  *  [UTF-8] "(Z)Ljava/lang/Boolean;"
         //  *  [CONSTANT_NameAndType_info] for above
         //  *  [CONSTANT_Methodref_info] for above
         //  *  [UTF-8] "booleanValue"
@@ -192,7 +194,7 @@
         //  *  [CONSTANT_Methodref_info] for above
         //  *  [UTF-8] "java/lang/Byte"
         //  *  [CONSTANT_Class_info] for above
-        //  *  [UTF-8] "(B)V"
+        //  *  [UTF-8] "(B)Ljava/lang/Byte;"
         //  *  [CONSTANT_NameAndType_info] for above
         //  *  [CONSTANT_Methodref_info] for above
         //  *  [UTF-8] "byteValue"
@@ -201,7 +203,7 @@
         //  *  [CONSTANT_Methodref_info] for above
         //  *  [UTF-8] "java/lang/Character"
         //  *  [CONSTANT_Class_info] for above
-        //  *  [UTF-8] "(C)V"
+        //  *  [UTF-8] "(C)Ljava/lang/Character;"
         //  *  [CONSTANT_NameAndType_info] for above
         //  *  [CONSTANT_Methodref_info] for above
         //  *  [UTF-8] "charValue"
@@ -210,7 +212,7 @@
         //  *  [CONSTANT_Methodref_info] for above
         //  *  [UTF-8] "java/lang/Double"
         //  *  [CONSTANT_Class_info] for above
-        //  *  [UTF-8] "(D)V"
+        //  *  [UTF-8] "(D)Ljava/lang/Double;"
         //  *  [CONSTANT_NameAndType_info] for above
         //  *  [CONSTANT_Methodref_info] for above
         //  *  [UTF-8] "doubleValue"
@@ -219,7 +221,7 @@
         //  *  [CONSTANT_Methodref_info] for above
         //  *  [UTF-8] "java/lang/Float"
         //  *  [CONSTANT_Class_info] for above
-        //  *  [UTF-8] "(F)V"
+        //  *  [UTF-8] "(F)Ljava/lang/Float;"
         //  *  [CONSTANT_NameAndType_info] for above
         //  *  [CONSTANT_Methodref_info] for above
         //  *  [UTF-8] "floatValue"
@@ -228,7 +230,7 @@
         //  *  [CONSTANT_Methodref_info] for above
         //  *  [UTF-8] "java/lang/Integer"
         //  *  [CONSTANT_Class_info] for above
-        //  *  [UTF-8] "(I)V"
+        //  *  [UTF-8] "(I)Ljava/lang/Integer;"
         //  *  [CONSTANT_NameAndType_info] for above
         //  *  [CONSTANT_Methodref_info] for above
         //  *  [UTF-8] "intValue"
@@ -237,7 +239,7 @@
         //  *  [CONSTANT_Methodref_info] for above
         //  *  [UTF-8] "java/lang/Long"
         //  *  [CONSTANT_Class_info] for above
-        //  *  [UTF-8] "(J)V"
+        //  *  [UTF-8] "(J)Ljava/lang/Long;"
         //  *  [CONSTANT_NameAndType_info] for above
         //  *  [CONSTANT_Methodref_info] for above
         //  *  [UTF-8] "longValue"
@@ -246,21 +248,26 @@
         //  *  [CONSTANT_Methodref_info] for above
         //  *  [UTF-8] "java/lang/Short"
         //  *  [CONSTANT_Class_info] for above
-        //  *  [UTF-8] "(S)V"
+        //  *  [UTF-8] "(S)Ljava/lang/Short;"
         //  *  [CONSTANT_NameAndType_info] for above
         //  *  [CONSTANT_Methodref_info] for above
         //  *  [UTF-8] "shortValue"
         //  *  [UTF-8] "()S"
         //  *  [CONSTANT_NameAndType_info] for above
         //  *  [CONSTANT_Methodref_info] for above
+
+        // valueOf-method name
+        asm.emitConstantPoolUTF8("valueOf");
+        valueOfIdx = asm.cpi();
+
         // Boolean
         asm.emitConstantPoolUTF8("java/lang/Boolean");
         asm.emitConstantPoolClass(asm.cpi());
         booleanIdx = asm.cpi();
-        asm.emitConstantPoolUTF8("(Z)V");
-        asm.emitConstantPoolNameAndType(initIdx, asm.cpi());
+        asm.emitConstantPoolUTF8("(Z)Ljava/lang/Boolean;");
+        asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi());
         asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi());
-        booleanCtorIdx = asm.cpi();
+        booleanBoxIdx = asm.cpi();
         asm.emitConstantPoolUTF8("booleanValue");
         asm.emitConstantPoolUTF8("()Z");
         asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
@@ -271,10 +278,10 @@
         asm.emitConstantPoolUTF8("java/lang/Byte");
         asm.emitConstantPoolClass(asm.cpi());
         byteIdx = asm.cpi();
-        asm.emitConstantPoolUTF8("(B)V");
-        asm.emitConstantPoolNameAndType(initIdx, asm.cpi());
+        asm.emitConstantPoolUTF8("(B)Ljava/lang/Byte;");
+        asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi());
         asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi());
-        byteCtorIdx = asm.cpi();
+        byteBoxIdx = asm.cpi();
         asm.emitConstantPoolUTF8("byteValue");
         asm.emitConstantPoolUTF8("()B");
         asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
@@ -285,10 +292,10 @@
         asm.emitConstantPoolUTF8("java/lang/Character");
         asm.emitConstantPoolClass(asm.cpi());
         characterIdx = asm.cpi();
-        asm.emitConstantPoolUTF8("(C)V");
-        asm.emitConstantPoolNameAndType(initIdx, asm.cpi());
+        asm.emitConstantPoolUTF8("(C)Ljava/lang/Character;");
+        asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi());
         asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi());
-        characterCtorIdx = asm.cpi();
+        characterBoxIdx = asm.cpi();
         asm.emitConstantPoolUTF8("charValue");
         asm.emitConstantPoolUTF8("()C");
         asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
@@ -299,10 +306,10 @@
         asm.emitConstantPoolUTF8("java/lang/Double");
         asm.emitConstantPoolClass(asm.cpi());
         doubleIdx = asm.cpi();
-        asm.emitConstantPoolUTF8("(D)V");
-        asm.emitConstantPoolNameAndType(initIdx, asm.cpi());
+        asm.emitConstantPoolUTF8("(D)Ljava/lang/Double;");
+        asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi());
         asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi());
-        doubleCtorIdx = asm.cpi();
+        doubleBoxIdx = asm.cpi();
         asm.emitConstantPoolUTF8("doubleValue");
         asm.emitConstantPoolUTF8("()D");
         asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
@@ -313,10 +320,10 @@
         asm.emitConstantPoolUTF8("java/lang/Float");
         asm.emitConstantPoolClass(asm.cpi());
         floatIdx = asm.cpi();
-        asm.emitConstantPoolUTF8("(F)V");
-        asm.emitConstantPoolNameAndType(initIdx, asm.cpi());
+        asm.emitConstantPoolUTF8("(F)Ljava/lang/Float;");
+        asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi());
         asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi());
-        floatCtorIdx = asm.cpi();
+        floatBoxIdx = asm.cpi();
         asm.emitConstantPoolUTF8("floatValue");
         asm.emitConstantPoolUTF8("()F");
         asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
@@ -327,10 +334,10 @@
         asm.emitConstantPoolUTF8("java/lang/Integer");
         asm.emitConstantPoolClass(asm.cpi());
         integerIdx = asm.cpi();
-        asm.emitConstantPoolUTF8("(I)V");
-        asm.emitConstantPoolNameAndType(initIdx, asm.cpi());
+        asm.emitConstantPoolUTF8("(I)Ljava/lang/Integer;");
+        asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi());
         asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi());
-        integerCtorIdx = asm.cpi();
+        integerBoxIdx = asm.cpi();
         asm.emitConstantPoolUTF8("intValue");
         asm.emitConstantPoolUTF8("()I");
         asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
@@ -341,10 +348,10 @@
         asm.emitConstantPoolUTF8("java/lang/Long");
         asm.emitConstantPoolClass(asm.cpi());
         longIdx = asm.cpi();
-        asm.emitConstantPoolUTF8("(J)V");
-        asm.emitConstantPoolNameAndType(initIdx, asm.cpi());
+        asm.emitConstantPoolUTF8("(J)Ljava/lang/Long;");
+        asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi());
         asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi());
-        longCtorIdx = asm.cpi();
+        longBoxIdx = asm.cpi();
         asm.emitConstantPoolUTF8("longValue");
         asm.emitConstantPoolUTF8("()J");
         asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
@@ -355,10 +362,10 @@
         asm.emitConstantPoolUTF8("java/lang/Short");
         asm.emitConstantPoolClass(asm.cpi());
         shortIdx = asm.cpi();
-        asm.emitConstantPoolUTF8("(S)V");
-        asm.emitConstantPoolNameAndType(initIdx, asm.cpi());
+        asm.emitConstantPoolUTF8("(S)Ljava/lang/Short;");
+        asm.emitConstantPoolNameAndType(valueOfIdx, asm.cpi());
         asm.emitConstantPoolMethodref(sub(asm.cpi(), S2), asm.cpi());
-        shortCtorIdx = asm.cpi();
+        shortBoxIdx = asm.cpi();
         asm.emitConstantPoolUTF8("shortValue");
         asm.emitConstantPoolUTF8("()S");
         asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi());
@@ -515,23 +522,23 @@
         throw new InternalError("Should have found primitive type");
     }
 
-    protected short ctorIndexForPrimitiveType(Class<?> type) {
+    protected short boxingMethodForPrimitiveType(Class<?> type) {
         if (type == Boolean.TYPE) {
-            return booleanCtorIdx;
+            return booleanBoxIdx;
         } else if (type == Byte.TYPE) {
-            return byteCtorIdx;
+            return byteBoxIdx;
         } else if (type == Character.TYPE) {
-            return characterCtorIdx;
+            return characterBoxIdx;
         } else if (type == Double.TYPE) {
-            return doubleCtorIdx;
+            return doubleBoxIdx;
         } else if (type == Float.TYPE) {
-            return floatCtorIdx;
+            return floatBoxIdx;
         } else if (type == Integer.TYPE) {
-            return integerCtorIdx;
+            return integerBoxIdx;
         } else if (type == Long.TYPE) {
-            return longCtorIdx;
+            return longBoxIdx;
         } else if (type == Short.TYPE) {
-            return shortCtorIdx;
+            return shortBoxIdx;
         }
         throw new InternalError("Should have found primitive type");
     }
--- a/src/java.base/share/classes/sun/reflect/MethodAccessorGenerator.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/MethodAccessorGenerator.java	Fri Sep 12 10:33:32 2014 -0700
@@ -660,9 +660,9 @@
         if (!isConstructor) {
             // Box return value if necessary
             if (isPrimitive(returnType)) {
-                cb.opc_invokespecial(ctorIndexForPrimitiveType(returnType),
-                                     typeSizeInStackSlots(returnType),
-                                     0);
+                cb.opc_invokestatic(boxingMethodForPrimitiveType(returnType),
+                                    typeSizeInStackSlots(returnType),
+                                    0);
             } else if (returnType == Void.TYPE) {
                 cb.opc_aconst_null();
             }
--- a/src/java.base/share/classes/sun/reflect/UnsafeBooleanFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeBooleanFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -33,7 +33,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Boolean(getBoolean(obj));
+        return Boolean.valueOf(getBoolean(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeByteFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeByteFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -33,7 +33,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Byte(getByte(obj));
+        return Byte.valueOf(getByte(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeCharacterFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeCharacterFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -33,7 +33,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Character(getChar(obj));
+        return Character.valueOf(getChar(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeDoubleFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeDoubleFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -33,7 +33,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Double(getDouble(obj));
+        return Double.valueOf(getDouble(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeFloatFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeFloatFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -33,7 +33,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Float(getFloat(obj));
+        return Float.valueOf(getFloat(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeIntegerFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeIntegerFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -33,7 +33,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Integer(getInt(obj));
+        return Integer.valueOf(getInt(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeLongFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeLongFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -33,7 +33,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Long(getLong(obj));
+        return Long.valueOf(getLong(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeQualifiedBooleanFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeQualifiedBooleanFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -35,7 +35,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Boolean(getBoolean(obj));
+        return Boolean.valueOf(getBoolean(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeQualifiedByteFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeQualifiedByteFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -35,7 +35,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Byte(getByte(obj));
+        return Byte.valueOf(getByte(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeQualifiedCharacterFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeQualifiedCharacterFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -35,7 +35,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Character(getChar(obj));
+        return Character.valueOf(getChar(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeQualifiedDoubleFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeQualifiedDoubleFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -35,7 +35,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Double(getDouble(obj));
+        return Double.valueOf(getDouble(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeQualifiedFloatFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeQualifiedFloatFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -35,7 +35,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Float(getFloat(obj));
+        return Float.valueOf(getFloat(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeQualifiedIntegerFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeQualifiedIntegerFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -35,7 +35,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Integer(getInt(obj));
+        return Integer.valueOf(getInt(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeQualifiedLongFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeQualifiedLongFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -35,7 +35,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Long(getLong(obj));
+        return Long.valueOf(getLong(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeQualifiedShortFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeQualifiedShortFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -35,7 +35,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Short(getShort(obj));
+        return Short.valueOf(getShort(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticBooleanFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticBooleanFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -35,7 +35,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Boolean(getBoolean(obj));
+        return Boolean.valueOf(getBoolean(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticByteFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticByteFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -35,7 +35,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Byte(getByte(obj));
+        return Byte.valueOf(getByte(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticCharacterFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticCharacterFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -35,7 +35,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Character(getChar(obj));
+        return Character.valueOf(getChar(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticDoubleFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticDoubleFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -35,7 +35,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Double(getDouble(obj));
+        return Double.valueOf(getDouble(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticFloatFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticFloatFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -35,7 +35,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Float(getFloat(obj));
+        return Float.valueOf(getFloat(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticIntegerFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticIntegerFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -35,7 +35,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Integer(getInt(obj));
+        return Integer.valueOf(getInt(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticLongFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticLongFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -35,7 +35,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Long(getLong(obj));
+        return Long.valueOf(getLong(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticShortFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeQualifiedStaticShortFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -35,7 +35,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Short(getShort(obj));
+        return Short.valueOf(getShort(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeShortFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeShortFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -33,7 +33,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Short(getShort(obj));
+        return Short.valueOf(getShort(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeStaticBooleanFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeStaticBooleanFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -33,7 +33,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Boolean(getBoolean(obj));
+        return Boolean.valueOf(getBoolean(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeStaticByteFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeStaticByteFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -33,7 +33,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Byte(getByte(obj));
+        return Byte.valueOf(getByte(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeStaticCharacterFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeStaticCharacterFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -33,7 +33,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Character(getChar(obj));
+        return Character.valueOf(getChar(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeStaticDoubleFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeStaticDoubleFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -33,7 +33,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Double(getDouble(obj));
+        return Double.valueOf(getDouble(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeStaticFloatFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeStaticFloatFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -33,7 +33,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Float(getFloat(obj));
+        return Float.valueOf(getFloat(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeStaticIntegerFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeStaticIntegerFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -33,7 +33,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Integer(getInt(obj));
+        return Integer.valueOf(getInt(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeStaticLongFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeStaticLongFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -33,7 +33,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Long(getLong(obj));
+        return Long.valueOf(getLong(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/classes/sun/reflect/UnsafeStaticShortFieldAccessorImpl.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/share/classes/sun/reflect/UnsafeStaticShortFieldAccessorImpl.java	Fri Sep 12 10:33:32 2014 -0700
@@ -33,7 +33,7 @@
     }
 
     public Object get(Object obj) throws IllegalArgumentException {
-        return new Short(getShort(obj));
+        return Short.valueOf(getShort(obj));
     }
 
     public boolean getBoolean(Object obj) throws IllegalArgumentException {
--- a/src/java.base/share/conf/security/sunpkcs11-solaris.cfg	Mon Sep 08 10:24:45 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-#
-# Configuration file to allow the SunPKCS11 provider to utilize
-# the Solaris Cryptographic Framework, if it is available
-#
-
-name = Solaris
-
-description = SunPKCS11 accessing Solaris Cryptographic Framework
-
-library = /usr/lib/$ISA/libpkcs11.so
-
-handleStartupErrors = ignoreAll
-
-# Use the X9.63 encoding for EC points (do not wrap in an ASN.1 OctetString).
-useEcX963Encoding = true
-
-attributes = compatibility
-
-disabledMechanisms = {
-  CKM_DSA_KEY_PAIR_GEN
-}
-
--- a/src/java.base/windows/native/libnet/NetworkInterface.c	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/windows/native/libnet/NetworkInterface.c	Fri Sep 12 10:33:32 2014 -0700
@@ -990,9 +990,11 @@
       case MIB_IF_TYPE_FDDI:
       case IF_TYPE_IEEE80211:
         len = ifRowP->dwPhysAddrLen;
-        ret = (*env)->NewByteArray(env, len);
-        if (!IS_NULL(ret)) {
-          (*env)->SetByteArrayRegion(env, ret, 0, len, (jbyte *) ifRowP->bPhysAddr);
+        if (len > 0) {
+            ret = (*env)->NewByteArray(env, len);
+            if (!IS_NULL(ret)) {
+              (*env)->SetByteArrayRegion(env, ret, 0, len, (jbyte *) ifRowP->bPhysAddr);
+            }
         }
         break;
       }
--- a/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c	Fri Sep 12 10:33:32 2014 -0700
@@ -493,6 +493,9 @@
                 }
             }
         } else {
+            /* NET_BindV6() closes both sockets upon a failure */
+            (*env)->SetObjectField(env, this, pdsi_fdID, NULL);
+            (*env)->SetObjectField(env, this, pdsi_fd1ID, NULL);
             NET_ThrowCurrent (env, "Cannot bind");
             return;
         }
--- a/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c	Fri Sep 12 10:33:32 2014 -0700
@@ -467,6 +467,10 @@
                     (*env)->SetIntField(env, fd1Obj, IO_fd_fdID, fd1);
                 }
             }
+        } else {
+            /* NET_BindV6() closes both sockets upon a failure */
+            (*env)->SetObjectField(env, this, psi_fdID, NULL);
+            (*env)->SetObjectField(env, this, psi_fd1ID, NULL);
         }
     } else {
         rv = NET_WinBind(fd, (struct sockaddr *)&him, len, exclBind);
--- a/src/java.base/windows/native/libnet/net_util_md.c	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.base/windows/native/libnet/net_util_md.c	Fri Sep 12 10:33:32 2014 -0700
@@ -627,7 +627,7 @@
  * and returns SOCKET_ERROR. Used in NET_BindV6 only.
  */
 
-#define CLOSE_SOCKETS_AND_RETURN {      \
+#define CLOSE_SOCKETS_AND_RETURN do {   \
     if (fd != -1) {                     \
         closesocket (fd);               \
         fd = -1;                        \
@@ -646,7 +646,7 @@
     }                                   \
     b->ipv4_fd = b->ipv6_fd = -1;       \
     return SOCKET_ERROR;                \
-}
+} while(0)
 
 /*
  * if ipv6 is available, call NET_BindV6 to bind to the required address/port.
--- a/src/java.management/share/classes/javax/management/loading/MLet.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.management/share/classes/javax/management/loading/MLet.java	Fri Sep 12 10:33:32 2014 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -1313,11 +1313,11 @@
         if (type.compareTo("java.lang.Long") == 0)
              return Long.valueOf(param);
         if (type.compareTo("java.lang.Integer") == 0)
-             return param;
+             return Integer.valueOf(param);
         if (type.compareTo("java.lang.Float") == 0)
-             return new Float(param);
+             return Float.valueOf(param);
         if (type.compareTo("java.lang.Double") == 0)
-             return new Double(param);
+             return Double.valueOf(param);
         if (type.compareTo("java.lang.String") == 0)
              return param;
 
--- a/src/java.management/share/classes/javax/management/remote/rmi/RMIConnector.java	Mon Sep 08 10:24:45 2014 -0700
+++ b/src/java.management/share/classes/javax/management/remote/rmi/RMIConnector.java	Fri Sep 12 10:33:32 2014 -0700
@@ -1335,66 +1335,94 @@
                 int maxNotifications,
                 long timeout)
                 throws IOException, ClassNotFoundException {
-            IOException org;
 
+            boolean retried = false;
             while (true) { // used for a successful re-connection
+                           // or a transient network problem
                 try {
                     return connection.fetchNotifications(clientSequenceNumber,
                             maxNotifications,
-                            timeout);
+                            timeout); // return normally
                 } catch (IOException ioe) {
-                    org = ioe;
+                    // Examine the chain of exceptions to determine whether this
+                    // is a deserialization issue. If so - we propagate the
+                    // appropriate exception to the caller, who will then
+                    // proceed with fetching notifications one by one
+                    rethrowDeserializationException(ioe);
 
-                    // inform of IOException
                     try {
                         communicatorAdmin.gotIOException(ioe);
+                        // reconnection OK, back to "while" to do again
+                    } catch (IOException ee) {
+                        boolean toClose = false;
 
-                        // The connection should be re-established.
-                        continue;
-                    } catch (IOException ee) {
-                        // No more fetch, the Exception will be re-thrown.
-                        break;
-                    } // never reached
-                } // never reached
+                        synchronized (this) {
+                            if (terminated) {
+                                // the connection is closed.
+                                throw ioe;
+                            } else if (retried) {
+                                toClose = true;
+                            }
+                        }
+
+                        if (toClose) {
+                            // JDK-8049303
+                            // We received an IOException - but the communicatorAdmin
+                            // did not close the connection - possibly because
+                            // the original exception was raised by a transient network
+                            // problem?
+                            // We already know that this exception is not due to a deserialization
+                            // issue as we already took care of that before involving the
+                            // communicatorAdmin. Moreover - we already made one retry attempt
+                            // at fetching the same batch of notifications - and the
+                            // problem persisted.
+                            // Since trying again doesn't seem to solve the issue, we will now
+                            // close the connection. Doing otherwise might cause the
+                            // NotifFetcher thread to die silently.
+                            final Notification failedNotif =
+                                    new JMXConnectionNotification(
+                                    JMXConnectionNotification.FAILED,
+                                    this,
+                                    connectionId,
+                                    clientNotifSeqNo++,
+                                    "Failed to communicate with the server: " + ioe.toString(),
+                                    ioe);
+
+                            sendNotification(failedNotif);
+
+                            try {
+                                close(true);
+                            } catch (Exception e) {
+                                // OK.
+                                // We are closing
+                            }
+                            throw ioe; // the connection is closed here.
+                        } else {
+                            // JDK-8049303 possible transient network problem,
+                            // let's try one more time
+                            retried = true;
+                        }
+                    }
+                }
             }
+        }
 
+        private void rethrowDeserializationException(IOException ioe)
+                throws ClassNotFoundException, IOException {
             // specially treating for an UnmarshalException
-            if (org instanceof UnmarshalException) {
-                UnmarshalException ume = (UnmarshalException)org;
-
-                if (ume.detail instanceof ClassNotFoundException)
-                    throw (ClassNotFoundException) ume.detail;
-
-                /* In Sun's RMI implementation, if a method return
-                   contains an unserializable object, then we get
-                   UnmarshalException wrapping WriteAbortedException
-                   wrapping NotSerializableException.  In that case we
-                   extract the NotSerializableException so that our
-                   caller can realize it should try to skip past the
-                   notification that presumably caused it.  It's not
-                   certain that every other RMI implementation will
-                   generate this exact exception sequence.  If not, we
-                   will not detect that the problem is due to an
-                   unserializable object, and we will stop trying to
-                   receive notifications from the server.  It's not
-                   clear we can do much better.  */
-                if (ume.detail instanceof WriteAbortedException) {
-                    WriteAbortedException wae =
-                            (WriteAbortedException) ume.detail;
-                    if (wae.detail instanceof IOException)
-                        throw (IOException) wae.detail;
-                }
-            } else if (org instanceof MarshalException) {