changeset 420:3b3f4347ab7e

meth-lazy: consolidate changes made during review
author jrose
date Sat, 21 Jul 2012 16:55:21 -0700
parents 905bcd21d2bb
children 0cd0e35d7fe6
files meth-lazy-7023639.bmh.patch meth-lazy-7023639.init.patch meth-lazy-7023639.review.patch meth-lazy-7023639.rmcode.patch series
diffstat 5 files changed, 4533 insertions(+), 5487 deletions(-) [+]
line wrap: on
line diff
--- a/meth-lazy-7023639.bmh.patch	Sat Jul 21 16:50:34 2012 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2724 +0,0 @@
-Addendum to meth-lazy-7023639.patch.
-Adjustments to BMHs.
-
-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
-@@ -25,27 +25,10 @@
- 
- package java.lang.invoke;
- 
--import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ACC_FINAL;
--import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ACC_PUBLIC;
--import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ACC_STATIC;
--import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ACC_SUPER;
--import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ALOAD;
--import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ARETURN;
--import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.DLOAD;
--import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.FLOAD;
--import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.GETFIELD;
--import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ILOAD;
--import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.INVOKESPECIAL;
--import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.INVOKESTATIC;
--import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
--import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.LLOAD;
--import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.PUTFIELD;
--import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.RETURN;
--import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.V1_6;
--import static java.lang.invoke.LambdaForm.arguments;
-+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.MethodType.methodType;
-+import static java.lang.invoke.MethodHandleStatics.*;
- 
- import java.lang.invoke.LambdaForm.Name;
- import java.lang.invoke.LambdaForm.NamedFunction;
-@@ -57,10 +40,10 @@
- 
- import sun.invoke.util.ValueConversions;
- import sun.invoke.util.Wrapper;
--import sun.misc.Unsafe;
- 
- 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
-@@ -83,19 +66,17 @@
-         // for some type signatures, there exist pre-defined concrete BMH classes
-         try {
-             switch (xtype) {
--            case 'L': return new BMH_L(type, form, x);
-+            case 'L':
-+                if (true)  return bindSingle(type, form, x);  // Use known fast path.
-+                return (BoundMethodHandle) Data.EMPTY.extendWithType('L').constructor[0].invokeBasic(type, form, x);
-             case 'I':
--                assert x instanceof Integer : "expected Integer, found " + x.getClass();
--                return (BoundMethodHandle) Data.get("I").constructor.invokeBasic(type, form, ((Integer) x).intValue());
-+                return (BoundMethodHandle) Data.EMPTY.extendWithType('I').constructor[0].invokeBasic(type, form, ValueConversions.widenSubword(x));
-             case 'J':
--                assert x instanceof Long;
--                return new BMH_J(type, form, ((Long) x).longValue());
-+                return (BoundMethodHandle) Data.EMPTY.extendWithType('J').constructor[0].invokeBasic(type, form, (long) x);
-             case 'F':
--                assert x instanceof Float;
--                return (BoundMethodHandle) Data.get("F").constructor.invokeBasic(type, form, ((Float) x).floatValue());
-+                return (BoundMethodHandle) Data.EMPTY.extendWithType('F').constructor[0].invokeBasic(type, form, (float) x);
-             case 'D':
--                assert x instanceof Double;
--                return (BoundMethodHandle) Data.get("D").constructor.invokeBasic(type, form, ((Double) x).doubleValue());
-+                return (BoundMethodHandle) Data.EMPTY.extendWithType('D').constructor[0].invokeBasic(type, form, (double) x);
-             default : throw new InternalError("unexpected xtype: " + xtype);
-             }
-         } catch (Throwable t) {
-@@ -103,38 +84,29 @@
-         }
-     }
- 
-+    static MethodHandle bindSingle(MethodType type, LambdaForm form, Object x) {
-+            return new BMH_L(type, form, x);
-+    }
-+
-     MethodHandle cloneExtend(MethodType type, LambdaForm form, char xtype, Object x) {
-         try {
-             switch (xtype) {
-             case 'L': return cloneExtendL(type, form, x);
--            case 'I':
--                assert x instanceof Integer : "expected Integer, found " + x.getClass();
--                return cloneExtendI(type, form, ((Integer) x).intValue());
--            case 'J':
--                assert x instanceof Long;
--                return cloneExtendJ(type, form, ((Long) x).longValue());
--            case 'F':
--                assert x instanceof Float;
--                return cloneExtendF(type, form, ((Float) x).floatValue());
--            case 'D':
--                assert x instanceof Double;
--                return cloneExtendD(type, form, ((Double) x).doubleValue());
--            default : throw new InternalError("unexpected type: " + xtype);
-+            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) {
--            System.out.println("cloneExtend "+Arrays.asList(type, form, xtype, x));//@@
-             throw new InternalError(t);
-         }
-+        throw new InternalError("unexpected type: " + xtype);
-     }
- 
-     @Override
-     MethodHandle bindArgument(int pos, char basicType, Object value) {
-         MethodType type = type().dropParameterTypes(pos, pos+1);
--        LambdaForm form = internalForm().bind(basicType, 1+pos, tcount());
--        if (basicType == 'I' && !(value instanceof Integer)) {
--            // Cf. ValueConversions.unboxInteger
--            value = ValueConversions.primitiveConversion(Wrapper.INT, value, true);
--        }
-+        LambdaForm form = internalForm().bind(1+pos, myData());
-         return cloneExtend(type, form, basicType, value);
-     }
- 
-@@ -157,68 +129,43 @@
-          }
-     }
- 
--    public int tcount() {
--        return types().length();
--    }
--
--    protected final Data myData() {
--        return Data.get(types());
-+    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 type signature of a concrete BMH. Each concrete BMH is required
--     * to implement this method to return its type signature as a constant String
--     * (the {@link #types} field).
-+     * Return the {@link Data} instance representing this BMH species. All subclasses must provide a
-+     * static field containing this value, and they must accordingly implement this method.
-      */
--    public abstract String types();
--
--    /**
--     * All subclasses must provide such a value describing their type signature.
--     */
--    public static final String types = "";
--
--    public char type(int i) {
--        return types().charAt(i);
--    }
--
--    /**
--     * 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.
--     */
--    static Name getterName(Name mhName, char basicType, int i) {
--        Class<?> paramCls = Wrapper.forBasicType(basicType).primitiveType();
--        MethodHandle bmhGetter;
--        try {
--            bmhGetter = Lookup.IMPL_LOOKUP.findVirtual(BoundMethodHandle.class, "arg" + basicType, methodType(paramCls, int.class));
--        } catch (IllegalAccessException | NoSuchMethodException e) {
--            throw new InternalError(e);
--        }
--
--        Name getterName = new Name(bmhGetter, mhName, i);
--        return getterName;
--    }
-+    protected abstract Data myData();
- 
-     @Override
-     final Object internalValues() {
--        Object[] boundValues = new Object[types().length()];
-+        Object[] boundValues = new Object[myData().fieldCount()];
-         for (int i = 0; i < boundValues.length; ++i) {
--            try {
--                switch (types().charAt(i)) {
--                case 'L': boundValues[i] = argL(i); break;
--                case 'I': boundValues[i] = argI(i); break;
--                case 'F': boundValues[i] = argF(i); break;
--                case 'D': boundValues[i] = argD(i); break;
--                case 'J': boundValues[i] = argJ(i); break;
--                default : throw new InternalError("unexpected type: " + types().charAt(i));
--                }
--            } catch (Throwable t) {
--                throw new InternalError(t);
--            }
-+            boundValues[i] = arg(i);
-         }
-         return Arrays.asList(boundValues);
-     }
- 
-+    public final Object arg(int i) {
-+        try {
-+            switch (myData().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: " + myData().types+"."+i);
-+    }
-     public final Object argL(int i) throws Throwable { return          myData().getters[i].invokeBasic(this); }
-     public final int    argI(int i) throws Throwable { return (int)    myData().getters[i].invokeBasic(this); }
-     public final float  argF(int i) throws Throwable { return (float)  myData().getters[i].invokeBasic(this); }
-@@ -236,54 +183,60 @@
-     public abstract BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float  narg) throws Throwable;
-     public abstract BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable;
- 
--    //
--    // getters to close bootstrap loops
--    //
--
--    public long   argJ0() throws Throwable { return argJ(0); }
--    public Object argL1() throws Throwable { return argL(1); }
-+    // 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 BMH_L extends BoundMethodHandle {
-         final Object argL0;
-         public BMH_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 String types() {
--            return types;
-+        public Data myData() {
-+            return DATA;
-         }
--        public static final String types = "L";
-+        public static final Data DATA = Data.getForClass("L", BMH_L.class);
-         @Override
-         public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
-             return new BMH_L(mt, lf, argL0);
-         }
-         @Override
-         public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
--            return new BMH_LL(mt, lf, argL0, narg);
-+            return (BoundMethodHandle) 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) Data.get("LI").constructor.invokeBasic(mt, lf, argL0, narg);
-+            return (BoundMethodHandle) 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) Data.get("LJ").constructor.invokeBasic(mt, lf, argL0, narg);
-+            return (BoundMethodHandle) 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) Data.get("LF").constructor.invokeBasic(mt, lf, argL0, narg);
-+            return (BoundMethodHandle) 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) Data.get("LD").constructor.invokeBasic(mt, lf, argL0, narg);
-+            return (BoundMethodHandle) DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, narg);
-         }
-     }
- 
-+/*
-     static final class BMH_LL extends BoundMethodHandle {
-         final Object argL0;
-         final Object argL1;
-@@ -293,33 +246,33 @@
-             this.argL1 = argL1;
-         }
-         @Override
--        public String types() {
--            return types;
-+        public Data myData() {
-+            return DATA;
-         }
--        public static final String types = "LL";
-+        public static final Data DATA = Data.getForClass("LL", BMH_LL.class);
-         @Override
-         public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
-             return new BMH_LL(mt, lf, argL0, argL1);
-         }
-         @Override
-         public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
--            return (BoundMethodHandle) Data.get("LLL").constructor.invokeBasic(mt, lf, argL0, argL1, narg);
-+            return (BoundMethodHandle) 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) Data.get("LLI").constructor.invokeBasic(mt, lf, argL0, argL1, narg);
-+            return (BoundMethodHandle) 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) Data.get("LLJ").constructor.invokeBasic(mt, lf, argL0, argL1, narg);
-+            return (BoundMethodHandle) 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) Data.get("LLF").constructor.invokeBasic(mt, lf, argL0, argL1, narg);
-+            return (BoundMethodHandle) 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) Data.get("LLD").constructor.invokeBasic(mt, lf, argL0, argL1, narg);
-+            return (BoundMethodHandle) DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
-         }
-     }
- 
-@@ -332,10 +285,10 @@
-             this.argL1 = argL1;
-         }
-         @Override
--        public String types() {
--            return types;
-+        public Data myData() {
-+            return DATA;
-         }
--        public static final String types = "JL";
-+        public static final Data DATA = Data.getForClass("JL", BMH_JL.class);
-         @Override public final long   argJ0() { return argJ0; }
-         @Override public final Object argL1() { return argL1; }
-         @Override
-@@ -344,103 +297,26 @@
-         }
-         @Override
-         public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
--            return (BoundMethodHandle) Data.get("JLL").constructor.invokeBasic(mt, lf, argJ0, argL1, narg);
-+            return (BoundMethodHandle) 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) Data.get("JLI").constructor.invokeBasic(mt, lf, argJ0, argL1, narg);
-+            return (BoundMethodHandle) 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) Data.get("JLJ").constructor.invokeBasic(mt, lf, argJ0, argL1, narg);
-+            return (BoundMethodHandle) 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) Data.get("JLF").constructor.invokeBasic(mt, lf, argJ0, argL1, narg);
-+            return (BoundMethodHandle) 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) Data.get("JLD").constructor.invokeBasic(mt, lf, argJ0, argL1, narg);
-+            return (BoundMethodHandle) DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
-         }
-     }
--
--    static final class BMH_J extends BoundMethodHandle {
--        final long argJ0;
--        public BMH_J(MethodType mt, LambdaForm lf, long argJ0) {
--            super(mt, lf);
--            this.argJ0 = argJ0;
--        }
--        @Override
--        public String types() {
--            return types;
--        }
--        public static final String types = "J";
--        @Override public final long argJ0() { return argJ0; }
--        @Override
--        public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
--            return new BMH_J(mt, lf, argJ0);
--        }
--        @Override
--        public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
--            return new BMH_JL(mt, lf, argJ0, narg);
--        }
--        @Override
--        public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
--            return (BoundMethodHandle) Data.get("JI").constructor.invokeBasic(mt, lf, argJ0, narg);
--        }
--        @Override
--        public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
--            return (BoundMethodHandle) Data.get("JJ").constructor.invokeBasic(mt, lf, argJ0, narg);
--        }
--        @Override
--        public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
--            return (BoundMethodHandle) Data.get("JF").constructor.invokeBasic(mt, lf, argJ0, narg);
--        }
--        @Override
--        public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
--            return (BoundMethodHandle) Data.get("JD").constructor.invokeBasic(mt, lf, argJ0, narg);
--        }
--    }
--
--    public static final MethodHandle MH_argJ0;
--    public static final MethodHandle MH_argL1;
--
--    static {
--        final Lookup LOOKUP = Lookup.IMPL_LOOKUP;
--        final Class<?> BMH = BoundMethodHandle.class;
--        try {
--            MH_argJ0 = LOOKUP.findVirtual(BMH, "argJ0", MethodType.methodType(long.class));
--            MH_argL1 = LOOKUP.findVirtual(BMH, "argL1", MethodType.methodType(Object.class));
--        } catch (NoSuchMethodException | IllegalAccessException e) {
--            throw new InternalError(e);
--        }
--    }
--
--    //
--    // reinvocation
--    //
--
--    /** Create a LF which simply reinvokes a target of the given basic type.
--     *  The target MH must have the reinvocation target bound to value #0.
--     */
--    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++;
--        Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
--        names[NEXT_MH] = getterName(names[THIS_BMH], 'L', 0);
--        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 Name(MH_invokeBasic, targetArgs);
--        return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_REINVOKE, new LambdaForm("BMH.reinvoke", ARG_LIMIT, names));
--    }
-+*/
- 
-     //
-     // BMH meta-data
-@@ -452,60 +328,157 @@
-     static class Data {
-         final String                             types;
-         final Class<? extends BoundMethodHandle> clazz;
--        final MethodHandle                       constructor;
-+        // Bootstrapping requires circular relations MH -> BMH -> Data -> MH
-+        // Therefore, we need a non-final link in the chain.  Use array elements.
-+        final MethodHandle[]                     constructor;
-         final MethodHandle[]                     getters;
-+        final Data[]                             extensions;
- 
--        Data(String types, Class<? extends BoundMethodHandle> clazz, MethodHandle constructor, MethodHandle[] getters) {
-+        public int fieldCount() {
-+            return types.length();
-+        }
-+        public char fieldType(int i) {
-+            return types.charAt(i);
-+        }
-+
-+        public String toString() {
-+            return "Data["+(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 Data EMPTY = new Data("", BoundMethodHandle.class);
-+
-+        private Data(String types, Class<? extends BoundMethodHandle> clazz) {
-             this.types = types;
-             this.clazz = clazz;
--            this.constructor = constructor;
--            this.getters = getters;
-+            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 Data[EXTENSION_TYPES.length()];
-         }
- 
--        static Map<String, Data> CACHE = new IdentityHashMap<>();
--
--        static Data make(String types) {
--            final Class<? extends BoundMethodHandle> cbmh = Factory.generateConcreteBMHClass(types);
--            final MethodHandle ctor = Factory.makeCbmhCtor(cbmh, types);
--            final MethodHandle[] getters = Factory.makeGetters(cbmh, types);
--            return new Data(types, cbmh, ctor, getters);
-+        private void initForBootstrap() {
-+            assert(!INIT_DONE);
-+            if (constructor[0] == null) {
-+                Factory.makeCtors(clazz, types, this.constructor);
-+                Factory.makeGetters(clazz, types, this.getters);
-+            }
-         }
- 
--        static Data get(String types) {
--            final String key = types.intern();
--            Data d = CACHE.get(key);
--            if (d == null) {
--                d = make(types);
--                Data e = CACHE.get(key);
--                if (e != null) {
--                    d = e;
--                } else {
--                    CACHE.put(key, d);
--                }
-+        private Data(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 Map<String, Data> CACHE = new IdentityHashMap<>();
-+        private static final boolean INIT_DONE;  // set after <clinit> finishes...
-+
-+        Data extendWithType(char type) {
-+            int i = extensionIndex(type);
-+            Data d = extensions[i];
-+            if (d != null)  return d;
-+            extensions[i] = d = get((types+type).intern());
-+            return d;
-+        }
-+
-+        Data extendWithIndex(byte index) {
-+            Data d = extensions[index];
-+            if (d != null)  return d;
-+            extensions[index] = d = get(types+EXTENSION_TYPES.charAt(index));
-+            return d;
-+        }
-+
-+        private static Data get(String types) {
-+            // Acquire cache lock for query.
-+            Data d = accessCache(types, null);
-+            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 = accessCache(types, null);
-+            // Class loading must have upgraded the cache.
-+            assert(d != null && !d.isPlaceholder());
-+            return d;
-+        }
-+        static Data getForClass(String types, Class<? extends BoundMethodHandle> clazz) {
-+            // clazz is a new class which is initializing its DATA field
-+            return accessCache(types, new Data(types, clazz));
-+        }
-+        private static synchronized Data accessCache(String types, Data upgrade) {
-+            assert(types == types.intern());  // caller responsibility
-+            Data d;
-+            if (upgrade != null) {
-+                assert((d = CACHE.get(types)) == null || d.isPlaceholder());
-+                d = upgrade;
-+                CACHE.put(types, d);
-+                return d;
-+            }
-+            d = CACHE.get(types);
-+            if (d != null) {
-+                return d;
-+            }
-+            d = new Data(types);
-+            assert(d.isPlaceholder());
-+            CACHE.put(types, d);
-             return d;
-         }
- 
-         static {
-             // pre-fill the BMH data cache with BMH's inner classes
--            final Class<BoundMethodHandle> BMH = BoundMethodHandle.class;
-+            final Class<BoundMethodHandle> rootCls = BoundMethodHandle.class;
-+            Data d0 = BoundMethodHandle.DATA;  // trigger class init
-+            assert(d0 == null || d0 == accessCache("", null)) : d0;
-             try {
--                for (Class<?> c : BMH.getDeclaredClasses()) {
--                    if (BMH.isAssignableFrom(c)) {
-+                for (Class<?> c : rootCls.getDeclaredClasses()) {
-+                    if (rootCls.isAssignableFrom(c)) {
-                         final Class<? extends BoundMethodHandle> cbmh = c.asSubclass(BoundMethodHandle.class);
--                        final String types = Factory.typesFromConcreteBMHClass(cbmh);
--                        final MethodHandle ctor = Factory.makeCbmhCtor(cbmh, types);
--                        final MethodHandle[] getters = Factory.makeGetters(cbmh, types);
--                        final Data d = new Data(types, cbmh, ctor, getters);
--                        CACHE.put(types.intern(), d);
-+                        Data d = Factory.dataFromConcreteBMHClass(cbmh);
-+                        assert(d != null) : cbmh.getName();
-+                        assert(d.clazz == cbmh);
-+                        assert(d == accessCache(d.types, null));
-                     }
-                 }
-             } catch (Throwable e) {
-                 throw new InternalError(e);
-             }
-+
-+            for (Data 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 Data getData(String types) {
-+        return Data.get(types);
-+    }
-+
-     /**
-      * Generation of concrete BMH classes.
-      *
-@@ -520,18 +493,20 @@
-      */
-     static class Factory {
- 
--        static final String JLO_SIG = "Ljava/lang/Object;";
--        static final String JLS_SIG = "Ljava/lang/String;";
--        static final String MH = "java/lang/invoke/MethodHandle";
--        static final String MH_SIG = "Ljava/lang/invoke/MethodHandle;";
--        static final String BMH = "java/lang/invoke/BoundMethodHandle";
--        static final String BMH_SIG = "Ljava/lang/invoke/BoundMethodHandle;";
--        static final String DATA = "java/lang/invoke/BoundMethodHandle$Data";
-+        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   = "Ljava/lang/invoke/MethodHandle;";
-+        static final String BMH      = "java/lang/invoke/BoundMethodHandle";
-+        static final String BMH_SIG  = "Ljava/lang/invoke/BoundMethodHandle;";
-+        static final String DATA     = "java/lang/invoke/BoundMethodHandle$Data";
-         static final String DATA_SIG = "Ljava/lang/invoke/BoundMethodHandle$Data;";
- 
--        static final String BMHDATA_GET_SIG = "(" + JLS_SIG + ")" + DATA_SIG;
--        static final String TYPES_SIG = "()" + JLS_SIG;
-+        static final String BMHDATA_EWI_SIG = "(B)" + DATA_SIG;
-+        static final String BMHDATA_GFC_SIG = "(" + JLS_SIG + JLC_SIG + ")" + DATA_SIG;
-         static final String MYDATA_SIG = "()" + DATA_SIG;
-+        static final String VOID_SIG   = "()V";
- 
-         static final String SIG_INCIPIT = "(Ljava/lang/invoke/MethodType;Ljava/lang/invoke/LambdaForm;";
- 
-@@ -547,7 +522,7 @@
-          * <pre>
-          * class BMH_<<types>> extends BMH {
-          *     <<fields>>
--         *     final String dataValueTypes() { return <<types>>; }
-+         *     final String dataValuemyTypes() { return <<types>>; }
-          * }
-          * </pre>
-          *
-@@ -572,25 +547,27 @@
-          *         this.argL1 = argL1;
-          *         this.argI2 = argI2;
-          *     }
--         *     public final String dataValueTypes() { return types; }
--         *     public static final String types = "LLI";
-+         *     public final String myTypes() { return TYPES; }
-+         *     public static final String TYPES = "LLI";
-+         *     public final Data myData() { return DATA; }
-+         *     public static final Data DATA = Data.getForClass(TYPES, BMH_LLI.class);
-          *     public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) {
--         *         return myData().constructor.invokeBasic(mt, lf, argL0, argL1, argI2);
-+         *         return DATA.constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2);
-          *     }
-          *     public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) {
--         *         return BMHData.get("LLIL").constructor.invokeBasic(mt, lf, argL0, argL1, argI2, narg);
-+         *         return BMHData.get("LLIL").constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
-          *     }
-          *     public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) {
--         *         return BMHData.get("LLII").constructor.invokeBasic(mt, lf, argL0, argL1, argI2, narg);
-+         *         return BMHData.get("LLII").constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
-          *     }
-          *     public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) {
--         *         return BMHData.get("LLIJ").constructor.invokeBasic(mt, lf, argL0, argL1, argI2, narg);
-+         *         return BMHData.get("LLIJ").constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
-          *     }
-          *     public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) {
--         *         return BMHData.get("LLIF").constructor.invokeBasic(mt, lf, argL0, argL1, argI2, narg);
-+         *         return BMHData.get("LLIF").constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
-          *     }
-          *     public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) {
--         *         return BMHData.get("LLID").constructor.invokeBasic(mt, lf, argL0, argL1, argI2, narg);
-+         *         return BMHData.get("LLID").constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
-          *     }
-          * }
-          * </pre>
-@@ -601,14 +578,13 @@
-         static Class<? extends BoundMethodHandle> generateConcreteBMHClass(String types) {
-             final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
- 
--            final String className = "java/lang/invoke/BMH_" + types;
-+            final String className = BMH + "$BMH_" + types;
-             final String sourceFile = "BMH_" + types;
--
-             cw.visit(V1_6, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, className, null, BMH, null);
-             cw.visitSource(sourceFile, null);
- 
--            // emit static types field
--            cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "types", JLS_SIG, null, types).visitEnd();
-+            // emit static types and data fields
-+            cw.visitField(ACC_PUBLIC + ACC_STATIC, "DATA", DATA_SIG, null, null).visitEnd();
- 
-             // emit bound argument fields
-             for (int i = 0; i < types.length(); ++i) {
-@@ -644,10 +620,20 @@
-             mv.visitMaxs(0, 0);
-             mv.visitEnd();
- 
--            // emit implementation of types()
--            mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "types", TYPES_SIG, null, null);
-+            // emit implementation of reinvokerTarget()
-+            mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "reinvokerTarget", "()" + MH_SIG, null, null);
-             mv.visitCode();
--            mv.visitLdcInsn(types);
-+            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 myData()
-+            mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "myData", MYDATA_SIG, null, null);
-+            mv.visitCode();
-+            mv.visitFieldInsn(GETSTATIC, className, "DATA", DATA_SIG);
-             mv.visitInsn(ARETURN);
-             mv.visitMaxs(0, 0);
-             mv.visitEnd();
-@@ -655,11 +641,13 @@
-             // emit clone()
-             mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "clone", makeSignature("", false), null, E_THROWABLE);
-             mv.visitCode();
--            // return myData().constructor.invokeBasic(mt, lf, argL0, ...)
-+            // return myData().constructor[0].invokeBasic(mt, lf, argL0, ...)
-             // obtain constructor
-             mv.visitVarInsn(ALOAD, 0);
--            mv.visitMethodInsn(INVOKESPECIAL, BMH, "myData", MYDATA_SIG);
--            mv.visitFieldInsn(GETFIELD, DATA, "constructor", MH_SIG);
-+            mv.visitFieldInsn(GETSTATIC, className, "DATA", DATA_SIG);
-+            mv.visitFieldInsn(GETFIELD, DATA, "constructor", "[" + MH_SIG);
-+            mv.visitInsn(ICONST_0);
-+            mv.visitInsn(AALOAD);
-             // load mt, lf
-             mv.visitVarInsn(ALOAD, 1);
-             mv.visitVarInsn(ALOAD, 2);
-@@ -674,14 +662,18 @@
-             // for each type, emit cloneExtendT()
-             for (Class<?> c : TYPES) {
-                 char t = Wrapper.basicTypeChar(c);
--                String extypes = types + t;
-                 mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "cloneExtend" + t, makeSignature(String.valueOf(t), false), null, E_THROWABLE);
-                 mv.visitCode();
--                // return BMHData.get(<extypes>).constructor.invokeBasic(mt, lf, argL0, ..., narg)
-+                // return DATA.extendWithIndex(extensionIndex(t)).constructor[0].invokeBasic(mt, lf, argL0, ..., narg)
-                 // obtain constructor
--                mv.visitLdcInsn(extypes);
--                mv.visitMethodInsn(INVOKESTATIC, DATA, "get", BMHDATA_GET_SIG);
--                mv.visitFieldInsn(GETFIELD, DATA, "constructor", MH_SIG);
-+                mv.visitFieldInsn(GETSTATIC, className, "DATA", DATA_SIG);
-+                int iconstInsn = ICONST_0 + extensionIndex(t);
-+                assert(iconstInsn <= ICONST_5);
-+                mv.visitInsn(iconstInsn);
-+                mv.visitMethodInsn(INVOKEVIRTUAL, DATA, "extendWithIndex", BMHDATA_EWI_SIG);
-+                mv.visitFieldInsn(GETFIELD, DATA, "constructor", "[" + MH_SIG);
-+                mv.visitInsn(ICONST_0);
-+                mv.visitInsn(AALOAD);
-                 // load mt, lf
-                 mv.visitVarInsn(ALOAD, 1);
-                 mv.visitVarInsn(ALOAD, 2);
-@@ -690,19 +682,31 @@
-                 // put narg on stack
-                 mv.visitVarInsn(typeLoadOp(t), 3);
-                 // finally, invoke the constructor and return
--                mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(extypes, false));
-+                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, DATA, "getForClass", BMHDATA_GFC_SIG);
-+            mv.visitFieldInsn(PUTSTATIC, className, "DATA", 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.defineAnonymousClass(BoundMethodHandle.class, classFile, null).asSubclass(BoundMethodHandle.class);
-+                UNSAFE.defineClass(className, classFile, 0, classFile.length).asSubclass(BoundMethodHandle.class);
-             UNSAFE.ensureClassInitialized(bmhClass);
- 
-             return bmhClass;
-@@ -745,24 +749,31 @@
-             }
-         }
- 
--        static MethodHandle[] makeGetters(Class<?> cbmhClass, String types) {
--            MethodHandle[] mhs = new MethodHandle[types.length()];
-+        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 String typesFromConcreteBMHClass(Class<? extends BoundMethodHandle> cbmh) {
-+        static Data dataFromConcreteBMHClass(Class<? extends BoundMethodHandle> cbmh) {
-             try {
--                Field ftypes = cbmh.getDeclaredField("types");
--                return (String) ftypes.get(null);
--            } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
--                throw new InternalError(e);
-+                Field fdata = cbmh.getDeclaredField("DATA");
-+                return (Data) fdata.get(null);
-+            } catch (Throwable ex) {
-+                throw new InternalError(ex);
-             }
-         }
- 
-@@ -832,13 +843,12 @@
-             return cmh;
-         }
- 
--        //
--        // Constants.
--        //
--
--        private static final Lookup LOOKUP = Lookup.IMPL_LOOKUP;
--        private static final Unsafe UNSAFE = Unsafe.getUnsafe();
--
-     }
- 
-+    private static final Lookup LOOKUP = Lookup.IMPL_LOOKUP;
-+
-+    /**
-+     * All subclasses must provide such a value describing their type signature.
-+     */
-+    static final Data DATA = Data.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;
- 
- /**
-@@ -233,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); }
-     }
- 
-@@ -248,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) {
-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,129 +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 java.util.Arrays;
--import static java.lang.invoke.LambdaForm.*;
--import static java.lang.invoke.MethodHandles.*;
--import static java.lang.invoke.MethodType.*;
--
--/**
-- * This method handle is used to optionally provide a count of how
-- * many times it was invoked.
-- *
-- * @author never
-- */
--class CountingMethodHandle extends BoundMethodHandle {
--    private MethodHandle target;
--    private int vmcount;
--
--    private CountingMethodHandle(MethodHandle target) {
--        super(target.type(), countingReinvokerForm(target.type().basicType()));
--        this.target = target;
--    }
--
--    /** 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;
--    }
--
--    @Override
--    public String types() {
--        return types;
--    }
--
--    public static final String types = "L";
--
--    @ForceInline
--    void vmcountBump() {
--        vmcount += 1;
--    }
--
--    /** Create a LF which reinvokes a target of the given basic type, and also bumps CountingMethodHandle.vmcount. */
--    private static LambdaForm countingReinvokerForm(MethodType mtype) {
--        assert(mtype == mtype.basicType());  // caller resp
--        LambdaForm reinvoker = mtype.form().cachedLambdaForm(MethodTypeForm.LF_COUNTER);
--        if (reinvoker != null)  return reinvoker;
--        MethodHandle MH_invokeBasic = MethodHandles.basicInvoker(mtype);
--        final int THIS_CMH    = 0;
--        final int ARG_BASE    = 1;
--        final int ARG_LIMIT   = ARG_BASE + mtype.parameterCount();
--        int nameCursor = ARG_LIMIT;
--        final int BUMP_COUNT  = nameCursor++;
--        final int NEXT_MH     = nameCursor++;
--        final int REINVOKE    = nameCursor++;
--        Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
--        names[BUMP_COUNT] = new Name(CountingMethodHandle.NF_vmcountBump, names[THIS_CMH]);
--        names[NEXT_MH] = BoundMethodHandle.getterName(names[THIS_CMH], 'L', 0);
--        Object[] targetArgs = Arrays.copyOfRange(names, THIS_CMH, ARG_LIMIT, Object[].class);
--        targetArgs[0] = names[NEXT_MH];  // overwrite CMH with next MH
--        names[REINVOKE] = new Name(MH_invokeBasic, targetArgs);
--        return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_COUNTER, new LambdaForm("CMH.reinvoke", ARG_LIMIT, names));
--    }
--
--    static final NamedFunction NF_vmcountBump;
--    static {
--        try {
--            NF_vmcountBump = new NamedFunction(Lookup.IMPL_LOOKUP
--                    .findVirtual(CountingMethodHandle.class, "vmcountBump", methodType(void.class)));
--        } catch (ReflectiveOperationException ex) {
--            throw new InternalError(ex);
--        }
--    }
--
--    @Override
--    public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
--        throw new IllegalStateException("NYI");
--    }
--
--    @Override
--    public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
--        throw new IllegalStateException("NYI");
--    }
--
--    @Override
--    public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
--        throw new IllegalStateException("NYI");
--    }
--
--    @Override
--    public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
--        throw new IllegalStateException("NYI");
--    }
--
--    @Override
--    public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
--        throw new IllegalStateException("NYI");
--    }
--
--    @Override
--    public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
--        throw new IllegalStateException("NYI");
--    }
--}
-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
-@@ -31,20 +31,25 @@
- 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 {
-     final MemberName member;
- 
-     // Constructors and factory methods in this class *must* be package scoped or private.
--    private DirectMethodHandle(MethodType mtype, MemberName member, LambdaForm form) {
-+    private DirectMethodHandle(MethodType mtype, LambdaForm form, MemberName member) {
-         super(mtype, form);
--        assert(member.isMethod() || member.isConstructor());
-         if (!member.isResolved())  throw new InternalError();
-         this.member = member;
-     }
-@@ -52,24 +57,54 @@
-     // Factory methods:
- 
-     static DirectMethodHandle make(Class<?> receiver, MemberName member) {
--        MethodType mtype = member.getMethodType();
-+        MethodType mtype = member.getMethodOrFieldType();
-         if (!member.isStatic()) {
--            if (!member.getDeclaringClass().isAssignableFrom(receiver))
-+            if (!member.getDeclaringClass().isAssignableFrom(receiver) || member.isConstructor())
-                 throw new InternalError(member.toString());
-             mtype = mtype.insertParameterTypes(0, receiver);
-         }
--        return new DirectMethodHandle(mtype, member, preparedLambdaForm(mtype.basicType(), member));
-+        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, member, lf);
-+        return new DirectMethodHandle(mt, lf, member);
-     }
- 
-     @Override
-@@ -116,7 +151,7 @@
-                 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(), concrete, preparedLambdaForm(type().basicType(), concrete));
-+                    return new DirectMethodHandle(type(), preparedLambdaForm(concrete), concrete);
-                 break;
-             }
-         }
-@@ -128,65 +163,117 @@
-      * Cache and share this structure among all methods with
-      * the same basicType and refKind.
-      */
--    private static LambdaForm preparedLambdaForm(MethodType mtype, MemberName m) {
--        assert(m.isInvocable()) : "not a method: " + m;
--        assert(mtype == mtype.basicType());
--        assert(m.getInvocationType().basicType() == mtype);
-+    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;
--        byte refKind = m.getReferenceKind();
--        int which = MethodTypeForm.LF_REF_KIND_FIRST + refKind;
--        if (refKind == REF_invokeStatic && shouldBeInitialized(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, refKind, which);
--            which = MethodTypeForm.LF_INVSTATIC_INIT;
-+            preparedLambdaForm(mtype, which);
-+            which = LF_INVSTATIC_INIT;
-         }
--        LambdaForm lform = preparedLambdaForm(mtype, refKind, which);
--        if (VerifyAccess.isSamePackage(m.getDeclaringClass(), MethodHandle.class))
--            // Help along bootstrapping...
--            lform.compileToBytecode();
-+        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, byte refKind, int which) {
-+
-+    private static LambdaForm preparedLambdaForm(MethodType mtype, int which) {
-         LambdaForm lform = mtype.form().cachedLambdaForm(which);
-         if (lform != null)  return lform;
--        lform = makePreparedLambdaForm(mtype, refKind, which);
-+        lform = makePreparedLambdaForm(mtype, which);
-         return mtype.form().setCachedLambdaForm(which, lform);
-     }
- 
--    private static LambdaForm makePreparedLambdaForm(MethodType mtype, byte refKind, int which) {
-+    private static LambdaForm makePreparedLambdaForm(MethodType mtype, int which) {
-+        boolean needsInit = (which == LF_INVSTATIC_INIT);
-+        boolean doesAlloc = (which == LF_NEWINVSPECIAL);
-         String linkerName, lambdaName;
--        switch (refKind) {
--        case REF_invokeVirtual:    linkerName = "linkToVirtual";    lambdaName = "DMH.invokeVirtual";    break;
--        case REF_invokeStatic:     linkerName = "linkToStatic";     lambdaName = "DMH.invokeStatic";     break;
--        case REF_invokeSpecial:    linkerName = "linkToSpecial";    lambdaName = "DMH.invokeSpecial";    break;
--        case REF_invokeInterface:  linkerName = "linkToInterface";  lambdaName = "DMH.invokeInterface";  break;
--        default:  throw new InternalError("refKind="+refKind);
-+        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);
--            assert(linker.isStatic());
-         } catch (ReflectiveOperationException ex) {
-             throw new InternalError(ex);
-         }
--        boolean needEnsureInit = (which == MethodTypeForm.LF_INVSTATIC_INIT);
-         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 (needEnsureInit)
-+        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
-+        } 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);
--        return new LambdaForm(lambdaName, ARG_LIMIT, names);
-+        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
-@@ -213,26 +300,19 @@
-             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 (MethodHandleImpl.UNSAFE.shouldBeInitialized(cls)) {
--                MethodHandleImpl.UNSAFE.ensureClassInitialized(cls);
-+            if (UNSAFE.shouldBeInitialized(cls)) {
-+                UNSAFE.ensureClassInitialized(cls);
-             }
-             return false;
-         }
--        return MethodHandleImpl.UNSAFE.shouldBeInitialized(cls);
--    }
--
--    /*non-public*/ static
--    @ForceInline
--    void ensureClassInitialized(Object memberObj) {
--        MemberName member = (MemberName) memberObj;
--        EnsureInitialized.INSTANCE.get(member.getDeclaringClass());
-+        return UNSAFE.shouldBeInitialized(cls);
-     }
- 
-     private static class EnsureInitialized extends ClassValue<WeakReference<Thread>> {
-         @Override
-         protected WeakReference<Thread> computeValue(Class<?> type) {
--            MethodHandleImpl.UNSAFE.ensureClassInitialized(type);
--            if (MethodHandleImpl.UNSAFE.shouldBeInitialized(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());
-@@ -241,29 +321,16 @@
-         static final EnsureInitialized INSTANCE = new EnsureInitialized();
-     }
- 
--    /** Static wrapper for DirectMethodHandle.internalMemberName. */
--    @ForceInline
--    /*non-public*/ static
--    Object internalMemberName(Object mh) {
--        return ((DirectMethodHandle)mh).member;
-+    private void ensureInitialized() {
-+        if (checkInitialized(member)) {
-+            // The coast is clear.  Delete the <clinit> barrier.
-+            if (member.isField())
-+                updateForm(preparedFieldLambdaForm(member));
-+            else
-+                updateForm(preparedLambdaForm(member));
-+        }
-     }
--
--    /** Static wrapper for DirectMethodHandle.internalMemberName.
--     * This one also forces initialization.
--     */
--    @ForceInline
--    /*non-public*/ static
--    Object internalMemberNameEnsureInit(Object mh) {
--        DirectMethodHandle dmh = (DirectMethodHandle)mh;
--        MemberName member = dmh.member;
--        if (ensureInitialized(member)) {
--            // The coast is clear.  Delete the cval and the barrier.
--            dmh.removeInitializationBarrier();
--        }
--        return member;
--    }
--
--    private static boolean ensureInitialized(MemberName member) {
-+    private static boolean checkInitialized(MemberName member) {
-         Class<?> defc = member.getDeclaringClass();
-         WeakReference<Thread> ref = EnsureInitialized.INSTANCE.get(defc);
-         if (ref == null) {
-@@ -273,65 +340,320 @@
-         // Somebody may still be running defc.<clinit>.
-         if (clinitThread == Thread.currentThread()) {
-             // If anybody is running defc.<clinit>, it is this thread.
--            if (MethodHandleImpl.UNSAFE.shouldBeInitialized(defc))
-+            if (UNSAFE.shouldBeInitialized(defc))
-                 // Yes, we are running it; keep the barrier for now.
-                 return false;
-         } else {
-             // We are in a random thread.  Block.
--            MethodHandleImpl.UNSAFE.ensureClassInitialized(defc);
-+            UNSAFE.ensureClassInitialized(defc);
-         }
--        assert(!MethodHandleImpl.UNSAFE.shouldBeInitialized(defc));
-+        assert(!UNSAFE.shouldBeInitialized(defc));
-         // put it into the final state
-         EnsureInitialized.INSTANCE.remove(defc);
-         return true;
-     }
- 
--    private void removeInitializationBarrier() {
--        MethodType mtype = type().basicType();
--        LambdaForm oldForm = mtype.form().cachedLambdaForm(MethodTypeForm.LF_INVSTATIC_INIT);
--        LambdaForm newForm = mtype.form().cachedLambdaForm(MethodTypeForm.LF_INVSTATIC);
--        assert(oldForm != null && newForm != null);
--        assert(this.form == oldForm || this.form == newForm);
--        if (this.form == oldForm) {
--            this.updateForm(newForm);  //dmh.form = newForm;
--        }
--        assert(this.form == newForm);
-+    /*non-public*/ static void ensureInitialized(Object mh) {
-+        ((DirectMethodHandle)mh).ensureInitialized();
-     }
- 
--    private static final NamedFunction NF_internalMemberName;
--    private static final NamedFunction NF_internalMemberNameEnsureInit;
-+    /** 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 {
--            NF_internalMemberName = new NamedFunction(DirectMethodHandle.class
--                    .getDeclaredMethod("internalMemberName", Object.class));
--            NF_internalMemberNameEnsureInit = new NamedFunction(DirectMethodHandle.class
--                    .getDeclaredMethod("internalMemberNameEnsureInit", Object.class));
--            NF_internalMemberName.resolve();
--            NF_internalMemberNameEnsureInit.resolve();
--            // bound
-+            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);
-         }
-     }
--
--/*
--    // Smoke-test:
--    static void testDirectMethodHandles() throws Throwable {
--        MemberName.Factory lookup = MemberName.getFactory();
--        MethodHandle asList_MH = make(Arrays.class.getMethod("asList", Object[].class));
--        System.out.println("about to call "+asList_MH);
--        Object[] abc = { "a", "bc" };
--        java.util.List<?> lst = (java.util.List<?>) asList_MH.invokeExact(abc);
--        System.out.println("lst="+lst);
--        MethodHandle toString_MH = make(new MemberName(Object.class.getMethod("toString")));
--        String s1 = (String) toString_MH.invokeExact((Object) lst);
--        toString_MH = make(new MemberName(Object.class.getMethod("toString"), true));
--        String s2 = (String) toString_MH.invokeExact((Object) lst);
--        System.out.println("[s1,s2,lst]="+Arrays.asList(s1, s2, lst.toString()));
--        MethodHandle toArray_MH = make(new MemberName(java.util.List.class.getMethod("toArray")));
--        Object[] arr = (Object[]) toArray_MH.invokeExact(lst);
--        System.out.println("toArray="+Arrays.toString(arr));
--    }
--    static { try { testDirectMethodHandles(); } catch (Throwable ex) { throw new RuntimeException(ex); } }
--//*/
- }
-diff --git a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
---- a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
-+++ b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
-@@ -30,7 +30,6 @@
- import java.lang.invoke.MethodHandles.Lookup;
- 
- import sun.invoke.util.Wrapper;
--import sun.misc.Unsafe;
- 
- import java.io.*;
- import java.util.*;
-@@ -82,7 +81,6 @@
-     private MethodVisitor mv;
- 
-     private static final MemberName.Factory MEMBERNAME_FACTORY = MemberName.getFactory();
--    private static final Unsafe UNSAFE = Unsafe.getUnsafe();
-     private static final Class<?> HOST_CLASS = LambdaForm.class;
- 
-     private InvokerBytecodeGenerator(LambdaForm lambdaForm, int localsMapSize,
-@@ -444,11 +442,7 @@
-         case 'L':
-             if (VerifyType.isNullConversion(Object.class, pclass))
-                 return;
--            // for BMH species, which are not representable as names in class files (anonymous classes!), cast to BMH instead
--            if (BoundMethodHandle.class.isAssignableFrom(pclass)) {
--                final String className = getInternalName(BoundMethodHandle.class);
--                mv.visitTypeInsn(Opcodes.CHECKCAST, className);
--            } else if (isStaticallyNameable(pclass)) {
-+            if (isStaticallyNameable(pclass)) {
-                 mv.visitTypeInsn(Opcodes.CHECKCAST, getInternalName(pclass));
-             } else {
-                 mv.visitLdcInsn(constantPlaceholder(pclass));
-@@ -525,7 +519,7 @@
- 
-         // iterate over the form's names, generating bytecode instructions for each
-         // start iterating at the first name following the arguments
--        for (int i = invokerType.parameterCount(); i < lambdaForm.names.length; i++) {
-+        for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
-             Name name = lambdaForm.names[i];
-             MemberName member = name.function.member();
- 
-@@ -595,15 +589,15 @@
- 
-     static private Class<?>[] STATICALLY_INVOCABLE_PACKAGES = {
-         // Sample classes from each package we are willing to bind to statically:
--        Object.class,
--        Arrays.class,
--        Unsafe.class
-+        java.lang.Object.class,
-+        java.util.Arrays.class,
-+        sun.misc.Unsafe.class
-         //MethodHandle.class already covered
-     };
- 
--    boolean isStaticallyInvocable(MemberName member) {
-+    static boolean isStaticallyInvocable(MemberName member) {
-         if (member == null)  return false;
--        assert !member.isConstructor();
-+        if (member.isConstructor())  return false;
-         Class<?> cls = member.getDeclaringClass();
-         if (cls.isArray() || cls.isPrimitive())
-             return false;  // FIXME
-@@ -618,7 +612,7 @@
-         return false;
-     }
- 
--    boolean isStaticallyNameable(Class<?> cls) {
-+    static boolean isStaticallyNameable(Class<?> cls) {
-         while (cls.isArray())
-             cls = cls.getComponentType();
-         if (cls.isPrimitive())
-@@ -643,10 +637,9 @@
-      */
-     void emitStaticInvoke(MemberName member, Name name) {
-         assert(member.equals(name.function.member()));
--        assert(member.isMethod());
-+        String cname = getInternalName(member.getDeclaringClass());
-         String mname = member.getName();
--        String mtype = member.getMethodType().toMethodDescriptorString();
--        String cname = getInternalName(member.getDeclaringClass());
-+        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
-@@ -660,22 +653,26 @@
-         }
- 
-         // 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:
--            mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, cname, mname, mtype);
--            break;
--        case REF_invokeStatic:
--            mv.visitMethodInsn(Opcodes.INVOKESTATIC,  cname, mname, mtype);
--            break;
--        case REF_invokeSpecial:
--            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, cname, mname, mtype);
--            break;
--        case REF_invokeInterface:
--            mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, cname, mname, mtype);
--            break;
--        default:
--            throw new InternalError(member.toString());
-+        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);
-     }
- 
-     /**
-@@ -753,6 +750,8 @@
-             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);
-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
-@@ -75,7 +75,7 @@
-         if (invoker != null)  return invoker;
-         MethodType mtype = targetType;
-         LambdaForm lform = invokeForm(mtype, MethodTypeForm.LF_EX_INVOKER);
--        invoker = new BoundMethodHandle.BMH_L(mtype.invokerType(), lform, mtype);
-+        invoker = BoundMethodHandle.bindSingle(mtype.invokerType(), lform, mtype);
-         assert(checkInvoker(invoker));
-         exactInvoker = invoker;
-         return invoker;
-@@ -87,7 +87,7 @@
-         MethodType mtype = targetType;
-         prepareForGenericCall(mtype);
-         LambdaForm lform = invokeForm(mtype, MethodTypeForm.LF_GEN_INVOKER);
--        invoker = new BoundMethodHandle.BMH_L(mtype.invokerType(), lform, mtype);
-+        invoker = BoundMethodHandle.bindSingle(mtype.invokerType(), lform, mtype);
-         assert(checkInvoker(invoker));
-         generalInvoker = invoker;
-         return invoker;
-@@ -241,7 +241,7 @@
-         assert(names.length == nameCursor);
-         if (MTYPE_ARG >= INARG_LIMIT) {
-             assert(names[MTYPE_ARG] == null);
--            names[MTYPE_ARG] = BoundMethodHandle.getterName(names[THIS_MH], 'L', 0);
-+            names[MTYPE_ARG] = BoundMethodHandle.getData("L").getterName(names[THIS_MH], 0);
-             // else if isLinker, then MTYPE is passed in from the caller (e.g., the JVM)
-         }
- 
-diff --git a/src/share/classes/java/lang/invoke/LambdaForm.java b/src/share/classes/java/lang/invoke/LambdaForm.java
---- a/src/share/classes/java/lang/invoke/LambdaForm.java
-+++ b/src/share/classes/java/lang/invoke/LambdaForm.java
-@@ -36,6 +36,7 @@
- import sun.invoke.util.Wrapper;
- import static java.lang.invoke.MethodHandleStatics.*;
- import static java.lang.invoke.MethodHandleNatives.Constants.*;
-+import java.lang.reflect.Field;
- 
- /**
-  * The symbolic, non-executable form of a method handle's invocation semantics.
-@@ -121,6 +122,7 @@
-     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;
-@@ -428,6 +430,9 @@
-      * 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;
-@@ -441,12 +446,14 @@
-     MemberName compileToBytecode() {
-         MethodType invokerType = methodType();
-         assert(vmentry == null || vmentry.getMethodType().basicType().equals(invokerType));
--        if (vmentry != null)
-+        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);
-@@ -574,7 +581,13 @@
-     }
- 
-     /** If the invocation count hits the threshold we spin bytecodes and call that subsequently. */
--    private static final int invocationThreshold = 30;
-+    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
-@@ -582,9 +595,10 @@
-     Object interpretWithArguments(Object... argumentValues) throws Throwable {
-         if (TRACE_INTERPRETER)
-             return interpretWithArgumentsTracing(argumentValues);
--        if (invocationCounter < invocationThreshold) {
-+        if (COMPILE_THRESHOLD != 0 &&
-+            invocationCounter < COMPILE_THRESHOLD) {
-             invocationCounter++;  // benign race
--            if (invocationCounter >= invocationThreshold) {
-+            if (invocationCounter >= COMPILE_THRESHOLD) {
-                 // Replace vmentry with a bytecode version of this LF.
-                 compileToBytecode();
-             }
-@@ -617,10 +631,10 @@
- 
-     Object interpretWithArgumentsTracing(Object... argumentValues) throws Throwable {
-         traceInterpreter("[ interpretWithArguments", this, argumentValues);
--        if (invocationCounter < invocationThreshold) {
-+        if (invocationCounter < COMPILE_THRESHOLD) {
-             int ctr = invocationCounter++;  // benign race
-             traceInterpreter("| invocationCounter", ctr);
--            if (invocationCounter >= invocationThreshold) {
-+            if (invocationCounter >= COMPILE_THRESHOLD) {
-                 compileToBytecode();
-             }
-         }
-@@ -759,17 +773,21 @@
-         return new LambdaForm(debugName, arity2, names2, result2);
-     }
- 
--    LambdaForm bind(char basicType, int namePos, int dataValuePos) {
--        Name dataValueName = BoundMethodHandle.getterName(names[0], basicType, dataValuePos);
--        return bind(names[namePos], dataValueName);
-+    LambdaForm bind(int namePos, BoundMethodHandle.Data oldData) {
-+        Name name = names[namePos];
-+        BoundMethodHandle.Data newData = oldData.extendWithType(name.type);
-+        return bind(name, newData.getterName(names[0], oldData.fieldCount()), oldData, newData);
-     }
--
--    LambdaForm bind(Name name, Name binding) {
-+    LambdaForm bind(Name name, Name binding,
-+                    BoundMethodHandle.Data oldData,
-+                    BoundMethodHandle.Data 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) {
-@@ -784,9 +802,32 @@
-         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);
-@@ -936,13 +977,16 @@
-             this.resolvedHandle = resolvedHandle;
-         }
- 
--        // The next 2 constructors are used to break circular dependencies on MH.invokeStatic, etc.
-+        // 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;
-@@ -1139,9 +1183,6 @@
-         }
- 
-         MemberName member() {
--            if (member == null) {
--                return resolvedHandle.internalMemberName();
--            }
-             assert(memberIsConsistent());
-             return member;
-         }
-@@ -1154,6 +1195,10 @@
-             return true;
-         }
- 
-+        Class<?> memberDeclaringClassOrNull() {
-+            return (member == null) ? null : member.getDeclaringClass();
-+        }
-+
-         char returnType() {
-             return basicType(methodType().returnType());
-         }
-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
-@@ -174,8 +174,10 @@
-      */
-     public MethodType getInvocationType() {
-         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;
-     }
- 
-@@ -322,6 +324,10 @@
-         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;
-     }
- 
-@@ -508,8 +514,16 @@
-     }
-     public MemberName asSpecial() {
-         switch (getReferenceKind()) {
--        case REF_invokeSpecial:  return this;
--        case REF_invokeVirtual:  return clone().changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual);
-+        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());
-     }
-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
-@@ -1089,7 +1089,6 @@
-         boolean lastMatch = asCollectorChecks(arrayType, 0);
-         if (isVarargsCollector() && lastMatch)
-             return this;
--        //return AdapterMethodHandle.makeVarargsCollector(this, arrayType);
-         return MethodHandleImpl.makeVarargsCollector(this, arrayType);
-     }
- 
-@@ -1238,7 +1237,6 @@
-         if (argc != 0) {
-             Class<?> arrayType = type().parameterType(argc-1);
-             if (arrayType.isArray()) {
--                //return AdapterMethodHandle.makeVarargsCollector(this, arrayType);
-                 return MethodHandleImpl.makeVarargsCollector(this, arrayType);
-             }
-         }
-@@ -1322,12 +1320,49 @@
-     }
- 
-     /*non-public*/
--    private BoundMethodHandle rebind() {
-+    MethodHandle rebind() {
-         // Bind 'this' into a new invoker, of the known class BMH.
-         MethodType type2 = type();
--        LambdaForm form2 = BoundMethodHandle.reinvokerForm(type2.basicType());
-+        LambdaForm form2 = reinvokerForm(type2.basicType());
-         // form2 = lambda (bmh, arg*) { thismh = bmh[0]; invokeBasic(thismh, arg*) }
--        return new BoundMethodHandle.BMH_L(type2, form2, this);
-+        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);
-+        }
-     }
- 
-     /**
-@@ -1342,14 +1377,14 @@
-     void updateForm(LambdaForm newForm) {
-         if (form == newForm)  return;
-         // ISSUE: Should we have a memory fence here?
--        MethodHandleImpl.UNSAFE.putObject(this, FORM_OFFSET, newForm);
-+        UNSAFE.putObject(this, FORM_OFFSET, newForm);
-         this.form.prepare();  // as in MethodHandle.<init>
-     }
- 
-     private static final long FORM_OFFSET;
-     static {
-         try {
--            FORM_OFFSET = MethodHandleImpl.UNSAFE.objectFieldOffset(MethodHandle.class.getDeclaredField("form"));
-+            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,13 +26,14 @@
- package java.lang.invoke;
- 
- import sun.invoke.util.VerifyType;
-+
-+import java.lang.invoke.BoundMethodHandle.Data;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.HashMap;
- 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.MethodHandleNatives.Constants.*;
- import static java.lang.invoke.MethodHandleStatics.*;
-@@ -50,41 +51,6 @@
-         MemberName.Factory.INSTANCE.getClass();
-     }
- 
--    /** Cache frequently used stuff. */
--    static final Unsafe UNSAFE = Unsafe.getUnsafe();
--
--    static MethodHandle makeAllocator(MethodHandle rawConstructor) {
--        MethodType rawConType = rawConstructor.type();
--        Class<?> allocateClass = rawConType.parameterType(0);
--        MethodType srcType = rawConType.dropParameterTypes(0, 1).changeReturnType(allocateClass);
--        final int THIS_MH     = 0;
--        final int ARG_BASE    = 1;
--        final int ARG_LIMIT   = ARG_BASE + srcType.parameterCount();
--        int nameCursor = ARG_LIMIT;
--        final int NEW_OBJ     = nameCursor++;
--        final int CALL_CTOR   = nameCursor++;
--        Name[] names = arguments(nameCursor - ARG_LIMIT, srcType.invokerType());
--        names[NEW_OBJ] = new Name(AllocatorData.UNSAFE_ALLOCATEINSTANCE, allocateClass);
--        Object[] conArgs = Arrays.copyOfRange(names, ARG_BASE-1, ARG_LIMIT, Object[].class);
--        conArgs[0] = names[NEW_OBJ];
--        names[CALL_CTOR] = new Name(rawConstructor, conArgs);
--        LambdaForm form = new LambdaForm("newInvokeSpecial", ARG_LIMIT, names, NEW_OBJ);
--        return new SimpleMethodHandle(srcType, form);
--    }
--
--    static final class AllocatorData {
--        static final MethodHandle UNSAFE_ALLOCATEINSTANCE;
--        static {
--            try {
--                assert(IMPL_LOOKUP != null) : "bootstrap problem";
--                UNSAFE_ALLOCATEINSTANCE =
--                    IMPL_LOOKUP.bind(UNSAFE, "allocateInstance", MethodType.methodType(Object.class, Class.class));
--            } catch (NoSuchMethodException | IllegalAccessException e) {
--                throw new InternalError(e);
--            }
--        }
--    }
--
-     static MethodHandle makeArrayElementAccessor(Class<?> arrayClass, boolean isSetter) {
-         if (!arrayClass.isArray())
-             throw newIllegalArgumentException("not an array: "+arrayClass);
-@@ -185,121 +151,6 @@
-         }
-     }
- 
--    static MethodHandle makeFieldAccessor(byte refKind, MemberName field, Class<?> receiver) {
--        boolean isStatic = !MethodHandleNatives.refKindHasReceiver(refKind);
--        MethodHandle accessor = FieldAccessor.getAccessor(refKind, field, receiver);
--
--        MethodType srcType = accessor.type();
--        MethodType mhType = srcType.dropParameterTypes(isStatic ? 0 : 1, 2);
--        MethodType lambdaType = mhType.insertParameterTypes(0, isStatic ? BoundMethodHandle.BMH_JL.class : BoundMethodHandle.BMH_J.class);
--
--        Name[] names = arguments(3, lambdaType);
--
--        final int _ARG    = 1;                // at this index in the names array, the object to be accessed is stored
--        final int _VALUE  = isStatic ? 1 : 2; // if this is for write access, the value to be written is stored at this index
--        final int _BASE   = names.length - 3; // the slots for _BASE and _NPE are shared
--        final int _NPE    = names.length - 3; // (the NPE check is used in the non-static case only, where _BASE is not required)
--        final int _OFFSET = names.length - 2;
--        final int _RESULT = names.length - 1;
--
--        if (isStatic) {
--            names[_OFFSET] = new Name(BoundMethodHandle.MH_argJ0, names[0]);
--            names[_BASE]   = new Name(BoundMethodHandle.MH_argL1, names[0]);
--        } else {
--            names[_NPE] = new Name(FieldAccessor.OBJECT_GETCLASS, names[_ARG]); // NPE check
--            names[_OFFSET] = new Name(BoundMethodHandle.MH_argJ0, names[0]);
--        }
--
--        Object[] args;
--        if (refKind == REF_putField || refKind == REF_putStatic) {
--            args = new Object[] { names[isStatic ? _BASE : _ARG], names[_OFFSET], names[_VALUE] };
--        } else {
--            args = new Object[] { names[isStatic ? _BASE : _ARG], names[_OFFSET] };
--        }
--        names[_RESULT] = new Name(accessor, args);
--        LambdaForm form = new LambdaForm(MethodHandleNatives.refKindName(refKind), lambdaType.parameterCount(), names);
--
--        BoundMethodHandle mh;
--        if (isStatic) {
--            long offset = MethodHandleNatives.staticFieldOffset(field);
--            Object base = MethodHandleNatives.staticFieldBase(field);
--            mh = new BoundMethodHandle.BMH_JL(mhType, form, offset, base);
--        } else {
--            long offset = MethodHandleNatives.objectFieldOffset(field);
--            mh = new BoundMethodHandle.BMH_J(mhType, form, offset);
--        }
--        return mh;
--    }
--
--    static final class FieldAccessor {
--        static final MethodHandle OBJECT_GETCLASS;
--        static {
--            try {
--                assert(IMPL_LOOKUP != null) : "bootstrap problem";
--                OBJECT_GETCLASS =
--                    IMPL_LOOKUP.findStatic(FieldAccessor.class, "getClass", MethodType.methodType(Object.class, Object.class));
--            } catch (NoSuchMethodException | IllegalAccessException e) {
--                throw new InternalError(e);
--            }
--        }
--
--        /** Static definition of Object.getClass for null-pointer checking. */
--        /*non-public*/ static
--        @ForceInline
--        Object getClass(Object obj) {
--            return obj.getClass();
--        }
--
--        static String name(byte refKind, MemberName field) {
--            String prefix = MethodHandleNatives.refKindIsGetter(refKind) ? "get" : "put";
--            String type   = Wrapper.forBasicType(field.getFieldType()).primitiveSimpleName();
--            String suffix = field.isVolatile() ? "Volatile" : "";
--            return prefix + Character.toUpperCase(type.charAt(0)) + type.substring(1) + suffix;
--        }
--        static MethodType type(byte refKind, MemberName field) {
--            Class<?> fieldClass = field.getFieldType();
--            return type(refKind, Object.class, fieldClass.isPrimitive() ? fieldClass : Object.class);
--        }
--        static MethodType strongType(byte refKind, MemberName field, Class<?> receiver) {
--            Class<?> fieldClass = field.getFieldType();
--            MethodType type;
--            if (MethodHandleNatives.refKindHasReceiver(refKind)) {
--                if (!field.getDeclaringClass().isAssignableFrom(receiver))
--                    throw new InternalError(field.toString());
--                type = type(refKind, receiver,     fieldClass);
--            } else {
--                type = type(refKind, Object.class, fieldClass);
--            }
--            return type.insertParameterTypes(0, Unsafe.class);
--        }
--        static MethodType type(byte refKind, Class<?> declaringClass, Class<?> fieldClass) {
--            if (MethodHandleNatives.refKindIsGetter(refKind))
--                return MethodType.methodType(fieldClass, declaringClass, long.class);
--            else
--                return MethodType.methodType(void.class, declaringClass, long.class, fieldClass);
--        }
--        static MethodHandle getAccessor(byte refKind, MemberName field, Class<?> receiver) {
--            if (!MethodHandleNatives.refKindIsField(refKind))
--                throw newIllegalArgumentException("refKind not a field: " + refKind);
--            String     name = name(refKind, field);
--            MethodType type = type(refKind, field);
--            MethodHandle mh;
--            try {
--                mh = IMPL_LOOKUP.findVirtual(Unsafe.class, name, type);
--            } catch (ReflectiveOperationException ex) {
--                throw uncaughtException(ex);
--            }
--            Class<?> declaringClass = field.getDeclaringClass();
--            Class<?> fieldClass     = field.getFieldType();
--            if ((!fieldClass.isPrimitive() && fieldClass != Object.class) || (MethodHandleNatives.refKindHasReceiver(refKind) && declaringClass != Object.class)) {
--                MethodType strongType = strongType(refKind, field, receiver);
--                mh = convertArguments(mh, strongType, 0);
--            }
--            mh = mh.bindImmediate(0, 'L', UNSAFE); // bind UNSAFE early
--            return mh;
--        }
--    }
--
-     /*non-public*/ static
-     MethodHandle convertArguments(MethodHandle target, MethodType srcType, int level) {
-         MethodType dstType = target.type();
-@@ -636,7 +487,7 @@
-         return new AsVarargsCollector(target, target.type(), arrayType);
-     }
- 
--    static class AsVarargsCollector extends BoundMethodHandle {
-+    static class AsVarargsCollector extends MethodHandle {
-         MethodHandle target;
-         final Class<?> arrayType;
-         MethodHandle cache;
-@@ -648,6 +499,8 @@
-             this.cache = target.asCollector(arrayType, 0);
-         }
- 
-+        @Override MethodHandle reinvokerTarget() { return target; }
-+
-         @Override
-         public boolean isVarargsCollector() {
-             return true;
-@@ -659,13 +512,6 @@
-         }
- 
-         @Override
--        public String types() {
--            return types;
--        }
--
--        public static final String types = "L";
--
--        @Override
-         public MethodHandle asType(MethodType newType) {
-             MethodType type = this.type();
-             int collectArg = type.parameterCount() - 1;
-@@ -730,36 +576,6 @@
-         MethodHandle permuteArguments(MethodType newType, int[] reorder) {
-             return asFixedArity().permuteArguments(newType, reorder);
-         }
--
--        @Override
--        public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
--            throw new IllegalStateException("NYI");
--        }
--
--        @Override
--        public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
--            throw new IllegalStateException("NYI");
--        }
--
--        @Override
--        public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
--            throw new IllegalStateException("NYI");
--        }
--
--        @Override
--        public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
--            throw new IllegalStateException("NYI");
--        }
--
--        @Override
--        public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
--            throw new IllegalStateException("NYI");
--        }
--
--        @Override
--        public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
--            throw new IllegalStateException("NYI");
--        }
-     }
- 
-     /** Can a checkcast adapter validly convert the target to srcType?
-@@ -1028,9 +844,7 @@
-                 indexes[i] = argIndex;
-             }
-         }
--        assert(nameCursor == names.length-1)
--                : Arrays.asList(Arrays.asList(names), names.length, nameCursor, srcType, lambdaType, target, spreadArgPos, spreadArgCount)//@@
--                ;  // leave room for the final call
-+        assert(nameCursor == names.length-1);  // leave room for the final call
- 
-         // Build argument array for the call.
-         Name[] targetArgs = new Name[targetType.parameterCount()];
-diff --git a/src/share/classes/java/lang/invoke/MethodHandleStatics.java b/src/share/classes/java/lang/invoke/MethodHandleStatics.java
---- a/src/share/classes/java/lang/invoke/MethodHandleStatics.java
-+++ b/src/share/classes/java/lang/invoke/MethodHandleStatics.java
-@@ -27,6 +27,7 @@
- 
- import java.security.AccessController;
- import java.security.PrivilegedAction;
-+import sun.misc.Unsafe;
- 
- /**
-  * This class consists exclusively of static names internal to the
-@@ -38,18 +39,22 @@
- 
-     private MethodHandleStatics() { }  // do not instantiate
- 
-+    static final Unsafe UNSAFE = Unsafe.getUnsafe();
-+
-     static final boolean DEBUG_METHOD_HANDLE_NAMES;
-     static final boolean DUMP_CLASS_FILES;
-     static final boolean TRACE_INTERPRETER;
-     static final boolean TRACE_METHOD_LINKAGE;
-+    static final Integer COMPILE_THRESHOLD;
-     static {
--        final Object[] values = { false, false, false, false };
-+        final Object[] values = { false, false, false, false, null };
-         AccessController.doPrivileged(new PrivilegedAction<Void>() {
-                 public Void run() {
-                     values[0] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
-                     values[1] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DUMP_CLASS_FILES");
-                     values[2] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_INTERPRETER");
-                     values[3] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE");
-+                    values[4] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD");
-                     return null;
-                 }
-             });
-@@ -57,6 +62,7 @@
-         DUMP_CLASS_FILES          = (Boolean) values[1];
-         TRACE_INTERPRETER         = (Boolean) values[2];
-         TRACE_METHOD_LINKAGE      = (Boolean) values[3];
-+        COMPILE_THRESHOLD         = (Integer) values[4];
-     }
- 
-     /*non-public*/ static String getNameString(MethodHandle target, MethodType type) {
-diff --git a/src/share/classes/java/lang/invoke/MethodHandles.java b/src/share/classes/java/lang/invoke/MethodHandles.java
---- a/src/share/classes/java/lang/invoke/MethodHandles.java
-+++ b/src/share/classes/java/lang/invoke/MethodHandles.java
-@@ -1111,9 +1111,7 @@
-         void checkAccess(byte refKind, Class<?> refc, MemberName m) throws IllegalAccessException {
-             assert(m.referenceKindIsConsistentWith(refKind) &&
-                    MethodHandleNatives.refKindIsValid(refKind) &&
--                   (MethodHandleNatives.refKindIsField(refKind) == m.isField()))
--                : m.toString()+"!="+refKind //@@
--                ;
-+                   (MethodHandleNatives.refKindIsField(refKind) == m.isField()));
-             int allowedModes = this.allowedModes;
-             if (allowedModes == TRUSTED)  return;
-             int mods = m.getModifiers();
-@@ -1221,7 +1219,7 @@
-         }
-         private MethodHandle getDirectField(byte refKind, Class<?> refc, MemberName field) throws IllegalAccessException {
-             checkField(refKind, refc, field);
--            MethodHandle mh = MethodHandleImpl.makeFieldAccessor(refKind, field, refc);
-+            MethodHandle mh = DirectMethodHandle.make(refc, field);
-             boolean doRestrict = (MethodHandleNatives.refKindHasReceiver(refKind) &&
-                                     restrictProtectedReceiver(field));
-             if (doRestrict)
-@@ -1231,8 +1229,7 @@
-         private MethodHandle getDirectConstructor(Class<?> refc, MemberName ctor) throws IllegalAccessException {
-             assert(ctor.isConstructor());
-             checkAccess(REF_newInvokeSpecial, refc, ctor);
--            MethodHandle mh = DirectMethodHandle.make(ctor);
--            return MethodHandleImpl.makeAllocator(mh).setVarargs(ctor);
-+            return DirectMethodHandle.make(ctor).setVarargs(ctor);
-         }
- 
-         /** Hook called from the JVM (via MethodHandleNatives) to link MH constants:
-diff --git a/src/share/classes/java/lang/invoke/MethodType.java b/src/share/classes/java/lang/invoke/MethodType.java
---- a/src/share/classes/java/lang/invoke/MethodType.java
-+++ b/src/share/classes/java/lang/invoke/MethodType.java
-@@ -824,6 +824,10 @@
-         return BytecodeDescriptor.unparse(this);
-     }
- 
-+    /*non-public*/ static String toFieldDescriptorString(Class<?> cls) {
-+        return BytecodeDescriptor.unparse(cls);
-+    }
-+
-     /// Serialization.
- 
-     /**
-@@ -896,18 +900,17 @@
-         // store them into the implementation-specific final fields.
-         checkRtype(rtype);
-         checkPtypes(ptypes);
--        unsafe.putObject(this, rtypeOffset, rtype);
--        unsafe.putObject(this, ptypesOffset, ptypes);
-+        UNSAFE.putObject(this, rtypeOffset, rtype);
-+        UNSAFE.putObject(this, ptypesOffset, ptypes);
-     }
- 
-     // Support for resetting final fields while deserializing
--    private static final sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
-     private static final long rtypeOffset, ptypesOffset;
-     static {
-         try {
--            rtypeOffset = unsafe.objectFieldOffset
-+            rtypeOffset = UNSAFE.objectFieldOffset
-                 (MethodType.class.getDeclaredField("rtype"));
--            ptypesOffset = unsafe.objectFieldOffset
-+            ptypesOffset = UNSAFE.objectFieldOffset
-                 (MethodType.class.getDeclaredField("ptypes"));
-         } catch (Exception ex) {
-             throw new Error(ex);
-diff --git a/src/share/classes/java/lang/invoke/MethodTypeForm.java b/src/share/classes/java/lang/invoke/MethodTypeForm.java
---- a/src/share/classes/java/lang/invoke/MethodTypeForm.java
-+++ b/src/share/classes/java/lang/invoke/MethodTypeForm.java
-@@ -59,22 +59,21 @@
-     final LambdaForm[] lambdaForms;
-     // Indexes into lambdaForms:
-     static final int
--            LF_REF_KIND_FIRST =  0,
--            LF_REF_KIND_LIMIT =  LF_REF_KIND_FIRST + REF_LIMIT,
--            // add more variations of DMH invokers as needed...
--            LF_INVSTATIC_INIT =  0 + LF_REF_KIND_LIMIT,
--            LF_INTERPRET      =  1 + LF_REF_KIND_LIMIT,
--            LF_COUNTER        =  2 + LF_REF_KIND_LIMIT,
--            LF_REINVOKE       =  3 + LF_REF_KIND_LIMIT,
--            LF_EX_LINKER      =  4 + LF_REF_KIND_LIMIT,
--            LF_EX_INVOKER     =  5 + LF_REF_KIND_LIMIT,
--            LF_GEN_LINKER     =  6 + LF_REF_KIND_LIMIT,
--            LF_GEN_INVOKER    =  7 + LF_REF_KIND_LIMIT,
--            LF_CS_LINKER      =  8 + LF_REF_KIND_LIMIT,
--            // add more here as needed...
--            LF_LIMIT          =  9 + LF_REF_KIND_LIMIT,
--            // Helpful alias:
--            LF_INVSTATIC      =  LF_REF_KIND_FIRST + REF_invokeStatic;
-+            LF_INVVIRTUAL     =  0,  // DMH invokeVirtual
-+            LF_INVSTATIC      =  1,
-+            LF_INVSPECIAL     =  2,
-+            LF_NEWINVSPECIAL  =  3,
-+            LF_INVINTERFACE   =  4,
-+            LF_INVSTATIC_INIT =  5,  // DMH invokeStatic with <clinit> barrier
-+            LF_INTERPRET      =  6,  // LF interpreter
-+            LF_COUNTER        =  7,  // CMH wrapper
-+            LF_REINVOKE       =  8,  // other wrapper
-+            LF_EX_LINKER      =  9,  // invokeExact_MT
-+            LF_EX_INVOKER     = 10,  // invokeExact MH
-+            LF_GEN_LINKER     = 11,
-+            LF_GEN_INVOKER    = 12,
-+            LF_CS_LINKER      = 13,  // linkToCallSite_CS
-+            LF_LIMIT          = 14;
- 
-     public MethodType erasedType() {
-         return erasedType;
-diff --git a/src/share/classes/java/lang/invoke/SimpleMethodHandle.java b/src/share/classes/java/lang/invoke/SimpleMethodHandle.java
---- a/src/share/classes/java/lang/invoke/SimpleMethodHandle.java
-+++ b/src/share/classes/java/lang/invoke/SimpleMethodHandle.java
-@@ -27,6 +27,8 @@
- 
- import static java.lang.invoke.LambdaForm.*;
- import static java.lang.invoke.MethodHandleNatives.Constants.*;
-+import java.util.logging.Level;
-+import java.util.logging.Logger;
- 
- /**
-  * A method handle whose behavior is determined only by its LambdaForm.
-@@ -40,7 +42,7 @@
-     @Override
-     MethodHandle bindArgument(int pos, char basicType, Object value) {
-         MethodType type2 = type().dropParameterTypes(pos, pos+1);
--        LambdaForm form2 = internalForm().bind(basicType, 1+pos, 0);
-+        LambdaForm form2 = internalForm().bind(1+pos, BoundMethodHandle.Data.EMPTY);
-         return BoundMethodHandle.bindSingle(type2, form2, basicType, value);
-     }
- 
-diff --git a/src/share/classes/sun/invoke/util/ValueConversions.java b/src/share/classes/sun/invoke/util/ValueConversions.java
---- a/src/share/classes/sun/invoke/util/ValueConversions.java
-+++ b/src/share/classes/sun/invoke/util/ValueConversions.java
-@@ -214,6 +214,12 @@
-     static private final Integer ZERO_INT = 0, ONE_INT = 1;
- 
-     /// Primitive conversions
-+    /**
-+     * Produce a Number which represents the given value {@code x}
-+     * according to the primitive type of the given wrapper {@code wrap}.
-+     * Caller must invoke intValue, byteValue, longValue (etc.) on the result
-+     * to retrieve the desired primitive value.
-+     */
-     public static Number primitiveConversion(Wrapper wrap, Object x, boolean cast) {
-         // Maybe merge this code with Wrapper.convert/cast.
-         Number res = null;
-@@ -238,6 +244,27 @@
-         return res;
-     }
- 
-+    /**
-+     * The JVM verifier allows boolean, byte, short, or char to widen to int.
-+     * Support exactly this conversion, from a boxed value type Boolean,
-+     * Byte, Short, Character, or Integer.
-+     */
-+    public static int widenSubword(Object x) {
-+        if (x instanceof Integer)
-+            return (int) x;
-+        else if (x instanceof Boolean)
-+            return fromBoolean((boolean) x);
-+        else if (x instanceof Character)
-+            return (char) x;
-+        else if (x instanceof Short)
-+            return (short) x;
-+        else if (x instanceof Byte)
-+            return (byte) x;
-+        else
-+            // Fail with a ClassCastException.
-+            return (int) x;
-+    }
-+
-     /// Converting primitives to references
- 
-     static Integer boxInteger(int x) {
-diff --git a/test/java/lang/invoke/MethodHandlesTest.java b/test/java/lang/invoke/MethodHandlesTest.java
---- a/test/java/lang/invoke/MethodHandlesTest.java
-+++ b/test/java/lang/invoke/MethodHandlesTest.java
-@@ -1821,7 +1821,7 @@
-         List<Object> argsToPass = new ArrayList<>(resList);
-         List<Object> argsToInsert = argsToPass.subList(pos, pos + ins);
-         if (verbosity >= 3)
--            System.out.println("insert: "+argsToInsert+" into "+target);
-+            System.out.println("insert: "+argsToInsert+" @"+pos+" into "+target);
-         @SuppressWarnings("cast")  // cast to spread Object... is helpful
-         MethodHandle target2 = MethodHandles.insertArguments(target, pos,
-                 (Object[]/*...*/) argsToInsert.toArray());
--- a/meth-lazy-7023639.init.patch	Sat Jul 21 16:50:34 2012 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,329 +0,0 @@
-Addendum to meth-lazy-7023639.patch.
-Fixes performance cliff with invokestatic on uninitialized classes.
-
-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
-@@ -122,6 +122,7 @@
-             default : throw new InternalError("unexpected type: " + xtype);
-             }
-         } catch (Throwable t) {
-+            System.out.println("cloneExtend "+Arrays.asList(type, form, xtype, x));//@@
-             throw new InternalError(t);
-         }
-     }
-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
-@@ -31,6 +31,8 @@
- import sun.invoke.util.VerifyAccess;
- import static java.lang.invoke.MethodHandleNatives.Constants.*;
- import static java.lang.invoke.LambdaForm.*;
-+import java.lang.ref.WeakReference;
-+import sun.invoke.util.ValueConversions;
- 
- /**
-  * The flavor of method handle which emulates invokespecial or invokestatic.
-@@ -133,14 +135,21 @@
-         assert(!m.isMethodHandleInvoke() || "invokeBasic".equals(m.getName())) : m;
-         byte refKind = m.getReferenceKind();
-         int which = MethodTypeForm.LF_REF_KIND_FIRST + refKind;
--        if (refKind == REF_invokeStatic && shouldBeInitialized(m))
-+        if (refKind == REF_invokeStatic && shouldBeInitialized(m)) {
-+            // precompute the barrier-free version:
-+            preparedLambdaForm(mtype, refKind, which);
-             which = MethodTypeForm.LF_INVSTATIC_INIT;
-+        }
-+        LambdaForm lform = preparedLambdaForm(mtype, refKind, which);
-+        if (VerifyAccess.isSamePackage(m.getDeclaringClass(), MethodHandle.class))
-+            // Help along bootstrapping...
-+            lform.compileToBytecode();
-+        return lform;
-+    }
-+    private static LambdaForm preparedLambdaForm(MethodType mtype, byte refKind, int which) {
-         LambdaForm lform = mtype.form().cachedLambdaForm(which);
-         if (lform != null)  return lform;
-         lform = makePreparedLambdaForm(mtype, refKind, which);
--        if (VerifyAccess.isSamePackage(m.getDeclaringClass(), MethodHandle.class))
--            // Help along bootstrapping...
--            lform.compileToBytecode();
-         return mtype.form().setCachedLambdaForm(which, lform);
-     }
- 
-@@ -167,13 +176,13 @@
-         final int ARG_LIMIT   = ARG_BASE + mtype.parameterCount();
-         int nameCursor = ARG_LIMIT;
-         final int GET_MEMBER  = nameCursor++;
--        final int ENSURE_INIT = (needEnsureInit ? nameCursor++ : -1);
-         final int LINKER_CALL = nameCursor++;
-         Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
-         assert(names.length == nameCursor);
--        names[GET_MEMBER] = new Name(NF_internalMemberName, names[DMH_THIS]);
--        if (ENSURE_INIT > 0)
--            names[ENSURE_INIT] = new Name(NF_ensureClassInitialized, names[GET_MEMBER]);
-+        if (needEnsureInit)
-+            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!
-         names[LINKER_CALL] = new Name(linker, outArgs);
-@@ -193,18 +202,23 @@
-             return false;
-         }
-         Class<?> cls = member.getDeclaringClass();
--        if (VerifyAccess.isSamePackage(MethodHandle.class, cls))
--            return false;
--        //return UNSAFE.shouldBeInitialized(cls);
--        if (MH_shouldBeInitialized == null) {
--            MethodHandleImpl.UNSAFE.ensureClassInitialized(cls);
-+        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;
-         }
--        try {
--            return (boolean) MH_shouldBeInitialized.invokeExact(MethodHandleImpl.UNSAFE, cls);
--        } catch (Throwable ex) {
--            throw new InternalError(ex);
-+        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 (MethodHandleImpl.UNSAFE.shouldBeInitialized(cls)) {
-+                MethodHandleImpl.UNSAFE.ensureClassInitialized(cls);
-+            }
-+            return false;
-         }
-+        return MethodHandleImpl.UNSAFE.shouldBeInitialized(cls);
-     }
- 
-     /*non-public*/ static
-@@ -213,40 +227,87 @@
-         MemberName member = (MemberName) memberObj;
-         EnsureInitialized.INSTANCE.get(member.getDeclaringClass());
-     }
--    private static class EnsureInitialized extends ClassValue<Void> {
-+
-+    private static class EnsureInitialized extends ClassValue<WeakReference<Thread>> {
-         @Override
--        protected Void computeValue(Class<?> type) {
-+        protected WeakReference<Thread> computeValue(Class<?> type) {
-             MethodHandleImpl.UNSAFE.ensureClassInitialized(type);
-+            if (MethodHandleImpl.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();
-     }
- 
-     /** 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.
-+     */
-+    @ForceInline
-+    /*non-public*/ static
-+    Object internalMemberNameEnsureInit(Object mh) {
-+        DirectMethodHandle dmh = (DirectMethodHandle)mh;
-+        MemberName member = dmh.member;
-+        if (ensureInitialized(member)) {
-+            // The coast is clear.  Delete the cval and the barrier.
-+            dmh.removeInitializationBarrier();
-+        }
-+        return member;
-+    }
-+
-+    private static boolean ensureInitialized(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 (MethodHandleImpl.UNSAFE.shouldBeInitialized(defc))
-+                // Yes, we are running it; keep the barrier for now.
-+                return false;
-+        } else {
-+            // We are in a random thread.  Block.
-+            MethodHandleImpl.UNSAFE.ensureClassInitialized(defc);
-+        }
-+        assert(!MethodHandleImpl.UNSAFE.shouldBeInitialized(defc));
-+        // put it into the final state
-+        EnsureInitialized.INSTANCE.remove(defc);
-+        return true;
-+    }
-+
-+    private void removeInitializationBarrier() {
-+        MethodType mtype = type().basicType();
-+        LambdaForm oldForm = mtype.form().cachedLambdaForm(MethodTypeForm.LF_INVSTATIC_INIT);
-+        LambdaForm newForm = mtype.form().cachedLambdaForm(MethodTypeForm.LF_INVSTATIC);
-+        assert(oldForm != null && newForm != null);
-+        assert(this.form == oldForm || this.form == newForm);
-+        if (this.form == oldForm) {
-+            this.updateForm(newForm);  //dmh.form = newForm;
-+        }
-+        assert(this.form == newForm);
-+    }
-+
-     private static final NamedFunction NF_internalMemberName;
--    private static final NamedFunction NF_ensureClassInitialized;
--    private static final MethodHandle MH_shouldBeInitialized;
-+    private static final NamedFunction NF_internalMemberNameEnsureInit;
-     static {
-         try {
-             NF_internalMemberName = new NamedFunction(DirectMethodHandle.class
-                     .getDeclaredMethod("internalMemberName", Object.class));
--            NF_ensureClassInitialized = new NamedFunction(DirectMethodHandle.class
--                    .getDeclaredMethod("ensureClassInitialized", Object.class));
--            MethodHandle mhOrNull = null;
--            try {
--                mhOrNull = make(Unsafe.class.getMethod("shouldBeInitialized", Class.class));
--            } catch (NoSuchMethodException ex) {
--                mhOrNull = null;  // new API call not in down-rev JVM
--            }
--            MH_shouldBeInitialized = mhOrNull;
-+            NF_internalMemberNameEnsureInit = new NamedFunction(DirectMethodHandle.class
-+                    .getDeclaredMethod("internalMemberNameEnsureInit", Object.class));
-             NF_internalMemberName.resolve();
--            NF_ensureClassInitialized.resolve();
--            MH_shouldBeInitialized.form.resolve();
-+            NF_internalMemberNameEnsureInit.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
---- a/src/share/classes/java/lang/invoke/LambdaForm.java
-+++ b/src/share/classes/java/lang/invoke/LambdaForm.java
-@@ -441,6 +441,8 @@
-     MemberName compileToBytecode() {
-         MethodType invokerType = methodType();
-         assert(vmentry == null || vmentry.getMethodType().basicType().equals(invokerType));
-+        if (vmentry != null)
-+            return vmentry;  // already compiled somehow
-         try {
-             vmentry = InvokerBytecodeGenerator.generateCustomizedCode(this, invokerType);
-             if (TRACE_INTERPRETER)
-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
-@@ -31,6 +31,8 @@
- 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,
-@@ -1327,4 +1329,29 @@
-         // form2 = lambda (bmh, arg*) { thismh = bmh[0]; invokeBasic(thismh, arg*) }
-         return new BoundMethodHandle.BMH_L(type2, form2, this);
-     }
-+
-+    /**
-+     * 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?
-+        MethodHandleImpl.UNSAFE.putObject(this, FORM_OFFSET, newForm);
-+        this.form.prepare();  // as in MethodHandle.<init>
-+    }
-+
-+    private static final long FORM_OFFSET;
-+    static {
-+        try {
-+            FORM_OFFSET = MethodHandleImpl.UNSAFE.objectFieldOffset(MethodHandle.class.getDeclaredField("form"));
-+        } catch (ReflectiveOperationException ex) {
-+            throw new InternalError(ex);
-+        }
-+    }
- }
-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
-@@ -289,7 +289,7 @@
-                                    Object[] appendixResult) {
-         MethodHandle bootstrapMethod = (MethodHandle)bootstrapMethodObj;
-         Class<?> caller = (Class<?>)callerObj;
--        String name = nameObj.toString();
-+        String name = nameObj.toString().intern();
-         MethodType type = (MethodType)typeObj;
-         appendixResult[0] = CallSite.makeSite(bootstrapMethod,
-                                               name,
-@@ -318,13 +318,15 @@
-     static MemberName linkMethod(Class<?> callerClass, int refKind,
-                                  Class<?> defc, String name, Object type,
-                                  Object[] appendixResult) {
--        if (TRACE_METHOD_LINKAGE)
--            System.out.println("linkMethod "+defc.getName()+"."+
--                               name+type+"/"+Integer.toHexString(refKind));
--        //assert(refKind == REF_invokeVirtual) : refKind;
-+        if (!TRACE_METHOD_LINKAGE)
-+            return linkMethodImpl(callerClass, refKind, defc, name, type, appendixResult);
-+        return linkMethodTracing(callerClass, refKind, defc, name, type, appendixResult);
-+    }
-+    static MemberName linkMethodImpl(Class<?> callerClass, int refKind,
-+                                     Class<?> defc, String name, Object type,
-+                                     Object[] appendixResult) {
-         if (defc != MethodHandle.class || refKind != REF_invokeVirtual)
-             throw new LinkageError("no such method "+defc.getName()+"."+name+type);
--
-         switch (name) {
-         case "invoke":
-             return Invokers.genericInvokerMethod(callerClass, type, appendixResult);
-@@ -333,6 +335,21 @@
-         }
-         throw new UnsupportedOperationException("linkMethod "+name);
-     }
-+    // Tracing logic:
-+    static MemberName linkMethodTracing(Class<?> callerClass, int refKind,
-+                                        Class<?> defc, String name, Object type,
-+                                        Object[] appendixResult) {
-+        System.out.println("linkMethod "+defc.getName()+"."+
-+                           name+type+"/"+Integer.toHexString(refKind));
-+        try {
-+            MemberName res = linkMethodImpl(callerClass, refKind, defc, name, type, appendixResult);
-+            System.out.println("linkMethod => "+res+" + "+appendixResult[0]);
-+            return res;
-+        } catch (Throwable ex) {
-+            System.out.println("linkMethod => throw "+ex);
-+            throw ex;
-+        }
-+    }
- 
-     /**
-      * The JVM is resolving a CONSTANT_MethodHandle CP entry.  And it wants our help.
-diff --git a/src/share/classes/java/lang/invoke/MethodTypeForm.java b/src/share/classes/java/lang/invoke/MethodTypeForm.java
---- a/src/share/classes/java/lang/invoke/MethodTypeForm.java
-+++ b/src/share/classes/java/lang/invoke/MethodTypeForm.java
-@@ -72,7 +72,9 @@
-             LF_GEN_INVOKER    =  7 + LF_REF_KIND_LIMIT,
-             LF_CS_LINKER      =  8 + LF_REF_KIND_LIMIT,
-             // add more here as needed...
--            LF_LIMIT          =  9 + LF_REF_KIND_LIMIT;
-+            LF_LIMIT          =  9 + LF_REF_KIND_LIMIT,
-+            // Helpful alias:
-+            LF_INVSTATIC      =  LF_REF_KIND_FIRST + REF_invokeStatic;
- 
-     public MethodType erasedType() {
-         return erasedType;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/meth-lazy-7023639.review.patch	Sat Jul 21 16:55:21 2012 -0700
@@ -0,0 +1,4532 @@
+Addendum to meth-lazy-7023639.patch.
+Fixes performance cliff with invokestatic on uninitialized classes.
+* * *
+Addendum to meth-lazy-7023639.patch.
+Adjustments to BMHs.
+
+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
+@@ -25,42 +25,24 @@
+ 
+ package java.lang.invoke;
+ 
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ACC_FINAL;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ACC_PUBLIC;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ACC_STATIC;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ACC_SUPER;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ALOAD;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ARETURN;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.DLOAD;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.FLOAD;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.GETFIELD;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ILOAD;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.INVOKESPECIAL;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.INVOKESTATIC;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.LLOAD;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.PUTFIELD;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.RETURN;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.V1_6;
+-import static java.lang.invoke.LambdaForm.arguments;
++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.MethodType.methodType;
++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.IdentityHashMap;
+-import java.util.Map;
++import java.util.HashMap;
+ 
+ import sun.invoke.util.ValueConversions;
+ import sun.invoke.util.Wrapper;
+-import sun.misc.Unsafe;
+ 
+ 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
+@@ -83,19 +65,17 @@
+         // for some type signatures, there exist pre-defined concrete BMH classes
+         try {
+             switch (xtype) {
+-            case 'L': return new BMH_L(type, form, x);
++            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':
+-                assert x instanceof Integer : "expected Integer, found " + x.getClass();
+-                return (BoundMethodHandle) Data.get("I").constructor.invokeBasic(type, form, ((Integer) x).intValue());
++                return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('I').constructor[0].invokeBasic(type, form, ValueConversions.widenSubword(x));
+             case 'J':
+-                assert x instanceof Long;
+-                return new BMH_J(type, form, ((Long) x).longValue());
++                return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('J').constructor[0].invokeBasic(type, form, (long) x);
+             case 'F':
+-                assert x instanceof Float;
+-                return (BoundMethodHandle) Data.get("F").constructor.invokeBasic(type, form, ((Float) x).floatValue());
++                return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('F').constructor[0].invokeBasic(type, form, (float) x);
+             case 'D':
+-                assert x instanceof Double;
+-                return (BoundMethodHandle) Data.get("D").constructor.invokeBasic(type, form, ((Double) x).doubleValue());
++                return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('D').constructor[0].invokeBasic(type, form, (double) x);
+             default : throw new InternalError("unexpected xtype: " + xtype);
+             }
+         } catch (Throwable t) {
+@@ -103,37 +83,29 @@
+         }
+     }
+ 
++    static MethodHandle bindSingle(MethodType type, LambdaForm form, Object x) {
++            return new Species_L(type, form, x);
++    }
++
+     MethodHandle cloneExtend(MethodType type, LambdaForm form, char xtype, Object x) {
+         try {
+             switch (xtype) {
+             case 'L': return cloneExtendL(type, form, x);
+-            case 'I':
+-                assert x instanceof Integer : "expected Integer, found " + x.getClass();
+-                return cloneExtendI(type, form, ((Integer) x).intValue());
+-            case 'J':
+-                assert x instanceof Long;
+-                return cloneExtendJ(type, form, ((Long) x).longValue());
+-            case 'F':
+-                assert x instanceof Float;
+-                return cloneExtendF(type, form, ((Float) x).floatValue());
+-            case 'D':
+-                assert x instanceof Double;
+-                return cloneExtendD(type, form, ((Double) x).doubleValue());
+-            default : throw new InternalError("unexpected type: " + xtype);
++            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 new InternalError("unexpected type: " + xtype);
+     }
+ 
+     @Override
+     MethodHandle bindArgument(int pos, char basicType, Object value) {
+         MethodType type = type().dropParameterTypes(pos, pos+1);
+-        LambdaForm form = internalForm().bind(basicType, 1+pos, tcount());
+-        if (basicType == 'I' && !(value instanceof Integer)) {
+-            // Cf. ValueConversions.unboxInteger
+-            value = ValueConversions.primitiveConversion(Wrapper.INT, value, true);
+-        }
++        LambdaForm form = internalForm().bind(1+pos, speciesData());
+         return cloneExtend(type, form, basicType, value);
+     }
+ 
+@@ -156,73 +128,48 @@
+          }
+     }
+ 
+-    public int tcount() {
+-        return types().length();
+-    }
+-
+-    protected final Data myData() {
+-        return Data.get(types());
++    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 type signature of a concrete BMH. Each concrete BMH is required
+-     * to implement this method to return its type signature as a constant String
+-     * (the {@link #types} field).
++     * 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.
+      */
+-    public abstract String types();
+-
+-    /**
+-     * All subclasses must provide such a value describing their type signature.
+-     */
+-    public static final String types = "";
+-
+-    public char type(int i) {
+-        return types().charAt(i);
+-    }
+-
+-    /**
+-     * 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.
+-     */
+-    static Name getterName(Name mhName, char basicType, int i) {
+-        Class<?> paramCls = Wrapper.forBasicType(basicType).primitiveType();
+-        MethodHandle bmhGetter;
+-        try {
+-            bmhGetter = Lookup.IMPL_LOOKUP.findVirtual(BoundMethodHandle.class, "arg" + basicType, methodType(paramCls, int.class));
+-        } catch (IllegalAccessException | NoSuchMethodException e) {
+-            throw new InternalError(e);
+-        }
+-
+-        Name getterName = new Name(bmhGetter, mhName, i);
+-        return getterName;
+-    }
++    protected abstract SpeciesData speciesData();
+ 
+     @Override
+     final Object internalValues() {
+-        Object[] boundValues = new Object[types().length()];
++        Object[] boundValues = new Object[speciesData().fieldCount()];
+         for (int i = 0; i < boundValues.length; ++i) {
+-            try {
+-                switch (types().charAt(i)) {
+-                case 'L': boundValues[i] = argL(i); break;
+-                case 'I': boundValues[i] = argI(i); break;
+-                case 'F': boundValues[i] = argF(i); break;
+-                case 'D': boundValues[i] = argD(i); break;
+-                case 'J': boundValues[i] = argJ(i); break;
+-                default : throw new InternalError("unexpected type: " + types().charAt(i));
+-                }
+-            } catch (Throwable t) {
+-                throw new InternalError(t);
+-            }
++            boundValues[i] = arg(i);
+         }
+         return Arrays.asList(boundValues);
+     }
+ 
+-    public final Object argL(int i) throws Throwable { return          myData().getters[i].invokeBasic(this); }
+-    public final int    argI(int i) throws Throwable { return (int)    myData().getters[i].invokeBasic(this); }
+-    public final float  argF(int i) throws Throwable { return (float)  myData().getters[i].invokeBasic(this); }
+-    public final double argD(int i) throws Throwable { return (double) myData().getters[i].invokeBasic(this); }
+-    public final long   argJ(int i) throws Throwable { return (long)   myData().getters[i].invokeBasic(this); }
++    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
+@@ -235,302 +182,330 @@
+     public abstract BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float  narg) throws Throwable;
+     public abstract BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable;
+ 
+-    //
+-    // getters to close bootstrap loops
+-    //
+-
+-    public long   argJ0() throws Throwable { return argJ(0); }
+-    public Object argL1() throws Throwable { return argL(1); }
++    // 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
+     //
+ 
+-    static final class BMH_L extends BoundMethodHandle {
++    private  // make it private to force users to access the enclosing class first
++    static final class Species_L extends BoundMethodHandle {
+         final Object argL0;
+-        public BMH_L(MethodType mt, LambdaForm lf, 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 String types() {
+-            return types;
++        public SpeciesData speciesData() {
++            return SPECIES_DATA;
+         }
+-        public static final String types = "L";
++        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 BMH_L(mt, lf, argL0);
++            return new Species_L(mt, lf, argL0);
+         }
+         @Override
+         public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
+-            return new BMH_LL(mt, lf, argL0, narg);
++            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) Data.get("LI").constructor.invokeBasic(mt, lf, argL0, narg);
++            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) Data.get("LJ").constructor.invokeBasic(mt, lf, argL0, narg);
++            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) Data.get("LF").constructor.invokeBasic(mt, lf, argL0, narg);
++            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) Data.get("LD").constructor.invokeBasic(mt, lf, argL0, narg);
++            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, narg);
+         }
+     }
+ 
+-    static final class BMH_LL extends BoundMethodHandle {
++/*
++    static final class Species_LL extends BoundMethodHandle {
+         final Object argL0;
+         final Object argL1;
+-        public BMH_LL(MethodType mt, LambdaForm lf, Object argL0, Object argL1) {
++        public Species_LL(MethodType mt, LambdaForm lf, Object argL0, Object argL1) {
+             super(mt, lf);
+             this.argL0 = argL0;
+             this.argL1 = argL1;
+         }
+         @Override
+-        public String types() {
+-            return types;
++        public SpeciesData speciesData() {
++            return SPECIES_DATA;
+         }
+-        public static final String types = "LL";
++        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 BMH_LL(mt, lf, argL0, argL1);
++            return new Species_LL(mt, lf, argL0, argL1);
+         }
+         @Override
+         public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
+-            return (BoundMethodHandle) Data.get("LLL").constructor.invokeBasic(mt, lf, argL0, argL1, narg);
++            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) Data.get("LLI").constructor.invokeBasic(mt, lf, argL0, argL1, narg);
++            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) Data.get("LLJ").constructor.invokeBasic(mt, lf, argL0, argL1, narg);
++            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) Data.get("LLF").constructor.invokeBasic(mt, lf, argL0, argL1, narg);
++            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) Data.get("LLD").constructor.invokeBasic(mt, lf, argL0, argL1, narg);
++            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
+         }
+     }
+ 
+-    static final class BMH_JL extends BoundMethodHandle {
++    static final class Species_JL extends BoundMethodHandle {
+         final long argJ0;
+         final Object argL1;
+-        public BMH_JL(MethodType mt, LambdaForm lf, long argJ0, Object argL1) {
++        public Species_JL(MethodType mt, LambdaForm lf, long argJ0, Object argL1) {
+             super(mt, lf);
+             this.argJ0 = argJ0;
+             this.argL1 = argL1;
+         }
+         @Override
+-        public String types() {
+-            return types;
++        public SpeciesData speciesData() {
++            return SPECIES_DATA;
+         }
+-        public static final String types = "JL";
++        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 BMH_JL(mt, lf, argJ0, argL1);
++            return new Species_JL(mt, lf, argJ0, argL1);
+         }
+         @Override
+         public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
+-            return (BoundMethodHandle) Data.get("JLL").constructor.invokeBasic(mt, lf, argJ0, argL1, narg);
++            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) Data.get("JLI").constructor.invokeBasic(mt, lf, argJ0, argL1, narg);
++            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) Data.get("JLJ").constructor.invokeBasic(mt, lf, argJ0, argL1, narg);
++            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) Data.get("JLF").constructor.invokeBasic(mt, lf, argJ0, argL1, narg);
++            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) Data.get("JLD").constructor.invokeBasic(mt, lf, argJ0, argL1, narg);
++            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
+         }
+     }
+-
+-    static final class BMH_J extends BoundMethodHandle {
+-        final long argJ0;
+-        public BMH_J(MethodType mt, LambdaForm lf, long argJ0) {
+-            super(mt, lf);
+-            this.argJ0 = argJ0;
+-        }
+-        @Override
+-        public String types() {
+-            return types;
+-        }
+-        public static final String types = "J";
+-        @Override public final long argJ0() { return argJ0; }
+-        @Override
+-        public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
+-            return new BMH_J(mt, lf, argJ0);
+-        }
+-        @Override
+-        public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
+-            return new BMH_JL(mt, lf, argJ0, narg);
+-        }
+-        @Override
+-        public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
+-            return (BoundMethodHandle) Data.get("JI").constructor.invokeBasic(mt, lf, argJ0, narg);
+-        }
+-        @Override
+-        public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
+-            return (BoundMethodHandle) Data.get("JJ").constructor.invokeBasic(mt, lf, argJ0, narg);
+-        }
+-        @Override
+-        public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
+-            return (BoundMethodHandle) Data.get("JF").constructor.invokeBasic(mt, lf, argJ0, narg);
+-        }
+-        @Override
+-        public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
+-            return (BoundMethodHandle) Data.get("JD").constructor.invokeBasic(mt, lf, argJ0, narg);
+-        }
+-    }
+-
+-    public static final MethodHandle MH_argJ0;
+-    public static final MethodHandle MH_argL1;
+-
+-    static {
+-        final Lookup LOOKUP = Lookup.IMPL_LOOKUP;
+-        final Class<?> BMH = BoundMethodHandle.class;
+-        try {
+-            MH_argJ0 = LOOKUP.findVirtual(BMH, "argJ0", MethodType.methodType(long.class));
+-            MH_argL1 = LOOKUP.findVirtual(BMH, "argL1", MethodType.methodType(Object.class));
+-        } catch (NoSuchMethodException | IllegalAccessException e) {
+-            throw new InternalError(e);
+-        }
+-    }
++*/
+ 
+     //
+-    // reinvocation
+-    //
+-
+-    /** Create a LF which simply reinvokes a target of the given basic type.
+-     *  The target MH must have the reinvocation target bound to value #0.
+-     */
+-    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++;
+-        Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
+-        names[NEXT_MH] = getterName(names[THIS_BMH], 'L', 0);
+-        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 Name(MH_invokeBasic, targetArgs);
+-        return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_REINVOKE, new LambdaForm("BMH.reinvoke", ARG_LIMIT, names));
+-    }
+-
+-    //
+-    // BMH meta-data
++    // BMH species meta-data
+     //
+ 
+     /**
+      * Meta-data wrapper for concrete BMH classes.
+      */
+-    static class Data {
++    static class SpeciesData {
+         final String                             types;
+         final Class<? extends BoundMethodHandle> clazz;
+-        final MethodHandle                       constructor;
++        // 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;
+ 
+-        Data(String types, Class<? extends BoundMethodHandle> clazz, MethodHandle constructor, MethodHandle[] getters) {
++        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;
+-            this.constructor = constructor;
+-            this.getters = getters;
++            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()];
+         }
+ 
+-        static Map<String, Data> CACHE = new IdentityHashMap<>();
+-
+-        static Data make(String types) {
+-            final Class<? extends BoundMethodHandle> cbmh = Factory.generateConcreteBMHClass(types);
+-            final MethodHandle ctor = Factory.makeCbmhCtor(cbmh, types);
+-            final MethodHandle[] getters = Factory.makeGetters(cbmh, types);
+-            return new Data(types, cbmh, ctor, getters);
++        private void initForBootstrap() {
++            assert(!INIT_DONE);
++            if (constructor[0] == null) {
++                Factory.makeCtors(clazz, types, this.constructor);
++                Factory.makeGetters(clazz, types, this.getters);
++            }
+         }
+ 
+-        static Data get(String types) {
+-            final String key = types.intern();
+-            Data d = CACHE.get(key);
+-            if (d == null) {
+-                d = make(types);
+-                Data e = CACHE.get(key);
+-                if (e != null) {
+-                    d = e;
+-                } else {
+-                    CACHE.put(key, d);
+-                }
++        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 data cache with BMH's inner classes
+-            final Class<BoundMethodHandle> BMH = BoundMethodHandle.class;
++            // 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 : BMH.getDeclaredClasses()) {
+-                    if (BMH.isAssignableFrom(c)) {
++                for (Class<?> c : rootCls.getDeclaredClasses()) {
++                    if (rootCls.isAssignableFrom(c)) {
+                         final Class<? extends BoundMethodHandle> cbmh = c.asSubclass(BoundMethodHandle.class);
+-                        final String types = Factory.typesFromConcreteBMHClass(cbmh);
+-                        final MethodHandle ctor = Factory.makeCbmhCtor(cbmh, types);
+-                        final MethodHandle[] getters = Factory.makeGetters(cbmh, types);
+-                        final Data d = new Data(types, cbmh, ctor, getters);
+-                        CACHE.put(types.intern(), d);
++                        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 is fit for binding a number of values adhering to a
++     * A concrete BMH species is fit for binding a number of values adhering to a
+      * given type pattern. Reference types are erased.
+      *
+-     * BMH classes are cached by type pattern.
++     * BMH species are cached by type pattern.
+      *
+-     * A concrete BMH has a number of fields with the concrete (possibly erased) types of
++     * 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 MH = "java/lang/invoke/MethodHandle";
+-        static final String MH_SIG = "Ljava/lang/invoke/MethodHandle;";
+-        static final String BMH = "java/lang/invoke/BoundMethodHandle";
+-        static final String BMH_SIG = "Ljava/lang/invoke/BoundMethodHandle;";
+-        static final String DATA = "java/lang/invoke/BoundMethodHandle$Data";
+-        static final String DATA_SIG = "Ljava/lang/invoke/BoundMethodHandle$Data;";
++        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 BMHDATA_GET_SIG = "(" + JLS_SIG + ")" + DATA_SIG;
+-        static final String TYPES_SIG = "()" + JLS_SIG;
+-        static final String MYDATA_SIG = "()" + DATA_SIG;
++        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;";
+ 
+@@ -541,12 +516,12 @@
+         /**
+          * Generate a concrete subclass of BMH for a given combination of bound types.
+          *
+-         * A concrete BMH subclass adheres to the following schema:
++         * A concrete BMH species adheres to the following schema:
+          *
+          * <pre>
+-         * class BMH_<<types>> extends BMH {
++         * class Species_<<types>> extends BoundMethodHandle {
+          *     <<fields>>
+-         *     final String dataValueTypes() { return <<types>>; }
++         *     final SpeciesData speciesData() { return SpeciesData.get("<<types>>"); }
+          * }
+          * </pre>
+          *
+@@ -557,39 +532,40 @@
+          * the type signature, adhering to the naming schema described in the definition of
+          * {@link #makeFieldName()}.
+          *
+-         * For example, a concrete BMH class for two reference and one integral bound values
++         * For example, a concrete BMH species for two reference and one integral bound values
+          * would have the following shape:
+          *
+          * <pre>
+-         * final class BMH_LLI extends BMH {
++         * class BoundMethodHandle { ... private static
++         * final class Species_LLI extends BoundMethodHandle {
+          *     final Object argL0;
+          *     final Object argL1;
+          *     final int argI2;
+-         *     public BMH_LLI(MethodType mt, LambdaForm lf, Object argL0, Object argL1, 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 String dataValueTypes() { return types; }
+-         *     public static final String types = "LLI";
++         *     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 myData().constructor.invokeBasic(mt, lf, argL0, argL1, argI2);
++         *         return SPECIES_DATA.constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2);
+          *     }
+          *     public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) {
+-         *         return BMHData.get("LLIL").constructor.invokeBasic(mt, lf, argL0, argL1, argI2, 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 BMHData.get("LLII").constructor.invokeBasic(mt, lf, argL0, argL1, argI2, 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 BMHData.get("LLIJ").constructor.invokeBasic(mt, lf, argL0, argL1, argI2, 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 BMHData.get("LLIF").constructor.invokeBasic(mt, lf, argL0, argL1, argI2, 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 BMHData.get("LLID").constructor.invokeBasic(mt, lf, argL0, argL1, argI2, narg);
++         *         return SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
+          *     }
+          * }
+          * </pre>
+@@ -600,14 +576,13 @@
+         static Class<? extends BoundMethodHandle> generateConcreteBMHClass(String types) {
+             final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
+ 
+-            final String className = "java/lang/invoke/BMH_" + types;
+-            final String sourceFile = "BMH_" + types;
+-
++            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 field
+-            cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "types", JLS_SIG, null, types).visitEnd();
++            // 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) {
+@@ -643,10 +618,20 @@
+             mv.visitMaxs(0, 0);
+             mv.visitEnd();
+ 
+-            // emit implementation of types()
+-            mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "types", TYPES_SIG, null, null);
++            // emit implementation of reinvokerTarget()
++            mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "reinvokerTarget", "()" + MH_SIG, null, null);
+             mv.visitCode();
+-            mv.visitLdcInsn(types);
++            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();
+@@ -654,11 +639,13 @@
+             // emit clone()
+             mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "clone", makeSignature("", false), null, E_THROWABLE);
+             mv.visitCode();
+-            // return myData().constructor.invokeBasic(mt, lf, argL0, ...)
++            // return speciesData().constructor[0].invokeBasic(mt, lf, argL0, ...)
+             // obtain constructor
+             mv.visitVarInsn(ALOAD, 0);
+-            mv.visitMethodInsn(INVOKESPECIAL, BMH, "myData", MYDATA_SIG);
+-            mv.visitFieldInsn(GETFIELD, DATA, "constructor", MH_SIG);
++            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);
+@@ -673,14 +660,18 @@
+             // for each type, emit cloneExtendT()
+             for (Class<?> c : TYPES) {
+                 char t = Wrapper.basicTypeChar(c);
+-                String extypes = types + t;
+                 mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "cloneExtend" + t, makeSignature(String.valueOf(t), false), null, E_THROWABLE);
+                 mv.visitCode();
+-                // return BMHData.get(<extypes>).constructor.invokeBasic(mt, lf, argL0, ..., narg)
++                // return SPECIES_DATA.extendWithIndex(extensionIndex(t)).constructor[0].invokeBasic(mt, lf, argL0, ..., narg)
+                 // obtain constructor
+-                mv.visitLdcInsn(extypes);
+-                mv.visitMethodInsn(INVOKESTATIC, DATA, "get", BMHDATA_GET_SIG);
+-                mv.visitFieldInsn(GETFIELD, DATA, "constructor", MH_SIG);
++                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);
+@@ -689,19 +680,31 @@
+                 // put narg on stack
+                 mv.visitVarInsn(typeLoadOp(t), 3);
+                 // finally, invoke the constructor and return
+-                mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(extypes, false));
++                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.defineAnonymousClass(BoundMethodHandle.class, classFile, null).asSubclass(BoundMethodHandle.class);
++                UNSAFE.defineClass(className, classFile, 0, classFile.length).asSubclass(BoundMethodHandle.class);
+             UNSAFE.ensureClassInitialized(bmhClass);
+ 
+             return bmhClass;
+@@ -744,24 +747,31 @@
+             }
+         }
+ 
+-        static MethodHandle[] makeGetters(Class<?> cbmhClass, String types) {
+-            MethodHandle[] mhs = new MethodHandle[types.length()];
++        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 String typesFromConcreteBMHClass(Class<? extends BoundMethodHandle> cbmh) {
++        static SpeciesData speciesDataFromConcreteBMHClass(Class<? extends BoundMethodHandle> cbmh) {
+             try {
+-                Field ftypes = cbmh.getDeclaredField("types");
+-                return (String) ftypes.get(null);
+-            } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
+-                throw new InternalError(e);
++                Field F_SPECIES_DATA = cbmh.getDeclaredField("SPECIES_DATA");
++                return (SpeciesData) F_SPECIES_DATA.get(null);
++            } catch (ReflectiveOperationException ex) {
++                throw new InternalError(ex);
+             }
+         }
+ 
+@@ -831,13 +841,12 @@
+             return cmh;
+         }
+ 
+-        //
+-        // Constants.
+-        //
+-
+-        private static final Lookup LOOKUP = Lookup.IMPL_LOOKUP;
+-        private static final Unsafe UNSAFE = Unsafe.getUnsafe();
+-
+     }
+ 
++    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;
+ 
+ /**
+@@ -233,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); }
+     }
+ 
+@@ -248,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) {
+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,129 +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 java.util.Arrays;
+-import static java.lang.invoke.LambdaForm.*;
+-import static java.lang.invoke.MethodHandles.*;
+-import static java.lang.invoke.MethodType.*;
+-
+-/**
+- * This method handle is used to optionally provide a count of how
+- * many times it was invoked.
+- *
+- * @author never
+- */
+-class CountingMethodHandle extends BoundMethodHandle {
+-    private MethodHandle target;
+-    private int vmcount;
+-
+-    private CountingMethodHandle(MethodHandle target) {
+-        super(target.type(), countingReinvokerForm(target.type().basicType()));
+-        this.target = target;
+-    }
+-
+-    /** 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;
+-    }
+-
+-    @Override
+-    public String types() {
+-        return types;
+-    }
+-
+-    public static final String types = "L";
+-
+-    @ForceInline
+-    void vmcountBump() {
+-        vmcount += 1;
+-    }
+-
+-    /** Create a LF which reinvokes a target of the given basic type, and also bumps CountingMethodHandle.vmcount. */
+-    private static LambdaForm countingReinvokerForm(MethodType mtype) {
+-        assert(mtype == mtype.basicType());  // caller resp
+-        LambdaForm reinvoker = mtype.form().cachedLambdaForm(MethodTypeForm.LF_COUNTER);
+-        if (reinvoker != null)  return reinvoker;
+-        MethodHandle MH_invokeBasic = MethodHandles.basicInvoker(mtype);
+-        final int THIS_CMH    = 0;
+-        final int ARG_BASE    = 1;
+-        final int ARG_LIMIT   = ARG_BASE + mtype.parameterCount();
+-        int nameCursor = ARG_LIMIT;
+-        final int BUMP_COUNT  = nameCursor++;
+-        final int NEXT_MH     = nameCursor++;
+-        final int REINVOKE    = nameCursor++;
+-        Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
+-        names[BUMP_COUNT] = new Name(CountingMethodHandle.NF_vmcountBump, names[THIS_CMH]);
+-        names[NEXT_MH] = BoundMethodHandle.getterName(names[THIS_CMH], 'L', 0);
+-        Object[] targetArgs = Arrays.copyOfRange(names, THIS_CMH, ARG_LIMIT, Object[].class);
+-        targetArgs[0] = names[NEXT_MH];  // overwrite CMH with next MH
+-        names[REINVOKE] = new Name(MH_invokeBasic, targetArgs);
+-        return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_COUNTER, new LambdaForm("CMH.reinvoke", ARG_LIMIT, names));
+-    }
+-
+-    static final NamedFunction NF_vmcountBump;
+-    static {
+-        try {
+-            NF_vmcountBump = new NamedFunction(Lookup.IMPL_LOOKUP
+-                    .findVirtual(CountingMethodHandle.class, "vmcountBump", methodType(void.class)));
+-        } catch (ReflectiveOperationException ex) {
+-            throw new InternalError(ex);
+-        }
+-    }
+-
+-    @Override
+-    public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
+-        throw new IllegalStateException("NYI");
+-    }
+-
+-    @Override
+-    public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
+-        throw new IllegalStateException("NYI");
+-    }
+-
+-    @Override
+-    public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
+-        throw new IllegalStateException("NYI");
+-    }
+-
+-    @Override
+-    public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
+-        throw new IllegalStateException("NYI");
+-    }
+-
+-    @Override
+-    public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
+-        throw new IllegalStateException("NYI");
+-    }
+-
+-    @Override
+-    public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
+-        throw new IllegalStateException("NYI");
+-    }
+-}
+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
+@@ -31,18 +31,25 @@
+ 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 {
+     final MemberName member;
+ 
+     // Constructors and factory methods in this class *must* be package scoped or private.
+-    private DirectMethodHandle(MethodType mtype, MemberName member, LambdaForm form) {
++    private DirectMethodHandle(MethodType mtype, LambdaForm form, MemberName member) {
+         super(mtype, form);
+-        assert(member.isMethod() || member.isConstructor());
+         if (!member.isResolved())  throw new InternalError();
+         this.member = member;
+     }
+@@ -50,24 +57,54 @@
+     // Factory methods:
+ 
+     static DirectMethodHandle make(Class<?> receiver, MemberName member) {
+-        MethodType mtype = member.getMethodType();
++        MethodType mtype = member.getMethodOrFieldType();
+         if (!member.isStatic()) {
+-            if (!member.getDeclaringClass().isAssignableFrom(receiver))
++            if (!member.getDeclaringClass().isAssignableFrom(receiver) || member.isConstructor())
+                 throw new InternalError(member.toString());
+             mtype = mtype.insertParameterTypes(0, receiver);
+         }
+-        return new DirectMethodHandle(mtype, member, preparedLambdaForm(mtype.basicType(), member));
++        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, member, lf);
++        return new DirectMethodHandle(mt, lf, member);
+     }
+ 
+     @Override
+@@ -114,7 +151,7 @@
+                 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(), concrete, preparedLambdaForm(type().basicType(), concrete));
++                    return new DirectMethodHandle(type(), preparedLambdaForm(concrete), concrete);
+                 break;
+             }
+         }
+@@ -126,58 +163,117 @@
+      * Cache and share this structure among all methods with
+      * the same basicType and refKind.
+      */
+-    private static LambdaForm preparedLambdaForm(MethodType mtype, MemberName m) {
+-        assert(m.isInvocable()) : "not a method: " + m;
+-        assert(mtype == mtype.basicType());
+-        assert(m.getInvocationType().basicType() == mtype);
++    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;
+-        byte refKind = m.getReferenceKind();
+-        int which = MethodTypeForm.LF_REF_KIND_FIRST + refKind;
+-        if (refKind == REF_invokeStatic && shouldBeInitialized(m))
+-            which = MethodTypeForm.LF_INVSTATIC_INIT;
++        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, refKind, which);
+-        if (VerifyAccess.isSamePackage(m.getDeclaringClass(), MethodHandle.class))
+-            // Help along bootstrapping...
+-            lform.compileToBytecode();
++        lform = makePreparedLambdaForm(mtype, which);
+         return mtype.form().setCachedLambdaForm(which, lform);
+     }
+ 
+-    private static LambdaForm makePreparedLambdaForm(MethodType mtype, byte refKind, int which) {
++    private static LambdaForm makePreparedLambdaForm(MethodType mtype, int which) {
++        boolean needsInit = (which == LF_INVSTATIC_INIT);
++        boolean doesAlloc = (which == LF_NEWINVSPECIAL);
+         String linkerName, lambdaName;
+-        switch (refKind) {
+-        case REF_invokeVirtual:    linkerName = "linkToVirtual";    lambdaName = "DMH.invokeVirtual";    break;
+-        case REF_invokeStatic:     linkerName = "linkToStatic";     lambdaName = "DMH.invokeStatic";     break;
+-        case REF_invokeSpecial:    linkerName = "linkToSpecial";    lambdaName = "DMH.invokeSpecial";    break;
+-        case REF_invokeInterface:  linkerName = "linkToInterface";  lambdaName = "DMH.invokeInterface";  break;
+-        default:  throw new InternalError("refKind="+refKind);
++        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);
+-            assert(linker.isStatic());
+         } catch (ReflectiveOperationException ex) {
+             throw new InternalError(ex);
+         }
+-        boolean needEnsureInit = (which == MethodTypeForm.LF_INVSTATIC_INIT);
+         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 ENSURE_INIT = (needEnsureInit ? nameCursor++ : -1);
+         final int LINKER_CALL = nameCursor++;
+         Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
+         assert(names.length == nameCursor);
+-        names[GET_MEMBER] = new Name(NF_internalMemberName, names[DMH_THIS]);
+-        if (ENSURE_INIT > 0)
+-            names[ENSURE_INIT] = new Name(NF_ensureClassInitialized, names[GET_MEMBER]);
++        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);
+-        return new LambdaForm(lambdaName, ARG_LIMIT, names);
++        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
+@@ -193,84 +289,371 @@
+             return false;
+         }
+         Class<?> cls = member.getDeclaringClass();
+-        if (VerifyAccess.isSamePackage(MethodHandle.class, cls))
+-            return false;
+-        //return UNSAFE.shouldBeInitialized(cls);
+-        if (MH_shouldBeInitialized == null) {
+-            MethodHandleImpl.UNSAFE.ensureClassInitialized(cls);
++        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;
+         }
+-        try {
+-            return (boolean) MH_shouldBeInitialized.invokeExact(MethodHandleImpl.UNSAFE, cls);
+-        } catch (Throwable ex) {
+-            throw new InternalError(ex);
++        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);
+     }
+ 
+-    /*non-public*/ static
+-    @ForceInline
+-    void ensureClassInitialized(Object memberObj) {
+-        MemberName member = (MemberName) memberObj;
+-        EnsureInitialized.INSTANCE.get(member.getDeclaringClass());
+-    }
+-    private static class EnsureInitialized extends ClassValue<Void> {
++    private static class EnsureInitialized extends ClassValue<WeakReference<Thread>> {
+         @Override
+-        protected Void computeValue(Class<?> type) {
+-            MethodHandleImpl.UNSAFE.ensureClassInitialized(type);
++        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();
+     }
+ 
+-    /** Static wrapper for DirectMethodHandle.internalMemberName. */
+-    /*non-public*/ static
+-    Object internalMemberName(Object mh) {
+-        return ((DirectMethodHandle)mh).member;
++    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;
+     }
+ 
+-    private static final NamedFunction NF_internalMemberName;
+-    private static final NamedFunction NF_ensureClassInitialized;
+-    private static final MethodHandle MH_shouldBeInitialized;
++    /*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 {
+-            NF_internalMemberName = new NamedFunction(DirectMethodHandle.class
+-                    .getDeclaredMethod("internalMemberName", Object.class));
+-            NF_ensureClassInitialized = new NamedFunction(DirectMethodHandle.class
+-                    .getDeclaredMethod("ensureClassInitialized", Object.class));
+-            MethodHandle mhOrNull = null;
+-            try {
+-                mhOrNull = make(Unsafe.class.getMethod("shouldBeInitialized", Class.class));
+-            } catch (NoSuchMethodException ex) {
+-                mhOrNull = null;  // new API call not in down-rev JVM
++            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();
+             }
+-            MH_shouldBeInitialized = mhOrNull;
+-            NF_internalMemberName.resolve();
+-            NF_ensureClassInitialized.resolve();
+-            MH_shouldBeInitialized.form.resolve();
+-            // bound
+         } catch (ReflectiveOperationException ex) {
+             throw new InternalError(ex);
+         }
+     }
+-
+-/*
+-    // Smoke-test:
+-    static void testDirectMethodHandles() throws Throwable {
+-        MemberName.Factory lookup = MemberName.getFactory();
+-        MethodHandle asList_MH = make(Arrays.class.getMethod("asList", Object[].class));
+-        System.out.println("about to call "+asList_MH);
+-        Object[] abc = { "a", "bc" };
+-        java.util.List<?> lst = (java.util.List<?>) asList_MH.invokeExact(abc);
+-        System.out.println("lst="+lst);
+-        MethodHandle toString_MH = make(new MemberName(Object.class.getMethod("toString")));
+-        String s1 = (String) toString_MH.invokeExact((Object) lst);
+-        toString_MH = make(new MemberName(Object.class.getMethod("toString"), true));
+-        String s2 = (String) toString_MH.invokeExact((Object) lst);
+-        System.out.println("[s1,s2,lst]="+Arrays.asList(s1, s2, lst.toString()));
+-        MethodHandle toArray_MH = make(new MemberName(java.util.List.class.getMethod("toArray")));
+-        Object[] arr = (Object[]) toArray_MH.invokeExact(lst);
+-        System.out.println("toArray="+Arrays.toString(arr));
+-    }
+-    static { try { testDirectMethodHandles(); } catch (Throwable ex) { throw new RuntimeException(ex); } }
+-//*/
+ }
+diff --git a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
+--- a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
++++ b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
+@@ -30,7 +30,6 @@
+ import java.lang.invoke.MethodHandles.Lookup;
+ 
+ import sun.invoke.util.Wrapper;
+-import sun.misc.Unsafe;
+ 
+ import java.io.*;
+ import java.util.*;
+@@ -82,7 +81,6 @@
+     private MethodVisitor mv;
+ 
+     private static final MemberName.Factory MEMBERNAME_FACTORY = MemberName.getFactory();
+-    private static final Unsafe UNSAFE = Unsafe.getUnsafe();
+     private static final Class<?> HOST_CLASS = LambdaForm.class;
+ 
+     private InvokerBytecodeGenerator(LambdaForm lambdaForm, int localsMapSize,
+@@ -444,11 +442,7 @@
+         case 'L':
+             if (VerifyType.isNullConversion(Object.class, pclass))
+                 return;
+-            // for BMH species, which are not representable as names in class files (anonymous classes!), cast to BMH instead
+-            if (BoundMethodHandle.class.isAssignableFrom(pclass)) {
+-                final String className = getInternalName(BoundMethodHandle.class);
+-                mv.visitTypeInsn(Opcodes.CHECKCAST, className);
+-            } else if (isStaticallyNameable(pclass)) {
++            if (isStaticallyNameable(pclass)) {
+                 mv.visitTypeInsn(Opcodes.CHECKCAST, getInternalName(pclass));
+             } else {
+                 mv.visitLdcInsn(constantPlaceholder(pclass));
+@@ -525,7 +519,7 @@
+ 
+         // iterate over the form's names, generating bytecode instructions for each
+         // start iterating at the first name following the arguments
+-        for (int i = invokerType.parameterCount(); i < lambdaForm.names.length; i++) {
++        for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
+             Name name = lambdaForm.names[i];
+             MemberName member = name.function.member();
+ 
+@@ -595,15 +589,15 @@
+ 
+     static private Class<?>[] STATICALLY_INVOCABLE_PACKAGES = {
+         // Sample classes from each package we are willing to bind to statically:
+-        Object.class,
+-        Arrays.class,
+-        Unsafe.class
++        java.lang.Object.class,
++        java.util.Arrays.class,
++        sun.misc.Unsafe.class
+         //MethodHandle.class already covered
+     };
+ 
+-    boolean isStaticallyInvocable(MemberName member) {
++    static boolean isStaticallyInvocable(MemberName member) {
+         if (member == null)  return false;
+-        assert !member.isConstructor();
++        if (member.isConstructor())  return false;
+         Class<?> cls = member.getDeclaringClass();
+         if (cls.isArray() || cls.isPrimitive())
+             return false;  // FIXME
+@@ -618,7 +612,7 @@
+         return false;
+     }
+ 
+-    boolean isStaticallyNameable(Class<?> cls) {
++    static boolean isStaticallyNameable(Class<?> cls) {
+         while (cls.isArray())
+             cls = cls.getComponentType();
+         if (cls.isPrimitive())
+@@ -643,10 +637,9 @@
+      */
+     void emitStaticInvoke(MemberName member, Name name) {
+         assert(member.equals(name.function.member()));
+-        assert(member.isMethod());
++        String cname = getInternalName(member.getDeclaringClass());
+         String mname = member.getName();
+-        String mtype = member.getMethodType().toMethodDescriptorString();
+-        String cname = getInternalName(member.getDeclaringClass());
++        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
+@@ -660,22 +653,26 @@
+         }
+ 
+         // 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:
+-            mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, cname, mname, mtype);
+-            break;
+-        case REF_invokeStatic:
+-            mv.visitMethodInsn(Opcodes.INVOKESTATIC,  cname, mname, mtype);
+-            break;
+-        case REF_invokeSpecial:
+-            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, cname, mname, mtype);
+-            break;
+-        case REF_invokeInterface:
+-            mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, cname, mname, mtype);
+-            break;
+-        default:
+-            throw new InternalError(member.toString());
++        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);
+     }
+ 
+     /**
+@@ -753,6 +750,8 @@
+             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);
+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
+@@ -75,7 +75,7 @@
+         if (invoker != null)  return invoker;
+         MethodType mtype = targetType;
+         LambdaForm lform = invokeForm(mtype, MethodTypeForm.LF_EX_INVOKER);
+-        invoker = new BoundMethodHandle.BMH_L(mtype.invokerType(), lform, mtype);
++        invoker = BoundMethodHandle.bindSingle(mtype.invokerType(), lform, mtype);
+         assert(checkInvoker(invoker));
+         exactInvoker = invoker;
+         return invoker;
+@@ -87,7 +87,7 @@
+         MethodType mtype = targetType;
+         prepareForGenericCall(mtype);
+         LambdaForm lform = invokeForm(mtype, MethodTypeForm.LF_GEN_INVOKER);
+-        invoker = new BoundMethodHandle.BMH_L(mtype.invokerType(), lform, mtype);
++        invoker = BoundMethodHandle.bindSingle(mtype.invokerType(), lform, mtype);
+         assert(checkInvoker(invoker));
+         generalInvoker = invoker;
+         return invoker;
+@@ -241,7 +241,7 @@
+         assert(names.length == nameCursor);
+         if (MTYPE_ARG >= INARG_LIMIT) {
+             assert(names[MTYPE_ARG] == null);
+-            names[MTYPE_ARG] = BoundMethodHandle.getterName(names[THIS_MH], 'L', 0);
++            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)
+         }
+ 
+@@ -320,9 +320,7 @@
+             form.genericInvoker = gamh;
+             return gamh;
+         } catch (Exception ex) {
+-            Error err = new InternalError("Exception while resolving inexact invoke", ex);
+-            err.initCause(ex);
+-            throw err;
++            throw new InternalError("Exception while resolving inexact invoke", ex);
+         }
+     }
+ 
+diff --git a/src/share/classes/java/lang/invoke/LambdaForm.java b/src/share/classes/java/lang/invoke/LambdaForm.java
+--- a/src/share/classes/java/lang/invoke/LambdaForm.java
++++ b/src/share/classes/java/lang/invoke/LambdaForm.java
+@@ -36,6 +36,8 @@
+ 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.
+@@ -121,6 +123,7 @@
+     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;
+@@ -428,6 +431,9 @@
+      * 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;
+@@ -441,10 +447,14 @@
+     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);
+@@ -572,7 +582,13 @@
+     }
+ 
+     /** If the invocation count hits the threshold we spin bytecodes and call that subsequently. */
+-    private static final int invocationThreshold = 30;
++    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
+@@ -580,9 +596,10 @@
+     Object interpretWithArguments(Object... argumentValues) throws Throwable {
+         if (TRACE_INTERPRETER)
+             return interpretWithArgumentsTracing(argumentValues);
+-        if (invocationCounter < invocationThreshold) {
++        if (COMPILE_THRESHOLD != 0 &&
++            invocationCounter < COMPILE_THRESHOLD) {
+             invocationCounter++;  // benign race
+-            if (invocationCounter >= invocationThreshold) {
++            if (invocationCounter >= COMPILE_THRESHOLD) {
+                 // Replace vmentry with a bytecode version of this LF.
+                 compileToBytecode();
+             }
+@@ -615,10 +632,10 @@
+ 
+     Object interpretWithArgumentsTracing(Object... argumentValues) throws Throwable {
+         traceInterpreter("[ interpretWithArguments", this, argumentValues);
+-        if (invocationCounter < invocationThreshold) {
++        if (invocationCounter < COMPILE_THRESHOLD) {
+             int ctr = invocationCounter++;  // benign race
+             traceInterpreter("| invocationCounter", ctr);
+-            if (invocationCounter >= invocationThreshold) {
++            if (invocationCounter >= COMPILE_THRESHOLD) {
+                 compileToBytecode();
+             }
+         }
+@@ -757,17 +774,21 @@
+         return new LambdaForm(debugName, arity2, names2, result2);
+     }
+ 
+-    LambdaForm bind(char basicType, int namePos, int dataValuePos) {
+-        Name dataValueName = BoundMethodHandle.getterName(names[0], basicType, dataValuePos);
+-        return bind(names[namePos], dataValueName);
++    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) {
++    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) {
+@@ -782,9 +803,32 @@
+         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);
+@@ -934,13 +978,16 @@
+             this.resolvedHandle = resolvedHandle;
+         }
+ 
+-        // The next 2 constructors are used to break circular dependencies on MH.invokeStatic, etc.
++        // 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;
+@@ -964,6 +1011,13 @@
+             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)) {
+@@ -1137,21 +1191,23 @@
+         }
+ 
+         MemberName member() {
+-            if (member == null) {
+-                return resolvedHandle.internalMemberName();
+-            }
+-            assert(memberIsConsistent());
++            assert(assertMemberIsConsistent());
+             return member;
+         }
+ 
+-        boolean memberIsConsistent() {
++        // Called only from assert.
++        private boolean assertMemberIsConsistent() {
+             if (resolvedHandle instanceof DirectMethodHandle) {
+                 MemberName m = resolvedHandle.internalMemberName();
+-                assert(m.equals(member)) : Arrays.asList(member, m, resolvedHandle);
++                assert(m.equals(member));
+             }
+             return true;
+         }
+ 
++        Class<?> memberDeclaringClassOrNull() {
++            return (member == null) ? null : member.getDeclaringClass();
++        }
++
+         char returnType() {
+             return basicType(methodType().returnType());
+         }
+@@ -1361,9 +1417,6 @@
+             return true;
+         }
+ 
+-        public boolean equals(Object x) {
+-            return x instanceof Name && equals((Name)x);
+-        }
+         /**
+          * Does this Name precede the given binding node in some canonical order?
+          * This predicate is used to order data bindings (via insertion sort)
+@@ -1393,6 +1446,7 @@
+             }
+             return false;
+         }
++
+         public boolean equals(Name that) {
+             if (this == that)  return true;
+             if (isParam())
+@@ -1404,6 +1458,11 @@
+                 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);
+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
+@@ -40,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
+@@ -77,32 +78,6 @@
+     //@Injected int         vmindex;
+     private Object     resolution;  // if null, this guy is resolved
+ 
+-    @Override
+-    public boolean equals(Object other) {
+-        if (this == other) return true;
+-        if (other == null) return false;
+-        if (!(other instanceof MemberName)) return false;
+-        MemberName that = (MemberName) other;
+-        return this.clazz == that.clazz
+-                && this.flags == that.flags
+-                && this.name.equals(that.name)
+-                && typesEqual(this.getType(), that.getType());
+-    }
+-
+-    private static boolean typesEqual(Object a, Object b) {
+-        if (a == null && b == null)
+-            return true;
+-        if (a == null ^ b == null)
+-            return false;
+-        if (a.getClass() != b.getClass())
+-            return false;
+-        if (a instanceof Class<?>)
+-            return a == b;
+-        if (a instanceof MethodType)
+-            return a.equals(b);
+-        return false;
+-    }
+-
+     /** Return the declaring class of this member.
+      *  In the case of a bare name and type, the declaring class will be null.
+      */
+@@ -174,8 +149,10 @@
+      */
+     public MethodType getInvocationType() {
+         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;
+     }
+ 
+@@ -322,6 +299,10 @@
+         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;
+     }
+ 
+@@ -508,8 +489,16 @@
+     }
+     public MemberName asSpecial() {
+         switch (getReferenceKind()) {
+-        case REF_invokeSpecial:  return this;
+-        case REF_invokeVirtual:  return clone().changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual);
++        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());
+     }
+@@ -590,22 +579,27 @@
+         return res;
+     }
+ 
+-    /*
+     @Override
+     public int hashCode() {
+-        Object[] elements = { getDeclaringClass(), getName(), getMethodOrFieldType(), getReferenceKind() };
+-        return Arrays.hashCode(elements);
++        return Objects.hash(clazz, flags, name, getType());
+     }
+     @Override
+     public boolean equals(Object that) {
+-        return (that instanceof MemberName && this.sameReference((MemberName)that));
++        return (that instanceof MemberName && this.equals((MemberName)that));
+     }
+-    */
+-    public boolean sameReference(MemberName that) {
+-        return (this.getDeclaringClass().equals(that.getDeclaringClass()) &&
+-                this.getName().equals(that.getName()) &&
+-                this.getMethodOrFieldType().equals(that.getMethodOrFieldType()) &&
+-                this.getReferenceKind() == that.getReferenceKind());
++
++    /** 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:
+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
+@@ -31,6 +31,8 @@
+ 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,
+@@ -803,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) {
+@@ -916,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
+@@ -1087,7 +1094,6 @@
+         boolean lastMatch = asCollectorChecks(arrayType, 0);
+         if (isVarargsCollector() && lastMatch)
+             return this;
+-        //return AdapterMethodHandle.makeVarargsCollector(this, arrayType);
+         return MethodHandleImpl.makeVarargsCollector(this, arrayType);
+     }
+ 
+@@ -1236,7 +1242,6 @@
+         if (argc != 0) {
+             Class<?> arrayType = type().parameterType(argc-1);
+             if (arrayType.isArray()) {
+-                //return AdapterMethodHandle.makeVarargsCollector(this, arrayType);
+                 return MethodHandleImpl.makeVarargsCollector(this, arrayType);
+             }
+         }
+@@ -1245,9 +1250,9 @@
+     /*non-public*/
+     MethodHandle viewAsType(MethodType newType) {
+         // No actual conversions, just a new view of the same method.
+-        MethodHandle mh = MethodHandleImpl.convertArguments(this, newType, type(), 0);
+-        if (mh == null)  throw new InternalError();
+-        return mh;
++        if (!type.isViewableAs(newType))
++            throw new InternalError();
++        return MethodHandleImpl.makePairwiseConvert(this, newType, 0);
+     }
+ 
+     // Decoding
+@@ -1273,7 +1278,7 @@
+ 
+     /*non-public*/ MethodHandle convertArguments(MethodType newType) {
+         // Override this if it can be improved.
+-        return MethodHandleImpl.convertArguments(this, newType, 1);
++        return MethodHandleImpl.makePairwiseConvert(this, newType, 1);
+     }
+ 
+     /*non-public*/
+@@ -1320,11 +1325,73 @@
+     }
+ 
+     /*non-public*/
+-    private BoundMethodHandle rebind() {
++    MethodHandle rebind() {
+         // Bind 'this' into a new invoker, of the known class BMH.
+         MethodType type2 = type();
+-        LambdaForm form2 = BoundMethodHandle.reinvokerForm(type2.basicType());
++        LambdaForm form2 = reinvokerForm(type2.basicType());
+         // form2 = lambda (bmh, arg*) { thismh = bmh[0]; invokeBasic(thismh, arg*) }
+-        return new BoundMethodHandle.BMH_L(type2, form2, this);
++        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,15 +26,14 @@
+ package java.lang.invoke;
+ 
+ import sun.invoke.util.VerifyType;
++
+ import java.util.ArrayList;
+ import java.util.Arrays;
+ import java.util.HashMap;
+ 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.MethodHandleNatives.Constants.*;
+ import static java.lang.invoke.MethodHandleStatics.*;
+ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
+ 
+@@ -50,41 +49,6 @@
+         MemberName.Factory.INSTANCE.getClass();
+     }
+ 
+-    /** Cache frequently used stuff. */
+-    static final Unsafe UNSAFE = Unsafe.getUnsafe();
+-
+-    static MethodHandle makeAllocator(MethodHandle rawConstructor) {
+-        MethodType rawConType = rawConstructor.type();
+-        Class<?> allocateClass = rawConType.parameterType(0);
+-        MethodType srcType = rawConType.dropParameterTypes(0, 1).changeReturnType(allocateClass);
+-        final int THIS_MH     = 0;
+-        final int ARG_BASE    = 1;
+-        final int ARG_LIMIT   = ARG_BASE + srcType.parameterCount();
+-        int nameCursor = ARG_LIMIT;
+-        final int NEW_OBJ     = nameCursor++;
+-        final int CALL_CTOR   = nameCursor++;
+-        Name[] names = arguments(nameCursor - ARG_LIMIT, srcType.invokerType());
+-        names[NEW_OBJ] = new Name(AllocatorData.UNSAFE_ALLOCATEINSTANCE, allocateClass);
+-        Object[] conArgs = Arrays.copyOfRange(names, ARG_BASE-1, ARG_LIMIT, Object[].class);
+-        conArgs[0] = names[NEW_OBJ];
+-        names[CALL_CTOR] = new Name(rawConstructor, conArgs);
+-        LambdaForm form = new LambdaForm("newInvokeSpecial", ARG_LIMIT, names, NEW_OBJ);
+-        return new SimpleMethodHandle(srcType, form);
+-    }
+-
+-    static final class AllocatorData {
+-        static final MethodHandle UNSAFE_ALLOCATEINSTANCE;
+-        static {
+-            try {
+-                assert(IMPL_LOOKUP != null) : "bootstrap problem";
+-                UNSAFE_ALLOCATEINSTANCE =
+-                    IMPL_LOOKUP.bind(UNSAFE, "allocateInstance", MethodType.methodType(Object.class, Class.class));
+-            } catch (NoSuchMethodException | IllegalAccessException e) {
+-                throw new InternalError(e);
+-            }
+-        }
+-    }
+-
+     static MethodHandle makeArrayElementAccessor(Class<?> arrayClass, boolean isSetter) {
+         if (!arrayClass.isArray())
+             throw newIllegalArgumentException("not an array: "+arrayClass);
+@@ -185,221 +149,6 @@
+         }
+     }
+ 
+-    static MethodHandle makeFieldAccessor(byte refKind, MemberName field, Class<?> receiver) {
+-        boolean isStatic = !MethodHandleNatives.refKindHasReceiver(refKind);
+-        MethodHandle accessor = FieldAccessor.getAccessor(refKind, field, receiver);
+-
+-        MethodType srcType = accessor.type();
+-        MethodType mhType = srcType.dropParameterTypes(isStatic ? 0 : 1, 2);
+-        MethodType lambdaType = mhType.insertParameterTypes(0, isStatic ? BoundMethodHandle.BMH_JL.class : BoundMethodHandle.BMH_J.class);
+-
+-        Name[] names = arguments(3, lambdaType);
+-
+-        final int _ARG    = 1;                // at this index in the names array, the object to be accessed is stored
+-        final int _VALUE  = isStatic ? 1 : 2; // if this is for write access, the value to be written is stored at this index
+-        final int _BASE   = names.length - 3; // the slots for _BASE and _NPE are shared
+-        final int _NPE    = names.length - 3; // (the NPE check is used in the non-static case only, where _BASE is not required)
+-        final int _OFFSET = names.length - 2;
+-        final int _RESULT = names.length - 1;
+-
+-        if (isStatic) {
+-            names[_OFFSET] = new Name(BoundMethodHandle.MH_argJ0, names[0]);
+-            names[_BASE]   = new Name(BoundMethodHandle.MH_argL1, names[0]);
+-        } else {
+-            names[_NPE] = new Name(FieldAccessor.OBJECT_GETCLASS, names[_ARG]); // NPE check
+-            names[_OFFSET] = new Name(BoundMethodHandle.MH_argJ0, names[0]);
+-        }
+-
+-        Object[] args;
+-        if (refKind == REF_putField || refKind == REF_putStatic) {
+-            args = new Object[] { names[isStatic ? _BASE : _ARG], names[_OFFSET], names[_VALUE] };
+-        } else {
+-            args = new Object[] { names[isStatic ? _BASE : _ARG], names[_OFFSET] };
+-        }
+-        names[_RESULT] = new Name(accessor, args);
+-        LambdaForm form = new LambdaForm(MethodHandleNatives.refKindName(refKind), lambdaType.parameterCount(), names);
+-
+-        BoundMethodHandle mh;
+-        if (isStatic) {
+-            long offset = MethodHandleNatives.staticFieldOffset(field);
+-            Object base = MethodHandleNatives.staticFieldBase(field);
+-            mh = new BoundMethodHandle.BMH_JL(mhType, form, offset, base);
+-        } else {
+-            long offset = MethodHandleNatives.objectFieldOffset(field);
+-            mh = new BoundMethodHandle.BMH_J(mhType, form, offset);
+-        }
+-        return mh;
+-    }
+-
+-    static final class FieldAccessor {
+-        static final MethodHandle OBJECT_GETCLASS;
+-        static {
+-            try {
+-                assert(IMPL_LOOKUP != null) : "bootstrap problem";
+-                OBJECT_GETCLASS =
+-                    IMPL_LOOKUP.findStatic(FieldAccessor.class, "getClass", MethodType.methodType(Object.class, Object.class));
+-            } catch (NoSuchMethodException | IllegalAccessException e) {
+-                throw new InternalError(e);
+-            }
+-        }
+-
+-        /** Static definition of Object.getClass for null-pointer checking. */
+-        /*non-public*/ static
+-        @ForceInline
+-        Object getClass(Object obj) {
+-            return obj.getClass();
+-        }
+-
+-        static String name(byte refKind, MemberName field) {
+-            String prefix = MethodHandleNatives.refKindIsGetter(refKind) ? "get" : "put";
+-            String type   = Wrapper.forBasicType(field.getFieldType()).primitiveSimpleName();
+-            String suffix = field.isVolatile() ? "Volatile" : "";
+-            return prefix + Character.toUpperCase(type.charAt(0)) + type.substring(1) + suffix;
+-        }
+-        static MethodType type(byte refKind, MemberName field) {
+-            Class<?> fieldClass = field.getFieldType();
+-            return type(refKind, Object.class, fieldClass.isPrimitive() ? fieldClass : Object.class);
+-        }
+-        static MethodType strongType(byte refKind, MemberName field, Class<?> receiver) {
+-            Class<?> fieldClass = field.getFieldType();
+-            MethodType type;
+-            if (MethodHandleNatives.refKindHasReceiver(refKind)) {
+-                if (!field.getDeclaringClass().isAssignableFrom(receiver))
+-                    throw new InternalError(field.toString());
+-                type = type(refKind, receiver,     fieldClass);
+-            } else {
+-                type = type(refKind, Object.class, fieldClass);
+-            }
+-            return type.insertParameterTypes(0, Unsafe.class);
+-        }
+-        static MethodType type(byte refKind, Class<?> declaringClass, Class<?> fieldClass) {
+-            if (MethodHandleNatives.refKindIsGetter(refKind))
+-                return MethodType.methodType(fieldClass, declaringClass, long.class);
+-            else
+-                return MethodType.methodType(void.class, declaringClass, long.class, fieldClass);
+-        }
+-        static MethodHandle getAccessor(byte refKind, MemberName field, Class<?> receiver) {
+-            if (!MethodHandleNatives.refKindIsField(refKind))
+-                throw newIllegalArgumentException("refKind not a field: " + refKind);
+-            String     name = name(refKind, field);
+-            MethodType type = type(refKind, field);
+-            MethodHandle mh;
+-            try {
+-                mh = IMPL_LOOKUP.findVirtual(Unsafe.class, name, type);
+-            } catch (ReflectiveOperationException ex) {
+-                throw uncaughtException(ex);
+-            }
+-            Class<?> declaringClass = field.getDeclaringClass();
+-            Class<?> fieldClass     = field.getFieldType();
+-            if ((!fieldClass.isPrimitive() && fieldClass != Object.class) || (MethodHandleNatives.refKindHasReceiver(refKind) && declaringClass != Object.class)) {
+-                MethodType strongType = strongType(refKind, field, receiver);
+-                mh = convertArguments(mh, strongType, 0);
+-            }
+-            mh = mh.bindImmediate(0, 'L', UNSAFE); // bind UNSAFE early
+-            return mh;
+-        }
+-    }
+-
+-    /*non-public*/ static
+-    MethodHandle convertArguments(MethodHandle target, MethodType srcType, int level) {
+-        MethodType dstType = target.type();
+-        if (dstType.equals(srcType))
+-            return target;
+-        assert(level > 1 || dstType.isConvertibleTo(srcType));
+-        MethodHandle retFilter = null;
+-        Class<?> oldRT = dstType.returnType();
+-        Class<?> newRT = srcType.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);
+-            }
+-            srcType = srcType.changeReturnType(oldRT);
+-        }
+-        MethodHandle res = null;
+-        Exception ex = null;
+-        try {
+-            res = convertArguments(target, srcType, dstType, level);
+-        } catch (IllegalArgumentException ex1) {
+-            ex = ex1;
+-        }
+-        if (res == null) {
+-            WrongMethodTypeException wmt = new WrongMethodTypeException("cannot convert to "+srcType+": "+target);
+-            wmt.initCause(ex);
+-            throw wmt;
+-        }
+-        if (retFilter != null)
+-            res = MethodHandles.filterReturnValue(res, retFilter);
+-        return res;
+-    }
+-
+-    static MethodHandle convertArguments(MethodHandle target,
+-                                         MethodType srcType,
+-                                         MethodType dstType,
+-                                         int level) {
+-        assert(dstType.parameterCount() == target.type().parameterCount());
+-        if (srcType == dstType)
+-            return target;
+-        if (dstType.parameterCount() != srcType.parameterCount())
+-            throw newIllegalArgumentException("mismatched parameter count", dstType, srcType);
+-        return makePairwiseConvert(srcType, target, level);
+-    }
+-
+-    /** Can a JVM-level adapter directly implement the proposed
+-     *  argument conversions, as if by fixed-arity MethodHandle.asType?
+-     */
+-    private static boolean canPairwiseConvert(MethodType srcType, MethodType dstType, int level) {
+-        // same number of args, of course
+-        int len = srcType.parameterCount();
+-        if (len != dstType.parameterCount())
+-            return false;
+-
+-        // Check return type.
+-        Class<?> exp = srcType.returnType();
+-        Class<?> ret = dstType.returnType();
+-        if (!VerifyType.isNullConversion(ret, exp)) {
+-            if (!canConvertArgument(ret, exp, level))
+-                return false;
+-        }
+-
+-        // Check args pairwise.
+-        for (int i = 0; i < len; i++) {
+-            Class<?> src = srcType.parameterType(i); // source type
+-            Class<?> dst = dstType.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?
+-     */
+-    private 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.
+@@ -413,13 +162,12 @@
+      *          or the original target if the types are already identical
+      *          or null if the adaptation cannot be made
+      */
+-    private static MethodHandle makePairwiseConvert(MethodType srcType, MethodHandle target, int level) {
++    static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType, int level) {
++        assert(level >= 0 && level <= 2);
+         MethodType dstType = target.type();
+-        if (srcType == dstType)  return target;
+-
+-        if (!canPairwiseConvert(srcType, dstType, level))
+-            return null;
+-        // (after this point, it is an assertion error to fail to convert)
++        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.
+@@ -427,27 +175,26 @@
+         for (int i = 0; i < srcType.parameterCount(); i++) {
+             Class<?> src = srcType.parameterType(i);
+             Class<?> dst = dstType.parameterType(i);
+-            if (!isTrivialConversion(src, dst, level)) {
++            if (!VerifyType.isNullConversion(src, dst)) {
+                 extra++;
+             }
+         }
+ 
+         Class<?> needReturn = srcType.returnType();
+         Class<?> haveReturn = dstType.returnType();
+-        boolean retConv = !isTrivialConversion(haveReturn, needReturn, level);
++        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()];
+ 
+-        MethodHandle adapter = target;
+         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 (isTrivialConversion(src, dst, level)) {
++            if (VerifyType.isNullConversion(src, dst)) {
+                 // do nothing: difference is trivial
+                 indexes[i] = argIndex;
+                 continue;
+@@ -457,24 +204,46 @@
+             midType = midType.changeParameterType(i, src);
+ 
+             // Tricky case analysis follows.
+-            // It parallels canConvertArgument() above.
+             MethodHandle fn = null;
+             if (src.isPrimitive()) {
+                 if (dst.isPrimitive()) {
+-                    fn = makePrimCast(src, dst);
++                    fn = ValueConversions.convertPrimitive(src, dst);
+                 } else {
+-                    fn = makeBoxArgument(midType, adapter, i, src);
++                    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.
+-                    fn = makeUnboxArgument(src, dst, level);
++                    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 = makeCheckCast(midType, adapter, i, dst);
++                    fn = ValueConversions.cast(dst);
+                 }
+             }
+             names[tmpIndex] = new Name(fn, names[argIndex]);
+@@ -482,9 +251,17 @@
+             tmpIndex++;
+         }
+         if (retConv) {
+-            MethodHandle fn = makeReturnConversion(adapter, haveReturn, needReturn);
+-            assert(fn != null);
+-            target = fn;
++            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.
+@@ -498,133 +275,12 @@
+         return new SimpleMethodHandle(srcType, form);
+     }
+ 
+-    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);
+-    }
+-
+-    /* 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;
+-        return diffParamTypes(adapterType, 0, targetType, 0, nargs, raw);
+-    }
+-    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? */
+-    // private 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.
+-     */
+-    // private static boolean canRetypeRaw(MethodType newType, MethodType targetType) {
+-    //     return canRetype(newType, targetType, true);
+-    // }
+-    // private static boolean canRetype(MethodType newType, MethodType targetType, boolean raw) {
+-    //     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 makeRetype(MethodType srcType, MethodHandle target) {
+-        MethodType dstType = target.type();
+-        if (dstType == srcType)  return target;
+-        // if (!canRetype(srcType, dstType, raw))
+-        //     return null;
+-        // TO DO:  clone the target guy, whatever he is, with new type.
+-        //return AdapterMethodHandle.makeRetype(srcType, target, raw);
+-        MethodType lambdaType = srcType.invokerType();
++    static MethodHandle makeReferenceIdentity(Class<?> refType) {
++        MethodType lambdaType = MethodType.genericMethodType(1).invokerType();
+         Name[] names = arguments(1, lambdaType);
+-
+-        Object[] targetArgs = Arrays.copyOfRange(names, 1, 1 + srcType.parameterCount(), Object[].class);
+-        names[names.length - 1] = new Name(target, targetArgs);
+-
+-        LambdaForm form = new LambdaForm("asType", lambdaType.parameterCount(), names);
+-        return new SimpleMethodHandle(srcType, form);
++        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 MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) {
+@@ -636,7 +292,7 @@
+         return new AsVarargsCollector(target, target.type(), arrayType);
+     }
+ 
+-    static class AsVarargsCollector extends BoundMethodHandle {
++    static class AsVarargsCollector extends MethodHandle {
+         MethodHandle target;
+         final Class<?> arrayType;
+         MethodHandle cache;
+@@ -648,6 +304,8 @@
+             this.cache = target.asCollector(arrayType, 0);
+         }
+ 
++        @Override MethodHandle reinvokerTarget() { return target; }
++
+         @Override
+         public boolean isVarargsCollector() {
+             return true;
+@@ -659,13 +317,6 @@
+         }
+ 
+         @Override
+-        public String types() {
+-            return types;
+-        }
+-
+-        public static final String types = "L";
+-
+-        @Override
+         public MethodHandle asType(MethodType newType) {
+             MethodType type = this.type();
+             int collectArg = type.parameterCount() - 1;
+@@ -730,283 +381,22 @@
+         MethodHandle permuteArguments(MethodType newType, int[] reorder) {
+             return asFixedArity().permuteArguments(newType, reorder);
+         }
+-
+-        @Override
+-        public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
+-            throw new IllegalStateException("NYI");
+-        }
+-
+-        @Override
+-        public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
+-            throw new IllegalStateException("NYI");
+-        }
+-
+-        @Override
+-        public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
+-            throw new IllegalStateException("NYI");
+-        }
+-
+-        @Override
+-        public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
+-            throw new IllegalStateException("NYI");
+-        }
+-
+-        @Override
+-        public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
+-            throw new IllegalStateException("NYI");
+-        }
+-
+-        @Override
+-        public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
+-            throw new IllegalStateException("NYI");
+-        }
+     }
+ 
+-    /** Can a checkcast adapter validly convert the target to srcType?
+-     *  The JVM supports all kind of reference casts, even silly ones.
+-     */
+-    private static boolean canCheckCast(MethodType srcType, MethodType targetType,
+-                                        int arg, Class<?> castType) {
+-        Class<?> src = srcType.parameterType(arg);
+-        Class<?> dst = targetType.parameterType(arg);
+-        if (!canCheckCast(src, castType)
+-                || !VerifyType.isNullConversion(castType, dst))
+-            return false;
+-        // int diff = diffTypes(srcType, targetType, false);
+-        // return (diff == arg+1) || (diff == 0);  // arg is sole non-trivial diff
+-        return true;
+-    }
+-    /** Can an primitive conversion adapter validly convert src to dst? */
+-    private static boolean canCheckCast(Class<?> src, Class<?> dst) {
+-        return (!src.isPrimitive() && !dst.isPrimitive());
+-    }
++    /** Factory method:  Spread selected argument. */
++    static MethodHandle makeSpreadArguments(MethodHandle target,
++                                            Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) {
++        MethodType targetType = target.type();
+ 
+-    /** 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.
+-     */
+-    private static MethodHandle makeCheckCast(MethodType srcType, MethodHandle target,
+-                                              int arg, Class<?> castType) {
+-        if (!canCheckCast(srcType, target.type(), arg, castType))
+-            return null;
+-        return ValueConversions.cast(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.
+-     */
+-    private static boolean canPrimCast(MethodType newType, MethodType targetType,
+-                                       int arg, Class<?> convType) {
+-        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
+-        return true;
+-    }
+-    /** Can an primitive conversion adapter validly convert src to dst? */
+-    static boolean canPrimCast(Class<?> src, Class<?> dst) {
+-        if (!src.isPrimitive() || !dst.isPrimitive()) {
+-            return false;
+-        }
+-        return true;
+-    }
+-
+-    /** Factory method:  Truncate the given argument with zero or sign extension,
+-     *  and/or convert between single and doubleword versions of integer or float.
+-     */
+-    private static MethodHandle makePrimCast(Class<?> src, Class<?> dst) {
+-        if (VerifyType.isNullConversion(src, dst))
+-            return ValueConversions.identity(dst);
+-        else
+-            return ValueConversions.convertPrimitive(src, dst);
+-    }
+-
+-    /** 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.
+-     */
+-    private static boolean canUnboxArgument(MethodType srcType, MethodType targetType,
+-                                            int arg, Class<?> convType, int level) {
+-        Class<?> src = srcType.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(srcType, targetType, false);
+-        // return (diff == arg+1);  // arg is sole non-trivial diff
+-        return true;
+-    }
+-    /** Can an primitive unboxing adapter validly convert src to dst? */
+-    private 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
+-        return true;
+-    }
+-
+-    /** Factory method:  Unbox the given argument.
+-     */
+-    private static MethodHandle makeUnboxArgument(Class<?> src, Class<?> dst, int level) {
+-        Class<?> convType = dst;
+-        Class<?> boxType = Wrapper.asWrapperType(convType);
+-        Class<?> primType = Wrapper.asPrimitiveType(convType);
+-        Class<?> castDone = src;
+-        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, srcType, conv, unboxMethod);
+-                    return unboxMethod;
+-                }
+-                // Example: Byte->int
+-                // Do this by reformulating the problem to Byte->byte.
+-                Class<?> srcPrim = Wrapper.forWrapperType(src).primitiveType();
+-                MethodHandle unbox = makeUnboxArgument(src, srcPrim, 0);
+-                // Compose the two conversions.  FIXME:  caller should make two Names for this job
+-                return unbox.asType(MethodType.methodType(dst, src));
+-            }
+-            castDone = boxType;
+-        }
+-        // long conv = makeConv(OP_REF_TO_PRIM, arg, T_OBJECT, basicType(primType));
+-        // MethodHandle adapter = new AdapterMethodHandle(target, castDone, conv, boxType);
+-        MethodHandle unboxMethod = ValueConversions.unbox(dst);
+-        if (castDone == src)
+-            return unboxMethod;
+-        return unboxMethod.asType(MethodType.methodType(src, dst));
+-    }
+-
+-    /** Can a boxing conversion validly convert src to dst? */
+-    private static boolean canBoxArgument(MethodType srcType, MethodType targetType,
+-                                          int arg, Class<?> convType) {
+-        Class<?> src = srcType.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(srcType, targetType, false);
+-        // return (diff == arg+1);  // arg is sole non-trivial diff
+-        return true;
+-    }
+-
+-    /** Can an primitive boxing adapter validly convert src to dst? */
+-    private static boolean canBoxArgument(Class<?> src, Class<?> dst) {
+-        return (src.isPrimitive() && !dst.isPrimitive());
+-    }
+-
+-    /** Factory method:  Box the given argument.
+-     *  Return null if this cannot be done.
+-     */
+-    private static MethodHandle makeBoxArgument(MethodType srcType, MethodHandle target,
+-                                                int arg, Class<?> convType) {
+-        MethodType dstType = target.type();
+-        Class<?> src = srcType.parameterType(arg);
+-        Class<?> dst = dstType.parameterType(arg);
+-        Class<?> boxType = Wrapper.asWrapperType(convType);
+-        Class<?> primType = Wrapper.asPrimitiveType(convType);
+-        if (!canBoxArgument(srcType, dstType, arg, convType)) {
+-            return null;
+-        }
+-        if (!VerifyType.isNullConversion(boxType, dst))
+-            target = makeCheckCast(dstType.changeParameterType(arg, boxType), target, arg, dst);
+-        return ValueConversions.box(Wrapper.forPrimitiveType(primType));
+-    }
+-
+-    static MethodHandle spreadArguments(MethodHandle target, Class<?> arrayType, int arrayLength) {
+-        MethodType oldType = target.type();
+-        int nargs = oldType.parameterCount();
+-        int keepPosArgs = nargs - arrayLength;
+-        MethodType srcType = oldType
+-                .dropParameterTypes(keepPosArgs, nargs)
+-                .insertParameterTypes(keepPosArgs, arrayType);
+-        return spreadArguments(target, srcType, keepPosArgs, arrayType, arrayLength);
+-    }
+-    // called internally only
+-    private static MethodHandle spreadArgumentsFromPos(MethodHandle target, MethodType srcType, int spreadArgPos) {
+-        int arrayLength = target.type().parameterCount() - spreadArgPos;
+-        return spreadArguments(target, srcType, spreadArgPos, Object[].class, arrayLength);
+-    }
+-    private static MethodHandle spreadArguments(MethodHandle target,
+-                                                MethodType srcType,
+-                                                int spreadArgPos,
+-                                                Class<?> arrayType,
+-                                                int arrayLength) {
+-        // TO DO: maybe allow the restarg to be Object and implicitly cast to Object[]
+-        MethodType dstType = target.type();
+-        // spread the last argument of srcType to dstType
+-        assert(arrayLength == dstType.parameterCount() - spreadArgPos);
+-        assert(srcType.parameterType(spreadArgPos) == arrayType);
+-        return makeSpreadArguments(srcType, target, arrayType, spreadArgPos, arrayLength);
+-    }
+-
+-    /** Can an adapter spread an argument to convert the target to srcType? */
+-    private static boolean canSpreadArguments(MethodType srcType, MethodType targetType,
+-                                              Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) {
+-        if (diffReturnTypes(srcType, targetType, false) != 0)
+-            return false;
+-        int nptypes = srcType.parameterCount();
+-        // parameter types must be the same up to the spread point
+-        if (spreadArgPos != 0 && diffParamTypes(srcType, 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(srcType, spreadArgPos+1, targetType, afterPos, afterCount, false) != 0)
+-            return false;
+-        // match the array element type to the spread arg types
+-        Class<?> rawSpreadArgType = srcType.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. */
+-    private static MethodHandle makeSpreadArguments(MethodType srcType, MethodHandle target,
+-                                                    Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) {
+-        // FIXME: Get rid of srcType; derive new arguments from structure of spreadArgType
+-        MethodType targetType = target.type();
+-        assert(canSpreadArguments(srcType, targetType, spreadArgType, spreadArgPos, spreadArgCount))
+-            : "[srcType, targetType, spreadArgType, spreadArgPos, spreadArgCount] = "
+-              + Arrays.asList(srcType, 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);
+ 
++        MethodType srcType = targetType
++                .replaceParameterTypes(spreadArgPos, spreadArgPos + spreadArgCount, spreadArgType);
+         // Now build a LambdaForm.
+         MethodType lambdaType = srcType.invokerType();
+         Name[] names = arguments(spreadArgCount + 2, lambdaType);
+@@ -1028,9 +418,7 @@
+                 indexes[i] = argIndex;
+             }
+         }
+-        assert(nameCursor == names.length-1)
+-                : Arrays.asList(Arrays.asList(names), names.length, nameCursor, srcType, lambdaType, target, spreadArgPos, spreadArgCount)//@@
+-                ;  // leave room for the final call
++        assert(nameCursor == names.length-1);  // leave room for the final call
+ 
+         // Build argument array for the call.
+         Name[] targetArgs = new Name[targetType.parameterCount()];
+@@ -1069,61 +457,18 @@
+         }
+     }
+ 
+-    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 srcType = type
+-                .dropParameterTypes(collectArg, collectArg+1)
+-                .insertParameterTypes(collectArg, collector.type().parameterArray());
+-        return collectArguments(target, srcType, collectArg, collector);
+-    }
+-    static MethodHandle collectArguments(MethodHandle target,
+-                                                MethodType srcType,
+-                                                int collectArg,
+-                                                MethodHandle collector) {
+-        MethodType dstType = target.type();     // (a...,c)=>r
+-        //         srcType                      // (a..., b...)=>r
+-        MethodType colType = collector.type();  // (b...)=>c
+-        //         dstType                      // (a..., b...)=>r
+-        assert(srcType.parameterCount() == collectArg + colType.parameterCount());
+-        assert(dstType.parameterCount() == collectArg + 1);
+-        assert(canCollectArguments(dstType, colType, collectArg, false));
+-        return makeCollectArguments(target, collector, collectArg, false);
+-    }
+-
+-    /** 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) {
+-        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();
++        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.dropParameterTypes(collectArgPos, collectArgPos+collectValCount);
+-        if (!retainOriginalArgs) {
++        MethodType srcType = targetType                 // (a..., [b...])=>r
++                .dropParameterTypes(collectArgPos, collectArgPos+collectValCount);
++        if (!retainOriginalArgs) {                      // (a..., b...)=>r
+             srcType = srcType.insertParameterTypes(collectArgPos, collectorType.parameterList());
+-        } else {
+-            // parameter types at the fold point must be the same
+-            assert(diffParamTypes(srcType, 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... ]
+@@ -1166,26 +511,6 @@
+         return new SimpleMethodHandle(srcType, form);
+     }
+ 
+-    static MethodHandle filterArgument(MethodHandle target,
+-                                       int pos,
+-                                       MethodHandle filter) {
+-        MethodType ftype = filter.type();
+-        assert(ftype.parameterCount() == 1);
+-        // return AdapterMethodHandle.makeCollectArguments(target, filter, pos, false);
+-        return 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(canCollectArguments(oldType, ctype, foldPos, true));
+-        // return AdapterMethodHandle.makeCollectArguments(target, combiner, foldPos, true);
+-        return makeCollectArguments(target, combiner, foldPos, true);
+-    }
+-
+     static
+     MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) {
+         return testResult ? target : fallback;
+@@ -1375,22 +700,20 @@
+             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 gtarget = makePairwiseConvert(target, gtype, 2);
++            MethodHandle gcatcher = makePairwiseConvert(catcher, gcatchType, 2);
+             GuardWithCatch gguard = new GuardWithCatch(gtarget, exType, gcatcher);
+-            if (gtarget == null || gcatcher == null || gguard == null)  return null;
++            if (gtarget == null || gcatcher == null)  throw new InternalError();
+             MethodHandle ginvoker = GuardWithCatch.INVOKES[nargs].bindReceiver(gguard);
+-            return convertArguments(ginvoker, type, gtype, 2);
++            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 gcatcher = makeSpreadArguments(catcher, Object[].class, 1, nargs);
+             GuardWithCatch gguard = new GuardWithCatch(gtarget, exType, gcatcher);
+-            if (gtarget == null || gcatcher == null || gguard == null)  return null;
++            if (gtarget == null || gcatcher == null)  throw new InternalError();
+             MethodHandle ginvoker = GuardWithCatch.VARARGS_INVOKE.bindReceiver(gguard);
+-            return collectArguments(ginvoker, type, 0, ValueConversions.varargsArray(nargs)).asType(type);
++            return makeCollectArguments(ginvoker, ValueConversions.varargsArray(nargs), 0, false);
+         }
+     }
+ 
+@@ -1401,7 +724,7 @@
+         if (arity > 1) {
+             return throwException(type.dropParameterTypes(1, arity)).dropArguments(type, 1, arity-1);
+         }
+-        return makeRetype(type, throwException());
++        return makePairwiseConvert(throwException(), type, 2);
+     }
+ 
+     static MethodHandle THROW_EXCEPTION;
+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
+@@ -289,7 +289,7 @@
+                                    Object[] appendixResult) {
+         MethodHandle bootstrapMethod = (MethodHandle)bootstrapMethodObj;
+         Class<?> caller = (Class<?>)callerObj;
+-        String name = nameObj.toString();
++        String name = nameObj.toString().intern();
+         MethodType type = (MethodType)typeObj;
+         appendixResult[0] = CallSite.makeSite(bootstrapMethod,
+                                               name,
+@@ -318,13 +318,15 @@
+     static MemberName linkMethod(Class<?> callerClass, int refKind,
+                                  Class<?> defc, String name, Object type,
+                                  Object[] appendixResult) {
+-        if (TRACE_METHOD_LINKAGE)
+-            System.out.println("linkMethod "+defc.getName()+"."+
+-                               name+type+"/"+Integer.toHexString(refKind));
+-        //assert(refKind == REF_invokeVirtual) : refKind;
++        if (!TRACE_METHOD_LINKAGE)
++            return linkMethodImpl(callerClass, refKind, defc, name, type, appendixResult);
++        return linkMethodTracing(callerClass, refKind, defc, name, type, appendixResult);
++    }
++    static MemberName linkMethodImpl(Class<?> callerClass, int refKind,
++                                     Class<?> defc, String name, Object type,
++                                     Object[] appendixResult) {
+         if (defc != MethodHandle.class || refKind != REF_invokeVirtual)
+             throw new LinkageError("no such method "+defc.getName()+"."+name+type);
+-
+         switch (name) {
+         case "invoke":
+             return Invokers.genericInvokerMethod(callerClass, type, appendixResult);
+@@ -333,6 +335,21 @@
+         }
+         throw new UnsupportedOperationException("linkMethod "+name);
+     }
++    // Tracing logic:
++    static MemberName linkMethodTracing(Class<?> callerClass, int refKind,
++                                        Class<?> defc, String name, Object type,
++                                        Object[] appendixResult) {
++        System.out.println("linkMethod "+defc.getName()+"."+
++                           name+type+"/"+Integer.toHexString(refKind));
++        try {
++            MemberName res = linkMethodImpl(callerClass, refKind, defc, name, type, appendixResult);
++            System.out.println("linkMethod => "+res+" + "+appendixResult[0]);
++            return res;
++        } catch (Throwable ex) {
++            System.out.println("linkMethod => throw "+ex);
++            throw ex;
++        }
++    }
+ 
+     /**
+      * The JVM is resolving a CONSTANT_MethodHandle CP entry.  And it wants our help.
+diff --git a/src/share/classes/java/lang/invoke/MethodHandleStatics.java b/src/share/classes/java/lang/invoke/MethodHandleStatics.java
+--- a/src/share/classes/java/lang/invoke/MethodHandleStatics.java
++++ b/src/share/classes/java/lang/invoke/MethodHandleStatics.java
+@@ -27,6 +27,7 @@
+ 
+ import java.security.AccessController;
+ import java.security.PrivilegedAction;
++import sun.misc.Unsafe;
+ 
+ /**
+  * This class consists exclusively of static names internal to the
+@@ -38,18 +39,22 @@
+ 
+     private MethodHandleStatics() { }  // do not instantiate
+ 
++    static final Unsafe UNSAFE = Unsafe.getUnsafe();
++
+     static final boolean DEBUG_METHOD_HANDLE_NAMES;
+     static final boolean DUMP_CLASS_FILES;
+     static final boolean TRACE_INTERPRETER;
+     static final boolean TRACE_METHOD_LINKAGE;
++    static final Integer COMPILE_THRESHOLD;
+     static {
+-        final Object[] values = { false, false, false, false };
++        final Object[] values = { false, false, false, false, null };
+         AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                 public Void run() {
+                     values[0] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
+                     values[1] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DUMP_CLASS_FILES");
+                     values[2] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_INTERPRETER");
+                     values[3] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE");
++                    values[4] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD");
+                     return null;
+                 }
+             });
+@@ -57,6 +62,7 @@
+         DUMP_CLASS_FILES          = (Boolean) values[1];
+         TRACE_INTERPRETER         = (Boolean) values[2];
+         TRACE_METHOD_LINKAGE      = (Boolean) values[3];
++        COMPILE_THRESHOLD         = (Integer) values[4];
+     }
+ 
+     /*non-public*/ static String getNameString(MethodHandle target, MethodType type) {
+diff --git a/src/share/classes/java/lang/invoke/MethodHandles.java b/src/share/classes/java/lang/invoke/MethodHandles.java
+--- a/src/share/classes/java/lang/invoke/MethodHandles.java
++++ b/src/share/classes/java/lang/invoke/MethodHandles.java
+@@ -1111,9 +1111,7 @@
+         void checkAccess(byte refKind, Class<?> refc, MemberName m) throws IllegalAccessException {
+             assert(m.referenceKindIsConsistentWith(refKind) &&
+                    MethodHandleNatives.refKindIsValid(refKind) &&
+-                   (MethodHandleNatives.refKindIsField(refKind) == m.isField()))
+-                : m.toString()+"!="+refKind //@@
+-                ;
++                   (MethodHandleNatives.refKindIsField(refKind) == m.isField()));
+             int allowedModes = this.allowedModes;
+             if (allowedModes == TRUSTED)  return;
+             int mods = m.getModifiers();
+@@ -1221,7 +1219,7 @@
+         }
+         private MethodHandle getDirectField(byte refKind, Class<?> refc, MemberName field) throws IllegalAccessException {
+             checkField(refKind, refc, field);
+-            MethodHandle mh = MethodHandleImpl.makeFieldAccessor(refKind, field, refc);
++            MethodHandle mh = DirectMethodHandle.make(refc, field);
+             boolean doRestrict = (MethodHandleNatives.refKindHasReceiver(refKind) &&
+                                     restrictProtectedReceiver(field));
+             if (doRestrict)
+@@ -1231,8 +1229,7 @@
+         private MethodHandle getDirectConstructor(Class<?> refc, MemberName ctor) throws IllegalAccessException {
+             assert(ctor.isConstructor());
+             checkAccess(REF_newInvokeSpecial, refc, ctor);
+-            MethodHandle mh = DirectMethodHandle.make(ctor);
+-            return MethodHandleImpl.makeAllocator(mh).setVarargs(ctor);
++            return DirectMethodHandle.make(ctor).setVarargs(ctor);
+         }
+ 
+         /** Hook called from the JVM (via MethodHandleNatives) to link MH constants:
+@@ -1470,7 +1467,10 @@
+      */
+     public static
+     MethodHandle explicitCastArguments(MethodHandle target, MethodType newType) {
+-        return MethodHandleImpl.convertArguments(target, newType, 2);
++        if (!target.type().isCastableTo(newType)) {
++            throw new WrongMethodTypeException("cannot explicitly cast "+target+" to "+newType);
++        }
++        return MethodHandleImpl.makePairwiseConvert(target, newType, 2);
+     }
+ 
+     /**
+@@ -1604,8 +1604,7 @@
+         else if (type.isPrimitive())
+             return ValueConversions.identity(Wrapper.forPrimitiveType(type));
+         else
+-            return MethodHandleImpl.makeRetype(
+-                     MethodType.methodType(type, type), ValueConversions.identity());
++            return MethodHandleImpl.makeReferenceIdentity(type);
+     }
+ 
+     /**
+@@ -1874,7 +1873,7 @@
+         if (filterType.parameterCount() != 1
+             || filterType.returnType() != targetType.parameterType(pos))
+             throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
+-        return MethodHandleImpl.filterArgument(target, pos, filter);
++        return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
+     }
+ 
+     /**
+@@ -1946,7 +1945,6 @@
+             throw newIllegalArgumentException("target and filter types do not match", target, filter);
+         // result = fold( lambda(retval, arg...) { filter(retval) },
+         //                lambda(        arg...) { target(arg...) } )
+-        assert(MethodHandleImpl.canCollectArguments(filterType, targetType, 0, false));
+         return MethodHandleImpl.makeCollectArguments(filter, target, 0, false);
+     }
+ 
+@@ -2045,9 +2043,7 @@
+         if (!ok)
+             throw misMatchedTypes("target and combiner types", targetType, combinerType);
+         MethodType newType = targetType.dropParameterTypes(foldPos, afterInsertPos);
+-        MethodHandle res = MethodHandleImpl.foldArguments(target, newType, foldPos, combiner);
+-        if (res == null)  throw newIllegalArgumentException("cannot fold from "+newType+" to " +targetType);
+-        return res;
++        return MethodHandleImpl.makeCollectArguments(target, combiner, foldPos, true);
+     }
+ 
+     /**
+diff --git a/src/share/classes/java/lang/invoke/MethodType.java b/src/share/classes/java/lang/invoke/MethodType.java
+--- a/src/share/classes/java/lang/invoke/MethodType.java
++++ b/src/share/classes/java/lang/invoke/MethodType.java
+@@ -33,6 +33,7 @@
+ import java.util.List;
+ import sun.invoke.util.BytecodeDescriptor;
+ import static java.lang.invoke.MethodHandleStatics.*;
++import sun.invoke.util.VerifyType;
+ 
+ /**
+  * A method type represents the arguments and return type accepted and
+@@ -240,8 +241,7 @@
+             ptypes = NO_PTYPES; trusted = true;
+         }
+         MethodType mt1 = new MethodType(rtype, ptypes);
+-        MethodType mt0;
+-        mt0 = internTable.get(mt1);
++        MethodType mt0 = internTable.get(mt1);
+         if (mt0 != null)
+             return mt0;
+         if (!trusted)
+@@ -383,6 +383,32 @@
+         return insertParameterTypes(parameterCount(), ptypesToInsert);
+     }
+ 
++     /**
++     * Finds or creates a method type with modified parameter types.
++     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
++     * @param start  the position (zero-based) of the first replaced parameter type(s)
++     * @param end    the position (zero-based) after the last replaced parameter type(s)
++     * @param ptypesToInsert zero or more new parameter types to insert into the parameter list
++     * @return the same type, except with the selected parameter(s) replaced
++     * @throws IndexOutOfBoundsException if {@code start} is negative or greater than {@code parameterCount()}
++     *                                  or if {@code end} is negative or greater than {@code parameterCount()}
++     *                                  or if {@code start} is greater than {@code end}
++     * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
++     *                                  or if the resulting method type would have more than 255 parameter slots
++     * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
++     */
++    /*non-public*/ MethodType replaceParameterTypes(int start, int end, Class<?>... ptypesToInsert) {
++        if (start == end)
++            return insertParameterTypes(start, ptypesToInsert);
++        int len = ptypes.length;
++        if (!(0 <= start && start <= end && end <= len))
++            throw newIndexOutOfBoundsException("start="+start+" end="+end);
++        int ilen = ptypesToInsert.length;
++        if (ilen == 0)
++            return dropParameterTypes(start, end);
++        return dropParameterTypes(start, end).insertParameterTypes(start, ptypesToInsert);
++    }
++
+     /**
+      * Finds or creates a method type with some parameter types omitted.
+      * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+@@ -573,6 +599,11 @@
+         return Collections.unmodifiableList(Arrays.asList(ptypes));
+     }
+ 
++    /*non-public*/ Class<?> lastParameterType() {
++        int len = ptypes.length;
++        return len == 0 ? void.class : ptypes[len-1];
++    }
++
+     /**
+      * Presents the parameter types as an array (a convenience method).
+      * Changes to the array will not result in changes to the type.
+@@ -642,6 +673,26 @@
+ 
+ 
+     /*non-public*/
++    boolean isViewableAs(MethodType newType) {
++        if (!VerifyType.isNullConversion(returnType(), newType.returnType()))
++            return false;
++        int argc = parameterCount();
++        if (argc != newType.parameterCount())
++            return false;
++        for (int i = 0; i < argc; i++) {
++            if (!VerifyType.isNullConversion(newType.parameterType(i), parameterType(i)))
++                return false;
++        }
++        return true;
++    }
++    /*non-public*/
++    boolean isCastableTo(MethodType newType) {
++        int argc = parameterCount();
++        if (argc != newType.parameterCount())
++            return false;
++        return true;
++    }
++    /*non-public*/
+     boolean isConvertibleTo(MethodType newType) {
+         if (!canConvert(returnType(), newType.returnType()))
+             return false;
+@@ -824,6 +875,10 @@
+         return BytecodeDescriptor.unparse(this);
+     }
+ 
++    /*non-public*/ static String toFieldDescriptorString(Class<?> cls) {
++        return BytecodeDescriptor.unparse(cls);
++    }
++
+     /// Serialization.
+ 
+     /**
+@@ -896,18 +951,17 @@
+         // store them into the implementation-specific final fields.
+         checkRtype(rtype);
+         checkPtypes(ptypes);
+-        unsafe.putObject(this, rtypeOffset, rtype);
+-        unsafe.putObject(this, ptypesOffset, ptypes);
++        UNSAFE.putObject(this, rtypeOffset, rtype);
++        UNSAFE.putObject(this, ptypesOffset, ptypes);
+     }
+ 
+     // Support for resetting final fields while deserializing
+-    private static final sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
+     private static final long rtypeOffset, ptypesOffset;
+     static {
+         try {
+-            rtypeOffset = unsafe.objectFieldOffset
++            rtypeOffset = UNSAFE.objectFieldOffset
+                 (MethodType.class.getDeclaredField("rtype"));
+-            ptypesOffset = unsafe.objectFieldOffset
++            ptypesOffset = UNSAFE.objectFieldOffset
+                 (MethodType.class.getDeclaredField("ptypes"));
+         } catch (Exception ex) {
+             throw new Error(ex);
+diff --git a/src/share/classes/java/lang/invoke/MethodTypeForm.java b/src/share/classes/java/lang/invoke/MethodTypeForm.java
+--- a/src/share/classes/java/lang/invoke/MethodTypeForm.java
++++ b/src/share/classes/java/lang/invoke/MethodTypeForm.java
+@@ -59,20 +59,21 @@
+     final LambdaForm[] lambdaForms;
+     // Indexes into lambdaForms:
+     static final int
+-            LF_REF_KIND_FIRST =  0,
+-            LF_REF_KIND_LIMIT =  LF_REF_KIND_FIRST + REF_LIMIT,
+-            // add more variations of DMH invokers as needed...
+-            LF_INVSTATIC_INIT =  0 + LF_REF_KIND_LIMIT,
+-            LF_INTERPRET      =  1 + LF_REF_KIND_LIMIT,
+-            LF_COUNTER        =  2 + LF_REF_KIND_LIMIT,
+-            LF_REINVOKE       =  3 + LF_REF_KIND_LIMIT,
+-            LF_EX_LINKER      =  4 + LF_REF_KIND_LIMIT,
+-            LF_EX_INVOKER     =  5 + LF_REF_KIND_LIMIT,
+-            LF_GEN_LINKER     =  6 + LF_REF_KIND_LIMIT,
+-            LF_GEN_INVOKER    =  7 + LF_REF_KIND_LIMIT,
+-            LF_CS_LINKER      =  8 + LF_REF_KIND_LIMIT,
+-            // add more here as needed...
+-            LF_LIMIT          =  9 + LF_REF_KIND_LIMIT;
++            LF_INVVIRTUAL     =  0,  // DMH invokeVirtual
++            LF_INVSTATIC      =  1,
++            LF_INVSPECIAL     =  2,
++            LF_NEWINVSPECIAL  =  3,
++            LF_INVINTERFACE   =  4,
++            LF_INVSTATIC_INIT =  5,  // DMH invokeStatic with <clinit> barrier
++            LF_INTERPRET      =  6,  // LF interpreter
++            LF_COUNTER        =  7,  // CMH wrapper
++            LF_REINVOKE       =  8,  // other wrapper
++            LF_EX_LINKER      =  9,  // invokeExact_MT
++            LF_EX_INVOKER     = 10,  // invokeExact MH
++            LF_GEN_LINKER     = 11,
++            LF_GEN_INVOKER    = 12,
++            LF_CS_LINKER      = 13,  // linkToCallSite_CS
++            LF_LIMIT          = 14;
+ 
+     public MethodType erasedType() {
+         return erasedType;
+diff --git a/src/share/classes/java/lang/invoke/SimpleMethodHandle.java b/src/share/classes/java/lang/invoke/SimpleMethodHandle.java
+--- a/src/share/classes/java/lang/invoke/SimpleMethodHandle.java
++++ b/src/share/classes/java/lang/invoke/SimpleMethodHandle.java
+@@ -27,6 +27,8 @@
+ 
+ import static java.lang.invoke.LambdaForm.*;
+ import static java.lang.invoke.MethodHandleNatives.Constants.*;
++import java.util.logging.Level;
++import java.util.logging.Logger;
+ 
+ /**
+  * A method handle whose behavior is determined only by its LambdaForm.
+@@ -40,7 +42,7 @@
+     @Override
+     MethodHandle bindArgument(int pos, char basicType, Object value) {
+         MethodType type2 = type().dropParameterTypes(pos, pos+1);
+-        LambdaForm form2 = internalForm().bind(basicType, 1+pos, 0);
++        LambdaForm form2 = internalForm().bind(1+pos, BoundMethodHandle.SpeciesData.EMPTY);
+         return BoundMethodHandle.bindSingle(type2, form2, basicType, value);
+     }
+ 
+diff --git a/src/share/classes/sun/invoke/util/ValueConversions.java b/src/share/classes/sun/invoke/util/ValueConversions.java
+--- a/src/share/classes/sun/invoke/util/ValueConversions.java
++++ b/src/share/classes/sun/invoke/util/ValueConversions.java
+@@ -118,43 +118,15 @@
+         return primitiveConversion(Wrapper.DOUBLE, x, cast).doubleValue();
+     }
+ 
+-    /// Converting references to "raw" values.
+-    /// A raw primitive value is always an int or long.
+-    /// FIXME: Get rid of the raw kind of conversions.
+-
+-    static int unboxByteRaw(Object x, boolean cast) {
+-        return unboxByte(x, cast);
+-    }
+-
+-    static int unboxShortRaw(Object x, boolean cast) {
+-        return unboxShort(x, cast);
+-    }
+-
+-    static int unboxBooleanRaw(Object x, boolean cast) {
+-        return unboxBoolean(x, cast) ? 1 : 0;
+-    }
+-
+-    static int unboxCharacterRaw(Object x, boolean cast) {
+-        return unboxCharacter(x, cast);
+-    }
+-
+-    static int unboxFloatRaw(Object x, boolean cast) {
+-        return Float.floatToIntBits(unboxFloat(x, cast));
+-    }
+-
+-    static long unboxDoubleRaw(Object x, boolean cast) {
+-        return Double.doubleToRawLongBits(unboxDouble(x, cast));
+-    }
+-
+-    private static MethodType unboxType(Wrapper wrap, boolean raw) {
+-        return MethodType.methodType(rawWrapper(wrap, raw).primitiveType(), Object.class, boolean.class);
++    private static MethodType unboxType(Wrapper wrap) {
++        return MethodType.methodType(wrap.primitiveType(), Object.class, boolean.class);
+     }
+ 
+     private static final EnumMap<Wrapper, MethodHandle>[]
+-            UNBOX_CONVERSIONS = newWrapperCaches(4);
++            UNBOX_CONVERSIONS = newWrapperCaches(2);
+ 
+-    private static MethodHandle unbox(Wrapper wrap, boolean raw, boolean cast) {
+-        EnumMap<Wrapper, MethodHandle> cache = UNBOX_CONVERSIONS[(cast?1:0)+(raw?2:0)];
++    private static MethodHandle unbox(Wrapper wrap, boolean cast) {
++        EnumMap<Wrapper, MethodHandle> cache = UNBOX_CONVERSIONS[(cast?1:0)];
+         MethodHandle mh = cache.get(wrap);
+         if (mh != null) {
+             return mh;
+@@ -164,19 +136,15 @@
+             case OBJECT:
+                 mh = IDENTITY; break;
+             case VOID:
+-                mh = raw ? ALWAYS_ZERO : IGNORE; break;
+-            case INT: case LONG:
+-                // these guys don't need separate raw channels
+-                if (raw)  mh = unbox(wrap, false, cast);
+-                break;
++                mh = IGNORE; break;
+         }
+         if (mh != null) {
+             cache.put(wrap, mh);
+             return mh;
+         }
+         // look up the method
+-        String name = "unbox" + wrap.wrapperSimpleName() + (raw ? "Raw" : "");
+-        MethodType type = unboxType(wrap, raw);
++        String name = "unbox" + wrap.wrapperSimpleName();
++        MethodType type = unboxType(wrap);
+         try {
+             mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
+         } catch (ReflectiveOperationException ex) {
+@@ -188,32 +156,30 @@
+             return mh;
+         }
+         throw new IllegalArgumentException("cannot find unbox adapter for " + wrap
+-                + (cast ? " (cast)" : "") + (raw ? " (raw)" : ""));
++                + (cast ? " (cast)" : ""));
+     }
+ 
+     public static MethodHandle unboxCast(Wrapper type) {
+-        return unbox(type, false, true);
+-    }
+-
+-    public static MethodHandle unboxRaw(Wrapper type) {
+-        return unbox(type, true, false);
++        return unbox(type, true);
+     }
+ 
+     public static MethodHandle unbox(Class<?> type) {
+-        return unbox(Wrapper.forPrimitiveType(type), false, false);
++        return unbox(Wrapper.forPrimitiveType(type), false);
+     }
+ 
+     public static MethodHandle unboxCast(Class<?> type) {
+-        return unbox(Wrapper.forPrimitiveType(type), false, true);
+-    }
+-
+-    public static MethodHandle unboxRaw(Class<?> type) {
+-        return unbox(Wrapper.forPrimitiveType(type), true, false);
++        return unbox(Wrapper.forPrimitiveType(type), true);
+     }
+ 
+     static private final Integer ZERO_INT = 0, ONE_INT = 1;
+ 
+     /// Primitive conversions
++    /**
++     * Produce a Number which represents the given value {@code x}
++     * according to the primitive type of the given wrapper {@code wrap}.
++     * Caller must invoke intValue, byteValue, longValue (etc.) on the result
++     * to retrieve the desired primitive value.
++     */
+     public static Number primitiveConversion(Wrapper wrap, Object x, boolean cast) {
+         // Maybe merge this code with Wrapper.convert/cast.
+         Number res = null;
+@@ -238,6 +204,27 @@
+         return res;
+     }
+ 
++    /**
++     * The JVM verifier allows boolean, byte, short, or char to widen to int.
++     * Support exactly this conversion, from a boxed value type Boolean,
++     * Byte, Short, Character, or Integer.
++     */
++    public static int widenSubword(Object x) {
++        if (x instanceof Integer)
++            return (int) x;
++        else if (x instanceof Boolean)
++            return fromBoolean((boolean) x);
++        else if (x instanceof Character)
++            return (char) x;
++        else if (x instanceof Short)
++            return (short) x;
++        else if (x instanceof Byte)
++            return (byte) x;
++        else
++            // Fail with a ClassCastException.
++            return (int) x;
++    }
++
+     /// Converting primitives to references
+ 
+     static Integer boxInteger(int x) {
+@@ -272,53 +259,17 @@
+         return x;
+     }
+ 
+-    /// Converting raw primitives to references
+-
+-    static Byte boxByteRaw(int x) {
+-        return boxByte((byte)x);
+-    }
+-
+-    static Short boxShortRaw(int x) {
+-        return boxShort((short)x);
+-    }
+-
+-    static Boolean boxBooleanRaw(int x) {
+-        return boxBoolean(x != 0);
+-    }
+-
+-    static Character boxCharacterRaw(int x) {
+-        return boxCharacter((char)x);
+-    }
+-
+-    static Float boxFloatRaw(int x) {
+-        return boxFloat(Float.intBitsToFloat(x));
+-    }
+-
+-    static Double boxDoubleRaw(long x) {
+-        return boxDouble(Double.longBitsToDouble(x));
+-    }
+-
+-    // a raw void value is (arbitrarily) a garbage int
+-    static Void boxVoidRaw(int x) {
+-        return null;
+-    }
+-
+-    private static MethodType boxType(Wrapper wrap, boolean raw) {
++    private static MethodType boxType(Wrapper wrap) {
+         // be exact, since return casts are hard to compose
+         Class<?> boxType = wrap.wrapperType();
+-        return MethodType.methodType(boxType, rawWrapper(wrap, raw).primitiveType());
+-    }
+-
+-    private static Wrapper rawWrapper(Wrapper wrap, boolean raw) {
+-        if (raw)  return wrap.isDoubleWord() ? Wrapper.LONG : Wrapper.INT;
+-        return wrap;
++        return MethodType.methodType(boxType, wrap.primitiveType());
+     }
+ 
+     private static final EnumMap<Wrapper, MethodHandle>[]
+-            BOX_CONVERSIONS = newWrapperCaches(4);
++            BOX_CONVERSIONS = newWrapperCaches(2);
+ 
+-    private static MethodHandle box(Wrapper wrap, boolean exact, boolean raw) {
+-        EnumMap<Wrapper, MethodHandle> cache = BOX_CONVERSIONS[(exact?1:0)+(raw?2:0)];
++    private static MethodHandle box(Wrapper wrap, boolean exact) {
++        EnumMap<Wrapper, MethodHandle> cache = BOX_CONVERSIONS[(exact?1:0)];
+         MethodHandle mh = cache.get(wrap);
+         if (mh != null) {
+             return mh;
+@@ -328,11 +279,7 @@
+             case OBJECT:
+                 mh = IDENTITY; break;
+             case VOID:
+-                if (!raw)  mh = ZERO_OBJECT;
+-                break;
+-            case INT: case LONG:
+-                // these guys don't need separate raw channels
+-                if (raw)  mh = box(wrap, exact, false);
++                mh = ZERO_OBJECT;
+                 break;
+         }
+         if (mh != null) {
+@@ -340,8 +287,8 @@
+             return mh;
+         }
+         // look up the method
+-        String name = "box" + wrap.wrapperSimpleName() + (raw ? "Raw" : "");
+-        MethodType type = boxType(wrap, raw);
++        String name = "box" + wrap.wrapperSimpleName();
++        MethodType type = boxType(wrap);
+         if (exact) {
+             try {
+                 mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
+@@ -349,143 +296,26 @@
+                 mh = null;
+             }
+         } else {
+-            mh = box(wrap, !exact, raw).asType(type.erase());
++            mh = box(wrap, !exact).asType(type.erase());
+         }
+         if (mh != null) {
+             cache.put(wrap, mh);
+             return mh;
+         }
+         throw new IllegalArgumentException("cannot find box adapter for "
+-                + wrap + (exact ? " (exact)" : "") + (raw ? " (raw)" : ""));
++                + wrap + (exact ? " (exact)" : ""));
+     }
+ 
+     public static MethodHandle box(Class<?> type) {
+         boolean exact = false;
+         // e.g., boxShort(short)Short if exact,
+         // e.g., boxShort(short)Object if !exact
+-        return box(Wrapper.forPrimitiveType(type), exact, false);
+-    }
+-
+-    public static MethodHandle boxRaw(Class<?> type) {
+-        boolean exact = false;
+-        // e.g., boxShortRaw(int)Short if exact
+-        // e.g., boxShortRaw(int)Object if !exact
+-        return box(Wrapper.forPrimitiveType(type), exact, true);
++        return box(Wrapper.forPrimitiveType(type), exact);
+     }
+ 
+     public static MethodHandle box(Wrapper type) {
+         boolean exact = false;
+-        return box(type, exact, false);
+-    }
+-
+-    public static MethodHandle boxRaw(Wrapper type) {
+-        boolean exact = false;
+-        return box(type, exact, true);
+-    }
+-
+-    /// Kludges for when raw values get accidentally boxed.
+-    /// FIXME: Get rid of the raw kind of conversions.
+-
+-    static int unboxRawInteger(Object x) {
+-        if (x instanceof Integer)
+-            return (int) x;
+-        else
+-            return (int) unboxLong(x, false);
+-    }
+-
+-    static Integer reboxRawInteger(Object x) {
+-        if (x instanceof Integer)
+-            return (Integer) x;
+-        else
+-            return (int) unboxLong(x, false);
+-    }
+-
+-    static Byte reboxRawByte(Object x) {
+-        if (x instanceof Byte)  return (Byte) x;
+-        return boxByteRaw(unboxRawInteger(x));
+-    }
+-
+-    static Short reboxRawShort(Object x) {
+-        if (x instanceof Short)  return (Short) x;
+-        return boxShortRaw(unboxRawInteger(x));
+-    }
+-
+-    static Boolean reboxRawBoolean(Object x) {
+-        if (x instanceof Boolean)  return (Boolean) x;
+-        return boxBooleanRaw(unboxRawInteger(x));
+-    }
+-
+-    static Character reboxRawCharacter(Object x) {
+-        if (x instanceof Character)  return (Character) x;
+-        return boxCharacterRaw(unboxRawInteger(x));
+-    }
+-
+-    static Float reboxRawFloat(Object x) {
+-        if (x instanceof Float)  return (Float) x;
+-        return boxFloatRaw(unboxRawInteger(x));
+-    }
+-
+-    static Long reboxRawLong(Object x) {
+-        return (Long) x;  //never a rebox
+-    }
+-
+-    static Double reboxRawDouble(Object x) {
+-        if (x instanceof Double)  return (Double) x;
+-        return boxDoubleRaw(unboxLong(x, true));
+-    }
+-
+-    private static MethodType reboxType(Wrapper wrap) {
+-        Class<?> boxType = wrap.wrapperType();
+-        return MethodType.methodType(boxType, Object.class);
+-    }
+-
+-    private static final EnumMap<Wrapper, MethodHandle>[]
+-            REBOX_CONVERSIONS = newWrapperCaches(1);
+-
+-    /**
+-     * Because we normalize primitive types to reduce the number of signatures,
+-     * primitives are sometimes manipulated under an "erased" type,
+-     * either int (for types other than long/double) or long (for all types).
+-     * When the erased primitive value is then boxed into an Integer or Long,
+-     * the final boxed primitive is sometimes required.  This transformation
+-     * is called a "rebox".  It takes an Integer or Long and produces some
+-     * other boxed value, typed (inexactly) as an Object
+-     */
+-    public static MethodHandle rebox(Wrapper wrap) {
+-        EnumMap<Wrapper, MethodHandle> cache = REBOX_CONVERSIONS[0];
+-        MethodHandle mh = cache.get(wrap);
+-        if (mh != null) {
+-            return mh;
+-        }
+-        // slow path
+-        switch (wrap) {
+-            case OBJECT:
+-                mh = IDENTITY; break;
+-            case VOID:
+-                throw new IllegalArgumentException("cannot rebox a void");
+-        }
+-        if (mh != null) {
+-            cache.put(wrap, mh);
+-            return mh;
+-        }
+-        // look up the method
+-        String name = "reboxRaw" + wrap.wrapperSimpleName();
+-        MethodType type = reboxType(wrap);
+-        try {
+-            mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
+-            mh = mh.asType(IDENTITY.type());
+-        } catch (ReflectiveOperationException ex) {
+-            mh = null;
+-        }
+-        if (mh != null) {
+-            cache.put(wrap, mh);
+-            return mh;
+-        }
+-        throw new IllegalArgumentException("cannot find rebox adapter for " + wrap);
+-    }
+-
+-    public static MethodHandle rebox(Class<?> type) {
+-        return rebox(Wrapper.forPrimitiveType(type));
++        return box(type, exact);
+     }
+ 
+     /// Constant functions
+@@ -548,12 +378,9 @@
+             return mh;
+         }
+ 
+-        // use the raw method
+-        Wrapper rawWrap = wrap.rawPrimitive();
+-        if (mh == null && rawWrap != wrap) {
+-            mh = MethodHandles.explicitCastArguments(zeroConstantFunction(rawWrap), type);
+-        }
+-        if (mh != null) {
++        // use zeroInt and cast the result
++        if (wrap.isSubwordOrInt() && wrap != Wrapper.INT) {
++            mh = MethodHandles.explicitCastArguments(zeroConstantFunction(Wrapper.INT), type);
+             cache.put(wrap, mh);
+             return mh;
+         }
+@@ -705,7 +532,6 @@
+         if (exact) {
+             MethodType xmt = MethodType.methodType(type, Object.class);
+             mh = MethodHandles.explicitCastArguments(mh, xmt);
+-            //mh = AdapterMethodHandle.makeRetypeRaw(IMPL_TOKEN, xmt, mh);
+         }
+         if (cache != null)
+             cache.put(wrap, mh);
+diff --git a/src/share/classes/sun/invoke/util/VerifyType.java b/src/share/classes/sun/invoke/util/VerifyType.java
+--- a/src/share/classes/sun/invoke/util/VerifyType.java
++++ b/src/share/classes/sun/invoke/util/VerifyType.java
+@@ -122,8 +122,6 @@
+         return isNullConversion(recv.returnType(), call.returnType());
+     }
+ 
+-    //TO DO: isRawConversion
+-
+     /**
+      * Determine if the JVM verifier allows a value of type call to be
+      * passed to a formal parameter (or return variable) of type recv.
+@@ -188,40 +186,6 @@
+         return -1;
+     }
+ 
+-    public static int canPassRaw(Class<?> src, Class<?> dst) {
+-        if (dst.isPrimitive()) {
+-            if (dst == void.class)
+-                // As above, return anything to a caller expecting void.
+-                return 1;
+-            if (src == void.class)
+-                // Special permission for raw conversions: allow a void
+-                // to be captured as a garbage int.
+-                // Caller promises that the actual value will be disregarded.
+-                return dst == int.class ? 1 : 0;
+-            if (isNullType(src))
+-                // Special permission for raw conversions: allow a null
+-                // to be reinterpreted as anything.  For objects, it is safe,
+-                // and for primitives you get a garbage value (probably zero).
+-                return 1;
+-            if (!src.isPrimitive())
+-                return 0;
+-            Wrapper sw = Wrapper.forPrimitiveType(src);
+-            Wrapper dw = Wrapper.forPrimitiveType(dst);
+-            if (sw.stackSlots() == dw.stackSlots())
+-                return 1;  // can do a reinterpret-cast on a stacked primitive
+-            if (sw.isSubwordOrInt() && dw == Wrapper.VOID)
+-                return 1;  // can drop an outgoing int value
+-            return 0;
+-        } else if (src.isPrimitive()) {
+-            return 0;
+-        }
+-
+-        // Both references.
+-        if (isNullReferenceConversion(src, dst))
+-            return 1;
+-        return -1;
+-    }
+-
+     public static boolean isSpreadArgType(Class<?> spreadArg) {
+         return spreadArg.isArray();
+     }
+diff --git a/src/share/classes/sun/invoke/util/Wrapper.java b/src/share/classes/sun/invoke/util/Wrapper.java
+--- a/src/share/classes/sun/invoke/util/Wrapper.java
++++ b/src/share/classes/sun/invoke/util/Wrapper.java
+@@ -562,67 +562,6 @@
+         throw new InternalError("bad wrapper");
+     }
+ 
+-    /** Wrap a value (a long or smaller value) in this wrapper's type.
+-     * Does not perform floating point conversion.
+-     * Produces a {@code Long} for {@code OBJECT}, although the exact type
+-     * of the operand is not known.
+-     * Returns null for {@code VOID}.
+-     */
+-    public Object wrapRaw(long x) {
+-        switch (basicTypeChar) {
+-            case 'F':  return Float.valueOf(Float.intBitsToFloat((int)x));
+-            case 'D':  return Double.valueOf(Double.longBitsToDouble(x));
+-            case 'L':  // same as 'J':
+-            case 'J':  return (Long) x;
+-        }
+-        // Other wrapping operations are just the same, given that the
+-        // operand is already promoted to an int.
+-        return wrap((int)x);
+-    }
+-
+-    /** Produce bitwise value which encodes the given wrapped value.
+-     * Does not perform floating point conversion.
+-     * Returns zero for {@code VOID}.
+-     */
+-    public long unwrapRaw(Object x) {
+-        switch (basicTypeChar) {
+-            case 'F':  return Float.floatToRawIntBits((Float) x);
+-            case 'D':  return Double.doubleToRawLongBits((Double) x);
+-
+-            case 'L': throw newIllegalArgumentException("cannot unwrap from sobject type");
+-            case 'V': return 0;
+-            case 'I': return (int)(Integer) x;
+-            case 'J': return (long)(Long) x;
+-            case 'S': return (short)(Short) x;
+-            case 'B': return (byte)(Byte) x;
+-            case 'C': return (char)(Character) x;
+-            case 'Z': return (boolean)(Boolean) x ? 1 : 0;
+-        }
+-        throw new InternalError("bad wrapper");
+-    }
+-
+-    /** Report what primitive type holds this guy's raw value. */
+-    public Class<?> rawPrimitiveType() {
+-        return rawPrimitive().primitiveType();
+-    }
+-
+-    /** Report, as a wrapper, what primitive type holds this guy's raw value.
+-     *  Returns self for INT, LONG, OBJECT; returns LONG for DOUBLE,
+-     *  else returns INT.
+-     */
+-    public Wrapper rawPrimitive() {
+-        switch (basicTypeChar) {
+-            case 'S': case 'B':
+-            case 'C': case 'Z':
+-            case 'V':
+-            case 'F':
+-                return INT;
+-            case 'D':
+-                return LONG;
+-        }
+-        return this;
+-    }
+-
+     private static Number numberValue(Object x) {
+         if (x instanceof Number)     return (Number)x;
+         if (x instanceof Character)  return (int)(Character)x;
+diff --git a/test/java/lang/invoke/MethodHandlesTest.java b/test/java/lang/invoke/MethodHandlesTest.java
+--- a/test/java/lang/invoke/MethodHandlesTest.java
++++ b/test/java/lang/invoke/MethodHandlesTest.java
+@@ -1821,7 +1821,7 @@
+         List<Object> argsToPass = new ArrayList<>(resList);
+         List<Object> argsToInsert = argsToPass.subList(pos, pos + ins);
+         if (verbosity >= 3)
+-            System.out.println("insert: "+argsToInsert+" into "+target);
++            System.out.println("insert: "+argsToInsert+" @"+pos+" into "+target);
+         @SuppressWarnings("cast")  // cast to spread Object... is helpful
+         MethodHandle target2 = MethodHandles.insertArguments(target, pos,
+                 (Object[]/*...*/) argsToInsert.toArray());
+diff --git a/test/sun/invoke/util/ValueConversionsTest.java b/test/sun/invoke/util/ValueConversionsTest.java
+--- a/test/sun/invoke/util/ValueConversionsTest.java
++++ b/test/sun/invoke/util/ValueConversionsTest.java
+@@ -122,36 +122,6 @@
+     }
+ 
+     @Test
+-    public void testUnboxRaw() throws Throwable {
+-        //System.out.println("unboxRaw");
+-        for (Wrapper w : Wrapper.values()) {
+-            if (w == Wrapper.OBJECT)  continue;  // skip this; no raw form
+-            //System.out.println(w);
+-            for (int n = -5; n < 10; n++) {
+-                Object box = w.wrap(n);
+-                long expResult = w.unwrapRaw(box);
+-                Object box2 = w.wrapRaw(expResult);
+-                assertEquals(box, box2);
+-                MethodHandle unboxer = ValueConversions.unboxRaw(w.primitiveType());
+-                long result = -1;
+-                switch (w) {
+-                    case INT:     result = (int)  unboxer.invokeExact(box); break;
+-                    case LONG:    result = (long) unboxer.invokeExact(box); break;
+-                    case FLOAT:   result = (int)  unboxer.invokeExact(box); break;
+-                    case DOUBLE:  result = (long) unboxer.invokeExact(box); break;
+-                    case CHAR:    result = (int)  unboxer.invokeExact(box); break;
+-                    case BYTE:    result = (int)  unboxer.invokeExact(box); break;
+-                    case SHORT:   result = (int)  unboxer.invokeExact(box); break;
+-                    case BOOLEAN: result = (int)  unboxer.invokeExact(box); break;
+-                    case VOID:    result = (int)  unboxer.invokeExact(box); break;
+-                }
+-                assertEquals("(w,n,box)="+Arrays.asList(w,n,box),
+-                             expResult, result);
+-            }
+-        }
+-    }
+-
+-    @Test
+     public void testBox() throws Throwable {
+         //System.out.println("box");
+         for (Wrapper w : Wrapper.values()) {
+@@ -180,65 +150,6 @@
+     }
+ 
+     @Test
+-    public void testBoxRaw() throws Throwable {
+-        //System.out.println("boxRaw");
+-        for (Wrapper w : Wrapper.values()) {
+-            if (w == Wrapper.VOID)  continue;  // skip this; no unboxed form
+-            if (w == Wrapper.OBJECT)  continue;  // skip this; no raw form
+-            //System.out.println(w);
+-            for (int n = -5; n < 10; n++) {
+-                Object box = w.wrap(n);
+-                long   raw = w.unwrapRaw(box);
+-                Object expResult = box;
+-                MethodHandle boxer = ValueConversions.boxRaw(w.primitiveType());
+-                Object result = null;
+-                switch (w) {
+-                case INT:     result = boxer.invokeExact((int)raw); break;
+-                case LONG:    result = boxer.invokeExact(raw); break;
+-                case FLOAT:   result = boxer.invokeExact((int)raw); break;
+-                case DOUBLE:  result = boxer.invokeExact(raw); break;
+-                case CHAR:    result = boxer.invokeExact((int)raw); break;
+-                case BYTE:    result = boxer.invokeExact((int)raw); break;
+-                case SHORT:   result = boxer.invokeExact((int)raw); break;
+-                case BOOLEAN: result = boxer.invokeExact((int)raw); break;
+-                }
+-                assertEquals("(dst,src,n,box)="+Arrays.asList(w,w,n,box),
+-                             expResult, result);
+-            }
+-        }
+-    }
+-
+-    @Test
+-    public void testReboxRaw() throws Throwable {
+-        //System.out.println("reboxRaw");
+-        for (Wrapper w : Wrapper.values()) {
+-            Wrapper pw = Wrapper.forPrimitiveType(w.rawPrimitiveType());
+-            if (w == Wrapper.VOID)  continue;  // skip this; no unboxed form
+-            if (w == Wrapper.OBJECT)  continue;  // skip this; no raw form
+-            //System.out.println(w);
+-            for (int n = -5; n < 10; n++) {
+-                Object box = w.wrap(n);
+-                Object raw = pw.wrap(w.unwrapRaw(box));
+-                Object expResult = box;
+-                MethodHandle boxer = ValueConversions.rebox(w.primitiveType());
+-                Object result = null;
+-                switch (w) {
+-                case INT:     result = boxer.invokeExact(raw); break;
+-                case LONG:    result = boxer.invokeExact(raw); break;
+-                case FLOAT:   result = boxer.invokeExact(raw); break;
+-                case DOUBLE:  result = boxer.invokeExact(raw); break;
+-                case CHAR:    result = boxer.invokeExact(raw); break;
+-                case BYTE:    result = boxer.invokeExact(raw); break;
+-                case SHORT:   result = boxer.invokeExact(raw); break;
+-                case BOOLEAN: result = boxer.invokeExact(raw); break;
+-                }
+-                assertEquals("(dst,src,n,box)="+Arrays.asList(w,w,n,box),
+-                             expResult, result);
+-            }
+-        }
+-    }
+-
+-    @Test
+     public void testCast() throws Throwable {
+         //System.out.println("cast");
+         Class<?>[] types = { Object.class, Serializable.class, String.class, Number.class, Integer.class };
--- a/meth-lazy-7023639.rmcode.patch	Sat Jul 21 16:50:34 2012 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2431 +0,0 @@
-# HG changeset patch
-# Parent 6683721e6afb216ff3d42a23cbbb40e6f99f4b21
-
-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
-@@ -35,8 +35,7 @@
- import java.lang.invoke.MethodHandles.Lookup;
- import java.lang.reflect.Field;
- import java.util.Arrays;
--import java.util.IdentityHashMap;
--import java.util.Map;
-+import java.util.HashMap;
- 
- import sun.invoke.util.ValueConversions;
- import sun.invoke.util.Wrapper;
-@@ -68,15 +67,15 @@
-             switch (xtype) {
-             case 'L':
-                 if (true)  return bindSingle(type, form, x);  // Use known fast path.
--                return (BoundMethodHandle) Data.EMPTY.extendWithType('L').constructor[0].invokeBasic(type, form, x);
-+                return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('L').constructor[0].invokeBasic(type, form, x);
-             case 'I':
--                return (BoundMethodHandle) Data.EMPTY.extendWithType('I').constructor[0].invokeBasic(type, form, ValueConversions.widenSubword(x));
-+                return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('I').constructor[0].invokeBasic(type, form, ValueConversions.widenSubword(x));
-             case 'J':
--                return (BoundMethodHandle) Data.EMPTY.extendWithType('J').constructor[0].invokeBasic(type, form, (long) x);
-+                return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('J').constructor[0].invokeBasic(type, form, (long) x);
-             case 'F':
--                return (BoundMethodHandle) Data.EMPTY.extendWithType('F').constructor[0].invokeBasic(type, form, (float) x);
-+                return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('F').constructor[0].invokeBasic(type, form, (float) x);
-             case 'D':
--                return (BoundMethodHandle) Data.EMPTY.extendWithType('D').constructor[0].invokeBasic(type, form, (double) x);
-+                return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('D').constructor[0].invokeBasic(type, form, (double) x);
-             default : throw new InternalError("unexpected xtype: " + xtype);
-             }
-         } catch (Throwable t) {
-@@ -85,7 +84,7 @@
-     }
- 
-     static MethodHandle bindSingle(MethodType type, LambdaForm form, Object x) {
--            return new BMH_L(type, form, x);
-+            return new Species_L(type, form, x);
-     }
- 
-     MethodHandle cloneExtend(MethodType type, LambdaForm form, char xtype, Object x) {
-@@ -106,7 +105,7 @@
-     @Override
-     MethodHandle bindArgument(int pos, char basicType, Object value) {
-         MethodType type = type().dropParameterTypes(pos, pos+1);
--        LambdaForm form = internalForm().bind(1+pos, myData());
-+        LambdaForm form = internalForm().bind(1+pos, speciesData());
-         return cloneExtend(type, form, basicType, value);
-     }
- 
-@@ -138,14 +137,14 @@
-     }
- 
-     /**
--     * Return the {@link Data} instance representing this BMH species. All subclasses must provide a
-+     * 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 Data myData();
-+    protected abstract SpeciesData speciesData();
- 
-     @Override
-     final Object internalValues() {
--        Object[] boundValues = new Object[myData().fieldCount()];
-+        Object[] boundValues = new Object[speciesData().fieldCount()];
-         for (int i = 0; i < boundValues.length; ++i) {
-             boundValues[i] = arg(i);
-         }
-@@ -154,7 +153,7 @@
- 
-     public final Object arg(int i) {
-         try {
--            switch (myData().fieldType(i)) {
-+            switch (speciesData().fieldType(i)) {
-             case 'L': return argL(i);
-             case 'I': return argI(i);
-             case 'F': return argF(i);
-@@ -164,13 +163,13 @@
-         } catch (Throwable ex) {
-             throw new InternalError(ex);
-         }
--        throw new InternalError("unexpected type: " + myData().types+"."+i);
-+        throw new InternalError("unexpected type: " + speciesData().types+"."+i);
-     }
--    public final Object argL(int i) throws Throwable { return          myData().getters[i].invokeBasic(this); }
--    public final int    argI(int i) throws Throwable { return (int)    myData().getters[i].invokeBasic(this); }
--    public final float  argF(int i) throws Throwable { return (float)  myData().getters[i].invokeBasic(this); }
--    public final double argD(int i) throws Throwable { return (double) myData().getters[i].invokeBasic(this); }
--    public final long   argJ(int i) throws Throwable { return (long)   myData().getters[i].invokeBasic(this); }
-+    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
-@@ -197,142 +196,142 @@
-     //
- 
-     private  // make it private to force users to access the enclosing class first
--    static final class BMH_L extends BoundMethodHandle {
-+    static final class Species_L extends BoundMethodHandle {
-         final Object argL0;
--        public BMH_L(MethodType mt, LambdaForm lf, 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 Data myData() {
--            return DATA;
-+        public SpeciesData speciesData() {
-+            return SPECIES_DATA;
-         }
--        public static final Data DATA = Data.getForClass("L", BMH_L.class);
-+        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 BMH_L(mt, lf, argL0);
-+            return new Species_L(mt, lf, argL0);
-         }
-         @Override
-         public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
--            return (BoundMethodHandle) DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, narg);
-+            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) DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, narg);
-+            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) DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, narg);
-+            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) DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, narg);
-+            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) DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, narg);
-+            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, narg);
-         }
-     }
- 
- /*
--    static final class BMH_LL extends BoundMethodHandle {
-+    static final class Species_LL extends BoundMethodHandle {
-         final Object argL0;
-         final Object argL1;
--        public BMH_LL(MethodType mt, LambdaForm lf, Object argL0, Object argL1) {
-+        public Species_LL(MethodType mt, LambdaForm lf, Object argL0, Object argL1) {
-             super(mt, lf);
-             this.argL0 = argL0;
-             this.argL1 = argL1;
-         }
-         @Override
--        public Data myData() {
--            return DATA;
-+        public SpeciesData speciesData() {
-+            return SPECIES_DATA;
-         }
--        public static final Data DATA = Data.getForClass("LL", BMH_LL.class);
-+        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 BMH_LL(mt, lf, argL0, argL1);
-+            return new Species_LL(mt, lf, argL0, argL1);
-         }
-         @Override
-         public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
--            return (BoundMethodHandle) DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
-+            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) DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
-+            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) DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
-+            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) DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
-+            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) DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
-+            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
-         }
-     }
- 
--    static final class BMH_JL extends BoundMethodHandle {
-+    static final class Species_JL extends BoundMethodHandle {
-         final long argJ0;
-         final Object argL1;
--        public BMH_JL(MethodType mt, LambdaForm lf, long argJ0, Object argL1) {
-+        public Species_JL(MethodType mt, LambdaForm lf, long argJ0, Object argL1) {
-             super(mt, lf);
-             this.argJ0 = argJ0;
-             this.argL1 = argL1;
-         }
-         @Override
--        public Data myData() {
--            return DATA;
-+        public SpeciesData speciesData() {
-+            return SPECIES_DATA;
-         }
--        public static final Data DATA = Data.getForClass("JL", BMH_JL.class);
-+        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 BMH_JL(mt, lf, argJ0, argL1);
-+            return new Species_JL(mt, lf, argJ0, argL1);
-         }
-         @Override
-         public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
--            return (BoundMethodHandle) DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
-+            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) DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
-+            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) DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
-+            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) DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
-+            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) DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
-+            return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
-         }
-     }
- */
- 
-     //
--    // BMH meta-data
-+    // BMH species meta-data
-     //
- 
-     /**
-      * Meta-data wrapper for concrete BMH classes.
-      */
--    static class Data {
-+    static class SpeciesData {
-         final String                             types;
-         final Class<? extends BoundMethodHandle> clazz;
--        // Bootstrapping requires circular relations MH -> BMH -> Data -> MH
-+        // 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 Data[]                             extensions;
-+        final SpeciesData[]                      extensions;
- 
-         public int fieldCount() {
-             return types.length();
-@@ -342,7 +341,7 @@
-         }
- 
-         public String toString() {
--            return "Data["+(isPlaceholder() ? "<placeholder>" : clazz.getSimpleName())+":"+types+"]";
-+            return "SpeciesData["+(isPlaceholder() ? "<placeholder>" : clazz.getSimpleName())+":"+types+"]";
-         }
- 
-         /**
-@@ -356,9 +355,9 @@
-             return new Name(mh, mhName);
-         }
- 
--        static final Data EMPTY = new Data("", BoundMethodHandle.class);
-+        static final SpeciesData EMPTY = new SpeciesData("", BoundMethodHandle.class);
- 
--        private Data(String types, Class<? extends BoundMethodHandle> clazz) {
-+        private SpeciesData(String types, Class<? extends BoundMethodHandle> clazz) {
-             this.types = types;
-             this.clazz = clazz;
-             if (!INIT_DONE) {
-@@ -368,7 +367,7 @@
-                 this.constructor = Factory.makeCtors(clazz, types, null);
-                 this.getters = Factory.makeGetters(clazz, types, null);
-             }
--            this.extensions = new Data[EXTENSION_TYPES.length()];
-+            this.extensions = new SpeciesData[EXTENSION_TYPES.length()];
-         }
- 
-         private void initForBootstrap() {
-@@ -379,7 +378,7 @@
-             }
-         }
- 
--        private Data(String types) {
-+        private SpeciesData(String types) {
-             // Placeholder only.
-             this.types = types;
-             this.clazz = null;
-@@ -389,27 +388,27 @@
-         }
-         private boolean isPlaceholder() { return clazz == null; }
- 
--        private static final Map<String, Data> CACHE = new IdentityHashMap<>();
-+        private static final HashMap<String, SpeciesData> CACHE = new HashMap<>();
-         private static final boolean INIT_DONE;  // set after <clinit> finishes...
- 
--        Data extendWithType(char type) {
-+        SpeciesData extendWithType(char type) {
-             int i = extensionIndex(type);
--            Data d = extensions[i];
-+            SpeciesData d = extensions[i];
-             if (d != null)  return d;
--            extensions[i] = d = get((types+type).intern());
-+            extensions[i] = d = get(types+type);
-             return d;
-         }
- 
--        Data extendWithIndex(byte index) {
--            Data d = extensions[index];
-+        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 Data get(String types) {
-+        private static SpeciesData get(String types) {
-             // Acquire cache lock for query.
--            Data d = accessCache(types, null);
-+            SpeciesData d = lookupCache(types);
-             if (!d.isPlaceholder())
-                 return d;
-             Class<? extends BoundMethodHandle> cbmh;
-@@ -419,54 +418,51 @@
-                 cbmh = Factory.generateConcreteBMHClass(types);
-             }
-             // Reacquire cache lock.
--            d = accessCache(types, null);
-+            d = lookupCache(types);
-             // Class loading must have upgraded the cache.
-             assert(d != null && !d.isPlaceholder());
-             return d;
-         }
--        static Data getForClass(String types, Class<? extends BoundMethodHandle> clazz) {
--            // clazz is a new class which is initializing its DATA field
--            return accessCache(types, new Data(types, clazz));
-+        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 Data accessCache(String types, Data upgrade) {
--            assert(types == types.intern());  // caller responsibility
--            Data d;
--            if (upgrade != null) {
--                assert((d = CACHE.get(types)) == null || d.isPlaceholder());
--                d = upgrade;
--                CACHE.put(types, d);
--                return d;
--            }
--            d = CACHE.get(types);
--            if (d != null) {
--                return d;
--            }
--            d = new Data(types);
-+        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 data cache with BMH's inner classes
-+            // pre-fill the BMH speciesdata cache with BMH's inner classes
-             final Class<BoundMethodHandle> rootCls = BoundMethodHandle.class;
--            Data d0 = BoundMethodHandle.DATA;  // trigger class init
--            assert(d0 == null || d0 == accessCache("", null)) : d0;
-+            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);
--                        Data d = Factory.dataFromConcreteBMHClass(cbmh);
-+                        SpeciesData d = Factory.speciesDataFromConcreteBMHClass(cbmh);
-                         assert(d != null) : cbmh.getName();
-                         assert(d.clazz == cbmh);
--                        assert(d == accessCache(d.types, null));
-+                        assert(d == lookupCache(d.types));
-                     }
-                 }
-             } catch (Throwable e) {
-                 throw new InternalError(e);
-             }
- 
--            for (Data d : CACHE.values()) {
-+            for (SpeciesData d : CACHE.values()) {
-                 d.initForBootstrap();
-             }
-             // Note:  Do not simplify this, because INIT_DONE must not be
-@@ -475,19 +471,19 @@
-         }
-     }
- 
--    static Data getData(String types) {
--        return Data.get(types);
-+    static SpeciesData getSpeciesData(String types) {
-+        return SpeciesData.get(types);
-     }
- 
-     /**
-      * Generation of concrete BMH classes.
-      *
--     * A concrete BMH is fit for binding a number of values adhering to a
-+     * A concrete BMH species is fit for binding a number of values adhering to a
-      * given type pattern. Reference types are erased.
-      *
--     * BMH classes are cached by type pattern.
-+     * BMH species are cached by type pattern.
-      *
--     * A concrete BMH has a number of fields with the concrete (possibly erased) types of
-+     * 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.
-      */
-@@ -497,15 +493,18 @@
-         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   = "Ljava/lang/invoke/MethodHandle;";
-+        static final String MH_SIG   = "L"+MH+";";
-         static final String BMH      = "java/lang/invoke/BoundMethodHandle";
--        static final String BMH_SIG  = "Ljava/lang/invoke/BoundMethodHandle;";
--        static final String DATA     = "java/lang/invoke/BoundMethodHandle$Data";
--        static final String DATA_SIG = "Ljava/lang/invoke/BoundMethodHandle$Data;";
-+        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 BMHDATA_EWI_SIG = "(B)" + DATA_SIG;
--        static final String BMHDATA_GFC_SIG = "(" + JLS_SIG + JLC_SIG + ")" + DATA_SIG;
--        static final String MYDATA_SIG = "()" + DATA_SIG;
-+        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;";
-@@ -517,12 +516,12 @@
-         /**
-          * Generate a concrete subclass of BMH for a given combination of bound types.
-          *
--         * A concrete BMH subclass adheres to the following schema:
-+         * A concrete BMH species adheres to the following schema:
-          *
-          * <pre>
--         * class BMH_<<types>> extends BMH {
-+         * class Species_<<types>> extends BoundMethodHandle {
-          *     <<fields>>
--         *     final String dataValuemyTypes() { return <<types>>; }
-+         *     final SpeciesData speciesData() { return SpeciesData.get("<<types>>"); }
-          * }
-          * </pre>
-          *
-@@ -533,41 +532,40 @@
-          * the type signature, adhering to the naming schema described in the definition of
-          * {@link #makeFieldName()}.
-          *
--         * For example, a concrete BMH class for two reference and one integral bound values
-+         * For example, a concrete BMH species for two reference and one integral bound values
-          * would have the following shape:
-          *
-          * <pre>
--         * final class BMH_LLI extends BMH {
-+         * class BoundMethodHandle { ... private static
-+         * final class Species_LLI extends BoundMethodHandle {
-          *     final Object argL0;
-          *     final Object argL1;
-          *     final int argI2;
--         *     public BMH_LLI(MethodType mt, LambdaForm lf, Object argL0, Object argL1, 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 String myTypes() { return TYPES; }
--         *     public static final String TYPES = "LLI";
--         *     public final Data myData() { return DATA; }
--         *     public static final Data DATA = Data.getForClass(TYPES, BMH_LLI.class);
-+         *     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 DATA.constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2);
-+         *         return SPECIES_DATA.constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2);
-          *     }
-          *     public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) {
--         *         return BMHData.get("LLIL").constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, 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 BMHData.get("LLII").constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, 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 BMHData.get("LLIJ").constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, 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 BMHData.get("LLIF").constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, 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 BMHData.get("LLID").constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
-+         *         return SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
-          *     }
-          * }
-          * </pre>
-@@ -578,13 +576,13 @@
-         static Class<? extends BoundMethodHandle> generateConcreteBMHClass(String types) {
-             final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
- 
--            final String className = BMH + "$BMH_" + types;
--            final String sourceFile = "BMH_" + types;
-+            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 data fields
--            cw.visitField(ACC_PUBLIC + ACC_STATIC, "DATA", DATA_SIG, null, null).visitEnd();
-+            // 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) {
-@@ -630,10 +628,10 @@
-             mv.visitMaxs(0, 0);
-             mv.visitEnd();
- 
--            // emit implementation of myData()
--            mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "myData", MYDATA_SIG, null, null);
-+            // emit implementation of speciesData()
-+            mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "speciesData", MYSPECIES_DATA_SIG, null, null);
-             mv.visitCode();
--            mv.visitFieldInsn(GETSTATIC, className, "DATA", DATA_SIG);
-+            mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
-             mv.visitInsn(ARETURN);
-             mv.visitMaxs(0, 0);
-             mv.visitEnd();
-@@ -641,11 +639,11 @@
-             // emit clone()
-             mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "clone", makeSignature("", false), null, E_THROWABLE);
-             mv.visitCode();
--            // return myData().constructor[0].invokeBasic(mt, lf, argL0, ...)
-+            // return speciesData().constructor[0].invokeBasic(mt, lf, argL0, ...)
-             // obtain constructor
-             mv.visitVarInsn(ALOAD, 0);
--            mv.visitFieldInsn(GETSTATIC, className, "DATA", DATA_SIG);
--            mv.visitFieldInsn(GETFIELD, DATA, "constructor", "[" + MH_SIG);
-+            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
-@@ -664,14 +662,14 @@
-                 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 DATA.extendWithIndex(extensionIndex(t)).constructor[0].invokeBasic(mt, lf, argL0, ..., narg)
-+                // return SPECIES_DATA.extendWithIndex(extensionIndex(t)).constructor[0].invokeBasic(mt, lf, argL0, ..., narg)
-                 // obtain constructor
--                mv.visitFieldInsn(GETSTATIC, className, "DATA", DATA_SIG);
-+                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, DATA, "extendWithIndex", BMHDATA_EWI_SIG);
--                mv.visitFieldInsn(GETFIELD, DATA, "constructor", "[" + MH_SIG);
-+                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
-@@ -693,8 +691,8 @@
-             mv.visitCode();
-             mv.visitLdcInsn(types);
-             mv.visitLdcInsn(Type.getObjectType(className));
--            mv.visitMethodInsn(INVOKESTATIC, DATA, "getForClass", BMHDATA_GFC_SIG);
--            mv.visitFieldInsn(PUTSTATIC, className, "DATA", DATA_SIG);
-+            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();
-@@ -768,11 +766,11 @@
-         // Auxiliary methods.
-         //
- 
--        static Data dataFromConcreteBMHClass(Class<? extends BoundMethodHandle> cbmh) {
-+        static SpeciesData speciesDataFromConcreteBMHClass(Class<? extends BoundMethodHandle> cbmh) {
-             try {
--                Field fdata = cbmh.getDeclaredField("DATA");
--                return (Data) fdata.get(null);
--            } catch (Throwable ex) {
-+                Field F_SPECIES_DATA = cbmh.getDeclaredField("SPECIES_DATA");
-+                return (SpeciesData) F_SPECIES_DATA.get(null);
-+            } catch (ReflectiveOperationException ex) {
-                 throw new InternalError(ex);
-             }
-         }
-@@ -850,5 +848,5 @@
-     /**
-      * All subclasses must provide such a value describing their type signature.
-      */
--    static final Data DATA = Data.EMPTY;
-+    static final SpeciesData SPECIES_DATA = SpeciesData.EMPTY;
- }
-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
-@@ -241,7 +241,7 @@
-         assert(names.length == nameCursor);
-         if (MTYPE_ARG >= INARG_LIMIT) {
-             assert(names[MTYPE_ARG] == null);
--            names[MTYPE_ARG] = BoundMethodHandle.getData("L").getterName(names[THIS_MH], 0);
-+            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)
-         }
- 
-@@ -320,9 +320,7 @@
-             form.genericInvoker = gamh;
-             return gamh;
-         } catch (Exception ex) {
--            Error err = new InternalError("Exception while resolving inexact invoke", ex);
--            err.initCause(ex);
--            throw err;
-+            throw new InternalError("Exception while resolving inexact invoke", ex);
-         }
-     }
- 
-diff --git a/src/share/classes/java/lang/invoke/LambdaForm.java b/src/share/classes/java/lang/invoke/LambdaForm.java
---- a/src/share/classes/java/lang/invoke/LambdaForm.java
-+++ b/src/share/classes/java/lang/invoke/LambdaForm.java
-@@ -37,6 +37,7 @@
- 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.
-@@ -773,14 +774,14 @@
-         return new LambdaForm(debugName, arity2, names2, result2);
-     }
- 
--    LambdaForm bind(int namePos, BoundMethodHandle.Data oldData) {
-+    LambdaForm bind(int namePos, BoundMethodHandle.SpeciesData oldData) {
-         Name name = names[namePos];
--        BoundMethodHandle.Data newData = oldData.extendWithType(name.type);
-+        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.Data oldData,
--                    BoundMethodHandle.Data newData) {
-+                    BoundMethodHandle.SpeciesData oldData,
-+                    BoundMethodHandle.SpeciesData newData) {
-         int pos = name.index;
-         assert(name.isParam());
-         assert(!binding.isParam());
-@@ -1010,6 +1011,13 @@
-             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)) {
-@@ -1183,14 +1191,15 @@
-         }
- 
-         MemberName member() {
--            assert(memberIsConsistent());
-+            assert(assertMemberIsConsistent());
-             return member;
-         }
- 
--        boolean memberIsConsistent() {
-+        // Called only from assert.
-+        private boolean assertMemberIsConsistent() {
-             if (resolvedHandle instanceof DirectMethodHandle) {
-                 MemberName m = resolvedHandle.internalMemberName();
--                assert(m.equals(member)) : Arrays.asList(member, m, resolvedHandle);
-+                assert(m.equals(member));
-             }
-             return true;
-         }
-@@ -1408,9 +1417,6 @@
-             return true;
-         }
- 
--        public boolean equals(Object x) {
--            return x instanceof Name && equals((Name)x);
--        }
-         /**
-          * Does this Name precede the given binding node in some canonical order?
-          * This predicate is used to order data bindings (via insertion sort)
-@@ -1440,6 +1446,7 @@
-             }
-             return false;
-         }
-+
-         public boolean equals(Name that) {
-             if (this == that)  return true;
-             if (isParam())
-@@ -1451,6 +1458,11 @@
-                 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);
-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
-@@ -40,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
-@@ -77,32 +78,6 @@
-     //@Injected int         vmindex;
-     private Object     resolution;  // if null, this guy is resolved
- 
--    @Override
--    public boolean equals(Object other) {
--        if (this == other) return true;
--        if (other == null) return false;
--        if (!(other instanceof MemberName)) return false;
--        MemberName that = (MemberName) other;
--        return this.clazz == that.clazz
--                && this.flags == that.flags
--                && this.name.equals(that.name)
--                && typesEqual(this.getType(), that.getType());
--    }
--
--    private static boolean typesEqual(Object a, Object b) {
--        if (a == null && b == null)
--            return true;
--        if (a == null ^ b == null)
--            return false;
--        if (a.getClass() != b.getClass())
--            return false;
--        if (a instanceof Class<?>)
--            return a == b;
--        if (a instanceof MethodType)
--            return a.equals(b);
--        return false;
--    }
--
-     /** Return the declaring class of this member.
-      *  In the case of a bare name and type, the declaring class will be null.
-      */
-@@ -604,22 +579,27 @@
-         return res;
-     }
- 
--    /*
-     @Override
-     public int hashCode() {
--        Object[] elements = { getDeclaringClass(), getName(), getMethodOrFieldType(), getReferenceKind() };
--        return Arrays.hashCode(elements);
-+        return Objects.hash(clazz, flags, name, getType());
-     }
-     @Override
-     public boolean equals(Object that) {
--        return (that instanceof MemberName && this.sameReference((MemberName)that));
-+        return (that instanceof MemberName && this.equals((MemberName)that));
-     }
--    */
--    public boolean sameReference(MemberName that) {
--        return (this.getDeclaringClass().equals(that.getDeclaringClass()) &&
--                this.getName().equals(that.getName()) &&
--                this.getMethodOrFieldType().equals(that.getMethodOrFieldType()) &&
--                this.getReferenceKind() == that.getReferenceKind());
-+
-+    /** 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:
-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
-@@ -805,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) {
-@@ -918,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
-@@ -1245,9 +1250,9 @@
-     /*non-public*/
-     MethodHandle viewAsType(MethodType newType) {
-         // No actual conversions, just a new view of the same method.
--        MethodHandle mh = MethodHandleImpl.convertArguments(this, newType, type(), 0);
--        if (mh == null)  throw new InternalError();
--        return mh;
-+        if (!type.isViewableAs(newType))
-+            throw new InternalError();
-+        return MethodHandleImpl.makePairwiseConvert(this, newType, 0);
-     }
- 
-     // Decoding
-@@ -1273,7 +1278,7 @@
- 
-     /*non-public*/ MethodHandle convertArguments(MethodType newType) {
-         // Override this if it can be improved.
--        return MethodHandleImpl.convertArguments(this, newType, 1);
-+        return MethodHandleImpl.makePairwiseConvert(this, newType, 1);
-     }
- 
-     /*non-public*/
-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
-@@ -27,7 +27,6 @@
- 
- import sun.invoke.util.VerifyType;
- 
--import java.lang.invoke.BoundMethodHandle.Data;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.HashMap;
-@@ -35,7 +34,6 @@
- import sun.invoke.util.ValueConversions;
- import sun.invoke.util.Wrapper;
- import static java.lang.invoke.LambdaForm.*;
--import static java.lang.invoke.MethodHandleNatives.Constants.*;
- import static java.lang.invoke.MethodHandleStatics.*;
- import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
- 
-@@ -151,106 +149,6 @@
-         }
-     }
- 
--    /*non-public*/ static
--    MethodHandle convertArguments(MethodHandle target, MethodType srcType, int level) {
--        MethodType dstType = target.type();
--        if (dstType.equals(srcType))
--            return target;
--        assert(level > 1 || dstType.isConvertibleTo(srcType));
--        MethodHandle retFilter = null;
--        Class<?> oldRT = dstType.returnType();
--        Class<?> newRT = srcType.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);
--            }
--            srcType = srcType.changeReturnType(oldRT);
--        }
--        MethodHandle res = null;
--        Exception ex = null;
--        try {
--            res = convertArguments(target, srcType, dstType, level);
--        } catch (IllegalArgumentException ex1) {
--            ex = ex1;
--        }
--        if (res == null) {
--            WrongMethodTypeException wmt = new WrongMethodTypeException("cannot convert to "+srcType+": "+target);
--            wmt.initCause(ex);
--            throw wmt;
--        }
--        if (retFilter != null)
--            res = MethodHandles.filterReturnValue(res, retFilter);
--        return res;
--    }
--
--    static MethodHandle convertArguments(MethodHandle target,
--                                         MethodType srcType,
--                                         MethodType dstType,
--                                         int level) {
--        assert(dstType.parameterCount() == target.type().parameterCount());
--        if (srcType == dstType)
--            return target;
--        if (dstType.parameterCount() != srcType.parameterCount())
--            throw newIllegalArgumentException("mismatched parameter count", dstType, srcType);
--        return makePairwiseConvert(srcType, target, level);
--    }
--
--    /** Can a JVM-level adapter directly implement the proposed
--     *  argument conversions, as if by fixed-arity MethodHandle.asType?
--     */
--    private static boolean canPairwiseConvert(MethodType srcType, MethodType dstType, int level) {
--        // same number of args, of course
--        int len = srcType.parameterCount();
--        if (len != dstType.parameterCount())
--            return false;
--
--        // Check return type.
--        Class<?> exp = srcType.returnType();
--        Class<?> ret = dstType.returnType();
--        if (!VerifyType.isNullConversion(ret, exp)) {
--            if (!canConvertArgument(ret, exp, level))
--                return false;
--        }
--
--        // Check args pairwise.
--        for (int i = 0; i < len; i++) {
--            Class<?> src = srcType.parameterType(i); // source type
--            Class<?> dst = dstType.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?
--     */
--    private 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.
-@@ -264,13 +162,12 @@
-      *          or the original target if the types are already identical
-      *          or null if the adaptation cannot be made
-      */
--    private static MethodHandle makePairwiseConvert(MethodType srcType, MethodHandle target, int level) {
-+    static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType, int level) {
-+        assert(level >= 0 && level <= 2);
-         MethodType dstType = target.type();
--        if (srcType == dstType)  return target;
--
--        if (!canPairwiseConvert(srcType, dstType, level))
--            return null;
--        // (after this point, it is an assertion error to fail to convert)
-+        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.
-@@ -278,27 +175,26 @@
-         for (int i = 0; i < srcType.parameterCount(); i++) {
-             Class<?> src = srcType.parameterType(i);
-             Class<?> dst = dstType.parameterType(i);
--            if (!isTrivialConversion(src, dst, level)) {
-+            if (!VerifyType.isNullConversion(src, dst)) {
-                 extra++;
-             }
-         }
- 
-         Class<?> needReturn = srcType.returnType();
-         Class<?> haveReturn = dstType.returnType();
--        boolean retConv = !isTrivialConversion(haveReturn, needReturn, level);
-+        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()];
- 
--        MethodHandle adapter = target;
-         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 (isTrivialConversion(src, dst, level)) {
-+            if (VerifyType.isNullConversion(src, dst)) {
-                 // do nothing: difference is trivial
-                 indexes[i] = argIndex;
-                 continue;
-@@ -308,24 +204,46 @@
-             midType = midType.changeParameterType(i, src);
- 
-             // Tricky case analysis follows.
--            // It parallels canConvertArgument() above.
-             MethodHandle fn = null;
-             if (src.isPrimitive()) {
-                 if (dst.isPrimitive()) {
--                    fn = makePrimCast(src, dst);
-+                    fn = ValueConversions.convertPrimitive(src, dst);
-                 } else {
--                    fn = makeBoxArgument(midType, adapter, i, src);
-+                    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.
--                    fn = makeUnboxArgument(src, dst, level);
-+                    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 = makeCheckCast(midType, adapter, i, dst);
-+                    fn = ValueConversions.cast(dst);
-                 }
-             }
-             names[tmpIndex] = new Name(fn, names[argIndex]);
-@@ -333,9 +251,17 @@
-             tmpIndex++;
-         }
-         if (retConv) {
--            MethodHandle fn = makeReturnConversion(adapter, haveReturn, needReturn);
--            assert(fn != null);
--            target = fn;
-+            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.
-@@ -349,133 +275,12 @@
-         return new SimpleMethodHandle(srcType, form);
-     }
- 
--    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);
--    }
--
--    /* 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;
--        return diffParamTypes(adapterType, 0, targetType, 0, nargs, raw);
--    }
--    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? */
--    // private 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.
--     */
--    // private static boolean canRetypeRaw(MethodType newType, MethodType targetType) {
--    //     return canRetype(newType, targetType, true);
--    // }
--    // private static boolean canRetype(MethodType newType, MethodType targetType, boolean raw) {
--    //     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 makeRetype(MethodType srcType, MethodHandle target) {
--        MethodType dstType = target.type();
--        if (dstType == srcType)  return target;
--        // if (!canRetype(srcType, dstType, raw))
--        //     return null;
--        // TO DO:  clone the target guy, whatever he is, with new type.
--        //return AdapterMethodHandle.makeRetype(srcType, target, raw);
--        MethodType lambdaType = srcType.invokerType();
-+    static MethodHandle makeReferenceIdentity(Class<?> refType) {
-+        MethodType lambdaType = MethodType.genericMethodType(1).invokerType();
-         Name[] names = arguments(1, lambdaType);
--
--        Object[] targetArgs = Arrays.copyOfRange(names, 1, 1 + srcType.parameterCount(), Object[].class);
--        names[names.length - 1] = new Name(target, targetArgs);
--
--        LambdaForm form = new LambdaForm("asType", lambdaType.parameterCount(), names);
--        return new SimpleMethodHandle(srcType, form);
-+        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 MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) {
-@@ -578,251 +383,20 @@
-         }
-     }
- 
--    /** Can a checkcast adapter validly convert the target to srcType?
--     *  The JVM supports all kind of reference casts, even silly ones.
--     */
--    private static boolean canCheckCast(MethodType srcType, MethodType targetType,
--                                        int arg, Class<?> castType) {
--        Class<?> src = srcType.parameterType(arg);
--        Class<?> dst = targetType.parameterType(arg);
--        if (!canCheckCast(src, castType)
--                || !VerifyType.isNullConversion(castType, dst))
--            return false;
--        // int diff = diffTypes(srcType, targetType, false);
--        // return (diff == arg+1) || (diff == 0);  // arg is sole non-trivial diff
--        return true;
--    }
--    /** Can an primitive conversion adapter validly convert src to dst? */
--    private static boolean canCheckCast(Class<?> src, Class<?> dst) {
--        return (!src.isPrimitive() && !dst.isPrimitive());
--    }
-+    /** Factory method:  Spread selected argument. */
-+    static MethodHandle makeSpreadArguments(MethodHandle target,
-+                                            Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) {
-+        MethodType targetType = target.type();
- 
--    /** 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.
--     */
--    private static MethodHandle makeCheckCast(MethodType srcType, MethodHandle target,
--                                              int arg, Class<?> castType) {
--        if (!canCheckCast(srcType, target.type(), arg, castType))
--            return null;
--        return ValueConversions.cast(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.
--     */
--    private static boolean canPrimCast(MethodType newType, MethodType targetType,
--                                       int arg, Class<?> convType) {
--        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
--        return true;
--    }
--    /** Can an primitive conversion adapter validly convert src to dst? */
--    static boolean canPrimCast(Class<?> src, Class<?> dst) {
--        if (!src.isPrimitive() || !dst.isPrimitive()) {
--            return false;
--        }
--        return true;
--    }
--
--    /** Factory method:  Truncate the given argument with zero or sign extension,
--     *  and/or convert between single and doubleword versions of integer or float.
--     */
--    private static MethodHandle makePrimCast(Class<?> src, Class<?> dst) {
--        if (VerifyType.isNullConversion(src, dst))
--            return ValueConversions.identity(dst);
--        else
--            return ValueConversions.convertPrimitive(src, dst);
--    }
--
--    /** 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.
--     */
--    private static boolean canUnboxArgument(MethodType srcType, MethodType targetType,
--                                            int arg, Class<?> convType, int level) {
--        Class<?> src = srcType.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(srcType, targetType, false);
--        // return (diff == arg+1);  // arg is sole non-trivial diff
--        return true;
--    }
--    /** Can an primitive unboxing adapter validly convert src to dst? */
--    private 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
--        return true;
--    }
--
--    /** Factory method:  Unbox the given argument.
--     */
--    private static MethodHandle makeUnboxArgument(Class<?> src, Class<?> dst, int level) {
--        Class<?> convType = dst;
--        Class<?> boxType = Wrapper.asWrapperType(convType);
--        Class<?> primType = Wrapper.asPrimitiveType(convType);
--        Class<?> castDone = src;
--        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, srcType, conv, unboxMethod);
--                    return unboxMethod;
--                }
--                // Example: Byte->int
--                // Do this by reformulating the problem to Byte->byte.
--                Class<?> srcPrim = Wrapper.forWrapperType(src).primitiveType();
--                MethodHandle unbox = makeUnboxArgument(src, srcPrim, 0);
--                // Compose the two conversions.  FIXME:  caller should make two Names for this job
--                return unbox.asType(MethodType.methodType(dst, src));
--            }
--            castDone = boxType;
--        }
--        // long conv = makeConv(OP_REF_TO_PRIM, arg, T_OBJECT, basicType(primType));
--        // MethodHandle adapter = new AdapterMethodHandle(target, castDone, conv, boxType);
--        MethodHandle unboxMethod = ValueConversions.unbox(dst);
--        if (castDone == src)
--            return unboxMethod;
--        return unboxMethod.asType(MethodType.methodType(src, dst));
--    }
--
--    /** Can a boxing conversion validly convert src to dst? */
--    private static boolean canBoxArgument(MethodType srcType, MethodType targetType,
--                                          int arg, Class<?> convType) {
--        Class<?> src = srcType.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(srcType, targetType, false);
--        // return (diff == arg+1);  // arg is sole non-trivial diff
--        return true;
--    }
--
--    /** Can an primitive boxing adapter validly convert src to dst? */
--    private static boolean canBoxArgument(Class<?> src, Class<?> dst) {
--        return (src.isPrimitive() && !dst.isPrimitive());
--    }
--
--    /** Factory method:  Box the given argument.
--     *  Return null if this cannot be done.
--     */
--    private static MethodHandle makeBoxArgument(MethodType srcType, MethodHandle target,
--                                                int arg, Class<?> convType) {
--        MethodType dstType = target.type();
--        Class<?> src = srcType.parameterType(arg);
--        Class<?> dst = dstType.parameterType(arg);
--        Class<?> boxType = Wrapper.asWrapperType(convType);
--        Class<?> primType = Wrapper.asPrimitiveType(convType);
--        if (!canBoxArgument(srcType, dstType, arg, convType)) {
--            return null;