changeset 410:32510db69498

meth: DirectMethodHandle.Accessor
author jrose
date Sun, 15 Jul 2012 04:32:24 -0700
parents 56879e348afe
children cec00d423fbc
files meth-lazy-7023639.bmh.patch
diffstat 1 files changed, 998 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/meth-lazy-7023639.bmh.patch	Sat Jul 14 18:02:46 2012 -0700
+++ b/meth-lazy-7023639.bmh.patch	Sun Jul 15 04:32:24 2012 -0700
@@ -37,27 +37,35 @@
  
  /**
   * The flavor of method handle which emulates an invoke instruction
-@@ -86,16 +71,16 @@
-             case 'L': return new BMH_L(type, form, x);
+@@ -83,19 +68,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);
              case 'I':
-                 assert x instanceof Integer : "expected Integer, found " + x.getClass();
+-                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, ((Integer) x).intValue());
++                return (BoundMethodHandle) Data.get("I").constructor[0].invokeBasic(type, form, (int) x);
              case 'J':
-                 assert x instanceof Long;
-                 return new BMH_J(type, form, ((Long) x).longValue());
+-                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);
              case 'F':
-                 assert x instanceof Float;
+-                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).floatValue());
++                return (BoundMethodHandle) Data.get("F").constructor[0].invokeBasic(type, form, (float) x);
              case 'D':
-                 assert x instanceof Double;
+-                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).doubleValue());
++                return (BoundMethodHandle) Data.get("D").constructor[0].invokeBasic(type, form, (double) x);
              default : throw new InternalError("unexpected xtype: " + xtype);
              }
          } catch (Throwable t) {
-@@ -122,7 +107,6 @@
+@@ -122,7 +106,6 @@
              default : throw new InternalError("unexpected type: " + xtype);
              }
          } catch (Throwable t) {
@@ -65,7 +73,16 @@
              throw new InternalError(t);
          }
      }
-@@ -158,27 +142,29 @@
+@@ -130,7 +113,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());
+         if (basicType == 'I' && !(value instanceof Integer)) {
+             // Cf. ValueConversions.unboxInteger
+             value = ValueConversions.primitiveConversion(Wrapper.INT, value, true);
+@@ -158,27 +141,29 @@
      }
  
      public int tcount() {
@@ -103,7 +120,25 @@
      }
  
      /**
-@@ -201,16 +187,16 @@
+@@ -186,7 +171,16 @@
+      * 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 @@
  
      @Override
      final Object internalValues() {
@@ -123,7 +158,22 @@
                  }
              } catch (Throwable t) {
                  throw new InternalError(t);
-@@ -254,10 +240,15 @@
+@@ -236,12 +230,14 @@
+     public abstract BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float  narg) throws Throwable;
+     public abstract BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable;
+ 
++    /*
+     //
+     // getters to close bootstrap loops
+     //
+ 
+     public long   argJ0() throws Throwable { return argJ(0); }
+     public Object argL1() throws Throwable { return argL(1); }
++    */
+ 
+     //
+     // concrete BMH classes required to close bootstrap loops
+@@ -254,10 +250,15 @@
              this.argL0 = argL0;
          }
          @Override
@@ -142,7 +192,7 @@
          @Override
          public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
              return new BMH_L(mt, lf, argL0);
-@@ -268,19 +259,19 @@
+@@ -268,19 +269,19 @@
          }
          @Override
          public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
@@ -166,7 +216,7 @@
          }
      }
  
-@@ -293,33 +284,38 @@
+@@ -293,36 +294,41 @@
              this.argL1 = argL1;
          }
          @Override
@@ -212,8 +262,12 @@
 +            return (BoundMethodHandle) Data.get("LLD").constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
          }
      }
- 
-@@ -332,10 +328,15 @@
+-
++    /*
+     static final class BMH_JL extends BoundMethodHandle {
+         final long argJ0;
+         final Object argL1;
+@@ -332,10 +338,15 @@
              this.argL1 = argL1;
          }
          @Override
@@ -232,7 +286,7 @@
          @Override public final long   argJ0() { return argJ0; }
          @Override public final Object argL1() { return argL1; }
          @Override
-@@ -344,23 +345,23 @@
+@@ -344,23 +355,23 @@
          }
          @Override
          public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
@@ -261,7 +315,7 @@
          }
      }
  
-@@ -371,10 +372,15 @@
+@@ -371,10 +382,15 @@
              this.argJ0 = argJ0;
          }
          @Override
@@ -280,7 +334,7 @@
          @Override public final long argJ0() { return argJ0; }
          @Override
          public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
-@@ -386,19 +392,19 @@
+@@ -386,19 +402,19 @@
          }
          @Override
          public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
@@ -304,7 +358,24 @@
          }
      }
  
-@@ -452,37 +458,80 @@
+@@ -415,6 +431,7 @@
+             throw new InternalError(e);
+         }
+     }
++    */
+ 
+     //
+     // 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 @@
      static class Data {
          final String                             types;
          final Class<? extends BoundMethodHandle> clazz;
@@ -406,7 +477,7 @@
              return d;
          }
  
-@@ -494,16 +543,23 @@
+@@ -494,16 +554,23 @@
                      if (BMH.isAssignableFrom(c)) {
                          final Class<? extends BoundMethodHandle> cbmh = c.asSubclass(BoundMethodHandle.class);
                          final String types = Factory.typesFromConcreteBMHClass(cbmh);
@@ -434,7 +505,7 @@
      }
  
      /**
-@@ -520,18 +576,21 @@
+@@ -520,18 +587,21 @@
       */
      static class Factory {
  
@@ -465,7 +536,7 @@
  
          static final String SIG_INCIPIT = "(Ljava/lang/invoke/MethodType;Ljava/lang/invoke/LambdaForm;";
  
-@@ -547,7 +606,7 @@
+@@ -547,7 +617,7 @@
           * <pre>
           * class BMH_<<types>> extends BMH {
           *     <<fields>>
@@ -474,7 +545,7 @@
           * }
           * </pre>
           *
-@@ -572,25 +631,27 @@
+@@ -572,25 +642,27 @@
           *         this.argL1 = argL1;
           *         this.argI2 = argI2;
           *     }
@@ -510,7 +581,7 @@
           *     }
           * }
           * </pre>
-@@ -601,14 +662,14 @@
+@@ -601,14 +673,14 @@
          static Class<? extends BoundMethodHandle> generateConcreteBMHClass(String types) {
              final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
  
@@ -529,7 +600,7 @@
  
              // emit bound argument fields
              for (int i = 0; i < types.length(); ++i) {
-@@ -644,22 +705,32 @@
+@@ -644,22 +716,32 @@
              mv.visitMaxs(0, 0);
              mv.visitEnd();
  
@@ -567,7 +638,7 @@
              // load mt, lf
              mv.visitVarInsn(ALOAD, 1);
              mv.visitVarInsn(ALOAD, 2);
-@@ -677,11 +748,13 @@
+@@ -677,11 +759,13 @@
                  String extypes = types + t;
                  mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "cloneExtend" + t, makeSignature(String.valueOf(t), false), null, E_THROWABLE);
                  mv.visitCode();
@@ -583,7 +654,7 @@
                  // load mt, lf
                  mv.visitVarInsn(ALOAD, 1);
                  mv.visitVarInsn(ALOAD, 2);
-@@ -696,13 +769,25 @@
+@@ -696,13 +780,25 @@
                  mv.visitEnd();
              }
  
@@ -610,7 +681,7 @@
              UNSAFE.ensureClassInitialized(bmhClass);
  
              return bmhClass;
-@@ -745,21 +830,27 @@
+@@ -745,21 +841,27 @@
              }
          }
  
@@ -641,7 +712,7 @@
                  return (String) ftypes.get(null);
              } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
                  throw new InternalError(e);
-@@ -832,13 +923,15 @@
+@@ -832,13 +934,15 @@
              return cmh;
          }
  
@@ -691,6 +762,557 @@
  
      @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]);
+-        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);
+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 @@
+ 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 java.lang.ref.WeakReference;
++import java.lang.reflect.Field;
+ import sun.invoke.util.ValueConversions;
++import sun.invoke.util.VerifyType;
++import sun.invoke.util.Wrapper;
+ 
+ /**
+- * The flavor of method handle which emulates invokespecial or invokestatic.
++ * The flavor of method handle which implements a constant reference
++ * to a class member.
+  * @author jrose
+  */
+ class DirectMethodHandle extends MethodHandle {
+@@ -44,7 +49,6 @@
+     // Constructors and factory methods in this class *must* be package scoped or private.
+     private DirectMethodHandle(MethodType mtype, MemberName member, LambdaForm form) {
+         super(mtype, form);
+-        assert(member.isMethod() || member.isConstructor());
+         if (!member.isResolved())  throw new InternalError();
+         this.member = member;
+     }
+@@ -52,13 +56,27 @@
+     // 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))
+                 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);
++        } 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);
++            } else {
++                long offset = MethodHandleNatives.objectFieldOffset(member);
++                assert(offset == (int)offset);
++                return new Accessor(mtype, member, lform, (int)offset);
++            }
++        }
+     }
+     static DirectMethodHandle make(MemberName member) {
+         return make(member.getDeclaringClass(), member);
+@@ -116,7 +134,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));
+                 break;
+             }
+         }
+@@ -128,49 +146,57 @@
+      * Cache and share this structure among all methods with
+      * the same basicType and refKind.
+      */
+-    private static LambdaForm preparedLambdaForm(MethodType mtype, MemberName m) {
+-        assert(m.isInvocable()) : "not a method: " + m;
+-        assert(mtype == mtype.basicType());
+-        assert(m.getInvocationType().basicType() == mtype);
++    private static LambdaForm preparedLambdaForm(MemberName m) {
++        assert(m.isInvocable()) : m;  // call preparedFieldLambdaForm instead
++        MethodType mtype = m.getInvocationType().basicType();
+         assert(!m.isMethodHandleInvoke() || "invokeBasic".equals(m.getName())) : m;
+-        byte refKind = m.getReferenceKind();
+-        int which = MethodTypeForm.LF_REF_KIND_FIRST + refKind;
+-        if (refKind == REF_invokeStatic && shouldBeInitialized(m)) {
++        int which;
++        switch (m.getReferenceKind()) {
++        case REF_invokeVirtual:    which = LF_INVVIRTUAL;    break;
++        case REF_invokeStatic:     which = LF_INVSTATIC;     break;
++        case REF_invokeSpecial:    which = LF_INVSPECIAL;    break;
++        case REF_invokeInterface:  which = LF_INVINTERFACE;  break;
++        case REF_newInvokeSpecial: which = LF_NEWINVSPECIAL; break;
++        default:  throw new InternalError(m.toString());
++        }
++        if (which == LF_INVSTATIC && shouldBeInitialized(m)) {
+             // precompute the barrier-free version:
+-            preparedLambdaForm(mtype, refKind, which);
+-            which = MethodTypeForm.LF_INVSTATIC_INIT;
++            preparedLambdaForm(mtype, which);
++            which = LF_INVSTATIC_INIT;
+         }
+-        LambdaForm lform = preparedLambdaForm(mtype, refKind, which);
+-        if (VerifyAccess.isSamePackage(m.getDeclaringClass(), MethodHandle.class))
+-            // Help along bootstrapping...
+-            lform.compileToBytecode();
++        LambdaForm lform = preparedLambdaForm(mtype, which);
++        maybeCompile(lform, m);
++        assert(lform.methodType().dropParameterTypes(0, 1)
++                .equals(m.getInvocationType().basicType()))
++                : Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType());
+         return lform;
+     }
+-    private static LambdaForm preparedLambdaForm(MethodType mtype, byte refKind, int which) {
++
++    private static LambdaForm preparedLambdaForm(MethodType mtype, int which) {
+         LambdaForm lform = mtype.form().cachedLambdaForm(which);
+         if (lform != null)  return lform;
+-        lform = makePreparedLambdaForm(mtype, refKind, which);
++        lform = makePreparedLambdaForm(mtype, which);
+         return mtype.form().setCachedLambdaForm(which, lform);
+     }
+ 
+-    private static LambdaForm makePreparedLambdaForm(MethodType mtype, byte refKind, int which) {
++    private static LambdaForm makePreparedLambdaForm(MethodType mtype, int which) {
++        boolean needsInit = (which == LF_INVSTATIC_INIT);
+         String linkerName, lambdaName;
+-        switch (refKind) {
+-        case REF_invokeVirtual:    linkerName = "linkToVirtual";    lambdaName = "DMH.invokeVirtual";    break;
+-        case REF_invokeStatic:     linkerName = "linkToStatic";     lambdaName = "DMH.invokeStatic";     break;
+-        case REF_invokeSpecial:    linkerName = "linkToSpecial";    lambdaName = "DMH.invokeSpecial";    break;
+-        case REF_invokeInterface:  linkerName = "linkToInterface";  lambdaName = "DMH.invokeInterface";  break;
+-        default:  throw new InternalError("refKind="+refKind);
++        switch (which) {
++        case LF_INVVIRTUAL:    linkerName = "linkToVirtual";    lambdaName = "DMH.invokeVirtual";    break;
++        case LF_INVSTATIC:     linkerName = "linkToStatic";     lambdaName = "DMH.invokeStatic";     break;
++        case LF_INVSTATIC_INIT:linkerName = "linkToStatic";     lambdaName = "DMH.invokeStaticInit"; break;
++        case LF_INVSPECIAL:    linkerName = "linkToSpecial";    lambdaName = "DMH.invokeSpecial";    break;
++        case LF_INVINTERFACE:  linkerName = "linkToInterface";  lambdaName = "DMH.invokeInterface";  break;
++        default:  throw new InternalError("which="+which);
+         }
+         MethodType mtypeWithArg = mtype.appendParameterTypes(MemberName.class);
+         MemberName linker = new MemberName(MethodHandle.class, linkerName, mtypeWithArg, REF_invokeStatic);
+         try {
+             linker = IMPL_NAMES.resolveOrFail(REF_invokeStatic, linker, null, NoSuchMethodException.class);
+-            assert(linker.isStatic());
+         } catch (ReflectiveOperationException ex) {
+             throw new InternalError(ex);
+         }
+-        boolean needEnsureInit = (which == MethodTypeForm.LF_INVSTATIC_INIT);
+         final int DMH_THIS    = 0;
+         final int ARG_BASE    = 1;
+         final int ARG_LIMIT   = ARG_BASE + mtype.parameterCount();
+@@ -179,7 +205,7 @@
+         final int LINKER_CALL = nameCursor++;
+         Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
+         assert(names.length == nameCursor);
+-        if (needEnsureInit)
++        if (needsInit)
+             names[GET_MEMBER] = new Name(NF_internalMemberNameEnsureInit, names[DMH_THIS]);
+         else
+             names[GET_MEMBER] = new Name(NF_internalMemberName, names[DMH_THIS]);
+@@ -189,6 +215,27 @@
+         return new LambdaForm(lambdaName, ARG_LIMIT, names);
+     }
+ 
++    private static void maybeCompile(LambdaForm lform, MemberName m) {
++        if (VerifyAccess.isSamePackage(m.getDeclaringClass(), MethodHandle.class))
++            // Help along bootstrapping...
++            lform.compileToBytecode();
++    }
++
++    /** Static wrapper for DirectMethodHandle.internalMemberName. */
++    @ForceInline
++    /*non-public*/ static Object internalMemberName(Object mh) {
++        return ((DirectMethodHandle)mh).member;
++    }
++
++    /** Static wrapper for DirectMethodHandle.internalMemberName.
++     * This one also forces initialization.
++     */
++    /*non-public*/ static Object internalMemberNameEnsureInit(Object mh) {
++        DirectMethodHandle dmh = (DirectMethodHandle)mh;
++        dmh.ensureInitialized();
++        return dmh.member;
++    }
++
+     /*non-public*/ static
+     boolean shouldBeInitialized(MemberName member) {
+         switch (member.getReferenceKind()) {
+@@ -221,13 +268,6 @@
+         return MethodHandleImpl.UNSAFE.shouldBeInitialized(cls);
+     }
+ 
+-    /*non-public*/ static
+-    @ForceInline
+-    void ensureClassInitialized(Object memberObj) {
+-        MemberName member = (MemberName) memberObj;
+-        EnsureInitialized.INSTANCE.get(member.getDeclaringClass());
+-    }
+-
+     private static class EnsureInitialized extends ClassValue<WeakReference<Thread>> {
+         @Override
+         protected WeakReference<Thread> computeValue(Class<?> type) {
+@@ -241,29 +281,16 @@
+         static final EnsureInitialized INSTANCE = new EnsureInitialized();
+     }
+ 
+-    /** Static wrapper for DirectMethodHandle.internalMemberName. */
+-    @ForceInline
+-    /*non-public*/ static
+-    Object internalMemberName(Object mh) {
+-        return ((DirectMethodHandle)mh).member;
++    private void ensureInitialized() {
++        if (checkInitialized(member)) {
++            // The coast is clear.  Delete the <clinit> barrier.
++            if (member.isField())
++                updateForm(preparedFieldLambdaForm(member));
++            else
++                updateForm(preparedLambdaForm(member));
++        }
+     }
+-
+-    /** Static wrapper for DirectMethodHandle.internalMemberName.
+-     * This one also forces initialization.
+-     */
+-    @ForceInline
+-    /*non-public*/ static
+-    Object internalMemberNameEnsureInit(Object mh) {
+-        DirectMethodHandle dmh = (DirectMethodHandle)mh;
+-        MemberName member = dmh.member;
+-        if (ensureInitialized(member)) {
+-            // The coast is clear.  Delete the cval and the barrier.
+-            dmh.removeInitializationBarrier();
+-        }
+-        return member;
+-    }
+-
+-    private static boolean ensureInitialized(MemberName member) {
++    private static boolean checkInitialized(MemberName member) {
+         Class<?> defc = member.getDeclaringClass();
+         WeakReference<Thread> ref = EnsureInitialized.INSTANCE.get(defc);
+         if (ref == null) {
+@@ -286,52 +313,261 @@
+         return true;
+     }
+ 
+-    private void removeInitializationBarrier() {
+-        MethodType mtype = type().basicType();
+-        LambdaForm oldForm = mtype.form().cachedLambdaForm(MethodTypeForm.LF_INVSTATIC_INIT);
+-        LambdaForm newForm = mtype.form().cachedLambdaForm(MethodTypeForm.LF_INVSTATIC);
+-        assert(oldForm != null && newForm != null);
+-        assert(this.form == oldForm || this.form == newForm);
+-        if (this.form == oldForm) {
+-            this.updateForm(newForm);  //dmh.form = newForm;
+-        }
+-        assert(this.form == newForm);
++    /*non-public*/ static void ensureInitialized(Object mh) {
++        ((DirectMethodHandle)mh).ensureInitialized();
+     }
+ 
+-    private static final NamedFunction NF_internalMemberName;
+-    private static final NamedFunction NF_internalMemberNameEnsureInit;
++    /** This subclass handles 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,
++                         int objectOffset) {
++            super(mtype, member, form);
++            this.fieldType    = member.getFieldType();
++            this.objectOffset = objectOffset;
++        }
++
++        @Override Object checkCast(Object obj) {
++            return fieldType.cast(obj);
++        }
++    }
++
++    @ForceInline
++    /*non-public*/ static long objectOffset(Object accessorObj) {
++        // Note: We return a long because that is what Unsafe.getObject likes.
++        // We store a plain int because it is more compact.
++        return ((Accessor)accessorObj).objectOffset;
++    }
++
++    /** This subclass handles static field references. */
++    static class StaticAccessor extends DirectMethodHandle {
++        final private Class<?> fieldType;
++        final private Object   staticBase;
++        final private long     staticOffset;
++
++        private StaticAccessor(MethodType mtype, MemberName member, LambdaForm form,
++                               Object staticBase, long staticOffset) {
++            super(mtype, member, form);
++            this.fieldType    = member.getFieldType();
++            this.staticBase   = staticBase;
++            this.staticOffset = staticOffset;
++        }
++
++        @Override Object checkCast(Object obj) {
++            return fieldType.cast(obj);
++        }
++    }
++
++    @ForceInline
++    /*non-public*/ static Object staticBase(Object accessorObj) {
++        return ((StaticAccessor)accessorObj).staticBase;
++    }
++
++    @ForceInline
++    /*non-public*/ static long staticOffset(Object accessorObj) {
++        return ((StaticAccessor)accessorObj).staticOffset;
++    }
++
++    @ForceInline
++    /*non-public*/ static Object nullCheck(Object obj) {
++        obj.getClass();
++        return obj;
++    }
++
++    @ForceInline
++    /*non-public*/ static Object checkCast(Object mh, Object obj) {
++        return ((DirectMethodHandle) mh).checkCast(obj);
++    }
++
++    Object checkCast(Object obj) {
++        return member.getReturnType().cast(obj);
++    }
++
++    // Caching machinery for field accessors:
++    private static byte
++            AF_GETFIELD        = 0,
++            AF_PUTFIELD        = 1,
++            AF_GETSTATIC       = 2,
++            AF_PUTSTATIC       = 3,
++            AF_GETSTATIC_INIT  = 4,
++            AF_PUTSTATIC_INIT  = 5,
++            AF_LIMIT           = 6;
++    // Enumerate the different field kinds using Wrapper,
++    // with an extra case added for checked references.
++    private static int
++            FT_LAST_WRAPPER    = Wrapper.values().length-1,
++            FT_UNCHECKED_REF   = Wrapper.OBJECT.ordinal(),
++            FT_CHECKED_REF     = FT_LAST_WRAPPER+1,
++            FT_LIMIT           = FT_LAST_WRAPPER+2;
++    private static int afIndex(byte formOp, boolean isVolatile, int ftypeKind) {
++        return ((formOp * FT_LIMIT * 2)
++                + (isVolatile ? FT_LIMIT : 0)
++                + ftypeKind);
++    }
++    private static final LambdaForm[] ACCESSOR_FORMS
++            = new LambdaForm[afIndex(AF_LIMIT, false, 0)];
++    private static int ftypeKind(Class<?> ftype) {
++        if (ftype.isPrimitive())
++            return Wrapper.forPrimitiveType(ftype).ordinal();
++        else if (VerifyType.isNullReferenceConversion(Object.class, ftype))
++            return FT_UNCHECKED_REF;
++        else
++            return FT_CHECKED_REF;
++    }
++
++    /**
++     * Create a LF which can access the given field.
++     * Cache and share this structure among all fields with
++     * the same basicType and refKind.
++     */
++    private static LambdaForm preparedFieldLambdaForm(MemberName m) {
++        Class<?> ftype = m.getFieldType();
++        boolean isVolatile = m.isVolatile();
++        byte formOp;
++        switch (m.getReferenceKind()) {
++        case REF_getField:      formOp = AF_GETFIELD;    break;
++        case REF_putField:      formOp = AF_PUTFIELD;    break;
++        case REF_getStatic:     formOp = AF_GETSTATIC;   break;
++        case REF_putStatic:     formOp = AF_PUTSTATIC;   break;
++        default:  throw new InternalError(m.toString());
++        }
++        if (shouldBeInitialized(m)) {
++            // precompute the barrier-free version:
++            preparedFieldLambdaForm(formOp, isVolatile, ftype);
++            assert((AF_GETSTATIC_INIT - AF_GETSTATIC) ==
++                   (AF_PUTSTATIC_INIT - AF_PUTSTATIC));
++            formOp += (AF_GETSTATIC_INIT - AF_GETSTATIC);
++        }
++        LambdaForm lform = preparedFieldLambdaForm(formOp, isVolatile, ftype);
++        maybeCompile(lform, m);
++        assert(lform.methodType().dropParameterTypes(0, 1)
++                .equals(m.getInvocationType().basicType()))
++                : Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType());
++        return lform;
++    }
++    private static LambdaForm preparedFieldLambdaForm(byte formOp, boolean isVolatile, Class<?> ftype) {
++        int afIndex = afIndex(formOp, isVolatile, ftypeKind(ftype));
++        LambdaForm lform = ACCESSOR_FORMS[afIndex];
++        if (lform != null)  return lform;
++        lform = makePreparedFieldLambdaForm(formOp, isVolatile, ftypeKind(ftype));
++        ACCESSOR_FORMS[afIndex] = lform;  // don't bother with a CAS
++        return lform;
++    }
++
++    private static LambdaForm makePreparedFieldLambdaForm(byte formOp, boolean isVolatile, int ftypeKind) {
++        boolean isGetter  = (formOp & 1) == (AF_GETFIELD & 1);
++        boolean isStatic  = (formOp >= AF_GETSTATIC);
++        boolean needsInit = (formOp >= AF_GETSTATIC_INIT);
++        boolean needsCast = (ftypeKind == FT_CHECKED_REF);
++        Wrapper fw = (needsCast ? Wrapper.OBJECT : Wrapper.values()[ftypeKind]);
++        Class<?> ft = fw.primitiveType();
++        assert(ftypeKind(needsCast ? String.class : ft) == ftypeKind);
++        String tname  = fw.primitiveSimpleName();
++        String ctname = Character.toUpperCase(tname.charAt(0)) + tname.substring(1);
++        String linkerName = ((isGetter ? "get" : "put") + ctname + (isVolatile? "Volatile" : ""));
++        MethodType linkerType;
++        if (isGetter)
++            linkerType = MethodType.methodType(ft, Object.class, long.class);
++        else
++            linkerType = MethodType.methodType(void.class, Object.class, long.class, ft);
++        MemberName linker = new MemberName(Unsafe.class, linkerName, linkerType, REF_invokeVirtual);
++        try {
++            linker = IMPL_NAMES.resolveOrFail(REF_invokeVirtual, linker, null, NoSuchMethodException.class);
++        } catch (ReflectiveOperationException ex) {
++            throw new InternalError(ex);
++        }
++
++        // What is the external type of the lambda form?
++        MethodType mtype;
++        if (isGetter)
++            mtype = MethodType.methodType(ft);
++        else
++            mtype = MethodType.methodType(void.class, ft);
++        mtype = mtype.basicType();  // erase short to int, etc.
++        if (!isStatic)
++            mtype = mtype.insertParameterTypes(0, Object.class);
++        final int DMH_THIS  = 0;
++        final int ARG_BASE  = 1;
++        final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
++        // if this is for non-static access, the base pointer is stored at this index:
++        final int OBJ_BASE  = isStatic ? -1 : ARG_BASE;
++        // if this is for write access, the value to be written is stored at this index:
++        final int SET_VALUE  = isGetter ? -1 : ARG_LIMIT - 1;
++        int nameCursor = ARG_LIMIT;
++        final int NPE_CHECK = (OBJ_BASE >= 0 ? nameCursor++ : -1);
++        final int INIT_BAR  = (needsInit ? nameCursor++ : -1);
++        final int CAST_1    = (needsCast && !isGetter ? nameCursor++ : -1);
++        final int F_OFFSET  = nameCursor++;
++        final int ST_BASE   = (isStatic ?  nameCursor++ : -1);
++        final int LINKER_CALL = nameCursor++;
++        final int CAST_2    = (needsCast && isGetter ? nameCursor++ : -1);
++        final int RESULT    = nameCursor-1;  // either the call or the cast
++        Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
++        if (needsInit)
++            names[INIT_BAR] = new Name(NF_ensureInitialized, names[DMH_THIS]);
++        if (needsCast && !isGetter)
++            names[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;
++        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]);
++        } else {
++            outArgs[1] = names[NPE_CHECK] = new Name(NF_nullCheck, names[OBJ_BASE]);
++            outArgs[2] = names[F_OFFSET]  = new Name(NF_objectOffset, names[DMH_THIS]);
++        }
++        if (!isGetter) {
++            outArgs[3] = (needsCast ? names[CAST_1] : names[SET_VALUE]);
++        }
++        for (Object a : outArgs)  assert(a != null);
++        names[LINKER_CALL] = new Name(linker, outArgs);
++        if (needsCast && isGetter)
++            names[CAST_2] = new Name(NF_checkCast, names[DMH_THIS], names[LINKER_CALL]);
++        for (Name n : names)  assert(n != null);
++        String lambdaName = linkerName;  // significant only for debugging
++        if (needsCast)  lambdaName += "Cast";
++        if (needsInit)  lambdaName += "Init";
++        return new LambdaForm(lambdaName, ARG_LIMIT, names);
++    }
++
++    private static final NamedFunction
++            NF_internalMemberName,
++            NF_internalMemberNameEnsureInit,
++            NF_ensureInitialized,
++            NF_staticBase,
++            NF_staticOffset,
++            NF_nullCheck,
++            NF_objectOffset,
++            NF_checkCast;
+     static {
+         try {
+-            NF_internalMemberName = new NamedFunction(DirectMethodHandle.class
+-                    .getDeclaredMethod("internalMemberName", Object.class));
+-            NF_internalMemberNameEnsureInit = new NamedFunction(DirectMethodHandle.class
+-                    .getDeclaredMethod("internalMemberNameEnsureInit", Object.class));
+-            NF_internalMemberName.resolve();
+-            NF_internalMemberNameEnsureInit.resolve();
+-            // bound
++            NamedFunction nfs[] = {
++                NF_internalMemberName = new NamedFunction(DirectMethodHandle.class
++                    .getDeclaredMethod("internalMemberName", Object.class)),
++                NF_internalMemberNameEnsureInit = new NamedFunction(DirectMethodHandle.class
++                    .getDeclaredMethod("internalMemberNameEnsureInit", Object.class)),
++                NF_ensureInitialized = new NamedFunction(DirectMethodHandle.class
++                    .getDeclaredMethod("ensureInitialized", Object.class)),
++                NF_staticBase = new NamedFunction(DirectMethodHandle.class
++                    .getDeclaredMethod("staticBase", Object.class)),
++                NF_staticOffset = new NamedFunction(DirectMethodHandle.class
++                    .getDeclaredMethod("staticOffset", Object.class)),
++                NF_nullCheck = new NamedFunction(DirectMethodHandle.class
++                    .getDeclaredMethod("nullCheck", Object.class)),
++                NF_objectOffset = new NamedFunction(DirectMethodHandle.class
++                    .getDeclaredMethod("objectOffset", Object.class)),
++                NF_checkCast = new NamedFunction(DirectMethodHandle.class
++                    .getDeclaredMethod("checkCast", Object.class, Object.class))
++            };
++            for (NamedFunction nf : nfs) {
++                // Each nf must be statically invocable or we get tied up in our bootstraps.
++                assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf.member)) : nf;
++                nf.resolve();
++            }
+         } catch (ReflectiveOperationException ex) {
+             throw new InternalError(ex);
+         }
+     }
+-
+-/*
+-    // Smoke-test:
+-    static void testDirectMethodHandles() throws Throwable {
+-        MemberName.Factory lookup = MemberName.getFactory();
+-        MethodHandle asList_MH = make(Arrays.class.getMethod("asList", Object[].class));
+-        System.out.println("about to call "+asList_MH);
+-        Object[] abc = { "a", "bc" };
+-        java.util.List<?> lst = (java.util.List<?>) asList_MH.invokeExact(abc);
+-        System.out.println("lst="+lst);
+-        MethodHandle toString_MH = make(new MemberName(Object.class.getMethod("toString")));
+-        String s1 = (String) toString_MH.invokeExact((Object) lst);
+-        toString_MH = make(new MemberName(Object.class.getMethod("toString"), true));
+-        String s2 = (String) toString_MH.invokeExact((Object) lst);
+-        System.out.println("[s1,s2,lst]="+Arrays.asList(s1, s2, lst.toString()));
+-        MethodHandle toArray_MH = make(new MemberName(java.util.List.class.getMethod("toArray")));
+-        Object[] arr = (Object[]) toArray_MH.invokeExact(lst);
+-        System.out.println("toArray="+Arrays.toString(arr));
+-    }
+-    static { try { testDirectMethodHandles(); } catch (Throwable ex) { throw new RuntimeException(ex); } }
+-//*/
+ }
 diff --git a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
 --- a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
 +++ b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
@@ -700,7 +1322,7 @@
  
 +        // Get the BMH class name, if used.
 +        String bmhClassName = constructBMHClassName();
-+        
++
          // 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++) {
@@ -717,6 +1339,24 @@
              } else if (isStaticallyInvocable(member)) {
                  emitStaticInvoke(member, name);
              } else {
+@@ -601,7 +606,7 @@
+         //MethodHandle.class already covered
+     };
+ 
+-    boolean isStaticallyInvocable(MemberName member) {
++    static boolean isStaticallyInvocable(MemberName member) {
+         if (member == null)  return false;
+         assert !member.isConstructor();
+         Class<?> cls = member.getDeclaringClass();
+@@ -618,7 +623,7 @@
+         return false;
+     }
+ 
+-    boolean isStaticallyNameable(Class<?> cls) {
++    static boolean isStaticallyNameable(Class<?> cls) {
+         while (cls.isArray())
+             cls = cls.getComponentType();
+         if (cls.isPrimitive())
 @@ -741,6 +746,75 @@
      }
  
@@ -793,6 +1433,92 @@
       *
       * @param name
       * @param paramIndex
+@@ -753,6 +827,8 @@
+             Name n = (Name) arg;
+             emitLoadInsn(n.type, n.index());
+             emitImplicitConversion(n.type, mtype.parameterType(paramIndex));
++        } else if ((arg == null || arg instanceof String) && ptype == 'L') {
++            emitConst(arg);
+         } else {
+             if (Wrapper.isWrapperType(arg.getClass()) && ptype != 'L') {
+                 emitConst(arg);
+diff --git a/src/share/classes/java/lang/invoke/Invokers.java b/src/share/classes/java/lang/invoke/Invokers.java
+--- a/src/share/classes/java/lang/invoke/Invokers.java
++++ b/src/share/classes/java/lang/invoke/Invokers.java
+@@ -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);
+             // 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 @@
+      * as a sort of pre-invocation linkage step.)
+      */
+     public void prepare() {
++        if (COMPILE_THRESHOLD == 0) {
++            compileToBytecode();
++        }
+         if (this.vmentry != null) {
+             // already prepared (e.g., a primitive DMH invoker form)
+             return;
+@@ -574,7 +577,13 @@
+     }
+ 
+     /** If the invocation count hits the threshold we spin bytecodes and call that subsequently. */
+-    private static final int invocationThreshold = 30;
++    private static final int COMPILE_THRESHOLD;
++    static {
++        if (MethodHandleStatics.COMPILE_THRESHOLD != null)
++            COMPILE_THRESHOLD = MethodHandleStatics.COMPILE_THRESHOLD;
++        else
++            COMPILE_THRESHOLD = 30;  // default value
++    }
+     private int invocationCounter = 0;
+ 
+     @Hidden
+@@ -582,9 +591,10 @@
+     Object interpretWithArguments(Object... argumentValues) throws Throwable {
+         if (TRACE_INTERPRETER)
+             return interpretWithArgumentsTracing(argumentValues);
+-        if (invocationCounter < invocationThreshold) {
++        if (COMPILE_THRESHOLD != 0 &&
++            invocationCounter < COMPILE_THRESHOLD) {
+             invocationCounter++;  // benign race
+-            if (invocationCounter >= invocationThreshold) {
++            if (invocationCounter >= COMPILE_THRESHOLD) {
+                 // Replace vmentry with a bytecode version of this LF.
+                 compileToBytecode();
+             }
+@@ -617,10 +627,10 @@
+ 
+     Object interpretWithArgumentsTracing(Object... argumentValues) throws Throwable {
+         traceInterpreter("[ interpretWithArguments", this, argumentValues);
+-        if (invocationCounter < invocationThreshold) {
++        if (invocationCounter < COMPILE_THRESHOLD) {
+             int ctr = invocationCounter++;  // benign race
+             traceInterpreter("| invocationCounter", ctr);
+-            if (invocationCounter >= invocationThreshold) {
++            if (invocationCounter >= COMPILE_THRESHOLD) {
+                 compileToBytecode();
+             }
+         }
+@@ -759,8 +769,8 @@
+         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);
+     }
+ 
 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
@@ -824,7 +1550,129 @@
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.HashMap;
-@@ -659,11 +661,14 @@
+@@ -185,121 +187,6 @@
+         }
+     }
+ 
+-    static MethodHandle makeFieldAccessor(byte refKind, MemberName field, Class<?> receiver) {
+-        boolean isStatic = !MethodHandleNatives.refKindHasReceiver(refKind);
+-        MethodHandle accessor = FieldAccessor.getAccessor(refKind, field, receiver);
+-
+-        MethodType srcType = accessor.type();
+-        MethodType mhType = srcType.dropParameterTypes(isStatic ? 0 : 1, 2);
+-        MethodType lambdaType = mhType.insertParameterTypes(0, isStatic ? BoundMethodHandle.BMH_JL.class : BoundMethodHandle.BMH_J.class);
+-
+-        Name[] names = arguments(3, lambdaType);
+-
+-        final int _ARG    = 1;                // at this index in the names array, the object to be accessed is stored
+-        final int _VALUE  = isStatic ? 1 : 2; // if this is for write access, the value to be written is stored at this index
+-        final int _BASE   = names.length - 3; // the slots for _BASE and _NPE are shared
+-        final int _NPE    = names.length - 3; // (the NPE check is used in the non-static case only, where _BASE is not required)
+-        final int _OFFSET = names.length - 2;
+-        final int _RESULT = names.length - 1;
+-
+-        if (isStatic) {
+-            names[_OFFSET] = new Name(BoundMethodHandle.MH_argJ0, names[0]);
+-            names[_BASE]   = new Name(BoundMethodHandle.MH_argL1, names[0]);
+-        } else {
+-            names[_NPE] = new Name(FieldAccessor.OBJECT_GETCLASS, names[_ARG]); // NPE check
+-            names[_OFFSET] = new Name(BoundMethodHandle.MH_argJ0, names[0]);
+-        }
+-
+-        Object[] args;
+-        if (refKind == REF_putField || refKind == REF_putStatic) {
+-            args = new Object[] { names[isStatic ? _BASE : _ARG], names[_OFFSET], names[_VALUE] };
+-        } else {
+-            args = new Object[] { names[isStatic ? _BASE : _ARG], names[_OFFSET] };
+-        }
+-        names[_RESULT] = new Name(accessor, args);
+-        LambdaForm form = new LambdaForm(MethodHandleNatives.refKindName(refKind), lambdaType.parameterCount(), names);
+-
+-        BoundMethodHandle mh;
+-        if (isStatic) {
+-            long offset = MethodHandleNatives.staticFieldOffset(field);
+-            Object base = MethodHandleNatives.staticFieldBase(field);
+-            mh = new BoundMethodHandle.BMH_JL(mhType, form, offset, base);
+-        } else {
+-            long offset = MethodHandleNatives.objectFieldOffset(field);
+-            mh = new BoundMethodHandle.BMH_J(mhType, form, offset);
+-        }
+-        return mh;
+-    }
+-
+-    static final class FieldAccessor {
+-        static final MethodHandle OBJECT_GETCLASS;
+-        static {
+-            try {
+-                assert(IMPL_LOOKUP != null) : "bootstrap problem";
+-                OBJECT_GETCLASS =
+-                    IMPL_LOOKUP.findStatic(FieldAccessor.class, "getClass", MethodType.methodType(Object.class, Object.class));
+-            } catch (NoSuchMethodException | IllegalAccessException e) {
+-                throw new InternalError(e);
+-            }
+-        }
+-
+-        /** Static definition of Object.getClass for null-pointer checking. */
+-        /*non-public*/ static
+-        @ForceInline
+-        Object getClass(Object obj) {
+-            return obj.getClass();
+-        }
+-
+-        static String name(byte refKind, MemberName field) {
+-            String prefix = MethodHandleNatives.refKindIsGetter(refKind) ? "get" : "put";
+-            String type   = Wrapper.forBasicType(field.getFieldType()).primitiveSimpleName();
+-            String suffix = field.isVolatile() ? "Volatile" : "";
+-            return prefix + Character.toUpperCase(type.charAt(0)) + type.substring(1) + suffix;
+-        }
+-        static MethodType type(byte refKind, MemberName field) {
+-            Class<?> fieldClass = field.getFieldType();
+-            return type(refKind, Object.class, fieldClass.isPrimitive() ? fieldClass : Object.class);
+-        }
+-        static MethodType strongType(byte refKind, MemberName field, Class<?> receiver) {
+-            Class<?> fieldClass = field.getFieldType();
+-            MethodType type;
+-            if (MethodHandleNatives.refKindHasReceiver(refKind)) {
+-                if (!field.getDeclaringClass().isAssignableFrom(receiver))
+-                    throw new InternalError(field.toString());
+-                type = type(refKind, receiver,     fieldClass);
+-            } else {
+-                type = type(refKind, Object.class, fieldClass);
+-            }
+-            return type.insertParameterTypes(0, Unsafe.class);
+-        }
+-        static MethodType type(byte refKind, Class<?> declaringClass, Class<?> fieldClass) {
+-            if (MethodHandleNatives.refKindIsGetter(refKind))
+-                return MethodType.methodType(fieldClass, declaringClass, long.class);
+-            else
+-                return MethodType.methodType(void.class, declaringClass, long.class, fieldClass);
+-        }
+-        static MethodHandle getAccessor(byte refKind, MemberName field, Class<?> receiver) {
+-            if (!MethodHandleNatives.refKindIsField(refKind))
+-                throw newIllegalArgumentException("refKind not a field: " + refKind);
+-            String     name = name(refKind, field);
+-            MethodType type = type(refKind, field);
+-            MethodHandle mh;
+-            try {
+-                mh = IMPL_LOOKUP.findVirtual(Unsafe.class, name, type);
+-            } catch (ReflectiveOperationException ex) {
+-                throw uncaughtException(ex);
+-            }
+-            Class<?> declaringClass = field.getDeclaringClass();
+-            Class<?> fieldClass     = field.getFieldType();
+-            if ((!fieldClass.isPrimitive() && fieldClass != Object.class) || (MethodHandleNatives.refKindHasReceiver(refKind) && declaringClass != Object.class)) {
+-                MethodType strongType = strongType(refKind, field, receiver);
+-                mh = convertArguments(mh, strongType, 0);
+-            }
+-            mh = mh.bindImmediate(0, 'L', UNSAFE); // bind UNSAFE early
+-            return mh;
+-        }
+-    }
+-
+     /*non-public*/ static
+     MethodHandle convertArguments(MethodHandle target, MethodType srcType, int level) {
+         MethodType dstType = target.type();
+@@ -659,11 +546,14 @@
          }
  
          @Override
@@ -842,3 +1690,119 @@
  
          @Override
          public MethodHandle asType(MethodType newType) {
+@@ -1028,9 +918,7 @@
+                 indexes[i] = argIndex;
+             }
+         }
+-        assert(nameCursor == names.length-1)
+-                : Arrays.asList(Arrays.asList(names), names.length, nameCursor, srcType, lambdaType, target, spreadArgPos, spreadArgCount)//@@
+-                ;  // leave room for the final call
++        assert(nameCursor == names.length-1);  // leave room for the final call
+ 
+         // Build argument array for the call.
+         Name[] targetArgs = new Name[targetType.parameterCount()];
+diff --git a/src/share/classes/java/lang/invoke/MethodHandleStatics.java b/src/share/classes/java/lang/invoke/MethodHandleStatics.java
+--- a/src/share/classes/java/lang/invoke/MethodHandleStatics.java
++++ b/src/share/classes/java/lang/invoke/MethodHandleStatics.java
+@@ -42,14 +42,16 @@
+     static final boolean DUMP_CLASS_FILES;
+     static final boolean TRACE_INTERPRETER;
+     static final boolean TRACE_METHOD_LINKAGE;
++    static final Integer COMPILE_THRESHOLD;
+     static {
+-        final Object[] values = { false, false, false, false };
++        final Object[] values = { false, false, false, false, null };
+         AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                 public Void run() {
+                     values[0] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
+                     values[1] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DUMP_CLASS_FILES");
+                     values[2] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_INTERPRETER");
+                     values[3] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE");
++                    values[4] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD");
+                     return null;
+                 }
+             });
+@@ -57,6 +59,7 @@
+         DUMP_CLASS_FILES          = (Boolean) values[1];
+         TRACE_INTERPRETER         = (Boolean) values[2];
+         TRACE_METHOD_LINKAGE      = (Boolean) values[3];
++        COMPILE_THRESHOLD         = (Integer) values[4];
+     }
+ 
+     /*non-public*/ static String getNameString(MethodHandle target, MethodType type) {
+diff --git a/src/share/classes/java/lang/invoke/MethodHandles.java b/src/share/classes/java/lang/invoke/MethodHandles.java
+--- a/src/share/classes/java/lang/invoke/MethodHandles.java
++++ b/src/share/classes/java/lang/invoke/MethodHandles.java
+@@ -1111,9 +1111,7 @@
+         void checkAccess(byte refKind, Class<?> refc, MemberName m) throws IllegalAccessException {
+             assert(m.referenceKindIsConsistentWith(refKind) &&
+                    MethodHandleNatives.refKindIsValid(refKind) &&
+-                   (MethodHandleNatives.refKindIsField(refKind) == m.isField()))
+-                : m.toString()+"!="+refKind //@@
+-                ;
++                   (MethodHandleNatives.refKindIsField(refKind) == m.isField()));
+             int allowedModes = this.allowedModes;
+             if (allowedModes == TRUSTED)  return;
+             int mods = m.getModifiers();
+@@ -1221,7 +1219,7 @@
+         }
+         private MethodHandle getDirectField(byte refKind, Class<?> refc, MemberName field) throws IllegalAccessException {
+             checkField(refKind, refc, field);
+-            MethodHandle mh = MethodHandleImpl.makeFieldAccessor(refKind, field, refc);
++            MethodHandle mh = DirectMethodHandle.make(refc, field);
+             boolean doRestrict = (MethodHandleNatives.refKindHasReceiver(refKind) &&
+                                     restrictProtectedReceiver(field));
+             if (doRestrict)
+diff --git a/src/share/classes/java/lang/invoke/MethodTypeForm.java b/src/share/classes/java/lang/invoke/MethodTypeForm.java
+--- a/src/share/classes/java/lang/invoke/MethodTypeForm.java
++++ b/src/share/classes/java/lang/invoke/MethodTypeForm.java
+@@ -59,22 +59,21 @@
+     final LambdaForm[] lambdaForms;
+     // Indexes into lambdaForms:
+     static final int
+-            LF_REF_KIND_FIRST =  0,
+-            LF_REF_KIND_LIMIT =  LF_REF_KIND_FIRST + REF_LIMIT,
+-            // add more variations of DMH invokers as needed...
+-            LF_INVSTATIC_INIT =  0 + LF_REF_KIND_LIMIT,
+-            LF_INTERPRET      =  1 + LF_REF_KIND_LIMIT,
+-            LF_COUNTER        =  2 + LF_REF_KIND_LIMIT,
+-            LF_REINVOKE       =  3 + LF_REF_KIND_LIMIT,
+-            LF_EX_LINKER      =  4 + LF_REF_KIND_LIMIT,
+-            LF_EX_INVOKER     =  5 + LF_REF_KIND_LIMIT,
+-            LF_GEN_LINKER     =  6 + LF_REF_KIND_LIMIT,
+-            LF_GEN_INVOKER    =  7 + LF_REF_KIND_LIMIT,
+-            LF_CS_LINKER      =  8 + LF_REF_KIND_LIMIT,
+-            // add more here as needed...
+-            LF_LIMIT          =  9 + LF_REF_KIND_LIMIT,
+-            // Helpful alias:
+-            LF_INVSTATIC      =  LF_REF_KIND_FIRST + REF_invokeStatic;
++            LF_INVVIRTUAL     =  0,  // DMH invokeVirtual
++            LF_INVSTATIC      =  1,
++            LF_INVSPECIAL     =  2,
++            LF_NEWINVSPECIAL  =  3,
++            LF_INVINTERFACE   =  4,
++            LF_INVSTATIC_INIT =  5,  // DMH invokeStatic with <clinit> barrier
++            LF_INTERPRET      =  6,  // LF interpreter
++            LF_COUNTER        =  7,  // CMH wrapper
++            LF_REINVOKE       =  8,  // other wrapper
++            LF_EX_LINKER      =  9,  // invokeExact_MT
++            LF_EX_INVOKER     = 10,  // invokeExact MH
++            LF_GEN_LINKER     = 11,
++            LF_GEN_INVOKER    = 12,
++            LF_CS_LINKER      = 13,  // linkToCallSite_CS
++            LF_LIMIT          = 14;
+ 
+     public MethodType erasedType() {
+         return erasedType;
+diff --git a/src/share/classes/java/lang/invoke/SimpleMethodHandle.java b/src/share/classes/java/lang/invoke/SimpleMethodHandle.java
+--- a/src/share/classes/java/lang/invoke/SimpleMethodHandle.java
++++ b/src/share/classes/java/lang/invoke/SimpleMethodHandle.java
+@@ -40,7 +40,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);
+         return BoundMethodHandle.bindSingle(type2, form2, basicType, value);
+     }
+