changeset 400:79c955d995f0

meth-lazy: merged BMH factory into BMH, added test for primitive parameter binding
author mhaupt
date Wed, 11 Jul 2012 22:07:17 +0200
parents e3ce088d7958
children 0a120a3124fe
files meth-lazy-7023639.xbmh.patch
diffstat 1 files changed, 559 insertions(+), 452 deletions(-) [+]
line wrap: on
line diff
--- a/meth-lazy-7023639.xbmh.patch	Wed Jul 11 04:52:00 2012 -0700
+++ b/meth-lazy-7023639.xbmh.patch	Wed Jul 11 22:07:17 2012 +0200
@@ -1,9 +1,9 @@
 More flexible bound method handles.
 Contributed-by: Michael Haupt
 
-diff -r e7d4a60c75ff src/share/classes/java/lang/invoke/BoundMethodHandle.java
---- a/src/share/classes/java/lang/invoke/BoundMethodHandle.java	Mon Jul 09 08:42:05 2012 +0200
-+++ b/src/share/classes/java/lang/invoke/BoundMethodHandle.java	Tue Jul 10 12:15:25 2012 +0200
+diff -r 25fcfb3a5f65 src/share/classes/java/lang/invoke/BoundMethodHandle.java
+--- a/src/share/classes/java/lang/invoke/BoundMethodHandle.java	Wed Jul 11 14:18:03 2012 +0200
++++ b/src/share/classes/java/lang/invoke/BoundMethodHandle.java	Wed Jul 11 22:06:34 2012 +0200
 @@ -1,5 +1,5 @@
  /*
 - * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
@@ -11,25 +11,50 @@
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
-@@ -25,308 +25,355 @@
+@@ -25,308 +25,380 @@
  
  package java.lang.invoke;
  
 -import static java.lang.invoke.LambdaForm.*;
 -import static java.lang.invoke.MethodHandles.*;
 -import static java.lang.invoke.MethodType.*;
++import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ACC_FINAL;
++import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ACC_PUBLIC;
++import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ACC_STATIC;
++import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ACC_SUPER;
++import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ALOAD;
++import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ARETURN;
++import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.DLOAD;
++import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.FLOAD;
++import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.GETFIELD;
++import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.ILOAD;
++import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.INVOKESPECIAL;
++import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.INVOKESTATIC;
++import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
++import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.LLOAD;
++import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.PUTFIELD;
++import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.RETURN;
++import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.V1_6;
++import static java.lang.invoke.LambdaForm.arguments;
++import static java.lang.invoke.LambdaForm.basicTypes;
++import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;
++import static java.lang.invoke.MethodType.methodType;
++
++import java.lang.invoke.LambdaForm.Name;
++import java.lang.invoke.LambdaForm.NamedFunction;
++import java.lang.invoke.MethodHandles.Lookup;
++import java.lang.reflect.Field;
  import java.util.Arrays;
 -import sun.invoke.util.*;
-+import static java.lang.invoke.LambdaForm.arguments;
-+import static java.lang.invoke.LambdaForm.basicTypes;
-+import static java.lang.invoke.MethodType.methodType;
-+
-+import java.lang.invoke.BoundMethodHandleFactory.BMHData;
-+import java.lang.invoke.LambdaForm.Name;
-+import java.lang.invoke.MethodHandles.Lookup;
++import java.util.IdentityHashMap;
++import java.util.Map;
 +
 +import sun.invoke.util.ValueConversions;
 +import sun.invoke.util.Wrapper;
++import sun.misc.Unsafe;
++
++import com.sun.xml.internal.ws.org.objectweb.asm.ClassWriter;
++import com.sun.xml.internal.ws.org.objectweb.asm.MethodVisitor;
  
  /**
   * The flavor of method handle which emulates an invoke instruction
@@ -169,7 +194,7 @@
 -    public final Object dataValue0() {
 -        return argument;
 +    protected final BMHData myData() {
-+        return BMHData.get(this.types());
++        return BMHData.get(types());
      }
  
 -    //public final Object objectDataValue0() { return           dataValue0(); }
@@ -607,7 +632,7 @@
      /** Create a LF which simply reinvokes a target of the given basic type.
       *  The target MH must have the reinvocation target bound to value #0.
       */
-@@ -342,7 +389,7 @@
+@@ -342,11 +414,409 @@
          final int NEXT_MH     = nameCursor++;
          final int REINVOKE    = nameCursor++;
          Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
@@ -616,384 +641,11 @@
          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);
-diff -r e7d4a60c75ff src/share/classes/java/lang/invoke/BoundMethodHandleFactory.java
---- /dev/null	Thu Jan 01 00:00:00 1970 +0000
-+++ b/src/share/classes/java/lang/invoke/BoundMethodHandleFactory.java	Tue Jul 10 12:15:25 2012 +0200
-@@ -0,0 +1,444 @@
-+/*
-+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
-+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-+ *
-+ * This code is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License version 2 only, as
-+ * published by the Free Software Foundation.  Oracle designates this
-+ * particular file as subject to the "Classpath" exception as provided
-+ * by Oracle in the LICENSE file that accompanied this code.
-+ *
-+ * This code is distributed in the hope that it will be useful, but WITHOUT
-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-+ * version 2 for more details (a copy is included in the LICENSE file that
-+ * accompanied this code).
-+ *
-+ * You should have received a copy of the GNU General Public License version
-+ * 2 along with this work; if not, write to the Free Software Foundation,
-+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-+ * or visit www.oracle.com if you need additional information or have any
-+ * questions.
-+ */
-+
-+package java.lang.invoke;
-+
-+import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.*;
-+import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;
-+
-+import java.lang.invoke.LambdaForm.Name;
-+import java.lang.invoke.LambdaForm.NamedFunction;
-+import java.lang.invoke.MethodHandles.Lookup;
-+import java.lang.reflect.Field;
-+import java.util.Arrays;
-+import java.util.IdentityHashMap;
-+import java.util.Map;
-+
-+import com.sun.xml.internal.ws.org.objectweb.asm.ClassWriter;
-+import com.sun.xml.internal.ws.org.objectweb.asm.MethodVisitor;
-+
-+import sun.invoke.util.Wrapper;
-+import sun.misc.Unsafe;
-+
-+/**
-+ * Generation of concrete BMH classes.
-+ *
-+ * A concrete BMH is fit for binding a number of values adhering to a
-+ * given type pattern. Reference types are erased.
-+ *
-+ * BMH classes are cached by type pattern.
-+ *
-+ * A concrete BMH has a number of fields with the concrete (possibly erased) types of
-+ * bound values. Setters are provided as an API in BMH. Getters are exposed as MHs,
-+ * which can be included as names in lambda forms.
-+ */
-+/* non-public */ class BoundMethodHandleFactory {
-+
+         return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_REINVOKE, new LambdaForm("BMH.reinvoke", ARG_LIMIT, names));
+     }
+ 
 +    //
-+    // Concrete BMH generation.
-+    //
-+
-+    private static final String JLO_SIG = "Ljava/lang/Object;";
-+    private static final String JLS_SIG = "Ljava/lang/String;";
-+    private static final String MH = "java/lang/invoke/MethodHandle";
-+    private static final String MH_SIG = "Ljava/lang/invoke/MethodHandle;";
-+    private static final String BMH = "java/lang/invoke/BoundMethodHandle";
-+    private static final String BMH_SIG = "Ljava/lang/invoke/BoundMethodHandle;";
-+    private static final String BMHDATA = "java/lang/invoke/BoundMethodHandleFactory$BMHData";
-+    private static final String BMHDATA_SIG = "Ljava/lang/invoke/BoundMethodHandleFactory$BMHData;";
-+
-+    private static final String BMHDATA_GET_SIG = "(" + JLS_SIG + ")" + BMHDATA_SIG;
-+    private static final String TYPES_SIG = "()" + JLS_SIG;
-+    private static final String MYDATA_SIG = "()" + BMHDATA_SIG;
-+
-+    private static final String SIG_INCIPIT = "(Ljava/lang/invoke/MethodType;Ljava/lang/invoke/LambdaForm;";
-+
-+    static final Class<?>[] TYPES = new Class<?>[] { Object.class, int.class, long.class, float.class, double.class };
-+
-+    static final String[] E_THROWABLE = new String[] { "java/lang/Throwable" };
-+
-+    /**
-+     * Generate a concrete subclass of BMH for a given combination of bound types.
-+     *
-+     * A concrete BMH subclass adheres to the following schema:
-+     *
-+     * <pre>
-+     * class BMH_<<types>> extends BMH {
-+     *     <<fields>>
-+     *     final String dataValueTypes() { return <<types>>; }
-+     * }
-+     * </pre>
-+     *
-+     * The {@code <<types>>} signature is precisely the string that is passed to this
-+     * method.
-+     *
-+     * The {@code <<fields>>} section consists of one field definition per character in
-+     * the type signature, adhering to the naming schema described in the definition of
-+     * {@link #makeFieldName()}.
-+     *
-+     * For example, a concrete BMH class for two reference and one integral bound values
-+     * would have the following shape:
-+     *
-+     * <pre>
-+     * final class BMH_LLI extends BMH {
-+     *     final Object argL0;
-+     *     final Object argL1;
-+     *     final int argI2;
-+     *     public BMH_LLI(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
-+     *         super(mt, lf);
-+     *         this.argL0 = argL0;
-+     *         this.argL1 = argL1;
-+     *         this.argI2 = argI2;
-+     *     }
-+     *     public final String dataValueTypes() { return types; }
-+     *     public static final String types = "LLI";
-+     *     public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) {
-+     *         return myData().constructor.invokeBasic(mt, lf, argL0, argL1, argI2);
-+     *     }
-+     *     public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) {
-+     *         return BMHData.get("LLIL").constructor.invokeBasic(mt, lf, argL0, argL1, argI2, narg);
-+     *     }
-+     *     public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) {
-+     *         return BMHData.get("LLII").constructor.invokeBasic(mt, lf, argL0, argL1, argI2, narg);
-+     *     }
-+     *     public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) {
-+     *         return BMHData.get("LLIJ").constructor.invokeBasic(mt, lf, argL0, argL1, argI2, narg);
-+     *     }
-+     *     public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) {
-+     *         return BMHData.get("LLIF").constructor.invokeBasic(mt, lf, argL0, argL1, argI2, narg);
-+     *     }
-+     *     public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) {
-+     *         return BMHData.get("LLID").constructor.invokeBasic(mt, lf, argL0, argL1, argI2, narg);
-+     *     }
-+     * }
-+     * </pre>
-+     *
-+     * @param types the type signature, wherein reference types are erased to 'L'
-+     * @return the generated concrete BMH class
-+     */
-+    private static Class<? extends BoundMethodHandle> generateConcreteBMHClass(String types) {
-+        final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
-+
-+        final String className = "java/lang/invoke/BMH_" + types;
-+        final String sourceFile = "BMH_" + types;
-+
-+        cw.visit(V1_6, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, className, null, BMH, null);
-+        cw.visitSource(sourceFile, null);
-+
-+        // emit static types field
-+        cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "types", JLS_SIG, null, types).visitEnd();
-+
-+        // emit bound argument fields
-+        for (int i = 0; i < types.length(); ++i) {
-+            final char t = types.charAt(i);
-+            final String fieldName = makeFieldName(types, i);
-+            final String fieldDesc = t == 'L' ? JLO_SIG : String.valueOf(t);
-+            cw.visitField(ACC_FINAL, fieldName, fieldDesc, null, null).visitEnd();
-+        }
-+
-+        MethodVisitor mv;
-+
-+        // emit constructor
-+        mv = cw.visitMethod(ACC_PUBLIC, "<init>", makeSignature(types, true), null, null);
-+        mv.visitCode();
-+        mv.visitVarInsn(ALOAD, 0);
-+        mv.visitVarInsn(ALOAD, 1);
-+        mv.visitVarInsn(ALOAD, 2);
-+
-+        mv.visitMethodInsn(INVOKESPECIAL, BMH, "<init>", makeSignature("", true));
-+
-+        for (int i = 0, j = 0; i < types.length(); ++i, ++j) {
-+            // i counts the arguments, j counts corresponding argument slots
-+            char t = types.charAt(i);
-+            mv.visitVarInsn(ALOAD, 0);
-+            mv.visitVarInsn(typeLoadOp(t), j + 3); // parameters start at 3
-+            mv.visitFieldInsn(PUTFIELD, className, makeFieldName(types, i), typeSig(t));
-+            if (t == 'J' || t == 'D') {
-+                ++j; // adjust argument register access
-+            }
-+        }
-+
-+        mv.visitInsn(RETURN);
-+        mv.visitMaxs(0, 0);
-+        mv.visitEnd();
-+
-+        // emit implementation of types()
-+        mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "types", TYPES_SIG, null, null);
-+        mv.visitCode();
-+        mv.visitLdcInsn(types);
-+        mv.visitInsn(ARETURN);
-+        mv.visitMaxs(0, 0);
-+        mv.visitEnd();
-+
-+        // emit clone()
-+        mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "clone", makeSignature("", false), null, E_THROWABLE);
-+        mv.visitCode();
-+        // return myData().constructor.invokeBasic(mt, lf, argL0, ...)
-+        // obtain myData().constructor
-+        mv.visitVarInsn(ALOAD, 0);
-+        mv.visitMethodInsn(INVOKESPECIAL, BMH, "myData", MYDATA_SIG);
-+        mv.visitFieldInsn(GETFIELD, BMHDATA, "constructor", MH_SIG);
-+        // load mt, lf
-+        mv.visitVarInsn(ALOAD, 1);
-+        mv.visitVarInsn(ALOAD, 2);
-+        // for each field, invoke the getter
-+        emitInvokeGetters(types, className, mv);
-+        // finally, invoke the constructor and return
-+        mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types, false));
-+        mv.visitInsn(ARETURN);
-+        mv.visitMaxs(0, 0);
-+        mv.visitEnd();
-+
-+        // for each type, emit cloneExtendT()
-+        for (Class<?> c : TYPES) {
-+            char t = Wrapper.basicTypeChar(c);
-+            String extypes = types + t;
-+            mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "cloneExtend" + t, makeSignature(String.valueOf(t), false), null, E_THROWABLE);
-+            mv.visitCode();
-+            // return BMHData.get(<extypes>).constructor.invokeBasic(mt, lf, argL0, ..., narg)
-+            // obtain constructor
-+            mv.visitLdcInsn(extypes);
-+            mv.visitMethodInsn(INVOKESTATIC, BMHDATA, "get", BMHDATA_GET_SIG);
-+            mv.visitFieldInsn(GETFIELD, BMHDATA, "constructor", MH_SIG);
-+            // load mt, lf
-+            mv.visitVarInsn(ALOAD, 1);
-+            mv.visitVarInsn(ALOAD, 2);
-+            emitInvokeGetters(types, className, mv);
-+            // put narg on stack
-+            mv.visitVarInsn(typeLoadOp(t), 3);
-+            // finally, invoke the constructor and return
-+            mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(extypes, false));
-+            mv.visitInsn(ARETURN);
-+            mv.visitMaxs(0, 0);
-+            mv.visitEnd();
-+        }
-+
-+        cw.visitEnd();
-+
-+        // load class
-+        final byte[] classFile = cw.toByteArray();
-+        InvokerBytecodeGenerator.maybeDump(className, classFile);
-+        Class<? extends BoundMethodHandle> bmhClass = (Class<? extends BoundMethodHandle>) UNSAFE.defineAnonymousClass(BoundMethodHandle.class, classFile, null);
-+        UNSAFE.ensureClassInitialized(bmhClass);
-+
-+        return bmhClass;
-+    }
-+
-+    private static int typeLoadOp(char t) {
-+        switch (t) {
-+        case 'L': return ALOAD;
-+        case 'I': return ILOAD;
-+        case 'J': return LLOAD;
-+        case 'F': return FLOAD;
-+        case 'D': return DLOAD;
-+        default : throw new InternalError("unrecognized type " + t);
-+        }
-+    }
-+
-+    private static void emitInvokeGetters(String types, String className, MethodVisitor mv) {
-+        for (int i = 0; i < types.length(); ++i) {
-+            char tc = types.charAt(i);
-+            mv.visitVarInsn(ALOAD, 0);
-+            mv.visitFieldInsn(GETFIELD, className, makeFieldName(types, i), typeSig(tc));
-+        }
-+    }
-+
-+    static String typeSig(char t) {
-+        return t == 'L' ? JLO_SIG : String.valueOf(t);
-+    }
-+
-+    //
-+    // Getter MH generation.
-+    //
-+
-+    private static MethodHandle makeGetter(Class<?> cbmhClass, String types, int index) {
-+        String fieldName = makeFieldName(types, index);
-+        Class<?> fieldType = Wrapper.forBasicType(types.charAt(index)).primitiveType();
-+        try {
-+            return LOOKUP.findGetter(cbmhClass, fieldName, fieldType);
-+        } catch (NoSuchFieldException | IllegalAccessException e) {
-+            throw new InternalError(e);
-+        }
-+    }
-+
-+    private static MethodHandle[] makeGetters(Class<?> cbmhClass, String types) {
-+        MethodHandle[] mhs = new MethodHandle[types.length()];
-+        for (int i = 0; i < mhs.length; ++i) {
-+            mhs[i] = makeGetter(cbmhClass, types, i);
-+        }
-+        return mhs;
-+    }
-+
-+    //
-+    // Auxiliary methods.
-+    //
-+
-+    private static String typesFromConcreteBMHClass(Class<? extends BoundMethodHandle> cbmh) {
-+        try {
-+            Field ftypes = cbmh.getDeclaredField("types");
-+            return (String) ftypes.get(null);
-+        } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
-+            throw new InternalError(e);
-+        }
-+    }
-+
-+    /**
-+     * Field names in concrete BMHs adhere to this pattern:
-+     * arg + type + index
-+     * where type is a single character (L, I, J, F, D).
-+     */
-+    private static String makeFieldName(String types, int index) {
-+        assert index >= 0 && index < types.length();
-+        return "arg" + types.charAt(index) + index;
-+    }
-+
-+    private static String makeSignature(String types, boolean ctor) {
-+        StringBuffer buf = new StringBuffer(SIG_INCIPIT);
-+        for (char c : types.toCharArray()) {
-+            buf.append(typeSig(c));
-+        }
-+        return buf.append(')').append(ctor ? "V" : BMH_SIG).toString();
-+    }
-+
-+    static MethodHandle makeCbmhCtor(Class<? extends BoundMethodHandle> cbmh, String types) {
-+        try {
-+            return linkConstructor(LOOKUP.findConstructor(cbmh, MethodType.fromMethodDescriptorString(makeSignature(types, true), null)));
-+        } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | TypeNotPresentException e) {
-+            throw new InternalError(e);
-+        }
-+    }
-+
-+    /**
-+     * Wrap a constructor call in a {@link LambdaForm}.
-+     *
-+     * If constructors ({@code <init>} methods) are called in LFs, problems might arise if the LFs
-+     * are turned into bytecode, because the call to the allocator is routed through an MH, and the
-+     * verifier cannot find a {@code NEW} instruction preceding the {@code INVOKESPECIAL} to
-+     * {@code <init>}. To avoid this, we add an indirection by invoking {@code <init>} through
-+     * {@link MethodHandle#linkToSpecial}.
-+     *
-+     * The last {@link LambdaForm#Name Name} in the argument's form is expected to be the {@code void}
-+     * result of the {@code <init>} invocation. This entry is replaced.
-+     */
-+    private static MethodHandle linkConstructor(MethodHandle cmh) {
-+        final LambdaForm lf = cmh.form;
-+        final int initNameIndex = lf.names.length - 1;
-+        final Name initName = lf.names[initNameIndex];
-+        final MemberName ctorMN = initName.function.member;
-+        final MethodType ctorMT = ctorMN.getInvocationType();
-+
-+        // obtain function member (call target)
-+        // linker method type replaces initial parameter (BMH species) with BMH to avoid naming a species (anonymous class!)
-+        final MethodType linkerMT = ctorMT.changeParameterType(0, BoundMethodHandle.class).appendParameterTypes(MemberName.class);
-+        MemberName linkerMN = new MemberName(MethodHandle.class, "linkToSpecial", linkerMT, REF_invokeStatic);
-+        try {
-+            linkerMN = MemberName.getFactory().resolveOrFail(REF_invokeStatic, linkerMN, null, NoSuchMethodException.class);
-+            assert(linkerMN.isStatic());
-+        } catch (ReflectiveOperationException ex) {
-+            throw new InternalError(ex);
-+        }
-+        // extend arguments array
-+        Object[] newArgs = Arrays.copyOf(initName.arguments, initName.arguments.length + 1);
-+        newArgs[newArgs.length - 1] = ctorMN;
-+        // replace function
-+        final NamedFunction nf = new NamedFunction(linkerMN);
-+        final Name linkedCtor = new Name(nf, newArgs);
-+        linkedCtor.initIndex(initNameIndex);
-+        lf.names[initNameIndex] = linkedCtor;
-+        return cmh;
-+    }
-+
-+    //
-+    // BMH meta-data caching and creation
++    // BMH meta-data
 +    //
 +
 +    /**
@@ -1015,9 +667,9 @@
 +        static Map<String, BMHData> CACHE = new IdentityHashMap<>();
 +
 +        static BMHData make(String types) {
-+            final Class<? extends BoundMethodHandle> cbmh = generateConcreteBMHClass(types);
-+            final MethodHandle ctor = makeCbmhCtor(cbmh, types);
-+            final MethodHandle[] getters = makeGetters(cbmh, 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 BMHData(types, cbmh, ctor, getters);
 +        }
 +
@@ -1043,9 +695,9 @@
 +                for (Class<?> c : bmh.getDeclaredClasses()) {
 +                    if (bmh.isAssignableFrom(c)) {
 +                        final Class<? extends BoundMethodHandle> cbmh = (Class<? extends BoundMethodHandle>) c;
-+                        final String types = typesFromConcreteBMHClass(cbmh);
-+                        final MethodHandle ctor = makeCbmhCtor(cbmh, types);
-+                        final MethodHandle[] getters = makeGetters(cbmh, types);
++                        final String types = Factory.typesFromConcreteBMHClass(cbmh);
++                        final MethodHandle ctor = Factory.makeCbmhCtor(cbmh, types);
++                        final MethodHandle[] getters = Factory.makeGetters(cbmh, types);
 +                        final BMHData d = new BMHData(types, (Class<? extends BoundMethodHandle>) c, ctor, getters);
 +                        CACHE.put(types.intern(), d);
 +                    }
@@ -1056,17 +708,344 @@
 +        }
 +    }
 +
-+    //
-+    // Constants.
-+    //
++    /**
++     * Generation of concrete BMH classes.
++     *
++     * A concrete BMH is fit for binding a number of values adhering to a
++     * given type pattern. Reference types are erased.
++     *
++     * BMH classes are cached by type pattern.
++     *
++     * A concrete BMH has a number of fields with the concrete (possibly erased) types of
++     * bound values. Setters are provided as an API in BMH. Getters are exposed as MHs,
++     * which can be included as names in lambda forms.
++     */
++    static class Factory {
 +
-+    private static final Lookup LOOKUP = Lookup.IMPL_LOOKUP;
-+    private static final Unsafe UNSAFE = Unsafe.getUnsafe();
++        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 BMHDATA = "java/lang/invoke/BoundMethodHandle$BMHData";
++        static final String BMHDATA_SIG = "Ljava/lang/invoke/BoundMethodHandle$BMHData;";
 +
-+}
-diff -r e7d4a60c75ff src/share/classes/java/lang/invoke/CountingMethodHandle.java
---- a/src/share/classes/java/lang/invoke/CountingMethodHandle.java	Mon Jul 09 08:42:05 2012 +0200
-+++ b/src/share/classes/java/lang/invoke/CountingMethodHandle.java	Tue Jul 10 12:15:25 2012 +0200
++        static final String BMHDATA_GET_SIG = "(" + JLS_SIG + ")" + BMHDATA_SIG;
++        static final String TYPES_SIG = "()" + JLS_SIG;
++        static final String MYDATA_SIG = "()" + BMHDATA_SIG;
++
++        static final String SIG_INCIPIT = "(Ljava/lang/invoke/MethodType;Ljava/lang/invoke/LambdaForm;";
++
++        static final Class<?>[] TYPES = new Class<?>[] { Object.class, int.class, long.class, float.class, double.class };
++
++        static final String[] E_THROWABLE = new String[] { "java/lang/Throwable" };
++
++        /**
++         * Generate a concrete subclass of BMH for a given combination of bound types.
++         *
++         * A concrete BMH subclass adheres to the following schema:
++         *
++         * <pre>
++         * class BMH_<<types>> extends BMH {
++         *     <<fields>>
++         *     final String dataValueTypes() { return <<types>>; }
++         * }
++         * </pre>
++         *
++         * The {@code <<types>>} signature is precisely the string that is passed to this
++         * method.
++         *
++         * The {@code <<fields>>} section consists of one field definition per character in
++         * the type signature, adhering to the naming schema described in the definition of
++         * {@link #makeFieldName()}.
++         *
++         * For example, a concrete BMH class for two reference and one integral bound values
++         * would have the following shape:
++         *
++         * <pre>
++         * final class BMH_LLI extends BMH {
++         *     final Object argL0;
++         *     final Object argL1;
++         *     final int argI2;
++         *     public BMH_LLI(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
++         *         super(mt, lf);
++         *         this.argL0 = argL0;
++         *         this.argL1 = argL1;
++         *         this.argI2 = argI2;
++         *     }
++         *     public final String dataValueTypes() { return types; }
++         *     public static final String types = "LLI";
++         *     public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) {
++         *         return myData().constructor.invokeBasic(mt, lf, argL0, argL1, argI2);
++         *     }
++         *     public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) {
++         *         return BMHData.get("LLIL").constructor.invokeBasic(mt, lf, argL0, argL1, argI2, narg);
++         *     }
++         *     public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) {
++         *         return BMHData.get("LLII").constructor.invokeBasic(mt, lf, argL0, argL1, argI2, narg);
++         *     }
++         *     public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) {
++         *         return BMHData.get("LLIJ").constructor.invokeBasic(mt, lf, argL0, argL1, argI2, narg);
++         *     }
++         *     public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) {
++         *         return BMHData.get("LLIF").constructor.invokeBasic(mt, lf, argL0, argL1, argI2, narg);
++         *     }
++         *     public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) {
++         *         return BMHData.get("LLID").constructor.invokeBasic(mt, lf, argL0, argL1, argI2, narg);
++         *     }
++         * }
++         * </pre>
++         *
++         * @param types the type signature, wherein reference types are erased to 'L'
++         * @return the generated concrete BMH class
++         */
++        static Class<? extends BoundMethodHandle> generateConcreteBMHClass(String types) {
++            final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
++
++            final String className = "java/lang/invoke/BMH_" + types;
++            final String sourceFile = "BMH_" + types;
++
++            cw.visit(V1_6, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, className, null, BMH, null);
++            cw.visitSource(sourceFile, null);
++
++            // emit static types field
++            cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "types", JLS_SIG, null, types).visitEnd();
++
++            // emit bound argument fields
++            for (int i = 0; i < types.length(); ++i) {
++                final char t = types.charAt(i);
++                final String fieldName = makeFieldName(types, i);
++                final String fieldDesc = t == 'L' ? JLO_SIG : String.valueOf(t);
++                cw.visitField(ACC_FINAL, fieldName, fieldDesc, null, null).visitEnd();
++            }
++
++            MethodVisitor mv;
++
++            // emit constructor
++            mv = cw.visitMethod(ACC_PUBLIC, "<init>", makeSignature(types, true), null, null);
++            mv.visitCode();
++            mv.visitVarInsn(ALOAD, 0);
++            mv.visitVarInsn(ALOAD, 1);
++            mv.visitVarInsn(ALOAD, 2);
++
++            mv.visitMethodInsn(INVOKESPECIAL, BMH, "<init>", makeSignature("", true));
++
++            for (int i = 0, j = 0; i < types.length(); ++i, ++j) {
++                // i counts the arguments, j counts corresponding argument slots
++                char t = types.charAt(i);
++                mv.visitVarInsn(ALOAD, 0);
++                mv.visitVarInsn(typeLoadOp(t), j + 3); // parameters start at 3
++                mv.visitFieldInsn(PUTFIELD, className, makeFieldName(types, i), typeSig(t));
++                if (t == 'J' || t == 'D') {
++                    ++j; // adjust argument register access
++                }
++            }
++
++            mv.visitInsn(RETURN);
++            mv.visitMaxs(0, 0);
++            mv.visitEnd();
++
++            // emit implementation of types()
++            mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "types", TYPES_SIG, null, null);
++            mv.visitCode();
++            mv.visitLdcInsn(types);
++            mv.visitInsn(ARETURN);
++            mv.visitMaxs(0, 0);
++            mv.visitEnd();
++
++            // emit clone()
++            mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "clone", makeSignature("", false), null, E_THROWABLE);
++            mv.visitCode();
++            // return myData().constructor.invokeBasic(mt, lf, argL0, ...)
++            // obtain constructor
++            mv.visitVarInsn(ALOAD, 0);
++            mv.visitMethodInsn(INVOKESPECIAL, BMH, "myData", MYDATA_SIG);
++            mv.visitFieldInsn(GETFIELD, BMHDATA, "constructor", MH_SIG);
++            // load mt, lf
++            mv.visitVarInsn(ALOAD, 1);
++            mv.visitVarInsn(ALOAD, 2);
++            // put fields on the stack
++            emitPushFields(types, className, mv);
++            // finally, invoke the constructor and return
++            mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types, false));
++            mv.visitInsn(ARETURN);
++            mv.visitMaxs(0, 0);
++            mv.visitEnd();
++
++            // for each type, emit cloneExtendT()
++            for (Class<?> c : TYPES) {
++                char t = Wrapper.basicTypeChar(c);
++                String extypes = types + t;
++                mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "cloneExtend" + t, makeSignature(String.valueOf(t), false), null, E_THROWABLE);
++                mv.visitCode();
++                // return BMHData.get(<extypes>).constructor.invokeBasic(mt, lf, argL0, ..., narg)
++                // obtain constructor
++                mv.visitLdcInsn(extypes);
++                mv.visitMethodInsn(INVOKESTATIC, BMHDATA, "get", BMHDATA_GET_SIG);
++                mv.visitFieldInsn(GETFIELD, BMHDATA, "constructor", MH_SIG);
++                // load mt, lf
++                mv.visitVarInsn(ALOAD, 1);
++                mv.visitVarInsn(ALOAD, 2);
++                // put fields on the stack
++                emitPushFields(types, className, mv);
++                // put narg on stack
++                mv.visitVarInsn(typeLoadOp(t), 3);
++                // finally, invoke the constructor and return
++                mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(extypes, false));
++                mv.visitInsn(ARETURN);
++                mv.visitMaxs(0, 0);
++                mv.visitEnd();
++            }
++
++            cw.visitEnd();
++
++            // load class
++            final byte[] classFile = cw.toByteArray();
++            InvokerBytecodeGenerator.maybeDump(className, classFile);
++            Class<? extends BoundMethodHandle> bmhClass = (Class<? extends BoundMethodHandle>) UNSAFE.defineAnonymousClass(BoundMethodHandle.class, classFile, null);
++            UNSAFE.ensureClassInitialized(bmhClass);
++
++            return bmhClass;
++        }
++
++        private static int typeLoadOp(char t) {
++            switch (t) {
++            case 'L': return ALOAD;
++            case 'I': return ILOAD;
++            case 'J': return LLOAD;
++            case 'F': return FLOAD;
++            case 'D': return DLOAD;
++            default : throw new InternalError("unrecognized type " + t);
++            }
++        }
++
++        private static void emitPushFields(String types, String className, MethodVisitor mv) {
++            for (int i = 0; i < types.length(); ++i) {
++                char tc = types.charAt(i);
++                mv.visitVarInsn(ALOAD, 0);
++                mv.visitFieldInsn(GETFIELD, className, makeFieldName(types, i), typeSig(tc));
++            }
++        }
++
++        static String typeSig(char t) {
++            return t == 'L' ? JLO_SIG : String.valueOf(t);
++        }
++
++        //
++        // Getter MH generation.
++        //
++
++        private static MethodHandle makeGetter(Class<?> cbmhClass, String types, int index) {
++            String fieldName = makeFieldName(types, index);
++            Class<?> fieldType = Wrapper.forBasicType(types.charAt(index)).primitiveType();
++            try {
++                return LOOKUP.findGetter(cbmhClass, fieldName, fieldType);
++            } catch (NoSuchFieldException | IllegalAccessException e) {
++                throw new InternalError(e);
++            }
++        }
++
++        static MethodHandle[] makeGetters(Class<?> cbmhClass, String types) {
++            MethodHandle[] mhs = new MethodHandle[types.length()];
++            for (int i = 0; i < mhs.length; ++i) {
++                mhs[i] = makeGetter(cbmhClass, types, i);
++            }
++            return mhs;
++        }
++
++        //
++        // Auxiliary methods.
++        //
++
++        static String typesFromConcreteBMHClass(Class<? extends BoundMethodHandle> cbmh) {
++            try {
++                Field ftypes = cbmh.getDeclaredField("types");
++                return (String) ftypes.get(null);
++            } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
++                throw new InternalError(e);
++            }
++        }
++
++        /**
++         * Field names in concrete BMHs adhere to this pattern:
++         * arg + type + index
++         * where type is a single character (L, I, J, F, D).
++         */
++        private static String makeFieldName(String types, int index) {
++            assert index >= 0 && index < types.length();
++            return "arg" + types.charAt(index) + index;
++        }
++
++        private static String makeSignature(String types, boolean ctor) {
++            StringBuffer buf = new StringBuffer(SIG_INCIPIT);
++            for (char c : types.toCharArray()) {
++                buf.append(typeSig(c));
++            }
++            return buf.append(')').append(ctor ? "V" : BMH_SIG).toString();
++        }
++
++        static MethodHandle makeCbmhCtor(Class<? extends BoundMethodHandle> cbmh, String types) {
++            try {
++                return linkConstructor(LOOKUP.findConstructor(cbmh, MethodType.fromMethodDescriptorString(makeSignature(types, true), null)));
++            } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | TypeNotPresentException e) {
++                throw new InternalError(e);
++            }
++        }
++
++        /**
++         * Wrap a constructor call in a {@link LambdaForm}.
++         *
++         * If constructors ({@code <init>} methods) are called in LFs, problems might arise if the LFs
++         * are turned into bytecode, because the call to the allocator is routed through an MH, and the
++         * verifier cannot find a {@code NEW} instruction preceding the {@code INVOKESPECIAL} to
++         * {@code <init>}. To avoid this, we add an indirection by invoking {@code <init>} through
++         * {@link MethodHandle#linkToSpecial}.
++         *
++         * The last {@link LambdaForm#Name Name} in the argument's form is expected to be the {@code void}
++         * result of the {@code <init>} invocation. This entry is replaced.
++         */
++        private static MethodHandle linkConstructor(MethodHandle cmh) {
++            final LambdaForm lf = cmh.form;
++            final int initNameIndex = lf.names.length - 1;
++            final Name initName = lf.names[initNameIndex];
++            final MemberName ctorMN = initName.function.member;
++            final MethodType ctorMT = ctorMN.getInvocationType();
++
++            // obtain function member (call target)
++            // linker method type replaces initial parameter (BMH species) with BMH to avoid naming a species (anonymous class!)
++            final MethodType linkerMT = ctorMT.changeParameterType(0, BoundMethodHandle.class).appendParameterTypes(MemberName.class);
++            MemberName linkerMN = new MemberName(MethodHandle.class, "linkToSpecial", linkerMT, REF_invokeStatic);
++            try {
++                linkerMN = MemberName.getFactory().resolveOrFail(REF_invokeStatic, linkerMN, null, NoSuchMethodException.class);
++                assert(linkerMN.isStatic());
++            } catch (ReflectiveOperationException ex) {
++                throw new InternalError(ex);
++            }
++            // extend arguments array
++            Object[] newArgs = Arrays.copyOf(initName.arguments, initName.arguments.length + 1);
++            newArgs[newArgs.length - 1] = ctorMN;
++            // replace function
++            final NamedFunction nf = new NamedFunction(linkerMN);
++            final Name linkedCtor = new Name(nf, newArgs);
++            linkedCtor.initIndex(initNameIndex);
++            lf.names[initNameIndex] = linkedCtor;
++            return cmh;
++        }
++
++        //
++        // Constants.
++        //
++
++        private static final Lookup LOOKUP = Lookup.IMPL_LOOKUP;
++        private static final Unsafe UNSAFE = Unsafe.getUnsafe();
++
++    }
++
+ }
+diff -r 25fcfb3a5f65 src/share/classes/java/lang/invoke/CountingMethodHandle.java
+--- a/src/share/classes/java/lang/invoke/CountingMethodHandle.java	Wed Jul 11 14:18:03 2012 +0200
++++ b/src/share/classes/java/lang/invoke/CountingMethodHandle.java	Wed Jul 11 22:06:34 2012 +0200
 @@ -36,11 +36,13 @@
   *
   * @author never
@@ -1140,9 +1119,9 @@
 +        throw new IllegalStateException("NYI");
 +    }
  }
-diff -r e7d4a60c75ff src/share/classes/java/lang/invoke/DataBinding.java
---- a/src/share/classes/java/lang/invoke/DataBinding.java	Mon Jul 09 08:42:05 2012 +0200
-+++ b/src/share/classes/java/lang/invoke/DataBinding.java	Tue Jul 10 12:15:25 2012 +0200
+diff -r 25fcfb3a5f65 src/share/classes/java/lang/invoke/DataBinding.java
+--- a/src/share/classes/java/lang/invoke/DataBinding.java	Wed Jul 11 14:18:03 2012 +0200
++++ b/src/share/classes/java/lang/invoke/DataBinding.java	Wed Jul 11 22:06:34 2012 +0200
 @@ -73,15 +73,12 @@
  
          @Override
@@ -1256,9 +1235,9 @@
                  }
                  values[i] = value;
              }
-diff -r e7d4a60c75ff src/share/classes/java/lang/invoke/DirectMethodHandle.java
---- a/src/share/classes/java/lang/invoke/DirectMethodHandle.java	Mon Jul 09 08:42:05 2012 +0200
-+++ b/src/share/classes/java/lang/invoke/DirectMethodHandle.java	Tue Jul 10 12:15:25 2012 +0200
+diff -r 25fcfb3a5f65 src/share/classes/java/lang/invoke/DirectMethodHandle.java
+--- a/src/share/classes/java/lang/invoke/DirectMethodHandle.java	Wed Jul 11 14:18:03 2012 +0200
++++ b/src/share/classes/java/lang/invoke/DirectMethodHandle.java	Wed Jul 11 22:06:34 2012 +0200
 @@ -66,24 +66,22 @@
      }
  
@@ -1303,9 +1282,9 @@
      private static final NamedFunction NF_internalMemberName;
      private static final NamedFunction NF_ensureClassInitialized;
      private static final MethodHandle MH_shouldBeInitialized;
-diff -r e7d4a60c75ff src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
---- a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java	Mon Jul 09 08:42:05 2012 +0200
-+++ b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java	Tue Jul 10 12:15:25 2012 +0200
+diff -r 25fcfb3a5f65 src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
+--- a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java	Wed Jul 11 14:18:03 2012 +0200
++++ b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java	Wed Jul 11 22:06:34 2012 +0200
 @@ -27,6 +27,7 @@
  
  import sun.invoke.util.VerifyAccess;
@@ -1364,7 +1343,7 @@
          // Suppress this method in backtraces displayed to the user.
          mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
  
-@@ -527,8 +531,6 @@
+@@ -530,8 +534,6 @@
                  // FIXME: make sure this idiom is really present!
                  emitSelectAlternative(name, lambdaForm.names[i + 1]);
                  i++;  // skip MH.invokeBasic of the selectAlternative result
@@ -1373,7 +1352,7 @@
              } else if (isStaticallyInvocable(member)) {
                  emitStaticInvoke(member, name);
              } else {
-@@ -550,9 +552,10 @@
+@@ -553,9 +555,10 @@
          emitReturn();
  
          classFileEpilogue();
@@ -1385,7 +1364,7 @@
          return classFile;
      }
  
-@@ -597,6 +600,7 @@
+@@ -600,6 +603,7 @@
  
      boolean isStaticallyInvocable(MemberName member) {
          if (member == null)  return false;
@@ -1393,7 +1372,7 @@
          Class<?> cls = member.getDeclaringClass();
          if (cls.isArray() || cls.isPrimitive())
              return false;  // FIXME
-@@ -697,6 +701,8 @@
+@@ -700,6 +704,8 @@
       * @param invokeBasicName
       */
      private void emitSelectAlternative(Name selectAlternativeName, Name invokeBasicName) {
@@ -1402,7 +1381,7 @@
          Name receiver = (Name) invokeBasicName.arguments[0];
  
          Label L_fallback = new Label();
-@@ -731,68 +737,68 @@
+@@ -734,68 +740,68 @@
          mv.visitLabel(L_done);
      }
  
@@ -1533,7 +1512,7 @@
  
      /**
       *
-@@ -802,16 +808,17 @@
+@@ -805,16 +811,17 @@
      private void emitPushArgument(Name name, int paramIndex) {
          Object arg = name.arguments[paramIndex];
          char ptype = name.function.parameterType(paramIndex);
@@ -1552,7 +1531,7 @@
              }
          }
      }
-@@ -987,9 +994,6 @@
+@@ -990,9 +997,6 @@
      private byte[] generateLambdaFormInterpreterEntryPointBytes() {
          classFilePrologue();
  
@@ -1562,7 +1541,7 @@
          // Suppress this method in backtraces displayed to the user.
          mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
  
-@@ -1022,9 +1026,10 @@
+@@ -1028,9 +1032,10 @@
          emitReturnInsn(rtype);
  
          classFileEpilogue();
@@ -1574,7 +1553,7 @@
          return classFile;
      }
  
-@@ -1042,13 +1047,12 @@
+@@ -1048,13 +1053,12 @@
          return g.loadMethod(g.generateNamedFunctionInvokerImpl(typeForm));
      }
  
@@ -1590,7 +1569,7 @@
          // Suppress this method in backtraces displayed to the user.
          mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
  
-@@ -1090,9 +1094,27 @@
+@@ -1099,9 +1103,27 @@
          emitReturnInsn(Object.class);  // NOTE: NamedFunction invokers always return a reference value.
  
          classFileEpilogue();
@@ -1619,9 +1598,9 @@
 +        }
 +    }
  }
-diff -r e7d4a60c75ff src/share/classes/java/lang/invoke/Invokers.java
---- a/src/share/classes/java/lang/invoke/Invokers.java	Mon Jul 09 08:42:05 2012 +0200
-+++ b/src/share/classes/java/lang/invoke/Invokers.java	Tue Jul 10 12:15:25 2012 +0200
+diff -r 25fcfb3a5f65 src/share/classes/java/lang/invoke/Invokers.java
+--- a/src/share/classes/java/lang/invoke/Invokers.java	Wed Jul 11 14:18:03 2012 +0200
++++ b/src/share/classes/java/lang/invoke/Invokers.java	Wed Jul 11 22:06:34 2012 +0200
 @@ -75,7 +75,7 @@
          if (invoker != null)  return invoker;
          MethodType mtype = targetType;
@@ -1649,9 +1628,9 @@
              // else if isLinker, then MTYPE is passed in from the caller (e.g., the JVM)
          }
  
-diff -r e7d4a60c75ff src/share/classes/java/lang/invoke/LambdaForm.java
---- a/src/share/classes/java/lang/invoke/LambdaForm.java	Mon Jul 09 08:42:05 2012 +0200
-+++ b/src/share/classes/java/lang/invoke/LambdaForm.java	Tue Jul 10 12:15:25 2012 +0200
+diff -r 25fcfb3a5f65 src/share/classes/java/lang/invoke/LambdaForm.java
+--- a/src/share/classes/java/lang/invoke/LambdaForm.java	Wed Jul 11 14:18:03 2012 +0200
++++ b/src/share/classes/java/lang/invoke/LambdaForm.java	Wed Jul 11 22:06:34 2012 +0200
 @@ -264,7 +264,7 @@
          // Do all names possess an index consistent with their local definition order?
          for (int i = 0; i < arity; i++) {
@@ -1694,7 +1673,7 @@
      static Object interpret_L(MethodHandle mh, Object x1, Object x2) throws Throwable {
          Object[] av = {mh, x1, x2};
          String sig = null;
-@@ -709,8 +706,57 @@
+@@ -711,8 +708,57 @@
          return buf.toString();
      }
  
@@ -1753,7 +1732,7 @@
          return bind(names[namePos], dataValueName);
      }
  
-@@ -723,7 +769,7 @@
+@@ -725,7 +771,7 @@
          if (bindCache != null) {
              LambdaForm form = bindCache[pos];
              if (form != null) {
@@ -1762,7 +1741,7 @@
                  return form;
              }
          } else {
-@@ -907,6 +953,15 @@
+@@ -909,6 +955,15 @@
              resolvedHandle = DirectMethodHandle.make(member);
          }
  
@@ -1778,9 +1757,9 @@
          // Put the predefined NamedFunction invokers into the table.
          static void initializeInvokers() {
              for (MemberName m : MemberName.getFactory().getMethods(NamedFunction.class, false, null, null, null)) {
-diff -r e7d4a60c75ff src/share/classes/java/lang/invoke/MemberName.java
---- a/src/share/classes/java/lang/invoke/MemberName.java	Mon Jul 09 08:42:05 2012 +0200
-+++ b/src/share/classes/java/lang/invoke/MemberName.java	Tue Jul 10 12:15:25 2012 +0200
+diff -r 25fcfb3a5f65 src/share/classes/java/lang/invoke/MemberName.java
+--- a/src/share/classes/java/lang/invoke/MemberName.java	Wed Jul 11 14:18:03 2012 +0200
++++ b/src/share/classes/java/lang/invoke/MemberName.java	Wed Jul 11 22:06:34 2012 +0200
 @@ -77,6 +77,32 @@
      //@Injected int         vmindex;
      private Object     resolution;  // if null, this guy is resolved
@@ -1814,9 +1793,9 @@
      /** Return the declaring class of this member.
       *  In the case of a bare name and type, the declaring class will be null.
       */
-diff -r e7d4a60c75ff src/share/classes/java/lang/invoke/MethodHandle.java
---- a/src/share/classes/java/lang/invoke/MethodHandle.java	Mon Jul 09 08:42:05 2012 +0200
-+++ b/src/share/classes/java/lang/invoke/MethodHandle.java	Tue Jul 10 12:15:25 2012 +0200
+diff -r 25fcfb3a5f65 src/share/classes/java/lang/invoke/MethodHandle.java
+--- a/src/share/classes/java/lang/invoke/MethodHandle.java	Wed Jul 11 14:18:03 2012 +0200
++++ b/src/share/classes/java/lang/invoke/MethodHandle.java	Wed Jul 11 22:06:34 2012 +0200
 @@ -28,11 +28,9 @@
  
  import java.util.*;
@@ -1870,9 +1849,9 @@
 +        return new BoundMethodHandle.BMH_L(type2, form2, this);
      }
  }
-diff -r e7d4a60c75ff src/share/classes/java/lang/invoke/MethodHandleImpl.java
---- a/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Mon Jul 09 08:42:05 2012 +0200
-+++ b/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Tue Jul 10 12:15:25 2012 +0200
+diff -r 25fcfb3a5f65 src/share/classes/java/lang/invoke/MethodHandleImpl.java
+--- a/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Wed Jul 11 14:18:03 2012 +0200
++++ b/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Wed Jul 11 22:06:34 2012 +0200
 @@ -186,43 +186,57 @@
      }
  
@@ -2057,10 +2036,10 @@
      }
  
      private static class GuardWithCatch {
-diff -r e7d4a60c75ff src/share/classes/java/lang/invoke/MethodHandleNatives.java
---- a/src/share/classes/java/lang/invoke/MethodHandleNatives.java	Mon Jul 09 08:42:05 2012 +0200
-+++ b/src/share/classes/java/lang/invoke/MethodHandleNatives.java	Tue Jul 10 12:15:25 2012 +0200
-@@ -326,19 +326,13 @@
+diff -r 25fcfb3a5f65 src/share/classes/java/lang/invoke/MethodHandleNatives.java
+--- a/src/share/classes/java/lang/invoke/MethodHandleNatives.java	Wed Jul 11 14:18:03 2012 +0200
++++ b/src/share/classes/java/lang/invoke/MethodHandleNatives.java	Wed Jul 11 22:06:34 2012 +0200
+@@ -325,19 +325,13 @@
          if (defc != MethodHandle.class || refKind != REF_invokeVirtual)
              throw new LinkageError("no such method "+defc.getName()+"."+name+type);
  
@@ -2086,9 +2065,9 @@
      }
  
      /**
-diff -r e7d4a60c75ff src/share/classes/java/lang/invoke/MethodType.java
---- a/src/share/classes/java/lang/invoke/MethodType.java	Mon Jul 09 08:42:05 2012 +0200
-+++ b/src/share/classes/java/lang/invoke/MethodType.java	Tue Jul 10 12:15:25 2012 +0200
+diff -r 25fcfb3a5f65 src/share/classes/java/lang/invoke/MethodType.java
+--- a/src/share/classes/java/lang/invoke/MethodType.java	Wed Jul 11 14:18:03 2012 +0200
++++ b/src/share/classes/java/lang/invoke/MethodType.java	Wed Jul 11 22:06:34 2012 +0200
 @@ -108,6 +108,8 @@
      /*trusted*/ Class<?> rtype() { return rtype; }
      /*trusted*/ Class<?>[] ptypes() { return ptypes; }
@@ -2098,9 +2077,9 @@
      private static void checkRtype(Class<?> rtype) {
          rtype.equals(rtype);  // null check
      }
-diff -r e7d4a60c75ff src/share/classes/java/lang/invoke/SimpleMethodHandle.java
---- a/src/share/classes/java/lang/invoke/SimpleMethodHandle.java	Mon Jul 09 08:42:05 2012 +0200
-+++ b/src/share/classes/java/lang/invoke/SimpleMethodHandle.java	Tue Jul 10 12:15:25 2012 +0200
+diff -r 25fcfb3a5f65 src/share/classes/java/lang/invoke/SimpleMethodHandle.java
+--- a/src/share/classes/java/lang/invoke/SimpleMethodHandle.java	Wed Jul 11 14:18:03 2012 +0200
++++ b/src/share/classes/java/lang/invoke/SimpleMethodHandle.java	Wed Jul 11 22:06:34 2012 +0200
 @@ -55,4 +55,10 @@
          LambdaForm form2 = internalForm().permuteArguments(1, reorder, basicTypes(newType.parameterList()));
          return new SimpleMethodHandle(newType, form2);
@@ -2112,3 +2091,131 @@
 +    }
 +
  }
+diff -r 25fcfb3a5f65 test/java/lang/invoke/MaxTest.java
+--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
++++ b/test/java/lang/invoke/MaxTest.java	Wed Jul 11 22:06:34 2012 +0200
+@@ -0,0 +1,124 @@
++/*
++ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation.  Oracle designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Oracle in the LICENSE file that accompanied this code.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
++ * or visit www.oracle.com if you need additional information or have any
++ * questions.
++ */
++
++/* @test
++ * @summary BoundMethodHandle tests with primitive types
++ * @compile MaxTest.java
++ * @run junit/othervm test.java.lang.invoke.MaxTest
++ */
++
++package test.java.lang.invoke;
++
++import static org.junit.Assert.assertEquals;
++
++import java.lang.invoke.MethodHandle;
++import java.lang.invoke.MethodHandles;
++import java.lang.invoke.MethodType;
++
++import org.junit.Test;
++
++public class MaxTest {
++
++    static MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
++
++    private MethodHandle getMax(Class<?> t) throws Throwable {
++        return LOOKUP.findStatic(Math.class, "max", MethodType.methodType(t, t, t));
++    }
++
++    @Test
++    public void testMaxLong() throws Throwable {
++        final Class<?> C = long.class;
++        final long P = 23L;
++        final long Q = 42L;
++        final long R = Math.max(P, Q);
++        MethodHandle h = getMax(C);
++        assertEquals((long) h.invokeExact(P, Q), R);
++        MethodHandle bh = MethodHandles.insertArguments(h, 0, P);
++        assertEquals((long) bh.invokeExact(Q), R);
++        MethodHandle bbh = MethodHandles.insertArguments(bh, 0, Q);
++        assertEquals((long) bbh.invokeExact(), R);
++        MethodHandle b2h = MethodHandles.insertArguments(h, 1, Q);
++        assertEquals((long) b2h.invokeExact(P), R);
++        MethodHandle bb2h = MethodHandles.insertArguments(b2h, 0, P);
++        assertEquals((long) bb2h.invokeExact(), R);
++    }
++
++    @Test
++    public void testMaxInt() throws Throwable {
++        final Class<?> C = int.class;
++        final int P = 23;
++        final int Q = 42;
++        final int R = Math.max(P, Q);
++        MethodHandle h = getMax(C);
++        assertEquals((int) h.invokeExact(P, Q), R);
++        MethodHandle bh = MethodHandles.insertArguments(h, 0, P);
++        assertEquals((int) bh.invokeExact(Q), R);
++        MethodHandle bbh = MethodHandles.insertArguments(bh, 0, Q);
++        assertEquals((int) bbh.invokeExact(), R);
++        MethodHandle b2h = MethodHandles.insertArguments(h, 1, Q);
++        assertEquals((int) b2h.invokeExact(P), R);
++        MethodHandle bb2h = MethodHandles.insertArguments(b2h, 0, P);
++        assertEquals((int) bb2h.invokeExact(), R);
++    }
++
++    @Test
++    public void testMaxFloat() throws Throwable {
++        final Class<?> C = float.class;
++        final float P = 23F;
++        final float Q = 42F;
++        final float R = Math.max(P, Q);
++        final float D = 0.1F;
++        MethodHandle h = getMax(C);
++        assertEquals((float) h.invokeExact(P, Q), R, D);
++        MethodHandle bh = MethodHandles.insertArguments(h, 0, P);
++        assertEquals((float) bh.invokeExact(Q), R, D);
++        MethodHandle bbh = MethodHandles.insertArguments(bh, 0, Q);
++        assertEquals((float) bbh.invokeExact(), R, D);
++        MethodHandle b2h = MethodHandles.insertArguments(h, 1, Q);
++        assertEquals((float) b2h.invokeExact(P), R, D);
++        MethodHandle bb2h = MethodHandles.insertArguments(b2h, 0, P);
++        assertEquals((float) bb2h.invokeExact(), R, D);
++    }
++
++    @Test
++    public void testMaxDouble() throws Throwable {
++        final Class<?> C = double.class;
++        final double P = 23F;
++        final double Q = 42F;
++        final double R = Math.max(P, Q);
++        final double D = 0.1;
++        MethodHandle h = getMax(C);
++        assertEquals((double) h.invokeExact(P, Q), R, D);
++        MethodHandle bh = MethodHandles.insertArguments(h, 0, P);
++        assertEquals((double) bh.invokeExact(Q), R, D);
++        MethodHandle bbh = MethodHandles.insertArguments(bh, 0, Q);
++        assertEquals((double) bbh.invokeExact(), R, D);
++        MethodHandle b2h = MethodHandles.insertArguments(h, 1, Q);
++        assertEquals((double) b2h.invokeExact(P), R, D);
++        MethodHandle bb2h = MethodHandles.insertArguments(b2h, 0, P);
++        assertEquals((double) bb2h.invokeExact(), R, D);
++    }
++
++}