changeset 453:383cbcabff6f

update JDK 8 JSR 292 specs
author jrose
date Fri, 13 Sep 2013 22:50:28 -0700
parents 58550230addb
children 27753ae4c64a
files indy-bsm-8024761.patch meth-clinit-8024599.patch meth-coll-8001110.patch meth-mr-8024438.patch meth-nsme-8001108.patch meth-spr-8001109.patch
diffstat 6 files changed, 3389 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/indy-bsm-8024761.patch	Fri Sep 13 22:50:28 2013 -0700
@@ -0,0 +1,1093 @@
+8024761: JSR 292 improve performance of generic invocation
+Summary: use a per-MH one element cache for MH.asType to speed up MH.invoke; also cache enough MH constants to cache LMF.metafactory
+
+Cherry-pick method handle optimizations which affect BSM lookup and invocation.
+Alternative to http://cr.openjdk.java.net/~skuksenko/jsr335/8024630/webrev.00/
+
+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
+@@ -360,6 +360,10 @@
+             return new Name(mh, mhName);
+         }
+ 
++        NamedFunction getterFunction(int i) {
++            return new NamedFunction(getters[i]);
++        }
++
+         static final SpeciesData EMPTY = new SpeciesData("", BoundMethodHandle.class);
+ 
+         private SpeciesData(String types, Class<? extends BoundMethodHandle> clazz) {
+diff --git a/src/share/classes/java/lang/invoke/CallSite.java b/src/share/classes/java/lang/invoke/CallSite.java
+--- a/src/share/classes/java/lang/invoke/CallSite.java
++++ b/src/share/classes/java/lang/invoke/CallSite.java
+@@ -273,14 +273,43 @@
+             } else {
+                 Object[] argv = (Object[]) info;
+                 maybeReBoxElements(argv);
+-                if (3 + argv.length > 255)
+-                    throw new BootstrapMethodError("too many bootstrap method arguments");
+-                MethodType bsmType = bootstrapMethod.type();
+-                if (bsmType.parameterCount() == 4 && bsmType.parameterType(3) == Object[].class)
+-                    binding = bootstrapMethod.invoke(caller, name, type, argv);
+-                else
+-                    binding = MethodHandles.spreadInvoker(bsmType, 3)
+-                        .invoke(bootstrapMethod, caller, name, type, argv);
++                switch (argv.length) {
++                case 0:
++                    binding = bootstrapMethod.invoke(caller, name, type);
++                    break;
++                case 1:
++                    binding = bootstrapMethod.invoke(caller, name, type,
++                                                     argv[0]);
++                    break;
++                case 2:
++                    binding = bootstrapMethod.invoke(caller, name, type,
++                                                     argv[0], argv[1]);
++                    break;
++                case 3:
++                    binding = bootstrapMethod.invoke(caller, name, type,
++                                                     argv[0], argv[1], argv[2]);
++                    break;
++                case 4:
++                    binding = bootstrapMethod.invoke(caller, name, type,
++                                                     argv[0], argv[1], argv[2], argv[3]);
++                    break;
++                case 5:
++                    binding = bootstrapMethod.invoke(caller, name, type,
++                                                     argv[0], argv[1], argv[2], argv[3], argv[4]);
++                    break;
++                case 6:
++                    binding = bootstrapMethod.invoke(caller, name, type,
++                                                     argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
++                    break;
++                default:
++                    if (3 + argv.length > MethodType.MAX_MH_ARITY)
++                        throw new BootstrapMethodError("too many bootstrap method arguments");
++                    MethodType bsmType = bootstrapMethod.type();
++                    MethodType invocationType = MethodType.genericMethodType(3 + argv.length);
++                    MethodHandle typedBSM = bootstrapMethod.asType(invocationType);
++                    MethodHandle spreader = invocationType.invokers().spreadInvoker(3);
++                    binding = spreader.invokeExact(typedBSM, /*(Object)*/caller, (Object)name, (Object)type, argv);
++                }
+             }
+             //System.out.println("BSM for "+name+type+" => "+binding);
+             if (binding instanceof CallSite) {
+diff --git a/src/share/classes/java/lang/invoke/InvokeGeneric.java b/src/share/classes/java/lang/invoke/InvokeGeneric.java
+deleted file mode 100644
+--- a/src/share/classes/java/lang/invoke/InvokeGeneric.java
++++ /dev/null
+@@ -1,148 +0,0 @@
+-/*
+- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+- *
+- * This code is free software; you can redistribute it and/or modify it
+- * under the terms of the GNU General Public License version 2 only, as
+- * published by the Free Software Foundation.  Oracle designates this
+- * particular file as subject to the "Classpath" exception as provided
+- * by Oracle in the LICENSE file that accompanied this code.
+- *
+- * This code is distributed in the hope that it will be useful, but WITHOUT
+- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+- * version 2 for more details (a copy is included in the LICENSE file that
+- * accompanied this code).
+- *
+- * You should have received a copy of the GNU General Public License version
+- * 2 along with this work; if not, write to the Free Software Foundation,
+- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+- *
+- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+- * or visit www.oracle.com if you need additional information or have any
+- * questions.
+- */
+-
+-package java.lang.invoke;
+-
+-import sun.invoke.util.*;
+-import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
+-
+-/**
+- * Adapters which manage inexact MethodHandle.invoke calls.
+- * The JVM calls one of these when the exact type match fails.
+- * @author jrose
+- */
+-class InvokeGeneric {
+-    // erased type for the call, which originates from an inexact invoke site
+-    private final MethodType erasedCallerType;
+-    // an invoker of type (MT, MH; A...) -> R
+-    private final MethodHandle initialInvoker;
+-
+-    /** Compute and cache information for this adapter, so that it can
+-     *  call out to targets of the erasure-family of the given erased type.
+-     */
+-    /*non-public*/ InvokeGeneric(MethodType erasedCallerType) throws ReflectiveOperationException {
+-        assert(erasedCallerType.equals(erasedCallerType.erase()));
+-        this.erasedCallerType = erasedCallerType;
+-        this.initialInvoker = makeInitialInvoker();
+-        assert initialInvoker.type().equals(erasedCallerType
+-                                            .insertParameterTypes(0, MethodType.class, MethodHandle.class))
+-            : initialInvoker.type();
+-    }
+-
+-    private static MethodHandles.Lookup lookup() {
+-        return IMPL_LOOKUP;
+-    }
+-
+-    /** Return the adapter information for this type's erasure. */
+-    /*non-public*/ static MethodHandle generalInvokerOf(MethodType erasedCallerType) throws ReflectiveOperationException {
+-        InvokeGeneric gen = new InvokeGeneric(erasedCallerType);
+-        return gen.initialInvoker;
+-    }
+-
+-    private MethodHandle makeInitialInvoker() throws ReflectiveOperationException {
+-        // postDispatch = #(MH'; MT, MH; A...){MH'(MT, MH; A)}
+-        MethodHandle postDispatch = makePostDispatchInvoker();
+-        MethodHandle invoker;
+-        if (returnConversionPossible()) {
+-            invoker = MethodHandles.foldArguments(postDispatch,
+-                                                  dispatcher("dispatchWithConversion"));
+-        } else {
+-            invoker = MethodHandles.foldArguments(postDispatch, dispatcher("dispatch"));
+-        }
+-        return invoker;
+-    }
+-
+-    private static final Class<?>[] EXTRA_ARGS = { MethodType.class, MethodHandle.class };
+-    private MethodHandle makePostDispatchInvoker() {
+-        // Take (MH'; MT, MH; A...) and run MH'(MT, MH; A...).
+-        MethodType invokerType = erasedCallerType.insertParameterTypes(0, EXTRA_ARGS);
+-        return invokerType.invokers().exactInvoker();
+-    }
+-    private MethodHandle dropDispatchArguments(MethodHandle targetInvoker) {
+-        assert(targetInvoker.type().parameterType(0) == MethodHandle.class);
+-        return MethodHandles.dropArguments(targetInvoker, 1, EXTRA_ARGS);
+-    }
+-
+-    private MethodHandle dispatcher(String dispatchName) throws ReflectiveOperationException {
+-        return lookup().bind(this, dispatchName,
+-                             MethodType.methodType(MethodHandle.class,
+-                                                   MethodType.class, MethodHandle.class));
+-    }
+-
+-    static final boolean USE_AS_TYPE_PATH = true;
+-
+-    /** Return a method handle to invoke on the callerType, target, and remaining arguments.
+-     *  The method handle must finish the call.
+-     *  This is the first look at the caller type and target.
+-     */
+-    private MethodHandle dispatch(MethodType callerType, MethodHandle target) {
+-        MethodType targetType = target.type();
+-        if (USE_AS_TYPE_PATH || target.isVarargsCollector()) {
+-            MethodHandle newTarget = target.asType(callerType);
+-            targetType = callerType;
+-            Invokers invokers = targetType.invokers();
+-            MethodHandle invoker = invokers.erasedInvokerWithDrops;
+-            if (invoker == null) {
+-                invokers.erasedInvokerWithDrops = invoker =
+-                    dropDispatchArguments(invokers.erasedInvoker());
+-            }
+-            return invoker.bindTo(newTarget);
+-        }
+-        throw new RuntimeException("NYI");
+-    }
+-
+-    private MethodHandle dispatchWithConversion(MethodType callerType, MethodHandle target) {
+-        MethodHandle finisher = dispatch(callerType, target);
+-        if (returnConversionNeeded(callerType, target))
+-            finisher = addReturnConversion(finisher, callerType.returnType());  //FIXME: slow
+-        return finisher;
+-    }
+-
+-    private boolean returnConversionPossible() {
+-        Class<?> needType = erasedCallerType.returnType();
+-        return !needType.isPrimitive();
+-    }
+-    private boolean returnConversionNeeded(MethodType callerType, MethodHandle target) {
+-        Class<?> needType = callerType.returnType();
+-        if (needType == erasedCallerType.returnType())
+-            return false;  // no conversions possible, since must be primitive or Object
+-        Class<?> haveType = target.type().returnType();
+-        if (VerifyType.isNullConversion(haveType, needType) && !needType.isInterface())
+-            return false;
+-        return true;
+-    }
+-    private MethodHandle addReturnConversion(MethodHandle finisher, Class<?> type) {
+-        // FIXME: This is slow because it creates a closure node on every call that requires a return cast.
+-        MethodType finisherType = finisher.type();
+-        MethodHandle caster = ValueConversions.identity(type);
+-        caster = caster.asType(caster.type().changeParameterType(0, finisherType.returnType()));
+-        finisher = MethodHandles.filterReturnValue(finisher, caster);
+-        return finisher.asType(finisherType);
+-    }
+-
+-    public String toString() {
+-        return "InvokeGeneric"+erasedCallerType;
+-    }
+-}
+diff --git a/src/share/classes/java/lang/invoke/Invokers.java b/src/share/classes/java/lang/invoke/Invokers.java
+--- a/src/share/classes/java/lang/invoke/Invokers.java
++++ b/src/share/classes/java/lang/invoke/Invokers.java
+@@ -44,6 +44,7 @@
+ 
+     // exact invoker for the outgoing call
+     private /*lazy*/ MethodHandle exactInvoker;
++    private /*lazy*/ MethodHandle basicInvoker;  // invokeBasic (unchecked exact)
+ 
+     // erased (partially untyped but with primitives) invoker for the outgoing call
+     // FIXME: get rid of
+@@ -76,19 +77,12 @@
+         if (invoker != null)  return invoker;
+         MethodType mtype = targetType;
+         MethodType invokerType = mtype.invokerType();
+-        LambdaForm lform;
+-        final int MTYPE_ARG_APPENDED = 1;  // argument count for appended mtype value
+-        if (mtype.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY - MTYPE_ARG_APPENDED) {
+-            lform = invokeForm(mtype, false, MethodTypeForm.LF_EX_INVOKER);
+-            invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype);
+-        } else {
+-            // At maximum arity, we cannot afford an extra mtype argument,
+-            // so build a fully customized (non-cached) invoker form.
+-            lform = invokeForm(mtype, true, MethodTypeForm.LF_EX_INVOKER);
+-            invoker = SimpleMethodHandle.make(invokerType, lform);
+-        }
++        LambdaForm lform = invokeHandleForm(mtype, false, MethodTypeForm.LF_EX_INVOKER);
++        invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype);
+         invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke("invokeExact", mtype));
+         assert(checkInvoker(invoker));
++        if (targetType == targetType.erase() && targetType.parameterCount() < 10)
++            invoker.form.compileToBytecode();
+         exactInvoker = invoker;
+         return invoker;
+     }
+@@ -98,41 +92,41 @@
+         if (invoker != null)  return invoker;
+         MethodType mtype = targetType;
+         MethodType invokerType = mtype.invokerType();
+-        LambdaForm lform;
+-        final int MTYPE_ARG_APPENDED = 1;  // argument count for appended mtype value
+-        assert(GENERIC_INVOKER_SLOP >= MTYPE_ARG_APPENDED);
+-        if (mtype.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY - GENERIC_INVOKER_SLOP) {
+-            prepareForGenericCall(mtype);
+-            lform = invokeForm(mtype, false, MethodTypeForm.LF_GEN_INVOKER);
+-            invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype);
+-        } else {
+-            // At maximum arity, we cannot afford an extra mtype argument,
+-            // so build a fully customized (non-cached) invoker form.
+-            lform = invokeForm(mtype, true, MethodTypeForm.LF_GEN_INVOKER);
+-            invoker = SimpleMethodHandle.make(invokerType, lform);
+-        }
++        LambdaForm lform = invokeHandleForm(mtype, false, MethodTypeForm.LF_GEN_INVOKER);
++        invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype);
+         invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke("invoke", mtype));
+         assert(checkInvoker(invoker));
++        if (targetType == targetType.erase() && targetType.parameterCount() < 10)
++            invoker.form.compileToBytecode();
+         generalInvoker = invoker;
+         return invoker;
+     }
+ 
+-    /*non-public*/ MethodHandle makeBasicInvoker() {
+-        MethodHandle invoker = DirectMethodHandle.make(invokeBasicMethod(targetType));
+-        assert(targetType == targetType.basicType());
+-        // Note:  This is not cached here.  It is cached by the calling MethodTypeForm.
++
++    /*non-public*/ MethodHandle basicInvoker() {
++        MethodHandle invoker = basicInvoker;
++        if (invoker != null)  return invoker;
++        MethodType basicType = targetType.basicType();
++        if (basicType != targetType) {
++            // double cache; not used significantly
++            return basicInvoker = basicType.invokers().basicInvoker();
++        }
++        MemberName method = invokeBasicMethod(basicType);
++        invoker = DirectMethodHandle.make(method);
+         assert(checkInvoker(invoker));
++        //invoker.form.compileToBytecode();
++        basicInvoker = invoker;
+         return invoker;
+     }
+ 
+-    static MemberName invokeBasicMethod(MethodType type) {
+-        type = type.basicType();
+-        String name = "invokeBasic";
++    // This next one is called from LambdaForm.NamedFunction.<init>.
++    /*non-public*/ static MemberName invokeBasicMethod(MethodType basicType) {
++        assert(basicType == basicType.basicType());
+         try {
+             //Lookup.findVirtual(MethodHandle.class, name, type);
+-            return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, name, type);
++            return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, "invokeBasic", basicType);
+         } catch (ReflectiveOperationException ex) {
+-            throw newInternalError("JVM cannot find invoker for "+type, ex);
++            throw newInternalError("JVM cannot find invoker for "+basicType, ex);
+         }
+     }
+ 
+@@ -184,6 +178,8 @@
+             vaInvoker = MethodHandles.filterArgument(arrayInvoker, 0, makeSpreader);
+         }
+         assert(vaInvoker.type().equals(spreadInvokerType.invokerType()));
++        if (targetType == targetType.erase() && targetType.parameterCount() < 10)
++            vaInvoker.form.compileToBytecode();
+         spreadInvokers[leadingArgCount] = vaInvoker;
+         return vaInvoker;
+     }
+@@ -231,32 +227,41 @@
+         return "Invokers"+targetType;
+     }
+ 
+-    static MemberName exactInvokerMethod(MethodType mtype, Object[] appendixResult) {
++    static MemberName exactInvokeLinkerMethod(MethodType mtype, Object[] appendixResult) {
+         LambdaForm lform;
+-        final int MTYPE_ARG_APPENDED = 1;  // argument count for appended mtype value
+-        if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - MTYPE_ARG_APPENDED) {
+-            lform = invokeForm(mtype, false, MethodTypeForm.LF_EX_LINKER);
++        if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - MH_LINKER_ARG_APPENDED) {
++            lform = invokeHandleForm(mtype, false, MethodTypeForm.LF_EX_LINKER);
+             appendixResult[0] = mtype;
+         } else {
+-            lform = invokeForm(mtype, true, MethodTypeForm.LF_EX_LINKER);
++            lform = invokeHandleForm(mtype, true, MethodTypeForm.LF_EX_LINKER);
+         }
+         return lform.vmentry;
+     }
+ 
+-    static MemberName genericInvokerMethod(MethodType mtype, Object[] appendixResult) {
++    static MemberName genericInvokeLinkerMethod(MethodType mtype, Object[] appendixResult) {
+         LambdaForm lform;
+-        final int MTYPE_ARG_APPENDED = 1;  // argument count for appended mtype value
+-        if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - (MTYPE_ARG_APPENDED + GENERIC_INVOKER_SLOP)) {
+-            lform = invokeForm(mtype, false, MethodTypeForm.LF_GEN_LINKER);
++        if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - MH_LINKER_ARG_APPENDED) {
++            lform = invokeHandleForm(mtype, false, MethodTypeForm.LF_GEN_LINKER);
+             appendixResult[0] = mtype;
+-            prepareForGenericCall(mtype);
+         } else {
+-            lform = invokeForm(mtype, true, MethodTypeForm.LF_GEN_LINKER);
++            lform = invokeHandleForm(mtype, true, MethodTypeForm.LF_GEN_LINKER);
+         }
+         return lform.vmentry;
+     }
+ 
+-    private static LambdaForm invokeForm(MethodType mtype, boolean customized, int which) {
++    // argument count to account for trailing "appendix value" (typically the mtype)
++    private static final int MH_LINKER_ARG_APPENDED = 1;
++
++    // Return an adapter for invokeExact or generic invoke, as a MH or constant pool linker
++    // mtype : the caller's method type (either basic or full-custom)
++    // customized : whether to use a trailing appendix argument (to carry the mtype)
++    // which&0x01 : whether it is a CP adapter ("linker") or MHs.invoker value ("invoker")
++    // which&0x02 : whether it is for invokeExact or generic invoke
++    //
++    // If !customized, caller is responsible for supplying, during adapter execution,
++    // a copy of the exact mtype.  This is because the adapter might be generalized to
++    // a basic type.
++    private static LambdaForm invokeHandleForm(MethodType mtype, boolean customized, int which) {
+         boolean isCached;
+         if (!customized) {
+             mtype = mtype.basicType();  // normalize Z to I, String to Object, etc.
+@@ -301,41 +306,24 @@
+                 : Arrays.asList(mtype, customized, which, nameCursor, names.length);
+         if (MTYPE_ARG >= INARG_LIMIT) {
+             assert(names[MTYPE_ARG] == null);
+-            names[MTYPE_ARG] = BoundMethodHandle.getSpeciesData("L").getterName(names[THIS_MH], 0);
++            NamedFunction getter = BoundMethodHandle.getSpeciesData("L").getterFunction(0);
++            names[MTYPE_ARG] = new Name(getter, names[THIS_MH]);
+             // else if isLinker, then MTYPE is passed in from the caller (e.g., the JVM)
+         }
+ 
+         // Make the final call.  If isGeneric, then prepend the result of type checking.
+-        MethodType outCallType;
+-        Object[] outArgs;
++        MethodType outCallType = mtype.basicType();
++        Object[] outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT, Object[].class);
+         Object mtypeArg = (customized ? mtype : names[MTYPE_ARG]);
+         if (!isGeneric) {
+             names[CHECK_TYPE] = new Name(NF_checkExactType, names[CALL_MH], mtypeArg);
+             // mh.invokeExact(a*):R => checkExactType(mh, TYPEOF(a*:R)); mh.invokeBasic(a*)
+-            outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT, Object[].class);
+-            outCallType = mtype;
+-        } else if (customized) {
+-            names[CHECK_TYPE] = new Name(NF_asType, names[CALL_MH], mtypeArg);
+-            // mh.invokeGeneric(a*):R =>
+-            //  let mt=TYPEOF(a*:R), tmh=asType(mh, mt);
+-            //    tmh.invokeBasic(a*)
+-            outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT, Object[].class);
+-            outCallType = mtype;
+         } else {
+             names[CHECK_TYPE] = new Name(NF_checkGenericType, names[CALL_MH], mtypeArg);
+-            // mh.invokeGeneric(a*):R =>
+-            //  let mt=TYPEOF(a*:R), gamh=checkGenericType(mh, mt);
+-            //    gamh.invokeBasic(mt, mh, a*)
+-            final int PREPEND_GAMH = 0, PREPEND_MT = 1, PREPEND_COUNT = 2;
+-            assert(GENERIC_INVOKER_SLOP == PREPEND_COUNT);
+-            outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT + PREPEND_COUNT, Object[].class);
+-            // prepend arguments:
+-            System.arraycopy(outArgs, 0, outArgs, PREPEND_COUNT, outArgs.length - PREPEND_COUNT);
+-            outArgs[PREPEND_GAMH] = names[CHECK_TYPE];
+-            outArgs[PREPEND_MT] = mtypeArg;
+-            outCallType = mtype.insertParameterTypes(0, MethodType.class, MethodHandle.class);
++            // mh.invokeGeneric(a*):R => checkGenericType(mh, TYPEOF(a*:R)).invokeBasic(a*)
++            outArgs[0] = names[CHECK_TYPE];
+         }
+-        names[LINKER_CALL] = new Name(invokeBasicMethod(outCallType), outArgs);
++        names[LINKER_CALL] = new Name(outCallType, outArgs);
+         lform = new LambdaForm(debugName, INARG_LIMIT, names);
+         if (isLinker)
+             lform.compileToBytecode();  // JVM needs a real methodOop
+@@ -343,7 +331,6 @@
+             lform = mtype.form().setCachedLambdaForm(which, lform);
+         return lform;
+     }
+-    private static final int GENERIC_INVOKER_SLOP = 2;  // used elsewhere to avoid arity problems
+ 
+     /*non-public*/ static
+     WrongMethodTypeException newWrongMethodTypeException(MethodType actual, MethodType expected) {
+@@ -362,47 +349,53 @@
+             throw newWrongMethodTypeException(expected, actual);
+     }
+ 
+-    /** Static definition of MethodHandle.invokeGeneric checking code. */
++    /** Static definition of MethodHandle.invokeGeneric checking code.
++     * Directly returns the type-adjusted MH to invoke, as follows:
++     * {@code (R)MH.invoke(a*) => MH.asType(TYPEOF(a*:R)).invokeBasic(a*)}
++     */
+     /*non-public*/ static
+     @ForceInline
+     Object checkGenericType(Object mhObj, Object expectedObj) {
+         MethodHandle mh = (MethodHandle) mhObj;
+         MethodType expected = (MethodType) expectedObj;
+-        //MethodType actual = mh.type();
+-        MethodHandle gamh = expected.form().genericInvoker;
+-        if (gamh != null)  return gamh;
+-        return prepareForGenericCall(expected);
+-    }
+-
+-    /**
+-     * Returns an adapter GA for invoking a MH with type adjustments.
+-     * The MethodType of the generic invocation site is prepended to MH
+-     * and its arguments as follows:
+-     * {@code (R)MH.invoke(A*) => GA.invokeBasic(TYPEOF<A*,R>, MH, A*)}
+-     */
+-    /*non-public*/ static MethodHandle prepareForGenericCall(MethodType mtype) {
+-        // force any needed adapters to be preconstructed
+-        MethodTypeForm form = mtype.form();
+-        MethodHandle gamh = form.genericInvoker;
+-        if (gamh != null)  return gamh;
+-        try {
+-            // Trigger adapter creation.
+-            gamh = InvokeGeneric.generalInvokerOf(form.erasedType);
+-            form.genericInvoker = gamh;
+-            return gamh;
+-        } catch (Exception ex) {
+-            throw newInternalError("Exception while resolving inexact invoke", ex);
+-        }
++        if (mh.type() == expected)  return mh;
++        MethodHandle atc = mh.asTypeCache;
++        if (atc != null && atc.type() == expected)  return atc;
++        return mh.asType(expected);
++        /* Maybe add more paths here.  Possible optimizations:
++         * for (R)MH.invoke(a*),
++         * let MT0 = TYPEOF(a*:R), MT1 = MH.type
++         *
++         * if MT0==MT1 or MT1 can be safely called by MT0
++         *  => MH.invokeBasic(a*)
++         * if MT1 can be safely called by MT0[R := Object]
++         *  => MH.invokeBasic(a*) & checkcast(R)
++         * if MT1 can be safely called by MT0[* := Object]
++         *  => checkcast(A)* & MH.invokeBasic(a*) & checkcast(R)
++         * if a big adapter BA can be pulled out of (MT0,MT1)
++         *  => BA.invokeBasic(MT0,MH,a*)
++         * if a local adapter LA can cached on static CS0 = new GICS(MT0)
++         *  => CS0.LA.invokeBasic(MH,a*)
++         * else
++         *  => MH.asType(MT0).invokeBasic(A*)
++         */
+     }
+ 
+     static MemberName linkToCallSiteMethod(MethodType mtype) {
+-        LambdaForm lform = callSiteForm(mtype);
++        LambdaForm lform = callSiteForm(mtype, false);
+         return lform.vmentry;
+     }
+ 
+-    private static LambdaForm callSiteForm(MethodType mtype) {
++    static MemberName linkToTargetMethod(MethodType mtype) {
++        LambdaForm lform = callSiteForm(mtype, true);
++        return lform.vmentry;
++    }
++
++    // skipCallSite is true if we are optimizing a ConstantCallSite
++    private static LambdaForm callSiteForm(MethodType mtype, boolean skipCallSite) {
+         mtype = mtype.basicType();  // normalize Z to I, String to Object, etc.
+-        LambdaForm lform = mtype.form().cachedLambdaForm(MethodTypeForm.LF_CS_LINKER);
++        final int which = (skipCallSite ? MethodTypeForm.LF_MH_LINKER : MethodTypeForm.LF_CS_LINKER);
++        LambdaForm lform = mtype.form().cachedLambdaForm(which);
+         if (lform != null)  return lform;
+         // exactInvokerForm (Object,Object)Object
+         //   link with java.lang.invoke.MethodHandle.invokeBasic(MethodHandle,Object,Object)Object/invokeSpecial
+@@ -410,24 +403,26 @@
+         final int OUTARG_LIMIT = ARG_BASE + mtype.parameterCount();
+         final int INARG_LIMIT  = OUTARG_LIMIT + 1;
+         int nameCursor = OUTARG_LIMIT;
+-        final int CSITE_ARG    = nameCursor++;  // the last in-argument
+-        final int CALL_MH      = nameCursor++;  // result of getTarget
++        final int APPENDIX_ARG = nameCursor++;  // the last in-argument
++        final int CSITE_ARG    = skipCallSite ? -1 : APPENDIX_ARG;
++        final int CALL_MH      = skipCallSite ? APPENDIX_ARG : nameCursor++;  // result of getTarget
+         final int LINKER_CALL  = nameCursor++;
+-        MethodType invokerFormType = mtype.appendParameterTypes(CallSite.class);
++        MethodType invokerFormType = mtype.appendParameterTypes(skipCallSite ? MethodHandle.class : CallSite.class);
+         Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType);
+         assert(names.length == nameCursor);
+-        assert(names[CSITE_ARG] != null);
+-        names[CALL_MH] = new Name(NF_getCallSiteTarget, names[CSITE_ARG]);
++        assert(names[APPENDIX_ARG] != null);
++        if (!skipCallSite)
++            names[CALL_MH] = new Name(NF_getCallSiteTarget, names[CSITE_ARG]);
+         // (site.)invokedynamic(a*):R => mh = site.getTarget(); mh.invokeBasic(a*)
+         final int PREPEND_MH = 0, PREPEND_COUNT = 1;
+         Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, OUTARG_LIMIT + PREPEND_COUNT, Object[].class);
+         // prepend MH argument:
+         System.arraycopy(outArgs, 0, outArgs, PREPEND_COUNT, outArgs.length - PREPEND_COUNT);
+         outArgs[PREPEND_MH] = names[CALL_MH];
+-        names[LINKER_CALL] = new Name(invokeBasicMethod(mtype), outArgs);
+-        lform = new LambdaForm("linkToCallSite", INARG_LIMIT, names);
++        names[LINKER_CALL] = new Name(mtype, outArgs);
++        lform = new LambdaForm((skipCallSite ? "linkToTargetMethod" : "linkToCallSite"), INARG_LIMIT, names);
+         lform.compileToBytecode();  // JVM needs a real methodOop
+-        lform = mtype.form().setCachedLambdaForm(MethodTypeForm.LF_CS_LINKER, lform);
++        lform = mtype.form().setCachedLambdaForm(which, lform);
+         return lform;
+     }
+ 
+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
+@@ -452,12 +452,12 @@
+         }
+         try {
+             vmentry = InvokerBytecodeGenerator.generateCustomizedCode(this, invokerType);
+-            if (TRACE_INTERPRETER)
++            if (TRACE_INTERPRETER && INIT_DONE)
+                 traceInterpreter("compileToBytecode", this);
+             isCompiled = true;
+             return vmentry;
+         } catch (Error | Exception ex) {
+-            throw newInternalError(this.toString(), ex);
++            throw newInternalError("compileToBytecode", ex);
+         }
+     }
+ 
+@@ -595,7 +595,7 @@
+     @DontInline
+     /** Interpretively invoke this form on the given arguments. */
+     Object interpretWithArguments(Object... argumentValues) throws Throwable {
+-        if (TRACE_INTERPRETER)
++        if (TRACE_INTERPRETER && INIT_DONE)
+             return interpretWithArgumentsTracing(argumentValues);
+         checkInvocationCounter();
+         assert(arityCheck(argumentValues));
+@@ -610,7 +610,7 @@
+     @DontInline
+     /** Evaluate a single Name within this form, applying its function to its arguments. */
+     Object interpretName(Name name, Object[] values) throws Throwable {
+-        if (TRACE_INTERPRETER)
++        if (TRACE_INTERPRETER && INIT_DONE)
+             traceInterpreter("| interpretName", name.debugString(), (Object[]) null);
+         Object[] arguments = Arrays.copyOf(name.arguments, name.arguments.length, Object[].class);
+         for (int i = 0; i < arguments.length; i++) {
+@@ -683,7 +683,7 @@
+     */
+ 
+     static void traceInterpreter(String event, Object obj, Object... args) {
+-        if (!TRACE_INTERPRETER)  return;
++        if (!(TRACE_INTERPRETER && INIT_DONE))  return;
+         System.out.println("LFI: "+event+" "+(obj != null ? obj : "")+(args != null && args.length != 0 ? Arrays.asList(args) : ""));
+     }
+     static void traceInterpreter(String event, Object obj) {
+@@ -722,7 +722,7 @@
+             buf.append(";");
+         }
+         buf.append(result < 0 ? "void" : names[result]).append("}");
+-        if (TRACE_INTERPRETER) {
++        if (TRACE_INTERPRETER && INIT_DONE) {
+             // Extra verbosity:
+             buf.append(":").append(basicTypeSignature());
+             buf.append("/").append(vmentry);
+@@ -982,6 +982,16 @@
+             //resolvedHandle = eraseSubwordTypes(resolvedHandle);
+             this.resolvedHandle = resolvedHandle;
+         }
++        NamedFunction(MethodType basicInvokerType) {
++            assert(basicInvokerType == basicInvokerType.basicType()) : basicInvokerType;
++            if (basicInvokerType.parameterSlotCount() < MethodType.MAX_MH_INVOKER_ARITY) {
++                this.resolvedHandle = basicInvokerType.invokers().basicInvoker();
++                this.member = resolvedHandle.internalMemberName();
++            } else {
++                // necessary to pass BigArityTest
++                this.member = Invokers.invokeBasicMethod(basicInvokerType);
++            }
++        }
+ 
+         // The next 3 constructors are used to break circular dependencies on MH.invokeStatic, etc.
+         // Any LambdaForm containing such a member is not interpretable.
+@@ -1131,7 +1141,7 @@
+         Object invokeWithArguments(Object... arguments) throws Throwable {
+             // If we have a cached invoker, call it right away.
+             // NOTE: The invoker always returns a reference value.
+-            if (TRACE_INTERPRETER)  return invokeWithArgumentsTracing(arguments);
++            if (TRACE_INTERPRETER && INIT_DONE)  return invokeWithArgumentsTracing(arguments);
+             assert(checkArgumentTypes(arguments, methodType()));
+             return invoker().invokeBasic(resolvedHandle(), arguments);
+         }
+@@ -1229,7 +1239,7 @@
+         }
+ 
+         public String toString() {
+-            if (member == null)  return resolvedHandle.toString();
++            if (member == null)  return String.valueOf(resolvedHandle);
+             return member.getDeclaringClass().getSimpleName()+"."+member.getName();
+         }
+     }
+@@ -1279,6 +1289,10 @@
+         Name(MethodHandle function, Object... arguments) {
+             this(new NamedFunction(function), arguments);
+         }
++        Name(MethodType functionType, Object... arguments) {
++            this(new NamedFunction(functionType), arguments);
++            assert(arguments[0] instanceof Name && ((Name)arguments[0]).type == 'L');
++        }
+         Name(MemberName function, Object... arguments) {
+             this(new NamedFunction(function), arguments);
+         }
+@@ -1622,4 +1636,5 @@
+  */
+ 
+     static { NamedFunction.initializeInvokers(); }
++    static final boolean INIT_DONE = Boolean.TRUE.booleanValue();
+ }
+diff --git a/src/share/classes/java/lang/invoke/MemberName.java b/src/share/classes/java/lang/invoke/MemberName.java
+--- a/src/share/classes/java/lang/invoke/MemberName.java
++++ b/src/share/classes/java/lang/invoke/MemberName.java
+@@ -530,6 +530,24 @@
+         }
+         throw new IllegalArgumentException(this.toString());
+     }
++    public MemberName asNormalOriginal() {
++        byte normalVirtual = clazz.isInterface() ? REF_invokeInterface : REF_invokeVirtual;
++        byte refKind = getReferenceKind();
++        byte newRefKind = refKind;
++        MemberName result = this;
++        switch (refKind) {
++        case REF_invokeInterface:
++        case REF_invokeVirtual:
++        case REF_invokeSpecial:
++            newRefKind = normalVirtual;
++            break;
++        }
++        if (newRefKind == refKind)
++            return this;
++        result = clone().changeReferenceKind(newRefKind, refKind);
++        assert(this.referenceKindIsConsistentWith(result.getReferenceKind()));
++        return result;
++    }
+     /** Create a name for the given reflected constructor.  The resulting name will be in a resolved state. */
+     @SuppressWarnings("LeakingThisInConstructor")
+     public MemberName(Constructor<?> ctor) {
+@@ -627,7 +645,7 @@
+ 
+     @Override
+     public int hashCode() {
+-        return Objects.hash(clazz, flags, name, getType());
++        return Objects.hash(clazz, getReferenceKind(), name, getType());
+     }
+     @Override
+     public boolean equals(Object that) {
+@@ -643,13 +661,14 @@
+         if (this == that)  return true;
+         if (that == null)  return false;
+         return this.clazz == that.clazz
+-                && this.flags == that.flags
++                && this.getReferenceKind() == that.getReferenceKind()
+                 && Objects.equals(this.name, that.name)
+                 && Objects.equals(this.getType(), that.getType());
+     }
+ 
+     // Construction from symbolic parts, for queries:
+-    /** Create a field or type name from the given components:  Declaring class, name, type, reference kind.
++    /** Create a field or type name from the given components:
++     *  Declaring class, name, type, reference kind.
+      *  The declaring class may be supplied as null if this is to be a bare name and type.
+      *  The resulting name will in an unresolved state.
+      */
+@@ -678,16 +697,31 @@
+         init(defClass, name, type, flagsMods(flags, 0, refKind));
+         initResolved(false);
+     }
+-//    /** Create a method or constructor name from the given components:  Declaring class, name, type, modifiers.
+-//     *  It will be a constructor if and only if the name is {@code "&lt;init&gt;"}.
+-//     *  The declaring class may be supplied as null if this is to be a bare name and type.
+-//     *  The modifier flags default to zero.
+-//     *  The resulting name will in an unresolved state.
+-//     */
+-//    public MemberName(Class<?> defClass, String name, MethodType type, Void unused) {
+-//        this(defClass, name, type, REF_NONE);
+-//    }
+-
++    /** Create a method, constructor, or field name from the given components:
++     *  Reference kind, declaring class, name, type.
++     */
++    public MemberName(byte refKind, Class<?> defClass, String name, Object type) {
++        @SuppressWarnings("LocalVariableHidesMemberVariable")
++        int kindFlags;
++        if (MethodHandleNatives.refKindIsField(refKind)) {
++            kindFlags = IS_FIELD;
++            if (!(type instanceof Class))
++                throw newIllegalArgumentException("not a field type");
++        } else if (MethodHandleNatives.refKindIsMethod(refKind)) {
++            kindFlags = IS_METHOD;
++            if (!(type instanceof MethodType))
++                throw newIllegalArgumentException("not a method type");
++        } else if (refKind == REF_newInvokeSpecial) {
++            kindFlags = IS_CONSTRUCTOR;
++            if (!(type instanceof MethodType) ||
++                !CONSTRUCTOR_NAME.equals(name))
++                throw newIllegalArgumentException("not a constructor type or name");
++        } else {
++            throw newIllegalArgumentException("bad reference kind "+refKind);
++        }
++        init(defClass, name, type, flagsMods(kindFlags, 0, refKind));
++        initResolved(false);
++    }
+     /** Query whether this member name is resolved to a non-static, non-final method.
+      */
+     public boolean hasReceiverTypeDispatch() {
+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
+@@ -420,6 +420,8 @@
+     private final MethodType type;
+     /*private*/ final LambdaForm form;
+     // form is not private so that invokers can easily fetch it
++    /*private*/ MethodHandle asTypeCache;
++    // asTypeCache is not private so that invokers can easily fetch it
+ 
+     /**
+      * Reports the type of this method handle.
+@@ -739,10 +741,24 @@
+      * @see MethodHandles#explicitCastArguments
+      */
+     public MethodHandle asType(MethodType newType) {
+-        if (!type.isConvertibleTo(newType)) {
++        // Fast path alternative to a heavyweight {@code asType} call.
++        // Return 'this' if the conversion will be a no-op.
++        if (newType == type) {
++            return this;
++        }
++        // Return 'this.asTypeCache' if the conversion is already memoized.
++        MethodHandle atc = asTypeCache;
++        if (atc != null && newType == atc.type) {
++            return atc;
++        }
++        return asTypeUncached(newType);
++    }
++
++    /** Override this to change asType behavior. */
++    /*non-public*/ MethodHandle asTypeUncached(MethodType newType) {
++        if (!type.isConvertibleTo(newType))
+             throw new WrongMethodTypeException("cannot convert "+this+" to "+newType);
+-        }
+-        return convertArguments(newType);
++        return asTypeCache = convertArguments(newType);
+     }
+ 
+     /**
+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
+@@ -314,13 +314,13 @@
+     static class AsVarargsCollector extends MethodHandle {
+         private final MethodHandle target;
+         private final Class<?> arrayType;
+-        private MethodHandle cache;
++        private /*@Stable*/ MethodHandle asCollectorCache;
+ 
+         AsVarargsCollector(MethodHandle target, MethodType type, Class<?> arrayType) {
+             super(type, reinvokerForm(target));
+             this.target = target;
+             this.arrayType = arrayType;
+-            this.cache = target.asCollector(arrayType, 0);
++            this.asCollectorCache = target.asCollector(arrayType, 0);
+         }
+ 
+         @Override MethodHandle reinvokerTarget() { return target; }
+@@ -336,18 +336,19 @@
+         }
+ 
+         @Override
+-        public MethodHandle asType(MethodType newType) {
++        public MethodHandle asTypeUncached(MethodType newType) {
+             MethodType type = this.type();
+             int collectArg = type.parameterCount() - 1;
+             int newArity = newType.parameterCount();
+             if (newArity == collectArg+1 &&
+                 type.parameterType(collectArg).isAssignableFrom(newType.parameterType(collectArg))) {
+                 // if arity and trailing parameter are compatible, do normal thing
+-                return asFixedArity().asType(newType);
++                return asTypeCache = asFixedArity().asType(newType);
+             }
+             // check cache
+-            if (cache.type().parameterCount() == newArity)
+-                return cache.asType(newType);
++            MethodHandle acc = asCollectorCache;
++            if (acc != null && acc.type().parameterCount() == newArity)
++                return asTypeCache = acc.asType(newType);
+             // build and cache a collector
+             int arrayLength = newArity - collectArg;
+             MethodHandle collector;
+@@ -357,8 +358,8 @@
+             } catch (IllegalArgumentException ex) {
+                 throw new WrongMethodTypeException("cannot build collector", ex);
+             }
+-            cache = collector;
+-            return collector.asType(newType);
++            asCollectorCache = collector;
++            return asTypeCache = collector.asType(newType);
+         }
+ 
+         @Override
+@@ -971,6 +972,12 @@
+             return target;
+         }
+         @Override
++        public MethodHandle asTypeUncached(MethodType newType) {
++            // This MH is an alias for target, except for the MemberName
++            // Drop the MemberName if there is any conversion.
++            return asTypeCache = target.asType(newType);
++        }
++        @Override
+         MemberName internalMemberName() {
+             return member;
+         }
+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
+@@ -233,7 +233,18 @@
+     }
+     static String refKindName(byte refKind) {
+         assert(refKindIsValid(refKind));
+-        return REFERENCE_KIND_NAME[refKind];
++        switch (refKind) {
++        case REF_getField:          return "getField";
++        case REF_getStatic:         return "getStatic";
++        case REF_putField:          return "putField";
++        case REF_putStatic:         return "putStatic";
++        case REF_invokeVirtual:     return "invokeVirtual";
++        case REF_invokeStatic:      return "invokeStatic";
++        case REF_invokeSpecial:     return "invokeSpecial";
++        case REF_newInvokeSpecial:  return "newInvokeSpecial";
++        case REF_invokeInterface:   return "invokeInterface";
++        default:                    return "REF_???";
++        }
+     }
+     private static String[] REFERENCE_KIND_NAME = {
+             null,
+@@ -294,12 +305,18 @@
+         Class<?> caller = (Class<?>)callerObj;
+         String name = nameObj.toString().intern();
+         MethodType type = (MethodType)typeObj;
+-        appendixResult[0] = CallSite.makeSite(bootstrapMethod,
++        CallSite callSite = CallSite.makeSite(bootstrapMethod,
+                                               name,
+                                               type,
+                                               staticArguments,
+                                               caller);
+-        return Invokers.linkToCallSiteMethod(type);
++        if (callSite instanceof ConstantCallSite) {
++            appendixResult[0] = callSite.dynamicInvoker();
++            return Invokers.linkToTargetMethod(type);
++        } else {
++            appendixResult[0] = callSite;
++            return Invokers.linkToCallSiteMethod(type);
++        }
+     }
+ 
+     /**
+@@ -390,9 +407,9 @@
+             if (defc == MethodHandle.class && refKind == REF_invokeVirtual) {
+                 switch (name) {
+                 case "invoke":
+-                    return Invokers.genericInvokerMethod(fixMethodType(callerClass, type), appendixResult);
++                    return Invokers.genericInvokeLinkerMethod(fixMethodType(callerClass, type), appendixResult);
+                 case "invokeExact":
+-                    return Invokers.exactInvokerMethod(fixMethodType(callerClass, type), appendixResult);
++                    return Invokers.exactInvokeLinkerMethod(fixMethodType(callerClass, type), appendixResult);
+                 }
+             }
+         } catch (Throwable ex) {
+diff --git a/src/share/classes/java/lang/invoke/MethodHandles.java b/src/share/classes/java/lang/invoke/MethodHandles.java
+--- a/src/share/classes/java/lang/invoke/MethodHandles.java
++++ b/src/share/classes/java/lang/invoke/MethodHandles.java
+@@ -39,6 +39,7 @@
+ import sun.security.util.SecurityConstants;
+ import static java.lang.invoke.MethodHandleStatics.*;
+ import static java.lang.invoke.MethodHandleNatives.Constants.*;
++import java.util.concurrent.ConcurrentHashMap;
+ import sun.security.util.SecurityConstants;
+ 
+ /**
+@@ -1102,7 +1103,15 @@
+                                             NoSuchMethodException.class);
+         }
+ 
++        MemberName resolveOrFail(byte refKind, MemberName member) throws ReflectiveOperationException {
++            checkSymbolicClass(member.getDeclaringClass());  // do this before attempting to resolve
++            member.getName().getClass(); member.getType().getClass();  // NPE
++            return IMPL_NAMES.resolveOrFail(refKind, member, lookupClassOrNull(),
++                                            ReflectiveOperationException.class);
++        }
++
+         void checkSymbolicClass(Class<?> refc) throws IllegalAccessException {
++            refc.getClass();  // NPE
+             Class<?> caller = lookupClassOrNull();
+             if (caller != null && !VerifyAccess.isClassAccessible(refc, caller, allowedModes))
+                 throw new MemberName(refc).makeAccessException("symbolic reference class is not public", this);
+@@ -1348,29 +1357,74 @@
+          */
+         /*non-public*/
+         MethodHandle linkMethodHandleConstant(byte refKind, Class<?> defc, String name, Object type) throws ReflectiveOperationException {
+-            MemberName resolved = null;
+-            if (type instanceof MemberName) {
+-                resolved = (MemberName) type;
+-                if (!resolved.isResolved())  throw new InternalError("unresolved MemberName");
+-                assert(name == null || name.equals(resolved.getName()));
++            if (!(type instanceof Class || type instanceof MethodType))
++                throw new InternalError("unresolved MemberName");
++            MemberName member = new MemberName(refKind, defc, name, type);
++            MethodHandle mh = LOOKASIDE_TABLE.get(member);
++            if (mh != null) {
++                checkSymbolicClass(defc);
++                return mh;
+             }
++            MemberName resolved = resolveOrFail(refKind, member);
++            mh = getDirectMethodHandle(refKind, defc, resolved);
++            if (mh instanceof DirectMethodHandle
++                    && canBeCached(refKind, defc, resolved)) {
++                MemberName key = mh.internalMemberName();
++                if (key != null) {
++                    key = key.asNormalOriginal();
++                }
++                if (member.equals(key)) {  // better safe than sorry
++                    LOOKASIDE_TABLE.put(key, (DirectMethodHandle) mh);
++                }
++            }
++            return mh;
++        }
++        private
++        boolean canBeCached(byte refKind, Class<?> defc, MemberName member) {
++            if (refKind == REF_invokeSpecial) {
++                return false;
++            }
++            if (!Modifier.isPublic(defc.getModifiers()) ||
++                    !Modifier.isPublic(member.getDeclaringClass().getModifiers()) ||
++                    !member.isPublic() ||
++                    member.isCallerSensitive()) {
++                return false;
++            }
++            ClassLoader loader = defc.getClassLoader();
++            if (!sun.misc.VM.isSystemDomainLoader(loader)) {
++                ClassLoader sysl = ClassLoader.getSystemClassLoader();
++                boolean found = false;
++                while (sysl != null) {
++                    if (loader == sysl) { found = true; break; }
++                    sysl = sysl.getParent();
++                }
++                if (!found) {
++                    return false;
++                }
++            }
++            try {
++                MemberName resolved2 = publicLookup().resolveOrFail(refKind,
++                    new MemberName(refKind, defc, member.getName(), member.getType()));
++                checkSecurityManager(defc, resolved2);
++            } catch (ReflectiveOperationException | SecurityException ex) {
++                return false;
++            }
++            return true;
++        }
++        private
++        MethodHandle getDirectMethodHandle(byte refKind, Class<?> defc, MemberName member) throws ReflectiveOperationException {
+             if (MethodHandleNatives.refKindIsField(refKind)) {
+-                MemberName field = (resolved != null) ? resolved
+-                        : resolveOrFail(refKind, defc, name, (Class<?>) type);
+-                return getDirectField(refKind, defc, field);
++                return getDirectField(refKind, defc, member);
+             } else if (MethodHandleNatives.refKindIsMethod(refKind)) {
+-                MemberName method = (resolved != null) ? resolved
+-                        : resolveOrFail(refKind, defc, name, (MethodType) type);
+-                return getDirectMethod(refKind, defc, method, lookupClass);
++                return getDirectMethod(refKind, defc, member, lookupClass);
+             } else if (refKind == REF_newInvokeSpecial) {
+-                assert(name == null || name.equals("<init>"));
+-                MemberName ctor = (resolved != null) ? resolved
+-                        : resolveOrFail(REF_newInvokeSpecial, defc, name, (MethodType) type);
+-                return getDirectConstructor(defc, ctor);
++                return getDirectConstructor(defc, member);
+             }
+             // oops
+-            throw new ReflectiveOperationException("bad MethodHandle constant #"+refKind+" "+name+" : "+type);
++            throw newIllegalArgumentException("bad MethodHandle constant #"+member);
+         }
++
++        static ConcurrentHashMap<MemberName, DirectMethodHandle> LOOKASIDE_TABLE = new ConcurrentHashMap<>();
+     }
+ 
+     /**
+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
+@@ -28,6 +28,7 @@
+ import sun.invoke.util.Wrapper;
+ import static java.lang.invoke.MethodHandleStatics.*;
+ import static java.lang.invoke.MethodHandleNatives.Constants.*;
++ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
+ 
+ /**
+  * Shared information for a group of method types, which differ
+@@ -73,7 +74,8 @@
+             LF_GEN_LINKER     = 11,
+             LF_GEN_INVOKER    = 12,
+             LF_CS_LINKER      = 13,  // linkToCallSite_CS
+-            LF_LIMIT          = 14;
++            LF_MH_LINKER      = 14,  // linkToCallSite_MH
++            LF_LIMIT          = 15;
+ 
+     public MethodType erasedType() {
+         return erasedType;
+@@ -96,11 +98,22 @@
+         assert(erasedType == basicType) : "erasedType: " + erasedType + " != basicType: " + basicType;  // primitives must be flattened also
+         MethodHandle invoker = basicInvoker;
+         if (invoker != null)  return invoker;
+-        invoker = basicType.invokers().makeBasicInvoker();
++        invoker = DirectMethodHandle.make(invokeBasicMethod(basicType));
+         basicInvoker = invoker;
+         return invoker;
+     }
+ 
++    // This next one is called from LambdaForm.NamedFunction.<init>.
++    /*non-public*/ static MemberName invokeBasicMethod(MethodType basicType) {
++        assert(basicType == basicType.basicType());
++        try {
++            //Lookup.findVirtual(MethodHandle.class, name, type);
++            return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, "invokeBasic", basicType);
++         } catch (ReflectiveOperationException ex) {
++            throw newInternalError("JVM cannot find invoker for "+basicType, ex);
++        }
++    }
++
+     /**
+      * Build an MTF for a given type, which must have all references erased to Object.
+      * This MTF will stand for that type and all un-erased variations.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/meth-clinit-8024599.patch	Fri Sep 13 22:50:28 2013 -0700
@@ -0,0 +1,397 @@
+8024599: JSR 292 direct method handles need to respect initialization rules for static members
+Summary: Align MH semantic with bytecode behavior of constructor and static member accesses, regarding <clinit> invocation.
+Reviewed-by: ?
+
+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
+@@ -72,6 +72,12 @@
+             if (!member.getDeclaringClass().isAssignableFrom(receiver) || member.isConstructor())
+                 throw new InternalError(member.toString());
+             mtype = mtype.insertParameterTypes(0, receiver);
++        } else if (EAGERLY_INITIALIZE_STATIC_TARGET_CLASSES) {
++            // Old JDK 7 docs claimed, "If the method's class has not
++            // yet been initialized, that is done immediately, before
++            // the method handle is returned."  This documented a bug.
++            // We can still simulate this behavior for manual testing.
++            UNSAFE.ensureClassInitialized(member.getDeclaringClass());
+         }
+         if (!member.isField()) {
+             if (refKind == REF_invokeSpecial) {
+@@ -95,6 +101,7 @@
+             }
+         }
+     }
++    private static final boolean EAGERLY_INITIALIZE_STATIC_TARGET_CLASSES = false;
+     static DirectMethodHandle make(Class<?> receiver, MemberName member) {
+         byte refKind = member.getReferenceKind();
+         if (refKind == REF_invokeSpecial)
+diff --git a/src/share/classes/java/lang/invoke/MethodHandles.java b/src/share/classes/java/lang/invoke/MethodHandles.java
+--- a/src/share/classes/java/lang/invoke/MethodHandles.java
++++ b/src/share/classes/java/lang/invoke/MethodHandles.java
+@@ -606,12 +606,13 @@
+          * additional receiver argument inserted into the method handle type,
+          * as there would be with {@link #findVirtual findVirtual} or {@link #findSpecial findSpecial}.)
+          * The method and all its argument types must be accessible to the lookup class.
+-         * If the method's class has not yet been initialized, that is done
+-         * immediately, before the method handle is returned.
+          * <p>
+          * The returned method handle will have
+          * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+          * the method's variable arity modifier bit ({@code 0x0080}) is set.
++         * <p>
++         * If the returned method handle is invoked, the method's class will
++         * be initialized, if it has not already been initialized.
+          * <b>Example:</b>
+          * <p><blockquote><pre>{@code
+ import static java.lang.invoke.MethodHandles.*;
+@@ -738,8 +739,6 @@
+          * The parameter types of the method handle will be those of the constructor,
+          * while the return type will be a reference to the constructor's class.
+          * The constructor and all its argument types must be accessible to the lookup class.
+-         * If the constructor's class has not yet been initialized, that is done
+-         * immediately, before the method handle is returned.
+          * <p>
+          * <em>(Note:  The requested type must have a return type of {@code void}.
+          * This is consistent with the JVM's treatment of constructor type descriptors.)</em>
+@@ -747,6 +746,9 @@
+          * The returned method handle will have
+          * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+          * the constructor's variable arity modifier bit ({@code 0x0080}) is set.
++         * <p>
++         * If the returned method handle is invoked, the constructor's class will
++         * be initialized, if it has not already been initialized.
+          * <b>Example:</b>
+          * <p><blockquote><pre>{@code
+ import static java.lang.invoke.MethodHandles.*;
+@@ -917,6 +919,9 @@
+          * value type.
+          * The method handle will take no arguments.
+          * Access checking is performed immediately on behalf of the lookup class.
++         * <p>
++         * If the returned method handle is invoked, the field's class will
++         * be initialized, if it has not already been initialized.
+          * @param refc the class or interface from which the method is accessed
+          * @param name the field's name
+          * @param type the field's type
+@@ -939,6 +944,9 @@
+          * The method handle will take a single
+          * argument, of the field's value type, the value to be stored.
+          * Access checking is performed immediately on behalf of the lookup class.
++         * <p>
++         * If the returned method handle is invoked, the field's class will
++         * be initialized, if it has not already been initialized.
+          * @param refc the class or interface from which the method is accessed
+          * @param name the field's name
+          * @param type the field's type
+@@ -1023,6 +1031,10 @@
+          * The returned method handle will have
+          * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+          * the method's variable arity modifier bit ({@code 0x0080}) is set.
++         * <p>
++         * If <i>m</i> is static, and
++         * if the returned method handle is invoked, the method's class will
++         * be initialized, if it has not already been initialized.
+          * @param m the reflected method
+          * @return a method handle which can invoke the reflected method
+          * @throws IllegalAccessException if access checking fails
+@@ -1094,6 +1106,9 @@
+          * The returned method handle will have
+          * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+          * the constructor's variable arity modifier bit ({@code 0x0080}) is set.
++         * <p>
++         * If the returned method handle is invoked, the constructor's class will
++         * be initialized, if it has not already been initialized.
+          * @param c the reflected constructor
+          * @return a method handle which can invoke the reflected constructor
+          * @throws IllegalAccessException if access checking fails
+@@ -1118,6 +1133,10 @@
+          * the field.
+          * If the field's {@code accessible} flag is not set,
+          * access checking is performed immediately on behalf of the lookup class.
++         * <p>
++         * If the field is static, and
++         * if the returned method handle is invoked, the field's class will
++         * be initialized, if it has not already been initialized.
+          * @param f the reflected field
+          * @return a method handle which can load values from the reflected field
+          * @throws IllegalAccessException if access checking fails
+@@ -1144,6 +1163,10 @@
+          * the field, and the value to be stored.
+          * If the field's {@code accessible} flag is not set,
+          * access checking is performed immediately on behalf of the lookup class.
++         * <p>
++         * If the field is static, and
++         * if the returned method handle is invoked, the field's class will
++         * be initialized, if it has not already been initialized.
+          * @param f the reflected field
+          * @return a method handle which can store values into the reflected field
+          * @throws IllegalAccessException if access checking fails
+diff --git a/test/java/lang/invoke/CallStaticInitOrder.java b/test/java/lang/invoke/CallStaticInitOrder.java
+new file mode 100644
+--- /dev/null
++++ b/test/java/lang/invoke/CallStaticInitOrder.java
+@@ -0,0 +1,263 @@
++/*
++ * Copyright (c) 2013, 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.
++ *
++ * 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 static initializer invocation order
++ *
++ * @build indify.Indify
++ * @compile CallStaticInitOrder.java
++ * @run main/othervm/timeout=3600
++ *      indify.Indify
++ *      --expand-properties --classpath ${test.classes}
++ *      --java test.java.lang.invoke.CallStaticInitOrder
++ */
++
++package test.java.lang.invoke;
++
++import java.io.*;
++
++import java.lang.invoke.*;
++import static java.lang.invoke.MethodHandles.*;
++import static java.lang.invoke.MethodType.*;
++
++public class CallStaticInitOrder {
++    private static int TICK;
++    private static synchronized int tick(String event) {
++        int n = ++TICK;
++        System.out.println("event #"+n+" = "+event);
++        return n;
++    }
++
++    private static int Init1Tick;
++    private static class Init1 {
++        static { Init1Tick = tick("foo -> Init1.<clinit>"); }
++        static int foo() { return Init1Tick; }
++    }
++
++    static int Init2Tick;
++    private static class Init2 {
++        static { Init2Tick = tick("bar -> Init2.<clinit>"); }
++        static int bar() { return Init2Tick; }
++    }
++
++    static int Init3Tick;
++    private static class Init3 {
++        static { Init3Tick = tick("baz -> Init3.<clinit>"); }
++        static int baz() { return Init3Tick; }
++    }
++
++    static int Init4Tick;
++    private static class Init4 {
++        static { Init4Tick = tick("bat -> Init4.<clinit>"); }
++        static int bat() { return Init4Tick; }
++    }
++
++    static int Init5Tick;
++    private static class Init5 {
++        static { Init5Tick = tick("read bang -> Init5.<clinit>"); }
++        static int bang = Init5Tick;
++    }
++
++    static int Init6Tick;
++    private static class Init6 {
++        static { Init6Tick = tick("write pong -> Init6.<clinit>"); }
++        static int pong;
++    }
++
++    private static final MutableCallSite CONSTANT_CS_baz;
++    private static MethodHandle MH_foo() throws ReflectiveOperationException {
++        return lookup().findStatic(Init1.class, "foo", methodType(int.class));
++    }
++    private static final MethodHandle CONSTANT_MH_bar;
++    private static MethodHandle MH_baz() throws ReflectiveOperationException {
++        return lookup().findStatic(Init3.class, "baz", methodType(int.class));
++    }
++    private static final MethodHandle CONSTANT_MH_bat;
++    private static final MethodHandle CONSTANT_MH_bangGetter;
++    private static final MethodHandle CONSTANT_MH_pongSetter;
++    static {
++        try {
++            int t1 = tick("CallStaticInitOrder.<clinit>");
++            {
++                CONSTANT_CS_baz = new MutableCallSite(methodType(int.class));
++                // MH_foo() := lookup().findStatic(Init1.class, "foo", methodType(int.class));
++                CONSTANT_MH_bar = lookup().findStatic(Init2.class, "bar", methodType(int.class));
++                // MH_baz() := lookup().findStatic(Init3.class, "baz", methodType(int.class));
++                CONSTANT_MH_bat = lookup().unreflect(Init4.class.getDeclaredMethod("bat"));
++                CONSTANT_MH_bangGetter = lookup().findStaticGetter(Init5.class, "bang", int.class);
++                MethodHandle pongSetter = lookup().findStaticSetter(Init6.class, "pong", int.class);
++                MethodHandle tickGetter = lookup().findStaticGetter(CallStaticInitOrder.class, "Init6Tick", int.class);
++                CONSTANT_MH_pongSetter = filterReturnValue(insertArguments(pongSetter, 0, -99), tickGetter);
++            }
++            int t2 = tick("CallStaticInitOrder.<clinit> done");
++            assertEquals(t1+1, t2);  // no ticks in between
++        } catch (Exception ex) {
++            throw new InternalError(ex.toString());
++        }
++    }
++
++    public static void main(String... av) throws Throwable {
++        testInit();
++        if (LAST_LOSER != null)  throw LAST_LOSER;
++    }
++
++    private static Throwable LAST_LOSER;
++
++    private static void assertEquals(int expected, int actual) {
++        if (expected != actual) {
++            Throwable loser = new AssertionError("expected: " + expected + ", actual: " + actual);
++            if (LAST_LOSER != null)
++                LAST_LOSER.printStackTrace(System.out);
++            LAST_LOSER = loser;
++        }
++    }
++
++    private static void testInit() throws Throwable {
++        System.out.println("runFoo = "+runFoo());
++        System.out.println("runBar = "+runBar());
++        try {
++            runBaz();
++        } catch (IllegalStateException ex) {
++            tick("runBaz throw/catch");
++        }
++        CONSTANT_CS_baz.setTarget(MH_baz());
++        System.out.println("runBaz = "+runBaz());
++        System.out.println("runBat = "+runBat());
++        System.out.println("runBang = "+runBang());
++        System.out.println("runPong = "+runPong());
++    }
++
++    private static int runFoo() throws Throwable {
++        int t1 = tick("runFoo");
++        int t2 = (int) INDY_foo().invokeExact();
++        int t3 = tick("runFoo done");
++        assertEquals(t1+2, t3);  // exactly two ticks in between
++        assertEquals(t1+1, t2);  // init happened inside
++        return t2;
++    }
++    private static MethodHandle INDY_foo() throws Throwable {
++        shouldNotCallThis();
++        return ((CallSite) MH_bsm().invoke(lookup(), "foo", methodType(int.class))).dynamicInvoker();
++    }
++
++    private static int runBar() throws Throwable {
++        int t1 = tick("runBar");
++        int t2 = (int) INDY_bar().invokeExact();
++        int t3 = tick("runBar done");
++        assertEquals(t1+2, t3);  // exactly two ticks in between
++        assertEquals(t1+1, t2);  // init happened inside
++        return t2;
++    }
++    private static MethodHandle INDY_bar() throws Throwable {
++        shouldNotCallThis();
++        return ((CallSite) MH_bsm().invoke(lookup(), "bar", methodType(int.class))).dynamicInvoker();
++    }
++
++    private static int runBaz() throws Throwable {
++        int t1 = tick("runBaz");
++        int t2 = (int) INDY_baz().invokeExact();
++        int t3 = tick("runBaz done");
++        assertEquals(t1+2, t3);  // exactly two ticks in between
++        assertEquals(t1+1, t2);  // init happened inside
++        return t2;
++    }
++    private static MethodHandle INDY_baz() throws Throwable {
++        shouldNotCallThis();
++        return ((CallSite) MH_bsm().invoke(lookup(), "baz", methodType(int.class))).dynamicInvoker();
++    }
++
++    private static int runBat() throws Throwable {
++        int t1 = tick("runBat");
++        int t2 = (int) INDY_bat().invokeExact();
++        int t3 = tick("runBat done");
++        assertEquals(t1+2, t3);  // exactly two ticks in between
++        assertEquals(t1+1, t2);  // init happened inside
++        return t2;
++    }
++    private static MethodHandle INDY_bat() throws Throwable {
++        shouldNotCallThis();
++        return ((CallSite) MH_bsm().invoke(lookup(), "bat", methodType(int.class))).dynamicInvoker();
++    }
++
++    private static int runBang() throws Throwable {
++        int t1 = tick("runBang");
++        int t2 = (int) INDY_bang().invokeExact();
++        int t3 = tick("runBang done");
++        assertEquals(t1+2, t3);  // exactly two ticks in between
++        assertEquals(t1+1, t2);  // init happened inside
++        return t2;
++    }
++    private static MethodHandle INDY_bang() throws Throwable {
++        shouldNotCallThis();
++        return ((CallSite) MH_bsm().invoke(lookup(), "bang", methodType(int.class))).dynamicInvoker();
++    }
++
++    private static int runPong() throws Throwable {
++        int t1 = tick("runPong");
++        int t2 = (int) INDY_pong().invokeExact();
++        int t3 = tick("runPong done");
++        assertEquals(t1+2, t3);  // exactly two ticks in between
++        assertEquals(t1+1, t2);  // init happened inside
++        return t2;
++    }
++    private static MethodHandle INDY_pong() throws Throwable {
++        shouldNotCallThis();
++        return ((CallSite) MH_bsm().invoke(lookup(), "pong", methodType(int.class))).dynamicInvoker();
++    }
++
++    private static CallSite bsm(Lookup caller, String name, MethodType type) throws ReflectiveOperationException {
++        System.out.println("bsm "+name+type);
++        CallSite res;
++        switch (name) {
++        case "foo":
++            res = new ConstantCallSite(MH_foo()); break;
++        case "bar":
++            res = new ConstantCallSite(CONSTANT_MH_bar); break;
++        case "baz":
++            res = CONSTANT_CS_baz; break;
++        case "bat":
++            res = new ConstantCallSite(CONSTANT_MH_bat); break;
++        case "bang":
++            res = new ConstantCallSite(CONSTANT_MH_bangGetter); break;
++        case "pong":
++            res = new ConstantCallSite(CONSTANT_MH_pongSetter); break;
++        default:
++            res = null;
++        }
++        if (res == null || !res.type().equals(type)) {
++            throw new AssertionError(String.valueOf(res));
++        }
++        return res;
++    }
++    private static MethodHandle MH_bsm() throws ReflectiveOperationException {
++        shouldNotCallThis();
++        return lookup().findStatic(lookup().lookupClass(), "bsm",
++                                   methodType(CallSite.class, Lookup.class, String.class, MethodType.class));
++    }
++    private static void shouldNotCallThis() {
++        // if this gets called, the transformation has not taken place
++        throw new AssertionError("this code should be statically transformed away by Indify");
++    }
++}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/meth-coll-8001110.patch	Fri Sep 13 22:50:28 2013 -0700
@@ -0,0 +1,416 @@
+8001110: method handles should have a collectArguments transform, generalizing asCollector
+Summary: promote an existing private method; make unit tests on all argument positions to arity 10 with mixed types
+
+diff --git a/src/share/classes/java/lang/invoke/MethodHandles.java b/src/share/classes/java/lang/invoke/MethodHandles.java
+--- a/src/share/classes/java/lang/invoke/MethodHandles.java
++++ b/src/share/classes/java/lang/invoke/MethodHandles.java
+@@ -2136,15 +2136,114 @@
+         return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
+     }
+ 
+-    // FIXME: Make this public in M1.
+-    /*non-public*/ static
+-    MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle collector) {
++    /**
++     * Adapts a target method handle by pre-processing
++     * a sub-sequence of its arguments with a filter (another method handle).
++     * The pre-processed arguments are replaced by the result (if any) of the
++     * filter function.
++     * The target is then called on the modified (usually shortened) argument list.
++     * <p>
++     * If the filter returns a value, the target must accept that value as
++     * its {@code pos} argument, plus any arguments not passed to the filter.
++     * If the filter returns void, the target must accept all arguments
++     * not passed to the filter.
++     * No arguments are reordered, and a result returned from the filter
++     * replaces (in order) the whole subsequence of arguments originally
++     * passed to the adapter.
++     * <p>
++     * The argument types (if any) of the filter
++     * replace zero or one argument types of the target, at position {@code pos},
++     * in the resulting adapted method handle.
++     * The return type of the filter (if any) must be identical to the
++     * argument type of the target at position {@code pos}, and that target argument
++     * is supplied by the return value of the filter.
++     * <p>
++     * In all cases, {@code pos} must be greater than or equal to zero, and
++     * {@code pos} must also be less than or equal to the target's arity.
++     * <b>Example:</b>
++     * <p><blockquote><pre>
++import static java.lang.invoke.MethodHandles.*;
++import static java.lang.invoke.MethodType.*;
++...
++MethodHandle deepToString = publicLookup()
++  .findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
++MethodHandle ts1 = deepToString.asCollector(String[].class, 1);
++assertEquals("[strange]", (String) ts1.invokeExact("strange"));
++MethodHandle ts2 = deepToString.asCollector(String[].class, 2);
++assertEquals("[up, down]", (String) ts2.invokeExact("up", "down"));
++MethodHandle ts3 = deepToString.asCollector(String[].class, 3);
++MethodHandle ts3_ts2 = collectArguments(ts3, 1, ts2);
++assertEquals("[top, [up, down], strange]",
++             (String) ts3_ts2.invokeExact("top", "up", "down", "strange"));
++MethodHandle ts3_ts2_ts1 = collectArguments(ts3_ts2, 3, ts1);
++assertEquals("[top, [up, down], [strange]]",
++             (String) ts3_ts2_ts1.invokeExact("top", "up", "down", "strange"));
++MethodHandle ts3_ts2_ts3 = collectArguments(ts3_ts2, 1, ts3);
++assertEquals("[top, [[up, down, strange], charm], bottom]",
++             (String) ts3_ts2_ts3.invokeExact("top", "up", "down", "strange", "charm", "bottom"));
++     * </pre></blockquote>
++     * <p> Here is pseudocode for the resulting adapter:
++     * <blockquote><pre>
++     * T target(A...,V,C...);
++     * V filter(B...);
++     * T adapter(A... a,B... b,C... c) {
++     *   V v = filter(b...);
++     *   return target(a...,v,c...);
++     * }
++     * // and if the filter has no arguments:
++     * T target2(A...,V,C...);
++     * V filter2();
++     * T adapter2(A... a,C... c) {
++     *   V v = filter2();
++     *   return target2(a...,v,c...);
++     * }
++     * // and if the filter has a void return:
++     * T target3(A...,C...);
++     * void filter3(B...);
++     * void adapter3(A... a,B... b,C... c) {
++     *   filter3(b...);
++     *   return target3(a...,c...);
++     * }
++     * </pre></blockquote>
++     * <p>
++     * A collection adapter {@code collectArguments(mh, 0, coll)} is equivalent to
++     * one which first "folds" the affected arguments, and then drops them, in separate
++     * steps as follows:
++     * <blockquote><pre>{@code
++     * mh = MethodHandles.dropArguments(mh, 1, coll.type().parameterList()); //step 2
++     * mh = MethodHandles.foldArguments(mh, coll); //step 1
++     * }</pre></blockquote>
++     * If the target method handle consumes no arguments besides than the result
++     * (if any) of the filter {@code coll}, then {@code collectArguments(mh, 0, coll)}
++     * is equivalent to {@code filterReturnValue(coll, mh)}.
++     * If the filter method handle {@code coll} consumes one argument and produces
++     * a non-void result, then {@code collectArguments(mh, N, coll)}
++     * is equivalent to {@code filterArguments(mh, N, coll)}.
++     * Other equivalences are possible but would require argument permutation.
++     *
++     * @param target the method handle to invoke after filtering the subsequence of arguments
++     * @param pos the position of the first adapter argument to pass to the filter,
++     *            and/or the target argument which receives the result of the filter
++     * @param filter method handle to call on the subsequence of arguments
++     * @return method handle which incorporates the specified argument subsequence filtering logic
++     * @throws NullPointerException if either argument is null
++     * @throws IllegalArgumentException if the return type of {@code filter}
++     *          is non-void and is not the same as the {@code pos} argument of the target,
++     *          or if {@code pos} is not between 0 and the target's arity, inclusive,
++     *          or if the resulting method handle's type would have
++     *          <a href="MethodHandle.html#maxarity">too many parameters</a>
++     * @see MethodHandles#foldArguments
++     * @see MethodHandles#filterArguments
++     * @see MethodHandles#filterReturnValue
++     */
++    public static
++    MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle filter) {
+         MethodType targetType = target.type();
+-        MethodType filterType = collector.type();
++        MethodType filterType = filter.type();
+         if (filterType.returnType() != void.class &&
+             filterType.returnType() != targetType.parameterType(pos))
+             throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
+-        return MethodHandleImpl.makeCollectArguments(target, collector, pos, false);
++        return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
+     }
+ 
+     /**
+diff --git a/src/share/classes/sun/invoke/util/ValueConversions.java b/src/share/classes/sun/invoke/util/ValueConversions.java
+--- a/src/share/classes/sun/invoke/util/ValueConversions.java
++++ b/src/share/classes/sun/invoke/util/ValueConversions.java
+@@ -502,51 +502,6 @@
+         }
+     }
+ 
+-    static MethodHandle collectArguments(MethodHandle mh, int pos, MethodHandle collector) {
+-        // FIXME: API needs public MHs.collectArguments.
+-        // Should be:
+-        //   return MethodHandles.collectArguments(mh, 0, collector);
+-        // The rest of this code is a workaround for not having that API.
+-        if (COLLECT_ARGUMENTS != null) {
+-            try {
+-                return (MethodHandle)
+-                    COLLECT_ARGUMENTS.invokeExact(mh, pos, collector);
+-            } catch (Throwable ex) {
+-                if (ex instanceof RuntimeException)
+-                    throw (RuntimeException) ex;
+-                if (ex instanceof Error)
+-                    throw (Error) ex;
+-                throw new Error(ex.getMessage(), ex);
+-            }
+-        }
+-        // Emulate MHs.collectArguments using fold + drop.
+-        // This is slightly inefficient.
+-        // More seriously, it can put a MH over the 255-argument limit.
+-        mh = MethodHandles.dropArguments(mh, 1, collector.type().parameterList());
+-        mh = MethodHandles.foldArguments(mh, collector);
+-        return mh;
+-    }
+-    private static final MethodHandle COLLECT_ARGUMENTS;
+-    static {
+-        MethodHandle mh = null;
+-        try {
+-            final java.lang.reflect.Method m = MethodHandles.class
+-                .getDeclaredMethod("collectArguments",
+-                    MethodHandle.class, int.class, MethodHandle.class);
+-            AccessController.doPrivileged(new PrivilegedAction<Void>() {
+-                    @Override
+-                    public Void run() {
+-                        m.setAccessible(true);
+-                        return null;
+-                    }
+-                });
+-            mh = IMPL_LOOKUP.unreflect(m);
+-        } catch (ReflectiveOperationException ex) {
+-            throw newInternalError(ex);
+-        }
+-        COLLECT_ARGUMENTS = mh;
+-    }
+-
+     private static final EnumMap<Wrapper, MethodHandle>[] WRAPPER_CASTS
+             = newWrapperCaches(1);
+ 
+@@ -1050,12 +1005,12 @@
+             if (mh == ARRAY_IDENTITY)
+                 mh = rightFiller;
+             else
+-                mh = collectArguments(mh, 0, rightFiller);
++                mh = MethodHandles.collectArguments(mh, 0, rightFiller);
+         }
+         if (mh == ARRAY_IDENTITY)
+             mh = leftCollector;
+         else
+-            mh = collectArguments(mh, 0, leftCollector);
++            mh = MethodHandles.collectArguments(mh, 0, leftCollector);
+         return mh;
+     }
+ 
+@@ -1101,7 +1056,7 @@
+         if (midLen == LEFT_ARGS)
+             return rightFill;
+         else
+-            return collectArguments(rightFill, 0, midFill);
++            return MethodHandles.collectArguments(rightFill, 0, midFill);
+     }
+ 
+     // Type-polymorphic version of varargs maker.
+diff --git a/test/java/lang/invoke/JavaDocExamplesTest.java b/test/java/lang/invoke/JavaDocExamplesTest.java
+--- a/test/java/lang/invoke/JavaDocExamplesTest.java
++++ b/test/java/lang/invoke/JavaDocExamplesTest.java
+@@ -292,6 +292,28 @@
+             }}
+     }
+ 
++    @Test public void testCollectArguments() throws Throwable {
++        {{
++{} /// JAVADOC
++MethodHandle deepToString = publicLookup()
++  .findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
++MethodHandle ts1 = deepToString.asCollector(String[].class, 1);
++assertEquals("[strange]", (String) ts1.invokeExact("strange"));
++MethodHandle ts2 = deepToString.asCollector(String[].class, 2);
++assertEquals("[up, down]", (String) ts2.invokeExact("up", "down"));
++MethodHandle ts3 = deepToString.asCollector(String[].class, 3);
++MethodHandle ts3_ts2 = collectArguments(ts3, 1, ts2);
++assertEquals("[top, [up, down], strange]",
++             (String) ts3_ts2.invokeExact("top", "up", "down", "strange"));
++MethodHandle ts3_ts2_ts1 = collectArguments(ts3_ts2, 3, ts1);
++assertEquals("[top, [up, down], [strange]]",
++             (String) ts3_ts2_ts1.invokeExact("top", "up", "down", "strange"));
++MethodHandle ts3_ts2_ts3 = collectArguments(ts3_ts2, 1, ts3);
++assertEquals("[top, [[up, down, strange], charm], bottom]",
++             (String) ts3_ts2_ts3.invokeExact("top", "up", "down", "strange", "charm", "bottom"));
++            }}
++    }
++
+     @Test public void testFoldArguments() throws Throwable {
+         {{
+ {} /// JAVADOC
+diff --git a/test/java/lang/invoke/MethodHandlesTest.java b/test/java/lang/invoke/MethodHandlesTest.java
+--- a/test/java/lang/invoke/MethodHandlesTest.java
++++ b/test/java/lang/invoke/MethodHandlesTest.java
+@@ -253,6 +253,9 @@
+             args[i] = randomArg(param);
+         return args;
+     }
++    static Object[] randomArgs(List<Class<?>> params) {
++        return randomArgs(params.toArray(new Class<?>[params.size()]));
++    }
+ 
+     @SafeVarargs @SuppressWarnings("varargs")
+     static <T, E extends T> T[] array(Class<T[]> atype, E... a) {
+@@ -323,6 +326,11 @@
+         }
+         return list.asType(listType);
+     }
++    /** Variation of varargsList, but with the given ptypes and rtype. */
++    static MethodHandle varargsList(List<Class<?>> ptypes, Class<?> rtype) {
++        MethodHandle list = varargsList(ptypes.size(), rtype);
++        return list.asType(MethodType.methodType(rtype, ptypes));
++    }
+     private static MethodHandle LIST_TO_STRING, LIST_TO_INT;
+     private static String listToString(List<?> x) { return x.toString(); }
+     private static int listToInt(List<?> x) { return x.toString().hashCode(); }
+@@ -1783,24 +1791,24 @@
+     }
+ 
+     @Test  // SLOW
+-    public void testCollectArguments() throws Throwable {
++    public void testAsCollector() throws Throwable {
+         if (CAN_SKIP_WORKING)  return;
+-        startTest("collectArguments");
++        startTest("asCollector");
+         for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {
+             if (verbosity >= 3)
+-                System.out.println("collectArguments "+argType);
++                System.out.println("asCollector "+argType);
+             for (int nargs = 0; nargs < 50; nargs++) {
+                 if (CAN_TEST_LIGHTLY && nargs > 11)  break;
+                 for (int pos = 0; pos <= nargs; pos++) {
+                     if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2)  continue;
+                     if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)
+                         continue;
+-                    testCollectArguments(argType, pos, nargs);
++                    testAsCollector(argType, pos, nargs);
+                 }
+             }
+         }
+     }
+-    public void testCollectArguments(Class<?> argType, int pos, int nargs) throws Throwable {
++    public void testAsCollector(Class<?> argType, int pos, int nargs) throws Throwable {
+         countTest();
+         // fake up a MH with the same type as the desired adapter:
+         MethodHandle fake = varargsArray(nargs);
+@@ -1947,37 +1955,108 @@
+     }
+ 
+     @Test
++    public void testCollectArguments() throws Throwable {
++        if (CAN_SKIP_WORKING)  return;
++        startTest("collectArguments");
++        testFoldOrCollectArguments(true);
++    }
++
++    @Test
+     public void testFoldArguments() throws Throwable {
+         if (CAN_SKIP_WORKING)  return;
+         startTest("foldArguments");
+-        for (int nargs = 0; nargs <= 4; nargs++) {
+-            for (int fold = 0; fold <= nargs; fold++) {
+-                for (int pos = 0; pos <= nargs; pos++) {
+-                    testFoldArguments(nargs, pos, fold);
++        testFoldOrCollectArguments(false);
++    }
++
++    void testFoldOrCollectArguments(boolean isCollect) throws Throwable {
++        for (Class<?> lastType : new Class<?>[]{ Object.class, String.class, int.class }) {
++            for (Class<?> collectType : new Class<?>[]{ Object.class, String.class, int.class, void.class }) {
++                int maxArity = 10;
++                if (collectType != String.class)  maxArity = 5;
++                if (lastType != Object.class)  maxArity = 4;
++                for (int nargs = 0; nargs <= maxArity; nargs++) {
++                    ArrayList<Class<?>> argTypes = new ArrayList<>(Collections.nCopies(nargs, Object.class));
++                    int maxMix = 20;
++                    if (collectType != Object.class)  maxMix = 0;
++                    Map<Object,Integer> argTypesSeen = new HashMap<>();
++                    for (int mix = 0; mix <= maxMix; mix++) {
++                        if (!mixArgs(argTypes, mix, argTypesSeen))  continue;
++                        for (int collect = 0; collect <= nargs; collect++) {
++                            for (int pos = 0; pos <= nargs - collect; pos++) {
++                                testFoldOrCollectArguments(argTypes, pos, collect, collectType, lastType, isCollect);
++                            }
++                        }
++                    }
+                 }
+             }
+         }
+     }
+ 
+-    void testFoldArguments(int nargs, int pos, int fold) throws Throwable {
+-        if (pos != 0)  return;  // can fold only at pos=0 for now
++    boolean mixArgs(List<Class<?>> argTypes, int mix, Map<Object,Integer> argTypesSeen) {
++        assert(mix >= 0);
++        if (mix == 0)  return true;  // no change
++        if ((mix >>> argTypes.size()) != 0)  return false;
++        for (int i = 0; i < argTypes.size(); i++) {
++            if (i >= 31)  break;
++            boolean bit = (mix & (1 << i)) != 0;
++            if (bit) {
++                Class<?> type = argTypes.get(i);
++                if (type == Object.class)
++                    type = String.class;
++                else if (type == String.class)
++                    type = int.class;
++                else
++                    type = Object.class;
++                argTypes.set(i, type);
++            }
++        }
++        Integer prev = argTypesSeen.put(new ArrayList<>(argTypes), mix);
++        if (prev != null) {
++            if (verbosity >= 4)  System.out.println("mix "+prev+" repeated "+mix+": "+argTypes);
++            return false;
++        }
++        if (verbosity >= 3)  System.out.println("mix "+mix+" = "+argTypes);
++        return true;
++    }
++
++    void testFoldOrCollectArguments(List<Class<?>> argTypes,  // argument types minus the inserted combineType
++                                    int pos, int fold, // position and length of the folded arguments
++                                    Class<?> combineType, // type returned from the combiner
++                                    Class<?> lastType,  // type returned from the target
++                                    boolean isCollect) throws Throwable {
++        int nargs = argTypes.size();
++        if (pos != 0 && !isCollect)  return;  // can fold only at pos=0 for now
+         countTest();
+-        MethodHandle target = varargsList(1 + nargs);
+-        MethodHandle combine = varargsList(fold).asType(MethodType.genericMethodType(fold));
+-        List<Object> argsToPass = Arrays.asList(randomArgs(nargs, Object.class));
++        List<Class<?>> combineArgTypes = argTypes.subList(pos, pos + fold);
++        List<Class<?>> targetArgTypes = new ArrayList<>(argTypes);
++        if (isCollect)  // does targret see arg[pos..pos+cc-1]?
++            targetArgTypes.subList(pos, pos + fold).clear();
++        if (combineType != void.class)
++            targetArgTypes.add(pos, combineType);
++        MethodHandle target = varargsList(targetArgTypes, lastType);
++        MethodHandle combine = varargsList(combineArgTypes, combineType);
++        List<Object> argsToPass = Arrays.asList(randomArgs(argTypes));
+         if (verbosity >= 3)
+-            System.out.println("fold "+target+" with "+combine);
+-        MethodHandle target2 = MethodHandles.foldArguments(target, combine);
++            System.out.println((isCollect ? "collect" : "fold")+" "+target+" with "+combine);
++        MethodHandle target2;
++        if (isCollect)
++            target2 = MethodHandles.collectArguments(target, pos, combine);
++        else
++            target2 = MethodHandles.foldArguments(target, combine);
+         // Simulate expected effect of combiner on arglist:
+-        List<Object> expected = new ArrayList<>(argsToPass);
+-        List<Object> argsToFold = expected.subList(pos, pos + fold);
++        List<Object> expectedList = new ArrayList<>(argsToPass);
++        List<Object> argsToFold = expectedList.subList(pos, pos + fold);
+         if (verbosity >= 3)
+-            System.out.println("fold: "+argsToFold+" into "+target2);
++            System.out.println((isCollect ? "collect" : "fold")+": "+argsToFold+" into "+target2);
+         Object foldedArgs = combine.invokeWithArguments(argsToFold);
+-        argsToFold.add(0, foldedArgs);
++        if (isCollect)
++            argsToFold.clear();
++        if (combineType != void.class)
++            argsToFold.add(0, foldedArgs);
+         Object result = target2.invokeWithArguments(argsToPass);
+         if (verbosity >= 3)
+             System.out.println("result: "+result);
++        Object expected = target.invokeWithArguments(expectedList);
+         if (!expected.equals(result))
+             System.out.println("*** fail at n/p/f = "+nargs+"/"+pos+"/"+fold+": "+argsToPass+" => "+result+" != "+expected);
+         assertEquals(expected, result);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/meth-mr-8024438.patch	Fri Sep 13 22:50:28 2013 -0700
@@ -0,0 +1,867 @@
+8024438: JSR 292 API specification maintenance for JDK 8
+
+- adjust alignment between access checks for CONSTANT_MethodHandle and Lookup.find* API calls
+- add wildcard to raw type in parameter to unreflectConstructor
+- clarify wording regarding bytecode behavior and access checking
+- clarify @CallerSensitive interactions (amended since JDK-7165628)
+- use {@code ...} inside <blockquote><pre> tags, other minor edits
+
+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
+@@ -573,10 +573,10 @@
+     /*non-public*/ static native @PolymorphicSignature Object linkToInterface(Object... args) throws Throwable;
+ 
+     /**
+-     * Performs a variable arity invocation, passing the arguments in the given array
++     * Performs a variable arity invocation, passing the arguments in the given list
+      * to the method handle, as if via an inexact {@link #invoke invoke} from a call site
+      * which mentions only the type {@code Object}, and whose arity is the length
+-     * of the argument array.
++     * of the argument list.
+      * <p>
+      * Specifically, execution proceeds as if by the following steps,
+      * although the methods are not guaranteed to be called if the JVM
+@@ -1308,6 +1308,11 @@
+     }
+ 
+     /*non-public*/
++    Class<?> internalCallerClass() {
++        return null;  // caller-bound MH for @CallerSensitive method returns caller
++    }
++
++    /*non-public*/
+     MethodHandle withInternalMemberName(MemberName member) {
+         if (member != null) {
+             return MethodHandleImpl.makeWrappedMember(this, member);
+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
+@@ -380,6 +380,10 @@
+         MemberName internalMemberName() {
+             return asFixedArity().internalMemberName();
+         }
++        @Override
++        Class<?> internalCallerClass() {
++            return asFixedArity().internalCallerClass();
++        }
+ 
+         /*non-public*/
+         @Override
+@@ -824,7 +828,7 @@
+             MethodHandle vamh = prepareForInvoker(mh);
+             // Cache the result of makeInjectedInvoker once per argument class.
+             MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass);
+-            return restoreToType(bccInvoker.bindTo(vamh), mh.type(), mh.internalMemberName());
++            return restoreToType(bccInvoker.bindTo(vamh), mh.type(), mh.internalMemberName(), hostClass);
+         }
+ 
+         private static MethodHandle makeInjectedInvoker(Class<?> hostClass) {
+@@ -879,10 +883,12 @@
+         }
+ 
+         // Undo the adapter effect of prepareForInvoker:
+-        private static MethodHandle restoreToType(MethodHandle vamh, MethodType type, MemberName member) {
++        private static MethodHandle restoreToType(MethodHandle vamh, MethodType type,
++                                                  MemberName member,
++                                                  Class<?> hostClass) {
+             MethodHandle mh = vamh.asCollector(Object[].class, type.parameterCount());
+             mh = mh.asType(type);
+-            mh = mh.withInternalMemberName(member);
++            mh = new WrappedMember(mh, type, member, hostClass);
+             return mh;
+         }
+ 
+@@ -951,11 +957,13 @@
+     static class WrappedMember extends MethodHandle {
+         private final MethodHandle target;
+         private final MemberName member;
++        private final Class<?> callerClass;
+ 
+-        private WrappedMember(MethodHandle target, MethodType type, MemberName member) {
++        private WrappedMember(MethodHandle target, MethodType type, MemberName member, Class<?> callerClass) {
+             super(type, reinvokerForm(target));
+             this.target = target;
+             this.member = member;
++            this.callerClass = callerClass;
+         }
+ 
+         @Override
+@@ -967,19 +975,23 @@
+             return member;
+         }
+         @Override
++        Class<?> internalCallerClass() {
++            return callerClass;
++        }
++        @Override
+         boolean isInvokeSpecial() {
+             return target.isInvokeSpecial();
+         }
+         @Override
+         MethodHandle viewAsType(MethodType newType) {
+-            return new WrappedMember(target, newType, member);
++            return new WrappedMember(target, newType, member, callerClass);
+         }
+     }
+ 
+     static MethodHandle makeWrappedMember(MethodHandle target, MemberName member) {
+         if (member.equals(target.internalMemberName()))
+             return target;
+-        return new WrappedMember(target, target.type(), member);
++        return new WrappedMember(target, target.type(), member, null);
+     }
+ 
+ }
+diff --git a/src/share/classes/java/lang/invoke/MethodHandleInfo.java b/src/share/classes/java/lang/invoke/MethodHandleInfo.java
+--- a/src/share/classes/java/lang/invoke/MethodHandleInfo.java
++++ b/src/share/classes/java/lang/invoke/MethodHandleInfo.java
+@@ -61,6 +61,18 @@
+  * Cracking must be done via a {@code Lookup} object equivalent to that which created
+  * the target method handle, or which has enough access permissions to recreate
+  * an equivalent method handle.
++ * <p>
++ * If the underlying method is <a href="#callsens">caller sensitive</a>,
++ * the direct method handle will have been "bound" to a particular caller class, the
++ * {@linkplain java.lang.invoke.MethodHandles.Lookup#lookupClass() lookup class}
++ * of the lookup object used to create it.
++ * Cracking this method handle with a different lookup class will fail
++ * even if the underlying method is public (like {@code Class.forName}).
++ * <p>
++ * The requirement of lookup object matching provides a "fast fail" behavior
++ * for programs which may otherwise trust erroneous revelation of a method
++ * handle with symbolic information (or caller binding) from an unexpected scope.
++ * Use {@link java.lang.invoke.MethodHandles#reflectAs} to override this limitation.
+  *
+  * <h1><a name="refkinds"></a>Reference kinds</h1>
+  * The <a href="MethodHandles.Lookup.html#lookups">Lookup Factory Methods</a>
+diff --git a/src/share/classes/java/lang/invoke/MethodHandleProxies.java b/src/share/classes/java/lang/invoke/MethodHandleProxies.java
+--- a/src/share/classes/java/lang/invoke/MethodHandleProxies.java
++++ b/src/share/classes/java/lang/invoke/MethodHandleProxies.java
+@@ -107,6 +107,11 @@
+      * such as abstract classes with single abstract methods.
+      * Future versions of this API may also equip wrapper instances
+      * with one or more additional public "marker" interfaces.
++     * <p>
++     * If a security manager is installed, this method is caller sensitive.
++     * During any invocation of the target method handle via the returned wrapper,
++     * the original creator of the wrapper (the caller) will be visible
++     * to context checks requested by the security manager.
+      *
+      * @param <T> the desired type of the wrapper, a single-method interface
+      * @param intfc a class object representing {@code T}
+diff --git a/src/share/classes/java/lang/invoke/MethodHandles.java b/src/share/classes/java/lang/invoke/MethodHandles.java
+--- a/src/share/classes/java/lang/invoke/MethodHandles.java
++++ b/src/share/classes/java/lang/invoke/MethodHandles.java
+@@ -48,7 +48,6 @@
+  * <li>Lookup methods which help create method handles for methods and fields.
+  * <li>Combinator methods, which combine or transform pre-existing method handles into new ones.
+  * <li>Other factory methods to create method handles that emulate other common JVM operations or control flow patterns.
+- * <li>Wrapper methods which can convert between method handles and interface types.
+  * </ul>
+  * <p>
+  * @author John Rose, JSR 292 EG
+@@ -65,12 +64,24 @@
+     //// Method handle creation from ordinary methods.
+ 
+     /**
+-     * Returns a {@link Lookup lookup object} on the caller,
+-     * which has the capability to access any method handle that the caller has access to,
+-     * including direct method handles to private fields and methods.
++     * Returns a {@link Lookup lookup object} with
++     * full capabilities to emulate all supported bytecode behaviors of the caller.
++     * These capabilities include <a href="privacc">private access</a> to the caller.
++     * Factory methods on the lookup object can create direct method handles for
++     * any member that the caller has access to via bytecodes,
++     * including protected and private fields and methods.
+      * This lookup object is a <em>capability</em> which may be delegated to trusted agents.
+      * Do not store it in place where untrusted code can access it.
+-     * @return a lookup object for the caller of this method
++     * <p>
++     * This method is caller sensitive, which means that it may return different
++     * values to different callers.
++     * <p>
++     * For any given caller class {@code C}, the lookup object returned by this call
++     * has equivalent capabilities to any lookup object
++     * supplied by the JVM to the bootstrap method of an
++     * <a href="package-summary.html#indyinsn">invokedynamic instruction</a>
++     * executing in the same caller class {@code C}.
++     * @return a lookup object for the caller of this method, with private access
+      */
+     @CallerSensitive
+     public static Lookup lookup() {
+@@ -84,11 +95,17 @@
+      * <p>
+      * As a matter of pure convention, the {@linkplain Lookup#lookupClass lookup class}
+      * of this lookup object will be {@link java.lang.Object}.
+-     * <p>
++     *
++     * <p style="font-size:smaller;">
++     * <em>Discussion:</em>
+      * The lookup class can be changed to any other class {@code C} using an expression of the form
+-     * {@linkplain Lookup#in <code>publicLookup().in(C.class)</code>}.
++     * {@link Lookup#in publicLookup().in(C.class)}.
+      * Since all classes have equal access to public names,
+      * such a change would confer no new access rights.
++     * A public lookup object is always subject to
++     * <a href="#secmgr">security manager checks</a>.
++     * Also, it cannot access
++     * <a href="#callsens">caller sensitive methods</a>.
+      * @return a lookup object which is trusted minimally
+      */
+     public static Lookup publicLookup() {
+@@ -149,10 +166,17 @@
+      * <h1><a name="lookups"></a>Lookup Factory Methods</h1>
+      * The factory methods on a {@code Lookup} object correspond to all major
+      * use cases for methods, constructors, and fields.
++     * Each method handle created by a factory method is the functional
++     * equivalent of a particular <em>bytecode behavior</em>.
++     * (Bytecode behaviors are described in section 5.4.3.5 of the Java Virtual Machine Specification.)
+      * Here is a summary of the correspondence between these factory methods and
+      * the behavior the resulting method handles:
+      * <table border=1 cellpadding=5 summary="lookup method behaviors">
+-     * <tr><th>lookup expression</th><th>member</th><th>behavior</th></tr>
++     * <tr>
++     *     <th><a name="equiv"></a>lookup expression</th>
++     *     <th>member</th>
++     *     <th>bytecode behavior</th>
++     * </tr>
+      * <tr>
+      *     <td>{@link java.lang.invoke.MethodHandles.Lookup#findGetter lookup.findGetter(C.class,"f",FT.class)}</td>
+      *     <td>{@code FT f;}</td><td>{@code (T) this.f;}</td>
+@@ -228,10 +252,12 @@
+      * In cases where the given member is of variable arity (i.e., a method or constructor)
+      * the returned method handle will also be of {@linkplain MethodHandle#asVarargsCollector variable arity}.
+      * In all other cases, the returned method handle will be of fixed arity.
+-     * <p>
++     * <p style="font-size:smaller;">
++     * <em>Discussion:</em>
+      * The equivalence between looked-up method handles and underlying
+-     * class members can break down in a few ways:
+-     * <ul>
++     * class members and bytecode behaviors
++     * can break down in a few ways:
++     * <ul style="font-size:smaller;">
+      * <li>If {@code C} is not symbolically accessible from the lookup class's loader,
+      * the lookup can still succeed, even when there is no equivalent
+      * Java expression or bytecoded constant.
+@@ -242,8 +268,8 @@
+      * {@code MethodHandle.invoke} will always succeed, regardless of requested type.
+      * <li>If there is a security manager installed, it can forbid the lookup
+      * on various grounds (<a href="#secmgr">see below</a>).
+-     * By contrast, the {@code ldc} instruction is not subject to
+-     * security manager checks.
++     * By contrast, the {@code ldc} instruction on a {@code CONSTANT_MethodHandle}
++     * constant is not subject to security manager checks.
+      * <li>If the looked-up method has a
+      * <a href="MethodHandle.html#maxarity">very large arity</a>,
+      * the method handle creation may fail, due to the method handle
+@@ -274,8 +300,9 @@
+      * <p>
+      * A lookup can fail, because
+      * the containing class is not accessible to the lookup class, or
+-     * because the desired class member is missing, or because the
+-     * desired class member is not accessible to the lookup class.
++     * because the desired class member is missing, because the
++     * desired class member is not accessible to the lookup class, or
++     * because the lookup object is not trusted enough to access the member.
+      * In any of these cases, a {@code ReflectiveOperationException} will be
+      * thrown from the attempted lookup.  The exact class will be one of
+      * the following:
+@@ -286,14 +313,23 @@
+      * </ul>
+      * <p>
+      * In general, the conditions under which a method handle may be
+-     * looked up for a method {@code M} are exactly equivalent to the conditions
+-     * under which the lookup class could have compiled and resolved a call to {@code M}.
++     * looked up for a method {@code M} are no more restrictive than the conditions
++     * under which the lookup class could have compiled, verified, and resolved a call to {@code M}.
+      * Where the JVM would raise exceptions like {@code NoSuchMethodError},
+      * a method handle lookup will generally raise a corresponding
+      * checked exception, such as {@code NoSuchMethodException}.
+      * And the effect of invoking the method handle resulting from the lookup
+-     * is exactly equivalent to executing the compiled and resolved call to {@code M}.
++     * is <a href="#equiv">exactly equivalent</a>
++     * to executing the compiled, verified, and resolved call to {@code M}.
+      * The same point is true of fields and constructors.
++     * <p style="font-size:smaller;">
++     * <em>Discussion:</em>
++     * Access checks only apply to named and reflected methods,
++     * constructors, and fields.
++     * Other method handle creation methods, such as
++     * {@link MethodHandle#asType MethodHandle.asType},
++     * do not require any access checks, and are used
++     * independently of any {@code Lookup} object.
+      * <p>
+      * If the desired member is {@code protected}, the usual JVM rules apply,
+      * including the requirement that the lookup class must be either be in the
+@@ -307,6 +343,12 @@
+      * (which will necessarily be a superclass of the lookup class)
+      * to the lookup class itself.
+      * <p>
++     * The JVM imposes a similar requirement on {@code invokespecial} instruction,
++     * that the receiver argument must match both the resolved method <em>and</em>
++     * the current class.  Again, this requirement is enforced by narrowing the
++     * type of the leading parameter to the resulting method handle.
++     * (See the Java Virtual Machine Specification, section 4.10.1.9.)
++     * <p>
+      * The JVM represents constructors and static initializer blocks as internal methods
+      * with special names ({@code "<init>"} and {@code "<clinit>"}).
+      * The internal syntax of invocation instructions allows them to refer to such internal
+@@ -326,6 +368,43 @@
+      * which can transform a lookup on {@code C.E} into one on any of those other
+      * classes, without special elevation of privilege.
+      * <p>
++     * The accesses permitted to a given lookup object may be limited,
++     * according to its set of {@link #lookupModes lookupModes},
++     * to a subset of members normally accessible to the lookup class.
++     * For example, the {@link MethodHandles#publicLookup publicLookup}
++     * method produces a lookup object which is only allowed to access
++     * public members in public classes.
++     * The caller sensitive method {@link MethodHandles#lookup lookup}
++     * produces a lookup object with full capabilities relative to
++     * its caller class, to emulate all supported bytecode behaviors.
++     * Also, the {@link Lookup#in Lookup.in} method may produce a lookup object
++     * with fewer access modes than the original lookup object.
++     *
++     * <p style="font-size:smaller;">
++     * <a name="privacc"></a>
++     * <em>Discussion of private access:</em>
++     * We say that a lookup has <em>private access</em>
++     * if its {@linkplain #lookupModes lookup modes}
++     * include the possibility of accessing {@code private} members.
++     * As documented in the relevant methods elsewhere,
++     * only lookups with private access possess the following capabilities:
++     * <ul style="font-size:smaller;">
++     * <li>access private fields, methods, and constructors of the lookup class
++     * <li>create method handles which invoke <a href="#callsens">caller sensitive</a> methods,
++     *     such as {@code Class.forName}
++     * <li>create method handles which {@link Lookup#findSpecial emulate invokespecial} instructions
++     * <li>avoid <a href="MethodHandles.Lookup.html#secmgr">package access checks</a>
++     *     for classes accessible to the lookup class
++     * <li>create {@link Lookup#in delegated lookup objects} which have private access to other classes
++     *     within the same package member
++     * </ul>
++     * <p style="font-size:smaller;">
++     * Each of these permissions is a consequence of the fact that a lookup object
++     * with private access can be securely traced back to an originating class,
++     * whose <a href="#equiv">bytecode behaviors</a> and Java language access permissions
++     * can be reliably determined and emulated by method handles.
++     *
++     * <h1><a name="secmgr"></a>Security manager interactions</h1>
+      * Although bytecode instructions can only refer to classes in
+      * a related class loader, this API can search for methods in any
+      * class, as long as a reference to its {@code Class} object is
+@@ -338,16 +417,6 @@
+      * and the Core Reflection API
+      * (as found on {@link java.lang.Class Class}).
+      * <p>
+-     * Access checks only apply to named and reflected methods,
+-     * constructors, and fields.
+-     * Other method handle creation methods, such as
+-     * {@link MethodHandle#asType MethodHandle.asType},
+-     * do not require any access checks, and are done
+-     * with static methods of {@link MethodHandles},
+-     * independently of any {@code Lookup} object.
+-     *
+-     * <h1>Security manager interactions</h1>
+-     * <a name="secmgr"></a>
+      * If a security manager is present, member lookups are subject to
+      * additional checks.
+      * From one to three calls are made to the security manager.
+@@ -360,7 +429,7 @@
+      * member is actually defined.
+      * The value {@code lookc} is defined as <em>not present</em>
+      * if the current lookup object does not have
+-     * {@linkplain java.lang.invoke.MethodHandles.Lookup#PRIVATE private access}.
++     * <a href="#privacc">private access</a>.
+      * The calls are made according to the following rules:
+      * <ul>
+      * <li>If {@code lookc} is not present, or if its class loader is not
+@@ -373,13 +442,59 @@
+      *     {@link SecurityManager#checkPermission smgr.checkPermission}
+      *     with {@code RuntimePermission("accessDeclaredMembers")} is called.
+      * <li>If the retrieved member is not public,
++     *     and if {@code lookc} is not present or else cannot access the retrieved member,
+      *     and if {@code defc} and {@code refc} are different,
+      *     then {@link SecurityManager#checkPackageAccess
+      *     smgr.checkPackageAccess(defcPkg)} is called,
+      *     where {@code defcPkg} is the package of {@code defc}.
+      * </ul>
++     *
++     * <h1><a name="callsens"></a>Caller sensitive methods</h1>
++     * A small number of Java methods have a special property called caller sensitivity.
++     * A <em>caller-sensitive</em> method can behave differently depending on the
++     * identity of its immediate caller.
++     * <p>
++     * If a method handle for a caller-sensitive method is requested,
++     * the general rules for <a href="#equiv">bytecode behaviors</a> apply,
++     * but they take account of the lookup class in a special way.
++     * The resulting method handle behaves as if it were called
++     * from an instruction contained in the lookup class,
++     * so that the caller-sensitive method detects the lookup class.
++     * (By contrast, the invoker of the method handle is disregarded.)
++     * Thus, in the case of caller-sensitive methods,
++     * different lookup classes may give rise to
++     * differently behaving method handles.
++     * <p>
++     * In cases where the lookup object is
++     * {@link MethodHandles#publicLookup() publicLookup()},
++     * or some other lookup object without
++     * <a href="#privacc">private access</a>,
++     * the lookup class is disregarded.
++     * In such cases, no caller-sensitive method handle can be created,
++     * access is forbidden, and the lookup fails with an
++     * {@code IllegalAccessException}.
++     * <p style="font-size:smaller;">
++     * <em>Discussion:</em>
++     * For example, the caller-sensitive method
++     * {@link java.lang.Class#forName(String) Class.forName(x)}
++     * can return varying classes or throw varying exceptions,
++     * depending on the class loader of the class that calls it.
++     * A public lookup of {@code Class.forName} will fail, because
++     * there is no reasonable way to determine its bytecode behavior.
++     * <p style="font-size:smaller;">
++     * If an application caches method handles for broad sharing,
++     * it should use {@code publicLookup()} to create them.
++     * If there is a lookup of {@code Class.forName}, it will fail,
++     * and the application must take appropriate action in that case.
++     * It may be that a later lookup, perhaps during the invocation of a
++     * bootstrap method, can incorporate the specific identity
++     * of the caller, making the method accessible.
++     * <p style="font-size:smaller;">
++     * The function {@code MethodHandles.lookup} is caller sensitive
++     * so that there can be a secure foundation for lookups.
++     * Nearly all other methods in the JSR 292 API rely on lookup
++     * objects to check access requests.
+      */
+-    // FIXME in MR1: clarify that the bytecode behavior of a caller-ID method (like Class.forName) is relative to the lookupClass used to create the method handle, not the dynamic caller of the method handle
+     public static final
+     class Lookup {
+         /** The class on behalf of whom the lookup is being performed. */
+@@ -605,7 +720,7 @@
+          * (Since static methods do not take receivers, there is no
+          * additional receiver argument inserted into the method handle type,
+          * as there would be with {@link #findVirtual findVirtual} or {@link #findSpecial findSpecial}.)
+-         * The method and all its argument types must be accessible to the lookup class.
++         * The method and all its argument types must be accessible to the lookup object.
+          * <p>
+          * The returned method handle will have
+          * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+@@ -646,7 +761,7 @@
+          * Produces a method handle for a virtual method.
+          * The type of the method handle will be that of the method,
+          * with the receiver type (usually {@code refc}) prepended.
+-         * The method and all its argument types must be accessible to the lookup class.
++         * The method and all its argument types must be accessible to the lookup object.
+          * <p>
+          * When called, the handle will treat the first argument as a receiver
+          * and dispatch on the receiver's type to determine which method
+@@ -663,7 +778,7 @@
+          * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+          * the method's variable arity modifier bit ({@code 0x0080}) is set.
+          * <p>
+-         * Because of the general equivalence between {@code invokevirtual}
++         * Because of the general <a href="#equiv">equivalence</a> between {@code invokevirtual}
+          * instructions and method handles produced by {@code findVirtual},
+          * if the class is {@code MethodHandle} and the name string is
+          * {@code invokeExact} or {@code invoke}, the resulting
+@@ -738,10 +853,10 @@
+          * the constructor of the specified type.
+          * The parameter types of the method handle will be those of the constructor,
+          * while the return type will be a reference to the constructor's class.
+-         * The constructor and all its argument types must be accessible to the lookup class.
++         * The constructor and all its argument types must be accessible to the lookup object.
+          * <p>
+-         * <em>(Note:  The requested type must have a return type of {@code void}.
+-         * This is consistent with the JVM's treatment of constructor type descriptors.)</em>
++         * The requested type must have a return type of {@code void}.
++         * (This is consistent with the JVM's treatment of constructor type descriptors.)
+          * <p>
+          * The returned method handle will have
+          * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+@@ -786,28 +901,27 @@
+         }
+ 
+         /**
+-         * Produces an early-bound method handle for a virtual method,
+-         * as if called from an {@code invokespecial}
+-         * instruction from {@code caller}.
++         * Produces an early-bound method handle for a virtual method.
++         * It will bypass checks for overriding methods on the receiver,
++         * <a href="#equiv">as if called</a> from an {@code invokespecial}
++         * instruction from within the explicitly specified {@code specialCaller}.
+          * The type of the method handle will be that of the method,
+-         * with a suitably restricted receiver type (such as {@code caller}) prepended.
++         * with a suitably restricted receiver type prepended.
++         * (The receiver type will be {@code specialCaller} or a subtype.)
+          * The method and all its argument types must be accessible
+-         * to the caller.
++         * to the lookup object.
+          * <p>
+-         * When called, the handle will treat the first argument as a receiver,
+-         * but will not dispatch on the receiver's type.
+-         * (This direct invocation action is identical with that performed by an
+-         * {@code invokespecial} instruction.)
+-         * <p>
+-         * If the explicitly specified caller class is not identical with the
+-         * lookup class, or if this lookup object does not have private access
++         * Before method resolution,
++         * if the explicitly specified caller class is not identical with the
++         * lookup class, or if this lookup object does not have
++         * <a href="#privacc">private access</a>
+          * privileges, the access fails.
+          * <p>
+          * The returned method handle will have
+          * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+          * the method's variable arity modifier bit ({@code 0x0080}) is set.
+-         * <p>
+-         * <em>(Note:  JVM internal methods named {@code <init>} not visible to this API,
++         * <p style="font-size:smaller;">
++         * <em>(Note:  JVM internal methods named {@code "<init>"} not visible to this API,
+          * even though the {@code invokespecial} instruction can refer to them
+          * in special circumstances.  Use {@link #findConstructor findConstructor}
+          * to access instance initialization methods in a safe manner.)</em>
+@@ -967,7 +1081,7 @@
+          * Produces an early-bound method handle for a non-static method.
+          * The receiver must have a supertype {@code defc} in which a method
+          * of the given name and type is accessible to the lookup class.
+-         * The method and all its argument types must be accessible to the lookup class.
++         * The method and all its argument types must be accessible to the lookup object.
+          * The type of the method handle will be that of the method,
+          * without any insertion of an additional receiver parameter.
+          * The given receiver will be bound into the method handle,
+@@ -982,7 +1096,7 @@
+          * the given receiver value will be bound to it.)
+          * <p>
+          * This is equivalent to the following code:
+-         * <blockquote><pre>
++         * <blockquote><pre>{@code
+ import static java.lang.invoke.MethodHandles.*;
+ import static java.lang.invoke.MethodType.*;
+ ...
+@@ -992,7 +1106,7 @@
+ if (mh0.isVarargsCollector())
+   mh1 = mh1.asVarargsCollector(mt1.parameterType(mt1.parameterCount()-1));
+ return mh1;
+-         * </pre></blockquote>
++         * }</pre></blockquote>
+          * where {@code defc} is either {@code receiver.getClass()} or a super
+          * type of that class, in which the requested method is accessible
+          * to the lookup class.
+@@ -1065,13 +1179,21 @@
+         /**
+          * Produces a method handle for a reflected method.
+          * It will bypass checks for overriding methods on the receiver,
+-         * as if by a {@code invokespecial} instruction from within the {@code specialCaller}.
++         * <a href="#equiv">as if called</a> from an {@code invokespecial}
++         * instruction from within the explicitly specified {@code specialCaller}.
+          * The type of the method handle will be that of the method,
+-         * with the special caller type prepended (and <em>not</em> the receiver of the method).
++         * with a suitably restricted receiver type prepended.
++         * (The receiver type will be {@code specialCaller} or a subtype.)
+          * If the method's {@code accessible} flag is not set,
+          * access checking is performed immediately on behalf of the lookup class,
+          * as if {@code invokespecial} instruction were being linked.
+          * <p>
++         * Before method resolution,
++         * if the explicitly specified caller class is not identical with the
++         * lookup class, or if this lookup object does not have
++         * <a href="#privacc">private access</a>
++         * privileges, the access fails.
++         * <p>
+          * The returned method handle will have
+          * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+          * the method's variable arity modifier bit ({@code 0x0080}) is set.
+@@ -1116,8 +1238,7 @@
+          *                                is set and {@code asVarargsCollector} fails
+          * @throws NullPointerException if the argument is null
+          */
+-        @SuppressWarnings("rawtypes")  // Will be Constructor<?> after JSR 292 MR
+-        public MethodHandle unreflectConstructor(Constructor c) throws IllegalAccessException {
++        public MethodHandle unreflectConstructor(Constructor<?> c) throws IllegalAccessException {
+             MemberName ctor = new MemberName(c);
+             assert(ctor.isConstructor());
+             Lookup lookup = c.isAccessible() ? IMPL_LOOKUP : this;
+@@ -1182,12 +1303,15 @@
+          * is capable of reproducing the target method handle.
+          * This means that the cracking may fail if target is a direct method handle
+          * but was created by an unrelated lookup object.
++         * This can happen if the method handle is <a href="#callsens">caller sensitive</a>
++         * and was created by a lookup object for a different class.
+          * @param target a direct method handle to crack into symbolic reference components
+          * @return a symbolic reference which can be used to reconstruct this method handle from this lookup object
+          * @exception SecurityException if a security manager is present and it
+          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+          * @throws IllegalArgumentException if the target is not a direct method handle or if access checking fails
+          * @exception NullPointerException if the target is {@code null}
++         * @see MethodHandleInfo
+          * @since 1.8
+          */
+         public MethodHandleInfo revealDirect(MethodHandle target) {
+@@ -1212,6 +1336,11 @@
+             } catch (IllegalAccessException ex) {
+                 throw new IllegalArgumentException(ex);
+             }
++            if (allowedModes != TRUSTED && member.isCallerSensitive()) {
++                Class<?> callerClass = target.internalCallerClass();
++                if (!hasPrivateAccess() || callerClass != lookupClass())
++                    throw new IllegalArgumentException("method handle is caller sensitive: "+callerClass);
++            }
+             // Produce the handle to the results.
+             return new InfoFromMemberName(this, member, refKind);
+         }
+@@ -1253,8 +1382,8 @@
+         Class<?> findBoundCallerClass(MemberName m) throws IllegalAccessException {
+             Class<?> callerClass = null;
+             if (MethodHandleNatives.isCallerSensitive(m)) {
+-                // Only full-power lookup is allowed to resolve caller-sensitive methods
+-                if (isFullPowerLookup()) {
++                // Only lookups with private access are allowed to resolve caller-sensitive methods
++                if (hasPrivateAccess()) {
+                     callerClass = lookupClass;
+                 } else {
+                     throw new IllegalAccessException("Attempt to lookup caller-sensitive method using restricted lookup object");
+@@ -1263,7 +1392,7 @@
+             return callerClass;
+         }
+ 
+-        private boolean isFullPowerLookup() {
++        private boolean hasPrivateAccess() {
+             return (allowedModes & PRIVATE) != 0;
+         }
+ 
+@@ -1278,7 +1407,8 @@
+             if (allowedModes == TRUSTED)  return;
+ 
+             // Step 1:
+-            if (!isFullPowerLookup() ||
++            boolean fullPowerLookup = hasPrivateAccess();
++            if (!fullPowerLookup ||
+                 !VerifyAccess.classLoaderIsAncestor(lookupClass, refc)) {
+                 ReflectUtil.checkPackageAccess(refc);
+             }
+@@ -1287,11 +1417,18 @@
+             if (m.isPublic()) return;
+             Class<?> defc = m.getDeclaringClass();
+             {
+-                if (!isFullPowerLookup()) {
++                if (!fullPowerLookup) {
+                     smgr.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
+                 }
+             }
+ 
++            // If a member is normally accessible from a trustable lookup class,
++            // a method handle on it emulates normal bytecode behavior,
++            // and therefore does not incur security manager checks.
++            if (fullPowerLookup &&
++                VerifyAccess.isMemberAccessible(refc, defc, m.getModifiers(), lookupClass, allowedModes))
++                return;
++
+             // Step 3:
+             if (defc != refc) {
+                 ReflectUtil.checkPackageAccess(defc);
+@@ -1376,7 +1513,7 @@
+         private void checkSpecialCaller(Class<?> specialCaller) throws IllegalAccessException {
+             int allowedModes = this.allowedModes;
+             if (allowedModes == TRUSTED)  return;
+-            if ((allowedModes & PRIVATE) == 0
++            if (!hasPrivateAccess()
+                 || (specialCaller != lookupClass()
+                     && !(ALLOW_NESTMATE_ACCESS &&
+                          VerifyAccess.isSamePackageMember(specialCaller, lookupClass()))))
+@@ -1459,7 +1596,7 @@
+             if (allowedModes == TRUSTED || !MethodHandleNatives.isCallerSensitive(method))
+                 return mh;
+             Class<?> hostClass = lookupClass;
+-            if ((allowedModes & PRIVATE) == 0)  // caller must use full-power lookup
++            if (!hasPrivateAccess())  // caller must have private access
+                 hostClass = callerClass;  // callerClass came from a security manager style stack walk
+             MethodHandle cbmh = MethodHandleImpl.bindCaller(mh, hostClass);
+             // Note: caller will apply varargs after this step happens.
+@@ -1572,13 +1709,12 @@
+      * an {@link IllegalArgumentException} instead of invoking the target.
+      * <p>
+      * This method is equivalent to the following code (though it may be more efficient):
+-     * <p><blockquote><pre>
++     * <blockquote><pre>{@code
+ MethodHandle invoker = MethodHandles.invoker(type);
+ int spreadArgCount = type.parameterCount() - leadingArgCount;
+ invoker = invoker.asSpreader(Object[].class, spreadArgCount);
+ return invoker;
+-     * </pre></blockquote>
+-     * <p>
++     * }</pre></blockquote>
+      * This method throws no reflective or security exceptions.
+      * @param type the desired target type
+      * @param leadingArgCount number of fixed arguments, to be passed unchanged to the target
+@@ -1604,9 +1740,7 @@
+      * an additional leading argument of type {@code MethodHandle}.
+      * <p>
+      * This method is equivalent to the following code (though it may be more efficient):
+-     * <p><blockquote><pre>
+-publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)
+-     * </pre></blockquote>
++     * {@code publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)}
+      *
+      * <p style="font-size:smaller;">
+      * <em>Discussion:</em>
+@@ -1621,7 +1755,7 @@
+      * If spreading, collecting, or other argument transformations are required,
+      * they can be applied once to the invoker {@code X} and reused on many {@code M}
+      * method handle values, as long as they are compatible with the type of {@code X}.
+-     * <p>
++     * <p style="font-size:smaller;">
+      * <em>(Note:  The invoker method is not available via the Core Reflection API.
+      * An attempt to call {@linkplain java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}
+      * on the declared {@code invokeExact} or {@code invoke} method will raise an
+@@ -1652,15 +1786,19 @@
+      * If the target is a {@linkplain MethodHandle#asVarargsCollector variable arity method handle},
+      * the required arity conversion will be made, again as if by {@link MethodHandle#asType asType}.
+      * <p>
+-     * A {@linkplain MethodType#genericMethodType general method type},
++     * This method is equivalent to the following code (though it may be more efficient):
++     * {@code publicLookup().findVirtual(MethodHandle.class, "invoke", type)}
++     * <p style="font-size:smaller;">
++     * <em>Discussion:</em>
++     * A {@linkplain MethodType#genericMethodType general method type} is one which
+      * mentions only {@code Object} arguments and return values.
+      * An invoker for such a type is capable of calling any method handle
+      * of the same arity as the general type.
+-     * <p>
+-     * This method is equivalent to the following code (though it may be more efficient):
+-     * <p><blockquote><pre>
+-publicLookup().findVirtual(MethodHandle.class, "invoke", type)
+-     * </pre></blockquote>
++     * <p style="font-size:smaller;">
++     * <em>(Note:  The invoker method is not available via the Core Reflection API.
++     * An attempt to call {@linkplain java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}
++     * on the declared {@code invokeExact} or {@code invoke} method will raise an
++     * {@link java.lang.UnsupportedOperationException UnsupportedOperationException}.)</em>
+      * <p>
+      * This method throws no reflective or security exceptions.
+      * @param type the desired target type
+@@ -1947,7 +2085,7 @@
+      * they will come after.
+      * <p>
+      * <b>Example:</b>
+-     * <p><blockquote><pre>
++     * <p><blockquote><pre>{@code
+ import static java.lang.invoke.MethodHandles.*;
+ import static java.lang.invoke.MethodType.*;
+ ...
+@@ -1958,7 +2096,7 @@
+ MethodHandle d0 = dropArguments(cat, 0, bigType.parameterList().subList(0,2));
+ assertEquals(bigType, d0.type());
+ assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z"));
+-     * </pre></blockquote>
++     * }</pre></blockquote>
+      * <p>
+      * This method is also equivalent to the following code:
+      * <p><blockquote><pre>
+@@ -2005,7 +2143,7 @@
+      * they will come after.
+      * <p>
+      * <b>Example:</b>
+-     * <p><blockquote><pre>
++     * <p><blockquote><pre>{@code
+ import static java.lang.invoke.MethodHandles.*;
+ import static java.lang.invoke.MethodType.*;
+ ...
+@@ -2020,7 +2158,7 @@
+ assertEquals("xy", (String) d2.invokeExact("x", "y", "z"));
+ MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);
+ assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
+-     * </pre></blockquote>
++     * }</pre></blockquote>
+      * <p>
+      * This method is also equivalent to the following code:
+      * <p><blockquote><pre>
+@@ -2071,7 +2209,7 @@
+      * (null or not)
+      * which do not correspond to argument positions in the target.
+      * <b>Example:</b>
+-     * <p><blockquote><pre>
++     * <p><blockquote><pre>{@code
+ import static java.lang.invoke.MethodHandles.*;
+ import static java.lang.invoke.MethodType.*;
+ ...
+@@ -2086,7 +2224,7 @@
+ assertEquals("xY", (String) f1.invokeExact("x", "y")); // xY
+ MethodHandle f2 = filterArguments(cat, 0, upcase, upcase);
+ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
+-     * </pre></blockquote>
++     * }</pre></blockquote>
+      * <p> Here is pseudocode for the resulting adapter:
+      * <blockquote><pre>
+      * V target(P... p, A[i]... a[i], B... b);
+@@ -2263,7 +2401,7 @@
+      * The argument type of the filter (if any) must be identical to the
+      * return type of the target.
+      * <b>Example:</b>
+-     * <p><blockquote><pre>
++     * <p><blockquote><pre>{@code
+ import static java.lang.invoke.MethodHandles.*;
+ import static java.lang.invoke.MethodType.*;
+ ...
+@@ -2274,7 +2412,7 @@
+ System.out.println((String) cat.invokeExact("x", "y")); // xy
+ MethodHandle f0 = filterReturnValue(cat, length);
+ System.out.println((int) f0.invokeExact("x", "y")); // 2
+-     * </pre></blockquote>
++     * }</pre></blockquote>
+      * <p> Here is pseudocode for the resulting adapter:
+      * <blockquote><pre>
+      * V target(A...);
+@@ -2354,7 +2492,7 @@
+      * arguments will not need to be live on the stack on entry to the
+      * target.)
+      * <b>Example:</b>
+-     * <p><blockquote><pre>
++     * <p><blockquote><pre>{@code
+ import static java.lang.invoke.MethodHandles.*;
+ import static java.lang.invoke.MethodType.*;
+ ...
+@@ -2367,7 +2505,7 @@
+ MethodHandle catTrace = foldArguments(cat, trace);
+ // also prints "boo":
+ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
+-     * </pre></blockquote>
++     * }</pre></blockquote>
+      * <p> Here is pseudocode for the resulting adapter:
+      * <blockquote><pre>
+      * // there are N arguments in A...
+diff --git a/test/java/lang/invoke/RevealDirectTest.java b/test/java/lang/invoke/RevealDirectTest.java
+--- a/test/java/lang/invoke/RevealDirectTest.java
++++ b/test/java/lang/invoke/RevealDirectTest.java
+@@ -104,6 +104,9 @@
+         private static Lookup localLookup() { return lookup(); }
+         private static List<Member> members() { return getMembers(lookup().lookupClass()); };
+     }
++    static class Nestmate {
++        private static Lookup localLookup() { return lookup(); }
++    }
+ 
+     static boolean VERBOSE = false;
+ 
+@@ -152,7 +155,10 @@
+                                   getMembers(Method.class, "invoke"));
+         mems = callerSensitive(true, publicOnly(mems));
+         // CS methods cannot be looked up with publicLookup
+-        testOnMembersNoLookup("testCallerSensitiveNegative", mems, publicLookup());
++        testOnMembersNoLookup("testCallerSensitiveNegative/1", mems, publicLookup());
++        // CS methods have to be revealed with a matching lookupClass
++        testOnMembersNoReveal("testCallerSensitiveNegative/2", mems, Simple.localLookup(), publicLookup());
++        testOnMembersNoReveal("testCallerSensitiveNegative/3", mems, Simple.localLookup(), Nestmate.localLookup());
+     }
+     @Test public void testMethodHandleNatives() throws Throwable {
+         if (VERBOSE)  System.out.println("@Test testMethodHandleNatives");
+@@ -703,7 +709,7 @@
+             try {
+                 info = revLookup.revealDirect(mh);
+                 if (expectEx2)  throw new AssertionError("unexpected revelation for negative test");
+-            } catch (Throwable ex2) {
++            } catch (IllegalArgumentException|SecurityException ex2) {
+                 if (VERBOSE)  System.out.println("  "+variation+": "+res+" => "+mh.getClass().getName()+" => (EX2)"+ex2);
+                 if (expectEx2)
+                     continue;  // this is OK; we expected the reflect to fail
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/meth-nsme-8001108.patch	Fri Sep 13 22:50:28 2013 -0700
@@ -0,0 +1,527 @@
+8001108: an attempt to use "<init>" as a method name should elicit NoSuchMethodException
+Summary: add an explicit check for leading "<", upgrade the unit tests
+Reviewed-by: ?
+
+diff --git a/src/share/classes/java/lang/invoke/MethodHandles.java b/src/share/classes/java/lang/invoke/MethodHandles.java
+--- a/src/share/classes/java/lang/invoke/MethodHandles.java
++++ b/src/share/classes/java/lang/invoke/MethodHandles.java
+@@ -288,6 +288,9 @@
+      * In general, the conditions under which a method handle may be
+      * looked up for a method {@code M} are exactly equivalent to the conditions
+      * under which the lookup class could have compiled and resolved a call to {@code M}.
++     * Where the JVM would raise exceptions like {@code NoSuchMethodError},
++     * a method handle lookup will generally raise a corresponding
++     * checked exception, such as {@code NoSuchMethodException}.
+      * And the effect of invoking the method handle resulting from the lookup
+      * is exactly equivalent to executing the compiled and resolved call to {@code M}.
+      * The same point is true of fields and constructors.
+@@ -304,6 +307,12 @@
+      * (which will necessarily be a superclass of the lookup class)
+      * to the lookup class itself.
+      * <p>
++     * The JVM represents constructors and static initializer blocks as internal methods
++     * with special names ({@code "<init>"} and {@code "<clinit>"}).
++     * The internal syntax of invocation instructions allows them to refer to such internal
++     * methods as if they were normal methods, but the JVM verifier rejects them.
++     * A lookup of such an internal method will produce a {@code NoSuchMethodException}.
++     * <p>
+      * In some cases, access between nested classes is obtained by the Java compiler by creating
+      * an wrapper method to access a private method of another class
+      * in the same top-level declaration.
+@@ -603,6 +612,15 @@
+          * The returned method handle will have
+          * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+          * the method's variable arity modifier bit ({@code 0x0080}) is set.
++         * <b>Example:</b>
++         * <p><blockquote><pre>{@code
++import static java.lang.invoke.MethodHandles.*;
++import static java.lang.invoke.MethodType.*;
++...
++MethodHandle MH_asList = publicLookup().findStatic(Arrays.class,
++  "asList", methodType(List.class, Object[].class));
++assertEquals("[x, y]", MH_asList.invoke("x", "y").toString());
++         * }</pre></blockquote>
+          * @param refc the class from which the method is accessed
+          * @param name the name of the method
+          * @param type the type of the method
+@@ -653,6 +671,34 @@
+          * {@link java.lang.invoke.MethodHandles#invoker MethodHandles.invoker}
+          * with the same {@code type} argument.
+          *
++         * <b>Example:</b>
++         * <p><blockquote><pre>{@code
++import static java.lang.invoke.MethodHandles.*;
++import static java.lang.invoke.MethodType.*;
++...
++MethodHandle MH_concat = publicLookup().findVirtual(String.class,
++  "concat", methodType(String.class, String.class));
++MethodHandle MH_hashCode = publicLookup().findVirtual(Object.class,
++  "hashCode", methodType(int.class));
++MethodHandle MH_hashCode_String = publicLookup().findVirtual(String.class,
++  "hashCode", methodType(int.class));
++assertEquals("xy", (String) MH_concat.invokeExact("x", "y"));
++assertEquals("xy".hashCode(), (int) MH_hashCode.invokeExact((Object)"xy"));
++assertEquals("xy".hashCode(), (int) MH_hashCode_String.invokeExact("xy"));
++// interface method:
++MethodHandle MH_subSequence = publicLookup().findVirtual(CharSequence.class,
++  "subSequence", methodType(CharSequence.class, int.class, int.class));
++assertEquals("def", MH_subSequence.invoke("abcdefghi", 3, 6).toString());
++// constructor "internal method" must be accessed differently:
++MethodType MT_newString = methodType(void.class); //()V for new String()
++try { assertEquals("impossible", lookup()
++        .findVirtual(String.class, "<init>", MT_newString));
++ } catch (NoSuchMethodException ex) { } // OK
++MethodHandle MH_newString = publicLookup()
++  .findConstructor(String.class, MT_newString);
++assertEquals("", (String) MH_newString.invokeExact());
++         * }</pre></blockquote>
++         *
+          * @param refc the class or interface from which the method is accessed
+          * @param name the name of the method
+          * @param type the type of the method, with the receiver argument omitted
+@@ -695,12 +741,30 @@
+          * If the constructor's class has not yet been initialized, that is done
+          * immediately, before the method handle is returned.
+          * <p>
+-         * Note:  The requested type must have a return type of {@code void}.
+-         * This is consistent with the JVM's treatment of constructor type descriptors.
++         * <em>(Note:  The requested type must have a return type of {@code void}.
++         * This is consistent with the JVM's treatment of constructor type descriptors.)</em>
+          * <p>
+          * The returned method handle will have
+          * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+          * the constructor's variable arity modifier bit ({@code 0x0080}) is set.
++         * <b>Example:</b>
++         * <p><blockquote><pre>{@code
++import static java.lang.invoke.MethodHandles.*;
++import static java.lang.invoke.MethodType.*;
++...
++MethodHandle MH_newArrayList = publicLookup().findConstructor(
++  ArrayList.class, methodType(void.class, Collection.class));
++Collection orig = Arrays.asList("x", "y");
++Collection copy = (ArrayList) MH_newArrayList.invokeExact(orig);
++assert(orig != copy);
++assertEquals(orig, copy);
++// a variable-arity constructor:
++MethodHandle MH_newProcessBuilder = publicLookup().findConstructor(
++  ProcessBuilder.class, methodType(void.class, String[].class));
++ProcessBuilder pb = (ProcessBuilder)
++  MH_newProcessBuilder.invoke("x", "y", "z");
++assertEquals("[x, y, z]", pb.command().toString());
++         * }</pre></blockquote>
+          * @param refc the class or interface from which the method is accessed
+          * @param type the type of the method, with the receiver argument omitted, and a void return type
+          * @return the desired method handle
+@@ -740,6 +804,45 @@
+          * The returned method handle will have
+          * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+          * the method's variable arity modifier bit ({@code 0x0080}) is set.
++         * <p>
++         * <em>(Note:  JVM internal methods named {@code <init>} not visible to this API,
++         * even though the {@code invokespecial} instruction can refer to them
++         * in special circumstances.  Use {@link #findConstructor findConstructor}
++         * to access instance initialization methods in a safe manner.)</em>
++         * <b>Example:</b>
++         * <p><blockquote><pre>{@code
++import static java.lang.invoke.MethodHandles.*;
++import static java.lang.invoke.MethodType.*;
++...
++static class Listie extends ArrayList {
++  public String toString() { return "[wee Listie]"; }
++  static Lookup lookup() { return MethodHandles.lookup(); }
++}
++...
++// no access to constructor via invokeSpecial:
++MethodHandle MH_newListie = Listie.lookup()
++  .findConstructor(Listie.class, methodType(void.class));
++Listie l = (Listie) MH_newListie.invokeExact();
++try { assertEquals("impossible", Listie.lookup().findSpecial(
++        Listie.class, "<init>", methodType(void.class), Listie.class));
++ } catch (NoSuchMethodException ex) { } // OK
++// access to super and self methods via invokeSpecial:
++MethodHandle MH_super = Listie.lookup().findSpecial(
++  ArrayList.class, "toString" , methodType(String.class), Listie.class);
++MethodHandle MH_this = Listie.lookup().findSpecial(
++  Listie.class, "toString" , methodType(String.class), Listie.class);
++MethodHandle MH_duper = Listie.lookup().findSpecial(
++  Object.class, "toString" , methodType(String.class), Listie.class);
++assertEquals("[]", (String) MH_super.invokeExact(l));
++assertEquals(""+l, (String) MH_this.invokeExact(l));
++assertEquals("[]", (String) MH_duper.invokeExact(l)); // ArrayList method
++try { assertEquals("inaccessible", Listie.lookup().findSpecial(
++        String.class, "toString", methodType(String.class), Listie.class));
++ } catch (IllegalAccessException ex) { } // OK
++Listie subl = new Listie() { public String toString() { return "[subclass]"; } };
++assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method
++         * }</pre></blockquote>
++         *
+          * @param refc the class or interface from which the method is accessed
+          * @param name the name of the method (which must not be "&lt;init&gt;")
+          * @param type the type of the method, with the receiver argument omitted
+@@ -1093,15 +1196,16 @@
+         /// Helper methods, all package-private.
+ 
+         MemberName resolveOrFail(byte refKind, Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
++            name.getClass(); type.getClass();  // NPE
+             checkSymbolicClass(refc);  // do this before attempting to resolve
+-            name.getClass(); type.getClass();  // NPE
+             return IMPL_NAMES.resolveOrFail(refKind, new MemberName(refc, name, type, refKind), lookupClassOrNull(),
+                                             NoSuchFieldException.class);
+         }
+ 
+         MemberName resolveOrFail(byte refKind, Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
++            type.getClass();  // NPE
+             checkSymbolicClass(refc);  // do this before attempting to resolve
+-            name.getClass(); type.getClass();  // NPE
++            checkMethodName(refKind, name);
+             return IMPL_NAMES.resolveOrFail(refKind, new MemberName(refc, name, type, refKind), lookupClassOrNull(),
+                                             NoSuchMethodException.class);
+         }
+@@ -1112,6 +1216,12 @@
+                 throw new MemberName(refc).makeAccessException("symbolic reference class is not public", this);
+         }
+ 
++        void checkMethodName(byte refKind, String name) throws NoSuchMethodException {
++            if (name.startsWith("<") && refKind != REF_newInvokeSpecial)
++                throw new NoSuchMethodException("illegal method name: "+name);
++        }
++
++
+         /**
+          * Find my trustable caller class if m is a caller sensitive method.
+          * If this lookup object has private access, then the caller class is the lookupClass.
+diff --git a/test/java/lang/invoke/JavaDocExamplesTest.java b/test/java/lang/invoke/JavaDocExamplesTest.java
+--- a/test/java/lang/invoke/JavaDocExamplesTest.java
++++ b/test/java/lang/invoke/JavaDocExamplesTest.java
+@@ -65,7 +65,11 @@
+     }
+ 
+     public void run() throws Throwable {
++        testMisc();
++        testFindStatic();
++        testFindConstructor();
+         testFindVirtual();
++        testFindSpecial();
+         testPermuteArguments();
+         testDropArguments();
+         testFilterArguments();
+@@ -110,7 +114,8 @@
+ 
+ {}
+ 
+-    @Test public void testFindVirtual() throws Throwable {
++    @Test public void testMisc() throws Throwable {
++// Extra tests, not from javadoc:
+ {}
+ MethodHandle CONCAT_3 = LOOKUP.findVirtual(String.class,
+   "concat", methodType(String.class, String.class));
+@@ -125,6 +130,92 @@
+ {}
+     }
+ 
++    @Test public void testFindStatic() throws Throwable {
++{}
++MethodHandle MH_asList = publicLookup().findStatic(Arrays.class,
++  "asList", methodType(List.class, Object[].class));
++assertEquals("[x, y]", MH_asList.invoke("x", "y").toString());
++{}
++    }
++
++    @Test public void testFindVirtual() throws Throwable {
++{}
++MethodHandle MH_concat = publicLookup().findVirtual(String.class,
++  "concat", methodType(String.class, String.class));
++MethodHandle MH_hashCode = publicLookup().findVirtual(Object.class,
++  "hashCode", methodType(int.class));
++MethodHandle MH_hashCode_String = publicLookup().findVirtual(String.class,
++  "hashCode", methodType(int.class));
++assertEquals("xy", (String) MH_concat.invokeExact("x", "y"));
++assertEquals("xy".hashCode(), (int) MH_hashCode.invokeExact((Object)"xy"));
++assertEquals("xy".hashCode(), (int) MH_hashCode_String.invokeExact("xy"));
++// interface method:
++MethodHandle MH_subSequence = publicLookup().findVirtual(CharSequence.class,
++  "subSequence", methodType(CharSequence.class, int.class, int.class));
++assertEquals("def", MH_subSequence.invoke("abcdefghi", 3, 6).toString());
++// constructor "internal method" must be accessed differently:
++MethodType MT_newString = methodType(void.class); //()V for new String()
++try { assertEquals("impossible", lookup()
++        .findVirtual(String.class, "<init>", MT_newString));
++ } catch (NoSuchMethodException ex) { } // OK
++MethodHandle MH_newString = publicLookup()
++  .findConstructor(String.class, MT_newString);
++assertEquals("", (String) MH_newString.invokeExact());
++{}
++    }
++
++    @Test public void testFindConstructor() throws Throwable {
++{}
++MethodHandle MH_newArrayList = publicLookup().findConstructor(
++  ArrayList.class, methodType(void.class, Collection.class));
++Collection orig = Arrays.asList("x", "y");
++Collection copy = (ArrayList) MH_newArrayList.invokeExact(orig);
++assert(orig != copy);
++assertEquals(orig, copy);
++// a variable-arity constructor:
++MethodHandle MH_newProcessBuilder = publicLookup().findConstructor(
++  ProcessBuilder.class, methodType(void.class, String[].class));
++ProcessBuilder pb = (ProcessBuilder)
++  MH_newProcessBuilder.invoke("x", "y", "z");
++assertEquals("[x, y, z]", pb.command().toString());
++{}
++    }
++
++// for testFindSpecial
++{}
++static class Listie extends ArrayList {
++  public String toString() { return "[wee Listie]"; }
++  static Lookup lookup() { return MethodHandles.lookup(); }
++}
++{}
++
++    @Test public void testFindSpecial() throws Throwable {
++{}
++// no access to constructor via invokeSpecial:
++MethodHandle MH_newListie = Listie.lookup()
++  .findConstructor(Listie.class, methodType(void.class));
++Listie l = (Listie) MH_newListie.invokeExact();
++try { assertEquals("impossible", Listie.lookup().findSpecial(
++        Listie.class, "<init>", methodType(void.class), Listie.class));
++ } catch (NoSuchMethodException ex) { } // OK
++// access to super and self methods via invokeSpecial:
++MethodHandle MH_super = Listie.lookup().findSpecial(
++  ArrayList.class, "toString" , methodType(String.class), Listie.class);
++MethodHandle MH_this = Listie.lookup().findSpecial(
++  Listie.class, "toString" , methodType(String.class), Listie.class);
++MethodHandle MH_duper = Listie.lookup().findSpecial(
++  Object.class, "toString" , methodType(String.class), Listie.class);
++assertEquals("[]", (String) MH_super.invokeExact(l));
++assertEquals(""+l, (String) MH_this.invokeExact(l));
++assertEquals("[]", (String) MH_duper.invokeExact(l)); // ArrayList method
++try { assertEquals("inaccessible", Listie.lookup().findSpecial(
++        String.class, "toString", methodType(String.class), Listie.class));
++ } catch (IllegalAccessException ex) { } // OK
++Listie subl = new Listie() { public String toString() { return "[subclass]"; } };
++assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method
++{}
++    }
++
+     @Test public void testPermuteArguments() throws Throwable {
+         {{
+ {} /// JAVADOC
+diff --git a/test/java/lang/invoke/MethodHandlesTest.java b/test/java/lang/invoke/MethodHandlesTest.java
+--- a/test/java/lang/invoke/MethodHandlesTest.java
++++ b/test/java/lang/invoke/MethodHandlesTest.java
+@@ -363,6 +363,7 @@
+         protected Example(String name) { this.name = name; }
+         @SuppressWarnings("LeakingThisInConstructor")
+         protected Example(int x) { this(); called("protected <init>", this, x); }
++        //Example(Void x) { does not exist; lookup elicts NoSuchMethodException }
+         @Override public String toString() { return name; }
+ 
+         public void            v0()     { called("v0", this); }
+@@ -463,6 +464,9 @@
+         return lookup.in(defc);
+     }
+ 
++    /** Is findVirtual (etc.) of "<init>" supposed to elicit a NoSuchMethodException? */
++    final static boolean INIT_REF_CAUSES_NSME = true;
++
+     @Test
+     public void testFindStatic() throws Throwable {
+         if (CAN_SKIP_WORKING)  return;
+@@ -483,6 +487,8 @@
+         testFindStatic(Example.class, Object.class, "s7", float.class, double.class);
+ 
+         testFindStatic(false, PRIVATE, Example.class, void.class, "bogus");
++        testFindStatic(false, PRIVATE, Example.class, void.class, "<init>", int.class);
++        testFindStatic(false, PRIVATE, Example.class, void.class, "<init>", Void.class);
+         testFindStatic(false, PRIVATE, Example.class, void.class, "v0");
+     }
+ 
+@@ -505,11 +511,12 @@
+             target = maybeMoveIn(lookup, defc).findStatic(defc, methodName, type);
+         } catch (ReflectiveOperationException ex) {
+             noAccess = ex;
++            assertExceptionClass(
++                (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>"))
++                ?   NoSuchMethodException.class
++                :   IllegalAccessException.class,
++                noAccess);
+             if (verbosity >= 5)  ex.printStackTrace(System.out);
+-            if (name.contains("bogus"))
+-                assertTrue(noAccess instanceof NoSuchMethodException);
+-            else
+-                assertTrue(noAccess instanceof IllegalAccessException);
+         }
+         if (verbosity >= 3)
+             System.out.println("findStatic "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target
+@@ -527,6 +534,13 @@
+             System.out.print(':');
+     }
+ 
++    static void assertExceptionClass(Class<? extends Throwable> expected,
++                                     Throwable actual) {
++        if (expected.isInstance(actual))  return;
++        actual.printStackTrace();
++        assertEquals(expected, actual.getClass());
++    }
++
+     static final boolean DEBUG_METHOD_HANDLE_NAMES = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
+ 
+     // rough check of name string
+@@ -556,6 +570,8 @@
+         testFindVirtual(PubExample.class, void.class, "Pub/pro_v0");
+ 
+         testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "bogus");
++        testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "<init>", int.class);
++        testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "<init>", Void.class);
+         testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "s0");
+ 
+         // test dispatch
+@@ -591,11 +607,12 @@
+             target = maybeMoveIn(lookup, defc).findVirtual(defc, methodName, type);
+         } catch (ReflectiveOperationException ex) {
+             noAccess = ex;
++            assertExceptionClass(
++                (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>"))
++                ?   NoSuchMethodException.class
++                :   IllegalAccessException.class,
++                noAccess);
+             if (verbosity >= 5)  ex.printStackTrace(System.out);
+-            if (name.contains("bogus"))
+-                assertTrue(noAccess instanceof NoSuchMethodException);
+-            else
+-                assertTrue(noAccess instanceof IllegalAccessException);
+         }
+         if (verbosity >= 3)
+             System.out.println("findVirtual "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target
+@@ -632,11 +649,11 @@
+         testFindSpecial(SubExample.class, Example.class, void.class, "pkg_v0");
+         testFindSpecial(RemoteExample.class, PubExample.class, void.class, "Pub/pro_v0");
+         // Do some negative testing:
+-        testFindSpecial(false, EXAMPLE, SubExample.class, Example.class, void.class, "bogus");
+-        testFindSpecial(false, PRIVATE, SubExample.class, Example.class, void.class, "bogus");
+         for (Lookup lookup : new Lookup[]{ PRIVATE, EXAMPLE, PACKAGE, PUBLIC }) {
+             testFindSpecial(false, lookup, Object.class, Example.class, void.class, "v0");
++            testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "bogus");
+             testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "<init>", int.class);
++            testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "<init>", Void.class);
+             testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "s0");
+         }
+     }
+@@ -662,19 +679,25 @@
+         countTest(positive);
+         String methodName = name.substring(1 + name.indexOf('/'));  // foo/bar => foo
+         MethodType type = MethodType.methodType(ret, params);
++        Lookup specialLookup = maybeMoveIn(lookup, specialCaller);
++        boolean specialAccessOK = (specialLookup.lookupClass() == specialCaller &&
++                                   (specialLookup.lookupModes() & Lookup.PRIVATE) != 0);
+         MethodHandle target = null;
+         Exception noAccess = null;
+         try {
+             if (verbosity >= 4)  System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
+-            if (verbosity >= 5)  System.out.println("  lookup => "+maybeMoveIn(lookup, specialCaller));
+-            target = maybeMoveIn(lookup, specialCaller).findSpecial(defc, methodName, type, specialCaller);
++            if (verbosity >= 5)  System.out.println("  lookup => "+specialLookup);
++            target = specialLookup.findSpecial(defc, methodName, type, specialCaller);
+         } catch (ReflectiveOperationException ex) {
+             noAccess = ex;
++            assertExceptionClass(
++                (!specialAccessOK)  // this check should happen first
++                ?   IllegalAccessException.class
++                : (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>"))
++                ?   NoSuchMethodException.class
++                : IllegalAccessException.class,
++                noAccess);
+             if (verbosity >= 5)  ex.printStackTrace(System.out);
+-            if (name.contains("bogus"))
+-                assertTrue(noAccess instanceof NoSuchMethodException);
+-            else
+-                assertTrue(noAccess instanceof IllegalAccessException);
+         }
+         if (verbosity >= 3)
+             System.out.println("findSpecial from "+specialCaller.getName()+" to "+defc.getName()+"."+name+"/"+type+" => "+target
+@@ -719,7 +742,7 @@
+             target = lookup.findConstructor(defc, type);
+         } catch (ReflectiveOperationException ex) {
+             noAccess = ex;
+-            assertTrue(noAccess instanceof IllegalAccessException);
++            assertTrue(noAccess.getClass().getName(), noAccess instanceof IllegalAccessException);
+         }
+         if (verbosity >= 3)
+             System.out.println("findConstructor "+defc.getName()+".<init>/"+type+" => "+target
+@@ -750,6 +773,8 @@
+         testBind(Example.class, Object.class, "v2", int.class, Object.class);
+         testBind(Example.class, Object.class, "v2", int.class, int.class);
+         testBind(false, PRIVATE, Example.class, void.class, "bogus");
++        testBind(false, PRIVATE, Example.class, void.class, "<init>", int.class);
++        testBind(false, PRIVATE, Example.class, void.class, "<init>", Void.class);
+         testBind(SubExample.class, void.class, "Sub/v0");
+         testBind(SubExample.class, void.class, "Sub/pkg_v0");
+         testBind(IntExample.Impl.class, void.class, "Int/v0");
+@@ -773,11 +798,12 @@
+             target = maybeMoveIn(lookup, defc).bind(receiver, methodName, type);
+         } catch (ReflectiveOperationException ex) {
+             noAccess = ex;
++            assertExceptionClass(
++                (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>"))
++                ?   NoSuchMethodException.class
++                :   IllegalAccessException.class,
++                noAccess);
+             if (verbosity >= 5)  ex.printStackTrace(System.out);
+-            if (name.contains("bogus"))
+-                assertTrue(noAccess instanceof NoSuchMethodException);
+-            else
+-                assertTrue(noAccess instanceof IllegalAccessException);
+         }
+         if (verbosity >= 3)
+             System.out.println("bind "+receiver+"."+name+"/"+type+" => "+target
+@@ -840,6 +866,10 @@
+         countTest(positive);
+         String methodName = name.substring(1 + name.indexOf('/'));  // foo/bar => foo
+         MethodType type = MethodType.methodType(ret, params);
++        Lookup specialLookup = (specialCaller != null ? maybeMoveIn(lookup, specialCaller) : null);
++        boolean specialAccessOK = (specialCaller != null &&
++                                   specialLookup.lookupClass() == specialCaller &&
++                                   (specialLookup.lookupModes() & Lookup.PRIVATE) != 0);
+         Method rmethod = defc.getDeclaredMethod(methodName, params);
+         MethodHandle target = null;
+         Exception noAccess = null;
+@@ -848,16 +878,15 @@
+         try {
+             if (verbosity >= 4)  System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
+             if (isSpecial)
+-                target = maybeMoveIn(lookup, specialCaller).unreflectSpecial(rmethod, specialCaller);
++                target = specialLookup.unreflectSpecial(rmethod, specialCaller);
+             else
+                 target = maybeMoveIn(lookup, defc).unreflect(rmethod);
+         } catch (ReflectiveOperationException ex) {
+             noAccess = ex;
++            assertExceptionClass(
++                IllegalAccessException.class,  // NSME is impossible, since it was already reflected
++                noAccess);
+             if (verbosity >= 5)  ex.printStackTrace(System.out);
+-            if (name.contains("bogus"))
+-                assertTrue(noAccess instanceof NoSuchMethodException);
+-            else
+-                assertTrue(noAccess instanceof IllegalAccessException);
+         }
+         if (verbosity >= 3)
+             System.out.println("unreflect"+(isSpecial?"Special":"")+" "+defc.getName()+"."+name+"/"+type
+@@ -1091,11 +1120,12 @@
+         } catch (ReflectiveOperationException ex) {
+             mh = null;
+             noAccess = ex;
++            assertExceptionClass(
++                (fname.contains("bogus"))
++                ?   NoSuchFieldException.class
++                :   IllegalAccessException.class,
++                noAccess);
+             if (verbosity >= 5)  ex.printStackTrace(System.out);
+-            if (fname.contains("bogus"))
+-                assertTrue(noAccess instanceof NoSuchFieldException);
+-            else
+-                assertTrue(noAccess instanceof IllegalAccessException);
+         }
+         if (verbosity >= 3)
+             System.out.println("find"+(isStatic?"Static":"")+(isGetter?"Getter":"Setter")+" "+fclass.getName()+"."+fname+"/"+ftype
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/meth-spr-8001109.patch	Fri Sep 13 22:50:28 2013 -0700
@@ -0,0 +1,89 @@
+8001109: arity mismatch on a call to spreader method handle should elicit IllegalArgumentException
+Summary: Document error conditions that may occur when calling a "spreader" method handle.  Use IAE in all cases.
+Reviewed-by: ?
+
+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
+@@ -788,6 +788,10 @@
+      * to the target method handle.
+      * (The array may also be null when zero elements are required.)
+      * <p>
++     * If, when the adapter is called, the supplied array argument does
++     * not have the correct number of elements, the adapter will throw
++     * an {@link IllegalArgumentException} instead of invoking the target.
++     * <p>
+      * Here are some simple examples of array-spreading method handles:
+      * <blockquote><pre>{@code
+ MethodHandle equals = publicLookup()
+@@ -798,6 +802,12 @@
+ MethodHandle eq2 = equals.asSpreader(Object[].class, 2);
+ assert( (boolean) eq2.invokeExact(new Object[]{ "me", "me" }));
+ assert(!(boolean) eq2.invokeExact(new Object[]{ "me", "thee" }));
++// try to spread from anything but a 2-array:
++for (int n = 0; n <= 10; n++) {
++  Object[] badArityArgs = (n == 2 ? null : new Object[n]);
++  try { assert((boolean) eq2.invokeExact(badArityArgs) && false); }
++  catch (IllegalArgumentException ex) { } // OK
++}
+ // spread both arguments from a String array:
+ MethodHandle eq2s = equals.asSpreader(String[].class, 2);
+ assert( (boolean) eq2s.invokeExact(new String[]{ "me", "me" }));
+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
+@@ -459,14 +459,8 @@
+     }
+ 
+     static void checkSpreadArgument(Object av, int n) {
+-        // FIXME: regression test for bug 7141637 erroneously expects an NPE, and other tests may expect IAE
+-        // but the actual exception raised by an arity mismatch should be WMTE
+-        final boolean RAISE_RANDOM_EXCEPTIONS = true;  // FIXME: delete in JSR 292 M1
+         if (av == null) {
+             if (n == 0)  return;
+-            int len;
+-            if (RAISE_RANDOM_EXCEPTIONS)
+-                len = ((Object[])av).length;  // throw NPE; but delete this after tests are fixed
+         } else if (av instanceof Object[]) {
+             int len = ((Object[])av).length;
+             if (len == n)  return;
+@@ -475,9 +469,7 @@
+             if (len == n)  return;
+         }
+         // fall through to error:
+-        if (RAISE_RANDOM_EXCEPTIONS)
+-            throw newIllegalArgumentException("Array is not of length "+n);
+-        throw new WrongMethodTypeException("Array is not of length "+n);
++        throw newIllegalArgumentException("array is not of length "+n);
+     }
+ 
+     private static final NamedFunction NF_checkSpreadArgument;
+diff --git a/src/share/classes/java/lang/invoke/MethodHandles.java b/src/share/classes/java/lang/invoke/MethodHandles.java
+--- a/src/share/classes/java/lang/invoke/MethodHandles.java
++++ b/src/share/classes/java/lang/invoke/MethodHandles.java
+@@ -1434,6 +1434,9 @@
+      * <p>
+      * Before invoking its target, the invoker will spread the final array, apply
+      * reference casts as necessary, and unbox and widen primitive arguments.
++     * If, when the invoker is called, the supplied array argument does
++     * not have the correct number of elements, the invoker will throw
++     * an {@link IllegalArgumentException} instead of invoking the target.
+      * <p>
+      * This method is equivalent to the following code (though it may be more efficient):
+      * <p><blockquote><pre>
+diff --git a/test/java/lang/invoke/JavaDocExamplesTest.java b/test/java/lang/invoke/JavaDocExamplesTest.java
+--- a/test/java/lang/invoke/JavaDocExamplesTest.java
++++ b/test/java/lang/invoke/JavaDocExamplesTest.java
+@@ -275,6 +275,12 @@
+ MethodHandle eq2 = equals.asSpreader(Object[].class, 2);
+ assert( (boolean) eq2.invokeExact(new Object[]{ "me", "me" }));
+ assert(!(boolean) eq2.invokeExact(new Object[]{ "me", "thee" }));
++// try to spread from anything but a 2-array:
++for (int n = 0; n <= 10; n++) {
++  Object[] badArityArgs = (n == 2 ? null : new Object[n]);
++  try { assert((boolean) eq2.invokeExact(badArityArgs) && false); }
++  catch (IllegalArgumentException ex) { } // OK
++}
+ // spread both arguments from a String array:
+ MethodHandle eq2s = equals.asSpreader(String[].class, 2);
+ assert( (boolean) eq2s.invokeExact(new String[]{ "me", "me" }));