changeset 424:38a9d08784f5

meth: rebase to current hsx/hotspot-comp
author jrose
date Sat, 11 Aug 2012 21:23:05 -0700
parents 90c60ec5aba4
children 17b551da7237
files meth-lazy-7023639.patch meth.patch series
diffstat 3 files changed, 2581 insertions(+), 13495 deletions(-) [+]
line wrap: on
line diff
--- a/meth-lazy-7023639.patch	Thu Jul 26 17:14:52 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13486 +0,0 @@
-7023639: JSR 292 method handle invocation needs a fast path for compiled code
-6984705: JSR 292 method handle creation should not go through JNI
-Summary: remove assembly code for JDK 7 chained method handles
-Reviewed-by: jrose, twisti, mhaupt, forax, David Schlosnagle, Aleksey Shipilev
-Contributed-by: jrose, twisti, mhaupt
-
-diff --git a/src/share/classes/java/lang/invoke/AdapterMethodHandle.java b/src/share/classes/java/lang/invoke/AdapterMethodHandle.java
-deleted file mode 100644
---- a/src/share/classes/java/lang/invoke/AdapterMethodHandle.java
-+++ /dev/null
-@@ -1,1204 +0,0 @@
--/*
-- * Copyright (c) 2008, 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.VerifyType;
--import sun.invoke.util.Wrapper;
--import sun.invoke.util.ValueConversions;
--import java.util.Arrays;
--import java.util.ArrayList;
--import java.util.Collections;
--import static java.lang.invoke.MethodHandleNatives.Constants.*;
--import static java.lang.invoke.MethodHandleStatics.*;
--
--/**
-- * This method handle performs simple conversion or checking of a single argument.
-- * @author jrose
-- */
--class AdapterMethodHandle extends BoundMethodHandle {
--
--    //MethodHandle vmtarget;   // next AMH or BMH in chain or final DMH
--    //Object       argument;   // parameter to the conversion if needed
--    //int          vmargslot;  // which argument slot is affected
--    private final int conversion;  // the type of conversion: RETYPE_ONLY, etc.
--
--    // Constructors in this class *must* be package scoped or private.
--    private AdapterMethodHandle(MethodHandle target, MethodType newType,
--                long conv, Object convArg) {
--        super(newType, convArg, newType.parameterSlotDepth(1+convArgPos(conv)));
--        this.conversion = convCode(conv);
--        // JVM might update VM-specific bits of conversion (ignore)
--        MethodHandleNatives.init(this, target, convArgPos(conv));
--    }
--    AdapterMethodHandle(MethodHandle target, MethodType newType,
--                long conv) {
--        this(target, newType, conv, null);
--    }
--
--    int getConversion() { return conversion; }
--
--    // TO DO:  When adapting another MH with a null conversion, clone
--    // the target and change its type, instead of adding another layer.
--
--    /** Can a JVM-level adapter directly implement the proposed
--     *  argument conversions, as if by fixed-arity MethodHandle.asType?
--     */
--    static boolean canPairwiseConvert(MethodType newType, MethodType oldType, int level) {
--        // same number of args, of course
--        int len = newType.parameterCount();
--        if (len != oldType.parameterCount())
--            return false;
--
--        // Check return type.
--        Class<?> exp = newType.returnType();
--        Class<?> ret = oldType.returnType();
--        if (!VerifyType.isNullConversion(ret, exp)) {
--            if (!convOpSupported(OP_COLLECT_ARGS))
--                return false;
--            if (!canConvertArgument(ret, exp, level))
--                return false;
--        }
--
--        // Check args pairwise.
--        for (int i = 0; i < len; i++) {
--            Class<?> src = newType.parameterType(i); // source type
--            Class<?> dst = oldType.parameterType(i); // destination type
--            if (!canConvertArgument(src, dst, level))
--                return false;
--        }
--
--        return true;
--    }
--
--    /** Can a JVM-level adapter directly implement the proposed
--     *  argument conversion, as if by fixed-arity MethodHandle.asType?
--     */
--    static boolean canConvertArgument(Class<?> src, Class<?> dst, int level) {
--        // ? Retool this logic to use RETYPE_ONLY, CHECK_CAST, etc., as opcodes,
--        // so we don't need to repeat so much decision making.
--        if (VerifyType.isNullConversion(src, dst)) {
--            return true;
--        } else if (convOpSupported(OP_COLLECT_ARGS)) {
--            // If we can build filters, we can convert anything to anything.
--            return true;
--        } else if (src.isPrimitive()) {
--            if (dst.isPrimitive())
--                return canPrimCast(src, dst);
--            else
--                return canBoxArgument(src, dst);
--        } else {
--            if (dst.isPrimitive())
--                return canUnboxArgument(src, dst, level);
--            else
--                return true;  // any two refs can be interconverted
--        }
--    }
--
--    /**
--     * Create a JVM-level adapter method handle to conform the given method
--     * handle to the similar newType, using only pairwise argument conversions.
--     * For each argument, convert incoming argument to the exact type needed.
--     * The argument conversions allowed are casting, boxing and unboxing,
--     * integral widening or narrowing, and floating point widening or narrowing.
--     * @param newType required call type
--     * @param target original method handle
--     * @param level which strength of conversion is allowed
--     * @return an adapter to the original handle with the desired new type,
--     *          or the original target if the types are already identical
--     *          or null if the adaptation cannot be made
--     */
--    static MethodHandle makePairwiseConvert(MethodType newType, MethodHandle target, int level) {
--        MethodType oldType = target.type();
--        if (newType == oldType)  return target;
--
--        if (!canPairwiseConvert(newType, oldType, level))
--            return null;
--        // (after this point, it is an assertion error to fail to convert)
--
--        // Find last non-trivial conversion (if any).
--        int lastConv = newType.parameterCount()-1;
--        while (lastConv >= 0) {
--            Class<?> src = newType.parameterType(lastConv); // source type
--            Class<?> dst = oldType.parameterType(lastConv); // destination type
--            if (isTrivialConversion(src, dst, level)) {
--                --lastConv;
--            } else {
--                break;
--            }
--        }
--
--        Class<?> needReturn = newType.returnType();
--        Class<?> haveReturn = oldType.returnType();
--        boolean retConv = !isTrivialConversion(haveReturn, needReturn, level);
--
--        // Now build a chain of one or more adapters.
--        MethodHandle adapter = target, adapter2;
--        MethodType midType = oldType;
--        for (int i = 0; i <= lastConv; i++) {
--            Class<?> src = newType.parameterType(i); // source type
--            Class<?> dst = midType.parameterType(i); // destination type
--            if (isTrivialConversion(src, dst, level)) {
--                // do nothing: difference is trivial
--                continue;
--            }
--            // Work the current type backward toward the desired caller type:
--            midType = midType.changeParameterType(i, src);
--            if (i == lastConv) {
--                // When doing the last (or only) real conversion,
--                // force all remaining null conversions to happen also.
--                MethodType lastMidType = newType;
--                if (retConv)  lastMidType = lastMidType.changeReturnType(haveReturn);
--                assert(VerifyType.isNullConversion(lastMidType, midType));
--                midType = lastMidType;
--            }
--
--            // Tricky case analysis follows.
--            // It parallels canConvertArgument() above.
--            if (src.isPrimitive()) {
--                if (dst.isPrimitive()) {
--                    adapter2 = makePrimCast(midType, adapter, i, dst);
--                } else {
--                    adapter2 = makeBoxArgument(midType, adapter, i, src);
--                }
--            } else {
--                if (dst.isPrimitive()) {
--                    // Caller has boxed a primitive.  Unbox it for the target.
--                    // The box type must correspond exactly to the primitive type.
--                    // This is simpler than the powerful set of widening
--                    // conversions supported by reflect.Method.invoke.
--                    // Those conversions require a big nest of if/then/else logic,
--                    // which we prefer to make a user responsibility.
--                    adapter2 = makeUnboxArgument(midType, adapter, i, dst, level);
--                } else {
--                    // Simple reference conversion.
--                    // Note:  Do not check for a class hierarchy relation
--                    // between src and dst.  In all cases a 'null' argument
--                    // will pass the cast conversion.
--                    adapter2 = makeCheckCast(midType, adapter, i, dst);
--                }
--            }
--            assert(adapter2 != null) : Arrays.asList(src, dst, midType, adapter, i, target, newType);
--            assert(adapter2.type() == midType);
--            adapter = adapter2;
--        }
--        if (retConv) {
--            adapter2 = makeReturnConversion(adapter, haveReturn, needReturn);
--            assert(adapter2 != null);
--            adapter = adapter2;
--        }
--        if (adapter.type() != newType) {
--            // Only trivial conversions remain.
--            adapter2 = makeRetypeOnly(newType, adapter);
--            assert(adapter2 != null);
--            adapter = adapter2;
--            // Actually, that's because there were no non-trivial ones:
--            assert(lastConv == -1 || retConv);
--        }
--        assert(adapter.type() == newType);
--        return adapter;
--    }
--
--    private static boolean isTrivialConversion(Class<?> src, Class<?> dst, int level) {
--        if (src == dst || dst == void.class)  return true;
--        if (!VerifyType.isNullConversion(src, dst))  return false;
--        if (level > 1)  return true;  // explicitCastArguments
--        boolean sp = src.isPrimitive();
--        boolean dp = dst.isPrimitive();
--        if (sp != dp)  return false;
--        if (sp) {
--            // in addition to being a null conversion, forbid boolean->int etc.
--            return Wrapper.forPrimitiveType(dst)
--                    .isConvertibleFrom(Wrapper.forPrimitiveType(src));
--        } else {
--            return dst.isAssignableFrom(src);
--        }
--    }
--
--    private static MethodHandle makeReturnConversion(MethodHandle target, Class<?> haveReturn, Class<?> needReturn) {
--        MethodHandle adjustReturn;
--        if (haveReturn == void.class) {
--            // synthesize a zero value for the given void
--            Object zero = Wrapper.forBasicType(needReturn).zero();
--            adjustReturn = MethodHandles.constant(needReturn, zero);
--        } else {
--            MethodType needConversion = MethodType.methodType(needReturn, haveReturn);
--            adjustReturn = MethodHandles.identity(needReturn).asType(needConversion);
--        }
--        return makeCollectArguments(adjustReturn, target, 0, false);
--    }
--
--    /**
--     * Create a JVM-level adapter method handle to permute the arguments
--     * of the given method.
--     * @param newType required call type
--     * @param target original method handle
--     * @param argumentMap for each target argument, position of its source in newType
--     * @return an adapter to the original handle with the desired new type,
--     *          or the original target if the types are already identical
--     *          and the permutation is null
--     * @throws IllegalArgumentException if the adaptation cannot be made
--     *          directly by a JVM-level adapter, without help from Java code
--     */
--    static MethodHandle makePermutation(MethodType newType, MethodHandle target,
--                int[] argumentMap) {
--        MethodType oldType = target.type();
--        boolean nullPermutation = true;
--        for (int i = 0; i < argumentMap.length; i++) {
--            int pos = argumentMap[i];
--            if (pos != i)
--                nullPermutation = false;
--            if (pos < 0 || pos >= newType.parameterCount()) {
--                argumentMap = new int[0]; break;
--            }
--        }
--        if (argumentMap.length != oldType.parameterCount())
--            throw newIllegalArgumentException("bad permutation: "+Arrays.toString(argumentMap));
--        if (nullPermutation) {
--            MethodHandle res = makePairwiseConvert(newType, target, 0);
--            // well, that was easy
--            if (res == null)
--                throw newIllegalArgumentException("cannot convert pairwise: "+newType);
--            return res;
--        }
--
--        // Check return type.  (Not much can be done with it.)
--        Class<?> exp = newType.returnType();
--        Class<?> ret = oldType.returnType();
--        if (!VerifyType.isNullConversion(ret, exp))
--            throw newIllegalArgumentException("bad return conversion for "+newType);
--
--        // See if the argument types match up.
--        for (int i = 0; i < argumentMap.length; i++) {
--            int j = argumentMap[i];
--            Class<?> src = newType.parameterType(j);
--            Class<?> dst = oldType.parameterType(i);
--            if (!VerifyType.isNullConversion(src, dst))
--                throw newIllegalArgumentException("bad argument #"+j+" conversion for "+newType);
--        }
--
--        // Now figure out a nice mix of SWAP, ROT, DUP, and DROP adapters.
--        // A workable greedy algorithm is as follows:
--        // Drop unused outgoing arguments (right to left: shallowest first).
--        // Duplicate doubly-used outgoing arguments (left to right: deepest first).
--        // Then the remaining problem is a true argument permutation.
--        // Marshal the outgoing arguments as required from left to right.
--        // That is, find the deepest outgoing stack position that does not yet
--        // have the correct argument value, and correct at least that position
--        // by swapping or rotating in the misplaced value (from a shallower place).
--        // If the misplaced value is followed by one or more consecutive values
--        // (also misplaced)  issue a rotation which brings as many as possible
--        // into position.  Otherwise make progress with either a swap or a
--        // rotation.  Prefer the swap as cheaper, but do not use it if it
--        // breaks a slot pair.  Prefer the rotation over the swap if it would
--        // preserve more consecutive values shallower than the target position.
--        // When more than one rotation will work (because the required value
--        // is already adjacent to the target position), then use a rotation
--        // which moves the old value in the target position adjacent to
--        // one of its consecutive values.  Also, prefer shorter rotation
--        // spans, since they use fewer memory cycles for shuffling.
--
--        throw new UnsupportedOperationException("NYI");
--    }
--
--    private static byte basicType(Class<?> type) {
--        if (type == null)  return T_VOID;
--        switch (Wrapper.forBasicType(type)) {
--            case BOOLEAN:  return T_BOOLEAN;
--            case CHAR:     return T_CHAR;
--            case FLOAT:    return T_FLOAT;
--            case DOUBLE:   return T_DOUBLE;
--            case BYTE:     return T_BYTE;
--            case SHORT:    return T_SHORT;
--            case INT:      return T_INT;
--            case LONG:     return T_LONG;
--            case OBJECT:   return T_OBJECT;
--            case VOID:     return T_VOID;
--        }
--        return 99; // T_ILLEGAL or some such
--    }
--
--    /** Number of stack slots for the given type.
--     *  Two for T_DOUBLE and T_FLOAT, one for the rest.
--     */
--    private static int type2size(int type) {
--        assert(type >= T_BOOLEAN && type <= T_OBJECT);
--        return (type == T_LONG || type == T_DOUBLE) ? 2 : 1;
--    }
--    private static int type2size(Class<?> type) {
--        return type2size(basicType(type));
--    }
--
--    /** The given stackMove is the number of slots pushed.
--     * It might be negative.  Scale it (multiply) by the
--     * VM's notion of how an address changes with a push,
--     * to get the raw SP change for stackMove.
--     * Then shift and mask it into the correct field.
--     */
--    private static long insertStackMove(int stackMove) {
--        // following variable must be long to avoid sign extension after '<<'
--        long spChange = stackMove * MethodHandleNatives.JVM_STACK_MOVE_UNIT;
--        return (spChange & CONV_STACK_MOVE_MASK) << CONV_STACK_MOVE_SHIFT;
--    }
--
--    static int extractStackMove(int convOp) {
--        int spChange = convOp >> CONV_STACK_MOVE_SHIFT;
--        return spChange / MethodHandleNatives.JVM_STACK_MOVE_UNIT;
--    }
--
--    static int extractStackMove(MethodHandle target) {
--        if (target instanceof AdapterMethodHandle) {
--            AdapterMethodHandle amh = (AdapterMethodHandle) target;
--            return extractStackMove(amh.getConversion());
--        } else {
--            return 0;
--        }
--    }
--
--    /** Construct an adapter conversion descriptor for a single-argument conversion. */
--    @SuppressWarnings("cast")  // some (int) casts below provide clarity but trigger warnings
--    private static long makeConv(int convOp, int argnum, int src, int dest) {
--        assert(src  == (src  & CONV_TYPE_MASK));
--        assert(dest == (dest & CONV_TYPE_MASK));
--        assert(convOp >= OP_CHECK_CAST && convOp <= OP_PRIM_TO_REF || convOp == OP_COLLECT_ARGS);
--        int stackMove = type2size(dest) - type2size(src);
--        return ((long) argnum << 32 |
--                (long) convOp << CONV_OP_SHIFT |
--                (int)  src    << CONV_SRC_TYPE_SHIFT |
--                (int)  dest   << CONV_DEST_TYPE_SHIFT |
--                insertStackMove(stackMove)
--                );
--    }
--    @SuppressWarnings("cast")  // some (int) casts below provide clarity but trigger warnings
--    private static long makeDupConv(int convOp, int argnum, int stackMove) {
--        // simple argument motion, requiring one slot to specify
--        assert(convOp == OP_DUP_ARGS || convOp == OP_DROP_ARGS);
--        byte src = 0, dest = 0;
--        return ((long) argnum << 32 |
--                (long) convOp << CONV_OP_SHIFT |
--                (int)  src    << CONV_SRC_TYPE_SHIFT |
--                (int)  dest   << CONV_DEST_TYPE_SHIFT |
--                insertStackMove(stackMove)
--                );
--    }
--    @SuppressWarnings("cast")  // some (int) casts below provide clarity but trigger warnings
--    private static long makeSwapConv(int convOp, int srcArg, byte srcType, int destSlot, byte destType) {
--        // more complex argument motion, requiring two slots to specify
--        assert(convOp == OP_SWAP_ARGS || convOp == OP_ROT_ARGS);
--        return ((long) srcArg << 32 |
--                (long) convOp << CONV_OP_SHIFT |
--                (int)  srcType << CONV_SRC_TYPE_SHIFT |
--                (int)  destType << CONV_DEST_TYPE_SHIFT |
--                (int)  destSlot << CONV_VMINFO_SHIFT
--                );
--    }
--    @SuppressWarnings("cast")  // some (int) casts below provide clarity but trigger warnings
--    private static long makeSpreadConv(int convOp, int argnum, int src, int dest, int stackMove) {
--        // spreading or collecting, at a particular slot location
--        assert(convOp == OP_SPREAD_ARGS || convOp == OP_COLLECT_ARGS || convOp == OP_FOLD_ARGS);
--        // src  = spread ? T_OBJECT (for array)  : common type of collected args (else void)
--        // dest = spread ? element type of array : result type of collector (can be void)
--        return ((long) argnum << 32 |
--                (long) convOp << CONV_OP_SHIFT |
--                (int)  src    << CONV_SRC_TYPE_SHIFT |
--                (int)  dest   << CONV_DEST_TYPE_SHIFT |
--                insertStackMove(stackMove)
--                );
--    }
--    static long makeConv(int convOp) {
--        assert(convOp == OP_RETYPE_ONLY || convOp == OP_RETYPE_RAW);
--        return ((long)-1 << 32) | (convOp << CONV_OP_SHIFT);   // stackMove, src, dst all zero
--    }
--    private static int convCode(long conv) {
--        return (int)conv;
--    }
--    private static int convArgPos(long conv) {
--        return (int)(conv >>> 32);
--    }
--    private static boolean convOpSupported(int convOp) {
--        assert(convOp >= 0 && convOp <= CONV_OP_LIMIT);
--        return ((1<<convOp) & MethodHandleNatives.CONV_OP_IMPLEMENTED_MASK) != 0;
--    }
--
--    /** One of OP_RETYPE_ONLY, etc. */
--    int conversionOp() { return (conversion & CONV_OP_MASK) >> CONV_OP_SHIFT; }
--
--    /* Return one plus the position of the first non-trivial difference
--     * between the given types.  This is not a symmetric operation;
--     * we are considering adapting the targetType to adapterType.
--     * Trivial differences are those which could be ignored by the JVM
--     * without subverting the verifier.  Otherwise, adaptable differences
--     * are ones for which we could create an adapter to make the type change.
--     * Return zero if there are no differences (other than trivial ones).
--     * Return 1+N if N is the only adaptable argument difference.
--     * Return the -2-N where N is the first of several adaptable
--     * argument differences.
--     * Return -1 if there there are differences which are not adaptable.
--     */
--    private static int diffTypes(MethodType adapterType,
--                                 MethodType targetType,
--                                 boolean raw) {
--        int diff;
--        diff = diffReturnTypes(adapterType, targetType, raw);
--        if (diff != 0)  return diff;
--        int nargs = adapterType.parameterCount();
--        if (nargs != targetType.parameterCount())
--            return -1;
--        diff = diffParamTypes(adapterType, 0, targetType, 0, nargs, raw);
--        //System.out.println("diff "+adapterType);
--        //System.out.println("  "+diff+" "+targetType);
--        return diff;
--    }
--    private static int diffReturnTypes(MethodType adapterType,
--                                       MethodType targetType,
--                                       boolean raw) {
--        Class<?> src = targetType.returnType();
--        Class<?> dst = adapterType.returnType();
--        if ((!raw
--             ? VerifyType.canPassUnchecked(src, dst)
--             : VerifyType.canPassRaw(src, dst)
--             ) > 0)
--            return 0;  // no significant difference
--        if (raw && !src.isPrimitive() && !dst.isPrimitive())
--            return 0;  // can force a reference return (very carefully!)
--        //if (false)  return 1;  // never adaptable!
--        return -1;  // some significant difference
--    }
--    private static int diffParamTypes(MethodType adapterType, int astart,
--                                      MethodType targetType, int tstart,
--                                      int nargs, boolean raw) {
--        assert(nargs >= 0);
--        int res = 0;
--        for (int i = 0; i < nargs; i++) {
--            Class<?> src  = adapterType.parameterType(astart+i);
--            Class<?> dest = targetType.parameterType(tstart+i);
--            if ((!raw
--                 ? VerifyType.canPassUnchecked(src, dest)
--                 : VerifyType.canPassRaw(src, dest)
--                ) <= 0) {
--                // found a difference; is it the only one so far?
--                if (res != 0)
--                    return -1-res; // return -2-i for prev. i
--                res = 1+i;
--            }
--        }
--        return res;
--    }
--
--    /** Can a retyping adapter (alone) validly convert the target to newType? */
--    static boolean canRetypeOnly(MethodType newType, MethodType targetType) {
--        return canRetype(newType, targetType, false);
--    }
--    /** Can a retyping adapter (alone) convert the target to newType?
--     *  It is allowed to widen subword types and void to int, to make bitwise
--     *  conversions between float/int and double/long, and to perform unchecked
--     *  reference conversions on return.  This last feature requires that the
--     *  caller be trusted, and perform explicit cast conversions on return values.
--     */
--    static boolean canRetypeRaw(MethodType newType, MethodType targetType) {
--        return canRetype(newType, targetType, true);
--    }
--    static boolean canRetype(MethodType newType, MethodType targetType, boolean raw) {
--        if (!convOpSupported(raw ? OP_RETYPE_RAW : OP_RETYPE_ONLY))  return false;
--        int diff = diffTypes(newType, targetType, raw);
--        // %%% This assert is too strong.  Factor diff into VerifyType and reconcile.
--        assert(raw || (diff == 0) == VerifyType.isNullConversion(newType, targetType));
--        return diff == 0;
--    }
--
--    /** Factory method:  Performs no conversions; simply retypes the adapter.
--     *  Allows unchecked argument conversions pairwise, if they are safe.
--     *  Returns null if not possible.
--     */
--    static MethodHandle makeRetypeOnly(MethodType newType, MethodHandle target) {
--        return makeRetype(newType, target, false);
--    }
--    static MethodHandle makeRetypeRaw(MethodType newType, MethodHandle target) {
--        return makeRetype(newType, target, true);
--    }
--    static MethodHandle makeRetype(MethodType newType, MethodHandle target, boolean raw) {
--        MethodType oldType = target.type();
--        if (oldType == newType)  return target;
--        if (!canRetype(newType, oldType, raw))
--            return null;
--        // TO DO:  clone the target guy, whatever he is, with new type.
--        return new AdapterMethodHandle(target, newType, makeConv(raw ? OP_RETYPE_RAW : OP_RETYPE_ONLY));
--    }
--
--    static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) {
--        MethodType type = target.type();
--        int last = type.parameterCount() - 1;
--        if (type.parameterType(last) != arrayType)
--            target = target.asType(type.changeParameterType(last, arrayType));
--        target = target.asFixedArity();  // make sure this attribute is turned off
--        return new AsVarargsCollector(target, arrayType);
--    }
--
--    static class AsVarargsCollector extends AdapterMethodHandle {
--        final MethodHandle target;
--        final Class<?> arrayType;
--        MethodHandle cache;
--
--        AsVarargsCollector(MethodHandle target, Class<?> arrayType) {
--            super(target, target.type(), makeConv(OP_RETYPE_ONLY));
--            this.target = target;
--            this.arrayType = arrayType;
--            this.cache = target.asCollector(arrayType, 0);
--        }
--
--        @Override
--        public boolean isVarargsCollector() {
--            return true;
--        }
--
--        @Override
--        public MethodHandle asFixedArity() {
--            return target;
--        }
--
--        @Override
--        public MethodHandle asType(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 super.asType(newType);
--            }
--            // check cache
--            if (cache.type().parameterCount() == newArity)
--                return cache.asType(newType);
--            // build and cache a collector
--            int arrayLength = newArity - collectArg;
--            MethodHandle collector;
--            try {
--                collector = target.asCollector(arrayType, arrayLength);
--            } catch (IllegalArgumentException ex) {
--                throw new WrongMethodTypeException("cannot build collector");
--            }
--            cache = collector;
--            return collector.asType(newType);
--        }
--    }
--
--    /** Can a checkcast adapter validly convert the target to newType?
--     *  The JVM supports all kind of reference casts, even silly ones.
--     */
--    static boolean canCheckCast(MethodType newType, MethodType targetType,
--                int arg, Class<?> castType) {
--        if (!convOpSupported(OP_CHECK_CAST))  return false;
--        Class<?> src = newType.parameterType(arg);
--        Class<?> dst = targetType.parameterType(arg);
--        if (!canCheckCast(src, castType)
--                || !VerifyType.isNullConversion(castType, dst))
--            return false;
--        int diff = diffTypes(newType, targetType, false);
--        return (diff == arg+1) || (diff == 0);  // arg is sole non-trivial diff
--    }
--    /** Can an primitive conversion adapter validly convert src to dst? */
--    static boolean canCheckCast(Class<?> src, Class<?> dst) {
--        return (!src.isPrimitive() && !dst.isPrimitive());
--    }
--
--    /** Factory method:  Forces a cast at the given argument.
--     *  The castType is the target of the cast, and can be any type
--     *  with a null conversion to the corresponding target parameter.
--     *  Return null if this cannot be done.
--     */
--    static MethodHandle makeCheckCast(MethodType newType, MethodHandle target,
--                int arg, Class<?> castType) {
--        if (!canCheckCast(newType, target.type(), arg, castType))
--            return null;
--        long conv = makeConv(OP_CHECK_CAST, arg, T_OBJECT, T_OBJECT);
--        return new AdapterMethodHandle(target, newType, conv, castType);
--    }
--
--    /** Can an primitive conversion adapter validly convert the target to newType?
--     *  The JVM currently supports all conversions except those between
--     *  floating and integral types.
--     */
--    static boolean canPrimCast(MethodType newType, MethodType targetType,
--                int arg, Class<?> convType) {
--        if (!convOpSupported(OP_PRIM_TO_PRIM))  return false;
--        Class<?> src = newType.parameterType(arg);
--        Class<?> dst = targetType.parameterType(arg);
--        if (!canPrimCast(src, convType)
--                || !VerifyType.isNullConversion(convType, dst))
--            return false;
--        int diff = diffTypes(newType, targetType, false);
--        return (diff == arg+1);  // arg is sole non-trivial diff
--    }
--    /** Can an primitive conversion adapter validly convert src to dst? */
--    static boolean canPrimCast(Class<?> src, Class<?> dst) {
--        if (src == dst || !src.isPrimitive() || !dst.isPrimitive()) {
--            return false;
--        } else {
--            boolean sflt = Wrapper.forPrimitiveType(src).isFloating();
--            boolean dflt = Wrapper.forPrimitiveType(dst).isFloating();
--            return !(sflt | dflt);  // no float support at present
--        }
--    }
--
--    /** Factory method:  Truncate the given argument with zero or sign extension,
--     *  and/or convert between single and doubleword versions of integer or float.
--     *  The convType is the target of the conversion, and can be any type
--     *  with a null conversion to the corresponding target parameter.
--     *  Return null if this cannot be done.
--     */
--    static MethodHandle makePrimCast(MethodType newType, MethodHandle target,
--                int arg, Class<?> convType) {
--        Class<?> src = newType.parameterType(arg);
--        if (canPrimCast(src, convType))
--            return makePrimCastOnly(newType, target, arg, convType);
--        Class<?> dst = convType;
--        boolean sflt = Wrapper.forPrimitiveType(src).isFloating();
--        boolean dflt = Wrapper.forPrimitiveType(dst).isFloating();
--        if (sflt | dflt) {
--            MethodHandle convMethod;
--            if (sflt)
--                convMethod = ((src == double.class)
--                        ? ValueConversions.convertFromDouble(dst)
--                        : ValueConversions.convertFromFloat(dst));
--            else
--                convMethod = ((dst == double.class)
--                        ? ValueConversions.convertToDouble(src)
--                        : ValueConversions.convertToFloat(src));
--            long conv = makeConv(OP_COLLECT_ARGS, arg, basicType(src), basicType(dst));
--            return new AdapterMethodHandle(target, newType, conv, convMethod);
--        }
--        throw new InternalError("makePrimCast");
--    }
--    static MethodHandle makePrimCastOnly(MethodType newType, MethodHandle target,
--                int arg, Class<?> convType) {
--        MethodType oldType = target.type();
--        if (!canPrimCast(newType, oldType, arg, convType))
--            return null;
--        Class<?> src = newType.parameterType(arg);
--        long conv = makeConv(OP_PRIM_TO_PRIM, arg, basicType(src), basicType(convType));
--        return new AdapterMethodHandle(target, newType, conv);
--    }
--
--    /** Can an unboxing conversion validly convert src to dst?
--     *  The JVM currently supports all kinds of casting and unboxing.
--     *  The convType is the unboxed type; it can be either a primitive or wrapper.
--     */
--    static boolean canUnboxArgument(MethodType newType, MethodType targetType,
--                int arg, Class<?> convType, int level) {
--        if (!convOpSupported(OP_REF_TO_PRIM))  return false;
--        Class<?> src = newType.parameterType(arg);
--        Class<?> dst = targetType.parameterType(arg);
--        Class<?> boxType = Wrapper.asWrapperType(convType);
--        convType = Wrapper.asPrimitiveType(convType);
--        if (!canCheckCast(src, boxType)
--                || boxType == convType
--                || !VerifyType.isNullConversion(convType, dst))
--            return false;
--        int diff = diffTypes(newType, targetType, false);
--        return (diff == arg+1);  // arg is sole non-trivial diff
--    }
--    /** Can an primitive unboxing adapter validly convert src to dst? */
--    static boolean canUnboxArgument(Class<?> src, Class<?> dst, int level) {
--        assert(dst.isPrimitive());
--        // if we have JVM support for boxing, we can also do complex unboxing
--        if (convOpSupported(OP_PRIM_TO_REF))  return true;
--        Wrapper dw = Wrapper.forPrimitiveType(dst);
--        // Level 0 means cast and unbox.  This works on any reference.
--        if (level == 0)  return !src.isPrimitive();
--        assert(level >= 0 && level <= 2);
--        // Levels 1 and 2 allow widening and/or narrowing conversions.
--        // These are not supported directly by the JVM.
--        // But if the input reference is monomorphic, we can do it.
--        return dw.wrapperType() == src;
--    }
--
--    /** Factory method:  Unbox the given argument.
--     *  Return null if this cannot be done.
--     */
--    static MethodHandle makeUnboxArgument(MethodType newType, MethodHandle target,
--                int arg, Class<?> convType, int level) {
--        MethodType oldType = target.type();
--        Class<?> src = newType.parameterType(arg);
--        Class<?> dst = oldType.parameterType(arg);
--        Class<?> boxType = Wrapper.asWrapperType(convType);
--        Class<?> primType = Wrapper.asPrimitiveType(convType);
--        if (!canUnboxArgument(newType, oldType, arg, convType, level))
--            return null;
--        MethodType castDone = newType;
--        if (!VerifyType.isNullConversion(src, boxType)) {
--            // Examples:  Object->int, Number->int, Comparable->int; Byte->int, Character->int
--            if (level != 0) {
--                // must include additional conversions
--                if (src == Object.class || !Wrapper.isWrapperType(src)) {
--                    // src must be examined at runtime, to detect Byte, Character, etc.
--                    MethodHandle unboxMethod = (level == 1
--                                                ? ValueConversions.unbox(dst)
--                                                : ValueConversions.unboxCast(dst));
--                    long conv = makeConv(OP_COLLECT_ARGS, arg, basicType(src), basicType(dst));
--                    return new AdapterMethodHandle(target, newType, conv, unboxMethod);
--                }
--                // Example: Byte->int
--                // Do this by reformulating the problem to Byte->byte.
--                Class<?> srcPrim = Wrapper.forWrapperType(src).primitiveType();
--                MethodType midType = newType.changeParameterType(arg, srcPrim);
--                MethodHandle fixPrim; // makePairwiseConvert(midType, target, 0);
--                if (canPrimCast(midType, oldType, arg, dst))
--                    fixPrim = makePrimCast(midType, target, arg, dst);
--                else
--                    fixPrim = target;
--                return makeUnboxArgument(newType, fixPrim, arg, srcPrim, 0);
--            }
--            castDone = newType.changeParameterType(arg, boxType);
--        }
--        long conv = makeConv(OP_REF_TO_PRIM, arg, T_OBJECT, basicType(primType));
--        MethodHandle adapter = new AdapterMethodHandle(target, castDone, conv, boxType);
--        if (castDone == newType)
--            return adapter;
--        return makeCheckCast(newType, adapter, arg, boxType);
--    }
--
--    /** Can a boxing conversion validly convert src to dst? */
--    static boolean canBoxArgument(MethodType newType, MethodType targetType,
--                int arg, Class<?> convType) {
--        if (!convOpSupported(OP_PRIM_TO_REF))  return false;
--        Class<?> src = newType.parameterType(arg);
--        Class<?> dst = targetType.parameterType(arg);
--        Class<?> boxType = Wrapper.asWrapperType(convType);
--        convType = Wrapper.asPrimitiveType(convType);
--        if (!canCheckCast(boxType, dst)
--                || boxType == convType
--                || !VerifyType.isNullConversion(src, convType))
--            return false;
--        int diff = diffTypes(newType, targetType, false);
--        return (diff == arg+1);  // arg is sole non-trivial diff
--    }
--
--    /** Can an primitive boxing adapter validly convert src to dst? */
--    static boolean canBoxArgument(Class<?> src, Class<?> dst) {
--        if (!convOpSupported(OP_PRIM_TO_REF))  return false;
--        return (src.isPrimitive() && !dst.isPrimitive());
--    }
--
--    /** Factory method:  Box the given argument.
--     *  Return null if this cannot be done.
--     */
--    static MethodHandle makeBoxArgument(MethodType newType, MethodHandle target,
--                int arg, Class<?> convType) {
--        MethodType oldType = target.type();
--        Class<?> src = newType.parameterType(arg);
--        Class<?> dst = oldType.parameterType(arg);
--        Class<?> boxType = Wrapper.asWrapperType(convType);
--        Class<?> primType = Wrapper.asPrimitiveType(convType);
--        if (!canBoxArgument(newType, oldType, arg, convType)) {
--            return null;
--        }
--        if (!VerifyType.isNullConversion(boxType, dst))
--            target = makeCheckCast(oldType.changeParameterType(arg, boxType), target, arg, dst);
--        MethodHandle boxerMethod = ValueConversions.box(Wrapper.forPrimitiveType(primType));
--        long conv = makeConv(OP_PRIM_TO_REF, arg, basicType(primType), T_OBJECT);
--        return new AdapterMethodHandle(target, newType, conv, boxerMethod);
--    }
--
--    /** Can an adapter simply drop arguments to convert the target to newType? */
--    static boolean canDropArguments(MethodType newType, MethodType targetType,
--                int dropArgPos, int dropArgCount) {
--        if (dropArgCount == 0)
--            return canRetypeOnly(newType, targetType);
--        if (!convOpSupported(OP_DROP_ARGS))  return false;
--        if (diffReturnTypes(newType, targetType, false) != 0)
--            return false;
--        int nptypes = newType.parameterCount();
--        // parameter types must be the same up to the drop point
--        if (dropArgPos != 0 && diffParamTypes(newType, 0, targetType, 0, dropArgPos, false) != 0)
--            return false;
--        int afterPos = dropArgPos + dropArgCount;
--        int afterCount = nptypes - afterPos;
--        if (dropArgPos < 0 || dropArgPos >= nptypes ||
--            dropArgCount < 1 || afterPos > nptypes ||
--            targetType.parameterCount() != nptypes - dropArgCount)
--            return false;
--        // parameter types after the drop point must also be the same
--        if (afterCount != 0 && diffParamTypes(newType, afterPos, targetType, dropArgPos, afterCount, false) != 0)
--            return false;
--        return true;
--    }
--
--    /** Factory method:  Drop selected arguments.
--     *  Allow unchecked retyping of remaining arguments, pairwise.
--     *  Return null if this is not possible.
--     */
--    static MethodHandle makeDropArguments(MethodType newType, MethodHandle target,
--                int dropArgPos, int dropArgCount) {
--        if (dropArgCount == 0)
--            return makeRetypeOnly(newType, target);
--        if (!canDropArguments(newType, target.type(), dropArgPos, dropArgCount))
--            return null;
--        // in  arglist: [0: ...keep1 | dpos: drop... | dpos+dcount: keep2... ]
--        // out arglist: [0: ...keep1 |                        dpos: keep2... ]
--        int keep2InPos  = dropArgPos + dropArgCount;
--        int dropSlot    = newType.parameterSlotDepth(keep2InPos);
--        int keep1InSlot = newType.parameterSlotDepth(dropArgPos);
--        int slotCount   = keep1InSlot - dropSlot;
--        assert(slotCount >= dropArgCount);
--        assert(target.type().parameterSlotCount() + slotCount == newType.parameterSlotCount());
--        long conv = makeDupConv(OP_DROP_ARGS, dropArgPos + dropArgCount - 1, -slotCount);
--        return new AdapterMethodHandle(target, newType, conv);
--    }
--
--    /** Can an adapter duplicate an argument to convert the target to newType? */
--    static boolean canDupArguments(MethodType newType, MethodType targetType,
--                int dupArgPos, int dupArgCount) {
--        if (!convOpSupported(OP_DUP_ARGS))  return false;
--        if (diffReturnTypes(newType, targetType, false) != 0)
--            return false;
--        int nptypes = newType.parameterCount();
--        if (dupArgCount < 0 || dupArgPos + dupArgCount > nptypes)
--            return false;
--        if (targetType.parameterCount() != nptypes + dupArgCount)
--            return false;
--        // parameter types must be the same up to the duplicated arguments
--        if (diffParamTypes(newType, 0, targetType, 0, nptypes, false) != 0)
--            return false;
--        // duplicated types must be, well, duplicates
--        if (diffParamTypes(newType, dupArgPos, targetType, nptypes, dupArgCount, false) != 0)
--            return false;
--        return true;
--    }
--
--    /** Factory method:  Duplicate the selected argument.
--     *  Return null if this is not possible.
--     */
--    static MethodHandle makeDupArguments(MethodType newType, MethodHandle target,
--                int dupArgPos, int dupArgCount) {
--        if (!canDupArguments(newType, target.type(), dupArgPos, dupArgCount))
--            return null;
--        if (dupArgCount == 0)
--            return target;
--        // in  arglist: [0: ...keep1 | dpos: dup... | dpos+dcount: keep2... ]
--        // out arglist: [0: ...keep1 | dpos: dup... | dpos+dcount: keep2... | dup... ]
--        int keep2InPos  = dupArgPos + dupArgCount;
--        int dupSlot     = newType.parameterSlotDepth(keep2InPos);
--        int keep1InSlot = newType.parameterSlotDepth(dupArgPos);
--        int slotCount   = keep1InSlot - dupSlot;
--        assert(target.type().parameterSlotCount() - slotCount == newType.parameterSlotCount());
--        long conv = makeDupConv(OP_DUP_ARGS, dupArgPos + dupArgCount - 1, slotCount);
--        return new AdapterMethodHandle(target, newType, conv);
--    }
--
--    /** Can an adapter swap two arguments to convert the target to newType? */
--    static boolean canSwapArguments(MethodType newType, MethodType targetType,
--                int swapArg1, int swapArg2) {
--        if (!convOpSupported(OP_SWAP_ARGS))  return false;
--        if (diffReturnTypes(newType, targetType, false) != 0)
--            return false;
--        if (swapArg1 >= swapArg2)  return false;  // caller resp
--        int nptypes = newType.parameterCount();
--        if (targetType.parameterCount() != nptypes)
--            return false;
--        if (swapArg1 < 0 || swapArg2 >= nptypes)
--            return false;
--        if (diffParamTypes(newType, 0, targetType, 0, swapArg1, false) != 0)
--            return false;
--        if (diffParamTypes(newType, swapArg1, targetType, swapArg2, 1, false) != 0)
--            return false;
--        if (diffParamTypes(newType, swapArg1+1, targetType, swapArg1+1, swapArg2-swapArg1-1, false) != 0)
--            return false;
--        if (diffParamTypes(newType, swapArg2, targetType, swapArg1, 1, false) != 0)
--            return false;
--        if (diffParamTypes(newType, swapArg2+1, targetType, swapArg2+1, nptypes-swapArg2-1, false) != 0)
--            return false;
--        return true;
--    }
--
--    /** Factory method:  Swap the selected arguments.
--     *  Return null if this is not possible.
--     */
--    static MethodHandle makeSwapArguments(MethodType newType, MethodHandle target,
--                int swapArg1, int swapArg2) {
--        if (swapArg1 == swapArg2)
--            return target;
--        if (swapArg1 > swapArg2) { int t = swapArg1; swapArg1 = swapArg2; swapArg2 = t; }
--        if (type2size(newType.parameterType(swapArg1)) !=
--            type2size(newType.parameterType(swapArg2))) {
--            // turn a swap into a pair of rotates:
--            // [x a b c y] rot2(-1,argc=5) => [a b c y x] rot1(+1,argc=4) => target[y a b c x]
--            int argc = swapArg2 - swapArg1 + 1;
--            final int ROT = 1;
--            ArrayList<Class<?>> rot1Params = new ArrayList<Class<?>>(target.type().parameterList());
--            Collections.rotate(rot1Params.subList(swapArg1, swapArg1 + argc), -ROT);
--            MethodType rot1Type = MethodType.methodType(target.type().returnType(), rot1Params);
--            MethodHandle rot1 = makeRotateArguments(rot1Type, target, swapArg1, argc, +ROT);
--            assert(rot1 != null);
--            if (argc == 2)  return rot1;
--            MethodHandle rot2 = makeRotateArguments(newType, rot1, swapArg1, argc-1, -ROT);
--            assert(rot2 != null);
--            return rot2;
--        }
--        if (!canSwapArguments(newType, target.type(), swapArg1, swapArg2))
--            return null;
--        Class<?> type1 = newType.parameterType(swapArg1);
--        Class<?> type2 = newType.parameterType(swapArg2);
--        // in  arglist: [0: ...keep1 | pos1: a1 | pos1+1: keep2... | pos2: a2 | pos2+1: keep3... ]
--        // out arglist: [0: ...keep1 | pos1: a2 | pos1+1: keep2... | pos2: a1 | pos2+1: keep3... ]
--        int swapSlot2  = newType.parameterSlotDepth(swapArg2 + 1);
--        long conv = makeSwapConv(OP_SWAP_ARGS, swapArg1, basicType(type1), swapSlot2, basicType(type2));
--        return new AdapterMethodHandle(target, newType, conv);
--    }
--
--    static int positiveRotation(int argCount, int rotateBy) {
--        assert(argCount > 0);
--        if (rotateBy >= 0) {
--            if (rotateBy < argCount)
--                return rotateBy;
--            return rotateBy % argCount;
--        } else if (rotateBy >= -argCount) {
--            return rotateBy + argCount;
--        } else {
--            return (-1-((-1-rotateBy) % argCount)) + argCount;
--        }
--    }
--
--    final static int MAX_ARG_ROTATION = 1;
--
--    /** Can an adapter rotate arguments to convert the target to newType? */
--    static boolean canRotateArguments(MethodType newType, MethodType targetType,
--                int firstArg, int argCount, int rotateBy) {
--        if (!convOpSupported(OP_ROT_ARGS))  return false;
--        rotateBy = positiveRotation(argCount, rotateBy);
--        if (rotateBy == 0)  return false;  // no rotation
--        if (rotateBy > MAX_ARG_ROTATION && rotateBy < argCount - MAX_ARG_ROTATION)
--            return false;  // too many argument positions
--        // Rotate incoming args right N to the out args, N in 1..(argCouunt-1).
--        if (diffReturnTypes(newType, targetType, false) != 0)
--            return false;
--        int nptypes = newType.parameterCount();
--        if (targetType.parameterCount() != nptypes)
--            return false;
--        if (firstArg < 0 || firstArg >= nptypes)  return false;
--        int argLimit = firstArg + argCount;
--        if (argLimit > nptypes)  return false;
--        if (diffParamTypes(newType, 0, targetType, 0, firstArg, false) != 0)
--            return false;
--        int newChunk1 = argCount - rotateBy, newChunk2 = rotateBy;
--        // swap new chunk1 with target chunk2
--        if (diffParamTypes(newType, firstArg, targetType, argLimit-newChunk1, newChunk1, false) != 0)
--            return false;
--        // swap new chunk2 with target chunk1
--        if (diffParamTypes(newType, firstArg+newChunk1, targetType, firstArg, newChunk2, false) != 0)
--            return false;
--        return true;
--    }
--
--    /** Factory method:  Rotate the selected argument range.
--     *  Return null if this is not possible.
--     */
--    static MethodHandle makeRotateArguments(MethodType newType, MethodHandle target,
--                int firstArg, int argCount, int rotateBy) {
--        rotateBy = positiveRotation(argCount, rotateBy);
--        if (!canRotateArguments(newType, target.type(), firstArg, argCount, rotateBy))
--            return null;
--        // Decide whether it should be done as a right or left rotation,
--        // on the JVM stack.  Return the number of stack slots to rotate by,
--        // positive if right, negative if left.
--        int limit = firstArg + argCount;
--        int depth0 = newType.parameterSlotDepth(firstArg);
--        int depth1 = newType.parameterSlotDepth(limit-rotateBy);
--        int depth2 = newType.parameterSlotDepth(limit);
--        int chunk1Slots = depth0 - depth1; assert(chunk1Slots > 0);
--        int chunk2Slots = depth1 - depth2; assert(chunk2Slots > 0);
--        // From here on out, it assumes a single-argument shift.
--        assert(MAX_ARG_ROTATION == 1);
--        int srcArg, dstArg;
--        int dstSlot;
--        int moveChunk;
--        if (rotateBy == 1) {
--            // Rotate right/down N (rotateBy = +N, N small, c2 small):
--            // in  arglist: [0: ...keep1 | arg1: c1...  | limit-N: c2 | limit: keep2... ]
--            // out arglist: [0: ...keep1 | arg1: c2 | arg1+N: c1...   | limit: keep2... ]
--            srcArg = limit-1;
--            dstArg = firstArg;
--            //dstSlot = depth0 - chunk2Slots;  //chunk2Slots is not relevant
--            dstSlot = depth0 + MethodHandleNatives.OP_ROT_ARGS_DOWN_LIMIT_BIAS;
--            moveChunk = chunk2Slots;
--        } else {
--            // Rotate left/up N (rotateBy = -N, N small, c1 small):
--            // in  arglist: [0: ...keep1 | arg1: c1 | arg1+N: c2...   | limit: keep2... ]
--            // out arglist: [0: ...keep1 | arg1: c2 ... | limit-N: c1 | limit: keep2... ]
--            srcArg = firstArg;
--            dstArg = limit-1;
--            dstSlot = depth2;
--            moveChunk = chunk1Slots;
--        }
--        byte srcType = basicType(newType.parameterType(srcArg));
--        byte dstType = basicType(newType.parameterType(dstArg));
--        assert(moveChunk == type2size(srcType));
--        long conv = makeSwapConv(OP_ROT_ARGS, srcArg, srcType, dstSlot, dstType);
--        return new AdapterMethodHandle(target, newType, conv);
--    }
--
--    /** Can an adapter spread an argument to convert the target to newType? */
--    static boolean canSpreadArguments(MethodType newType, MethodType targetType,
--                Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) {
--        if (!convOpSupported(OP_SPREAD_ARGS))  return false;
--        if (diffReturnTypes(newType, targetType, false) != 0)
--            return false;
--        int nptypes = newType.parameterCount();
--        // parameter types must be the same up to the spread point
--        if (spreadArgPos != 0 && diffParamTypes(newType, 0, targetType, 0, spreadArgPos, false) != 0)
--            return false;
--        int afterPos = spreadArgPos + spreadArgCount;
--        int afterCount = nptypes - (spreadArgPos + 1);
--        if (spreadArgPos < 0 || spreadArgPos >= nptypes ||
--            spreadArgCount < 0 ||
--            targetType.parameterCount() != afterPos + afterCount)
--            return false;
--        // parameter types after the spread point must also be the same
--        if (afterCount != 0 && diffParamTypes(newType, spreadArgPos+1, targetType, afterPos, afterCount, false) != 0)
--            return false;
--        // match the array element type to the spread arg types
--        Class<?> rawSpreadArgType = newType.parameterType(spreadArgPos);
--        if (rawSpreadArgType != spreadArgType && !canCheckCast(rawSpreadArgType, spreadArgType))
--            return false;
--        for (int i = 0; i < spreadArgCount; i++) {
--            Class<?> src = VerifyType.spreadArgElementType(spreadArgType, i);
--            Class<?> dst = targetType.parameterType(spreadArgPos + i);
--            if (src == null || !canConvertArgument(src, dst, 1))
--                return false;
--        }
--        return true;
--    }
--
--
--    /** Factory method:  Spread selected argument. */
--    static MethodHandle makeSpreadArguments(MethodType newType, MethodHandle target,
--                Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) {
--        // FIXME: Get rid of newType; derive new arguments from structure of spreadArgType
--        MethodType targetType = target.type();
--        assert(canSpreadArguments(newType, targetType, spreadArgType, spreadArgPos, spreadArgCount))
--            : "[newType, targetType, spreadArgType, spreadArgPos, spreadArgCount] = "
--              + Arrays.asList(newType, targetType, spreadArgType, spreadArgPos, spreadArgCount);
--        // dest is not significant; remove?
--        int dest = T_VOID;
--        for (int i = 0; i < spreadArgCount; i++) {
--            Class<?> arg = VerifyType.spreadArgElementType(spreadArgType, i);
--            if (arg == null)  arg = Object.class;
--            int dest2 = basicType(arg);
--            if      (dest == T_VOID)  dest = dest2;
--            else if (dest != dest2)   dest = T_VOID;
--            if (dest == T_VOID)  break;
--            targetType = targetType.changeParameterType(spreadArgPos + i, arg);
--        }
--        target = target.asType(targetType);
--        int arrayArgSize = 1;  // always a reference
--        // in  arglist: [0: ...keep1 | spos: spreadArg | spos+1:      keep2... ]
--        // out arglist: [0: ...keep1 | spos: spread... | spos+scount: keep2... ]
--        int keep2OutPos  = spreadArgPos + spreadArgCount;
--        int keep1OutSlot = targetType.parameterSlotDepth(spreadArgPos);   // leading edge of |spread...|
--        int spreadSlot   = targetType.parameterSlotDepth(keep2OutPos);    // trailing edge of |spread...|
--        assert(spreadSlot == newType.parameterSlotDepth(spreadArgPos+arrayArgSize));
--        int slotCount    = keep1OutSlot - spreadSlot;                     // slots in |spread...|
--        assert(slotCount >= spreadArgCount);
--        int stackMove = - arrayArgSize + slotCount;  // pop array, push N slots
--        long conv = makeSpreadConv(OP_SPREAD_ARGS, spreadArgPos, T_OBJECT, dest, stackMove);
--        MethodHandle res = new AdapterMethodHandle(target, newType, conv, spreadArgType);
--        assert(res.type().parameterType(spreadArgPos) == spreadArgType);
--        return res;
--    }
--
--    /** Can an adapter collect a series of arguments, replacing them by zero or one results? */
--    static boolean canCollectArguments(MethodType targetType,
--                MethodType collectorType, int collectArgPos, boolean retainOriginalArgs) {
--        if (!convOpSupported(retainOriginalArgs ? OP_FOLD_ARGS : OP_COLLECT_ARGS))  return false;
--        int collectArgCount = collectorType.parameterCount();
--        Class<?> rtype = collectorType.returnType();
--        assert(rtype == void.class || targetType.parameterType(collectArgPos) == rtype)
--                // [(Object)Object[], (Object[])Object[], 0, 1]
--                : Arrays.asList(targetType, collectorType, collectArgPos, collectArgCount)
--                ;
--        return true;
--    }
--
--    /** Factory method:  Collect or filter selected argument(s). */
--    static MethodHandle makeCollectArguments(MethodHandle target,
--                MethodHandle collector, int collectArgPos, boolean retainOriginalArgs) {
--        assert(canCollectArguments(target.type(), collector.type(), collectArgPos, retainOriginalArgs));
--        MethodType targetType = target.type();
--        MethodType collectorType = collector.type();
--        int collectArgCount = collectorType.parameterCount();
--        Class<?> collectValType = collectorType.returnType();
--        int collectValCount = (collectValType == void.class ? 0 : 1);
--        int collectValSlots = collectorType.returnSlotCount();
--        MethodType newType = targetType
--                .dropParameterTypes(collectArgPos, collectArgPos+collectValCount);
--        if (!retainOriginalArgs) {
--            newType = newType
--                .insertParameterTypes(collectArgPos, collectorType.parameterList());
--        } else {
--            // parameter types at the fold point must be the same
--            assert(diffParamTypes(newType, collectArgPos, targetType, collectValCount, collectArgCount, false) == 0)
--                : Arrays.asList(target, collector, collectArgPos, retainOriginalArgs);
--        }
--        // in  arglist: [0: ...keep1 | cpos: collect...  | cpos+cacount: keep2... ]
--        // out arglist: [0: ...keep1 | cpos: collectVal? | cpos+cvcount: keep2... ]
--        // out(retain): [0: ...keep1 | cpos: cV? coll... | cpos+cvc+cac: keep2... ]
--        int keep2InPos   = collectArgPos + collectArgCount;
--        int keep1InSlot  = newType.parameterSlotDepth(collectArgPos);  // leading edge of |collect...|
--        int collectSlot  = newType.parameterSlotDepth(keep2InPos);     // trailing edge of |collect...|
--        int slotCount    = keep1InSlot - collectSlot;                  // slots in |collect...|
--        assert(slotCount >= collectArgCount);
--        assert(collectSlot == targetType.parameterSlotDepth(
--                collectArgPos + collectValCount + (retainOriginalArgs ? collectArgCount : 0) ));
--        int dest = basicType(collectValType);
--        int src = T_VOID;
--        // src is not significant; remove?
--        for (int i = 0; i < collectArgCount; i++) {
--            int src2 = basicType(collectorType.parameterType(i));
--            if      (src == T_VOID)  src = src2;
--            else if (src != src2)    src = T_VOID;
--            if (src == T_VOID)  break;
--        }
--        int stackMove = collectValSlots;  // push 0..2 results
--        if (!retainOriginalArgs)  stackMove -= slotCount; // pop N arguments
--        int lastCollectArg = keep2InPos-1;
--        long conv = makeSpreadConv(retainOriginalArgs ? OP_FOLD_ARGS : OP_COLLECT_ARGS,
--                                   lastCollectArg, src, dest, stackMove);
--        MethodHandle res = new AdapterMethodHandle(target, newType, conv, collector);
--        assert(res.type().parameterList().subList(collectArgPos, collectArgPos+collectArgCount)
--                .equals(collector.type().parameterList()));
--        return res;
--    }
--
--    @Override
--    String debugString() {
--        return getNameString(nonAdapter((MethodHandle)vmtarget), this);
--    }
--
--    private static MethodHandle nonAdapter(MethodHandle mh) {
--        while (mh instanceof AdapterMethodHandle) {
--            mh = (MethodHandle) mh.vmtarget;
--        }
--        return mh;
--    }
--}
-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
-@@ -1,5 +1,5 @@
- /*
-- * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
-+ * Copyright (c) 2008, 2012, 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
-@@ -25,164 +25,828 @@
- 
- package java.lang.invoke;
- 
--import sun.invoke.util.VerifyType;
-+import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.*;
-+import static java.lang.invoke.LambdaForm.basicTypes;
-+import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;
-+import static java.lang.invoke.MethodHandleStatics.*;
-+
-+import java.lang.invoke.LambdaForm.Name;
-+import java.lang.invoke.LambdaForm.NamedFunction;
-+import java.lang.invoke.MethodHandles.Lookup;
-+import java.lang.reflect.Field;
-+import java.util.Arrays;
-+import java.util.HashMap;
-+
-+import sun.invoke.util.ValueConversions;
- import sun.invoke.util.Wrapper;
--import static java.lang.invoke.MethodHandleStatics.*;
-+
-+import com.sun.xml.internal.ws.org.objectweb.asm.ClassWriter;
-+import com.sun.xml.internal.ws.org.objectweb.asm.MethodVisitor;
-+import com.sun.xml.internal.ws.org.objectweb.asm.Type;
- 
- /**
-  * The flavor of method handle which emulates an invoke instruction
-  * on a predetermined argument.  The JVM dispatches to the correct method
-  * when the handle is created, not when it is invoked.
-- * @author jrose
-+ *
-+ * All bound arguments are encapsulated in dedicated species.
-  */
--class BoundMethodHandle extends MethodHandle {
--    //MethodHandle vmtarget;           // next BMH or final DMH or methodOop
--    private final Object argument;     // argument to insert
--    private final int    vmargslot;    // position at which it is inserted
-+/* non-public */ abstract class BoundMethodHandle extends MethodHandle {
- 
--    // Constructors in this class *must* be package scoped or private.
--
--    /** Bind a direct MH to its receiver (or first ref. argument).
--     *  The JVM will pre-dispatch the MH if it is not already static.
--     */
--    /*non-public*/ BoundMethodHandle(DirectMethodHandle mh, Object argument) {
--        super(mh.type().dropParameterTypes(0, 1));
--        // check the type now, once for all:
--        this.argument = checkReferenceArgument(argument, mh, 0);
--        this.vmargslot = this.type().parameterSlotCount();
--        initTarget(mh, 0);
-+    /* non-public */ BoundMethodHandle(MethodType type, LambdaForm form) {
-+        super(type, form);
-     }
- 
--    /** Insert an argument into an arbitrary method handle.
--     *  If argnum is zero, inserts the first argument, etc.
--     *  The argument type must be a reference.
--     */
--    /*non-public*/ BoundMethodHandle(MethodHandle mh, Object argument, int argnum) {
--        this(mh.type().dropParameterTypes(argnum, argnum+1),
--             mh, argument, argnum);
-+    //
-+    // 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 new InternalError(t);
-+        }
-     }
- 
--    /** Insert an argument into an arbitrary method handle.
--     *  If argnum is zero, inserts the first argument, etc.
--     */
--    /*non-public*/ BoundMethodHandle(MethodType type, MethodHandle mh, Object argument, int argnum) {
--        super(type);
--        if (mh.type().parameterType(argnum).isPrimitive())
--            this.argument = bindPrimitiveArgument(argument, mh, argnum);
--        else {
--            this.argument = checkReferenceArgument(argument, mh, argnum);
--        }
--        this.vmargslot = type.parameterSlotDepth(argnum);
--        initTarget(mh, argnum);
-+    static MethodHandle bindSingle(MethodType type, LambdaForm form, Object x) {
-+            return new Species_L(type, form, x);
-     }
- 
--    private void initTarget(MethodHandle mh, int argnum) {
--        //this.vmtarget = mh;  // maybe updated by JVM
--        MethodHandleNatives.init(this, mh, argnum);
--    }
--
--    /** For the AdapterMethodHandle subclass.
--     */
--    /*non-public*/ BoundMethodHandle(MethodType type, Object argument, int vmargslot) {
--        super(type);
--        this.argument = argument;
--        this.vmargslot = vmargslot;
--        assert(this instanceof AdapterMethodHandle);
--    }
--
--    /** Initialize the current object as a self-bound method handle, binding it
--     *  as the first argument of the method handle {@code entryPoint}.
--     *  The invocation type of the resulting method handle will be the
--     *  same as {@code entryPoint},  except that the first argument
--     *  type will be dropped.
--     */
--    /*non-public*/ BoundMethodHandle(MethodHandle entryPoint) {
--        super(entryPoint.type().dropParameterTypes(0, 1));
--        this.argument = this; // kludge; get rid of
--        this.vmargslot = this.type().parameterSlotDepth(0);
--        initTarget(entryPoint, 0);
--    }
--
--    /** Make sure the given {@code argument} can be used as {@code argnum}-th
--     *  parameter of the given method handle {@code mh}, which must be a reference.
--     *  <p>
--     *  If this fails, throw a suitable {@code WrongMethodTypeException},
--     *  which will prevent the creation of an illegally typed bound
--     *  method handle.
--     */
--    final static Object checkReferenceArgument(Object argument, MethodHandle mh, int argnum) {
--        Class<?> ptype = mh.type().parameterType(argnum);
--        if (ptype.isPrimitive()) {
--            // fail
--        } else if (argument == null) {
--            return null;
--        } else if (VerifyType.isNullReferenceConversion(argument.getClass(), ptype)) {
--            return argument;
-+    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 new InternalError(t);
-         }
--        throw badBoundArgumentException(argument, mh, argnum);
--    }
--
--    /** Make sure the given {@code argument} can be used as {@code argnum}-th
--     *  parameter of the given method handle {@code mh}, which must be a primitive.
--     *  <p>
--     *  If this fails, throw a suitable {@code WrongMethodTypeException},
--     *  which will prevent the creation of an illegally typed bound
--     *  method handle.
--     */
--    final static Object bindPrimitiveArgument(Object argument, MethodHandle mh, int argnum) {
--        Class<?> ptype = mh.type().parameterType(argnum);
--        Wrapper  wrap = Wrapper.forPrimitiveType(ptype);
--        Object   zero  = wrap.zero();
--        if (zero == null) {
--            // fail
--        } else if (argument == null) {
--            if (ptype != int.class && wrap.isSubwordOrInt())
--                return Integer.valueOf(0);
--            else
--                return zero;
--        } else if (VerifyType.isNullReferenceConversion(argument.getClass(), zero.getClass())) {
--            if (ptype != int.class && wrap.isSubwordOrInt())
--                return Wrapper.INT.wrap(argument);
--            else
--                return argument;
--        }
--        throw badBoundArgumentException(argument, mh, argnum);
--    }
--
--    final static RuntimeException badBoundArgumentException(Object argument, MethodHandle mh, int argnum) {
--        String atype = (argument == null) ? "null" : argument.getClass().toString();
--        return new ClassCastException("cannot bind "+atype+" argument to parameter #"+argnum+" of "+mh.type());
-+        throw new InternalError("unexpected type: " + xtype);
-     }
- 
-     @Override
--    String debugString() {
--        return addTypeString(baseName(), this);
-+    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);
-     }
- 
--    /** Component of toString() before the type string. */
--    protected String baseName() {
--        MethodHandle mh = this;
--        while (mh instanceof BoundMethodHandle) {
--            Object info = MethodHandleNatives.getTargetInfo(mh);
--            if (info instanceof MethodHandle) {
--                mh = (MethodHandle) info;
--            } else {
--                String name = null;
--                if (info instanceof MemberName)
--                    name = ((MemberName)info).getName();
--                if (name != null)
--                    return name;
--                else
--                    return noParens(super.toString()); // "invoke", probably
--            }
--            assert(mh != this);
--        }
--        return noParens(mh.toString());
-+    @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 new InternalError(t);
-+         }
-     }
- 
--    private static String noParens(String str) {
--        int paren = str.indexOf('(');
--        if (paren >= 0) str = str.substring(0, paren);
--        return str;
-+    @Override
-+    MethodHandle permuteArguments(MethodType newType, int[] reorder) {
-+        try {
-+             return clone(newType, form.permuteArguments(1, reorder, basicTypes(newType.parameterList())));
-+         } catch (Throwable t) {
-+             throw new InternalError(t);
-+         }
-     }
-+
-+    static final String EXTENSION_TYPES = "LIJFD";
-+    static final byte INDEX_L = 0, INDEX_I = 1, INDEX_J = 2, INDEX_F = 3, INDEX_D = 4;
-+    static byte extensionIndex(char type) {
-+        int i = EXTENSION_TYPES.indexOf(type);
-+        if (i < 0)  throw new InternalError();
-+        return (byte) i;
-+    }
-+
-+    /**
-+     * Return the {@link SpeciesData} instance representing this BMH species. All subclasses must provide a
-+     * static field containing this value, and they must accordingly implement this method.
-+     */
-+    protected abstract SpeciesData speciesData();
-+
-+    @Override
-+    final Object internalValues() {
-+        Object[] boundValues = new Object[speciesData().fieldCount()];
-+        for (int i = 0; i < boundValues.length; ++i) {
-+            boundValues[i] = arg(i);
-+        }
-+        return Arrays.asList(boundValues);
-+    }
-+
-+    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);
-+            }
-+        } catch (Throwable ex) {
-+            throw new InternalError(ex);
-+        }
-+        throw new InternalError("unexpected type: " + speciesData().types+"."+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 new InternalError(ex);
-+        }
-+    }
-+
-+    //
-+    // concrete BMH classes required to close bootstrap loops
-+    //
-+
-+    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) {
-+            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);
-+        }
-+        @Override
-+        public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
-+            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
-+        }
-+        @Override
-+        public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
-+            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
-+        }
-+        @Override
-+        public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
-+            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
-+        }
-+        @Override
-+        public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
-+            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
-+        }
-+        @Override
-+        public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
-+            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
-+        }
-+    }
-+
-+    static final class Species_JL extends BoundMethodHandle {
-+        final long argJ0;
-+        final Object argL1;
-+        public Species_JL(MethodType mt, LambdaForm lf, long argJ0, Object argL1) {
-+            super(mt, lf);
-+            this.argJ0 = argJ0;
-+            this.argL1 = argL1;
-+        }
-+        @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.
-+     */
-+    static class SpeciesData {
-+        final String                             types;
-+        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 SpeciesData[]                      extensions;
-+
-+        public int fieldCount() {
-+            return types.length();
-+        }
-+        public char fieldType(int i) {
-+            return types.charAt(i);
-+        }
-+
-+        public String toString() {
-+            return "SpeciesData["+(isPlaceholder() ? "<placeholder>" : clazz.getSimpleName())+":"+types+"]";
-+        }
-+
-+        /**
-+         * Return a {@link LambdaForm.Name} containing a {@link LambdaForm.NamedFunction} that
-+         * 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);
-+        }
-+
-+        static final SpeciesData EMPTY = new SpeciesData("", BoundMethodHandle.class);
-+
-+        private SpeciesData(String types, Class<? extends BoundMethodHandle> clazz) {
-+            this.types = types;
-+            this.clazz = clazz;
-+            if (!INIT_DONE) {
-+                this.constructor = new MethodHandle[1];
-+                this.getters = new MethodHandle[types.length()];
-+            } else {
-+                this.constructor = Factory.makeCtors(clazz, types, null);
-+                this.getters = Factory.makeGetters(clazz, types, null);
-+            }
-+            this.extensions = new SpeciesData[EXTENSION_TYPES.length()];
-+        }
-+
-+        private void initForBootstrap() {
-+            assert(!INIT_DONE);
-+            if (constructor[0] == null) {
-+                Factory.makeCtors(clazz, types, this.constructor);
-+                Factory.makeGetters(clazz, types, this.getters);
-+            }
-+        }
-+
-+        private SpeciesData(String types) {
-+            // Placeholder only.
-+            this.types = types;
-+            this.clazz = null;
-+            this.constructor = null;
-+            this.getters = null;
-+            this.extensions = null;
-+        }
-+        private boolean isPlaceholder() { return clazz == null; }
-+
-+        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];
-+            if (d != null)  return d;
-+            extensions[i] = d = get(types+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;
-+        }
-+
-+        private static SpeciesData get(String types) {
-+            // Acquire cache lock for query.
-+            SpeciesData d = lookupCache(types);
-+            if (!d.isPlaceholder())
-+                return d;
-+            Class<? extends BoundMethodHandle> cbmh;
-+            synchronized (d) {
-+                // Use synch. on the placeholder to prevent multiple instantiation of one species.
-+                // Creating this class forces a recursive call to getForClass.
-+                cbmh = Factory.generateConcreteBMHClass(types);
-+            }
-+            // Reacquire cache lock.
-+            d = lookupCache(types);
-+            // Class loading must have upgraded the cache.
-+            assert(d != null && !d.isPlaceholder());
-+            return d;
-+        }
-+        static SpeciesData getForClass(String types, Class<? extends BoundMethodHandle> clazz) {
-+            // clazz is a new class which is initializing its SPECIES_DATA field
-+            return updateCache(types, new SpeciesData(types, clazz));
-+        }
-+        private static synchronized SpeciesData lookupCache(String types) {
-+            SpeciesData d = CACHE.get(types);
-+            if (d != null)  return d;
-+            d = new SpeciesData(types);
-+            assert(d.isPlaceholder());
-+            CACHE.put(types, d);
-+            return d;
-+        }
-+        private static synchronized SpeciesData updateCache(String types, SpeciesData d) {
-+            SpeciesData d2;
-+            assert((d2 = CACHE.get(types)) == null || d2.isPlaceholder());
-+            assert(!d.isPlaceholder());
-+            CACHE.put(types, d);
-+            return d;
-+        }
-+
-+        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)) {
-+                        final Class<? extends BoundMethodHandle> cbmh = c.asSubclass(BoundMethodHandle.class);
-+                        SpeciesData d = Factory.speciesDataFromConcreteBMHClass(cbmh);
-+                        assert(d != null) : cbmh.getName();
-+                        assert(d.clazz == cbmh);
-+                        assert(d == lookupCache(d.types));
-+                    }
-+                }
-+            } catch (Throwable e) {
-+                throw new InternalError(e);
-+            }
-+
-+            for (SpeciesData d : CACHE.values()) {
-+                d.initForBootstrap();
-+            }
-+            // Note:  Do not simplify this, because INIT_DONE must not be
-+            // a compile-time constant during bootstrapping.
-+            INIT_DONE = Boolean.TRUE;
-+        }
-+    }
-+
-+    static SpeciesData getSpeciesData(String types) {
-+        return SpeciesData.get(types);
-+    }
-+
-+    /**
-+     * Generation of concrete BMH classes.
-+     *
-+     * A concrete BMH species is fit for binding a number of values adhering to a
-+     * given type pattern. Reference types are erased.
-+     *
-+     * BMH species are cached by type pattern.
-+     *
-+     * A BMH species has a number of fields with the concrete (possibly erased) types of
-+     * bound values. Setters are provided as an API in BMH. Getters are exposed as MHs,
-+     * which can be included as names in lambda forms.
-+     */
-+    static class Factory {
-+
-+        static final String JLO_SIG  = "Ljava/lang/Object;";
-+        static final String JLS_SIG  = "Ljava/lang/String;";
-+        static final String JLC_SIG  = "Ljava/lang/Class;";
-+        static final String MH       = "java/lang/invoke/MethodHandle";
-+        static final String MH_SIG   = "L"+MH+";";
-+        static final String BMH      = "java/lang/invoke/BoundMethodHandle";
-+        static final String BMH_SIG  = "L"+BMH+";";
-+        static final String SPECIES_DATA     = "java/lang/invoke/BoundMethodHandle$SpeciesData";
-+        static final String SPECIES_DATA_SIG = "L"+SPECIES_DATA+";";
-+
-+        static final String SPECIES_PREFIX_NAME = "Species_";
-+        static final String SPECIES_PREFIX_PATH = BMH + "$" + SPECIES_PREFIX_NAME;
-+
-+        static final String BMHSPECIES_DATA_EWI_SIG = "(B)" + SPECIES_DATA_SIG;
-+        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 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" };
-+
-+        /**
-+         * Generate a concrete subclass of BMH for a given combination of bound types.
-+         *
-+         * A concrete BMH species adheres to the following schema:
-+         *
-+         * <pre>
-+         * class Species_<<types>> extends BoundMethodHandle {
-+         *     <<fields>>
-+         *     final SpeciesData speciesData() { return SpeciesData.get("<<types>>"); }
-+         * }
-+         * </pre>
-+         *
-+         * The {@code <<types>>} signature is precisely the string that is passed to this
-+         * method.
-+         *
-+         * The {@code <<fields>>} section consists of one field definition per character in
-+         * the type signature, adhering to the naming schema described in the definition of
-+         * {@link #makeFieldName()}.
-+         *
-+         * For example, a concrete BMH species for two reference and one integral bound values
-+         * would have the following shape:
-+         *
-+         * <pre>
-+         * class BoundMethodHandle { ... private static
-+         * final class Species_LLI extends BoundMethodHandle {
-+         *     final Object argL0;
-+         *     final Object argL1;
-+         *     final int argI2;
-+         *     public 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 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 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 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 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 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 cloneExtendD(MethodType mt, LambdaForm lf, double narg) {
-+         *         return SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
-+         *     }
-+         * }
-+         * </pre>
-+         *
-+         * @param types the type signature, wherein reference types are erased to 'L'
-+         * @return the generated concrete BMH class
-+         */
-+        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;
-+            cw.visit(V1_6, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, className, null, BMH, null);
-+            cw.visitSource(sourceFile, null);
-+
-+            // emit static types and SPECIES_DATA fields
-+            cw.visitField(ACC_PUBLIC + ACC_STATIC, "SPECIES_DATA", SPECIES_DATA_SIG, null, null).visitEnd();
-+
-+            // emit bound argument fields
-+            for (int i = 0; i < types.length(); ++i) {
-+                final char t = types.charAt(i);
-+                final String fieldName = makeFieldName(types, i);
-+                final String fieldDesc = t == 'L' ? JLO_SIG : String.valueOf(t);
-+                cw.visitField(ACC_FINAL, fieldName, fieldDesc, null, null).visitEnd();
-+            }
-+
-+            MethodVisitor mv;
-+
-+            // emit constructor
-+            mv = cw.visitMethod(ACC_PUBLIC, "<init>", makeSignature(types, true), null, null);
-+            mv.visitCode();
-+            mv.visitVarInsn(ALOAD, 0);
-+            mv.visitVarInsn(ALOAD, 1);
-+            mv.visitVarInsn(ALOAD, 2);
-+
-+            mv.visitMethodInsn(INVOKESPECIAL, BMH, "<init>", makeSignature("", true));
-+
-+            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(ALOAD, 0);
-+                mv.visitVarInsn(typeLoadOp(t), j + 3); // parameters start at 3
-+                mv.visitFieldInsn(PUTFIELD, className, makeFieldName(types, i), typeSig(t));
-+                if (t == 'J' || t == 'D') {
-+                    ++j; // adjust argument register access
-+                }
-+            }
-+
-+            mv.visitInsn(RETURN);
-+            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();
-+            mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
-+            mv.visitInsn(ARETURN);
-+            mv.visitMaxs(0, 0);
-+            mv.visitEnd();
-+
-+            // emit clone()
-+            mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "clone", makeSignature("", false), null, E_THROWABLE);
-+            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);
-+            // 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.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);
-+                mv.visitCode();
-+                // return SPECIES_DATA.extendWithIndex(extensionIndex(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);
-+                assert(iconstInsn <= ICONST_5);
-+                mv.visitInsn(iconstInsn);
-+                mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "extendWithIndex", BMHSPECIES_DATA_EWI_SIG);
-+                mv.visitFieldInsn(GETFIELD, SPECIES_DATA, "constructor", "[" + MH_SIG);
-+                mv.visitInsn(ICONST_0);
-+                mv.visitInsn(AALOAD);
-+                // load mt, lf
-+                mv.visitVarInsn(ALOAD, 1);
-+                mv.visitVarInsn(ALOAD, 2);
-+                // put fields on the stack
-+                emitPushFields(types, className, mv);
-+                // put narg on stack
-+                mv.visitVarInsn(typeLoadOp(t), 3);
-+                // finally, invoke the constructor and return
-+                mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types + t, false));
-+                mv.visitInsn(ARETURN);
-+                mv.visitMaxs(0, 0);
-+                mv.visitEnd();
-+            }
-+
-+            // emit class initializer
-+            mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "<clinit>", VOID_SIG, null, null);
-+            mv.visitCode();
-+            mv.visitLdcInsn(types);
-+            mv.visitLdcInsn(Type.getObjectType(className));
-+            mv.visitMethodInsn(INVOKESTATIC, SPECIES_DATA, "getForClass", BMHSPECIES_DATA_GFC_SIG);
-+            mv.visitFieldInsn(PUTSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
-+            mv.visitInsn(RETURN);
-+            mv.visitMaxs(0, 0);
-+            mv.visitEnd();
-+
-+            cw.visitEnd();
-+
-+            // load class
-+            final byte[] classFile = cw.toByteArray();
-+            InvokerBytecodeGenerator.maybeDump(className, classFile);
-+            Class<? extends BoundMethodHandle> bmhClass =
-+                //UNSAFE.defineAnonymousClass(BoundMethodHandle.class, classFile, null).asSubclass(BoundMethodHandle.class);
-+                UNSAFE.defineClass(className, classFile, 0, classFile.length).asSubclass(BoundMethodHandle.class);
-+            UNSAFE.ensureClassInitialized(bmhClass);
-+
-+            return bmhClass;
-+        }
-+
-+        private static int typeLoadOp(char t) {
-+            switch (t) {
-+            case 'L': return ALOAD;
-+            case 'I': return ILOAD;
-+            case 'J': return LLOAD;
-+            case 'F': return FLOAD;
-+            case 'D': return DLOAD;
-+            default : throw new InternalError("unrecognized type " + t);
-+            }
-+        }
-+
-+        private static void emitPushFields(String types, String className, MethodVisitor mv) {
-+            for (int i = 0; i < types.length(); ++i) {
-+                char tc = types.charAt(i);
-+                mv.visitVarInsn(ALOAD, 0);
-+                mv.visitFieldInsn(GETFIELD, className, makeFieldName(types, i), typeSig(tc));
-+            }
-+        }
-+
-+        static String typeSig(char t) {
-+            return t == 'L' ? JLO_SIG : String.valueOf(t);
-+        }
-+
-+        //
-+        // Getter MH generation.
-+        //
-+
-+        private static MethodHandle makeGetter(Class<?> cbmhClass, String types, int index) {
-+            String fieldName = makeFieldName(types, index);
-+            Class<?> fieldType = Wrapper.forBasicType(types.charAt(index)).primitiveType();
-+            try {
-+                return LOOKUP.findGetter(cbmhClass, fieldName, fieldType);
-+            } catch (NoSuchFieldException | IllegalAccessException e) {
-+                throw new InternalError(e);
-+            }
-+        }
-+
-+        static MethodHandle[] makeGetters(Class<?> cbmhClass, String types, MethodHandle[] mhs) {
-+            if (mhs == null)  mhs = new MethodHandle[types.length()];
-+            for (int i = 0; i < mhs.length; ++i) {
-+                mhs[i] = makeGetter(cbmhClass, types, i);
-+                assert(mhs[i].internalMemberName().getDeclaringClass() == cbmhClass);
-+            }
-+            return mhs;
-+        }
-+
-+        static MethodHandle[] makeCtors(Class<? extends BoundMethodHandle> cbmh, String types, MethodHandle mhs[]) {
-+            if (mhs == null)  mhs = new MethodHandle[1];
-+            mhs[0] = makeCbmhCtor(cbmh, types);
-+            return mhs;
-+        }
-+
-+        //
-+        // Auxiliary methods.
-+        //
-+
-+        static SpeciesData speciesDataFromConcreteBMHClass(Class<? extends BoundMethodHandle> cbmh) {
-+            try {
-+                Field F_SPECIES_DATA = cbmh.getDeclaredField("SPECIES_DATA");
-+                return (SpeciesData) F_SPECIES_DATA.get(null);
-+            } catch (ReflectiveOperationException ex) {
-+                throw new InternalError(ex);
-+            }
-+        }
-+
-+        /**
-+         * Field names in concrete BMHs adhere to this pattern:
-+         * arg + type + index
-+         * where type is a single character (L, I, J, F, D).
-+         */
-+        private static String makeFieldName(String types, int index) {
-+            assert index >= 0 && index < types.length();
-+            return "arg" + types.charAt(index) + index;
-+        }
-+
-+        private static String makeSignature(String types, boolean ctor) {
-+            StringBuilder buf = new StringBuilder(SIG_INCIPIT);
-+            for (char c : types.toCharArray()) {
-+                buf.append(typeSig(c));
-+            }
-+            return buf.append(')').append(ctor ? "V" : BMH_SIG).toString();
-+        }
-+
-+        static MethodHandle makeCbmhCtor(Class<? extends BoundMethodHandle> cbmh, String types) {
-+            try {
-+                return linkConstructor(LOOKUP.findConstructor(cbmh, MethodType.fromMethodDescriptorString(makeSignature(types, true), null)));
-+            } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | TypeNotPresentException e) {
-+                throw new InternalError(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 new InternalError(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;
- }
-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
-@@ -26,7 +26,7 @@
- package java.lang.invoke;
- 
- import sun.invoke.empty.Empty;
--import sun.misc.Unsafe;
-+import static java.lang.invoke.MethodHandleStatics.*;
- import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
- 
- /**
-@@ -86,13 +86,9 @@
- public class CallSite {
-     static { MethodHandleImpl.initStatics(); }
- 
--    // Fields used only by the JVM.  Do not use or change.
--    private MemberName vmmethod; // supplied by the JVM (ref. to calling method)
--    private int        vmindex;  // supplied by the JVM (BCI within calling method)
--
-     // The actual payload of this call site:
-     /*package-private*/
--    MethodHandle target;
-+    MethodHandle target;    // Note: This field is known to the JVM.  Do not change.
- 
-     /**
-      * Make a blank call site object with the given method type.
-@@ -151,24 +147,6 @@
-         return target.type();
-     }
- 
--    /** Called from JVM (or low-level Java code) after the BSM returns the newly created CallSite.
--     *  The parameters are JVM-specific.
--     */
--    void initializeFromJVM(String name,
--                           MethodType type,
--                           MemberName callerMethod,
--                           int        callerBCI) {
--        if (this.vmmethod != null) {
--            // FIXME
--            throw new BootstrapMethodError("call site has already been linked to an invokedynamic instruction");
--        }
--        if (!this.type().equals(type)) {
--            throw wrongTargetType(target, type);
--        }
--        this.vmindex  = callerBCI;
--        this.vmmethod = callerMethod;
--    }
--
-     /**
-      * Returns the target method of the call site, according to the
-      * behavior defined by this call site's specific class.
-@@ -233,7 +211,7 @@
-     public abstract MethodHandle dynamicInvoker();
- 
-     /*non-public*/ MethodHandle makeDynamicInvoker() {
--        MethodHandle getTarget = MethodHandleImpl.bindReceiver(GET_TARGET, this);
-+        MethodHandle getTarget = GET_TARGET.bindReceiver(this);
-         MethodHandle invoker = MethodHandles.exactInvoker(this.type());
-         return MethodHandles.foldArguments(invoker, getTarget);
-     }
-@@ -255,12 +233,10 @@
-     }
- 
-     // unsafe stuff:
--    private static final Unsafe unsafe = Unsafe.getUnsafe();
-     private static final long TARGET_OFFSET;
--
-     static {
-         try {
--            TARGET_OFFSET = unsafe.objectFieldOffset(CallSite.class.getDeclaredField("target"));
-+            TARGET_OFFSET = UNSAFE.objectFieldOffset(CallSite.class.getDeclaredField("target"));
-         } catch (Exception ex) { throw new Error(ex); }
-     }
- 
-@@ -270,7 +246,7 @@
-     }
-     /*package-private*/
-     MethodHandle getTargetVolatile() {
--        return (MethodHandle) unsafe.getObjectVolatile(this, TARGET_OFFSET);
-+        return (MethodHandle) UNSAFE.getObjectVolatile(this, TARGET_OFFSET);
-     }
-     /*package-private*/
-     void setTargetVolatile(MethodHandle newTarget) {
-@@ -284,8 +260,7 @@
-                              // Extra arguments for BSM, if any:
-                              Object info,
-                              // Caller information:
--                             MemberName callerMethod, int callerBCI) {
--        Class<?> callerClass = callerMethod.getDeclaringClass();
-+                             Class<?> callerClass) {
-         Object caller = IMPL_LOOKUP.in(callerClass);
-         CallSite site;
-         try {
-diff --git a/src/share/classes/java/lang/invoke/CountingMethodHandle.java b/src/share/classes/java/lang/invoke/CountingMethodHandle.java
-deleted file mode 100644
---- a/src/share/classes/java/lang/invoke/CountingMethodHandle.java
-+++ /dev/null
-@@ -1,50 +0,0 @@
--/*
-- * Copyright (c) 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 static java.lang.invoke.MethodHandleNatives.Constants.*;
--
--/**
-- * This method handle is used to optionally provide a count of how
-- * many times it was invoked.
-- *
-- * @author never
-- */
--class CountingMethodHandle extends AdapterMethodHandle {
--    private int vmcount;
--
--    private CountingMethodHandle(MethodHandle target) {
--        super(target, target.type(), AdapterMethodHandle.makeConv(OP_RETYPE_ONLY));
--    }
--
--    /** Wrap the incoming MethodHandle in a CountingMethodHandle if they are enabled */
--    static MethodHandle wrap(MethodHandle mh) {
--        if (MethodHandleNatives.COUNT_GWT) {
--            return new CountingMethodHandle(mh);
--        }
--        return mh;
--    }
--}
-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
-@@ -25,29 +25,635 @@
- 
- package java.lang.invoke;
- 
-+import sun.misc.Unsafe;
-+import java.lang.reflect.Method;
-+import java.util.Arrays;
-+import sun.invoke.util.VerifyAccess;
- import static java.lang.invoke.MethodHandleNatives.Constants.*;
-+import static java.lang.invoke.LambdaForm.*;
-+import static java.lang.invoke.MethodTypeForm.*;
-+import static java.lang.invoke.MethodHandleStatics.*;
-+import java.lang.ref.WeakReference;
-+import java.lang.reflect.Field;
-+import sun.invoke.util.ValueConversions;
-+import sun.invoke.util.VerifyType;
-+import sun.invoke.util.Wrapper;
- 
- /**
-- * The flavor of method handle which emulates invokespecial or invokestatic.
-+ * The flavor of method handle which implements a constant reference
-+ * to a class member.
-  * @author jrose
-  */
- class DirectMethodHandle extends MethodHandle {
--    //inherited oop    vmtarget;    // methodOop or virtual class/interface oop
--    private final int  vmindex;     // method index within class or interface
--    { vmindex = VM_INDEX_UNINITIALIZED; }  // JVM may change this
-+    final MemberName member;
- 
--    // Constructors in this class *must* be package scoped or private.
--    DirectMethodHandle(MethodType mtype, MemberName m, boolean doDispatch, Class<?> lookupClass) {
--        super(mtype);
--
--        assert(m.isMethod() || !doDispatch && m.isConstructor());
--        if (!m.isResolved())
--            throw new InternalError();
--
--        MethodHandleNatives.init(this, (Object) m, doDispatch, lookupClass);
-+    // Constructors and factory methods in this class *must* be package scoped or private.
-+    private DirectMethodHandle(MethodType mtype, LambdaForm form, MemberName member) {
-+        super(mtype, form);
-+        if (!member.isResolved())  throw new InternalError();
-+        this.member = member;
-     }
- 
--    boolean isValid() {
--        return (vmindex != VM_INDEX_UNINITIALIZED);
-+    // Factory methods:
-+
-+    static DirectMethodHandle make(Class<?> receiver, MemberName member) {
-+        MethodType mtype = member.getMethodOrFieldType();
-+        if (!member.isStatic()) {
-+            if (!member.getDeclaringClass().isAssignableFrom(receiver) || member.isConstructor())
-+                throw new InternalError(member.toString());
-+            mtype = mtype.insertParameterTypes(0, receiver);
-+        }
-+        if (!member.isField()) {
-+            LambdaForm lform = preparedLambdaForm(member);
-+            return new DirectMethodHandle(mtype, lform, member);
-+        } else {
-+            LambdaForm lform = preparedFieldLambdaForm(member);
-+            if (member.isStatic()) {
-+                long offset = MethodHandleNatives.staticFieldOffset(member);
-+                Object base = MethodHandleNatives.staticFieldBase(member);
-+                return new StaticAccessor(mtype, lform, member, base, offset);
-+            } else {
-+                long offset = MethodHandleNatives.objectFieldOffset(member);
-+                assert(offset == (int)offset);
-+                return new Accessor(mtype, lform, member, (int)offset);
-+            }
-+        }
-+    }
-+    static DirectMethodHandle make(MemberName member) {
-+        if (member.isConstructor())
-+            return makeAllocator(member);
-+        return make(member.getDeclaringClass(), member);
-+    }
-+    static DirectMethodHandle make(Method method) {
-+        return make(method.getDeclaringClass(), new MemberName(method));
-+    }
-+    static DirectMethodHandle make(Field field) {
-+        return make(field.getDeclaringClass(), new MemberName(field));
-+    }
-+    private static DirectMethodHandle makeAllocator(MemberName ctor) {
-+        assert(ctor.isConstructor() && ctor.getName().equals("<init>"));
-+        Class<?> instanceClass = ctor.getDeclaringClass();
-+        ctor = ctor.asConstructor();
-+        assert(ctor.isConstructor() && ctor.getReferenceKind() == REF_newInvokeSpecial) : ctor;
-+        MethodType mtype = ctor.getMethodType().changeReturnType(instanceClass);
-+        LambdaForm lform = preparedLambdaForm(ctor);
-+        MemberName init = ctor.asSpecial();
-+        assert(init.getMethodType().returnType() == void.class);
-+        return new Constructor(mtype, lform, ctor, init, instanceClass);
-+    }
-+
-+    @Override
-+    MethodHandle copyWith(MethodType mt, LambdaForm lf) {
-+        return new DirectMethodHandle(mt, lf, member);
-+    }
-+
-+    @Override
-+    String debugString() {
-+        return "DMH["+member.toString()+"]="+super.debugString();
-+    }
-+
-+    //// Implementation methods.
-+    @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
-+     * the same basicType and refKind.
-+     */
-+    private static LambdaForm preparedLambdaForm(MemberName m) {
-+        assert(m.isInvocable()) : m;  // call preparedFieldLambdaForm instead
-+        MethodType mtype = m.getInvocationType().basicType();
-+        assert(!m.isMethodHandleInvoke() || "invokeBasic".equals(m.getName())) : m;
-+        int which;
-+        switch (m.getReferenceKind()) {
-+        case REF_invokeVirtual:    which = LF_INVVIRTUAL;    break;
-+        case REF_invokeStatic:     which = LF_INVSTATIC;     break;
-+        case REF_invokeSpecial:    which = LF_INVSPECIAL;    break;
-+        case REF_invokeInterface:  which = LF_INVINTERFACE;  break;
-+        case REF_newInvokeSpecial: which = LF_NEWINVSPECIAL; break;
-+        default:  throw new InternalError(m.toString());
-+        }
-+        if (which == LF_INVSTATIC && shouldBeInitialized(m)) {
-+            // precompute the barrier-free version:
-+            preparedLambdaForm(mtype, which);
-+            which = LF_INVSTATIC_INIT;
-+        }
-+        LambdaForm lform = preparedLambdaForm(mtype, which);
-+        maybeCompile(lform, m);
-+        assert(lform.methodType().dropParameterTypes(0, 1)
-+                .equals(m.getInvocationType().basicType()))
-+                : Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType());
-+        return lform;
-+    }
-+
-+    private static LambdaForm preparedLambdaForm(MethodType mtype, int which) {
-+        LambdaForm lform = mtype.form().cachedLambdaForm(which);
-+        if (lform != null)  return lform;
-+        lform = makePreparedLambdaForm(mtype, which);
-+        return mtype.form().setCachedLambdaForm(which, lform);
-+    }
-+
-+    private static LambdaForm makePreparedLambdaForm(MethodType mtype, int which) {
-+        boolean needsInit = (which == LF_INVSTATIC_INIT);
-+        boolean doesAlloc = (which == LF_NEWINVSPECIAL);
-+        String linkerName, lambdaName;
-+        switch (which) {
-+        case LF_INVVIRTUAL:    linkerName = "linkToVirtual";    lambdaName = "DMH.invokeVirtual";    break;
-+        case LF_INVSTATIC:     linkerName = "linkToStatic";     lambdaName = "DMH.invokeStatic";     break;
-+        case LF_INVSTATIC_INIT:linkerName = "linkToStatic";     lambdaName = "DMH.invokeStaticInit"; break;
-+        case LF_INVSPECIAL:    linkerName = "linkToSpecial";    lambdaName = "DMH.invokeSpecial";    break;
-+        case LF_INVINTERFACE:  linkerName = "linkToInterface";  lambdaName = "DMH.invokeInterface";  break;
-+        case LF_NEWINVSPECIAL: linkerName = "linkToSpecial";    lambdaName = "DMH.newInvokeSpecial"; break;
-+        default:  throw new InternalError("which="+which);
-+        }
-+        MethodType mtypeWithArg = mtype.appendParameterTypes(MemberName.class);
-+        if (doesAlloc)
-+            mtypeWithArg = mtypeWithArg
-+                    .insertParameterTypes(0, Object.class)  // insert newly allocated obj
-+                    .changeReturnType(void.class);          // <init> returns void
-+        MemberName linker = new MemberName(MethodHandle.class, linkerName, mtypeWithArg, REF_invokeStatic);
-+        try {
-+            linker = IMPL_NAMES.resolveOrFail(REF_invokeStatic, linker, null, NoSuchMethodException.class);
-+        } catch (ReflectiveOperationException ex) {
-+            throw new InternalError(ex);
-+        }
-+        final int DMH_THIS    = 0;
-+        final int ARG_BASE    = 1;
-+        final int ARG_LIMIT   = ARG_BASE + mtype.parameterCount();
-+        int nameCursor = ARG_LIMIT;
-+        final int NEW_OBJ     = (doesAlloc ? nameCursor++ : -1);
-+        final int GET_MEMBER  = nameCursor++;
-+        final int LINKER_CALL = nameCursor++;
-+        Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
-+        assert(names.length == nameCursor);
-+        if (doesAlloc) {
-+            // names = { argx,y,z,... new C, init method }
-+            names[NEW_OBJ] = new Name(NF_allocateInstance, names[DMH_THIS]);
-+            names[GET_MEMBER] = new Name(NF_constructorMethod, names[DMH_THIS]);
-+        } else if (needsInit) {
-+            names[GET_MEMBER] = new Name(NF_internalMemberNameEnsureInit, names[DMH_THIS]);
-+        } else {
-+            names[GET_MEMBER] = new Name(NF_internalMemberName, names[DMH_THIS]);
-+        }
-+        Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, GET_MEMBER+1, Object[].class);
-+        assert(outArgs[outArgs.length-1] == names[GET_MEMBER]);  // look, shifted args!
-+        int result = LambdaForm.LAST_RESULT;
-+        if (doesAlloc) {
-+            assert(outArgs[outArgs.length-2] == names[NEW_OBJ]);  // got to move this one
-+            System.arraycopy(outArgs, 0, outArgs, 1, outArgs.length-2);
-+            outArgs[0] = names[NEW_OBJ];
-+            result = NEW_OBJ;
-+        }
-+        names[LINKER_CALL] = new Name(linker, outArgs);
-+        lambdaName += "_" + LambdaForm.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();
-+        return lform;
-+    }
-+
-+    private static void maybeCompile(LambdaForm lform, MemberName m) {
-+        if (VerifyAccess.isSamePackage(m.getDeclaringClass(), MethodHandle.class))
-+            // Help along bootstrapping...
-+            lform.compileToBytecode();
-+    }
-+
-+    /** Static wrapper for DirectMethodHandle.internalMemberName. */
-+    @ForceInline
-+    /*non-public*/ static Object internalMemberName(Object mh) {
-+        return ((DirectMethodHandle)mh).member;
-+    }
-+
-+    /** Static wrapper for DirectMethodHandle.internalMemberName.
-+     * This one also forces initialization.
-+     */
-+    /*non-public*/ static Object internalMemberNameEnsureInit(Object mh) {
-+        DirectMethodHandle dmh = (DirectMethodHandle)mh;
-+        dmh.ensureInitialized();
-+        return dmh.member;
-+    }
-+
-+    /*non-public*/ static
-+    boolean shouldBeInitialized(MemberName member) {
-+        switch (member.getReferenceKind()) {
-+        case REF_invokeStatic:
-+        case REF_getStatic:
-+        case REF_putStatic:
-+        case REF_newInvokeSpecial:
-+            break;
-+        default:
-+            // No need to initialize the class on this kind of member.
-+            return false;
-+        }
-+        Class<?> cls = member.getDeclaringClass();
-+        if (cls == ValueConversions.class ||
-+            cls == MethodHandleImpl.class ||
-+            cls == Invokers.class) {
-+            // These guys have lots of <clinit> DMH creation but we know
-+            // the MHs will not be used until the system is booted.
-+            return false;
-+        }
-+        if (VerifyAccess.isSamePackage(MethodHandle.class, cls) ||
-+            VerifyAccess.isSamePackage(ValueConversions.class, cls)) {
-+            // It is a system class.  It is probably in the process of
-+            // being initialized, but we will help it along just to be safe.
-+            if (UNSAFE.shouldBeInitialized(cls)) {
-+                UNSAFE.ensureClassInitialized(cls);
-+            }
-+            return false;
-+        }
-+        return UNSAFE.shouldBeInitialized(cls);
-+    }
-+
-+    private static class EnsureInitialized extends ClassValue<WeakReference<Thread>> {
-+        @Override
-+        protected WeakReference<Thread> computeValue(Class<?> type) {
-+            UNSAFE.ensureClassInitialized(type);
-+            if (UNSAFE.shouldBeInitialized(type))
-+                // If the previous call didn't block, this can happen.
-+                // We are executing inside <clinit>.
-+                return new WeakReference<>(Thread.currentThread());
-+            return null;
-+        }
-+        static final EnsureInitialized INSTANCE = new EnsureInitialized();
-+    }
-+
-+    private void ensureInitialized() {
-+        if (checkInitialized(member)) {
-+            // The coast is clear.  Delete the <clinit> barrier.
-+            if (member.isField())
-+                updateForm(preparedFieldLambdaForm(member));
-+            else
-+                updateForm(preparedLambdaForm(member));
-+        }
-+    }
-+    private static boolean checkInitialized(MemberName member) {
-+        Class<?> defc = member.getDeclaringClass();
-+        WeakReference<Thread> ref = EnsureInitialized.INSTANCE.get(defc);
-+        if (ref == null) {
-+            return true;  // the final state
-+        }
-+        Thread clinitThread = ref.get();
-+        // Somebody may still be running defc.<clinit>.
-+        if (clinitThread == Thread.currentThread()) {
-+            // If anybody is running defc.<clinit>, it is this thread.
-+            if (UNSAFE.shouldBeInitialized(defc))
-+                // Yes, we are running it; keep the barrier for now.
-+                return false;
-+        } else {
-+            // We are in a random thread.  Block.
-+            UNSAFE.ensureClassInitialized(defc);
-+        }
-+        assert(!UNSAFE.shouldBeInitialized(defc));
-+        // put it into the final state
-+        EnsureInitialized.INSTANCE.remove(defc);
-+        return true;
-+    }
-+
-+    /*non-public*/ static void ensureInitialized(Object mh) {
-+        ((DirectMethodHandle)mh).ensureInitialized();
-+    }
-+
-+    /** This subclass handles constructor references. */
-+    static class Constructor extends DirectMethodHandle {
-+        final MemberName initMethod;
-+        final Class<?>   instanceClass;
-+
-+        private Constructor(MethodType mtype, LambdaForm form, MemberName constructor,
-+                            MemberName initMethod, Class<?> instanceClass) {
-+            super(mtype, form, constructor);
-+            this.initMethod = initMethod;
-+            this.instanceClass = instanceClass;
-+            assert(initMethod.isResolved());
-+        }
-+    }
-+
-+    /*non-public*/ static Object constructorMethod(Object mh) {
-+        Constructor dmh = (Constructor)mh;
-+        return dmh.initMethod;
-+    }
-+
-+    /*non-public*/ static Object allocateInstance(Object mh) throws InstantiationException {
-+        Constructor dmh = (Constructor)mh;
-+        return UNSAFE.allocateInstance(dmh.instanceClass);
-+    }
-+
-+    /** This subclass handles non-static field references. */
-+    static class Accessor extends DirectMethodHandle {
-+        final Class<?> fieldType;
-+        final int      fieldOffset;
-+        private Accessor(MethodType mtype, LambdaForm form, MemberName member,
-+                         int fieldOffset) {
-+            super(mtype, form, member);
-+            this.fieldType   = member.getFieldType();
-+            this.fieldOffset = fieldOffset;
-+        }
-+
-+        @Override Object checkCast(Object obj) {
-+            return fieldType.cast(obj);
-+        }
-+    }
-+
-+    @ForceInline
-+    /*non-public*/ static long fieldOffset(Object accessorObj) {
-+        // Note: We return a long because that is what Unsafe.getObject likes.
-+        // We store a plain int because it is more compact.
-+        return ((Accessor)accessorObj).fieldOffset;
-+    }
-+
-+    @ForceInline
-+    /*non-public*/ static Object checkBase(Object obj) {
-+        // Note that the object's class has already been verified,
-+        // since the parameter type of the Accessor method handle
-+        // is either member.getDeclaringClass or a subclass.
-+        // This was verified in DirectMethodHandle.make.
-+        // Therefore, the only remaining check is for null.
-+        // Since this check is *not* guaranteed by Unsafe.getInt
-+        // and its siblings, we need to make an explicit one here.
-+        obj.getClass();  // maybe throw NPE
-+        return obj;
-+    }
-+
-+    /** This subclass handles static field references. */
-+    static class StaticAccessor extends DirectMethodHandle {
-+        final private Class<?> fieldType;
-+        final private Object   staticBase;
-+        final private long     staticOffset;
-+
-+        private StaticAccessor(MethodType mtype, LambdaForm form, MemberName member,
-+                               Object staticBase, long staticOffset) {
-+            super(mtype, form, member);
-+            this.fieldType    = member.getFieldType();
-+            this.staticBase   = staticBase;
-+            this.staticOffset = staticOffset;
-+        }
-+
-+        @Override Object checkCast(Object obj) {
-+            return fieldType.cast(obj);
-+        }
-+    }
-+
-+    @ForceInline
-+    /*non-public*/ static Object nullCheck(Object obj) {
-+        obj.getClass();
-+        return obj;
-+    }
-+
-+    @ForceInline
-+    /*non-public*/ static Object staticBase(Object accessorObj) {
-+        return ((StaticAccessor)accessorObj).staticBase;
-+    }
-+
-+    @ForceInline
-+    /*non-public*/ static long staticOffset(Object accessorObj) {
-+        return ((StaticAccessor)accessorObj).staticOffset;
-+    }
-+
-+    @ForceInline
-+    /*non-public*/ static Object checkCast(Object mh, Object obj) {
-+        return ((DirectMethodHandle) mh).checkCast(obj);
-+    }
-+
-+    Object checkCast(Object obj) {
-+        return member.getReturnType().cast(obj);
-+    }
-+
-+    // Caching machinery for field accessors:
-+    private static byte
-+            AF_GETFIELD        = 0,
-+            AF_PUTFIELD        = 1,
-+            AF_GETSTATIC       = 2,
-+            AF_PUTSTATIC       = 3,
-+            AF_GETSTATIC_INIT  = 4,
-+            AF_PUTSTATIC_INIT  = 5,
-+            AF_LIMIT           = 6;
-+    // Enumerate the different field kinds using Wrapper,
-+    // with an extra case added for checked references.
-+    private static int
-+            FT_LAST_WRAPPER    = Wrapper.values().length-1,
-+            FT_UNCHECKED_REF   = Wrapper.OBJECT.ordinal(),
-+            FT_CHECKED_REF     = FT_LAST_WRAPPER+1,
-+            FT_LIMIT           = FT_LAST_WRAPPER+2;
-+    private static int afIndex(byte formOp, boolean isVolatile, int ftypeKind) {
-+        return ((formOp * FT_LIMIT * 2)
-+                + (isVolatile ? FT_LIMIT : 0)
-+                + ftypeKind);
-+    }
-+    private static final LambdaForm[] ACCESSOR_FORMS
-+            = new LambdaForm[afIndex(AF_LIMIT, false, 0)];
-+    private static int ftypeKind(Class<?> ftype) {
-+        if (ftype.isPrimitive())
-+            return Wrapper.forPrimitiveType(ftype).ordinal();
-+        else if (VerifyType.isNullReferenceConversion(Object.class, ftype))
-+            return FT_UNCHECKED_REF;
-+        else
-+            return FT_CHECKED_REF;
-+    }
-+
-+    /**
-+     * Create a LF which can access the given field.
-+     * Cache and share this structure among all fields with
-+     * the same basicType and refKind.
-+     */
-+    private static LambdaForm preparedFieldLambdaForm(MemberName m) {
-+        Class<?> ftype = m.getFieldType();
-+        boolean isVolatile = m.isVolatile();
-+        byte formOp;
-+        switch (m.getReferenceKind()) {
-+        case REF_getField:      formOp = AF_GETFIELD;    break;
-+        case REF_putField:      formOp = AF_PUTFIELD;    break;
-+        case REF_getStatic:     formOp = AF_GETSTATIC;   break;
-+        case REF_putStatic:     formOp = AF_PUTSTATIC;   break;
-+        default:  throw new InternalError(m.toString());
-+        }
-+        if (shouldBeInitialized(m)) {
-+            // precompute the barrier-free version:
-+            preparedFieldLambdaForm(formOp, isVolatile, ftype);
-+            assert((AF_GETSTATIC_INIT - AF_GETSTATIC) ==
-+                   (AF_PUTSTATIC_INIT - AF_PUTSTATIC));
-+            formOp += (AF_GETSTATIC_INIT - AF_GETSTATIC);
-+        }
-+        LambdaForm lform = preparedFieldLambdaForm(formOp, isVolatile, ftype);
-+        maybeCompile(lform, m);
-+        assert(lform.methodType().dropParameterTypes(0, 1)
-+                .equals(m.getInvocationType().basicType()))
-+                : Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType());
-+        return lform;
-+    }
-+    private static LambdaForm preparedFieldLambdaForm(byte formOp, boolean isVolatile, Class<?> ftype) {
-+        int afIndex = afIndex(formOp, isVolatile, ftypeKind(ftype));
-+        LambdaForm lform = ACCESSOR_FORMS[afIndex];
-+        if (lform != null)  return lform;
-+        lform = makePreparedFieldLambdaForm(formOp, isVolatile, ftypeKind(ftype));
-+        ACCESSOR_FORMS[afIndex] = lform;  // don't bother with a CAS
-+        return lform;
-+    }
-+
-+    private static LambdaForm makePreparedFieldLambdaForm(byte formOp, boolean isVolatile, int ftypeKind) {
-+        boolean isGetter  = (formOp & 1) == (AF_GETFIELD & 1);
-+        boolean isStatic  = (formOp >= AF_GETSTATIC);
-+        boolean needsInit = (formOp >= AF_GETSTATIC_INIT);
-+        boolean needsCast = (ftypeKind == FT_CHECKED_REF);
-+        Wrapper fw = (needsCast ? Wrapper.OBJECT : Wrapper.values()[ftypeKind]);
-+        Class<?> ft = fw.primitiveType();
-+        assert(ftypeKind(needsCast ? String.class : ft) == ftypeKind);
-+        String tname  = fw.primitiveSimpleName();
-+        String ctname = Character.toUpperCase(tname.charAt(0)) + tname.substring(1);
-+        if (isVolatile)  ctname += "Volatile";
-+        String getOrPut = (isGetter ? "get" : "put");
-+        String linkerName = (getOrPut + ctname);  // getObject, putIntVolatile, etc.
-+        MethodType linkerType;
-+        if (isGetter)
-+            linkerType = MethodType.methodType(ft, Object.class, long.class);
-+        else
-+            linkerType = MethodType.methodType(void.class, Object.class, long.class, ft);
-+        MemberName linker = new MemberName(Unsafe.class, linkerName, linkerType, REF_invokeVirtual);
-+        try {
-+            linker = IMPL_NAMES.resolveOrFail(REF_invokeVirtual, linker, null, NoSuchMethodException.class);
-+        } catch (ReflectiveOperationException ex) {
-+            throw new InternalError(ex);
-+        }
-+
-+        // What is the external type of the lambda form?
-+        MethodType mtype;
-+        if (isGetter)
-+            mtype = MethodType.methodType(ft);
-+        else
-+            mtype = MethodType.methodType(void.class, ft);
-+        mtype = mtype.basicType();  // erase short to int, etc.
-+        if (!isStatic)
-+            mtype = mtype.insertParameterTypes(0, Object.class);
-+        final int DMH_THIS  = 0;
-+        final int ARG_BASE  = 1;
-+        final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
-+        // if this is for non-static access, the base pointer is stored at this index:
-+        final int OBJ_BASE  = isStatic ? -1 : ARG_BASE;
-+        // if this is for write access, the value to be written is stored at this index:
-+        final int SET_VALUE  = isGetter ? -1 : ARG_LIMIT - 1;
-+        int nameCursor = ARG_LIMIT;
-+        final int F_HOLDER  = (isStatic ? nameCursor++ : -1);  // static base if any
-+        final int F_OFFSET  = nameCursor++;  // Either static offset or field offset.
-+        final int OBJ_CHECK = (OBJ_BASE >= 0 ? nameCursor++ : -1);
-+        final int INIT_BAR  = (needsInit ? nameCursor++ : -1);
-+        final int PRE_CAST  = (needsCast && !isGetter ? nameCursor++ : -1);
-+        final int LINKER_CALL = nameCursor++;
-+        final int POST_CAST = (needsCast && isGetter ? nameCursor++ : -1);
-+        final int RESULT    = nameCursor-1;  // either the call or the cast
-+        Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
-+        if (needsInit)
-+            names[INIT_BAR] = new Name(NF_ensureInitialized, names[DMH_THIS]);
-+        if (needsCast && !isGetter)
-+            names[PRE_CAST] = new Name(NF_checkCast, names[DMH_THIS], names[SET_VALUE]);
-+        Object[] outArgs = new Object[1 + linkerType.parameterCount()];
-+        assert(outArgs.length == (isGetter ? 3 : 4));
-+        outArgs[0] = UNSAFE;
-+        if (isStatic) {
-+            outArgs[1] = names[F_HOLDER]  = new Name(NF_staticBase, names[DMH_THIS]);
-+            outArgs[2] = names[F_OFFSET]  = new Name(NF_staticOffset, names[DMH_THIS]);
-+        } else {
-+            outArgs[1] = names[OBJ_CHECK] = new Name(NF_checkBase, names[OBJ_BASE]);
-+            outArgs[2] = names[F_OFFSET]  = new Name(NF_fieldOffset, names[DMH_THIS]);
-+        }
-+        if (!isGetter) {
-+            outArgs[3] = (needsCast ? names[PRE_CAST] : names[SET_VALUE]);
-+        }
-+        for (Object a : outArgs)  assert(a != null);
-+        names[LINKER_CALL] = new Name(linker, outArgs);
-+        if (needsCast && isGetter)
-+            names[POST_CAST] = new Name(NF_checkCast, names[DMH_THIS], names[LINKER_CALL]);
-+        for (Name n : names)  assert(n != null);
-+        String fieldOrStatic = (isStatic ? "Static" : "Field");
-+        String lambdaName = (linkerName + fieldOrStatic);  // significant only for debugging
-+        if (needsCast)  lambdaName += "Cast";
-+        if (needsInit)  lambdaName += "Init";
-+        return new LambdaForm(lambdaName, ARG_LIMIT, names, RESULT);
-+    }
-+
-+    private static final NamedFunction
-+            NF_internalMemberName,
-+            NF_internalMemberNameEnsureInit,
-+            NF_ensureInitialized,
-+            NF_fieldOffset,
-+            NF_checkBase,
-+            NF_staticBase,
-+            NF_staticOffset,
-+            NF_checkCast,
-+            NF_allocateInstance,
-+            NF_constructorMethod;
-+    static {
-+        try {
-+            NamedFunction nfs[] = {
-+                NF_internalMemberName = new NamedFunction(DirectMethodHandle.class
-+                    .getDeclaredMethod("internalMemberName", Object.class)),
-+                NF_internalMemberNameEnsureInit = new NamedFunction(DirectMethodHandle.class
-+                    .getDeclaredMethod("internalMemberNameEnsureInit", Object.class)),
-+                NF_ensureInitialized = new NamedFunction(DirectMethodHandle.class
-+                    .getDeclaredMethod("ensureInitialized", Object.class)),
-+                NF_fieldOffset = new NamedFunction(DirectMethodHandle.class
-+                    .getDeclaredMethod("fieldOffset", Object.class)),
-+                NF_checkBase = new NamedFunction(DirectMethodHandle.class
-+                    .getDeclaredMethod("checkBase", Object.class)),
-+                NF_staticBase = new NamedFunction(DirectMethodHandle.class
-+                    .getDeclaredMethod("staticBase", Object.class)),
-+                NF_staticOffset = new NamedFunction(DirectMethodHandle.class
-+                    .getDeclaredMethod("staticOffset", Object.class)),
-+                NF_checkCast = new NamedFunction(DirectMethodHandle.class
-+                    .getDeclaredMethod("checkCast", Object.class, Object.class)),
-+                NF_allocateInstance = new NamedFunction(DirectMethodHandle.class
-+                    .getDeclaredMethod("allocateInstance", Object.class)),
-+                NF_constructorMethod = new NamedFunction(DirectMethodHandle.class
-+                    .getDeclaredMethod("constructorMethod", 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 new InternalError(ex);
-+        }
-     }
- }
-diff --git a/src/share/classes/java/lang/invoke/DontInline.java b/src/share/classes/java/lang/invoke/DontInline.java
-new file mode 100644
---- /dev/null
-+++ b/src/share/classes/java/lang/invoke/DontInline.java
-@@ -0,0 +1,37 @@
-+/*
-+ * Copyright (c) 2012, 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.lang.annotation.*;
-+
-+/**
-+ * Internal marker for some methods in the JSR 292 implementation.
-+ */
-+/*non-public*/
-+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
-+@Retention(RetentionPolicy.RUNTIME)
-+@interface DontInline {
-+}
-diff --git a/src/share/classes/java/lang/invoke/ForceInline.java b/src/share/classes/java/lang/invoke/ForceInline.java
-new file mode 100644
---- /dev/null
-+++ b/src/share/classes/java/lang/invoke/ForceInline.java
-@@ -0,0 +1,37 @@
-+/*
-+ * Copyright (c) 2012, 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.lang.annotation.*;
-+
-+/**
-+ * Internal marker for some methods in the JSR 292 implementation.
-+ */
-+/*non-public*/
-+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
-+@Retention(RetentionPolicy.RUNTIME)
-+@interface ForceInline {
-+}
-diff --git a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
-new file mode 100644
---- /dev/null
-+++ b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
-@@ -0,0 +1,1065 @@
-+/*
-+ * Copyright (c) 2012, 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.VerifyAccess;
-+import java.lang.invoke.LambdaForm.Name;
-+import java.lang.invoke.MethodHandles.Lookup;
-+
-+import sun.invoke.util.Wrapper;
-+
-+import java.io.*;
-+import java.util.*;
-+
-+import com.sun.xml.internal.ws.org.objectweb.asm.*;
-+
-+import java.lang.reflect.*;
-+import static java.lang.invoke.MethodHandleStatics.*;
-+import static java.lang.invoke.MethodHandleNatives.Constants.*;
-+import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
-+import sun.invoke.util.ValueConversions;
-+import sun.invoke.util.VerifyType;
-+
-+/**
-+ * Code generation backend for LambdaForm.
-+ * <p>
-+ * @author John Rose, JSR 292 EG
-+ */
-+class InvokerBytecodeGenerator {
-+    /** Define class names for convenience. */
-+    private static final String MH      = "java/lang/invoke/MethodHandle";
-+    private static final String BMH     = "java/lang/invoke/BoundMethodHandle";
-+    private static final String LF      = "java/lang/invoke/LambdaForm";
-+    private static final String LFN     = "java/lang/invoke/LambdaForm$Name";
-+    private static final String CLS     = "java/lang/Class";
-+    private static final String OBJ     = "java/lang/Object";
-+    private static final String OBJARY  = "[Ljava/lang/Object;";
-+
-+    private static final String LF_SIG  = "L" + LF + ";";
-+    private static final String LFN_SIG = "L" + LFN + ";";
-+    private static final String LL_SIG  = "(L" + OBJ + ";)L" + OBJ + ";";
-+
-+    /** Name of its super class*/
-+    private static final String superName = LF;
-+
-+    /** Name of new class */
-+    private final String className;
-+
-+    /** Name of the source file (for stack trace printing). */
-+    private final String sourceFile;
-+
-+    private final LambdaForm lambdaForm;
-+    private final String     invokerName;
-+    private final MethodType invokerType;
-+    private final int[] localsMap;
-+
-+    /** ASM bytecode generation. */
-+    private ClassWriter cw;
-+    private MethodVisitor mv;
-+
-+    private static final MemberName.Factory MEMBERNAME_FACTORY = MemberName.getFactory();
-+    private static final Class<?> HOST_CLASS = LambdaForm.class;
-+
-+    private InvokerBytecodeGenerator(LambdaForm lambdaForm, int localsMapSize,
-+                                     String className, String invokerName, MethodType invokerType) {
-+        if (invokerName.contains(".")) {
-+            int p = invokerName.indexOf(".");
-+            className = invokerName.substring(0, p);
-+            invokerName = invokerName.substring(p+1);
-+        }
-+        if (DUMP_CLASS_FILES) {
-+            className = makeDumpableClassName(className);
-+        }
-+        this.className  = superName + "$" + className;
-+        this.sourceFile = "LambdaForm$" + className;
-+        this.lambdaForm = lambdaForm;
-+        this.invokerName = invokerName;
-+        this.invokerType = invokerType;
-+        this.localsMap = new int[localsMapSize];
-+    }
-+
-+    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.
-+        for (int i = 0; i < localsMap.length; i++) {
-+            localsMap[i] = invokerType.parameterSlotCount() - invokerType.parameterSlotDepth(i);
-+        }
-+    }
-+
-+    private InvokerBytecodeGenerator(String className, LambdaForm form, MethodType invokerType) {
-+        this(form, form.names.length,
-+             className, form.debugName, invokerType);
-+        // Create an array to map name indexes to locals indexes.
-+        Name[] names = form.names;
-+        for (int i = 0, index = 0; i < localsMap.length; i++) {
-+            localsMap[i] = index;
-+            index += Wrapper.forBasicType(names[i].type).stackSlots();
-+        }
-+    }
-+
-+
-+    /** instance counters for dumped classes */
-+    private final static HashMap<String,Integer> DUMP_CLASS_FILES_COUNTERS;
-+    /** debugging flag for saving generated class files */
-+    private final static File DUMP_CLASS_FILES_DIR;
-+
-+    static {
-+        if (DUMP_CLASS_FILES) {
-+            DUMP_CLASS_FILES_COUNTERS = new HashMap<>();
-+            try {
-+                File dumpDir = new File("DUMP_CLASS_FILES");
-+                if (!dumpDir.exists()) {
-+                    dumpDir.mkdirs();
-+                }
-+                DUMP_CLASS_FILES_DIR = dumpDir;
-+                System.out.println("Dumping class files to "+DUMP_CLASS_FILES_DIR+"/...");
-+            } catch (Exception e) {
-+                throw new InternalError(e);
-+            }
-+        } else {
-+            DUMP_CLASS_FILES_COUNTERS = null;
-+            DUMP_CLASS_FILES_DIR = null;
-+        }
-+    }
-+
-+    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() {
-+                    try {
-+                        String dumpName = className;
-+                        //dumpName = dumpName.replace('/', '-');
-+                        File dumpFile = new File(DUMP_CLASS_FILES_DIR, dumpName+".class");
-+                        dumpFile.getParentFile().mkdirs();
-+                        FileOutputStream file = new FileOutputStream(dumpFile);
-+                        file.write(classFile);
-+                        file.close();
-+                        return null;
-+                    } catch (IOException ex) {
-+                        throw new InternalError(ex);
-+                    }
-+                }
-+            });
-+        }
-+
-+    }
-+
-+    private static String makeDumpableClassName(String className) {
-+        Integer ctr;
-+        synchronized (DUMP_CLASS_FILES_COUNTERS) {
-+            ctr = DUMP_CLASS_FILES_COUNTERS.get(className);
-+            if (ctr == null)  ctr = 0;
-+            DUMP_CLASS_FILES_COUNTERS.put(className, ctr+1);
-+        }
-+        String sfx = ctr.toString();
-+        while (sfx.length() < 3)
-+            sfx = "0"+sfx;
-+        className += sfx;
-+        return className;
-+    }
-+
-+    class CpPatch {
-+        int index;
-+        Object value;
-+        CpPatch(int index, Object value) {
-+            this.index = index;
-+            this.value = value;
-+        }
-+    }
-+
-+    Map<Object, CpPatch> cpPatches = new HashMap<>();
-+
-+    int cph = 0;  // for counting constant placeholders
-+
-+    String constantPlaceholder(Object arg) {
-+        String cpPlaceholder = "CONSTANT_PLACEHOLDER_" + cph++;
-+        if (DUMP_CLASS_FILES) cpPlaceholder += " <<" + arg.toString() + ">>";  // debugging aid
-+        if (cpPatches.containsKey(cpPlaceholder)) {
-+            throw new InternalError("observed CP placeholder twice: " + cpPlaceholder);
-+        }
-+        // insert placeholder in CP and remember the patch
-+        int index = cw.newConst((Object) cpPlaceholder);  // TODO check if aready in the constant pool
-+        cpPatches.put(cpPlaceholder, new CpPatch(index, arg));
-+        return cpPlaceholder;
-+    }
-+
-+    Object[] cpPatches(byte[] classFile) {
-+        int size = getConstantPoolSize(classFile);
-+        Object[] res = new Object[size];
-+        for (CpPatch p : cpPatches.values()) {
-+                res[p.index] = p.value;
-+        }
-+        return res;
-+    }
-+
-+    /**
-+     * Extract the number of constant pool entries from a given class file.
-+     *
-+     * @param classFile the bytes of the class file in question.
-+     * @return the number of entries in the constant pool.
-+     */
-+    private static int getConstantPoolSize(byte[] classFile) {
-+        // The first few bytes:
-+        // u4 magic;
-+        // u2 minor_version;
-+        // u2 major_version;
-+        // u2 constant_pool_count;
-+        return ((classFile[8] << 8) & 0xFF) | ( classFile[9] & 0xFF);
-+    }
-+
-+    /**
-+     * Extract the MemberName of a newly-defined method.
-+     *
-+     * @param classFile
-+     * @return
-+     */
-+    private MemberName loadMethod(byte[] classFile) {
-+        Class<?> invokerClass = loadAndInitializeInvokerClass(classFile, cpPatches(classFile));
-+        return resolveInvokerMember(invokerClass, invokerName, invokerType);
-+    }
-+
-+    /**
-+     * Define a given class as anonymous class in the runtime system.
-+     *
-+     * @param classBytes
-+     * @param patches
-+     * @return
-+     */
-+    private static Class<?> loadAndInitializeInvokerClass(byte[] classBytes, Object[] patches) {
-+        Class<?> invokerClass = UNSAFE.defineAnonymousClass(HOST_CLASS, classBytes, patches);
-+        UNSAFE.ensureClassInitialized(invokerClass);  // Make sure the class is initialized; VM might complain.
-+        return invokerClass;
-+    }
-+
-+    /**
-+     * TODO
-+     *
-+     * @param invokerClass
-+     * @param name
-+     * @param type
-+     * @return
-+     */
-+    private static MemberName resolveInvokerMember(Class<?> invokerClass, String name, MethodType type) {
-+        MemberName member = new MemberName(invokerClass, name, type, REF_invokeStatic);
-+        //System.out.println("resolveInvokerMember => "+member);
-+        //for (Method m : invokerClass.getDeclaredMethods())  System.out.println("  "+m);
-+        try {
-+            member = MEMBERNAME_FACTORY.resolveOrFail(REF_invokeStatic, member, HOST_CLASS, ReflectiveOperationException.class);
-+        } catch (ReflectiveOperationException e) {
-+            throw new InternalError(e);
-+        }
-+        //System.out.println("resolveInvokerMember => "+member);
-+        return member;
-+    }
-+
-+    /**
-+     * Set up class file generation.
-+     */
-+    private void classFilePrologue() {
-+        cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
-+        cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, className, null, superName, null);
-+        cw.visitSource(sourceFile, null);
-+
-+        String invokerDesc = invokerType.toMethodDescriptorString();
-+        mv = cw.visitMethod(Opcodes.ACC_STATIC, invokerName, invokerDesc, null, null);
-+
-+        // Force inlining of this invoker method.
-+        mv.visitAnnotation("Ljava/lang/invoke/ForceInline;", true);
-+    }
-+
-+    /**
-+     * Tear down class file generation.
-+     */
-+    private void classFileEpilogue() {
-+        mv.visitMaxs(0, 0);
-+        mv.visitEnd();
-+    }
-+
-+    /*
-+     * Low-level emit helpers.
-+     */
-+    private void emitConst(Object con) {
-+        if (con == null) {
-+            mv.visitInsn(Opcodes.ACONST_NULL);
-+            return;
-+        }
-+        if (con instanceof Integer) {
-+            emitIconstInsn((int) con);
-+            return;
-+        }
-+        if (con instanceof Long) {
-+            long x = (long) con;
-+            if (x == (short) x) {
-+                emitIconstInsn((int) x);
-+                mv.visitInsn(Opcodes.I2L);
-+                return;
-+            }
-+        }
-+        if (con instanceof Float) {
-+            float x = (float) con;
-+            if (x == (short) x) {
-+                emitIconstInsn((int) x);
-+                mv.visitInsn(Opcodes.I2F);
-+                return;
-+            }
-+        }
-+        if (con instanceof Double) {
-+            double x = (double) con;
-+            if (x == (short) x) {
-+                emitIconstInsn((int) x);
-+                mv.visitInsn(Opcodes.I2D);
-+                return;
-+            }
-+        }
-+        if (con instanceof Boolean) {
-+            emitIconstInsn((boolean) con ? 1 : 0);
-+            return;
-+        }
-+        // fall through:
-+        mv.visitLdcInsn(con);
-+    }
-+
-+    private void emitIconstInsn(int i) {
-+        int opcode;
-+        switch (i) {
-+        case 0:  opcode = Opcodes.ICONST_0;  break;
-+        case 1:  opcode = Opcodes.ICONST_1;  break;
-+        case 2:  opcode = Opcodes.ICONST_2;  break;
-+        case 3:  opcode = Opcodes.ICONST_3;  break;
-+        case 4:  opcode = Opcodes.ICONST_4;  break;
-+        case 5:  opcode = Opcodes.ICONST_5;  break;
-+        default:
-+            if (i == (byte) i) {
-+                mv.visitIntInsn(Opcodes.BIPUSH, i & 0xFF);
-+            } else if (i == (short) i) {
-+                mv.visitIntInsn(Opcodes.SIPUSH, (char) i);
-+            } else {
-+                mv.visitLdcInsn(i);
-+            }
-+            return;
-+        }
-+        mv.visitInsn(opcode);
-+    }
-+
-+    /*
-+     * NOTE: These load/store methods use the localsMap to find the correct index!
-+     */
-+    private void emitLoadInsn(char 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;
-+        default:
-+            throw new InternalError("unknown type: " + type);
-+        }
-+        mv.visitVarInsn(opcode, localsMap[index]);
-+    }
-+    private void emitAloadInsn(int index) {
-+        emitLoadInsn('L', index);
-+    }
-+
-+    private void emitStoreInsn(char 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;
-+        default:
-+            throw new InternalError("unknown type: " + type);
-+        }
-+        mv.visitVarInsn(opcode, localsMap[index]);
-+    }
-+    private void emitAstoreInsn(int index) {
-+        emitStoreInsn('L', index);
-+    }
-+
-+    /**
-+     * Emit a boxing call.
-+     *
-+     * @param type primitive type class to box.
-+     */
-+    private void emitBoxing(Class<?> type) {
-+        Wrapper wrapper = Wrapper.forPrimitiveType(type);
-+        String owner = "java/lang/" + wrapper.wrapperType().getSimpleName();
-+        String name  = "valueOf";
-+        String desc  = "(" + wrapper.basicTypeChar() + ")L" + owner + ";";
-+        mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc);
-+    }
-+
-+    /**
-+     * Emit an unboxing call (plus preceding checkcast).
-+     *
-+     * @param type wrapper type class to unbox.
-+     */
-+    private void emitUnboxing(Class<?> type) {
-+        Wrapper wrapper = Wrapper.forWrapperType(type);
-+        String owner = "java/lang/" + wrapper.wrapperType().getSimpleName();
-+        String name  = wrapper.primitiveSimpleName() + "Value";
-+        String desc  = "()" + wrapper.basicTypeChar();
-+        mv.visitTypeInsn(Opcodes.CHECKCAST, owner);
-+        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc);
-+    }
-+
-+    /**
-+     * Emit an implicit conversion.
-+     *
-+     * @param ptype type of value present on stack
-+     * @param pclass type of value required on stack
-+     */
-+    private void emitImplicitConversion(char ptype, Class<?> pclass) {
-+        switch (ptype) {
-+        case 'L':
-+            if (VerifyType.isNullConversion(Object.class, pclass))
-+                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);
-+            }
-+            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);
-+            return;
-+        }
-+        throw new InternalError("bad implicit conversion: tc="+ptype+": "+pclass);
-+    }
-+
-+    /**
-+     * Emits an actual return instruction conforming to the given return type.
-+     */
-+    private void emitReturnInsn(Class<?> 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;
-+        default:
-+            throw new InternalError("unknown return type: " + type);
-+        }
-+        mv.visitInsn(opcode);
-+    }
-+
-+    private static String getInternalName(Class<?> c) {
-+        assert(VerifyAccess.isTypeVisible(c, Object.class));
-+        return c.getName().replace('.', '/');
-+    }
-+
-+    /**
-+     * Generate customized bytecode for a given LambdaForm.
-+     *
-+     * @param form
-+     * @param invokerType
-+     * @return
-+     */
-+    static MemberName generateCustomizedCode(LambdaForm form, MethodType invokerType) {
-+        InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("MH", form, invokerType);
-+        return g.loadMethod(g.generateCustomizedCodeBytes());
-+    }
-+
-+    /**
-+     * Generate an invoker method for the passed {@link LambdaForm}.
-+     */
-+    private byte[] generateCustomizedCodeBytes() {
-+        classFilePrologue();
-+
-+        // Suppress this method in backtraces displayed to the user.
-+        mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
-+
-+        // Mark this method as a compiled LambdaForm
-+        mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Compiled;", true);
-+
-+        // iterate over the form's names, generating bytecode instructions for each
-+        // start iterating at the first name following the arguments
-+        for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
-+            Name name = lambdaForm.names[i];
-+            MemberName member = name.function.member();
-+
-+            if (isSelectAlternative(member)) {
-+                // selectAlternative idiom
-+                // FIXME: make sure this idiom is really present!
-+                emitSelectAlternative(name, lambdaForm.names[i + 1]);
-+                i++;  // skip MH.invokeBasic of the selectAlternative result
-+            } else if (isStaticallyInvocable(member)) {
-+                emitStaticInvoke(member, name);
-+            } else {
-+                emitInvoke(name);
-+            }
-+
-+            // store the result from evaluating to the target name in a local if required
-+            // (if this is the last value, i.e., the one that is going to be returned,
-+            // avoid store/load/return and just return)
-+            if (i == lambdaForm.names.length - 1 && i == lambdaForm.result) {
-+                // return value - do nothing
-+            } else if (name.type != 'V') {
-+                // non-void: actually assign
-+                emitStoreInsn(name.type, name.index());
-+            }
-+        }
-+
-+        // return statement
-+        emitReturn();
-+
-+        classFileEpilogue();
-+        bogusMethod(lambdaForm);
-+
-+        final byte[] classFile = cw.toByteArray();
-+        maybeDump(className, classFile);
-+        return classFile;
-+    }
-+
-+    /**
-+     * Emit an invoke for the given name.
-+     *
-+     * @param name
-+     */
-+    void emitInvoke(Name name) {
-+        if (true) {
-+            // push receiver
-+            MethodHandle target = name.function.resolvedHandle;
-+            assert(target != null) : name.exprString();
-+            mv.visitLdcInsn(constantPlaceholder(target));
-+            mv.visitTypeInsn(Opcodes.CHECKCAST, MH);
-+        } else {
-+            // load receiver
-+            emitAloadInsn(0);
-+            mv.visitTypeInsn(Opcodes.CHECKCAST, MH);
-+            mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", LF_SIG);
-+            mv.visitFieldInsn(Opcodes.GETFIELD, LF, "names", LFN_SIG);
-+            // TODO more to come
-+        }
-+
-+        // push arguments
-+        for (int i = 0; i < name.arguments.length; i++) {
-+            emitPushArgument(name, i);
-+        }
-+
-+        // invocation
-+        MethodType type = name.function.methodType();
-+        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", type.basicType().toMethodDescriptorString());
-+    }
-+
-+    static private Class<?>[] STATICALLY_INVOCABLE_PACKAGES = {
-+        // Sample classes from each package we are willing to bind to statically:
-+        java.lang.Object.class,
-+        java.util.Arrays.class,
-+        sun.misc.Unsafe.class
-+        //MethodHandle.class already covered
-+    };
-+
-+    static boolean isStaticallyInvocable(MemberName member) {
-+        if (member == null)  return false;
-+        if (member.isConstructor())  return false;
-+        Class<?> cls = member.getDeclaringClass();
-+        if (cls.isArray() || cls.isPrimitive())
-+            return false;  // FIXME
-+        if (cls.isAnonymousClass() || cls.isLocalClass())
-+            return false;  // inner class of some sort
-+        if (cls.getClassLoader() != MethodHandle.class.getClassLoader())
-+            return false;  // not on BCP
-+        if (!member.isPrivate() && VerifyAccess.isSamePackage(MethodHandle.class, cls))
-+            return true;   // in java.lang.invoke package
-+        if (member.isPublic() && isStaticallyNameable(cls))
-+            return true;
-+        return false;
-+    }
-+
-+    static boolean isStaticallyNameable(Class<?> cls) {
-+        while (cls.isArray())
-+            cls = cls.getComponentType();
-+        if (cls.isPrimitive())
-+            return true;  // int[].class, for example
-+        if (cls.getClassLoader() != Object.class.getClassLoader())
-+            return false;
-+        if (VerifyAccess.isSamePackage(MethodHandle.class, cls))
-+            return true;
-+        if (!Modifier.isPublic(cls.getModifiers()))
-+            return false;
-+        for (Class<?> pkgcls : STATICALLY_INVOCABLE_PACKAGES) {
-+            if (VerifyAccess.isSamePackage(pkgcls, cls))
-+                return true;
-+        }
-+        return false;
-+    }
-+
-+    /**
-+     * Emit an invoke for the given name, using the MemberName directly.
-+     *
-+     * @param name
-+     */
-+    void emitStaticInvoke(MemberName member, Name name) {
-+        assert(member.equals(name.function.member()));
-+        String cname = getInternalName(member.getDeclaringClass());
-+        String mname = member.getName();
-+        String mtype;
-+        byte refKind = member.getReferenceKind();
-+        if (refKind == REF_invokeSpecial) {
-+            // in order to pass the verifier, we need to convert this to invokevirtual in all cases
-+            assert(member.canBeStaticallyBound()) : member;
-+            refKind = REF_invokeVirtual;
-+        }
-+
-+        // push arguments
-+        for (int i = 0; i < name.arguments.length; i++) {
-+            emitPushArgument(name, i);
-+        }
-+
-+        // invocation
-+        if (member.isMethod()) {
-+            mtype = member.getMethodType().toMethodDescriptorString();
-+            mv.visitMethodInsn(refKindOpcode(refKind), cname, mname, mtype);
-+        } else {
-+            mtype = MethodType.toFieldDescriptorString(member.getFieldType());
-+            mv.visitFieldInsn(refKindOpcode(refKind), cname, mname, mtype);
-+        }
-+    }
-+    int refKindOpcode(byte refKind) {
-+        switch (refKind) {
-+        case REF_invokeVirtual:      return Opcodes.INVOKEVIRTUAL;
-+        case REF_invokeStatic:       return Opcodes.INVOKESTATIC;
-+        case REF_invokeSpecial:      return Opcodes.INVOKESPECIAL;
-+        case REF_invokeInterface:    return Opcodes.INVOKEINTERFACE;
-+        case REF_getField:           return Opcodes.GETFIELD;
-+        case REF_putField:           return Opcodes.PUTFIELD;
-+        case REF_getStatic:          return Opcodes.GETSTATIC;
-+        case REF_putStatic:          return Opcodes.PUTSTATIC;
-+        }
-+        throw new InternalError("refKind="+refKind);
-+    }
-+
-+    /**
-+     * Check if MemberName is a call to MethodHandleImpl.selectAlternative.
-+     *
-+     * @param member
-+     * @return true if member is a call to MethodHandleImpl.selectAlternative
-+     */
-+    private boolean isSelectAlternative(MemberName member) {
-+        return member != null &&
-+               member.getDeclaringClass() == MethodHandleImpl.class &&
-+               member.getName().equals("selectAlternative");
-+    }
-+
-+    /**
-+     * Emit bytecode for the selectAlternative idiom.
-+     *
-+     * The pattern looks like (Cf. MethodHandleImpl.makeGuardWithTest):
-+     *
-+     *   Lambda(a0:L,a1:I)=>{
-+     *     t2:I=foo.test(a1:I);
-+     *     t3:L=MethodHandleImpl.selectAlternative(t2:I,(MethodHandle(int)int),(MethodHandle(int)int));
-+     *     t4:I=MethodHandle.invokeBasic(t3:L,a1:I);t4:I}
-+     *
-+     * @param selectAlternativeName
-+     * @param invokeBasicName
-+     */
-+    private void emitSelectAlternative(Name selectAlternativeName, Name invokeBasicName) {
-+        MethodType type = selectAlternativeName.function.methodType();
-+
-+        Name receiver = (Name) invokeBasicName.arguments[0];
-+
-+        Label L_fallback = new Label();
-+        Label L_done     = new Label();
-+
-+        // load test result
-+        emitPushArgument(selectAlternativeName, 0);
-+        mv.visitInsn(Opcodes.ICONST_1);
-+
-+        // if_icmpne L_fallback
-+        mv.visitJumpInsn(Opcodes.IF_ICMPNE, 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);
-+
-+        // goto L_done
-+        mv.visitJumpInsn(Opcodes.GOTO, L_done);
-+
-+        // L_fallback:
-+        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);
-+
-+        // L_done:
-+        mv.visitLabel(L_done);
-+    }
-+
-+    /**
-+     *
-+     * @param name
-+     * @param paramIndex
-+     */
-+    private void emitPushArgument(Name name, int paramIndex) {
-+        Object arg = name.arguments[paramIndex];
-+        char 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') {
-+            emitConst(arg);
-+        } else {
-+            if (Wrapper.isWrapperType(arg.getClass()) && ptype != 'L') {
-+                emitConst(arg);
-+            } else {
-+                mv.visitLdcInsn(constantPlaceholder(arg));
-+                emitImplicitConversion('L', mtype.parameterType(paramIndex));
-+            }
-+        }
-+    }
-+
-+    /**
-+     * Emits a return statement from a LF invoker. If required, the result type is cast to the correct return type.
-+     */
-+    private void emitReturn() {
-+        // return statement
-+        if (lambdaForm.result == -1) {
-+            // void
-+            mv.visitInsn(Opcodes.RETURN);
-+        } 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");
-+                    }
-+                }
-+            }
-+
-+            // generate actual return statement
-+            emitReturnInsn(invokerType.returnType());
-+        }
-+    }
-+
-+    /**
-+     * Emit a type conversion bytecode casting from "from" to "to".
-+     */
-+    private void emitPrimCast(char from, char to) {
-+        // Here's how.
-+        // -   indicates forbidden
-+        // <-> indicates implicit
-+        //      to ----> boolean  byte     short    char     int      long     float    double
-+        // from boolean    <->        -        -        -        -        -        -        -
-+        //      byte        -       <->       i2s      i2c      <->      i2l      i2f      i2d
-+        //      short       -       i2b       <->      i2c      <->      i2l      i2f      i2d
-+        //      char        -       i2b       i2s      <->      <->      i2l      i2f      i2d
-+        //      int         -       i2b       i2s      i2c      <->      i2l      i2f      i2d
-+        //      long        -     l2i,i2b   l2i,i2s  l2i,i2c    l2i      <->      l2f      l2d
-+        //      float       -     f2i,i2b   f2i,i2s  f2i,i2c    f2i      f2l      <->      f2d
-+        //      double      -     d2i,i2b   d2i,i2s  d2i,i2c    d2i      d2l      d2f      <->
-+        if (from == to) {
-+            // no cast required, should be dead code anyway
-+            return;
-+        }
-+        Wrapper wfrom = Wrapper.forBasicType(from);
-+        Wrapper wto   = Wrapper.forBasicType(to);
-+        if (wfrom.isSubwordOrInt()) {
-+            // cast from {byte,short,char,int} to anything
-+            emitI2X(to);
-+        } else {
-+            // cast from {long,float,double} to anything
-+            if (wto.isSubwordOrInt()) {
-+                // cast to {byte,short,char,int}
-+                emitX2I(from);
-+                if (wto.bitWidth() < 32) {
-+                    // targets other than int require another conversion
-+                    emitI2X(to);
-+                }
-+            } else {
-+                // 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;
-+                    break;
-+                case 'F':
-+                         if (to == 'J') { mv.visitInsn(Opcodes.F2L); }
-+                    else if (to == 'D') { mv.visitInsn(Opcodes.F2D); }
-+                    else error = true;
-+                    break;
-+                case 'D':
-+                         if (to == 'J') { mv.visitInsn(Opcodes.D2L); }
-+                    else if (to == 'F') { mv.visitInsn(Opcodes.D2F); }
-+                    else error = true;
-+                    break;
-+                default:
-+                    error = true;
-+                    break;
-+                }
-+                if (error) {
-+                    throw new IllegalStateException("unhandled prim cast: " + from + "2" + to);
-+                }
-+            }
-+        }
-+    }
-+
-+    private void emitI2X(char 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':
-+            // For compatibility with ValueConversions and explicitCastArguments:
-+            mv.visitInsn(Opcodes.ICONST_1);
-+            mv.visitInsn(Opcodes.IAND);
-+            break;
-+        default:   throw new InternalError("unknown type: " + type);
-+        }
-+    }
-+
-+    private void emitX2I(char 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);
-+        }
-+    }
-+
-+    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.
-+     *
-+     * @param sig
-+     * @return
-+     */
-+    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);
-+        return g.loadMethod(g.generateLambdaFormInterpreterEntryPointBytes());
-+    }
-+
-+    private byte[] generateLambdaFormInterpreterEntryPointBytes() {
-+        classFilePrologue();
-+
-+        // Suppress this method in backtraces displayed to the user.
-+        mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
-+
-+        // create parameter array
-+        emitIconstInsn(invokerType.parameterCount());
-+        mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
-+
-+        // fill parameter array
-+        for (int i = 0; i < invokerType.parameterCount(); i++) {
-+            Class<?> ptype = invokerType.parameterType(i);
-+            mv.visitInsn(Opcodes.DUP);
-+            emitIconstInsn(i);
-+            emitLoadInsn(Wrapper.basicTypeChar(ptype), i);
-+            // box if primitive type
-+            if (ptype.isPrimitive()) {
-+                emitBoxing(ptype);
-+            }
-+            mv.visitInsn(Opcodes.AASTORE);
-+        }
-+        // invoke
-+        emitAloadInsn(0);
-+        mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", "Ljava/lang/invoke/LambdaForm;");
-+        mv.visitInsn(Opcodes.SWAP);  // swap form and array; avoid local variable
-+        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, LF, "interpretWithArguments", "([Ljava/lang/Object;)Ljava/lang/Object;");
-+
-+        // maybe unbox
-+        Class<?> rtype = invokerType.returnType();
-+        if (rtype.isPrimitive() && rtype != void.class) {
-+            emitUnboxing(Wrapper.asWrapperType(rtype));
-+        }
-+
-+        // return statement
-+        emitReturnInsn(rtype);
-+
-+        classFileEpilogue();
-+        bogusMethod(invokerType);
-+
-+        final byte[] classFile = cw.toByteArray();
-+        maybeDump(className, classFile);
-+        return classFile;
-+    }
-+
-+    /**
-+     * Generate bytecode for a NamedFunction invoker.
-+     *
-+     * @param srcType
-+     * @param dstType
-+     * @return
-+     */
-+    static MemberName generateNamedFunctionInvoker(MethodTypeForm typeForm) {
-+        MethodType invokerType = LambdaForm.NamedFunction.INVOKER_METHOD_TYPE;
-+        String invokerName = basicTypeCharSignature("invoke_", typeForm.erasedType());
-+        InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("NFI", invokerName, invokerType);
-+        return g.loadMethod(g.generateNamedFunctionInvokerImpl(typeForm));
-+    }
-+
-+    static int nfi = 0;
-+
-+    private byte[] generateNamedFunctionInvokerImpl(MethodTypeForm typeForm) {
-+        MethodType dstType = typeForm.erasedType();
-+        classFilePrologue();
-+
-+        // Suppress this method in backtraces displayed to the user.
-+        mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
-+
-+        // Load receiver
-+        emitAloadInsn(0);
-+
-+        // Load arguments from array
-+        for (int i = 0; i < dstType.parameterCount(); i++) {
-+            emitAloadInsn(1);
-+            emitIconstInsn(i);
-+            mv.visitInsn(Opcodes.AALOAD);
-+
-+            // Maybe unbox
-+            Class<?> dptype = dstType.parameterType(i);
-+            if (dptype.isPrimitive()) {
-+                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());
-+            }
-+        }
-+
-+        // Invoke
-+        String targetDesc = dstType.basicType().toMethodDescriptorString();
-+        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", targetDesc);
-+
-+        // Box primitive types
-+        Class<?> rtype = dstType.returnType();
-+        if (rtype != void.class && rtype.isPrimitive()) {
-+            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());
-+        }
-+
-+        // 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.
-+
-+        classFileEpilogue();
-+        bogusMethod(dstType);
-+
-+        final byte[] classFile = cw.toByteArray();
-+        maybeDump(className, classFile);
-+        return classFile;
-+    }
-+
-+    /**
-+     * Emit a bogus method that just loads some string constants. This is to get the constants into the constant pool
-+     * for debugging purposes.
-+     */
-+    private void bogusMethod(Object... os) {
-+        if (DUMP_CLASS_FILES) {
-+            mv = cw.visitMethod(Opcodes.ACC_STATIC, "dummy", "()V", null, null);
-+            for (Object o : os) {
-+                mv.visitLdcInsn(o.toString());
-+                mv.visitInsn(Opcodes.POP);
-+            }
-+            mv.visitInsn(Opcodes.RETURN);
-+            mv.visitMaxs(0, 0);
-+            mv.visitEnd();
-+        }
-+    }
-+}
-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
-@@ -25,8 +25,11 @@
- 
- package java.lang.invoke;
- 
-+import java.util.Arrays;
- import sun.invoke.empty.Empty;
-+import static java.lang.invoke.MethodHandleNatives.Constants.*;
- import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
-+import static java.lang.invoke.LambdaForm.*;
- 
- /**
-  * Construction and caching of often-used invokers.
-@@ -36,11 +39,15 @@
-     // exact type (sans leading taget MH) for the outgoing call
-     private final MethodType targetType;
- 
-+    // FIXME: Get rid of the invokers that are not useful.
-+
-     // exact invoker for the outgoing call
-     private /*lazy*/ MethodHandle exactInvoker;
- 
-     // erased (partially untyped but with primitives) invoker for the outgoing call
-+    // FIXME: get rid of
-     private /*lazy*/ MethodHandle erasedInvoker;
-+    // FIXME: get rid of
-     /*lazy*/ MethodHandle erasedInvokerWithDrops;  // for InvokeGeneric
- 
-     // general invoker for the outgoing call
-@@ -63,14 +70,13 @@
-         this.spreadInvokers = new MethodHandle[targetType.parameterCount()+1];
-     }
- 
--    /*non-public*/ static MethodType invokerType(MethodType targetType) {
--        return targetType.insertParameterTypes(0, MethodHandle.class);
--    }
--
-     /*non-public*/ MethodHandle exactInvoker() {
-         MethodHandle invoker = exactInvoker;
-         if (invoker != null)  return invoker;
--        invoker = lookupInvoker("invokeExact");
-+        MethodType mtype = targetType;
-+        LambdaForm lform = invokeForm(mtype, MethodTypeForm.LF_EX_INVOKER);
-+        invoker = BoundMethodHandle.bindSingle(mtype.invokerType(), lform, mtype);
-+        assert(checkInvoker(invoker));
-         exactInvoker = invoker;
-         return invoker;
-     }
-@@ -78,29 +84,50 @@
-     /*non-public*/ MethodHandle generalInvoker() {
-         MethodHandle invoker = generalInvoker;
-         if (invoker != null)  return invoker;
--        invoker = lookupInvoker("invoke");
-+        MethodType mtype = targetType;
-+        prepareForGenericCall(mtype);
-+        LambdaForm lform = invokeForm(mtype, MethodTypeForm.LF_GEN_INVOKER);
-+        invoker = BoundMethodHandle.bindSingle(mtype.invokerType(), lform, mtype);
-+        assert(checkInvoker(invoker));
-         generalInvoker = invoker;
-         return invoker;
-     }
- 
--    private MethodHandle lookupInvoker(String name) {
--        MethodHandle invoker;
--        try {
--            invoker = IMPL_LOOKUP.findVirtual(MethodHandle.class, name, targetType);
--        } catch (ReflectiveOperationException ex) {
--            throw new InternalError("JVM cannot find invoker for "+targetType, ex);
--        }
--        assert(invokerType(targetType) == invoker.type());
--        assert(!invoker.isVarargsCollector());
-+    /*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.
-+        assert(checkInvoker(invoker));
-         return invoker;
-     }
- 
-+    static MemberName invokeBasicMethod(MethodType type) {
-+        String name = "invokeBasic";
-+        try {
-+            //Lookup.findVirtual(MethodHandle.class, name, type);
-+            return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, name, type);
-+
-+        } catch (ReflectiveOperationException ex) {
-+            throw new InternalError("JVM cannot find invoker for "+type, ex);
-+        }
-+    }
-+
-+    private boolean checkInvoker(MethodHandle invoker) {
-+        assert(targetType.invokerType().equals(invoker.type()))
-+                : java.util.Arrays.asList(targetType, targetType.invokerType(), invoker);
-+        assert(invoker.internalMemberName() == null ||
-+               invoker.internalMemberName().getMethodType().equals(targetType));
-+        assert(!invoker.isVarargsCollector());
-+        return true;
-+    }
-+
-+    // FIXME: get rid of
-     /*non-public*/ MethodHandle erasedInvoker() {
-         MethodHandle xinvoker = exactInvoker();
-         MethodHandle invoker = erasedInvoker;
-         if (invoker != null)  return invoker;
-         MethodType erasedType = targetType.erase();
--        invoker = xinvoker.asType(invokerType(erasedType));
-+        invoker = xinvoker.asType(erasedType.invokerType());
-         erasedInvoker = invoker;
-         return invoker;
-     }
-@@ -118,7 +145,7 @@
-     /*non-public*/ MethodHandle varargsInvoker() {
-         MethodHandle vaInvoker = varargsInvoker;
-         if (vaInvoker != null)  return vaInvoker;
--        vaInvoker = spreadInvoker(0).asType(invokerType(MethodType.genericMethodType(0, true)));
-+        vaInvoker = spreadInvoker(0).asType(MethodType.genericMethodType(0, true).invokerType());
-         varargsInvoker = vaInvoker;
-         return vaInvoker;
-     }
-@@ -137,16 +164,18 @@
-             uninitializedCallSite = invoker;
-             return invoker;
-         }
--        if (THROW_UCS == null) {
-+        invoker = THROW_UCS;
-+        if (invoker == null) {
-             try {
--                THROW_UCS = IMPL_LOOKUP
-+                THROW_UCS = invoker = IMPL_LOOKUP
-                     .findStatic(CallSite.class, "uninitializedCallSite",
-                                 MethodType.methodType(Empty.class));
-             } catch (ReflectiveOperationException ex) {
-                 throw new RuntimeException(ex);
-             }
-         }
--        invoker = AdapterMethodHandle.makeRetypeRaw(targetType, THROW_UCS);
-+        invoker = MethodHandles.explicitCastArguments(invoker, MethodType.methodType(targetType.returnType()));
-+        invoker = invoker.dropArguments(targetType, 0, targetType.parameterCount());
-         assert(invoker.type().equals(targetType));
-         uninitializedCallSite = invoker;
-         return invoker;
-@@ -155,4 +184,208 @@
-     public String toString() {
-         return "Invokers"+targetType;
-     }
-+
-+    private static MethodType fixMethodType(Class<?> callerClass, Object type) {
-+        if (type instanceof MethodType)
-+            return (MethodType) type;
-+        else
-+            return MethodType.fromMethodDescriptorString((String)type, callerClass.getClassLoader());
-+    }
-+
-+    static MemberName exactInvokerMethod(Class<?> callerClass, Object type, Object[] appendixResult) {
-+        MethodType mtype = fixMethodType(callerClass, type);
-+        LambdaForm lform = invokeForm(mtype, MethodTypeForm.LF_EX_LINKER);
-+        appendixResult[0] = mtype;
-+        return lform.vmentry;
-+    }
-+
-+    static MemberName genericInvokerMethod(Class<?> callerClass, Object type, Object[] appendixResult) {
-+        MethodType mtype = fixMethodType(callerClass, type);
-+        LambdaForm lform = invokeForm(mtype, MethodTypeForm.LF_GEN_LINKER);
-+        prepareForGenericCall(mtype);
-+        appendixResult[0] = mtype;
-+        return lform.vmentry;
-+    }
-+
-+    private static LambdaForm invokeForm(MethodType mtype, int which) {
-+        mtype = mtype.basicType();  // normalize Z to I, String to Object, etc.
-+        boolean isLinker, isGeneric;
-+        String debugName;
-+        switch (which) {
-+        case MethodTypeForm.LF_EX_LINKER:   isLinker = true;  isGeneric = false; debugName = "invokeExact_MT"; break;
-+        case MethodTypeForm.LF_EX_INVOKER:  isLinker = false; isGeneric = false; debugName = "exactInvoker"; break;
-+        case MethodTypeForm.LF_GEN_LINKER:  isLinker = true;  isGeneric = true;  debugName = "invoke_MT"; break;
-+        case MethodTypeForm.LF_GEN_INVOKER: isLinker = false; isGeneric = true;  debugName = "invoker"; break;
-+        default: throw new InternalError();
-+        }
-+        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
-+        final int THIS_MH      = 0;
-+        final int CALL_MH      = THIS_MH + (isLinker ? 0 : 1);
-+        final int ARG_BASE     = CALL_MH + 1;
-+        final int OUTARG_LIMIT = ARG_BASE + mtype.parameterCount();
-+        final int INARG_LIMIT  = OUTARG_LIMIT + (isLinker ? 1 : 0);
-+        int nameCursor = OUTARG_LIMIT;
-+        final int MTYPE_ARG    = nameCursor++;  // might be last in-argument
-+        final int CHECK_TYPE   = nameCursor++;
-+        final int LINKER_CALL  = nameCursor++;
-+        MethodType invokerFormType = mtype.invokerType();
-+        if (isLinker) {
-+            invokerFormType = invokerFormType.appendParameterTypes(MemberName.class);
-+        } else {
-+            invokerFormType = invokerFormType.invokerType();
-+        }
-+        Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType);
-+        assert(names.length == nameCursor);
-+        if (MTYPE_ARG >= INARG_LIMIT) {
-+            assert(names[MTYPE_ARG] == null);
-+            names[MTYPE_ARG] = BoundMethodHandle.getSpeciesData("L").getterName(names[THIS_MH], 0);
-+            // 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;
-+        if (!isGeneric) {
-+            names[CHECK_TYPE] = new Name(NF_checkExactType, names[CALL_MH], names[MTYPE_ARG]);
-+            // 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 {
-+            names[CHECK_TYPE] = new Name(NF_checkGenericType, names[CALL_MH], names[MTYPE_ARG]);
-+            // 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;
-+            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] = names[MTYPE_ARG];
-+            outCallType = mtype.insertParameterTypes(0, MethodType.class, MethodHandle.class);
-+        }
-+        names[LINKER_CALL] = new Name(invokeBasicMethod(outCallType), outArgs);
-+        lform = new LambdaForm(debugName, INARG_LIMIT, names);
-+        if (isLinker)
-+            lform.compileToBytecode();  // JVM needs a real methodOop
-+        lform = mtype.form().setCachedLambdaForm(which, lform);
-+        return lform;
-+    }
-+
-+    /*non-public*/ static
-+    WrongMethodTypeException newWrongMethodTypeException(MethodType actual, MethodType expected) {
-+        // FIXME: merge with JVM logic for throwing WMTE
-+        return new WrongMethodTypeException("expected "+expected+" but found "+actual);
-+    }
-+
-+    /** Static definition of MethodHandle.invokeExact checking code. */
-+    /*non-public*/ static
-+    @ForceInline
-+    void checkExactType(Object mhObj, Object expectedObj) {
-+        MethodHandle mh = (MethodHandle) mhObj;
-+        MethodType expected = (MethodType) expectedObj;
-+        MethodType actual = mh.type();
-+        if (actual != expected)
-+            throw newWrongMethodTypeException(expected, actual);
-+    }
-+
-+    /** Static definition of MethodHandle.invokeGeneric checking code. */
-+    /*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 new InternalError("Exception while resolving inexact invoke", ex);
-+        }
-+    }
-+
-+    static MemberName linkToCallSiteMethod(MethodType mtype) {
-+        LambdaForm lform = callSiteForm(mtype);
-+        return lform.vmentry;
-+    }
-+
-+    private static LambdaForm callSiteForm(MethodType mtype) {
-+        mtype = mtype.basicType();  // normalize Z to I, String to Object, etc.
-+        LambdaForm lform = mtype.form().cachedLambdaForm(MethodTypeForm.LF_CS_LINKER);
-+        if (lform != null)  return lform;
-+        // exactInvokerForm (Object,Object)Object
-+        //   link with java.lang.invoke.MethodHandle.invokeBasic(MethodHandle,Object,Object)Object/invokeSpecial
-+        final int ARG_BASE     = 0;
-+        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 LINKER_CALL  = nameCursor++;
-+        MethodType invokerFormType = mtype.appendParameterTypes(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]);
-+        // (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);
-+        lform.compileToBytecode();  // JVM needs a real methodOop
-+        lform = mtype.form().setCachedLambdaForm(MethodTypeForm.LF_CS_LINKER, lform);
-+        return lform;
-+    }
-+
-+    /** Static definition of MethodHandle.invokeGeneric checking code. */
-+    /*non-public*/ static
-+    @ForceInline
-+    Object getCallSiteTarget(Object site) {
-+        return ((CallSite)site).getTarget();
-+    }
-+
-+    // Local constant functions:
-+    private static final NamedFunction NF_checkExactType;
-+    private static final NamedFunction NF_checkGenericType;
-+    private static final NamedFunction 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_getCallSiteTarget = new NamedFunction(Invokers.class
-+                    .getDeclaredMethod("getCallSiteTarget", Object.class));
-+            NF_checkExactType.resolve();
-+            NF_checkGenericType.resolve();
-+            NF_getCallSiteTarget.resolve();
-+            // bound
-+        } catch (ReflectiveOperationException ex) {
-+            throw new InternalError(ex);
-+        }
-+    }
-+
- }
-diff --git a/src/share/classes/java/lang/invoke/LambdaForm.java b/src/share/classes/java/lang/invoke/LambdaForm.java
-new file mode 100644
---- /dev/null
-+++ b/src/share/classes/java/lang/invoke/LambdaForm.java
-@@ -0,0 +1,1620 @@
-+/*
-+ * Copyright (c) 2011, 2012, 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.lang.annotation.*;
-+import java.lang.reflect.Method;
-+import java.util.Map;
-+import java.util.List;
-+import java.util.Arrays;
-+import java.util.ArrayList;
-+import java.util.HashMap;
-+import java.util.concurrent.ConcurrentHashMap;
-+import sun.invoke.util.Wrapper;
-+import static java.lang.invoke.MethodHandleStatics.*;
-+import static java.lang.invoke.MethodHandleNatives.Constants.*;
-+import java.lang.reflect.Field;
-+import java.util.Objects;
-+
-+/**
-+ * The symbolic, non-executable form of a method handle's invocation semantics.
-+ * It consists of a series of names.
-+ * The first N (N=arity) names are parameters,
-+ * while any remaining names are temporary values.
-+ * Each temporary specifies the application of a function to some arguments.
-+ * The functions are method handles, while the arguments are mixes of
-+ * constant values and local names.
-+ * The result of the lambda is defined as one of the names, often the last one.
-+ * <p>
-+ * Here is an approximate grammar:
-+ * <pre>
-+ * LambdaForm = "(" ArgName* ")=>{" TempName* Result "}"
-+ * ArgName = "a" N ":" T
-+ * TempName = "t" N ":" T "=" Function "(" Argument* ");"
-+ * Function = ConstantValue
-+ * Argument = NameRef | ConstantValue
-+ * Result = NameRef | "void"
-+ * NameRef = "a" N | "t" N
-+ * N = (any whole number)
-+ * T = "L" | "I" | "J" | "F" | "D" | "V"
-+ * </pre>
-+ * Names are numbered consecutively from left to right starting at zero.
-+ * (The letters are merely a taste of syntax sugar.)
-+ * Thus, the first temporary (if any) is always numbered N (where N=arity).
-+ * Every occurrence of a name reference in an argument list must refer to
-+ * a name previously defined within the same lambda.
-+ * A lambda has a void result if and only if its result index is -1.
-+ * If a temporary has the type "V", it cannot be the subject of a NameRef,
-+ * even though possesses a number.
-+ * Note that all reference types are erased to "L", which stands for {@code Object).
-+ * All subword types (boolean, byte, short, char) are erased to "I" which is {@code int}.
-+ * The other types stand for the usual primitive types.
-+ * <p>
-+ * Function invocation closely follows the static rules of the Java verifier.
-+ * Arguments and return values must exactly match when their "Name" types are
-+ * considered.
-+ * Conversions are allowed only if they do not change the erased type.
-+ * <ul>
-+ * <li>L = Object: casts are used freely to convert into and out of reference types
-+ * <li>I = int: subword types are forcibly narrowed when passed as arguments (see {@code explicitCastArguments})
-+ * <li>J = long: no implicit conversions
-+ * <li>F = float: no implicit conversions
-+ * <li>D = double: no implicit conversions
-+ * <li>V = void: a function result may be void if and only if its Name is of type "V"
-+ * </ul>
-+ * Although implicit conversions are not allowed, explicit ones can easily be
-+ * encoded by using temporary expressions which call type-transformed identity functions.
-+ * <p>
-+ * Examples:
-+ * <pre>
-+ * (a0:J)=>{ a0 }
-+ *     == identity(long)
-+ * (a0:I)=>{ t1:V = System.out#println(a0); void }
-+ *     == System.out#println(int)
-+ * (a0:L)=>{ t1:V = System.out#println(a0); a0 }
-+ *     == identity, with printing side-effect
-+ * (a0:L, a1:L)=>{ t2:L = BoundMethodHandle#argument(a0);
-+ *                 t3:L = BoundMethodHandle#target(a0);
-+ *                 t4:L = MethodHandle#invoke(t3, t2, a1); t4 }
-+ *     == general invoker for unary insertArgument combination
-+ * (a0:L, a1:L)=>{ t2:L = FilterMethodHandle#filter(a0);
-+ *                 t3:L = MethodHandle#invoke(t2, a1);
-+ *                 t4:L = FilterMethodHandle#target(a0);
-+ *                 t5:L = MethodHandle#invoke(t4, t3); t5 }
-+ *     == general invoker for unary filterArgument combination
-+ * (a0:L, a1:L)=>{ ...(same as previous example)...
-+ *                 t5:L = MethodHandle#invoke(t4, t3, a1); t5 }
-+ *     == general invoker for unary/unary foldArgument combination
-+ * (a0:L, a1:I)=>{ t2:I = identity(long).asType((int)->long)(a1); t2 }
-+ *     == invoker for identity method handle which performs i2l
-+ * (a0:L, a1:L)=>{ t2:L = BoundMethodHandle#argument(a0);
-+ *                 t3:L = Class#cast(t2,a1); t3 }
-+ *     == invoker for identity method handle which performs cast
-+ * </pre>
-+ * <p>
-+ * @author John Rose, JSR 292 EG
-+ */
-+class LambdaForm {
-+    final int arity;
-+    final int result;
-+    final Name[] names;
-+    final String debugName;
-+    MemberName vmentry;   // low-level behavior, or null if not yet prepared
-+    private boolean isCompiled;
-+
-+    // Caches for common structural transforms:
-+    LambdaForm[] bindCache;
-+
-+    public static final int VOID_RESULT = -1, LAST_RESULT = -2;
-+
-+    LambdaForm(String debugName,
-+               int arity, Name[] names, int result) {
-+        assert(namesOK(arity, names));
-+        this.arity = arity;
-+        this.result = fixResult(result, names);
-+        this.names = names.clone();
-+        this.debugName = debugName;
-+        normalize();
-+    }
-+
-+    LambdaForm(String debugName,
-+               int arity, Name[] names) {
-+        this(debugName,
-+             arity, names, LAST_RESULT);
-+    }
-+
-+    LambdaForm(String debugName,
-+               Name[] formals, Name[] temps, Name result) {
-+        this(debugName,
-+             formals.length, buildNames(formals, temps, result), LAST_RESULT);
-+    }
-+
-+    private static Name[] buildNames(Name[] formals, Name[] temps, Name result) {
-+        int arity = formals.length;
-+        int length = arity + temps.length + (result == null ? 0 : 1);
-+        Name[] names = Arrays.copyOf(formals, length);
-+        System.arraycopy(temps, 0, names, arity, temps.length);
-+        if (result != null)
-+            names[length - 1] = result;
-+        return names;
-+    }
-+
-+    private LambdaForm(String sig) {
-+        // Make a blank lambda form, which returns a constant zero or null.
-+        // It is used as a template for managing the invocation of similar forms that are non-empty.
-+        // Called only from getPreparedForm.
-+        assert(isValidSignature(sig));
-+        this.arity = signatureArity(sig);
-+        this.result = (signatureReturn(sig) == 'V' ? -1 : arity);
-+        this.names = buildEmptyNames(arity, sig);
-+        this.debugName = "LF.zero";
-+        assert(nameRefsAreLegal());
-+        assert(isEmpty());
-+        assert(sig.equals(basicTypeSignature()));
-+    }
-+
-+    private static Name[] buildEmptyNames(int arity, String basicTypeSignature) {
-+        assert(isValidSignature(basicTypeSignature));
-+        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);
-+        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));
-+        }
-+        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;
-+        }
-+        return result;
-+    }
-+
-+    private static boolean namesOK(int arity, Name[] names) {
-+        for (int i = 0; i < names.length; i++) {
-+            Name n = names[i];
-+            assert(n != null) : "n is null";
-+            if (i < arity)
-+                assert( n.isParam()) : n + " is not param at " + i;
-+            else
-+                assert(!n.isParam()) : n + " is param at " + i;
-+        }
-+        return true;
-+    }
-+
-+    /** Renumber and/or replace params so that they are interned and canonically numbered. */
-+    private void normalize() {
-+        Name[] oldNames = null;
-+        int changesStart = 0;
-+        for (int i = 0; i < names.length; i++) {
-+            Name n = names[i];
-+            if (!n.initIndex(i)) {
-+                if (oldNames == null) {
-+                    oldNames = names.clone();
-+                    changesStart = i;
-+                }
-+                names[i] = n.cloneWithIndex(i);
-+            }
-+        }
-+        if (oldNames != null) {
-+            int startFixing = arity;
-+            if (startFixing <= changesStart)
-+                startFixing = changesStart+1;
-+            for (int i = startFixing; i < names.length; i++) {
-+                Name fixed = names[i].replaceNames(oldNames, names, changesStart, i);
-+                names[i] = fixed.newIndex(i);
-+            }
-+        }
-+        assert(nameRefsAreLegal());
-+        int maxInterned = Math.min(arity, INTERNED_ARGUMENT_LIMIT);
-+        boolean needIntern = false;
-+        for (int i = 0; i < maxInterned; i++) {
-+            Name n = names[i], n2 = internArgument(n);
-+            if (n != n2) {
-+                names[i] = n2;
-+                needIntern = true;
-+            }
-+        }
-+        if (needIntern) {
-+            for (int i = arity; i < names.length; i++) {
-+                names[i].internArguments();
-+            }
-+            assert(nameRefsAreLegal());
-+        }
-+    }
-+
-+    /**
-+     * Check that all embedded Name references are localizable to this lambda,
-+     * and are properly ordered after their corresponding definitions.
-+     * <p>
-+     * Note that a Name can be local to multiple lambdas, as long as
-+     * it possesses the same index in each use site.
-+     * This allows Name references to be freely reused to construct
-+     * fresh lambdas, without confusion.
-+     */
-+    private 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?
-+        for (int i = 0; i < arity; i++) {
-+            Name n = names[i];
-+            assert(n.index() == i) : Arrays.asList(n.index(), i);
-+            assert(n.isParam());
-+        }
-+        // Also, do all local name references
-+        for (int i = arity; i < names.length; i++) {
-+            Name n = names[i];
-+            assert(n.index() == i);
-+            for (Object arg : n.arguments) {
-+                if (arg instanceof Name) {
-+                    Name n2 = (Name) arg;
-+                    int i2 = n2.index;
-+                    assert(0 <= i2 && i2 < names.length) : n.debugString() + ": 0 <= i2 && i2 < names.length: 0 <= " + i2 + " < " + names.length;
-+                    assert(names[i2] == n2) : Arrays.asList("-1-", i, "-2-", n.debugString(), "-3-", i2, "-4-", n2.debugString(), "-5-", names[i2].debugString(), "-6-", this);
-+                    assert(i2 < i);  // ref must come after def!
-+                }
-+            }
-+        }
-+        return true;
-+    }
-+
-+    /** Invoke this form on the given arguments. */
-+    // final Object invoke(Object... args) throws Throwable {
-+    //     // NYI: fit this into the fast path?
-+    //     return interpretWithArguments(args);
-+    // }
-+
-+    /** Report the return type. */
-+    char returnType() {
-+        if (result < 0)  return 'V';
-+        Name n = names[result];
-+        return n.type;
-+    }
-+
-+    /** Report the N-th argument type. */
-+    char parameterType(int n) {
-+        assert(n < arity);
-+        return names[n].type;
-+    }
-+
-+    /** Report the arity. */
-+    int arity() {
-+        return arity;
-+    }
-+
-+    /** Return the method type corresponding to my basic type signature. */
-+    MethodType methodType() {
-+        return signatureType(basicTypeSignature());
-+    }
-+    /** Return ABC_Z, where the ABC are parameter type characters, and Z is the return type character. */
-+    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();
-+    }
-+    static int signatureArity(String sig) {
-+        assert(isValidSignature(sig));
-+        return sig.indexOf('_');
-+    }
-+    static char signatureReturn(String sig) {
-+        return sig.charAt(signatureArity(sig)+1);
-+    }
-+    static boolean isValidSignature(String sig) {
-+        int arity = sig.indexOf('_');
-+        if (arity < 0)  return false;  // must be of the form *_*
-+        int siglen = sig.length();
-+        if (siglen != arity + 2)  return false;  // *_X
-+        for (int i = 0; i < siglen; i++) {
-+            if (i == arity)  continue;  // skip '_'
-+            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]
-+        }
-+        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));
-+        return MethodType.methodType(rtype, ptypes);
-+    }
-+
-+    /*
-+     * Code generation issues:
-+     *
-+     * Compiled LFs should be reusable in general.
-+     * The biggest issue is how to decide when to pull a name into
-+     * the bytecode, versus loading a reified form from the MH data.
-+     *
-+     * For example, an asType wrapper may require execution of a cast
-+     * after a call to a MH.  The target type of the cast can be placed
-+     * as a constant in the LF itself.  This will force the cast type
-+     * to be compiled into the bytecodes and native code for the MH.
-+     * Or, the target type of the cast can be erased in the LF, and
-+     * loaded from the MH data.  (Later on, if the MH as a whole is
-+     * inlined, the data will flow into the inlined instance of the LF,
-+     * as a constant, and the end result will be an optimal cast.)
-+     *
-+     * This erasure of cast types can be done with any use of
-+     * reference types.  It can also be done with whole method
-+     * handles.  Erasing a method handle might leave behind
-+     * LF code that executes correctly for any MH of a given
-+     * type, and load the required MH from the enclosing MH's data.
-+     * Or, the erasure might even erase the expected MT.
-+     *
-+     * Also, for direct MHs, the MemberName of the target
-+     * could be erased, and loaded from the containing direct MH.
-+     * As a simple case, a LF for all int-valued non-static
-+     * field getters would perform a cast on its input argument
-+     * (to non-constant base type derived from the MemberName)
-+     * and load an integer value from the input object
-+     * (at a non-constant offset also derived from the MemberName).
-+     * Such MN-erased LFs would be inlinable back to optimized
-+     * code, whenever a constant enclosing DMH is available
-+     * to supply a constant MN from its data.
-+     *
-+     * The main problem here is to keep LFs reasonably generic,
-+     * while ensuring that hot spots will inline good instances.
-+     * "Reasonably generic" means that we don't end up with
-+     * repeated versions of bytecode or machine code that do
-+     * not differ in their optimized form.  Repeated versions
-+     * of machine would have the undesirable overheads of
-+     * (a) redundant compilation work and (b) extra I$ pressure.
-+     * To control repeated versions, we need to be ready to
-+     * erase details from LFs and move them into MH data,
-+     * whevener those details are not relevant to significant
-+     * optimization.  "Significant" means optimization of
-+     * code that is actually hot.
-+     *
-+     * Achieving this may require dynamic splitting of MHs, by replacing
-+     * a generic LF with a more specialized one, on the same MH,
-+     * if (a) the MH is frequently executed and (b) the MH cannot
-+     * be inlined into a containing caller, such as an invokedynamic.
-+     *
-+     * Compiled LFs that are no longer used should be GC-able.
-+     * If they contain non-BCP references, they should be properly
-+     * interlinked with the class loader(s) that their embedded types
-+     * depend on.  This probably means that reusable compiled LFs
-+     * will be tabulated (indexed) on relevant class loaders,
-+     * or else that the tables that cache them will have weak links.
-+     */
-+
-+    /**
-+     * Make this LF directly executable, as part of a MethodHandle.
-+     * Invariant:  Every MH which is invoked must prepare its LF
-+     * before invocation.
-+     * (In principle, the JVM could do this very lazily,
-+     * as a sort of pre-invocation linkage step.)
-+     */
-+    public void prepare() {
-+        if (COMPILE_THRESHOLD == 0) {
-+            compileToBytecode();
-+        }
-+        if (this.vmentry != null) {
-+            // already prepared (e.g., a primitive DMH invoker form)
-+            return;
-+        }
-+        LambdaForm prep = getPreparedForm(basicTypeSignature());
-+        this.vmentry = prep.vmentry;
-+        // TO DO: Maybe add invokeGeneric, invokeWithArguments
-+    }
-+
-+    /** Generate optimizable bytecode for this form. */
-+    MemberName compileToBytecode() {
-+        MethodType invokerType = methodType();
-+        assert(vmentry == null || vmentry.getMethodType().basicType().equals(invokerType));
-+        if (vmentry != null && isCompiled) {
-+            return vmentry;  // already compiled somehow
-+        }
-+        try {
-+            vmentry = InvokerBytecodeGenerator.generateCustomizedCode(this, invokerType);
-+            if (TRACE_INTERPRETER)
-+                traceInterpreter("compileToBytecode", this);
-+            isCompiled = true;
-+            return vmentry;
-+        } catch (Error | Exception ex) {
-+            throw new InternalError(this.toString(), ex);
-+        }
-+    }
-+
-+    private static final ConcurrentHashMap<String,LambdaForm> PREPARED_FORMS;
-+    static {
-+        int   capacity   = 512;    // expect many distinct signatures over time
-+        float loadFactor = 0.75f;  // normal default
-+        int   writers    = 1;
-+        PREPARED_FORMS = new ConcurrentHashMap<>(capacity, loadFactor, writers);
-+    }
-+
-+    private static Map<String,LambdaForm> computeInitialPreparedForms() {
-+        // Find all predefined invokers and associate them with canonical empty lambda forms.
-+        HashMap<String,LambdaForm> forms = new HashMap<>();
-+        for (MemberName m : MemberName.getFactory().getMethods(LambdaForm.class, false, null, null, null)) {
-+            if (!m.isStatic() || !m.isPackage())  continue;
-+            MethodType mt = m.getMethodType();
-+            if (mt.parameterCount() > 0 &&
-+                mt.parameterType(0) == MethodHandle.class &&
-+                m.getName().startsWith("interpret_")) {
-+                String sig = basicTypeSignature(mt);
-+                assert(m.getName().equals("interpret" + sig.substring(sig.indexOf('_'))));
-+                LambdaForm form = new LambdaForm(sig);
-+                form.vmentry = m;
-+                mt.form().setCachedLambdaForm(MethodTypeForm.LF_COUNTER, form);
-+                // FIXME: get rid of PREPARED_FORMS; use MethodTypeForm cache only
-+                forms.put(sig, form);
-+            }
-+        }
-+        //System.out.println("computeInitialPreparedForms => "+forms);
-+        return forms;
-+    }
-+
-+    // Set this false to disable use of the interpret_L methods defined in this file.
-+    private static final boolean USE_PREDEFINED_INTERPRET_METHODS = true;
-+
-+    // The following are predefined exact invokers.  The system must build
-+    // a separate invoker for each distinct signature.
-+    static Object interpret_L(MethodHandle mh) throws Throwable {
-+        Object[] av = {mh};
-+        String sig = null;
-+        assert(argumentTypesMatch(sig = "L_L", av));
-+        Object res = mh.form.interpretWithArguments(av);
-+        assert(returnTypesMatch(sig, av, res));
-+        return res;
-+    }
-+    static Object interpret_L(MethodHandle mh, Object x1) throws Throwable {
-+        Object[] av = {mh, x1};
-+        String sig = null;
-+        assert(argumentTypesMatch(sig = "LL_L", av));
-+        Object res = mh.form.interpretWithArguments(av);
-+        assert(returnTypesMatch(sig, av, res));
-+        return res;
-+    }
-+    static Object interpret_L(MethodHandle mh, Object x1, Object x2) throws Throwable {
-+        Object[] av = {mh, x1, x2};
-+        String sig = null;
-+        assert(argumentTypesMatch(sig = "LLL_L", av));
-+        Object res = mh.form.interpretWithArguments(av);
-+        assert(returnTypesMatch(sig, av, res));
-+        return res;
-+    }
-+    private static LambdaForm getPreparedForm(String sig) {
-+        MethodType mtype = signatureType(sig);
-+        //LambdaForm prep = PREPARED_FORMS.get(sig);
-+        LambdaForm prep =  mtype.form().cachedLambdaForm(MethodTypeForm.LF_INTERPRET);
-+        if (prep != null)  return prep;
-+        assert(isValidSignature(sig));
-+        prep = new LambdaForm(sig);
-+        prep.vmentry = InvokerBytecodeGenerator.generateLambdaFormInterpreterEntryPoint(sig);
-+        //LambdaForm prep2 = PREPARED_FORMS.putIfAbsent(sig.intern(), prep);
-+        return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_INTERPRET, prep);
-+    }
-+
-+    // The next few routines are called only from assert expressions
-+    // They verify that the built-in invokers process the correct raw data types.
-+    private static boolean argumentTypesMatch(String sig, Object[] av) {
-+        int arity = signatureArity(sig);
-+        assert(av.length == arity) : "av.length == arity: av.length=" + av.length + ", arity=" + arity;
-+        assert(av[0] instanceof MethodHandle) : "av[0] not instace of MethodHandle: " + av[0];
-+        MethodHandle mh = (MethodHandle) av[0];
-+        MethodType mt = mh.type();
-+        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]));
-+        }
-+        return true;
-+    }
-+    private static boolean valueMatches(char 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
-+        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
-+        default:  assert(false);
-+        }
-+        return true;
-+    }
-+    private static boolean returnTypesMatch(String sig, Object[] av, Object res) {
-+        MethodHandle mh = (MethodHandle) av[0];
-+        return valueMatches(signatureReturn(sig), mh.type().returnType(), res);
-+    }
-+    private static boolean checkInt(Class<?> type, Object x) {
-+        assert(x instanceof Integer);
-+        if (type == int.class)  return true;
-+        Wrapper w = Wrapper.forBasicType(type);
-+        assert(w.isSubwordOrInt());
-+        Object x1 = Wrapper.INT.wrap(w.wrap(x));
-+        return x.equals(x1);
-+    }
-+    private static boolean checkRef(Class<?> type, Object x) {
-+        assert(!type.isPrimitive());
-+        if (x == null)  return true;
-+        if (type.isInterface())  return true;
-+        return type.isInstance(x);
-+    }
-+
-+    /** If the invocation count hits the threshold we spin bytecodes and call that subsequently. */
-+    private static final int COMPILE_THRESHOLD;
-+    static {
-+        if (MethodHandleStatics.COMPILE_THRESHOLD != null)
-+            COMPILE_THRESHOLD = MethodHandleStatics.COMPILE_THRESHOLD;
-+        else
-+            COMPILE_THRESHOLD = 30;  // default value
-+    }
-+    private int invocationCounter = 0;
-+
-+    @Hidden
-+    /** Interpretively invoke this form on the given arguments. */
-+    Object interpretWithArguments(Object... argumentValues) throws Throwable {
-+        if (TRACE_INTERPRETER)
-+            return interpretWithArgumentsTracing(argumentValues);
-+        if (COMPILE_THRESHOLD != 0 &&
-+            invocationCounter < COMPILE_THRESHOLD) {
-+            invocationCounter++;  // benign race
-+            if (invocationCounter >= COMPILE_THRESHOLD) {
-+                // Replace vmentry with a bytecode version of this LF.
-+                compileToBytecode();
-+            }
-+        }
-+        assert(arityCheck(argumentValues));
-+        Object[] values = Arrays.copyOf(argumentValues, names.length);
-+        for (int i = argumentValues.length; i < values.length; i++) {
-+            values[i] = interpretName(names[i], values);
-+        }
-+        return (result < 0) ? null : values[result];
-+    }
-+
-+    @Hidden
-+    /** Evaluate a single Name within this form, applying its function to its arguments. */
-+    Object interpretName(Name name, Object[] values) throws Throwable {
-+        if (TRACE_INTERPRETER)
-+            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++) {
-+            Object a = arguments[i];
-+            if (a instanceof Name) {
-+                int i2 = ((Name)a).index();
-+                assert(names[i2] == a);
-+                a = values[i2];
-+                arguments[i] = a;
-+            }
-+        }
-+        return name.function.invokeWithArguments(arguments);
-+    }
-+
-+    Object interpretWithArgumentsTracing(Object... argumentValues) throws Throwable {
-+        traceInterpreter("[ interpretWithArguments", this, argumentValues);
-+        if (invocationCounter < COMPILE_THRESHOLD) {
-+            int ctr = invocationCounter++;  // benign race
-+            traceInterpreter("| invocationCounter", ctr);
-+            if (invocationCounter >= COMPILE_THRESHOLD) {
-+                compileToBytecode();
-+            }
-+        }
-+        Object rval;
-+        try {
-+            assert(arityCheck(argumentValues));
-+            Object[] values = Arrays.copyOf(argumentValues, names.length);
-+            for (int i = argumentValues.length; i < values.length; i++) {
-+                values[i] = interpretName(names[i], values);
-+            }
-+            rval = (result < 0) ? null : values[result];
-+        } catch (Throwable ex) {
-+            traceInterpreter("] throw =>", ex);
-+            throw ex;
-+        }
-+        traceInterpreter("] return =>", rval);
-+        return rval;
-+    }
-+
-+    //** This transform is applied (statically) to every name.function. */
-+    /*
-+    private static MethodHandle eraseSubwordTypes(MethodHandle mh) {
-+        MethodType mt = mh.type();
-+        if (mt.hasPrimitives()) {
-+            mt = mt.changeReturnType(eraseSubwordType(mt.returnType()));
-+            for (int i = 0; i < mt.parameterCount(); i++) {
-+                mt = mt.changeParameterType(i, eraseSubwordType(mt.parameterType(i)));
-+            }
-+            mh = MethodHandles.explicitCastArguments(mh, mt);
-+        }
-+        return mh;
-+    }
-+    private static Class<?> eraseSubwordType(Class<?> type) {
-+        if (!type.isPrimitive())  return type;
-+        if (type == int.class)  return type;
-+        Wrapper w = Wrapper.forPrimitiveType(type);
-+        if (w.isSubwordOrInt())  return int.class;
-+        return type;
-+    }
-+    */
-+
-+    static void traceInterpreter(String event, Object obj, Object... args) {
-+        if (!TRACE_INTERPRETER)  return;
-+        System.out.println("LFI: "+event+" "+(obj != null ? obj : "")+(args != null && args.length != 0 ? Arrays.asList(args) : ""));
-+    }
-+    static void traceInterpreter(String event, Object obj) {
-+        traceInterpreter(event, obj, (Object[])null);
-+    }
-+    private boolean arityCheck(Object[] argumentValues) {
-+        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);
-+        // note:  argument #0 could also be an interface wrapper, in the future
-+        return true;
-+    }
-+
-+    private boolean isEmpty() {
-+        if (result < 0)
-+            return (names.length == arity);
-+        else if (result == arity && names.length == arity + 1)
-+            return names[arity].isConstantZero();
-+        else
-+            return false;
-+    }
-+
-+    public String toString() {
-+        StringBuilder buf = new StringBuilder("Lambda(");
-+        for (int i = 0; i < names.length; i++) {
-+            if (i == arity)  buf.append(")=>{");
-+            Name n = names[i];
-+            if (i >= arity)  buf.append("\n    ");
-+            buf.append(n);
-+            if (i < arity) {
-+                if (i+1 < arity)  buf.append(",");
-+                continue;
-+            }
-+            buf.append("=").append(n.exprString());
-+            buf.append(";");
-+        }
-+        buf.append(result < 0 ? "void" : names[result]).append("}");
-+        if (TRACE_INTERPRETER) {
-+            // Extra verbosity:
-+            buf.append(":").append(basicTypeSignature());
-+            buf.append("/").append(vmentry);
-+        }
-+        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);
-+    }
-+    LambdaForm bind(Name name, Name binding,
-+                    BoundMethodHandle.SpeciesData oldData,
-+                    BoundMethodHandle.SpeciesData newData) {
-+        int pos = name.index;
-+        assert(name.isParam());
-+        assert(!binding.isParam());
-+        assert(name.type == binding.type);
-+        assert(0 <= pos && pos < arity && names[pos] == name);
-+        assert(binding.function.memberDeclaringClassOrNull() == newData.clazz);
-+        assert(oldData.getters.length == newData.getters.length-1);
-+        if (bindCache != null) {
-+            LambdaForm form = bindCache[pos];
-+            if (form != null) {
-+                assert(form.contains(binding)) : "form << " + form + " >> does not contain binding << " + binding + " >>";
-+                return form;
-+            }
-+        } else {
-+            bindCache = new LambdaForm[arity];
-+        }
-+        assert(nameRefsAreLegal());
-+        int arity2 = arity-1;
-+        Name[] names2 = names.clone();
-+        names2[pos] = binding;  // we might move this in a moment
-+
-+        // The newly created LF will run with a different BMH.
-+        // Switch over any pre-existing BMH field references to the new BMH class.
-+        int firstOldRef = -1;
-+        for (int i = 0; i < names2.length; i++) {
-+            Name n = names[i];
-+            if (n.function != null &&
-+                n.function.memberDeclaringClassOrNull() == oldData.clazz) {
-+                MethodHandle oldGetter = n.function.resolvedHandle;
-+                MethodHandle newGetter = null;
-+                for (int j = 0; j < oldData.getters.length; j++) {
-+                    if (oldGetter == oldData.getters[j])
-+                        newGetter =  newData.getters[j];
-+                }
-+                if (newGetter != null) {
-+                    if (firstOldRef < 0)  firstOldRef = i;
-+                    Name n2 = new Name(newGetter, n.arguments);
-+                    names2[i] = n2;
-+                }
-+            }
-+        }
-+
-+        // Walk over the new list of names once, in forward order.
-+        // Replace references to 'name' with 'binding'.
-+        // Replace data structure references to the old BMH species with the new.
-+        // This might cause a ripple effect, but it will settle in one pass.
-+        assert(firstOldRef < 0 || firstOldRef > pos);
-+        for (int i = pos+1; i < names2.length; i++) {
-+            if (i <= arity2)  continue;
-+            names2[i] = names2[i].replaceNames(names, names2, pos, i);
-+        }
-+
-+        //  (a0, a1, name=a2, a3, a4)  =>  (a0, a1, a3, a4, binding)
-+        int insPos = pos;
-+        for (; insPos+1 < names2.length; insPos++) {
-+            Name n = names2[insPos+1];
-+            if (n.isSiblingBindingBefore(binding)) {
-+                names2[insPos] = n;
-+            } else {
-+                break;
-+            }
-+        }
-+        names2[insPos] = binding;
-+
-+        // Since we moved some stuff, maybe update the result reference:
-+        int result2 = result;
-+        if (result2 == pos)
-+            result2 = insPos;
-+        else if (result2 > pos && result2 <= insPos)
-+            result2 -= 1;
-+
-+        return bindCache[pos] = new LambdaForm(debugName, arity2, names2, result2);
-+    }
-+
-+    boolean contains(Name name) {
-+        int pos = name.index();
-+        if (pos >= 0) {
-+            return pos < names.length && name.equals(names[pos]);
-+        }
-+        for (int i = arity; i < names.length; i++) {
-+            if (name.equals(names[i]))
-+                return true;
-+        }
-+        return false;
-+    }
-+
-+    LambdaForm addArguments(int pos, char... types) {
-+        assert(pos <= arity);
-+        int length = names.length;
-+        int inTypes = types.length;
-+        Name[] names2 = Arrays.copyOf(names, length + inTypes);
-+        int arity2 = arity + inTypes;
-+        int result2 = result;
-+        if (result2 >= arity)
-+            result2 += inTypes;
-+        // names array has MH in slot 0; skip it.
-+        int argpos = pos + 1;
-+        // Note:  The LF constructor will rename names2[argpos...].
-+        // Make space for new arguments (shift temporaries).
-+        System.arraycopy(names, argpos, names2, argpos + inTypes, length - argpos);
-+        for (int i = 0; i < inTypes; i++) {
-+            names2[argpos + i] = new Name(types[i]);
-+        }
-+        return new LambdaForm(debugName, arity2, names2, result2);
-+    }
-+
-+    LambdaForm addArguments(int pos, List<Class<?>> types) {
-+        char[] basicTypes = new char[types.size()];
-+        for (int i = 0; i < basicTypes.length; i++)
-+            basicTypes[i] = basicType(types.get(i));
-+        return addArguments(pos, basicTypes);
-+    }
-+
-+    LambdaForm permuteArguments(int skip, int[] reorder, char[] 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;
-+        int inTypes = types.length;
-+        int outArgs = reorder.length;
-+        assert(skip+outArgs == arity);
-+        assert(permutedTypesMatch(reorder, types, names, skip));
-+        int pos = 0;
-+        // skip trivial first part of reordering:
-+        while (pos < outArgs && reorder[pos] == pos)  pos += 1;
-+        Name[] names2 = new Name[length - outArgs + inTypes];
-+        System.arraycopy(names, 0, names2, 0, skip+pos);
-+        // copy the body:
-+        int bodyLength = length - arity;
-+        System.arraycopy(names, skip+outArgs, names2, skip+inTypes, bodyLength);
-+        int arity2 = names2.length - bodyLength;
-+        int result2 = result;
-+        if (result2 >= 0) {
-+            if (result2 < skip+outArgs) {
-+                // return the corresponding inArg
-+                result2 = reorder[result2-skip];
-+            } else {
-+                result2 = result2 - outArgs + inTypes;
-+            }
-+        }
-+        // rework names in the body:
-+        for (int j = pos; j < outArgs; j++) {
-+            Name n = names[skip+j];
-+            int i = reorder[j];
-+            // replace names[skip+j] by names2[skip+i]
-+            Name n2 = names2[skip+i];
-+            if (n2 == null)
-+                names2[skip+i] = n2 = new Name(types[i]);
-+            else
-+                assert(n2.type == types[i]);
-+            for (int k = arity2; k < names2.length; k++) {
-+                names2[k] = names2[k].replaceName(n, n2);
-+            }
-+        }
-+        // some names are unused, but must be filled in
-+        for (int i = skip+pos; i < arity2; i++) {
-+            if (names2[i] == null)
-+                names2[i] = argument(i, types[i - skip]);
-+        }
-+        for (int j = arity; j < names.length; j++) {
-+            int i = j - arity + arity2;
-+            // replace names2[i] by names[j]
-+            Name n = names[j];
-+            Name n2 = names2[i];
-+            if (n != n2) {
-+                for (int k = i+1; k < names2.length; k++) {
-+                    names2[k] = names2[k].replaceName(n, n2);
-+                }
-+            }
-+        }
-+        return new LambdaForm(debugName, arity2, names2, result2);
-+    }
-+
-+    static boolean permutedTypesMatch(int[] reorder, char[] types, Name[] names, int skip) {
-+        int inTypes = types.length;
-+        int outArgs = reorder.length;
-+        for (int i = 0; i < outArgs; i++) {
-+            assert(names[skip+i].isParam());
-+            assert(names[skip+i].type == types[reorder[i]]);
-+        }
-+        return true;
-+    }
-+
-+    static class NamedFunction {
-+        final MemberName member;
-+        MethodHandle resolvedHandle;
-+        MethodHandle invoker;
-+
-+        NamedFunction(MethodHandle resolvedHandle) {
-+            this(resolvedHandle.internalMemberName(), resolvedHandle);
-+        }
-+        NamedFunction(MemberName member, MethodHandle resolvedHandle) {
-+            this.member = member;
-+            //resolvedHandle = eraseSubwordTypes(resolvedHandle);
-+            this.resolvedHandle = resolvedHandle;
-+        }
-+
-+        // The next 3 constructors are used to break circular dependencies on MH.invokeStatic, etc.
-+        // Any LambdaForm containing such a member is not interpretable.
-+        // This is OK, since all such LFs are prepared with special primitive vmentry points.
-+        // And even without the resolvedHandle, the name can still be compiled and optimized.
-+        NamedFunction(Method method) {
-+            this(new MemberName(method));
-+        }
-+        NamedFunction(Field field) {
-+            this(new MemberName(field));
-+        }
-+        NamedFunction(MemberName member) {
-+            this.member = member;
-+            this.resolvedHandle = null;
-+        }
-+
-+        MethodHandle resolvedHandle() {
-+            if (resolvedHandle == null)  resolve();
-+            return resolvedHandle;
-+        }
-+
-+        void resolve() {
-+            resolvedHandle = DirectMethodHandle.make(member);
-+        }
-+
-+        @Override
-+        public boolean equals(Object other) {
-+            if (this == other) return true;
-+            if (other == null) return false;
-+            if (!(other instanceof NamedFunction)) return false;
-+            NamedFunction that = (NamedFunction) other;
-+            return this.member != null && this.member.equals(that.member);
-+        }
-+
-+        @Override
-+        public int hashCode() {
-+            if (member != null)
-+                return member.hashCode();
-+            return super.hashCode();
-+        }
-+
-+        // Put the predefined NamedFunction invokers into the table.
-+        static void initializeInvokers() {
-+            for (MemberName m : MemberName.getFactory().getMethods(NamedFunction.class, false, null, null, null)) {
-+                if (!m.isStatic() || !m.isPackage())  continue;
-+                MethodType type = m.getMethodType();
-+                if (type.equals(INVOKER_METHOD_TYPE) &&
-+                    m.getName().startsWith("invoke_")) {
-+                    String sig = m.getName().substring("invoke_".length());
-+                    int arity = LambdaForm.signatureArity(sig);
-+                    MethodType srcType = MethodType.genericMethodType(arity);
-+                    if (LambdaForm.signatureReturn(sig) == 'V')
-+                        srcType = srcType.changeReturnType(void.class);
-+                    MethodTypeForm typeForm = srcType.form();
-+                    typeForm.namedFunctionInvoker = DirectMethodHandle.make(m);
-+                }
-+            }
-+        }
-+
-+        // The following are predefined NamedFunction invokers.  The system must build
-+        // a separate invoker for each distinct signature.
-+        /** void return type invokers. */
-+        @Hidden
-+        static Object invoke__V(MethodHandle mh, Object[] a) throws Throwable {
-+            assert(a.length == 0);
-+            mh.invokeBasic();
-+            return null;
-+        }
-+        @Hidden
-+        static Object invoke_L_V(MethodHandle mh, Object[] a) throws Throwable {
-+            assert(a.length == 1);
-+            mh.invokeBasic(a[0]);
-+            return null;
-+        }
-+        @Hidden
-+        static Object invoke_LL_V(MethodHandle mh, Object[] a) throws Throwable {
-+            assert(a.length == 2);
-+            mh.invokeBasic(a[0], a[1]);
-+            return null;
-+        }
-+        @Hidden
-+        static Object invoke_LLL_V(MethodHandle mh, Object[] a) throws Throwable {
-+            assert(a.length == 3);
-+            mh.invokeBasic(a[0], a[1], a[2]);
-+            return null;
-+        }
-+        @Hidden
-+        static Object invoke_LLLL_V(MethodHandle mh, Object[] a) throws Throwable {
-+            assert(a.length == 4);
-+            mh.invokeBasic(a[0], a[1], a[2], a[3]);
-+            return null;
-+        }
-+        @Hidden
-+        static Object invoke_LLLLL_V(MethodHandle mh, Object[] a) throws Throwable {
-+            assert(a.length == 5);
-+            mh.invokeBasic(a[0], a[1], a[2], a[3], a[4]);
-+            return null;
-+        }
-+        /** Object return type invokers. */
-+        @Hidden
-+        static Object invoke__L(MethodHandle mh, Object[] a) throws Throwable {
-+            assert(a.length == 0);
-+            return mh.invokeBasic();
-+        }
-+        @Hidden
-+        static Object invoke_L_L(MethodHandle mh, Object[] a) throws Throwable {
-+            assert(a.length == 1);
-+            return mh.invokeBasic(a[0]);
-+        }
-+        @Hidden
-+        static Object invoke_LL_L(MethodHandle mh, Object[] a) throws Throwable {
-+            assert(a.length == 2);
-+            return mh.invokeBasic(a[0], a[1]);
-+        }
-+        @Hidden
-+        static Object invoke_LLL_L(MethodHandle mh, Object[] a) throws Throwable {
-+            assert(a.length == 3);
-+            return mh.invokeBasic(a[0], a[1], a[2]);
-+        }
-+        @Hidden
-+        static Object invoke_LLLL_L(MethodHandle mh, Object[] a) throws Throwable {
-+            assert(a.length == 4);
-+            return mh.invokeBasic(a[0], a[1], a[2], a[3]);
-+        }
-+        @Hidden
-+        static Object invoke_LLLLL_L(MethodHandle mh, Object[] a) throws Throwable {
-+            assert(a.length == 5);
-+            return mh.invokeBasic(a[0], a[1], a[2], a[3], a[4]);
-+        }
-+
-+        static final MethodType INVOKER_METHOD_TYPE =
-+            MethodType.methodType(Object.class, MethodHandle.class, Object[].class);
-+
-+        private static MethodHandle computeInvoker(MethodTypeForm typeForm) {
-+            MethodHandle mh = typeForm.namedFunctionInvoker;
-+            if (mh != null)  return mh;
-+            MemberName invoker = InvokerBytecodeGenerator.generateNamedFunctionInvoker(typeForm);  // this could take a while
-+            mh = DirectMethodHandle.make(invoker);
-+            MethodHandle mh2 = typeForm.namedFunctionInvoker;
-+            if (mh2 != null)  return mh2;  // benign race
-+            if (!mh.type().equals(INVOKER_METHOD_TYPE))
-+                throw new InternalError(mh.debugString());
-+            return typeForm.namedFunctionInvoker = mh;
-+        }
-+
-+        @Hidden
-+        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);
-+            assert(checkArgumentTypes(arguments, methodType()));
-+            return invoker().invokeBasic(resolvedHandle(), arguments);
-+        }
-+
-+        @Hidden
-+        Object invokeWithArgumentsTracing(Object[] arguments) throws Throwable {
-+            Object rval;
-+            try {
-+                traceInterpreter("[ call", this, arguments);
-+                if (invoker == null) {
-+                    traceInterpreter("| getInvoker", this);
-+                    invoker();
-+                }
-+                if (resolvedHandle == null) {
-+                    traceInterpreter("| resolve", this);
-+                    resolvedHandle();
-+                }
-+                assert(checkArgumentTypes(arguments, methodType()));
-+                rval = invoker().invokeBasic(resolvedHandle(), arguments);
-+            } catch (Throwable ex) {
-+                traceInterpreter("] throw =>", ex);
-+                throw ex;
-+            }
-+            traceInterpreter("] return =>", rval);
-+            return rval;
-+        }
-+
-+        private MethodHandle invoker() {
-+            if (invoker != null)  return invoker;
-+            // Get an invoker and cache it.
-+            return invoker = computeInvoker(methodType().form());
-+        }
-+
-+        private static boolean checkArgumentTypes(Object[] arguments, MethodType methodType) {
-+            if (true)  return true;  // FIXME
-+            MethodType dstType = methodType.form().erasedType();
-+            MethodType srcType = dstType.basicType().wrap();
-+            Class<?>[] ptypes = new Class<?>[arguments.length];
-+            for (int i = 0; i < arguments.length; i++) {
-+                Object arg = arguments[i];
-+                Class<?> ptype = arg == null ? Object.class : arg.getClass();
-+                // If the dest. type is a primitive we keep the
-+                // argument type.
-+                ptypes[i] = dstType.parameterType(i).isPrimitive() ? ptype : Object.class;
-+            }
-+            MethodType argType = MethodType.methodType(srcType.returnType(), ptypes).wrap();
-+            assert(argType.isConvertibleTo(srcType)) : "wrong argument types: cannot convert " + argType + " to " + srcType;
-+            return true;
-+        }
-+
-+        String basicTypeSignature() {
-+            //return LambdaForm.basicTypeSignature(resolvedHandle.type());
-+            return LambdaForm.basicTypeSignature(methodType());
-+        }
-+
-+        MethodType methodType() {
-+            if (resolvedHandle != null)
-+                return resolvedHandle.type();
-+            else
-+                // only for certain internal LFs during bootstrapping
-+                return member.getInvocationType();
-+        }
-+
-+        MemberName member() {
-+            assert(assertMemberIsConsistent());
-+            return member;
-+        }
-+
-+        // Called only from assert.
-+        private boolean assertMemberIsConsistent() {
-+            if (resolvedHandle instanceof DirectMethodHandle) {
-+                MemberName m = resolvedHandle.internalMemberName();
-+                assert(m.equals(member));
-+            }
-+            return true;
-+        }
-+
-+        Class<?> memberDeclaringClassOrNull() {
-+            return (member == null) ? null : member.getDeclaringClass();
-+        }
-+
-+        char returnType() {
-+            return basicType(methodType().returnType());
-+        }
-+
-+        char parameterType(int n) {
-+            return basicType(methodType().parameterType(n));
-+        }
-+
-+        int arity() {
-+            //int siglen = member.getMethodType().parameterCount();
-+            //if (!member.isStatic())  siglen += 1;
-+            //return siglen;
-+            return methodType().parameterCount();
-+        }
-+
-+        public String toString() {
-+            if (member == null)  return resolvedHandle.toString();
-+            return member.getDeclaringClass().getSimpleName()+"."+member.getName();
-+        }
-+    }
-+
-+    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[] basicTypes(List<Class<?>> types) {
-+        char[] btypes = new char[types.size()];
-+        for (int i = 0; i < btypes.length; i++) {
-+            btypes[i] = basicType(types.get(i));
-+        }
-+        return btypes;
-+    }
-+    public static String basicTypeSignature(MethodType type) {
-+        char[] sig = new char[type.parameterCount() + 2];
-+        int sigp = 0;
-+        for (Class<?> pt : type.parameterList()) {
-+            sig[sigp++] = basicType(pt);
-+        }
-+        sig[sigp++] = '_';
-+        sig[sigp++] = basicType(type.returnType());
-+        assert(sigp == sig.length);
-+        return String.valueOf(sig);
-+    }
-+
-+    static final class Name {
-+        final char type;
-+        private short index;
-+        final NamedFunction function;
-+        final Object[] arguments;
-+
-+        private Name(int index, char type, NamedFunction function, Object[] arguments) {
-+            this.index = (short)index;
-+            this.type = type;
-+            this.function = function;
-+            this.arguments = arguments;
-+            assert(this.index == index);
-+        }
-+        Name(MethodHandle function, Object... arguments) {
-+            this(new NamedFunction(function), arguments);
-+        }
-+        Name(MemberName function, Object... arguments) {
-+            this(new NamedFunction(function), arguments);
-+        }
-+        Name(NamedFunction function, Object... arguments) {
-+            this(-1, function.returnType(), function, arguments = arguments.clone());
-+            assert(arguments.length == function.arity()) : "arity mismatch: arguments.length=" + arguments.length + " == function.arity()=" + function.arity() + " in " + debugString();
-+            for (int i = 0; i < arguments.length; i++)
-+                assert(typesMatch(function.parameterType(i), arguments[i])) : "types don't match: function.parameterType(" + i + ")=" + function.parameterType(i) + ", arguments[" + i + "]=" + arguments[i] + " in " + debugString();
-+        }
-+        Name(int index, char type) {
-+            this(index, type, null, null);
-+        }
-+        Name(char type) {
-+            this(-1, type);
-+        }
-+
-+        char type() { return type; }
-+        int index() { return index; }
-+        boolean initIndex(int i) {
-+            if (index != i) {
-+                if (index != -1)  return false;
-+                index = (short)i;
-+            }
-+            return true;
-+        }
-+
-+
-+        void resolve() {
-+            if (function != null)
-+                function.resolve();
-+        }
-+
-+        Name newIndex(int i) {
-+            if (initIndex(i))  return this;
-+            return cloneWithIndex(i);
-+        }
-+        Name cloneWithIndex(int i) {
-+            Object[] newArguments = (arguments == null) ? null : arguments.clone();
-+            return new Name(i, type, function, newArguments);
-+        }
-+        Name replaceName(Name oldName, Name newName) {  // FIXME: use replaceNames uniformly
-+            if (oldName == newName)  return this;
-+            @SuppressWarnings("LocalVariableHidesMemberVariable")
-+            Object[] arguments = this.arguments;
-+            if (arguments == null)  return this;
-+            boolean replaced = false;
-+            for (int j = 0; j < arguments.length; j++) {
-+                if (arguments[j] == oldName) {
-+                    if (!replaced) {
-+                        replaced = true;
-+                        arguments = arguments.clone();
-+                    }
-+                    arguments[j] = newName;
-+                }
-+            }
-+            if (!replaced)  return this;
-+            return new Name(function, arguments);
-+        }
-+        Name replaceNames(Name[] oldNames, Name[] newNames, int start, int end) {
-+            @SuppressWarnings("LocalVariableHidesMemberVariable")
-+            Object[] arguments = this.arguments;
-+            boolean replaced = false;
-+        eachArg:
-+            for (int j = 0; j < arguments.length; j++) {
-+                if (arguments[j] instanceof Name) {
-+                    Name n = (Name) arguments[j];
-+                    int check = n.index;
-+                    // harmless check to see if the thing is already in newNames:
-+                    if (check >= 0 && check < newNames.length && n == newNames[check])
-+                        continue eachArg;
-+                    // n might not have the correct index: n != oldNames[n.index].
-+                    for (int i = start; i < end; i++) {
-+                        if (n == oldNames[i]) {
-+                            if (n == newNames[i])
-+                                continue eachArg;
-+                            if (!replaced) {
-+                                replaced = true;
-+                                arguments = arguments.clone();
-+                            }
-+                            arguments[j] = newNames[i];
-+                            continue eachArg;
-+                        }
-+                    }
-+                }
-+            }
-+            if (!replaced)  return this;
-+            return new Name(function, arguments);
-+        }
-+        void internArguments() {
-+            @SuppressWarnings("LocalVariableHidesMemberVariable")
-+            Object[] arguments = this.arguments;
-+            for (int j = 0; j < arguments.length; j++) {
-+                if (arguments[j] instanceof Name) {
-+                    Name n = (Name) arguments[j];
-+                    if (n.isParam() && n.index < INTERNED_ARGUMENT_LIMIT)
-+                        arguments[j] = internArgument(n);
-+                }
-+            }
-+        }
-+        boolean isParam() {
-+            return function == null;
-+        }
-+        boolean isConstantZero() {
-+            return !isParam() && arguments.length == 0 && function.equals(constantZero(0, type).function);
-+        }
-+
-+        public String toString() {
-+            return (isParam()?"a":"t")+(index >= 0 ? index : System.identityHashCode(this))+":"+type;
-+        }
-+        public String debugString() {
-+            String s = toString();
-+            return (function == null) ? s : s + "=" + exprString();
-+        }
-+        public String exprString() {
-+            if (function == null)  return "null";
-+            StringBuilder buf = new StringBuilder(function.toString());
-+            buf.append("(");
-+            String cma = "";
-+            for (Object a : arguments) {
-+                buf.append(cma); cma = ",";
-+                if (a instanceof Name || a instanceof Integer)
-+                    buf.append(a);
-+                else
-+                    buf.append("(").append(a).append(")");
-+            }
-+            buf.append(")");
-+            return buf.toString();
-+        }
-+
-+        private static boolean typesMatch(char 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;
-+            }
-+            assert(parameterType == 'L');
-+            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
-+         */
-+        boolean isSiblingBindingBefore(Name binding) {
-+            assert(!binding.isParam());
-+            if (isParam())  return true;
-+            if (function.equals(binding.function) &&
-+                arguments.length == binding.arguments.length) {
-+                boolean sawInt = false;
-+                for (int i = 0; i < arguments.length; i++) {
-+                    Object a1 = arguments[i];
-+                    Object a2 = binding.arguments[i];
-+                    if (!a1.equals(a2)) {
-+                        if (a1 instanceof Integer && a2 instanceof Integer) {
-+                            if (sawInt)  continue;
-+                            sawInt = true;
-+                            if ((int)a1 < (int)a2)  continue;  // still might be true
-+                        }
-+                        return false;
-+                    }
-+                }
-+                return sawInt;
-+            }
-+            return false;
-+        }
-+
-+        public boolean equals(Name that) {
-+            if (this == that)  return true;
-+            if (isParam())
-+                // each parameter is a unique atom
-+                return false;  // this != that
-+            return
-+                //this.index == that.index &&
-+                this.type == that.type &&
-+                this.function.equals(that.function) &&
-+                Arrays.equals(this.arguments, that.arguments);
-+        }
-+        @Override
-+        public boolean equals(Object x) {
-+            return x instanceof Name && equals((Name)x);
-+        }
-+        @Override
-+        public int hashCode() {
-+            if (isParam())
-+                return index | (type << 8);
-+            return function.hashCode() ^ Arrays.hashCode(arguments);
-+        }
-+    }
-+
-+    static Name argument(int which, char type) {
-+        int tn = ALL_TYPES.indexOf(type);
-+        if (tn < 0 || which >= INTERNED_ARGUMENT_LIMIT)
-+            return new Name(which, type);
-+        return INTERNED_ARGUMENTS[tn][which];
-+    }
-+    static Name internArgument(Name n) {
-+        assert(n.isParam()) : "not param: " + n;
-+        assert(n.index < INTERNED_ARGUMENT_LIMIT);
-+        return argument(n.index, n.type);
-+    }
-+    static Name[] arguments(int extra, String types) {
-+        int length = types.length();
-+        Name[] names = new Name[length + extra];
-+        for (int i = 0; i < length; i++)
-+            names[i] = argument(i, types.charAt(i));
-+        return names;
-+    }
-+    static Name[] arguments(int extra, char... types) {
-+        int length = types.length;
-+        Name[] names = new Name[length + extra];
-+        for (int i = 0; i < length; i++)
-+            names[i] = argument(i, types[i]);
-+        return names;
-+    }
-+    static Name[] arguments(int extra, List<Class<?>> types) {
-+        int length = types.size();
-+        Name[] names = new Name[length + extra];
-+        for (int i = 0; i < length; i++)
-+            names[i] = argument(i, basicType(types.get(i)));
-+        return names;
-+    }
-+    static Name[] arguments(int extra, Class<?>... types) {
-+        int length = types.length;
-+        Name[] names = new Name[length + extra];
-+        for (int i = 0; i < length; i++)
-+            names[i] = argument(i, basicType(types[i]));
-+        return names;
-+    }
-+    static Name[] arguments(int extra, MethodType types) {
-+        int length = types.parameterCount();
-+        Name[] names = new Name[length + extra];
-+        for (int i = 0; i < length; i++)
-+            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];
-+    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);
-+            }
-+        }
-+    }
-+
-+    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);
-+    }
-+    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);
-+            try {
-+                zmem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, zmem, null, NoSuchMethodException.class);
-+            } catch (IllegalAccessException|NoSuchMethodException ex) {
-+                throw new InternalError(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());
-+        }
-+    }
-+
-+    // Avoid appealing to ValueConversions at bootstrap time:
-+    private static int zeroI() { return 0; }
-+    private static long zeroJ() { return 0; }
-+    private static float zeroF() { return 0; }
-+    private static double zeroD() { return 0; }
-+    private static Object zeroL() { return null; }
-+
-+    // Put this last, so that previous static inits can run before.
-+    static {
-+        if (USE_PREDEFINED_INTERPRET_METHODS)
-+            PREPARED_FORMS.putAll(computeInitialPreparedForms());
-+    }
-+
-+    /**
-+     * Internal marker for byte-compiled LambdaForms.
-+     */
-+    /*non-public*/
-+    @Target(ElementType.METHOD)
-+    @Retention(RetentionPolicy.RUNTIME)
-+    @interface Compiled {
-+    }
-+
-+    /**
-+     * Internal marker for LambdaForm interpreter frames.
-+     */
-+    /*non-public*/
-+    @Target(ElementType.METHOD)
-+    @Retention(RetentionPolicy.RUNTIME)
-+    @interface Hidden {
-+    }
-+
-+
-+/*
-+    // Smoke-test for the invokers used in this file.
-+    static void testMethodHandleLinkers() throws Throwable {
-+        MemberName.Factory lookup = MemberName.getFactory();
-+        MemberName asList_MN = new MemberName(Arrays.class, "asList",
-+                                              MethodType.methodType(List.class, Object[].class),
-+                                              REF_invokeStatic);
-+        //MethodHandleNatives.resolve(asList_MN, null);
-+        asList_MN = lookup.resolveOrFail(asList_MN, REF_invokeStatic, null, NoSuchMethodException.class);
-+        System.out.println("about to call "+asList_MN);
-+        Object[] abc = { "a", "bc" };
-+        List<?> lst = (List<?>) MethodHandle.linkToStatic(abc, asList_MN);
-+        System.out.println("lst="+lst);
-+        MemberName toString_MN = new MemberName(Object.class.getMethod("toString"));
-+        String s1 = (String) MethodHandle.linkToVirtual(lst, toString_MN);
-+        toString_MN = new MemberName(Object.class.getMethod("toString"), true);
-+        String s2 = (String) MethodHandle.linkToSpecial(lst, toString_MN);
-+        System.out.println("[s1,s2,lst]="+Arrays.asList(s1, s2, lst.toString()));
-+        MemberName toArray_MN = new MemberName(List.class.getMethod("toArray"));
-+        Object[] arr = (Object[]) MethodHandle.linkToInterface(lst, toArray_MN);
-+        System.out.println("toArray="+Arrays.toString(arr));
-+    }
-+    static { try { testMethodHandleLinkers(); } catch (Throwable ex) { throw new RuntimeException(ex); } }
-+    // Requires these definitions in MethodHandle:
-+    static final native Object linkToStatic(Object x1, MemberName mn) throws Throwable;
-+    static final native Object linkToVirtual(Object x1, MemberName mn) throws Throwable;
-+    static final native Object linkToSpecial(Object x1, MemberName mn) throws Throwable;
-+    static final native Object linkToInterface(Object x1, MemberName mn) throws Throwable;
-+ */
-+
-+    static { NamedFunction.initializeInvokers(); }
-+}
-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
-@@ -26,6 +26,8 @@
- package java.lang.invoke;
- 
- import sun.invoke.util.BytecodeDescriptor;
-+import sun.invoke.util.VerifyAccess;
-+
- import java.lang.reflect.Constructor;
- import java.lang.reflect.Field;
- import java.lang.reflect.Method;
-@@ -38,6 +40,7 @@
- import java.util.List;
- import static java.lang.invoke.MethodHandleNatives.Constants.*;
- import static java.lang.invoke.MethodHandleStatics.*;
-+import java.util.Objects;
- 
- /**
-  * A {@code MemberName} is a compact symbolic datum which fully characterizes
-@@ -71,19 +74,14 @@
-     private String     name;        // may be null if not yet materialized
-     private Object     type;        // may be null if not yet materialized
-     private int        flags;       // modifier bits; see reflect.Modifier
--
--    private Object     vmtarget;    // VM-specific target value
--    private int        vmindex;     // method index within class or interface
--
--    { vmindex = VM_INDEX_UNINITIALIZED; }
-+    //@Injected JVM_Method* vmtarget;
-+    //@Injected int         vmindex;
-+    private Object     resolution;  // if null, this guy is resolved
- 
-     /** Return the declaring class of this member.
-      *  In the case of a bare name and type, the declaring class will be null.
-      */
-     public Class<?> getDeclaringClass() {
--        if (clazz == null && isResolved()) {
--            expandFromVM();
--        }
-         return clazz;
-     }
- 
-@@ -105,6 +103,16 @@
-         return name;
-     }
- 
-+    public MethodType getMethodOrFieldType() {
-+        if (isInvocable())
-+            return getMethodType();
-+        if (isGetter())
-+            return MethodType.methodType(getFieldType());
-+        if (isSetter())
-+            return MethodType.methodType(void.class, getFieldType());
-+        throw new InternalError("not a method or field: "+this);
-+    }
-+
-     /** Return the declared type of this member, which
-      *  must be a method or constructor.
-      */
-@@ -140,9 +148,11 @@
-      *  a reference to declaring class.  For static methods, it is the same as the declared type.
-      */
-     public MethodType getInvocationType() {
--        MethodType itype = getMethodType();
-+        MethodType itype = getMethodOrFieldType();
-+        if (isConstructor() && getReferenceKind() == REF_newInvokeSpecial)
-+            return itype.changeReturnType(clazz);
-         if (!isStatic())
--            itype = itype.insertParameterTypes(0, clazz);
-+            return itype.insertParameterTypes(0, clazz);
-         return itype;
-     }
- 
-@@ -208,9 +218,98 @@
-         return (flags & RECOGNIZED_MODIFIERS);
-     }
- 
-+    /** Return the reference kind of this member, or zero if none.
-+     */
-+    public byte getReferenceKind() {
-+        return (byte) ((flags >>> MN_REFERENCE_KIND_SHIFT) & MN_REFERENCE_KIND_MASK);
-+    }
-+    private boolean referenceKindIsConsistent() {
-+        byte refKind = getReferenceKind();
-+        if (refKind == REF_NONE)  return isType();
-+        if (isField()) {
-+            assert(staticIsConsistent());
-+            assert(MethodHandleNatives.refKindIsField(refKind));
-+        } else if (isConstructor()) {
-+            assert(refKind == REF_newInvokeSpecial || refKind == REF_invokeSpecial);
-+        } else if (isMethod()) {
-+            assert(staticIsConsistent());
-+            assert(MethodHandleNatives.refKindIsMethod(refKind));
-+            if (clazz.isInterface())
-+                assert(refKind == REF_invokeInterface ||
-+                       refKind == REF_invokeVirtual && isObjectPublicMethod());
-+        } else {
-+            assert(false);
-+        }
-+        return true;
-+    }
-+    private boolean isObjectPublicMethod() {
-+        if (clazz == Object.class)  return true;
-+        MethodType mtype = getMethodType();
-+        if (name.equals("toString") && mtype.returnType() == String.class && mtype.parameterCount() == 0)
-+            return true;
-+        if (name.equals("hashCode") && mtype.returnType() == int.class && mtype.parameterCount() == 0)
-+            return true;
-+        if (name.equals("equals") && mtype.returnType() == boolean.class && mtype.parameterCount() == 1 && mtype.parameterType(0) == Object.class)
-+            return true;
-+        return false;
-+    }
-+    /*non-public*/ boolean referenceKindIsConsistentWith(int originalRefKind) {
-+        int refKind = getReferenceKind();
-+        if (refKind == originalRefKind)  return true;
-+        switch (originalRefKind) {
-+        case REF_invokeInterface:
-+            // Looking up an interface method, can get (e.g.) Object.hashCode
-+            assert(refKind == REF_invokeVirtual ||
-+                   refKind == REF_invokeSpecial) : this;
-+            return true;
-+        case REF_invokeVirtual:
-+        case REF_newInvokeSpecial:
-+            // Looked up a virtual, can get (e.g.) final String.hashCode.
-+            assert(refKind == REF_invokeSpecial) : this;
-+            return true;
-+        }
-+        assert(false) : this;
-+        return true;
-+    }
-+    private boolean staticIsConsistent() {
-+        byte refKind = getReferenceKind();
-+        return MethodHandleNatives.refKindIsStatic(refKind) == isStatic() || getModifiers() == 0;
-+    }
-+    private boolean vminfoIsConsistent() {
-+        byte refKind = getReferenceKind();
-+        assert(isResolved());  // else don't call
-+        Object vminfo = MethodHandleNatives.getMemberVMInfo(this);
-+        assert(vminfo instanceof Object[]);
-+        long vmindex = (Long) ((Object[])vminfo)[0];
-+        Object vmtarget = ((Object[])vminfo)[1];
-+        if (MethodHandleNatives.refKindIsField(refKind)) {
-+            assert(vmindex >= 0) : vmindex + ":" + this;
-+            assert(vmtarget instanceof Class);
-+        } else {
-+            if (MethodHandleNatives.refKindDoesDispatch(refKind))
-+                assert(vmindex >= 0) : vmindex + ":" + this;
-+            else
-+                assert(vmindex < 0) : vmindex;
-+            assert(vmtarget instanceof MemberName) : vmtarget + " in " + this;
-+        }
-+        return true;
-+    }
-+
-+    private MemberName changeReferenceKind(byte refKind, byte oldKind) {
-+        assert(getReferenceKind() == oldKind);
-+        assert(MethodHandleNatives.refKindIsValid(refKind));
-+        flags += (((int)refKind - oldKind) << MN_REFERENCE_KIND_SHIFT);
-+//        if (isConstructor() && refKind != REF_newInvokeSpecial)
-+//            flags += (IS_METHOD - IS_CONSTRUCTOR);
-+//        else if (refKind == REF_newInvokeSpecial && isMethod())
-+//            flags += (IS_CONSTRUCTOR - IS_METHOD);
-+        return this;
-+    }
-+
-     private void setFlags(int flags) {
-         this.flags = flags;
-         assert(testAnyFlags(ALL_KINDS));
-+        assert(referenceKindIsConsistent());
-     }
- 
-     private boolean testFlags(int mask, int value) {
-@@ -223,6 +322,17 @@
-         return !testFlags(mask, 0);
-     }
- 
-+    /** Utility method to query if this member is a method handle invocation (invoke or invokeExact). */
-+    public boolean isMethodHandleInvoke() {
-+        final int bits = Modifier.NATIVE | Modifier.FINAL;
-+        final int negs = Modifier.STATIC;
-+        if (testFlags(bits | negs, bits) &&
-+            clazz == MethodHandle.class) {
-+            return name.equals("invoke") || name.equals("invokeExact");
-+        }
-+        return false;
-+    }
-+
-     /** Utility method to query the modifier flags of this member. */
-     public boolean isStatic() {
-         return Modifier.isStatic(flags);
-@@ -243,10 +353,22 @@
-     public boolean isFinal() {
-         return Modifier.isFinal(flags);
-     }
-+    /** Utility method to query whether this member or its defining class is final. */
-+    public boolean canBeStaticallyBound() {
-+        return Modifier.isFinal(flags | clazz.getModifiers());
-+    }
-+    /** Utility method to query the modifier flags of this member. */
-+    public boolean isVolatile() {
-+        return Modifier.isVolatile(flags);
-+    }
-     /** Utility method to query the modifier flags of this member. */
-     public boolean isAbstract() {
-         return Modifier.isAbstract(flags);
-     }
-+    /** Utility method to query the modifier flags of this member. */
-+    public boolean isNative() {
-+        return Modifier.isNative(flags);
-+    }
-     // let the rest (native, volatile, transient, etc.) be tested via Modifier.isFoo
- 
-     // unofficial modifier flags, used by HotSpot:
-@@ -279,15 +401,12 @@
-             IS_CONSTRUCTOR = MN_IS_CONSTRUCTOR, // constructor
-             IS_FIELD       = MN_IS_FIELD,       // field
-             IS_TYPE        = MN_IS_TYPE;        // nested type
--    static final int  // for MethodHandleNatives.getMembers
--            SEARCH_SUPERCLASSES = MN_SEARCH_SUPERCLASSES,
--            SEARCH_INTERFACES   = MN_SEARCH_INTERFACES;
- 
-     static final int ALL_ACCESS = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED;
-     static final int ALL_KINDS = IS_METHOD | IS_CONSTRUCTOR | IS_FIELD | IS_TYPE;
-     static final int IS_INVOCABLE = IS_METHOD | IS_CONSTRUCTOR;
-     static final int IS_FIELD_OR_METHOD = IS_METHOD | IS_FIELD;
--    static final int SEARCH_ALL_SUPERS = SEARCH_SUPERCLASSES | SEARCH_INTERFACES;
-+    static final int SEARCH_ALL_SUPERS = MN_SEARCH_SUPERCLASSES | MN_SEARCH_INTERFACES;
- 
-     /** Utility method to query whether this member is a method or constructor. */
-     public boolean isInvocable() {
-@@ -318,6 +437,12 @@
-         return !testAnyFlags(ALL_ACCESS);
-     }
- 
-+    /** Utility method to query whether this member is accessible from a given lookup class. */
-+    public boolean isAccessibleFrom(Class<?> lookupClass) {
-+        return VerifyAccess.isMemberAccessible(this.getDeclaringClass(), this.getDeclaringClass(), flags,
-+                                               lookupClass, ALL_ACCESS|MethodHandles.Lookup.PACKAGE);
-+    }
-+
-     /** 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)
-@@ -328,7 +453,7 @@
-         this.name = name;
-         this.type = type;
-         setFlags(flags);
--        assert(!isResolved());
-+        assert(this.resolution == null);  // nobody should have touched this yet
-     }
- 
-     private void expandFromVM() {
-@@ -339,39 +464,91 @@
-     }
- 
-     // Capturing information from the Core Reflection API:
--    private static int flagsMods(int flags, int mods) {
-+    private static int flagsMods(int flags, int mods, byte refKind) {
-         assert((flags & RECOGNIZED_MODIFIERS) == 0);
-         assert((mods & ~RECOGNIZED_MODIFIERS) == 0);
--        return flags | mods;
-+        assert((refKind & ~MN_REFERENCE_KIND_MASK) == 0);
-+        return flags | mods | (refKind << MN_REFERENCE_KIND_SHIFT);
-     }
-     /** Create a name for the given reflected method.  The resulting name will be in a resolved state. */
-     public MemberName(Method m) {
--        Object[] typeInfo = { m.getReturnType(), m.getParameterTypes() };
--        init(m.getDeclaringClass(), m.getName(), typeInfo, flagsMods(IS_METHOD, m.getModifiers()));
-+        this(m, false);
-+    }
-+    @SuppressWarnings("LeakingThisInConstructor")
-+    public MemberName(Method m, boolean wantSpecial) {
-         // fill in vmtarget, vmindex while we have m in hand:
-         MethodHandleNatives.init(this, m);
--        assert(isResolved());
-+        assert(isResolved() && this.clazz != null);
-+        this.name = m.getName();
-+        if (this.type == null)
-+            this.type = new Object[] { m.getReturnType(), m.getParameterTypes() };
-+        if (wantSpecial) {
-+            if (getReferenceKind() == REF_invokeVirtual)
-+                changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual);
-+        }
-+    }
-+    public MemberName asSpecial() {
-+        switch (getReferenceKind()) {
-+        case REF_invokeSpecial:     return this;
-+        case REF_invokeVirtual:     return clone().changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual);
-+        case REF_newInvokeSpecial:  return clone().changeReferenceKind(REF_invokeSpecial, REF_newInvokeSpecial);
-+        }
-+        throw new IllegalArgumentException(this.toString());
-+    }
-+    public MemberName asConstructor() {
-+        switch (getReferenceKind()) {
-+        case REF_invokeSpecial:     return clone().changeReferenceKind(REF_newInvokeSpecial, REF_invokeSpecial);
-+        case REF_newInvokeSpecial:  return this;
-+        }
-+        throw new IllegalArgumentException(this.toString());
-     }
-     /** Create a name for the given reflected constructor.  The resulting name will be in a resolved state. */
-+    @SuppressWarnings("LeakingThisInConstructor")
-     public MemberName(Constructor<?> ctor) {
--        Object[] typeInfo = { void.class, ctor.getParameterTypes() };
--        init(ctor.getDeclaringClass(), CONSTRUCTOR_NAME, typeInfo, flagsMods(IS_CONSTRUCTOR, ctor.getModifiers()));
-         // fill in vmtarget, vmindex while we have ctor in hand:
-         MethodHandleNatives.init(this, ctor);
--        assert(isResolved());
-+        assert(isResolved() && this.clazz != null);
-+        this.name = CONSTRUCTOR_NAME;
-+        if (this.type == null)
-+            this.type = new Object[] { void.class, ctor.getParameterTypes() };
-     }
--    /** Create a name for the given reflected field.  The resulting name will be in a resolved state. */
-+    /** Create a name for the given reflected field.  The resulting name will be in a resolved state.
-+     */
-     public MemberName(Field fld) {
--        init(fld.getDeclaringClass(), fld.getName(), fld.getType(), flagsMods(IS_FIELD, fld.getModifiers()));
-+        this(fld, false);
-+    }
-+    @SuppressWarnings("LeakingThisInConstructor")
-+    public MemberName(Field fld, boolean makeSetter) {
-         // fill in vmtarget, vmindex while we have fld in hand:
-         MethodHandleNatives.init(this, fld);
--        assert(isResolved());
-+        assert(isResolved() && this.clazz != null);
-+        this.name = fld.getName();
-+        this.type = fld.getType();
-+        assert((REF_putStatic - REF_getStatic) == (REF_putField - REF_getField));
-+        byte refKind = this.getReferenceKind();
-+        assert(refKind == (isStatic() ? REF_getStatic : REF_getField));
-+        if (makeSetter) {
-+            changeReferenceKind((byte)(refKind + (REF_putStatic - REF_getStatic)), refKind);
-+        }
-+    }
-+    public boolean isGetter() {
-+        return MethodHandleNatives.refKindIsGetter(getReferenceKind());
-+    }
-+    public boolean isSetter() {
-+        return MethodHandleNatives.refKindIsSetter(getReferenceKind());
-+    }
-+    public MemberName asSetter() {
-+        byte refKind = getReferenceKind();
-+        assert(MethodHandleNatives.refKindIsGetter(refKind));
-+        assert((REF_putStatic - REF_getStatic) == (REF_putField - REF_getField));
-+        byte setterRefKind = (byte)(refKind + (REF_putField - REF_getField));
-+        return clone().changeReferenceKind(setterRefKind, refKind);
-     }
-     /** Create a name for the given class.  The resulting name will be in a resolved state. */
-     public MemberName(Class<?> type) {
--        init(type.getDeclaringClass(), type.getSimpleName(), type, flagsMods(IS_TYPE, type.getModifiers()));
--        vmindex = 0;  // isResolved
--        assert(isResolved());
-+        init(type.getDeclaringClass(), type.getSimpleName(), type,
-+                flagsMods(IS_TYPE, type.getModifiers(), REF_NONE));
-+        initResolved(true);
-     }
- 
-     // bare-bones constructor; the JVM will fill it in
-@@ -386,41 +563,89 @@
-         }
-      }
- 
--    // %%% define equals/hashcode?
-+    /** Get the definition of this member name.
-+     *  This may be in a super-class of the declaring class of this member.
-+     */
-+    public MemberName getDefinition() {
-+        if (!isResolved())  throw new IllegalStateException("must be resolved: "+this);
-+        if (isType())  return this;
-+        MemberName res = this.clone();
-+        res.clazz = null;
-+        res.type = null;
-+        res.name = null;
-+        res.resolution = res;
-+        res.expandFromVM();
-+        assert(res.getName().equals(this.getName()));
-+        return res;
-+    }
-+
-+    @Override
-+    public int hashCode() {
-+        return Objects.hash(clazz, flags, name, getType());
-+    }
-+    @Override
-+    public boolean equals(Object that) {
-+        return (that instanceof MemberName && this.equals((MemberName)that));
-+    }
-+
-+    /** Decide if two member names have exactly the same symbolic content.
-+     *  Does not take into account any actual class members, so even if
-+     *  two member names resolve to the same actual member, they may
-+     *  be distinct references.
-+     */
-+    public boolean equals(MemberName that) {
-+        if (this == that)  return true;
-+        if (that == null)  return false;
-+        return this.clazz == that.clazz
-+                && this.flags == that.flags
-+                && 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, modifiers.
-+    /** 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.
-      */
--    public MemberName(Class<?> defClass, String name, Class<?> type, int modifiers) {
--        init(defClass, name, type, IS_FIELD | (modifiers & RECOGNIZED_MODIFIERS));
-+    public MemberName(Class<?> defClass, String name, Class<?> type, byte refKind) {
-+        init(defClass, name, type, flagsMods(IS_FIELD, 0, refKind));
-+        initResolved(false);
-     }
-     /** Create a field or type name from the given components:  Declaring class, name, type.
-      *  The declaring class may be supplied as null if this is to be a bare name and type.
-      *  The modifier flags default to zero.
-      *  The resulting name will in an unresolved state.
-      */
--    public MemberName(Class<?> defClass, String name, Class<?> type) {
--        this(defClass, name, type, 0);
-+    public MemberName(Class<?> defClass, String name, Class<?> type, Void unused) {
-+        this(defClass, name, type, REF_NONE);
-+        initResolved(false);
-     }
-     /** Create a method or constructor name from the given components:  Declaring class, name, type, modifiers.
-      *  It will be a constructor if and only if the name is {@code "&lt;init&gt;"}.
-      *  The declaring class may be supplied as null if this is to be a bare name and type.
-+     *  The last argument is optional, a boolean which requests REF_invokeSpecial.
-      *  The resulting name will in an unresolved state.
-      */
--    public MemberName(Class<?> defClass, String name, MethodType type, int modifiers) {
--        int flagBit = (name.equals(CONSTRUCTOR_NAME) ? IS_CONSTRUCTOR : IS_METHOD);
--        init(defClass, name, type, flagBit | (modifiers & RECOGNIZED_MODIFIERS));
-+    public MemberName(Class<?> defClass, String name, MethodType type, byte refKind) {
-+        @SuppressWarnings("LocalVariableHidesMemberVariable")
-+        int flags = (name != null && name.equals(CONSTRUCTOR_NAME) ? IS_CONSTRUCTOR : IS_METHOD);
-+        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.
-+//    /** 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);
-+//    }
-+
-+    /** Query whether this member name is resolved to a non-static, non-final method.
-      */
--    public MemberName(Class<?> defClass, String name, MethodType type) {
--        this(defClass, name, type, 0);
-+    public boolean hasReceiverTypeDispatch() {
-+        return MethodHandleNatives.refKindDoesDispatch(getReferenceKind());
-     }
- 
-     /** Query whether this member name is resolved.
-@@ -429,15 +654,38 @@
-      *  (Document?)
-      */
-     public boolean isResolved() {
--        return (vmindex != VM_INDEX_UNINITIALIZED);
-+        return resolution == null;
-     }
- 
--    /** Query whether this member name is resolved to a non-static, non-final method.
--     */
--    public boolean hasReceiverTypeDispatch() {
--        return (isMethod() && getVMIndex() >= 0);
-+    private void initResolved(boolean isResolved) {
-+        assert(this.resolution == null);  // not initialized yet!
-+        if (!isResolved)
-+            this.resolution = this;
-+        assert(isResolved() == isResolved);
-     }
- 
-+    void checkForTypeAlias() {
-+        if (isInvocable()) {
-+            MethodType type;
-+            if (this.type instanceof MethodType)
-+                type = (MethodType) this.type;
-+            else
-+                this.type = type = getMethodType();
-+            if (type.erase() == type)  return;
-+            if (VerifyAccess.isTypeVisible(type, clazz))  return;
-+            throw new LinkageError("bad method type alias: "+type+" not visible from "+clazz);
-+        } else {
-+            Class<?> type;
-+            if (this.type instanceof Class<?>)
-+                type = (Class<?>) this.type;
-+            else
-+                this.type = type = getFieldType();
-+            if (VerifyAccess.isTypeVisible(type, clazz))  return;
-+            throw new LinkageError("bad field type alias: "+type+" not visible from "+clazz);
-+        }
-+    }
-+
-+
-     /** Produce a string form of this member name.
-      *  For types, it is simply the type's own string (as reported by {@code toString}).
-      *  For fields, it is {@code "DeclaringClass.name/type"}.
-@@ -445,6 +693,7 @@
-      *  If the declaring class is null, the prefix {@code "DeclaringClass."} is omitted.
-      *  If the member is unresolved, a prefix {@code "*."} is prepended.
-      */
-+    @SuppressWarnings("LocalVariableHidesMemberVariable")
-     @Override
-     public String toString() {
-         if (isType())
-@@ -464,22 +713,12 @@
-         } else {
-             buf.append(type == null ? "(*)*" : getName(type));
-         }
--        /*
--        buf.append('/');
--        // key: Public, private, pRotected, sTatic, Final, sYnchronized,
--        // transient/Varargs, native, (interface), abstract, sTrict, sYnthetic,
--        // (annotation), Enum, (unused)
--        final String FIELD_MOD_CHARS  = "PprTF?vt????Y?E?";
--        final String METHOD_MOD_CHARS = "PprTFybVn?atY???";
--        String modChars = (isInvocable() ? METHOD_MOD_CHARS : FIELD_MOD_CHARS);
--        for (int i = 0; i < modChars.length(); i++) {
--            if ((flags & (1 << i)) != 0) {
--                char mc = modChars.charAt(i);
--                if (mc != '?')
--                    buf.append(mc);
--            }
-+        byte refKind = getReferenceKind();
-+        if (refKind != REF_NONE) {
-+            buf.append('/');
-+            buf.append(MethodHandleNatives.refKindName(refKind));
-         }
--         */
-+        //buf.append("#").append(System.identityHashCode(this));
-         return buf.toString();
-     }
-     private static String getName(Object obj) {
-@@ -488,19 +727,6 @@
-         return String.valueOf(obj);
-     }
- 
--    // Queries to the JVM:
--    /** Document? */
--    /*non-public*/ int getVMIndex() {
--        if (!isResolved())
--            throw newIllegalStateException("not resolved", this);
--        return vmindex;
--    }
--//    /*non-public*/ Object getVMTarget() {
--//        if (!isResolved())
--//            throw newIllegalStateException("not resolved", this);
--//        return vmtarget;
--//    }
--
-     public IllegalAccessException makeAccessException(String message, Object from) {
-         message = message + ": "+ toString();
-         if (from != null)  message += ", from " + from;
-@@ -518,14 +744,19 @@
-     }
-     public ReflectiveOperationException makeAccessException() {
-         String message = message() + ": "+ toString();
--        if (isResolved())
--            return new IllegalAccessException(message);
-+        ReflectiveOperationException ex;
-+        if (isResolved() || !(resolution instanceof NoSuchMethodError ||
-+                              resolution instanceof NoSuchFieldError))
-+            ex = new IllegalAccessException(message);
-         else if (isConstructor())
--            return new NoSuchMethodException(message);
-+            ex = new NoSuchMethodException(message);
-         else if (isMethod())
--            return new NoSuchMethodException(message);
-+            ex = new NoSuchMethodException(message);
-         else
--            return new NoSuchFieldException(message);
-+            ex = new NoSuchFieldException(message);
-+        if (resolution instanceof Throwable)
-+            ex.initCause((Throwable) resolution);
-+        return ex;
-     }
- 
-     /** Actually making a query requires an access check. */
-@@ -539,7 +770,7 @@
-         private Factory() { } // singleton pattern
-         static Factory INSTANCE = new Factory();
- 
--        private static int ALLOWED_FLAGS = SEARCH_ALL_SUPERS | ALL_KINDS;
-+        private static int ALLOWED_FLAGS = ALL_KINDS;
- 
-         /// Queries
-         List<MemberName> getMembers(Class<?> defc,
-@@ -573,14 +804,14 @@
-                 // JVM returned to us with an intentional overflow!
-                 totalCount += buf.length;
-                 int excess = bufCount - buf.length;
--                if (bufs == null)  bufs = new ArrayList<MemberName[]>(1);
-+                if (bufs == null)  bufs = new ArrayList<>(1);
-                 bufs.add(buf);
-                 int len2 = buf.length;
-                 len2 = Math.max(len2, excess);
-                 len2 = Math.max(len2, totalCount / 4);
-                 buf = newMemberBuffer(Math.min(BUF_MAX, len2));
-             }
--            ArrayList<MemberName> result = new ArrayList<MemberName>(totalCount);
-+            ArrayList<MemberName> result = new ArrayList<>(totalCount);
-             if (bufs != null) {
-                 for (MemberName[] buf0 : bufs) {
-                     Collections.addAll(result, buf0);
-@@ -599,47 +830,29 @@
-             }
-             return result;
-         }
--        boolean resolveInPlace(MemberName m, boolean searchSupers, Class<?> lookupClass) {
--            if (m.name == null || m.type == null) {  // find unique non-overloaded name
--                Class<?> defc = m.getDeclaringClass();
--                List<MemberName> choices = null;
--                if (m.isMethod())
--                    choices = getMethods(defc, searchSupers, m.name, (MethodType) m.type, lookupClass);
--                else if (m.isConstructor())
--                    choices = getConstructors(defc, lookupClass);
--                else if (m.isField())
--                    choices = getFields(defc, searchSupers, m.name, (Class<?>) m.type, lookupClass);
--                //System.out.println("resolving "+m+" to "+choices);
--                if (choices == null || choices.size() != 1)
--                    return false;
--                if (m.name == null)  m.name = choices.get(0).name;
--                if (m.type == null)  m.type = choices.get(0).type;
--            }
--            MethodHandleNatives.resolve(m, lookupClass);
--            if (m.isResolved())  return true;
--            int matchFlags = m.flags | (searchSupers ? SEARCH_ALL_SUPERS : 0);
--            String matchSig = m.getSignature();
--            MemberName[] buf = { m };
--            int n = MethodHandleNatives.getMembers(m.getDeclaringClass(),
--                    m.getName(), matchSig, matchFlags, lookupClass, 0, buf);
--            if (n == 0 || !m.isResolved())
--                return false;  // no result
--            else if (n == 1 || m.clazz.isInterface())
--                return true;   // unique result, or multiple inheritance is OK
--            else
--                return false;  // ambiguous result (can this happen?)
--        }
-         /** Produce a resolved version of the given member.
-          *  Super types are searched (for inherited members) if {@code searchSupers} is true.
-          *  Access checking is performed on behalf of the given {@code lookupClass}.
-          *  If lookup fails or access is not permitted, null is returned.
-          *  Otherwise a fresh copy of the given member is returned, with modifier bits filled in.
-          */
--        public MemberName resolveOrNull(MemberName m, boolean searchSupers, Class<?> lookupClass) {
--            MemberName result = m.clone();
--            if (resolveInPlace(result, searchSupers, lookupClass))
--                return result;
--            return null;
-+        private MemberName resolve(byte refKind, MemberName ref, Class<?> lookupClass) {
-+            MemberName m = ref.clone();  // JVM will side-effect the ref
-+            assert(refKind == m.getReferenceKind());
-+            try {
-+                m = MethodHandleNatives.resolve(m, lookupClass);
-+                m.checkForTypeAlias();
-+                m.resolution = null;
-+            } catch (LinkageError ex) {
-+                // JVM reports that the "bytecode behavior" would get an error
-+                assert(!m.isResolved());
-+                m.resolution = ex;
-+                return m;
-+            }
-+            assert(m.referenceKindIsConsistent());
-+            m.initResolved(true);
-+            assert(m.vminfoIsConsistent());
-+            return m;
-         }
-         /** Produce a resolved version of the given member.
-          *  Super types are searched (for inherited members) if {@code searchSupers} is true.
-@@ -649,16 +862,29 @@
-          */
-         public
-         <NoSuchMemberException extends ReflectiveOperationException>
--        MemberName resolveOrFail(MemberName m, boolean searchSupers, Class<?> lookupClass,
-+        MemberName resolveOrFail(byte refKind, MemberName m, Class<?> lookupClass,
-                                  Class<NoSuchMemberException> nsmClass)
-                 throws IllegalAccessException, NoSuchMemberException {
--            MemberName result = resolveOrNull(m, searchSupers, lookupClass);
--            if (result != null)
-+            MemberName result = resolve(refKind, m, lookupClass);
-+            if (result.isResolved())
-                 return result;
--            ReflectiveOperationException ex = m.makeAccessException();
-+            ReflectiveOperationException ex = result.makeAccessException();
-             if (ex instanceof IllegalAccessException)  throw (IllegalAccessException) ex;
-             throw nsmClass.cast(ex);
-         }
-+        /** Produce a resolved version of the given member.
-+         *  Super types are searched (for inherited members) if {@code searchSupers} is true.
-+         *  Access checking is performed on behalf of the given {@code lookupClass}.
-+         *  If lookup fails or access is not permitted, return null.
-+         *  Otherwise a fresh copy of the given member is returned, with modifier bits filled in.
-+         */
-+        public
-+        MemberName resolveOrNull(byte refKind, MemberName m, Class<?> lookupClass) {
-+            MemberName result = resolve(refKind, m, lookupClass);
-+            if (result.isResolved())
-+                return result;
-+            return null;
-+        }
-         /** Return a list of all methods defined by the given class.
-          *  Super types are searched (for inherited members) if {@code searchSupers} is true.
-          *  Access checking is performed on behalf of the given {@code lookupClass}.
-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
-@@ -26,9 +26,13 @@
- package java.lang.invoke;
- 
- 
--import java.util.ArrayList;
--import sun.invoke.util.ValueConversions;
-+import java.util.*;
-+import sun.invoke.util.*;
-+import sun.misc.Unsafe;
-+
- import static java.lang.invoke.MethodHandleStatics.*;
-+import java.util.logging.Level;
-+import java.util.logging.Logger;
- 
- /**
-  * A method handle is a typed, directly executable reference to an underlying method,
-@@ -208,8 +212,8 @@
-  * refers directly to an associated {@code CONSTANT_Methodref},
-  * {@code CONSTANT_InterfaceMethodref}, or {@code CONSTANT_Fieldref}
-  * constant pool entry.
-- * (For more details on method handle constants,
-- * see the <a href="package-summary.html#mhcon">package summary</a>.)
-+ * (For full details on method handle constants,
-+ * see sections 4.4.8 and 5.4.3.5 of the Java Virtual Machine Specification.)
-  * <p>
-  * Method handles produced by lookups or constant loads from methods or
-  * constructors with the variable arity modifier bit ({@code 0x0080})
-@@ -224,6 +228,19 @@
-  * (E.g., if a non-static method handle is obtained via {@code ldc},
-  * the type of the receiver is the class named in the constant pool entry.)
-  * <p>
-+ * Method handle constants are subject to the same link-time access checks
-+ * their corresponding bytecode instructions, and the {@code ldc} instruction
-+ * will throw corresponding linkage errors if the bytecode behaviors would
-+ * throw such errors.
-+ * <p>
-+ * As a corollary of this, access to protected members is restricted
-+ * to receivers only of the accessing class, or one of its subclasses,
-+ * and the accessing class must in turn be a subclass (or package sibling)
-+ * of the protected member's defining class.
-+ * If a method reference refers to a protected non-static method or field
-+ * of a class outside the current package, the receiver argument will
-+ * be narrowed to the type of the accessing class.
-+ * <p>
-  * When a method handle to a virtual method is invoked, the method is
-  * always looked up in the receiver (that is, the first argument).
-  * <p>
-@@ -390,39 +407,8 @@
-  * @author John Rose, JSR 292 EG
-  */
- public abstract class MethodHandle {
--    // { JVM internals:
--
--    private byte       vmentry;    // adapter stub or method entry point
--    //private int      vmslots;    // optionally, hoist type.form.vmslots
--    /*non-public*/ Object vmtarget;   // VM-specific, class-specific target value
--
--    // TO DO:  vmtarget should be invisible to Java, since the JVM puts internal
--    // managed pointers into it.  Making it visible exposes it to debuggers,
--    // which can cause errors when they treat the pointer as an Object.
--
--    // These two dummy fields are present to force 'I' and 'J' signatures
--    // into this class's constant pool, so they can be transferred
--    // to vmentry when this class is loaded.
--    static final int  INT_FIELD = 0;
--    static final long LONG_FIELD = 0;
--
--    // vmentry (a void* field) is used *only* by the JVM.
--    // The JVM adjusts its type to int or long depending on system wordsize.
--    // Since it is statically typed as neither int nor long, it is impossible
--    // to use this field from Java bytecode.  (Please don't try to, either.)
--
--    // The vmentry is an assembly-language stub which is jumped to
--    // immediately after the method type is verified.
--    // For a direct MH, this stub loads the vmtarget's entry point
--    // and jumps to it.
--
--    // } End of JVM internals.
--
-     static { MethodHandleImpl.initStatics(); }
- 
--    // interface MethodHandle<R throws X extends Exception,A...>
--    // { MethodType<R throws X,A...> type(); public R invokeExact(A...) throws X; }
--
-     /**
-      * Internal marker interface which distinguishes (to the Java compiler)
-      * those methods which are <a href="MethodHandle.html#sigpoly">signature polymorphic</a>.
-@@ -431,7 +417,9 @@
-     @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
-     @interface PolymorphicSignature { }
- 
--    private MethodType type;
-+    private final MethodType type;
-+    /*private*/ final LambdaForm form;
-+    // form is not private so that invokers can easily fetch it
- 
-     /**
-      * Reports the type of this method handle.
-@@ -448,9 +436,13 @@
-      * the {@code java.lang.invoke} package.
-      */
-     // @param type type (permanently assigned) of the new method handle
--    /*non-public*/ MethodHandle(MethodType type) {
--        type.getClass();  // elicit NPE
-+    /*non-public*/ MethodHandle(MethodType type, LambdaForm form) {
-+        type.getClass();  // explicit NPE
-+        form.getClass();  // explicit NPE
-         this.type = type;
-+        this.form = form;
-+
-+        form.prepare();  // TO DO:  Try to delay this step until just before invocation.
-     }
- 
-     /**
-@@ -506,6 +498,46 @@
-     public final native @PolymorphicSignature Object invoke(Object... args) throws Throwable;
- 
-     /**
-+     * Private method for trusted invocation of a method handle respecting simplified signatures.
-+     * Type mismatches will not throw {@code WrongMethodTypeException}, but could crash the JVM.
-+     * <p>
-+     * The caller signature is restricted to the following basic types:
-+     * Object, int, long, float, double, and void return.
-+     * <p>
-+     * The caller is responsible for maintaining type correctness by ensuring
-+     * that the each outgoing argument value is a member of the range of the corresponding
-+     * callee argument type.
-+     * (The caller should therefore issue appropriate casts and integer narrowing
-+     * operations on outgoing argument values.)
-+     * The caller can assume that the incoming result value is part of the range
-+     * of the callee's return type.
-+     */
-+    /*non-public*/ final native @PolymorphicSignature Object invokeBasic(Object... args) throws Throwable;
-+
-+    /*non-public*/ static native @PolymorphicSignature Object linkToVirtual(Object... args) throws Throwable;
-+
-+    /**
-+     * Private method for trusted invocation of a MemberName of kind {@code REF_invokeStatic}.
-+     * The caller signature is restricted to basic types as with {@code invokeBasic}.
-+     * The trailing (not leading) argument must be a MemberName.
-+     */
-+    /*non-public*/ static native @PolymorphicSignature Object linkToStatic(Object... args) throws Throwable;
-+
-+    /**
-+     * Private method for trusted invocation of a MemberName of kind {@code REF_invokeSpecial}.
-+     * The caller signature is restricted to basic types as with {@code invokeBasic}.
-+     * The trailing (not leading) argument must be a MemberName.
-+     */
-+    /*non-public*/ static native @PolymorphicSignature Object linkToSpecial(Object... args) throws Throwable;
-+
-+    /**
-+     * Private method for trusted invocation of a MemberName of kind {@code REF_invokeInterface}.
-+     * The caller signature is restricted to basic types as with {@code invokeBasic}.
-+     * The trailing (not leading) argument must be a MemberName.
-+     */
-+    /*non-public*/ static native @PolymorphicSignature Object linkToInterface(Object... args) throws Throwable;
-+
-+    /**
-      * Performs a variable arity invocation, passing the arguments in the given array
-      * to the method handle, as if via an inexact {@link #invoke invoke} from a call site
-      * which mentions only the type {@code Object}, and whose arity is the length
-@@ -557,6 +589,7 @@
-      */
-     public Object invokeWithArguments(Object... arguments) throws Throwable {
-         int argc = arguments == null ? 0 : arguments.length;
-+        @SuppressWarnings("LocalVariableHidesMemberVariable")
-         MethodType type = type();
-         if (type.parameterCount() != argc || isVarargsCollector()) {
-             // simulate invoke
-@@ -690,7 +723,7 @@
-         if (!type.isConvertibleTo(newType)) {
-             throw new WrongMethodTypeException("cannot convert "+this+" to "+newType);
-         }
--        return MethodHandleImpl.convertArguments(this, newType, 1);
-+        return convertArguments(newType);
-     }
- 
-     /**
-@@ -772,7 +805,8 @@
-      */
-     public MethodHandle asSpreader(Class<?> arrayType, int arrayLength) {
-         asSpreaderChecks(arrayType, arrayLength);
--        return MethodHandleImpl.spreadArguments(this, arrayType, arrayLength);
-+        int spreadArgPos = type.parameterCount() - arrayLength;
-+        return MethodHandleImpl.makeSpreadArguments(this, arrayType, spreadArgPos, arrayLength);
-     }
- 
-     private void asSpreaderChecks(Class<?> arrayType, int arrayLength) {
-@@ -790,7 +824,7 @@
-                 }
-             }
-             if (sawProblem) {
--                ArrayList<Class<?>> ptypes = new ArrayList<Class<?>>(type().parameterList());
-+                ArrayList<Class<?>> ptypes = new ArrayList<>(type().parameterList());
-                 for (int i = nargs - arrayLength; i < nargs; i++) {
-                     ptypes.set(i, arrayElement);
-                 }
-@@ -885,8 +919,12 @@
-      */
-     public MethodHandle asCollector(Class<?> arrayType, int arrayLength) {
-         asCollectorChecks(arrayType, arrayLength);
-+        int collectArgPos = type().parameterCount()-1;
-+        MethodHandle target = this;
-+        if (arrayType != type().parameterType(collectArgPos))
-+            target = convertArguments(type().changeParameterType(collectArgPos, arrayType));
-         MethodHandle collector = ValueConversions.varargsArray(arrayType, arrayLength);
--        return MethodHandleImpl.collectArguments(this, type.parameterCount()-1, collector);
-+        return MethodHandleImpl.makeCollectArguments(target, collector, collectArgPos, false);
-     }
- 
-     // private API: return true if last param exactly matches arrayType
-@@ -1056,7 +1094,7 @@
-         boolean lastMatch = asCollectorChecks(arrayType, 0);
-         if (isVarargsCollector() && lastMatch)
-             return this;
--        return AdapterMethodHandle.makeVarargsCollector(this, arrayType);
-+        return MethodHandleImpl.makeVarargsCollector(this, arrayType);
-     }
- 
-     /**
-@@ -1155,14 +1193,13 @@
-      */
-     public MethodHandle bindTo(Object x) {
-         Class<?> ptype;
--        if (type().parameterCount() == 0 ||
--            (ptype = type().parameterType(0)).isPrimitive())
-+        @SuppressWarnings("LocalVariableHidesMemberVariable")
-+        MethodType type = type();
-+        if (type.parameterCount() == 0 ||
-+            (ptype = type.parameterType(0)).isPrimitive())
-             throw newIllegalArgumentException("no leading reference parameter", x);
--        x = MethodHandles.checkValue(ptype, x);
--        // Cf. MethodHandles.insertArguments for the following logic:
--        MethodHandle bmh = MethodHandleImpl.bindReceiver(this, x);
--        if (bmh != null)  return bmh;
--        return MethodHandleImpl.bindArgument(this, 0, x);
-+        x = ptype.cast(x);  // throw CCE if needed
-+        return bindReceiver(x);
-     }
- 
-     /**
-@@ -1183,11 +1220,178 @@
-     @Override
-     public String toString() {
-         if (DEBUG_METHOD_HANDLE_NAMES)  return debugString();
-+        return standardString();
-+    }
-+    String standardString() {
-         return "MethodHandle"+type;
-     }
-+    String debugString() {
-+        return standardString()+"="+internalForm()+internalValues();
-+    }
-+
-+    //// Implementation methods.
-+    //// Sub-classes can override these default implementations.
-+    //// All these methods assume arguments are already validated.
-+
-+    // Other transforms to do:  convert, explicitCast, permute, drop, filter, fold, GWT, catch
-+
-+    /*non-public*/
-+    MethodHandle setVarargs(MemberName member) throws IllegalAccessException {
-+        if (!member.isVarargs())  return this;
-+        int argc = type().parameterCount();
-+        if (argc != 0) {
-+            Class<?> arrayType = type().parameterType(argc-1);
-+            if (arrayType.isArray()) {
-+                return MethodHandleImpl.makeVarargsCollector(this, arrayType);
-+            }
-+        }
-+        throw member.makeAccessException("cannot make variable arity", null);
-+    }
-+    /*non-public*/
-+    MethodHandle viewAsType(MethodType newType) {
-+        // No actual conversions, just a new view of the same method.
-+        if (!type.isViewableAs(newType))
-+            throw new InternalError();
-+        return MethodHandleImpl.makePairwiseConvert(this, newType, 0);
-+    }
-+
-+    // Decoding
-+
-+    /*non-public*/
-+    LambdaForm internalForm() {
-+        return form;
-+    }
- 
-     /*non-public*/
--    String debugString() {
--        return getNameString(this);
-+    MemberName internalMemberName() {
-+        return null;  // DMH returns DMH.member
-+    }
-+
-+    /*non-public*/
-+    Object internalValues() {
-+        return "";
-+    }
-+
-+    //// Method handle implementation methods.
-+    //// Sub-classes can override these default implementations.
-+    //// All these methods assume arguments are already validated.
-+
-+    /*non-public*/ MethodHandle convertArguments(MethodType newType) {
-+        // Override this if it can be improved.
-+        return MethodHandleImpl.makePairwiseConvert(this, newType, 1);
-+    }
-+
-+    /*non-public*/
-+    MethodHandle bindArgument(int pos, char basicType, Object value) {
-+        // Override this if it can be improved.
-+        return rebind().bindArgument(pos, basicType, value);
-+    }
-+
-+    /*non-public*/
-+    MethodHandle bindReceiver(Object receiver) {
-+        // Override this if it can be improved.
-+        return bindArgument(0, 'L', receiver);
-+    }
-+
-+    /*non-public*/
-+    MethodHandle bindImmediate(int pos, char basicType, Object value) {
-+        // Bind an immediate value to a position in the arguments.
-+        // This means, elide the respective argument,
-+        // and replace all references to it in NamedFunction args with the specified value.
-+
-+        // CURRENT RESTRICTIONS
-+        // * only for pos 0 and UNSAFE (position is adjusted in MHImpl to make API usable for others)
-+        assert pos == 0 && basicType == 'L' && value instanceof Unsafe;
-+        MethodType type2 = type.dropParameterTypes(pos, pos + 1); // adjustment: ignore receiver!
-+        LambdaForm form2 = form.bindImmediate(pos + 1, basicType, value); // adjust pos to form-relative pos
-+        return copyWith(type2, form2);
-+    }
-+
-+    /*non-public*/
-+    MethodHandle copyWith(MethodType mt, LambdaForm lf) {
-+        throw new InternalError("copyWith: " + this.getClass());
-+    }
-+
-+    /*non-public*/
-+    MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
-+        // Override this if it can be improved.
-+        return rebind().dropArguments(srcType, pos, drops);
-+    }
-+
-+    /*non-public*/
-+    MethodHandle permuteArguments(MethodType newType, int[] reorder) {
-+        // Override this if it can be improved.
-+        return rebind().permuteArguments(newType, reorder);
-+    }
-+
-+    /*non-public*/
-+    MethodHandle rebind() {
-+        // Bind 'this' into a new invoker, of the known class BMH.
-+        MethodType type2 = type();
-+        LambdaForm form2 = reinvokerForm(type2.basicType());
-+        // form2 = lambda (bmh, arg*) { thismh = bmh[0]; invokeBasic(thismh, arg*) }
-+        return BoundMethodHandle.bindSingle(type2, form2, this);
-+    }
-+
-+    /*non-public*/
-+    MethodHandle reinvokerTarget() {
-+        throw new InternalError("not a reinvoker MH: "+this.getClass().getName()+": "+this);
-+    }
-+
-+    /** Create a LF which simply reinvokes a target of the given basic type.
-+     *  The target MH must override {@link #reinvokerTarget} to provide the target.
-+     */
-+    static LambdaForm reinvokerForm(MethodType mtype) {
-+        mtype = mtype.basicType();
-+        LambdaForm reinvoker = mtype.form().cachedLambdaForm(MethodTypeForm.LF_REINVOKE);
-+        if (reinvoker != null)  return reinvoker;
-+        MethodHandle MH_invokeBasic = MethodHandles.basicInvoker(mtype);
-+        final int THIS_BMH    = 0;
-+        final int ARG_BASE    = 1;
-+        final int ARG_LIMIT   = ARG_BASE + mtype.parameterCount();
-+        int nameCursor = ARG_LIMIT;
-+        final int NEXT_MH     = nameCursor++;
-+        final int REINVOKE    = nameCursor++;
-+        LambdaForm.Name[] names = LambdaForm.arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
-+        names[NEXT_MH] = new LambdaForm.Name(NF_reinvokerTarget, names[THIS_BMH]);
-+        Object[] targetArgs = Arrays.copyOfRange(names, THIS_BMH, ARG_LIMIT, Object[].class);
-+        targetArgs[0] = names[NEXT_MH];  // overwrite this MH with next MH
-+        names[REINVOKE] = new LambdaForm.Name(MH_invokeBasic, targetArgs);
-+        return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_REINVOKE, new LambdaForm("BMH.reinvoke", ARG_LIMIT, names));
-+    }
-+
-+    private static final LambdaForm.NamedFunction NF_reinvokerTarget;
-+    static {
-+        try {
-+            NF_reinvokerTarget = new LambdaForm.NamedFunction(MethodHandle.class
-+                .getDeclaredMethod("reinvokerTarget"));
-+        } catch (ReflectiveOperationException ex) {
-+            throw new InternalError(ex);
-+        }
-+    }
-+
-+    /**
-+     * Replace the old lambda form of this method handle with a new one.
-+     * The new one must be functionally equivalent to the old one.
-+     * Threads may continue running the old form indefinitely,
-+     * but it is likely that the new one will be preferred for new executions.
-+     * Use with discretion.
-+     * @param newForm
-+     */
-+    /*non-public*/
-+    void updateForm(LambdaForm newForm) {
-+        if (form == newForm)  return;
-+        // ISSUE: Should we have a memory fence here?
-+        UNSAFE.putObject(this, FORM_OFFSET, newForm);
-+        this.form.prepare();  // as in MethodHandle.<init>
-+    }
-+
-+    private static final long FORM_OFFSET;
-+    static {
-+        try {
-+            FORM_OFFSET = UNSAFE.objectFieldOffset(MethodHandle.class.getDeclaredField("form"));
-+        } catch (ReflectiveOperationException ex) {
-+            throw new InternalError(ex);
-+        }
-     }
- }
-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
-@@ -26,17 +26,14 @@
- package java.lang.invoke;
- 
- import sun.invoke.util.VerifyType;
--import java.security.AccessController;
--import java.security.PrivilegedAction;
-+
- import java.util.ArrayList;
- import java.util.Arrays;
--import java.util.Collections;
- import java.util.HashMap;
--import java.util.List;
- import sun.invoke.empty.Empty;
- import sun.invoke.util.ValueConversions;
- import sun.invoke.util.Wrapper;
--import sun.misc.Unsafe;
-+import static java.lang.invoke.LambdaForm.*;
- import static java.lang.invoke.MethodHandleStatics.*;
- import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
- 
-@@ -47,673 +44,471 @@
- /*non-public*/ abstract class MethodHandleImpl {
-     /// Factory methods to create method handles:
- 
--    private static final MemberName.Factory LOOKUP = MemberName.Factory.INSTANCE;
--
-     static void initStatics() {
--        // Trigger preceding sequence.
-+        // Trigger selected static initializations.
-+        MemberName.Factory.INSTANCE.getClass();
-     }
- 
--    /** Look up a given method.
--     * Callable only from sun.invoke and related packages.
--     * <p>
--     * The resulting method handle type will be of the given type,
--     * with a receiver type {@code rcvc} prepended if the member is not static.
--     * <p>
--     * Access checks are made as of the given lookup class.
--     * In particular, if the method is protected and {@code defc} is in a
--     * different package from the lookup class, then {@code rcvc} must be
--     * the lookup class or a subclass.
--     * @param token Proof that the lookup class has access to this package.
--     * @param member Resolved method or constructor to call.
--     * @param name Name of the desired method.
--     * @param rcvc Receiver type of desired non-static method (else null)
--     * @param doDispatch whether the method handle will test the receiver type
--     * @param lookupClass access-check relative to this class
--     * @return a direct handle to the matching method
--     * @throws IllegalAccessException if the given method cannot be accessed by the lookup class
--     */
--    static
--    MethodHandle findMethod(MemberName method,
--                            boolean doDispatch, Class<?> lookupClass) throws IllegalAccessException {
--        MethodType mtype = method.getMethodType();
--        if (!method.isStatic()) {
--            // adjust the advertised receiver type to be exactly the one requested
--            // (in the case of invokespecial, this will be the calling class)
--            Class<?> recvType = method.getDeclaringClass();
--            mtype = mtype.insertParameterTypes(0, recvType);
-+    static MethodHandle makeArrayElementAccessor(Class<?> arrayClass, boolean isSetter) {
-+        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 = new SimpleMethodHandle(srcType, form);
-+        if (ArrayAccessor.needCast(arrayClass)) {
-+            mh = mh.bindTo(arrayClass);
-         }
--        DirectMethodHandle mh = new DirectMethodHandle(mtype, method, doDispatch, lookupClass);
--        if (!mh.isValid())
--            throw method.makeAccessException("no direct method handle", lookupClass);
--        assert(mh.type() == mtype);
--        if (!method.isVarargs())
--            return mh;
--        int argc = mtype.parameterCount();
--        if (argc != 0) {
--            Class<?> arrayType = mtype.parameterType(argc-1);
--            if (arrayType.isArray())
--                return AdapterMethodHandle.makeVarargsCollector(mh, arrayType);
--        }
--        throw method.makeAccessException("cannot make variable arity", null);
-+        mh = mh.asType(ArrayAccessor.correctType(arrayClass, isSetter));
-+        return mh;
-     }
- 
--    static
--    MethodHandle makeAllocator(MethodHandle rawConstructor) {
--        MethodType rawConType = rawConstructor.type();
--        Class<?> allocateClass = rawConType.parameterType(0);
--        // Wrap the raw (unsafe) constructor with the allocation of a suitable object.
--        assert(AdapterMethodHandle.canCollectArguments(rawConType, MethodType.methodType(allocateClass), 0, true));
--        // allocator(arg...)
--        // [fold]=> cookedConstructor(obj=allocate(C), arg...)
--        // [dup,collect]=> identity(obj, void=rawConstructor(obj, arg...))
--        MethodHandle returner = MethodHandles.identity(allocateClass);
--        MethodType ctype = rawConType.insertParameterTypes(0, allocateClass).changeReturnType(allocateClass);
--        MethodHandle  cookedConstructor = AdapterMethodHandle.makeCollectArguments(returner, rawConstructor, 1, false);
--        assert(cookedConstructor.type().equals(ctype));
--        ctype = ctype.dropParameterTypes(0, 1);
--        cookedConstructor = AdapterMethodHandle.makeCollectArguments(cookedConstructor, returner, 0, true);
--        AllocateObject allocator = new AllocateObject(allocateClass);
--        // allocate() => new C(void)
--        assert(allocator.type().equals(MethodType.methodType(allocateClass)));
--        ctype = ctype.dropParameterTypes(0, 1);
--        MethodHandle fold = foldArguments(cookedConstructor, ctype, 0, allocator);
--        return fold;
--    }
-+    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 class AllocateObject /*<C>*/ extends BoundMethodHandle {
--        private static final Unsafe unsafe = Unsafe.getUnsafe();
-+        static int     getElementI(int[]     a, int i)            { return              a[i]; }
-+        static long    getElementJ(long[]    a, int i)            { return              a[i]; }
-+        static float   getElementF(float[]   a, int i)            { return              a[i]; }
-+        static double  getElementD(double[]  a, int i)            { return              a[i]; }
-+        static boolean getElementZ(boolean[] a, int i)            { return              a[i]; }
-+        static byte    getElementB(byte[]    a, int i)            { return              a[i]; }
-+        static short   getElementS(short[]   a, int i)            { return              a[i]; }
-+        static char    getElementC(char[]    a, int i)            { return              a[i]; }
-+        static Object  getElementL(Object[]  a, int i)            { return              a[i]; }
- 
--        private final Class<?> /*<C>*/ allocateClass;
-+        static void    setElementI(int[]     a, int i, int     x) {              a[i] = x; }
-+        static void    setElementJ(long[]    a, int i, long    x) {              a[i] = x; }
-+        static void    setElementF(float[]   a, int i, float   x) {              a[i] = x; }
-+        static void    setElementD(double[]  a, int i, double  x) {              a[i] = x; }
-+        static void    setElementZ(boolean[] a, int i, boolean x) {              a[i] = x; }
-+        static void    setElementB(byte[]    a, int i, byte    x) {              a[i] = x; }
-+        static void    setElementS(short[]   a, int i, short   x) {              a[i] = x; }
-+        static void    setElementC(char[]    a, int i, char    x) {              a[i] = x; }
-+        static void    setElementL(Object[]  a, int i, Object  x) {              a[i] = x; }
- 
--        // for allocation only:
--        private AllocateObject(Class<?> /*<C>*/ allocateClass) {
--            super(ALLOCATE.asType(MethodType.methodType(allocateClass, AllocateObject.class)));
--            this.allocateClass = allocateClass;
-+        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;
-         }
--        @SuppressWarnings("unchecked")
--        private Object /*C*/ allocate() throws InstantiationException {
--            return unsafe.allocateInstance(allocateClass);
-+        static String name(Class<?> arrayClass, boolean isSetter) {
-+            Class<?> elemClass = arrayClass.getComponentType();
-+            if (elemClass == null)  throw new IllegalArgumentException();
-+            return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(elemClass);
-         }
--        static final MethodHandle ALLOCATE;
--        static {
-+        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;
-+            }
-+            if (!needCast(arrayClass)) {
-+                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();
-+            return !isSetter ?
-+                    MethodType.methodType(elemClass,  arrayClass, int.class) :
-+                    MethodType.methodType(void.class, arrayClass, int.class, elemClass);
-+        }
-+        static MethodHandle getAccessor(Class<?> arrayClass, boolean isSetter) {
-+            String     name = name(arrayClass, isSetter);
-+            MethodType type = type(arrayClass, isSetter);
-             try {
--                ALLOCATE = IMPL_LOOKUP.findVirtual(AllocateObject.class, "allocate", MethodType.genericMethodType(0));
-+                return IMPL_LOOKUP.findStatic(ArrayAccessor.class, name, type);
-             } catch (ReflectiveOperationException ex) {
-                 throw uncaughtException(ex);
-             }
-         }
-     }
- 
--    static
--    MethodHandle accessField(MemberName member, boolean isSetter,
--                             Class<?> lookupClass) {
--        // Use sun. misc.Unsafe to dig up the dirt on the field.
--        FieldAccessor accessor = new FieldAccessor(member, isSetter);
--        return accessor;
-+    /**
-+     * Create a JVM-level adapter method handle to conform the given method
-+     * handle to the similar newType, using only pairwise argument conversions.
-+     * For each argument, convert incoming argument to the exact type needed.
-+     * The argument conversions allowed are casting, boxing and unboxing,
-+     * integral widening or narrowing, and floating point widening or narrowing.
-+     * @param srcType required call type
-+     * @param target original method handle
-+     * @param level which strength of conversion is allowed
-+     * @return an adapter to the original handle with the desired new type,
-+     *          or the original target if the types are already identical
-+     *          or null if the adaptation cannot be made
-+     */
-+    static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType, int level) {
-+        assert(level >= 0 && level <= 2);
-+        MethodType dstType = target.type();
-+        assert(dstType.parameterCount() == target.type().parameterCount());
-+        if (srcType == dstType)
-+            return target;
-+
-+        // Calculate extra arguments (temporaries) required in the names array.
-+        // FIXME: Use an ArrayList<Name>.  Some arguments require more than one conversion step.
-+        int extra = 0;
-+        for (int i = 0; i < srcType.parameterCount(); i++) {
-+            Class<?> src = srcType.parameterType(i);
-+            Class<?> dst = dstType.parameterType(i);
-+            if (!VerifyType.isNullConversion(src, dst)) {
-+                extra++;
-+            }
-+        }
-+
-+        Class<?> needReturn = srcType.returnType();
-+        Class<?> haveReturn = dstType.returnType();
-+        boolean retConv = !VerifyType.isNullConversion(haveReturn, needReturn);
-+
-+        // Now build a LambdaForm.
-+        MethodType lambdaType = srcType.invokerType();
-+        Name[] names = arguments(extra + 1, lambdaType);
-+        int[] indexes = new int[lambdaType.parameterCount()];
-+
-+        MethodType midType = dstType;
-+        for (int i = 0, argIndex = 1, tmpIndex = lambdaType.parameterCount(); i < srcType.parameterCount(); i++, argIndex++) {
-+            Class<?> src = srcType.parameterType(i);
-+            Class<?> dst = midType.parameterType(i);
-+
-+            if (VerifyType.isNullConversion(src, dst)) {
-+                // do nothing: difference is trivial
-+                indexes[i] = argIndex;
-+                continue;
-+            }
-+
-+            // Work the current type backward toward the desired caller type:
-+            midType = midType.changeParameterType(i, src);
-+
-+            // Tricky case analysis follows.
-+            MethodHandle fn = null;
-+            if (src.isPrimitive()) {
-+                if (dst.isPrimitive()) {
-+                    fn = ValueConversions.convertPrimitive(src, dst);
-+                } else {
-+                    Wrapper w = Wrapper.forPrimitiveType(src);
-+                    MethodHandle boxMethod = ValueConversions.box(w);
-+                    if (dst == w.wrapperType())
-+                        fn = boxMethod;
-+                    else
-+                        fn = boxMethod.asType(MethodType.methodType(dst, src));
-+                }
-+            } else {
-+                if (dst.isPrimitive()) {
-+                    // Caller has boxed a primitive.  Unbox it for the target.
-+                    Wrapper w = Wrapper.forPrimitiveType(dst);
-+                    if (level == 0 || VerifyType.isNullConversion(src, w.wrapperType())) {
-+                        fn = ValueConversions.unbox(dst);
-+                    } else if (src == Object.class || !Wrapper.isWrapperType(src)) {
-+                        // Examples:  Object->int, Number->int, Comparable->int; Byte->int, Character->int
-+                        // must include additional conversions
-+                        // src must be examined at runtime, to detect Byte, Character, etc.
-+                        MethodHandle unboxMethod = (level == 1
-+                                                    ? ValueConversions.unbox(dst)
-+                                                    : ValueConversions.unboxCast(dst));
-+                        fn = unboxMethod;
-+                    } else {
-+                        // Example: Byte->int
-+                        // Do this by reformulating the problem to Byte->byte.
-+                        Class<?> srcPrim = Wrapper.forWrapperType(src).primitiveType();
-+                        MethodHandle unbox = ValueConversions.unbox(srcPrim);
-+                        // Compose the two conversions.  FIXME:  should make two Names for this job
-+                        fn = unbox.asType(MethodType.methodType(dst, src));
-+                    }
-+                } else {
-+                    // Simple reference conversion.
-+                    // Note:  Do not check for a class hierarchy relation
-+                    // between src and dst.  In all cases a 'null' argument
-+                    // will pass the cast conversion.
-+                    fn = ValueConversions.cast(dst);
-+                }
-+            }
-+            names[tmpIndex] = new Name(fn, names[argIndex]);
-+            indexes[i] = tmpIndex;
-+            tmpIndex++;
-+        }
-+        if (retConv) {
-+            MethodHandle adjustReturn;
-+            if (haveReturn == void.class) {
-+                // synthesize a zero value for the given void
-+                Object zero = Wrapper.forBasicType(needReturn).zero();
-+                adjustReturn = MethodHandles.constant(needReturn, zero);
-+            } else {
-+                MethodHandle identity = MethodHandles.identity(needReturn);
-+                MethodType needConversion = identity.type().changeParameterType(0, haveReturn);
-+                adjustReturn = makePairwiseConvert(identity, needConversion, level);
-+            }
-+            target = makeCollectArguments(adjustReturn, target, 0, false);
-+        }
-+
-+        // Build argument array for the call.
-+        Name[] targetArgs = new Name[dstType.parameterCount()];
-+        for (int i = 0; i < dstType.parameterCount(); i++) {
-+            int idx = indexes[i];
-+            targetArgs[i] = names[idx];
-+        }
-+        names[names.length - 1] = new Name(target, (Object[]) targetArgs);
-+        LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names);
-+        return new SimpleMethodHandle(srcType, form);
-     }
- 
--    static
--    MethodHandle accessArrayElement(Class<?> arrayClass, boolean isSetter) {
--        if (!arrayClass.isArray())
--            throw newIllegalArgumentException("not an array: "+arrayClass);
--        Class<?> elemClass = arrayClass.getComponentType();
--        MethodHandle[] mhs = FieldAccessor.ARRAY_CACHE.get(elemClass);
--        if (mhs == null) {
--            if (!FieldAccessor.doCache(elemClass))
--                return FieldAccessor.ahandle(arrayClass, isSetter);
--            mhs = new MethodHandle[] {
--                FieldAccessor.ahandle(arrayClass, false),
--                FieldAccessor.ahandle(arrayClass, true)
--            };
--            if (mhs[0].type().parameterType(0) == Class.class) {
--                mhs[0] = mhs[0].bindTo(elemClass);
--                mhs[1] = mhs[1].bindTo(elemClass);
--            }
--            synchronized (FieldAccessor.ARRAY_CACHE) {}  // memory barrier
--            FieldAccessor.ARRAY_CACHE.put(elemClass, mhs);
--        }
--        return mhs[isSetter ? 1 : 0];
-+    static MethodHandle makeReferenceIdentity(Class<?> refType) {
-+        MethodType lambdaType = MethodType.genericMethodType(1).invokerType();
-+        Name[] names = arguments(1, lambdaType);
-+        names[names.length - 1] = new Name(ValueConversions.identity(), names[1]);
-+        LambdaForm form = new LambdaForm("identity", lambdaType.parameterCount(), names);
-+        return new SimpleMethodHandle(MethodType.methodType(refType, refType), form);
-     }
- 
--    static final class FieldAccessor /*<C,V>*/ extends BoundMethodHandle {
--        private static final Unsafe unsafe = Unsafe.getUnsafe();
--        final Object base;  // for static refs only
--        final long offset;
--        final String name;
-+    static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) {
-+        MethodType type = target.type();
-+        int last = type.parameterCount() - 1;
-+        if (type.parameterType(last) != arrayType)
-+            target = target.asType(type.changeParameterType(last, arrayType));
-+        target = target.asFixedArity();  // make sure this attribute is turned off
-+        return new AsVarargsCollector(target, target.type(), arrayType);
-+    }
- 
--        FieldAccessor(MemberName field, boolean isSetter) {
--            super(fhandle(field.getDeclaringClass(), field.getFieldType(), isSetter, field.isStatic()));
--            this.offset = (long) field.getVMIndex();
--            this.name = field.getName();
--            this.base = staticBase(field);
--        }
--        @Override
--        String debugString() { return addTypeString(name, this); }
-+    static class AsVarargsCollector extends MethodHandle {
-+        MethodHandle target;
-+        final Class<?> arrayType;
-+        MethodHandle cache;
- 
--        private static Object nullCheck(Object obj) {
--            obj.getClass();  // NPE
--            return obj;
-+        AsVarargsCollector(MethodHandle target, MethodType type, Class<?> arrayType) {
-+            super(type, reinvokerForm(type));
-+            this.target = target;
-+            this.arrayType = arrayType;
-+            this.cache = target.asCollector(arrayType, 0);
-         }
- 
--        int getFieldI(Object /*C*/ obj) { return unsafe.getInt(nullCheck(obj), offset); }
--        void setFieldI(Object /*C*/ obj, int x) { unsafe.putInt(nullCheck(obj), offset, x); }
--        long getFieldJ(Object /*C*/ obj) { return unsafe.getLong(nullCheck(obj), offset); }
--        void setFieldJ(Object /*C*/ obj, long x) { unsafe.putLong(nullCheck(obj), offset, x); }
--        float getFieldF(Object /*C*/ obj) { return unsafe.getFloat(nullCheck(obj), offset); }
--        void setFieldF(Object /*C*/ obj, float x) { unsafe.putFloat(nullCheck(obj), offset, x); }
--        double getFieldD(Object /*C*/ obj) { return unsafe.getDouble(nullCheck(obj), offset); }
--        void setFieldD(Object /*C*/ obj, double x) { unsafe.putDouble(nullCheck(obj), offset, x); }
--        boolean getFieldZ(Object /*C*/ obj) { return unsafe.getBoolean(nullCheck(obj), offset); }
--        void setFieldZ(Object /*C*/ obj, boolean x) { unsafe.putBoolean(nullCheck(obj), offset, x); }
--        byte getFieldB(Object /*C*/ obj) { return unsafe.getByte(nullCheck(obj), offset); }
--        void setFieldB(Object /*C*/ obj, byte x) { unsafe.putByte(nullCheck(obj), offset, x); }
--        short getFieldS(Object /*C*/ obj) { return unsafe.getShort(nullCheck(obj), offset); }
--        void setFieldS(Object /*C*/ obj, short x) { unsafe.putShort(nullCheck(obj), offset, x); }
--        char getFieldC(Object /*C*/ obj) { return unsafe.getChar(nullCheck(obj), offset); }
--        void setFieldC(Object /*C*/ obj, char x) { unsafe.putChar(nullCheck(obj), offset, x); }
--        Object /*V*/ getFieldL(Object /*C*/ obj) { return unsafe.getObject(nullCheck(obj), offset); }
--        void setFieldL(Object /*C*/ obj, Object /*V*/ x) { unsafe.putObject(nullCheck(obj), offset, x); }
-+        @Override MethodHandle reinvokerTarget() { return target; }
- 
--        static Object staticBase(final MemberName field) {
--            if (!field.isStatic())  return null;
--            return AccessController.doPrivileged(new PrivilegedAction<Object>() {
--                    public Object run() {
--                        try {
--                            Class<?> c = field.getDeclaringClass();
--                            // FIXME:  Should not have to create 'f' to get this value.
--                            java.lang.reflect.Field f = c.getDeclaredField(field.getName());
--                            return unsafe.staticFieldBase(f);
--                        } catch (NoSuchFieldException ee) {
--                            throw uncaughtException(ee);
--                        }
--                    }
--                });
-+        @Override
-+        public boolean isVarargsCollector() {
-+            return true;
-         }
- 
--        int getStaticI() { return unsafe.getInt(base, offset); }
--        void setStaticI(int x) { unsafe.putInt(base, offset, x); }
--        long getStaticJ() { return unsafe.getLong(base, offset); }
--        void setStaticJ(long x) { unsafe.putLong(base, offset, x); }
--        float getStaticF() { return unsafe.getFloat(base, offset); }
--        void setStaticF(float x) { unsafe.putFloat(base, offset, x); }
--        double getStaticD() { return unsafe.getDouble(base, offset); }
--        void setStaticD(double x) { unsafe.putDouble(base, offset, x); }
--        boolean getStaticZ() { return unsafe.getBoolean(base, offset); }
--        void setStaticZ(boolean x) { unsafe.putBoolean(base, offset, x); }
--        byte getStaticB() { return unsafe.getByte(base, offset); }
--        void setStaticB(byte x) { unsafe.putByte(base, offset, x); }
--        short getStaticS() { return unsafe.getShort(base, offset); }
--        void setStaticS(short x) { unsafe.putShort(base, offset, x); }
--        char getStaticC() { return unsafe.getChar(base, offset); }
--        void setStaticC(char x) { unsafe.putChar(base, offset, x); }
--        Object /*V*/ getStaticL() { return unsafe.getObject(base, offset); }
--        void setStaticL(Object /*V*/ x) { unsafe.putObject(base, offset, x); }
--
--        static String fname(Class<?> vclass, boolean isSetter, boolean isStatic) {
--            String stem;
--            if (!isStatic)
--                stem = (!isSetter ? "getField" : "setField");
--            else
--                stem = (!isSetter ? "getStatic" : "setStatic");
--            return stem + Wrapper.basicTypeChar(vclass);
--        }
--        static MethodType ftype(Class<?> cclass, Class<?> vclass, boolean isSetter, boolean isStatic) {
--            MethodType type;
--            if (!isStatic) {
--                if (!isSetter)
--                    return MethodType.methodType(vclass, cclass);
--                else
--                    return MethodType.methodType(void.class, cclass, vclass);
--            } else {
--                if (!isSetter)
--                    return MethodType.methodType(vclass);
--                else
--                    return MethodType.methodType(void.class, vclass);
--            }
--        }
--        static MethodHandle fhandle(Class<?> cclass, Class<?> vclass, boolean isSetter, boolean isStatic) {
--            String name = FieldAccessor.fname(vclass, isSetter, isStatic);
--            if (cclass.isPrimitive())  throw newIllegalArgumentException("primitive "+cclass);
--            Class<?> ecclass = Object.class;  //erase this type
--            Class<?> evclass = vclass;
--            if (!evclass.isPrimitive())  evclass = Object.class;
--            MethodType type = FieldAccessor.ftype(ecclass, evclass, isSetter, isStatic);
--            MethodHandle mh;
--            try {
--                mh = IMPL_LOOKUP.findVirtual(FieldAccessor.class, name, type);
--            } catch (ReflectiveOperationException ex) {
--                throw uncaughtException(ex);
--            }
--            if (evclass != vclass || (!isStatic && ecclass != cclass)) {
--                MethodType strongType = FieldAccessor.ftype(cclass, vclass, isSetter, isStatic);
--                strongType = strongType.insertParameterTypes(0, FieldAccessor.class);
--                mh = convertArguments(mh, strongType, 0);
--            }
--            return mh;
-+        @Override
-+        public MethodHandle asFixedArity() {
-+            return target;
-         }
- 
--        /// Support for array element access
--        static final HashMap<Class<?>, MethodHandle[]> ARRAY_CACHE =
--                new HashMap<Class<?>, MethodHandle[]>();
--        // FIXME: Cache on the classes themselves, not here.
--        static boolean doCache(Class<?> elemClass) {
--            if (elemClass.isPrimitive())  return true;
--            ClassLoader cl = elemClass.getClassLoader();
--            return cl == null || cl == ClassLoader.getSystemClassLoader();
-+        @Override
-+        public MethodHandle asType(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);
-+            }
-+            // check cache
-+            if (cache.type().parameterCount() == newArity)
-+                return cache.asType(newType);
-+            // build and cache a collector
-+            int arrayLength = newArity - collectArg;
-+            MethodHandle collector;
-+            try {
-+                collector = asFixedArity().asCollector(arrayType, arrayLength);
-+            } catch (IllegalArgumentException ex) {
-+                throw new WrongMethodTypeException("cannot build collector");
-+            }
-+            cache = collector;
-+            return collector.asType(newType);
-         }
--        static int getElementI(int[] a, int i) { return a[i]; }
--        static void setElementI(int[] a, int i, int x) { a[i] = x; }
--        static long getElementJ(long[] a, int i) { return a[i]; }
--        static void setElementJ(long[] a, int i, long x) { a[i] = x; }
--        static float getElementF(float[] a, int i) { return a[i]; }
--        static void setElementF(float[] a, int i, float x) { a[i] = x; }
--        static double getElementD(double[] a, int i) { return a[i]; }
--        static void setElementD(double[] a, int i, double x) { a[i] = x; }
--        static boolean getElementZ(boolean[] a, int i) { return a[i]; }
--        static void setElementZ(boolean[] a, int i, boolean x) { a[i] = x; }
--        static byte getElementB(byte[] a, int i) { return a[i]; }
--        static void setElementB(byte[] a, int i, byte x) { a[i] = x; }
--        static short getElementS(short[] a, int i) { return a[i]; }
--        static void setElementS(short[] a, int i, short x) { a[i] = x; }
--        static char getElementC(char[] a, int i) { return a[i]; }
--        static void setElementC(char[] a, int i, char x) { a[i] = x; }
--        static Object getElementL(Object[] a, int i) { return a[i]; }
--        static void setElementL(Object[] a, int i, Object x) { a[i] = x; }
--        static <V> V getElementL(Class<V[]> aclass, V[] a, int i) { return aclass.cast(a)[i]; }
--        static <V> void setElementL(Class<V[]> aclass, V[] a, int i, V x) { aclass.cast(a)[i] = x; }
- 
--        static String aname(Class<?> aclass, boolean isSetter) {
--            Class<?> vclass = aclass.getComponentType();
--            if (vclass == null)  throw new IllegalArgumentException();
--            return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(vclass);
-+        @Override
-+        MethodHandle setVarargs(MemberName member) {
-+            if (member.isVarargs())  return this;
-+            return asFixedArity();
-         }
--        static MethodType atype(Class<?> aclass, boolean isSetter) {
--            Class<?> vclass = aclass.getComponentType();
--            if (!isSetter)
--                return MethodType.methodType(vclass, aclass, int.class);
--            else
--                return MethodType.methodType(void.class, aclass, int.class, vclass);
-+
-+        @Override
-+        MethodHandle viewAsType(MethodType newType) {
-+            MethodHandle mh = super.viewAsType(newType);
-+            // put back the varargs bit:
-+            MethodType type = mh.type();
-+            int arity = type.parameterCount();
-+            return mh.asVarargsCollector(type.parameterType(arity-1));
-         }
--        static MethodHandle ahandle(Class<?> aclass, boolean isSetter) {
--            Class<?> vclass = aclass.getComponentType();
--            String name = FieldAccessor.aname(aclass, isSetter);
--            Class<?> caclass = null;
--            if (!vclass.isPrimitive() && vclass != Object.class) {
--                caclass = aclass;
--                aclass = Object[].class;
--                vclass = Object.class;
--            }
--            MethodType type = FieldAccessor.atype(aclass, isSetter);
--            if (caclass != null)
--                type = type.insertParameterTypes(0, Class.class);
--            MethodHandle mh;
--            try {
--                mh = IMPL_LOOKUP.findStatic(FieldAccessor.class, name, type);
--            } catch (ReflectiveOperationException ex) {
--                throw uncaughtException(ex);
--            }
--            if (caclass != null) {
--                MethodType strongType = FieldAccessor.atype(caclass, isSetter);
--                mh = mh.bindTo(caclass);
--                mh = convertArguments(mh, strongType, 0);
--            }
--            return mh;
-+
-+        @Override
-+        MemberName internalMemberName() {
-+            return asFixedArity().internalMemberName();
-+        }
-+
-+
-+        @Override
-+        MethodHandle bindArgument(int pos, char basicType, Object value) {
-+            return asFixedArity().bindArgument(pos, basicType, value);
-+        }
-+
-+        @Override
-+        MethodHandle bindReceiver(Object receiver) {
-+            return asFixedArity().bindReceiver(receiver);
-+        }
-+
-+        @Override
-+        MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
-+            return asFixedArity().dropArguments(srcType, pos, drops);
-+        }
-+
-+        @Override
-+        MethodHandle permuteArguments(MethodType newType, int[] reorder) {
-+            return asFixedArity().permuteArguments(newType, reorder);
-         }
-     }
- 
--    /** Bind a predetermined first argument to the given direct method handle.
--     * Callable only from MethodHandles.
--     * @param token Proof that the caller has access to this package.
--     * @param target Any direct method handle.
--     * @param receiver Receiver (or first static method argument) to pre-bind.
--     * @return a BoundMethodHandle for the given DirectMethodHandle, or null if it does not exist
--     */
--    static
--    MethodHandle bindReceiver(MethodHandle target, Object receiver) {
--        if (receiver == null)  return null;
--        if (target instanceof AdapterMethodHandle &&
--            ((AdapterMethodHandle)target).conversionOp() == MethodHandleNatives.Constants.OP_RETYPE_ONLY
--            ) {
--            Object info = MethodHandleNatives.getTargetInfo(target);
--            if (info instanceof DirectMethodHandle) {
--                DirectMethodHandle dmh = (DirectMethodHandle) info;
--                if (dmh.type().parameterType(0).isAssignableFrom(receiver.getClass())) {
--                    MethodHandle bmh = new BoundMethodHandle(dmh, receiver, 0);
--                    MethodType newType = target.type().dropParameterTypes(0, 1);
--                    return convertArguments(bmh, newType, bmh.type(), 0);
-+    /** Factory method:  Spread selected argument. */
-+    static MethodHandle makeSpreadArguments(MethodHandle target,
-+                                            Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) {
-+        MethodType targetType = target.type();
-+
-+        for (int i = 0; i < spreadArgCount; i++) {
-+            Class<?> arg = VerifyType.spreadArgElementType(spreadArgType, i);
-+            if (arg == null)  arg = Object.class;
-+            targetType = targetType.changeParameterType(spreadArgPos + i, arg);
-+        }
-+        target = target.asType(targetType);
-+
-+        MethodType srcType = targetType
-+                .replaceParameterTypes(spreadArgPos, spreadArgPos + spreadArgCount, spreadArgType);
-+        // Now build a LambdaForm.
-+        MethodType lambdaType = srcType.invokerType();
-+        Name[] names = arguments(spreadArgCount + 2, lambdaType);
-+        int nameCursor = lambdaType.parameterCount();
-+        int[] indexes = new int[targetType.parameterCount()];
-+
-+        for (int i = 0, argIndex = 1; i < targetType.parameterCount() + 1; i++, argIndex++) {
-+            Class<?> src = lambdaType.parameterType(i);
-+            if (i == spreadArgPos) {
-+                // Spread the array.
-+                MethodHandle aload = MethodHandles.arrayElementGetter(spreadArgType);
-+                Name array = names[argIndex];
-+                names[nameCursor++] = new Name(NF_checkSpreadArgument, array, spreadArgCount);
-+                for (int j = 0; j < spreadArgCount; i++, j++) {
-+                    indexes[i] = nameCursor;
-+                    names[nameCursor++] = new Name(aload, array, j);
-                 }
-+            } else if (i < indexes.length) {
-+                indexes[i] = argIndex;
-             }
-         }
--        if (target instanceof DirectMethodHandle)
--            return new BoundMethodHandle((DirectMethodHandle)target, receiver, 0);
--        return null;   // let caller try something else
-+        assert(nameCursor == names.length-1);  // leave room for the final call
-+
-+        // Build argument array for the call.
-+        Name[] targetArgs = new Name[targetType.parameterCount()];
-+        for (int i = 0; i < targetType.parameterCount(); i++) {
-+            int idx = indexes[i];
-+            targetArgs[i] = names[idx];
-+        }
-+        names[names.length - 1] = new Name(target, (Object[]) targetArgs);
-+
-+        LambdaForm form = new LambdaForm("spread", lambdaType.parameterCount(), names);
-+        return new SimpleMethodHandle(srcType, form);
-     }
- 
--    /** Bind a predetermined argument to the given arbitrary method handle.
--     * Callable only from MethodHandles.
--     * @param token Proof that the caller has access to this package.
--     * @param target Any method handle.
--     * @param receiver Argument (which can be a boxed primitive) to pre-bind.
--     * @return a suitable BoundMethodHandle
--     */
--    static
--    MethodHandle bindArgument(MethodHandle target, int argnum, Object receiver) {
--        return new BoundMethodHandle(target, receiver, argnum);
-+    static void checkSpreadArgument(Object av, int n) {
-+        if (av == null) {
-+            if (n == 0)  return;
-+        } else if (av instanceof Object[]) {
-+            int len = ((Object[])av).length;
-+            if (len == n)  return;
-+        } else {
-+            int len = java.lang.reflect.Array.getLength(av);
-+            if (len == n)  return;
-+        }
-+        // fall through to error:
-+        throw newIllegalArgumentException("Array is not of length "+n);
-     }
- 
--    static MethodHandle permuteArguments(MethodHandle target,
--                                                MethodType newType,
--                                                MethodType oldType,
--                                                int[] permutationOrNull) {
--        assert(oldType.parameterCount() == target.type().parameterCount());
--        int outargs = oldType.parameterCount(), inargs = newType.parameterCount();
--        if (permutationOrNull.length != outargs)
--            throw newIllegalArgumentException("wrong number of arguments in permutation");
--        // Make the individual outgoing argument types match up first.
--        Class<?>[] callTypeArgs = new Class<?>[outargs];
--        for (int i = 0; i < outargs; i++)
--            callTypeArgs[i] = newType.parameterType(permutationOrNull[i]);
--        MethodType callType = MethodType.methodType(oldType.returnType(), callTypeArgs);
--        target = convertArguments(target, callType, oldType, 0);
--        assert(target != null);
--        oldType = target.type();
--        List<Integer> goal = new ArrayList<Integer>();  // i*TOKEN
--        List<Integer> state = new ArrayList<Integer>(); // i*TOKEN
--        List<Integer> drops = new ArrayList<Integer>(); // not tokens
--        List<Integer> dups = new ArrayList<Integer>();  // not tokens
--        final int TOKEN = 10; // to mark items which are symbolic only
--        // state represents the argument values coming into target
--        for (int i = 0; i < outargs; i++) {
--            state.add(permutationOrNull[i] * TOKEN);
-+    private static final NamedFunction NF_checkSpreadArgument;
-+    static {
-+        try {
-+            NF_checkSpreadArgument = new NamedFunction(MethodHandleImpl.class
-+                    .getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
-+            NF_checkSpreadArgument.resolve();
-+        } catch (ReflectiveOperationException ex) {
-+            throw new InternalError(ex);
-         }
--        // goal represents the desired state
--        for (int i = 0; i < inargs; i++) {
--            if (state.contains(i * TOKEN)) {
--                goal.add(i * TOKEN);
--            } else {
--                // adapter must initially drop all unused arguments
--                drops.add(i);
--            }
--        }
--        // detect duplications
--        while (state.size() > goal.size()) {
--            for (int i2 = 0; i2 < state.size(); i2++) {
--                int arg1 = state.get(i2);
--                int i1 = state.indexOf(arg1);
--                if (i1 != i2) {
--                    // found duplicate occurrence at i2
--                    int arg2 = (inargs++) * TOKEN;
--                    state.set(i2, arg2);
--                    dups.add(goal.indexOf(arg1));
--                    goal.add(arg2);
--                }
--            }
--        }
--        assert(state.size() == goal.size());
--        int size = goal.size();
--        while (!state.equals(goal)) {
--            // Look for a maximal sequence of adjacent misplaced arguments,
--            // and try to rotate them into place.
--            int bestRotArg = -10 * TOKEN, bestRotLen = 0;
--            int thisRotArg = -10 * TOKEN, thisRotLen = 0;
--            for (int i = 0; i < size; i++) {
--                int arg = state.get(i);
--                // Does this argument match the current run?
--                if (arg == thisRotArg + TOKEN) {
--                    thisRotArg = arg;
--                    thisRotLen += 1;
--                    if (bestRotLen < thisRotLen) {
--                        bestRotLen = thisRotLen;
--                        bestRotArg = thisRotArg;
--                    }
--                } else {
--                    // The old sequence (if any) stops here.
--                    thisRotLen = 0;
--                    thisRotArg = -10 * TOKEN;
--                    // But maybe a new one starts here also.
--                    int wantArg = goal.get(i);
--                    final int MAX_ARG_ROTATION = AdapterMethodHandle.MAX_ARG_ROTATION;
--                    if (arg != wantArg &&
--                        arg >= wantArg - TOKEN * MAX_ARG_ROTATION &&
--                        arg <= wantArg + TOKEN * MAX_ARG_ROTATION) {
--                        thisRotArg = arg;
--                        thisRotLen = 1;
--                    }
--                }
--            }
--            if (bestRotLen >= 2) {
--                // Do a rotation if it can improve argument positioning
--                // by at least 2 arguments.  This is not always optimal,
--                // but it seems to catch common cases.
--                int dstEnd = state.indexOf(bestRotArg);
--                int srcEnd = goal.indexOf(bestRotArg);
--                int rotBy = dstEnd - srcEnd;
--                int dstBeg = dstEnd - (bestRotLen - 1);
--                int srcBeg = srcEnd - (bestRotLen - 1);
--                assert((dstEnd | dstBeg | srcEnd | srcBeg) >= 0); // no negs
--                // Make a span which covers both source and destination.
--                int rotBeg = Math.min(dstBeg, srcBeg);
--                int rotEnd = Math.max(dstEnd, srcEnd);
--                int score = 0;
--                for (int i = rotBeg; i <= rotEnd; i++) {
--                    if ((int)state.get(i) != (int)goal.get(i))
--                        score += 1;
--                }
--                List<Integer> rotSpan = state.subList(rotBeg, rotEnd+1);
--                Collections.rotate(rotSpan, -rotBy);  // reverse direction
--                for (int i = rotBeg; i <= rotEnd; i++) {
--                    if ((int)state.get(i) != (int)goal.get(i))
--                        score -= 1;
--                }
--                if (score >= 2) {
--                    // Improved at least two argument positions.  Do it.
--                    List<Class<?>> ptypes = Arrays.asList(oldType.parameterArray());
--                    Collections.rotate(ptypes.subList(rotBeg, rotEnd+1), -rotBy);
--                    MethodType rotType = MethodType.methodType(oldType.returnType(), ptypes);
--                    MethodHandle nextTarget
--                            = AdapterMethodHandle.makeRotateArguments(rotType, target,
--                                    rotBeg, rotSpan.size(), rotBy);
--                    if (nextTarget != null) {
--                        //System.out.println("Rot: "+rotSpan+" by "+rotBy);
--                        target = nextTarget;
--                        oldType = rotType;
--                        continue;
--                    }
--                }
--                // Else de-rotate, and drop through to the swap-fest.
--                Collections.rotate(rotSpan, rotBy);
--            }
--
--            // Now swap like the wind!
--            List<Class<?>> ptypes = Arrays.asList(oldType.parameterArray());
--            for (int i = 0; i < size; i++) {
--                // What argument do I want here?
--                int arg = goal.get(i);
--                if (arg != state.get(i)) {
--                    // Where is it now?
--                    int j = state.indexOf(arg);
--                    Collections.swap(ptypes, i, j);
--                    MethodType swapType = MethodType.methodType(oldType.returnType(), ptypes);
--                    target = AdapterMethodHandle.makeSwapArguments(swapType, target, i, j);
--                    if (target == null)  throw newIllegalArgumentException("cannot swap");
--                    assert(target.type() == swapType);
--                    oldType = swapType;
--                    Collections.swap(state, i, j);
--                }
--            }
--            // One pass of swapping must finish the job.
--            assert(state.equals(goal));
--        }
--        while (!dups.isEmpty()) {
--            // Grab a contiguous trailing sequence of dups.
--            int grab = dups.size() - 1;
--            int dupArgPos = dups.get(grab), dupArgCount = 1;
--            while (grab - 1 >= 0) {
--                int dup0 = dups.get(grab - 1);
--                if (dup0 != dupArgPos - 1)  break;
--                dupArgPos -= 1;
--                dupArgCount += 1;
--                grab -= 1;
--            }
--            //if (dupArgCount > 1)  System.out.println("Dup: "+dups.subList(grab, dups.size()));
--            dups.subList(grab, dups.size()).clear();
--            // In the new target type drop that many args from the tail:
--            List<Class<?>> ptypes = oldType.parameterList();
--            ptypes = ptypes.subList(0, ptypes.size() - dupArgCount);
--            MethodType dupType = MethodType.methodType(oldType.returnType(), ptypes);
--            target = AdapterMethodHandle.makeDupArguments(dupType, target, dupArgPos, dupArgCount);
--            if (target == null)
--                throw newIllegalArgumentException("cannot dup");
--            oldType = target.type();
--        }
--        while (!drops.isEmpty()) {
--            // Grab a contiguous initial sequence of drops.
--            int dropArgPos = drops.get(0), dropArgCount = 1;
--            while (dropArgCount < drops.size()) {
--                int drop1 = drops.get(dropArgCount);
--                if (drop1 != dropArgPos + dropArgCount)  break;
--                dropArgCount += 1;
--            }
--            //if (dropArgCount > 1)  System.out.println("Drop: "+drops.subList(0, dropArgCount));
--            drops.subList(0, dropArgCount).clear();
--            List<Class<?>> dropTypes = newType.parameterList()
--                    .subList(dropArgPos, dropArgPos + dropArgCount);
--            MethodType dropType = oldType.insertParameterTypes(dropArgPos, dropTypes);
--            target = AdapterMethodHandle.makeDropArguments(dropType, target, dropArgPos, dropArgCount);
--            if (target == null)  throw newIllegalArgumentException("cannot drop");
--            oldType = target.type();
--        }
--        target = convertArguments(target, newType, oldType, 0);
--        assert(target != null);
--        return target;
-     }
- 
--    /*non-public*/ static
--    MethodHandle convertArguments(MethodHandle target, MethodType newType, int level) {
--        MethodType oldType = target.type();
--        if (oldType.equals(newType))
--            return target;
--        assert(level > 1 || oldType.isConvertibleTo(newType));
--        MethodHandle retFilter = null;
--        Class<?> oldRT = oldType.returnType();
--        Class<?> newRT = newType.returnType();
--        if (!VerifyType.isNullConversion(oldRT, newRT)) {
--            if (oldRT == void.class) {
--                Wrapper wrap = newRT.isPrimitive() ? Wrapper.forPrimitiveType(newRT) : Wrapper.OBJECT;
--                retFilter = ValueConversions.zeroConstantFunction(wrap);
--            } else {
--                retFilter = MethodHandles.identity(newRT);
--                retFilter = convertArguments(retFilter, retFilter.type().changeParameterType(0, oldRT), level);
--            }
--            newType = newType.changeReturnType(oldRT);
-+    /** Factory method:  Collect or filter selected argument(s). */
-+    static MethodHandle makeCollectArguments(MethodHandle target,
-+                MethodHandle collector, int collectArgPos, boolean retainOriginalArgs) {
-+        MethodType targetType = target.type();          // (a..., c, [b...])=>r
-+        MethodType collectorType = collector.type();    // (b...)=>c
-+        int collectArgCount = collectorType.parameterCount();
-+        Class<?> collectValType = collectorType.returnType();
-+        int collectValCount = (collectValType == void.class ? 0 : 1);
-+        MethodType srcType = targetType                 // (a..., [b...])=>r
-+                .dropParameterTypes(collectArgPos, collectArgPos+collectValCount);
-+        if (!retainOriginalArgs) {                      // (a..., b...)=>r
-+            srcType = srcType.insertParameterTypes(collectArgPos, collectorType.parameterList());
-         }
--        MethodHandle res = null;
--        Exception ex = null;
--        try {
--            res = convertArguments(target, newType, oldType, level);
--        } catch (IllegalArgumentException ex1) {
--            ex = ex1;
-+        // in  arglist: [0: ...keep1 | cpos: collect...  | cpos+cacount: keep2... ]
-+        // out arglist: [0: ...keep1 | cpos: collectVal? | cpos+cvcount: keep2... ]
-+        // out(retain): [0: ...keep1 | cpos: cV? coll... | cpos+cvc+cac: keep2... ]
-+
-+        // Now build a LambdaForm.
-+        MethodType lambdaType = srcType.invokerType();
-+        Name[] names = arguments(2, lambdaType);
-+        final int collectNamePos = names.length - 2;
-+        final int targetNamePos  = names.length - 1;
-+
-+        Name[] collectorArgs = Arrays.copyOfRange(names, 1 + collectArgPos, 1 + collectArgPos + collectArgCount);
-+        names[collectNamePos] = new Name(collector, (Object[]) collectorArgs);
-+
-+        // Build argument array for the target.
-+        // Incoming LF args to copy are: [ (mh) headArgs collectArgs tailArgs ].
-+        // Output argument array is [ headArgs (collectVal)? (collectArgs)? tailArgs ].
-+        Name[] targetArgs = new Name[targetType.parameterCount()];
-+        int inputArgPos  = 1;  // incoming LF args to copy to target
-+        int targetArgPos = 0;  // fill pointer for targetArgs
-+        int chunk = collectArgPos;  // |headArgs|
-+        System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk);
-+        inputArgPos  += chunk;
-+        targetArgPos += chunk;
-+        if (collectValType != void.class) {
-+            targetArgs[targetArgPos++] = names[collectNamePos];
-         }
--        if (res == null) {
--            WrongMethodTypeException wmt = new WrongMethodTypeException("cannot convert to "+newType+": "+target);
--            wmt.initCause(ex);
--            throw wmt;
-+        chunk = collectArgCount;
-+        if (retainOriginalArgs) {
-+            System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk);
-+            targetArgPos += chunk;   // optionally pass on the collected chunk
-         }
--        if (retFilter != null)
--            res = MethodHandles.filterReturnValue(res, retFilter);
--        return res;
--    }
-+        inputArgPos += chunk;
-+        chunk = targetArgs.length - targetArgPos;  // all the rest
-+        System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk);
-+        assert(inputArgPos + chunk == collectNamePos);  // use of rest of input args also
-+        names[targetNamePos] = new Name(target, (Object[]) targetArgs);
- 
--    static MethodHandle convertArguments(MethodHandle target,
--                                                MethodType newType,
--                                                MethodType oldType,
--                                                int level) {
--        assert(oldType.parameterCount() == target.type().parameterCount());
--        if (newType == oldType)
--            return target;
--        if (oldType.parameterCount() != newType.parameterCount())
--            throw newIllegalArgumentException("mismatched parameter count", oldType, newType);
--        return AdapterMethodHandle.makePairwiseConvert(newType, target, level);
--    }
--
--    static MethodHandle spreadArguments(MethodHandle target, Class<?> arrayType, int arrayLength) {
--        MethodType oldType = target.type();
--        int nargs = oldType.parameterCount();
--        int keepPosArgs = nargs - arrayLength;
--        MethodType newType = oldType
--                .dropParameterTypes(keepPosArgs, nargs)
--                .insertParameterTypes(keepPosArgs, arrayType);
--        return spreadArguments(target, newType, keepPosArgs, arrayType, arrayLength);
--    }
--    // called internally only
--    static MethodHandle spreadArgumentsFromPos(MethodHandle target, MethodType newType, int spreadArgPos) {
--        int arrayLength = target.type().parameterCount() - spreadArgPos;
--        return spreadArguments(target, newType, spreadArgPos, Object[].class, arrayLength);
--    }
--    static MethodHandle spreadArguments(MethodHandle target,
--                                               MethodType newType,
--                                               int spreadArgPos,
--                                               Class<?> arrayType,
--                                               int arrayLength) {
--        // TO DO: maybe allow the restarg to be Object and implicitly cast to Object[]
--        MethodType oldType = target.type();
--        // spread the last argument of newType to oldType
--        assert(arrayLength == oldType.parameterCount() - spreadArgPos);
--        assert(newType.parameterType(spreadArgPos) == arrayType);
--        return AdapterMethodHandle.makeSpreadArguments(newType, target, arrayType, spreadArgPos, arrayLength);
--    }
--
--    static MethodHandle collectArguments(MethodHandle target,
--                                                int collectArg,
--                                                MethodHandle collector) {
--        MethodType type = target.type();
--        Class<?> collectType = collector.type().returnType();
--        assert(collectType != void.class);  // else use foldArguments
--        if (collectType != type.parameterType(collectArg))
--            target = target.asType(type.changeParameterType(collectArg, collectType));
--        MethodType newType = type
--                .dropParameterTypes(collectArg, collectArg+1)
--                .insertParameterTypes(collectArg, collector.type().parameterArray());
--        return collectArguments(target, newType, collectArg, collector);
--    }
--    static MethodHandle collectArguments(MethodHandle target,
--                                                MethodType newType,
--                                                int collectArg,
--                                                MethodHandle collector) {
--        MethodType oldType = target.type();     // (a...,c)=>r
--        //         newType                      // (a..., b...)=>r
--        MethodType colType = collector.type();  // (b...)=>c
--        //         oldType                      // (a..., b...)=>r
--        assert(newType.parameterCount() == collectArg + colType.parameterCount());
--        assert(oldType.parameterCount() == collectArg + 1);
--        assert(AdapterMethodHandle.canCollectArguments(oldType, colType, collectArg, false));
--        return AdapterMethodHandle.makeCollectArguments(target, collector, collectArg, false);
--    }
--
--    static MethodHandle filterArgument(MethodHandle target,
--                                       int pos,
--                                       MethodHandle filter) {
--        MethodType ttype = target.type();
--        MethodType ftype = filter.type();
--        assert(ftype.parameterCount() == 1);
--        return AdapterMethodHandle.makeCollectArguments(target, filter, pos, false);
--    }
--
--    static MethodHandle foldArguments(MethodHandle target,
--                                      MethodType newType,
--                                      int foldPos,
--                                      MethodHandle combiner) {
--        MethodType oldType = target.type();
--        MethodType ctype = combiner.type();
--        assert(AdapterMethodHandle.canCollectArguments(oldType, ctype, foldPos, true));
--        return AdapterMethodHandle.makeCollectArguments(target, combiner, foldPos, true);
--    }
--
--    static
--    MethodHandle dropArguments(MethodHandle target,
--                               MethodType newType, int argnum) {
--        int drops = newType.parameterCount() - target.type().parameterCount();
--        return AdapterMethodHandle.makeDropArguments(newType, target, argnum, drops);
-+        LambdaForm form = new LambdaForm("collect", lambdaType.parameterCount(), names);
-+        return new SimpleMethodHandle(srcType, form);
-     }
- 
-     static
-@@ -738,47 +533,42 @@
-     MethodHandle makeGuardWithTest(MethodHandle test,
-                                    MethodHandle target,
-                                    MethodHandle fallback) {
--        // gwt(arg...)
--        // [fold]=> continueAfterTest(z=test(arg...), arg...)
--        // [filter]=> (tf=select(z))(arg...)
--        //    where select(z) = select(z, t, f).bindTo(t, f) => z ? t f
--        // [tailcall]=> tf(arg...)
--        assert(test.type().returnType() == boolean.class);
--        MethodType targetType = target.type();
--        MethodType foldTargetType = targetType.insertParameterTypes(0, boolean.class);
--        assert(AdapterMethodHandle.canCollectArguments(foldTargetType, test.type(), 0, true));
--        // working backwards, as usual:
--        assert(target.type().equals(fallback.type()));
--        MethodHandle tailcall = MethodHandles.exactInvoker(target.type());
--        MethodHandle select = selectAlternative();
--        select = bindArgument(select, 2, CountingMethodHandle.wrap(fallback));
--        select = bindArgument(select, 1, CountingMethodHandle.wrap(target));
--        // select(z: boolean) => (z ? target : fallback)
--        MethodHandle filter = filterArgument(tailcall, 0, select);
--        assert(filter.type().parameterType(0) == boolean.class);
--        MethodHandle fold = foldArguments(filter, filter.type().dropParameterTypes(0, 1), 0, test);
--        return fold;
-+        MethodType basicType = target.type().basicType();
-+        MethodHandle invokeBasic = MethodHandles.basicInvoker(basicType);
-+        int arity = basicType.parameterCount();
-+        int extraNames = 3;
-+        MethodType lambdaType = basicType.invokerType();
-+        Name[] names = arguments(extraNames, lambdaType);
-+
-+        Object[] testArgs   = Arrays.copyOfRange(names, 1, 1 + arity, Object[].class);
-+        Object[] targetArgs = Arrays.copyOfRange(names, 0, 1 + arity, Object[].class);
-+
-+        // call test
-+        names[arity + 1] = new Name(test, testArgs);
-+
-+        // call selectAlternative
-+        Object[] selectArgs = { names[arity + 1], target, fallback };
-+        names[arity + 2] = new Name(MethodHandleImpl.selectAlternative(), selectArgs);
-+        targetArgs[0] = names[arity + 2];
-+
-+        // call target or fallback
-+        names[arity + 3] = new Name(new NamedFunction(invokeBasic), targetArgs);
-+
-+        LambdaForm form = new LambdaForm("guard", lambdaType.parameterCount(), names);
-+        return new SimpleMethodHandle(target.type(), form);
-     }
- 
--    private static class GuardWithCatch extends BoundMethodHandle {
-+    private static class GuardWithCatch {
-         private final MethodHandle target;
-         private final Class<? extends Throwable> exType;
-         private final MethodHandle catcher;
-+        // FIXME: Build the control flow out of foldArguments.
-         GuardWithCatch(MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
--            this(INVOKES[target.type().parameterCount()], target, exType, catcher);
--        }
--        // FIXME: Build the control flow out of foldArguments.
--        GuardWithCatch(MethodHandle invoker,
--                       MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
--            super(invoker);
-             this.target = target;
-             this.exType = exType;
-             this.catcher = catcher;
-         }
--        @Override
--        String debugString() {
--            return addTypeString(target, this);
--        }
-+        @LambdaForm.Hidden
-         private Object invoke_V(Object... av) throws Throwable {
-             try {
-                 return target.invokeExact(av);
-@@ -787,6 +577,7 @@
-                 return catcher.invokeExact(t, av);
-             }
-         }
-+        @LambdaForm.Hidden
-         private Object invoke_L0() throws Throwable {
-             try {
-                 return target.invokeExact();
-@@ -795,6 +586,7 @@
-                 return catcher.invokeExact(t);
-             }
-         }
-+        @LambdaForm.Hidden
-         private Object invoke_L1(Object a0) throws Throwable {
-             try {
-                 return target.invokeExact(a0);
-@@ -803,6 +595,7 @@
-                 return catcher.invokeExact(t, a0);
-             }
-         }
-+        @LambdaForm.Hidden
-         private Object invoke_L2(Object a0, Object a1) throws Throwable {
-             try {
-                 return target.invokeExact(a0, a1);
-@@ -811,6 +604,7 @@
-                 return catcher.invokeExact(t, a0, a1);
-             }
-         }
-+        @LambdaForm.Hidden
-         private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
-             try {
-                 return target.invokeExact(a0, a1, a2);
-@@ -819,6 +613,7 @@
-                 return catcher.invokeExact(t, a0, a1, a2);
-             }
-         }
-+        @LambdaForm.Hidden
-         private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
-             try {
-                 return target.invokeExact(a0, a1, a2, a3);
-@@ -827,6 +622,7 @@
-                 return catcher.invokeExact(t, a0, a1, a2, a3);
-             }
-         }
-+        @LambdaForm.Hidden
-         private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
-             try {
-                 return target.invokeExact(a0, a1, a2, a3, a4);
-@@ -835,6 +631,7 @@
-                 return catcher.invokeExact(t, a0, a1, a2, a3, a4);
-             }
-         }
-+        @LambdaForm.Hidden
-         private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
-             try {
-                 return target.invokeExact(a0, a1, a2, a3, a4, a5);
-@@ -843,6 +640,7 @@
-                 return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5);
-             }
-         }
-+        @LambdaForm.Hidden
-         private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
-             try {
-                 return target.invokeExact(a0, a1, a2, a3, a4, a5, a6);
-@@ -851,6 +649,7 @@
-                 return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6);
-             }
-         }
-+        @LambdaForm.Hidden
-         private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
-             try {
-                 return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
-@@ -860,7 +659,7 @@
-             }
-         }
-         static MethodHandle[] makeInvokes() {
--            ArrayList<MethodHandle> invokes = new ArrayList<MethodHandle>();
-+            ArrayList<MethodHandle> invokes = new ArrayList<>();
-             MethodHandles.Lookup lookup = IMPL_LOOKUP;
-             for (;;) {
-                 int nargs = invokes.size();
-@@ -901,39 +700,60 @@
-             MethodType gtype = type.generic();
-             MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
-             // Note: convertArguments(...2) avoids interface casts present in convertArguments(...0)
--            MethodHandle gtarget = convertArguments(target, gtype, type, 2);
--            MethodHandle gcatcher = convertArguments(catcher, gcatchType, ctype, 2);
--            MethodHandle gguard = new GuardWithCatch(gtarget, exType, gcatcher);
--            if (gtarget == null || gcatcher == null || gguard == null)  return null;
--            return convertArguments(gguard, type, gtype, 2);
-+            MethodHandle gtarget = makePairwiseConvert(target, gtype, 2);
-+            MethodHandle gcatcher = makePairwiseConvert(catcher, gcatchType, 2);
-+            GuardWithCatch gguard = new GuardWithCatch(gtarget, exType, gcatcher);
-+            if (gtarget == null || gcatcher == null)  throw new InternalError();
-+            MethodHandle ginvoker = GuardWithCatch.INVOKES[nargs].bindReceiver(gguard);
-+            return makePairwiseConvert(ginvoker, type, 2);
-         } else {
--            MethodType gtype = MethodType.genericMethodType(0, true);
--            MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
--            MethodHandle gtarget = spreadArgumentsFromPos(target, gtype, 0);
-+            MethodHandle gtarget = makeSpreadArguments(target, Object[].class, 0, nargs);
-             catcher = catcher.asType(ctype.changeParameterType(0, Throwable.class));
--            MethodHandle gcatcher = spreadArgumentsFromPos(catcher, gcatchType, 1);
--            MethodHandle gguard = new GuardWithCatch(GuardWithCatch.VARARGS_INVOKE, gtarget, exType, gcatcher);
--            if (gtarget == null || gcatcher == null || gguard == null)  return null;
--            return collectArguments(gguard, type, 0, ValueConversions.varargsArray(nargs)).asType(type);
-+            MethodHandle gcatcher = makeSpreadArguments(catcher, Object[].class, 1, nargs);
-+            GuardWithCatch gguard = new GuardWithCatch(gtarget, exType, gcatcher);
-+            if (gtarget == null || gcatcher == null)  throw new InternalError();
-+            MethodHandle ginvoker = GuardWithCatch.VARARGS_INVOKE.bindReceiver(gguard);
-+            return makeCollectArguments(ginvoker, ValueConversions.varargsArray(nargs), 0, false);
-         }
-     }
- 
-     static
-     MethodHandle throwException(MethodType type) {
--        return AdapterMethodHandle.makeRetypeRaw(type, throwException());
-+        assert(Throwable.class.isAssignableFrom(type.parameterType(0)));
-+        int arity = type.parameterCount();
-+        if (arity > 1) {
-+            return throwException(type.dropParameterTypes(1, arity)).dropArguments(type, 1, arity-1);
-+        }
-+        return makePairwiseConvert(throwException(), type, 2);
-     }
- 
-     static MethodHandle THROW_EXCEPTION;
-     static MethodHandle throwException() {
--        if (THROW_EXCEPTION != null)  return THROW_EXCEPTION;
-+        MethodHandle mh = THROW_EXCEPTION;
-+        if (mh != null)  return mh;
-         try {
--            THROW_EXCEPTION
-+            mh
-             = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "throwException",
-                     MethodType.methodType(Empty.class, Throwable.class));
-         } catch (ReflectiveOperationException ex) {
-             throw new RuntimeException(ex);
-         }
--        return THROW_EXCEPTION;
-+        THROW_EXCEPTION = mh;
-+        return mh;
-     }
-     static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
-+
-+    static MethodHandle FAKE_METHOD_HANDLE_INVOKE;
-+    static
-+    MethodHandle fakeMethodHandleInvoke(MemberName method) {
-+        MethodType type = method.getInvocationType();
-+        assert(type.equals(MethodType.methodType(Object.class, Object[].class)));
-+        MethodHandle mh = FAKE_METHOD_HANDLE_INVOKE;
-+        if (mh != null)  return mh;
-+        mh = throwException(type.insertParameterTypes(0, UnsupportedOperationException.class));
-+        mh = mh.bindTo(new UnsupportedOperationException("cannot reflectively invoke MethodHandle"));
-+        FAKE_METHOD_HANDLE_INVOKE = mh;
-+        return mh;
-+    }
-+
- }
-diff --git a/src/share/classes/java/lang/invoke/MethodHandleInfo.java b/src/share/classes/java/lang/invoke/MethodHandleInfo.java
-new file mode 100644
---- /dev/null
-+++ b/src/share/classes/java/lang/invoke/MethodHandleInfo.java
-@@ -0,0 +1,71 @@
-+/*
-+ * Copyright (c) 2012, 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.lang.invoke.MethodHandleNatives.Constants;
-+
-+//Not yet public: public
-+class MethodHandleInfo {
-+   public static final int
-+       REF_NONE                    = Constants.REF_NONE,
-+       REF_getField                = Constants.REF_getField,
-+       REF_getStatic               = Constants.REF_getStatic,
-+       REF_putField                = Constants.REF_putField,
-+       REF_putStatic               = Constants.REF_putStatic,
-+       REF_invokeVirtual           = Constants.REF_invokeVirtual,
-+       REF_invokeStatic            = Constants.REF_invokeStatic,
-+       REF_invokeSpecial           = Constants.REF_invokeSpecial,
-+       REF_newInvokeSpecial        = Constants.REF_newInvokeSpecial,
-+       REF_invokeInterface         = Constants.REF_invokeInterface;
-+
-+   private final Class<?> declaringClass;
-+   private final String name;
-+   private final MethodType methodType;
-+   private final int referenceKind;
-+
-+   public MethodHandleInfo(MethodHandle mh) throws ReflectiveOperationException {
-+       MemberName mn = mh.internalMemberName();
-+       this.declaringClass = mn.getDeclaringClass();
-+       this.name = mn.getName();
-+       this.methodType = mn.getMethodType();
-+       this.referenceKind = mn.getReferenceKind();
-+   }
-+
-+   public Class<?> getDeclaringClass() {
-+       return declaringClass;
-+   }
-+
-+   public String getName() {
-+       return name;
-+   }
-+
-+   public MethodType getMethodType() {
-+       return methodType;
-+   }
-+
-+   public int getReferenceKind() {
-+       return referenceKind;
-+   }
-+}
-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
-@@ -1,5 +1,5 @@
- /*
-- * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
-+ * Copyright (c) 2008, 2012, 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
-@@ -29,6 +29,7 @@
- import java.lang.reflect.AccessibleObject;
- import java.lang.reflect.Field;
- import static java.lang.invoke.MethodHandleNatives.Constants.*;
-+import static java.lang.invoke.MethodHandleStatics.*;
- import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
- 
- /**
-@@ -41,76 +42,28 @@
- 
-     private MethodHandleNatives() { } // static only
- 
--    /// MethodName support
-+    /// MemberName support
- 
-     static native void init(MemberName self, Object ref);
-     static native void expand(MemberName self);
--    static native void resolve(MemberName self, Class<?> caller);
-+    static native MemberName resolve(MemberName self, Class<?> caller) throws LinkageError;
-     static native int getMembers(Class<?> defc, String matchName, String matchSig,
-             int matchFlags, Class<?> caller, int skip, MemberName[] results);
- 
-+    /// Field layout queries parallel to sun.misc.Unsafe:
-+    static native long objectFieldOffset(MemberName self);  // e.g., returns vmindex
-+    static native long staticFieldOffset(MemberName self);  // e.g., returns vmindex
-+    static native Object staticFieldBase(MemberName self);  // e.g., returns clazz
-+    static native Object getMemberVMInfo(MemberName self);  // returns {vmindex,vmtarget}
-+
-     /// MethodHandle support
- 
--    /** Initialize the method handle to adapt the call. */
--    static native void init(AdapterMethodHandle self, MethodHandle target, int argnum);
--    /** Initialize the method handle to call the correct method, directly. */
--    static native void init(BoundMethodHandle self, Object target, int argnum);
--    /** Initialize the method handle to call as if by an invoke* instruction. */
--    static native void init(DirectMethodHandle self, Object ref, boolean doDispatch, Class<?> caller);
--
--    /** Initialize a method type, once per form. */
--    static native void init(MethodType self);
--
--    /** Fetch the vmtarget field.
--     *  It will be sanitized as necessary to avoid exposing non-Java references.
--     *  This routine is for debugging and reflection.
--     */
--    static native Object getTarget(MethodHandle self, int format);
--
--    /** Fetch the name of the handled method, if available.
--     *  This routine is for debugging and reflection.
--     */
--    static MemberName getMethodName(MethodHandle self) {
--        return (MemberName) getTarget(self, ETF_METHOD_NAME);
--    }
--
--    /** Fetch the reflective version of the handled method, if available.
--     */
--    static AccessibleObject getTargetMethod(MethodHandle self) {
--        return (AccessibleObject) getTarget(self, ETF_REFLECT_METHOD);
--    }
--
--    /** Fetch the target of this method handle.
--     *  If it directly targets a method, return a MemberName for the method.
--     *  If it is chained to another method handle, return that handle.
--     */
--    static Object getTargetInfo(MethodHandle self) {
--        return getTarget(self, ETF_HANDLE_OR_METHOD_NAME);
--    }
--
--    static Object[] makeTarget(Class<?> defc, String name, String sig, int mods, Class<?> refc) {
--        return new Object[] { defc, name, sig, mods, refc };
--    }
--
-     /** Fetch MH-related JVM parameter.
-      *  which=0 retrieves MethodHandlePushLimit
-      *  which=1 retrieves stack slot push size (in address units)
-      */
-     static native int getConstant(int which);
- 
--    /** Java copy of MethodHandlePushLimit in range 2..255. */
--    static final int JVM_PUSH_LIMIT;
--    /** JVM stack motion (in words) after one slot is pushed, usually -1.
--     */
--    static final int JVM_STACK_MOVE_UNIT;
--
--    /** Which conv-ops are implemented by the JVM? */
--    static final int CONV_OP_IMPLEMENTED_MASK;
--    /** Derived mode flag.  Only false on some old JVM implementations. */
--    static final boolean HAVE_RICOCHET_FRAMES;
--
--    static final int OP_ROT_ARGS_DOWN_LIMIT_BIAS;
--
-     static final boolean COUNT_GWT;
- 
-     /// CallSite support
-@@ -122,17 +75,11 @@
-     private static native void registerNatives();
-     static {
-         registerNatives();
--        int k;
--        JVM_PUSH_LIMIT              = getConstant(Constants.GC_JVM_PUSH_LIMIT);
--        JVM_STACK_MOVE_UNIT         = getConstant(Constants.GC_JVM_STACK_MOVE_UNIT);
--        k                           = getConstant(Constants.GC_CONV_OP_IMPLEMENTED_MASK);
--        CONV_OP_IMPLEMENTED_MASK    = (k != 0) ? k : DEFAULT_CONV_OP_IMPLEMENTED_MASK;
--        k                           = getConstant(Constants.GC_OP_ROT_ARGS_DOWN_LIMIT_BIAS);
--        OP_ROT_ARGS_DOWN_LIMIT_BIAS = (k != 0) ? (byte)k : -1;
--        HAVE_RICOCHET_FRAMES        = (CONV_OP_IMPLEMENTED_MASK & (1<<OP_COLLECT_ARGS)) != 0;
-         COUNT_GWT                   = getConstant(Constants.GC_COUNT_GWT) != 0;
--        //sun.reflect.Reflection.registerMethodsToFilter(MethodHandleImpl.class, "init");
--    }
-+
-+        // The JVM calls MethodHandleNatives.<clinit>.  Cascade the <clinit> calls as needed:
-+        MethodHandleImpl.initStatics();
-+}
- 
-     // All compile-time constants go here.
-     // There is an opportunity to check them against the JVM's idea of them.
-@@ -140,16 +87,8 @@
-         Constants() { } // static only
-         // MethodHandleImpl
-         static final int // for getConstant
--                GC_JVM_PUSH_LIMIT = 0,
--                GC_JVM_STACK_MOVE_UNIT = 1,
--                GC_CONV_OP_IMPLEMENTED_MASK = 2,
--                GC_OP_ROT_ARGS_DOWN_LIMIT_BIAS = 3,
--                GC_COUNT_GWT = 4;
--        static final int
--                ETF_HANDLE_OR_METHOD_NAME = 0, // all available data (immediate MH or method)
--                ETF_DIRECT_HANDLE         = 1, // ultimate method handle (will be a DMH, may be self)
--                ETF_METHOD_NAME           = 2, // ultimate method as MemberName
--                ETF_REFLECT_METHOD        = 3; // ultimate method as java.lang.reflect object (sans refClass)
-+                GC_COUNT_GWT = 4,
-+                GC_LAMBDA_SUPPORT = 5;
- 
-         // MemberName
-         // The JVM uses values of -2 and above for vtable indexes.
-@@ -162,65 +101,11 @@
-                 MN_IS_CONSTRUCTOR      = 0x00020000, // constructor
-                 MN_IS_FIELD            = 0x00040000, // field
-                 MN_IS_TYPE             = 0x00080000, // nested type
--                MN_SEARCH_SUPERCLASSES = 0x00100000, // for MHN.getMembers
--                MN_SEARCH_INTERFACES   = 0x00200000, // for MHN.getMembers
--                VM_INDEX_UNINITIALIZED = -99;
--
--        // BoundMethodHandle
--        /** Constants for decoding the vmargslot field, which contains 2 values. */
--        static final int
--            ARG_SLOT_PUSH_SHIFT = 16,
--            ARG_SLOT_MASK = (1<<ARG_SLOT_PUSH_SHIFT)-1;
--
--        // AdapterMethodHandle
--        /** Conversions recognized by the JVM.
--         *  They must align with the constants in java.lang.invoke.AdapterMethodHandle,
--         *  in the JVM file hotspot/src/share/vm/classfile/javaClasses.hpp.
--         */
--        static final int
--            OP_RETYPE_ONLY   = 0x0, // no argument changes; straight retype
--            OP_RETYPE_RAW    = 0x1, // straight retype, trusted (void->int, Object->T)
--            OP_CHECK_CAST    = 0x2, // ref-to-ref conversion; requires a Class argument
--            OP_PRIM_TO_PRIM  = 0x3, // converts from one primitive to another
--            OP_REF_TO_PRIM   = 0x4, // unboxes a wrapper to produce a primitive
--            OP_PRIM_TO_REF   = 0x5, // boxes a primitive into a wrapper
--            OP_SWAP_ARGS     = 0x6, // swap arguments (vminfo is 2nd arg)
--            OP_ROT_ARGS      = 0x7, // rotate arguments (vminfo is displaced arg)
--            OP_DUP_ARGS      = 0x8, // duplicates one or more arguments (at TOS)
--            OP_DROP_ARGS     = 0x9, // remove one or more argument slots
--            OP_COLLECT_ARGS  = 0xA, // combine arguments using an auxiliary function
--            OP_SPREAD_ARGS   = 0xB, // expand in place a varargs array (of known size)
--            OP_FOLD_ARGS     = 0xC, // combine but do not remove arguments; prepend result
--            //OP_UNUSED_13   = 0xD, // unused code, perhaps for reified argument lists
--            CONV_OP_LIMIT    = 0xE; // limit of CONV_OP enumeration
--        /** Shift and mask values for decoding the AMH.conversion field.
--         *  These numbers are shared with the JVM for creating AMHs.
--         */
--        static final int
--            CONV_OP_MASK     = 0xF00, // this nybble contains the conversion op field
--            CONV_TYPE_MASK   = 0x0F,  // fits T_ADDRESS and below
--            CONV_VMINFO_MASK = 0x0FF, // LSB is reserved for JVM use
--            CONV_VMINFO_SHIFT     =  0, // position of bits in CONV_VMINFO_MASK
--            CONV_OP_SHIFT         =  8, // position of bits in CONV_OP_MASK
--            CONV_DEST_TYPE_SHIFT  = 12, // byte 2 has the adapter BasicType (if needed)
--            CONV_SRC_TYPE_SHIFT   = 16, // byte 2 has the source BasicType (if needed)
--            CONV_STACK_MOVE_SHIFT = 20, // high 12 bits give signed SP change
--            CONV_STACK_MOVE_MASK  = (1 << (32 - CONV_STACK_MOVE_SHIFT)) - 1;
--
--        /** Which conv-ops are implemented by the JVM? */
--        static final int DEFAULT_CONV_OP_IMPLEMENTED_MASK =
--                // Value to use if the corresponding JVM query fails.
--                ((1<<OP_RETYPE_ONLY)
--                |(1<<OP_RETYPE_RAW)
--                |(1<<OP_CHECK_CAST)
--                |(1<<OP_PRIM_TO_PRIM)
--                |(1<<OP_REF_TO_PRIM)
--                |(1<<OP_SWAP_ARGS)
--                |(1<<OP_ROT_ARGS)
--                |(1<<OP_DUP_ARGS)
--                |(1<<OP_DROP_ARGS)
--                //|(1<<OP_SPREAD_ARGS)
--                );
-+                MN_REFERENCE_KIND_SHIFT = 24, // refKind
-+                MN_REFERENCE_KIND_MASK = 0x0F000000 >> MN_REFERENCE_KIND_SHIFT,
-+                // The SEARCH_* bits are not for MN.flags but for the matchFlags argument of MHN.getMembers:
-+                MN_SEARCH_SUPERCLASSES = 0x00100000,
-+                MN_SEARCH_INTERFACES   = 0x00200000;
- 
-         /**
-          * Basic types as encoded in the JVM.  These code values are not
-@@ -243,9 +128,54 @@
-             T_ILLEGAL  = 99;
- 
-         /**
-+         * Constant pool entry types.
-+         */
-+        static final byte
-+            CONSTANT_Utf8                = 1,
-+            CONSTANT_Integer             = 3,
-+            CONSTANT_Float               = 4,
-+            CONSTANT_Long                = 5,
-+            CONSTANT_Double              = 6,
-+            CONSTANT_Class               = 7,
-+            CONSTANT_String              = 8,
-+            CONSTANT_Fieldref            = 9,
-+            CONSTANT_Methodref           = 10,
-+            CONSTANT_InterfaceMethodref  = 11,
-+            CONSTANT_NameAndType         = 12,
-+            CONSTANT_MethodHandle        = 15,  // JSR 292
-+            CONSTANT_MethodType          = 16,  // JSR 292
-+            CONSTANT_InvokeDynamic       = 18,
-+            CONSTANT_LIMIT               = 19;   // Limit to tags found in classfiles
-+
-+        /**
-+         * Access modifier flags.
-+         */
-+        static final char
-+            ACC_PUBLIC                 = 0x0001,
-+            ACC_PRIVATE                = 0x0002,
-+            ACC_PROTECTED              = 0x0004,
-+            ACC_STATIC                 = 0x0008,
-+            ACC_FINAL                  = 0x0010,
-+            ACC_SYNCHRONIZED           = 0x0020,
-+            ACC_VOLATILE               = 0x0040,
-+            ACC_TRANSIENT              = 0x0080,
-+            ACC_NATIVE                 = 0x0100,
-+            ACC_INTERFACE              = 0x0200,
-+            ACC_ABSTRACT               = 0x0400,
-+            ACC_STRICT                 = 0x0800,
-+            ACC_SYNTHETIC              = 0x1000,
-+            ACC_ANNOTATION             = 0x2000,
-+            ACC_ENUM                   = 0x4000,
-+            // aliases:
-+            ACC_SUPER                  = ACC_SYNCHRONIZED,
-+            ACC_BRIDGE                 = ACC_VOLATILE,
-+            ACC_VARARGS                = ACC_TRANSIENT;
-+
-+        /**
-          * Constant pool reference-kind codes, as used by CONSTANT_MethodHandle CP entries.
-          */
--        static final int
-+        static final byte
-+            REF_NONE                    = 0,  // null value
-             REF_getField                = 1,
-             REF_getStatic               = 2,
-             REF_putField                = 3,
-@@ -254,9 +184,67 @@
-             REF_invokeStatic            = 6,
-             REF_invokeSpecial           = 7,
-             REF_newInvokeSpecial        = 8,
--            REF_invokeInterface         = 9;
-+            REF_invokeInterface         = 9,
-+            REF_LIMIT                  = 10;
-     }
- 
-+    static boolean refKindIsValid(int refKind) {
-+        return (refKind > REF_NONE && refKind < REF_LIMIT);
-+    }
-+    static boolean refKindIsField(byte refKind) {
-+        assert(refKindIsValid(refKind));
-+        return (refKind <= REF_putStatic);
-+    }
-+    static boolean refKindIsGetter(byte refKind) {
-+        assert(refKindIsValid(refKind));
-+        return (refKind <= REF_getStatic);
-+    }
-+    static boolean refKindIsSetter(byte refKind) {
-+        return refKindIsField(refKind) && !refKindIsGetter(refKind);
-+    }
-+    static boolean refKindIsMethod(byte refKind) {
-+        return !refKindIsField(refKind) && (refKind != REF_newInvokeSpecial);
-+    }
-+    static boolean refKindHasReceiver(byte refKind) {
-+        assert(refKindIsValid(refKind));
-+        return (refKind & 1) != 0;
-+    }
-+    static boolean refKindIsStatic(byte refKind) {
-+        return !refKindHasReceiver(refKind) && (refKind != REF_newInvokeSpecial);
-+    }
-+    static boolean refKindDoesDispatch(byte refKind) {
-+        assert(refKindIsValid(refKind));
-+        return (refKind == REF_invokeVirtual ||
-+                refKind == REF_invokeInterface);
-+    }
-+    static {
-+        final int HR_MASK = ((1 << REF_getField) |
-+                             (1 << REF_putField) |
-+                             (1 << REF_invokeVirtual) |
-+                             (1 << REF_invokeSpecial) |
-+                             (1 << REF_invokeInterface)
-+                            );
-+        for (byte refKind = REF_NONE+1; refKind < REF_LIMIT; refKind++) {
-+            assert(refKindHasReceiver(refKind) == (((1<<refKind) & HR_MASK) != 0)) : refKind;
-+        }
-+    }
-+    static String refKindName(byte refKind) {
-+        assert(refKindIsValid(refKind));
-+        return REFERENCE_KIND_NAME[refKind];
-+    }
-+    private static String[] REFERENCE_KIND_NAME = {
-+            null,
-+            "getField",
-+            "getStatic",
-+            "putField",
-+            "putStatic",
-+            "invokeVirtual",
-+            "invokeStatic",
-+            "invokeSpecial",
-+            "newInvokeSpecial",
-+            "invokeInterface"
-+    };
-+
-     private static native int getNamedCon(int which, Object[] name);
-     static boolean verifyConstants() {
-         Object[] box = { null };
-@@ -275,16 +263,11 @@
-                     continue;
-                 }
-                 throw new InternalError(err);
--            } catch (Exception ex) {
--                if (ex instanceof NoSuchFieldException) {
--                    String err = (name+": JVM has "+vmval+" which Java does not define");
--                    // ignore exotic ops the JVM cares about; we just wont issue them
--                    if (name.startsWith("OP_") || name.startsWith("GC_")) {
--                        System.err.println("warning: "+err);
--                        continue;
--                    }
--                }
--                throw new InternalError(name+": access failed, got "+ex);
-+            } catch (NoSuchFieldException | IllegalAccessException ex) {
-+                String err = (name+": JVM has "+vmval+" which Java does not define");
-+                // ignore exotic ops the JVM cares about; we just wont issue them
-+                //System.err.println("warning: "+err);
-+                continue;
-             }
-         }
-         return true;
-@@ -299,18 +282,21 @@
-     /**
-      * The JVM is linking an invokedynamic instruction.  Create a reified call site for it.
-      */
--    static CallSite makeDynamicCallSite(MethodHandle bootstrapMethod,
--                                        String name, MethodType type,
--                                        Object info,
--                                        MemberName callerMethod, int callerBCI) {
--        return CallSite.makeSite(bootstrapMethod, name, type, info, callerMethod, callerBCI);
--    }
--
--    /**
--     * Called by the JVM to check the length of a spread array.
--     */
--    static void checkSpreadArgument(Object av, int n) {
--        MethodHandleStatics.checkSpreadArgument(av, n);
-+    static MemberName linkCallSite(Object callerObj,
-+                                   Object bootstrapMethodObj,
-+                                   Object nameObj, Object typeObj,
-+                                   Object staticArguments,
-+                                   Object[] appendixResult) {
-+        MethodHandle bootstrapMethod = (MethodHandle)bootstrapMethodObj;
-+        Class<?> caller = (Class<?>)callerObj;
-+        String name = nameObj.toString().intern();
-+        MethodType type = (MethodType)typeObj;
-+        appendixResult[0] = CallSite.makeSite(bootstrapMethod,
-+                                              name,
-+                                              type,
-+                                              staticArguments,
-+                                              caller);
-+        return Invokers.linkToCallSiteMethod(type);
-     }
- 
-     /**
-@@ -321,71 +307,64 @@
-     }
-