changeset 456:cf0407968713

rebase to current jdk8/tl; split meth-{asm,btype,tidy} out of meth-lfc
author jrose
date Sun, 06 Oct 2013 22:41:41 -0700
parents 393962c8f84e
children 93a6c619b0ca
files indy-bsm-8024761.patch meth-aclone-8001105.patch meth-arity-8019417.patch meth-asm.patch meth-btype.patch meth-clinit-8024599.patch meth-coll-8001110.patch meth-counts.patch meth-lfc.patch meth-mr-8024438.patch meth-nsme-8001108.patch meth-spr-8001109.patch meth-tidy.patch meth.patch series testng-anti-diff.patch tl-fixes.1.patch tl-fixes.2.patch tl-fixes.3.patch
diffstat 19 files changed, 7853 insertions(+), 11987 deletions(-) [+]
line wrap: on
line diff
--- a/indy-bsm-8024761.patch	Sun Sep 15 17:15:12 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1093 +0,0 @@
-8024761: JSR 292 improve performance of generic invocation
-Summary: use a per-MH one element cache for MH.asType to speed up MH.invoke; also cache enough MH constants to cache LMF.metafactory
-
-Cherry-pick method handle optimizations which affect BSM lookup and invocation.
-Alternative to http://cr.openjdk.java.net/~skuksenko/jsr335/8024630/webrev.00/
-
-diff --git a/src/share/classes/java/lang/invoke/BoundMethodHandle.java b/src/share/classes/java/lang/invoke/BoundMethodHandle.java
---- a/src/share/classes/java/lang/invoke/BoundMethodHandle.java
-+++ b/src/share/classes/java/lang/invoke/BoundMethodHandle.java
-@@ -360,6 +360,10 @@
-             return new Name(mh, mhName);
-         }
- 
-+        NamedFunction getterFunction(int i) {
-+            return new NamedFunction(getters[i]);
-+        }
-+
-         static final SpeciesData EMPTY = new SpeciesData("", BoundMethodHandle.class);
- 
-         private SpeciesData(String types, Class<? extends BoundMethodHandle> clazz) {
-diff --git a/src/share/classes/java/lang/invoke/CallSite.java b/src/share/classes/java/lang/invoke/CallSite.java
---- a/src/share/classes/java/lang/invoke/CallSite.java
-+++ b/src/share/classes/java/lang/invoke/CallSite.java
-@@ -273,14 +273,43 @@
-             } else {
-                 Object[] argv = (Object[]) info;
-                 maybeReBoxElements(argv);
--                if (3 + argv.length > 255)
--                    throw new BootstrapMethodError("too many bootstrap method arguments");
--                MethodType bsmType = bootstrapMethod.type();
--                if (bsmType.parameterCount() == 4 && bsmType.parameterType(3) == Object[].class)
--                    binding = bootstrapMethod.invoke(caller, name, type, argv);
--                else
--                    binding = MethodHandles.spreadInvoker(bsmType, 3)
--                        .invoke(bootstrapMethod, caller, name, type, argv);
-+                switch (argv.length) {
-+                case 0:
-+                    binding = bootstrapMethod.invoke(caller, name, type);
-+                    break;
-+                case 1:
-+                    binding = bootstrapMethod.invoke(caller, name, type,
-+                                                     argv[0]);
-+                    break;
-+                case 2:
-+                    binding = bootstrapMethod.invoke(caller, name, type,
-+                                                     argv[0], argv[1]);
-+                    break;
-+                case 3:
-+                    binding = bootstrapMethod.invoke(caller, name, type,
-+                                                     argv[0], argv[1], argv[2]);
-+                    break;
-+                case 4:
-+                    binding = bootstrapMethod.invoke(caller, name, type,
-+                                                     argv[0], argv[1], argv[2], argv[3]);
-+                    break;
-+                case 5:
-+                    binding = bootstrapMethod.invoke(caller, name, type,
-+                                                     argv[0], argv[1], argv[2], argv[3], argv[4]);
-+                    break;
-+                case 6:
-+                    binding = bootstrapMethod.invoke(caller, name, type,
-+                                                     argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
-+                    break;
-+                default:
-+                    if (3 + argv.length > MethodType.MAX_MH_ARITY)
-+                        throw new BootstrapMethodError("too many bootstrap method arguments");
-+                    MethodType bsmType = bootstrapMethod.type();
-+                    MethodType invocationType = MethodType.genericMethodType(3 + argv.length);
-+                    MethodHandle typedBSM = bootstrapMethod.asType(invocationType);
-+                    MethodHandle spreader = invocationType.invokers().spreadInvoker(3);
-+                    binding = spreader.invokeExact(typedBSM, /*(Object)*/caller, (Object)name, (Object)type, argv);
-+                }
-             }
-             //System.out.println("BSM for "+name+type+" => "+binding);
-             if (binding instanceof CallSite) {
-diff --git a/src/share/classes/java/lang/invoke/InvokeGeneric.java b/src/share/classes/java/lang/invoke/InvokeGeneric.java
-deleted file mode 100644
---- a/src/share/classes/java/lang/invoke/InvokeGeneric.java
-+++ /dev/null
-@@ -1,148 +0,0 @@
--/*
-- * Copyright (c) 2009, 2011, 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 sun.invoke.util.*;
--import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
--
--/**
-- * Adapters which manage inexact MethodHandle.invoke calls.
-- * The JVM calls one of these when the exact type match fails.
-- * @author jrose
-- */
--class InvokeGeneric {
--    // erased type for the call, which originates from an inexact invoke site
--    private final MethodType erasedCallerType;
--    // an invoker of type (MT, MH; A...) -> R
--    private final MethodHandle initialInvoker;
--
--    /** Compute and cache information for this adapter, so that it can
--     *  call out to targets of the erasure-family of the given erased type.
--     */
--    /*non-public*/ InvokeGeneric(MethodType erasedCallerType) throws ReflectiveOperationException {
--        assert(erasedCallerType.equals(erasedCallerType.erase()));
--        this.erasedCallerType = erasedCallerType;
--        this.initialInvoker = makeInitialInvoker();
--        assert initialInvoker.type().equals(erasedCallerType
--                                            .insertParameterTypes(0, MethodType.class, MethodHandle.class))
--            : initialInvoker.type();
--    }
--
--    private static MethodHandles.Lookup lookup() {
--        return IMPL_LOOKUP;
--    }
--
--    /** Return the adapter information for this type's erasure. */
--    /*non-public*/ static MethodHandle generalInvokerOf(MethodType erasedCallerType) throws ReflectiveOperationException {
--        InvokeGeneric gen = new InvokeGeneric(erasedCallerType);
--        return gen.initialInvoker;
--    }
--
--    private MethodHandle makeInitialInvoker() throws ReflectiveOperationException {
--        // postDispatch = #(MH'; MT, MH; A...){MH'(MT, MH; A)}
--        MethodHandle postDispatch = makePostDispatchInvoker();
--        MethodHandle invoker;
--        if (returnConversionPossible()) {
--            invoker = MethodHandles.foldArguments(postDispatch,
--                                                  dispatcher("dispatchWithConversion"));
--        } else {
--            invoker = MethodHandles.foldArguments(postDispatch, dispatcher("dispatch"));
--        }
--        return invoker;
--    }
--
--    private static final Class<?>[] EXTRA_ARGS = { MethodType.class, MethodHandle.class };
--    private MethodHandle makePostDispatchInvoker() {
--        // Take (MH'; MT, MH; A...) and run MH'(MT, MH; A...).
--        MethodType invokerType = erasedCallerType.insertParameterTypes(0, EXTRA_ARGS);
--        return invokerType.invokers().exactInvoker();
--    }
--    private MethodHandle dropDispatchArguments(MethodHandle targetInvoker) {
--        assert(targetInvoker.type().parameterType(0) == MethodHandle.class);
--        return MethodHandles.dropArguments(targetInvoker, 1, EXTRA_ARGS);
--    }
--
--    private MethodHandle dispatcher(String dispatchName) throws ReflectiveOperationException {
--        return lookup().bind(this, dispatchName,
--                             MethodType.methodType(MethodHandle.class,
--                                                   MethodType.class, MethodHandle.class));
--    }
--
--    static final boolean USE_AS_TYPE_PATH = true;
--
--    /** Return a method handle to invoke on the callerType, target, and remaining arguments.
--     *  The method handle must finish the call.
--     *  This is the first look at the caller type and target.
--     */
--    private MethodHandle dispatch(MethodType callerType, MethodHandle target) {
--        MethodType targetType = target.type();
--        if (USE_AS_TYPE_PATH || target.isVarargsCollector()) {
--            MethodHandle newTarget = target.asType(callerType);
--            targetType = callerType;
--            Invokers invokers = targetType.invokers();
--            MethodHandle invoker = invokers.erasedInvokerWithDrops;
--            if (invoker == null) {
--                invokers.erasedInvokerWithDrops = invoker =
--                    dropDispatchArguments(invokers.erasedInvoker());
--            }
--            return invoker.bindTo(newTarget);
--        }
--        throw new RuntimeException("NYI");
--    }
--
--    private MethodHandle dispatchWithConversion(MethodType callerType, MethodHandle target) {
--        MethodHandle finisher = dispatch(callerType, target);
--        if (returnConversionNeeded(callerType, target))
--            finisher = addReturnConversion(finisher, callerType.returnType());  //FIXME: slow
--        return finisher;
--    }
--
--    private boolean returnConversionPossible() {
--        Class<?> needType = erasedCallerType.returnType();
--        return !needType.isPrimitive();
--    }
--    private boolean returnConversionNeeded(MethodType callerType, MethodHandle target) {
--        Class<?> needType = callerType.returnType();
--        if (needType == erasedCallerType.returnType())
--            return false;  // no conversions possible, since must be primitive or Object
--        Class<?> haveType = target.type().returnType();
--        if (VerifyType.isNullConversion(haveType, needType) && !needType.isInterface())
--            return false;
--        return true;
--    }
--    private MethodHandle addReturnConversion(MethodHandle finisher, Class<?> type) {
--        // FIXME: This is slow because it creates a closure node on every call that requires a return cast.
--        MethodType finisherType = finisher.type();
--        MethodHandle caster = ValueConversions.identity(type);
--        caster = caster.asType(caster.type().changeParameterType(0, finisherType.returnType()));
--        finisher = MethodHandles.filterReturnValue(finisher, caster);
--        return finisher.asType(finisherType);
--    }
--
--    public String toString() {
--        return "InvokeGeneric"+erasedCallerType;
--    }
--}
-diff --git a/src/share/classes/java/lang/invoke/Invokers.java b/src/share/classes/java/lang/invoke/Invokers.java
---- a/src/share/classes/java/lang/invoke/Invokers.java
-+++ b/src/share/classes/java/lang/invoke/Invokers.java
-@@ -44,6 +44,7 @@
- 
-     // 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
-@@ -76,19 +77,12 @@
-         if (invoker != null)  return invoker;
-         MethodType mtype = targetType;
-         MethodType invokerType = mtype.invokerType();
--        LambdaForm lform;
--        final int MTYPE_ARG_APPENDED = 1;  // argument count for appended mtype value
--        if (mtype.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY - MTYPE_ARG_APPENDED) {
--            lform = invokeForm(mtype, false, MethodTypeForm.LF_EX_INVOKER);
--            invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype);
--        } else {
--            // At maximum arity, we cannot afford an extra mtype argument,
--            // so build a fully customized (non-cached) invoker form.
--            lform = invokeForm(mtype, true, MethodTypeForm.LF_EX_INVOKER);
--            invoker = SimpleMethodHandle.make(invokerType, lform);
--        }
-+        LambdaForm lform = invokeHandleForm(mtype, false, MethodTypeForm.LF_EX_INVOKER);
-+        invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype);
-         invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke("invokeExact", mtype));
-         assert(checkInvoker(invoker));
-+        if (targetType == targetType.erase() && targetType.parameterCount() < 10)
-+            invoker.form.compileToBytecode();
-         exactInvoker = invoker;
-         return invoker;
-     }
-@@ -98,41 +92,41 @@
-         if (invoker != null)  return invoker;
-         MethodType mtype = targetType;
-         MethodType invokerType = mtype.invokerType();
--        LambdaForm lform;
--        final int MTYPE_ARG_APPENDED = 1;  // argument count for appended mtype value
--        assert(GENERIC_INVOKER_SLOP >= MTYPE_ARG_APPENDED);
--        if (mtype.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY - GENERIC_INVOKER_SLOP) {
--            prepareForGenericCall(mtype);
--            lform = invokeForm(mtype, false, MethodTypeForm.LF_GEN_INVOKER);
--            invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype);
--        } else {
--            // At maximum arity, we cannot afford an extra mtype argument,
--            // so build a fully customized (non-cached) invoker form.
--            lform = invokeForm(mtype, true, MethodTypeForm.LF_GEN_INVOKER);
--            invoker = SimpleMethodHandle.make(invokerType, lform);
--        }
-+        LambdaForm lform = invokeHandleForm(mtype, false, MethodTypeForm.LF_GEN_INVOKER);
-+        invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype);
-         invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke("invoke", mtype));
-         assert(checkInvoker(invoker));
-+        if (targetType == targetType.erase() && targetType.parameterCount() < 10)
-+            invoker.form.compileToBytecode();
-         generalInvoker = invoker;
-         return invoker;
-     }
- 
--    /*non-public*/ MethodHandle makeBasicInvoker() {
--        MethodHandle invoker = DirectMethodHandle.make(invokeBasicMethod(targetType));
--        assert(targetType == targetType.basicType());
--        // Note:  This is not cached here.  It is cached by the calling MethodTypeForm.
-+
-+    /*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));
-+        //invoker.form.compileToBytecode();
-+        basicInvoker = invoker;
-         return invoker;
-     }
- 
--    static MemberName invokeBasicMethod(MethodType type) {
--        type = type.basicType();
--        String name = "invokeBasic";
-+    // This next one is called from LambdaForm.NamedFunction.<init>.
-+    /*non-public*/ static MemberName invokeBasicMethod(MethodType basicType) {
-+        assert(basicType == basicType.basicType());
-         try {
-             //Lookup.findVirtual(MethodHandle.class, name, type);
--            return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, name, type);
-+            return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, "invokeBasic", basicType);
-         } catch (ReflectiveOperationException ex) {
--            throw newInternalError("JVM cannot find invoker for "+type, ex);
-+            throw newInternalError("JVM cannot find invoker for "+basicType, ex);
-         }
-     }
- 
-@@ -184,6 +178,8 @@
-             vaInvoker = MethodHandles.filterArgument(arrayInvoker, 0, makeSpreader);
-         }
-         assert(vaInvoker.type().equals(spreadInvokerType.invokerType()));
-+        if (targetType == targetType.erase() && targetType.parameterCount() < 10)
-+            vaInvoker.form.compileToBytecode();
-         spreadInvokers[leadingArgCount] = vaInvoker;
-         return vaInvoker;
-     }
-@@ -231,32 +227,41 @@
-         return "Invokers"+targetType;
-     }
- 
--    static MemberName exactInvokerMethod(MethodType mtype, Object[] appendixResult) {
-+    static MemberName exactInvokeLinkerMethod(MethodType mtype, Object[] appendixResult) {
-         LambdaForm lform;
--        final int MTYPE_ARG_APPENDED = 1;  // argument count for appended mtype value
--        if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - MTYPE_ARG_APPENDED) {
--            lform = invokeForm(mtype, false, MethodTypeForm.LF_EX_LINKER);
-+        if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - MH_LINKER_ARG_APPENDED) {
-+            lform = invokeHandleForm(mtype, false, MethodTypeForm.LF_EX_LINKER);
-             appendixResult[0] = mtype;
-         } else {
--            lform = invokeForm(mtype, true, MethodTypeForm.LF_EX_LINKER);
-+            lform = invokeHandleForm(mtype, true, MethodTypeForm.LF_EX_LINKER);
-         }
-         return lform.vmentry;
-     }
- 
--    static MemberName genericInvokerMethod(MethodType mtype, Object[] appendixResult) {
-+    static MemberName genericInvokeLinkerMethod(MethodType mtype, Object[] appendixResult) {
-         LambdaForm lform;
--        final int MTYPE_ARG_APPENDED = 1;  // argument count for appended mtype value
--        if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - (MTYPE_ARG_APPENDED + GENERIC_INVOKER_SLOP)) {
--            lform = invokeForm(mtype, false, MethodTypeForm.LF_GEN_LINKER);
-+        if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - MH_LINKER_ARG_APPENDED) {
-+            lform = invokeHandleForm(mtype, false, MethodTypeForm.LF_GEN_LINKER);
-             appendixResult[0] = mtype;
--            prepareForGenericCall(mtype);
-         } else {
--            lform = invokeForm(mtype, true, MethodTypeForm.LF_GEN_LINKER);
-+            lform = invokeHandleForm(mtype, true, MethodTypeForm.LF_GEN_LINKER);
-         }
-         return lform.vmentry;
-     }
- 
--    private static LambdaForm invokeForm(MethodType mtype, boolean customized, int which) {
-+    // argument count to account for trailing "appendix value" (typically the mtype)
-+    private static final int MH_LINKER_ARG_APPENDED = 1;
-+
-+    // Return an adapter for invokeExact or generic invoke, as a MH or constant pool linker
-+    // mtype : the caller's method type (either basic or full-custom)
-+    // customized : whether to use a trailing appendix argument (to carry the mtype)
-+    // which&0x01 : whether it is a CP adapter ("linker") or MHs.invoker value ("invoker")
-+    // which&0x02 : whether it is for invokeExact or generic invoke
-+    //
-+    // If !customized, caller is responsible for supplying, during adapter execution,
-+    // a copy of the exact mtype.  This is because the adapter might be generalized to
-+    // a basic type.
-+    private static LambdaForm invokeHandleForm(MethodType mtype, boolean customized, int which) {
-         boolean isCached;
-         if (!customized) {
-             mtype = mtype.basicType();  // normalize Z to I, String to Object, etc.
-@@ -301,41 +306,24 @@
-                 : Arrays.asList(mtype, customized, which, nameCursor, names.length);
-         if (MTYPE_ARG >= INARG_LIMIT) {
-             assert(names[MTYPE_ARG] == null);
--            names[MTYPE_ARG] = BoundMethodHandle.getSpeciesData("L").getterName(names[THIS_MH], 0);
-+            NamedFunction getter = BoundMethodHandle.getSpeciesData("L").getterFunction(0);
-+            names[MTYPE_ARG] = new Name(getter, names[THIS_MH]);
-             // else if isLinker, then MTYPE is passed in from the caller (e.g., the JVM)
-         }
- 
-         // Make the final call.  If isGeneric, then prepend the result of type checking.
--        MethodType outCallType;
--        Object[] outArgs;
-+        MethodType outCallType = mtype.basicType();
-+        Object[] outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT, Object[].class);
-         Object mtypeArg = (customized ? mtype : names[MTYPE_ARG]);
-         if (!isGeneric) {
-             names[CHECK_TYPE] = new Name(NF_checkExactType, names[CALL_MH], mtypeArg);
-             // mh.invokeExact(a*):R => checkExactType(mh, TYPEOF(a*:R)); mh.invokeBasic(a*)
--            outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT, Object[].class);
--            outCallType = mtype;
--        } else if (customized) {
--            names[CHECK_TYPE] = new Name(NF_asType, names[CALL_MH], mtypeArg);
--            // mh.invokeGeneric(a*):R =>
--            //  let mt=TYPEOF(a*:R), tmh=asType(mh, mt);
--            //    tmh.invokeBasic(a*)
--            outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT, Object[].class);
--            outCallType = mtype;
-         } else {
-             names[CHECK_TYPE] = new Name(NF_checkGenericType, names[CALL_MH], mtypeArg);
--            // mh.invokeGeneric(a*):R =>
--            //  let mt=TYPEOF(a*:R), gamh=checkGenericType(mh, mt);
--            //    gamh.invokeBasic(mt, mh, a*)
--            final int PREPEND_GAMH = 0, PREPEND_MT = 1, PREPEND_COUNT = 2;
--            assert(GENERIC_INVOKER_SLOP == PREPEND_COUNT);
--            outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT + PREPEND_COUNT, Object[].class);
--            // prepend arguments:
--            System.arraycopy(outArgs, 0, outArgs, PREPEND_COUNT, outArgs.length - PREPEND_COUNT);
--            outArgs[PREPEND_GAMH] = names[CHECK_TYPE];
--            outArgs[PREPEND_MT] = mtypeArg;
--            outCallType = mtype.insertParameterTypes(0, MethodType.class, MethodHandle.class);
-+            // mh.invokeGeneric(a*):R => checkGenericType(mh, TYPEOF(a*:R)).invokeBasic(a*)
-+            outArgs[0] = names[CHECK_TYPE];
-         }
--        names[LINKER_CALL] = new Name(invokeBasicMethod(outCallType), outArgs);
-+        names[LINKER_CALL] = new Name(outCallType, outArgs);
-         lform = new LambdaForm(debugName, INARG_LIMIT, names);
-         if (isLinker)
-             lform.compileToBytecode();  // JVM needs a real methodOop
-@@ -343,7 +331,6 @@
-             lform = mtype.form().setCachedLambdaForm(which, lform);
-         return lform;
-     }
--    private static final int GENERIC_INVOKER_SLOP = 2;  // used elsewhere to avoid arity problems
- 
-     /*non-public*/ static
-     WrongMethodTypeException newWrongMethodTypeException(MethodType actual, MethodType expected) {
-@@ -362,47 +349,53 @@
-             throw newWrongMethodTypeException(expected, actual);
-     }
- 
--    /** Static definition of MethodHandle.invokeGeneric checking code. */
-+    /** Static definition of MethodHandle.invokeGeneric checking code.
-+     * Directly returns the type-adjusted MH to invoke, as follows:
-+     * {@code (R)MH.invoke(a*) => MH.asType(TYPEOF(a*:R)).invokeBasic(a*)}
-+     */
-     /*non-public*/ static
-     @ForceInline
-     Object checkGenericType(Object mhObj, Object expectedObj) {
-         MethodHandle mh = (MethodHandle) mhObj;
-         MethodType expected = (MethodType) expectedObj;
--        //MethodType actual = mh.type();
--        MethodHandle gamh = expected.form().genericInvoker;
--        if (gamh != null)  return gamh;
--        return prepareForGenericCall(expected);
--    }
--
--    /**
--     * Returns an adapter GA for invoking a MH with type adjustments.
--     * The MethodType of the generic invocation site is prepended to MH
--     * and its arguments as follows:
--     * {@code (R)MH.invoke(A*) => GA.invokeBasic(TYPEOF<A*,R>, MH, A*)}
--     */
--    /*non-public*/ static MethodHandle prepareForGenericCall(MethodType mtype) {
--        // force any needed adapters to be preconstructed
--        MethodTypeForm form = mtype.form();
--        MethodHandle gamh = form.genericInvoker;
--        if (gamh != null)  return gamh;
--        try {
--            // Trigger adapter creation.
--            gamh = InvokeGeneric.generalInvokerOf(form.erasedType);
--            form.genericInvoker = gamh;
--            return gamh;
--        } catch (Exception ex) {
--            throw newInternalError("Exception while resolving inexact invoke", ex);
--        }
-+        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*),
-+         * let MT0 = TYPEOF(a*:R), MT1 = MH.type
-+         *
-+         * if MT0==MT1 or MT1 can be safely called by MT0
-+         *  => MH.invokeBasic(a*)
-+         * if MT1 can be safely called by MT0[R := Object]
-+         *  => MH.invokeBasic(a*) & checkcast(R)
-+         * if MT1 can be safely called by MT0[* := Object]
-+         *  => checkcast(A)* & MH.invokeBasic(a*) & checkcast(R)
-+         * if a big adapter BA can be pulled out of (MT0,MT1)
-+         *  => BA.invokeBasic(MT0,MH,a*)
-+         * if a local adapter LA can cached on static CS0 = new GICS(MT0)
-+         *  => CS0.LA.invokeBasic(MH,a*)
-+         * else
-+         *  => MH.asType(MT0).invokeBasic(A*)
-+         */
-     }
- 
-     static MemberName linkToCallSiteMethod(MethodType mtype) {
--        LambdaForm lform = callSiteForm(mtype);
-+        LambdaForm lform = callSiteForm(mtype, false);
-         return lform.vmentry;
-     }
- 
--    private static LambdaForm callSiteForm(MethodType mtype) {
-+    static MemberName linkToTargetMethod(MethodType mtype) {
-+        LambdaForm lform = callSiteForm(mtype, true);
-+        return lform.vmentry;
-+    }
-+
-+    // skipCallSite is true if we are optimizing a ConstantCallSite
-+    private static LambdaForm callSiteForm(MethodType mtype, boolean skipCallSite) {
-         mtype = mtype.basicType();  // normalize Z to I, String to Object, etc.
--        LambdaForm lform = mtype.form().cachedLambdaForm(MethodTypeForm.LF_CS_LINKER);
-+        final int which = (skipCallSite ? MethodTypeForm.LF_MH_LINKER : MethodTypeForm.LF_CS_LINKER);
-+        LambdaForm lform = mtype.form().cachedLambdaForm(which);
-         if (lform != null)  return lform;
-         // exactInvokerForm (Object,Object)Object
-         //   link with java.lang.invoke.MethodHandle.invokeBasic(MethodHandle,Object,Object)Object/invokeSpecial
-@@ -410,24 +403,26 @@
-         final int OUTARG_LIMIT = ARG_BASE + mtype.parameterCount();
-         final int INARG_LIMIT  = OUTARG_LIMIT + 1;
-         int nameCursor = OUTARG_LIMIT;
--        final int CSITE_ARG    = nameCursor++;  // the last in-argument
--        final int CALL_MH      = nameCursor++;  // result of getTarget
-+        final int APPENDIX_ARG = nameCursor++;  // the last in-argument
-+        final int CSITE_ARG    = skipCallSite ? -1 : APPENDIX_ARG;
-+        final int CALL_MH      = skipCallSite ? APPENDIX_ARG : nameCursor++;  // result of getTarget
-         final int LINKER_CALL  = nameCursor++;
--        MethodType invokerFormType = mtype.appendParameterTypes(CallSite.class);
-+        MethodType invokerFormType = mtype.appendParameterTypes(skipCallSite ? MethodHandle.class : CallSite.class);
-         Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType);
-         assert(names.length == nameCursor);
--        assert(names[CSITE_ARG] != null);
--        names[CALL_MH] = new Name(NF_getCallSiteTarget, names[CSITE_ARG]);
-+        assert(names[APPENDIX_ARG] != null);
-+        if (!skipCallSite)
-+            names[CALL_MH] = new Name(NF_getCallSiteTarget, names[CSITE_ARG]);
-         // (site.)invokedynamic(a*):R => mh = site.getTarget(); mh.invokeBasic(a*)
-         final int PREPEND_MH = 0, PREPEND_COUNT = 1;
-         Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, OUTARG_LIMIT + PREPEND_COUNT, Object[].class);
-         // prepend MH argument:
-         System.arraycopy(outArgs, 0, outArgs, PREPEND_COUNT, outArgs.length - PREPEND_COUNT);
-         outArgs[PREPEND_MH] = names[CALL_MH];
--        names[LINKER_CALL] = new Name(invokeBasicMethod(mtype), outArgs);
--        lform = new LambdaForm("linkToCallSite", INARG_LIMIT, names);
-+        names[LINKER_CALL] = new Name(mtype, outArgs);
-+        lform = new LambdaForm((skipCallSite ? "linkToTargetMethod" : "linkToCallSite"), INARG_LIMIT, names);
-         lform.compileToBytecode();  // JVM needs a real methodOop
--        lform = mtype.form().setCachedLambdaForm(MethodTypeForm.LF_CS_LINKER, lform);
-+        lform = mtype.form().setCachedLambdaForm(which, lform);
-         return lform;
-     }
- 
-diff --git a/src/share/classes/java/lang/invoke/LambdaForm.java b/src/share/classes/java/lang/invoke/LambdaForm.java
---- a/src/share/classes/java/lang/invoke/LambdaForm.java
-+++ b/src/share/classes/java/lang/invoke/LambdaForm.java
-@@ -452,12 +452,12 @@
-         }
-         try {
-             vmentry = InvokerBytecodeGenerator.generateCustomizedCode(this, invokerType);
--            if (TRACE_INTERPRETER)
-+            if (TRACE_INTERPRETER && INIT_DONE)
-                 traceInterpreter("compileToBytecode", this);
-             isCompiled = true;
-             return vmentry;
-         } catch (Error | Exception ex) {
--            throw newInternalError(this.toString(), ex);
-+            throw newInternalError("compileToBytecode", ex);
-         }
-     }
- 
-@@ -595,7 +595,7 @@
-     @DontInline
-     /** Interpretively invoke this form on the given arguments. */
-     Object interpretWithArguments(Object... argumentValues) throws Throwable {
--        if (TRACE_INTERPRETER)
-+        if (TRACE_INTERPRETER && INIT_DONE)
-             return interpretWithArgumentsTracing(argumentValues);
-         checkInvocationCounter();
-         assert(arityCheck(argumentValues));
-@@ -610,7 +610,7 @@
-     @DontInline
-     /** Evaluate a single Name within this form, applying its function to its arguments. */
-     Object interpretName(Name name, Object[] values) throws Throwable {
--        if (TRACE_INTERPRETER)
-+        if (TRACE_INTERPRETER && INIT_DONE)
-             traceInterpreter("| interpretName", name.debugString(), (Object[]) null);
-         Object[] arguments = Arrays.copyOf(name.arguments, name.arguments.length, Object[].class);
-         for (int i = 0; i < arguments.length; i++) {
-@@ -683,7 +683,7 @@
-     */
- 
-     static void traceInterpreter(String event, Object obj, Object... args) {
--        if (!TRACE_INTERPRETER)  return;
-+        if (!(TRACE_INTERPRETER && INIT_DONE))  return;
-         System.out.println("LFI: "+event+" "+(obj != null ? obj : "")+(args != null && args.length != 0 ? Arrays.asList(args) : ""));
-     }
-     static void traceInterpreter(String event, Object obj) {
-@@ -722,7 +722,7 @@
-             buf.append(";");
-         }
-         buf.append(result < 0 ? "void" : names[result]).append("}");
--        if (TRACE_INTERPRETER) {
-+        if (TRACE_INTERPRETER && INIT_DONE) {
-             // Extra verbosity:
-             buf.append(":").append(basicTypeSignature());
-             buf.append("/").append(vmentry);
-@@ -982,6 +982,16 @@
-             //resolvedHandle = eraseSubwordTypes(resolvedHandle);
-             this.resolvedHandle = resolvedHandle;
-         }
-+        NamedFunction(MethodType basicInvokerType) {
-+            assert(basicInvokerType == basicInvokerType.basicType()) : basicInvokerType;
-+            if (basicInvokerType.parameterSlotCount() < MethodType.MAX_MH_INVOKER_ARITY) {
-+                this.resolvedHandle = basicInvokerType.invokers().basicInvoker();
-+                this.member = resolvedHandle.internalMemberName();
-+            } else {
-+                // necessary to pass BigArityTest
-+                this.member = Invokers.invokeBasicMethod(basicInvokerType);
-+            }
-+        }
- 
-         // The next 3 constructors are used to break circular dependencies on MH.invokeStatic, etc.
-         // Any LambdaForm containing such a member is not interpretable.
-@@ -1131,7 +1141,7 @@
-         Object invokeWithArguments(Object... arguments) throws Throwable {
-             // If we have a cached invoker, call it right away.
-             // NOTE: The invoker always returns a reference value.
--            if (TRACE_INTERPRETER)  return invokeWithArgumentsTracing(arguments);
-+            if (TRACE_INTERPRETER && INIT_DONE)  return invokeWithArgumentsTracing(arguments);
-             assert(checkArgumentTypes(arguments, methodType()));
-             return invoker().invokeBasic(resolvedHandle(), arguments);
-         }
-@@ -1229,7 +1239,7 @@
-         }
- 
-         public String toString() {
--            if (member == null)  return resolvedHandle.toString();
-+            if (member == null)  return String.valueOf(resolvedHandle);
-             return member.getDeclaringClass().getSimpleName()+"."+member.getName();
-         }
-     }
-@@ -1279,6 +1289,10 @@
-         Name(MethodHandle function, Object... arguments) {
-             this(new NamedFunction(function), arguments);
-         }
-+        Name(MethodType functionType, Object... arguments) {
-+            this(new NamedFunction(functionType), arguments);
-+            assert(arguments[0] instanceof Name && ((Name)arguments[0]).type == 'L');
-+        }
-         Name(MemberName function, Object... arguments) {
-             this(new NamedFunction(function), arguments);
-         }
-@@ -1622,4 +1636,5 @@
-  */
- 
-     static { NamedFunction.initializeInvokers(); }
-+    static final boolean INIT_DONE = Boolean.TRUE.booleanValue();
- }
-diff --git a/src/share/classes/java/lang/invoke/MemberName.java b/src/share/classes/java/lang/invoke/MemberName.java
---- a/src/share/classes/java/lang/invoke/MemberName.java
-+++ b/src/share/classes/java/lang/invoke/MemberName.java
-@@ -530,6 +530,24 @@
-         }
-         throw new IllegalArgumentException(this.toString());
-     }
-+    public MemberName asNormalOriginal() {
-+        byte normalVirtual = clazz.isInterface() ? REF_invokeInterface : REF_invokeVirtual;
-+        byte refKind = getReferenceKind();
-+        byte newRefKind = refKind;
-+        MemberName result = this;
-+        switch (refKind) {
-+        case REF_invokeInterface:
-+        case REF_invokeVirtual:
-+        case REF_invokeSpecial:
-+            newRefKind = normalVirtual;
-+            break;
-+        }
-+        if (newRefKind == refKind)
-+            return this;
-+        result = clone().changeReferenceKind(newRefKind, refKind);
-+        assert(this.referenceKindIsConsistentWith(result.getReferenceKind()));
-+        return result;
-+    }
-     /** Create a name for the given reflected constructor.  The resulting name will be in a resolved state. */
-     @SuppressWarnings("LeakingThisInConstructor")
-     public MemberName(Constructor<?> ctor) {
-@@ -627,7 +645,7 @@
- 
-     @Override
-     public int hashCode() {
--        return Objects.hash(clazz, flags, name, getType());
-+        return Objects.hash(clazz, getReferenceKind(), name, getType());
-     }
-     @Override
-     public boolean equals(Object that) {
-@@ -643,13 +661,14 @@
-         if (this == that)  return true;
-         if (that == null)  return false;
-         return this.clazz == that.clazz
--                && this.flags == that.flags
-+                && this.getReferenceKind() == that.getReferenceKind()
-                 && Objects.equals(this.name, that.name)
-                 && Objects.equals(this.getType(), that.getType());
-     }
- 
-     // Construction from symbolic parts, for queries:
--    /** Create a field or type name from the given components:  Declaring class, name, type, reference kind.
-+    /** Create a field or type name from the given components:
-+     *  Declaring class, name, type, reference kind.
-      *  The declaring class may be supplied as null if this is to be a bare name and type.
-      *  The resulting name will in an unresolved state.
-      */
-@@ -678,16 +697,31 @@
-         init(defClass, name, type, flagsMods(flags, 0, refKind));
-         initResolved(false);
-     }
--//    /** Create a method or constructor name from the given components:  Declaring class, name, type, modifiers.
--//     *  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 modifier flags default to zero.
--//     *  The resulting name will in an unresolved state.
--//     */
--//    public MemberName(Class<?> defClass, String name, MethodType type, Void unused) {
--//        this(defClass, name, type, REF_NONE);
--//    }
--
-+    /** Create a method, constructor, or field name from the given components:
-+     *  Reference kind, declaring class, name, type.
-+     */
-+    public MemberName(byte refKind, Class<?> defClass, String name, Object type) {
-+        @SuppressWarnings("LocalVariableHidesMemberVariable")
-+        int kindFlags;
-+        if (MethodHandleNatives.refKindIsField(refKind)) {
-+            kindFlags = IS_FIELD;
-+            if (!(type instanceof Class))
-+                throw newIllegalArgumentException("not a field type");
-+        } else if (MethodHandleNatives.refKindIsMethod(refKind)) {
-+            kindFlags = IS_METHOD;
-+            if (!(type instanceof MethodType))
-+                throw newIllegalArgumentException("not a method type");
-+        } else if (refKind == REF_newInvokeSpecial) {
-+            kindFlags = IS_CONSTRUCTOR;
-+            if (!(type instanceof MethodType) ||
-+                !CONSTRUCTOR_NAME.equals(name))
-+                throw newIllegalArgumentException("not a constructor type or name");
-+        } else {
-+            throw newIllegalArgumentException("bad reference kind "+refKind);
-+        }
-+        init(defClass, name, type, flagsMods(kindFlags, 0, refKind));
-+        initResolved(false);
-+    }
-     /** Query whether this member name is resolved to a non-static, non-final method.
-      */
-     public boolean hasReceiverTypeDispatch() {
-diff --git a/src/share/classes/java/lang/invoke/MethodHandle.java b/src/share/classes/java/lang/invoke/MethodHandle.java
---- a/src/share/classes/java/lang/invoke/MethodHandle.java
-+++ b/src/share/classes/java/lang/invoke/MethodHandle.java
-@@ -420,6 +420,8 @@
-     private final MethodType type;
-     /*private*/ final LambdaForm form;
-     // form is not private so that invokers can easily fetch it
-+    /*private*/ MethodHandle asTypeCache;
-+    // asTypeCache is not private so that invokers can easily fetch it
- 
-     /**
-      * Reports the type of this method handle.
-@@ -739,10 +741,24 @@
-      * @see MethodHandles#explicitCastArguments
-      */
-     public MethodHandle asType(MethodType newType) {
--        if (!type.isConvertibleTo(newType)) {
-+        // Fast path alternative to a heavyweight {@code asType} call.
-+        // Return 'this' if the conversion will be a no-op.
-+        if (newType == type) {
-+            return this;
-+        }
-+        // Return 'this.asTypeCache' if the conversion is already memoized.
-+        MethodHandle atc = asTypeCache;
-+        if (atc != null && newType == atc.type) {
-+            return atc;
-+        }
-+        return asTypeUncached(newType);
-+    }
-+
-+    /** 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 convertArguments(newType);
-+        return asTypeCache = convertArguments(newType);
-     }
- 
-     /**
-diff --git a/src/share/classes/java/lang/invoke/MethodHandleImpl.java b/src/share/classes/java/lang/invoke/MethodHandleImpl.java
---- a/src/share/classes/java/lang/invoke/MethodHandleImpl.java
-+++ b/src/share/classes/java/lang/invoke/MethodHandleImpl.java
-@@ -314,13 +314,13 @@
-     static class AsVarargsCollector extends MethodHandle {
-         private final MethodHandle target;
-         private final Class<?> arrayType;
--        private MethodHandle cache;
-+        private /*@Stable*/ MethodHandle asCollectorCache;
- 
-         AsVarargsCollector(MethodHandle target, MethodType type, Class<?> arrayType) {
-             super(type, reinvokerForm(target));
-             this.target = target;
-             this.arrayType = arrayType;
--            this.cache = target.asCollector(arrayType, 0);
-+            this.asCollectorCache = target.asCollector(arrayType, 0);
-         }
- 
-         @Override MethodHandle reinvokerTarget() { return target; }
-@@ -336,18 +336,19 @@
-         }
- 
-         @Override
--        public MethodHandle asType(MethodType newType) {
-+        public MethodHandle asTypeUncached(MethodType newType) {
-             MethodType type = this.type();
-             int collectArg = type.parameterCount() - 1;
-             int newArity = newType.parameterCount();
-             if (newArity == collectArg+1 &&
-                 type.parameterType(collectArg).isAssignableFrom(newType.parameterType(collectArg))) {
-                 // if arity and trailing parameter are compatible, do normal thing
--                return asFixedArity().asType(newType);
-+                return asTypeCache = asFixedArity().asType(newType);
-             }
-             // check cache
--            if (cache.type().parameterCount() == newArity)
--                return cache.asType(newType);
-+            MethodHandle acc = asCollectorCache;
-+            if (acc != null && acc.type().parameterCount() == newArity)
-+                return asTypeCache = acc.asType(newType);
-             // build and cache a collector
-             int arrayLength = newArity - collectArg;
-             MethodHandle collector;
-@@ -357,8 +358,8 @@
-             } catch (IllegalArgumentException ex) {
-                 throw new WrongMethodTypeException("cannot build collector", ex);
-             }
--            cache = collector;
--            return collector.asType(newType);
-+            asCollectorCache = collector;
-+            return asTypeCache = collector.asType(newType);
-         }
- 
-         @Override
-@@ -971,6 +972,12 @@
-             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;
-         }
-diff --git a/src/share/classes/java/lang/invoke/MethodHandleNatives.java b/src/share/classes/java/lang/invoke/MethodHandleNatives.java
---- a/src/share/classes/java/lang/invoke/MethodHandleNatives.java
-+++ b/src/share/classes/java/lang/invoke/MethodHandleNatives.java
-@@ -233,7 +233,18 @@
-     }
-     static String refKindName(byte refKind) {
-         assert(refKindIsValid(refKind));
--        return REFERENCE_KIND_NAME[refKind];
-+        switch (refKind) {
-+        case REF_getField:          return "getField";
-+        case REF_getStatic:         return "getStatic";
-+        case REF_putField:          return "putField";
-+        case REF_putStatic:         return "putStatic";
-+        case REF_invokeVirtual:     return "invokeVirtual";
-+        case REF_invokeStatic:      return "invokeStatic";
-+        case REF_invokeSpecial:     return "invokeSpecial";
-+        case REF_newInvokeSpecial:  return "newInvokeSpecial";
-+        case REF_invokeInterface:   return "invokeInterface";
-+        default:                    return "REF_???";
-+        }
-     }
-     private static String[] REFERENCE_KIND_NAME = {
-             null,
-@@ -294,12 +305,18 @@
-         Class<?> caller = (Class<?>)callerObj;
-         String name = nameObj.toString().intern();
-         MethodType type = (MethodType)typeObj;
--        appendixResult[0] = CallSite.makeSite(bootstrapMethod,
-+        CallSite callSite = CallSite.makeSite(bootstrapMethod,
-                                               name,
-                                               type,
-                                               staticArguments,
-                                               caller);
--        return Invokers.linkToCallSiteMethod(type);
-+        if (callSite instanceof ConstantCallSite) {
-+            appendixResult[0] = callSite.dynamicInvoker();
-+            return Invokers.linkToTargetMethod(type);
-+        } else {
-+            appendixResult[0] = callSite;
-+            return Invokers.linkToCallSiteMethod(type);
-+        }
-     }
- 
-     /**
-@@ -390,9 +407,9 @@
-             if (defc == MethodHandle.class && refKind == REF_invokeVirtual) {
-                 switch (name) {
-                 case "invoke":
--                    return Invokers.genericInvokerMethod(fixMethodType(callerClass, type), appendixResult);
-+                    return Invokers.genericInvokeLinkerMethod(fixMethodType(callerClass, type), appendixResult);
-                 case "invokeExact":
--                    return Invokers.exactInvokerMethod(fixMethodType(callerClass, type), appendixResult);
-+                    return Invokers.exactInvokeLinkerMethod(fixMethodType(callerClass, type), appendixResult);
-                 }
-             }
-         } catch (Throwable ex) {
-diff --git a/src/share/classes/java/lang/invoke/MethodHandles.java b/src/share/classes/java/lang/invoke/MethodHandles.java
---- a/src/share/classes/java/lang/invoke/MethodHandles.java
-+++ b/src/share/classes/java/lang/invoke/MethodHandles.java
-@@ -39,6 +39,7 @@
- import sun.security.util.SecurityConstants;
- import static java.lang.invoke.MethodHandleStatics.*;
- import static java.lang.invoke.MethodHandleNatives.Constants.*;
-+import java.util.concurrent.ConcurrentHashMap;
- import sun.security.util.SecurityConstants;
- 
- /**
-@@ -1102,7 +1103,15 @@
-                                             NoSuchMethodException.class);
-         }
- 
-+        MemberName resolveOrFail(byte refKind, MemberName member) throws ReflectiveOperationException {
-+            checkSymbolicClass(member.getDeclaringClass());  // do this before attempting to resolve
-+            member.getName().getClass(); member.getType().getClass();  // NPE
-+            return IMPL_NAMES.resolveOrFail(refKind, member, lookupClassOrNull(),
-+                                            ReflectiveOperationException.class);
-+        }
-+
-         void checkSymbolicClass(Class<?> refc) throws IllegalAccessException {
-+            refc.getClass();  // NPE
-             Class<?> caller = lookupClassOrNull();
-             if (caller != null && !VerifyAccess.isClassAccessible(refc, caller, allowedModes))
-                 throw new MemberName(refc).makeAccessException("symbolic reference class is not public", this);
-@@ -1348,29 +1357,74 @@
-          */
-         /*non-public*/
-         MethodHandle linkMethodHandleConstant(byte refKind, Class<?> defc, String name, Object type) throws ReflectiveOperationException {
--            MemberName resolved = null;
--            if (type instanceof MemberName) {
--                resolved = (MemberName) type;
--                if (!resolved.isResolved())  throw new InternalError("unresolved MemberName");
--                assert(name == null || name.equals(resolved.getName()));
-+            if (!(type instanceof Class || type instanceof MethodType))
-+                throw new InternalError("unresolved MemberName");
-+            MemberName member = new MemberName(refKind, defc, name, type);
-+            MethodHandle mh = LOOKASIDE_TABLE.get(member);
-+            if (mh != null) {
-+                checkSymbolicClass(defc);
-+                return mh;
-             }
-+            MemberName resolved = resolveOrFail(refKind, member);
-+            mh = getDirectMethodHandle(refKind, defc, resolved);
-+            if (mh instanceof DirectMethodHandle
-+                    && canBeCached(refKind, defc, resolved)) {
-+                MemberName key = mh.internalMemberName();
-+                if (key != null) {
-+                    key = key.asNormalOriginal();
-+                }
-+                if (member.equals(key)) {  // better safe than sorry
-+                    LOOKASIDE_TABLE.put(key, (DirectMethodHandle) mh);
-+                }
-+            }
-+            return mh;
-+        }
-+        private
-+        boolean canBeCached(byte refKind, Class<?> defc, MemberName member) {
-+            if (refKind == REF_invokeSpecial) {
-+                return false;
-+            }
-+            if (!Modifier.isPublic(defc.getModifiers()) ||
-+                    !Modifier.isPublic(member.getDeclaringClass().getModifiers()) ||
-+                    !member.isPublic() ||
-+                    member.isCallerSensitive()) {
-+                return false;
-+            }
-+            ClassLoader loader = defc.getClassLoader();
-+            if (!sun.misc.VM.isSystemDomainLoader(loader)) {
-+                ClassLoader sysl = ClassLoader.getSystemClassLoader();
-+                boolean found = false;
-+                while (sysl != null) {
-+                    if (loader == sysl) { found = true; break; }
-+                    sysl = sysl.getParent();
-+                }
-+                if (!found) {
-+                    return false;
-+                }
-+            }
-+            try {
-+                MemberName resolved2 = publicLookup().resolveOrFail(refKind,
-+                    new MemberName(refKind, defc, member.getName(), member.getType()));
-+                checkSecurityManager(defc, resolved2);
-+            } catch (ReflectiveOperationException | SecurityException ex) {
-+                return false;
-+            }
-+            return true;
-+        }
-+        private
-+        MethodHandle getDirectMethodHandle(byte refKind, Class<?> defc, MemberName member) throws ReflectiveOperationException {
-             if (MethodHandleNatives.refKindIsField(refKind)) {
--                MemberName field = (resolved != null) ? resolved
--                        : resolveOrFail(refKind, defc, name, (Class<?>) type);
--                return getDirectField(refKind, defc, field);
-+                return getDirectField(refKind, defc, member);
-             } else if (MethodHandleNatives.refKindIsMethod(refKind)) {
--                MemberName method = (resolved != null) ? resolved
--                        : resolveOrFail(refKind, defc, name, (MethodType) type);
--                return getDirectMethod(refKind, defc, method, lookupClass);
-+                return getDirectMethod(refKind, defc, member, lookupClass);
-             } else if (refKind == REF_newInvokeSpecial) {
--                assert(name == null || name.equals("<init>"));
--                MemberName ctor = (resolved != null) ? resolved
--                        : resolveOrFail(REF_newInvokeSpecial, defc, name, (MethodType) type);
--                return getDirectConstructor(defc, ctor);
-+                return getDirectConstructor(defc, member);
-             }
-             // oops
--            throw new ReflectiveOperationException("bad MethodHandle constant #"+refKind+" "+name+" : "+type);
-+            throw newIllegalArgumentException("bad MethodHandle constant #"+member);
-         }
-+
-+        static ConcurrentHashMap<MemberName, DirectMethodHandle> LOOKASIDE_TABLE = new ConcurrentHashMap<>();
-     }
- 
-     /**
-diff --git a/src/share/classes/java/lang/invoke/MethodTypeForm.java b/src/share/classes/java/lang/invoke/MethodTypeForm.java
---- a/src/share/classes/java/lang/invoke/MethodTypeForm.java
-+++ b/src/share/classes/java/lang/invoke/MethodTypeForm.java
-@@ -28,6 +28,7 @@
- import sun.invoke.util.Wrapper;
- import static java.lang.invoke.MethodHandleStatics.*;
- import static java.lang.invoke.MethodHandleNatives.Constants.*;
-+ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
- 
- /**
-  * Shared information for a group of method types, which differ
-@@ -73,7 +74,8 @@
-             LF_GEN_LINKER     = 11,
-             LF_GEN_INVOKER    = 12,
-             LF_CS_LINKER      = 13,  // linkToCallSite_CS
--            LF_LIMIT          = 14;
-+            LF_MH_LINKER      = 14,  // linkToCallSite_MH
-+            LF_LIMIT          = 15;
- 
-     public MethodType erasedType() {
-         return erasedType;
-@@ -96,11 +98,22 @@
-         assert(erasedType == basicType) : "erasedType: " + erasedType + " != basicType: " + basicType;  // primitives must be flattened also
-         MethodHandle invoker = basicInvoker;
-         if (invoker != null)  return invoker;
--        invoker = basicType.invokers().makeBasicInvoker();
-+        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 {
-+            //Lookup.findVirtual(MethodHandle.class, name, type);
-+            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.
--- a/meth-aclone-8001105.patch	Sun Sep 15 17:15:12 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,120 +0,0 @@
-8001105: findVirtual of Object[].clone produces internal error
-http://mail.openjdk.java.net/pipermail/mlvm-dev/2012-October/005035.html
-
-diff --git a/src/share/classes/java/lang/invoke/MethodHandles.java b/src/share/classes/java/lang/invoke/MethodHandles.java
---- a/src/share/classes/java/lang/invoke/MethodHandles.java
-+++ b/src/share/classes/java/lang/invoke/MethodHandles.java
-@@ -1206,6 +1206,13 @@
-             int allowedModes = this.allowedModes;
-             if (allowedModes == TRUSTED)  return;
-             int mods = m.getModifiers();
-+            if (Modifier.isProtected(mods) &&
-+                    refKind == REF_invokeVirtual &&
-+                    m.getDeclaringClass() == Object.class &&
-+                    m.getName().equals("clone") &&
-+                    refc.isArray())
-+                // The JVM does this hack also, to make int[].clone be public.
-+                mods ^= Modifier.PROTECTED | Modifier.PUBLIC;
-             if (Modifier.isFinal(mods) &&
-                     MethodHandleNatives.refKindIsSetter(refKind))
-                 throw m.makeAccessException("unexpected set of a final field", this);
-diff --git a/test/java/lang/invoke/MethodHandlesTest.java b/test/java/lang/invoke/MethodHandlesTest.java
---- a/test/java/lang/invoke/MethodHandlesTest.java
-+++ b/test/java/lang/invoke/MethodHandlesTest.java
-@@ -140,7 +140,7 @@
-         Object actual   = calledLog.get(calledLog.size() - 1);
-         if (expected.equals(actual) && verbosity < 9)  return;
-         System.out.println("assertCalled "+name+":");
--        System.out.println("expected:   "+expected);
-+        System.out.println("expected:   "+deepToString(expected));
-         System.out.println("actual:     "+actual);
-         System.out.println("ex. types:  "+getClasses(expected));
-         System.out.println("act. types: "+getClasses(actual));
-@@ -148,7 +148,25 @@
-     }
-     static void printCalled(MethodHandle target, String name, Object... args) {
-         if (verbosity >= 3)
--            System.out.println("calling MH="+target+" to "+name+Arrays.toString(args));
-+            System.out.println("calling MH="+target+" to "+name+deepToString(args));
-+    }
-+    static String deepToString(Object x) {
-+        if (x == null)  return "null";
-+        if (x instanceof Collection)
-+            x = ((Collection)x).toArray();
-+        if (x instanceof Object[]) {
-+            Object[] ax = (Object[]) x;
-+            ax = Arrays.copyOf(ax, ax.length, Object[].class);
-+            for (int i = 0; i < ax.length; i++)
-+                ax[i] = deepToString(ax[i]);
-+            x = Arrays.deepToString(ax);
-+        }
-+        if (x.getClass().isArray())
-+            try {
-+                x = Arrays.class.getMethod("toString", x.getClass()).invoke(null, x);
-+            } catch (ReflectiveOperationException ex) { throw new Error(ex); }
-+        assert(!(x instanceof Object[]));
-+        return x.toString();
-     }
- 
-     static Object castToWrapper(Object value, Class<?> dst) {
-@@ -230,6 +248,12 @@
-                     { param = c; break; }
-             }
-         }
-+        if (param.isArray()) {
-+            Class<?> ctype = param.getComponentType();
-+            Object arg = Array.newInstance(ctype, 2);
-+            Array.set(arg, 0, randomArg(ctype));
-+            return arg;
-+        }
-         if (param.isInterface() && param.isAssignableFrom(List.class))
-             return Arrays.asList("#"+nextArg());
-         if (param.isInterface() || param.isAssignableFrom(String.class))
-@@ -590,6 +614,13 @@
-         testFindVirtual(SubExample.class,         Example.class, void.class, "Sub/pkg_v0");
-         testFindVirtual(Example.class,         IntExample.class, void.class, "v0");
-         testFindVirtual(IntExample.Impl.class, IntExample.class, void.class, "Int/v0");
-+
-+        // test some ad hoc system methods
-+        testFindVirtual(false, PUBLIC, Object.class, Object.class, "clone");
-+        testFindVirtual(true, PUBLIC, Object[].class, Object.class, "clone");
-+        testFindVirtual(true, PUBLIC, int[].class, Object.class, "clone");
-+        for (Class<?> cls : new Class<?>[]{ boolean[].class, long[].class, float[].class, char[].class })
-+            testFindVirtual(true, PUBLIC, cls, Object.class, "clone");
-     }
- 
-     void testFindVirtual(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
-@@ -604,6 +635,9 @@
-     void testFindVirtual(Lookup lookup, Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
-         testFindVirtual(true, lookup, rcvc, defc, ret, name, params);
-     }
-+    void testFindVirtual(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
-+        testFindVirtual(positive, lookup, defc, defc, ret, name, params);
-+    }
-     void testFindVirtual(boolean positive, Lookup lookup, Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
-         countTest(positive);
-         String methodName = name.substring(1 + name.indexOf('/'));  // foo/bar => foo
-@@ -643,8 +677,21 @@
-         Object[] argsWithSelf = randomArgs(paramsWithSelf);
-         if (selfc.isAssignableFrom(rcvc) && rcvc != selfc)  argsWithSelf[0] = randomArg(rcvc);
-         printCalled(target, name, argsWithSelf);
--        target.invokeWithArguments(argsWithSelf);
--        assertCalled(name, argsWithSelf);
-+        Object res = target.invokeWithArguments(argsWithSelf);
-+        if (Example.class.isAssignableFrom(defc) || IntExample.class.isAssignableFrom(defc)) {
-+            assertCalled(name, argsWithSelf);
-+        } else if (name.equals("clone")) {
-+            // Ad hoc method call outside Example.  For Object[].clone.
-+            printCalled(target, name, argsWithSelf);
-+            assertEquals(MethodType.methodType(Object.class, rcvc), target.type());
-+            Object orig = argsWithSelf[0];
-+            assertEquals(orig.getClass(), res.getClass());
-+            if (res instanceof Object[])
-+                assertArrayEquals((Object[])res, (Object[])argsWithSelf[0]);
-+            assert(Arrays.deepEquals(new Object[]{res}, new Object[]{argsWithSelf[0]}));
-+        } else {
-+            assert(false) : Arrays.asList(positive, lookup, rcvc, defc, ret, name, deepToString(params));
-+        }
-         if (verbosity >= 1)
-             System.out.print(':');
-     }
--- a/meth-arity-8019417.patch	Sun Sep 15 17:15:12 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,390 +0,0 @@
-8019417: JSR 292 javadoc should clarify method handle arity limits
-Summary: clarification of erroneous reading of spec. that led to 7194534
-Reviewed-by: ?
-
-diff --git a/src/share/classes/java/lang/invoke/MethodHandle.java b/src/share/classes/java/lang/invoke/MethodHandle.java
---- a/src/share/classes/java/lang/invoke/MethodHandle.java
-+++ b/src/share/classes/java/lang/invoke/MethodHandle.java
-@@ -392,7 +392,7 @@
-  * Java types.
-  * <ul>
-  * <li>Method types range over all possible arities,
-- * from no arguments to up to 255 of arguments (a limit imposed by the JVM).
-+ * from no arguments to up to the  <a href="MethodHandle.html#maxarity">maximum number</a> of allowed arguments.
-  * Generics are not variadic, and so cannot represent this.</li>
-  * <li>Method types can specify arguments of primitive types,
-  * which Java generic types cannot range over.</li>
-@@ -402,6 +402,22 @@
-  * genericity with a Java type parameter.</li>
-  * </ul>
-  *
-+ * <h1><a name="maxarity"></a>Arity limits</h1>
-+ * The JVM imposes on all methods and constructors of any kind an absolute
-+ * limit of 255 stacked arguments.  This limit can appear more restrictive
-+ * in certain cases:
-+ * <ul>
-+ * <li>A {@code long} or {@code double} argument counts (for purposes of arity limits) as two argument slots.
-+ * <li>A non-static method consumes an extra argument for the object on which the method is called.
-+ * <li>A constructor consumes an extra argument for the object which is being constructed.
-+ * <li>Since a method handle&rsquo;s {@code invoke} method (or other signature-polymorphic method) is non-virtual,
-+ *     it consumes an extra argument for the method handle itself, in addition to any non-virtual receiver object.
-+ * </ul>
-+ * These limits imply that certain method handles cannot be created, solely because of the JVM limit on stacked arguments.
-+ * For example, if a static JVM method accepts exactly 255 arguments, a method handle cannot be created for it.
-+ * Attempts to create method handles with impossible method types lead to an {@link IllegalArgumentException}.
-+ * In particular, a method handle&rsquo;s type must not have an arity of the exact maximum 255.
-+ *
-  * @see MethodType
-  * @see MethodHandles
-  * @author John Rose, JSR 292 EG
-@@ -815,10 +831,12 @@
-      * @return a new method handle which spreads its final array argument,
-      *         before calling the original method handle
-      * @throws NullPointerException if {@code arrayType} is a null reference
--     * @throws IllegalArgumentException if {@code arrayType} is not an array type
--     * @throws IllegalArgumentException if target does not have at least
-+     * @throws IllegalArgumentException if {@code arrayType} is not an array type,
-+     *         or if target does not have at least
-      *         {@code arrayLength} parameter types,
--     *         or if {@code arrayLength} is negative
-+     *         or if {@code arrayLength} is negative,
-+     *         or if the resulting method handle's type would have
-+     *         <a href="MethodHandle.html#maxarity">too many parameters</a>
-      * @throws WrongMethodTypeException if the implied {@code asType} call fails
-      * @see #asCollector
-      */
-@@ -931,7 +949,9 @@
-      * @throws NullPointerException if {@code arrayType} is a null reference
-      * @throws IllegalArgumentException if {@code arrayType} is not an array type
-      *         or {@code arrayType} is not assignable to this method handle's trailing parameter type,
--     *         or {@code arrayLength} is not a legal array size
-+     *         or {@code arrayLength} is not a legal array size,
-+     *         or the resulting method handle's type would have
-+     *         <a href="MethodHandle.html#maxarity">too many parameters</a>
-      * @throws WrongMethodTypeException if the implied {@code asType} call fails
-      * @see #asSpreader
-      * @see #asVarargsCollector
-diff --git a/src/share/classes/java/lang/invoke/MethodHandles.java b/src/share/classes/java/lang/invoke/MethodHandles.java
---- a/src/share/classes/java/lang/invoke/MethodHandles.java
-+++ b/src/share/classes/java/lang/invoke/MethodHandles.java
-@@ -244,6 +244,10 @@
-      * on various grounds (<a href="#secmgr">see below</a>).
-      * By contrast, the {@code ldc} instruction is not subject to
-      * security manager checks.
-+     * <li>If the looked-up method has a
-+     * <a href="MethodHandle.html#maxarity">very large arity</a>,
-+     * the method handle creation may fail, due to the method handle
-+     * type having too many parameters.
-      * </ul>
-      *
-      * <h1><a name="access"></a>Access checking</h1>
-@@ -1445,7 +1449,9 @@
-      * @return a method handle suitable for invoking any method handle of the given type
-      * @throws NullPointerException if {@code type} is null
-      * @throws IllegalArgumentException if {@code leadingArgCount} is not in
--     *                  the range from 0 to {@code type.parameterCount()} inclusive
-+     *                  the range from 0 to {@code type.parameterCount()} inclusive,
-+     *                  or if the resulting method handle's type would have
-+     *          <a href="MethodHandle.html#maxarity">too many parameters</a>
-      */
-     static public
-     MethodHandle spreadInvoker(MethodType type, int leadingArgCount) {
-@@ -1488,6 +1494,8 @@
-      * This method throws no reflective or security exceptions.
-      * @param type the desired target type
-      * @return a method handle suitable for invoking any method handle of the given type
-+     * @throws IllegalArgumentException if the resulting method handle's type would have
-+     *          <a href="MethodHandle.html#maxarity">too many parameters</a>
-      */
-     static public
-     MethodHandle exactInvoker(MethodType type) {
-@@ -1521,6 +1529,8 @@
-      * This method throws no reflective or security exceptions.
-      * @param type the desired target type
-      * @return a method handle suitable for invoking any method handle convertible to the given type
-+     * @throws IllegalArgumentException if the resulting method handle's type would have
-+     *          <a href="MethodHandle.html#maxarity">too many parameters</a>
-      */
-     static public
-     MethodHandle invoker(MethodType type) {
-@@ -1889,7 +1899,8 @@
-      *                              or if the {@code valueTypes} array or any of its elements is null
-      * @throws IllegalArgumentException if any element of {@code valueTypes} is {@code void.class},
-      *                  or if {@code pos} is negative or greater than the arity of the target,
--     *                  or if the new method handle's type would have too many parameters
-+     *                  or if the new method handle's type would have
-+     *                  <a href="MethodHandle.html#maxarity">too many parameters</a>
-      */
-     public static
-     MethodHandle dropArguments(MethodHandle target, int pos, Class<?>... valueTypes) {
-@@ -1957,7 +1968,9 @@
-      *                              or if the {@code filters} array is null
-      * @throws IllegalArgumentException if a non-null element of {@code filters}
-      *          does not match a corresponding argument type of target as described above,
--     *          or if the {@code pos+filters.length} is greater than {@code target.type().parameterCount()}
-+     *          or if the {@code pos+filters.length} is greater than {@code target.type().parameterCount()},
-+     *          or if the resulting method handle's type would have
-+     *          <a href="MethodHandle.html#maxarity">too many parameters</a>
-      */
-     public static
-     MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters) {
-diff --git a/test/java/lang/invoke/BigArityTest.java b/test/java/lang/invoke/BigArityTest.java
---- a/test/java/lang/invoke/BigArityTest.java
-+++ b/test/java/lang/invoke/BigArityTest.java
-@@ -93,6 +93,65 @@
-     }
- 
-     @Test
-+    public void asCollectorIAE01() throws ReflectiveOperationException {
-+        final int [] INVALID_ARRAY_LENGTHS = {
-+            Integer.MIN_VALUE, Integer.MIN_VALUE + 1, -2, -1, 255, 256, Integer.MAX_VALUE - 1, Integer.MAX_VALUE
-+        };
-+        MethodHandle target = MethodHandles.publicLookup().findStatic(Arrays.class,
-+                "deepToString", MethodType.methodType(String.class, Object[].class));
-+        int minbig = Integer.MAX_VALUE;
-+        for (int invalidLength : INVALID_ARRAY_LENGTHS) {
-+            if (minbig > invalidLength && invalidLength > 100)  minbig = invalidLength;
-+            try {
-+                target.asCollector(Object[].class, invalidLength);
-+                assert(false) : invalidLength;
-+            } catch (IllegalArgumentException ex) {
-+                System.out.println("OK: "+ex);
-+            }
-+        }
-+        // Sizes not in the above array are good:
-+        target.asCollector(Object[].class, minbig-1);
-+        for (int i = 2; i <= 10; i++)
-+            target.asCollector(Object[].class, minbig-i);
-+    }
-+
-+    @Test
-+    public void invoker02() {
-+        for (int i = 0; i < 255; i++) {
-+            MethodType mt = MethodType.genericMethodType(i);
-+            MethodType expMT = mt.insertParameterTypes(0, MethodHandle.class);
-+            if (i < 254) {
-+                assertEquals(expMT, MethodHandles.invoker(mt).type());
-+            } else {
-+                try {
-+                    MethodHandles.invoker(mt);
-+                    assert(false) : i;
-+                } catch (IllegalArgumentException ex) {
-+                    System.out.println("OK: "+ex);
-+                }
-+            }
-+        }
-+    }
-+
-+    @Test
-+    public void exactInvoker02() {
-+        for (int i = 0; i < 255; i++) {
-+            MethodType mt = MethodType.genericMethodType(i);
-+            MethodType expMT = mt.insertParameterTypes(0, MethodHandle.class);
-+            if (i < 254) {
-+                assertEquals(expMT, MethodHandles.exactInvoker(mt).type());
-+            } else {
-+                try {
-+                    MethodHandles.exactInvoker(mt);
-+                    assert(false) : i;
-+                } catch (IllegalArgumentException ex) {
-+                    System.out.println("OK: "+ex);
-+                }
-+            }
-+        }
-+    }
-+
-+    @Test
-     public void testBoundaryValues() throws Throwable {
-         for (int badArity : new int[]{ -1, MAX_JVM_ARITY+1, MAX_JVM_ARITY }) {
-             try {
-@@ -102,6 +161,37 @@
-                 System.out.println("OK: "+ex);
-             }
-         }
-+        final int MAX_MH_ARITY      = MAX_JVM_ARITY - 1;  // mh.invoke(arg*[N])
-+        final int MAX_INVOKER_ARITY = MAX_MH_ARITY - 1;   // inv.invoke(mh, arg*[N])
-+        for (int arity : new int[]{ 0, 1, MAX_MH_ARITY-2, MAX_MH_ARITY-1, MAX_MH_ARITY }) {
-+            MethodHandle mh = MH_hashArguments(arity);
-+            if (arity < MAX_INVOKER_ARITY) {
-+                MethodHandle ximh = MethodHandles.exactInvoker(mh.type());
-+                MethodHandle gimh = MethodHandles.invoker(mh.type());
-+                MethodHandle simh = MethodHandles.spreadInvoker(mh.type(), 0);
-+                if (arity != 0) {
-+                    simh = MethodHandles.spreadInvoker(mh.type(), 1);
-+                } else {
-+                    try {
-+                        simh = MethodHandles.spreadInvoker(mh.type(), 1);
-+                        assert(false) : arity;
-+                    } catch (IllegalArgumentException ex) {
-+                        System.out.println("OK: "+ex);
-+                    }
-+                }
-+                if (arity != 0) {
-+                    simh = MethodHandles.spreadInvoker(mh.type(), arity-1);
-+                } else {
-+                    try {
-+                        simh = MethodHandles.spreadInvoker(mh.type(), arity-1);
-+                        assert(false) : arity;
-+                    } catch (IllegalArgumentException ex) {
-+                        System.out.println("OK: "+ex);
-+                    }
-+                }
-+                simh = MethodHandles.spreadInvoker(mh.type(), arity);
-+            }
-+        }
-     }
- 
-     // Make sure the basic argument spreading and varargs mechanisms are working.
-@@ -133,7 +223,7 @@
-             if (cls == Object[].class)
-                 r = smh.invokeExact(tail);
-             else if (cls == Integer[].class)
--                r = smh.invokeExact((Integer[]) tail);
-+                r = smh.invokeExact((Integer[]) tail); //warning OK, see 8019340
-             else
-                 r = smh.invoke(tail);
-             assertEquals(r0, r);
-@@ -235,21 +325,41 @@
-             MethodHandle mh_VA = mh.asSpreader(cls, arity);
-             assert(mh_VA.type().parameterType(0) == cls);
-             testArities(cls, arity, iterations, verbose, mh, mh_VA);
-+            // mh_CA will collect arguments of a particular type and pass them to mh_VA
-+            MethodHandle mh_CA = mh_VA.asCollector(cls, arity);
-+            MethodHandle mh_VA2 = mh_CA.asSpreader(cls, arity);
-+            assert(mh_CA.type().equals(mh.type()));
-+            assert(mh_VA2.type().equals(mh_VA.type()));
-             if (cls != Object[].class) {
--                // mh_CA will collect arguments of a particular type and pass them to mh_VA
--                MethodHandle mh_CA = mh_VA.asCollector(cls, arity);
--                MethodHandle mh_VA2 = mh_CA.asSpreader(cls, arity);
-                 try {
-                     mh_VA2.invokeWithArguments(new Object[arity]);
-                     throw new AssertionError("should not reach");
-                 } catch (ClassCastException | WrongMethodTypeException ex) {
-                 }
--                assert(mh_CA.type().equals(mh.type()));
--                assert(mh_VA2.type().equals(mh_VA.type()));
--                testArities(cls, arity, iterations, false, mh_CA, mh_VA2);
-             }
-+            int iterations_VA = iterations / 100;
-+            testArities(cls, arity, iterations_VA, false, mh_CA, mh_VA2);
-         }
-     }
-+ 
-+   /**
-+     * Tests calls to {@link BigArityTest#hashArguments hashArguments} as related to a single given arity N.
-+     * Applies the given {@code mh} to a set of N integer arguments, checking the answer.
-+     * Also applies the varargs variation {@code mh_VA} to an array of type C[] (given by {@code cls}).
-+     * Test steps:
-+     * <ul>
-+     * <li>mh_VA.invokeExact(new C[]{ arg, ... })</li>
-+     * <li>mh.invokeWithArguments((Object[]) new C[]{ arg, ... })</li>
-+     * <li>exactInvoker(mh.type()).invokeWithArguments(new Object[]{ mh, arg, ... })</li>
-+     * <li>invoker(mh.type()).invokeWithArguments(new Object[]{ mh, arg, ... })</li>
-+     * </ul>
-+     * @param cls     array type for varargs call (one of Object[], Number[], Integer[], Comparable[])
-+     * @param arity   N, the number of arguments to {@code mh} and length of its varargs array, in [0..255]
-+     * @param iterations  number of times to repeat each test step (at least 4)
-+     * @param verbose are we printing extra output?
-+     * @param mh      a fixed-arity version of {@code hashArguments}
-+     * @param mh_VA   a variable-arity version of {@code hashArguments}, accepting the given array type {@code cls}
-+     */
-     private void testArities(Class<? extends Object[]> cls,
-                              int arity,
-                              int iterations,
-@@ -292,7 +402,7 @@
-             if (cls == Object[].class)
-                 r = mh_VA.invokeExact(args);
-             else if (cls == Integer[].class)
--                r = mh_VA.invokeExact((Integer[])args);
-+                r = mh_VA.invokeExact((Integer[])args); //warning OK, see 8019340
-             else
-                 r = mh_VA.invoke(args);
-             assertEquals(r0, r);
-@@ -392,10 +502,16 @@
-     a[0xE0], a[0xE1], a[0xE2], a[0xE3], a[0xE4], a[0xE5], a[0xE6], a[0xE7], a[0xE8], a[0xE9], a[0xEA], a[0xEB], a[0xEC], a[0xED], a[0xEE], a[0xEF],
-     a[0xF0], a[0xF1], a[0xF2], a[0xF3], a[0xF4], a[0xF5], a[0xF6], a[0xF7],
-     // </editor-fold>
--    a[0xF8], a[0xF9], a[0xFA], a[0xFB]);
-+    a[0xF8], a[0xF9], a[0xFA], a[0xFB]); // hashArguments_252
-         assertEquals(r0, r);
-         MethodType mt = MethodType.genericMethodType(ARITY);
-         MethodHandle mh = MethodHandles.lookup().findStatic(BigArityTest.class, "hashArguments_"+ARITY, mt);
-+        test252(mh, a, r0);
-+        MethodHandle mh_CA = MH_hashArguments_VA.asFixedArity().asCollector(Object[].class, ARITY);
-+        test252(mh_CA, a, r0);
-+    }
-+    public void test252(MethodHandle mh, Object[] a, Object r0) throws Throwable {
-+        Object r;
-         r = mh.invokeExact(
-     // <editor-fold defaultstate="collapsed" desc="a[0x00], a[0x01], a[0x02], a[0x03], a[0x04], ...">
-     a[0x00], a[0x01], a[0x02], a[0x03], a[0x04], a[0x05], a[0x06], a[0x07], a[0x08], a[0x09], a[0x0A], a[0x0B], a[0x0C], a[0x0D], a[0x0E], a[0x0F],
-@@ -599,10 +715,16 @@
-     a[0xE0], a[0xE1], a[0xE2], a[0xE3], a[0xE4], a[0xE5], a[0xE6], a[0xE7], a[0xE8], a[0xE9], a[0xEA], a[0xEB], a[0xEC], a[0xED], a[0xEE], a[0xEF],
-     a[0xF0], a[0xF1], a[0xF2], a[0xF3], a[0xF4], a[0xF5], a[0xF6], a[0xF7],
-     // </editor-fold>
--    a[0xF8], a[0xF9], a[0xFA], a[0xFB], a[0xFC]);
-+    a[0xF8], a[0xF9], a[0xFA], a[0xFB], a[0xFC]); // hashArguments_253
-         assertEquals(r0, r);
-         MethodType mt = MethodType.genericMethodType(ARITY);
-         MethodHandle mh = MethodHandles.lookup().findStatic(BigArityTest.class, "hashArguments_"+ARITY, mt);
-+        test253(mh, a, r0);
-+        MethodHandle mh_CA = MH_hashArguments_VA.asFixedArity().asCollector(Object[].class, ARITY);
-+        test253(mh_CA, a, r0);
-+    }
-+    public void test253(MethodHandle mh, Object[] a, Object r0) throws Throwable {
-+        Object r;
-         r = mh.invokeExact(
-     // <editor-fold defaultstate="collapsed" desc="a[0x00], a[0x01], a[0x02], a[0x03], a[0x04], ...">
-     a[0x00], a[0x01], a[0x02], a[0x03], a[0x04], a[0x05], a[0x06], a[0x07], a[0x08], a[0x09], a[0x0A], a[0x0B], a[0x0C], a[0x0D], a[0x0E], a[0x0F],
-@@ -648,7 +770,6 @@
-     // </editor-fold>
-     a[0xF8], a[0xF9], a[0xFA], a[0xFB], a[0xFC]);
-         assertEquals(r0, r);
--        // FIXME: This next one fails, because it uses an internal invoker of arity 255.
-         r = ximh.invokeWithArguments(cat(mh,a));
-         assertEquals(r0, r);
-         MethodHandle gimh = MethodHandles.invoker(mh.type());
-@@ -674,7 +795,6 @@
-     // </editor-fold>
-     a[0xF8], a[0xF9], a[0xFA], a[0xFB], a[0xFC]);
-         assertEquals(r0, r);
--        // FIXME: This next one fails, because it uses an internal invoker of arity 255.
-         r = gimh.invokeWithArguments(cat(mh,a));
-         assertEquals(r0, r);
-         mh = mh.asType(mh.type().changeParameterType(0x10, Integer.class));
-@@ -808,10 +928,16 @@
-     a[0xE0], a[0xE1], a[0xE2], a[0xE3], a[0xE4], a[0xE5], a[0xE6], a[0xE7], a[0xE8], a[0xE9], a[0xEA], a[0xEB], a[0xEC], a[0xED], a[0xEE], a[0xEF],
-     a[0xF0], a[0xF1], a[0xF2], a[0xF3], a[0xF4], a[0xF5], a[0xF6], a[0xF7],
-     // </editor-fold>
--    a[0xF8], a[0xF9], a[0xFA], a[0xFB], a[0xFC], a[0xFD]);
-+    a[0xF8], a[0xF9], a[0xFA], a[0xFB], a[0xFC], a[0xFD]); // hashArguments_254
-         assertEquals(r0, r);
-         MethodType mt = MethodType.genericMethodType(ARITY);
-         MethodHandle mh = MethodHandles.lookup().findStatic(BigArityTest.class, "hashArguments_"+ARITY, mt);
-+        test254(mh, a, r0);
-+        MethodHandle mh_CA = MH_hashArguments_VA.asFixedArity().asCollector(Object[].class, ARITY);
-+        test254(mh_CA, a, r0);
-+    }
-+    public void test254(MethodHandle mh, Object[] a, Object r0) throws Throwable {
-+        Object r;
-         r = mh.invokeExact(
-     // <editor-fold defaultstate="collapsed" desc="a[0x00], a[0x01], a[0x02], a[0x03], a[0x04], ...">
-     a[0x00], a[0x01], a[0x02], a[0x03], a[0x04], a[0x05], a[0x06], a[0x07], a[0x08], a[0x09], a[0x0A], a[0x0B], a[0x0C], a[0x0D], a[0x0E], a[0x0F],
-@@ -833,7 +959,6 @@
-     // </editor-fold>
-     a[0xF8], a[0xF9], a[0xFA], a[0xFB], a[0xFC], a[0xFD]);
-         assertEquals(r0, r);
--        // FIXME: This next one fails, because it uses an internal invoker of arity 255.
-         r = mh.invokeWithArguments(a);
-         assertEquals(r0, r);
-         try {
-@@ -998,7 +1123,7 @@
-     a[0xE0], a[0xE1], a[0xE2], a[0xE3], a[0xE4], a[0xE5], a[0xE6], a[0xE7], a[0xE8], a[0xE9], a[0xEA], a[0xEB], a[0xEC], a[0xED], a[0xEE], a[0xEF],
-     a[0xF0], a[0xF1], a[0xF2], a[0xF3], a[0xF4], a[0xF5], a[0xF6], a[0xF7],
-     // </editor-fold>
--    a[0xF8], a[0xF9], a[0xFA], a[0xFB], a[0xFC], a[0xFD], a[0xFE]);
-+    a[0xF8], a[0xF9], a[0xFA], a[0xFB], a[0xFC], a[0xFD], a[0xFE]); // hashArguments_255
-         assertEquals(r0, r);
-         MethodType mt = MethodType.genericMethodType(ARITY);
-         MethodHandle mh;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/meth-asm.patch	Sun Oct 06 22:41:41 2013 -0700
@@ -0,0 +1,1048 @@
+Improvements and cleanups to bytecode assembly for lambda forms.
+
+diff --git a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
+--- a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
++++ b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
+@@ -25,12 +25,6 @@
+ 
+ package java.lang.invoke;
+ 
+-import sun.invoke.util.VerifyAccess;
+-import java.lang.invoke.MethodHandles.Lookup;
+-import static java.lang.invoke.LambdaForm.*;
+-
+-import sun.invoke.util.Wrapper;
+-
+ import java.io.*;
+ import java.util.*;
+ 
+@@ -40,8 +34,12 @@
+ import static java.lang.invoke.MethodHandleStatics.*;
+ import static java.lang.invoke.MethodHandleNatives.Constants.*;
+ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
++import static java.lang.invoke.LambdaForm.*;
++import java.lang.invoke.MethodHandleImpl.ArrayAccessor;
+ import sun.invoke.util.ValueConversions;
+ import sun.invoke.util.VerifyType;
++import sun.invoke.util.VerifyAccess;
++import sun.invoke.util.Wrapper;
+ 
+ /**
+  * Code generation backend for LambdaForm.
+@@ -75,6 +73,8 @@
+     private final String     invokerName;
+     private final MethodType invokerType;
+     private final int[] localsMap;
++    private final byte[] localTypes;
++    private final Class<?>[] localClasses;
+ 
+     /** ASM bytecode generation. */
+     private ClassWriter cw;
+@@ -83,6 +83,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 +99,27 @@
+         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 byte[localsMapSize+1];
++        this.localClasses = new Class<?>[localsMapSize+1];
++        bump(EC_bytecode);
+     }
+ 
++    /** 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] = T_VOID;
+         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 +127,11 @@
+         Name[] names = form.names;
+         for (int i = 0, index = 0; i < localsMap.length; i++) {
+             localsMap[i] = index;
+-            index += basicTypeWrapper(names[i].type).stackSlots();
++            if (i < names.length) {
++                byte type = names[i].type();
++                index += basicTypeSlots(type);
++                localTypes[i] = type;
++            }
+         }
+     }
+ 
+@@ -148,7 +162,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 +169,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 +218,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 +239,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.
+      *
+@@ -252,6 +277,7 @@
+      * Define a given class as anonymous class in the runtime system.
+      */
+     private static Class<?> loadAndInitializeInvokerClass(byte[] classBytes, Object[] patches) {
++        bump(EC_bytecode);
+         Class<?> invokerClass = UNSAFE.defineAnonymousClass(HOST_CLASS, classBytes, patches);
+         UNSAFE.ensureClassInitialized(invokerClass);  // Make sure the class is initialized; VM might complain.
+         return invokerClass;
+@@ -403,6 +429,30 @@
+         emitStoreInsn(L_TYPE, index);
+     }
+ 
++    private void freeFrameLocal(int oldFrameLocal) {
++        int i = indexForFrameLocal(oldFrameLocal);
++        if (i < 0)  return;
++        byte 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(byte type) {
++        int frameLocal = localsMap[localsMap.length - 1];
++        localsMap[localsMap.length - 1] = frameLocal + basicTypeSlots(type);
++        return frameLocal;
++    }
++
+     /**
+      * Emit a boxing call.
+      *
+@@ -424,43 +474,80 @@
+         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);
+     }
+ 
+     /**
+-     * 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(byte ptype, Class<?> pclass) {
++    private void emitImplicitConversion(byte ptype, Class<?> pclass, Object arg) {
+         assert(basicType(pclass) == ptype);  // boxing/unboxing handled by caller
+         if (pclass == basicTypeClass(ptype) && ptype != L_TYPE)
+             return;   // nothing to do
+         switch (ptype) {
+         case L_TYPE:
+-            if (VerifyType.isNullConversion(Object.class, pclass))
++            if (VerifyType.isNullConversion(Object.class, pclass, false)) {
++                if (PROFILE_LEVEL >= 0)
++                    emitReferenceCast(Object.class, 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.INVOKEVIRTUAL, CLS, "cast", LL_SIG);
+-                if (pclass.isArray())
+-                    mv.visitTypeInsn(Opcodes.CHECKCAST, OBJARY);
+             }
++            emitReferenceCast(pclass, arg);
+             return;
+         case I_TYPE:
+-            if (!VerifyType.isNullConversion(int.class, pclass))
++            if (!VerifyType.isNullConversion(int.class, pclass, false))
+                 emitPrimCast(basicTypeWrapper(ptype), Wrapper.forPrimitiveType(pclass));
+             return;
+         }
+         throw new InternalError("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;
++            }
++        }
++        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);
++            if (Object[].class.isAssignableFrom(cls))
++                mv.visitTypeInsn(Opcodes.CHECKCAST, OBJARY);
++            else if (PROFILE_LEVEL >= 0)
++                mv.visitTypeInsn(Opcodes.CHECKCAST, OBJ);
++            mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, CLS, "cast", LL_SIG);
++        }
++        if (writeBack != null) {
++            mv.visitInsn(Opcodes.DUP);
++            emitAstoreInsn(writeBack.index());
++        }
++    }
++
+     /**
+      * Emits an actual return instruction conforming to the given return type.
+      */
+@@ -480,6 +567,10 @@
+     }
+ 
+     private static String getInternalName(Class<?> c) {
++        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));
+         return c.getName().replace('.', '/');
+     }
+@@ -512,16 +603,29 @@
+         for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
+             Name name = lambdaForm.names[i];
+             MemberName member = name.function.member();
++            Name nextName;
++            Class<?> rtype = name.function.methodType().returnType();
+ 
+-            if (isSelectAlternative(member)) {
++            if (isSelectAlternative(name) &&
++                    i+1 < lambdaForm.names.length &&
++                    isInvokeBasic(nextName = lambdaForm.names[i+1]) &&
++                    nextName.lastUseIndex(name) == 0 &&
++                    lambdaForm.lastUseIndex(name) == i+1) {
+                 // selectAlternative idiom
+-                // FIXME: make sure this idiom is really present!
+-                emitSelectAlternative(name, lambdaForm.names[i + 1]);
++                bump(EC_bytecode_invoke_selectAlternative);
++                emitSelectAlternative(name, nextName);
+                 i++;  // skip MH.invokeBasic of the selectAlternative result
+-                name = lambdaForm.names[i];
++                name = nextName;
++            } else if (isNewArray(rtype, name)) {
++                bump(EC_bytecode_invoke_newarray);
++                emitNewArray(rtype, name);
+             } else if (isStaticallyInvocable(member)) {
++                bump(EC_bytecode_invoke_named);
++                if (isLinkerMethodInvoke(name))
++                    preserveLinkerMethodTarget(name);
+                 emitStaticInvoke(member, name);
+             } else {
++                bump(EC_bytecode_invoke_handle);
+                 emitInvoke(name);
+             }
+ 
+@@ -547,20 +651,48 @@
+         return classFile;
+     }
+ 
++    /** Certain parts of the JVM expect that, when a call to linkToStatic is made,
++     *  the DMH that produced its MN argument is in local #0.
++     *  This is often true, since the lambda form of a DMH will start with
++     *  the DMH 'l'in arg 0 (local #0) and will end with a call to its linker method.
++     *  But if the DMH is transformed, a new lambda form may be created with
++     *  the DMH placed elsewhere.
++     */
++    private void preserveLinkerMethodTarget(Name name) {
++        Object lastArg = name.arguments[name.arguments.length - 1];
++        Name targetMember = (Name) lastArg;
++        assert(targetMember.type() == L_TYPE &&
++                !targetMember.isParam() &&
++                isStaticallyInvocable(targetMember.function.member()) &&
++                targetMember.arguments.length == 1);
++        Object targetDMH = DirectMethodHandle.findDirectMethodHandle(targetMember);
++        assert(targetDMH != null);
++        if (!(targetDMH instanceof Name && ((Name)targetDMH).index() == 0)) {
++            // Oops, the DMH is not in a local #0, or is a constant.
++            int DMH_FRAME_INDEX = 0;  // hardwired to local #0
++            byte DMH_TYPE = L_TYPE;
++            freeFrameLocal(DMH_FRAME_INDEX);
++            // Save it to local #0:
++            emitPushArgument(Object.class, targetDMH);
++            mv.visitVarInsn(storeInsnOpcode(DMH_TYPE), DMH_FRAME_INDEX);
++        }
++    }
++
+     /**
+      * 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
+@@ -606,8 +738,14 @@
+             return true;
+         return false;
+     }
++    static {
++        assert(isStaticallyInvocable(ArrayAccessor.OBJECT_ARRAY_GETTER.internalMemberName()));
++        assert(isStaticallyInvocable(ArrayAccessor.OBJECT_ARRAY_SETTER.internalMemberName()));
++    }
+ 
+     static boolean isStaticallyNameable(Class<?> cls) {
++        if (cls == Object.class)
++            return true;
+         while (cls.isArray())
+             cls = cls.getComponentType();
+         if (cls.isPrimitive())
+@@ -630,7 +768,8 @@
+      */
+     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();
+@@ -646,13 +785,71 @@
+         }
+ 
+         // invocation
+-        if (member.isMethod()) {
++        if (defc == ArrayAccessor.class &&
++                match(member, ArrayAccessor.OBJECT_ARRAY_GETTER)) {
++            bump(EC_bytecode_invoke_named_instruction);
++            mv.visitInsn(Opcodes.AALOAD);
++        } else if (defc == ArrayAccessor.class &&
++                match(member, ArrayAccessor.OBJECT_ARRAY_SETTER)) {
++            bump(EC_bytecode_invoke_named_instruction);
++            mv.visitInsn(Opcodes.AASTORE);
++        } else if (member.isMethod()) {
++            bump(EC_bytecode_invoke_named_method);
+             mtype = member.getMethodType().toMethodDescriptorString();
+             mv.visitMethodInsn(refKindOpcode(refKind), cname, mname, mtype);
+         } else {
++            bump(EC_bytecode_invoke_named_field);
+             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') {
++            Class<?> rtype = member.getInvocationType().returnType();
++            assert(!rtype.isPrimitive());
++            if (rtype != Object.class && !rtype.isInterface()) {
++                assertStaticType(rtype, name);
++            }
++        }
++    }
++
++    boolean isNewArray(Class<?> rtype, Name name) {
++        return rtype.isArray() &&
++                isStaticallyNameable(rtype) &&
++                isArrayBuilder(name.function.resolvedHandle) &&
++                name.arguments.length > 0;
++    }
++
++    void emitNewArray(Class<?> rtype, Name name) throws InternalError {
++        Class<?> arrayElementType = rtype.getComponentType();
++        emitIconstInsn(name.arguments.length);
++        int xas;
++        if (!arrayElementType.isPrimitive()) {
++            mv.visitTypeInsn(Opcodes.ANEWARRAY, getInternalName(arrayElementType));
++            xas = Opcodes.AASTORE;
++        } else {
++            int tc;
++            switch (Wrapper.forPrimitiveType(arrayElementType)) {
++            case BOOLEAN: tc = Opcodes.T_BOOLEAN; xas = Opcodes.BASTORE; break;
++            case BYTE:    tc = Opcodes.T_BYTE;    xas = Opcodes.BASTORE; break;
++            case CHAR:    tc = Opcodes.T_CHAR;    xas = Opcodes.CASTORE; break;
++            case SHORT:   tc = Opcodes.T_SHORT;   xas = Opcodes.SASTORE; break;
++            case INT:     tc = Opcodes.T_INT;     xas = Opcodes.IASTORE; break;
++            case LONG:    tc = Opcodes.T_LONG;    xas = Opcodes.LASTORE; break;
++            case FLOAT:   tc = Opcodes.T_FLOAT;   xas = Opcodes.FASTORE; break;
++            case DOUBLE:  tc = Opcodes.T_DOUBLE;  xas = Opcodes.DASTORE; break;
++            default:      throw new InternalError(rtype.getName());
++            }
++            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) {
+@@ -668,16 +865,67 @@
+         throw new InternalError("refKind="+refKind);
+     }
+ 
++    static boolean isArrayBuilder(MethodHandle fn) {
++        if (fn == null)
++            return false;
++        MethodType mtype = fn.type();
++        Class<?> rtype = mtype.returnType();
++        Class<?> arrayElementType = rtype.getComponentType();
++        if (arrayElementType == null)
++            return false;
++        List<Class<?>> ptypes = mtype.parameterList();
++        int size = ptypes.size();
++        if (!ptypes.equals(Collections.nCopies(size, arrayElementType)))
++            return false;
++        // Assume varargsArray caches pointers.
++        if (fn != ValueConversions.varargsArray(rtype, size))
++            return false;
++        return true;
++    }
++    static boolean match(MemberName member, MethodHandle fn) {
++        if (member == null || fn == null)  return false;
++        return member.equals(fn.internalMemberName());
++    }
++
+     /**
+      * Check if MemberName is a call to MethodHandleImpl.selectAlternative.
+      */
+-    private boolean isSelectAlternative(MemberName member) {
++    private boolean isSelectAlternative(Name name) {
++        if (name.function == null)  return false;
++        MemberName member = name.function.member();
+         return member != null &&
+                member.getDeclaringClass() == MethodHandleImpl.class &&
+                member.getName().equals("selectAlternative");
+     }
+ 
+     /**
++     * Check if MemberName is a call to MethodHandle.invokeBasic.
++     */
++    private boolean isInvokeBasic(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().equals("invokeBasic");
++    }
++
++
++    /**
++     * 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");
++    }
++
++    /**
+      * Emit bytecode for the selectAlternative idiom.
+      *
+      * The pattern looks like (Cf. MethodHandleImpl.makeGuardWithTest):
+@@ -698,13 +946,12 @@
+ 
+         // 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]
+-        MethodHandle target = (MethodHandle) 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);
+@@ -716,13 +963,15 @@
+         mv.visitLabel(L_fallback);
+ 
+         // invoke selectAlternativeName.arguments[2]
+-        MethodHandle fallback = (MethodHandle) 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);
+ 
+         // 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);
+     }
+ 
+     private void emitPushArgument(Name name, int paramIndex) {
+@@ -736,7 +985,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 {
+@@ -744,7 +993,7 @@
+                 emitConst(arg);
+             } else {
+                 mv.visitLdcInsn(constantPlaceholder(arg));
+-                emitImplicitConversion(L_TYPE, ptype);
++                emitImplicitConversion(L_TYPE, ptype, arg);
+             }
+         }
+     }
+@@ -765,11 +1014,12 @@
+             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) {
+-                emitLoadInsn(rn.type, lambdaForm.result);
++            if (lambdaForm.result != lambdaForm.names.length - 1 ||
++                    lambdaForm.result < lambdaForm.arity) {
++                emitLoadInsn(rtype, lambdaForm.result);
+             }
+ 
+-            emitImplicitConversion(rtype, rclass);
++            emitImplicitConversion(rtype, rclass, rn);
+ 
+             // generate actual return statement
+             emitReturnInsn(rtype);
+@@ -875,6 +1125,7 @@
+      * Generate bytecode for a LambdaForm.vmentry which calls interpretWithArguments.
+      */
+     static MemberName generateLambdaFormInterpreterEntryPoint(String sig) {
++        bump(EC_bytecode_interp_LambdaForm);
+         assert(isValidSignature(sig));
+         String name = "interpret_"+basicTypeChar(signatureReturn(sig));
+         MethodType type = signatureType(sig);  // sig includes leading argument
+@@ -935,6 +1186,7 @@
+      * Generate bytecode for a NamedFunction invoker.
+      */
+     static MemberName generateNamedFunctionInvoker(MethodTypeForm typeForm) {
++        bump(EC_bytecode_interp_NamedFunction);
+         MethodType invokerType = NamedFunction.INVOKER_METHOD_TYPE;
+         String invokerName = "invoke_" + shortenSignature(basicTypeSignature(typeForm.erasedType()));
+         InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("NFI", invokerName, invokerType);
+@@ -1017,4 +1269,19 @@
+             mv.visitEnd();
+         }
+     }
++
++    private static final EventCounter EC_bytecode = eventCounter("bytecode");
++    private static final EventCounter EC_bytecode_interp = eventCounter(EC_bytecode, "interp", /*autosum=*/true);
++    private static final EventCounter EC_bytecode_interp_LambdaForm = eventCounter(EC_bytecode_interp, "LambdaForm");
++    private static final EventCounter EC_bytecode_interp_NamedFunction = eventCounter(EC_bytecode_interp, "NamedFunction");
++    // bytecode.invoke is named similarly but a separate set of counters
++    private static final EventCounter EC_bytecode_invoke = eventCounter("bytecode.invoke", /*autosum=*/true);
++    private static final EventCounter EC_bytecode_invoke_selectAlternative = eventCounter(EC_bytecode_invoke, "selectAlternative");
++    private static final EventCounter EC_bytecode_invoke_newarray = eventCounter(EC_bytecode_invoke, "newarray");
++    private static final EventCounter EC_bytecode_invoke_named = eventCounter(EC_bytecode_invoke, "named");
++    private static final EventCounter EC_bytecode_invoke_named_method = eventCounter(EC_bytecode_invoke_named, "method");
++    private static final EventCounter EC_bytecode_invoke_named_field = eventCounter(EC_bytecode_invoke_named, "field");
++    private static final EventCounter EC_bytecode_invoke_named_instruction = eventCounter(EC_bytecode_invoke_named, "instruction");
++    private static final EventCounter EC_bytecode_invoke_handle = eventCounter(EC_bytecode_invoke, "handle");
++    private static final EventCounter EC_bytecode_invoke_handle_direct = eventCounter(EC_bytecode_invoke_handle, "direct");
+ }
+diff --git a/src/share/classes/java/lang/invoke/LambdaForm.java b/src/share/classes/java/lang/invoke/LambdaForm.java
+--- a/src/share/classes/java/lang/invoke/LambdaForm.java
++++ b/src/share/classes/java/lang/invoke/LambdaForm.java
+@@ -525,6 +525,7 @@
+             bump(EC_lambdaForm_comp);
+             return vmentry;
+         } catch (Error | Exception ex) {
++            ex.printStackTrace(System.out);//@@
+             throw newInternalError("compileToBytecode", ex);
+         }
+     }
+@@ -1637,6 +1638,30 @@
+             }
+             return false;
+         }
++        /** Return the index of the last occurrence of n in the argument array.
++         *  Return -1 if the name is not used.
++         */
++        int lastUseIndex(Name n) {
++            if (arguments == null)  return -1;
++            for (int i = arguments.length; --i >= 0; ) {
++                if (arguments[i] == n)  return i;
++            }
++            return -1;
++        }
++        /** Return the number of occurrences of n in the argument array.
++         *  Return 0 if the name is not used.
++         */
++        int useCount(Name n) {
++            if (arguments == null)  return 0;
++            int count = 0;
++            for (int i = arguments.length; --i >= 0; ) {
++                if (arguments[i] == n)  ++count;
++            }
++            return count;
++        }
++        boolean contains(Name n) {
++            return this == n || lastUseIndex(n) >= 0;
++        }
+ 
+         public boolean equals(Name that) {
+             if (this == that)  return true;
+@@ -1661,6 +1686,35 @@
+         }
+     }
+ 
++    /** Return the index of the last name which contains n as an argument.
++     *  Return -1 if the name is not used.  Return names.length if it is the return value.
++     */
++    int lastUseIndex(Name n) {
++        int ni = n.index, nmax = names.length;
++        assert(names[ni] == n);
++        if (result == ni)  return nmax;  // live all the way beyond the end
++        for (int i = nmax; --i > ni; ) {
++            if (names[i].lastUseIndex(n) >= 0)
++                return i;
++        }
++        return -1;
++    }
++
++    /** Return the number of times n is used as an argument or return value. */
++    int useCount(Name n) {
++        int ni = n.index, nmax = names.length;
++        int end = lastUseIndex(n);
++        if (end < 0)  return 0;
++        int count = 0;
++        if (end == nmax) { count++; end--; }
++        int beg = n.index() + 1;
++        if (beg < arity)  beg = arity;
++        for (int i = beg; i <= end; i++) {
++            count += names[i].useCount(n);
++        }
++        return count;
++    }
++
+     static Name argument(int which, char type) {
+         return argument(which, basicType(type));
+     }
+diff --git a/src/share/classes/java/lang/invoke/MethodHandleImpl.java b/src/share/classes/java/lang/invoke/MethodHandleImpl.java
+--- a/src/share/classes/java/lang/invoke/MethodHandleImpl.java
++++ b/src/share/classes/java/lang/invoke/MethodHandleImpl.java
+@@ -50,30 +50,46 @@
+     static void initStatics() {
+         // Trigger selected static initializations.
+         MemberName.Factory.INSTANCE.getClass();
+-    }
++   }
+ 
+     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);
+         }
+-        mh = mh.asType(ArrayAccessor.correctType(arrayClass, isSetter));
++        cache[cacheIndex] = mh;
+         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 = getAccessor(Object[].class, false);
++            cache[SETTER_INDEX] = OBJECT_ARRAY_SETTER = getAccessor(Object[].class, true);
++        }
+ 
+         static int     getElementI(int[]     a, int i)            { return              a[i]; }
+         static long    getElementJ(long[]    a, int i)            { return              a[i]; }
+@@ -95,45 +111,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();
+@@ -181,7 +173,7 @@
+         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) ||
++            if (!VerifyType.isNullConversion(src, dst, false) ||
+                 level <= 1 && dst.isInterface() && !dst.isAssignableFrom(src)) {
+                 needConv[i] = true;
+                 conversions++;
+@@ -189,6 +181,10 @@
+             }
+         }
+         boolean retConv = needConv[INARG_COUNT];
++        if (retConv && srcType.returnType() == void.class) {
++            retConv = false;
++            conversions--;
++        }
+ 
+         final int IN_MH         = 0;
+         final int INARG_BASE    = 1;
+@@ -196,6 +192,7 @@
+         final int NAME_LIMIT    = INARG_LIMIT + conversions + 1;
+         final int RETURN_CONV   = (!retConv ? -1         : NAME_LIMIT - 1);
+         final int OUT_CALL      = (!retConv ? NAME_LIMIT : RETURN_CONV) - 1;
++        final int RESULT        = (srcType.returnType() == void.class ? -1 : NAME_LIMIT - 1);
+ 
+         // Now build a LambdaForm.
+         MethodType lambdaType = srcType.basicType().invokerType();
+@@ -233,7 +230,7 @@
+                 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())) {
++                    if (level == 0 || VerifyType.isNullConversion(src, w.wrapperType(), false)) {
+                         fn = ValueConversions.unbox(dst);
+                     } else if (src == Object.class || !Wrapper.isWrapperType(src)) {
+                         // Examples:  Object->int, Number->int, Comparable->int; Byte->int, Character->int
+@@ -292,7 +289,7 @@
+             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);
+     }
+ 
+diff --git a/src/share/classes/java/lang/invoke/MethodHandleStatics.java b/src/share/classes/java/lang/invoke/MethodHandleStatics.java
+--- a/src/share/classes/java/lang/invoke/MethodHandleStatics.java
++++ b/src/share/classes/java/lang/invoke/MethodHandleStatics.java
+@@ -50,8 +50,9 @@
+     static final boolean TRACE_METHOD_LINKAGE;
+     static final boolean COUNT_EVENTS;
+     static final Integer COMPILE_THRESHOLD;
++    static final int PROFILE_LEVEL;
+     static {
+-        final Object[] values = { false, 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");
+@@ -60,6 +61,7 @@
+                     values[3] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE");
+                     values[4] = Boolean.getBoolean("java.lang.invoke.MethodHandle.COUNT_EVENTS");
+                     values[5] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD");
++                    values[6] = Integer.getInteger("java.lang.invoke.MethodHandle.PROFILE_LEVEL", 0);
+                     return null;
+                 }
+             });
+@@ -69,6 +71,7 @@
+         TRACE_METHOD_LINKAGE      = (Boolean) values[3];
+         COUNT_EVENTS              = (Boolean) values[4];
+         COMPILE_THRESHOLD         = (Integer) values[5];
++        PROFILE_LEVEL             = (Integer) values[6];
+     }
+ 
+     /** Tell if any of the debugging switches are turned on.
+@@ -169,10 +172,12 @@
+     }
+     static long count(EventCounter ec) {
+         if (!COUNT_EVENTS)  return -1;
++        if (ec == null)     return 0;  // still bootstrapping
+         return ec.count();
+     }
+     static void bump(EventCounter ec) {
+         if (!COUNT_EVENTS)  return;
++        if (ec == null)     return;  // still bootstrapping
+         ec.bump();
+     }
+     static class EventCounter implements Comparable<EventCounter> {
+diff --git a/src/share/classes/java/lang/invoke/MethodType.java b/src/share/classes/java/lang/invoke/MethodType.java
+--- a/src/share/classes/java/lang/invoke/MethodType.java
++++ b/src/share/classes/java/lang/invoke/MethodType.java
+@@ -721,13 +721,13 @@
+ 
+     /*non-public*/
+     boolean isViewableAs(MethodType newType) {
+-        if (!VerifyType.isNullConversion(returnType(), newType.returnType()))
++        if (!VerifyType.isNullConversion(returnType(), newType.returnType(), true))
+             return false;
+         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), true))
+                 return false;
+         }
+         return true;
+diff --git a/src/share/classes/sun/invoke/util/VerifyType.java b/src/share/classes/sun/invoke/util/VerifyType.java
+--- a/src/share/classes/sun/invoke/util/VerifyType.java
++++ b/src/share/classes/sun/invoke/util/VerifyType.java
+@@ -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 difference 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);
+     }
+ 
+     /**
+diff --git a/src/share/classes/sun/invoke/util/Wrapper.java b/src/share/classes/sun/invoke/util/Wrapper.java
+--- a/src/share/classes/sun/invoke/util/Wrapper.java
++++ b/src/share/classes/sun/invoke/util/Wrapper.java
+@@ -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.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/meth-btype.patch	Sun Oct 06 22:41:41 2013 -0700
@@ -0,0 +1,1962 @@
+Get rid of char-based descriptions 'J' of basic types; use short dense indexes LambdaForm.J_TYPE.
+
+diff --git a/src/share/classes/java/lang/invoke/BoundMethodHandle.java b/src/share/classes/java/lang/invoke/BoundMethodHandle.java
+--- a/src/share/classes/java/lang/invoke/BoundMethodHandle.java
++++ b/src/share/classes/java/lang/invoke/BoundMethodHandle.java
+@@ -26,7 +26,7 @@
+ package java.lang.invoke;
+ 
+ import static jdk.internal.org.objectweb.asm.Opcodes.*;
+-import static java.lang.invoke.LambdaForm.basicTypes;
++import static java.lang.invoke.LambdaForm.*;
+ import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;
+ import static java.lang.invoke.MethodHandleStatics.*;
+ 
+@@ -71,27 +71,25 @@
+         }
+     }
+ 
+-    private int fieldCount() { return speciesData().fieldCount(); }
+-
+     //
+     // BMH API and internals
+     //
+ 
+-    static MethodHandle bindSingle(MethodType type, LambdaForm form, char xtype, Object x) {
++    static MethodHandle bindSingle(MethodType type, LambdaForm form, byte xtype, Object x) {
+         // for some type signatures, there exist pre-defined concrete BMH classes
+         try {
+             switch (xtype) {
+-            case 'L':
++            case L_TYPE:
+                 if (true)  return bindSingle(type, form, x);  // Use known fast path.
+-                return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('L').constructor[0].invokeBasic(type, form, x);
+-            case 'I':
+-                return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('I').constructor[0].invokeBasic(type, form, ValueConversions.widenSubword(x));
+-            case 'J':
+-                return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('J').constructor[0].invokeBasic(type, form, (long) x);
+-            case 'F':
+-                return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('F').constructor[0].invokeBasic(type, form, (float) x);
+-            case 'D':
+-                return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('D').constructor[0].invokeBasic(type, form, (double) x);
++                return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(L_TYPE).constructor[0].invokeBasic(type, form, x);
++            case I_TYPE:
++                return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(I_TYPE).constructor[0].invokeBasic(type, form, ValueConversions.widenSubword(x));
++            case J_TYPE:
++                return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(J_TYPE).constructor[0].invokeBasic(type, form, (long) x);
++            case F_TYPE:
++                return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(F_TYPE).constructor[0].invokeBasic(type, form, (float) x);
++            case D_TYPE:
++                return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(D_TYPE).constructor[0].invokeBasic(type, form, (double) x);
+             default : throw new InternalError("unexpected xtype: " + xtype);
+             }
+         } catch (Throwable t) {
+@@ -103,14 +101,14 @@
+             return new Species_L(type, form, x);
+     }
+ 
+-    MethodHandle cloneExtend(MethodType type, LambdaForm form, char xtype, Object x) {
++    MethodHandle cloneExtend(MethodType type, LambdaForm form, byte xtype, Object x) {
+         try {
+             switch (xtype) {
+-            case 'L': return cloneExtendL(type, form, x);
+-            case 'I': return cloneExtendI(type, form, ValueConversions.widenSubword(x));
+-            case 'J': return cloneExtendJ(type, form, (long) x);
+-            case 'F': return cloneExtendF(type, form, (float) x);
+-            case 'D': return cloneExtendD(type, form, (double) x);
++            case L_TYPE: return copyWithExtendL(type, form, x);
++            case I_TYPE: return copyWithExtendI(type, form, ValueConversions.widenSubword(x));
++            case J_TYPE: return copyWithExtendJ(type, form, (long) x);
++            case F_TYPE: return copyWithExtendF(type, form, (float) x);
++            case D_TYPE: return copyWithExtendD(type, form, (double) x);
+             }
+         } catch (Throwable t) {
+             throw newInternalError(t);
+@@ -119,7 +117,7 @@
+     }
+ 
+     @Override
+-    MethodHandle bindArgument(int pos, char basicType, Object value) {
++    MethodHandle bindArgument(int pos, byte basicType, Object value) {
+         MethodType type = type().dropParameterTypes(pos, pos+1);
+         LambdaForm form = internalForm().bind(1+pos, speciesData());
+         return cloneExtend(type, form, basicType, value);
+@@ -129,7 +127,7 @@
+     MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
+         LambdaForm form = internalForm().addArguments(pos, srcType.parameterList().subList(pos, pos+drops));
+         try {
+-             return clone(srcType, form);
++             return copyWith(srcType, form);
+          } catch (Throwable t) {
+              throw newInternalError(t);
+          }
+@@ -138,7 +136,7 @@
+     @Override
+     MethodHandle permuteArguments(MethodType newType, int[] reorder) {
+         try {
+-             return clone(newType, form.permuteArguments(1, reorder, basicTypes(newType.parameterList())));
++             return copyWith(newType, form.permuteArguments(1, reorder, basicTypes(newType.parameterList())));
+          } catch (Throwable t) {
+              throw newInternalError(t);
+          }
+@@ -156,7 +154,12 @@
+      * Return the {@link SpeciesData} instance representing this BMH species. All subclasses must provide a
+      * static field containing this value, and they must accordingly implement this method.
+      */
+-    protected abstract SpeciesData speciesData();
++    public abstract SpeciesData speciesData();
++
++    /**
++     * Return the number of fields in this BMH.  Equivalent to speciesData().fieldCount().
++     */
++    public abstract int fieldCount();
+ 
+     @Override
+     final Object internalProperties() {
+@@ -175,43 +178,39 @@
+     public final Object arg(int i) {
+         try {
+             switch (speciesData().fieldType(i)) {
+-            case 'L': return argL(i);
+-            case 'I': return argI(i);
+-            case 'F': return argF(i);
+-            case 'D': return argD(i);
+-            case 'J': return argJ(i);
++            case L_TYPE: return          speciesData().getters[i].invokeBasic(this);
++            case I_TYPE: return (int)    speciesData().getters[i].invokeBasic(this);
++            case J_TYPE: return (long)   speciesData().getters[i].invokeBasic(this);
++            case F_TYPE: return (float)  speciesData().getters[i].invokeBasic(this);
++            case D_TYPE: return (double) speciesData().getters[i].invokeBasic(this);
+             }
+         } catch (Throwable ex) {
+             throw newInternalError(ex);
+         }
+-        throw new InternalError("unexpected type: " + speciesData().types+"."+i);
++        throw new InternalError("unexpected type: " + speciesData().typeChars+"."+i);
+     }
+-    public final Object argL(int i) throws Throwable { return          speciesData().getters[i].invokeBasic(this); }
+-    public final int    argI(int i) throws Throwable { return (int)    speciesData().getters[i].invokeBasic(this); }
+-    public final float  argF(int i) throws Throwable { return (float)  speciesData().getters[i].invokeBasic(this); }
+-    public final double argD(int i) throws Throwable { return (double) speciesData().getters[i].invokeBasic(this); }
+-    public final long   argJ(int i) throws Throwable { return (long)   speciesData().getters[i].invokeBasic(this); }
+ 
+     //
+     // cloning API
+     //
+ 
+-    public abstract BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable;
+-    public abstract BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable;
+-    public abstract BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int    narg) throws Throwable;
+-    public abstract BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long   narg) throws Throwable;
+-    public abstract BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float  narg) throws Throwable;
+-    public abstract BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable;
+-
+     // The following is a grossly irregular hack:
+     @Override MethodHandle reinvokerTarget() {
+         try {
+-            return (MethodHandle) argL(0);
++            return (MethodHandle) arg(0);
+         } catch (Throwable ex) {
+             throw newInternalError(ex);
+         }
+     }
+ 
++    @Override
++    public abstract BoundMethodHandle copyWith(MethodType mt, LambdaForm lf);
++    public abstract BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg);
++    public abstract BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int    narg);
++    public abstract BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long   narg);
++    public abstract BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float  narg);
++    public abstract BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg);
++
+     //
+     // concrete BMH classes required to close bootstrap loops
+     //
+@@ -219,150 +218,103 @@
+     private  // make it private to force users to access the enclosing class first
+     static final class Species_L extends BoundMethodHandle {
+         final Object argL0;
+-        public Species_L(MethodType mt, LambdaForm lf, Object argL0) {
++        private Species_L(MethodType mt, LambdaForm lf, Object argL0) {
+             super(mt, lf);
+             this.argL0 = argL0;
+         }
+-        // The following is a grossly irregular hack:
+-        @Override MethodHandle reinvokerTarget() { return (MethodHandle) argL0; }
+-        @Override
+-        public SpeciesData speciesData() {
+-            return SPECIES_DATA;
+-        }
+-        public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("L", Species_L.class);
+-        @Override
+-        public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
+-            return new Species_L(mt, lf, argL0);
+-        }
+-        @Override
+-        public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
+-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, narg);
+-        }
+-        @Override
+-        public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
+-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, narg);
+-        }
+-        @Override
+-        public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
+-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, narg);
+-        }
+-        @Override
+-        public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
+-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, narg);
+-        }
+-        @Override
+-        public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
+-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, narg);
+-        }
+-    }
+-
+-/*
+-    static final class Species_LL extends BoundMethodHandle {
+-        final Object argL0;
+-        final Object argL1;
+-        public Species_LL(MethodType mt, LambdaForm lf, Object argL0, Object argL1) {
+-            super(mt, lf);
+-            this.argL0 = argL0;
+-            this.argL1 = argL1;
+-        }
+         @Override
+         public SpeciesData speciesData() {
+             return SPECIES_DATA;
+         }
+-        public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("LL", Species_LL.class);
+         @Override
+-        public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
+-            return new Species_LL(mt, lf, argL0, argL1);
++        public int fieldCount() {
++            return 1;
++        }
++        public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("L", Species_L.class);
++        public static BoundMethodHandle make(MethodType mt, LambdaForm lf, Object argL0) {
++            return new Species_L(mt, lf, argL0);
+         }
+         @Override
+-        public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
+-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
++        public final BoundMethodHandle copyWith(MethodType mt, LambdaForm lf) {
++            return new Species_L(mt, lf, argL0);
+         }
+         @Override
+-        public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
+-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
++        public final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) {
++            try {
++                return (BoundMethodHandle) SPECIES_DATA.extendWith(L_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
++            } catch (Throwable ex) {
++                throw uncaughtException(ex);
++            }
+         }
+         @Override
+-        public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
+-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
++        public final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) {
++            try {
++                return (BoundMethodHandle) SPECIES_DATA.extendWith(I_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
++            } catch (Throwable ex) {
++                throw uncaughtException(ex);
++            }
+         }
+         @Override
+-        public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
+-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
++        public final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) {
++            try {
++                return (BoundMethodHandle) SPECIES_DATA.extendWith(J_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
++            } catch (Throwable ex) {
++                throw uncaughtException(ex);
++            }
+         }
+         @Override
+-        public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
+-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
++        public final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) {
++            try {
++                return (BoundMethodHandle) SPECIES_DATA.extendWith(F_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
++            } catch (Throwable ex) {
++                throw uncaughtException(ex);
++            }
++        }
++        @Override
++        public final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) {
++            try {
++                return (BoundMethodHandle) SPECIES_DATA.extendWith(D_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
++            } catch (Throwable ex) {
++                throw uncaughtException(ex);
++            }
+         }
+     }
+ 
+-    static final class Species_JL extends BoundMethodHandle {
+-        final long argJ0;
+-        final Object argL1;
+-        public Species_JL(MethodType mt, LambdaForm lf, long argJ0, Object argL1) {
+-            super(mt, lf);
+-            this.argJ0 = argJ0;
+-            this.argL1 = argL1;
+-        }
+-        @Override
+-        public SpeciesData speciesData() {
+-            return SPECIES_DATA;
+-        }
+-        public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("JL", Species_JL.class);
+-        @Override public final long   argJ0() { return argJ0; }
+-        @Override public final Object argL1() { return argL1; }
+-        @Override
+-        public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
+-            return new Species_JL(mt, lf, argJ0, argL1);
+-        }
+-        @Override
+-        public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
+-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
+-        }
+-        @Override
+-        public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
+-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
+-        }
+-        @Override
+-        public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
+-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
+-        }
+-        @Override
+-        public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
+-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
+-        }
+-        @Override
+-        public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
+-            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
+-        }
+-    }
+-*/
+-
+     //
+     // BMH species meta-data
+     //
+ 
+     /**
+-     * Meta-data wrapper for concrete BMH classes.
++     * Meta-data wrapper for concrete BMH types.
++     * Each BMH type corresponds to a given sequence of basic field types (LIJFD).
++     * The fields are immutable; their values are fully specified at object construction.
++     * Each BMH type supplies an array of getter functions which may be used in lambda forms.
++     * A BMH is constructed by cloning a shorter BMH and adding one or more new field values.
++     * As a degenerate and common case, the "shorter BMH" can be missing, and contributes zero prior fields.
+      */
+     static class SpeciesData {
+-        final String                             types;
++        final String                             typeChars;
++        final byte[]                             typeCodes;
+         final Class<? extends BoundMethodHandle> clazz;
+         // Bootstrapping requires circular relations MH -> BMH -> SpeciesData -> MH
+         // Therefore, we need a non-final link in the chain.  Use array elements.
+         final MethodHandle[]                     constructor;
+         final MethodHandle[]                     getters;
++        final NamedFunction[]                    nominalGetters;
+         final SpeciesData[]                      extensions;
+ 
+         public int fieldCount() {
+-            return types.length();
++            return typeCodes.length;
+         }
+-        public char fieldType(int i) {
+-            return types.charAt(i);
++        public byte fieldType(int i) {
++            return typeCodes[i];
++        }
++        public char fieldTypeChar(int i) {
++            return typeChars.charAt(i);
+         }
+ 
+         public String toString() {
+-            return "SpeciesData["+(isPlaceholder() ? "<placeholder>" : clazz.getSimpleName())+":"+types+"]";
++            return "SpeciesData["+(isPlaceholder() ? "<placeholder>" : clazz.getSimpleName())+":"+typeChars+"]";
+         }
+ 
+         /**
+@@ -370,45 +322,46 @@
+          * represents a MH bound to a generic invoker, which in turn forwards to the corresponding
+          * getter.
+          */
+-        Name getterName(Name mhName, int i) {
+-            MethodHandle mh = getters[i];
+-            assert(mh != null) : this+"."+i;
+-            return new Name(mh, mhName);
+-        }
+-
+         NamedFunction getterFunction(int i) {
+-            return new NamedFunction(getters[i]);
++            return nominalGetters[i];
+         }
+ 
+         static final SpeciesData EMPTY = new SpeciesData("", BoundMethodHandle.class);
+ 
+         private SpeciesData(String types, Class<? extends BoundMethodHandle> clazz) {
+-            this.types = types;
++            this.typeChars = types;
++            this.typeCodes = basicTypes(types);
+             this.clazz = clazz;
+             if (!INIT_DONE) {
+-                this.constructor = new MethodHandle[1];
++                this.constructor = new MethodHandle[1];  // only one ctor
+                 this.getters = new MethodHandle[types.length()];
++                this.nominalGetters = new NamedFunction[types.length()];
+             } else {
+                 this.constructor = Factory.makeCtors(clazz, types, null);
+                 this.getters = Factory.makeGetters(clazz, types, null);
++                this.nominalGetters = Factory.makeNominalGetters(clazz, types, null, this.getters);
+             }
+-            this.extensions = new SpeciesData[EXTENSION_TYPES.length()];
++            this.extensions = new SpeciesData[ARG_TYPE_LIMIT];
+         }
+ 
+         private void initForBootstrap() {
+             assert(!INIT_DONE);
+             if (constructor[0] == null) {
++                String types = typeChars;
+                 Factory.makeCtors(clazz, types, this.constructor);
+                 Factory.makeGetters(clazz, types, this.getters);
++                Factory.makeNominalGetters(clazz, types, this.nominalGetters, this.getters);
+             }
+         }
+ 
+-        private SpeciesData(String types) {
++        private SpeciesData(String typeChars) {
+             // Placeholder only.
+-            this.types = types;
++            this.typeChars = typeChars;
++            this.typeCodes = basicTypes(typeChars);
+             this.clazz = null;
+             this.constructor = null;
+             this.getters = null;
++            this.nominalGetters = null;
+             this.extensions = null;
+         }
+         private boolean isPlaceholder() { return clazz == null; }
+@@ -417,19 +370,19 @@
+         static { CACHE.put("", EMPTY); }  // make bootstrap predictable
+         private static final boolean INIT_DONE;  // set after <clinit> finishes...
+ 
+-        SpeciesData extendWithType(char type) {
+-            int i = extensionIndex(type);
+-            SpeciesData d = extensions[i];
++        SpeciesData extendWith(byte type) {
++            SpeciesData d = extensions[type];
+             if (d != null)  return d;
+-            extensions[i] = d = get(types+type);
++            extensions[type] = d = get(typeChars+basicTypeChar(type));
+             return d;
+         }
+ 
+-        SpeciesData extendWithIndex(byte index) {
+-            SpeciesData d = extensions[index];
+-            if (d != null)  return d;
+-            extensions[index] = d = get(types+EXTENSION_TYPES.charAt(index));
+-            return d;
++        SpeciesData extendWith(Class<?> type) {
++            return extendWith(basicType(type));
++        }
++
++        SpeciesData extendWithChar(char type) {
++            return extendWith(basicType(type));
+         }
+ 
+         private static SpeciesData get(String types) {
+@@ -469,11 +422,11 @@
+             return d;
+         }
+ 
++        static void initStatics() {}
++
+         static {
+             // pre-fill the BMH speciesdata cache with BMH's inner classes
+             final Class<BoundMethodHandle> rootCls = BoundMethodHandle.class;
+-            SpeciesData d0 = BoundMethodHandle.SPECIES_DATA;  // trigger class init
+-            assert(d0 == null || d0 == lookupCache("")) : d0;
+             try {
+                 for (Class<?> c : rootCls.getDeclaredClasses()) {
+                     if (rootCls.isAssignableFrom(c)) {
+@@ -481,7 +434,7 @@
+                         SpeciesData d = Factory.speciesDataFromConcreteBMHClass(cbmh);
+                         assert(d != null) : cbmh.getName();
+                         assert(d.clazz == cbmh);
+-                        assert(d == lookupCache(d.types));
++                        assert(d == lookupCache(d.typeChars));
+                     }
+                 }
+             } catch (Throwable e) {
+@@ -532,11 +485,10 @@
+         static final String BMHSPECIES_DATA_GFC_SIG = "(" + JLS_SIG + JLC_SIG + ")" + SPECIES_DATA_SIG;
+         static final String MYSPECIES_DATA_SIG = "()" + SPECIES_DATA_SIG;
+         static final String VOID_SIG   = "()V";
++        static final String INT_SIG    = "()I";
+ 
+         static final String SIG_INCIPIT = "(Ljava/lang/invoke/MethodType;Ljava/lang/invoke/LambdaForm;";
+ 
+-        static final Class<?>[] TYPES = new Class<?>[] { Object.class, int.class, long.class, float.class, double.class };
+-
+         static final String[] E_THROWABLE = new String[] { "java/lang/Throwable" };
+ 
+         /**
+@@ -567,31 +519,35 @@
+          *     final Object argL0;
+          *     final Object argL1;
+          *     final int argI2;
+-         *     public Species_LLI(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
++         *     private Species_LLI(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
+          *         super(mt, lf);
+          *         this.argL0 = argL0;
+          *         this.argL1 = argL1;
+          *         this.argI2 = argI2;
+          *     }
+          *     public final SpeciesData speciesData() { return SPECIES_DATA; }
++         *     public final int fieldCount() { return 3; }
+          *     public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("LLI", Species_LLI.class);
+-         *     public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) {
+-         *         return SPECIES_DATA.constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2);
++         *     public BoundMethodHandle make(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
++         *         return new Species_LLI(mt, lf, argL0, argL1, argI2);
+          *     }
+-         *     public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) {
+-         *         return SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
++         *     public final BoundMethodHandle copyWith(MethodType mt, LambdaForm lf) {
++         *         return new Species_LLI(mt, lf, argL0, argL1, argI2);
+          *     }
+-         *     public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) {
+-         *         return SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
++         *     public final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) {
++         *         return SPECIES_DATA.extendWith(L_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
+          *     }
+-         *     public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) {
+-         *         return SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
++         *     public final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) {
++         *         return SPECIES_DATA.extendWith(I_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
+          *     }
+-         *     public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) {
+-         *         return SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
++         *     public final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) {
++         *         return SPECIES_DATA.extendWith(J_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
+          *     }
+-         *     public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) {
+-         *         return SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
++         *     public final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) {
++         *         return SPECIES_DATA.extendWith(F_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
++         *     }
++         *     public final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) {
++         *         return SPECIES_DATA.extendWith(D_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
+          *     }
+          * }
+          * </pre>
+@@ -622,11 +578,11 @@
+             MethodVisitor mv;
+ 
+             // emit constructor
+-            mv = cw.visitMethod(ACC_PUBLIC, "<init>", makeSignature(types, true), null, null);
++            mv = cw.visitMethod(ACC_PRIVATE, "<init>", makeSignature(types, true), null, null);
+             mv.visitCode();
+-            mv.visitVarInsn(ALOAD, 0);
+-            mv.visitVarInsn(ALOAD, 1);
+-            mv.visitVarInsn(ALOAD, 2);
++            mv.visitVarInsn(ALOAD, 0); // this
++            mv.visitVarInsn(ALOAD, 1); // type
++            mv.visitVarInsn(ALOAD, 2); // form
+ 
+             mv.visitMethodInsn(INVOKESPECIAL, BMH, "<init>", makeSignature("", true));
+ 
+@@ -645,16 +601,6 @@
+             mv.visitMaxs(0, 0);
+             mv.visitEnd();
+ 
+-            // emit implementation of reinvokerTarget()
+-            mv = cw.visitMethod(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(ACC_PUBLIC + ACC_FINAL, "speciesData", MYSPECIES_DATA_SIG, null, null);
+             mv.visitCode();
+@@ -663,39 +609,72 @@
+             mv.visitMaxs(0, 0);
+             mv.visitEnd();
+ 
+-            // emit clone()
+-            mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "clone", makeSignature("", false), null, E_THROWABLE);
++            // emit implementation of fieldCount()
++            mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "fieldCount", INT_SIG, null, null);
+             mv.visitCode();
+-            // return speciesData().constructor[0].invokeBasic(mt, lf, argL0, ...)
+-            // obtain constructor
+-            mv.visitVarInsn(ALOAD, 0);
+-            mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
+-            mv.visitFieldInsn(GETFIELD, SPECIES_DATA, "constructor", "[" + MH_SIG);
+-            mv.visitInsn(ICONST_0);
+-            mv.visitInsn(AALOAD);
++            int fc = types.length();
++            if (fc <= (ICONST_5 - ICONST_0))
++                mv.visitInsn(ICONST_0 + fc);
++            else
++                mv.visitIntInsn(SIPUSH, fc);
++            mv.visitInsn(IRETURN);
++            mv.visitMaxs(0, 0);
++            mv.visitEnd();
++
++            // emit make()  ...factory method wrapping constructor
++            mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "make", makeSignature(types, false), null, null);
++            mv.visitCode();
++            // make instance
++            mv.visitTypeInsn(NEW, className);
++            mv.visitInsn(DUP);
++            // load mt, lf
++            mv.visitVarInsn(ALOAD, 0);  // type
++            mv.visitVarInsn(ALOAD, 1);  // form
++            // load factory method arguments
++            for (int i = 0, j = 0; i < types.length(); ++i, ++j) {
++                // i counts the arguments, j counts corresponding argument slots
++                char t = types.charAt(i);
++                mv.visitVarInsn(typeLoadOp(t), j + 2); // parameters start at 3
++                if (t == 'J' || t == 'D') {
++                    ++j; // adjust argument register access
++                }
++            }
++
++            // finally, invoke the constructor and return
++            mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", makeSignature(types, true));
++            mv.visitInsn(ARETURN);
++            mv.visitMaxs(0, 0);
++            mv.visitEnd();
++
++            // emit copyWith()
++            mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "copyWith", makeSignature("", false), null, null);
++            mv.visitCode();
++            // make instance
++            mv.visitTypeInsn(NEW, className);
++            mv.visitInsn(DUP);
+             // load mt, lf
+             mv.visitVarInsn(ALOAD, 1);
+             mv.visitVarInsn(ALOAD, 2);
+             // put fields on the stack
+             emitPushFields(types, className, mv);
+             // finally, invoke the constructor and return
+-            mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types, false));
++            mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", makeSignature(types, true));
+             mv.visitInsn(ARETURN);
+             mv.visitMaxs(0, 0);
+             mv.visitEnd();
+ 
+-            // for each type, emit cloneExtendT()
+-            for (Class<?> c : TYPES) {
+-                char t = Wrapper.basicTypeChar(c);
+-                mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "cloneExtend" + t, makeSignature(String.valueOf(t), false), null, E_THROWABLE);
++            // for each type, emit copyWithExtendT()
++            for (byte bt = 0; bt < ARG_TYPE_LIMIT; bt++) {
++                char t = basicTypeChar(bt);
++                mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "copyWithExtend" + t, makeSignature(String.valueOf(t), false), null, E_THROWABLE);
+                 mv.visitCode();
+-                // return SPECIES_DATA.extendWithIndex(extensionIndex(t)).constructor[0].invokeBasic(mt, lf, argL0, ..., narg)
++                // return SPECIES_DATA.extendWith(t).constructor[0].invokeBasic(mt, lf, argL0, ..., narg)
+                 // obtain constructor
+                 mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
+-                int iconstInsn = ICONST_0 + extensionIndex(t);
++                int iconstInsn = ICONST_0 + bt;
+                 assert(iconstInsn <= ICONST_5);
+                 mv.visitInsn(iconstInsn);
+-                mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "extendWithIndex", BMHSPECIES_DATA_EWI_SIG);
++                mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "extendWith", BMHSPECIES_DATA_EWI_SIG);
+                 mv.visitFieldInsn(GETFIELD, SPECIES_DATA, "constructor", "[" + MH_SIG);
+                 mv.visitInsn(ICONST_0);
+                 mv.visitInsn(AALOAD);
+@@ -787,10 +766,19 @@
+ 
+         static MethodHandle[] makeCtors(Class<? extends BoundMethodHandle> cbmh, String types, MethodHandle mhs[]) {
+             if (mhs == null)  mhs = new MethodHandle[1];
++            if (types.equals(""))  return mhs;  // hack for empty BMH species
+             mhs[0] = makeCbmhCtor(cbmh, types);
+             return mhs;
+         }
+ 
++        static NamedFunction[] makeNominalGetters(Class<?> cbmhClass, String types, NamedFunction[] nfs, MethodHandle[] getters) {
++            if (nfs == null)  nfs = new NamedFunction[types.length()];
++            for (int i = 0; i < nfs.length; ++i) {
++                nfs[i] = new NamedFunction(getters[i]);
++            }
++            return nfs;
++        }
++
+         //
+         // Auxiliary methods.
+         //
+@@ -824,60 +812,28 @@
+ 
+         static MethodHandle makeCbmhCtor(Class<? extends BoundMethodHandle> cbmh, String types) {
+             try {
+-                return linkConstructor(LOOKUP.findConstructor(cbmh, MethodType.fromMethodDescriptorString(makeSignature(types, true), null)));
++                return LOOKUP.findStatic(cbmh, "make", MethodType.fromMethodDescriptorString(makeSignature(types, false), null));
+             } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | TypeNotPresentException e) {
+                 throw newInternalError(e);
+             }
+         }
+-
+-        /**
+-         * Wrap a constructor call in a {@link LambdaForm}.
+-         *
+-         * If constructors ({@code <init>} methods) are called in LFs, problems might arise if the LFs
+-         * are turned into bytecode, because the call to the allocator is routed through an MH, and the
+-         * verifier cannot find a {@code NEW} instruction preceding the {@code INVOKESPECIAL} to
+-         * {@code <init>}. To avoid this, we add an indirection by invoking {@code <init>} through
+-         * {@link MethodHandle#linkToSpecial}.
+-         *
+-         * The last {@link LambdaForm.Name Name} in the argument's form is expected to be the {@code void}
+-         * result of the {@code <init>} invocation. This entry is replaced.
+-         */
+-        private static MethodHandle linkConstructor(MethodHandle cmh) {
+-            final LambdaForm lf = cmh.form;
+-            final int initNameIndex = lf.names.length - 1;
+-            final Name initName = lf.names[initNameIndex];
+-            final MemberName ctorMN = initName.function.member;
+-            final MethodType ctorMT = ctorMN.getInvocationType();
+-
+-            // obtain function member (call target)
+-            // linker method type replaces initial parameter (BMH species) with BMH to avoid naming a species (anonymous class!)
+-            final MethodType linkerMT = ctorMT.changeParameterType(0, BoundMethodHandle.class).appendParameterTypes(MemberName.class);
+-            MemberName linkerMN = new MemberName(MethodHandle.class, "linkToSpecial", linkerMT, REF_invokeStatic);
+-            try {
+-                linkerMN = MemberName.getFactory().resolveOrFail(REF_invokeStatic, linkerMN, null, NoSuchMethodException.class);
+-                assert(linkerMN.isStatic());
+-            } catch (ReflectiveOperationException ex) {
+-                throw newInternalError(ex);
+-            }
+-            // extend arguments array
+-            Object[] newArgs = Arrays.copyOf(initName.arguments, initName.arguments.length + 1);
+-            newArgs[newArgs.length - 1] = ctorMN;
+-            // replace function
+-            final NamedFunction nf = new NamedFunction(linkerMN);
+-            final Name linkedCtor = new Name(nf, newArgs);
+-            linkedCtor.initIndex(initNameIndex);
+-            lf.names[initNameIndex] = linkedCtor;
+-            return cmh;
+-        }
+-
+     }
+ 
+     private static final Lookup LOOKUP = Lookup.IMPL_LOOKUP;
++ 
++   static void initStatics() {}
++    static { SpeciesData.initStatics(); }
+ 
+-    /**
+-     * All subclasses must provide such a value describing their type signature.
+-     */
+-    static final SpeciesData SPECIES_DATA = SpeciesData.EMPTY;
++    private static final SpeciesData[] SPECIES_DATA_CACHE = new SpeciesData[4];
++    private static SpeciesData checkCache(int index, String types) {
++        SpeciesData data = SPECIES_DATA_CACHE[index];
++        if (data != null)  return data;
++        SPECIES_DATA_CACHE[index] = data = getSpeciesData(types);
++        return data;
++    }
++    static SpeciesData speciesData_L()     { return checkCache(1, "L"); }
++    static SpeciesData speciesData_LL()    { return checkCache(2, "LL"); }
++    static SpeciesData speciesData_LLL()   { return checkCache(3, "LLL"); }
+ 
+     // Event counters
+     private static final EventCounter EC_methodHandle_bound = eventCounter(EC_methodHandle, "bound", true);  // autoSum=true
+diff --git a/src/share/classes/java/lang/invoke/DirectMethodHandle.java b/src/share/classes/java/lang/invoke/DirectMethodHandle.java
+--- a/src/share/classes/java/lang/invoke/DirectMethodHandle.java
++++ b/src/share/classes/java/lang/invoke/DirectMethodHandle.java
+@@ -147,7 +147,7 @@
+     }
+ 
+     @Override
+-    MethodHandle bindArgument(int pos, char basicType, Object value) {
++    MethodHandle bindArgument(int pos, byte basicType, Object value) {
+         // If the member needs dispatching, do so.
+         if (pos == 0 && basicType == 'L') {
+             DirectMethodHandle concrete = maybeRebind(value);
+diff --git a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
+--- a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
++++ b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
+@@ -117,7 +117,7 @@
+         Name[] names = form.names;
+         for (int i = 0, index = 0; i < localsMap.length; i++) {
+             localsMap[i] = index;
+-            index += Wrapper.forBasicType(names[i].type).stackSlots();
++            index += basicTypeWrapper(names[i].type).stackSlots();
+         }
+     }
+ 
+@@ -359,38 +359,48 @@
+     /*
+      * NOTE: These load/store methods use the localsMap to find the correct index!
+      */
+-    private void emitLoadInsn(char type, int index) {
++    private void emitLoadInsn(byte type, int index) {
++        int opcode = loadInsnOpcode(type);
++        mv.visitVarInsn(opcode, localsMap[index]);
++    }
++
++    private int loadInsnOpcode(byte type) throws InternalError {
+         int opcode;
+         switch (type) {
+-        case 'I':  opcode = Opcodes.ILOAD;  break;
+-        case 'J':  opcode = Opcodes.LLOAD;  break;
+-        case 'F':  opcode = Opcodes.FLOAD;  break;
+-        case 'D':  opcode = Opcodes.DLOAD;  break;
+-        case 'L':  opcode = Opcodes.ALOAD;  break;
++        case I_TYPE:  opcode = Opcodes.ILOAD;  break;
++        case J_TYPE:  opcode = Opcodes.LLOAD;  break;
++        case F_TYPE:  opcode = Opcodes.FLOAD;  break;
++        case D_TYPE:  opcode = Opcodes.DLOAD;  break;
++        case L_TYPE:  opcode = Opcodes.ALOAD;  break;
+         default:
+             throw new InternalError("unknown type: " + type);
+         }
++        return opcode;
++    }
++    private void emitAloadInsn(int index) {
++        emitLoadInsn(L_TYPE, index);
++    }
++
++    private void emitStoreInsn(byte type, int index) {
++        int opcode = storeInsnOpcode(type);
+         mv.visitVarInsn(opcode, localsMap[index]);
+     }
+-    private void emitAloadInsn(int index) {
+-        emitLoadInsn('L', index);
+-    }
+ 
+-    private void emitStoreInsn(char type, int index) {
++    private int storeInsnOpcode(byte type) throws InternalError {
+         int opcode;
+         switch (type) {
+-        case 'I':  opcode = Opcodes.ISTORE;  break;
+-        case 'J':  opcode = Opcodes.LSTORE;  break;
+-        case 'F':  opcode = Opcodes.FSTORE;  break;
+-        case 'D':  opcode = Opcodes.DSTORE;  break;
+-        case 'L':  opcode = Opcodes.ASTORE;  break;
++        case I_TYPE:  opcode = Opcodes.ISTORE;  break;
++        case J_TYPE:  opcode = Opcodes.LSTORE;  break;
++        case F_TYPE:  opcode = Opcodes.FSTORE;  break;
++        case D_TYPE:  opcode = Opcodes.DSTORE;  break;
++        case L_TYPE:  opcode = Opcodes.ASTORE;  break;
+         default:
+             throw new InternalError("unknown type: " + type);
+         }
+-        mv.visitVarInsn(opcode, localsMap[index]);
++        return opcode;
+     }
+     private void emitAstoreInsn(int index) {
+-        emitStoreInsn('L', index);
++        emitStoreInsn(L_TYPE, index);
+     }
+ 
+     /**
+@@ -398,8 +408,7 @@
+      *
+      * @param type primitive type class to box.
+      */
+-    private void emitBoxing(Class<?> type) {
+-        Wrapper wrapper = Wrapper.forPrimitiveType(type);
++    private void emitBoxing(Wrapper wrapper) {
+         String owner = "java/lang/" + wrapper.wrapperType().getSimpleName();
+         String name  = "valueOf";
+         String desc  = "(" + wrapper.basicTypeChar() + ")L" + owner + ";";
+@@ -411,8 +420,7 @@
+      *
+      * @param type wrapper type class to unbox.
+      */
+-    private void emitUnboxing(Class<?> type) {
+-        Wrapper wrapper = Wrapper.forWrapperType(type);
++    private void emitUnboxing(Wrapper wrapper) {
+         String owner = "java/lang/" + wrapper.wrapperType().getSimpleName();
+         String name  = wrapper.primitiveSimpleName() + "Value";
+         String desc  = "()" + wrapper.basicTypeChar();
+@@ -426,9 +434,12 @@
+      * @param ptype type of value present on stack
+      * @param pclass type of value required on stack
+      */
+-    private void emitImplicitConversion(char ptype, Class<?> pclass) {
++    private void emitImplicitConversion(byte ptype, Class<?> pclass) {
++        assert(basicType(pclass) == ptype);  // boxing/unboxing handled by caller
++        if (pclass == basicTypeClass(ptype) && ptype != L_TYPE)
++            return;   // nothing to do
+         switch (ptype) {
+-        case 'L':
++        case L_TYPE:
+             if (VerifyType.isNullConversion(Object.class, pclass))
+                 return;
+             if (isStaticallyNameable(pclass)) {
+@@ -442,18 +453,9 @@
+                     mv.visitTypeInsn(Opcodes.CHECKCAST, OBJARY);
+             }
+             return;
+-        case 'I':
++        case I_TYPE:
+             if (!VerifyType.isNullConversion(int.class, pclass))
+-                emitPrimCast(ptype, Wrapper.basicTypeChar(pclass));
+-            return;
+-        case 'J':
+-            assert(pclass == long.class);
+-            return;
+-        case 'F':
+-            assert(pclass == float.class);
+-            return;
+-        case 'D':
+-            assert(pclass == double.class);
++                emitPrimCast(basicTypeWrapper(ptype), Wrapper.forPrimitiveType(pclass));
+             return;
+         }
+         throw new InternalError("bad implicit conversion: tc="+ptype+": "+pclass);
+@@ -462,15 +464,15 @@
+     /**
+      * Emits an actual return instruction conforming to the given return type.
+      */
+-    private void emitReturnInsn(Class<?> type) {
++    private void emitReturnInsn(byte type) {
+         int opcode;
+-        switch (Wrapper.basicTypeChar(type)) {
+-        case 'I':  opcode = Opcodes.IRETURN;  break;
+-        case 'J':  opcode = Opcodes.LRETURN;  break;
+-        case 'F':  opcode = Opcodes.FRETURN;  break;
+-        case 'D':  opcode = Opcodes.DRETURN;  break;
+-        case 'L':  opcode = Opcodes.ARETURN;  break;
+-        case 'V':  opcode = Opcodes.RETURN;   break;
++        switch (type) {
++        case I_TYPE:  opcode = Opcodes.IRETURN;  break;
++        case J_TYPE:  opcode = Opcodes.LRETURN;  break;
++        case F_TYPE:  opcode = Opcodes.FRETURN;  break;
++        case D_TYPE:  opcode = Opcodes.DRETURN;  break;
++        case L_TYPE:  opcode = Opcodes.ARETURN;  break;
++        case V_TYPE:  opcode = Opcodes.RETURN;   break;
+         default:
+             throw new InternalError("unknown return type: " + type);
+         }
+@@ -516,6 +518,7 @@
+                 // FIXME: make sure this idiom is really present!
+                 emitSelectAlternative(name, lambdaForm.names[i + 1]);
+                 i++;  // skip MH.invokeBasic of the selectAlternative result
++                name = lambdaForm.names[i];
+             } else if (isStaticallyInvocable(member)) {
+                 emitStaticInvoke(member, name);
+             } else {
+@@ -527,7 +530,7 @@
+             // avoid store/load/return and just return)
+             if (i == lambdaForm.names.length - 1 && i == lambdaForm.result) {
+                 // return value - do nothing
+-            } else if (name.type != 'V') {
++            } else if (name.type != V_TYPE) {
+                 // non-void: actually assign
+                 emitStoreInsn(name.type, name.index());
+             }
+@@ -724,20 +727,24 @@
+ 
+     private void emitPushArgument(Name name, int paramIndex) {
+         Object arg = name.arguments[paramIndex];
+-        char ptype = name.function.parameterType(paramIndex);
+-        MethodType mtype = name.function.methodType();
++        Class<?> ptype = name.function.methodType().parameterType(paramIndex);
++        emitPushArgument(ptype, arg);
++    }
++
++    private void emitPushArgument(Class<?> ptype, Object arg) {
++        byte bptype = basicType(ptype);
+         if (arg instanceof Name) {
+             Name n = (Name) arg;
+             emitLoadInsn(n.type, n.index());
+-            emitImplicitConversion(n.type, mtype.parameterType(paramIndex));
+-        } else if ((arg == null || arg instanceof String) && ptype == 'L') {
++            emitImplicitConversion(n.type, ptype);
++        } else if ((arg == null || arg instanceof String) && bptype == L_TYPE) {
+             emitConst(arg);
+         } else {
+-            if (Wrapper.isWrapperType(arg.getClass()) && ptype != 'L') {
++            if (Wrapper.isWrapperType(arg.getClass()) && bptype != L_TYPE) {
+                 emitConst(arg);
+             } else {
+                 mv.visitLdcInsn(constantPlaceholder(arg));
+-                emitImplicitConversion('L', mtype.parameterType(paramIndex));
++                emitImplicitConversion(L_TYPE, ptype);
+             }
+         }
+     }
+@@ -747,52 +754,32 @@
+      */
+     private void emitReturn() {
+         // return statement
+-        if (lambdaForm.result == -1) {
++        Class<?> rclass = invokerType.returnType();
++        byte rtype = lambdaForm.returnType();
++        assert(rtype == basicType(rclass));  // must agree
++        if (rtype == V_TYPE) {
+             // void
+             mv.visitInsn(Opcodes.RETURN);
++            // it doesn't matter what rclass is; the JVM will discard any value
+         } else {
+             LambdaForm.Name rn = lambdaForm.names[lambdaForm.result];
+-            char rtype = Wrapper.basicTypeChar(invokerType.returnType());
+ 
+             // put return value on the stack if it is not already there
+             if (lambdaForm.result != lambdaForm.names.length - 1) {
+                 emitLoadInsn(rn.type, lambdaForm.result);
+             }
+ 
+-            // potentially generate cast
+-            // rtype is the return type of the invoker - generated code must conform to this
+-            // rn.type is the type of the result Name in the LF
+-            if (rtype != rn.type) {
+-                // need cast
+-                if (rtype == 'L') {
+-                    // possibly cast the primitive to the correct type for boxing
+-                    char boxedType = Wrapper.forWrapperType(invokerType.returnType()).basicTypeChar();
+-                    if (boxedType != rn.type) {
+-                        emitPrimCast(rn.type, boxedType);
+-                    }
+-                    // cast primitive to reference ("boxing")
+-                    emitBoxing(invokerType.returnType());
+-                } else {
+-                    // to-primitive cast
+-                    if (rn.type != 'L') {
+-                        // prim-to-prim cast
+-                        emitPrimCast(rn.type, rtype);
+-                    } else {
+-                        // ref-to-prim cast ("unboxing")
+-                        throw new InternalError("no ref-to-prim (unboxing) casts supported right now");
+-                    }
+-                }
+-            }
++            emitImplicitConversion(rtype, rclass);
+ 
+             // generate actual return statement
+-            emitReturnInsn(invokerType.returnType());
++            emitReturnInsn(rtype);
+         }
+     }
+ 
+     /**
+      * Emit a type conversion bytecode casting from "from" to "to".
+      */
+-    private void emitPrimCast(char from, char to) {
++    private void emitPrimCast(Wrapper from, Wrapper to) {
+         // Here's how.
+         // -   indicates forbidden
+         // <-> indicates implicit
+@@ -809,17 +796,15 @@
+             // no cast required, should be dead code anyway
+             return;
+         }
+-        Wrapper wfrom = Wrapper.forBasicType(from);
+-        Wrapper wto   = Wrapper.forBasicType(to);
+-        if (wfrom.isSubwordOrInt()) {
++        if (from.isSubwordOrInt()) {
+             // cast from {byte,short,char,int} to anything
+             emitI2X(to);
+         } else {
+             // cast from {long,float,double} to anything
+-            if (wto.isSubwordOrInt()) {
++            if (to.isSubwordOrInt()) {
+                 // cast to {byte,short,char,int}
+                 emitX2I(from);
+-                if (wto.bitWidth() < 32) {
++                if (to.bitWidth() < 32) {
+                     // targets other than int require another conversion
+                     emitI2X(to);
+                 }
+@@ -827,20 +812,26 @@
+                 // cast to {long,float,double} - this is verbose
+                 boolean error = false;
+                 switch (from) {
+-                case 'J':
+-                         if (to == 'F') { mv.visitInsn(Opcodes.L2F); }
+-                    else if (to == 'D') { mv.visitInsn(Opcodes.L2D); }
+-                    else error = true;
++                case LONG:
++                    switch (to) {
++                    case FLOAT:   mv.visitInsn(Opcodes.L2F);  break;
++                    case DOUBLE:  mv.visitInsn(Opcodes.L2D);  break;
++                    default:      error = true;               break;
++                    }
+                     break;
+-                case 'F':
+-                         if (to == 'J') { mv.visitInsn(Opcodes.F2L); }
+-                    else if (to == 'D') { mv.visitInsn(Opcodes.F2D); }
+-                    else error = true;
++                case FLOAT:
++                    switch (to) {
++                    case LONG :   mv.visitInsn(Opcodes.F2L);  break;
++                    case DOUBLE:  mv.visitInsn(Opcodes.F2D);  break;
++                    default:      error = true;               break;
++                    }
+                     break;
+-                case 'D':
+-                         if (to == 'J') { mv.visitInsn(Opcodes.D2L); }
+-                    else if (to == 'F') { mv.visitInsn(Opcodes.D2F); }
+-                    else error = true;
++                case DOUBLE:
++                    switch (to) {
++                    case LONG :   mv.visitInsn(Opcodes.D2L);  break;
++                    case FLOAT:   mv.visitInsn(Opcodes.D2F);  break;
++                    default:      error = true;               break;
++                    }
+                     break;
+                 default:
+                     error = true;
+@@ -853,16 +844,16 @@
+         }
+     }
+ 
+-    private void emitI2X(char type) {
++    private void emitI2X(Wrapper type) {
+         switch (type) {
+-        case 'B':  mv.visitInsn(Opcodes.I2B);  break;
+-        case 'S':  mv.visitInsn(Opcodes.I2S);  break;
+-        case 'C':  mv.visitInsn(Opcodes.I2C);  break;
+-        case 'I':  /* naught */                break;
+-        case 'J':  mv.visitInsn(Opcodes.I2L);  break;
+-        case 'F':  mv.visitInsn(Opcodes.I2F);  break;
+-        case 'D':  mv.visitInsn(Opcodes.I2D);  break;
+-        case 'Z':
++        case BYTE:    mv.visitInsn(Opcodes.I2B);  break;
++        case SHORT:   mv.visitInsn(Opcodes.I2S);  break;
++        case CHAR:    mv.visitInsn(Opcodes.I2C);  break;
++        case INT:     /* naught */                break;
++        case LONG:    mv.visitInsn(Opcodes.I2L);  break;
++        case FLOAT:   mv.visitInsn(Opcodes.I2F);  break;
++        case DOUBLE:  mv.visitInsn(Opcodes.I2D);  break;
++        case BOOLEAN:
+             // For compatibility with ValueConversions and explicitCastArguments:
+             mv.visitInsn(Opcodes.ICONST_1);
+             mv.visitInsn(Opcodes.IAND);
+@@ -871,39 +862,24 @@
+         }
+     }
+ 
+-    private void emitX2I(char type) {
++    private void emitX2I(Wrapper type) {
+         switch (type) {
+-        case 'J':  mv.visitInsn(Opcodes.L2I);  break;
+-        case 'F':  mv.visitInsn(Opcodes.F2I);  break;
+-        case 'D':  mv.visitInsn(Opcodes.D2I);  break;
+-        default:   throw new InternalError("unknown type: " + type);
++        case LONG:    mv.visitInsn(Opcodes.L2I);  break;
++        case FLOAT:   mv.visitInsn(Opcodes.F2I);  break;
++        case DOUBLE:  mv.visitInsn(Opcodes.D2I);  break;
++        default:      throw new InternalError("unknown type: " + type);
+         }
+     }
+ 
+-    private static String basicTypeCharSignature(String prefix, MethodType type) {
+-        StringBuilder buf = new StringBuilder(prefix);
+-        for (Class<?> ptype : type.parameterList())
+-            buf.append(Wrapper.forBasicType(ptype).basicTypeChar());
+-        buf.append('_').append(Wrapper.forBasicType(type.returnType()).basicTypeChar());
+-        return buf.toString();
+-    }
+-
+     /**
+      * Generate bytecode for a LambdaForm.vmentry which calls interpretWithArguments.
+      */
+     static MemberName generateLambdaFormInterpreterEntryPoint(String sig) {
+-        assert(LambdaForm.isValidSignature(sig));
+-        //System.out.println("generateExactInvoker "+sig);
+-        // compute method type
+-        // first parameter and return type
+-        char tret = LambdaForm.signatureReturn(sig);
+-        MethodType type = MethodType.methodType(LambdaForm.typeClass(tret), MethodHandle.class);
+-        // other parameter types
+-        int arity = LambdaForm.signatureArity(sig);
+-        for (int i = 1; i < arity; i++) {
+-            type = type.appendParameterTypes(LambdaForm.typeClass(sig.charAt(i)));
+-        }
+-        InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("LFI", "interpret_"+tret, type);
++        assert(isValidSignature(sig));
++        String name = "interpret_"+basicTypeChar(signatureReturn(sig));
++        MethodType type = signatureType(sig);  // sig includes leading argument
++        type = type.changeParameterType(0, MethodHandle.class);
++        InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("LFI", name, type);
+         return g.loadMethod(g.generateLambdaFormInterpreterEntryPointBytes());
+     }
+ 
+@@ -925,10 +901,10 @@
+             Class<?> ptype = invokerType.parameterType(i);
+             mv.visitInsn(Opcodes.DUP);
+             emitIconstInsn(i);
+-            emitLoadInsn(Wrapper.basicTypeChar(ptype), i);
++            emitLoadInsn(basicType(ptype), i);
+             // box if primitive type
+             if (ptype.isPrimitive()) {
+-                emitBoxing(ptype);
++                emitBoxing(Wrapper.forPrimitiveType(ptype));
+             }
+             mv.visitInsn(Opcodes.AASTORE);
+         }
+@@ -941,11 +917,11 @@
+         // maybe unbox
+         Class<?> rtype = invokerType.returnType();
+         if (rtype.isPrimitive() && rtype != void.class) {
+-            emitUnboxing(Wrapper.asWrapperType(rtype));
++            emitUnboxing(Wrapper.forPrimitiveType(rtype));
+         }
+ 
+         // return statement
+-        emitReturnInsn(rtype);
++        emitReturnInsn(basicType(rtype));
+ 
+         classFileEpilogue();
+         bogusMethod(invokerType);
+@@ -992,8 +968,8 @@
+                 Class<?> sptype = dstType.basicType().wrap().parameterType(i);
+                 Wrapper dstWrapper = Wrapper.forBasicType(dptype);
+                 Wrapper srcWrapper = dstWrapper.isSubwordOrInt() ? Wrapper.INT : dstWrapper;  // narrow subword from int
+-                emitUnboxing(srcWrapper.wrapperType());
+-                emitPrimCast(srcWrapper.basicTypeChar(), dstWrapper.basicTypeChar());
++                emitUnboxing(srcWrapper);
++                emitPrimCast(srcWrapper, dstWrapper);
+             }
+         }
+ 
+@@ -1007,15 +983,15 @@
+             Wrapper srcWrapper = Wrapper.forBasicType(rtype);
+             Wrapper dstWrapper = srcWrapper.isSubwordOrInt() ? Wrapper.INT : srcWrapper;  // widen subword to int
+             // boolean casts not allowed
+-            emitPrimCast(srcWrapper.basicTypeChar(), dstWrapper.basicTypeChar());
+-            emitBoxing(dstWrapper.primitiveType());
++            emitPrimCast(srcWrapper, dstWrapper);
++            emitBoxing(dstWrapper);
+         }
+ 
+         // If the return type is void we return a null reference.
+         if (rtype == void.class) {
+             mv.visitInsn(Opcodes.ACONST_NULL);
+         }
+-        emitReturnInsn(Object.class);  // NOTE: NamedFunction invokers always return a reference value.
++        emitReturnInsn(L_TYPE);  // NOTE: NamedFunction invokers always return a reference value.
+ 
+         classFileEpilogue();
+         bogusMethod(dstType);
+diff --git a/src/share/classes/java/lang/invoke/LambdaForm.java b/src/share/classes/java/lang/invoke/LambdaForm.java
+--- a/src/share/classes/java/lang/invoke/LambdaForm.java
++++ b/src/share/classes/java/lang/invoke/LambdaForm.java
+@@ -130,6 +130,47 @@
+ 
+     public static final int VOID_RESULT = -1, LAST_RESULT = -2;
+ 
++    // Numeric indexes for basic type characters.
++    public static final byte
++            L_TYPE = 0,  // all reference types
++            I_TYPE = 1, J_TYPE = 2, F_TYPE = 3, D_TYPE = 4,  // all primitive types
++            V_TYPE = 5,  // not valid in all contexts
++            ARG_TYPE_LIMIT = V_TYPE, TYPE_LIMIT = V_TYPE+1;
++    public static final String BASIC_TYPE_CHARS = "LIJFDV";
++    private static final Class<?>[] BASIC_TYPE_CLASSES = {
++        Object.class,
++        int.class, long.class, float.class, double.class,
++        void.class
++    };
++    private static final Wrapper[] BASIC_TYPE_WRAPPERS = {
++        Wrapper.OBJECT,
++        Wrapper.INT, Wrapper.LONG, Wrapper.FLOAT, Wrapper.DOUBLE,
++        Wrapper.VOID
++    };
++    static { assert(verifyBasicTypeChars()); }
++    private static boolean verifyBasicTypeChars() {
++        Object[] data = {
++            'L', L_TYPE, 'I', I_TYPE, 'J', J_TYPE, 'F', F_TYPE, 'D', D_TYPE, 'V', V_TYPE
++        };
++        assert(data.length == TYPE_LIMIT*2);  // all cases covered
++        for (int i = 0; i < TYPE_LIMIT; i++) {
++            char btc = (char) data[2*i+0];
++            byte bti = (byte) data[2*i+1];
++            assert(BASIC_TYPE_CHARS.charAt(bti) == btc);
++            Class<?> c = BASIC_TYPE_CLASSES[bti];
++            assert(Wrapper.basicTypeChar(c) == btc);
++            if (btc != 'V')
++                assert(bti < ARG_TYPE_LIMIT);  // all arg types must come before void
++            else
++                assert(bti == ARG_TYPE_LIMIT);  // void type must be beyond arg type sequence
++        }
++        assert(ARG_TYPE_LIMIT == V_TYPE);  // V must be after all arg types
++        assert(BASIC_TYPE_CHARS.length() == TYPE_LIMIT);
++        assert(BASIC_TYPE_CLASSES.length == TYPE_LIMIT);
++        assert(BASIC_TYPE_WRAPPERS.length == TYPE_LIMIT);
++        return true;
++    }
++
+     LambdaForm(String debugName,
+                int arity, Name[] names, int result) {
+         assert(namesOK(arity, names));
+@@ -169,12 +210,12 @@
+         // Called only from getPreparedForm.
+         assert(isValidSignature(sig));
+         this.arity = signatureArity(sig);
+-        this.result = (signatureReturn(sig) == 'V' ? -1 : arity);
++        this.result = (signatureReturn(sig) == V_TYPE ? -1 : arity);
+         this.names = buildEmptyNames(arity, sig);
+         this.debugName = "LF.zero";
+         assert(nameRefsAreLegal());
+         assert(isEmpty());
+-        assert(sig.equals(basicTypeSignature()));
++        assert(sig.equals(basicTypeSignature())) : sig + " != " + basicTypeSignature();
+         bump(EC_lambdaForm);
+         bump(EC_lambdaForm_blank);
+     }
+@@ -184,21 +225,20 @@
+         int resultPos = arity + 1;  // skip '_'
+         if (arity < 0 || basicTypeSignature.length() != resultPos+1)
+             throw new IllegalArgumentException("bad arity for "+basicTypeSignature);
+-        int numRes = (basicTypeSignature.charAt(resultPos) == 'V' ? 0 : 1);
++        int numRes = (basicType(basicTypeSignature.charAt(resultPos)) == V_TYPE ? 0 : 1);
+         Name[] names = arguments(numRes, basicTypeSignature.substring(0, arity));
+         for (int i = 0; i < numRes; i++) {
+-            names[arity + i] = constantZero(arity + i, basicTypeSignature.charAt(resultPos + i));
++            Name zero = new Name(constantZero(basicType(basicTypeSignature.charAt(resultPos + i))));
++            names[arity + i] = zero.newIndex(arity + i);
+         }
+         return names;
+     }
+ 
+     private static int fixResult(int result, Name[] names) {
+-        if (result >= 0) {
+-            if (names[result].type == 'V')
+-                return -1;
+-        } else if (result == LAST_RESULT) {
+-            return names.length - 1;
+-        }
++        if (result == LAST_RESULT)
++            result = names.length - 1;  // might still be void
++        if (result >= 0 && names[result].type == V_TYPE)
++            result = -1;
+         return result;
+     }
+ 
+@@ -329,14 +369,14 @@
+     // }
+ 
+     /** Report the return type. */
+-    char returnType() {
+-        if (result < 0)  return 'V';
++    byte returnType() {
++        if (result < 0)  return V_TYPE;
+         Name n = names[result];
+         return n.type;
+     }
+ 
+     /** Report the N-th argument type. */
+-    char parameterType(int n) {
++    byte parameterType(int n) {
+         assert(n < arity);
+         return names[n].type;
+     }
+@@ -354,15 +394,15 @@
+     final String basicTypeSignature() {
+         StringBuilder buf = new StringBuilder(arity() + 3);
+         for (int i = 0, a = arity(); i < a; i++)
+-            buf.append(parameterType(i));
+-        return buf.append('_').append(returnType()).toString();
++            buf.append(basicTypeChar(parameterType(i)));
++        return buf.append('_').append(basicTypeChar(returnType())).toString();
+     }
+     static int signatureArity(String sig) {
+         assert(isValidSignature(sig));
+         return sig.indexOf('_');
+     }
+-    static char signatureReturn(String sig) {
+-        return sig.charAt(signatureArity(sig)+1);
++    static byte signatureReturn(String sig) {
++        return basicType(sig.charAt(signatureArity(sig)+1));
+     }
+     static boolean isValidSignature(String sig) {
+         int arity = sig.indexOf('_');
+@@ -374,27 +414,15 @@
+             char c = sig.charAt(i);
+             if (c == 'V')
+                 return (i == siglen - 1 && arity == siglen - 2);
+-            if (ALL_TYPES.indexOf(c) < 0)  return false; // must be [LIJFD]
++            if (BASIC_TYPE_CHARS.indexOf(c) < 0)  return false; // must be [LIJFD]
+         }
+         return true;  // [LIJFD]*_[LIJFDV]
+     }
+-    static Class<?> typeClass(char t) {
+-        switch (t) {
+-        case 'I': return int.class;
+-        case 'J': return long.class;
+-        case 'F': return float.class;
+-        case 'D': return double.class;
+-        case 'L': return Object.class;
+-        case 'V': return void.class;
+-        default: assert false;
+-        }
+-        return null;
+-    }
+     static MethodType signatureType(String sig) {
+         Class<?>[] ptypes = new Class<?>[signatureArity(sig)];
+         for (int i = 0; i < ptypes.length; i++)
+-            ptypes[i] = typeClass(sig.charAt(i));
+-        Class<?> rtype = typeClass(signatureReturn(sig));
++            ptypes[i] = basicTypeClass(basicType(sig.charAt(i)));
++        Class<?> rtype = basicTypeClass(signatureReturn(sig));
+         return MethodType.methodType(rtype, ptypes);
+     }
+ 
+@@ -583,21 +611,21 @@
+         assert(mt.parameterCount() == arity-1);
+         for (int i = 0; i < av.length; i++) {
+             Class<?> pt = (i == 0 ? MethodHandle.class : mt.parameterType(i-1));
+-            assert(valueMatches(sig.charAt(i), pt, av[i]));
++            assert(valueMatches(basicType(sig.charAt(i)), pt, av[i]));
+         }
+         return true;
+     }
+-    private static boolean valueMatches(char tc, Class<?> type, Object x) {
++    private static boolean valueMatches(byte tc, Class<?> type, Object x) {
+         // The following line is needed because (...)void method handles can use non-void invokers
+-        if (type == void.class)  tc = 'V';   // can drop any kind of value
++        if (type == void.class)  tc = V_TYPE;   // can drop any kind of value
+         assert tc == basicType(type) : tc + " == basicType(" + type + ")=" + basicType(type);
+         switch (tc) {
+-        case 'I': assert checkInt(type, x)   : "checkInt(" + type + "," + x +")";   break;
+-        case 'J': assert x instanceof Long   : "instanceof Long: " + x;             break;
+-        case 'F': assert x instanceof Float  : "instanceof Float: " + x;            break;
+-        case 'D': assert x instanceof Double : "instanceof Double: " + x;           break;
+-        case 'L': assert checkRef(type, x)   : "checkRef(" + type + "," + x + ")";  break;
+-        case 'V': break;  // allow anything here; will be dropped
++        case I_TYPE: assert checkInt(type, x)   : "checkInt(" + type + "," + x +")";   break;
++        case J_TYPE: assert x instanceof Long   : "instanceof Long: " + x;             break;
++        case F_TYPE: assert x instanceof Float  : "instanceof Float: " + x;            break;
++        case D_TYPE: assert x instanceof Double : "instanceof Double: " + x;           break;
++        case L_TYPE: assert checkRef(type, x)   : "checkRef(" + type + "," + x + ")";  break;
++        case V_TYPE: break;  // allow anything here; will be dropped
+         default:  assert(false);
+         }
+         return true;
+@@ -777,7 +805,7 @@
+      * The first parameter to a LambdaForm, a0:L, always represents the form's method handle, so 0 is not
+      * accepted as valid.
+      */
+-    LambdaForm bindImmediate(int pos, char basicType, Object value) {
++    LambdaForm bindImmediate(int pos, byte 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);
+ 
+@@ -823,8 +851,8 @@
+ 
+     LambdaForm bind(int namePos, BoundMethodHandle.SpeciesData oldData) {
+         Name name = names[namePos];
+-        BoundMethodHandle.SpeciesData newData = oldData.extendWithType(name.type);
+-        return bind(name, newData.getterName(names[0], oldData.fieldCount()), oldData, newData);
++        BoundMethodHandle.SpeciesData newData = oldData.extendWith(name.type);
++        return bind(name, new Name(newData.getterFunction(oldData.fieldCount()), names[0]), oldData, newData);
+     }
+     LambdaForm bind(Name name, Name binding,
+                     BoundMethodHandle.SpeciesData oldData,
+@@ -915,7 +943,7 @@
+         return false;
+     }
+ 
+-    LambdaForm addArguments(int pos, char... types) {
++    LambdaForm addArguments(int pos, byte... types) {
+         assert(pos <= arity);
+         int length = names.length;
+         int inTypes = types.length;
+@@ -936,13 +964,13 @@
+     }
+ 
+     LambdaForm addArguments(int pos, List<Class<?>> types) {
+-        char[] basicTypes = new char[types.size()];
++        byte[] basicTypes = new byte[types.size()];
+         for (int i = 0; i < basicTypes.length; i++)
+             basicTypes[i] = basicType(types.get(i));
+         return addArguments(pos, basicTypes);
+     }
+ 
+-    LambdaForm permuteArguments(int skip, int[] reorder, char[] types) {
++    LambdaForm permuteArguments(int skip, int[] reorder, byte[] types) {
+         // Note:  When inArg = reorder[outArg], outArg is fed by a copy of inArg.
+         // The types are the types of the new (incoming) arguments.
+         int length = names.length;
+@@ -1001,7 +1029,7 @@
+         return new LambdaForm(debugName, arity2, names2, result2);
+     }
+ 
+-    static boolean permutedTypesMatch(int[] reorder, char[] types, Name[] names, int skip) {
++    static boolean permutedTypesMatch(int[] reorder, byte[] types, Name[] names, int skip) {
+         int inTypes = types.length;
+         int outArgs = reorder.length;
+         for (int i = 0; i < outArgs; i++) {
+@@ -1087,7 +1115,7 @@
+                     String sig = m.getName().substring("invoke_".length());
+                     int arity = LambdaForm.signatureArity(sig);
+                     MethodType srcType = MethodType.genericMethodType(arity);
+-                    if (LambdaForm.signatureReturn(sig) == 'V')
++                    if (LambdaForm.signatureReturn(sig) == V_TYPE)
+                         srcType = srcType.changeReturnType(void.class);
+                     MethodTypeForm typeForm = srcType.form();
+                     typeForm.namedFunctionInvoker = DirectMethodHandle.make(m);
+@@ -1269,11 +1297,11 @@
+             return (member == null) ? null : member.getDeclaringClass();
+         }
+ 
+-        char returnType() {
++        byte returnType() {
+             return basicType(methodType().returnType());
+         }
+ 
+-        char parameterType(int n) {
++        byte parameterType(int n) {
+             return basicType(methodType().parameterType(n));
+         }
+ 
+@@ -1288,33 +1316,79 @@
+             if (member == null)  return String.valueOf(resolvedHandle);
+             return member.getDeclaringClass().getSimpleName()+"."+member.getName();
+         }
++
++        public boolean isIdentity() {
++            return this.equals(identity(returnType()));
++        }
++
++        public boolean isConstantZero() {
++            return this.equals(constantZero(returnType()));
++        }
+     }
+ 
+     void resolve() {
+         for (Name n : names) n.resolve();
+     }
+ 
+-    public static char basicType(Class<?> type) {
+-        char c = Wrapper.basicTypeChar(type);
+-        if ("ZBSC".indexOf(c) >= 0)  c = 'I';
+-        assert("LIJFDV".indexOf(c) >= 0);
+-        return c;
++    public static char basicTypeChar(byte type) {
++        return BASIC_TYPE_CHARS.charAt(type);
+     }
+-    public static char[] basicTypes(List<Class<?>> types) {
+-        char[] btypes = new char[types.size()];
++    public static byte basicType(char type) {
++        int bti = BASIC_TYPE_CHARS.indexOf(type);
++        if (bti >= 0)  return (byte) bti;
++        assert("ZBSC".indexOf(type) >= 0);
++        return I_TYPE;  // all subword types are represented as ints
++    }
++
++    public static Wrapper basicTypeWrapper(byte type) {
++        return BASIC_TYPE_WRAPPERS[type];
++    }
++    public static byte basicType(Wrapper type) {
++        char c = type.basicTypeChar();
++        return basicType(c);
++    }
++    public static int basicTypeSlots(byte type) {
++        return basicTypeWrapper(type).stackSlots();
++    }
++
++    public static Class<?> basicTypeClass(byte type) {
++        return BASIC_TYPE_CLASSES[type];
++    }
++    public static byte basicType(Class<?> type) {
++        if (!type.isPrimitive())  return L_TYPE;
++        return basicType(Wrapper.forPrimitiveType(type));
++    }
++    public static Class<?> basicTypeClass(Class<?> type) {
++        if (!type.isPrimitive())  return Object.class;
++        Wrapper w = Wrapper.forPrimitiveType(type);
++        if (w.isSubwordOrInt())  return int.class;
++        return w.primitiveType();
++    }
++    public static char basicTypeChar(Class<?> type) {
++        return BASIC_TYPE_CHARS.charAt(basicType(type));
++    }
++    public static byte[] basicTypes(List<Class<?>> types) {
++        byte[] btypes = new byte[types.size()];
+         for (int i = 0; i < btypes.length; i++) {
+             btypes[i] = basicType(types.get(i));
+         }
+         return btypes;
+     }
++    public static byte[] basicTypes(String types) {
++        byte[] btypes = new byte[types.length()];
++        for (int i = 0; i < btypes.length; i++) {
++            btypes[i] = basicType(types.charAt(i));
++        }
++        return btypes;
++    }
+     public static String basicTypeSignature(MethodType type) {
+         char[] sig = new char[type.parameterCount() + 2];
+         int sigp = 0;
+         for (Class<?> pt : type.parameterList()) {
+-            sig[sigp++] = basicType(pt);
++            sig[sigp++] = basicTypeChar(pt);
+         }
+         sig[sigp++] = '_';
+-        sig[sigp++] = basicType(type.returnType());
++        sig[sigp++] = basicTypeChar(type.returnType());
+         assert(sigp == sig.length);
+         return String.valueOf(sig);
+     }
+@@ -1370,12 +1444,12 @@
+     }
+ 
+     static final class Name {
+-        final char type;
++        final byte type;
+         private short index;
+         final NamedFunction function;
+         @Stable final Object[] arguments;
+ 
+-        private Name(int index, char type, NamedFunction function, Object[] arguments) {
++        private Name(int index, byte type, NamedFunction function, Object[] arguments) {
+             this.index = (short)index;
+             this.type = type;
+             this.function = function;
+@@ -1387,7 +1461,7 @@
+         }
+         Name(MethodType functionType, Object... arguments) {
+             this(new NamedFunction(functionType), arguments);
+-            assert(arguments[0] instanceof Name && ((Name)arguments[0]).type == 'L');
++            assert(arguments[0] instanceof Name && ((Name)arguments[0]).type == L_TYPE);
+         }
+         Name(MemberName function, Object... arguments) {
+             this(new NamedFunction(function), arguments);
+@@ -1398,14 +1472,16 @@
+             for (int i = 0; i < arguments.length; i++)
+                 assert(typesMatch(function.parameterType(i), arguments[i])) : "types don't match: function.parameterType(" + i + ")=" + function.parameterType(i) + ", arguments[" + i + "]=" + arguments[i] + " in " + debugString();
+         }
+-        Name(int index, char type) {
++        /** Create a raw parameter of the given type, with an expected index. */
++        Name(int index, byte type) {
+             this(index, type, null, null);
+         }
+-        Name(char type) {
++        /** Create a raw parameter of the given type. */
++        Name(byte type) {
+             this(-1, type);
+         }
+ 
+-        char type() { return type; }
++        byte type() { return type; }
+         int index() { return index; }
+         boolean initIndex(int i) {
+             if (index != i) {
+@@ -1414,7 +1490,9 @@
+             }
+             return true;
+         }
+-
++        char typeChar() {
++            return basicTypeChar(type);
++        }
+ 
+         void resolve() {
+             if (function != null)
+@@ -1492,18 +1570,18 @@
+             return function == null;
+         }
+         boolean isConstantZero() {
+-            return !isParam() && arguments.length == 0 && function.equals(constantZero(0, type).function);
++            return !isParam() && arguments.length == 0 && function.isConstantZero();
+         }
+ 
+         public String toString() {
+-            return (isParam()?"a":"t")+(index >= 0 ? index : System.identityHashCode(this))+":"+type;
++            return (isParam()?"a":"t")+(index >= 0 ? index : System.identityHashCode(this))+":"+typeChar();
+         }
+         public String debugString() {
+             String s = toString();
+             return (function == null) ? s : s + "=" + exprString();
+         }
+         public String exprString() {
+-            if (function == null)  return "null";
++            if (function == null)  return toString();
+             StringBuilder buf = new StringBuilder(function.toString());
+             buf.append("(");
+             String cma = "";
+@@ -1518,17 +1596,17 @@
+             return buf.toString();
+         }
+ 
+-        private static boolean typesMatch(char parameterType, Object object) {
++        static boolean typesMatch(byte parameterType, Object object) {
+             if (object instanceof Name) {
+                 return ((Name)object).type == parameterType;
+             }
+             switch (parameterType) {
+-                case 'I':  return object instanceof Integer;
+-                case 'J':  return object instanceof Long;
+-                case 'F':  return object instanceof Float;
+-                case 'D':  return object instanceof Double;
++                case I_TYPE:  return object instanceof Integer;
++                case J_TYPE:  return object instanceof Long;
++                case F_TYPE:  return object instanceof Float;
++                case D_TYPE:  return object instanceof Double;
+             }
+-            assert(parameterType == 'L');
++            assert(parameterType == L_TYPE);
+             return true;
+         }
+ 
+@@ -1584,10 +1662,12 @@
+     }
+ 
+     static Name argument(int which, char type) {
+-        int tn = ALL_TYPES.indexOf(type);
+-        if (tn < 0 || which >= INTERNED_ARGUMENT_LIMIT)
++        return argument(which, basicType(type));
++    }
++    static Name argument(int which, byte type) {
++        if (which >= INTERNED_ARGUMENT_LIMIT)
+             return new Name(which, type);
+-        return INTERNED_ARGUMENTS[tn][which];
++        return INTERNED_ARGUMENTS[type][which];
+     }
+     static Name internArgument(Name n) {
+         assert(n.isParam()) : "not param: " + n;
+@@ -1629,50 +1709,117 @@
+             names[i] = argument(i, basicType(types.parameterType(i)));
+         return names;
+     }
+-    static final String ALL_TYPES = "LIJFD";  // omit V, not an argument type
+     static final int INTERNED_ARGUMENT_LIMIT = 10;
+     private static final Name[][] INTERNED_ARGUMENTS
+-            = new Name[ALL_TYPES.length()][INTERNED_ARGUMENT_LIMIT];
++            = new Name[ARG_TYPE_LIMIT][INTERNED_ARGUMENT_LIMIT];
+     static {
+-        for (int tn = 0; tn < ALL_TYPES.length(); tn++) {
+-            for (int i = 0; i < INTERNED_ARGUMENTS[tn].length; i++) {
+-                char type = ALL_TYPES.charAt(tn);
+-                INTERNED_ARGUMENTS[tn][i] = new Name(i, type);
++        for (byte type = 0; type < ARG_TYPE_LIMIT; type++) {
++            for (int i = 0; i < INTERNED_ARGUMENTS[type].length; i++) {
++                INTERNED_ARGUMENTS[type][i] = new Name(i, type);
+             }
+         }
+     }
+ 
+     private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
+ 
+-    static Name constantZero(int which, char type) {
+-        return CONSTANT_ZERO[ALL_TYPES.indexOf(type)].newIndex(which);
++    static LambdaForm identityForm(byte type) {
++        return LF_identityForm[type];
+     }
+-    private static final Name[] CONSTANT_ZERO
+-            = new Name[ALL_TYPES.length()];
+-    static {
+-        for (int tn = 0; tn < ALL_TYPES.length(); tn++) {
+-            char bt = ALL_TYPES.charAt(tn);
+-            Wrapper wrap = Wrapper.forBasicType(bt);
+-            MemberName zmem = new MemberName(LambdaForm.class, "zero"+bt, MethodType.methodType(wrap.primitiveType()), REF_invokeStatic);
++    static LambdaForm zeroForm(byte type) {
++        return LF_zeroForm[type];
++    }
++    static NamedFunction identity(byte type) {
++        return NF_identity[type];
++    }
++    static NamedFunction constantZero(byte type) {
++        return NF_zero[type];
++    }
++    private static final LambdaForm[] LF_identityForm = new LambdaForm[TYPE_LIMIT];
++    private static final LambdaForm[] LF_zeroForm = new LambdaForm[TYPE_LIMIT];
++    private static final NamedFunction[] NF_identity = new NamedFunction[TYPE_LIMIT];
++    private static final NamedFunction[] NF_zero = new NamedFunction[TYPE_LIMIT];
++    private static void createIdentityForms() {
++        for (byte bt = 0; bt < TYPE_LIMIT; bt++) {
++            char btChar = basicTypeChar(bt);
++            boolean isVoid = (bt == V_TYPE);
++            Class<?> btClass = basicTypeClass(bt);
++            MethodType zeType = MethodType.methodType(btClass);
++            MethodType idType = isVoid ? zeType : zeType.appendParameterTypes(btClass);
++
++            // Look up some symbolic names.  It might not be necessary to have these,
++            // but if we need to emit direct references to bytecodes, it helps.
++            // Zero is built from a call to an identity function with a constant zero input.
++            MemberName idMem = new MemberName(LambdaForm.class, "identity_"+btChar, idType, REF_invokeStatic);
++            MemberName zeMem = new MemberName(LambdaForm.class, "zero_"+btChar, zeType, REF_invokeStatic);
+             try {
+-                zmem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, zmem, null, NoSuchMethodException.class);
++                zeMem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, zeMem, null, NoSuchMethodException.class);
++                idMem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, idMem, null, NoSuchMethodException.class);
+             } catch (IllegalAccessException|NoSuchMethodException ex) {
+                 throw newInternalError(ex);
+             }
+-            NamedFunction zcon = new NamedFunction(zmem);
+-            Name n = new Name(zcon).newIndex(0);
+-            assert(n.type == ALL_TYPES.charAt(tn));
+-            CONSTANT_ZERO[tn] = n;
+-            assert(n.isConstantZero());
++
++            NamedFunction idFun = new NamedFunction(idMem);
++            LambdaForm idForm;
++            if (isVoid) {
++                Name[] idNames = new Name[] { argument(0, L_TYPE) };
++                idForm = new LambdaForm(idMem.getName(), 1, idNames, VOID_RESULT);
++            } else {
++                Name[] idNames = new Name[] { argument(0, L_TYPE), argument(1, bt) };
++                idForm = new LambdaForm(idMem.getName(), 2, idNames, 1);
++            }
++            LF_identityForm[bt] = idForm;
++            NF_identity[bt] = idFun;
++            //idFun.resolvedHandle = SimpleMethodHandle.make(idMem.getInvocationType(), idForm);
++
++            NamedFunction zeFun = new NamedFunction(zeMem);
++            LambdaForm zeForm;
++            if (isVoid) {
++                zeForm = idForm;
++            } else {
++                Object zeValue = Wrapper.forBasicType(basicTypeChar(bt)).zero();
++                Name[] zeNames = new Name[] { argument(0, L_TYPE), new Name(idFun, zeValue) };
++                zeForm = new LambdaForm(zeMem.getName(), 1, zeNames, 1);
++            }
++            LF_zeroForm[bt] = zeForm;
++            NF_zero[bt] = zeFun;
++            //zeFun.resolvedHandle = SimpleMethodHandle.make(zeMem.getInvocationType(), zeForm);
++
++            assert(idFun.isIdentity());
++            assert(zeFun.isConstantZero());
++            assert(new Name(zeFun).isConstantZero());
++        }
++
++        // Do this in a separate pass, so that SimpleMethodHandle.make can see the tables.
++        for (byte bt = 0; bt < TYPE_LIMIT; bt++) {
++            NamedFunction idFun = NF_identity[bt];
++            LambdaForm idForm = LF_identityForm[bt];
++            MemberName idMem = idFun.member;
++            idFun.resolvedHandle = SimpleMethodHandle.make(idMem.getInvocationType(), idForm);
++
++            NamedFunction zeFun = NF_zero[bt];
++            LambdaForm zeForm = LF_zeroForm[bt];
++            MemberName zeMem = zeFun.member;
++            zeFun.resolvedHandle = SimpleMethodHandle.make(zeMem.getInvocationType(), zeForm);
++
++            assert(idFun.isIdentity());
++            assert(zeFun.isConstantZero());
++            assert(new Name(zeFun).isConstantZero());
+         }
+     }
+ 
+     // Avoid appealing to ValueConversions at bootstrap time:
+-    private static int zeroI() { return 0; }
+-    private static long zeroJ() { return 0; }
+-    private static float zeroF() { return 0; }
+-    private static double zeroD() { return 0; }
+-    private static Object zeroL() { return null; }
++    private static int identity_I(int x) { return x; }
++    private static long identity_J(long x) { return x; }
++    private static float identity_F(float x) { return x; }
++    private static double identity_D(double x) { return x; }
++    private static Object identity_L(Object x) { return x; }
++    private static void identity_V() { return; }  // same as zeroV, but that's OK
++    private static int zero_I() { return 0; }
++    private static long zero_J() { return 0; }
++    private static float zero_F() { return 0; }
++    private static double zero_D() { return 0; }
++    private static Object zero_L() { return null; }
++    private static void zero_V() { return; }
+ 
+     /**
+      * Internal marker for byte-compiled LambdaForms.
+@@ -1741,6 +1888,7 @@
+ 
+     // Put this last, so that previous static inits can run before.
+     static {
++        createIdentityForms();
+         if (USE_PREDEFINED_INTERPRET_METHODS)
+             PREPARED_FORMS.putAll(computeInitialPreparedForms());
+         NamedFunction.initializeInvokers();
+diff --git a/src/share/classes/java/lang/invoke/MethodHandle.java b/src/share/classes/java/lang/invoke/MethodHandle.java
+--- a/src/share/classes/java/lang/invoke/MethodHandle.java
++++ b/src/share/classes/java/lang/invoke/MethodHandle.java
+@@ -1380,7 +1380,7 @@
+     }
+ 
+     /*non-public*/
+-    MethodHandle bindArgument(int pos, char basicType, Object value) {
++    MethodHandle bindArgument(int pos, byte basicType, Object value) {
+         // Override this if it can be improved.
+         return rebind().bindArgument(pos, basicType, value);
+     }
+@@ -1388,18 +1388,18 @@
+     /*non-public*/
+     MethodHandle bindReceiver(Object receiver) {
+         // Override this if it can be improved.
+-        return bindArgument(0, 'L', receiver);
++        return bindArgument(0, LambdaForm.L_TYPE, receiver);
+     }
+ 
+     /*non-public*/
+-    MethodHandle bindImmediate(int pos, char basicType, Object value) {
++    MethodHandle bindImmediate(int pos, byte basicType, Object value) {
+         // Bind an immediate value to a position in the arguments.
+         // This means, elide the respective argument,
+         // and replace all references to it in NamedFunction args with the specified value.
+ 
+         // CURRENT RESTRICTIONS
+         // * only for pos 0 and UNSAFE (position is adjusted in MHImpl to make API usable for others)
+-        assert pos == 0 && basicType == 'L' && value instanceof Unsafe;
++        assert pos == 0 && basicType == LambdaForm.L_TYPE && value instanceof Unsafe;
+         MethodType type2 = type.dropParameterTypes(pos, pos + 1); // adjustment: ignore receiver!
+         LambdaForm form2 = form.bindImmediate(pos + 1, basicType, value); // adjust pos to form-relative pos
+         return copyWith(type2, form2);
+diff --git a/src/share/classes/java/lang/invoke/MethodHandleImpl.java b/src/share/classes/java/lang/invoke/MethodHandleImpl.java
+--- a/src/share/classes/java/lang/invoke/MethodHandleImpl.java
++++ b/src/share/classes/java/lang/invoke/MethodHandleImpl.java
+@@ -397,7 +397,7 @@
+ 
+ 
+         @Override
+-        MethodHandle bindArgument(int pos, char basicType, Object value) {
++        MethodHandle bindArgument(int pos, byte basicType, Object value) {
+             return asFixedArity().bindArgument(pos, basicType, value);
+         }
+ 
+diff --git a/src/share/classes/java/lang/invoke/MethodHandles.java b/src/share/classes/java/lang/invoke/MethodHandles.java
+--- a/src/share/classes/java/lang/invoke/MethodHandles.java
++++ b/src/share/classes/java/lang/invoke/MethodHandles.java
+@@ -2198,12 +2198,12 @@
+             Object value = values[i];
+             Class<?> ptype = oldType.parameterType(pos+i);
+             if (ptype.isPrimitive()) {
+-                char btype = 'I';
++                byte btype = LambdaForm.I_TYPE;
+                 Wrapper w = Wrapper.forPrimitiveType(ptype);
+                 switch (w) {
+-                case LONG:    btype = 'J'; break;
+-                case FLOAT:   btype = 'F'; break;
+-                case DOUBLE:  btype = 'D'; break;
++                case LONG:    btype = LambdaForm.J_TYPE; break;
++                case FLOAT:   btype = LambdaForm.F_TYPE; break;
++                case DOUBLE:  btype = LambdaForm.D_TYPE; break;
+                 }
+                 // perform unboxing and/or primitive conversion
+                 value = w.convert(value, ptype);
+@@ -2214,7 +2214,7 @@
+             if (pos == 0) {
+                 result = result.bindReceiver(value);
+             } else {
+-                result = result.bindArgument(pos, 'L', value);
++                result = result.bindArgument(pos, LambdaForm.L_TYPE, value);
+             }
+         }
+         return result;
+diff --git a/src/share/classes/java/lang/invoke/SimpleMethodHandle.java b/src/share/classes/java/lang/invoke/SimpleMethodHandle.java
+--- a/src/share/classes/java/lang/invoke/SimpleMethodHandle.java
++++ b/src/share/classes/java/lang/invoke/SimpleMethodHandle.java
+@@ -44,7 +44,7 @@
+     }
+ 
+     @Override
+-    MethodHandle bindArgument(int pos, char basicType, Object value) {
++    MethodHandle bindArgument(int pos, byte 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);
--- a/meth-clinit-8024599.patch	Sun Sep 15 17:15:12 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,397 +0,0 @@
-8024599: JSR 292 direct method handles need to respect initialization rules for static members
-Summary: Align MH semantic with bytecode behavior of constructor and static member accesses, regarding <clinit> invocation.
-Reviewed-by: ?
-
-diff --git a/src/share/classes/java/lang/invoke/DirectMethodHandle.java b/src/share/classes/java/lang/invoke/DirectMethodHandle.java
---- a/src/share/classes/java/lang/invoke/DirectMethodHandle.java
-+++ b/src/share/classes/java/lang/invoke/DirectMethodHandle.java
-@@ -72,6 +72,12 @@
-             if (!member.getDeclaringClass().isAssignableFrom(receiver) || member.isConstructor())
-                 throw new InternalError(member.toString());
-             mtype = mtype.insertParameterTypes(0, receiver);
-+        } else if (EAGERLY_INITIALIZE_STATIC_TARGET_CLASSES) {
-+            // Old JDK 7 docs claimed, "If the method's class has not
-+            // yet been initialized, that is done immediately, before
-+            // the method handle is returned."  This documented a bug.
-+            // We can still simulate this behavior for manual testing.
-+            UNSAFE.ensureClassInitialized(member.getDeclaringClass());
-         }
-         if (!member.isField()) {
-             if (refKind == REF_invokeSpecial) {
-@@ -95,6 +101,7 @@
-             }
-         }
-     }
-+    private static final boolean EAGERLY_INITIALIZE_STATIC_TARGET_CLASSES = false;
-     static DirectMethodHandle make(Class<?> receiver, MemberName member) {
-         byte refKind = member.getReferenceKind();
-         if (refKind == REF_invokeSpecial)
-diff --git a/src/share/classes/java/lang/invoke/MethodHandles.java b/src/share/classes/java/lang/invoke/MethodHandles.java
---- a/src/share/classes/java/lang/invoke/MethodHandles.java
-+++ b/src/share/classes/java/lang/invoke/MethodHandles.java
-@@ -606,12 +606,13 @@
-          * additional receiver argument inserted into the method handle type,
-          * as there would be with {@link #findVirtual findVirtual} or {@link #findSpecial findSpecial}.)
-          * The method and all its argument types must be accessible to the lookup class.
--         * If the method's class has not yet been initialized, that is done
--         * immediately, before the method handle is returned.
-          * <p>
-          * The returned method handle will have
-          * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
-          * the method's variable arity modifier bit ({@code 0x0080}) is set.
-+         * <p>
-+         * If the returned method handle is invoked, the method's class will
-+         * be initialized, if it has not already been initialized.
-          * <b>Example:</b>
-          * <p><blockquote><pre>{@code
- import static java.lang.invoke.MethodHandles.*;
-@@ -738,8 +739,6 @@
-          * The parameter types of the method handle will be those of the constructor,
-          * while the return type will be a reference to the constructor's class.
-          * The constructor and all its argument types must be accessible to the lookup class.
--         * If the constructor's class has not yet been initialized, that is done
--         * immediately, before the method handle is returned.
-          * <p>
-          * <em>(Note:  The requested type must have a return type of {@code void}.
-          * This is consistent with the JVM's treatment of constructor type descriptors.)</em>
-@@ -747,6 +746,9 @@
-          * The returned method handle will have
-          * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
-          * the constructor's variable arity modifier bit ({@code 0x0080}) is set.
-+         * <p>
-+         * If the returned method handle is invoked, the constructor's class will
-+         * be initialized, if it has not already been initialized.
-          * <b>Example:</b>
-          * <p><blockquote><pre>{@code
- import static java.lang.invoke.MethodHandles.*;
-@@ -917,6 +919,9 @@
-          * value type.
-          * The method handle will take no arguments.
-          * Access checking is performed immediately on behalf of the lookup class.
-+         * <p>
-+         * If the returned method handle is invoked, the field's class will
-+         * be initialized, if it has not already been initialized.
-          * @param refc the class or interface from which the method is accessed
-          * @param name the field's name
-          * @param type the field's type
-@@ -939,6 +944,9 @@
-          * The method handle will take a single
-          * argument, of the field's value type, the value to be stored.
-          * Access checking is performed immediately on behalf of the lookup class.
-+         * <p>
-+         * If the returned method handle is invoked, the field's class will
-+         * be initialized, if it has not already been initialized.
-          * @param refc the class or interface from which the method is accessed
-          * @param name the field's name
-          * @param type the field's type
-@@ -1023,6 +1031,10 @@
-          * The returned method handle will have
-          * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
-          * the method's variable arity modifier bit ({@code 0x0080}) is set.
-+         * <p>
-+         * If <i>m</i> is static, and
-+         * if the returned method handle is invoked, the method's class will
-+         * be initialized, if it has not already been initialized.
-          * @param m the reflected method
-          * @return a method handle which can invoke the reflected method
-          * @throws IllegalAccessException if access checking fails
-@@ -1094,6 +1106,9 @@
-          * The returned method handle will have
-          * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
-          * the constructor's variable arity modifier bit ({@code 0x0080}) is set.
-+         * <p>
-+         * If the returned method handle is invoked, the constructor's class will
-+         * be initialized, if it has not already been initialized.
-          * @param c the reflected constructor
-          * @return a method handle which can invoke the reflected constructor
-          * @throws IllegalAccessException if access checking fails
-@@ -1118,6 +1133,10 @@
-          * the field.
-          * If the field's {@code accessible} flag is not set,
-          * access checking is performed immediately on behalf of the lookup class.
-+         * <p>
-+         * If the field is static, and
-+         * if the returned method handle is invoked, the field's class will
-+         * be initialized, if it has not already been initialized.
-          * @param f the reflected field
-          * @return a method handle which can load values from the reflected field
-          * @throws IllegalAccessException if access checking fails
-@@ -1144,6 +1163,10 @@
-          * the field, and the value to be stored.
-          * If the field's {@code accessible} flag is not set,
-          * access checking is performed immediately on behalf of the lookup class.
-+         * <p>
-+         * If the field is static, and
-+         * if the returned method handle is invoked, the field's class will
-+         * be initialized, if it has not already been initialized.
-          * @param f the reflected field
-          * @return a method handle which can store values into the reflected field
-          * @throws IllegalAccessException if access checking fails
-diff --git a/test/java/lang/invoke/CallStaticInitOrder.java b/test/java/lang/invoke/CallStaticInitOrder.java
-new file mode 100644
---- /dev/null
-+++ b/test/java/lang/invoke/CallStaticInitOrder.java
-@@ -0,0 +1,263 @@
-+/*
-+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
-+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-+ *
-+ * This code is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License version 2 only, as
-+ * published by the Free Software Foundation.
-+ *
-+ * This code is distributed in the hope that it will be useful, but WITHOUT
-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-+ * version 2 for more details (a copy is included in the LICENSE file that
-+ * accompanied this code).
-+ *
-+ * You should have received a copy of the GNU General Public License version
-+ * 2 along with this work; if not, write to the Free Software Foundation,
-+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-+ * or visit www.oracle.com if you need additional information or have any
-+ * questions.
-+ *
-+ */
-+
-+/**
-+ * @test
-+ * @summary static initializer invocation order
-+ *
-+ * @build indify.Indify
-+ * @compile CallStaticInitOrder.java
-+ * @run main/othervm/timeout=3600
-+ *      indify.Indify
-+ *      --expand-properties --classpath ${test.classes}
-+ *      --java test.java.lang.invoke.CallStaticInitOrder
-+ */
-+
-+package test.java.lang.invoke;
-+
-+import java.io.*;
-+
-+import java.lang.invoke.*;
-+import static java.lang.invoke.MethodHandles.*;
-+import static java.lang.invoke.MethodType.*;
-+
-+public class CallStaticInitOrder {
-+    private static int TICK;
-+    private static synchronized int tick(String event) {
-+        int n = ++TICK;
-+        System.out.println("event #"+n+" = "+event);
-+        return n;
-+    }
-+
-+    private static int Init1Tick;
-+    private static class Init1 {
-+        static { Init1Tick = tick("foo -> Init1.<clinit>"); }
-+        static int foo() { return Init1Tick; }
-+    }
-+
-+    static int Init2Tick;
-+    private static class Init2 {
-+        static { Init2Tick = tick("bar -> Init2.<clinit>"); }
-+        static int bar() { return Init2Tick; }
-+    }
-+
-+    static int Init3Tick;
-+    private static class Init3 {
-+        static { Init3Tick = tick("baz -> Init3.<clinit>"); }
-+        static int baz() { return Init3Tick; }
-+    }
-+
-+    static int Init4Tick;
-+    private static class Init4 {
-+        static { Init4Tick = tick("bat -> Init4.<clinit>"); }
-+        static int bat() { return Init4Tick; }
-+    }
-+
-+    static int Init5Tick;
-+    private static class Init5 {
-+        static { Init5Tick = tick("read bang -> Init5.<clinit>"); }
-+        static int bang = Init5Tick;
-+    }
-+
-+    static int Init6Tick;
-+    private static class Init6 {
-+        static { Init6Tick = tick("write pong -> Init6.<clinit>"); }
-+        static int pong;
-+    }
-+
-+    private static final MutableCallSite CONSTANT_CS_baz;
-+    private static MethodHandle MH_foo() throws ReflectiveOperationException {
-+        return lookup().findStatic(Init1.class, "foo", methodType(int.class));
-+    }
-+    private static final MethodHandle CONSTANT_MH_bar;
-+    private static MethodHandle MH_baz() throws ReflectiveOperationException {
-+        return lookup().findStatic(Init3.class, "baz", methodType(int.class));
-+    }
-+    private static final MethodHandle CONSTANT_MH_bat;
-+    private static final MethodHandle CONSTANT_MH_bangGetter;
-+    private static final MethodHandle CONSTANT_MH_pongSetter;
-+    static {
-+        try {
-+            int t1 = tick("CallStaticInitOrder.<clinit>");
-+            {
-+                CONSTANT_CS_baz = new MutableCallSite(methodType(int.class));
-+                // MH_foo() := lookup().findStatic(Init1.class, "foo", methodType(int.class));
-+                CONSTANT_MH_bar = lookup().findStatic(Init2.class, "bar", methodType(int.class));
-+                // MH_baz() := lookup().findStatic(Init3.class, "baz", methodType(int.class));
-+                CONSTANT_MH_bat = lookup().unreflect(Init4.class.getDeclaredMethod("bat"));
-+                CONSTANT_MH_bangGetter = lookup().findStaticGetter(Init5.class, "bang", int.class);
-+                MethodHandle pongSetter = lookup().findStaticSetter(Init6.class, "pong", int.class);
-+                MethodHandle tickGetter = lookup().findStaticGetter(CallStaticInitOrder.class, "Init6Tick", int.class);
-+                CONSTANT_MH_pongSetter = filterReturnValue(insertArguments(pongSetter, 0, -99), tickGetter);
-+            }
-+            int t2 = tick("CallStaticInitOrder.<clinit> done");
-+            assertEquals(t1+1, t2);  // no ticks in between
-+        } catch (Exception ex) {
-+            throw new InternalError(ex.toString());
-+        }
-+    }
-+
-+    public static void main(String... av) throws Throwable {
-+        testInit();
-+        if (LAST_LOSER != null)  throw LAST_LOSER;
-+    }
-+
-+    private static Throwable LAST_LOSER;
-+
-+    private static void assertEquals(int expected, int actual) {
-+        if (expected != actual) {
-+            Throwable loser = new AssertionError("expected: " + expected + ", actual: " + actual);
-+            if (LAST_LOSER != null)
-+                LAST_LOSER.printStackTrace(System.out);
-+            LAST_LOSER = loser;
-+        }
-+    }
-+
-+    private static void testInit() throws Throwable {
-+        System.out.println("runFoo = "+runFoo());
-+        System.out.println("runBar = "+runBar());
-+        try {
-+            runBaz();
-+        } catch (IllegalStateException ex) {
-+            tick("runBaz throw/catch");
-+        }
-+        CONSTANT_CS_baz.setTarget(MH_baz());
-+        System.out.println("runBaz = "+runBaz());
-+        System.out.println("runBat = "+runBat());
-+        System.out.println("runBang = "+runBang());
-+        System.out.println("runPong = "+runPong());
-+    }
-+
-+    private static int runFoo() throws Throwable {
-+        int t1 = tick("runFoo");
-+        int t2 = (int) INDY_foo().invokeExact();
-+        int t3 = tick("runFoo done");
-+        assertEquals(t1+2, t3);  // exactly two ticks in between
-+        assertEquals(t1+1, t2);  // init happened inside
-+        return t2;
-+    }
-+    private static MethodHandle INDY_foo() throws Throwable {
-+        shouldNotCallThis();
-+        return ((CallSite) MH_bsm().invoke(lookup(), "foo", methodType(int.class))).dynamicInvoker();
-+    }
-+
-+    private static int runBar() throws Throwable {
-+        int t1 = tick("runBar");
-+        int t2 = (int) INDY_bar().invokeExact();
-+        int t3 = tick("runBar done");
-+        assertEquals(t1+2, t3);  // exactly two ticks in between
-+        assertEquals(t1+1, t2);  // init happened inside
-+        return t2;
-+    }
-+    private static MethodHandle INDY_bar() throws Throwable {
-+        shouldNotCallThis();
-+        return ((CallSite) MH_bsm().invoke(lookup(), "bar", methodType(int.class))).dynamicInvoker();
-+    }
-+
-+    private static int runBaz() throws Throwable {
-+        int t1 = tick("runBaz");
-+        int t2 = (int) INDY_baz().invokeExact();
-+        int t3 = tick("runBaz done");
-+        assertEquals(t1+2, t3);  // exactly two ticks in between
-+        assertEquals(t1+1, t2);  // init happened inside
-+        return t2;
-+    }
-+    private static MethodHandle INDY_baz() throws Throwable {
-+        shouldNotCallThis();
-+        return ((CallSite) MH_bsm().invoke(lookup(), "baz", methodType(int.class))).dynamicInvoker();
-+    }
-+
-+    private static int runBat() throws Throwable {
-+        int t1 = tick("runBat");
-+        int t2 = (int) INDY_bat().invokeExact();
-+        int t3 = tick("runBat done");
-+        assertEquals(t1+2, t3);  // exactly two ticks in between
-+        assertEquals(t1+1, t2);  // init happened inside
-+        return t2;
-+    }
-+    private static MethodHandle INDY_bat() throws Throwable {
-+        shouldNotCallThis();
-+        return ((CallSite) MH_bsm().invoke(lookup(), "bat", methodType(int.class))).dynamicInvoker();
-+    }
-+
-+    private static int runBang() throws Throwable {
-+        int t1 = tick("runBang");
-+        int t2 = (int) INDY_bang().invokeExact();
-+        int t3 = tick("runBang done");
-+        assertEquals(t1+2, t3);  // exactly two ticks in between
-+        assertEquals(t1+1, t2);  // init happened inside
-+        return t2;
-+    }
-+    private static MethodHandle INDY_bang() throws Throwable {
-+        shouldNotCallThis();
-+        return ((CallSite) MH_bsm().invoke(lookup(), "bang", methodType(int.class))).dynamicInvoker();
-+    }
-+
-+    private static int runPong() throws Throwable {
-+        int t1 = tick("runPong");
-+        int t2 = (int) INDY_pong().invokeExact();
-+        int t3 = tick("runPong done");
-+        assertEquals(t1+2, t3);  // exactly two ticks in between
-+        assertEquals(t1+1, t2);  // init happened inside
-+        return t2;
-+    }
-+    private static MethodHandle INDY_pong() throws Throwable {
-+        shouldNotCallThis();
-+        return ((CallSite) MH_bsm().invoke(lookup(), "pong", methodType(int.class))).dynamicInvoker();
-+    }
-+
-+    private static CallSite bsm(Lookup caller, String name, MethodType type) throws ReflectiveOperationException {
-+        System.out.println("bsm "+name+type);
-+        CallSite res;
-+        switch (name) {
-+        case "foo":
-+            res = new ConstantCallSite(MH_foo()); break;
-+        case "bar":
-+            res = new ConstantCallSite(CONSTANT_MH_bar); break;
-+        case "baz":
-+            res = CONSTANT_CS_baz; break;
-+        case "bat":
-+            res = new ConstantCallSite(CONSTANT_MH_bat); break;
-+        case "bang":
-+            res = new ConstantCallSite(CONSTANT_MH_bangGetter); break;
-+        case "pong":
-+            res = new ConstantCallSite(CONSTANT_MH_pongSetter); break;
-+        default:
-+            res = null;
-+        }
-+        if (res == null || !res.type().equals(type)) {
-+            throw new AssertionError(String.valueOf(res));
-+        }
-+        return res;
-+    }
-+    private static MethodHandle MH_bsm() throws ReflectiveOperationException {
-+        shouldNotCallThis();
-+        return lookup().findStatic(lookup().lookupClass(), "bsm",
-+                                   methodType(CallSite.class, Lookup.class, String.class, MethodType.class));
-+    }
-+    private static void shouldNotCallThis() {
-+        // if this gets called, the transformation has not taken place
-+        throw new AssertionError("this code should be statically transformed away by Indify");
-+    }
-+}
--- a/meth-coll-8001110.patch	Sun Sep 15 17:15:12 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,416 +0,0 @@
-8001110: method handles should have a collectArguments transform, generalizing asCollector
-Summary: promote an existing private method; make unit tests on all argument positions to arity 10 with mixed types
-
-diff --git a/src/share/classes/java/lang/invoke/MethodHandles.java b/src/share/classes/java/lang/invoke/MethodHandles.java
---- a/src/share/classes/java/lang/invoke/MethodHandles.java
-+++ b/src/share/classes/java/lang/invoke/MethodHandles.java
-@@ -2136,15 +2136,114 @@
-         return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
-     }
- 
--    // FIXME: Make this public in M1.
--    /*non-public*/ static
--    MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle collector) {
-+    /**
-+     * Adapts a target method handle by pre-processing
-+     * a sub-sequence of its arguments with a filter (another method handle).
-+     * The pre-processed arguments are replaced by the result (if any) of the
-+     * filter function.
-+     * The target is then called on the modified (usually shortened) argument list.
-+     * <p>
-+     * If the filter returns a value, the target must accept that value as
-+     * its {@code pos} argument, plus any arguments not passed to the filter.
-+     * If the filter returns void, the target must accept all arguments
-+     * not passed to the filter.
-+     * No arguments are reordered, and a result returned from the filter
-+     * replaces (in order) the whole subsequence of arguments originally
-+     * passed to the adapter.
-+     * <p>
-+     * The argument types (if any) of the filter
-+     * replace zero or one argument types of the target, at position {@code pos},
-+     * in the resulting adapted method handle.
-+     * The return type of the filter (if any) must be identical to the
-+     * argument type of the target at position {@code pos}, and that target argument
-+     * is supplied by the return value of the filter.
-+     * <p>
-+     * In all cases, {@code pos} must be greater than or equal to zero, and
-+     * {@code pos} must also be less than or equal to the target's arity.
-+     * <b>Example:</b>
-+     * <p><blockquote><pre>
-+import static java.lang.invoke.MethodHandles.*;
-+import static java.lang.invoke.MethodType.*;
-+...
-+MethodHandle deepToString = publicLookup()
-+  .findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
-+MethodHandle ts1 = deepToString.asCollector(String[].class, 1);
-+assertEquals("[strange]", (String) ts1.invokeExact("strange"));
-+MethodHandle ts2 = deepToString.asCollector(String[].class, 2);
-+assertEquals("[up, down]", (String) ts2.invokeExact("up", "down"));
-+MethodHandle ts3 = deepToString.asCollector(String[].class, 3);
-+MethodHandle ts3_ts2 = collectArguments(ts3, 1, ts2);
-+assertEquals("[top, [up, down], strange]",
-+             (String) ts3_ts2.invokeExact("top", "up", "down", "strange"));
-+MethodHandle ts3_ts2_ts1 = collectArguments(ts3_ts2, 3, ts1);
-+assertEquals("[top, [up, down], [strange]]",
-+             (String) ts3_ts2_ts1.invokeExact("top", "up", "down", "strange"));
-+MethodHandle ts3_ts2_ts3 = collectArguments(ts3_ts2, 1, ts3);
-+assertEquals("[top, [[up, down, strange], charm], bottom]",
-+             (String) ts3_ts2_ts3.invokeExact("top", "up", "down", "strange", "charm", "bottom"));
-+     * </pre></blockquote>
-+     * <p> Here is pseudocode for the resulting adapter:
-+     * <blockquote><pre>
-+     * T target(A...,V,C...);
-+     * V filter(B...);
-+     * T adapter(A... a,B... b,C... c) {
-+     *   V v = filter(b...);
-+     *   return target(a...,v,c...);
-+     * }
-+     * // and if the filter has no arguments:
-+     * T target2(A...,V,C...);
-+     * V filter2();
-+     * T adapter2(A... a,C... c) {
-+     *   V v = filter2();
-+     *   return target2(a...,v,c...);
-+     * }
-+     * // and if the filter has a void return:
-+     * T target3(A...,C...);
-+     * void filter3(B...);
-+     * void adapter3(A... a,B... b,C... c) {
-+     *   filter3(b...);
-+     *   return target3(a...,c...);
-+     * }
-+     * </pre></blockquote>
-+     * <p>
-+     * A collection adapter {@code collectArguments(mh, 0, coll)} is equivalent to
-+     * one which first "folds" the affected arguments, and then drops them, in separate
-+     * steps as follows:
-+     * <blockquote><pre>{@code
-+     * mh = MethodHandles.dropArguments(mh, 1, coll.type().parameterList()); //step 2
-+     * mh = MethodHandles.foldArguments(mh, coll); //step 1
-+     * }</pre></blockquote>
-+     * If the target method handle consumes no arguments besides than the result
-+     * (if any) of the filter {@code coll}, then {@code collectArguments(mh, 0, coll)}
-+     * is equivalent to {@code filterReturnValue(coll, mh)}.
-+     * If the filter method handle {@code coll} consumes one argument and produces
-+     * a non-void result, then {@code collectArguments(mh, N, coll)}
-+     * is equivalent to {@code filterArguments(mh, N, coll)}.
-+     * Other equivalences are possible but would require argument permutation.
-+     *
-+     * @param target the method handle to invoke after filtering the subsequence of arguments
-+     * @param pos the position of the first adapter argument to pass to the filter,
-+     *            and/or the target argument which receives the result of the filter
-+     * @param filter method handle to call on the subsequence of arguments
-+     * @return method handle which incorporates the specified argument subsequence filtering logic
-+     * @throws NullPointerException if either argument is null
-+     * @throws IllegalArgumentException if the return type of {@code filter}
-+     *          is non-void and is not the same as the {@code pos} argument of the target,
-+     *          or if {@code pos} is not between 0 and the target's arity, inclusive,
-+     *          or if the resulting method handle's type would have
-+     *          <a href="MethodHandle.html#maxarity">too many parameters</a>
-+     * @see MethodHandles#foldArguments
-+     * @see MethodHandles#filterArguments
-+     * @see MethodHandles#filterReturnValue
-+     */
-+    public static
-+    MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle filter) {
-         MethodType targetType = target.type();
--        MethodType filterType = collector.type();
-+        MethodType filterType = filter.type();
-         if (filterType.returnType() != void.class &&
-             filterType.returnType() != targetType.parameterType(pos))
-             throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
--        return MethodHandleImpl.makeCollectArguments(target, collector, pos, false);
-+        return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
-     }
- 
-     /**
-diff --git a/src/share/classes/sun/invoke/util/ValueConversions.java b/src/share/classes/sun/invoke/util/ValueConversions.java
---- a/src/share/classes/sun/invoke/util/ValueConversions.java
-+++ b/src/share/classes/sun/invoke/util/ValueConversions.java
-@@ -502,51 +502,6 @@
-         }
-     }
- 
--    static MethodHandle collectArguments(MethodHandle mh, int pos, MethodHandle collector) {
--        // FIXME: API needs public MHs.collectArguments.
--        // Should be:
--        //   return MethodHandles.collectArguments(mh, 0, collector);
--        // The rest of this code is a workaround for not having that API.
--        if (COLLECT_ARGUMENTS != null) {
--            try {
--                return (MethodHandle)
--                    COLLECT_ARGUMENTS.invokeExact(mh, pos, collector);
--            } catch (Throwable ex) {
--                if (ex instanceof RuntimeException)
--                    throw (RuntimeException) ex;
--                if (ex instanceof Error)
--                    throw (Error) ex;
--                throw new Error(ex.getMessage(), ex);
--            }
--        }
--        // Emulate MHs.collectArguments using fold + drop.
--        // This is slightly inefficient.
--        // More seriously, it can put a MH over the 255-argument limit.
--        mh = MethodHandles.dropArguments(mh, 1, collector.type().parameterList());
--        mh = MethodHandles.foldArguments(mh, collector);
--        return mh;
--    }
--    private static final MethodHandle COLLECT_ARGUMENTS;
--    static {
--        MethodHandle mh = null;
--        try {
--            final java.lang.reflect.Method m = MethodHandles.class
--                .getDeclaredMethod("collectArguments",
--                    MethodHandle.class, int.class, MethodHandle.class);
--            AccessController.doPrivileged(new PrivilegedAction<Void>() {
--                    @Override
--                    public Void run() {
--                        m.setAccessible(true);
--                        return null;
--                    }
--                });
--            mh = IMPL_LOOKUP.unreflect(m);
--        } catch (ReflectiveOperationException ex) {
--            throw newInternalError(ex);
--        }
--        COLLECT_ARGUMENTS = mh;
--    }
--
-     private static final EnumMap<Wrapper, MethodHandle>[] WRAPPER_CASTS
-             = newWrapperCaches(1);
- 
-@@ -1050,12 +1005,12 @@
-             if (mh == ARRAY_IDENTITY)
-                 mh = rightFiller;
-             else
--                mh = collectArguments(mh, 0, rightFiller);
-+                mh = MethodHandles.collectArguments(mh, 0, rightFiller);
-         }
-         if (mh == ARRAY_IDENTITY)
-             mh = leftCollector;
-         else
--            mh = collectArguments(mh, 0, leftCollector);
-+            mh = MethodHandles.collectArguments(mh, 0, leftCollector);
-         return mh;
-     }
- 
-@@ -1101,7 +1056,7 @@
-         if (midLen == LEFT_ARGS)
-             return rightFill;
-         else
--            return collectArguments(rightFill, 0, midFill);
-+            return MethodHandles.collectArguments(rightFill, 0, midFill);
-     }
- 
-     // Type-polymorphic version of varargs maker.
-diff --git a/test/java/lang/invoke/JavaDocExamplesTest.java b/test/java/lang/invoke/JavaDocExamplesTest.java
---- a/test/java/lang/invoke/JavaDocExamplesTest.java
-+++ b/test/java/lang/invoke/JavaDocExamplesTest.java
-@@ -292,6 +292,28 @@
-             }}
-     }
- 
-+    @Test public void testCollectArguments() throws Throwable {
-+        {{
-+{} /// JAVADOC
-+MethodHandle deepToString = publicLookup()
-+  .findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
-+MethodHandle ts1 = deepToString.asCollector(String[].class, 1);
-+assertEquals("[strange]", (String) ts1.invokeExact("strange"));
-+MethodHandle ts2 = deepToString.asCollector(String[].class, 2);
-+assertEquals("[up, down]", (String) ts2.invokeExact("up", "down"));
-+MethodHandle ts3 = deepToString.asCollector(String[].class, 3);
-+MethodHandle ts3_ts2 = collectArguments(ts3, 1, ts2);
-+assertEquals("[top, [up, down], strange]",
-+             (String) ts3_ts2.invokeExact("top", "up", "down", "strange"));
-+MethodHandle ts3_ts2_ts1 = collectArguments(ts3_ts2, 3, ts1);
-+assertEquals("[top, [up, down], [strange]]",
-+             (String) ts3_ts2_ts1.invokeExact("top", "up", "down", "strange"));
-+MethodHandle ts3_ts2_ts3 = collectArguments(ts3_ts2, 1, ts3);
-+assertEquals("[top, [[up, down, strange], charm], bottom]",
-+             (String) ts3_ts2_ts3.invokeExact("top", "up", "down", "strange", "charm", "bottom"));
-+            }}
-+    }
-+
-     @Test public void testFoldArguments() throws Throwable {
-         {{
- {} /// JAVADOC
-diff --git a/test/java/lang/invoke/MethodHandlesTest.java b/test/java/lang/invoke/MethodHandlesTest.java
---- a/test/java/lang/invoke/MethodHandlesTest.java
-+++ b/test/java/lang/invoke/MethodHandlesTest.java
-@@ -253,6 +253,9 @@
-             args[i] = randomArg(param);
-         return args;
-     }
-+    static Object[] randomArgs(List<Class<?>> params) {
-+        return randomArgs(params.toArray(new Class<?>[params.size()]));
-+    }
- 
-     @SafeVarargs @SuppressWarnings("varargs")
-     static <T, E extends T> T[] array(Class<T[]> atype, E... a) {
-@@ -323,6 +326,11 @@
-         }
-         return list.asType(listType);
-     }
-+    /** Variation of varargsList, but with the given ptypes and rtype. */
-+    static MethodHandle varargsList(List<Class<?>> ptypes, Class<?> rtype) {
-+        MethodHandle list = varargsList(ptypes.size(), rtype);
-+        return list.asType(MethodType.methodType(rtype, ptypes));
-+    }
-     private static MethodHandle LIST_TO_STRING, LIST_TO_INT;
-     private static String listToString(List<?> x) { return x.toString(); }
-     private static int listToInt(List<?> x) { return x.toString().hashCode(); }
-@@ -1783,24 +1791,24 @@
-     }
- 
-     @Test  // SLOW
--    public void testCollectArguments() throws Throwable {
-+    public void testAsCollector() throws Throwable {
-         if (CAN_SKIP_WORKING)  return;
--        startTest("collectArguments");
-+        startTest("asCollector");
-         for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {
-             if (verbosity >= 3)
--                System.out.println("collectArguments "+argType);
-+                System.out.println("asCollector "+argType);
-             for (int nargs = 0; nargs < 50; nargs++) {
-                 if (CAN_TEST_LIGHTLY && nargs > 11)  break;
-                 for (int pos = 0; pos <= nargs; pos++) {
-                     if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2)  continue;
-                     if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)
-                         continue;
--                    testCollectArguments(argType, pos, nargs);
-+                    testAsCollector(argType, pos, nargs);
-                 }
-             }
-         }
-     }
--    public void testCollectArguments(Class<?> argType, int pos, int nargs) throws Throwable {
-+    public void testAsCollector(Class<?> argType, int pos, int nargs) throws Throwable {
-         countTest();
-         // fake up a MH with the same type as the desired adapter:
-         MethodHandle fake = varargsArray(nargs);
-@@ -1947,37 +1955,108 @@
-     }
- 
-     @Test
-+    public void testCollectArguments() throws Throwable {
-+        if (CAN_SKIP_WORKING)  return;
-+        startTest("collectArguments");
-+        testFoldOrCollectArguments(true);
-+    }
-+
-+    @Test
-     public void testFoldArguments() throws Throwable {
-         if (CAN_SKIP_WORKING)  return;
-         startTest("foldArguments");
--        for (int nargs = 0; nargs <= 4; nargs++) {
--            for (int fold = 0; fold <= nargs; fold++) {
--                for (int pos = 0; pos <= nargs; pos++) {
--                    testFoldArguments(nargs, pos, fold);
-+        testFoldOrCollectArguments(false);
-+    }
-+
-+    void testFoldOrCollectArguments(boolean isCollect) throws Throwable {
-+        for (Class<?> lastType : new Class<?>[]{ Object.class, String.class, int.class }) {
-+            for (Class<?> collectType : new Class<?>[]{ Object.class, String.class, int.class, void.class }) {
-+                int maxArity = 10;
-+                if (collectType != String.class)  maxArity = 5;
-+                if (lastType != Object.class)  maxArity = 4;
-+                for (int nargs = 0; nargs <= maxArity; nargs++) {
-+                    ArrayList<Class<?>> argTypes = new ArrayList<>(Collections.nCopies(nargs, Object.class));
-+                    int maxMix = 20;
-+                    if (collectType != Object.class)  maxMix = 0;
-+                    Map<Object,Integer> argTypesSeen = new HashMap<>();
-+                    for (int mix = 0; mix <= maxMix; mix++) {
-+                        if (!mixArgs(argTypes, mix, argTypesSeen))  continue;
-+                        for (int collect = 0; collect <= nargs; collect++) {
-+                            for (int pos = 0; pos <= nargs - collect; pos++) {
-+                                testFoldOrCollectArguments(argTypes, pos, collect, collectType, lastType, isCollect);
-+                            }
-+                        }
-+                    }
-                 }
-             }
-         }
-     }
- 
--    void testFoldArguments(int nargs, int pos, int fold) throws Throwable {
--        if (pos != 0)  return;  // can fold only at pos=0 for now
-+    boolean mixArgs(List<Class<?>> argTypes, int mix, Map<Object,Integer> argTypesSeen) {
-+        assert(mix >= 0);
-+        if (mix == 0)  return true;  // no change
-+        if ((mix >>> argTypes.size()) != 0)  return false;
-+        for (int i = 0; i < argTypes.size(); i++) {
-+            if (i >= 31)  break;
-+            boolean bit = (mix & (1 << i)) != 0;
-+            if (bit) {
-+                Class<?> type = argTypes.get(i);
-+                if (type == Object.class)
-+                    type = String.class;
-+                else if (type == String.class)
-+                    type = int.class;
-+                else
-+                    type = Object.class;
-+                argTypes.set(i, type);
-+            }
-+        }
-+        Integer prev = argTypesSeen.put(new ArrayList<>(argTypes), mix);
-+        if (prev != null) {
-+            if (verbosity >= 4)  System.out.println("mix "+prev+" repeated "+mix+": "+argTypes);
-+            return false;
-+        }
-+        if (verbosity >= 3)  System.out.println("mix "+mix+" = "+argTypes);
-+        return true;
-+    }
-+
-+    void testFoldOrCollectArguments(List<Class<?>> argTypes,  // argument types minus the inserted combineType
-+                                    int pos, int fold, // position and length of the folded arguments
-+                                    Class<?> combineType, // type returned from the combiner
-+                                    Class<?> lastType,  // type returned from the target
-+                                    boolean isCollect) throws Throwable {
-+        int nargs = argTypes.size();
-+        if (pos != 0 && !isCollect)  return;  // can fold only at pos=0 for now
-         countTest();
--        MethodHandle target = varargsList(1 + nargs);
--        MethodHandle combine = varargsList(fold).asType(MethodType.genericMethodType(fold));
--        List<Object> argsToPass = Arrays.asList(randomArgs(nargs, Object.class));
-+        List<Class<?>> combineArgTypes = argTypes.subList(pos, pos + fold);
-+        List<Class<?>> targetArgTypes = new ArrayList<>(argTypes);
-+        if (isCollect)  // does targret see arg[pos..pos+cc-1]?
-+            targetArgTypes.subList(pos, pos + fold).clear();
-+        if (combineType != void.class)
-+            targetArgTypes.add(pos, combineType);
-+        MethodHandle target = varargsList(targetArgTypes, lastType);
-+        MethodHandle combine = varargsList(combineArgTypes, combineType);
-+        List<Object> argsToPass = Arrays.asList(randomArgs(argTypes));
-         if (verbosity >= 3)
--            System.out.println("fold "+target+" with "+combine);
--        MethodHandle target2 = MethodHandles.foldArguments(target, combine);
-+            System.out.println((isCollect ? "collect" : "fold")+" "+target+" with "+combine);
-+        MethodHandle target2;
-+        if (isCollect)
-+            target2 = MethodHandles.collectArguments(target, pos, combine);
-+        else
-+            target2 = MethodHandles.foldArguments(target, combine);
-         // Simulate expected effect of combiner on arglist:
--        List<Object> expected = new ArrayList<>(argsToPass);
--        List<Object> argsToFold = expected.subList(pos, pos + fold);
-+        List<Object> expectedList = new ArrayList<>(argsToPass);
-+        List<Object> argsToFold = expectedList.subList(pos, pos + fold);
-         if (verbosity >= 3)
--            System.out.println("fold: "+argsToFold+" into "+target2);
-+            System.out.println((isCollect ? "collect" : "fold")+": "+argsToFold+" into "+target2);
-         Object foldedArgs = combine.invokeWithArguments(argsToFold);
--        argsToFold.add(0, foldedArgs);
-+        if (isCollect)
-+            argsToFold.clear();
-+        if (combineType != void.class)
-+            argsToFold.add(0, foldedArgs);
-         Object result = target2.invokeWithArguments(argsToPass);
-         if (verbosity >= 3)
-             System.out.println("result: "+result);
-+        Object expected = target.invokeWithArguments(expectedList);
-         if (!expected.equals(result))
-             System.out.println("*** fail at n/p/f = "+nargs+"/"+pos+"/"+fold+": "+argsToPass+" => "+result+" != "+expected);
-         assertEquals(expected, result);
--- a/meth-counts.patch	Sun Sep 15 17:15:12 2013 -0700
+++ b/meth-counts.patch	Sun Oct 06 22:41:41 2013 -0700
@@ -28,7 +28,19 @@
      //
      // BMH API and internals
      //
-@@ -860,4 +876,13 @@
+@@ -586,8 +602,9 @@
+         static Class<? extends BoundMethodHandle> generateConcreteBMHClass(String types) {
+             final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
+ 
+-            final String className  = SPECIES_PREFIX_PATH + types;
+-            final String sourceFile = SPECIES_PREFIX_NAME + types;
++            String shortTypes = LambdaForm.shortenSignature(types);
++            final String className  = SPECIES_PREFIX_PATH + shortTypes;
++            final String sourceFile = SPECIES_PREFIX_NAME + shortTypes;
+             cw.visit(V1_6, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, className, null, BMH, null);
+             cw.visitSource(sourceFile, null);
+ 
+@@ -861,4 +878,13 @@
       * All subclasses must provide such a value describing their type signature.
       */
      static final SpeciesData SPECIES_DATA = SpeciesData.EMPTY;
@@ -53,6 +65,15 @@
      }
  
      // Factory methods:
+@@ -274,7 +275,7 @@
+             result = NEW_OBJ;
+         }
+         names[LINKER_CALL] = new Name(linker, outArgs);
+-        lambdaName += "_" + LambdaForm.basicTypeSignature(mtype);
++        lambdaName += "_" + shortenSignature(basicTypeSignature(mtype));
+         LambdaForm lform = new LambdaForm(lambdaName, ARG_LIMIT, names, result);
+         // This is a tricky bit of code.  Don't send it through the LF interpreter.
+         lform.compileToBytecode();
 @@ -665,6 +666,9 @@
          return new LambdaForm(lambdaName, ARG_LIMIT, names, RESULT);
      }
@@ -60,13 +81,37 @@
 +    // Event counters
 +    private static final EventCounter EC_methodHandle_direct = eventCounter(EC_methodHandle, "direct");
 +
-     private static final NamedFunction
-             NF_internalMemberName,
-             NF_internalMemberNameEnsureInit,
+     /**
+      * Pre-initialized NamedFunctions for bootstrapping purposes.
+      * Factored in an inner class to delay initialization until first usage.
+diff --git a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
+--- a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
++++ b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
+@@ -26,8 +26,8 @@
+ package java.lang.invoke;
+ 
+ import sun.invoke.util.VerifyAccess;
+-import java.lang.invoke.LambdaForm.Name;
+ import java.lang.invoke.MethodHandles.Lookup;
++import static java.lang.invoke.LambdaForm.*;
+ 
+ import sun.invoke.util.Wrapper;
+ 
+@@ -959,8 +959,8 @@
+      * Generate bytecode for a NamedFunction invoker.
+      */
+     static MemberName generateNamedFunctionInvoker(MethodTypeForm typeForm) {
+-        MethodType invokerType = LambdaForm.NamedFunction.INVOKER_METHOD_TYPE;
+-        String invokerName = basicTypeCharSignature("invoke_", typeForm.erasedType());
++        MethodType invokerType = NamedFunction.INVOKER_METHOD_TYPE;
++        String invokerName = "invoke_" + shortenSignature(basicTypeSignature(typeForm.erasedType()));
+         InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("NFI", invokerName, invokerType);
+         return g.loadMethod(g.generateNamedFunctionInvokerImpl(typeForm));
+     }
 diff --git a/src/share/classes/java/lang/invoke/Invokers.java b/src/share/classes/java/lang/invoke/Invokers.java
 --- a/src/share/classes/java/lang/invoke/Invokers.java
 +++ b/src/share/classes/java/lang/invoke/Invokers.java
-@@ -358,6 +358,11 @@
+@@ -360,6 +360,11 @@
      Object checkGenericType(Object mhObj, Object expectedObj) {
          MethodHandle mh = (MethodHandle) mhObj;
          MethodType expected = (MethodType) expectedObj;
@@ -78,7 +123,7 @@
          if (mh.type() == expected)  return mh;
          MethodHandle atc = mh.asTypeCache;
          if (atc != null && atc.type() == expected)  return atc;
-@@ -390,6 +395,10 @@
+@@ -392,6 +397,10 @@
          LambdaForm lform = callSiteForm(mtype, true);
          return lform.vmentry;
      }
@@ -92,9 +137,12 @@
 diff --git a/src/share/classes/java/lang/invoke/LambdaForm.java b/src/share/classes/java/lang/invoke/LambdaForm.java
 --- a/src/share/classes/java/lang/invoke/LambdaForm.java
 +++ b/src/share/classes/java/lang/invoke/LambdaForm.java
-@@ -138,6 +138,7 @@
+@@ -136,8 +136,9 @@
+         this.arity = arity;
+         this.result = fixResult(result, names);
          this.names = names.clone();
-         this.debugName = debugName;
+-        this.debugName = debugName;
++        this.debugName = fixDebugName(debugName);
          normalize();
 +        bump(EC_lambdaForm);
      }
@@ -109,7 +157,46 @@
      }
  
      private static Name[] buildEmptyNames(int arity, String basicTypeSignature) {
-@@ -441,6 +444,10 @@
+@@ -199,6 +202,38 @@
+         return result;
+     }
+ 
++    private static String fixDebugName(String debugName) {
++        if (DEBUG_NAME_COUNTERS != null) {
++            int under = debugName.indexOf('_');
++            int length = debugName.length();
++            if (under < 0)  under = length;
++            String debugNameStem = debugName.substring(0, under);
++            Integer ctr;
++            synchronized (DEBUG_NAME_COUNTERS) {
++                ctr = DEBUG_NAME_COUNTERS.get(debugNameStem);
++                if (ctr == null)  ctr = 0;
++                DEBUG_NAME_COUNTERS.put(debugNameStem, ctr+1);
++            }
++            StringBuilder buf = new StringBuilder(debugNameStem);
++            buf.append('_');
++            int leadingZero = buf.length();
++            buf.append((int) ctr);
++            for (int i = buf.length() - leadingZero; i < 3; i++)
++                buf.insert(leadingZero, '0');
++            if (under < length) {
++                ++under;    // skip "_"
++                while (under < length && Character.isDigit(debugName.charAt(under))) {
++                    ++under;
++                }
++                if (under < length && debugName.charAt(under) == '_')  ++under;
++                if (under < length)
++                    buf.append('_').append(debugName, under, length);
++            }
++            return buf.toString();
++        }
++        return debugName;
++    }
++
+     private static boolean namesOK(int arity, Name[] names) {
+         for (int i = 0; i < names.length; i++) {
+             Name n = names[i];
+@@ -441,6 +476,10 @@
          LambdaForm prep = getPreparedForm(basicTypeSignature());
          this.vmentry = prep.vmentry;
          // TO DO: Maybe add invokeGeneric, invokeWithArguments
@@ -120,23 +207,23 @@
      }
  
      /** Generate optimizable bytecode for this form. */
-@@ -455,6 +462,7 @@
-             if (TRACE_INTERPRETER && INIT_DONE)
+@@ -455,6 +494,7 @@
+             if (TRACE_INTERPRETER)
                  traceInterpreter("compileToBytecode", this);
              isCompiled = true;
 +            bump(EC_lambdaForm_comp);
              return vmentry;
          } catch (Error | Exception ex) {
              throw newInternalError("compileToBytecode", ex);
-@@ -595,6 +603,7 @@
+@@ -595,6 +635,7 @@
      @DontInline
      /** Interpretively invoke this form on the given arguments. */
      Object interpretWithArguments(Object... argumentValues) throws Throwable {
 +        bump(EC_lambdaForm_interp);
-         if (TRACE_INTERPRETER && INIT_DONE)
+         if (TRACE_INTERPRETER)
              return interpretWithArgumentsTracing(argumentValues);
          checkInvocationCounter();
-@@ -981,7 +990,9 @@
+@@ -982,7 +1023,9 @@
              this.member = member;
              //resolvedHandle = eraseSubwordTypes(resolvedHandle);
              this.resolvedHandle = resolvedHandle;
@@ -146,7 +233,7 @@
          NamedFunction(MethodType basicInvokerType) {
              assert(basicInvokerType == basicInvokerType.basicType()) : basicInvokerType;
              if (basicInvokerType.parameterSlotCount() < MethodType.MAX_MH_INVOKER_ARITY) {
-@@ -1134,6 +1145,7 @@
+@@ -1135,6 +1178,7 @@
              if (mh2 != null)  return mh2;  // benign race
              if (!mh.type().equals(INVOKER_METHOD_TYPE))
                  throw new InternalError(mh.debugString());
@@ -154,15 +241,72 @@
              return typeForm.namedFunctionInvoker = mh;
          }
  
-@@ -1141,6 +1153,7 @@
+@@ -1142,6 +1186,7 @@
          Object invokeWithArguments(Object... arguments) throws Throwable {
              // If we have a cached invoker, call it right away.
              // NOTE: The invoker always returns a reference value.
 +            bump(EC_lambdaForm_interp_name);
-             if (TRACE_INTERPRETER && INIT_DONE)  return invokeWithArgumentsTracing(arguments);
+             if (TRACE_INTERPRETER)  return invokeWithArgumentsTracing(arguments);
              assert(checkArgumentTypes(arguments, methodType()));
              return invoker().invokeBasic(resolvedHandle(), arguments);
-@@ -1580,12 +1593,6 @@
+@@ -1273,6 +1318,56 @@
+         assert(sigp == sig.length);
+         return String.valueOf(sig);
+     }
++    public static String shortenSignature(String signature) {
++        // Hack to make signatures more readable when they show up in method names.
++        final int NO_CHAR = -1, MIN_RUN = 3;
++        int c0, c1 = NO_CHAR, c1reps = 0;
++        StringBuilder buf = null;
++        int len = signature.length();
++        if (len < MIN_RUN)  return signature;
++        for (int i = 0; i <= len; i++) {
++            // shift in the next char:
++            c0 = c1; c1 = (i == len ? NO_CHAR : signature.charAt(i));
++            if (c1 == c0) { ++c1reps; continue; }
++            // shift in the next count:
++            int c0reps = c1reps; c1reps = 1;
++            // end of a  character run
++            if (c0reps < MIN_RUN) {
++                if (buf != null) {
++                    while (--c0reps >= 0)
++                        buf.append((char)c0);
++                }
++                continue;
++            }
++            // found three or more in a row
++            if (buf == null)
++                buf = new StringBuilder().append(signature, 0, i - c0reps);
++            buf.append((char)c0).append(c0reps);
++        }
++        return (buf == null) ? signature : buf.toString();
++    }
++    static void testShortenSignature() {
++        for (String s : new String[] {
++                // invariant strings:
++                "L", "LL", "ILL", "LIL", "LLI", "IILL", "ILIL", "ILLI",
++                // a few mappings:
++                "LLL=L3", "LLLL=L4", "LLLLLLLLLL=L10",
++                "IIIDDD=I3D3", "IDDD=ID3", "IIDDD=IID3", "IIID=I3D", "IIIDD=I3DD"
++            }) {
++            String s2 = s.substring(s.indexOf('=')+1);
++            String s1 = s.equals(s2) ? s : s.substring(0, s.length() - s2.length() - 1);
++            // mix the above cases with before and after reps of Z*
++            for (int k = -3; k <= 3; k++) {
++                String beg = (k < 0 ? "ZZZZ".substring(-k) : "");
++                String end = (k > 0 ? "ZZZZ".substring(+k) : "");
++                String ks1 = beg+s1+end;
++                String ks2 = shortenSignature(beg)+s2+shortenSignature(end);
++                String ks3 = shortenSignature(ks1);
++                if (!ks3.equals(ks2)) System.out.println(Arrays.asList(ks1, ks2, ks3));
++                assert(ks3.equals(ks2)) : Arrays.asList(ks1, ks2, ks3);
++            }
++        }
++    }
+ 
+     static final class Name {
+         final char type;
+@@ -1579,12 +1674,6 @@
      private static double zeroD() { return 0; }
      private static Object zeroL() { return null; }
  
@@ -175,7 +319,7 @@
      /**
       * Internal marker for byte-compiled LambdaForms.
       */
-@@ -1635,6 +1642,19 @@
+@@ -1634,7 +1723,28 @@
      static final native Object linkToInterface(Object x1, MemberName mn) throws Throwable;
   */
  
@@ -188,18 +332,27 @@
 +    private static final EventCounter EC_lambdaForm_interp_name = eventCounter(EC_lambdaForm_interp, "name");
 +    private static final EventCounter EC_lambdaForm_invoker = eventCounter(EC_lambdaForm, "invoker");
 +
++    private static final HashMap<String,Integer> DEBUG_NAME_COUNTERS;
++    static {
++        if (debugEnabled())
++            DEBUG_NAME_COUNTERS = new HashMap<>();
++        else
++            DEBUG_NAME_COUNTERS = null;
++    }
++
 +    // Put this last, so that previous static inits can run before.
 +    static {
 +        if (USE_PREDEFINED_INTERPRET_METHODS)
 +            PREPARED_FORMS.putAll(computeInitialPreparedForms());
 +        NamedFunction.initializeInvokers();
 +    }
-     static final boolean INIT_DONE = Boolean.TRUE.booleanValue();
- }
+ 
+     // The following hack is necessary in order to suppress TRACE_INTERPRETER
+     // during execution of the static initializes of this class.
 diff --git a/src/share/classes/java/lang/invoke/MemberName.java b/src/share/classes/java/lang/invoke/MemberName.java
 --- a/src/share/classes/java/lang/invoke/MemberName.java
 +++ b/src/share/classes/java/lang/invoke/MemberName.java
-@@ -448,6 +448,15 @@
+@@ -474,6 +474,15 @@
                                                 lookupClass, ALL_ACCESS|MethodHandles.Lookup.PACKAGE);
      }
  
@@ -215,15 +368,15 @@
      /** Initialize a query.   It is not resolved. */
      private void init(Class<?> defClass, String name, Object type, int flags) {
          // defining class is allowed to be null (for a naked name/type pair)
-@@ -467,6 +476,7 @@
-         if (!isResolved())  return;
-         if (type instanceof Object[])
-             type = null;  // don't saddle JVM w/ typeInfo
+@@ -500,6 +509,7 @@
+         if (!isResolved()) {
+             return;
+         }
 +        bump(EC_natives_expand);
          MethodHandleNatives.expand(this);
      }
  
-@@ -485,6 +495,7 @@
+@@ -518,6 +528,7 @@
      public MemberName(Method m, boolean wantSpecial) {
          m.getClass();  // NPE check
          // fill in vmtarget, vmindex while we have m in hand:
@@ -231,7 +384,7 @@
          MethodHandleNatives.init(this, m);
          if (clazz == null) {  // MHN.init failed
              if (m.getDeclaringClass() == MethodHandle.class &&
-@@ -553,6 +564,7 @@
+@@ -597,6 +608,7 @@
      public MemberName(Constructor<?> ctor) {
          ctor.getClass();  // NPE check
          // fill in vmtarget, vmindex while we have ctor in hand:
@@ -239,7 +392,7 @@
          MethodHandleNatives.init(this, ctor);
          assert(isResolved() && this.clazz != null);
          this.name = CONSTRUCTOR_NAME;
-@@ -568,6 +580,7 @@
+@@ -612,6 +624,7 @@
      public MemberName(Field fld, boolean makeSetter) {
          fld.getClass();  // NPE check
          // fill in vmtarget, vmindex while we have fld in hand:
@@ -247,7 +400,7 @@
          MethodHandleNatives.init(this, fld);
          assert(isResolved() && this.clazz != null);
          this.name = fld.getName();
-@@ -872,6 +885,7 @@
+@@ -914,6 +927,7 @@
              ArrayList<MemberName[]> bufs = null;
              int bufCount = 0;
              for (;;) {
@@ -255,7 +408,7 @@
                  bufCount = MethodHandleNatives.getMembers(defc,
                          matchName, matchSig, matchFlags,
                          lookupClass,
-@@ -920,6 +934,7 @@
+@@ -962,6 +976,7 @@
              MemberName m = ref.clone();  // JVM will side-effect the ref
              assert(refKind == m.getReferenceKind());
              try {
@@ -275,7 +428,7 @@
  
  /**
   * A method handle is a typed, directly executable reference to an underlying method,
-@@ -445,6 +443,7 @@
+@@ -461,6 +459,7 @@
          this.form = form;
  
          form.prepare();  // TO DO:  Try to delay this step until just before invocation.
@@ -283,7 +436,7 @@
      }
  
      /**
-@@ -715,7 +714,7 @@
+@@ -731,7 +730,7 @@
       * <li>If the return type <em>T0</em> is void and <em>T1</em> a primitive,
       *     a zero value is introduced.
       * </ul>
@@ -292,7 +445,7 @@
       * because neither corresponds specifically to the <em>dynamic type</em> of any
       * actual argument or return value.)
       * <p>
-@@ -741,6 +740,7 @@
+@@ -757,6 +756,7 @@
       * @see MethodHandles#explicitCastArguments
       */
      public MethodHandle asType(MethodType newType) {
@@ -300,7 +453,7 @@
          // Fast path alternative to a heavyweight {@code asType} call.
          // Return 'this' if the conversion will be a no-op.
          if (newType == type) {
-@@ -839,6 +839,7 @@
+@@ -867,6 +867,7 @@
       * @see #asCollector
       */
      public MethodHandle asSpreader(Class<?> arrayType, int arrayLength) {
@@ -308,7 +461,7 @@
          asSpreaderChecks(arrayType, arrayLength);
          int spreadArgPos = type.parameterCount() - arrayLength;
          return MethodHandleImpl.makeSpreadArguments(this, arrayType, spreadArgPos, arrayLength);
-@@ -953,6 +954,7 @@
+@@ -983,6 +984,7 @@
       * @see #asVarargsCollector
       */
      public MethodHandle asCollector(Class<?> arrayType, int arrayLength) {
@@ -316,7 +469,7 @@
          asCollectorChecks(arrayType, arrayLength);
          int collectArgPos = type().parameterCount()-1;
          MethodHandle target = this;
-@@ -1125,6 +1127,7 @@
+@@ -1155,6 +1157,7 @@
       * @see #asFixedArity
       */
      public MethodHandle asVarargsCollector(Class<?> arrayType) {
@@ -324,7 +477,7 @@
          Class<?> arrayElement = arrayType.getComponentType();
          boolean lastMatch = asCollectorChecks(arrayType, 0);
          if (isVarargsCollector() && lastMatch)
-@@ -1227,6 +1230,7 @@
+@@ -1257,6 +1260,7 @@
       * @see MethodHandles#insertArguments
       */
      public MethodHandle bindTo(Object x) {
@@ -332,7 +485,7 @@
          Class<?> ptype;
          @SuppressWarnings("LocalVariableHidesMemberVariable")
          MethodType type = type();
-@@ -1468,4 +1472,11 @@
+@@ -1502,4 +1506,11 @@
              throw newInternalError(ex);
          }
      }
@@ -371,16 +524,16 @@
          }
  
          @Override MethodHandle reinvokerTarget() { return target; }
-@@ -965,6 +968,7 @@
-             super(type, reinvokerForm(target));
+@@ -971,6 +974,7 @@
              this.target = target;
              this.member = member;
+             this.callerClass = callerClass;
 +            bump(EC_methodHandle_wrappedMember);
          }
  
          @Override
-@@ -997,4 +1001,9 @@
-         return new WrappedMember(target, target.type(), member);
+@@ -1007,4 +1011,9 @@
+         return new WrappedMember(target, target.type(), member, null);
      }
  
 +    // Event counters
@@ -401,7 +554,7 @@
  
      // All compile-time constants go here.
      // There is an opportunity to check them against the JVM's idea of them.
-@@ -301,6 +301,25 @@
+@@ -289,6 +289,25 @@
                                     Object nameObj, Object typeObj,
                                     Object staticArguments,
                                     Object[] appendixResult) {
@@ -427,7 +580,7 @@
          MethodHandle bootstrapMethod = (MethodHandle)bootstrapMethodObj;
          Class<?> caller = (Class<?>)callerObj;
          String name = nameObj.toString().intern();
-@@ -311,6 +330,7 @@
+@@ -299,6 +318,7 @@
                                                staticArguments,
                                                caller);
          if (callSite instanceof ConstantCallSite) {
@@ -435,7 +588,7 @@
              appendixResult[0] = callSite.dynamicInvoker();
              return Invokers.linkToTargetMethod(type);
          } else {
-@@ -323,6 +343,7 @@
+@@ -311,6 +331,7 @@
       * The JVM wants a pointer to a MethodType.  Oblige it by finding or creating one.
       */
      static MethodType findMethodHandleType(Class<?> rtype, Class<?>[] ptypes) {
@@ -443,18 +596,18 @@
          return MethodType.makeImpl(rtype, ptypes, true);
      }
  
-@@ -407,8 +428,10 @@
+@@ -393,6 +414,10 @@
+                                      Object[] appendixResult) {
+         try {
              if (defc == MethodHandle.class && refKind == REF_invokeVirtual) {
-                 switch (name) {
-                 case "invoke":
-+                    bump(EC_link_invokeGeneric);
-                     return Invokers.genericInvokeLinkerMethod(fixMethodType(callerClass, type), appendixResult);
-                 case "invokeExact":
-+                    bump(EC_link_invokeExact);
-                     return Invokers.exactInvokeLinkerMethod(fixMethodType(callerClass, type), appendixResult);
-                 }
++                 switch (name) {
++                 case "invoke":          bump(EC_link_invokeGeneric);  break;
++                 case "invokeExact":     bump(EC_link_invokeExact);    break;
++                 }
+                 return Invokers.methodHandleInvokeLinkerMethod(name, fixMethodType(callerClass, type), appendixResult);
              }
-@@ -453,6 +476,7 @@
+         } catch (Throwable ex) {
+@@ -436,6 +461,7 @@
       */
      static MethodHandle linkMethodHandleConstant(Class<?> callerClass, int refKind,
                                                   Class<?> defc, String name, Object type) {
@@ -462,7 +615,7 @@
          try {
              Lookup lookup = IMPL_LOOKUP.in(callerClass);
              assert(refKindIsValid(refKind));
-@@ -494,4 +518,19 @@
+@@ -497,4 +523,19 @@
          return (definingClass.isAssignableFrom(symbolicRefClass) ||  // Msym overrides Mdef
                  symbolicRefClass.isInterface());                     // Mdef implements Msym
      }
@@ -485,16 +638,17 @@
 diff --git a/src/share/classes/java/lang/invoke/MethodHandleStatics.java b/src/share/classes/java/lang/invoke/MethodHandleStatics.java
 --- a/src/share/classes/java/lang/invoke/MethodHandleStatics.java
 +++ b/src/share/classes/java/lang/invoke/MethodHandleStatics.java
-@@ -28,6 +28,8 @@
+@@ -28,6 +28,9 @@
  import java.security.AccessController;
  import java.security.PrivilegedAction;
  import sun.misc.Unsafe;
 +import java.io.PrintStream;
 +import java.util.ArrayList;
++import java.util.Collections;
  
  /**
   * This class consists exclusively of static names internal to the
-@@ -45,16 +47,18 @@
+@@ -45,16 +48,18 @@
      static final boolean DUMP_CLASS_FILES;
      static final boolean TRACE_INTERPRETER;
      static final boolean TRACE_METHOD_LINKAGE;
@@ -515,17 +669,28 @@
                      return null;
                  }
              });
-@@ -62,7 +66,8 @@
+@@ -62,7 +67,19 @@
          DUMP_CLASS_FILES          = (Boolean) values[1];
          TRACE_INTERPRETER         = (Boolean) values[2];
          TRACE_METHOD_LINKAGE      = (Boolean) values[3];
 -        COMPILE_THRESHOLD         = (Integer) values[4];
 +        COUNT_EVENTS              = (Boolean) values[4];
 +        COMPILE_THRESHOLD         = (Integer) values[5];
++    }
++
++    /** Tell if any of the debugging switches are turned on.
++     *  If this is the case, it is reasonable to perform extra checks or save extra information.
++     */
++    static boolean debugEnabled() {
++        return (DEBUG_METHOD_HANDLE_NAMES |
++                DUMP_CLASS_FILES |
++                TRACE_INTERPRETER |
++                TRACE_METHOD_LINKAGE |
++                COUNT_EVENTS);
      }
  
      /*non-public*/ static String getNameString(MethodHandle target, MethodType type) {
-@@ -128,4 +133,136 @@
+@@ -128,4 +145,142 @@
          if (obj != null || obj2 != null)  message = message + ": " + obj + ", " + obj2;
          return message;
      }
@@ -559,7 +724,7 @@
 +        if (!COUNT_EVENTS)  return;
 +        ec.bump();
 +    }
-+    static class EventCounter {
++    static class EventCounter implements Comparable<EventCounter> {
 +        final String name;
 +        final boolean autoSum;
 +        final EventCounter sup;  // used for toString
@@ -573,11 +738,17 @@
 +            for (EventCounter ec : ecs) {
 +                if (name.equals(ec.name))  throw new IllegalArgumentException("duplicate: "+ec);
 +            }
-+            ecs.add(this);
++            synchronized (EventCounter.class) {
++                ecs.add(this);
++                Collections.sort(ecs);  // keep in order
++            }
 +        }
 +        public String toString() {
 +            return (sup == null ? "EventCounter:"+name : sup+"."+name);
 +        }
++        public int compareTo(EventCounter that) {
++            return this.name.compareTo(that.name);
++        }
 +        long count() {
 +            if (autoSum && count == 0) {
 +                for (EventCounter ec : subs) {
@@ -665,7 +836,7 @@
 diff --git a/src/share/classes/java/lang/invoke/MethodHandles.java b/src/share/classes/java/lang/invoke/MethodHandles.java
 --- a/src/share/classes/java/lang/invoke/MethodHandles.java
 +++ b/src/share/classes/java/lang/invoke/MethodHandles.java
-@@ -75,6 +75,7 @@
+@@ -87,6 +87,7 @@
       */
      @CallerSensitive
      public static Lookup lookup() {
@@ -673,7 +844,7 @@
          return new Lookup(Reflection.getCallerClass());
      }
  
-@@ -93,6 +94,7 @@
+@@ -111,6 +112,7 @@
       * @return a lookup object which is trusted minimally
       */
      public static Lookup publicLookup() {
@@ -681,7 +852,7 @@
          return Lookup.PUBLIC_LOOKUP;
      }
  
-@@ -119,6 +121,7 @@
+@@ -138,6 +140,7 @@
       */
      public static <T extends Member> T
      reflectAs(Class<T> expected, MethodHandle target) {
@@ -689,7 +860,7 @@
          SecurityManager smgr = System.getSecurityManager();
          if (smgr != null)  smgr.checkPermission(ACCESS_PERMISSION);
          Lookup lookup = Lookup.IMPL_LOOKUP;  // use maximally privileged lookup
-@@ -493,6 +496,7 @@
+@@ -630,6 +633,7 @@
           * @throws NullPointerException if the argument is null
           */
          public Lookup in(Class<?> requestedLookupClass) {
@@ -697,15 +868,15 @@
              requestedLookupClass.getClass();  // null check
              if (allowedModes == TRUSTED)  // IMPL_LOOKUP can make any lookup at all
                  return new Lookup(requestedLookupClass, ALL_MODES);
-@@ -615,6 +619,7 @@
+@@ -762,6 +766,7 @@
           */
          public
          MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
 +            bump(EC_lookup_findStatic);
              MemberName method = resolveOrFail(REF_invokeStatic, refc, name, type);
-             checkSecurityManager(refc, method);
              return getDirectMethod(REF_invokeStatic, refc, method, findBoundCallerClass(method));
-@@ -664,6 +669,7 @@
+         }
+@@ -838,6 +843,7 @@
           * @throws NullPointerException if any argument is null
           */
          public MethodHandle findVirtual(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
@@ -713,15 +884,15 @@
              if (refc == MethodHandle.class) {
                  MethodHandle mh = findVirtualForMH(name, type);
                  if (mh != null)  return mh;
-@@ -710,6 +716,7 @@
+@@ -902,6 +908,7 @@
           * @throws NullPointerException if any argument is null
           */
          public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException {
 +            bump(EC_lookup_findConstructor);
              String name = "<init>";
              MemberName ctor = resolveOrFail(REF_newInvokeSpecial, refc, name, type);
-             checkSecurityManager(refc, ctor);
-@@ -752,6 +759,7 @@
+             return getDirectConstructor(refc, ctor);
+@@ -981,6 +988,7 @@
           */
          public MethodHandle findSpecial(Class<?> refc, String name, MethodType type,
                                          Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException {
@@ -729,47 +900,47 @@
              checkSpecialCaller(specialCaller);
              Lookup specialLookup = this.in(specialCaller);
              MemberName method = specialLookup.resolveOrFail(REF_invokeSpecial, refc, name, type);
-@@ -777,6 +785,7 @@
+@@ -1005,6 +1013,7 @@
           * @throws NullPointerException if any argument is null
           */
          public MethodHandle findGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
 +            bump(EC_lookup_findGetter);
              MemberName field = resolveOrFail(REF_getField, refc, name, type);
-             checkSecurityManager(refc, field);
              return getDirectField(REF_getField, refc, field);
-@@ -800,6 +809,7 @@
+         }
+@@ -1027,6 +1036,7 @@
           * @throws NullPointerException if any argument is null
           */
          public MethodHandle findSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
 +            bump(EC_lookup_findSetter);
              MemberName field = resolveOrFail(REF_putField, refc, name, type);
-             checkSecurityManager(refc, field);
              return getDirectField(REF_putField, refc, field);
-@@ -822,6 +832,7 @@
+         }
+@@ -1051,6 +1061,7 @@
           * @throws NullPointerException if any argument is null
           */
          public MethodHandle findStaticGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
 +            bump(EC_lookup_findStaticGetter);
              MemberName field = resolveOrFail(REF_getStatic, refc, name, type);
-             checkSecurityManager(refc, field);
              return getDirectField(REF_getStatic, refc, field);
-@@ -844,6 +855,7 @@
+         }
+@@ -1075,6 +1086,7 @@
           * @throws NullPointerException if any argument is null
           */
          public MethodHandle findStaticSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
 +            bump(EC_lookup_findStaticSetter);
              MemberName field = resolveOrFail(REF_putStatic, refc, name, type);
-             checkSecurityManager(refc, field);
              return getDirectField(REF_putStatic, refc, field);
-@@ -896,6 +908,7 @@
-          * @throws NullPointerException if any argument is null
+         }
+@@ -1128,6 +1140,7 @@
+          * @see #findVirtual
           */
          public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
 +            bump(EC_lookup_bind);
              Class<? extends Object> refc = receiver.getClass(); // may get NPE
              MemberName method = resolveOrFail(REF_invokeSpecial, refc, name, type);
-             checkSecurityManager(refc, method);
-@@ -925,6 +938,7 @@
+             MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method, findBoundCallerClass(method));
+@@ -1161,6 +1174,7 @@
           * @throws NullPointerException if the argument is null
           */
          public MethodHandle unreflect(Method m) throws IllegalAccessException {
@@ -777,7 +948,7 @@
              if (m.getDeclaringClass() == MethodHandle.class) {
                  MethodHandle mh = unreflectForMH(m);
                  if (mh != null)  return mh;
-@@ -966,6 +980,7 @@
+@@ -1210,6 +1224,7 @@
           * @throws NullPointerException if any argument is null
           */
          public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws IllegalAccessException {
@@ -785,15 +956,15 @@
              checkSpecialCaller(specialCaller);
              Lookup specialLookup = this.in(specialCaller);
              MemberName method = new MemberName(m, true);
-@@ -997,6 +1012,7 @@
+@@ -1243,6 +1258,7 @@
+          * @throws NullPointerException if the argument is null
           */
-         @SuppressWarnings("rawtypes")  // Will be Constructor<?> after JSR 292 MR
-         public MethodHandle unreflectConstructor(Constructor c) throws IllegalAccessException {
+         public MethodHandle unreflectConstructor(Constructor<?> c) throws IllegalAccessException {
 +            bump(EC_lookup_unreflectConstructor);
              MemberName ctor = new MemberName(c);
              assert(ctor.isConstructor());
              Lookup lookup = c.isAccessible() ? IMPL_LOOKUP : this;
-@@ -1018,6 +1034,7 @@
+@@ -1268,6 +1284,7 @@
           * @throws NullPointerException if the argument is null
           */
          public MethodHandle unreflectGetter(Field f) throws IllegalAccessException {
@@ -801,7 +972,7 @@
              return unreflectField(f, false);
          }
          private MethodHandle unreflectField(Field f, boolean isSetter) throws IllegalAccessException {
-@@ -1044,6 +1061,7 @@
+@@ -1298,6 +1315,7 @@
           * @throws NullPointerException if the argument is null
           */
          public MethodHandle unreflectSetter(Field f) throws IllegalAccessException {
@@ -809,7 +980,7 @@
              return unreflectField(f, true);
          }
  
-@@ -1062,6 +1080,7 @@
+@@ -1320,6 +1338,7 @@
           * @since 1.8
           */
          public MethodHandleInfo revealDirect(MethodHandle target) {
@@ -817,7 +988,7 @@
              MemberName member = target.internalMemberName();
              if (member == null || (!member.isResolved() && !member.isMethodHandleInvoke()))
                  throw newIllegalArgumentException("not a direct method handle");
-@@ -1446,6 +1465,7 @@
+@@ -1782,6 +1801,7 @@
       */
      public static
      MethodHandle arrayElementGetter(Class<?> arrayClass) throws IllegalArgumentException {
@@ -825,7 +996,7 @@
          return MethodHandleImpl.makeArrayElementAccessor(arrayClass, false);
      }
  
-@@ -1461,6 +1481,7 @@
+@@ -1797,6 +1817,7 @@
       */
      public static
      MethodHandle arrayElementSetter(Class<?> arrayClass) throws IllegalArgumentException {
@@ -833,7 +1004,7 @@
          return MethodHandleImpl.makeArrayElementAccessor(arrayClass, true);
      }
  
-@@ -1641,6 +1662,7 @@
+@@ -1987,6 +2008,7 @@
       */
      public static
      MethodHandle explicitCastArguments(MethodHandle target, MethodType newType) {
@@ -841,7 +1012,7 @@
          if (!target.type().isCastableTo(newType)) {
              throw new WrongMethodTypeException("cannot explicitly cast "+target+" to "+newType);
          }
-@@ -1708,6 +1730,7 @@
+@@ -2054,6 +2076,7 @@
       */
      public static
      MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder) {
@@ -849,7 +1020,7 @@
          checkReorder(reorder, newType, target.type());
          return target.permuteArguments(newType, reorder);
      }
-@@ -1752,6 +1775,7 @@
+@@ -2098,6 +2121,7 @@
       */
      public static
      MethodHandle constant(Class<?> type, Object value) {
@@ -857,7 +1028,7 @@
          if (type.isPrimitive()) {
              if (type == void.class)
                  throw newIllegalArgumentException("void type");
-@@ -1771,6 +1795,7 @@
+@@ -2117,6 +2141,7 @@
       */
      public static
      MethodHandle identity(Class<?> type) {
@@ -865,7 +1036,7 @@
          if (type == void.class)
              throw newIllegalArgumentException("void type");
          else if (type == Object.class)
-@@ -1813,6 +1838,7 @@
+@@ -2159,6 +2184,7 @@
       */
      public static
      MethodHandle insertArguments(MethodHandle target, int pos, Object... values) {
@@ -873,7 +1044,7 @@
          int insCount = values.length;
          MethodType oldType = target.type();
          int outargs = oldType.parameterCount();
-@@ -1892,6 +1918,7 @@
+@@ -2238,6 +2264,7 @@
       */
      public static
      MethodHandle dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes) {
@@ -881,7 +1052,7 @@
          MethodType oldType = target.type();  // get NPE
          int dropped = valueTypes.size();
          MethodType.checkSlotCount(dropped);
-@@ -2022,6 +2049,7 @@
+@@ -2371,6 +2398,7 @@
       */
      public static
      MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters) {
@@ -889,15 +1060,15 @@
          MethodType targetType = target.type();
          MethodHandle adapter = target;
          MethodType adapterType = null;
-@@ -2053,6 +2081,7 @@
-     // FIXME: Make this public in M1.
-     /*non-public*/ static
-     MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle collector) {
+@@ -2507,6 +2535,7 @@
+      */
+     public static
+     MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle filter) {
 +        bump(EC_transform_collectArguments);
          MethodType targetType = target.type();
-         MethodType filterType = collector.type();
+         MethodType filterType = filter.type();
          if (filterType.returnType() != void.class &&
-@@ -2120,6 +2149,7 @@
+@@ -2574,6 +2603,7 @@
       */
      public static
      MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter) {
@@ -905,7 +1076,7 @@
          MethodType targetType = target.type();
          MethodType filterType = filter.type();
          Class<?> rtype = targetType.returnType();
-@@ -2211,6 +2241,7 @@
+@@ -2665,6 +2695,7 @@
       */
      public static
      MethodHandle foldArguments(MethodHandle target, MethodHandle combiner) {
@@ -913,7 +1084,7 @@
          int pos = 0;
          MethodType targetType = target.type();
          MethodType combinerType = combiner.type();
-@@ -2267,6 +2298,7 @@
+@@ -2721,6 +2752,7 @@
      MethodHandle guardWithTest(MethodHandle test,
                                 MethodHandle target,
                                 MethodHandle fallback) {
@@ -921,7 +1092,7 @@
          MethodType gtype = test.type();
          MethodType ttype = target.type();
          MethodType ftype = fallback.type();
-@@ -2337,6 +2369,7 @@
+@@ -2791,6 +2823,7 @@
      MethodHandle catchException(MethodHandle target,
                                  Class<? extends Throwable> exType,
                                  MethodHandle handler) {
@@ -929,7 +1100,7 @@
          MethodType ttype = target.type();
          MethodType htype = handler.type();
          if (htype.parameterCount() < 1 ||
-@@ -2371,8 +2404,45 @@
+@@ -2825,8 +2858,45 @@
       */
      public static
      MethodHandle throwException(Class<?> returnType, Class<? extends Throwable> exType) {
--- a/meth-lfc.patch	Sun Sep 15 17:15:12 2013 -0700
+++ b/meth-lfc.patch	Sun Oct 06 22:41:41 2013 -0700
@@ -5,1756 +5,119 @@
 diff --git a/src/share/classes/java/lang/invoke/BoundMethodHandle.java b/src/share/classes/java/lang/invoke/BoundMethodHandle.java
 --- a/src/share/classes/java/lang/invoke/BoundMethodHandle.java
 +++ b/src/share/classes/java/lang/invoke/BoundMethodHandle.java
-@@ -26,7 +26,7 @@
- package java.lang.invoke;
- 
- import static jdk.internal.org.objectweb.asm.Opcodes.*;
--import static java.lang.invoke.LambdaForm.basicTypes;
-+import static java.lang.invoke.LambdaForm.*;
- import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;
- import static java.lang.invoke.MethodHandleStatics.*;
- 
-@@ -71,92 +71,84 @@
-         }
-     }
- 
--    private int fieldCount() { return speciesData().fieldCount(); }
--
-     //
+@@ -75,36 +75,31 @@
      // BMH API and internals
      //
  
--    static MethodHandle bindSingle(MethodType type, LambdaForm form, char xtype, Object x) {
--        // for some type signatures, there exist pre-defined concrete BMH classes
--        try {
--            switch (xtype) {
--            case 'L':
--                if (true)  return bindSingle(type, form, x);  // Use known fast path.
--                return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('L').constructor[0].invokeBasic(type, form, x);
--            case 'I':
--                return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('I').constructor[0].invokeBasic(type, form, ValueConversions.widenSubword(x));
--            case 'J':
--                return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('J').constructor[0].invokeBasic(type, form, (long) x);
--            case 'F':
--                return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('F').constructor[0].invokeBasic(type, form, (float) x);
--            case 'D':
--                return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('D').constructor[0].invokeBasic(type, form, (double) x);
--            default : throw new InternalError("unexpected xtype: " + xtype);
--            }
--        } catch (Throwable t) {
--            throw newInternalError(t);
 +    /*non-public*/
 +    LambdaFormEditor editor() {
 +        return form.editor();
 +    }
 +
-+    @Override // there is a default binder in the super class, for 'L' types only
-+    /*non-public*/
-+    BoundMethodHandle bindArgumentL(int pos, Object value) {
+     @Override // there is a default binder in the super class, for 'L' types only
+     /*non-public*/
+     BoundMethodHandle bindArgumentL(int pos, Object value) {
+-        MethodType type = type().dropParameterTypes(pos, pos+1);
+-        LambdaForm form = internalForm().bind(1+pos, speciesData());
+-        return copyWithExtendL(type, form, value);
 +        return editor().bindArgumentL(this, pos, value);
-+    }
-+    /*non-public*/
-+    BoundMethodHandle bindArgumentI(int pos, int value) {
+     }
+     /*non-public*/
+     BoundMethodHandle bindArgumentI(int pos, int value) {
+-        MethodType type = type().dropParameterTypes(pos, pos+1);
+-        LambdaForm form = internalForm().bind(1+pos, speciesData());
+-        return copyWithExtendI(type, form, value);
 +        return editor().bindArgumentI(this, pos, value);
-+    }
-+    /*non-public*/
-+    BoundMethodHandle bindArgumentJ(int pos, long value) {
+     }
+     /*non-public*/
+     BoundMethodHandle bindArgumentJ(int pos, long value) {
+-        MethodType type = type().dropParameterTypes(pos, pos+1);
+-        LambdaForm form = internalForm().bind(1+pos, speciesData());
+-        return copyWithExtendJ(type, form, value);
 +        return editor().bindArgumentJ(this, pos, value);
-+    }
-+    /*non-public*/
-+    BoundMethodHandle bindArgumentF(int pos, float value) {
+     }
+     /*non-public*/
+     BoundMethodHandle bindArgumentF(int pos, float value) {
+-        MethodType type = type().dropParameterTypes(pos, pos+1);
+-        LambdaForm form = internalForm().bind(1+pos, speciesData());
+-        return copyWithExtendF(type, form, value);
 +        return editor().bindArgumentF(this, pos, value);
-+    }
-+    /*non-public*/
-+    BoundMethodHandle bindArgumentD(int pos, double value) {
+     }
+     /*non-public*/
+     BoundMethodHandle bindArgumentD(int pos, double value) {
+-        MethodType type = type().dropParameterTypes(pos, pos+1);
+-        LambdaForm form = internalForm().bind(1+pos, speciesData());
+-        return copyWithExtendD(type, form, value);
 +        return editor().bindArgumentD(this, pos, value);
-+    }
-+
-+    @Override
-+    BoundMethodHandle rebind() {
-+        if (!tooComplex()) {
-+            return this;
-+        }
-+        bump(EC_methodHandle_rebind_complex);
-+        return makeRebind(this);
-+    }
-+
-+    private boolean tooComplex() {
-+        return (fieldCount() > FIELD_COUNT_THRESHOLD ||
-+                form.expressionCount() > FORM_EXPRESSION_THRESHOLD);
-+    }
-+    private static int FIELD_COUNT_THRESHOLD = 12;  // largest convenient BMH field count
-+    private static int FORM_EXPRESSION_THRESHOLD = 24;  // largest convenient BMH expression count
-+
-+    static BoundMethodHandle makeRebind(MethodHandle target) {
-+        bump(EC_methodHandle_rebind);
-+        LambdaForm form = DelegatingMethodHandle.makeReinvokerForm(
-+                target, MethodTypeForm.LF_REBIND, Species_L.SPECIES_DATA.getterFunction(0) );
-+        return Species_L.make(target.type(), form, target);
-+    }
-+
-+    @Override
-+    void compileToBytecode() {
-+        super.compileToBytecode();
-+        for (int i = 0, len = fieldCount(); i < len; i++) {
-+            Object arg = arg(i);
-+            if (arg instanceof MethodHandle)
-+                ((MethodHandle)arg).compileToBytecode();
+     }
+ 
+     @Override
+diff --git a/src/share/classes/java/lang/invoke/DirectMethodHandle.java b/src/share/classes/java/lang/invoke/DirectMethodHandle.java
+--- a/src/share/classes/java/lang/invoke/DirectMethodHandle.java
++++ b/src/share/classes/java/lang/invoke/DirectMethodHandle.java
+@@ -128,7 +128,9 @@
+ 
+     @Override
+     BoundMethodHandle rebind() {
+-        return BoundMethodHandle.makeReinvoker(this);
++        //return BoundMethodHandle.makeReinvoker(this);
++        LambdaForm newForm = form.editor().bindArgumentForm(0, BoundMethodHandle.SpeciesData.EMPTY);
++        return BoundMethodHandle.bindSingle(type(), newForm, this);
+     }
+ 
+     @Override
+diff --git a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
+--- a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
++++ b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
+@@ -645,6 +645,7 @@
+                 emitStaticInvoke(member, name);
+             } else {
+                 bump(EC_bytecode_invoke_handle);
++                if (true || member == null || member.isMethodHandleInvoke())  Thread.dumpStack(); //@@
+                 emitInvoke(name);
+             }
+ 
+@@ -835,14 +836,33 @@
          }
      }
  
--    static MethodHandle bindSingle(MethodType type, LambdaForm form, Object x) {
--            return new Species_L(type, form, x);
--    }
--
--    MethodHandle cloneExtend(MethodType type, LambdaForm form, char xtype, Object x) {
--        try {
--            switch (xtype) {
--            case 'L': return cloneExtendL(type, form, x);
--            case 'I': return cloneExtendI(type, form, ValueConversions.widenSubword(x));
--            case 'J': return cloneExtendJ(type, form, (long) x);
--            case 'F': return cloneExtendF(type, form, (float) x);
--            case 'D': return cloneExtendD(type, form, (double) x);
--            }
--        } catch (Throwable t) {
--            throw newInternalError(t);
--        }
--        throw new InternalError("unexpected type: " + xtype);
--    }
--
--    @Override
--    MethodHandle bindArgument(int pos, char basicType, Object value) {
--        MethodType type = type().dropParameterTypes(pos, pos+1);
--        LambdaForm form = internalForm().bind(1+pos, speciesData());
--        return cloneExtend(type, form, basicType, value);
--    }
--
--    @Override
--    MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
--        LambdaForm form = internalForm().addArguments(pos, srcType.parameterList().subList(pos, pos+drops));
--        try {
--             return clone(srcType, form);
--         } catch (Throwable t) {
--             throw newInternalError(t);
--         }
--    }
--
--    @Override
--    MethodHandle permuteArguments(MethodType newType, int[] reorder) {
--        try {
--             return clone(newType, form.permuteArguments(1, reorder, basicTypes(newType.parameterList())));
--         } catch (Throwable t) {
--             throw newInternalError(t);
--         }
--    }
--
--    static final String EXTENSION_TYPES = "LIJFD";
--    static final byte INDEX_L = 0, INDEX_I = 1, INDEX_J = 2, INDEX_F = 3, INDEX_D = 4;
--    static byte extensionIndex(char type) {
--        int i = EXTENSION_TYPES.indexOf(type);
--        if (i < 0)  throw new InternalError();
--        return (byte) i;
-+    static BoundMethodHandle bindSingle(MethodType type, LambdaForm form, Object x) {
-+        return Species_L.make(type, form, x);
+-    boolean isNewArray(Class<?> rtype, Name name) {
++    boolean isNewArray(Class<?> rtype, Name name) {//@@
++        boolean z = isNewArray0(rtype, name);
++        if (!z && name.function.member != null && name.function.member.getName().contains("array"))//@@
++            Thread.dumpStack();//@@
++        return z;
++    }
++    boolean isNewArray0(Class<?> rtype, Name name) {
+         return rtype.isArray() &&
+                 isStaticallyNameable(rtype) &&
+-                isArrayBuilder(name.function.resolvedHandle) &&
+-                name.arguments.length > 0;
++                isArrayBuilder(name.function.resolvedHandle);
      }
  
-     /**
-      * Return the {@link SpeciesData} instance representing this BMH species. All subclasses must provide a
-      * static field containing this value, and they must accordingly implement this method.
-      */
--    protected abstract SpeciesData speciesData();
-+    public abstract SpeciesData speciesData();
-+
-+    /**
-+     * Return the number of fields in this BMH.  Equivalent to speciesData().fieldCount().
-+     */
-+    public abstract int fieldCount();
- 
-     @Override
-     final Object internalProperties() {
-@@ -175,42 +167,29 @@
-     public final Object arg(int i) {
-         try {
-             switch (speciesData().fieldType(i)) {
--            case 'L': return argL(i);
--            case 'I': return argI(i);
--            case 'F': return argF(i);
--            case 'D': return argD(i);
--            case 'J': return argJ(i);
-+            case L_TYPE: return          speciesData().getters[i].invokeBasic(this);
-+            case I_TYPE: return (int)    speciesData().getters[i].invokeBasic(this);
-+            case J_TYPE: return (long)   speciesData().getters[i].invokeBasic(this);
-+            case F_TYPE: return (float)  speciesData().getters[i].invokeBasic(this);
-+            case D_TYPE: return (double) speciesData().getters[i].invokeBasic(this);
-             }
-         } catch (Throwable ex) {
-             throw newInternalError(ex);
-         }
--        throw new InternalError("unexpected type: " + speciesData().types+"."+i);
-+        throw new InternalError("unexpected type: " + speciesData().typeChars+"."+i);
-     }
--    public final Object argL(int i) throws Throwable { return          speciesData().getters[i].invokeBasic(this); }
--    public final int    argI(int i) throws Throwable { return (int)    speciesData().getters[i].invokeBasic(this); }
--    public final float  argF(int i) throws Throwable { return (float)  speciesData().getters[i].invokeBasic(this); }
--    public final double argD(int i) throws Throwable { return (double) speciesData().getters[i].invokeBasic(this); }
--    public final long   argJ(int i) throws Throwable { return (long)   speciesData().getters[i].invokeBasic(this); }
- 
-     //
-     // cloning API
-     //
- 
--    public abstract BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable;
--    public abstract BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable;
--    public abstract BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int    narg) throws Throwable;
--    public abstract BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long   narg) throws Throwable;
--    public abstract BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float  narg) throws Throwable;
--    public abstract BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable;
--
--    // The following is a grossly irregular hack:
--    @Override MethodHandle reinvokerTarget() {
--        try {
--            return (MethodHandle) argL(0);
--        } catch (Throwable ex) {
--            throw newInternalError(ex);
--        }
--    }
-+    @Override
-+    public abstract BoundMethodHandle copyWith(MethodType mt, LambdaForm lf);
-+    public abstract BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg);
-+    public abstract BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int    narg);
-+    public abstract BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long   narg);
-+    public abstract BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float  narg);
-+    public abstract BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg);
- 
-     //
-     // concrete BMH classes required to close bootstrap loops
-@@ -219,150 +198,103 @@
-     private  // make it private to force users to access the enclosing class first
-     static final class Species_L extends BoundMethodHandle {
-         final Object argL0;
--        public Species_L(MethodType mt, LambdaForm lf, Object argL0) {
-+        private Species_L(MethodType mt, LambdaForm lf, Object argL0) {
-             super(mt, lf);
-             this.argL0 = argL0;
-         }
--        // The following is a grossly irregular hack:
--        @Override MethodHandle reinvokerTarget() { return (MethodHandle) argL0; }
--        @Override
--        public SpeciesData speciesData() {
--            return SPECIES_DATA;
--        }
--        public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("L", Species_L.class);
--        @Override
--        public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
--            return new Species_L(mt, lf, argL0);
--        }
--        @Override
--        public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
--            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, narg);
--        }
--        @Override
--        public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
--            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, narg);
--        }
--        @Override
--        public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
--            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, narg);
--        }
--        @Override
--        public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
--            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, narg);
--        }
--        @Override
--        public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
--            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, narg);
--        }
--    }
--
--/*
--    static final class Species_LL extends BoundMethodHandle {
--        final Object argL0;
--        final Object argL1;
--        public Species_LL(MethodType mt, LambdaForm lf, Object argL0, Object argL1) {
--            super(mt, lf);
--            this.argL0 = argL0;
--            this.argL1 = argL1;
--        }
-         @Override
-         public SpeciesData speciesData() {
-             return SPECIES_DATA;
-         }
--        public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("LL", Species_LL.class);
-         @Override
--        public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
--            return new Species_LL(mt, lf, argL0, argL1);
-+        public int fieldCount() {
-+            return 1;
+     void emitNewArray(Class<?> rtype, Name name) throws InternalError {
++        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;
 +        }
-+        public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("L", Species_L.class);
-+        public static BoundMethodHandle make(MethodType mt, LambdaForm lf, Object argL0) {
-+            return new Species_L(mt, lf, argL0);
-         }
-         @Override
--        public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
--            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
-+        public final BoundMethodHandle copyWith(MethodType mt, LambdaForm lf) {
-+            return new Species_L(mt, lf, argL0);
-         }
-         @Override
--        public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
--            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
-+        public final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) {
-+            try {
-+                return (BoundMethodHandle) SPECIES_DATA.extendWith(L_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
-+            } catch (Throwable ex) {
-+                throw uncaughtException(ex);
-+            }
-         }
-         @Override
--        public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
--            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
-+        public final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) {
-+            try {
-+                return (BoundMethodHandle) SPECIES_DATA.extendWith(I_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
-+            } catch (Throwable ex) {
-+                throw uncaughtException(ex);
-+            }
-         }
-         @Override
--        public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
--            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
-+        public final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) {
-+            try {
-+                return (BoundMethodHandle) SPECIES_DATA.extendWith(J_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
-+            } catch (Throwable ex) {
-+                throw uncaughtException(ex);
-+            }
-         }
-         @Override
--        public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
--            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
-+        public final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) {
-+            try {
-+                return (BoundMethodHandle) SPECIES_DATA.extendWith(F_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
-+            } catch (Throwable ex) {
-+                throw uncaughtException(ex);
-+            }
-+        }
-+        @Override
-+        public final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) {
-+            try {
-+                return (BoundMethodHandle) SPECIES_DATA.extendWith(D_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
-+            } catch (Throwable ex) {
-+                throw uncaughtException(ex);
-+            }
-         }
-     }
- 
--    static final class Species_JL extends BoundMethodHandle {
--        final long argJ0;
--        final Object argL1;
--        public Species_JL(MethodType mt, LambdaForm lf, long argJ0, Object argL1) {
--            super(mt, lf);
--            this.argJ0 = argJ0;
--            this.argL1 = argL1;
--        }
--        @Override
--        public SpeciesData speciesData() {
--            return SPECIES_DATA;
--        }
--        public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("JL", Species_JL.class);
--        @Override public final long   argJ0() { return argJ0; }
--        @Override public final Object argL1() { return argL1; }
--        @Override
--        public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
--            return new Species_JL(mt, lf, argJ0, argL1);
--        }
--        @Override
--        public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
--            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
--        }
--        @Override
--        public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
--            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
--        }
--        @Override
--        public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
--            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
--        }
--        @Override
--        public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
--            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
--        }
--        @Override
--        public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
--            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
--        }
--    }
--*/
--
-     //
-     // BMH species meta-data
-     //
- 
-     /**
--     * Meta-data wrapper for concrete BMH classes.
-+     * Meta-data wrapper for concrete BMH types.
-+     * Each BMH type corresponds to a given sequence of basic field types (LIJFD).
-+     * The fields are immutable; their values are fully specified at object construction.
-+     * Each BMH type supplies an array of getter functions which may be used in lambda forms.
-+     * A BMH is constructed by cloning a shorter BMH and adding one or more new field values.
-+     * As a degenerate and common case, the "shorter BMH" can be missing, and contributes zero prior fields.
-      */
-     static class SpeciesData {
--        final String                             types;
-+        final String                             typeChars;
-+        final byte[]                             typeCodes;
-         final Class<? extends BoundMethodHandle> clazz;
-         // Bootstrapping requires circular relations MH -> BMH -> SpeciesData -> MH
-         // Therefore, we need a non-final link in the chain.  Use array elements.
-         final MethodHandle[]                     constructor;
-         final MethodHandle[]                     getters;
-+        final NamedFunction[]                    nominalGetters;
-         final SpeciesData[]                      extensions;
- 
-         public int fieldCount() {
--            return types.length();
-+            return typeCodes.length;
-         }
--        public char fieldType(int i) {
--            return types.charAt(i);
-+        public byte fieldType(int i) {
-+            return typeCodes[i];
-+        }
-+        public char fieldTypeChar(int i) {
-+            return typeChars.charAt(i);
-         }
- 
-         public String toString() {
--            return "SpeciesData["+(isPlaceholder() ? "<placeholder>" : clazz.getSimpleName())+":"+types+"]";
-+            return "SpeciesData["+(isPlaceholder() ? "<placeholder>" : clazz.getSimpleName())+":"+typeChars+"]";
-         }
- 
-         /**
-@@ -370,45 +302,46 @@
-          * represents a MH bound to a generic invoker, which in turn forwards to the corresponding
-          * getter.
-          */
--        Name getterName(Name mhName, int i) {
--            MethodHandle mh = getters[i];
--            assert(mh != null) : this+"."+i;
--            return new Name(mh, mhName);
--        }
--
-         NamedFunction getterFunction(int i) {
--            return new NamedFunction(getters[i]);
-+            return nominalGetters[i];
-         }
- 
-         static final SpeciesData EMPTY = new SpeciesData("", BoundMethodHandle.class);
- 
-         private SpeciesData(String types, Class<? extends BoundMethodHandle> clazz) {
--            this.types = types;
-+            this.typeChars = types;
-+            this.typeCodes = basicTypes(types);
-             this.clazz = clazz;
-             if (!INIT_DONE) {
--                this.constructor = new MethodHandle[1];
-+                this.constructor = new MethodHandle[1];  // only one ctor
-                 this.getters = new MethodHandle[types.length()];
-+                this.nominalGetters = new NamedFunction[types.length()];
-             } else {
-                 this.constructor = Factory.makeCtors(clazz, types, null);
-                 this.getters = Factory.makeGetters(clazz, types, null);
-+                this.nominalGetters = Factory.makeNominalGetters(clazz, types, null, this.getters);
-             }
--            this.extensions = new SpeciesData[EXTENSION_TYPES.length()];
-+            this.extensions = new SpeciesData[ARG_TYPE_LIMIT];
-         }
- 
-         private void initForBootstrap() {
-             assert(!INIT_DONE);
-             if (constructor[0] == null) {
-+                String types = typeChars;
-                 Factory.makeCtors(clazz, types, this.constructor);
-                 Factory.makeGetters(clazz, types, this.getters);
-+                Factory.makeNominalGetters(clazz, types, this.nominalGetters, this.getters);
-             }
-         }
- 
--        private SpeciesData(String types) {
-+        private SpeciesData(String typeChars) {
-             // Placeholder only.
--            this.types = types;
-+            this.typeChars = typeChars;
-+            this.typeCodes = basicTypes(typeChars);
-             this.clazz = null;
-             this.constructor = null;
-             this.getters = null;
-+            this.nominalGetters = null;
-             this.extensions = null;
-         }
-         private boolean isPlaceholder() { return clazz == null; }
-@@ -416,19 +349,19 @@
-         private static final HashMap<String, SpeciesData> CACHE = new HashMap<>();
-         private static final boolean INIT_DONE;  // set after <clinit> finishes...
- 
--        SpeciesData extendWithType(char type) {
--            int i = extensionIndex(type);
--            SpeciesData d = extensions[i];
-+        SpeciesData extendWith(byte type) {
-+            SpeciesData d = extensions[type];
-             if (d != null)  return d;
--            extensions[i] = d = get(types+type);
-+            extensions[type] = d = get(typeChars+basicTypeChar(type));
-             return d;
-         }
- 
--        SpeciesData extendWithIndex(byte index) {
--            SpeciesData d = extensions[index];
--            if (d != null)  return d;
--            extensions[index] = d = get(types+EXTENSION_TYPES.charAt(index));
--            return d;
-+        SpeciesData extendWith(Class<?> type) {
-+            return extendWith(basicType(type));
-+        }
-+
-+        SpeciesData extendWithChar(char type) {
-+            return extendWith(basicType(type));
-         }
- 
-         private static SpeciesData get(String types) {
-@@ -468,11 +401,11 @@
-             return d;
-         }
- 
-+        static void initStatics() {}
-+
-         static {
-             // pre-fill the BMH speciesdata cache with BMH's inner classes
-             final Class<BoundMethodHandle> rootCls = BoundMethodHandle.class;
--            SpeciesData d0 = BoundMethodHandle.SPECIES_DATA;  // trigger class init
--            assert(d0 == null || d0 == lookupCache("")) : d0;
-             try {
-                 for (Class<?> c : rootCls.getDeclaredClasses()) {
-                     if (rootCls.isAssignableFrom(c)) {
-@@ -480,7 +413,7 @@
-                         SpeciesData d = Factory.speciesDataFromConcreteBMHClass(cbmh);
-                         assert(d != null) : cbmh.getName();
-                         assert(d.clazz == cbmh);
--                        assert(d == lookupCache(d.types));
-+                        assert(d == lookupCache(d.typeChars));
-                     }
-                 }
-             } catch (Throwable e) {
-@@ -531,11 +464,10 @@
-         static final String BMHSPECIES_DATA_GFC_SIG = "(" + JLS_SIG + JLC_SIG + ")" + SPECIES_DATA_SIG;
-         static final String MYSPECIES_DATA_SIG = "()" + SPECIES_DATA_SIG;
-         static final String VOID_SIG   = "()V";
-+        static final String INT_SIG    = "()I";
- 
-         static final String SIG_INCIPIT = "(Ljava/lang/invoke/MethodType;Ljava/lang/invoke/LambdaForm;";
- 
--        static final Class<?>[] TYPES = new Class<?>[] { Object.class, int.class, long.class, float.class, double.class };
--
-         static final String[] E_THROWABLE = new String[] { "java/lang/Throwable" };
- 
-         /**
-@@ -566,31 +498,35 @@
-          *     final Object argL0;
-          *     final Object argL1;
-          *     final int argI2;
--         *     public Species_LLI(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
-+         *     private Species_LLI(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
-          *         super(mt, lf);
-          *         this.argL0 = argL0;
-          *         this.argL1 = argL1;
-          *         this.argI2 = argI2;
-          *     }
-          *     public final SpeciesData speciesData() { return SPECIES_DATA; }
-+         *     public final int fieldCount() { return 3; }
-          *     public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("LLI", Species_LLI.class);
--         *     public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) {
--         *         return SPECIES_DATA.constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2);
-+         *     public BoundMethodHandle make(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
-+         *         return new Species_LLI(mt, lf, argL0, argL1, argI2);
-          *     }
--         *     public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) {
--         *         return SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
-+         *     public final BoundMethodHandle copyWith(MethodType mt, LambdaForm lf) {
-+         *         return new Species_LLI(mt, lf, argL0, argL1, argI2);
-          *     }
--         *     public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) {
--         *         return SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
-+         *     public final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) {
-+         *         return SPECIES_DATA.extendWith(L_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
-          *     }
--         *     public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) {
--         *         return SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
-+         *     public final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) {
-+         *         return SPECIES_DATA.extendWith(I_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
-          *     }
--         *     public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) {
--         *         return SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
-+         *     public final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) {
-+         *         return SPECIES_DATA.extendWith(J_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
-          *     }
--         *     public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) {
--         *         return SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
-+         *     public final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) {
-+         *         return SPECIES_DATA.extendWith(F_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
-+         *     }
-+         *     public final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) {
-+         *         return SPECIES_DATA.extendWith(D_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
-          *     }
-          * }
-          * </pre>
-@@ -620,11 +556,11 @@
-             MethodVisitor mv;
- 
-             // emit constructor
--            mv = cw.visitMethod(ACC_PUBLIC, "<init>", makeSignature(types, true), null, null);
-+            mv = cw.visitMethod(ACC_PRIVATE, "<init>", makeSignature(types, true), null, null);
-             mv.visitCode();
--            mv.visitVarInsn(ALOAD, 0);
--            mv.visitVarInsn(ALOAD, 1);
--            mv.visitVarInsn(ALOAD, 2);
-+            mv.visitVarInsn(ALOAD, 0); // this
-+            mv.visitVarInsn(ALOAD, 1); // type
-+            mv.visitVarInsn(ALOAD, 2); // form
- 
-             mv.visitMethodInsn(INVOKESPECIAL, BMH, "<init>", makeSignature("", true));
- 
-@@ -643,16 +579,6 @@
-             mv.visitMaxs(0, 0);
-             mv.visitEnd();
- 
--            // emit implementation of reinvokerTarget()
--            mv = cw.visitMethod(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(ACC_PUBLIC + ACC_FINAL, "speciesData", MYSPECIES_DATA_SIG, null, null);
-             mv.visitCode();
-@@ -661,39 +587,72 @@
-             mv.visitMaxs(0, 0);
-             mv.visitEnd();
- 
--            // emit clone()
--            mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "clone", makeSignature("", false), null, E_THROWABLE);
-+            // emit implementation of fieldCount()
-+            mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "fieldCount", INT_SIG, null, null);
-             mv.visitCode();
--            // return speciesData().constructor[0].invokeBasic(mt, lf, argL0, ...)
--            // obtain constructor
--            mv.visitVarInsn(ALOAD, 0);
--            mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
--            mv.visitFieldInsn(GETFIELD, SPECIES_DATA, "constructor", "[" + MH_SIG);
--            mv.visitInsn(ICONST_0);
--            mv.visitInsn(AALOAD);
-+            int fc = types.length();
-+            if (fc <= (ICONST_5 - ICONST_0))
-+                mv.visitInsn(ICONST_0 + fc);
-+            else
-+                mv.visitIntInsn(SIPUSH, fc);
-+            mv.visitInsn(IRETURN);
-+            mv.visitMaxs(0, 0);
-+            mv.visitEnd();
-+
-+            // emit make()  ...factory method wrapping constructor
-+            mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "make", makeSignature(types, false), null, null);
-+            mv.visitCode();
-+            // make instance
-+            mv.visitTypeInsn(NEW, className);
-+            mv.visitInsn(DUP);
-+            // load mt, lf
-+            mv.visitVarInsn(ALOAD, 0);  // type
-+            mv.visitVarInsn(ALOAD, 1);  // form
-+            // load factory method arguments
-+            for (int i = 0, j = 0; i < types.length(); ++i, ++j) {
-+                // i counts the arguments, j counts corresponding argument slots
-+                char t = types.charAt(i);
-+                mv.visitVarInsn(typeLoadOp(t), j + 2); // parameters start at 3
-+                if (t == 'J' || t == 'D') {
-+                    ++j; // adjust argument register access
-+                }
-+            }
-+
-+            // finally, invoke the constructor and return
-+            mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", makeSignature(types, true));
-+            mv.visitInsn(ARETURN);
-+            mv.visitMaxs(0, 0);
-+            mv.visitEnd();
-+
-+            // emit copyWith()
-+            mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "copyWith", makeSignature("", false), null, null);
-+            mv.visitCode();
-+            // make instance
-+            mv.visitTypeInsn(NEW, className);
-+            mv.visitInsn(DUP);
-             // load mt, lf
-             mv.visitVarInsn(ALOAD, 1);
-             mv.visitVarInsn(ALOAD, 2);
-             // put fields on the stack
-             emitPushFields(types, className, mv);
-             // finally, invoke the constructor and return
--            mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types, false));
-+            mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", makeSignature(types, true));
-             mv.visitInsn(ARETURN);
-             mv.visitMaxs(0, 0);
-             mv.visitEnd();
- 
--            // for each type, emit cloneExtendT()
--            for (Class<?> c : TYPES) {
--                char t = Wrapper.basicTypeChar(c);
--                mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "cloneExtend" + t, makeSignature(String.valueOf(t), false), null, E_THROWABLE);
-+            // for each type, emit copyWithExtendT()
-+            for (byte bt = 0; bt < ARG_TYPE_LIMIT; bt++) {
-+                char t = basicTypeChar(bt);
-+                mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "copyWithExtend" + t, makeSignature(String.valueOf(t), false), null, E_THROWABLE);
-                 mv.visitCode();
--                // return SPECIES_DATA.extendWithIndex(extensionIndex(t)).constructor[0].invokeBasic(mt, lf, argL0, ..., narg)
-+                // return SPECIES_DATA.extendWith(t).constructor[0].invokeBasic(mt, lf, argL0, ..., narg)
-                 // obtain constructor
-                 mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
--                int iconstInsn = ICONST_0 + extensionIndex(t);
-+                int iconstInsn = ICONST_0 + bt;
-                 assert(iconstInsn <= ICONST_5);
-                 mv.visitInsn(iconstInsn);
--                mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "extendWithIndex", BMHSPECIES_DATA_EWI_SIG);
-+                mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "extendWith", BMHSPECIES_DATA_EWI_SIG);
-                 mv.visitFieldInsn(GETFIELD, SPECIES_DATA, "constructor", "[" + MH_SIG);
-                 mv.visitInsn(ICONST_0);
-                 mv.visitInsn(AALOAD);
-@@ -789,6 +748,14 @@
-             return mhs;
-         }
- 
-+        static NamedFunction[] makeNominalGetters(Class<?> cbmhClass, String types, NamedFunction[] nfs, MethodHandle[] getters) {
-+            if (nfs == null)  nfs = new NamedFunction[types.length()];
-+            for (int i = 0; i < nfs.length; ++i) {
-+                nfs[i] = new NamedFunction(getters[i]);
-+            }
-+            return nfs;
-+        }
-+
-         //
-         // Auxiliary methods.
-         //
-@@ -822,60 +789,28 @@
- 
-         static MethodHandle makeCbmhCtor(Class<? extends BoundMethodHandle> cbmh, String types) {
-             try {
--                return linkConstructor(LOOKUP.findConstructor(cbmh, MethodType.fromMethodDescriptorString(makeSignature(types, true), null)));
-+                return LOOKUP.findStatic(cbmh, "make", MethodType.fromMethodDescriptorString(makeSignature(types, false), null));
-             } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | TypeNotPresentException e) {
-                 throw newInternalError(e);
-             }
-         }
--
--        /**
--         * Wrap a constructor call in a {@link LambdaForm}.
--         *
--         * If constructors ({@code <init>} methods) are called in LFs, problems might arise if the LFs
--         * are turned into bytecode, because the call to the allocator is routed through an MH, and the
--         * verifier cannot find a {@code NEW} instruction preceding the {@code INVOKESPECIAL} to
--         * {@code <init>}. To avoid this, we add an indirection by invoking {@code <init>} through
--         * {@link MethodHandle#linkToSpecial}.
--         *
--         * The last {@link LambdaForm#Name Name} in the argument's form is expected to be the {@code void}
--         * result of the {@code <init>} invocation. This entry is replaced.
--         */
--        private static MethodHandle linkConstructor(MethodHandle cmh) {
--            final LambdaForm lf = cmh.form;
--            final int initNameIndex = lf.names.length - 1;
--            final Name initName = lf.names[initNameIndex];
--            final MemberName ctorMN = initName.function.member;
--            final MethodType ctorMT = ctorMN.getInvocationType();
--
--            // obtain function member (call target)
--            // linker method type replaces initial parameter (BMH species) with BMH to avoid naming a species (anonymous class!)
--            final MethodType linkerMT = ctorMT.changeParameterType(0, BoundMethodHandle.class).appendParameterTypes(MemberName.class);
--            MemberName linkerMN = new MemberName(MethodHandle.class, "linkToSpecial", linkerMT, REF_invokeStatic);
--            try {
--                linkerMN = MemberName.getFactory().resolveOrFail(REF_invokeStatic, linkerMN, null, NoSuchMethodException.class);
--                assert(linkerMN.isStatic());
--            } catch (ReflectiveOperationException ex) {
--                throw newInternalError(ex);
--            }
--            // extend arguments array
--            Object[] newArgs = Arrays.copyOf(initName.arguments, initName.arguments.length + 1);
--            newArgs[newArgs.length - 1] = ctorMN;
--            // replace function
--            final NamedFunction nf = new NamedFunction(linkerMN);
--            final Name linkedCtor = new Name(nf, newArgs);
--            linkedCtor.initIndex(initNameIndex);
--            lf.names[initNameIndex] = linkedCtor;
--            return cmh;
--        }
--
-     }
- 
-     private static final Lookup LOOKUP = Lookup.IMPL_LOOKUP;
- 
--    /**
--     * All subclasses must provide such a value describing their type signature.
--     */
--    static final SpeciesData SPECIES_DATA = SpeciesData.EMPTY;
-+    static void initStatics() {}
-+    static { SpeciesData.initStatics(); }
-+
-+    private static final SpeciesData[] SPECIES_DATA_CACHE = new SpeciesData[4];
-+    private static SpeciesData checkCache(int index, String types) {
-+        SpeciesData data = SPECIES_DATA_CACHE[index];
-+        if (data != null)  return data;
-+        SPECIES_DATA_CACHE[index] = data = getSpeciesData(types);
-+        return data;
-+    }
-+    static SpeciesData speciesData_L()     { return checkCache(1, "L"); }
-+    static SpeciesData speciesData_LL()    { return checkCache(2, "LL"); }
-+    static SpeciesData speciesData_LLL()   { return checkCache(3, "LLL"); }
- 
-     // Event counters
-     private static final EventCounter EC_methodHandle_bound = eventCounter(EC_methodHandle, "bound", true);  // autoSum=true
-@@ -885,4 +820,6 @@
-     private static final EventCounter EC_methodHandle_bound_arg3 = eventCounter(EC_methodHandle_bound, "arg3");
-     private static final EventCounter EC_methodHandle_bound_arg4 = eventCounter(EC_methodHandle_bound, "arg4");
-     private static final EventCounter EC_methodHandle_bound_arg5up = eventCounter(EC_methodHandle_bound, "arg5up");
-+    private static final EventCounter EC_methodHandle_rebind = eventCounter(EC_methodHandle_bound, "rebind");
-+    private static final EventCounter EC_methodHandle_rebind_complex = eventCounter(EC_methodHandle_rebind, "complex");
- }
-diff --git a/src/share/classes/java/lang/invoke/CallSite.java b/src/share/classes/java/lang/invoke/CallSite.java
---- a/src/share/classes/java/lang/invoke/CallSite.java
-+++ b/src/share/classes/java/lang/invoke/CallSite.java
-@@ -102,7 +102,7 @@
-      */
-     /*package-private*/
-     CallSite(MethodType type) {
--        target = type.invokers().uninitializedCallSite();
-+        target = makeUninitializedCallSite(type);
-     }
- 
-     /**
-@@ -114,6 +114,7 @@
-     CallSite(MethodHandle target) {
-         target.type();  // null check
-         this.target = target;
-+        target.maybeCompileToBytecode();
-     }
- 
-     /**
-@@ -133,6 +134,7 @@
-         MethodHandle boundTarget = (MethodHandle) createTargetHook.invokeWithArguments(selfCCS);
-         checkTargetChange(this.target, boundTarget);
-         this.target = boundTarget;
-+        boundTarget.maybeCompileToBytecode();
-     }
- 
-     /**
-@@ -188,6 +190,7 @@
-         MethodType newType = newTarget.type();  // null check!
-         if (!newType.equals(oldType))
-             throw wrongTargetType(newTarget, oldType);
-+        newTarget.maybeCompileToBytecode();
-     }
- 
-     private static WrongMethodTypeException wrongTargetType(MethodHandle target, MethodType type) {
-@@ -211,27 +214,41 @@
-     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 {
-@@ -320,6 +337,7 @@
-             if (!site.getTarget().type().equals(type))
-                 throw new WrongMethodTypeException("wrong type: "+site.getTarget());
-         } catch (Throwable ex) {
-+            ex.printStackTrace();//@@
-             BootstrapMethodError bex;
-             if (ex instanceof BootstrapMethodError)
-                 bex = (BootstrapMethodError) ex;
-diff --git a/src/share/classes/java/lang/invoke/DelegatingMethodHandle.java b/src/share/classes/java/lang/invoke/DelegatingMethodHandle.java
-new file mode 100644
---- /dev/null
-+++ b/src/share/classes/java/lang/invoke/DelegatingMethodHandle.java
-@@ -0,0 +1,132 @@
-+/*
-+ * Copyright (c) 2013, 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(target.type(), makeReinvokerForm(target, MethodTypeForm.LF_DELEGATE, NF_getTarget));
-+    }
-+
-+    /** Define this to extract the delegated target which supplies the invocation behavior. */
-+    abstract protected MethodHandle getTarget();
-+
-+    @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
-+    BoundMethodHandle rebind() {
-+        return getTarget().rebind();
-+    }
-+
-+    @Override
-+    void compileToBytecode() {
-+        super.compileToBytecode();
-+        getTarget().compileToBytecode();
-+    }
-+
-+    /** Create a LF which simply reinvokes a target of the given basic type.
-+     */
-+    static LambdaForm makeReinvokerForm(MethodHandle target,
-+                                        int whichCache,
-+                                        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);
-+        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 =
-+                (whichCache == MethodTypeForm.LF_REBIND ? "BMH.reinvoke" :
-+                whichCache == MethodTypeForm.LF_DELEGATE ? "MH.delegate" : "MH.reinvoke");
-+        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);
-+        }
-+    }
-+}
-diff --git a/src/share/classes/java/lang/invoke/DirectMethodHandle.java b/src/share/classes/java/lang/invoke/DirectMethodHandle.java
---- a/src/share/classes/java/lang/invoke/DirectMethodHandle.java
-+++ b/src/share/classes/java/lang/invoke/DirectMethodHandle.java
-@@ -58,6 +58,7 @@
-             MemberName m = new MemberName(Object.class, member.getName(), member.getMethodType(), member.getReferenceKind());
-             m = MemberName.getFactory().resolveOrNull(m.getReferenceKind(), m, null);
-             if (m != null && m.isPublic()) {
-+                assert(member.getReferenceKind() == m.getReferenceKind());  // else this.form is wrong
-                 member = m;
-             }
-         }
-@@ -127,6 +128,7 @@
- 
-     @Override
-     MethodHandle copyWith(MethodType mt, LambdaForm lf) {
-+        assert(this.getClass() == DirectMethodHandle.class);  // must override in subclasses
-         return new DirectMethodHandle(mt, lf, member);
-     }
- 
-@@ -137,54 +139,13 @@
- 
-     //// Implementation methods.
-     @Override
--    MethodHandle viewAsType(MethodType newType) {
--        return new DirectMethodHandle(newType, form, member);
--    }
--    @Override
-     @ForceInline
-     MemberName internalMemberName() {
-         return member;
-     }
- 
--    @Override
--    MethodHandle bindArgument(int pos, char basicType, Object value) {
--        // If the member needs dispatching, do so.
--        if (pos == 0 && basicType == 'L') {
--            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
-@@ -394,8 +355,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);
-         }
-     }
- 
-@@ -412,8 +373,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);
-         }
-     }
- 
-@@ -442,8 +403,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);
-         }
-     }
- 
-@@ -485,8 +446,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);
-         }
-     }
- 
-diff --git a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
---- a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
-+++ b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
-@@ -25,12 +25,6 @@
- 
- package java.lang.invoke;
- 
--import sun.invoke.util.VerifyAccess;
--import java.lang.invoke.LambdaForm.Name;
--import java.lang.invoke.MethodHandles.Lookup;
--
--import sun.invoke.util.Wrapper;
--
- import java.io.*;
- import java.util.*;
- 
-@@ -40,8 +34,11 @@
- import static java.lang.invoke.MethodHandleStatics.*;
- import static java.lang.invoke.MethodHandleNatives.Constants.*;
- import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
-+import static java.lang.invoke.LambdaForm.*;
- import sun.invoke.util.ValueConversions;
- import sun.invoke.util.VerifyType;
-+import sun.invoke.util.VerifyAccess;
-+import sun.invoke.util.Wrapper;
- 
- /**
-  * Code generation backend for LambdaForm.
-@@ -117,7 +114,7 @@
-         Name[] names = form.names;
-         for (int i = 0, index = 0; i < localsMap.length; i++) {
-             localsMap[i] = index;
--            index += Wrapper.forBasicType(names[i].type).stackSlots();
-+            index += Wrapper.forBasicType(names[i].typeChar()).stackSlots();
-         }
-     }
- 
-@@ -374,38 +371,38 @@
-     /*
-      * NOTE: These load/store methods use the localsMap to find the correct index!
-      */
--    private void emitLoadInsn(char type, int index) {
-+    private void emitLoadInsn(byte type, int index) {
-         int opcode;
-         switch (type) {
--        case 'I':  opcode = Opcodes.ILOAD;  break;
--        case 'J':  opcode = Opcodes.LLOAD;  break;
--        case 'F':  opcode = Opcodes.FLOAD;  break;
--        case 'D':  opcode = Opcodes.DLOAD;  break;
--        case 'L':  opcode = Opcodes.ALOAD;  break;
-+        case I_TYPE:  opcode = Opcodes.ILOAD;  break;
-+        case J_TYPE:  opcode = Opcodes.LLOAD;  break;
-+        case F_TYPE:  opcode = Opcodes.FLOAD;  break;
-+        case D_TYPE:  opcode = Opcodes.DLOAD;  break;
-+        case L_TYPE:  opcode = Opcodes.ALOAD;  break;
-         default:
-             throw new InternalError("unknown type: " + type);
-         }
-         mv.visitVarInsn(opcode, localsMap[index]);
-     }
-     private void emitAloadInsn(int index) {
--        emitLoadInsn('L', index);
-+        emitLoadInsn(L_TYPE, index);
-     }
- 
--    private void emitStoreInsn(char type, int index) {
-+    private void emitStoreInsn(byte type, int index) {
-         int opcode;
-         switch (type) {
--        case 'I':  opcode = Opcodes.ISTORE;  break;
--        case 'J':  opcode = Opcodes.LSTORE;  break;
--        case 'F':  opcode = Opcodes.FSTORE;  break;
--        case 'D':  opcode = Opcodes.DSTORE;  break;
--        case 'L':  opcode = Opcodes.ASTORE;  break;
-+        case I_TYPE:  opcode = Opcodes.ISTORE;  break;
-+        case J_TYPE:  opcode = Opcodes.LSTORE;  break;
-+        case F_TYPE:  opcode = Opcodes.FSTORE;  break;
-+        case D_TYPE:  opcode = Opcodes.DSTORE;  break;
-+        case L_TYPE:  opcode = Opcodes.ASTORE;  break;
-         default:
-             throw new InternalError("unknown type: " + type);
-         }
-         mv.visitVarInsn(opcode, localsMap[index]);
-     }
-     private void emitAstoreInsn(int index) {
--        emitStoreInsn('L', index);
-+        emitStoreInsn(L_TYPE, index);
-     }
- 
-     /**
-@@ -413,8 +410,7 @@
-      *
-      * @param type primitive type class to box.
-      */
--    private void emitBoxing(Class<?> type) {
--        Wrapper wrapper = Wrapper.forPrimitiveType(type);
-+    private void emitBoxing(Wrapper wrapper) {
-         String owner = "java/lang/" + wrapper.wrapperType().getSimpleName();
-         String name  = "valueOf";
-         String desc  = "(" + wrapper.basicTypeChar() + ")L" + owner + ";";
-@@ -426,8 +422,7 @@
-      *
-      * @param type wrapper type class to unbox.
-      */
--    private void emitUnboxing(Class<?> type) {
--        Wrapper wrapper = Wrapper.forWrapperType(type);
-+    private void emitUnboxing(Wrapper wrapper) {
-         String owner = "java/lang/" + wrapper.wrapperType().getSimpleName();
-         String name  = wrapper.primitiveSimpleName() + "Value";
-         String desc  = "()" + wrapper.basicTypeChar();
-@@ -436,56 +431,60 @@
-     }
- 
-     /**
--     * 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
-      */
--    private void emitImplicitConversion(char ptype, Class<?> pclass) {
-+    private void emitImplicitConversion(byte ptype, Class<?> pclass) {
-+        assert(basicType(pclass) == ptype);  // boxing/unboxing handled by caller
-+        if (pclass == basicTypeClass(ptype) && ptype != L_TYPE)
-+            return;   // nothing to do
-         switch (ptype) {
--        case 'L':
--            if (VerifyType.isNullConversion(Object.class, pclass))
-+        case L_TYPE:
-+            if (VerifyType.isNullConversion(Object.class, pclass, false)) {
-+                if (PROFILE_LEVEL >= 0)
-+                    mv.visitTypeInsn(Opcodes.CHECKCAST, OBJ);
-                 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.INVOKEVIRTUAL, CLS, "cast", LL_SIG);
-                 if (pclass.isArray())
-                     mv.visitTypeInsn(Opcodes.CHECKCAST, OBJARY);
-+                else if (PROFILE_LEVEL >= 0)
-+                    mv.visitTypeInsn(Opcodes.CHECKCAST, OBJ);
-+                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, CLS, "cast", LL_SIG);
-             }
-             return;
--        case 'I':
--            if (!VerifyType.isNullConversion(int.class, pclass))
--                emitPrimCast(ptype, Wrapper.basicTypeChar(pclass));
--            return;
--        case 'J':
--            assert(pclass == long.class);
--            return;
--        case 'F':
--            assert(pclass == float.class);
--            return;
--        case 'D':
--            assert(pclass == double.class);
-+        case I_TYPE:
-+            if (!VerifyType.isNullConversion(int.class, pclass, false))
-+                emitPrimCast(basicTypeWrapper(ptype), Wrapper.forPrimitiveType(pclass));
-             return;
-         }
-         throw new InternalError("bad implicit conversion: tc="+ptype+": "+pclass);
-     }
- 
-+    private void emitReferenceCast(Class<?> pclass) {
-+        
-+    }
-+
-     /**
-      * Emits an actual return instruction conforming to the given return type.
-      */
--    private void emitReturnInsn(Class<?> type) {
-+    private void emitReturnInsn(byte type) {
-         int opcode;
--        switch (Wrapper.basicTypeChar(type)) {
--        case 'I':  opcode = Opcodes.IRETURN;  break;
--        case 'J':  opcode = Opcodes.LRETURN;  break;
--        case 'F':  opcode = Opcodes.FRETURN;  break;
--        case 'D':  opcode = Opcodes.DRETURN;  break;
--        case 'L':  opcode = Opcodes.ARETURN;  break;
--        case 'V':  opcode = Opcodes.RETURN;   break;
-+        switch (type) {
-+        case I_TYPE:  opcode = Opcodes.IRETURN;  break;
-+        case J_TYPE:  opcode = Opcodes.LRETURN;  break;
-+        case F_TYPE:  opcode = Opcodes.FRETURN;  break;
-+        case D_TYPE:  opcode = Opcodes.DRETURN;  break;
-+        case L_TYPE:  opcode = Opcodes.ARETURN;  break;
-+        case V_TYPE:  opcode = Opcodes.RETURN;   break;
-         default:
-             throw new InternalError("unknown return type: " + type);
-         }
-@@ -529,11 +528,15 @@
-         for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
-             Name name = lambdaForm.names[i];
-             MemberName member = name.function.member();
-+            Name nextName;
- 
--            if (isSelectAlternative(member)) {
-+            if (isSelectAlternative(name) &&
-+                    i+1 < lambdaForm.names.length &&
-+                    isInvokeBasic(nextName = lambdaForm.names[i+1]) &&
-+                    nextName.lastUseIndex(name) == 0 &&
-+                    lambdaForm.lastUseIndex(name) == i+1) {
-                 // selectAlternative idiom
--                // FIXME: make sure this idiom is really present!
--                emitSelectAlternative(name, lambdaForm.names[i + 1]);
-+                emitSelectAlternative(name, nextName);
-                 i++;  // skip MH.invokeBasic of the selectAlternative result
-             } else if (isStaticallyInvocable(member)) {
-                 emitStaticInvoke(member, name);
-@@ -546,7 +549,7 @@
-             // avoid store/load/return and just return)
-             if (i == lambdaForm.names.length - 1 && i == lambdaForm.result) {
-                 // return value - do nothing
--            } else if (name.type != 'V') {
-+            } else if (name.type != V_TYPE) {
-                 // non-void: actually assign
-                 emitStoreInsn(name.type, name.index());
-             }
-@@ -694,13 +697,30 @@
-      * @param member
-      * @return true if member is a call to MethodHandleImpl.selectAlternative
-      */
--    private boolean isSelectAlternative(MemberName member) {
-+    private boolean isSelectAlternative(Name name) {
-+        if (name.function == null)  return false;
-+        MemberName member = name.function.member();
-         return member != null &&
-                member.getDeclaringClass() == MethodHandleImpl.class &&
-                member.getName().equals("selectAlternative");
-     }
- 
-     /**
-+     * Check if MemberName is a call to MethodHandle.invokeBasic.
-+     *
-+     * @param member
-+     * @return true if member is a call to MethodHandleImpl.selectAlternative
-+     */
-+    private boolean isInvokeBasic(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.getName().equals("invokeBasic");
-+    }
-+
-+    /**
-      * Emit bytecode for the selectAlternative idiom.
-      *
-      * The pattern looks like (Cf. MethodHandleImpl.makeGuardWithTest):
-@@ -723,13 +743,11 @@
- 
-         // 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]
--        MethodHandle target = (MethodHandle) selectAlternativeName.arguments[1];
-         emitPushArgument(selectAlternativeName, 1);  // get 2nd argument of selectAlternative
-         emitAstoreInsn(receiver.index());  // store the MH in the receiver slot
-         emitInvoke(invokeBasicName);
-@@ -741,7 +759,6 @@
-         mv.visitLabel(L_fallback);
- 
-         // invoke selectAlternativeName.arguments[2]
--        MethodHandle fallback = (MethodHandle) selectAlternativeName.arguments[2];
-         emitPushArgument(selectAlternativeName, 2);  // get 3rd argument of selectAlternative
-         emitAstoreInsn(receiver.index());  // store the MH in the receiver slot
-         emitInvoke(invokeBasicName);
-@@ -757,20 +774,20 @@
-      */
-     private void emitPushArgument(Name name, int paramIndex) {
-         Object arg = name.arguments[paramIndex];
--        char ptype = name.function.parameterType(paramIndex);
-+        byte ptype = name.function.parameterType(paramIndex);
-         MethodType mtype = name.function.methodType();
-         if (arg instanceof Name) {
-             Name n = (Name) arg;
-             emitLoadInsn(n.type, n.index());
-             emitImplicitConversion(n.type, mtype.parameterType(paramIndex));
--        } else if ((arg == null || arg instanceof String) && ptype == 'L') {
-+        } else if ((arg == null || arg instanceof String) && ptype == L_TYPE) {
-             emitConst(arg);
-         } else {
--            if (Wrapper.isWrapperType(arg.getClass()) && ptype != 'L') {
-+            if (Wrapper.isWrapperType(arg.getClass()) && ptype != L_TYPE) {
-                 emitConst(arg);
-             } else {
-                 mv.visitLdcInsn(constantPlaceholder(arg));
--                emitImplicitConversion('L', mtype.parameterType(paramIndex));
-+                emitImplicitConversion(L_TYPE, mtype.parameterType(paramIndex));
-             }
-         }
-     }
-@@ -780,52 +797,37 @@
-      */
-     private void emitReturn() {
-         // return statement
--        if (lambdaForm.result == -1) {
-+        Class<?> rclass = invokerType.returnType();
-+        byte rtype = lambdaForm.returnType();
-+        assert(rtype == basicType(rclass));  // must agree
-+        if (rtype == V_TYPE) {
-             // void
-             mv.visitInsn(Opcodes.RETURN);
-+            // it doesn't matter what rclass is; the JVM will discard any value
-         } else {
--            LambdaForm.Name rn = lambdaForm.names[lambdaForm.result];
--            char rtype = Wrapper.basicTypeChar(invokerType.returnType());
-+            Name rn = lambdaForm.names[lambdaForm.result];
-+            assert(rtype == rn.type);
- 
-             // put return value on the stack if it is not already there
--            if (lambdaForm.result != lambdaForm.names.length - 1) {
--                emitLoadInsn(rn.type, lambdaForm.result);
-+            if (lambdaForm.result != lambdaForm.names.length - 1 ||
-+                    lambdaForm.result < lambdaForm.arity) {
-+                emitLoadInsn(rtype, lambdaForm.result);
-             }
- 
-             // potentially generate cast
-             // rtype is the return type of the invoker - generated code must conform to this
-             // rn.type is the type of the result Name in the LF
--            if (rtype != rn.type) {
--                // need cast
--                if (rtype == 'L') {
--                    // possibly cast the primitive to the correct type for boxing
--                    char boxedType = Wrapper.forWrapperType(invokerType.returnType()).basicTypeChar();
--                    if (boxedType != rn.type) {
--                        emitPrimCast(rn.type, boxedType);
--                    }
--                    // cast primitive to reference ("boxing")
--                    emitBoxing(invokerType.returnType());
--                } else {
--                    // to-primitive cast
--                    if (rn.type != 'L') {
--                        // prim-to-prim cast
--                        emitPrimCast(rn.type, rtype);
--                    } else {
--                        // ref-to-prim cast ("unboxing")
--                        throw new InternalError("no ref-to-prim (unboxing) casts supported right now");
--                    }
--                }
--            }
-+            emitImplicitConversion(rtype, rclass);
- 
-             // generate actual return statement
--            emitReturnInsn(invokerType.returnType());
-+            emitReturnInsn(rtype);
-         }
-     }
- 
-     /**
-      * Emit a type conversion bytecode casting from "from" to "to".
-      */
--    private void emitPrimCast(char from, char to) {
-+    private void emitPrimCast(Wrapper from, Wrapper to) {
-         // Here's how.
-         // -   indicates forbidden
-         // <-> indicates implicit
-@@ -842,17 +844,15 @@
-             // no cast required, should be dead code anyway
-             return;
-         }
--        Wrapper wfrom = Wrapper.forBasicType(from);
--        Wrapper wto   = Wrapper.forBasicType(to);
--        if (wfrom.isSubwordOrInt()) {
-+        if (from.isSubwordOrInt()) {
-             // cast from {byte,short,char,int} to anything
-             emitI2X(to);
-         } else {
-             // cast from {long,float,double} to anything
--            if (wto.isSubwordOrInt()) {
-+            if (to.isSubwordOrInt()) {
-                 // cast to {byte,short,char,int}
-                 emitX2I(from);
--                if (wto.bitWidth() < 32) {
-+                if (to.bitWidth() < 32) {
-                     // targets other than int require another conversion
-                     emitI2X(to);
-                 }
-@@ -860,20 +860,26 @@
-                 // cast to {long,float,double} - this is verbose
-                 boolean error = false;
-                 switch (from) {
--                case 'J':
--                         if (to == 'F') { mv.visitInsn(Opcodes.L2F); }
--                    else if (to == 'D') { mv.visitInsn(Opcodes.L2D); }
--                    else error = true;
-+                case LONG:
-+                    switch (to) {
-+                    case FLOAT:   mv.visitInsn(Opcodes.L2F);  break;
-+                    case DOUBLE:  mv.visitInsn(Opcodes.L2D);  break;
-+                    default:      error = true;               break;
-+                    }
-                     break;
--                case 'F':
--                         if (to == 'J') { mv.visitInsn(Opcodes.F2L); }
--                    else if (to == 'D') { mv.visitInsn(Opcodes.F2D); }
--                    else error = true;
-+                case FLOAT:
-+                    switch (to) {
-+                    case LONG :   mv.visitInsn(Opcodes.F2L);  break;
-+                    case DOUBLE:  mv.visitInsn(Opcodes.F2D);  break;
-+                    default:      error = true;               break;
-+                    }
-                     break;
--                case 'D':
--                         if (to == 'J') { mv.visitInsn(Opcodes.D2L); }
--                    else if (to == 'F') { mv.visitInsn(Opcodes.D2F); }
--                    else error = true;
-+                case DOUBLE:
-+                    switch (to) {
-+                    case LONG :   mv.visitInsn(Opcodes.D2L);  break;
-+                    case FLOAT:   mv.visitInsn(Opcodes.D2F);  break;
-+                    default:      error = true;               break;
-+                    }
-                     break;
-                 default:
-                     error = true;
-@@ -886,16 +892,16 @@
-         }
-     }
- 
--    private void emitI2X(char type) {
-+    private void emitI2X(Wrapper type) {
-         switch (type) {
--        case 'B':  mv.visitInsn(Opcodes.I2B);  break;
--        case 'S':  mv.visitInsn(Opcodes.I2S);  break;
--        case 'C':  mv.visitInsn(Opcodes.I2C);  break;
--        case 'I':  /* naught */                break;
--        case 'J':  mv.visitInsn(Opcodes.I2L);  break;
--        case 'F':  mv.visitInsn(Opcodes.I2F);  break;
--        case 'D':  mv.visitInsn(Opcodes.I2D);  break;
--        case 'Z':
-+        case BYTE:    mv.visitInsn(Opcodes.I2B);  break;
-+        case SHORT:   mv.visitInsn(Opcodes.I2S);  break;
-+        case CHAR:    mv.visitInsn(Opcodes.I2C);  break;
-+        case INT:     /* naught */                break;
-+        case LONG:    mv.visitInsn(Opcodes.I2L);  break;
-+        case FLOAT:   mv.visitInsn(Opcodes.I2F);  break;
-+        case DOUBLE:  mv.visitInsn(Opcodes.I2D);  break;
-+        case BOOLEAN:
-             // For compatibility with ValueConversions and explicitCastArguments:
-             mv.visitInsn(Opcodes.ICONST_1);
-             mv.visitInsn(Opcodes.IAND);
-@@ -904,12 +910,12 @@
-         }
-     }
- 
--    private void emitX2I(char type) {
-+    private void emitX2I(Wrapper type) {
-         switch (type) {
--        case 'J':  mv.visitInsn(Opcodes.L2I);  break;
--        case 'F':  mv.visitInsn(Opcodes.F2I);  break;
--        case 'D':  mv.visitInsn(Opcodes.D2I);  break;
--        default:   throw new InternalError("unknown type: " + type);
-+        case LONG:    mv.visitInsn(Opcodes.L2I);  break;
-+        case FLOAT:   mv.visitInsn(Opcodes.F2I);  break;
-+        case DOUBLE:  mv.visitInsn(Opcodes.D2I);  break;
-+        default:      throw new InternalError("unknown type: " + type);
-         }
-     }
- 
-@@ -928,16 +934,16 @@
-      * @return
-      */
-     static MemberName generateLambdaFormInterpreterEntryPoint(String sig) {
--        assert(LambdaForm.isValidSignature(sig));
-+        assert(isValidSignature(sig));
-         //System.out.println("generateExactInvoker "+sig);
-         // compute method type
-         // first parameter and return type
--        char tret = LambdaForm.signatureReturn(sig);
--        MethodType type = MethodType.methodType(LambdaForm.typeClass(tret), MethodHandle.class);
-+        byte tret = signatureReturn(sig);
-+        MethodType type = MethodType.methodType(basicTypeClass(tret), MethodHandle.class);
-         // other parameter types
--        int arity = LambdaForm.signatureArity(sig);
-+        int arity = signatureArity(sig);
-         for (int i = 1; i < arity; i++) {
--            type = type.appendParameterTypes(LambdaForm.typeClass(sig.charAt(i)));
-+            type = type.appendParameterTypes(basicTypeClass(basicType(sig.charAt(i))));
-         }
-         InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("LFI", "interpret_"+tret, type);
-         return g.loadMethod(g.generateLambdaFormInterpreterEntryPointBytes());
-@@ -961,10 +967,10 @@
-             Class<?> ptype = invokerType.parameterType(i);
-             mv.visitInsn(Opcodes.DUP);
-             emitIconstInsn(i);
--            emitLoadInsn(Wrapper.basicTypeChar(ptype), i);
-+            emitLoadInsn(basicType(ptype), i);
-             // box if primitive type
-             if (ptype.isPrimitive()) {
--                emitBoxing(ptype);
-+                emitBoxing(Wrapper.forPrimitiveType(ptype));
-             }
-             mv.visitInsn(Opcodes.AASTORE);
-         }
-@@ -977,11 +983,11 @@
-         // maybe unbox
-         Class<?> rtype = invokerType.returnType();
-         if (rtype.isPrimitive() && rtype != void.class) {
--            emitUnboxing(Wrapper.asWrapperType(rtype));
-+            emitUnboxing(Wrapper.forPrimitiveType(rtype));
-         }
- 
-         // return statement
--        emitReturnInsn(rtype);
-+        emitReturnInsn(basicType(rtype));
- 
-         classFileEpilogue();
-         bogusMethod(invokerType);
-@@ -999,7 +1005,7 @@
-      * @return
-      */
-     static MemberName generateNamedFunctionInvoker(MethodTypeForm typeForm) {
--        MethodType invokerType = LambdaForm.NamedFunction.INVOKER_METHOD_TYPE;
-+        MethodType invokerType = NamedFunction.INVOKER_METHOD_TYPE;
-         String invokerName = basicTypeCharSignature("invoke_", typeForm.erasedType());
-         InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("NFI", invokerName, invokerType);
-         return g.loadMethod(g.generateNamedFunctionInvokerImpl(typeForm));
-@@ -1032,8 +1038,8 @@
-                 Class<?> sptype = dstType.basicType().wrap().parameterType(i);
-                 Wrapper dstWrapper = Wrapper.forBasicType(dptype);
-                 Wrapper srcWrapper = dstWrapper.isSubwordOrInt() ? Wrapper.INT : dstWrapper;  // narrow subword from int
--                emitUnboxing(srcWrapper.wrapperType());
--                emitPrimCast(srcWrapper.basicTypeChar(), dstWrapper.basicTypeChar());
-+                emitUnboxing(srcWrapper);
-+                emitPrimCast(srcWrapper, dstWrapper);
-             }
-         }
- 
-@@ -1047,15 +1053,15 @@
-             Wrapper srcWrapper = Wrapper.forBasicType(rtype);
-             Wrapper dstWrapper = srcWrapper.isSubwordOrInt() ? Wrapper.INT : srcWrapper;  // widen subword to int
-             // boolean casts not allowed
--            emitPrimCast(srcWrapper.basicTypeChar(), dstWrapper.basicTypeChar());
--            emitBoxing(dstWrapper.primitiveType());
-+            emitPrimCast(srcWrapper, dstWrapper);
-+            emitBoxing(dstWrapper);
-         }
- 
-         // If the return type is void we return a null reference.
-         if (rtype == void.class) {
-             mv.visitInsn(Opcodes.ACONST_NULL);
-         }
--        emitReturnInsn(Object.class);  // NOTE: NamedFunction invokers always return a reference value.
-+        emitReturnInsn(L_TYPE);  // NOTE: NamedFunction invokers always return a reference value.
- 
-         classFileEpilogue();
-         bogusMethod(dstType);
+         Class<?> arrayElementType = rtype.getComponentType();
+         emitIconstInsn(name.arguments.length);
+         int xas;
 diff --git a/src/share/classes/java/lang/invoke/Invokers.java b/src/share/classes/java/lang/invoke/Invokers.java
 --- a/src/share/classes/java/lang/invoke/Invokers.java
 +++ b/src/share/classes/java/lang/invoke/Invokers.java
-@@ -1,5 +1,5 @@
- /*
-- * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
-+ * Copyright (c) 2008, 2013, 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
-@@ -16,7 +16,7 @@
-  *
-  * 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.
-+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-13*1 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
-@@ -31,91 +31,109 @@
+@@ -31,6 +31,8 @@
  import static java.lang.invoke.MethodHandleNatives.Constants.*;
  import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
  import static java.lang.invoke.LambdaForm.*;
@@ -1763,11 +126,8 @@
  
  /**
   * Construction and caching of often-used invokers.
-  * @author jrose
-  */
- class Invokers {
--    // exact type (sans leading taget MH) for the outgoing call
-+    // exact type (sans leading target MH) for the outgoing call
+@@ -40,51 +42,53 @@
+     // exact type (sans leading target MH) for the outgoing call
      private final MethodType targetType;
  
 -    // FIXME: Get rid of the invokers that are not useful.
@@ -1814,14 +174,6 @@
 -
 -    // invoker for an unbound callsite
 -    private /*lazy*/ MethodHandle uninitializedCallSite;
-+    /** Limit on implicitly generated spreader size.
-+     *  Above this limit, we use explicit argument arrays.
-+     */
-+    //@@ REMOVE?
-+    private static final int MAX_SPREAD_ARITY =
-+            Math.max(2,
-+                     Math.min(MethodType.MAX_JVM_ARITY,
-+                              (SPREAD_THRESHOLD == 0 ? Integer.MAX_VALUE : SPREAD_THRESHOLD)));
  
      /** Compute and cache information common to all collecting adapters
       *  that implement members of the erasure-family of the given erased type.
@@ -1835,17 +187,8 @@
 -        MethodHandle invoker = exactInvoker;
 +        MethodHandle invoker = invokers[INV_EXACT];
          if (invoker != null)  return invoker;
-         MethodType mtype = targetType;
-         MethodType invokerType = mtype.invokerType();
-         LambdaForm lform = invokeHandleForm(mtype, false, MethodTypeForm.LF_EX_INVOKER);
-         invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype);
--        invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke("invokeExact", mtype));
-+        invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke("invokeExact", mtype), false);
-         assert(checkInvoker(invoker));
-         if (targetType == targetType.erase() && targetType.parameterCount() < 10)
-             invoker.form.compileToBytecode();
+         invoker = makeExactOrGeneralInvoker(true);
 -        exactInvoker = invoker;
-+        //invoker.form.compileToBytecode();
 +        invokers[INV_EXACT] = invoker;
          return invoker;
      }
@@ -1855,21 +198,14 @@
 +    /*non-public*/ MethodHandle genericInvoker() {
 +        MethodHandle invoker = invokers[INV_GENERIC];
          if (invoker != null)  return invoker;
-         MethodType mtype = targetType;
-         MethodType invokerType = mtype.invokerType();
-         LambdaForm lform = invokeHandleForm(mtype, false, MethodTypeForm.LF_GEN_INVOKER);
-         invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype);
--        invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke("invoke", mtype));
-+        invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke("invoke", mtype), false);
-         assert(checkInvoker(invoker));
-         if (targetType == targetType.erase() && targetType.parameterCount() < 10)
-             invoker.form.compileToBytecode();
+         invoker = makeExactOrGeneralInvoker(false);
 -        generalInvoker = invoker;
-+        //invoker.form.compileToBytecode();
 +        invokers[INV_GENERIC] = invoker;
          return invoker;
      }
  
+@@ -111,17 +115,21 @@
+     }
  
      /*non-public*/ MethodHandle basicInvoker() {
 -        MethodHandle invoker = basicInvoker;
@@ -1884,7 +220,6 @@
 -        MemberName method = invokeBasicMethod(basicType);
 -        invoker = DirectMethodHandle.make(method);
 -        assert(checkInvoker(invoker));
--        //invoker.form.compileToBytecode();
 -        basicInvoker = invoker;
 +        invoker = basicType.form().cachedMethodHandle(MethodTypeForm.MH_BASIC_INV);
 +        if (invoker == null) {
@@ -1892,13 +227,12 @@
 +            invoker = DirectMethodHandle.make(method);
 +            assert(checkInvoker(invoker));
 +            invoker = basicType.form().setCachedMethodHandle(MethodTypeForm.MH_BASIC_INV, invoker);
-+            //invoker.form.compileToBytecode();
 +        }
 +        invokers[INV_BASIC] = invoker;
          return invoker;
      }
  
-@@ -130,6 +148,52 @@
+@@ -136,6 +144,52 @@
          }
      }
  
@@ -1951,7 +285,7 @@
      private boolean checkInvoker(MethodHandle invoker) {
          assert(targetType.invokerType().equals(invoker.type()))
                  : java.util.Arrays.asList(targetType, targetType.invokerType(), invoker);
-@@ -139,88 +203,197 @@
+@@ -145,87 +199,195 @@
          return true;
      }
  
@@ -2096,8 +430,7 @@
 +            vaInvoker = MethodHandles.filterArgument(arrayInvoker, 0, makeSpreader);
 +        }
 +        assert(vaInvoker.type().equals(preSpreadType.invokerType()));
-+        if (targetType == targetType.erase() && targetType.parameterCount() < 10)
-+            vaInvoker.form.compileToBytecode();
++        maybeCompileToBytecode(vaInvoker);
 +        invs[leadingArgCount] = vaInvoker;
 +        return vaInvoker;
 +    }
@@ -2148,12 +481,11 @@
 +            coInvoker = MethodHandles.filterArgument(normalInvoker, 0, makeCollector);
          }
 -        assert(vaInvoker.type().equals(spreadInvokerType.invokerType()));
-+        assert(coInvoker.type().equals(preCollectType.invokerType()));
-         if (targetType == targetType.erase() && targetType.parameterCount() < 10)
--            vaInvoker.form.compileToBytecode();
+-        maybeCompileToBytecode(vaInvoker);
 -        spreadInvokers[leadingArgCount] = vaInvoker;
 -        return vaInvoker;
-+            coInvoker.form.compileToBytecode();
++        assert(coInvoker.type().equals(preCollectType.invokerType()));
++        maybeCompileToBytecode(coInvoker);
 +        invs[leadingArgCount] = coInvoker;
 +        return coInvoker;
      }
@@ -2199,7 +531,7 @@
 -            }
 -        }
 -        invoker = MethodHandles.explicitCastArguments(invoker, MethodType.methodType(targetType.returnType()));
--        invoker = invoker.dropArguments(targetType, 0, targetType.parameterCount());
+-        invoker = MethodHandles.dropArguments(invoker, 0, targetType.parameterList());
 -        assert(invoker.type().equals(targetType));
 -        uninitializedCallSite = invoker;
 -        return invoker;
@@ -2208,100 +540,33 @@
      }
  
      public String toString() {
-@@ -306,7 +479,7 @@
-                 : Arrays.asList(mtype, customized, which, nameCursor, names.length);
-         if (MTYPE_ARG >= INARG_LIMIT) {
-             assert(names[MTYPE_ARG] == null);
--            NamedFunction getter = BoundMethodHandle.getSpeciesData("L").getterFunction(0);
-+            NamedFunction getter = BoundMethodHandle.speciesData_L().getterFunction(0);
-             names[MTYPE_ARG] = new Name(getter, names[THIS_MH]);
-             // else if isLinker, then MTYPE is passed in from the caller (e.g., the JVM)
-         }
-@@ -361,6 +534,7 @@
-         if (COUNT_EVENTS) {
-             bump(EC_checkGenericType);
-             if (mh.type() == expected)  bump(EC_checkGenericType_exact);
-+            else if (mh.asTypeCache != null && mh.asTypeCache.type() == expected)  bump(EC_checkGenericType_hit);
-             else  bump(EC_checkGenericType_miss);
-         }
-         if (mh.type() == expected)  return mh;
-@@ -385,6 +559,10 @@
-          *  => MH.asType(MT0).invokeBasic(A*)
-          */
-     }
-+    private static final EventCounter EC_checkGenericType = eventCounter("checkGenericType");
-+    private static final EventCounter EC_checkGenericType_exact = eventCounter(EC_checkGenericType, "exact");
-+    private static final EventCounter EC_checkGenericType_hit = eventCounter(EC_checkGenericType, "hit");
-+    private static final EventCounter EC_checkGenericType_miss = eventCounter(EC_checkGenericType, "miss");
- 
-     static MemberName linkToCallSiteMethod(MethodType mtype) {
-         LambdaForm lform = callSiteForm(mtype, false);
-@@ -395,10 +573,6 @@
-         LambdaForm lform = callSiteForm(mtype, true);
-         return lform.vmentry;
-     }
--    private static final EventCounter EC_checkGenericType = eventCounter("checkGenericType");
--    private static final EventCounter EC_checkGenericType_exact = eventCounter(EC_checkGenericType, "exact");
--    private static final EventCounter EC_checkGenericType_hit = eventCounter(EC_checkGenericType, "hit");
--    private static final EventCounter EC_checkGenericType_miss = eventCounter(EC_checkGenericType, "miss");
- 
-     // skipCallSite is true if we are optimizing a ConstantCallSite
-     private static LambdaForm callSiteForm(MethodType mtype, boolean skipCallSite) {
-@@ -443,24 +617,34 @@
-     }
- 
-     // 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,
+@@ -446,6 +608,9 @@
+     private static final NamedFunction
+         NF_checkExactType,
+         NF_checkGenericType,
 +        NF_nextParameterTypes,
 +        NF_convertParameter,
 +        NF_convertReturn,
-+        NF_getCallSiteTarget;
+         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)),
+@@ -454,6 +619,12 @@
+                         .getDeclaredMethod("checkExactType", Object.class, Object.class)),
+                 NF_checkGenericType = new NamedFunction(Invokers.class
+                         .getDeclaredMethod("checkGenericType", Object.class, Object.class)),
 +                NF_nextParameterTypes = new NamedFunction(Invokers.class
 +                        .getDeclaredMethod("nextParameterTypes", Object.class, Object.class)),
 +                NF_convertParameter = new NamedFunction(Invokers.class
 +                        .getDeclaredMethod("convertParameter", Object.class, int.class, Object.class)),
 +                NF_convertReturn = new NamedFunction(Invokers.class
 +                        .getDeclaredMethod("convertReturn", 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);
-         }
+                 NF_getCallSiteTarget = new NamedFunction(Invokers.class
+                         .getDeclaredMethod("getCallSiteTarget", Object.class))
+             };
 diff --git a/src/share/classes/java/lang/invoke/LambdaForm.java b/src/share/classes/java/lang/invoke/LambdaForm.java
 --- a/src/share/classes/java/lang/invoke/LambdaForm.java
 +++ b/src/share/classes/java/lang/invoke/LambdaForm.java
-@@ -124,12 +124,51 @@
+@@ -124,9 +124,7 @@
      final String debugName;
      MemberName vmentry;   // low-level behavior, or null if not yet prepared
      private boolean isCompiled;
@@ -2312,367 +577,14 @@
  
      public static final int VOID_RESULT = -1, LAST_RESULT = -2;
  
-+    // Numeric indexes for basic type characters.
-+    public static final byte
-+            L_TYPE = 0,  // all reference types
-+            I_TYPE = 1, J_TYPE = 2, F_TYPE = 3, D_TYPE = 4,  // all primitive types
-+            V_TYPE = 5,  // not valid in all contexts
-+            ARG_TYPE_LIMIT = V_TYPE, TYPE_LIMIT = V_TYPE+1;
-+    public static final String BASIC_TYPE_CHARS = "LIJFDV";
-+    private static final Class<?>[] BASIC_TYPE_CLASSES = {
-+        Object.class,
-+        int.class, long.class, float.class, double.class,
-+        void.class
-+    };
-+    private static final Wrapper[] BASIC_TYPE_WRAPPERS = {
-+        Wrapper.OBJECT,
-+        Wrapper.INT, Wrapper.LONG, Wrapper.FLOAT, Wrapper.DOUBLE,
-+        Wrapper.VOID
-+    };
-+    static { assert(verifyBasicTypeChars()); }
-+    private static boolean verifyBasicTypeChars() {
-+        Object[] data = {
-+            'L', L_TYPE, 'I', I_TYPE, 'J', J_TYPE, 'F', F_TYPE, 'D', D_TYPE, 'V', V_TYPE
-+        };
-+        assert(data.length == TYPE_LIMIT*2);  // all cases covered
-+        for (int i = 0; i < TYPE_LIMIT; i++) {
-+            char btc = (char) data[2*i+0];
-+            byte bti = (byte) data[2*i+1];
-+            assert(BASIC_TYPE_CHARS.charAt(bti) == btc);
-+            Class<?> c = BASIC_TYPE_CLASSES[bti];
-+            assert(Wrapper.basicTypeChar(c) == btc);
-+            if (btc != 'V')
-+                assert(bti < ARG_TYPE_LIMIT);  // all arg types must come before void
-+            else
-+                assert(bti == ARG_TYPE_LIMIT);  // void type must be beyond arg type sequence
-+        }
-+        assert(ARG_TYPE_LIMIT == V_TYPE);  // V must be after all arg types
-+        assert(BASIC_TYPE_CHARS.length() == TYPE_LIMIT);
-+        assert(BASIC_TYPE_CLASSES.length == TYPE_LIMIT);
-+        assert(BASIC_TYPE_WRAPPERS.length == TYPE_LIMIT);
-+        return true;
-+    }
-+
-     LambdaForm(String debugName,
-                int arity, Name[] names, int result) {
-         assert(namesOK(arity, names));
-@@ -169,12 +208,12 @@
-         // Called only from getPreparedForm.
-         assert(isValidSignature(sig));
-         this.arity = signatureArity(sig);
--        this.result = (signatureReturn(sig) == 'V' ? -1 : arity);
-+        this.result = (signatureReturn(sig) == V_TYPE ? -1 : arity);
-         this.names = buildEmptyNames(arity, sig);
-         this.debugName = "LF.zero";
-         assert(nameRefsAreLegal());
-         assert(isEmpty());
--        assert(sig.equals(basicTypeSignature()));
-+        assert(sig.equals(basicTypeSignature())) : sig + " != " + basicTypeSignature();
-         bump(EC_lambdaForm);
-         bump(EC_lambdaForm_blank);
-     }
-@@ -184,17 +223,17 @@
-         int resultPos = arity + 1;  // skip '_'
-         if (arity < 0 || basicTypeSignature.length() != resultPos+1)
-             throw new IllegalArgumentException("bad arity for "+basicTypeSignature);
--        int numRes = (basicTypeSignature.charAt(resultPos) == 'V' ? 0 : 1);
-+        int numRes = (basicType(basicTypeSignature.charAt(resultPos)) == V_TYPE ? 0 : 1);
-         Name[] names = arguments(numRes, basicTypeSignature.substring(0, arity));
-         for (int i = 0; i < numRes; i++) {
--            names[arity + i] = constantZero(arity + i, basicTypeSignature.charAt(resultPos + i));
-+            names[arity + i] = constantZero(arity + i, basicType(basicTypeSignature.charAt(resultPos + i)));
-         }
-         return names;
-     }
- 
-     private static int fixResult(int result, Name[] names) {
-         if (result >= 0) {
--            if (names[result].type == 'V')
-+            if (names[result].type == V_TYPE)
-                 return -1;
-         } else if (result == LAST_RESULT) {
-             return names.length - 1;
-@@ -264,7 +303,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?
-@@ -297,14 +336,14 @@
-     // }
- 
-     /** Report the return type. */
--    char returnType() {
--        if (result < 0)  return 'V';
-+    byte returnType() {
-+        if (result < 0)  return V_TYPE;
-         Name n = names[result];
-         return n.type;
-     }
- 
-     /** Report the N-th argument type. */
--    char parameterType(int n) {
-+    byte parameterType(int n) {
-         assert(n < arity);
-         return names[n].type;
-     }
-@@ -314,6 +353,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());
-@@ -322,15 +366,15 @@
-     final String basicTypeSignature() {
-         StringBuilder buf = new StringBuilder(arity() + 3);
-         for (int i = 0, a = arity(); i < a; i++)
--            buf.append(parameterType(i));
--        return buf.append('_').append(returnType()).toString();
-+            buf.append(basicTypeChar(parameterType(i)));
-+        return buf.append('_').append(basicTypeChar(returnType())).toString();
-     }
-     static int signatureArity(String sig) {
-         assert(isValidSignature(sig));
-         return sig.indexOf('_');
-     }
--    static char signatureReturn(String sig) {
--        return sig.charAt(signatureArity(sig)+1);
-+    static byte signatureReturn(String sig) {
-+        return basicType(sig.charAt(signatureArity(sig)+1));
-     }
-     static boolean isValidSignature(String sig) {
-         int arity = sig.indexOf('_');
-@@ -342,27 +386,15 @@
-             char c = sig.charAt(i);
-             if (c == 'V')
-                 return (i == siglen - 1 && arity == siglen - 2);
--            if (ALL_TYPES.indexOf(c) < 0)  return false; // must be [LIJFD]
-+            if (BASIC_TYPE_CHARS.indexOf(c) < 0)  return false; // must be [LIJFD]
-         }
-         return true;  // [LIJFD]*_[LIJFDV]
-     }
--    static Class<?> typeClass(char t) {
--        switch (t) {
--        case 'I': return int.class;
--        case 'J': return long.class;
--        case 'F': return float.class;
--        case 'D': return double.class;
--        case 'L': return Object.class;
--        case 'V': return void.class;
--        default: assert false;
--        }
--        return null;
--    }
-     static MethodType signatureType(String sig) {
-         Class<?>[] ptypes = new Class<?>[signatureArity(sig)];
-         for (int i = 0; i < ptypes.length; i++)
--            ptypes[i] = typeClass(sig.charAt(i));
--        Class<?> rtype = typeClass(signatureReturn(sig));
-+            ptypes[i] = basicTypeClass(basicType(sig.charAt(i)));
-+        Class<?> rtype = basicTypeClass(signatureReturn(sig));
-         return MethodType.methodType(rtype, ptypes);
-     }
- 
-@@ -446,7 +478,7 @@
-         // TO DO: Maybe add invokeGeneric, invokeWithArguments
-         bump(EC_lambdaForm_prep);
-         if (false && COUNT_EVENTS)//@@
--        if ((EC_lambdaForm_prep.count() & (0x2000-1)) == 0)  Thread.dumpStack();//@@
-+        if ((EC_lambdaForm_prep.count() % 100) == 0)  Thread.dumpStack();//@@
- 
-     }
- 
-@@ -463,10 +495,17 @@
-                 traceInterpreter("compileToBytecode", this);
-             isCompiled = true;
-             bump(EC_lambdaForm_comp);
--            return vmentry;
-         } catch (Error | Exception ex) {
--            throw newInternalError("compileToBytecode", ex);
-+            throw newInternalError(this.toString(), ex);
-         }
-+        // Also compile functions used inside:
-+        for (Name n : names) {
-+            if (n.isParam())  continue;
-+            MethodHandle fn = n.function.resolvedHandle;
-+            if (fn != null)
-+                fn.form.compileToBytecode();
-+        }
-+        return vmentry;
-     }
- 
-     private static final ConcurrentHashMap<String,LambdaForm> PREPARED_FORMS;
-@@ -490,7 +529,7 @@
-                 assert(m.getName().equals("interpret" + sig.substring(sig.indexOf('_'))));
-                 LambdaForm form = new LambdaForm(sig);
-                 form.vmentry = m;
--                mt.form().setCachedLambdaForm(MethodTypeForm.LF_COUNTER, form);
-+                //mt.form().setCachedLambdaForm(MethodTypeForm.LF_?, form);
-                 // FIXME: get rid of PREPARED_FORMS; use MethodTypeForm cache only
-                 forms.put(sig, form);
-             }
-@@ -551,21 +590,21 @@
-         assert(mt.parameterCount() == arity-1);
-         for (int i = 0; i < av.length; i++) {
-             Class<?> pt = (i == 0 ? MethodHandle.class : mt.parameterType(i-1));
--            assert(valueMatches(sig.charAt(i), pt, av[i]));
-+            assert(valueMatches(basicType(sig.charAt(i)), pt, av[i]));
-         }
-         return true;
-     }
--    private static boolean valueMatches(char tc, Class<?> type, Object x) {
-+    private static boolean valueMatches(byte tc, Class<?> type, Object x) {
-         // The following line is needed because (...)void method handles can use non-void invokers
--        if (type == void.class)  tc = 'V';   // can drop any kind of value
-+        if (type == void.class)  tc = V_TYPE;   // can drop any kind of value
-         assert tc == basicType(type) : tc + " == basicType(" + type + ")=" + basicType(type);
-         switch (tc) {
--        case 'I': assert checkInt(type, x)   : "checkInt(" + type + "," + x +")";   break;
--        case 'J': assert x instanceof Long   : "instanceof Long: " + x;             break;
--        case 'F': assert x instanceof Float  : "instanceof Float: " + x;            break;
--        case 'D': assert x instanceof Double : "instanceof Double: " + x;           break;
--        case 'L': assert checkRef(type, x)   : "checkRef(" + type + "," + x + ")";  break;
--        case 'V': break;  // allow anything here; will be dropped
-+        case I_TYPE: assert checkInt(type, x)   : "checkInt(" + type + "," + x +")";   break;
-+        case J_TYPE: assert x instanceof Long   : "instanceof Long: " + x;             break;
-+        case F_TYPE: assert x instanceof Float  : "instanceof Float: " + x;            break;
-+        case D_TYPE: assert x instanceof Double : "instanceof Double: " + x;           break;
-+        case L_TYPE: assert checkRef(type, x)   : "checkRef(" + type + "," + x + ")";  break;
-+        case V_TYPE: break;  // allow anything here; will be dropped
-         default:  assert(false);
-         }
-         return true;
-@@ -590,14 +629,23 @@
-     }
- 
-     /** If the invocation count hits the threshold we spin bytecodes and call that subsequently. */
--    private static final int COMPILE_THRESHOLD;
-+    static final int COMPILE_THRESHOLD;
-     static {
--        if (MethodHandleStatics.COMPILE_THRESHOLD != null)
--            COMPILE_THRESHOLD = MethodHandleStatics.COMPILE_THRESHOLD;
-+        if (MethodHandleStatics.COMPILE_THRESHOLD == 0)
-+            COMPILE_THRESHOLD = 30;  // default value
-         else
--            COMPILE_THRESHOLD = 30;  // default value
-+            COMPILE_THRESHOLD = Math.max(-1, MethodHandleStatics.COMPILE_THRESHOLD);
-     }
-     private int invocationCounter = 0;
-+    int getInvocationsRemaining() {
-+        return Math.max(0, COMPILE_THRESHOLD - invocationCounter);
-+    }
-+    void setInvocationsRemaining(int n) {
-+        if (invocationCounter >= COMPILE_THRESHOLD)  return;
-+        if (n < 0)  n = 0;
-+        if (n > COMPILE_THRESHOLD)  n = COMPILE_THRESHOLD;
-+        invocationCounter = Math.max(invocationCounter, COMPILE_THRESHOLD - n);
-+    }
- 
-     @Hidden
-     @DontInline
-@@ -612,7 +660,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
-@@ -702,8 +752,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;
-     }
- 
-@@ -730,6 +788,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 && INIT_DONE) {
-             // Extra verbosity:
-@@ -739,135 +798,11 @@
+@@ -832,86 +830,11 @@
          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, char 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);
--    }
--
 -    LambdaForm bind(int namePos, BoundMethodHandle.SpeciesData oldData) {
 -        Name name = names[namePos];
--        BoundMethodHandle.SpeciesData newData = oldData.extendWithType(name.type);
--        return bind(name, newData.getterName(names[0], oldData.fieldCount()), oldData, newData);
+-        BoundMethodHandle.SpeciesData newData = oldData.extendWith(name.type);
+-        return bind(name, new Name(newData.getterFunction(oldData.fieldCount()), names[0]), oldData, newData);
 -    }
 -    LambdaForm bind(Name name, Name binding,
 -                    BoundMethodHandle.SpeciesData oldData,
@@ -2733,7 +645,7 @@
 -        int insPos = pos;
 -        for (; insPos+1 < names2.length; insPos++) {
 -            Name n = names2[insPos+1];
--            if (n.isSiblingBindingBefore(binding)) {
+-            if (n.isParam()) {
 -                names2[insPos] = n;
 -            } else {
 -                break;
@@ -2757,11 +669,11 @@
      }
  
      boolean contains(Name name) {
-@@ -882,102 +817,6 @@
+@@ -926,102 +849,6 @@
          return false;
      }
  
--    LambdaForm addArguments(int pos, char... types) {
+-    LambdaForm addArguments(int pos, byte... types) {
 -        assert(pos <= arity);
 -        int length = names.length;
 -        int inTypes = types.length;
@@ -2782,13 +694,13 @@
 -    }
 -
 -    LambdaForm addArguments(int pos, List<Class<?>> types) {
--        char[] basicTypes = new char[types.size()];
+-        byte[] basicTypes = new byte[types.size()];
 -        for (int i = 0; i < basicTypes.length; i++)
 -            basicTypes[i] = basicType(types.get(i));
 -        return addArguments(pos, basicTypes);
 -    }
 -
--    LambdaForm permuteArguments(int skip, int[] reorder, char[] types) {
+-    LambdaForm permuteArguments(int skip, int[] reorder, byte[] types) {
 -        // Note:  When inArg = reorder[outArg], outArg is fed by a copy of inArg.
 -        // The types are the types of the new (incoming) arguments.
 -        int length = names.length;
@@ -2847,7 +759,7 @@
 -        return new LambdaForm(debugName, arity2, names2, result2);
 -    }
 -
--    static boolean permutedTypesMatch(int[] reorder, char[] types, Name[] names, int skip) {
+-    static boolean permutedTypesMatch(int[] reorder, byte[] types, Name[] names, int skip) {
 -        int inTypes = types.length;
 -        int outArgs = reorder.length;
 -        for (int i = 0; i < outArgs; i++) {
@@ -2860,388 +772,11 @@
      static class NamedFunction {
          final MemberName member;
          MethodHandle resolvedHandle;
-@@ -987,13 +826,14 @@
-             this(resolvedHandle.internalMemberName(), resolvedHandle);
-         }
-         NamedFunction(MemberName member, MethodHandle resolvedHandle) {
-+            bump(EC_namedFunction);
-             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) {
-             bump(EC_namedFunction);
--        }
--        private static final EventCounter EC_namedFunction = eventCounter("namedFunction");
--        NamedFunction(MethodType basicInvokerType) {
-             assert(basicInvokerType == basicInvokerType.basicType()) : basicInvokerType;
-             if (basicInvokerType.parameterSlotCount() < MethodType.MAX_MH_INVOKER_ARITY) {
-                 this.resolvedHandle = basicInvokerType.invokers().basicInvoker();
-@@ -1002,6 +842,12 @@
-                 // necessary to pass BigArityTest
-                 this.member = Invokers.invokeBasicMethod(basicInvokerType);
-             }
-+            assert(isInvokeBasic());
-+        }
-+        private static final EventCounter EC_namedFunction = eventCounter("namedFunction");
-+
-+        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.
-@@ -1054,10 +900,10 @@
-                     String sig = m.getName().substring("invoke_".length());
-                     int arity = LambdaForm.signatureArity(sig);
-                     MethodType srcType = MethodType.genericMethodType(arity);
--                    if (LambdaForm.signatureReturn(sig) == 'V')
-+                    if (LambdaForm.signatureReturn(sig) == V_TYPE)
-                         srcType = srcType.changeReturnType(void.class);
-                     MethodTypeForm typeForm = srcType.form();
--                    typeForm.namedFunctionInvoker = DirectMethodHandle.make(m);
-+                    typeForm.setCachedMethodHandle(MethodTypeForm.MH_NF_INV, DirectMethodHandle.make(m));
-                 }
-             }
-         }
-@@ -1137,16 +983,17 @@
-             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 new InternalError(mh.debugString());
-             bump(EC_lambdaForm_invoker);
--            return typeForm.namedFunctionInvoker = mh;
-+            return typeForm.setCachedMethodHandle(MethodTypeForm.MH_NF_INV, mh);
-         }
- 
-         @Hidden
-@@ -1236,11 +1083,11 @@
-             return (member == null) ? null : member.getDeclaringClass();
-         }
- 
--        char returnType() {
-+        byte returnType() {
-             return basicType(methodType().returnType());
-         }
- 
--        char parameterType(int n) {
-+        byte parameterType(int n) {
-             return basicType(methodType().parameterType(n));
-         }
- 
-@@ -1261,38 +1108,67 @@
-         for (Name n : names) n.resolve();
-     }
- 
--    public static char basicType(Class<?> type) {
--        char c = Wrapper.basicTypeChar(type);
--        if ("ZBSC".indexOf(c) >= 0)  c = 'I';
--        assert("LIJFDV".indexOf(c) >= 0);
--        return c;
-+    public static char basicTypeChar(byte type) {
-+        return BASIC_TYPE_CHARS.charAt(type);
-     }
--    public static char[] basicTypes(List<Class<?>> types) {
--        char[] btypes = new char[types.size()];
-+    public static byte basicType(char type) {
-+        int bti = BASIC_TYPE_CHARS.indexOf(type);
-+        if (bti >= 0)  return (byte) bti;
-+        assert("ZBSC".indexOf(type) >= 0);
-+        return I_TYPE;  // all subword types are represented as ints
-+    }
-+
-+    public static Wrapper basicTypeWrapper(byte type) {
-+        return BASIC_TYPE_WRAPPERS[type];
-+    }
-+    public static byte basicType(Wrapper type) {
-+        char c = type.basicTypeChar();
-+        return basicType(c);
-+    }
-+
-+    public static Class<?> basicTypeClass(byte type) {
-+        return BASIC_TYPE_CLASSES[type];
-+    }
-+    public static byte basicType(Class<?> type) {
-+        if (!type.isPrimitive())  return L_TYPE;
-+        return basicType(Wrapper.forPrimitiveType(type));
-+    }
-+    public static char basicTypeChar(Class<?> type) {
-+        return BASIC_TYPE_CHARS.charAt(basicType(type));
-+    }
-+    public static byte[] basicTypes(List<Class<?>> types) {
-+        byte[] btypes = new byte[types.size()];
-         for (int i = 0; i < btypes.length; i++) {
-             btypes[i] = basicType(types.get(i));
-         }
-         return btypes;
-     }
-+    public static byte[] basicTypes(String types) {
-+        byte[] btypes = new byte[types.length()];
-+        for (int i = 0; i < btypes.length; i++) {
-+            btypes[i] = basicType(types.charAt(i));
-+        }
-+        return btypes;
-+    }
-     public static String basicTypeSignature(MethodType type) {
-         char[] sig = new char[type.parameterCount() + 2];
-         int sigp = 0;
-         for (Class<?> pt : type.parameterList()) {
--            sig[sigp++] = basicType(pt);
-+            sig[sigp++] = basicTypeChar(pt);
-         }
-         sig[sigp++] = '_';
--        sig[sigp++] = basicType(type.returnType());
-+        sig[sigp++] = basicTypeChar(type.returnType());
-         assert(sigp == sig.length);
-         return String.valueOf(sig);
-     }
- 
-     static final class Name {
--        final char type;
-+        final byte type;
-         private short index;
-         final NamedFunction function;
-         final Object[] arguments;
- 
--        private Name(int index, char type, NamedFunction function, Object[] arguments) {
-+        private Name(int index, byte type, NamedFunction function, Object[] arguments) {
-             this.index = (short)index;
-             this.type = type;
-             this.function = function;
-@@ -1304,7 +1180,7 @@
-         }
-         Name(MethodType functionType, Object... arguments) {
-             this(new NamedFunction(functionType), arguments);
--            assert(arguments[0] instanceof Name && ((Name)arguments[0]).type == 'L');
-+            assert(arguments[0] instanceof Name && ((Name)arguments[0]).type == L_TYPE);
-         }
-         Name(MemberName function, Object... arguments) {
-             this(new NamedFunction(function), arguments);
-@@ -1315,14 +1191,16 @@
-             for (int i = 0; i < arguments.length; i++)
-                 assert(typesMatch(function.parameterType(i), arguments[i])) : "types don't match: function.parameterType(" + i + ")=" + function.parameterType(i) + ", arguments[" + i + "]=" + arguments[i] + " in " + debugString();
-         }
--        Name(int index, char type) {
-+        /** Create a raw parameter of the given type, with an expected index. */
-+        Name(int index, byte type) {
-             this(index, type, null, null);
-         }
--        Name(char type) {
-+        /** Create a raw parameter of the given type. */
-+        Name(byte type) {
-             this(-1, type);
-         }
- 
--        char type() { return type; }
-+        byte type() { return type; }
-         int index() { return index; }
-         boolean initIndex(int i) {
-             if (index != i) {
-@@ -1331,7 +1209,9 @@
-             }
-             return true;
-         }
--
-+        char typeChar() {
-+            return basicTypeChar(type);
-+        }
- 
-         void resolve() {
-             if (function != null)
-@@ -1364,7 +1244,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;
-@@ -1413,14 +1297,14 @@
-         }
- 
-         public String toString() {
--            return (isParam()?"a":"t")+(index >= 0 ? index : System.identityHashCode(this))+":"+type;
-+            return (isParam()?"a":"t")+(index >= 0 ? index : System.identityHashCode(this))+":"+typeChar();
-         }
-         public String debugString() {
-             String s = toString();
-             return (function == null) ? s : s + "=" + exprString();
-         }
-         public String exprString() {
--            if (function == null)  return "null";
-+            if (function == null)  return toString();
-             StringBuilder buf = new StringBuilder(function.toString());
-             buf.append("(");
-             String cma = "";
-@@ -1435,48 +1319,32 @@
-             return buf.toString();
-         }
- 
--        private static boolean typesMatch(char parameterType, Object object) {
-+        static boolean typesMatch(byte parameterType, Object object) {
-             if (object instanceof Name) {
-                 return ((Name)object).type == parameterType;
-             }
-             switch (parameterType) {
--                case 'I':  return object instanceof Integer;
--                case 'J':  return object instanceof Long;
--                case 'F':  return object instanceof Float;
--                case 'D':  return object instanceof Double;
-+                case I_TYPE:  return object instanceof Integer;
-+                case J_TYPE:  return object instanceof Long;
-+                case F_TYPE:  return object instanceof Float;
-+                case D_TYPE:  return object instanceof Double;
-             }
--            assert(parameterType == 'L');
-+            assert(parameterType == L_TYPE);
-             return true;
-         }
- 
--        /**
--         * 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.
--         * @param binding
--         * @return
-+        /** Return the index of the last occurrence of n in the argument array.
-+         *  Return -1 if the name is not used.
-          */
--        boolean isSiblingBindingBefore(Name binding) {
--            assert(!binding.isParam());
--            if (isParam())  return true;
--            if (function.equals(binding.function) &&
--                arguments.length == binding.arguments.length) {
--                boolean sawInt = false;