changeset 409:56879e348afe

meth: performance work
author jrose
date Sat, 14 Jul 2012 18:02:46 -0700
parents a436cf481411
children 32510db69498
files meth-lazy-7023639.bmh.patch meth-lazy-7023639.init.patch series
diffstat 3 files changed, 1175 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/meth-lazy-7023639.bmh.patch	Sat Jul 14 18:02:46 2012 -0700
@@ -0,0 +1,844 @@
+Addendum to meth-lazy-7023639.patch.
+Adjustments to BMHs.
+
+diff --git a/src/share/classes/java/lang/invoke/BoundMethodHandle.java b/src/share/classes/java/lang/invoke/BoundMethodHandle.java
+--- a/src/share/classes/java/lang/invoke/BoundMethodHandle.java
++++ b/src/share/classes/java/lang/invoke/BoundMethodHandle.java
+@@ -25,23 +25,7 @@
+ 
+ package java.lang.invoke;
+ 
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ACC_FINAL;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ACC_PUBLIC;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ACC_STATIC;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ACC_SUPER;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ALOAD;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ARETURN;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.DLOAD;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.FLOAD;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.GETFIELD;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ILOAD;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.INVOKESPECIAL;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.INVOKESTATIC;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.LLOAD;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.PUTFIELD;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.RETURN;
+-import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.V1_6;
++import static 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 com.sun.xml.internal.ws.org.objectweb.asm.ClassWriter;
+ import com.sun.xml.internal.ws.org.objectweb.asm.MethodVisitor;
++import com.sun.xml.internal.ws.org.objectweb.asm.Type;
+ 
+ /**
+  * The flavor of method handle which emulates an invoke instruction
+@@ -86,16 +71,16 @@
+             case 'L': return new BMH_L(type, form, x);
+             case 'I':
+                 assert x instanceof Integer : "expected Integer, found " + x.getClass();
+-                return (BoundMethodHandle) Data.get("I").constructor.invokeBasic(type, form, ((Integer) x).intValue());
++                return (BoundMethodHandle) Data.get("I").constructor[0].invokeBasic(type, form, ((Integer) x).intValue());
+             case 'J':
+                 assert x instanceof Long;
+                 return new BMH_J(type, form, ((Long) x).longValue());
+             case 'F':
+                 assert x instanceof Float;
+-                return (BoundMethodHandle) Data.get("F").constructor.invokeBasic(type, form, ((Float) x).floatValue());
++                return (BoundMethodHandle) Data.get("F").constructor[0].invokeBasic(type, form, ((Float) x).floatValue());
+             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).doubleValue());
+             default : throw new InternalError("unexpected xtype: " + xtype);
+             }
+         } catch (Throwable t) {
+@@ -122,7 +107,6 @@
+             default : throw new InternalError("unexpected type: " + xtype);
+             }
+         } catch (Throwable t) {
+-            System.out.println("cloneExtend "+Arrays.asList(type, form, xtype, x));//@@
+             throw new InternalError(t);
+         }
+     }
+@@ -158,27 +142,29 @@
+     }
+ 
+     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);
+     }
+ 
+     /**
+@@ -201,16 +187,16 @@
+ 
+     @Override
+     final Object internalValues() {
+-        Object[] boundValues = new Object[types().length()];
++        Object[] boundValues = new Object[myTypes().length()];
+         for (int i = 0; i < boundValues.length; ++i) {
+             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;
+-                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);
+@@ -254,10 +240,15 @@
+             this.argL0 = argL0;
+         }
+         @Override
+-        public String types() {
+-            return types;
++        public String myTypes() {
++            return TYPES;
+         }
+-        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);
+         @Override
+         public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
+             return new BMH_L(mt, lf, argL0);
+@@ -268,19 +259,19 @@
+         }
+         @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);
+         }
+         @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);
+         }
+         @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);
+         }
+         @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);
+         }
+     }
+ 
+@@ -293,33 +284,38 @@
+             this.argL1 = argL1;
+         }
+         @Override
+-        public String types() {
+-            return types;
++        public String myTypes() {
++            return TYPES;
+         }
+-        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);
+         @Override
+         public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
+             return new BMH_LL(mt, lf, argL0, argL1);
+         }
+         @Override
+         public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
+-            return (BoundMethodHandle) Data.get("LLL").constructor.invokeBasic(mt, lf, argL0, argL1, narg);
++            return (BoundMethodHandle) Data.get("LLL").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);
+         }
+         @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);
+         }
+         @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);
+         }
+         @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);
+         }
+     }
+ 
+@@ -332,10 +328,15 @@
+             this.argL1 = argL1;
+         }
+         @Override
+-        public String types() {
+-            return types;
++        public String myTypes() {
++            return TYPES;
+         }
+-        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);
+         @Override public final long   argJ0() { return argJ0; }
+         @Override public final Object argL1() { return argL1; }
+         @Override
+@@ -344,23 +345,23 @@
+         }
+         @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);
+         }
+         @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);
+         }
+         @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);
+         }
+         @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);
+         }
+         @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);
+         }
+     }
+ 
+@@ -371,10 +372,15 @@
+             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 +392,19 @@
+         }
+         @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 {
+-            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 {
+-            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 {
+-            return (BoundMethodHandle) Data.get("JD").constructor.invokeBasic(mt, lf, argJ0, narg);
++            return (BoundMethodHandle) Data.get("JD").constructor[0].invokeBasic(mt, lf, argJ0, narg);
+         }
+     }
+ 
+@@ -452,37 +458,80 @@
+     static class Data {
+         final String                             types;
+         final Class<? extends BoundMethodHandle> clazz;
+-        final MethodHandle                       constructor;
++        // Bootstrapping requires circular relations MH -> BMH -> Data -> MH
++        // Therefore, we need a non-final link in the chain.  Use array elements.
++        final MethodHandle[]                     constructor;
+         final MethodHandle[]                     getters;
+ 
+-        Data(String types, Class<? extends BoundMethodHandle> clazz, MethodHandle constructor, MethodHandle[] getters) {
++        private Data(String types, Class<? extends BoundMethodHandle> clazz) {
+             this.types = types;
+             this.clazz = clazz;
+-            this.constructor = constructor;
+-            this.getters = getters;
++            if (!INIT_DONE) {
++                this.constructor = new MethodHandle[1];
++                this.getters = new MethodHandle[types.length()];
++            } else {
++                this.constructor = Factory.makeCtors(clazz, types, null);
++                this.getters = Factory.makeGetters(clazz, types, null);
++            }
+         }
+ 
+-        static Map<String, Data> CACHE = new IdentityHashMap<>();
+-
+-        static Data make(String types) {
+-            final Class<? extends BoundMethodHandle> cbmh = Factory.generateConcreteBMHClass(types);
+-            final MethodHandle ctor = Factory.makeCbmhCtor(cbmh, types);
+-            final MethodHandle[] getters = Factory.makeGetters(cbmh, types);
+-            return new Data(types, cbmh, ctor, getters);
++        private void initForBootstrap() {
++            assert(!INIT_DONE);
++            if (constructor[0] == null) {
++                Factory.makeCtors(clazz, types, this.constructor);
++                Factory.makeGetters(clazz, types, this.getters);
++            }
+         }
+ 
++        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) {
+-            final String key = types.intern();
+-            Data d = CACHE.get(key);
+-            if (d == null) {
+-                d = make(types);
+-                Data e = CACHE.get(key);
+-                if (e != null) {
+-                    d = e;
+-                } else {
+-                    CACHE.put(key, d);
+-                }
++            // Acquire cache lock for query.
++            Data d = accessCache(types, null);
++            if (!d.isPlaceholder())
++                return d;
++            Class<? extends BoundMethodHandle> cbmh;
++            synchronized (d) {
++                // Use synch. on the placeholder to prevent multiple instantiation of one species.
++                // Creating this class forces a recursive call to getForClass.
++                cbmh = Factory.generateConcreteBMHClass(types);
+             }
++            // Reacquire cache lock.
++            d = accessCache(types, null);
++            // Class loading must have upgraded the cache.
++            assert(d != null && !d.isPlaceholder());
++            return d;
++        }
++        static Data getForClass(String types, Class<? extends BoundMethodHandle> clazz) {
++            // clazz is a new class which is initializing its DATA field
++            return accessCache(types, new Data(types, clazz));
++        }
++        private static synchronized Data accessCache(String types, Data upgrade) {
++            assert(types == types.intern());  // caller responsibility
++            Data d;
++            if (upgrade != null) {
++                assert((d = CACHE.get(types)) == null || d.isPlaceholder());
++                d = upgrade;
++                CACHE.put(types, d);
++                return d;
++            }
++            d = CACHE.get(types);
++            if (d != null) {
++                return d;
++            }
++            d = new Data(types);
++            assert(d.isPlaceholder());
++            CACHE.put(types, d);
+             return d;
+         }
+ 
+@@ -494,16 +543,23 @@
+                     if (BMH.isAssignableFrom(c)) {
+                         final Class<? extends BoundMethodHandle> cbmh = c.asSubclass(BoundMethodHandle.class);
+                         final String types = Factory.typesFromConcreteBMHClass(cbmh);
+-                        final MethodHandle ctor = Factory.makeCbmhCtor(cbmh, types);
+-                        final MethodHandle[] getters = Factory.makeGetters(cbmh, types);
+-                        final Data d = new Data(types, cbmh, ctor, getters);
+-                        CACHE.put(types.intern(), d);
++                        Data d;
++                        assert((d = accessCache(types, null)) != null && d.clazz == cbmh);
+                     }
+                 }
+             } 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;
++        }
+     }
+ 
+     /**
+@@ -520,18 +576,21 @@
+      */
+     static class Factory {
+ 
+-        static final String JLO_SIG = "Ljava/lang/Object;";
+-        static final String JLS_SIG = "Ljava/lang/String;";
+-        static final String MH = "java/lang/invoke/MethodHandle";
+-        static final String MH_SIG = "Ljava/lang/invoke/MethodHandle;";
+-        static final String BMH = "java/lang/invoke/BoundMethodHandle";
+-        static final String BMH_SIG = "Ljava/lang/invoke/BoundMethodHandle;";
+-        static final String DATA = "java/lang/invoke/BoundMethodHandle$Data";
++        static final String JLO_SIG  = "Ljava/lang/Object;";
++        static final String JLS_SIG  = "Ljava/lang/String;";
++        static final String JLC_SIG  = "Ljava/lang/Class;";
++        static final String MH       = "java/lang/invoke/MethodHandle";
++        static final String MH_SIG   = "Ljava/lang/invoke/MethodHandle;";
++        static final String BMH      = "java/lang/invoke/BoundMethodHandle";
++        static final String BMH_SIG  = "Ljava/lang/invoke/BoundMethodHandle;";
++        static final String DATA     = "java/lang/invoke/BoundMethodHandle$Data";
+         static final String DATA_SIG = "Ljava/lang/invoke/BoundMethodHandle$Data;";
+ 
+-        static final String BMHDATA_GET_SIG = "(" + JLS_SIG + ")" + DATA_SIG;
+-        static final String TYPES_SIG = "()" + JLS_SIG;
++        static final String BMHDATA_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 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 +606,7 @@
+          * <pre>
+          * class BMH_<<types>> extends BMH {
+          *     <<fields>>
+-         *     final String dataValueTypes() { return <<types>>; }
++         *     final String dataValuemyTypes() { return <<types>>; }
+          * }
+          * </pre>
+          *
+@@ -572,25 +631,27 @@
+          *         this.argL1 = argL1;
+          *         this.argI2 = argI2;
+          *     }
+-         *     public final String dataValueTypes() { return types; }
+-         *     public static final String types = "LLI";
++         *     public final String myTypes() { return TYPES; }
++         *     public static final String TYPES = "LLI";
++         *     public final Data myData() { return DATA; }
++         *     public static final Data DATA = Data.getForClass(TYPES, BMH_LLI.class);
+          *     public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) {
+-         *         return myData().constructor.invokeBasic(mt, lf, argL0, argL1, argI2);
++         *         return DATA.constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2);
+          *     }
+          *     public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) {
+-         *         return BMHData.get("LLIL").constructor.invokeBasic(mt, lf, argL0, argL1, argI2, narg);
++         *         return BMHData.get("LLIL").constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
+          *     }
+          *     public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) {
+-         *         return BMHData.get("LLII").constructor.invokeBasic(mt, lf, argL0, argL1, argI2, narg);
++         *         return BMHData.get("LLII").constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
+          *     }
+          *     public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) {
+-         *         return BMHData.get("LLIJ").constructor.invokeBasic(mt, lf, argL0, argL1, argI2, narg);
++         *         return BMHData.get("LLIJ").constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
+          *     }
+          *     public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) {
+-         *         return BMHData.get("LLIF").constructor.invokeBasic(mt, lf, argL0, argL1, argI2, narg);
++         *         return BMHData.get("LLIF").constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
+          *     }
+          *     public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) {
+-         *         return BMHData.get("LLID").constructor.invokeBasic(mt, lf, argL0, argL1, argI2, narg);
++         *         return BMHData.get("LLID").constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
+          *     }
+          * }
+          * </pre>
+@@ -601,14 +662,14 @@
+         static Class<? extends BoundMethodHandle> generateConcreteBMHClass(String types) {
+             final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
+ 
+-            final String className = "java/lang/invoke/BMH_" + types;
++            final String className = BMH + "$BMH_" + types;
+             final String sourceFile = "BMH_" + types;
+-
+             cw.visit(V1_6, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, className, null, BMH, null);
+             cw.visitSource(sourceFile, null);
+ 
+-            // emit static types field
+-            cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "types", JLS_SIG, null, types).visitEnd();
++            // emit static types and data fields
++            cw.visitField(ACC_PUBLIC + ACC_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 +705,32 @@
+             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);
+             mv.visitCode();
+             mv.visitLdcInsn(types);
+             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();
++
+             // emit clone()
+             mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "clone", makeSignature("", false), null, E_THROWABLE);
+             mv.visitCode();
+-            // return myData().constructor.invokeBasic(mt, lf, argL0, ...)
++            // return myData().constructor[0].invokeBasic(mt, lf, argL0, ...)
+             // obtain constructor
+             mv.visitVarInsn(ALOAD, 0);
+-            mv.visitMethodInsn(INVOKESPECIAL, BMH, "myData", MYDATA_SIG);
+-            mv.visitFieldInsn(GETFIELD, DATA, "constructor", MH_SIG);
++            mv.visitFieldInsn(GETSTATIC, className, "DATA", DATA_SIG);
++            mv.visitFieldInsn(GETFIELD, DATA, "constructor", "[" + MH_SIG);
++            mv.visitInsn(ICONST_0);
++            mv.visitInsn(AALOAD);
+             // load mt, lf
+             mv.visitVarInsn(ALOAD, 1);
+             mv.visitVarInsn(ALOAD, 2);
+@@ -677,11 +748,13 @@
+                 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)
+                 // obtain constructor
+                 mv.visitLdcInsn(extypes);
+                 mv.visitMethodInsn(INVOKESTATIC, DATA, "get", BMHDATA_GET_SIG);
+-                mv.visitFieldInsn(GETFIELD, DATA, "constructor", MH_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 +769,25 @@
+                 mv.visitEnd();
+             }
+ 
++            // emit class initializer
++            mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "<clinit>", VOID_SIG, null, null);
++            mv.visitCode();
++            mv.visitLdcInsn(types);
++            mv.visitLdcInsn(Type.getObjectType(className));
++            mv.visitMethodInsn(INVOKESTATIC, DATA, "getForClass", BMHDATA_GET2_SIG);
++            mv.visitFieldInsn(PUTSTATIC, className, "DATA", DATA_SIG);
++            mv.visitInsn(RETURN);
++            mv.visitMaxs(0, 0);
++            mv.visitEnd();
++
+             cw.visitEnd();
+ 
+             // load class
+             final byte[] classFile = cw.toByteArray();
+             InvokerBytecodeGenerator.maybeDump(className, classFile);
+             Class<? extends BoundMethodHandle> bmhClass =
+-                UNSAFE.defineAnonymousClass(BoundMethodHandle.class, classFile, null).asSubclass(BoundMethodHandle.class);
++                //UNSAFE.defineAnonymousClass(BoundMethodHandle.class, classFile, null).asSubclass(BoundMethodHandle.class);
++                UNSAFE.defineClass(className, classFile, 0, classFile.length).asSubclass(BoundMethodHandle.class);
+             UNSAFE.ensureClassInitialized(bmhClass);
+ 
+             return bmhClass;
+@@ -745,21 +830,27 @@
+             }
+         }
+ 
+-        static MethodHandle[] makeGetters(Class<?> cbmhClass, String types) {
+-            MethodHandle[] mhs = new MethodHandle[types.length()];
++        static MethodHandle[] makeGetters(Class<?> cbmhClass, String types, MethodHandle[] mhs) {
++            if (mhs == null)  mhs = new MethodHandle[types.length()];
+             for (int i = 0; i < mhs.length; ++i) {
+                 mhs[i] = makeGetter(cbmhClass, types, i);
+             }
+             return mhs;
+         }
+ 
++        static MethodHandle[] makeCtors(Class<? extends BoundMethodHandle> cbmh, String types, MethodHandle mhs[]) {
++            if (mhs == null)  mhs = new MethodHandle[1];
++            mhs[0] = makeCbmhCtor(cbmh, types);
++            return mhs;
++        }
++
+         //
+         // Auxiliary methods.
+         //
+ 
+         static String typesFromConcreteBMHClass(Class<? extends BoundMethodHandle> cbmh) {
+             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 +923,15 @@
+             return cmh;
+         }
+ 
+-        //
+-        // Constants.
+-        //
+-
+-        private static final Lookup LOOKUP = Lookup.IMPL_LOOKUP;
+         private static final Unsafe UNSAFE = Unsafe.getUnsafe();
+ 
+     }
+ 
++    private static final Lookup LOOKUP = Lookup.IMPL_LOOKUP;
++
++    static {
++        // force initialisation
++        Data.get("L");
++    }
++
+ }
+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 @@
+ 
+ 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 @@
+     }
+ 
+     @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() {
+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);
+ 
++        // 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++) {
++        for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
+             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 {
+@@ -741,6 +746,75 @@
+     }
+ 
+     /**
++     * 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
+diff --git a/src/share/classes/java/lang/invoke/MethodHandle.java b/src/share/classes/java/lang/invoke/MethodHandle.java
+--- a/src/share/classes/java/lang/invoke/MethodHandle.java
++++ b/src/share/classes/java/lang/invoke/MethodHandle.java
+@@ -1089,7 +1089,6 @@
+         boolean lastMatch = asCollectorChecks(arrayType, 0);
+         if (isVarargsCollector() && lastMatch)
+             return this;
+-        //return AdapterMethodHandle.makeVarargsCollector(this, arrayType);
+         return MethodHandleImpl.makeVarargsCollector(this, arrayType);
+     }
+ 
+@@ -1238,7 +1237,6 @@
+         if (argc != 0) {
+             Class<?> arrayType = type().parameterType(argc-1);
+             if (arrayType.isArray()) {
+-                //return AdapterMethodHandle.makeVarargsCollector(this, arrayType);
+                 return MethodHandleImpl.makeVarargsCollector(this, arrayType);
+             }
+         }
+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 @@
+ package java.lang.invoke;
+ 
+ import sun.invoke.util.VerifyType;
++
++import java.lang.invoke.BoundMethodHandle.Data;
+ import java.util.ArrayList;
+ import java.util.Arrays;
+ import java.util.HashMap;
+@@ -659,11 +661,14 @@
+         }
+ 
+         @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
++        }
+ 
+         @Override
+         public MethodHandle asType(MethodType newType) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/meth-lazy-7023639.init.patch	Sat Jul 14 18:02:46 2012 -0700
@@ -0,0 +1,329 @@
+Addendum to meth-lazy-7023639.patch.
+Fixes performance cliff with invokestatic on uninitialized classes.
+
+diff --git a/src/share/classes/java/lang/invoke/BoundMethodHandle.java b/src/share/classes/java/lang/invoke/BoundMethodHandle.java
+--- a/src/share/classes/java/lang/invoke/BoundMethodHandle.java
++++ b/src/share/classes/java/lang/invoke/BoundMethodHandle.java
+@@ -122,6 +122,7 @@
+             default : throw new InternalError("unexpected type: " + xtype);
+             }
+         } catch (Throwable t) {
++            System.out.println("cloneExtend "+Arrays.asList(type, form, xtype, x));//@@
+             throw new InternalError(t);
+         }
+     }
+diff --git a/src/share/classes/java/lang/invoke/DirectMethodHandle.java b/src/share/classes/java/lang/invoke/DirectMethodHandle.java
+--- a/src/share/classes/java/lang/invoke/DirectMethodHandle.java
++++ b/src/share/classes/java/lang/invoke/DirectMethodHandle.java
+@@ -31,6 +31,8 @@
+ import sun.invoke.util.VerifyAccess;
+ import static java.lang.invoke.MethodHandleNatives.Constants.*;
+ import static java.lang.invoke.LambdaForm.*;
++import java.lang.ref.WeakReference;
++import sun.invoke.util.ValueConversions;
+ 
+ /**
+  * The flavor of method handle which emulates invokespecial or invokestatic.
+@@ -133,14 +135,21 @@
+         assert(!m.isMethodHandleInvoke() || "invokeBasic".equals(m.getName())) : m;
+         byte refKind = m.getReferenceKind();
+         int which = MethodTypeForm.LF_REF_KIND_FIRST + refKind;
+-        if (refKind == REF_invokeStatic && shouldBeInitialized(m))
++        if (refKind == REF_invokeStatic && shouldBeInitialized(m)) {
++            // precompute the barrier-free version:
++            preparedLambdaForm(mtype, refKind, which);
+             which = MethodTypeForm.LF_INVSTATIC_INIT;
++        }
++        LambdaForm lform = preparedLambdaForm(mtype, refKind, which);
++        if (VerifyAccess.isSamePackage(m.getDeclaringClass(), MethodHandle.class))
++            // Help along bootstrapping...
++            lform.compileToBytecode();
++        return lform;
++    }
++    private static LambdaForm preparedLambdaForm(MethodType mtype, byte refKind, int which) {
+         LambdaForm lform = mtype.form().cachedLambdaForm(which);
+         if (lform != null)  return lform;
+         lform = makePreparedLambdaForm(mtype, refKind, which);
+-        if (VerifyAccess.isSamePackage(m.getDeclaringClass(), MethodHandle.class))
+-            // Help along bootstrapping...
+-            lform.compileToBytecode();
+         return mtype.form().setCachedLambdaForm(which, lform);
+     }
+ 
+@@ -167,13 +176,13 @@
+         final int ARG_LIMIT   = ARG_BASE + mtype.parameterCount();
+         int nameCursor = ARG_LIMIT;
+         final int GET_MEMBER  = nameCursor++;
+-        final int ENSURE_INIT = (needEnsureInit ? nameCursor++ : -1);
+         final int LINKER_CALL = nameCursor++;
+         Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
+         assert(names.length == nameCursor);
+-        names[GET_MEMBER] = new Name(NF_internalMemberName, names[DMH_THIS]);
+-        if (ENSURE_INIT > 0)
+-            names[ENSURE_INIT] = new Name(NF_ensureClassInitialized, names[GET_MEMBER]);
++        if (needEnsureInit)
++            names[GET_MEMBER] = new Name(NF_internalMemberNameEnsureInit, names[DMH_THIS]);
++        else
++            names[GET_MEMBER] = new Name(NF_internalMemberName, names[DMH_THIS]);
+         Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, GET_MEMBER+1, Object[].class);
+         assert(outArgs[outArgs.length-1] == names[GET_MEMBER]);  // look, shifted args!
+         names[LINKER_CALL] = new Name(linker, outArgs);
+@@ -193,18 +202,23 @@
+             return false;
+         }
+         Class<?> cls = member.getDeclaringClass();
+-        if (VerifyAccess.isSamePackage(MethodHandle.class, cls))
+-            return false;
+-        //return UNSAFE.shouldBeInitialized(cls);
+-        if (MH_shouldBeInitialized == null) {
+-            MethodHandleImpl.UNSAFE.ensureClassInitialized(cls);
++        if (cls == ValueConversions.class ||
++            cls == MethodHandleImpl.class ||
++            cls == Invokers.class) {
++            // These guys have lots of <clinit> DMH creation but we know
++            // the MHs will not be used until the system is booted.
+             return false;
+         }
+-        try {
+-            return (boolean) MH_shouldBeInitialized.invokeExact(MethodHandleImpl.UNSAFE, cls);
+-        } catch (Throwable ex) {
+-            throw new InternalError(ex);
++        if (VerifyAccess.isSamePackage(MethodHandle.class, cls) ||
++            VerifyAccess.isSamePackage(ValueConversions.class, cls)) {
++            // It is a system class.  It is probably in the process of
++            // being initialized, but we will help it along just to be safe.
++            if (MethodHandleImpl.UNSAFE.shouldBeInitialized(cls)) {
++                MethodHandleImpl.UNSAFE.ensureClassInitialized(cls);
++            }
++            return false;
+         }
++        return MethodHandleImpl.UNSAFE.shouldBeInitialized(cls);
+     }
+ 
+     /*non-public*/ static
+@@ -213,40 +227,87 @@
+         MemberName member = (MemberName) memberObj;
+         EnsureInitialized.INSTANCE.get(member.getDeclaringClass());
+     }
+-    private static class EnsureInitialized extends ClassValue<Void> {
++
++    private static class EnsureInitialized extends ClassValue<WeakReference<Thread>> {
+         @Override
+-        protected Void computeValue(Class<?> type) {
++        protected WeakReference<Thread> computeValue(Class<?> type) {
+             MethodHandleImpl.UNSAFE.ensureClassInitialized(type);
++            if (MethodHandleImpl.UNSAFE.shouldBeInitialized(type))
++                // If the previous call didn't block, this can happen.
++                // We are executing inside <clinit>.
++                return new WeakReference<>(Thread.currentThread());
+             return null;
+         }
+         static final EnsureInitialized INSTANCE = new EnsureInitialized();
+     }
+ 
+     /** Static wrapper for DirectMethodHandle.internalMemberName. */
++    @ForceInline
+     /*non-public*/ static
+     Object internalMemberName(Object mh) {
+         return ((DirectMethodHandle)mh).member;
+     }
+ 
++    /** Static wrapper for DirectMethodHandle.internalMemberName.
++     * This one also forces initialization.
++     */
++    @ForceInline
++    /*non-public*/ static
++    Object internalMemberNameEnsureInit(Object mh) {
++        DirectMethodHandle dmh = (DirectMethodHandle)mh;
++        MemberName member = dmh.member;
++        if (ensureInitialized(member)) {
++            // The coast is clear.  Delete the cval and the barrier.
++            dmh.removeInitializationBarrier();
++        }
++        return member;
++    }
++
++    private static boolean ensureInitialized(MemberName member) {
++        Class<?> defc = member.getDeclaringClass();
++        WeakReference<Thread> ref = EnsureInitialized.INSTANCE.get(defc);
++        if (ref == null) {
++            return true;  // the final state
++        }
++        Thread clinitThread = ref.get();
++        // Somebody may still be running defc.<clinit>.
++        if (clinitThread == Thread.currentThread()) {
++            // If anybody is running defc.<clinit>, it is this thread.
++            if (MethodHandleImpl.UNSAFE.shouldBeInitialized(defc))
++                // Yes, we are running it; keep the barrier for now.
++                return false;
++        } else {
++            // We are in a random thread.  Block.
++            MethodHandleImpl.UNSAFE.ensureClassInitialized(defc);
++        }
++        assert(!MethodHandleImpl.UNSAFE.shouldBeInitialized(defc));
++        // put it into the final state
++        EnsureInitialized.INSTANCE.remove(defc);
++        return true;
++    }
++
++    private void removeInitializationBarrier() {
++        MethodType mtype = type().basicType();
++        LambdaForm oldForm = mtype.form().cachedLambdaForm(MethodTypeForm.LF_INVSTATIC_INIT);
++        LambdaForm newForm = mtype.form().cachedLambdaForm(MethodTypeForm.LF_INVSTATIC);
++        assert(oldForm != null && newForm != null);
++        assert(this.form == oldForm || this.form == newForm);
++        if (this.form == oldForm) {
++            this.updateForm(newForm);  //dmh.form = newForm;
++        }
++        assert(this.form == newForm);
++    }
++
+     private static final NamedFunction NF_internalMemberName;
+-    private static final NamedFunction NF_ensureClassInitialized;
+-    private static final MethodHandle MH_shouldBeInitialized;
++    private static final NamedFunction NF_internalMemberNameEnsureInit;
+     static {
+         try {
+             NF_internalMemberName = new NamedFunction(DirectMethodHandle.class
+                     .getDeclaredMethod("internalMemberName", Object.class));
+-            NF_ensureClassInitialized = new NamedFunction(DirectMethodHandle.class
+-                    .getDeclaredMethod("ensureClassInitialized", Object.class));
+-            MethodHandle mhOrNull = null;
+-            try {
+-                mhOrNull = make(Unsafe.class.getMethod("shouldBeInitialized", Class.class));
+-            } catch (NoSuchMethodException ex) {
+-                mhOrNull = null;  // new API call not in down-rev JVM
+-            }
+-            MH_shouldBeInitialized = mhOrNull;
++            NF_internalMemberNameEnsureInit = new NamedFunction(DirectMethodHandle.class
++                    .getDeclaredMethod("internalMemberNameEnsureInit", Object.class));
+             NF_internalMemberName.resolve();
+-            NF_ensureClassInitialized.resolve();
+-            MH_shouldBeInitialized.form.resolve();
++            NF_internalMemberNameEnsureInit.resolve();
+             // bound
+         } catch (ReflectiveOperationException ex) {
+             throw new InternalError(ex);
+diff --git a/src/share/classes/java/lang/invoke/LambdaForm.java b/src/share/classes/java/lang/invoke/LambdaForm.java
+--- a/src/share/classes/java/lang/invoke/LambdaForm.java
++++ b/src/share/classes/java/lang/invoke/LambdaForm.java
+@@ -441,6 +441,8 @@
+     MemberName compileToBytecode() {
+         MethodType invokerType = methodType();
+         assert(vmentry == null || vmentry.getMethodType().basicType().equals(invokerType));
++        if (vmentry != null)
++            return vmentry;  // already compiled somehow
+         try {
+             vmentry = InvokerBytecodeGenerator.generateCustomizedCode(this, invokerType);
+             if (TRACE_INTERPRETER)
+diff --git a/src/share/classes/java/lang/invoke/MethodHandle.java b/src/share/classes/java/lang/invoke/MethodHandle.java
+--- a/src/share/classes/java/lang/invoke/MethodHandle.java
++++ b/src/share/classes/java/lang/invoke/MethodHandle.java
+@@ -31,6 +31,8 @@
+ import sun.misc.Unsafe;
+ 
+ import static java.lang.invoke.MethodHandleStatics.*;
++import java.util.logging.Level;
++import java.util.logging.Logger;
+ 
+ /**
+  * A method handle is a typed, directly executable reference to an underlying method,
+@@ -1327,4 +1329,29 @@
+         // form2 = lambda (bmh, arg*) { thismh = bmh[0]; invokeBasic(thismh, arg*) }
+         return new BoundMethodHandle.BMH_L(type2, form2, this);
+     }
++
++    /**
++     * Replace the old lambda form of this method handle with a new one.
++     * The new one must be functionally equivalent to the old one.
++     * Threads may continue running the old form indefinitely,
++     * but it is likely that the new one will be preferred for new executions.
++     * Use with discretion.
++     * @param newForm
++     */
++    /*non-public*/
++    void updateForm(LambdaForm newForm) {
++        if (form == newForm)  return;
++        // ISSUE: Should we have a memory fence here?
++        MethodHandleImpl.UNSAFE.putObject(this, FORM_OFFSET, newForm);
++        this.form.prepare();  // as in MethodHandle.<init>
++    }
++
++    private static final long FORM_OFFSET;
++    static {
++        try {
++            FORM_OFFSET = MethodHandleImpl.UNSAFE.objectFieldOffset(MethodHandle.class.getDeclaredField("form"));
++        } catch (ReflectiveOperationException ex) {
++            throw new InternalError(ex);
++        }
++    }
+ }
+diff --git a/src/share/classes/java/lang/invoke/MethodHandleNatives.java b/src/share/classes/java/lang/invoke/MethodHandleNatives.java
+--- a/src/share/classes/java/lang/invoke/MethodHandleNatives.java
++++ b/src/share/classes/java/lang/invoke/MethodHandleNatives.java
+@@ -289,7 +289,7 @@
+                                    Object[] appendixResult) {
+         MethodHandle bootstrapMethod = (MethodHandle)bootstrapMethodObj;
+         Class<?> caller = (Class<?>)callerObj;
+-        String name = nameObj.toString();
++        String name = nameObj.toString().intern();
+         MethodType type = (MethodType)typeObj;
+         appendixResult[0] = CallSite.makeSite(bootstrapMethod,
+                                               name,
+@@ -318,13 +318,15 @@
+     static MemberName linkMethod(Class<?> callerClass, int refKind,
+                                  Class<?> defc, String name, Object type,
+                                  Object[] appendixResult) {
+-        if (TRACE_METHOD_LINKAGE)
+-            System.out.println("linkMethod "+defc.getName()+"."+
+-                               name+type+"/"+Integer.toHexString(refKind));
+-        //assert(refKind == REF_invokeVirtual) : refKind;
++        if (!TRACE_METHOD_LINKAGE)
++            return linkMethodImpl(callerClass, refKind, defc, name, type, appendixResult);
++        return linkMethodTracing(callerClass, refKind, defc, name, type, appendixResult);
++    }
++    static MemberName linkMethodImpl(Class<?> callerClass, int refKind,
++                                     Class<?> defc, String name, Object type,
++                                     Object[] appendixResult) {
+         if (defc != MethodHandle.class || refKind != REF_invokeVirtual)
+             throw new LinkageError("no such method "+defc.getName()+"."+name+type);
+-
+         switch (name) {
+         case "invoke":
+             return Invokers.genericInvokerMethod(callerClass, type, appendixResult);
+@@ -333,6 +335,21 @@
+         }
+         throw new UnsupportedOperationException("linkMethod "+name);
+     }
++    // Tracing logic:
++    static MemberName linkMethodTracing(Class<?> callerClass, int refKind,
++                                        Class<?> defc, String name, Object type,
++                                        Object[] appendixResult) {
++        System.out.println("linkMethod "+defc.getName()+"."+
++                           name+type+"/"+Integer.toHexString(refKind));
++        try {
++            MemberName res = linkMethodImpl(callerClass, refKind, defc, name, type, appendixResult);
++            System.out.println("linkMethod => "+res+" + "+appendixResult[0]);
++            return res;
++        } catch (Throwable ex) {
++            System.out.println("linkMethod => throw "+ex);
++            throw ex;
++        }
++    }
+ 
+     /**
+      * The JVM is resolving a CONSTANT_MethodHandle CP entry.  And it wants our help.
+diff --git a/src/share/classes/java/lang/invoke/MethodTypeForm.java b/src/share/classes/java/lang/invoke/MethodTypeForm.java
+--- a/src/share/classes/java/lang/invoke/MethodTypeForm.java
++++ b/src/share/classes/java/lang/invoke/MethodTypeForm.java
+@@ -72,7 +72,9 @@
+             LF_GEN_INVOKER    =  7 + LF_REF_KIND_LIMIT,
+             LF_CS_LINKER      =  8 + LF_REF_KIND_LIMIT,
+             // add more here as needed...
+-            LF_LIMIT          =  9 + LF_REF_KIND_LIMIT;
++            LF_LIMIT          =  9 + LF_REF_KIND_LIMIT,
++            // Helpful alias:
++            LF_INVSTATIC      =  LF_REF_KIND_FIRST + REF_invokeStatic;
+ 
+     public MethodType erasedType() {
+         return erasedType;
--- a/series	Fri Jul 13 11:18:57 2012 -0700
+++ b/series	Sat Jul 14 18:02:46 2012 -0700
@@ -5,6 +5,8 @@
 
 # review pending before push to hotspot-comp:
 meth-lazy-7023639.patch         #-/meth #+78f1f4e4e9c7
+meth-lazy-7023639.init.patch    #-/meth #+78f1f4e4e9c7
+meth-lazy-7023639.bmh.patch     #-/meth #+78f1f4e4e9c7
 
 # non-pushed files are under review or development, or merely experimental:
 meth-7177472.patch              #(78f1f4e4e9c7) #-buildable