changeset 405:8e60c519b9f8

meth: merge xbmh patch into main patch for review
author jrose
date Fri, 13 Jul 2012 02:18:29 -0700
parents 4deb4756153e
children 8bf7abfe2a9d
files meth-lazy-7023639.patch meth-lazy-7023639.xbmh.patch series
diffstat 3 files changed, 1386 insertions(+), 2977 deletions(-) [+]
line wrap: on
line diff
--- a/meth-lazy-7023639.patch	Fri Jul 13 01:55:05 2012 -0700
+++ b/meth-lazy-7023639.patch	Fri Jul 13 02:18:29 2012 -0700
@@ -1,8 +1,8 @@
 7023639: JSR 292 method handle invocation needs a fast path for compiled code
 6984705: JSR 292 method handle creation should not go through JNI
-remove assembly code for JDK 7 chained method handles
+Summary: remove assembly code for JDK 7 chained method handles
+Reviewed-by: jrose, twisti, mhaupt
 Contributed-by: jrose, twisti, mhaupt
-Reviewed-by: jrose, twisti, mhaupt
 
 diff --git a/src/share/classes/java/lang/invoke/AdapterMethodHandle.java b/src/share/classes/java/lang/invoke/AdapterMethodHandle.java
 deleted file mode 100644
@@ -1216,33 +1216,71 @@
 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,9 +25,11 @@
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
++ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+  *
+  * This code is free software; you can redistribute it and/or modify it
+@@ -25,164 +25,819 @@
  
  package java.lang.invoke;
  
 -import sun.invoke.util.VerifyType;
--import sun.invoke.util.Wrapper;
++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 java.lang.invoke.LambdaForm.basicTypes;
++import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;
++import static java.lang.invoke.MethodType.methodType;
++
++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 sun.invoke.util.ValueConversions;
+ import sun.invoke.util.Wrapper;
 -import static java.lang.invoke.MethodHandleStatics.*;
-+import static java.lang.invoke.LambdaForm.*;
-+import static java.lang.invoke.MethodHandles.*;
-+import static java.lang.invoke.MethodType.*;
-+import java.util.Arrays;
-+import sun.invoke.util.*;
++import sun.misc.Unsafe;
++
++import com.sun.xml.internal.ws.org.objectweb.asm.ClassWriter;
++import com.sun.xml.internal.ws.org.objectweb.asm.MethodVisitor;
  
  /**
   * The flavor of method handle which emulates an invoke instruction
-@@ -35,72 +37,114 @@
+  * on a predetermined argument.  The JVM dispatches to the correct method
   * when the handle is created, not when it is invoked.
-  * @author jrose
+- * @author jrose
++ *
++ * All bound arguments are encapsulated in dedicated species.
   */
 -class BoundMethodHandle extends MethodHandle {
 -    //MethodHandle vmtarget;           // next BMH or final DMH or methodOop
 -    private final Object argument;     // argument to insert
 -    private final int    vmargslot;    // position at which it is inserted
-+class BoundMethodHandle<T> extends MethodHandle {
-+    final T argument;   // first or only argument to insert
- 
-     // Constructors in this class *must* be package scoped or private.
++/* non-public */ abstract class BoundMethodHandle extends MethodHandle {
+ 
+-    // Constructors in this class *must* be package scoped or private.
 -
 -    /** Bind a direct MH to its receiver (or first ref. argument).
 -     *  The JVM will pre-dispatch the MH if it is not already static.
@@ -1253,10 +1291,8 @@
 -        this.argument = checkReferenceArgument(argument, mh, 0);
 -        this.vmargslot = this.type().parameterSlotCount();
 -        initTarget(mh, 0);
-+    /*non-public*/
-+    BoundMethodHandle(MethodType type, LambdaForm form, T argument) {
++    /* non-public */ BoundMethodHandle(MethodType type, LambdaForm form) {
 +        super(type, form);
-+        this.argument = argument;
      }
  
 -    /** Insert an argument into an arbitrary method handle.
@@ -1266,11 +1302,32 @@
 -    /*non-public*/ BoundMethodHandle(MethodHandle mh, Object argument, int argnum) {
 -        this(mh.type().dropParameterTypes(argnum, argnum+1),
 -             mh, argument, argnum);
-+    static MethodHandle bindSingle(MethodType type2, LambdaForm form2, char xtype, Object x) {
-+        if (xtype == 'L')
-+            return new BoundMethodHandle<>(type2, form2, x);
-+        else
-+            return new BoundMethodHandle.Multiple(null, type2, form2, 1, xtype, x);
++    //
++    // BMH API and internals
++    //
++
++    static MethodHandle bindSingle(MethodType type, LambdaForm form, char xtype, Object x) {
++        // for some type signatures, there exist pre-defined concrete BMH classes
++        try {
++            switch (xtype) {
++            case 'L': return new BMH_L(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());
++            case 'J':
++                assert x instanceof Long;
++                return new BMH_J(type, form, ((Long) x).longValue());
++            case 'F':
++                assert x instanceof Float;
++                return (BoundMethodHandle) Data.get("F").constructor.invokeBasic(type, form, ((Float) x).floatValue());
++            case 'D':
++                assert x instanceof Double;
++                return (BoundMethodHandle) Data.get("D").constructor.invokeBasic(type, form, ((Double) x).doubleValue());
++            default : throw new InternalError("unexpected xtype: " + xtype);
++            }
++        } catch (Throwable t) {
++            throw new InternalError(t);
++        }
      }
  
 -    /** Insert an argument into an arbitrary method handle.
@@ -1282,23 +1339,36 @@
 -            this.argument = bindPrimitiveArgument(argument, mh, argnum);
 -        else {
 -            this.argument = checkReferenceArgument(argument, mh, argnum);
--        }
++    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);
++            }
++        } catch (Throwable t) {
++            throw new InternalError(t);
+         }
 -        this.vmargslot = type.parameterSlotDepth(argnum);
 -        initTarget(mh, argnum);
-+    // Note:  Subclasses must override this, for obvious reasons.
-+    MethodHandle clone(MethodType type2, LambdaForm form2) {
-+        return new BoundMethodHandle<>(type2, form2, argument); // override this
-     }
- 
+-    }
+-
 -    private void initTarget(MethodHandle mh, int argnum) {
 -        //this.vmtarget = mh;  // maybe updated by JVM
 -        MethodHandleNatives.init(this, mh, argnum);
-+    // Note:  Subclasses must override this, as with clone.
-+    MethodHandle cloneExtend(MethodType type2, LambdaForm form2, char xtype, Object x) {
-+        Multiple nextArg = new Multiple(null, type2, form2, 2, xtype, x);
-+        return new Multiple(nextArg, type2, form2, 1, 'L', argument);
-     }
- 
+-    }
+-
 -    /** For the AdapterMethodHandle subclass.
 -     */
 -    /*non-public*/ BoundMethodHandle(MethodType type, Object argument, int vmargslot) {
@@ -1306,17 +1376,8 @@
 -        this.argument = argument;
 -        this.vmargslot = vmargslot;
 -        assert(this instanceof AdapterMethodHandle);
-+    @Override
-+    MethodHandle bindArgument(int pos, char basicType, Object value) {
-+        MethodType type2 = type().dropParameterTypes(pos, pos+1);
-+        LambdaForm form2 = internalForm().bind(basicType, 1+pos, dataValueCount());
-+        if (basicType == 'I' && !(value instanceof Integer)) {
-+            // Cf. ValueConversions.unboxInteger
-+            value = ValueConversions.primitiveConversion(Wrapper.INT, value, true);
-+        }
-+        return cloneExtend(type2, form2, basicType, value);
-     }
- 
+-    }
+-
 -    /** Initialize the current object as a self-bound method handle, binding it
 -     *  as the first argument of the method handle {@code entryPoint}.
 -     *  The invocation type of the resulting method handle will be the
@@ -1328,186 +1389,70 @@
 -        this.argument = this; // kludge; get rid of
 -        this.vmargslot = this.type().parameterSlotDepth(0);
 -        initTarget(entryPoint, 0);
-+    @Override
-+    MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
-+        LambdaForm form2 = internalForm().addArguments(pos, srcType.parameterList().subList(pos, pos+drops));
-+        return clone(srcType, form2);
-+    }
-+
-+    @Override
-+    MethodHandle permuteArguments(MethodType newType, int[] reorder) {
-+        return clone(newType, form.permuteArguments(1, reorder, basicTypes(newType.parameterList())));
-+    }
-+
-+    // Singleton implementation of DataBinding:
-+    public int dataValueCount() {
-+        return 1;
-+    }
-+    public String dataValueTypes() {
-+        return "L";
-+    }
-+    public char dataValueType(int i) {
-+        assert(i == 0);
-+        return 'L';
-+    }
-+
-+    public final Object dataValue0() {
-+        return argument;
-+    }
-+
-+    //public final Object objectDataValue0() { return           dataValue0(); }
-+    public final int       intDataValue0() { return (Integer) dataValue0(); }
-+    public final long     longDataValue0() { return (Long)    dataValue0(); }
-+    public final float   floatDataValue0() { return (Float)   dataValue0(); }
-+    public final double doubleDataValue0() { return (Double)  dataValue0(); }
-+
-+    static Name dataValueName(Name mhName, char basicType, int i) {
-+        NamedFunction getter;
-+        if (i == 0) {
-+            switch (basicType) {
-+            case 'L':  getter =       NF_dataValue0; break;
-+            case 'I':  getter =    NF_intDataValue0; break;
-+            case 'J':  getter =   NF_longDataValue0; break;
-+            case 'F':  getter =  NF_floatDataValue0; break;
-+            case 'D':  getter = NF_doubleDataValue0; break;
-+            default:
-+                throw new InternalError("unknown type: " + basicType);
-+            }
-+            return new Name(getter, mhName);
-+        } else {
-+            switch (basicType) {
-+            case 'L':
-+                if (i == 1)  return new Name(NF_dataValue1, mhName);
-+                if (i == 2)  return new Name(NF_dataValue2, mhName);
-+                if (i == 3)  return new Name(NF_dataValue3, mhName);
-+                getter = NF_dataValue;
-+                break;
-+            case 'I':
-+                if (i == 1)  return new Name(NF_intDataValue1, mhName);
-+                getter = NF_intDataValue;
-+                break;
-+            case 'J':
-+                if (i == 1)  return new Name(NF_longDataValue1, mhName);
-+                getter = NF_longDataValue;
-+                break;
-+            case 'F':  getter =  NF_floatDataValue; break;
-+            case 'D':  getter = NF_doubleDataValue; break;
-+            default:
-+                throw new InternalError("unknown type: " + basicType);
-+            }
-+            return new Name(getter, mhName, i);
-+        }
-     }
- 
-     /** Make sure the given {@code argument} can be used as {@code argnum}-th
-@@ -110,7 +154,7 @@
-      *  which will prevent the creation of an illegally typed bound
-      *  method handle.
-      */
+-    }
+-
+-    /** Make sure the given {@code argument} can be used as {@code argnum}-th
+-     *  parameter of the given method handle {@code mh}, which must be a reference.
+-     *  <p>
+-     *  If this fails, throw a suitable {@code WrongMethodTypeException},
+-     *  which will prevent the creation of an illegally typed bound
+-     *  method handle.
+-     */
 -    final static Object checkReferenceArgument(Object argument, MethodHandle mh, int argnum) {
-+    private static Object checkReferenceArgument(Object argument, MethodHandle mh, int argnum) {
-         Class<?> ptype = mh.type().parameterType(argnum);
-         if (ptype.isPrimitive()) {
-             // fail
-@@ -129,7 +173,7 @@
-      *  which will prevent the creation of an illegally typed bound
-      *  method handle.
-      */
+-        Class<?> ptype = mh.type().parameterType(argnum);
+-        if (ptype.isPrimitive()) {
+-            // fail
+-        } else if (argument == null) {
+-            return null;
+-        } else if (VerifyType.isNullReferenceConversion(argument.getClass(), ptype)) {
+-            return argument;
+-        }
+-        throw badBoundArgumentException(argument, mh, argnum);
+-    }
+-
+-    /** Make sure the given {@code argument} can be used as {@code argnum}-th
+-     *  parameter of the given method handle {@code mh}, which must be a primitive.
+-     *  <p>
+-     *  If this fails, throw a suitable {@code WrongMethodTypeException},
+-     *  which will prevent the creation of an illegally typed bound
+-     *  method handle.
+-     */
 -    final static Object bindPrimitiveArgument(Object argument, MethodHandle mh, int argnum) {
-+    private static Object bindPrimitiveArgument(Object argument, MethodHandle mh, int argnum) {
-         Class<?> ptype = mh.type().parameterType(argnum);
-         Wrapper  wrap = Wrapper.forPrimitiveType(ptype);
-         Object   zero  = wrap.zero();
-@@ -149,40 +193,160 @@
-         throw badBoundArgumentException(argument, mh, argnum);
-     }
- 
+-        Class<?> ptype = mh.type().parameterType(argnum);
+-        Wrapper  wrap = Wrapper.forPrimitiveType(ptype);
+-        Object   zero  = wrap.zero();
+-        if (zero == null) {
+-            // fail
+-        } else if (argument == null) {
+-            if (ptype != int.class && wrap.isSubwordOrInt())
+-                return Integer.valueOf(0);
+-            else
+-                return zero;
+-        } else if (VerifyType.isNullReferenceConversion(argument.getClass(), zero.getClass())) {
+-            if (ptype != int.class && wrap.isSubwordOrInt())
+-                return Wrapper.INT.wrap(argument);
+-            else
+-                return argument;
+-        }
+-        throw badBoundArgumentException(argument, mh, argnum);
+-    }
+-
 -    final static RuntimeException badBoundArgumentException(Object argument, MethodHandle mh, int argnum) {
-+    private static RuntimeException badBoundArgumentException(Object argument, MethodHandle mh, int argnum) {
-         String atype = (argument == null) ? "null" : argument.getClass().toString();
-         return new ClassCastException("cannot bind "+atype+" argument to parameter #"+argnum+" of "+mh.type());
-     }
- 
--    @Override
+-        String atype = (argument == null) ? "null" : argument.getClass().toString();
+-        return new ClassCastException("cannot bind "+atype+" argument to parameter #"+argnum+" of "+mh.type());
+     }
+ 
+     @Override
 -    String debugString() {
 -        return addTypeString(baseName(), this);
-+
-+    // Subclasses for additional data binding:
-+    static class Multiple extends BoundMethodHandle<Object> {
-+        /*lazy*/ String boundValueTypes;
-+        final int boundValueCount;
-+        final Multiple next;
-+        final char xtype;
-+
-+        public Multiple(Multiple next, MethodType type, LambdaForm form, int boundValueCount, char xtype, Object x) {
-+            super(type, form, x);
-+            this.boundValueCount = boundValueCount;
-+            this.next = next;
-+            this.xtype = xtype;
-+        }
-+
-+        /// Implementation of multi-level binding:
-+        @Override
-+        public final String dataValueTypes() {
-+            assert false;
-+            String types = boundValueTypes;
-+            if (types == null)
-+                boundValueTypes = types = DataBinding.Methods.dataValueTypes(this);
-+            return types;
-+        }
-+        @Override
-+        public final int dataValueCount() {
-+            Multiple p = this;
-+            while (p.next != null) {
-+                p = p.next;
-+            }
-+            return p.boundValueCount;
-+        }
-+
-+        @Override
-+        public final char dataValueType(int i) {
-+            Multiple p = this;
-+            while (--i >= 0) {
-+                p = p.next;
-+            }
-+            return p.xtype;
-+        }
-+
-+        public final Object dataValue1() { return this.next.argument; }
-+        public final Object dataValue2() { return this.next.next.argument; }
-+        public final Object dataValue3() { return this.next.next.next.argument; }
-+        public final Object dataValue(int i) {
-+            Multiple p = this;
-+            while (--i >= 0) {
-+                p = p.next;
-+            }
-+            return p.argument;
-+        }
-+
-+        public final int   intDataValue1() { return (Integer) this.next.argument; }
-+        public final long longDataValue1() { return (Long)    this.next.argument; }
-+
-+        //public final Object objectDataValue(int i) { return           dataValue(i); }
-+        public final int       intDataValue(int i) { return (Integer) dataValue(i); }
-+        public final long     longDataValue(int i) { return (Long)    dataValue(i); }
-+        public final float   floatDataValue(int i) { return (Float)   dataValue(i); }
-+        public final double doubleDataValue(int i) { return (Double)  dataValue(i); }
-+
-+        @Override
-+        MethodHandle cloneExtend(MethodType type2, LambdaForm form2, char xtype2, Object x2) {
-+            Multiple nextArg;
-+            if (this.next == null) {
-+                nextArg = new Multiple(null, type2, form2, boundValueCount + 1, xtype2, x2);
-+            } else {
-+                nextArg = (Multiple) this.next.cloneExtend(type2, form2, xtype2, x2);
-+            }
-+            return new Multiple(nextArg, type2, form2, boundValueCount, xtype, argument);
-+        }
-+
-+        @Override
-+        MethodHandle clone(MethodType type2, LambdaForm form2) {
-+            return new Multiple(next, type2, form2, boundValueCount, xtype, argument);
-+        }
++    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);
++        }
++        return cloneExtend(type, form, basicType, value);
      }
  
 -    /** Component of toString() before the type string. */
@@ -1527,61 +1472,294 @@
 -                    return noParens(super.toString()); // "invoke", probably
 -            }
 -            assert(mh != this);
-+    static final NamedFunction NF_dataValue0;
-+    static final NamedFunction NF_intDataValue0;
-+    static final NamedFunction NF_longDataValue0;
-+    static final NamedFunction NF_floatDataValue0;
-+    static final NamedFunction NF_doubleDataValue0;
-+
-+    static final NamedFunction NF_dataValue1;
-+    static final NamedFunction NF_dataValue2;
-+    static final NamedFunction NF_dataValue3;
-+
-+    static final NamedFunction NF_intDataValue1;
-+
-+    static final NamedFunction NF_longDataValue1;
-+
-+    static final NamedFunction NF_dataValue;
-+    static final NamedFunction NF_intDataValue;
-+    static final NamedFunction NF_longDataValue;
-+    static final NamedFunction NF_floatDataValue;
-+    static final NamedFunction NF_doubleDataValue;
-+
-+    static {
+-        }
+-        return noParens(mh.toString());
++    @Override
++    MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
++        LambdaForm form = internalForm().addArguments(pos, srcType.parameterList().subList(pos, pos+drops));
 +        try {
-+            Lookup l = Lookup.IMPL_LOOKUP;
-+            Class<?> b = BoundMethodHandle.class;
-+            Class<?> m = Multiple.class;
-+
-+            NF_dataValue0       = new NamedFunction(l.findVirtual(b, "dataValue0",       methodType(Object.class)));
-+            NF_intDataValue0    = new NamedFunction(l.findVirtual(b, "intDataValue0",    methodType(int.class)));
-+            NF_longDataValue0   = new NamedFunction(l.findVirtual(b, "longDataValue0",   methodType(long.class)));
-+            NF_floatDataValue0  = new NamedFunction(l.findVirtual(b, "floatDataValue0",  methodType(float.class)));
-+            NF_doubleDataValue0 = new NamedFunction(l.findVirtual(b, "doubleDataValue0", methodType(double.class)));
-+
-+            NF_dataValue1       = new NamedFunction(l.findVirtual(m, "dataValue1",       methodType(Object.class)));
-+            NF_dataValue2       = new NamedFunction(l.findVirtual(m, "dataValue2",       methodType(Object.class)));
-+            NF_dataValue3       = new NamedFunction(l.findVirtual(m, "dataValue3",       methodType(Object.class)));
-+
-+            NF_intDataValue1    = new NamedFunction(l.findVirtual(m, "intDataValue1",    methodType(int.class)));
-+
-+            NF_longDataValue1   = new NamedFunction(l.findVirtual(m, "longDataValue1",   methodType(long.class)));
-+
-+            NF_dataValue        = new NamedFunction(l.findVirtual(m, "dataValue",        methodType(Object.class, int.class)));
-+            NF_intDataValue     = new NamedFunction(l.findVirtual(m, "intDataValue",     methodType(int.class,    int.class)));
-+            NF_longDataValue    = new NamedFunction(l.findVirtual(m, "longDataValue",    methodType(long.class,   int.class)));
-+            NF_floatDataValue   = new NamedFunction(l.findVirtual(m, "floatDataValue",   methodType(float.class,  int.class)));
-+            NF_doubleDataValue  = new NamedFunction(l.findVirtual(m, "doubleDataValue",  methodType(double.class, int.class)));
-+        } catch (ReflectiveOperationException ex) {
-+            throw new InternalError(ex);
-         }
--        return noParens(mh.toString());
++             return clone(srcType, form);
++         } catch (Throwable t) {
++             throw new InternalError(t);
++         }
      }
  
 -    private static String noParens(String str) {
 -        int paren = str.indexOf('(');
 -        if (paren >= 0) str = str.substring(0, paren);
 -        return str;
++    @Override
++    MethodHandle permuteArguments(MethodType newType, int[] reorder) {
++        try {
++             return clone(newType, form.permuteArguments(1, reorder, basicTypes(newType.parameterList())));
++         } catch (Throwable t) {
++             throw new InternalError(t);
++         }
+     }
++
++    public int tcount() {
++        return types().length();
++    }
++
++    protected final Data myData() {
++        return Data.get(types());
++    }
++
++    /**
++     * 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).
++     */
++    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;
++    }
++
++    @Override
++    final Object internalValues() {
++        Object[] boundValues = new Object[types().length()];
++        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);
++            }
++        }
++        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); }
++
++    //
++    // cloning API
++    //
++
++    public abstract BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable;
++    public abstract BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable;
++    public abstract BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int    narg) throws Throwable;
++    public abstract BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long   narg) throws Throwable;
++    public abstract BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float  narg) throws Throwable;
++    public abstract BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable;
++
++    //
++    // getters to close bootstrap loops
++    //
++
++    public long   argJ0() throws Throwable { return argJ(0); }
++    public Object argL1() throws Throwable { return argL(1); }
++
++    //
++    // concrete BMH classes required to close bootstrap loops
++    //
++
++    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;
++        }
++        @Override
++        public String types() {
++            return types;
++        }
++        public static final String types = "L";
++        @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);
++        }
++        @Override
++        public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
++            return (BoundMethodHandle) Data.get("LI").constructor.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);
++        }
++        @Override
++        public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
++            return (BoundMethodHandle) Data.get("LF").constructor.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);
++        }
++    }
++
++    static final class BMH_LL extends BoundMethodHandle {
++        final Object argL0;
++        final Object argL1;
++        public BMH_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 static final String types = "LL";
++        @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);
++        }
++        @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);
++        }
++        @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);
++        }
++        @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);
++        }
++        @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);
++        }
++    }
++
++    static final class BMH_JL extends BoundMethodHandle {
++        final long argJ0;
++        final Object argL1;
++        public BMH_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 static final String types = "JL";
++        @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);
++        }
++        @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);
++        }
++        @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);
++        }
++        @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);
++        }
++        @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);
++        }
++        @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);
++        }
++    }
++
++    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.
 +     */
@@ -1597,12 +1775,411 @@
 +        final int NEXT_MH     = nameCursor++;
 +        final int REINVOKE    = nameCursor++;
 +        Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
-+        names[NEXT_MH] = dataValueName(names[THIS_BMH], 'L', 0);
++        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
++    //
++
++    /**
++     * Meta-data wrapper for concrete BMH classes.
++     */
++    static class Data {
++        final String                             types;
++        final Class<? extends BoundMethodHandle> clazz;
++        final MethodHandle                       constructor;
++        final MethodHandle[]                     getters;
++
++        Data(String types, Class<? extends BoundMethodHandle> clazz, MethodHandle constructor, MethodHandle[] getters) {
++            this.types = types;
++            this.clazz = clazz;
++            this.constructor = constructor;
++            this.getters = getters;
++        }
++
++        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);
++        }
++
++        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);
++                }
++            }
++            return d;
++        }
++
++        static {
++            // pre-fill the BMH data cache with BMH's inner classes
++            final Class<BoundMethodHandle> BMH = BoundMethodHandle.class;
++            try {
++                for (Class<?> c : BMH.getDeclaredClasses()) {
++                    if (BMH.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);
++                    }
++                }
++            } catch (Throwable e) {
++                throw new InternalError(e);
++            }
++        }
++    }
++
++    /**
++     * Generation of concrete BMH classes.
++     *
++     * A concrete BMH 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.
++     *
++     * A concrete BMH 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 BMHDATA_GET_SIG = "(" + JLS_SIG + ")" + DATA_SIG;
++        static final String TYPES_SIG = "()" + JLS_SIG;
++        static final String MYDATA_SIG = "()" + DATA_SIG;
++
++        static final String SIG_INCIPIT = "(Ljava/lang/invoke/MethodType;Ljava/lang/invoke/LambdaForm;";
++
++        static final Class<?>[] TYPES = new Class<?>[] { Object.class, int.class, long.class, float.class, double.class };
++
++        static final String[] E_THROWABLE = new String[] { "java/lang/Throwable" };
++
++        /**
++         * Generate a concrete subclass of BMH for a given combination of bound types.
++         *
++         * A concrete BMH subclass adheres to the following schema:
++         *
++         * <pre>
++         * class BMH_<<types>> extends BMH {
++         *     <<fields>>
++         *     final String dataValueTypes() { return <<types>>; }
++         * }
++         * </pre>
++         *
++         * The {@code <<types>>} signature is precisely the string that is passed to this
++         * method.
++         *
++         * The {@code <<fields>>} section consists of one field definition per character in
++         * the type signature, adhering to the naming schema described in the definition of
++         * {@link #makeFieldName()}.
++         *
++         * For example, a concrete BMH class for two reference and one integral bound values
++         * would have the following shape:
++         *
++         * <pre>
++         * final class BMH_LLI extends BMH {
++         *     final Object argL0;
++         *     final Object argL1;
++         *     final int argI2;
++         *     public BMH_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 BoundMethodHandle clone(MethodType mt, LambdaForm lf) {
++         *         return myData().constructor.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);
++         *     }
++         *     public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) {
++         *         return BMHData.get("LLII").constructor.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);
++         *     }
++         *     public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) {
++         *         return BMHData.get("LLIF").constructor.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);
++         *     }
++         * }
++         * </pre>
++         *
++         * @param types the type signature, wherein reference types are erased to 'L'
++         * @return the generated concrete BMH class
++         */
++        static Class<? extends BoundMethodHandle> generateConcreteBMHClass(String types) {
++            final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
++
++            final String className = "java/lang/invoke/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 bound argument fields
++            for (int i = 0; i < types.length(); ++i) {
++                final char t = types.charAt(i);
++                final String fieldName = makeFieldName(types, i);
++                final String fieldDesc = t == 'L' ? JLO_SIG : String.valueOf(t);
++                cw.visitField(ACC_FINAL, fieldName, fieldDesc, null, null).visitEnd();
++            }
++
++            MethodVisitor mv;
++
++            // emit constructor
++            mv = cw.visitMethod(ACC_PUBLIC, "<init>", makeSignature(types, true), null, null);
++            mv.visitCode();
++            mv.visitVarInsn(ALOAD, 0);
++            mv.visitVarInsn(ALOAD, 1);
++            mv.visitVarInsn(ALOAD, 2);
++
++            mv.visitMethodInsn(INVOKESPECIAL, BMH, "<init>", makeSignature("", true));
++
++            for (int i = 0, j = 0; i < types.length(); ++i, ++j) {
++                // i counts the arguments, j counts corresponding argument slots
++                char t = types.charAt(i);
++                mv.visitVarInsn(ALOAD, 0);
++                mv.visitVarInsn(typeLoadOp(t), j + 3); // parameters start at 3
++                mv.visitFieldInsn(PUTFIELD, className, makeFieldName(types, i), typeSig(t));
++                if (t == 'J' || t == 'D') {
++                    ++j; // adjust argument register access
++                }
++            }
++
++            mv.visitInsn(RETURN);
++            mv.visitMaxs(0, 0);
++            mv.visitEnd();
++
++            // emit implementation of types()
++            mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "types", TYPES_SIG, null, null);
++            mv.visitCode();
++            mv.visitLdcInsn(types);
++            mv.visitInsn(ARETURN);
++            mv.visitMaxs(0, 0);
++            mv.visitEnd();
++
++            // emit clone()
++            mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "clone", makeSignature("", false), null, E_THROWABLE);
++            mv.visitCode();
++            // return myData().constructor.invokeBasic(mt, lf, argL0, ...)
++            // obtain constructor
++            mv.visitVarInsn(ALOAD, 0);
++            mv.visitMethodInsn(INVOKESPECIAL, BMH, "myData", MYDATA_SIG);
++            mv.visitFieldInsn(GETFIELD, DATA, "constructor", MH_SIG);
++            // load mt, lf
++            mv.visitVarInsn(ALOAD, 1);
++            mv.visitVarInsn(ALOAD, 2);
++            // put fields on the stack
++            emitPushFields(types, className, mv);
++            // finally, invoke the constructor and return
++            mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types, false));
++            mv.visitInsn(ARETURN);
++            mv.visitMaxs(0, 0);
++            mv.visitEnd();
++
++            // for each type, emit cloneExtendT()
++            for (Class<?> c : TYPES) {
++                char t = Wrapper.basicTypeChar(c);
++                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)
++                // obtain constructor
++                mv.visitLdcInsn(extypes);
++                mv.visitMethodInsn(INVOKESTATIC, DATA, "get", BMHDATA_GET_SIG);
++                mv.visitFieldInsn(GETFIELD, DATA, "constructor", MH_SIG);
++                // load mt, lf
++                mv.visitVarInsn(ALOAD, 1);
++                mv.visitVarInsn(ALOAD, 2);
++                // put fields on the stack
++                emitPushFields(types, className, mv);
++                // put narg on stack
++                mv.visitVarInsn(typeLoadOp(t), 3);
++                // finally, invoke the constructor and return
++                mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(extypes, false));
++                mv.visitInsn(ARETURN);
++                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.ensureClassInitialized(bmhClass);
++
++            return bmhClass;
++        }
++
++        private static int typeLoadOp(char t) {
++            switch (t) {
++            case 'L': return ALOAD;
++            case 'I': return ILOAD;
++            case 'J': return LLOAD;
++            case 'F': return FLOAD;
++            case 'D': return DLOAD;
++            default : throw new InternalError("unrecognized type " + t);
++            }
++        }
++
++        private static void emitPushFields(String types, String className, MethodVisitor mv) {
++            for (int i = 0; i < types.length(); ++i) {
++                char tc = types.charAt(i);
++                mv.visitVarInsn(ALOAD, 0);
++                mv.visitFieldInsn(GETFIELD, className, makeFieldName(types, i), typeSig(tc));
++            }
++        }
++
++        static String typeSig(char t) {
++            return t == 'L' ? JLO_SIG : String.valueOf(t);
++        }
++
++        //
++        // Getter MH generation.
++        //
++
++        private static MethodHandle makeGetter(Class<?> cbmhClass, String types, int index) {
++            String fieldName = makeFieldName(types, index);
++            Class<?> fieldType = Wrapper.forBasicType(types.charAt(index)).primitiveType();
++            try {
++                return LOOKUP.findGetter(cbmhClass, fieldName, fieldType);
++            } catch (NoSuchFieldException | IllegalAccessException e) {
++                throw new InternalError(e);
++            }
++        }
++
++        static MethodHandle[] makeGetters(Class<?> cbmhClass, String types) {
++            MethodHandle[] mhs = new MethodHandle[types.length()];
++            for (int i = 0; i < mhs.length; ++i) {
++                mhs[i] = makeGetter(cbmhClass, types, i);
++            }
++            return mhs;
++        }
++
++        //
++        // Auxiliary methods.
++        //
++
++        static String typesFromConcreteBMHClass(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 names in concrete BMHs adhere to this pattern:
++         * arg + type + index
++         * where type is a single character (L, I, J, F, D).
++         */
++        private static String makeFieldName(String types, int index) {
++            assert index >= 0 && index < types.length();
++            return "arg" + types.charAt(index) + index;
++        }
++
++        private static String makeSignature(String types, boolean ctor) {
++            StringBuilder buf = new StringBuilder(SIG_INCIPIT);
++            for (char c : types.toCharArray()) {
++                buf.append(typeSig(c));
++            }
++            return buf.append(')').append(ctor ? "V" : BMH_SIG).toString();
++        }
++
++        static MethodHandle makeCbmhCtor(Class<? extends BoundMethodHandle> cbmh, String types) {
++            try {
++                return linkConstructor(LOOKUP.findConstructor(cbmh, MethodType.fromMethodDescriptorString(makeSignature(types, true), null)));
++            } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | TypeNotPresentException e) {
++                throw new InternalError(e);
++            }
++        }
++
++        /**
++         * Wrap a constructor call in a {@link LambdaForm}.
++         *
++         * If constructors ({@code <init>} methods) are called in LFs, problems might arise if the LFs
++         * are turned into bytecode, because the call to the allocator is routed through an MH, and the
++         * verifier cannot find a {@code NEW} instruction preceding the {@code INVOKESPECIAL} to
++         * {@code <init>}. To avoid this, we add an indirection by invoking {@code <init>} through
++         * {@link MethodHandle#linkToSpecial}.
++         *
++         * The last {@link LambdaForm#Name Name} in the argument's form is expected to be the {@code void}
++         * result of the {@code <init>} invocation. This entry is replaced.
++         */
++        private static MethodHandle linkConstructor(MethodHandle cmh) {
++            final LambdaForm lf = cmh.form;
++            final int initNameIndex = lf.names.length - 1;
++            final Name initName = lf.names[initNameIndex];
++            final MemberName ctorMN = initName.function.member;
++            final MethodType ctorMT = ctorMN.getInvocationType();
++
++            // obtain function member (call target)
++            // linker method type replaces initial parameter (BMH species) with BMH to avoid naming a species (anonymous class!)
++            final MethodType linkerMT = ctorMT.changeParameterType(0, BoundMethodHandle.class).appendParameterTypes(MemberName.class);
++            MemberName linkerMN = new MemberName(MethodHandle.class, "linkToSpecial", linkerMT, REF_invokeStatic);
++            try {
++                linkerMN = MemberName.getFactory().resolveOrFail(REF_invokeStatic, linkerMN, null, NoSuchMethodException.class);
++                assert(linkerMN.isStatic());
++            } catch (ReflectiveOperationException ex) {
++                throw new InternalError(ex);
++            }
++            // extend arguments array
++            Object[] newArgs = Arrays.copyOf(initName.arguments, initName.arguments.length + 1);
++            newArgs[newArgs.length - 1] = ctorMN;
++            // replace function
++            final NamedFunction nf = new NamedFunction(linkerMN);
++            final Name linkedCtor = new Name(nf, newArgs);
++            linkedCtor.initIndex(initNameIndex);
++            lf.names[initNameIndex] = linkedCtor;
++            return cmh;
++        }
++
++        //
++        // Constants.
++        //
++
++        private static final Lookup LOOKUP = Lookup.IMPL_LOOKUP;
++        private static final Unsafe UNSAFE = Unsafe.getUnsafe();
++
++    }
 +
  }
 diff --git a/src/share/classes/java/lang/invoke/CallSite.java b/src/share/classes/java/lang/invoke/CallSite.java
@@ -1682,17 +2259,19 @@
  
  /**
   * This method handle is used to optionally provide a count of how
-@@ -33,18 +36,56 @@
+@@ -33,18 +36,94 @@
   *
   * @author never
   */
 -class CountingMethodHandle extends AdapterMethodHandle {
-+class CountingMethodHandle extends BoundMethodHandle<MethodHandle> {
++class CountingMethodHandle extends BoundMethodHandle {
++    private MethodHandle target;
      private int vmcount;
  
      private CountingMethodHandle(MethodHandle target) {
 -        super(target, target.type(), AdapterMethodHandle.makeConv(OP_RETYPE_ONLY));
-+        super(target.type(), countingReinvokerForm(target.type().basicType()), target);
++        super(target.type(), countingReinvokerForm(target.type().basicType()));
++        this.target = target;
      }
  
      /** Wrap the incoming MethodHandle in a CountingMethodHandle if they are enabled */
@@ -1704,6 +2283,13 @@
          return mh;
      }
 +
++    @Override
++    public String types() {
++        return types;
++    }
++
++    public static final String types = "L";
++
 +    @ForceInline
 +    void vmcountBump() {
 +        vmcount += 1;
@@ -1724,7 +2310,7 @@
 +        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.dataValueName(names[THIS_CMH], 'L', 0);
++        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);
@@ -1741,202 +2327,40 @@
 +        }
 +    }
 +
++    @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/DataBinding.java b/src/share/classes/java/lang/invoke/DataBinding.java
-new file mode 100644
---- /dev/null
-+++ b/src/share/classes/java/lang/invoke/DataBinding.java
-@@ -0,0 +1,186 @@
-+/*
-+ * 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.List;
-+import java.util.AbstractList;
-+
-+/**
-+ * Interface for binding data values into a method handle or other object.
-+ * @author John Rose, JSR 292 EG
-+ */
-+interface DataBinding {
-+    // /** Get basic types of the data fields, as a string of the form {@code "[LIJFD]*"}. */
-+    // public String dataValueTypes();
-+    // /** Get the number of data fields, equivalent to {@code getSignature().length()}. */
-+    // public int dataValueCount();
-+    // /** Get the basic type of the N-th value, one of the characters in {@code "LIJFD"}. */
-+    // public char  dataValueType(int i);
-+
-+    // /** Get the N-th value, boxed as needed. */
-+    // public Object dataValue(int i);
-+    // /** Get the N-th value, which must be a reference. */
-+    // public Object objectDataValue(int i);
-+    // /** Get the N-th value, which must be an int. */
-+    // public int intDataValue(int i);
-+    // /** Get the N-th value, which must be a long. */
-+    // public long longDataValue(int i);
-+    // /** Get the N-th value, which must be a float. */
-+    // public float floatDataValue(int i);
-+    // /** Get the N-th value, which must be a double. */
-+    // public double doubleDataValue(int i);
-+
-+//    /** Create an object with the same values, plus the added reference. */
-+//    public DataBinding addObjectDataValue(Object valule);
-+//    /** Create an object with the same values, plus the added int. */
-+//    public DataBinding addIntDataValue(int value);
-+//    /** Create an object with the same values, plus the added long. */
-+//    public DataBinding addLongDataValue(long value);
-+//    /** Create an object with the same values, plus the added float. */
-+//    public DataBinding addFloatDataValue(float value);
-+//    /** Create an object with the same values, plus the added double. */
-+//    public DataBinding addDoubleDataValue(double value);
-+
-+    class ListView extends AbstractList<Object> {
-+        final BoundMethodHandle data;
-+
-+        ListView(BoundMethodHandle data) {
-+            this.data = data;
-+        }
-+
-+        @Override
-+        public Object get(int i) {
-+            if (i == 0)
-+                return data.dataValue0();
-+            else
-+                return ((BoundMethodHandle.Multiple) data).dataValue(i);
-+        }
-+
-+        @Override
-+        public int size() {
-+            return data.dataValueCount();
-+        }
-+
-+        @Override
-+        public Object[] toArray() {
-+            return Methods.toArray(data);
-+        }
-+    }
-+
-+    public class Methods {
-+        private Methods() { throw new InternalError(); }
-+
-+        public static boolean checkDataValueType(BoundMethodHandle data, int i, char type) {
-+            char actualType = data.dataValueType(i);
-+            if (actualType != type) {
-+                throw new IllegalArgumentException("actual type is "+actualType);
-+            }
-+            return true;  // pass boolean back for use with assert()
-+        }
-+
-+        public static int dataValueCount(BoundMethodHandle data) {
-+            return data.dataValueTypes().length();
-+        }
-+        public static char dataValueType(BoundMethodHandle data, int i) {
-+            return data.dataValueTypes().charAt(i);
-+        }
-+        public static String dataValueTypes(BoundMethodHandle data) {
-+            char[] types = new char[data.dataValueCount()];
-+            for (int i = 0; i < types.length; i++)
-+                types[i] = data.dataValueType(i);
-+            return new String(types);
-+        }
-+
-+        /*
-+        public static Object objectDataValue(BoundMethodHandle data, int i) {
-+            //checkDataValueType(data, i, 'L');
-+            return data.dataValue(i);
-+        }
-+        public static int intDataValue(BoundMethodHandle data, int i) {
-+            //checkDataValueType(data, i, 'I');
-+            return (Integer) data.dataValue(i);
-+        }
-+        public static long longDataValue(BoundMethodHandle data, int i) {
-+            //checkDataValueType(data, i, 'J');
-+            return (Long) data.dataValue(i);
-+        }
-+        public static float floatDataValue(BoundMethodHandle data, int i) {
-+            //checkDataValueType(data, i, 'F');
-+            return (Float) data.dataValue(i);
-+        }
-+        public static double doubleDataValue(BoundMethodHandle data, int i) {
-+            //checkDataValueType(data, i, 'D');
-+            return (Double) data.dataValue(i);
-+        }
-+
-+        public static Object dataValue(BoundMethodHandle data, int i) {
-+            switch (data.dataValueType(i)) {
-+                case 'I':  return data.intDataValue(i);
-+                case 'J':  return data.longDataValue(i);
-+                case 'F':  return data.floatDataValue(i);
-+                case 'D':  return data.doubleDataValue(i);
-+                case 'L':  return data.objectDataValue(i);
-+                default:   throw new InternalError();
-+            }
-+        }
-+        */
-+
-+        public static Object[] toArray(BoundMethodHandle data) {
-+            String types = data.dataValueTypes();
-+            int size = types.length();
-+            Object[] values = new Object[size];
-+            for (int i = 0; i < size; i++) {
-+                Object value;
-+                if (data instanceof BoundMethodHandle) {
-+                    switch (types.charAt(i)) {
-+                    case 'I':  value = data.intDataValue0();     break;
-+                    case 'J':  value = data.longDataValue0();    break;
-+                    case 'F':  value = data.floatDataValue0();   break;
-+                    case 'D':  value = data.doubleDataValue0();  break;
-+                    case 'L':  value = data.dataValue0();        break;
-+                    default:   throw new InternalError();
-+                    }
-+                } else {
-+                    BoundMethodHandle.Multiple m = (BoundMethodHandle.Multiple) data;
-+                    switch (types.charAt(i)) {
-+                    case 'I':  value = m.intDataValue(i);     break;
-+                    case 'J':  value = m.longDataValue(i);    break;
-+                    case 'F':  value = m.floatDataValue(i);   break;
-+                    case 'D':  value = m.doubleDataValue(i);  break;
-+                    case 'L':  value = m.dataValue(i);        break;
-+                    default:   throw new InternalError();
-+                    }
-+                }
-+                values[i] = value;
-+            }
-+            return values;
-+        }
-+
-+        public static List<Object> toList(BoundMethodHandle data) {
-+            return new ListView(data);
-+        }
-+    }
-+}
 diff --git a/src/share/classes/java/lang/invoke/DirectMethodHandle.java b/src/share/classes/java/lang/invoke/DirectMethodHandle.java
 --- a/src/share/classes/java/lang/invoke/DirectMethodHandle.java
 +++ b/src/share/classes/java/lang/invoke/DirectMethodHandle.java
-@@ -25,29 +25,248 @@
+@@ -25,29 +25,252 @@
  
  package java.lang.invoke;
  
@@ -1995,24 +2419,22 @@
 +    }
 +
 +    @Override
++    MethodHandle copyWith(MethodType mt, LambdaForm lf) {
++        return new DirectMethodHandle(mt, member, lf);
++    }
++
++    @Override
 +    String debugString() {
 +        return "DMH["+member.toString()+"]="+super.debugString();
 +    }
 +
 +    //// Implementation methods.
 +    @Override
++    @ForceInline
 +    MemberName internalMemberName() {
 +        return member;
 +    }
 +
-+    /** Static wrapper for DirectMethodHandle.internalMemberName. */
-+    @ForceInline
-+    /*non-public*/ static
-+    Object internalMemberName(Object mh) {
-+        return ((DirectMethodHandle)mh).member;
-+    }
-+
-+
 +    @Override
 +    MethodHandle bindArgument(int pos, char basicType, Object value) {
 +        // If the member needs dispatching, do so.
@@ -2153,6 +2575,12 @@
 +        static final EnsureInitialized INSTANCE = new EnsureInitialized();
 +    }
 +
++    /** Static wrapper for DirectMethodHandle.internalMemberName. */
++    /*non-public*/ static
++    Object internalMemberName(Object mh) {
++        return ((DirectMethodHandle)mh).member;
++    }
++
 +    private static final NamedFunction NF_internalMemberName;
 +    private static final NamedFunction NF_ensureClassInitialized;
 +    private static final MethodHandle MH_shouldBeInitialized;
@@ -2287,7 +2715,7 @@
 new file mode 100644
 --- /dev/null
 +++ b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
-@@ -0,0 +1,1107 @@
+@@ -0,0 +1,1066 @@
 +/*
 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -2317,6 +2745,7 @@
 +
 +import sun.invoke.util.VerifyAccess;
 +import java.lang.invoke.LambdaForm.Name;
++import java.lang.invoke.MethodHandles.Lookup;
 +
 +import sun.invoke.util.Wrapper;
 +import sun.misc.Unsafe;
@@ -2342,7 +2771,6 @@
 +    /** Define class names for convenience. */
 +    private static final String MH      = "java/lang/invoke/MethodHandle";
 +    private static final String BMH     = "java/lang/invoke/BoundMethodHandle";
-+    private static final String BMHM    = "java/lang/invoke/BoundMethodHandle$Multiple";
 +    private static final String LF      = "java/lang/invoke/LambdaForm";
 +    private static final String LFN     = "java/lang/invoke/LambdaForm$Name";
 +    private static final String CLS     = "java/lang/Class";
@@ -2438,7 +2866,7 @@
 +        }
 +    }
 +
-+    private void maybeDump(final byte[] classFile) {
++    static void maybeDump(final String className, final byte[] classFile) {
 +        if (DUMP_CLASS_FILES) {
 +            System.out.println("dump: " + className);
 +            java.security.AccessController.doPrivileged(
@@ -2580,6 +3008,9 @@
 +
 +        String invokerDesc = invokerType.toMethodDescriptorString();
 +        mv = cw.visitMethod(Opcodes.ACC_STATIC, invokerName, invokerDesc, null, null);
++
++        // Force inlining of this invoker method.
++        mv.visitAnnotation("Ljava/lang/invoke/ForceInline;", true);
 +    }
 +
 +    /**
@@ -2731,7 +3162,11 @@
 +        case 'L':
 +            if (VerifyType.isNullConversion(Object.class, pclass))
 +                return;
-+            if (isStaticallyNameable(pclass)) {
++            // 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)) {
 +                mv.visitTypeInsn(Opcodes.CHECKCAST, getInternalName(pclass));
 +            } else {
 +                mv.visitLdcInsn(constantPlaceholder(pclass));
@@ -2800,9 +3235,6 @@
 +    private byte[] generateCustomizedCodeBytes() {
 +        classFilePrologue();
 +
-+        // Force inlining of this invoker method.
-+        mv.visitAnnotation("Ljava/lang/invoke/ForceInline;", true);
-+
 +        // Suppress this method in backtraces displayed to the user.
 +        mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
 +
@@ -2820,8 +3252,6 @@
 +                // FIXME: make sure this idiom is really present!
 +                emitSelectAlternative(name, lambdaForm.names[i + 1]);
 +                i++;  // skip MH.invokeBasic of the selectAlternative result
-+            } else if (isBoundArgumentLoad(member)) {
-+                emitBoundArgumentLoad(member, name);
 +            } else if (isStaticallyInvocable(member)) {
 +                emitStaticInvoke(member, name);
 +            } else {
@@ -2843,9 +3273,10 @@
 +        emitReturn();
 +
 +        classFileEpilogue();
++        bogusMethod(lambdaForm);
 +
 +        final byte[] classFile = cw.toByteArray();
-+        maybeDump(classFile);
++        maybeDump(className, classFile);
 +        return classFile;
 +    }
 +
@@ -2890,6 +3321,7 @@
 +
 +    boolean isStaticallyInvocable(MemberName member) {
 +        if (member == null)  return false;
++        assert !member.isConstructor();
 +        Class<?> cls = member.getDeclaringClass();
 +        if (cls.isArray() || cls.isPrimitive())
 +            return false;  // FIXME
@@ -2990,6 +3422,8 @@
 +     * @param invokeBasicName
 +     */
 +    private void emitSelectAlternative(Name selectAlternativeName, Name invokeBasicName) {
++        MethodType type = selectAlternativeName.function.methodType();
++
 +        Name receiver = (Name) invokeBasicName.arguments[0];
 +
 +        Label L_fallback = new Label();
@@ -3025,69 +3459,6 @@
 +    }
 +
 +    /**
-+     * Check if MemberName is a call to retrieve a bound argument.
-+     *
-+     * @param member
-+     * @return
-+     */
-+    private boolean isBoundArgumentLoad(MemberName member) {
-+        if (member == null) {
-+            return false;
-+        }
-+        Class<?> klass = member.getDeclaringClass();
-+        String   name  = member.getName();
-+        if (klass != BoundMethodHandle.class && klass != BoundMethodHandle.Multiple.class) {
-+            return false;
-+        }
-+        if (!name.startsWith("dataValue") &&
-+            !name.startsWith("intDataValue") &&
-+            !name.startsWith("longDataValue")) {
-+            return false;
-+        }
-+        if (name.equals("dataValue") || name.equals("intDataValue") || name.equals("longDataValue")) {
-+            return false;
-+        }
-+        int arity = member.getInvocationType().parameterCount();
-+        if (arity == 2)
-+            return false;  // do not handle Multiple.dataValue(int i), yet
-+        assert(arity == 1);
-+        return true;
-+    }
-+
-+    private void emitBoundArgumentLoad(MemberName member, Name argLoadName) {
-+        assert(argLoadName.arguments.length == 1 &&
-+               argLoadName.arguments[0] == this.lambdaForm.names[0]) : argLoadName.exprString();
-+        String name = member.getName();
-+        int index = Integer.valueOf(name.substring(name.length() - 1));
-+
-+        if (index == 0) {
-+            // aload_0
-+            // checkcast  // class java/lang/invoke/BoundMethodHandle
-+            // getfield   // Field argument:Ljava/lang/Object;
-+            emitAloadInsn(0);
-+            mv.visitTypeInsn(Opcodes.CHECKCAST, BMH);
-+            mv.visitFieldInsn(Opcodes.GETFIELD, BMH, "argument", "Ljava/lang/Object;");
-+        } else {
-+            // aload_0
-+            // checkcast  // class java/lang/invoke/BoundMethodHandle$Multiple
-+            // getfield   // Field next:Ljava/lang/invoke/BoundMethodHandle$Multiple;
-+            // getfield   // Field argument:Ljava/lang/Object;
-+            emitAloadInsn(0);
-+            mv.visitTypeInsn(Opcodes.CHECKCAST, BMHM);
-+            for (int i = 0; i < index; i++) {
-+                mv.visitFieldInsn(Opcodes.GETFIELD, BMHM, "next", "Ljava/lang/invoke/BoundMethodHandle$Multiple;");
-+            }
-+            mv.visitFieldInsn(Opcodes.GETFIELD, BMH, "argument", "Ljava/lang/Object;");
-+        }
-+
-+        if (name.startsWith("intDataValue")) {
-+            emitUnboxing(Integer.class);
-+        } else if (name.startsWith("longDataValue")) {
-+            emitUnboxing(Long.class);
-+        }
-+    }
-+
-+    /**
 +     *
 +     * @param name
 +     * @param paramIndex
@@ -3095,16 +3466,17 @@
 +    private void emitPushArgument(Name name, int paramIndex) {
 +        Object arg = name.arguments[paramIndex];
 +        char ptype = name.function.parameterType(paramIndex);
++        MethodType mtype = name.function.methodType();
 +        if (arg instanceof Name) {
 +            Name n = (Name) arg;
 +            emitLoadInsn(n.type, n.index());
-+            MethodType mtype = name.function.methodType();
 +            emitImplicitConversion(n.type, mtype.parameterType(paramIndex));
 +        } else {
 +            if (Wrapper.isWrapperType(arg.getClass()) && ptype != 'L') {
 +                emitConst(arg);
 +            } else {
 +                mv.visitLdcInsn(constantPlaceholder(arg));
++                emitImplicitConversion('L', mtype.parameterType(paramIndex));
 +            }
 +        }
 +    }
@@ -3280,9 +3652,6 @@
 +    private byte[] generateLambdaFormInterpreterEntryPointBytes() {
 +        classFilePrologue();
 +
-+        // Prevent inlining of this invoker method.
-+        mv.visitAnnotation("Ljava/lang/invoke/DontInline;", true);
-+
 +        // Suppress this method in backtraces displayed to the user.
 +        mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
 +
@@ -3318,9 +3687,10 @@
 +        emitReturnInsn(rtype);
 +
 +        classFileEpilogue();
++        bogusMethod(invokerType);
 +
 +        final byte[] classFile = cw.toByteArray();
-+        maybeDump(classFile);
++        maybeDump(className, classFile);
 +        return classFile;
 +    }
 +
@@ -3338,13 +3708,12 @@
 +        return g.loadMethod(g.generateNamedFunctionInvokerImpl(typeForm));
 +    }
 +
++    static int nfi = 0;
++
 +    private byte[] generateNamedFunctionInvokerImpl(MethodTypeForm typeForm) {
 +        MethodType dstType = typeForm.erasedType();
 +        classFilePrologue();
 +
-+        // Force inlining of this invoker method.
-+        mv.visitAnnotation("Ljava/lang/invoke/ForceInline;", true);
-+
 +        // Suppress this method in backtraces displayed to the user.
 +        mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
 +
@@ -3389,11 +3758,29 @@
 +        emitReturnInsn(Object.class);  // NOTE: NamedFunction invokers always return a reference value.
 +
 +        classFileEpilogue();
++        bogusMethod(dstType);
 +
 +        final byte[] classFile = cw.toByteArray();
-+        maybeDump(classFile);
++        maybeDump(className, classFile);
 +        return classFile;
 +    }
++
++    /**
++     * Emit a bogus method that just loads some string constants. This is to get the constants into the constant pool
++     * for debugging purposes.
++     */
++    private void bogusMethod(Object... os) {
++        if (DUMP_CLASS_FILES) {
++            mv = cw.visitMethod(Opcodes.ACC_STATIC, "dummy", "()V", null, null);
++            for (Object o : os) {
++                mv.visitLdcInsn(o.toString());
++                mv.visitInsn(Opcodes.POP);
++            }
++            mv.visitInsn(Opcodes.RETURN);
++            mv.visitMaxs(0, 0);
++            mv.visitEnd();
++        }
++    }
 +}
 diff --git a/src/share/classes/java/lang/invoke/Invokers.java b/src/share/classes/java/lang/invoke/Invokers.java
 --- a/src/share/classes/java/lang/invoke/Invokers.java
@@ -3440,7 +3827,7 @@
 -        invoker = lookupInvoker("invokeExact");
 +        MethodType mtype = targetType;
 +        LambdaForm lform = invokeForm(mtype, MethodTypeForm.LF_EX_INVOKER);
-+        invoker = new BoundMethodHandle<MethodType>(mtype.invokerType(), lform, mtype);
++        invoker = new BoundMethodHandle.BMH_L(mtype.invokerType(), lform, mtype);
 +        assert(checkInvoker(invoker));
          exactInvoker = invoker;
          return invoker;
@@ -3453,7 +3840,7 @@
 +        MethodType mtype = targetType;
 +        prepareForGenericCall(mtype);
 +        LambdaForm lform = invokeForm(mtype, MethodTypeForm.LF_GEN_INVOKER);
-+        invoker = new BoundMethodHandle<MethodType>(mtype.invokerType(), lform, mtype);
++        invoker = new BoundMethodHandle.BMH_L(mtype.invokerType(), lform, mtype);
 +        assert(checkInvoker(invoker));
          generalInvoker = invoker;
          return invoker;
@@ -3599,7 +3986,7 @@
 +        assert(names.length == nameCursor);
 +        if (MTYPE_ARG >= INARG_LIMIT) {
 +            assert(names[MTYPE_ARG] == null);
-+            names[MTYPE_ARG] = BoundMethodHandle.dataValueName(names[THIS_MH], 'L', 0);
++            names[MTYPE_ARG] = BoundMethodHandle.getterName(names[THIS_MH], 'L', 0);
 +            // else if isLinker, then MTYPE is passed in from the caller (e.g., the JVM)
 +        }
 +
@@ -3753,7 +4140,7 @@
 new file mode 100644
 --- /dev/null
 +++ b/src/share/classes/java/lang/invoke/LambdaForm.java
-@@ -0,0 +1,1506 @@
+@@ -0,0 +1,1561 @@
 +/*
 + * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -4020,7 +4407,7 @@
 +        // Do all names possess an index consistent with their local definition order?
 +        for (int i = 0; i < arity; i++) {
 +            Name n = names[i];
-+            assert(n.index() == i);
++            assert(n.index() == i) : Arrays.asList(n.index(), i);
 +            assert(n.isParam());
 +        }
 +        // Also, do all local name references
@@ -4032,7 +4419,7 @@
 +                    Name n2 = (Name) arg;
 +                    int i2 = n2.index;
 +                    assert(0 <= i2 && i2 < names.length) : n.debugString() + ": 0 <= i2 && i2 < names.length: 0 <= " + i2 + " < " + names.length;
-+                    assert(names[i2] == n2) : Arrays.asList(i, n.debugString(), i2, n2.debugString(), names[i2].debugString(), this);
++                    assert(names[i2] == n2) : Arrays.asList("-1-", i, "-2-", n.debugString(), "-3-", i2, "-4-", n2.debugString(), "-5-", names[i2].debugString(), "-6-", this);
 +                    assert(i2 < i);  // ref must come after def!
 +                }
 +            }
@@ -4242,7 +4629,6 @@
 +
 +    // The following are predefined exact invokers.  The system must build
 +    // a separate invoker for each distinct signature.
-+    @DontInline
 +    static Object interpret_L(MethodHandle mh) throws Throwable {
 +        Object[] av = {mh};
 +        String sig = null;
@@ -4251,7 +4637,6 @@
 +        assert(returnTypesMatch(sig, av, res));
 +        return res;
 +    }
-+    @DontInline
 +    static Object interpret_L(MethodHandle mh, Object x1) throws Throwable {
 +        Object[] av = {mh, x1};
 +        String sig = null;
@@ -4260,7 +4645,6 @@
 +        assert(returnTypesMatch(sig, av, res));
 +        return res;
 +    }
-+    @DontInline
 +    static Object interpret_L(MethodHandle mh, Object x1, Object x2) throws Throwable {
 +        Object[] av = {mh, x1, x2};
 +        String sig = null;
@@ -4467,8 +4851,57 @@
 +        return buf.toString();
 +    }
 +
++    /**
++     * Apply immediate binding for a Name in this form indicated by its position relative to the form.
++     * The first parameter to a LambdaForm, a0:L, always represents the form's method handle, so 0 is not
++     * accepted as valid.
++     */
++    LambdaForm bindImmediate(int pos, char basicType, Object value) {
++        // must be an argument, and the types must match
++        assert pos > 0 && pos < arity && names[pos].type == basicType && Name.typesMatch(basicType, value);
++
++        int arity2 = arity - 1;
++        Name[] names2 = new Name[names.length - 1];
++        for (int r = 0, w = 0; r < names.length; ++r, ++w) { // (r)ead from names, (w)rite to names2
++            Name n = names[r];
++            if (n.isParam()) {
++                if (n.index == pos) {
++                    // do not copy over the argument that is to be replaced with a literal,
++                    // but adjust the write index
++                    --w;
++                } else {
++                    names2[w] = new Name(w, n.type);
++                }
++            } else {
++                Object[] arguments2 = new Object[n.arguments.length];
++                for (int i = 0; i < n.arguments.length; ++i) {
++                    Object arg = n.arguments[i];
++                    if (arg instanceof Name) {
++                        int ni = ((Name) arg).index;
++                        if (ni == pos) {
++                            arguments2[i] = value;
++                        } else if (ni < pos) {
++                            // replacement position not yet passed
++                            arguments2[i] = names2[ni];
++                        } else {
++                            // replacement position passed
++                            arguments2[i] = names2[ni - 1];
++                        }
++                    } else {
++                        arguments2[i] = arg;
++                    }
++                }
++                names2[w] = new Name(n.function, arguments2);
++                names2[w].initIndex(w);
++            }
++        }
++
++        int result2 = result == -1 ? -1 : result - 1;
++        return new LambdaForm(debugName, arity2, names2, result2);
++    }
++
 +    LambdaForm bind(char basicType, int namePos, int dataValuePos) {
-+        Name dataValueName = BoundMethodHandle.dataValueName(names[0], basicType, dataValuePos);
++        Name dataValueName = BoundMethodHandle.getterName(names[0], basicType, dataValuePos);
 +        return bind(names[namePos], dataValueName);
 +    }
 +
@@ -4481,7 +4914,7 @@
 +        if (bindCache != null) {
 +            LambdaForm form = bindCache[pos];
 +            if (form != null) {
-+                assert(form.contains(binding));
++                assert(form.contains(binding)) : "form << " + form + " >> does not contain binding << " + binding + " >>";
 +                return form;
 +            }
 +        } else {
@@ -4665,6 +5098,15 @@
 +            resolvedHandle = DirectMethodHandle.make(member);
 +        }
 +
++        @Override
++        public boolean equals(Object other) {
++            if (this == other) return true;
++            if (other == null) return false;
++            if (!(other instanceof NamedFunction)) return false;
++            NamedFunction that = (NamedFunction) other;
++            return this.member != null && this.member.equals(that.member);
++        }
++
 +        // Put the predefined NamedFunction invokers into the table.
 +        static void initializeInvokers() {
 +            for (MemberName m : MemberName.getFactory().getMethods(NamedFunction.class, false, null, null, null)) {
@@ -5272,19 +5714,43 @@
  import java.lang.reflect.Constructor;
  import java.lang.reflect.Field;
  import java.lang.reflect.Method;
-@@ -71,19 +73,14 @@
+@@ -71,19 +73,40 @@
      private String     name;        // may be null if not yet materialized
      private Object     type;        // may be null if not yet materialized
      private int        flags;       // modifier bits; see reflect.Modifier
--
--    private Object     vmtarget;    // VM-specific target value
--    private int        vmindex;     // method index within class or interface
--
--    { vmindex = VM_INDEX_UNINITIALIZED; }
 +    //@Injected JVM_Method* vmtarget;
 +    //@Injected int         vmindex;
 +    private Object     resolution;  // if null, this guy is resolved
  
+-    private Object     vmtarget;    // VM-specific target value
+-    private int        vmindex;     // method index within class or interface
++    @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());
++    }
+ 
+-    { vmindex = VM_INDEX_UNINITIALIZED; }
++    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.
       */
@@ -5295,7 +5761,7 @@
          return clazz;
      }
  
-@@ -105,6 +102,16 @@
+@@ -105,6 +128,16 @@
          return name;
      }
  
@@ -5312,7 +5778,7 @@
      /** Return the declared type of this member, which
       *  must be a method or constructor.
       */
-@@ -140,7 +147,7 @@
+@@ -140,7 +173,7 @@
       *  a reference to declaring class.  For static methods, it is the same as the declared type.
       */
      public MethodType getInvocationType() {
@@ -5321,7 +5787,7 @@
          if (!isStatic())
              itype = itype.insertParameterTypes(0, clazz);
          return itype;
-@@ -208,9 +215,94 @@
+@@ -208,9 +241,94 @@
          return (flags & RECOGNIZED_MODIFIERS);
      }
  
@@ -5416,7 +5882,7 @@
      }
  
      private boolean testFlags(int mask, int value) {
-@@ -223,6 +315,17 @@
+@@ -223,6 +341,17 @@
          return !testFlags(mask, 0);
      }
  
@@ -5434,7 +5900,7 @@
      /** Utility method to query the modifier flags of this member. */
      public boolean isStatic() {
          return Modifier.isStatic(flags);
-@@ -243,10 +346,22 @@
+@@ -243,10 +372,22 @@
      public boolean isFinal() {
          return Modifier.isFinal(flags);
      }
@@ -5457,7 +5923,7 @@
      // let the rest (native, volatile, transient, etc.) be tested via Modifier.isFoo
  
      // unofficial modifier flags, used by HotSpot:
-@@ -279,15 +394,12 @@
+@@ -279,15 +420,12 @@
              IS_CONSTRUCTOR = MN_IS_CONSTRUCTOR, // constructor
              IS_FIELD       = MN_IS_FIELD,       // field
              IS_TYPE        = MN_IS_TYPE;        // nested type
@@ -5474,7 +5940,7 @@
  
      /** Utility method to query whether this member is a method or constructor. */
      public boolean isInvocable() {
-@@ -318,6 +430,12 @@
+@@ -318,6 +456,12 @@
          return !testAnyFlags(ALL_ACCESS);
      }
  
@@ -5487,7 +5953,7 @@
      /** Initialize a query.   It is not resolved. */
      private void init(Class<?> defClass, String name, Object type, int flags) {
          // defining class is allowed to be null (for a naked name/type pair)
-@@ -328,7 +446,7 @@
+@@ -328,7 +472,7 @@
          this.name = name;
          this.type = type;
          setFlags(flags);
@@ -5496,7 +5962,7 @@
      }
  
      private void expandFromVM() {
-@@ -339,39 +457,83 @@
+@@ -339,39 +483,83 @@
      }
  
      // Capturing information from the Core Reflection API:
@@ -5594,7 +6060,7 @@
      }
  
      // bare-bones constructor; the JVM will fill it in
-@@ -386,41 +548,84 @@
+@@ -386,41 +574,84 @@
          }
       }
  
@@ -5695,7 +6161,7 @@
      }
  
      /** Query whether this member name is resolved.
-@@ -429,15 +634,38 @@
+@@ -429,15 +660,38 @@
       *  (Document?)
       */
      public boolean isResolved() {
@@ -5739,7 +6205,7 @@
      /** Produce a string form of this member name.
       *  For types, it is simply the type's own string (as reported by {@code toString}).
       *  For fields, it is {@code "DeclaringClass.name/type"}.
-@@ -445,6 +673,7 @@
+@@ -445,6 +699,7 @@
       *  If the declaring class is null, the prefix {@code "DeclaringClass."} is omitted.
       *  If the member is unresolved, a prefix {@code "*."} is prepended.
       */
@@ -5747,7 +6213,7 @@
      @Override
      public String toString() {
          if (isType())
-@@ -464,22 +693,12 @@
+@@ -464,22 +719,12 @@
          } else {
              buf.append(type == null ? "(*)*" : getName(type));
          }
@@ -5775,7 +6241,7 @@
          return buf.toString();
      }
      private static String getName(Object obj) {
-@@ -488,19 +707,6 @@
+@@ -488,19 +733,6 @@
          return String.valueOf(obj);
      }
  
@@ -5795,7 +6261,7 @@
      public IllegalAccessException makeAccessException(String message, Object from) {
          message = message + ": "+ toString();
          if (from != null)  message += ", from " + from;
-@@ -518,14 +724,19 @@
+@@ -518,14 +750,19 @@
      }
      public ReflectiveOperationException makeAccessException() {
          String message = message() + ": "+ toString();
@@ -5820,7 +6286,7 @@
      }
  
      /** Actually making a query requires an access check. */
-@@ -539,7 +750,7 @@
+@@ -539,7 +776,7 @@
          private Factory() { } // singleton pattern
          static Factory INSTANCE = new Factory();
  
@@ -5829,7 +6295,7 @@
  
          /// Queries
          List<MemberName> getMembers(Class<?> defc,
-@@ -573,14 +784,14 @@
+@@ -573,14 +810,14 @@
                  // JVM returned to us with an intentional overflow!
                  totalCount += buf.length;
                  int excess = bufCount - buf.length;
@@ -5846,7 +6312,7 @@
              if (bufs != null) {
                  for (MemberName[] buf0 : bufs) {
                      Collections.addAll(result, buf0);
-@@ -599,47 +810,29 @@
+@@ -599,47 +836,29 @@
              }
              return result;
          }
@@ -5911,7 +6377,7 @@
          }
          /** Produce a resolved version of the given member.
           *  Super types are searched (for inherited members) if {@code searchSupers} is true.
-@@ -649,16 +842,29 @@
+@@ -649,16 +868,29 @@
           */
          public
          <NoSuchMemberException extends ReflectiveOperationException>
@@ -5948,7 +6414,7 @@
 diff --git a/src/share/classes/java/lang/invoke/MethodHandle.java b/src/share/classes/java/lang/invoke/MethodHandle.java
 --- a/src/share/classes/java/lang/invoke/MethodHandle.java
 +++ b/src/share/classes/java/lang/invoke/MethodHandle.java
-@@ -26,9 +26,13 @@
+@@ -26,8 +26,10 @@
  package java.lang.invoke;
  
  
@@ -5956,15 +6422,12 @@
 -import sun.invoke.util.ValueConversions;
 +import java.util.*;
 +import sun.invoke.util.*;
-+
-+import static java.lang.invoke.LambdaForm.*;
++import sun.misc.Unsafe;
++
  import static java.lang.invoke.MethodHandleStatics.*;
-+import static java.lang.invoke.MethodHandles.*;
-+import static java.lang.invoke.MethodType.*;
  
  /**
-  * A method handle is a typed, directly executable reference to an underlying method,
-@@ -208,8 +212,8 @@
+@@ -208,8 +210,8 @@
   * refers directly to an associated {@code CONSTANT_Methodref},
   * {@code CONSTANT_InterfaceMethodref}, or {@code CONSTANT_Fieldref}
   * constant pool entry.
@@ -5975,7 +6438,7 @@
   * <p>
   * Method handles produced by lookups or constant loads from methods or
   * constructors with the variable arity modifier bit ({@code 0x0080})
-@@ -224,6 +228,19 @@
+@@ -224,6 +226,19 @@
   * (E.g., if a non-static method handle is obtained via {@code ldc},
   * the type of the receiver is the class named in the constant pool entry.)
   * <p>
@@ -5995,7 +6458,7 @@
   * When a method handle to a virtual method is invoked, the method is
   * always looked up in the receiver (that is, the first argument).
   * <p>
-@@ -390,39 +407,8 @@
+@@ -390,39 +405,8 @@
   * @author John Rose, JSR 292 EG
   */
  public abstract class MethodHandle {
@@ -6035,7 +6498,8 @@
      /**
       * Internal marker interface which distinguishes (to the Java compiler)
       * those methods which are <a href="MethodHandle.html#sigpoly">signature polymorphic</a>.
-@@ -432,6 +418,8 @@
+@@ -431,7 +415,9 @@
+     @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
      @interface PolymorphicSignature { }
  
 -    private MethodType type;
@@ -6045,7 +6509,7 @@
  
      /**
       * Reports the type of this method handle.
-@@ -448,9 +437,13 @@
+@@ -448,9 +434,13 @@
       * the {@code java.lang.invoke} package.
       */
      // @param type type (permanently assigned) of the new method handle
@@ -6061,7 +6525,7 @@
      }
  
      /**
-@@ -506,6 +499,46 @@
+@@ -506,6 +496,46 @@
      public final native @PolymorphicSignature Object invoke(Object... args) throws Throwable;
  
      /**
@@ -6108,7 +6572,7 @@
       * Performs a variable arity invocation, passing the arguments in the given array
       * to the method handle, as if via an inexact {@link #invoke invoke} from a call site
       * which mentions only the type {@code Object}, and whose arity is the length
-@@ -557,6 +590,7 @@
+@@ -557,6 +587,7 @@
       */
      public Object invokeWithArguments(Object... arguments) throws Throwable {
          int argc = arguments == null ? 0 : arguments.length;
@@ -6116,7 +6580,7 @@
          MethodType type = type();
          if (type.parameterCount() != argc || isVarargsCollector()) {
              // simulate invoke
-@@ -690,7 +724,7 @@
+@@ -690,7 +721,7 @@
          if (!type.isConvertibleTo(newType)) {
              throw new WrongMethodTypeException("cannot convert "+this+" to "+newType);
          }
@@ -6125,7 +6589,7 @@
      }
  
      /**
-@@ -790,7 +824,7 @@
+@@ -790,7 +821,7 @@
                  }
              }
              if (sawProblem) {
@@ -6134,7 +6598,7 @@
                  for (int i = nargs - arrayLength; i < nargs; i++) {
                      ptypes.set(i, arrayElement);
                  }
-@@ -1056,7 +1090,8 @@
+@@ -1056,7 +1087,8 @@
          boolean lastMatch = asCollectorChecks(arrayType, 0);
          if (isVarargsCollector() && lastMatch)
              return this;
@@ -6144,7 +6608,7 @@
      }
  
      /**
-@@ -1155,14 +1190,13 @@
+@@ -1155,14 +1187,13 @@
       */
      public MethodHandle bindTo(Object x) {
          Class<?> ptype;
@@ -6165,7 +6629,7 @@
      }
  
      /**
-@@ -1183,11 +1217,100 @@
+@@ -1183,11 +1214,117 @@
      @Override
      public String toString() {
          if (DEBUG_METHOD_HANDLE_NAMES)  return debugString();
@@ -6221,8 +6685,6 @@
 +
 +    /*non-public*/
 +    Object internalValues() {
-+        if (this instanceof BoundMethodHandle)
-+            return DataBinding.Methods.toList((BoundMethodHandle) this);
 +        return "";
 +    }
 +
@@ -6248,6 +6710,25 @@
 +    }
 +
 +    /*non-public*/
++    MethodHandle bindImmediate(int pos, char basicType, Object value) {
++        // Bind an immediate value to a position in the arguments.
++        // This means, elide the respective argument,
++        // and replace all references to it in NamedFunction args with the specified value.
++
++        // CURRENT RESTRICTIONS
++        // * only for pos 0 and UNSAFE (position is adjusted in MHImpl to make API usable for others)
++        assert pos == 0 && basicType == 'L' && value instanceof Unsafe;
++        MethodType type2 = type.dropParameterTypes(pos, pos + 1); // adjustment: ignore receiver!
++        LambdaForm form2 = form.bindImmediate(pos + 1, basicType, value); // adjust pos to form-relative pos
++        return copyWith(type2, form2);
++    }
++
++    /*non-public*/
++    MethodHandle copyWith(MethodType mt, LambdaForm lf) {
++        throw new InternalError("copyWith: " + this.getClass());
++    }
++
++    /*non-public*/
 +    MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
 +        // Override this if it can be improved.
 +        return rebind().dropArguments(srcType, pos, drops);
@@ -6260,12 +6741,12 @@
 +    }
 +
 +    /*non-public*/
-+    private BoundMethodHandle<MethodHandle> rebind() {
++    private BoundMethodHandle rebind() {
 +        // Bind 'this' into a new invoker, of the known class BMH.
 +        MethodType type2 = type();
 +        LambdaForm form2 = BoundMethodHandle.reinvokerForm(type2.basicType());
 +        // form2 = lambda (bmh, arg*) { thismh = bmh[0]; invokeBasic(thismh, arg*) }
-+        return new BoundMethodHandle<>(type2, form2, this);
++        return new BoundMethodHandle.BMH_L(type2, form2, this);
      }
  }
 diff --git a/src/share/classes/java/lang/invoke/MethodHandleImpl.java b/src/share/classes/java/lang/invoke/MethodHandleImpl.java
@@ -6291,7 +6772,7 @@
  import static java.lang.invoke.MethodHandleStatics.*;
  import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
  
-@@ -47,556 +45,255 @@
+@@ -47,556 +45,270 @@
  /*non-public*/ abstract class MethodHandleImpl {
      /// Factory methods to create method handles:
  
@@ -6521,33 +7002,47 @@
 -        FieldAccessor accessor = new FieldAccessor(member, isSetter);
 -        return accessor;
 +    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 lambdaType = srcType.invokerType();
-+        Name[] names;
-+        boolean isStatic = !MethodHandleNatives.refKindHasReceiver(refKind);
++        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 = arguments(1, lambdaType);
++            names[_OFFSET] = new Name(BoundMethodHandle.MH_argJ0, names[0]);
++            names[_BASE]   = new Name(BoundMethodHandle.MH_argL1, names[0]);
 +        } else {
-+            names = arguments(2, lambdaType);
-+            names[names.length - 2] = new Name(FieldAccessor.GETCLASS, names[2]);  // NPE check
-+        }
-+        Name[] args = Arrays.copyOfRange(names, 1, 1 + srcType.parameterCount());
-+        names[names.length - 1] = new Name(accessor, (Object[]) args);
++            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);
-+        MethodHandle mh = new SimpleMethodHandle(srcType, form);
-+
-+        // Bind accessor arguments (Unsafe.getXXX(Object o, long offset).
++
++        BoundMethodHandle mh;
 +        if (isStatic) {
-+            Object base   = MethodHandleNatives.staticFieldBase(field);
-+            long   offset = MethodHandleNatives.staticFieldOffset(field);
-+            mh = mh.bindArgument(2, 'J', offset);
-+            mh = mh.bindArgument(1, 'L', base);
-+            mh = mh.bindReceiver(UNSAFE);
++            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 = mh.bindArgument(2, 'J', offset);
-+            mh = mh.bindReceiver(UNSAFE);
++            long offset = MethodHandleNatives.objectFieldOffset(field);
++            mh = new BoundMethodHandle.BMH_J(mhType, form, offset);
 +        }
 +        return mh;
      }
@@ -6569,11 +7064,11 @@
 -                mhs[0] = mhs[0].bindTo(elemClass);
 -                mhs[1] = mhs[1].bindTo(elemClass);
 +    static final class FieldAccessor {
-+        static final MethodHandle GETCLASS;
++        static final MethodHandle OBJECT_GETCLASS;
 +        static {
 +            try {
 +                assert(IMPL_LOOKUP != null) : "bootstrap problem";
-+                GETCLASS =
++                OBJECT_GETCLASS =
 +                    IMPL_LOOKUP.findStatic(FieldAccessor.class, "getClass", MethodType.methodType(Object.class, Object.class));
 +            } catch (NoSuchMethodException | IllegalAccessException e) {
 +                throw new InternalError(e);
@@ -6733,8 +7228,12 @@
 -            if (evclass != vclass || (!isStatic && ecclass != cclass)) {
 -                MethodType strongType = FieldAccessor.ftype(cclass, vclass, isSetter, isStatic);
 -                strongType = strongType.insertParameterTypes(0, FieldAccessor.class);
--                mh = convertArguments(mh, strongType, 0);
--            }
++            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);
+             }
 -            return mh;
 -        }
 -
@@ -6801,12 +7300,9 @@
 -            if (caclass != null) {
 -                MethodType strongType = FieldAccessor.atype(caclass, isSetter);
 -                mh = mh.bindTo(caclass);
-+            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 = convertArguments(mh, strongType, 0);
+-            }
++            mh = mh.bindImmediate(0, 'L', UNSAFE); // bind UNSAFE early
              return mh;
          }
      }
@@ -7056,7 +7552,7 @@
          if (!VerifyType.isNullConversion(oldRT, newRT)) {
              if (oldRT == void.class) {
                  Wrapper wrap = newRT.isPrimitive() ? Wrapper.forPrimitiveType(newRT) : Wrapper.OBJECT;
-@@ -605,17 +302,17 @@
+@@ -605,17 +317,17 @@
                  retFilter = MethodHandles.identity(newRT);
                  retFilter = convertArguments(retFilter, retFilter.type().changeParameterType(0, oldRT), level);
              }
@@ -7077,7 +7573,7 @@
              wmt.initCause(ex);
              throw wmt;
          }
-@@ -625,42 +322,697 @@
+@@ -625,42 +337,736 @@
      }
  
      static MethodHandle convertArguments(MethodHandle target,
@@ -7388,12 +7884,14 @@
 +        return new AsVarargsCollector(target, target.type(), arrayType);
 +    }
 +
-+    static class AsVarargsCollector extends BoundMethodHandle<MethodHandle> {
++    static class AsVarargsCollector extends BoundMethodHandle {
++        MethodHandle target;
 +        final Class<?> arrayType;
 +        MethodHandle cache;
 +
 +        AsVarargsCollector(MethodHandle target, MethodType type, Class<?> arrayType) {
-+            super(type, reinvokerForm(type), target);
++            super(type, reinvokerForm(type));
++            this.target = target;
 +            this.arrayType = arrayType;
 +            this.cache = target.asCollector(arrayType, 0);
 +        }
@@ -7405,8 +7903,15 @@
 +
 +        @Override
 +        public MethodHandle asFixedArity() {
-+            return argument;
-+        }
++            return target;
++        }
++
++        @Override
++        public String types() {
++            return types;
++        }
++
++        public static final String types = "L";
 +
 +        @Override
 +        public MethodHandle asType(MethodType newType) {
@@ -7473,6 +7978,36 @@
 +        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?
@@ -7797,7 +8332,7 @@
      }
  
      static MethodHandle collectArguments(MethodHandle target,
-@@ -671,32 +1023,102 @@
+@@ -671,32 +1077,102 @@
          assert(collectType != void.class);  // else use foldArguments
          if (collectType != type.parameterType(collectArg))
              target = target.asType(type.changeParameterType(collectArg, collectType));
@@ -7912,7 +8447,7 @@
      }
  
      static MethodHandle foldArguments(MethodHandle target,
-@@ -705,15 +1127,9 @@
+@@ -705,15 +1181,9 @@
                                        MethodHandle combiner) {
          MethodType oldType = target.type();
          MethodType ctype = combiner.type();
@@ -7931,7 +8466,7 @@
      }
  
      static
-@@ -738,47 +1154,42 @@
+@@ -738,47 +1208,42 @@
      MethodHandle makeGuardWithTest(MethodHandle test,
                                     MethodHandle target,
                                     MethodHandle fallback) {
@@ -7941,7 +8476,7 @@
 -        //    where select(z) = select(z, t, f).bindTo(t, f) => z ? t f
 -        // [tailcall]=> tf(arg...)
 -        assert(test.type().returnType() == boolean.class);
--        MethodType targetType = target.type();
+         MethodType targetType = target.type();
 -        MethodType foldTargetType = targetType.insertParameterTypes(0, boolean.class);
 -        assert(AdapterMethodHandle.canCollectArguments(foldTargetType, test.type(), 0, true));
 -        // working backwards, as usual:
@@ -7955,11 +8490,10 @@
 -        assert(filter.type().parameterType(0) == boolean.class);
 -        MethodHandle fold = foldArguments(filter, filter.type().dropParameterTypes(0, 1), 0, test);
 -        return fold;
-+        MethodType basicType = target.type().basicType();
-+        MethodHandle invokeBasic = MethodHandles.basicInvoker(basicType);
-+        int arity = basicType.parameterCount();
++        MethodHandle invokeBasic = MethodHandles.basicInvoker(targetType);
++        int arity = targetType.parameterCount();
 +        int extraNames = 3;
-+        MethodType lambdaType = basicType.invokerType();
++        MethodType lambdaType = targetType.invokerType();
 +        Name[] names = arguments(extraNames, lambdaType);
 +
 +        Object[] testArgs   = Arrays.copyOfRange(names, 1, 1 + arity, Object[].class);
@@ -7977,7 +8511,7 @@
 +        names[arity + 3] = new Name(new NamedFunction(invokeBasic), targetArgs);
 +
 +        LambdaForm form = new LambdaForm("guard", lambdaType.parameterCount(), names);
-+        return new SimpleMethodHandle(target.type(), form);
++        return new SimpleMethodHandle(targetType, form);
      }
  
 -    private static class GuardWithCatch extends BoundMethodHandle {
@@ -8005,7 +8539,7 @@
          private Object invoke_V(Object... av) throws Throwable {
              try {
                  return target.invokeExact(av);
-@@ -787,6 +1198,7 @@
+@@ -787,6 +1252,7 @@
                  return catcher.invokeExact(t, av);
              }
          }
@@ -8013,7 +8547,7 @@
          private Object invoke_L0() throws Throwable {
              try {
                  return target.invokeExact();
-@@ -795,6 +1207,7 @@
+@@ -795,6 +1261,7 @@
                  return catcher.invokeExact(t);
              }
          }
@@ -8021,7 +8555,7 @@
          private Object invoke_L1(Object a0) throws Throwable {
              try {
                  return target.invokeExact(a0);
-@@ -803,6 +1216,7 @@
+@@ -803,6 +1270,7 @@
                  return catcher.invokeExact(t, a0);
              }
          }
@@ -8029,7 +8563,7 @@
          private Object invoke_L2(Object a0, Object a1) throws Throwable {
              try {
                  return target.invokeExact(a0, a1);
-@@ -811,6 +1225,7 @@
+@@ -811,6 +1279,7 @@
                  return catcher.invokeExact(t, a0, a1);
              }
          }
@@ -8037,7 +8571,7 @@
          private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
              try {
                  return target.invokeExact(a0, a1, a2);
-@@ -819,6 +1234,7 @@
+@@ -819,6 +1288,7 @@
                  return catcher.invokeExact(t, a0, a1, a2);
              }
          }
@@ -8045,7 +8579,7 @@
          private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
              try {
                  return target.invokeExact(a0, a1, a2, a3);
-@@ -827,6 +1243,7 @@
+@@ -827,6 +1297,7 @@
                  return catcher.invokeExact(t, a0, a1, a2, a3);
              }
          }
@@ -8053,7 +8587,7 @@
          private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
              try {
                  return target.invokeExact(a0, a1, a2, a3, a4);
-@@ -835,6 +1252,7 @@
+@@ -835,6 +1306,7 @@
                  return catcher.invokeExact(t, a0, a1, a2, a3, a4);
              }
          }
@@ -8061,7 +8595,7 @@
          private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
              try {
                  return target.invokeExact(a0, a1, a2, a3, a4, a5);
-@@ -843,6 +1261,7 @@
+@@ -843,6 +1315,7 @@
                  return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5);
              }
          }
@@ -8069,7 +8603,7 @@
          private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
              try {
                  return target.invokeExact(a0, a1, a2, a3, a4, a5, a6);
-@@ -851,6 +1270,7 @@
+@@ -851,6 +1324,7 @@
                  return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6);
              }
          }
@@ -8077,7 +8611,7 @@
          private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
              try {
                  return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
-@@ -860,7 +1280,7 @@
+@@ -860,7 +1334,7 @@
              }
          }
          static MethodHandle[] makeInvokes() {
@@ -8086,7 +8620,7 @@
              MethodHandles.Lookup lookup = IMPL_LOOKUP;
              for (;;) {
                  int nargs = invokes.size();
-@@ -903,37 +1323,60 @@
+@@ -903,37 +1377,60 @@
              // Note: convertArguments(...2) avoids interface casts present in convertArguments(...0)
              MethodHandle gtarget = convertArguments(target, gtype, type, 2);
              MethodHandle gcatcher = convertArguments(catcher, gcatchType, ctype, 2);
@@ -8551,7 +9085,7 @@
      }
  
      /**
-@@ -321,71 +307,53 @@
+@@ -321,71 +307,47 @@
      }
  
      /**
@@ -8595,13 +9129,7 @@
 -                message = "required array"+reqLength+", but encountered wrong length "+actualLength;
 -                break;
 -            } catch (IllegalArgumentException ex) {
-+        try {
-+            switch (name) {
-+            case "invoke":
-+                return Invokers.genericInvokerMethod(callerClass, type, appendixResult);
-+            case "invokeExact":
-+                return Invokers.exactInvokerMethod(callerClass, type, appendixResult);
-             }
+-            }
 -            required = Object[].class;  // should have been an array
 -            code = 192; // checkcast
 -            break;
@@ -8611,7 +9139,12 @@
 -                throw new BootstrapMethodError((Throwable) actual);
 -            }
 -            break;
--        }
++        switch (name) {
++        case "invoke":
++            return Invokers.genericInvokerMethod(callerClass, type, appendixResult);
++        case "invokeExact":
++            return Invokers.exactInvokerMethod(callerClass, type, appendixResult);
+         }
 -        // disregard the identity of the actual object, if it is not a class:
 -        if (message == null) {
 -            if (!(actual instanceof Class) && !(actual instanceof MethodType))
@@ -8630,12 +9163,8 @@
 -            throw new ClassCastException(message);
 -        default:
 -            throw new InternalError("unexpected code "+code+": "+message);
-+            throw new UnsupportedOperationException("linkMethod "+name);
-+        } catch (Throwable ex) {
-+            if (TRACE_METHOD_LINKAGE)
-+                ex.printStackTrace();
-+            throw ex;
-         }
+-        }
++        throw new UnsupportedOperationException("linkMethod "+name);
      }
  
      /**
@@ -9497,7 +10026,16 @@
 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
-@@ -127,7 +127,7 @@
+@@ -108,6 +108,8 @@
+     /*trusted*/ Class<?> rtype() { return rtype; }
+     /*trusted*/ Class<?>[] ptypes() { return ptypes; }
+ 
++    void setForm(MethodTypeForm f) { form = f; }
++
+     private static void checkRtype(Class<?> rtype) {
+         rtype.equals(rtype);  // null check
+     }
+@@ -127,7 +129,7 @@
          checkSlotCount(ptypes.length + slots);
          return slots;
      }
@@ -9506,7 +10044,7 @@
          if ((count & 0xFF) != count)
              throw newIllegalArgumentException("bad parameter count "+count);
      }
-@@ -248,10 +248,6 @@
+@@ -248,10 +250,6 @@
          // promote the object to the Real Thing, and reprobe
          MethodTypeForm form = MethodTypeForm.findForm(mt1);
          mt1.form = form;
@@ -9517,7 +10055,7 @@
          return internTable.add(mt1);
      }
      private static final MethodType[] objectOnlyTypes = new MethodType[20];
-@@ -465,6 +461,23 @@
+@@ -465,6 +463,23 @@
      }
  
      /**
@@ -9897,7 +10435,7 @@
 copy to src/share/classes/java/lang/invoke/SimpleMethodHandle.java
 --- a/src/share/classes/java/lang/invoke/DirectMethodHandle.java
 +++ b/src/share/classes/java/lang/invoke/SimpleMethodHandle.java
-@@ -25,29 +25,34 @@
+@@ -25,29 +25,40 @@
  
  package java.lang.invoke;
  
@@ -9935,7 +10473,7 @@
 +        MethodType type2 = type().dropParameterTypes(pos, pos+1);
 +        LambdaForm form2 = internalForm().bind(basicType, 1+pos, 0);
 +        return BoundMethodHandle.bindSingle(type2, form2, basicType, value);
-+    }
+     }
 +
 +    @Override
 +    MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
@@ -9947,7 +10485,13 @@
 +    MethodHandle permuteArguments(MethodType newType, int[] reorder) {
 +        LambdaForm form2 = internalForm().permuteArguments(1, reorder, basicTypes(newType.parameterList()));
 +        return new SimpleMethodHandle(newType, form2);
-     }
++    }
++
++    @Override
++    MethodHandle copyWith(MethodType mt, LambdaForm lf) {
++        return new SimpleMethodHandle(mt, lf);
++    }
++
  }
 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
@@ -10728,6 +11272,154 @@
  public class JavaDocExamplesTest {
      /** Wrapper for running the JUnit tests in this module.
       *  Put JUnit on the classpath!
+diff --git a/test/java/lang/invoke/MaxTest.java b/test/java/lang/invoke/MaxTest.java
+new file mode 100644
+--- /dev/null
++++ b/test/java/lang/invoke/MaxTest.java
+@@ -0,0 +1,143 @@
++/*
++ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation.  Oracle designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Oracle in the LICENSE file that accompanied this code.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
++ * or visit www.oracle.com if you need additional information or have any
++ * questions.
++ */
++
++/* @test
++ * @summary BoundMethodHandle tests with primitive types
++ * @compile MaxTest.java
++ * @run junit/othervm test.java.lang.invoke.MaxTest
++ */
++
++package test.java.lang.invoke;
++
++import static org.junit.Assert.assertEquals;
++
++import java.lang.invoke.MethodHandle;
++import java.lang.invoke.MethodHandles;
++import java.lang.invoke.MethodType;
++
++import org.junit.Test;
++
++public class MaxTest {
++
++    static MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
++
++    private MethodHandle getMax(Class<?> t) throws Throwable {
++        return LOOKUP.findStatic(Math.class, "max", MethodType.methodType(t, t, t));
++    }
++
++    static int ITERATION_COUNT = 40000;
++    static {
++        String iterations = System.getProperty(MaxTest.class.getSimpleName() + ".ITERATION_COUNT");
++        if (iterations == null) {
++            iterations = System.getProperty(MaxTest.class.getName() + ".ITERATION_COUNT");
++        }
++        if (iterations != null) {
++            ITERATION_COUNT = Integer.parseInt(iterations);
++        }
++    }
++
++    @Test
++    public void testMaxLong() throws Throwable {
++        final Class<?> C = long.class;
++        final long P = 23L;
++        final long Q = 42L;
++        final long R = Math.max(P, Q);
++        for (int i = 0; i < ITERATION_COUNT; ++i) {
++            MethodHandle h = getMax(C);
++            assertEquals((long) h.invokeExact(P, Q), R);
++            MethodHandle bh = MethodHandles.insertArguments(h, 0, P);
++            assertEquals((long) bh.invokeExact(Q), R);
++            MethodHandle bbh = MethodHandles.insertArguments(bh, 0, Q);
++            assertEquals((long) bbh.invokeExact(), R);
++            MethodHandle b2h = MethodHandles.insertArguments(h, 1, Q);
++            assertEquals((long) b2h.invokeExact(P), R);
++            MethodHandle bb2h = MethodHandles.insertArguments(b2h, 0, P);
++            assertEquals((long) bb2h.invokeExact(), R);
++        }
++    }
++
++    @Test
++    public void testMaxInt() throws Throwable {
++        final Class<?> C = int.class;
++        final int P = 23;
++        final int Q = 42;
++        final int R = Math.max(P, Q);
++        for (int i = 0; i < ITERATION_COUNT; ++i) {
++            MethodHandle h = getMax(C);
++            assertEquals((int) h.invokeExact(P, Q), R);
++            MethodHandle bh = MethodHandles.insertArguments(h, 0, P);
++            assertEquals((int) bh.invokeExact(Q), R);
++            MethodHandle bbh = MethodHandles.insertArguments(bh, 0, Q);
++            assertEquals((int) bbh.invokeExact(), R);
++            MethodHandle b2h = MethodHandles.insertArguments(h, 1, Q);
++            assertEquals((int) b2h.invokeExact(P), R);
++            MethodHandle bb2h = MethodHandles.insertArguments(b2h, 0, P);
++            assertEquals((int) bb2h.invokeExact(), R);
++        }
++    }
++
++    @Test
++    public void testMaxFloat() throws Throwable {
++        final Class<?> C = float.class;
++        final float P = 23F;
++        final float Q = 42F;
++        final float R = Math.max(P, Q);
++        final float D = 0.1F;
++        for (int i = 0; i < ITERATION_COUNT; ++i) {
++            MethodHandle h = getMax(C);
++            assertEquals((float) h.invokeExact(P, Q), R, D);
++            MethodHandle bh = MethodHandles.insertArguments(h, 0, P);
++            assertEquals((float) bh.invokeExact(Q), R, D);
++            MethodHandle bbh = MethodHandles.insertArguments(bh, 0, Q);
++            assertEquals((float) bbh.invokeExact(), R, D);
++            MethodHandle b2h = MethodHandles.insertArguments(h, 1, Q);
++            assertEquals((float) b2h.invokeExact(P), R, D);
++            MethodHandle bb2h = MethodHandles.insertArguments(b2h, 0, P);
++            assertEquals((float) bb2h.invokeExact(), R, D);
++        }
++    }
++
++    @Test
++    public void testMaxDouble() throws Throwable {
++        final Class<?> C = double.class;
++        final double P = 23F;
++        final double Q = 42F;
++        final double R = Math.max(P, Q);
++        final double D = 0.1;
++        for (int i = 0; i < ITERATION_COUNT; ++i) {
++            MethodHandle h = getMax(C);
++            assertEquals((double) h.invokeExact(P, Q), R, D);
++            MethodHandle bh = MethodHandles.insertArguments(h, 0, P);
++            assertEquals((double) bh.invokeExact(Q), R, D);
++            MethodHandle bbh = MethodHandles.insertArguments(bh, 0, Q);
++            assertEquals((double) bbh.invokeExact(), R, D);
++            MethodHandle b2h = MethodHandles.insertArguments(h, 1, Q);
++            assertEquals((double) b2h.invokeExact(P), R, D);
++            MethodHandle bb2h = MethodHandles.insertArguments(b2h, 0, P);
++            assertEquals((double) bb2h.invokeExact(), R, D);
++        }
++    }
++
++}
 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
--- a/meth-lazy-7023639.xbmh.patch	Fri Jul 13 01:55:05 2012 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2282 +0,0 @@
-More flexible bound method handles.
-Contributed-by: Michael Haupt
-
-diff -r 1478423d0bfc src/share/classes/java/lang/invoke/BoundMethodHandle.java
---- a/src/share/classes/java/lang/invoke/BoundMethodHandle.java	Thu Jul 12 19:03:13 2012 +0200
-+++ b/src/share/classes/java/lang/invoke/BoundMethodHandle.java	Fri Jul 13 10:44:45 2012 +0200
-@@ -1,5 +1,5 @@
- /*
-- * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
-+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
-  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-  *
-  * This code is free software; you can redistribute it and/or modify it
-@@ -25,308 +25,400 @@
- 
- package java.lang.invoke;
- 
--import static java.lang.invoke.LambdaForm.*;
--import static java.lang.invoke.MethodHandles.*;
--import static java.lang.invoke.MethodType.*;
-+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 java.lang.invoke.LambdaForm.basicTypes;
-+import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;
-+import static java.lang.invoke.MethodType.methodType;
-+
-+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 sun.invoke.util.*;
-+import java.util.IdentityHashMap;
-+import java.util.Map;
-+
-+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;
- 
- /**
-  * The flavor of method handle which emulates an invoke instruction
-  * on a predetermined argument.  The JVM dispatches to the correct method
-  * when the handle is created, not when it is invoked.
-- * @author jrose
-+ *
-+ * All bound arguments are encapsulated in dedicated species.
-  */
--class BoundMethodHandle<T> extends MethodHandle {
--    final T argument;   // first or only argument to insert
-+/* non-public */ abstract class BoundMethodHandle extends MethodHandle {
- 
--    // Constructors in this class *must* be package scoped or private.
--    /*non-public*/
--    BoundMethodHandle(MethodType type, LambdaForm form, T argument) {
-+    /* non-public */ BoundMethodHandle(MethodType type, LambdaForm form) {
-         super(type, form);
--        this.argument = argument;
-     }
- 
--    static MethodHandle bindSingle(MethodType type2, LambdaForm form2, char xtype, Object x) {
--        if (xtype == 'L')
--            return new BoundMethodHandle<>(type2, form2, x);
--        else
--            return new BoundMethodHandle.Multiple(null, type2, form2, 1, xtype, x);
-+    //
-+    // BMH API and internals
-+    //
-+
-+    static MethodHandle bindSingle(MethodType type, LambdaForm form, char xtype, Object x) {
-+        // for some type signatures, there exist pre-defined concrete BMH classes
-+        try {
-+            switch (xtype) {
-+            case 'L': return new BMH_L(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());
-+            case 'J':
-+                assert x instanceof Long;
-+                return new BMH_J(type, form, ((Long) x).longValue());
-+            case 'F':
-+                assert x instanceof Float;
-+                return (BoundMethodHandle) Data.get("F").constructor.invokeBasic(type, form, ((Float) x).floatValue());
-+            case 'D':
-+                assert x instanceof Double;
-+                return (BoundMethodHandle) Data.get("D").constructor.invokeBasic(type, form, ((Double) x).doubleValue());
-+            default : throw new InternalError("unexpected xtype: " + xtype);
-+            }
-+        } catch (Throwable t) {
-+            throw new InternalError(t);
-+        }
-     }
- 
--    // Note:  Subclasses must override this, for obvious reasons.
--    MethodHandle clone(MethodType type2, LambdaForm form2) {
--        return new BoundMethodHandle<>(type2, form2, argument); // override this
--    }
--
--    // Note:  Subclasses must override this, as with clone.
--    MethodHandle cloneExtend(MethodType type2, LambdaForm form2, char xtype, Object x) {
--        Multiple nextArg = new Multiple(null, type2, form2, 2, xtype, x);
--        return new Multiple(nextArg, type2, form2, 1, 'L', argument);
-+    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);
-+            }
-+        } catch (Throwable t) {
-+            throw new InternalError(t);
-+        }
-     }
- 
-     @Override
-     MethodHandle bindArgument(int pos, char basicType, Object value) {
--        MethodType type2 = type().dropParameterTypes(pos, pos+1);
--        LambdaForm form2 = internalForm().bind(basicType, 1+pos, dataValueCount());
-+        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);
-         }
--        return cloneExtend(type2, form2, basicType, value);
-+        return cloneExtend(type, form, basicType, value);
-     }
- 
-     @Override
-     MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
--        LambdaForm form2 = internalForm().addArguments(pos, srcType.parameterList().subList(pos, pos+drops));
--        return clone(srcType, form2);
-+        LambdaForm form = internalForm().addArguments(pos, srcType.parameterList().subList(pos, pos+drops));
-+        try {
-+             return clone(srcType, form);
-+         } catch (Throwable t) {
-+             throw new InternalError(t);
-+         }
-     }
- 
-     @Override
-     MethodHandle permuteArguments(MethodType newType, int[] reorder) {
--        return clone(newType, form.permuteArguments(1, reorder, basicTypes(newType.parameterList())));
-+        try {
-+             return clone(newType, form.permuteArguments(1, reorder, basicTypes(newType.parameterList())));
-+         } catch (Throwable t) {
-+             throw new InternalError(t);
-+         }
-     }
- 
--    // Singleton implementation of DataBinding:
--    public int dataValueCount() {
--        return 1;
--    }
--    public String dataValueTypes() {
--        return "L";
--    }
--    public char dataValueType(int i) {
--        assert(i == 0);
--        return 'L';
-+    public int tcount() {
-+        return types().length();
-     }
- 
--    public final Object dataValue0() {
--        return argument;
-+    protected final Data myData() {
-+        return Data.get(types());
-     }
- 
--    //public final Object objectDataValue0() { return           dataValue0(); }
--    public final int       intDataValue0() { return (Integer) dataValue0(); }
--    public final long     longDataValue0() { return (Long)    dataValue0(); }
--    public final float   floatDataValue0() { return (Float)   dataValue0(); }
--    public final double doubleDataValue0() { return (Double)  dataValue0(); }
-+    /**
-+     * 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).
-+     */
-+    public abstract String types();
- 
--    static Name dataValueName(Name mhName, char basicType, int i) {
--        NamedFunction getter;
--        if (i == 0) {
--            switch (basicType) {
--            case 'L':  getter =       NF_dataValue0; break;
--            case 'I':  getter =    NF_intDataValue0; break;
--            case 'J':  getter =   NF_longDataValue0; break;
--            case 'F':  getter =  NF_floatDataValue0; break;
--            case 'D':  getter = NF_doubleDataValue0; break;
--            default:
--                throw new InternalError("unknown type: " + basicType);
-+    /**
-+     * 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;
-+    }
-+
-+    @Override
-+    final Object internalValues() {
-+        Object[] boundValues = new Object[types().length()];
-+        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);
-             }
--            return new Name(getter, mhName);
--        } else {
--            switch (basicType) {
--            case 'L':
--                if (i == 1)  return new Name(NF_dataValue1, mhName);
--                if (i == 2)  return new Name(NF_dataValue2, mhName);
--                if (i == 3)  return new Name(NF_dataValue3, mhName);
--                getter = NF_dataValue;
--                break;
--            case 'I':
--                if (i == 1)  return new Name(NF_intDataValue1, mhName);
--                getter = NF_intDataValue;
--                break;
--            case 'J':
--                if (i == 1)  return new Name(NF_longDataValue1, mhName);
--                getter = NF_longDataValue;
--                break;
--            case 'F':  getter =  NF_floatDataValue; break;
--            case 'D':  getter = NF_doubleDataValue; break;
--            default:
--                throw new InternalError("unknown type: " + basicType);
--            }
--            return new Name(getter, mhName, 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); }
-+
-+    //
-+    // cloning API
-+    //
-+
-+    public abstract BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable;
-+    public abstract BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable;
-+    public abstract BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int    narg) throws Throwable;
-+    public abstract BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long   narg) throws Throwable;
-+    public abstract BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float  narg) throws Throwable;
-+    public abstract BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable;
-+
-+    //
-+    // getters to close bootstrap loops
-+    //
-+
-+    public long   argJ0() throws Throwable { return argJ(0); }
-+    public Object argL1() throws Throwable { return argL(1); }
-+
-+    //
-+    // concrete BMH classes required to close bootstrap loops
-+    //
-+
-+    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;
-+        }
-+        @Override
-+        public String types() {
-+            return types;
-+        }
-+        public static final String types = "L";
-+        @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);
-+        }
-+        @Override
-+        public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
-+            return (BoundMethodHandle) Data.get("LI").constructor.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);
-+        }
-+        @Override
-+        public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
-+            return (BoundMethodHandle) Data.get("LF").constructor.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);
-         }
-     }
- 
--    /** Make sure the given {@code argument} can be used as {@code argnum}-th
--     *  parameter of the given method handle {@code mh}, which must be a reference.
--     *  <p>
--     *  If this fails, throw a suitable {@code WrongMethodTypeException},
--     *  which will prevent the creation of an illegally typed bound
--     *  method handle.
--     */
--    private static Object checkReferenceArgument(Object argument, MethodHandle mh, int argnum) {
--        Class<?> ptype = mh.type().parameterType(argnum);
--        if (ptype.isPrimitive()) {
--            // fail
--        } else if (argument == null) {
--            return null;
--        } else if (VerifyType.isNullReferenceConversion(argument.getClass(), ptype)) {
--            return argument;
-+    static final class BMH_LL extends BoundMethodHandle {
-+        final Object argL0;
-+        final Object argL1;
-+        public BMH_LL(MethodType mt, LambdaForm lf, Object argL0, Object argL1) {
-+            super(mt, lf);
-+            this.argL0 = argL0;
-+            this.argL1 = argL1;
-         }
--        throw badBoundArgumentException(argument, mh, argnum);
--    }
--
--    /** Make sure the given {@code argument} can be used as {@code argnum}-th
--     *  parameter of the given method handle {@code mh}, which must be a primitive.
--     *  <p>
--     *  If this fails, throw a suitable {@code WrongMethodTypeException},
--     *  which will prevent the creation of an illegally typed bound
--     *  method handle.
--     */
--    private static Object bindPrimitiveArgument(Object argument, MethodHandle mh, int argnum) {
--        Class<?> ptype = mh.type().parameterType(argnum);
--        Wrapper  wrap = Wrapper.forPrimitiveType(ptype);
--        Object   zero  = wrap.zero();
--        if (zero == null) {
--            // fail
--        } else if (argument == null) {
--            if (ptype != int.class && wrap.isSubwordOrInt())
--                return Integer.valueOf(0);
--            else
--                return zero;
--        } else if (VerifyType.isNullReferenceConversion(argument.getClass(), zero.getClass())) {
--            if (ptype != int.class && wrap.isSubwordOrInt())
--                return Wrapper.INT.wrap(argument);
--            else
--                return argument;
--        }
--        throw badBoundArgumentException(argument, mh, argnum);
--    }
--
--    private static RuntimeException badBoundArgumentException(Object argument, MethodHandle mh, int argnum) {
--        String atype = (argument == null) ? "null" : argument.getClass().toString();
--        return new ClassCastException("cannot bind "+atype+" argument to parameter #"+argnum+" of "+mh.type());
--    }
--
--
--    // Subclasses for additional data binding:
--    static class Multiple extends BoundMethodHandle<Object> {
--        /*lazy*/ String boundValueTypes;
--        final int boundValueCount;
--        final Multiple next;
--        final char xtype;
--
--        public Multiple(Multiple next, MethodType type, LambdaForm form, int boundValueCount, char xtype, Object x) {
--            super(type, form, x);
--            this.boundValueCount = boundValueCount;
--            this.next = next;
--            this.xtype = xtype;
--        }
--
--        /// Implementation of multi-level binding:
-         @Override
--        public final String dataValueTypes() {
--            assert false;
--            String types = boundValueTypes;
--            if (types == null)
--                boundValueTypes = types = DataBinding.Methods.dataValueTypes(this);
-+        public String types() {
-             return types;
-         }
-+        public static final String types = "LL";
-         @Override
--        public final int dataValueCount() {
--            Multiple p = this;
--            while (p.next != null) {
--                p = p.next;
--            }
--            return p.boundValueCount;
-+        public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
-+            return new BMH_LL(mt, lf, argL0, argL1);
-         }
--
-         @Override
--        public final char dataValueType(int i) {
--            Multiple p = this;
--            while (--i >= 0) {
--                p = p.next;
--            }
--            return p.xtype;
-+        public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
-+            return (BoundMethodHandle) Data.get("LLL").constructor.invokeBasic(mt, lf, argL0, argL1, narg);
-         }
--
--        public final Object dataValue1() { return this.next.argument; }
--        public final Object dataValue2() { return this.next.next.argument; }
--        public final Object dataValue3() { return this.next.next.next.argument; }
--        public final Object dataValue(int i) {
--            Multiple p = this;
--            while (--i >= 0) {
--                p = p.next;
--            }
--            return p.argument;
-+        @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);
-         }
--
--        public final int   intDataValue1() { return (Integer) this.next.argument; }
--        public final long longDataValue1() { return (Long)    this.next.argument; }
--
--        //public final Object objectDataValue(int i) { return           dataValue(i); }
--        public final int       intDataValue(int i) { return (Integer) dataValue(i); }
--        public final long     longDataValue(int i) { return (Long)    dataValue(i); }
--        public final float   floatDataValue(int i) { return (Float)   dataValue(i); }
--        public final double doubleDataValue(int i) { return (Double)  dataValue(i); }
--
-         @Override
--        MethodHandle cloneExtend(MethodType type2, LambdaForm form2, char xtype2, Object x2) {
--            Multiple nextArg;
--            if (this.next == null) {
--                nextArg = new Multiple(null, type2, form2, boundValueCount + 1, xtype2, x2);
--            } else {
--                nextArg = (Multiple) this.next.cloneExtend(type2, form2, xtype2, x2);
--            }
--            return new Multiple(nextArg, type2, form2, boundValueCount, xtype, argument);
-+        public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
-+            return (BoundMethodHandle) Data.get("LLJ").constructor.invokeBasic(mt, lf, argL0, argL1, narg);
-         }
--
-         @Override
--        MethodHandle clone(MethodType type2, LambdaForm form2) {
--            return new Multiple(next, type2, form2, boundValueCount, xtype, argument);
-+        public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
-+            return (BoundMethodHandle) Data.get("LLF").constructor.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);
-         }
-     }
- 
--    static final NamedFunction NF_dataValue0;
--    static final NamedFunction NF_intDataValue0;
--    static final NamedFunction NF_longDataValue0;
--    static final NamedFunction NF_floatDataValue0;
--    static final NamedFunction NF_doubleDataValue0;
-+    static final class BMH_JL extends BoundMethodHandle {
-+        final long argJ0;
-+        final Object argL1;
-+        public BMH_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 static final String types = "JL";
-+        @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);
-+        }
-+        @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);
-+        }
-+        @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);
-+        }
-+        @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);
-+        }
-+        @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);
-+        }
-+        @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);
-+        }
-+    }
- 
--    static final NamedFunction NF_dataValue1;
--    static final NamedFunction NF_dataValue2;
--    static final NamedFunction NF_dataValue3;
-+    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);
-+        }
-+    }
- 
--    static final NamedFunction NF_intDataValue1;
--
--    static final NamedFunction NF_longDataValue1;
--
--    static final NamedFunction NF_dataValue;
--    static final NamedFunction NF_intDataValue;
--    static final NamedFunction NF_longDataValue;
--    static final NamedFunction NF_floatDataValue;
--    static final NamedFunction NF_doubleDataValue;
-+    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 {
--            Lookup l = Lookup.IMPL_LOOKUP;
--            Class<?> b = BoundMethodHandle.class;
--            Class<?> m = Multiple.class;
--
--            NF_dataValue0       = new NamedFunction(l.findVirtual(b, "dataValue0",       methodType(Object.class)));
--            NF_intDataValue0    = new NamedFunction(l.findVirtual(b, "intDataValue0",    methodType(int.class)));
--            NF_longDataValue0   = new NamedFunction(l.findVirtual(b, "longDataValue0",   methodType(long.class)));
--            NF_floatDataValue0  = new NamedFunction(l.findVirtual(b, "floatDataValue0",  methodType(float.class)));
--            NF_doubleDataValue0 = new NamedFunction(l.findVirtual(b, "doubleDataValue0", methodType(double.class)));
--
--            NF_dataValue1       = new NamedFunction(l.findVirtual(m, "dataValue1",       methodType(Object.class)));
--            NF_dataValue2       = new NamedFunction(l.findVirtual(m, "dataValue2",       methodType(Object.class)));
--            NF_dataValue3       = new NamedFunction(l.findVirtual(m, "dataValue3",       methodType(Object.class)));
--
--            NF_intDataValue1    = new NamedFunction(l.findVirtual(m, "intDataValue1",    methodType(int.class)));
--
--            NF_longDataValue1   = new NamedFunction(l.findVirtual(m, "longDataValue1",   methodType(long.class)));
--
--            NF_dataValue        = new NamedFunction(l.findVirtual(m, "dataValue",        methodType(Object.class, int.class)));
--            NF_intDataValue     = new NamedFunction(l.findVirtual(m, "intDataValue",     methodType(int.class,    int.class)));
--            NF_longDataValue    = new NamedFunction(l.findVirtual(m, "longDataValue",    methodType(long.class,   int.class)));
--            NF_floatDataValue   = new NamedFunction(l.findVirtual(m, "floatDataValue",   methodType(float.class,  int.class)));
--            NF_doubleDataValue  = new NamedFunction(l.findVirtual(m, "doubleDataValue",  methodType(double.class, int.class)));
--        } catch (ReflectiveOperationException ex) {
--            throw new InternalError(ex);
-+            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.
-      */
-@@ -342,11 +434,410 @@
-         final int NEXT_MH     = nameCursor++;
-         final int REINVOKE    = nameCursor++;
-         Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
--        names[NEXT_MH] = dataValueName(names[THIS_BMH], 'L', 0);
-+        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
-+    //
-+
-+    /**
-+     * Meta-data wrapper for concrete BMH classes.
-+     */
-+    static class Data {
-+        final String                             types;
-+        final Class<? extends BoundMethodHandle> clazz;
-+        final MethodHandle                       constructor;
-+        final MethodHandle[]                     getters;
-+
-+        Data(String types, Class<? extends BoundMethodHandle> clazz, MethodHandle constructor, MethodHandle[] getters) {
-+            this.types = types;
-+            this.clazz = clazz;
-+            this.constructor = constructor;
-+            this.getters = getters;
-+        }
-+
-+        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);
-+        }
-+
-+        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);
-+                }
-+            }
-+            return d;
-+        }
-+
-+        static {
-+            // pre-fill the BMH data cache with BMH's inner classes
-+            final Class<BoundMethodHandle> BMH = BoundMethodHandle.class;
-+            try {
-+                for (Class<?> c : BMH.getDeclaredClasses()) {
-+                    if (BMH.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);
-+                    }
-+                }
-+            } catch (Throwable e) {
-+                throw new InternalError(e);
-+            }
-+        }
-+    }
-+
-+    /**
-+     * Generation of concrete BMH classes.
-+     *
-+     * A concrete BMH 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.
-+     *
-+     * A concrete BMH 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 BMHDATA_GET_SIG = "(" + JLS_SIG + ")" + DATA_SIG;
-+        static final String TYPES_SIG = "()" + JLS_SIG;
-+        static final String MYDATA_SIG = "()" + DATA_SIG;
-+
-+        static final String SIG_INCIPIT = "(Ljava/lang/invoke/MethodType;Ljava/lang/invoke/LambdaForm;";
-+
-+        static final Class<?>[] TYPES = new Class<?>[] { Object.class, int.class, long.class, float.class, double.class };
-+
-+        static final String[] E_THROWABLE = new String[] { "java/lang/Throwable" };
-+
-+        /**
-+         * Generate a concrete subclass of BMH for a given combination of bound types.
-+         *
-+         * A concrete BMH subclass adheres to the following schema:
-+         *
-+         * <pre>
-+         * class BMH_<<types>> extends BMH {
-+         *     <<fields>>
-+         *     final String dataValueTypes() { return <<types>>; }
-+         * }
-+         * </pre>
-+         *
-+         * The {@code <<types>>} signature is precisely the string that is passed to this
-+         * method.
-+         *
-+         * The {@code <<fields>>} section consists of one field definition per character in
-+         * the type signature, adhering to the naming schema described in the definition of
-+         * {@link #makeFieldName()}.
-+         *
-+         * For example, a concrete BMH class for two reference and one integral bound values
-+         * would have the following shape:
-+         *
-+         * <pre>
-+         * final class BMH_LLI extends BMH {
-+         *     final Object argL0;
-+         *     final Object argL1;
-+         *     final int argI2;
-+         *     public BMH_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 BoundMethodHandle clone(MethodType mt, LambdaForm lf) {
-+         *         return myData().constructor.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);
-+         *     }
-+         *     public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) {
-+         *         return BMHData.get("LLII").constructor.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);
-+         *     }
-+         *     public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) {
-+         *         return BMHData.get("LLIF").constructor.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);
-+         *     }
-+         * }
-+         * </pre>
-+         *
-+         * @param types the type signature, wherein reference types are erased to 'L'
-+         * @return the generated concrete BMH class
-+         */
-+        static Class<? extends BoundMethodHandle> generateConcreteBMHClass(String types) {
-+            final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
-+
-+            final String className = "java/lang/invoke/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 bound argument fields
-+            for (int i = 0; i < types.length(); ++i) {
-+                final char t = types.charAt(i);
-+                final String fieldName = makeFieldName(types, i);
-+                final String fieldDesc = t == 'L' ? JLO_SIG : String.valueOf(t);
-+                cw.visitField(ACC_FINAL, fieldName, fieldDesc, null, null).visitEnd();
-+            }
-+
-+            MethodVisitor mv;
-+
-+            // emit constructor
-+            mv = cw.visitMethod(ACC_PUBLIC, "<init>", makeSignature(types, true), null, null);
-+            mv.visitCode();
-+            mv.visitVarInsn(ALOAD, 0);
-+            mv.visitVarInsn(ALOAD, 1);
-+            mv.visitVarInsn(ALOAD, 2);
-+
-+            mv.visitMethodInsn(INVOKESPECIAL, BMH, "<init>", makeSignature("", true));
-+
-+            for (int i = 0, j = 0; i < types.length(); ++i, ++j) {
-+                // i counts the arguments, j counts corresponding argument slots
-+                char t = types.charAt(i);
-+                mv.visitVarInsn(ALOAD, 0);
-+                mv.visitVarInsn(typeLoadOp(t), j + 3); // parameters start at 3
-+                mv.visitFieldInsn(PUTFIELD, className, makeFieldName(types, i), typeSig(t));
-+                if (t == 'J' || t == 'D') {
-+                    ++j; // adjust argument register access
-+                }
-+            }
-+
-+            mv.visitInsn(RETURN);
-+            mv.visitMaxs(0, 0);
-+            mv.visitEnd();
-+
-+            // emit implementation of types()
-+            mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "types", TYPES_SIG, null, null);
-+            mv.visitCode();
-+            mv.visitLdcInsn(types);
-+            mv.visitInsn(ARETURN);
-+            mv.visitMaxs(0, 0);
-+            mv.visitEnd();
-+
-+            // emit clone()
-+            mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "clone", makeSignature("", false), null, E_THROWABLE);
-+            mv.visitCode();
-+            // return myData().constructor.invokeBasic(mt, lf, argL0, ...)
-+            // obtain constructor
-+            mv.visitVarInsn(ALOAD, 0);
-+            mv.visitMethodInsn(INVOKESPECIAL, BMH, "myData", MYDATA_SIG);
-+            mv.visitFieldInsn(GETFIELD, DATA, "constructor", MH_SIG);
-+            // load mt, lf
-+            mv.visitVarInsn(ALOAD, 1);
-+            mv.visitVarInsn(ALOAD, 2);
-+            // put fields on the stack
-+            emitPushFields(types, className, mv);
-+            // finally, invoke the constructor and return
-+            mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types, false));
-+            mv.visitInsn(ARETURN);
-+            mv.visitMaxs(0, 0);
-+            mv.visitEnd();
-+
-+            // for each type, emit cloneExtendT()
-+            for (Class<?> c : TYPES) {
-+                char t = Wrapper.basicTypeChar(c);
-+                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)
-+                // obtain constructor
-+                mv.visitLdcInsn(extypes);
-+                mv.visitMethodInsn(INVOKESTATIC, DATA, "get", BMHDATA_GET_SIG);
-+                mv.visitFieldInsn(GETFIELD, DATA, "constructor", MH_SIG);
-+                // load mt, lf
-+                mv.visitVarInsn(ALOAD, 1);
-+                mv.visitVarInsn(ALOAD, 2);
-+                // put fields on the stack
-+                emitPushFields(types, className, mv);
-+                // put narg on stack
-+                mv.visitVarInsn(typeLoadOp(t), 3);
-+                // finally, invoke the constructor and return
-+                mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(extypes, false));
-+                mv.visitInsn(ARETURN);
-+                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.ensureClassInitialized(bmhClass);
-+
-+            return bmhClass;
-+        }
-+
-+        private static int typeLoadOp(char t) {
-+            switch (t) {
-+            case 'L': return ALOAD;
-+            case 'I': return ILOAD;
-+            case 'J': return LLOAD;
-+            case 'F': return FLOAD;
-+            case 'D': return DLOAD;
-+            default : throw new InternalError("unrecognized type " + t);
-+            }
-+        }
-+
-+        private static void emitPushFields(String types, String className, MethodVisitor mv) {
-+            for (int i = 0; i < types.length(); ++i) {
-+                char tc = types.charAt(i);
-+                mv.visitVarInsn(ALOAD, 0);
-+                mv.visitFieldInsn(GETFIELD, className, makeFieldName(types, i), typeSig(tc));
-+            }
-+        }
-+
-+        static String typeSig(char t) {
-+            return t == 'L' ? JLO_SIG : String.valueOf(t);
-+        }
-+
-+        //
-+        // Getter MH generation.
-+        //
-+
-+        private static MethodHandle makeGetter(Class<?> cbmhClass, String types, int index) {
-+            String fieldName = makeFieldName(types, index);
-+            Class<?> fieldType = Wrapper.forBasicType(types.charAt(index)).primitiveType();
-+            try {
-+                return LOOKUP.findGetter(cbmhClass, fieldName, fieldType);
-+            } catch (NoSuchFieldException | IllegalAccessException e) {
-+                throw new InternalError(e);
-+            }
-+        }
-+
-+        static MethodHandle[] makeGetters(Class<?> cbmhClass, String types) {
-+            MethodHandle[] mhs = new MethodHandle[types.length()];
-+            for (int i = 0; i < mhs.length; ++i) {
-+                mhs[i] = makeGetter(cbmhClass, types, i);
-+            }
-+            return mhs;
-+        }
-+
-+        //
-+        // Auxiliary methods.
-+        //
-+
-+        static String typesFromConcreteBMHClass(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 names in concrete BMHs adhere to this pattern:
-+         * arg + type + index
-+         * where type is a single character (L, I, J, F, D).
-+         */
-+        private static String makeFieldName(String types, int index) {
-+            assert index >= 0 && index < types.length();
-+            return "arg" + types.charAt(index) + index;
-+        }
-+
-+        private static String makeSignature(String types, boolean ctor) {
-+            StringBuilder buf = new StringBuilder(SIG_INCIPIT);
-+            for (char c : types.toCharArray()) {
-+                buf.append(typeSig(c));
-+            }
-+            return buf.append(')').append(ctor ? "V" : BMH_SIG).toString();
-+        }
-+
-+        static MethodHandle makeCbmhCtor(Class<? extends BoundMethodHandle> cbmh, String types) {
-+            try {
-+                return linkConstructor(LOOKUP.findConstructor(cbmh, MethodType.fromMethodDescriptorString(makeSignature(types, true), null)));
-+            } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | TypeNotPresentException e) {
-+                throw new InternalError(e);
-+            }
-+        }
-+
-+        /**
-+         * Wrap a constructor call in a {@link LambdaForm}.
-+         *
-+         * If constructors ({@code <init>} methods) are called in LFs, problems might arise if the LFs
-+         * are turned into bytecode, because the call to the allocator is routed through an MH, and the
-+         * verifier cannot find a {@code NEW} instruction preceding the {@code INVOKESPECIAL} to
-+         * {@code <init>}. To avoid this, we add an indirection by invoking {@code <init>} through
-+         * {@link MethodHandle#linkToSpecial}.
-+         *
-+         * The last {@link LambdaForm#Name Name} in the argument's form is expected to be the {@code void}
-+         * result of the {@code <init>} invocation. This entry is replaced.
-+         */
-+        private static MethodHandle linkConstructor(MethodHandle cmh) {
-+            final LambdaForm lf = cmh.form;
-+            final int initNameIndex = lf.names.length - 1;
-+            final Name initName = lf.names[initNameIndex];
-+            final MemberName ctorMN = initName.function.member;
-+            final MethodType ctorMT = ctorMN.getInvocationType();
-+
-+            // obtain function member (call target)
-+            // linker method type replaces initial parameter (BMH species) with BMH to avoid naming a species (anonymous class!)
-+            final MethodType linkerMT = ctorMT.changeParameterType(0, BoundMethodHandle.class).appendParameterTypes(MemberName.class);
-+            MemberName linkerMN = new MemberName(MethodHandle.class, "linkToSpecial", linkerMT, REF_invokeStatic);
-+            try {
-+                linkerMN = MemberName.getFactory().resolveOrFail(REF_invokeStatic, linkerMN, null, NoSuchMethodException.class);
-+                assert(linkerMN.isStatic());
-+            } catch (ReflectiveOperationException ex) {
-+                throw new InternalError(ex);
-+            }
-+            // extend arguments array
-+            Object[] newArgs = Arrays.copyOf(initName.arguments, initName.arguments.length + 1);
-+            newArgs[newArgs.length - 1] = ctorMN;
-+            // replace function
-+            final NamedFunction nf = new NamedFunction(linkerMN);
-+            final Name linkedCtor = new Name(nf, newArgs);
-+            linkedCtor.initIndex(initNameIndex);
-+            lf.names[initNameIndex] = linkedCtor;
-+            return cmh;
-+        }
-+
-+        //
-+        // Constants.
-+        //
-+
-+        private static final Lookup LOOKUP = Lookup.IMPL_LOOKUP;
-+        private static final Unsafe UNSAFE = Unsafe.getUnsafe();
-+
-+    }
-+
- }
-diff -r 1478423d0bfc src/share/classes/java/lang/invoke/CountingMethodHandle.java
---- a/src/share/classes/java/lang/invoke/CountingMethodHandle.java	Thu Jul 12 19:03:13 2012 +0200
-+++ b/src/share/classes/java/lang/invoke/CountingMethodHandle.java	Fri Jul 13 10:44:45 2012 +0200
-@@ -36,11 +36,13 @@
-  *
-  * @author never
-  */
--class CountingMethodHandle extends BoundMethodHandle<MethodHandle> {
-+class CountingMethodHandle extends BoundMethodHandle {
-+    private MethodHandle target;
-     private int vmcount;
- 
-     private CountingMethodHandle(MethodHandle target) {
--        super(target.type(), countingReinvokerForm(target.type().basicType()), target);
-+        super(target.type(), countingReinvokerForm(target.type().basicType()));
-+        this.target = target;
-     }
- 
-     /** Wrap the incoming MethodHandle in a CountingMethodHandle if they are enabled */
-@@ -51,6 +53,13 @@
-         return mh;
-     }
- 
-+    @Override
-+    public String types() {
-+        return types;
-+    }
-+
-+    public static final String types = "L";
-+
-     @ForceInline
-     void vmcountBump() {
-         vmcount += 1;
-@@ -71,7 +80,7 @@
-         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.dataValueName(names[THIS_CMH], 'L', 0);
-+        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);
-@@ -88,4 +97,33 @@
-         }
-     }
- 
-+    @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 -r 1478423d0bfc src/share/classes/java/lang/invoke/DataBinding.java
---- a/src/share/classes/java/lang/invoke/DataBinding.java	Thu Jul 12 19:03:13 2012 +0200
-+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
-@@ -1,186 +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.List;
--import java.util.AbstractList;
--
--/**
-- * Interface for binding data values into a method handle or other object.
-- * @author John Rose, JSR 292 EG
-- */
--interface DataBinding {
--    // /** Get basic types of the data fields, as a string of the form {@code "[LIJFD]*"}. */
--    // public String dataValueTypes();
--    // /** Get the number of data fields, equivalent to {@code getSignature().length()}. */
--    // public int dataValueCount();
--    // /** Get the basic type of the N-th value, one of the characters in {@code "LIJFD"}. */
--    // public char  dataValueType(int i);
--
--    // /** Get the N-th value, boxed as needed. */
--    // public Object dataValue(int i);
--    // /** Get the N-th value, which must be a reference. */
--    // public Object objectDataValue(int i);
--    // /** Get the N-th value, which must be an int. */
--    // public int intDataValue(int i);
--    // /** Get the N-th value, which must be a long. */
--    // public long longDataValue(int i);
--    // /** Get the N-th value, which must be a float. */
--    // public float floatDataValue(int i);
--    // /** Get the N-th value, which must be a double. */
--    // public double doubleDataValue(int i);
--
--//    /** Create an object with the same values, plus the added reference. */
--//    public DataBinding addObjectDataValue(Object valule);
--//    /** Create an object with the same values, plus the added int. */
--//    public DataBinding addIntDataValue(int value);
--//    /** Create an object with the same values, plus the added long. */
--//    public DataBinding addLongDataValue(long value);
--//    /** Create an object with the same values, plus the added float. */
--//    public DataBinding addFloatDataValue(float value);
--//    /** Create an object with the same values, plus the added double. */
--//    public DataBinding addDoubleDataValue(double value);
--
--    class ListView extends AbstractList<Object> {
--        final BoundMethodHandle data;
--
--        ListView(BoundMethodHandle data) {
--            this.data = data;
--        }
--
--        @Override
--        public Object get(int i) {
--            if (i == 0)
--                return data.dataValue0();
--            else
--                return ((BoundMethodHandle.Multiple) data).dataValue(i);
--        }
--
--        @Override
--        public int size() {
--            return data.dataValueCount();
--        }
--
--        @Override
--        public Object[] toArray() {
--            return Methods.toArray(data);
--        }
--    }
--
--    public class Methods {
--        private Methods() { throw new InternalError(); }
--
--        public static boolean checkDataValueType(BoundMethodHandle data, int i, char type) {
--            char actualType = data.dataValueType(i);
--            if (actualType != type) {
--                throw new IllegalArgumentException("actual type is "+actualType);
--            }
--            return true;  // pass boolean back for use with assert()
--        }
--
--        public static int dataValueCount(BoundMethodHandle data) {
--            return data.dataValueTypes().length();
--        }
--        public static char dataValueType(BoundMethodHandle data, int i) {
--            return data.dataValueTypes().charAt(i);
--        }
--        public static String dataValueTypes(BoundMethodHandle data) {
--            char[] types = new char[data.dataValueCount()];
--            for (int i = 0; i < types.length; i++)
--                types[i] = data.dataValueType(i);
--            return new String(types);
--        }
--
--        /*
--        public static Object objectDataValue(BoundMethodHandle data, int i) {
--            //checkDataValueType(data, i, 'L');
--            return data.dataValue(i);
--        }
--        public static int intDataValue(BoundMethodHandle data, int i) {
--            //checkDataValueType(data, i, 'I');
--            return (Integer) data.dataValue(i);
--        }
--        public static long longDataValue(BoundMethodHandle data, int i) {
--            //checkDataValueType(data, i, 'J');
--            return (Long) data.dataValue(i);
--        }
--        public static float floatDataValue(BoundMethodHandle data, int i) {
--            //checkDataValueType(data, i, 'F');
--            return (Float) data.dataValue(i);
--        }
--        public static double doubleDataValue(BoundMethodHandle data, int i) {
--            //checkDataValueType(data, i, 'D');
--            return (Double) data.dataValue(i);
--        }
--
--        public static Object dataValue(BoundMethodHandle data, int i) {
--            switch (data.dataValueType(i)) {
--                case 'I':  return data.intDataValue(i);
--                case 'J':  return data.longDataValue(i);
--                case 'F':  return data.floatDataValue(i);
--                case 'D':  return data.doubleDataValue(i);
--                case 'L':  return data.objectDataValue(i);
--                default:   throw new InternalError();
--            }
--        }
--        */
--
--        public static Object[] toArray(BoundMethodHandle data) {
--            String types = data.dataValueTypes();
--            int size = types.length();
--            Object[] values = new Object[size];
--            for (int i = 0; i < size; i++) {
--                Object value;
--                if (data instanceof BoundMethodHandle) {
--                    switch (types.charAt(i)) {
--                    case 'I':  value = data.intDataValue0();     break;
--                    case 'J':  value = data.longDataValue0();    break;
--                    case 'F':  value = data.floatDataValue0();   break;
--                    case 'D':  value = data.doubleDataValue0();  break;
--                    case 'L':  value = data.dataValue0();        break;
--                    default:   throw new InternalError();
--                    }
--                } else {
--                    BoundMethodHandle.Multiple m = (BoundMethodHandle.Multiple) data;
--                    switch (types.charAt(i)) {
--                    case 'I':  value = m.intDataValue(i);     break;
--                    case 'J':  value = m.longDataValue(i);    break;
--                    case 'F':  value = m.floatDataValue(i);   break;
--                    case 'D':  value = m.doubleDataValue(i);  break;
--                    case 'L':  value = m.dataValue(i);        break;
--                    default:   throw new InternalError();
--                    }
--                }
--                values[i] = value;
--            }
--            return values;
--        }
--
--        public static List<Object> toList(BoundMethodHandle data) {
--            return new ListView(data);
--        }
--    }
--}
-diff -r 1478423d0bfc src/share/classes/java/lang/invoke/DirectMethodHandle.java
---- a/src/share/classes/java/lang/invoke/DirectMethodHandle.java	Thu Jul 12 19:03:13 2012 +0200
-+++ b/src/share/classes/java/lang/invoke/DirectMethodHandle.java	Fri Jul 13 10:44:45 2012 +0200
-@@ -66,24 +66,22 @@
-     }
- 
-     @Override
-+    MethodHandle copyWith(MethodType mt, LambdaForm lf) {
-+        return new DirectMethodHandle(mt, member, lf);
-+    }
-+
-+    @Override
-     String debugString() {
-         return "DMH["+member.toString()+"]="+super.debugString();
-     }
- 
-     //// Implementation methods.
-     @Override
-+    @ForceInline
-     MemberName internalMemberName() {
-         return member;
-     }
- 
--    /** Static wrapper for DirectMethodHandle.internalMemberName. */
--    @ForceInline
--    /*non-public*/ static
--    Object internalMemberName(Object mh) {
--        return ((DirectMethodHandle)mh).member;
--    }
--
--
-     @Override
-     MethodHandle bindArgument(int pos, char basicType, Object value) {
-         // If the member needs dispatching, do so.
-@@ -224,6 +222,12 @@
-         static final EnsureInitialized INSTANCE = new EnsureInitialized();
-     }
- 
-+    /** Static wrapper for DirectMethodHandle.internalMemberName. */
-+    /*non-public*/ static
-+    Object internalMemberName(Object mh) {
-+        return ((DirectMethodHandle)mh).member;
-+    }
-+
-     private static final NamedFunction NF_internalMemberName;
-     private static final NamedFunction NF_ensureClassInitialized;
-     private static final MethodHandle MH_shouldBeInitialized;
-diff -r 1478423d0bfc src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
---- a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java	Thu Jul 12 19:03:13 2012 +0200
-+++ b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java	Fri Jul 13 10:44:45 2012 +0200
-@@ -27,6 +27,7 @@
- 
- import sun.invoke.util.VerifyAccess;
- import java.lang.invoke.LambdaForm.Name;
-+import java.lang.invoke.MethodHandles.Lookup;
- 
- import sun.invoke.util.Wrapper;
- import sun.misc.Unsafe;
-@@ -52,7 +53,6 @@
-     /** Define class names for convenience. */
-     private static final String MH      = "java/lang/invoke/MethodHandle";
-     private static final String BMH     = "java/lang/invoke/BoundMethodHandle";
--    private static final String BMHM    = "java/lang/invoke/BoundMethodHandle$Multiple";
-     private static final String LF      = "java/lang/invoke/LambdaForm";
-     private static final String LFN     = "java/lang/invoke/LambdaForm$Name";
-     private static final String CLS     = "java/lang/Class";
-@@ -148,7 +148,7 @@
-         }
-     }
- 
--    private void maybeDump(final byte[] classFile) {
-+    static void maybeDump(final String className, final byte[] classFile) {
-         if (DUMP_CLASS_FILES) {
-             System.out.println("dump: " + className);
-             java.security.AccessController.doPrivileged(
-@@ -290,6 +290,9 @@
- 
-         String invokerDesc = invokerType.toMethodDescriptorString();
-         mv = cw.visitMethod(Opcodes.ACC_STATIC, invokerName, invokerDesc, null, null);
-+
-+        // Force inlining of this invoker method.
-+        mv.visitAnnotation("Ljava/lang/invoke/ForceInline;", true);
-     }
- 
-     /**
-@@ -441,7 +444,11 @@
-         case 'L':
-             if (VerifyType.isNullConversion(Object.class, pclass))
-                 return;
--            if (isStaticallyNameable(pclass)) {
-+            // 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)) {
-                 mv.visitTypeInsn(Opcodes.CHECKCAST, getInternalName(pclass));
-             } else {
-                 mv.visitLdcInsn(constantPlaceholder(pclass));
-@@ -510,9 +517,6 @@
-     private byte[] generateCustomizedCodeBytes() {
-         classFilePrologue();
- 
--        // Force inlining of this invoker method.
--        mv.visitAnnotation("Ljava/lang/invoke/ForceInline;", true);
--
-         // Suppress this method in backtraces displayed to the user.
-         mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
- 
-@@ -530,8 +534,6 @@
-                 // FIXME: make sure this idiom is really present!
-                 emitSelectAlternative(name, lambdaForm.names[i + 1]);
-                 i++;  // skip MH.invokeBasic of the selectAlternative result
--            } else if (isBoundArgumentLoad(member)) {
--                emitBoundArgumentLoad(member, name);
-             } else if (isStaticallyInvocable(member)) {
-                 emitStaticInvoke(member, name);
-             } else {
-@@ -553,9 +555,10 @@
-         emitReturn();
- 
-         classFileEpilogue();
-+        bogusMethod(lambdaForm);
- 
-         final byte[] classFile = cw.toByteArray();
--        maybeDump(classFile);
-+        maybeDump(className, classFile);
-         return classFile;
-     }
- 
-@@ -600,6 +603,7 @@
- 
-     boolean isStaticallyInvocable(MemberName member) {
-         if (member == null)  return false;
-+        assert !member.isConstructor();
-         Class<?> cls = member.getDeclaringClass();
-         if (cls.isArray() || cls.isPrimitive())
-             return false;  // FIXME
-@@ -700,6 +704,8 @@
-      * @param invokeBasicName
-      */
-     private void emitSelectAlternative(Name selectAlternativeName, Name invokeBasicName) {
-+        MethodType type = selectAlternativeName.function.methodType();
-+
-         Name receiver = (Name) invokeBasicName.arguments[0];
- 
-         Label L_fallback = new Label();
-@@ -735,69 +741,6 @@
-     }
- 
-     /**
--     * Check if MemberName is a call to retrieve a bound argument.
--     *
--     * @param member
--     * @return
--     */
--    private boolean isBoundArgumentLoad(MemberName member) {
--        if (member == null) {
--            return false;
--        }
--        Class<?> klass = member.getDeclaringClass();
--        String   name  = member.getName();
--        if (klass != BoundMethodHandle.class && klass != BoundMethodHandle.Multiple.class) {
--            return false;
--        }
--        if (!name.startsWith("dataValue") &&
--            !name.startsWith("intDataValue") &&
--            !name.startsWith("longDataValue")) {
--            return false;
--        }
--        if (name.equals("dataValue") || name.equals("intDataValue") || name.equals("longDataValue")) {
--            return false;
--        }
--        int arity = member.getInvocationType().parameterCount();
--        if (arity == 2)
--            return false;  // do not handle Multiple.dataValue(int i), yet
--        assert(arity == 1);
--        return true;
--    }
--
--    private void emitBoundArgumentLoad(MemberName member, Name argLoadName) {
--        assert(argLoadName.arguments.length == 1 &&
--               argLoadName.arguments[0] == this.lambdaForm.names[0]) : argLoadName.exprString();
--        String name = member.getName();
--        int index = Integer.valueOf(name.substring(name.length() - 1));
--
--        if (index == 0) {
--            // aload_0
--            // checkcast  // class java/lang/invoke/BoundMethodHandle
--            // getfield   // Field argument:Ljava/lang/Object;
--            emitAloadInsn(0);
--            mv.visitTypeInsn(Opcodes.CHECKCAST, BMH);
--            mv.visitFieldInsn(Opcodes.GETFIELD, BMH, "argument", "Ljava/lang/Object;");
--        } else {
--            // aload_0
--            // checkcast  // class java/lang/invoke/BoundMethodHandle$Multiple
--            // getfield   // Field next:Ljava/lang/invoke/BoundMethodHandle$Multiple;
--            // getfield   // Field argument:Ljava/lang/Object;
--            emitAloadInsn(0);
--            mv.visitTypeInsn(Opcodes.CHECKCAST, BMHM);
--            for (int i = 0; i < index; i++) {
--                mv.visitFieldInsn(Opcodes.GETFIELD, BMHM, "next", "Ljava/lang/invoke/BoundMethodHandle$Multiple;");
--            }
--            mv.visitFieldInsn(Opcodes.GETFIELD, BMH, "argument", "Ljava/lang/Object;");
--        }
--
--        if (name.startsWith("intDataValue")) {
--            emitUnboxing(Integer.class);
--        } else if (name.startsWith("longDataValue")) {
--            emitUnboxing(Long.class);
--        }
--    }
--
--    /**
-      *
-      * @param name
-      * @param paramIndex
-@@ -805,16 +748,17 @@
-     private void emitPushArgument(Name name, int paramIndex) {
-         Object arg = name.arguments[paramIndex];
-         char ptype = name.function.parameterType(paramIndex);
-+        MethodType mtype = name.function.methodType();
-         if (arg instanceof Name) {
-             Name n = (Name) arg;
-             emitLoadInsn(n.type, n.index());
--            MethodType mtype = name.function.methodType();
-             emitImplicitConversion(n.type, mtype.parameterType(paramIndex));
-         } else {
-             if (Wrapper.isWrapperType(arg.getClass()) && ptype != 'L') {
-                 emitConst(arg);
-             } else {
-                 mv.visitLdcInsn(constantPlaceholder(arg));
-+                emitImplicitConversion('L', mtype.parameterType(paramIndex));
-             }
-         }
-     }
-@@ -990,9 +934,6 @@
-     private byte[] generateLambdaFormInterpreterEntryPointBytes() {
-         classFilePrologue();
- 
--        // Prevent inlining of this invoker method.
--        mv.visitAnnotation("Ljava/lang/invoke/DontInline;", true);
--
-         // Suppress this method in backtraces displayed to the user.
-         mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
- 
-@@ -1028,9 +969,10 @@
-         emitReturnInsn(rtype);
- 
-         classFileEpilogue();
-+        bogusMethod(invokerType);
- 
-         final byte[] classFile = cw.toByteArray();
--        maybeDump(classFile);
-+        maybeDump(className, classFile);
-         return classFile;
-     }
- 
-@@ -1048,13 +990,12 @@
-         return g.loadMethod(g.generateNamedFunctionInvokerImpl(typeForm));
-     }
- 
-+    static int nfi = 0;
-+
-     private byte[] generateNamedFunctionInvokerImpl(MethodTypeForm typeForm) {
-         MethodType dstType = typeForm.erasedType();
-         classFilePrologue();
- 
--        // Force inlining of this invoker method.
--        mv.visitAnnotation("Ljava/lang/invoke/ForceInline;", true);
--
-         // Suppress this method in backtraces displayed to the user.
-         mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
- 
-@@ -1099,9 +1040,27 @@
-         emitReturnInsn(Object.class);  // NOTE: NamedFunction invokers always return a reference value.
- 
-         classFileEpilogue();
-+        bogusMethod(dstType);
- 
-         final byte[] classFile = cw.toByteArray();
--        maybeDump(classFile);
-+        maybeDump(className, classFile);
-         return classFile;
-     }
-+
-+    /**
-+     * Emit a bogus method that just loads some string constants. This is to get the constants into the constant pool
-+     * for debugging purposes.
-+     */
-+    private void bogusMethod(Object... os) {
-+        if (DUMP_CLASS_FILES) {
-+            mv = cw.visitMethod(Opcodes.ACC_STATIC, "dummy", "()V", null, null);
-+            for (Object o : os) {
-+                mv.visitLdcInsn(o.toString());
-+                mv.visitInsn(Opcodes.POP);
-+            }
-+            mv.visitInsn(Opcodes.RETURN);
-+            mv.visitMaxs(0, 0);
-+            mv.visitEnd();
-+        }
-+    }
- }
-diff -r 1478423d0bfc src/share/classes/java/lang/invoke/Invokers.java
---- a/src/share/classes/java/lang/invoke/Invokers.java	Thu Jul 12 19:03:13 2012 +0200
-+++ b/src/share/classes/java/lang/invoke/Invokers.java	Fri Jul 13 10:44:45 2012 +0200
-@@ -75,7 +75,7 @@
-         if (invoker != null)  return invoker;
-         MethodType mtype = targetType;
-         LambdaForm lform = invokeForm(mtype, MethodTypeForm.LF_EX_INVOKER);
--        invoker = new BoundMethodHandle<MethodType>(mtype.invokerType(), lform, mtype);
-+        invoker = new BoundMethodHandle.BMH_L(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<MethodType>(mtype.invokerType(), lform, mtype);
-+        invoker = new BoundMethodHandle.BMH_L(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.dataValueName(names[THIS_MH], 'L', 0);
-+            names[MTYPE_ARG] = BoundMethodHandle.getterName(names[THIS_MH], 'L', 0);
-             // else if isLinker, then MTYPE is passed in from the caller (e.g., the JVM)
-         }
- 
-diff -r 1478423d0bfc src/share/classes/java/lang/invoke/LambdaForm.java
---- a/src/share/classes/java/lang/invoke/LambdaForm.java	Thu Jul 12 19:03:13 2012 +0200
-+++ b/src/share/classes/java/lang/invoke/LambdaForm.java	Fri Jul 13 10:44:45 2012 +0200
-@@ -264,7 +264,7 @@
-         // Do all names possess an index consistent with their local definition order?
-         for (int i = 0; i < arity; i++) {
-             Name n = names[i];
--            assert(n.index() == i);
-+            assert(n.index() == i) : Arrays.asList(n.index(), i);
-             assert(n.isParam());
-         }
-         // Also, do all local name references
-@@ -276,7 +276,7 @@
-                     Name n2 = (Name) arg;
-                     int i2 = n2.index;
-                     assert(0 <= i2 && i2 < names.length) : n.debugString() + ": 0 <= i2 && i2 < names.length: 0 <= " + i2 + " < " + names.length;
--                    assert(names[i2] == n2) : Arrays.asList(i, n.debugString(), i2, n2.debugString(), names[i2].debugString(), this);
-+                    assert(names[i2] == n2) : Arrays.asList("-1-", i, "-2-", n.debugString(), "-3-", i2, "-4-", n2.debugString(), "-5-", names[i2].debugString(), "-6-", this);
-                     assert(i2 < i);  // ref must come after def!
-                 }
-             }
-@@ -486,7 +486,6 @@
- 
-     // The following are predefined exact invokers.  The system must build
-     // a separate invoker for each distinct signature.
--    @DontInline
-     static Object interpret_L(MethodHandle mh) throws Throwable {
-         Object[] av = {mh};
-         String sig = null;
-@@ -495,7 +494,6 @@
-         assert(returnTypesMatch(sig, av, res));
-         return res;
-     }
--    @DontInline
-     static Object interpret_L(MethodHandle mh, Object x1) throws Throwable {
-         Object[] av = {mh, x1};
-         String sig = null;
-@@ -504,7 +502,6 @@
-         assert(returnTypesMatch(sig, av, res));
-         return res;
-     }
--    @DontInline
-     static Object interpret_L(MethodHandle mh, Object x1, Object x2) throws Throwable {
-         Object[] av = {mh, x1, x2};
-         String sig = null;
-@@ -711,8 +708,57 @@
-         return buf.toString();
-     }
- 
-+    /**
-+     * Apply immediate binding for a Name in this form indicated by its position relative to the form.
-+     * The first parameter to a LambdaForm, a0:L, always represents the form's method handle, so 0 is not
-+     * accepted as valid.
-+     */
-+    LambdaForm bindImmediate(int pos, char basicType, Object value) {
-+        // must be an argument, and the types must match
-+        assert pos > 0 && pos < arity && names[pos].type == basicType && Name.typesMatch(basicType, value);
-+
-+        int arity2 = arity - 1;
-+        Name[] names2 = new Name[names.length - 1];
-+        for (int r = 0, w = 0; r < names.length; ++r, ++w) { // (r)ead from names, (w)rite to names2
-+            Name n = names[r];
-+            if (n.isParam()) {
-+                if (n.index == pos) {
-+                    // do not copy over the argument that is to be replaced with a literal,
-+                    // but adjust the write index
-+                    --w;
-+                } else {
-+                    names2[w] = new Name(w, n.type);
-+                }
-+            } else {
-+                Object[] arguments2 = new Object[n.arguments.length];
-+                for (int i = 0; i < n.arguments.length; ++i) {
-+                    Object arg = n.arguments[i];
-+                    if (arg instanceof Name) {
-+                        int ni = ((Name) arg).index;
-+                        if (ni == pos) {
-+                            arguments2[i] = value;
-+                        } else if (ni < pos) {
-+                            // replacement position not yet passed
-+                            arguments2[i] = names2[ni];
-+                        } else {
-+                            // replacement position passed
-+                            arguments2[i] = names2[ni - 1];
-+                        }
-+                    } else {
-+                        arguments2[i] = arg;
-+                    }
-+                }
-+                names2[w] = new Name(n.function, arguments2);
-+                names2[w].initIndex(w);
-+            }
-+        }
-+
-+        int result2 = result == -1 ? -1 : result - 1;
-+        return new LambdaForm(debugName, arity2, names2, result2);
-+    }
-+
-     LambdaForm bind(char basicType, int namePos, int dataValuePos) {
--        Name dataValueName = BoundMethodHandle.dataValueName(names[0], basicType, dataValuePos);
-+        Name dataValueName = BoundMethodHandle.getterName(names[0], basicType, dataValuePos);
-         return bind(names[namePos], dataValueName);
-     }
- 
-@@ -725,7 +771,7 @@
-         if (bindCache != null) {
-             LambdaForm form = bindCache[pos];
-             if (form != null) {
--                assert(form.contains(binding));
-+                assert(form.contains(binding)) : "form << " + form + " >> does not contain binding << " + binding + " >>";
-                 return form;
-             }
-         } else {
-@@ -909,6 +955,15 @@
-             resolvedHandle = DirectMethodHandle.make(member);
-         }
- 
-+        @Override
-+        public boolean equals(Object other) {
-+            if (this == other) return true;
-+            if (other == null) return false;
-+            if (!(other instanceof NamedFunction)) return false;
-+            NamedFunction that = (NamedFunction) other;
-+            return this.member != null && this.member.equals(that.member);
-+        }
-+
-         // Put the predefined NamedFunction invokers into the table.
-         static void initializeInvokers() {
-             for (MemberName m : MemberName.getFactory().getMethods(NamedFunction.class, false, null, null, null)) {
-diff -r 1478423d0bfc src/share/classes/java/lang/invoke/MemberName.java
---- a/src/share/classes/java/lang/invoke/MemberName.java	Thu Jul 12 19:03:13 2012 +0200
-+++ b/src/share/classes/java/lang/invoke/MemberName.java	Fri Jul 13 10:44:45 2012 +0200
-@@ -77,6 +77,32 @@
-     //@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.
-      */
-diff -r 1478423d0bfc src/share/classes/java/lang/invoke/MethodHandle.java
---- a/src/share/classes/java/lang/invoke/MethodHandle.java	Thu Jul 12 19:03:13 2012 +0200
-+++ b/src/share/classes/java/lang/invoke/MethodHandle.java	Fri Jul 13 10:44:45 2012 +0200
-@@ -28,11 +28,9 @@
- 
- import java.util.*;
- import sun.invoke.util.*;
-+import sun.misc.Unsafe;
- 
--import static java.lang.invoke.LambdaForm.*;
- import static java.lang.invoke.MethodHandleStatics.*;
--import static java.lang.invoke.MethodHandles.*;
--import static java.lang.invoke.MethodType.*;
- 
- /**
-  * A method handle is a typed, directly executable reference to an underlying method,
-@@ -1267,8 +1265,6 @@
- 
-     /*non-public*/
-     Object internalValues() {
--        if (this instanceof BoundMethodHandle)
--            return DataBinding.Methods.toList((BoundMethodHandle) this);
-         return "";
-     }
- 
-@@ -1294,6 +1290,25 @@
-     }
- 
-     /*non-public*/
-+    MethodHandle bindImmediate(int pos, char basicType, Object value) {
-+        // Bind an immediate value to a position in the arguments.
-+        // This means, elide the respective argument,
-+        // and replace all references to it in NamedFunction args with the specified value.
-+
-+        // CURRENT RESTRICTIONS
-+        // * only for pos 0 and UNSAFE (position is adjusted in MHImpl to make API usable for others)
-+        assert pos == 0 && basicType == 'L' && value instanceof Unsafe;
-+        MethodType type2 = type.dropParameterTypes(pos, pos + 1); // adjustment: ignore receiver!
-+        LambdaForm form2 = form.bindImmediate(pos + 1, basicType, value); // adjust pos to form-relative pos
-+        return copyWith(type2, form2);
-+    }
-+
-+    /*non-public*/
-+    MethodHandle copyWith(MethodType mt, LambdaForm lf) {
-+        throw new InternalError("copyWith: " + this.getClass());
-+    }
-+
-+    /*non-public*/
-     MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
-         // Override this if it can be improved.
-         return rebind().dropArguments(srcType, pos, drops);
-@@ -1306,11 +1321,11 @@
-     }
- 
-     /*non-public*/
--    private BoundMethodHandle<MethodHandle> rebind() {
-+    private BoundMethodHandle rebind() {
-         // Bind 'this' into a new invoker, of the known class BMH.
-         MethodType type2 = type();
-         LambdaForm form2 = BoundMethodHandle.reinvokerForm(type2.basicType());
-         // form2 = lambda (bmh, arg*) { thismh = bmh[0]; invokeBasic(thismh, arg*) }
--        return new BoundMethodHandle<>(type2, form2, this);
-+        return new BoundMethodHandle.BMH_L(type2, form2, this);
-     }
- }
-diff -r 1478423d0bfc src/share/classes/java/lang/invoke/MethodHandleImpl.java
---- a/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Thu Jul 12 19:03:13 2012 +0200
-+++ b/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Fri Jul 13 10:44:45 2012 +0200
-@@ -186,43 +186,57 @@
-     }
- 
-     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 lambdaType = srcType.invokerType();
--        Name[] names;
--        boolean isStatic = !MethodHandleNatives.refKindHasReceiver(refKind);
-+        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 = arguments(1, lambdaType);
-+            names[_OFFSET] = new Name(BoundMethodHandle.MH_argJ0, names[0]);
-+            names[_BASE]   = new Name(BoundMethodHandle.MH_argL1, names[0]);
-         } else {
--            names = arguments(2, lambdaType);
--            names[names.length - 2] = new Name(FieldAccessor.GETCLASS, names[2]);  // NPE check
-+            names[_NPE] = new Name(FieldAccessor.OBJECT_GETCLASS, names[_ARG]); // NPE check
-+            names[_OFFSET] = new Name(BoundMethodHandle.MH_argJ0, names[0]);
-         }
--        Name[] args = Arrays.copyOfRange(names, 1, 1 + srcType.parameterCount());
--        names[names.length - 1] = new Name(accessor, (Object[]) args);
-+
-+        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);
--        MethodHandle mh = new SimpleMethodHandle(srcType, form);
- 
--        // Bind accessor arguments (Unsafe.getXXX(Object o, long offset).
-+        BoundMethodHandle mh;
-         if (isStatic) {
--            Object base   = MethodHandleNatives.staticFieldBase(field);
--            long   offset = MethodHandleNatives.staticFieldOffset(field);
--            mh = mh.bindArgument(2, 'J', offset);
--            mh = mh.bindArgument(1, 'L', base);
--            mh = mh.bindReceiver(UNSAFE);
-+            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 = mh.bindArgument(2, 'J', offset);
--            mh = mh.bindReceiver(UNSAFE);
-+            long offset = MethodHandleNatives.objectFieldOffset(field);
-+            mh = new BoundMethodHandle.BMH_J(mhType, form, offset);
-         }
-         return mh;
-     }
- 
-     static final class FieldAccessor {
--        static final MethodHandle GETCLASS;
-+        static final MethodHandle OBJECT_GETCLASS;
-         static {
-             try {
-                 assert(IMPL_LOOKUP != null) : "bootstrap problem";
--                GETCLASS =
-+                OBJECT_GETCLASS =
-                     IMPL_LOOKUP.findStatic(FieldAccessor.class, "getClass", MethodType.methodType(Object.class, Object.class));
-             } catch (NoSuchMethodException | IllegalAccessException e) {
-                 throw new InternalError(e);
-@@ -281,6 +295,7 @@
-                 MethodType strongType = strongType(refKind, field, receiver);
-                 mh = convertArguments(mh, strongType, 0);
-             }
-+            mh = mh.bindImmediate(0, 'L', UNSAFE); // bind UNSAFE early
-             return mh;
-         }
-     }
-@@ -621,12 +636,14 @@
-         return new AsVarargsCollector(target, target.type(), arrayType);
-     }
- 
--    static class AsVarargsCollector extends BoundMethodHandle<MethodHandle> {
-+    static class AsVarargsCollector extends BoundMethodHandle {
-+        MethodHandle target;
-         final Class<?> arrayType;
-         MethodHandle cache;
- 
-         AsVarargsCollector(MethodHandle target, MethodType type, Class<?> arrayType) {
--            super(type, reinvokerForm(type), target);
-+            super(type, reinvokerForm(type));
-+            this.target = target;
-             this.arrayType = arrayType;
-             this.cache = target.asCollector(arrayType, 0);
-         }
-@@ -638,10 +655,17 @@
- 
-         @Override
-         public MethodHandle asFixedArity() {
--            return argument;
-+            return target;
-         }
- 
-         @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;
-@@ -706,6 +730,36 @@
-         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?
-@@ -1154,11 +1208,11 @@
-     MethodHandle makeGuardWithTest(MethodHandle test,
-                                    MethodHandle target,
-                                    MethodHandle fallback) {
--        MethodType basicType = target.type().basicType();
--        MethodHandle invokeBasic = MethodHandles.basicInvoker(basicType);
--        int arity = basicType.parameterCount();
-+        MethodType targetType = target.type();
-+        MethodHandle invokeBasic = MethodHandles.basicInvoker(targetType);
-+        int arity = targetType.parameterCount();
-         int extraNames = 3;
--        MethodType lambdaType = basicType.invokerType();
-+        MethodType lambdaType = targetType.invokerType();
-         Name[] names = arguments(extraNames, lambdaType);
- 
-         Object[] testArgs   = Arrays.copyOfRange(names, 1, 1 + arity, Object[].class);
-@@ -1176,7 +1230,7 @@
-         names[arity + 3] = new Name(new NamedFunction(invokeBasic), targetArgs);
- 
-         LambdaForm form = new LambdaForm("guard", lambdaType.parameterCount(), names);
--        return new SimpleMethodHandle(target.type(), form);
-+        return new SimpleMethodHandle(targetType, form);
-     }
- 
-     private static class GuardWithCatch {
-diff -r 1478423d0bfc src/share/classes/java/lang/invoke/MethodHandleNatives.java
---- a/src/share/classes/java/lang/invoke/MethodHandleNatives.java	Thu Jul 12 19:03:13 2012 +0200
-+++ b/src/share/classes/java/lang/invoke/MethodHandleNatives.java	Fri Jul 13 10:44:45 2012 +0200
-@@ -325,19 +325,13 @@
-         if (defc != MethodHandle.class || refKind != REF_invokeVirtual)
-             throw new LinkageError("no such method "+defc.getName()+"."+name+type);
- 
--        try {
--            switch (name) {
--            case "invoke":
--                return Invokers.genericInvokerMethod(callerClass, type, appendixResult);
--            case "invokeExact":
--                return Invokers.exactInvokerMethod(callerClass, type, appendixResult);
--            }
--            throw new UnsupportedOperationException("linkMethod "+name);
--        } catch (Throwable ex) {
--            if (TRACE_METHOD_LINKAGE)
--                ex.printStackTrace();
--            throw ex;
-+        switch (name) {
-+        case "invoke":
-+            return Invokers.genericInvokerMethod(callerClass, type, appendixResult);
-+        case "invokeExact":
-+            return Invokers.exactInvokerMethod(callerClass, type, appendixResult);
-         }
-+        throw new UnsupportedOperationException("linkMethod "+name);
-     }
- 
-     /**
-diff -r 1478423d0bfc src/share/classes/java/lang/invoke/MethodType.java
---- a/src/share/classes/java/lang/invoke/MethodType.java	Thu Jul 12 19:03:13 2012 +0200
-+++ b/src/share/classes/java/lang/invoke/MethodType.java	Fri Jul 13 10:44:45 2012 +0200
-@@ -108,6 +108,8 @@
-     /*trusted*/ Class<?> rtype() { return rtype; }
-     /*trusted*/ Class<?>[] ptypes() { return ptypes; }
- 
-+    void setForm(MethodTypeForm f) { form = f; }
-+
-     private static void checkRtype(Class<?> rtype) {
-         rtype.equals(rtype);  // null check
-     }
-diff -r 1478423d0bfc src/share/classes/java/lang/invoke/SimpleMethodHandle.java
---- a/src/share/classes/java/lang/invoke/SimpleMethodHandle.java	Thu Jul 12 19:03:13 2012 +0200
-+++ b/src/share/classes/java/lang/invoke/SimpleMethodHandle.java	Fri Jul 13 10:44:45 2012 +0200
-@@ -55,4 +55,10 @@
-         LambdaForm form2 = internalForm().permuteArguments(1, reorder, basicTypes(newType.parameterList()));
-         return new SimpleMethodHandle(newType, form2);
-     }
-+
-+    @Override
-+    MethodHandle copyWith(MethodType mt, LambdaForm lf) {
-+        return new SimpleMethodHandle(mt, lf);
-+    }
-+
- }
-diff -r 1478423d0bfc test/java/lang/invoke/MaxTest.java
---- /dev/null	Thu Jan 01 00:00:00 1970 +0000
-+++ b/test/java/lang/invoke/MaxTest.java	Fri Jul 13 10:44:45 2012 +0200
-@@ -0,0 +1,143 @@
-+/*
-+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
-+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-+ *
-+ * This code is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License version 2 only, as
-+ * published by the Free Software Foundation.  Oracle designates this
-+ * particular file as subject to the "Classpath" exception as provided
-+ * by Oracle in the LICENSE file that accompanied this code.
-+ *
-+ * This code is distributed in the hope that it will be useful, but WITHOUT
-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-+ * version 2 for more details (a copy is included in the LICENSE file that
-+ * accompanied this code).
-+ *
-+ * You should have received a copy of the GNU General Public License version
-+ * 2 along with this work; if not, write to the Free Software Foundation,
-+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-+ * or visit www.oracle.com if you need additional information or have any
-+ * questions.
-+ */
-+
-+/* @test
-+ * @summary BoundMethodHandle tests with primitive types
-+ * @compile MaxTest.java
-+ * @run junit/othervm test.java.lang.invoke.MaxTest
-+ */
-+
-+package test.java.lang.invoke;
-+
-+import static org.junit.Assert.assertEquals;
-+
-+import java.lang.invoke.MethodHandle;
-+import java.lang.invoke.MethodHandles;
-+import java.lang.invoke.MethodType;
-+
-+import org.junit.Test;
-+
-+public class MaxTest {
-+
-+    static MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
-+
-+    private MethodHandle getMax(Class<?> t) throws Throwable {
-+        return LOOKUP.findStatic(Math.class, "max", MethodType.methodType(t, t, t));
-+    }
-+
-+    static int ITERATION_COUNT = 40000;
-+    static {
-+        String iterations = System.getProperty(MaxTest.class.getSimpleName() + ".ITERATION_COUNT");
-+        if (iterations == null) {
-+            iterations = System.getProperty(MaxTest.class.getName() + ".ITERATION_COUNT");
-+        }
-+        if (iterations != null) {
-+            ITERATION_COUNT = Integer.parseInt(iterations);
-+        }
-+    }
-+
-+    @Test
-+    public void testMaxLong() throws Throwable {
-+        final Class<?> C = long.class;
-+        final long P = 23L;
-+        final long Q = 42L;
-+        final long R = Math.max(P, Q);
-+        for (int i = 0; i < ITERATION_COUNT; ++i) {
-+            MethodHandle h = getMax(C);
-+            assertEquals((long) h.invokeExact(P, Q), R);
-+            MethodHandle bh = MethodHandles.insertArguments(h, 0, P);
-+            assertEquals((long) bh.invokeExact(Q), R);
-+            MethodHandle bbh = MethodHandles.insertArguments(bh, 0, Q);
-+            assertEquals((long) bbh.invokeExact(), R);
-+            MethodHandle b2h = MethodHandles.insertArguments(h, 1, Q);
-+            assertEquals((long) b2h.invokeExact(P), R);
-+            MethodHandle bb2h = MethodHandles.insertArguments(b2h, 0, P);
-+            assertEquals((long) bb2h.invokeExact(), R);
-+        }
-+    }
-+
-+    @Test
-+    public void testMaxInt() throws Throwable {
-+        final Class<?> C = int.class;
-+        final int P = 23;
-+        final int Q = 42;
-+        final int R = Math.max(P, Q);
-+        for (int i = 0; i < ITERATION_COUNT; ++i) {
-+            MethodHandle h = getMax(C);
-+            assertEquals((int) h.invokeExact(P, Q), R);
-+            MethodHandle bh = MethodHandles.insertArguments(h, 0, P);
-+            assertEquals((int) bh.invokeExact(Q), R);
-+            MethodHandle bbh = MethodHandles.insertArguments(bh, 0, Q);
-+            assertEquals((int) bbh.invokeExact(), R);
-+            MethodHandle b2h = MethodHandles.insertArguments(h, 1, Q);
-+            assertEquals((int) b2h.invokeExact(P), R);
-+            MethodHandle bb2h = MethodHandles.insertArguments(b2h, 0, P);
-+            assertEquals((int) bb2h.invokeExact(), R);
-+        }
-+    }
-+
-+    @Test
-+    public void testMaxFloat() throws Throwable {
-+        final Class<?> C = float.class;
-+        final float P = 23F;
-+        final float Q = 42F;
-+        final float R = Math.max(P, Q);
-+        final float D = 0.1F;
-+        for (int i = 0; i < ITERATION_COUNT; ++i) {
-+            MethodHandle h = getMax(C);
-+            assertEquals((float) h.invokeExact(P, Q), R, D);
-+            MethodHandle bh = MethodHandles.insertArguments(h, 0, P);
-+            assertEquals((float) bh.invokeExact(Q), R, D);
-+            MethodHandle bbh = MethodHandles.insertArguments(bh, 0, Q);
-+            assertEquals((float) bbh.invokeExact(), R, D);
-+            MethodHandle b2h = MethodHandles.insertArguments(h, 1, Q);
-+            assertEquals((float) b2h.invokeExact(P), R, D);
-+            MethodHandle bb2h = MethodHandles.insertArguments(b2h, 0, P);
-+            assertEquals((float) bb2h.invokeExact(), R, D);
-+        }
-+    }
-+
-+    @Test
-+    public void testMaxDouble() throws Throwable {
-+        final Class<?> C = double.class;
-+        final double P = 23F;
-+        final double Q = 42F;
-+        final double R = Math.max(P, Q);
-+        final double D = 0.1;
-+        for (int i = 0; i < ITERATION_COUNT; ++i) {
-+            MethodHandle h = getMax(C);
-+            assertEquals((double) h.invokeExact(P, Q), R, D);
-+            MethodHandle bh = MethodHandles.insertArguments(h, 0, P);
-+            assertEquals((double) bh.invokeExact(Q), R, D);
-+            MethodHandle bbh = MethodHandles.insertArguments(bh, 0, Q);
-+            assertEquals((double) bbh.invokeExact(), R, D);
-+            MethodHandle b2h = MethodHandles.insertArguments(h, 1, Q);
-+            assertEquals((double) b2h.invokeExact(P), R, D);
-+            MethodHandle bb2h = MethodHandles.insertArguments(b2h, 0, P);
-+            assertEquals((double) bb2h.invokeExact(), R, D);
-+        }
-+    }
-+
-+}
--- a/series	Fri Jul 13 01:55:05 2012 -0700
+++ b/series	Fri Jul 13 02:18:29 2012 -0700
@@ -4,8 +4,7 @@
 # (none)
 
 # review pending before push to hotspot-comp:
-meth-lazy-7023639.patch         #-/meth #+78f1f4e4e9c7 #-testable
-meth-lazy-7023639.xbmh.patch    #-/meth #+78f1f4e4e9c7 #-testable
+meth-lazy-7023639.patch         #-/meth #+78f1f4e4e9c7
 
 # non-pushed files are under review or development, or merely experimental:
 meth-7177472.patch              #(78f1f4e4e9c7) #-buildable