changeset 412:f07d59dc449e

meth: make BMHs be more strongly typed; various cleanups
author jrose
date Tue, 17 Jul 2012 05:25:50 -0700
parents cec00d423fbc
children 72d2a3526502
files meth-lazy-7023639.bmh.patch
diffstat 1 files changed, 1249 insertions(+), 430 deletions(-) [+]
line wrap: on
line diff
--- a/meth-lazy-7023639.bmh.patch	Mon Jul 16 01:10:54 2012 -0700
+++ b/meth-lazy-7023639.bmh.patch	Tue Jul 17 05:25:50 2012 -0700
@@ -4,7 +4,7 @@
 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,23 +25,7 @@
+@@ -25,27 +25,10 @@
  
  package java.lang.invoke;
  
@@ -25,11 +25,20 @@
 -import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.PUTFIELD;
 -import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.RETURN;
 -import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.V1_6;
+-import static java.lang.invoke.LambdaForm.arguments;
 +import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.*;
- import static java.lang.invoke.LambdaForm.arguments;
  import static java.lang.invoke.LambdaForm.basicTypes;
  import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;
-@@ -61,6 +45,7 @@
+-import static java.lang.invoke.MethodType.methodType;
++import static java.lang.invoke.MethodHandleStatics.*;
+ 
+ import java.lang.invoke.LambdaForm.Name;
+ import java.lang.invoke.LambdaForm.NamedFunction;
+@@ -57,10 +40,10 @@
+ 
+ import sun.invoke.util.ValueConversions;
+ import sun.invoke.util.Wrapper;
+-import sun.misc.Unsafe;
  
  import com.sun.xml.internal.ws.org.objectweb.asm.ClassWriter;
  import com.sun.xml.internal.ws.org.objectweb.asm.MethodVisitor;
@@ -37,35 +46,46 @@
  
  /**
   * The flavor of method handle which emulates an invoke instruction
-@@ -83,19 +68,18 @@
+@@ -83,19 +66,18 @@
          // for some type signatures, there exist pre-defined concrete BMH classes
          try {
              switch (xtype) {
 -            case 'L': return new BMH_L(type, form, x);
 +            case 'L':
-+                //return (BoundMethodHandle) Data.get("L").constructor[0].invokeBasic(type, form, x);
-+                return new BMH_L(type, form, x);
++                if (true)
++                    return bindSingle(type, form, x);
++                return (BoundMethodHandle) Data.get("L").constructor[0].invokeBasic(type, form, x);
              case 'I':
 -                assert x instanceof Integer : "expected Integer, found " + x.getClass();
 -                return (BoundMethodHandle) Data.get("I").constructor.invokeBasic(type, form, ((Integer) x).intValue());
-+                return (BoundMethodHandle) Data.get("I").constructor[0].invokeBasic(type, form, (int) x);
++                return (BoundMethodHandle) Data.EMPTY.extendWithType('I').constructor[0].invokeBasic(type, form, (int) x);
              case 'J':
 -                assert x instanceof Long;
 -                return new BMH_J(type, form, ((Long) x).longValue());
-+                //return new BMH_J(type, form, ((Long) x).longValue());
-+                return (BoundMethodHandle) Data.get("J").constructor[0].invokeBasic(type, form, (long) x);
++                return (BoundMethodHandle) Data.EMPTY.extendWithType('J').constructor[0].invokeBasic(type, form, (long) x);
              case 'F':
 -                assert x instanceof Float;
 -                return (BoundMethodHandle) Data.get("F").constructor.invokeBasic(type, form, ((Float) x).floatValue());
-+                return (BoundMethodHandle) Data.get("F").constructor[0].invokeBasic(type, form, (float) x);
++                return (BoundMethodHandle) Data.EMPTY.extendWithType('F').constructor[0].invokeBasic(type, form, (float) x);
              case 'D':
 -                assert x instanceof Double;
 -                return (BoundMethodHandle) Data.get("D").constructor.invokeBasic(type, form, ((Double) x).doubleValue());
-+                return (BoundMethodHandle) Data.get("D").constructor[0].invokeBasic(type, form, (double) x);
++                return (BoundMethodHandle) Data.EMPTY.extendWithType('D').constructor[0].invokeBasic(type, form, (double) x);
              default : throw new InternalError("unexpected xtype: " + xtype);
              }
          } catch (Throwable t) {
-@@ -122,7 +106,6 @@
+@@ -103,6 +85,10 @@
+         }
+     }
+ 
++    static MethodHandle bindSingle(MethodType type, LambdaForm form, Object x) {
++            return new BMH_L(type, form, x);
++    }
++
+     MethodHandle cloneExtend(MethodType type, LambdaForm form, char xtype, Object x) {
+         try {
+             switch (xtype) {
+@@ -122,7 +108,6 @@
              default : throw new InternalError("unexpected type: " + xtype);
              }
          } catch (Throwable t) {
@@ -73,165 +93,195 @@
              throw new InternalError(t);
          }
      }
-@@ -130,7 +113,7 @@
+@@ -130,7 +115,7 @@
      @Override
      MethodHandle bindArgument(int pos, char basicType, Object value) {
          MethodType type = type().dropParameterTypes(pos, pos+1);
 -        LambdaForm form = internalForm().bind(basicType, 1+pos, tcount());
-+        LambdaForm form = internalForm().bind(1+pos, (myTypes()+basicType).intern(), tcount());
++        LambdaForm form = internalForm().bind(1+pos, myData());
          if (basicType == 'I' && !(value instanceof Integer)) {
              // Cf. ValueConversions.unboxInteger
              value = ValueConversions.primitiveConversion(Wrapper.INT, value, true);
-@@ -158,27 +141,29 @@
+@@ -157,68 +142,43 @@
+          }
      }
  
-     public int tcount() {
+-    public int tcount() {
 -        return types().length();
-+        return myTypes().length();
-     }
- 
+-    }
+-
 -    protected final Data myData() {
 -        return Data.get(types());
--    }
-+    /**
-+     * Return the {@link Data} instance representing this BMH species. All subclasses must provide a
-+     * static field containing this value, and they must accordingly implement this method.
-+     */
-+    protected abstract Data myData();
- 
-     /**
-      * 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).
-+     * (the {@link #TYPES} field).
-      */
--    public abstract String types();
-+    public abstract String myTypes();
- 
-     /**
-      * All subclasses must provide such a value describing their type signature.
-      */
--    public static final String types = "";
-+    public static final String TYPES = "";
- 
-     public char type(int i) {
--        return types().charAt(i);
-+        return myTypes().charAt(i);
++    static final String EXTENSION_TYPES = "LIJFD";
++    static final byte INDEX_L = 0, INDEX_I = 1, INDEX_J = 2, INDEX_F = 3, INDEX_D = 4;
++    static byte extensionIndex(char type) {
++        int i = EXTENSION_TYPES.indexOf(type);
++        if (i < 0)  throw new InternalError();
++        return (byte) i;
      }
  
      /**
-@@ -186,7 +171,16 @@
-      * represents a MH bound to a generic invoker, which in turn forwards to the corresponding
-      * getter.
+-     * Return the type signature of a concrete BMH. Each concrete BMH is required
+-     * to implement this method to return its type signature as a constant String
+-     * (the {@link #types} field).
++     * Return the {@link Data} instance representing this BMH species. All subclasses must provide a
++     * static field containing this value, and they must accordingly implement this method.
       */
+-    public abstract String types();
+-
+-    /**
+-     * All subclasses must provide such a value describing their type signature.
+-     */
+-    public static final String types = "";
+-
+-    public char type(int i) {
+-        return types().charAt(i);
+-    }
+-
+-    /**
+-     * Return a {@link LambdaForm.Name} containing a {@link LambdaForm.NamedFunction} that
+-     * represents a MH bound to a generic invoker, which in turn forwards to the corresponding
+-     * getter.
+-     */
 -    static Name getterName(Name mhName, char basicType, int i) {
-+    static Name getterName(Name mhName, String types, int i) {
-+        if (i > 1) {  // FIXME: short circuit getters to simple field refs
-+            Data d = Data.get(types);
-+            MethodHandle mh = d.getters[i];
-+            if (mh != null) {
-+                return new Name(mh, mhName);
-+            }
-+            // If we get here we probably lose in LambdaForm.bind, assert(form.contains(binding)).
-+        }
-+        char basicType = types.charAt(i);
-         Class<?> paramCls = Wrapper.forBasicType(basicType).primitiveType();
-         MethodHandle bmhGetter;
-         try {
-@@ -201,16 +195,16 @@
+-        Class<?> paramCls = Wrapper.forBasicType(basicType).primitiveType();
+-        MethodHandle bmhGetter;
+-        try {
+-            bmhGetter = Lookup.IMPL_LOOKUP.findVirtual(BoundMethodHandle.class, "arg" + basicType, methodType(paramCls, int.class));
+-        } catch (IllegalAccessException | NoSuchMethodException e) {
+-            throw new InternalError(e);
+-        }
+-
+-        Name getterName = new Name(bmhGetter, mhName, i);
+-        return getterName;
+-    }
++    protected abstract Data myData();
  
      @Override
      final Object internalValues() {
 -        Object[] boundValues = new Object[types().length()];
-+        Object[] boundValues = new Object[myTypes().length()];
++        Object[] boundValues = new Object[myData().fieldCount()];
          for (int i = 0; i < boundValues.length; ++i) {
-             try {
+-            try {
 -                switch (types().charAt(i)) {
-+                switch (myTypes().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;
+-                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));
-+                default : throw new InternalError("unexpected type: " + myTypes().charAt(i));
-                 }
-             } catch (Throwable t) {
-                 throw new InternalError(t);
-@@ -236,12 +230,14 @@
+-                }
+-            } catch (Throwable t) {
+-                throw new InternalError(t);
+-            }
++            boundValues[i] = arg(i);
+         }
+         return Arrays.asList(boundValues);
+     }
+ 
++    public final Object arg(int i) {
++        try {
++            switch (myData().fieldType(i)) {
++            case 'L': return argL(i);
++            case 'I': return argI(i);
++            case 'F': return argF(i);
++            case 'D': return argD(i);
++            case 'J': return argJ(i);
++            }
++        } catch (Throwable ex) {
++            throw new InternalError(ex);
++        }
++        throw new InternalError("unexpected type: " + myData().types+"."+i);
++    }
+     public final Object argL(int i) throws Throwable { return          myData().getters[i].invokeBasic(this); }
+     public final int    argI(int i) throws Throwable { return (int)    myData().getters[i].invokeBasic(this); }
+     public final float  argF(int i) throws Throwable { return (float)  myData().getters[i].invokeBasic(this); }
+@@ -236,54 +196,60 @@
      public abstract BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float  narg) throws Throwable;
      public abstract BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable;
  
-+    /*
-     //
-     // getters to close bootstrap loops
-     //
- 
-     public long   argJ0() throws Throwable { return argJ(0); }
-     public Object argL1() throws Throwable { return argL(1); }
-+    */
+-    //
+-    // getters to close bootstrap loops
+-    //
+-
+-    public long   argJ0() throws Throwable { return argJ(0); }
+-    public Object argL1() throws Throwable { return argL(1); }
++    // The following is a grossly irregular hack:
++    @Override MethodHandle reinvokerTarget() {
++        try {
++            return (MethodHandle) argL(0);
++        } catch (Throwable ex) {
++            throw new InternalError(ex);
++        }
++    }
  
      //
      // concrete BMH classes required to close bootstrap loops
-@@ -254,10 +250,15 @@
+     //
+ 
++    private  // make it private to force users to access the enclosing class first
+     static final class BMH_L extends BoundMethodHandle {
+         final Object argL0;
+         public BMH_L(MethodType mt, LambdaForm lf, Object argL0) {
+             super(mt, lf);
              this.argL0 = argL0;
          }
++        // The following is a grossly irregular hack:
++        @Override MethodHandle reinvokerTarget() { return (MethodHandle) argL0; }
          @Override
 -        public String types() {
 -            return types;
-+        public String myTypes() {
-+            return TYPES;
++        public Data myData() {
++            return DATA;
          }
 -        public static final String types = "L";
-+        public static final String TYPES = "L";
-+        @Override
-+        public Data myData() {
-+            return DATA;
-+        }
-+        public static final Data DATA = Data.getForClass(TYPES, BMH_L.class);
++        public static final Data DATA = Data.getForClass("L", BMH_L.class);
          @Override
          public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
              return new BMH_L(mt, lf, argL0);
-@@ -268,19 +269,19 @@
+         }
+         @Override
+         public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
+-            return new BMH_LL(mt, lf, argL0, narg);
++            return (BoundMethodHandle) DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, narg);
          }
          @Override
          public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
 -            return (BoundMethodHandle) Data.get("LI").constructor.invokeBasic(mt, lf, argL0, narg);
-+            return (BoundMethodHandle) Data.get("LI").constructor[0].invokeBasic(mt, lf, argL0, narg);
++            return (BoundMethodHandle) DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, narg);
          }
          @Override
          public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
 -            return (BoundMethodHandle) Data.get("LJ").constructor.invokeBasic(mt, lf, argL0, narg);
-+            return (BoundMethodHandle) Data.get("LJ").constructor[0].invokeBasic(mt, lf, argL0, narg);
++            return (BoundMethodHandle) DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, narg);
          }
          @Override
          public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
 -            return (BoundMethodHandle) Data.get("LF").constructor.invokeBasic(mt, lf, argL0, narg);
-+            return (BoundMethodHandle) Data.get("LF").constructor[0].invokeBasic(mt, lf, argL0, narg);
++            return (BoundMethodHandle) DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, narg);
          }
          @Override
          public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
 -            return (BoundMethodHandle) Data.get("LD").constructor.invokeBasic(mt, lf, argL0, narg);
-+            return (BoundMethodHandle) Data.get("LD").constructor[0].invokeBasic(mt, lf, argL0, narg);
++            return (BoundMethodHandle) DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, narg);
          }
      }
  
-@@ -293,36 +294,41 @@
++/*
+     static final class BMH_LL extends BoundMethodHandle {
+         final Object argL0;
+         final Object argL1;
+@@ -293,33 +259,33 @@
              this.argL1 = argL1;
          }
          @Override
 -        public String types() {
 -            return types;
-+        public String myTypes() {
-+            return TYPES;
++        public Data myData() {
++            return DATA;
          }
 -        public static final String types = "LL";
-+        public static final String TYPES = "LL";
-+        @Override
-+        public Data myData() {
-+            return DATA;
-+        }
-+        public static final Data DATA = Data.getForClass(TYPES, BMH_LL.class);
++        public static final Data DATA = Data.getForClass("LL", BMH_LL.class);
          @Override
          public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
              return new BMH_LL(mt, lf, argL0, argL1);
@@ -239,143 +289,155 @@
          @Override
          public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
 -            return (BoundMethodHandle) Data.get("LLL").constructor.invokeBasic(mt, lf, argL0, argL1, narg);
-+            return (BoundMethodHandle) Data.get("LLL").constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
++            return (BoundMethodHandle) DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
          }
          @Override
          public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
 -            return (BoundMethodHandle) Data.get("LLI").constructor.invokeBasic(mt, lf, argL0, argL1, narg);
-+            return (BoundMethodHandle) Data.get("LLI").constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
++            return (BoundMethodHandle) DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
          }
          @Override
          public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
 -            return (BoundMethodHandle) Data.get("LLJ").constructor.invokeBasic(mt, lf, argL0, argL1, narg);
-+            return (BoundMethodHandle) Data.get("LLJ").constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
++            return (BoundMethodHandle) DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
          }
          @Override
          public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
 -            return (BoundMethodHandle) Data.get("LLF").constructor.invokeBasic(mt, lf, argL0, argL1, narg);
-+            return (BoundMethodHandle) Data.get("LLF").constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
++            return (BoundMethodHandle) DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
          }
          @Override
          public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
 -            return (BoundMethodHandle) Data.get("LLD").constructor.invokeBasic(mt, lf, argL0, argL1, narg);
-+            return (BoundMethodHandle) Data.get("LLD").constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
++            return (BoundMethodHandle) DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
          }
      }
--
-+    /*
-     static final class BMH_JL extends BoundMethodHandle {
-         final long argJ0;
-         final Object argL1;
-@@ -332,10 +338,15 @@
+ 
+@@ -332,10 +298,10 @@
              this.argL1 = argL1;
          }
          @Override
 -        public String types() {
 -            return types;
-+        public String myTypes() {
-+            return TYPES;
++        public Data myData() {
++            return DATA;
          }
 -        public static final String types = "JL";
-+        public static final String TYPES = "JL";
-+        @Override
-+        public Data myData() {
-+            return DATA;
-+        }
-+        public static final Data DATA = Data.getForClass(TYPES, BMH_JL.class);
++        public static final Data DATA = Data.getForClass("JL", BMH_JL.class);
          @Override public final long   argJ0() { return argJ0; }
          @Override public final Object argL1() { return argL1; }
          @Override
-@@ -344,23 +355,23 @@
+@@ -344,103 +310,26 @@
          }
          @Override
          public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
 -            return (BoundMethodHandle) Data.get("JLL").constructor.invokeBasic(mt, lf, argJ0, argL1, narg);
-+            return (BoundMethodHandle) Data.get("JLL").constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
++            return (BoundMethodHandle) DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
          }
          @Override
          public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
 -            return (BoundMethodHandle) Data.get("JLI").constructor.invokeBasic(mt, lf, argJ0, argL1, narg);
-+            return (BoundMethodHandle) Data.get("JLI").constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
++            return (BoundMethodHandle) DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
          }
          @Override
          public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
 -            return (BoundMethodHandle) Data.get("JLJ").constructor.invokeBasic(mt, lf, argJ0, argL1, narg);
-+            return (BoundMethodHandle) Data.get("JLJ").constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
++            return (BoundMethodHandle) DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
          }
          @Override
          public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
 -            return (BoundMethodHandle) Data.get("JLF").constructor.invokeBasic(mt, lf, argJ0, argL1, narg);
-+            return (BoundMethodHandle) Data.get("JLF").constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
++            return (BoundMethodHandle) DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
          }
          @Override
          public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
 -            return (BoundMethodHandle) Data.get("JLD").constructor.invokeBasic(mt, lf, argJ0, argL1, narg);
-+            return (BoundMethodHandle) Data.get("JLD").constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
++            return (BoundMethodHandle) DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
          }
      }
- 
-@@ -371,10 +382,15 @@
-             this.argJ0 = argJ0;
-         }
-         @Override
+-
+-    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 String myTypes() {
-+            return TYPES;
-         }
+-        }
 -        public static final String types = "J";
-+        public static final String TYPES = "J";
-+        @Override
-+        public Data myData() {
-+            return DATA;
-+        }
-+        public static final Data DATA = Data.getForClass(TYPES, BMH_J.class);
-         @Override public final long argJ0() { return argJ0; }
-         @Override
-         public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
-@@ -386,19 +402,19 @@
-         }
-         @Override
-         public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
+-        @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);
-+            return (BoundMethodHandle) Data.get("JI").constructor[0].invokeBasic(mt, lf, argJ0, narg);
-         }
-         @Override
-         public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
+-        }
+-        @Override
+-        public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
 -            return (BoundMethodHandle) Data.get("JJ").constructor.invokeBasic(mt, lf, argJ0, narg);
-+            return (BoundMethodHandle) Data.get("JJ").constructor[0].invokeBasic(mt, lf, argJ0, narg);
-         }
-         @Override
-         public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
+-        }
+-        @Override
+-        public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
 -            return (BoundMethodHandle) Data.get("JF").constructor.invokeBasic(mt, lf, argJ0, narg);
-+            return (BoundMethodHandle) Data.get("JF").constructor[0].invokeBasic(mt, lf, argJ0, narg);
-         }
-         @Override
-         public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
+-        }
+-        @Override
+-        public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
 -            return (BoundMethodHandle) Data.get("JD").constructor.invokeBasic(mt, lf, argJ0, narg);
-+            return (BoundMethodHandle) Data.get("JD").constructor[0].invokeBasic(mt, lf, argJ0, narg);
-         }
-     }
- 
-@@ -415,6 +431,7 @@
-             throw new InternalError(e);
-         }
-     }
-+    */
+-        }
+-    }
+-
+-    public static final MethodHandle MH_argJ0;
+-    public static final MethodHandle MH_argL1;
+-
+-    static {
+-        final Lookup LOOKUP = Lookup.IMPL_LOOKUP;
+-        final Class<?> BMH = BoundMethodHandle.class;
+-        try {
+-            MH_argJ0 = LOOKUP.findVirtual(BMH, "argJ0", MethodType.methodType(long.class));
+-            MH_argL1 = LOOKUP.findVirtual(BMH, "argL1", MethodType.methodType(Object.class));
+-        } catch (NoSuchMethodException | IllegalAccessException e) {
+-            throw new InternalError(e);
+-        }
+-    }
+-
+-    //
+-    // reinvocation
+-    //
+-
+-    /** Create a LF which simply reinvokes a target of the given basic type.
+-     *  The target MH must have the reinvocation target bound to value #0.
+-     */
+-    static LambdaForm reinvokerForm(MethodType mtype) {
+-        mtype = mtype.basicType();
+-        LambdaForm reinvoker = mtype.form().cachedLambdaForm(MethodTypeForm.LF_REINVOKE);
+-        if (reinvoker != null)  return reinvoker;
+-        MethodHandle MH_invokeBasic = MethodHandles.basicInvoker(mtype);
+-        final int THIS_BMH    = 0;
+-        final int ARG_BASE    = 1;
+-        final int ARG_LIMIT   = ARG_BASE + mtype.parameterCount();
+-        int nameCursor = ARG_LIMIT;
+-        final int NEXT_MH     = nameCursor++;
+-        final int REINVOKE    = nameCursor++;
+-        Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
+-        names[NEXT_MH] = getterName(names[THIS_BMH], 'L', 0);
+-        Object[] targetArgs = Arrays.copyOfRange(names, THIS_BMH, ARG_LIMIT, Object[].class);
+-        targetArgs[0] = names[NEXT_MH];  // overwrite this MH with next MH
+-        names[REINVOKE] = new Name(MH_invokeBasic, targetArgs);
+-        return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_REINVOKE, new LambdaForm("BMH.reinvoke", ARG_LIMIT, names));
+-    }
++*/
  
      //
-     // reinvocation
-@@ -435,7 +452,7 @@
-         final int NEXT_MH     = nameCursor++;
-         final int REINVOKE    = nameCursor++;
-         Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
--        names[NEXT_MH] = getterName(names[THIS_BMH], 'L', 0);
-+        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);
-@@ -452,37 +469,80 @@
+     // BMH meta-data
+@@ -452,60 +341,157 @@
      static class Data {
          final String                             types;
          final Class<? extends BoundMethodHandle> clazz;
@@ -384,8 +446,33 @@
 +        // Therefore, we need a non-final link in the chain.  Use array elements.
 +        final MethodHandle[]                     constructor;
          final MethodHandle[]                     getters;
++        final Data[]                             extensions;
  
 -        Data(String types, Class<? extends BoundMethodHandle> clazz, MethodHandle constructor, MethodHandle[] getters) {
++        public int fieldCount() {
++            return types.length();
++        }
++        public char fieldType(int i) {
++            return types.charAt(i);
++        }
++
++        public String toString() {
++            return "Data["+(isPlaceholder() ? "<placeholder>" : clazz.getSimpleName())+":"+types+"]";
++        }
++
++        /**
++         * Return a {@link LambdaForm.Name} containing a {@link LambdaForm.NamedFunction} that
++         * represents a MH bound to a generic invoker, which in turn forwards to the corresponding
++         * getter.
++         */
++        Name getterName(Name mhName, int i) {
++            MethodHandle mh = getters[i];
++            assert(mh != null) : this+"."+i;
++            return new Name(mh, mhName);
++        }
++
++        static final Data EMPTY = new Data("", BoundMethodHandle.class);
++
 +        private Data(String types, Class<? extends BoundMethodHandle> clazz) {
              this.types = types;
              this.clazz = clazz;
@@ -398,6 +485,7 @@
 +                this.constructor = Factory.makeCtors(clazz, types, null);
 +                this.getters = Factory.makeGetters(clazz, types, null);
 +            }
++            this.extensions = new Data[EXTENSION_TYPES.length()];
          }
  
 -        static Map<String, Data> CACHE = new IdentityHashMap<>();
@@ -415,19 +503,7 @@
 +            }
          }
  
-+        private Data(String types) {
-+            // Placeholder only.
-+            this.types = types;
-+            this.clazz = null;
-+            this.constructor = null;
-+            this.getters = null;
-+        }
-+        private boolean isPlaceholder() { return clazz == null; }
-+
-+        private static final Map<String, Data> CACHE = new IdentityHashMap<>();
-+        private static final boolean INIT_DONE;  // set after <clinit> finishes...
-+
-         static Data get(String types) {
+-        static Data get(String types) {
 -            final String key = types.intern();
 -            Data d = CACHE.get(key);
 -            if (d == null) {
@@ -438,6 +514,35 @@
 -                } else {
 -                    CACHE.put(key, d);
 -                }
++        private Data(String types) {
++            // Placeholder only.
++            this.types = types;
++            this.clazz = null;
++            this.constructor = null;
++            this.getters = null;
++            this.extensions = null;
++        }
++        private boolean isPlaceholder() { return clazz == null; }
++
++        private static final Map<String, Data> CACHE = new IdentityHashMap<>();
++        private static final boolean INIT_DONE;  // set after <clinit> finishes...
++
++        Data extendWithType(char type) {
++            int i = extensionIndex(type);
++            Data d = extensions[i];
++            if (d != null)  return d;
++            extensions[i] = d = get((types+type).intern());
++            return d;
++        }
++
++        Data extendWithIndex(byte index) {
++            Data d = extensions[index];
++            if (d != null)  return d;
++            extensions[index] = d = get(types+EXTENSION_TYPES.charAt(index));
++            return d;
++        }
++
++        private static Data get(String types) {
 +            // Acquire cache lock for query.
 +            Data d = accessCache(types, null);
 +            if (!d.isPlaceholder())
@@ -477,35 +582,50 @@
              return d;
          }
  
-@@ -494,16 +554,23 @@
-                     if (BMH.isAssignableFrom(c)) {
+         static {
+             // pre-fill the BMH data cache with BMH's inner classes
+-            final Class<BoundMethodHandle> BMH = BoundMethodHandle.class;
++            final Class<BoundMethodHandle> rootCls = BoundMethodHandle.class;
++            Data d0 = BoundMethodHandle.DATA;  // trigger class init
++            assert(d0 == null || d0 == accessCache("", null)) : d0;
+             try {
+-                for (Class<?> c : BMH.getDeclaredClasses()) {
+-                    if (BMH.isAssignableFrom(c)) {
++                for (Class<?> c : rootCls.getDeclaredClasses()) {
++                    if (rootCls.isAssignableFrom(c)) {
                          final Class<? extends BoundMethodHandle> cbmh = c.asSubclass(BoundMethodHandle.class);
-                         final String types = Factory.typesFromConcreteBMHClass(cbmh);
+-                        final String types = Factory.typesFromConcreteBMHClass(cbmh);
 -                        final MethodHandle ctor = Factory.makeCbmhCtor(cbmh, types);
 -                        final MethodHandle[] getters = Factory.makeGetters(cbmh, types);
 -                        final Data d = new Data(types, cbmh, ctor, getters);
 -                        CACHE.put(types.intern(), d);
-+                        Data d;
-+                        assert((d = accessCache(types, null)) != null && d.clazz == cbmh);
++                        Data d = Factory.dataFromConcreteBMHClass(cbmh);
++                        assert(d != null) : cbmh.getName();
++                        assert(d.clazz == cbmh);
++                        assert(d == accessCache(d.types, null));
                      }
                  }
              } catch (Throwable e) {
                  throw new InternalError(e);
              }
-         }
 +
-+        static {
 +            for (Data d : CACHE.values()) {
 +                d.initForBootstrap();
 +            }
 +            // Note:  Do not simplify this, because INIT_DONE must not be
 +            // a compile-time constant during bootstrapping.
 +            INIT_DONE = Boolean.TRUE;
-+        }
+         }
      }
  
++    static Data getData(String types) {
++        return Data.get(types);
++    }
++
      /**
-@@ -520,18 +587,21 @@
+      * Generation of concrete BMH classes.
+      *
+@@ -520,18 +506,20 @@
       */
      static class Factory {
  
@@ -528,15 +648,14 @@
  
 -        static final String BMHDATA_GET_SIG = "(" + JLS_SIG + ")" + DATA_SIG;
 -        static final String TYPES_SIG = "()" + JLS_SIG;
-+        static final String BMHDATA_GET_SIG  = "(" + JLS_SIG           + ")" + DATA_SIG;
-+        static final String BMHDATA_GET2_SIG = "(" + JLS_SIG + JLC_SIG + ")" + DATA_SIG;
-+        static final String TYPES_SIG  = "()" + JLS_SIG;
++        static final String BMHDATA_EWI_SIG = "(B)" + DATA_SIG;
++        static final String BMHDATA_GFC_SIG = "(" + JLS_SIG + JLC_SIG + ")" + DATA_SIG;
          static final String MYDATA_SIG = "()" + DATA_SIG;
 +        static final String VOID_SIG   = "()V";
  
          static final String SIG_INCIPIT = "(Ljava/lang/invoke/MethodType;Ljava/lang/invoke/LambdaForm;";
  
-@@ -547,7 +617,7 @@
+@@ -547,7 +535,7 @@
           * <pre>
           * class BMH_<<types>> extends BMH {
           *     <<fields>>
@@ -545,7 +664,7 @@
           * }
           * </pre>
           *
-@@ -572,25 +642,27 @@
+@@ -572,25 +560,27 @@
           *         this.argL1 = argL1;
           *         this.argI2 = argI2;
           *     }
@@ -581,7 +700,7 @@
           *     }
           * }
           * </pre>
-@@ -601,14 +673,14 @@
+@@ -601,14 +591,13 @@
          static Class<? extends BoundMethodHandle> generateConcreteBMHClass(String types) {
              final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
  
@@ -595,33 +714,25 @@
 -            // emit static types field
 -            cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "types", JLS_SIG, null, types).visitEnd();
 +            // emit static types and data fields
-+            cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "TYPES", JLS_SIG, null, types).visitEnd();
 +            cw.visitField(ACC_PUBLIC + ACC_STATIC, "DATA", DATA_SIG, null, null).visitEnd();
  
              // emit bound argument fields
              for (int i = 0; i < types.length(); ++i) {
-@@ -644,22 +716,32 @@
+@@ -644,10 +633,10 @@
              mv.visitMaxs(0, 0);
              mv.visitEnd();
  
 -            // emit implementation of types()
 -            mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "types", TYPES_SIG, null, null);
-+            // emit implementation of myTypes()
-+            mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "myTypes", TYPES_SIG, null, null);
++            // emit implementation of myData()
++            mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "myData", MYDATA_SIG, null, null);
              mv.visitCode();
-             mv.visitLdcInsn(types);
+-            mv.visitLdcInsn(types);
++            mv.visitFieldInsn(GETSTATIC, className, "DATA", DATA_SIG);
              mv.visitInsn(ARETURN);
              mv.visitMaxs(0, 0);
              mv.visitEnd();
- 
-+            // emit implementation of myData()
-+            mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "myData", MYDATA_SIG, null, null);
-+            mv.visitCode();
-+            mv.visitFieldInsn(GETSTATIC, className, "DATA", DATA_SIG);
-+            mv.visitInsn(ARETURN);
-+            mv.visitMaxs(0, 0);
-+            mv.visitEnd();
-+
+@@ -655,11 +644,13 @@
              // emit clone()
              mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "clone", makeSignature("", false), null, E_THROWABLE);
              mv.visitCode();
@@ -638,23 +749,38 @@
              // load mt, lf
              mv.visitVarInsn(ALOAD, 1);
              mv.visitVarInsn(ALOAD, 2);
-@@ -677,11 +759,13 @@
-                 String extypes = types + t;
+@@ -674,14 +665,18 @@
+             // for each type, emit cloneExtendT()
+             for (Class<?> c : TYPES) {
+                 char t = Wrapper.basicTypeChar(c);
+-                String extypes = types + t;
                  mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "cloneExtend" + t, makeSignature(String.valueOf(t), false), null, E_THROWABLE);
                  mv.visitCode();
 -                // return BMHData.get(<extypes>).constructor.invokeBasic(mt, lf, argL0, ..., narg)
-+                // return BMHData.get(<extypes>).constructor[0].invokeBasic(mt, lf, argL0, ..., narg)
++                // return DATA.extendWithIndex(extensionIndex(t)).constructor[0].invokeBasic(mt, lf, argL0, ..., narg)
                  // obtain constructor
-                 mv.visitLdcInsn(extypes);
-                 mv.visitMethodInsn(INVOKESTATIC, DATA, "get", BMHDATA_GET_SIG);
+-                mv.visitLdcInsn(extypes);
+-                mv.visitMethodInsn(INVOKESTATIC, DATA, "get", BMHDATA_GET_SIG);
 -                mv.visitFieldInsn(GETFIELD, DATA, "constructor", MH_SIG);
++                mv.visitFieldInsn(GETSTATIC, className, "DATA", DATA_SIG);
++                int iconstInsn = ICONST_0 + extensionIndex(t);
++                assert(iconstInsn <= ICONST_5);
++                mv.visitInsn(iconstInsn);
++                mv.visitMethodInsn(INVOKEVIRTUAL, DATA, "extendWithIndex", BMHDATA_EWI_SIG);
 +                mv.visitFieldInsn(GETFIELD, DATA, "constructor", "[" + MH_SIG);
 +                mv.visitInsn(ICONST_0);
 +                mv.visitInsn(AALOAD);
                  // load mt, lf
                  mv.visitVarInsn(ALOAD, 1);
                  mv.visitVarInsn(ALOAD, 2);
-@@ -696,13 +780,25 @@
+@@ -690,19 +685,31 @@
+                 // put narg on stack
+                 mv.visitVarInsn(typeLoadOp(t), 3);
+                 // finally, invoke the constructor and return
+-                mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(extypes, false));
++                mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types + t, false));
+                 mv.visitInsn(ARETURN);
+                 mv.visitMaxs(0, 0);
                  mv.visitEnd();
              }
  
@@ -663,7 +789,7 @@
 +            mv.visitCode();
 +            mv.visitLdcInsn(types);
 +            mv.visitLdcInsn(Type.getObjectType(className));
-+            mv.visitMethodInsn(INVOKESTATIC, DATA, "getForClass", BMHDATA_GET2_SIG);
++            mv.visitMethodInsn(INVOKESTATIC, DATA, "getForClass", BMHDATA_GFC_SIG);
 +            mv.visitFieldInsn(PUTSTATIC, className, "DATA", DATA_SIG);
 +            mv.visitInsn(RETURN);
 +            mv.visitMaxs(0, 0);
@@ -681,7 +807,7 @@
              UNSAFE.ensureClassInitialized(bmhClass);
  
              return bmhClass;
-@@ -745,21 +841,27 @@
+@@ -745,24 +752,31 @@
              }
          }
  
@@ -691,6 +817,7 @@
 +            if (mhs == null)  mhs = new MethodHandle[types.length()];
              for (int i = 0; i < mhs.length; ++i) {
                  mhs[i] = makeGetter(cbmhClass, types, i);
++                assert(mhs[i].internalMemberName().getDeclaringClass() == cbmhClass);
              }
              return mhs;
          }
@@ -705,14 +832,21 @@
          // Auxiliary methods.
          //
  
-         static String typesFromConcreteBMHClass(Class<? extends BoundMethodHandle> cbmh) {
+-        static String typesFromConcreteBMHClass(Class<? extends BoundMethodHandle> cbmh) {
++        static Data dataFromConcreteBMHClass(Class<? extends BoundMethodHandle> cbmh) {
              try {
 -                Field ftypes = cbmh.getDeclaredField("types");
-+                Field ftypes = cbmh.getDeclaredField("TYPES");
-                 return (String) ftypes.get(null);
-             } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
-                 throw new InternalError(e);
-@@ -832,13 +934,15 @@
+-                return (String) ftypes.get(null);
+-            } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
+-                throw new InternalError(e);
++                Field fdata = cbmh.getDeclaredField("DATA");
++                return (Data) fdata.get(null);
++            } catch (Throwable ex) {
++                throw new InternalError(ex);
+             }
+         }
+ 
+@@ -832,13 +846,12 @@
              return cmh;
          }
  
@@ -721,64 +855,195 @@
 -        //
 -
 -        private static final Lookup LOOKUP = Lookup.IMPL_LOOKUP;
-         private static final Unsafe UNSAFE = Unsafe.getUnsafe();
- 
+-        private static final Unsafe UNSAFE = Unsafe.getUnsafe();
+-
      }
  
 +    private static final Lookup LOOKUP = Lookup.IMPL_LOOKUP;
 +
-+    static {
-+        // force initialisation
-+        Data.get("L");
-+    }
-+
++    /**
++     * All subclasses must provide such a value describing their type signature.
++     */
++    static final Data DATA = Data.EMPTY;
  }
-diff --git a/src/share/classes/java/lang/invoke/CountingMethodHandle.java b/src/share/classes/java/lang/invoke/CountingMethodHandle.java
---- a/src/share/classes/java/lang/invoke/CountingMethodHandle.java
-+++ b/src/share/classes/java/lang/invoke/CountingMethodHandle.java
-@@ -25,6 +25,7 @@
- 
+diff --git a/src/share/classes/java/lang/invoke/CallSite.java b/src/share/classes/java/lang/invoke/CallSite.java
+--- a/src/share/classes/java/lang/invoke/CallSite.java
++++ b/src/share/classes/java/lang/invoke/CallSite.java
+@@ -26,7 +26,7 @@
  package java.lang.invoke;
  
-+import java.lang.invoke.BoundMethodHandle.Data;
- import java.util.Arrays;
- import static java.lang.invoke.LambdaForm.*;
- import static java.lang.invoke.MethodHandles.*;
-@@ -54,11 +55,14 @@
+ import sun.invoke.empty.Empty;
+-import sun.misc.Unsafe;
++import static java.lang.invoke.MethodHandleStatics.*;
+ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
+ 
+ /**
+@@ -233,12 +233,10 @@
      }
  
-     @Override
+     // unsafe stuff:
+-    private static final Unsafe unsafe = Unsafe.getUnsafe();
+     private static final long TARGET_OFFSET;
+-
+     static {
+         try {
+-            TARGET_OFFSET = unsafe.objectFieldOffset(CallSite.class.getDeclaredField("target"));
++            TARGET_OFFSET = UNSAFE.objectFieldOffset(CallSite.class.getDeclaredField("target"));
+         } catch (Exception ex) { throw new Error(ex); }
+     }
+ 
+@@ -248,7 +246,7 @@
+     }
+     /*package-private*/
+     MethodHandle getTargetVolatile() {
+-        return (MethodHandle) unsafe.getObjectVolatile(this, TARGET_OFFSET);
++        return (MethodHandle) UNSAFE.getObjectVolatile(this, TARGET_OFFSET);
+     }
+     /*package-private*/
+     void setTargetVolatile(MethodHandle newTarget) {
+diff --git a/src/share/classes/java/lang/invoke/CountingMethodHandle.java b/src/share/classes/java/lang/invoke/CountingMethodHandle.java
+deleted file mode 100644
+--- a/src/share/classes/java/lang/invoke/CountingMethodHandle.java
++++ /dev/null
+@@ -1,129 +0,0 @@
+-/*
+- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+- *
+- * This code is free software; you can redistribute it and/or modify it
+- * under the terms of the GNU General Public License version 2 only, as
+- * published by the Free Software Foundation.  Oracle designates this
+- * particular file as subject to the "Classpath" exception as provided
+- * by Oracle in the LICENSE file that accompanied this code.
+- *
+- * This code is distributed in the hope that it will be useful, but WITHOUT
+- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+- * version 2 for more details (a copy is included in the LICENSE file that
+- * accompanied this code).
+- *
+- * You should have received a copy of the GNU General Public License version
+- * 2 along with this work; if not, write to the Free Software Foundation,
+- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+- *
+- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+- * or visit www.oracle.com if you need additional information or have any
+- * questions.
+- */
+-
+-package java.lang.invoke;
+-
+-import java.util.Arrays;
+-import static java.lang.invoke.LambdaForm.*;
+-import static java.lang.invoke.MethodHandles.*;
+-import static java.lang.invoke.MethodType.*;
+-
+-/**
+- * This method handle is used to optionally provide a count of how
+- * many times it was invoked.
+- *
+- * @author never
+- */
+-class CountingMethodHandle extends BoundMethodHandle {
+-    private MethodHandle target;
+-    private int vmcount;
+-
+-    private CountingMethodHandle(MethodHandle target) {
+-        super(target.type(), countingReinvokerForm(target.type().basicType()));
+-        this.target = target;
+-    }
+-
+-    /** Wrap the incoming MethodHandle in a CountingMethodHandle if they are enabled */
+-    static MethodHandle wrap(MethodHandle mh) {
+-        if (MethodHandleNatives.COUNT_GWT) {
+-             return new CountingMethodHandle(mh);
+-        }
+-        return mh;
+-    }
+-
+-    @Override
 -    public String types() {
 -        return types;
-+    public String myTypes() {
-+        return BoundMethodHandle.BMH_L.TYPES; // same types signature
-     }
- 
+-    }
+-
 -    public static final String types = "L";
-+    @Override
-+    public Data myData() {
-+        return BoundMethodHandle.BMH_L.DATA; // same types signature
-+    }
- 
-     @ForceInline
-     void vmcountBump() {
-@@ -80,7 +84,7 @@
-         final int REINVOKE    = nameCursor++;
-         Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
-         names[BUMP_COUNT] = new Name(CountingMethodHandle.NF_vmcountBump, names[THIS_CMH]);
+-
+-    @ForceInline
+-    void vmcountBump() {
+-        vmcount += 1;
+-    }
+-
+-    /** Create a LF which reinvokes a target of the given basic type, and also bumps CountingMethodHandle.vmcount. */
+-    private static LambdaForm countingReinvokerForm(MethodType mtype) {
+-        assert(mtype == mtype.basicType());  // caller resp
+-        LambdaForm reinvoker = mtype.form().cachedLambdaForm(MethodTypeForm.LF_COUNTER);
+-        if (reinvoker != null)  return reinvoker;
+-        MethodHandle MH_invokeBasic = MethodHandles.basicInvoker(mtype);
+-        final int THIS_CMH    = 0;
+-        final int ARG_BASE    = 1;
+-        final int ARG_LIMIT   = ARG_BASE + mtype.parameterCount();
+-        int nameCursor = ARG_LIMIT;
+-        final int BUMP_COUNT  = nameCursor++;
+-        final int NEXT_MH     = nameCursor++;
+-        final int REINVOKE    = nameCursor++;
+-        Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
+-        names[BUMP_COUNT] = new Name(CountingMethodHandle.NF_vmcountBump, names[THIS_CMH]);
 -        names[NEXT_MH] = BoundMethodHandle.getterName(names[THIS_CMH], 'L', 0);
-+        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);
+-        Object[] targetArgs = Arrays.copyOfRange(names, THIS_CMH, ARG_LIMIT, Object[].class);
+-        targetArgs[0] = names[NEXT_MH];  // overwrite CMH with next MH
+-        names[REINVOKE] = new Name(MH_invokeBasic, targetArgs);
+-        return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_COUNTER, new LambdaForm("CMH.reinvoke", ARG_LIMIT, names));
+-    }
+-
+-    static final NamedFunction NF_vmcountBump;
+-    static {
+-        try {
+-            NF_vmcountBump = new NamedFunction(Lookup.IMPL_LOOKUP
+-                    .findVirtual(CountingMethodHandle.class, "vmcountBump", methodType(void.class)));
+-        } catch (ReflectiveOperationException ex) {
+-            throw new InternalError(ex);
+-        }
+-    }
+-
+-    @Override
+-    public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
+-        throw new IllegalStateException("NYI");
+-    }
+-
+-    @Override
+-    public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
+-        throw new IllegalStateException("NYI");
+-    }
+-
+-    @Override
+-    public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
+-        throw new IllegalStateException("NYI");
+-    }
+-
+-    @Override
+-    public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
+-        throw new IllegalStateException("NYI");
+-    }
+-
+-    @Override
+-    public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
+-        throw new IllegalStateException("NYI");
+-    }
+-
+-    @Override
+-    public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
+-        throw new IllegalStateException("NYI");
+-    }
+-}
 diff --git a/src/share/classes/java/lang/invoke/DirectMethodHandle.java b/src/share/classes/java/lang/invoke/DirectMethodHandle.java
 --- a/src/share/classes/java/lang/invoke/DirectMethodHandle.java
 +++ b/src/share/classes/java/lang/invoke/DirectMethodHandle.java
-@@ -31,11 +31,16 @@
+@@ -31,20 +31,25 @@
  import sun.invoke.util.VerifyAccess;
  import static java.lang.invoke.MethodHandleNatives.Constants.*;
  import static java.lang.invoke.LambdaForm.*;
 +import static java.lang.invoke.MethodTypeForm.*;
++import static java.lang.invoke.MethodHandleStatics.*;
  import java.lang.ref.WeakReference;
 +import java.lang.reflect.Field;
  import sun.invoke.util.ValueConversions;
@@ -792,54 +1057,83 @@
   * @author jrose
   */
  class DirectMethodHandle extends MethodHandle {
-@@ -44,7 +49,6 @@
+     final MemberName member;
+ 
      // Constructors and factory methods in this class *must* be package scoped or private.
-     private DirectMethodHandle(MethodType mtype, MemberName member, LambdaForm form) {
+-    private DirectMethodHandle(MethodType mtype, MemberName member, LambdaForm form) {
++    private DirectMethodHandle(MethodType mtype, LambdaForm form, MemberName member) {
          super(mtype, form);
 -        assert(member.isMethod() || member.isConstructor());
          if (!member.isResolved())  throw new InternalError();
          this.member = member;
      }
-@@ -52,13 +56,27 @@
+@@ -52,24 +57,52 @@
      // Factory methods:
  
      static DirectMethodHandle make(Class<?> receiver, MemberName member) {
 -        MethodType mtype = member.getMethodType();
 +        MethodType mtype = member.getMethodOrFieldType();
          if (!member.isStatic()) {
-             if (!member.getDeclaringClass().isAssignableFrom(receiver))
+-            if (!member.getDeclaringClass().isAssignableFrom(receiver))
++            if (!member.getDeclaringClass().isAssignableFrom(receiver) || member.isConstructor())
                  throw new InternalError(member.toString());
              mtype = mtype.insertParameterTypes(0, receiver);
          }
 -        return new DirectMethodHandle(mtype, member, preparedLambdaForm(mtype.basicType(), member));
 +        if (!member.isField()) {
 +            LambdaForm lform = preparedLambdaForm(member);
-+            return new DirectMethodHandle(mtype, member, lform);
++            return new DirectMethodHandle(mtype, lform, member);
 +        } else {
 +            LambdaForm lform = preparedFieldLambdaForm(member);
 +            if (member.isStatic()) {
 +                long offset = MethodHandleNatives.staticFieldOffset(member);
 +                Object base = MethodHandleNatives.staticFieldBase(member);
-+                return new StaticAccessor(mtype, member, lform, base, offset);
++                return new StaticAccessor(mtype, lform, member, base, offset);
 +            } else {
 +                long offset = MethodHandleNatives.objectFieldOffset(member);
 +                assert(offset == (int)offset);
-+                return new Accessor(mtype, member, lform, (int)offset);
++                return new Accessor(mtype, lform, member, (int)offset);
 +            }
 +        }
      }
      static DirectMethodHandle make(MemberName member) {
++        if (member.isConstructor())
++            return makeAllocator(member);
          return make(member.getDeclaringClass(), member);
-@@ -116,7 +134,7 @@
+     }
+     static DirectMethodHandle make(Method method) {
+         return make(method.getDeclaringClass(), new MemberName(method));
+     }
++    static DirectMethodHandle make(Field field) {
++        return make(field.getDeclaringClass(), new MemberName(field));
++    }
++    private static DirectMethodHandle makeAllocator(MemberName ctor) {
++        assert(ctor.isConstructor() && ctor.getName().equals("<init>"));
++        Class<?> instanceClass = ctor.getDeclaringClass();
++        ctor = ctor.asConstructor();
++        assert(ctor.isConstructor() && ctor.getReferenceKind() == REF_newInvokeSpecial) : ctor;
++        MethodType mtype = ctor.getMethodType().changeReturnType(instanceClass);
++        LambdaForm lform = preparedLambdaForm(ctor);
++        return new Constructor(mtype, lform, ctor, ctor.asSpecial(), instanceClass);
++    }
+ 
+     @Override
+     MethodHandle copyWith(MethodType mt, LambdaForm lf) {
+-        return new DirectMethodHandle(mt, member, lf);
++        return new DirectMethodHandle(mt, lf, member);
+     }
+ 
+     @Override
+@@ -116,7 +149,7 @@
                  MemberName concrete = new MemberName(concreteClass, member.getName(), member.getMethodType(), REF_invokeSpecial);
                  concrete = IMPL_NAMES.resolveOrNull(REF_invokeSpecial, concrete, concreteClass);
                  if (concrete != null)
 -                    return new DirectMethodHandle(type(), concrete, preparedLambdaForm(type().basicType(), concrete));
-+                    return new DirectMethodHandle(type(), concrete, preparedLambdaForm(concrete));
++                    return new DirectMethodHandle(type(), preparedLambdaForm(concrete), concrete);
                  break;
              }
          }
-@@ -128,49 +146,57 @@
+@@ -128,65 +161,115 @@
       * Cache and share this structure among all methods with
       * the same basicType and refKind.
       */
@@ -894,6 +1188,7 @@
 -    private static LambdaForm makePreparedLambdaForm(MethodType mtype, byte refKind, int which) {
 +    private static LambdaForm makePreparedLambdaForm(MethodType mtype, int which) {
 +        boolean needsInit = (which == LF_INVSTATIC_INIT);
++        boolean doesAlloc = (which == LF_NEWINVSPECIAL);
          String linkerName, lambdaName;
 -        switch (refKind) {
 -        case REF_invokeVirtual:    linkerName = "linkToVirtual";    lambdaName = "DMH.invokeVirtual";    break;
@@ -907,9 +1202,12 @@
 +        case LF_INVSTATIC_INIT:linkerName = "linkToStatic";     lambdaName = "DMH.invokeStaticInit"; break;
 +        case LF_INVSPECIAL:    linkerName = "linkToSpecial";    lambdaName = "DMH.invokeSpecial";    break;
 +        case LF_INVINTERFACE:  linkerName = "linkToInterface";  lambdaName = "DMH.invokeInterface";  break;
++        case LF_NEWINVSPECIAL: linkerName = "linkToSpecial";    lambdaName = "DMH.newInvokeSpecial"; break;
 +        default:  throw new InternalError("which="+which);
          }
          MethodType mtypeWithArg = mtype.appendParameterTypes(MemberName.class);
++        if (doesAlloc)
++            mtypeWithArg = mtypeWithArg.insertParameterTypes(0, Object.class);  // insert newly allocated obj
          MemberName linker = new MemberName(MethodHandle.class, linkerName, mtypeWithArg, REF_invokeStatic);
          try {
              linker = IMPL_NAMES.resolveOrFail(REF_invokeStatic, linker, null, NoSuchMethodException.class);
@@ -921,22 +1219,41 @@
          final int DMH_THIS    = 0;
          final int ARG_BASE    = 1;
          final int ARG_LIMIT   = ARG_BASE + mtype.parameterCount();
-@@ -179,16 +205,38 @@
+         int nameCursor = ARG_LIMIT;
++        final int NEW_OBJ     = (doesAlloc ? nameCursor++ : -1);
+         final int GET_MEMBER  = nameCursor++;
          final int LINKER_CALL = nameCursor++;
          Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
          assert(names.length == nameCursor);
 -        if (needEnsureInit)
-+        if (needsInit)
++        if (doesAlloc) {
++            // names = { argx,y,z,... new C, init method }
++            names[NEW_OBJ] = new Name(NF_allocateInstance, names[DMH_THIS]);
++            names[GET_MEMBER] = new Name(NF_constructorMethod, names[DMH_THIS]);
++        } else if (needsInit) {
              names[GET_MEMBER] = new Name(NF_internalMemberNameEnsureInit, names[DMH_THIS]);
-         else
+-        else
++        } else {
              names[GET_MEMBER] = new Name(NF_internalMemberName, names[DMH_THIS]);
++        }
          Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, GET_MEMBER+1, Object[].class);
          assert(outArgs[outArgs.length-1] == names[GET_MEMBER]);  // look, shifted args!
++        int result = LambdaForm.LAST_RESULT;
++        if (doesAlloc) {
++            assert(outArgs[outArgs.length-2] == names[NEW_OBJ]);  // got to move this one
++            System.arraycopy(outArgs, 0, outArgs, 1, outArgs.length-2);
++            outArgs[0] = names[NEW_OBJ];
++            result = NEW_OBJ;
++        }
          names[LINKER_CALL] = new Name(linker, outArgs);
+-        return new LambdaForm(lambdaName, ARG_LIMIT, names);
 +        lambdaName += "_" + LambdaForm.basicTypeSignature(mtype);
-         return new LambdaForm(lambdaName, ARG_LIMIT, names);
-     }
- 
++        LambdaForm lform = new LambdaForm(lambdaName, ARG_LIMIT, names, result);
++        // This is a tricky bit of code.  Don't send it through the LF interpreter.
++        lform.compileToBytecode();
++        return lform;
++    }
++
 +    private static void maybeCompile(LambdaForm lform, MemberName m) {
 +        if (VerifyAccess.isSamePackage(m.getDeclaringClass(), MethodHandle.class))
 +            // Help along bootstrapping...
@@ -956,26 +1273,42 @@
 +        DirectMethodHandle dmh = (DirectMethodHandle)mh;
 +        dmh.ensureInitialized();
 +        return dmh.member;
-+    }
-+
-     /*non-public*/ static
-     boolean shouldBeInitialized(MemberName member) {
-         switch (member.getReferenceKind()) {
-@@ -221,13 +269,6 @@
-         return MethodHandleImpl.UNSAFE.shouldBeInitialized(cls);
      }
  
+     /*non-public*/ static
+@@ -213,26 +296,19 @@
+             VerifyAccess.isSamePackage(ValueConversions.class, cls)) {
+             // It is a system class.  It is probably in the process of
+             // being initialized, but we will help it along just to be safe.
+-            if (MethodHandleImpl.UNSAFE.shouldBeInitialized(cls)) {
+-                MethodHandleImpl.UNSAFE.ensureClassInitialized(cls);
++            if (UNSAFE.shouldBeInitialized(cls)) {
++                UNSAFE.ensureClassInitialized(cls);
+             }
+             return false;
+         }
+-        return MethodHandleImpl.UNSAFE.shouldBeInitialized(cls);
+-    }
+-
 -    /*non-public*/ static
 -    @ForceInline
 -    void ensureClassInitialized(Object memberObj) {
 -        MemberName member = (MemberName) memberObj;
 -        EnsureInitialized.INSTANCE.get(member.getDeclaringClass());
--    }
--
++        return UNSAFE.shouldBeInitialized(cls);
+     }
+ 
      private static class EnsureInitialized extends ClassValue<WeakReference<Thread>> {
          @Override
          protected WeakReference<Thread> computeValue(Class<?> type) {
-@@ -241,29 +282,16 @@
+-            MethodHandleImpl.UNSAFE.ensureClassInitialized(type);
+-            if (MethodHandleImpl.UNSAFE.shouldBeInitialized(type))
++            UNSAFE.ensureClassInitialized(type);
++            if (UNSAFE.shouldBeInitialized(type))
+                 // If the previous call didn't block, this can happen.
+                 // We are executing inside <clinit>.
+                 return new WeakReference<>(Thread.currentThread());
+@@ -241,29 +317,16 @@
          static final EnsureInitialized INSTANCE = new EnsureInitialized();
      }
  
@@ -1014,7 +1347,23 @@
          Class<?> defc = member.getDeclaringClass();
          WeakReference<Thread> ref = EnsureInitialized.INSTANCE.get(defc);
          if (ref == null) {
-@@ -286,52 +314,261 @@
+@@ -273,65 +336,304 @@
+         // Somebody may still be running defc.<clinit>.
+         if (clinitThread == Thread.currentThread()) {
+             // If anybody is running defc.<clinit>, it is this thread.
+-            if (MethodHandleImpl.UNSAFE.shouldBeInitialized(defc))
++            if (UNSAFE.shouldBeInitialized(defc))
+                 // Yes, we are running it; keep the barrier for now.
+                 return false;
+         } else {
+             // We are in a random thread.  Block.
+-            MethodHandleImpl.UNSAFE.ensureClassInitialized(defc);
++            UNSAFE.ensureClassInitialized(defc);
+         }
+-        assert(!MethodHandleImpl.UNSAFE.shouldBeInitialized(defc));
++        assert(!UNSAFE.shouldBeInitialized(defc));
+         // put it into the final state
+         EnsureInitialized.INSTANCE.remove(defc);
          return true;
      }
  
@@ -1034,13 +1383,37 @@
  
 -    private static final NamedFunction NF_internalMemberName;
 -    private static final NamedFunction NF_internalMemberNameEnsureInit;
++    /** This subclass handles constructor references. */
++    static class Constructor extends DirectMethodHandle {
++        final MemberName initMethod;
++        final Class<?>   instanceClass;
++
++        private Constructor(MethodType mtype, LambdaForm form, MemberName constructor,
++                            MemberName initMethod, Class<?> instanceClass) {
++            super(mtype, form, constructor);
++            this.initMethod = initMethod;
++            this.instanceClass = instanceClass;
++            assert(initMethod.isResolved());
++        }
++    }
++
++    /*non-public*/ static Object constructorMethod(Object mh) {
++        Constructor dmh = (Constructor)mh;
++        return dmh.initMethod;
++    }
++
++    /*non-public*/ static Object allocateInstance(Object mh) throws InstantiationException {
++        Constructor dmh = (Constructor)mh;
++        return UNSAFE.allocateInstance(dmh.instanceClass);
++    }
++
 +    /** This subclass handles non-static field references. */
 +    static class Accessor extends DirectMethodHandle {
 +        final private Class<?> fieldType;
 +        final private int objectOffset;
-+        private Accessor(MethodType mtype, MemberName member, LambdaForm form,
++        private Accessor(MethodType mtype, LambdaForm form, MemberName member,
 +                         int objectOffset) {
-+            super(mtype, member, form);
++            super(mtype, form, member);
 +            this.fieldType    = member.getFieldType();
 +            this.objectOffset = objectOffset;
 +        }
@@ -1063,9 +1436,9 @@
 +        final private Object   staticBase;
 +        final private long     staticOffset;
 +
-+        private StaticAccessor(MethodType mtype, MemberName member, LambdaForm form,
++        private StaticAccessor(MethodType mtype, LambdaForm form, MemberName member,
 +                               Object staticBase, long staticOffset) {
-+            super(mtype, member, form);
++            super(mtype, form, member);
 +            this.fieldType    = member.getFieldType();
 +            this.staticBase   = staticBase;
 +            this.staticOffset = staticOffset;
@@ -1227,7 +1600,7 @@
 +            names[CAST_1] = new Name(NF_checkCast, names[DMH_THIS], names[SET_VALUE]);
 +        Object[] outArgs = new Object[1 + linkerType.parameterCount()];
 +        assert(outArgs.length == (isGetter ? 3 : 4));
-+        outArgs[0] = MethodHandleImpl.UNSAFE;
++        outArgs[0] = UNSAFE;
 +        if (isStatic) {
 +            outArgs[1] = names[ST_BASE]   = new Name(NF_staticBase, names[DMH_THIS]);
 +            outArgs[2] = names[F_OFFSET]  = new Name(NF_staticOffset, names[DMH_THIS]);
@@ -1257,7 +1630,9 @@
 +            NF_staticOffset,
 +            NF_nullCheck,
 +            NF_objectOffset,
-+            NF_checkCast;
++            NF_checkCast,
++            NF_allocateInstance,
++            NF_constructorMethod;
      static {
          try {
 -            NF_internalMemberName = new NamedFunction(DirectMethodHandle.class
@@ -1283,7 +1658,11 @@
 +                NF_objectOffset = new NamedFunction(DirectMethodHandle.class
 +                    .getDeclaredMethod("objectOffset", Object.class)),
 +                NF_checkCast = new NamedFunction(DirectMethodHandle.class
-+                    .getDeclaredMethod("checkCast", Object.class, Object.class))
++                    .getDeclaredMethod("checkCast", Object.class, Object.class)),
++                NF_allocateInstance = new NamedFunction(DirectMethodHandle.class
++                    .getDeclaredMethod("allocateInstance", Object.class)),
++                NF_constructorMethod = new NamedFunction(DirectMethodHandle.class
++                    .getDeclaredMethod("constructorMethod", Object.class))
 +            };
 +            for (NamedFunction nf : nfs) {
 +                // Each nf must be statically invocable or we get tied up in our bootstraps.
@@ -1319,13 +1698,37 @@
 diff --git a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
 --- a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
 +++ b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
-@@ -523,9 +523,12 @@
-         // Mark this method as a compiled LambdaForm
-         mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Compiled;", true);
+@@ -30,7 +30,6 @@
+ import java.lang.invoke.MethodHandles.Lookup;
  
-+        // Get the BMH class name, if used.
-+        String bmhClassName = constructBMHClassName();
-+
+ import sun.invoke.util.Wrapper;
+-import sun.misc.Unsafe;
+ 
+ import java.io.*;
+ import java.util.*;
+@@ -82,7 +81,6 @@
+     private MethodVisitor mv;
+ 
+     private static final MemberName.Factory MEMBERNAME_FACTORY = MemberName.getFactory();
+-    private static final Unsafe UNSAFE = Unsafe.getUnsafe();
+     private static final Class<?> HOST_CLASS = LambdaForm.class;
+ 
+     private InvokerBytecodeGenerator(LambdaForm lambdaForm, int localsMapSize,
+@@ -444,11 +442,7 @@
+         case 'L':
+             if (VerifyType.isNullConversion(Object.class, pclass))
+                 return;
+-            // for BMH species, which are not representable as names in class files (anonymous classes!), cast to BMH instead
+-            if (BoundMethodHandle.class.isAssignableFrom(pclass)) {
+-                final String className = getInternalName(BoundMethodHandle.class);
+-                mv.visitTypeInsn(Opcodes.CHECKCAST, className);
+-            } else if (isStaticallyNameable(pclass)) {
++            if (isStaticallyNameable(pclass)) {
+                 mv.visitTypeInsn(Opcodes.CHECKCAST, getInternalName(pclass));
+             } else {
+                 mv.visitLdcInsn(constantPlaceholder(pclass));
+@@ -525,7 +519,7 @@
+ 
          // iterate over the form's names, generating bytecode instructions for each
          // start iterating at the first name following the arguments
 -        for (int i = invokerType.parameterCount(); i < lambdaForm.names.length; i++) {
@@ -1333,25 +1736,28 @@
              Name name = lambdaForm.names[i];
              MemberName member = name.function.member();
  
-@@ -534,6 +537,8 @@
-                 // 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, bmhClassName);
-             } else if (isStaticallyInvocable(member)) {
-                 emitStaticInvoke(member, name);
-             } else {
-@@ -601,7 +606,7 @@
+@@ -595,15 +589,15 @@
+ 
+     static private Class<?>[] STATICALLY_INVOCABLE_PACKAGES = {
+         // Sample classes from each package we are willing to bind to statically:
+-        Object.class,
+-        Arrays.class,
+-        Unsafe.class
++        java.lang.Object.class,
++        java.util.Arrays.class,
++        sun.misc.Unsafe.class
          //MethodHandle.class already covered
      };
  
 -    boolean isStaticallyInvocable(MemberName member) {
 +    static boolean isStaticallyInvocable(MemberName member) {
          if (member == null)  return false;
-         assert !member.isConstructor();
+-        assert !member.isConstructor();
++        if (member.isConstructor())  return false;
          Class<?> cls = member.getDeclaringClass();
-@@ -618,7 +623,7 @@
+         if (cls.isArray() || cls.isPrimitive())
+             return false;  // FIXME
+@@ -618,7 +612,7 @@
          return false;
      }
  
@@ -1360,83 +1766,61 @@
          while (cls.isArray())
              cls = cls.getComponentType();
          if (cls.isPrimitive())
-@@ -741,6 +746,75 @@
+@@ -643,10 +637,9 @@
+      */
+     void emitStaticInvoke(MemberName member, Name name) {
+         assert(member.equals(name.function.member()));
+-        assert(member.isMethod());
++        String cname = getInternalName(member.getDeclaringClass());
+         String mname = member.getName();
+-        String mtype = member.getMethodType().toMethodDescriptorString();
+-        String cname = getInternalName(member.getDeclaringClass());
++        String mtype;
+         byte refKind = member.getReferenceKind();
+         if (refKind == REF_invokeSpecial) {
+             // in order to pass the verifier, we need to convert this to invokevirtual in all cases
+@@ -660,22 +653,26 @@
+         }
+ 
+         // invocation
++        if (member.isMethod()) {
++            mtype = member.getMethodType().toMethodDescriptorString();
++            mv.visitMethodInsn(refKindOpcode(refKind), cname, mname, mtype);
++        } else {
++            mtype = MethodType.toFieldDescriptorString(member.getFieldType());
++            mv.visitFieldInsn(refKindOpcode(refKind), cname, mname, mtype);
++        }
++    }
++    int refKindOpcode(byte refKind) {
+         switch (refKind) {
+-        case REF_invokeVirtual:
+-            mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, cname, mname, mtype);
+-            break;
+-        case REF_invokeStatic:
+-            mv.visitMethodInsn(Opcodes.INVOKESTATIC,  cname, mname, mtype);
+-            break;
+-        case REF_invokeSpecial:
+-            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, cname, mname, mtype);
+-            break;
+-        case REF_invokeInterface:
+-            mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, cname, mname, mtype);
+-            break;
+-        default:
+-            throw new InternalError(member.toString());
++        case REF_invokeVirtual:      return Opcodes.INVOKEVIRTUAL;
++        case REF_invokeStatic:       return Opcodes.INVOKESTATIC;
++        case REF_invokeSpecial:      return Opcodes.INVOKESPECIAL;
++        case REF_invokeInterface:    return Opcodes.INVOKEINTERFACE;
++        case REF_getField:           return Opcodes.GETFIELD;
++        case REF_putField:           return Opcodes.PUTFIELD;
++        case REF_getStatic:          return Opcodes.GETSTATIC;
++        case REF_putStatic:          return Opcodes.PUTSTATIC;
+         }
++        throw new InternalError("refKind="+refKind);
      }
  
      /**
-+     * 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 || !name.startsWith("arg")) {
-+            return false;
-+        }
-+        int arity = member.getInvocationType().parameterCount();
-+        // argJ0 and argL1
-+        if (arity == 1) {
-+            return false;
-+        }
-+        assert(arity == 2) : "member: " + member;
-+        return true;
-+    }
-+
-+    private String constructBMHClassName() {
-+        char[] types = new char[lambdaForm.names.length - lambdaForm.arity];
-+        int count = -1;
-+        for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
-+            Name name = lambdaForm.names[i];
-+            MemberName member = name.function.member();
-+            if (isBoundArgumentLoad(member)) {
-+                String methodName = member.getName();
-+                char   type  = methodName.charAt(methodName.length() - 1);
-+                int    index = (int) name.arguments[1];
-+                types[index] = type;
-+                count = Math.max(count, index);
-+            }
-+        }
-+        if (count > -1) {
-+            for (int i = 0; i < count + 1; i++) {
-+                if (types[i] == '\0')
-+                    throw new InternalError("missing BMH type at " + i);
-+            }
-+            return BMH + "$BMH_" + new String(types, 0, count + 1);
-+        }
-+        return null;
-+    }
-+
-+    private void emitBoundArgumentLoad(MemberName member, Name name, String bmhClass) {
-+        String methodName = member.getName();
-+        char   type  = methodName.charAt(methodName.length() - 1);
-+        int    index = (int) name.arguments[1];
-+
-+        // aload_0
-+        // checkcast  // class java/lang/invoke/BoundMethodHandle$BMH_???
-+        // getfield   // Field arg?n:?
-+        emitAloadInsn(0);
-+        mv.visitTypeInsn(Opcodes.CHECKCAST, bmhClass);
-+
-+        switch (type) {
-+        case 'I':  mv.visitFieldInsn(Opcodes.GETFIELD, bmhClass, "argI" + index, "I");  break;
-+        case 'J':  mv.visitFieldInsn(Opcodes.GETFIELD, bmhClass, "argJ" + index, "J");  break;
-+        case 'F':  mv.visitFieldInsn(Opcodes.GETFIELD, bmhClass, "argF" + index, "F");  break;
-+        case 'D':  mv.visitFieldInsn(Opcodes.GETFIELD, bmhClass, "argD" + index, "D");  break;
-+        case 'L':  mv.visitFieldInsn(Opcodes.GETFIELD, bmhClass, "argL" + index, "Ljava/lang/Object;");  break;
-+        default:  throw new InternalError("unexpected type: " + type);
-+        }
-+    }
-+
-+    /**
-      *
-      * @param name
-      * @param paramIndex
-@@ -753,6 +827,8 @@
+@@ -753,6 +750,8 @@
              Name n = (Name) arg;
              emitLoadInsn(n.type, n.index());
              emitImplicitConversion(n.type, mtype.parameterType(paramIndex));
@@ -1448,19 +1832,53 @@
 diff --git a/src/share/classes/java/lang/invoke/Invokers.java b/src/share/classes/java/lang/invoke/Invokers.java
 --- a/src/share/classes/java/lang/invoke/Invokers.java
 +++ b/src/share/classes/java/lang/invoke/Invokers.java
+@@ -75,7 +75,7 @@
+         if (invoker != null)  return invoker;
+         MethodType mtype = targetType;
+         LambdaForm lform = invokeForm(mtype, MethodTypeForm.LF_EX_INVOKER);
+-        invoker = new BoundMethodHandle.BMH_L(mtype.invokerType(), lform, mtype);
++        invoker = BoundMethodHandle.bindSingle(mtype.invokerType(), lform, mtype);
+         assert(checkInvoker(invoker));
+         exactInvoker = invoker;
+         return invoker;
+@@ -87,7 +87,7 @@
+         MethodType mtype = targetType;
+         prepareForGenericCall(mtype);
+         LambdaForm lform = invokeForm(mtype, MethodTypeForm.LF_GEN_INVOKER);
+-        invoker = new BoundMethodHandle.BMH_L(mtype.invokerType(), lform, mtype);
++        invoker = BoundMethodHandle.bindSingle(mtype.invokerType(), lform, mtype);
+         assert(checkInvoker(invoker));
+         generalInvoker = invoker;
+         return invoker;
 @@ -241,7 +241,7 @@
          assert(names.length == nameCursor);
          if (MTYPE_ARG >= INARG_LIMIT) {
              assert(names[MTYPE_ARG] == null);
 -            names[MTYPE_ARG] = BoundMethodHandle.getterName(names[THIS_MH], 'L', 0);
-+            names[MTYPE_ARG] = BoundMethodHandle.getterName(names[THIS_MH], "L", 0);
++            names[MTYPE_ARG] = BoundMethodHandle.getData("L").getterName(names[THIS_MH], 0);
              // else if isLinker, then MTYPE is passed in from the caller (e.g., the JVM)
          }
  
 diff --git a/src/share/classes/java/lang/invoke/LambdaForm.java b/src/share/classes/java/lang/invoke/LambdaForm.java
 --- a/src/share/classes/java/lang/invoke/LambdaForm.java
 +++ b/src/share/classes/java/lang/invoke/LambdaForm.java
-@@ -428,6 +428,9 @@
+@@ -36,6 +36,7 @@
+ import sun.invoke.util.Wrapper;
+ import static java.lang.invoke.MethodHandleStatics.*;
+ import static java.lang.invoke.MethodHandleNatives.Constants.*;
++import java.lang.reflect.Field;
+ 
+ /**
+  * The symbolic, non-executable form of a method handle's invocation semantics.
+@@ -121,6 +122,7 @@
+     final Name[] names;
+     final String debugName;
+     MemberName vmentry;   // low-level behavior, or null if not yet prepared
++    private boolean isCompiled;
+ 
+     // Caches for common structural transforms:
+     LambdaForm[] bindCache;
+@@ -428,6 +430,9 @@
       * as a sort of pre-invocation linkage step.)
       */
      public void prepare() {
@@ -1470,7 +1888,23 @@
          if (this.vmentry != null) {
              // already prepared (e.g., a primitive DMH invoker form)
              return;
-@@ -574,7 +577,13 @@
+@@ -441,12 +446,14 @@
+     MemberName compileToBytecode() {
+         MethodType invokerType = methodType();
+         assert(vmentry == null || vmentry.getMethodType().basicType().equals(invokerType));
+-        if (vmentry != null)
++        if (vmentry != null && isCompiled) {
+             return vmentry;  // already compiled somehow
++        }
+         try {
+             vmentry = InvokerBytecodeGenerator.generateCustomizedCode(this, invokerType);
+             if (TRACE_INTERPRETER)
+                 traceInterpreter("compileToBytecode", this);
++            isCompiled = true;
+             return vmentry;
+         } catch (Error | Exception ex) {
+             throw new InternalError(this.toString(), ex);
+@@ -574,7 +581,13 @@
      }
  
      /** If the invocation count hits the threshold we spin bytecodes and call that subsequently. */
@@ -1485,7 +1919,7 @@
      private int invocationCounter = 0;
  
      @Hidden
-@@ -582,9 +591,10 @@
+@@ -582,9 +595,10 @@
      Object interpretWithArguments(Object... argumentValues) throws Throwable {
          if (TRACE_INTERPRETER)
              return interpretWithArgumentsTracing(argumentValues);
@@ -1498,7 +1932,7 @@
                  // Replace vmentry with a bytecode version of this LF.
                  compileToBytecode();
              }
-@@ -617,10 +627,10 @@
+@@ -617,10 +631,10 @@
  
      Object interpretWithArgumentsTracing(Object... argumentValues) throws Throwable {
          traceInterpreter("[ interpretWithArguments", this, argumentValues);
@@ -1511,17 +1945,150 @@
                  compileToBytecode();
              }
          }
-@@ -759,8 +769,8 @@
+@@ -759,17 +773,21 @@
          return new LambdaForm(debugName, arity2, names2, result2);
      }
  
 -    LambdaForm bind(char basicType, int namePos, int dataValuePos) {
 -        Name dataValueName = BoundMethodHandle.getterName(names[0], basicType, dataValuePos);
-+    LambdaForm bind(int namePos, String dataValueTypes, int dataValuePos) {
-+        Name dataValueName = BoundMethodHandle.getterName(names[0], dataValueTypes, dataValuePos);
-         return bind(names[namePos], dataValueName);
+-        return bind(names[namePos], dataValueName);
++    LambdaForm bind(int namePos, BoundMethodHandle.Data oldData) {
++        Name name = names[namePos];
++        BoundMethodHandle.Data newData = oldData.extendWithType(name.type);
++        return bind(name, newData.getterName(names[0], oldData.fieldCount()), oldData, newData);
+     }
+-
+-    LambdaForm bind(Name name, Name binding) {
++    LambdaForm bind(Name name, Name binding,
++                    BoundMethodHandle.Data oldData,
++                    BoundMethodHandle.Data newData) {
+         int pos = name.index;
+         assert(name.isParam());
+         assert(!binding.isParam());
+         assert(name.type == binding.type);
+         assert(0 <= pos && pos < arity && names[pos] == name);
++        assert(binding.function.memberDeclaringClassOrNull() == newData.clazz);
++        assert(oldData.getters.length == newData.getters.length-1);
+         if (bindCache != null) {
+             LambdaForm form = bindCache[pos];
+             if (form != null) {
+@@ -784,9 +802,32 @@
+         Name[] names2 = names.clone();
+         names2[pos] = binding;  // we might move this in a moment
+ 
++        // The newly created LF will run with a different BMH.
++        // Switch over any pre-existing BMH field references to the new BMH class.
++        int firstOldRef = -1;
++        for (int i = 0; i < names2.length; i++) {
++            Name n = names[i];
++            if (n.function != null &&
++                n.function.memberDeclaringClassOrNull() == oldData.clazz) {
++                MethodHandle oldGetter = n.function.resolvedHandle;
++                MethodHandle newGetter = null;
++                for (int j = 0; j < oldData.getters.length; j++) {
++                    if (oldGetter == oldData.getters[j])
++                        newGetter =  newData.getters[j];
++                }
++                if (newGetter != null) {
++                    if (firstOldRef < 0)  firstOldRef = i;
++                    Name n2 = new Name(newGetter, n.arguments);
++                    names2[i] = n2;
++                }
++            }
++        }
++
+         // Walk over the new list of names once, in forward order.
+         // Replace references to 'name' with 'binding'.
++        // Replace data structure references to the old BMH species with the new.
+         // This might cause a ripple effect, but it will settle in one pass.
++        assert(firstOldRef < 0 || firstOldRef > pos);
+         for (int i = pos+1; i < names2.length; i++) {
+             if (i <= arity2)  continue;
+             names2[i] = names2[i].replaceNames(names, names2, pos, i);
+@@ -936,13 +977,16 @@
+             this.resolvedHandle = resolvedHandle;
+         }
+ 
+-        // The next 2 constructors are used to break circular dependencies on MH.invokeStatic, etc.
++        // The next 3 constructors are used to break circular dependencies on MH.invokeStatic, etc.
+         // Any LambdaForm containing such a member is not interpretable.
+         // This is OK, since all such LFs are prepared with special primitive vmentry points.
+         // And even without the resolvedHandle, the name can still be compiled and optimized.
+         NamedFunction(Method method) {
+             this(new MemberName(method));
+         }
++        NamedFunction(Field field) {
++            this(new MemberName(field));
++        }
+         NamedFunction(MemberName member) {
+             this.member = member;
+             this.resolvedHandle = null;
+@@ -1139,9 +1183,6 @@
+         }
+ 
+         MemberName member() {
+-            if (member == null) {
+-                return resolvedHandle.internalMemberName();
+-            }
+             assert(memberIsConsistent());
+             return member;
+         }
+@@ -1154,6 +1195,10 @@
+             return true;
+         }
+ 
++        Class<?> memberDeclaringClassOrNull() {
++            return (member == null) ? null : member.getDeclaringClass();
++        }
++
+         char returnType() {
+             return basicType(methodType().returnType());
+         }
+diff --git a/src/share/classes/java/lang/invoke/MemberName.java b/src/share/classes/java/lang/invoke/MemberName.java
+--- a/src/share/classes/java/lang/invoke/MemberName.java
++++ b/src/share/classes/java/lang/invoke/MemberName.java
+@@ -174,8 +174,10 @@
+      */
+     public MethodType getInvocationType() {
+         MethodType itype = getMethodOrFieldType();
++        if (isConstructor() && getReferenceKind() == REF_newInvokeSpecial)
++            return itype.changeReturnType(clazz);
+         if (!isStatic())
+-            itype = itype.insertParameterTypes(0, clazz);
++            return itype.insertParameterTypes(0, clazz);
+         return itype;
      }
  
+@@ -322,6 +324,10 @@
+         assert(getReferenceKind() == oldKind);
+         assert(MethodHandleNatives.refKindIsValid(refKind));
+         flags += (((int)refKind - oldKind) << MN_REFERENCE_KIND_SHIFT);
++//        if (isConstructor() && refKind != REF_newInvokeSpecial)
++//            flags += (IS_METHOD - IS_CONSTRUCTOR);
++//        else if (refKind == REF_newInvokeSpecial && isMethod())
++//            flags += (IS_CONSTRUCTOR - IS_METHOD);
+         return this;
+     }
+ 
+@@ -508,8 +514,16 @@
+     }
+     public MemberName asSpecial() {
+         switch (getReferenceKind()) {
+-        case REF_invokeSpecial:  return this;
+-        case REF_invokeVirtual:  return clone().changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual);
++        case REF_invokeSpecial:     return this;
++        case REF_invokeVirtual:     return clone().changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual);
++        case REF_newInvokeSpecial:  return clone().changeReferenceKind(REF_invokeSpecial, REF_newInvokeSpecial);
++        }
++        throw new IllegalArgumentException(this.toString());
++    }
++    public MemberName asConstructor() {
++        switch (getReferenceKind()) {
++        case REF_invokeSpecial:     return clone().changeReferenceKind(REF_newInvokeSpecial, REF_invokeSpecial);
++        case REF_newInvokeSpecial:  return this;
+         }
+         throw new IllegalArgumentException(this.toString());
+     }
 diff --git a/src/share/classes/java/lang/invoke/MethodHandle.java b/src/share/classes/java/lang/invoke/MethodHandle.java
 --- a/src/share/classes/java/lang/invoke/MethodHandle.java
 +++ b/src/share/classes/java/lang/invoke/MethodHandle.java
@@ -1541,10 +2108,80 @@
                  return MethodHandleImpl.makeVarargsCollector(this, arrayType);
              }
          }
+@@ -1322,12 +1320,49 @@
+     }
+ 
+     /*non-public*/
+-    private BoundMethodHandle rebind() {
++    MethodHandle rebind() {
+         // Bind 'this' into a new invoker, of the known class BMH.
+         MethodType type2 = type();
+-        LambdaForm form2 = BoundMethodHandle.reinvokerForm(type2.basicType());
++        LambdaForm form2 = reinvokerForm(type2.basicType());
+         // form2 = lambda (bmh, arg*) { thismh = bmh[0]; invokeBasic(thismh, arg*) }
+-        return new BoundMethodHandle.BMH_L(type2, form2, this);
++        return BoundMethodHandle.bindSingle(type2, form2, this);
++    }
++
++    /*non-public*/
++    MethodHandle reinvokerTarget() {
++        throw new InternalError("not a reinvoker MH: "+this.getClass().getName()+": "+this);
++    }
++
++    /** Create a LF which simply reinvokes a target of the given basic type.
++     *  The target MH must override {@link #reinvokerTarget} to provide the target.
++     */
++    static LambdaForm reinvokerForm(MethodType mtype) {
++        mtype = mtype.basicType();
++        LambdaForm reinvoker = mtype.form().cachedLambdaForm(MethodTypeForm.LF_REINVOKE);
++        if (reinvoker != null)  return reinvoker;
++        MethodHandle MH_invokeBasic = MethodHandles.basicInvoker(mtype);
++        final int THIS_BMH    = 0;
++        final int ARG_BASE    = 1;
++        final int ARG_LIMIT   = ARG_BASE + mtype.parameterCount();
++        int nameCursor = ARG_LIMIT;
++        final int NEXT_MH     = nameCursor++;
++        final int REINVOKE    = nameCursor++;
++        LambdaForm.Name[] names = LambdaForm.arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
++        names[NEXT_MH] = new LambdaForm.Name(NF_reinvokerTarget, names[THIS_BMH]);
++        Object[] targetArgs = Arrays.copyOfRange(names, THIS_BMH, ARG_LIMIT, Object[].class);
++        targetArgs[0] = names[NEXT_MH];  // overwrite this MH with next MH
++        names[REINVOKE] = new LambdaForm.Name(MH_invokeBasic, targetArgs);
++        return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_REINVOKE, new LambdaForm("BMH.reinvoke", ARG_LIMIT, names));
++    }
++
++    private static final LambdaForm.NamedFunction NF_reinvokerTarget;
++    static {
++        try {
++            NF_reinvokerTarget = new LambdaForm.NamedFunction(MethodHandle.class
++                .getDeclaredMethod("reinvokerTarget"));
++        } catch (ReflectiveOperationException ex) {
++            throw new InternalError(ex);
++        }
+     }
+ 
+     /**
+@@ -1342,14 +1377,14 @@
+     void updateForm(LambdaForm newForm) {
+         if (form == newForm)  return;
+         // ISSUE: Should we have a memory fence here?
+-        MethodHandleImpl.UNSAFE.putObject(this, FORM_OFFSET, newForm);
++        UNSAFE.putObject(this, FORM_OFFSET, newForm);
+         this.form.prepare();  // as in MethodHandle.<init>
+     }
+ 
+     private static final long FORM_OFFSET;
+     static {
+         try {
+-            FORM_OFFSET = MethodHandleImpl.UNSAFE.objectFieldOffset(MethodHandle.class.getDeclaredField("form"));
++            FORM_OFFSET = UNSAFE.objectFieldOffset(MethodHandle.class.getDeclaredField("form"));
+         } catch (ReflectiveOperationException ex) {
+             throw new InternalError(ex);
+         }
 diff --git a/src/share/classes/java/lang/invoke/MethodHandleImpl.java b/src/share/classes/java/lang/invoke/MethodHandleImpl.java
 --- a/src/share/classes/java/lang/invoke/MethodHandleImpl.java
 +++ b/src/share/classes/java/lang/invoke/MethodHandleImpl.java
-@@ -26,6 +26,8 @@
+@@ -26,13 +26,14 @@
  package java.lang.invoke;
  
  import sun.invoke.util.VerifyType;
@@ -1553,7 +2190,56 @@
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.HashMap;
-@@ -185,121 +187,6 @@
+ import sun.invoke.empty.Empty;
+ import sun.invoke.util.ValueConversions;
+ import sun.invoke.util.Wrapper;
+-import sun.misc.Unsafe;
+ import static java.lang.invoke.LambdaForm.*;
+ import static java.lang.invoke.MethodHandleNatives.Constants.*;
+ import static java.lang.invoke.MethodHandleStatics.*;
+@@ -50,41 +51,6 @@
+         MemberName.Factory.INSTANCE.getClass();
+     }
+ 
+-    /** Cache frequently used stuff. */
+-    static final Unsafe UNSAFE = Unsafe.getUnsafe();
+-
+-    static MethodHandle makeAllocator(MethodHandle rawConstructor) {
+-        MethodType rawConType = rawConstructor.type();
+-        Class<?> allocateClass = rawConType.parameterType(0);
+-        MethodType srcType = rawConType.dropParameterTypes(0, 1).changeReturnType(allocateClass);
+-        final int THIS_MH     = 0;
+-        final int ARG_BASE    = 1;
+-        final int ARG_LIMIT   = ARG_BASE + srcType.parameterCount();
+-        int nameCursor = ARG_LIMIT;
+-        final int NEW_OBJ     = nameCursor++;
+-        final int CALL_CTOR   = nameCursor++;
+-        Name[] names = arguments(nameCursor - ARG_LIMIT, srcType.invokerType());
+-        names[NEW_OBJ] = new Name(AllocatorData.UNSAFE_ALLOCATEINSTANCE, allocateClass);
+-        Object[] conArgs = Arrays.copyOfRange(names, ARG_BASE-1, ARG_LIMIT, Object[].class);
+-        conArgs[0] = names[NEW_OBJ];
+-        names[CALL_CTOR] = new Name(rawConstructor, conArgs);
+-        LambdaForm form = new LambdaForm("newInvokeSpecial", ARG_LIMIT, names, NEW_OBJ);
+-        return new SimpleMethodHandle(srcType, form);
+-    }
+-
+-    static final class AllocatorData {
+-        static final MethodHandle UNSAFE_ALLOCATEINSTANCE;
+-        static {
+-            try {
+-                assert(IMPL_LOOKUP != null) : "bootstrap problem";
+-                UNSAFE_ALLOCATEINSTANCE =
+-                    IMPL_LOOKUP.bind(UNSAFE, "allocateInstance", MethodType.methodType(Object.class, Class.class));
+-            } catch (NoSuchMethodException | IllegalAccessException e) {
+-                throw new InternalError(e);
+-            }
+-        }
+-    }
+-
+     static MethodHandle makeArrayElementAccessor(Class<?> arrayClass, boolean isSetter) {
+         if (!arrayClass.isArray())
+             throw newIllegalArgumentException("not an array: "+arrayClass);
+@@ -185,121 +151,6 @@
          }
      }
  
@@ -1675,25 +2361,76 @@
      /*non-public*/ static
      MethodHandle convertArguments(MethodHandle target, MethodType srcType, int level) {
          MethodType dstType = target.type();
-@@ -659,11 +546,14 @@
+@@ -636,7 +487,7 @@
+         return new AsVarargsCollector(target, target.type(), arrayType);
+     }
+ 
+-    static class AsVarargsCollector extends BoundMethodHandle {
++    static class AsVarargsCollector extends MethodHandle {
+         MethodHandle target;
+         final Class<?> arrayType;
+         MethodHandle cache;
+@@ -648,6 +499,8 @@
+             this.cache = target.asCollector(arrayType, 0);
+         }
+ 
++        @Override MethodHandle reinvokerTarget() { return target; }
++
+         @Override
+         public boolean isVarargsCollector() {
+             return true;
+@@ -659,13 +512,6 @@
          }
  
          @Override
 -        public String types() {
 -            return types;
-+        public String myTypes() {
-+            return BoundMethodHandle.BMH_L.TYPES; // same types signature
+-        }
+-
+-        public static final String types = "L";
+-
+-        @Override
+         public MethodHandle asType(MethodType newType) {
+             MethodType type = this.type();
+             int collectArg = type.parameterCount() - 1;
+@@ -730,36 +576,6 @@
+         MethodHandle permuteArguments(MethodType newType, int[] reorder) {
+             return asFixedArity().permuteArguments(newType, reorder);
          }
+-
+-        @Override
+-        public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
+-            throw new IllegalStateException("NYI");
+-        }
+-
+-        @Override
+-        public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
+-            throw new IllegalStateException("NYI");
+-        }
+-
+-        @Override
+-        public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
+-            throw new IllegalStateException("NYI");
+-        }
+-
+-        @Override
+-        public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
+-            throw new IllegalStateException("NYI");
+-        }
+-
+-        @Override
+-        public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
+-            throw new IllegalStateException("NYI");
+-        }
+-
+-        @Override
+-        public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
+-            throw new IllegalStateException("NYI");
+-        }
+     }
  
--        public static final String types = "L";
-+        @Override
-+        public Data myData() {
-+            return BoundMethodHandle.BMH_L.DATA; // same types signature
-+        }
- 
-         @Override
-         public MethodHandle asType(MethodType newType) {
-@@ -1028,9 +918,7 @@
+     /** Can a checkcast adapter validly convert the target to srcType?
+@@ -1028,9 +844,7 @@
                  indexes[i] = argIndex;
              }
          }
@@ -1707,7 +2444,21 @@
 diff --git a/src/share/classes/java/lang/invoke/MethodHandleStatics.java b/src/share/classes/java/lang/invoke/MethodHandleStatics.java
 --- a/src/share/classes/java/lang/invoke/MethodHandleStatics.java
 +++ b/src/share/classes/java/lang/invoke/MethodHandleStatics.java
-@@ -42,14 +42,16 @@
+@@ -27,6 +27,7 @@
+ 
+ import java.security.AccessController;
+ import java.security.PrivilegedAction;
++import sun.misc.Unsafe;
+ 
+ /**
+  * This class consists exclusively of static names internal to the
+@@ -38,18 +39,22 @@
+ 
+     private MethodHandleStatics() { }  // do not instantiate
+ 
++    static final Unsafe UNSAFE = Unsafe.getUnsafe();
++
+     static final boolean DEBUG_METHOD_HANDLE_NAMES;
      static final boolean DUMP_CLASS_FILES;
      static final boolean TRACE_INTERPRETER;
      static final boolean TRACE_METHOD_LINKAGE;
@@ -1725,7 +2476,7 @@
                      return null;
                  }
              });
-@@ -57,6 +59,7 @@
+@@ -57,6 +62,7 @@
          DUMP_CLASS_FILES          = (Boolean) values[1];
          TRACE_INTERPRETER         = (Boolean) values[2];
          TRACE_METHOD_LINKAGE      = (Boolean) values[3];
@@ -1756,6 +2507,53 @@
              boolean doRestrict = (MethodHandleNatives.refKindHasReceiver(refKind) &&
                                      restrictProtectedReceiver(field));
              if (doRestrict)
+@@ -1231,8 +1229,7 @@
+         private MethodHandle getDirectConstructor(Class<?> refc, MemberName ctor) throws IllegalAccessException {
+             assert(ctor.isConstructor());
+             checkAccess(REF_newInvokeSpecial, refc, ctor);
+-            MethodHandle mh = DirectMethodHandle.make(ctor);
+-            return MethodHandleImpl.makeAllocator(mh).setVarargs(ctor);
++            return DirectMethodHandle.make(ctor).setVarargs(ctor);
+         }
+ 
+         /** Hook called from the JVM (via MethodHandleNatives) to link MH constants:
+diff --git a/src/share/classes/java/lang/invoke/MethodType.java b/src/share/classes/java/lang/invoke/MethodType.java
+--- a/src/share/classes/java/lang/invoke/MethodType.java
++++ b/src/share/classes/java/lang/invoke/MethodType.java
+@@ -824,6 +824,10 @@
+         return BytecodeDescriptor.unparse(this);
+     }
+ 
++    /*non-public*/ static String toFieldDescriptorString(Class<?> cls) {
++        return BytecodeDescriptor.unparse(cls);
++    }
++
+     /// Serialization.
+ 
+     /**
+@@ -896,18 +900,17 @@
+         // store them into the implementation-specific final fields.
+         checkRtype(rtype);
+         checkPtypes(ptypes);
+-        unsafe.putObject(this, rtypeOffset, rtype);
+-        unsafe.putObject(this, ptypesOffset, ptypes);
++        UNSAFE.putObject(this, rtypeOffset, rtype);
++        UNSAFE.putObject(this, ptypesOffset, ptypes);
+     }
+ 
+     // Support for resetting final fields while deserializing
+-    private static final sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
+     private static final long rtypeOffset, ptypesOffset;
+     static {
+         try {
+-            rtypeOffset = unsafe.objectFieldOffset
++            rtypeOffset = UNSAFE.objectFieldOffset
+                 (MethodType.class.getDeclaredField("rtype"));
+-            ptypesOffset = unsafe.objectFieldOffset
++            ptypesOffset = UNSAFE.objectFieldOffset
+                 (MethodType.class.getDeclaredField("ptypes"));
+         } catch (Exception ex) {
+             throw new Error(ex);
 diff --git a/src/share/classes/java/lang/invoke/MethodTypeForm.java b/src/share/classes/java/lang/invoke/MethodTypeForm.java
 --- a/src/share/classes/java/lang/invoke/MethodTypeForm.java
 +++ b/src/share/classes/java/lang/invoke/MethodTypeForm.java
@@ -1800,12 +2598,33 @@
 diff --git a/src/share/classes/java/lang/invoke/SimpleMethodHandle.java b/src/share/classes/java/lang/invoke/SimpleMethodHandle.java
 --- a/src/share/classes/java/lang/invoke/SimpleMethodHandle.java
 +++ b/src/share/classes/java/lang/invoke/SimpleMethodHandle.java
-@@ -40,7 +40,7 @@
+@@ -27,6 +27,8 @@
+ 
+ import static java.lang.invoke.LambdaForm.*;
+ import static java.lang.invoke.MethodHandleNatives.Constants.*;
++import java.util.logging.Level;
++import java.util.logging.Logger;
+ 
+ /**
+  * A method handle whose behavior is determined only by its LambdaForm.
+@@ -40,7 +42,7 @@
      @Override
      MethodHandle bindArgument(int pos, char basicType, Object value) {
          MethodType type2 = type().dropParameterTypes(pos, pos+1);
 -        LambdaForm form2 = internalForm().bind(basicType, 1+pos, 0);
-+        LambdaForm form2 = internalForm().bind(1+pos, String.valueOf(basicType), 0);
++        LambdaForm form2 = internalForm().bind(1+pos, BoundMethodHandle.Data.EMPTY);
          return BoundMethodHandle.bindSingle(type2, form2, basicType, value);
      }
  
+diff --git a/test/java/lang/invoke/MethodHandlesTest.java b/test/java/lang/invoke/MethodHandlesTest.java
+--- a/test/java/lang/invoke/MethodHandlesTest.java
++++ b/test/java/lang/invoke/MethodHandlesTest.java
+@@ -1821,7 +1821,7 @@
+         List<Object> argsToPass = new ArrayList<>(resList);
+         List<Object> argsToInsert = argsToPass.subList(pos, pos + ins);
+         if (verbosity >= 3)
+-            System.out.println("insert: "+argsToInsert+" into "+target);
++            System.out.println("insert: "+argsToInsert+" @"+pos+" into "+target);
+         @SuppressWarnings("cast")  // cast to spread Object... is helpful
+         MethodHandle target2 = MethodHandles.insertArguments(target, pos,
+                 (Object[]/*...*/) argsToInsert.toArray());