Invokers.java revision 11871:b41a4874ae5f
1243730Srwatson/*
2243730Srwatson * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
3243730Srwatson * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4243730Srwatson *
5243730Srwatson * This code is free software; you can redistribute it and/or modify it
6243730Srwatson * under the terms of the GNU General Public License version 2 only, as
7243730Srwatson * published by the Free Software Foundation.  Oracle designates this
8243730Srwatson * particular file as subject to the "Classpath" exception as provided
9243730Srwatson * by Oracle in the LICENSE file that accompanied this code.
10243730Srwatson *
11243730Srwatson * This code is distributed in the hope that it will be useful, but WITHOUT
12243730Srwatson * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13243730Srwatson * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14243730Srwatson * version 2 for more details (a copy is included in the LICENSE file that
15243730Srwatson * accompanied this code).
16243730Srwatson *
17243730Srwatson * You should have received a copy of the GNU General Public License version
18243730Srwatson * 2 along with this work; if not, write to the Free Software Foundation,
19243730Srwatson * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20243730Srwatson *
21243730Srwatson * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22243730Srwatson * or visit www.oracle.com if you need additional information or have any
23243730Srwatson * questions.
24243730Srwatson */
25243730Srwatson
26243730Srwatsonpackage java.lang.invoke;
27243730Srwatson
28243730Srwatsonimport java.lang.reflect.Array;
29243730Srwatsonimport java.util.Arrays;
30243730Srwatson
31243730Srwatsonimport static java.lang.invoke.MethodHandleStatics.*;
32243730Srwatsonimport static java.lang.invoke.MethodHandleNatives.Constants.*;
33243730Srwatsonimport static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
34243730Srwatsonimport static java.lang.invoke.LambdaForm.*;
35243730Srwatson
36243730Srwatson/**
37243730Srwatson * Construction and caching of often-used invokers.
38243730Srwatson * @author jrose
39243730Srwatson */
40243730Srwatsonclass Invokers {
41243730Srwatson    // exact type (sans leading target MH) for the outgoing call
42243730Srwatson    private final MethodType targetType;
43243730Srwatson
44243730Srwatson    // Cached adapter information:
45243730Srwatson    private final @Stable MethodHandle[] invokers = new MethodHandle[INV_LIMIT];
46243730Srwatson    // Indexes into invokers:
47243730Srwatson    static final int
48243730Srwatson            INV_EXACT          =  0,  // MethodHandles.exactInvoker
49243730Srwatson            INV_GENERIC        =  1,  // MethodHandles.invoker (generic invocation)
50243730Srwatson            INV_BASIC          =  2,  // MethodHandles.basicInvoker
51243730Srwatson            INV_LIMIT          =  3;
52243730Srwatson
53243730Srwatson    /** Compute and cache information common to all collecting adapters
54243730Srwatson     *  that implement members of the erasure-family of the given erased type.
55243730Srwatson     */
56243730Srwatson    /*non-public*/ Invokers(MethodType targetType) {
57243730Srwatson        this.targetType = targetType;
58243730Srwatson    }
59243730Srwatson
60243730Srwatson    /*non-public*/ MethodHandle exactInvoker() {
61243730Srwatson        MethodHandle invoker = cachedInvoker(INV_EXACT);
62243730Srwatson        if (invoker != null)  return invoker;
63243730Srwatson        invoker = makeExactOrGeneralInvoker(true);
64243730Srwatson        return setCachedInvoker(INV_EXACT, invoker);
65243730Srwatson    }
66243730Srwatson
67243730Srwatson    /*non-public*/ MethodHandle genericInvoker() {
68243730Srwatson        MethodHandle invoker = cachedInvoker(INV_GENERIC);
69243730Srwatson        if (invoker != null)  return invoker;
70243730Srwatson        invoker = makeExactOrGeneralInvoker(false);
71243730Srwatson        return setCachedInvoker(INV_GENERIC, invoker);
72243730Srwatson    }
73243730Srwatson
74243730Srwatson    /*non-public*/ MethodHandle basicInvoker() {
75243730Srwatson        MethodHandle invoker = cachedInvoker(INV_BASIC);
76243730Srwatson        if (invoker != null)  return invoker;
77243730Srwatson        MethodType basicType = targetType.basicType();
78243730Srwatson        if (basicType != targetType) {
79243730Srwatson            // double cache; not used significantly
80243730Srwatson            return setCachedInvoker(INV_BASIC, basicType.invokers().basicInvoker());
81243730Srwatson        }
82243730Srwatson        invoker = basicType.form().cachedMethodHandle(MethodTypeForm.MH_BASIC_INV);
83243730Srwatson        if (invoker == null) {
84243730Srwatson            MemberName method = invokeBasicMethod(basicType);
85243730Srwatson            invoker = DirectMethodHandle.make(method);
86243730Srwatson            assert(checkInvoker(invoker));
87243730Srwatson            invoker = basicType.form().setCachedMethodHandle(MethodTypeForm.MH_BASIC_INV, invoker);
88243730Srwatson        }
89243730Srwatson        return setCachedInvoker(INV_BASIC, invoker);
90243730Srwatson    }
91243730Srwatson
92243730Srwatson    private MethodHandle cachedInvoker(int idx) {
93243730Srwatson        return invokers[idx];
94243730Srwatson    }
95243730Srwatson
96243730Srwatson    private synchronized MethodHandle setCachedInvoker(int idx, final MethodHandle invoker) {
97243730Srwatson        // Simulate a CAS, to avoid racy duplication of results.
98243730Srwatson        MethodHandle prev = invokers[idx];
99243730Srwatson        if (prev != null)  return prev;
100243730Srwatson        return invokers[idx] = invoker;
101243730Srwatson    }
102243730Srwatson
103243730Srwatson    private MethodHandle makeExactOrGeneralInvoker(boolean isExact) {
104243730Srwatson        MethodType mtype = targetType;
105243730Srwatson        MethodType invokerType = mtype.invokerType();
106243730Srwatson        int which = (isExact ? MethodTypeForm.LF_EX_INVOKER : MethodTypeForm.LF_GEN_INVOKER);
107243730Srwatson        LambdaForm lform = invokeHandleForm(mtype, false, which);
108243730Srwatson        MethodHandle invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype);
109243730Srwatson        String whichName = (isExact ? "invokeExact" : "invoke");
110243730Srwatson        invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke(whichName, mtype), false);
111243730Srwatson        assert(checkInvoker(invoker));
112243730Srwatson        maybeCompileToBytecode(invoker);
113243730Srwatson        return invoker;
114243730Srwatson    }
115243730Srwatson
116243730Srwatson    /** If the target type seems to be common enough, eagerly compile the invoker to bytecodes. */
117243730Srwatson    private void maybeCompileToBytecode(MethodHandle invoker) {
118243730Srwatson        final int EAGER_COMPILE_ARITY_LIMIT = 10;
119243730Srwatson        if (targetType == targetType.erase() &&
120243730Srwatson            targetType.parameterCount() < EAGER_COMPILE_ARITY_LIMIT) {
121243730Srwatson            invoker.form.compileToBytecode();
122243730Srwatson        }
123243730Srwatson    }
124243730Srwatson
125243730Srwatson    // This next one is called from LambdaForm.NamedFunction.<init>.
126243730Srwatson    /*non-public*/ static MemberName invokeBasicMethod(MethodType basicType) {
127243730Srwatson        assert(basicType == basicType.basicType());
128243730Srwatson        try {
129243730Srwatson            //Lookup.findVirtual(MethodHandle.class, name, type);
130243730Srwatson            return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, "invokeBasic", basicType);
131243730Srwatson        } catch (ReflectiveOperationException ex) {
132243730Srwatson            throw newInternalError("JVM cannot find invoker for "+basicType, ex);
133243730Srwatson        }
134243730Srwatson    }
135243730Srwatson
136243730Srwatson    private boolean checkInvoker(MethodHandle invoker) {
137243730Srwatson        assert(targetType.invokerType().equals(invoker.type()))
138243730Srwatson                : java.util.Arrays.asList(targetType, targetType.invokerType(), invoker);
139243730Srwatson        assert(invoker.internalMemberName() == null ||
140243730Srwatson               invoker.internalMemberName().getMethodType().equals(targetType));
141243730Srwatson        assert(!invoker.isVarargsCollector());
142243730Srwatson        return true;
143243730Srwatson    }
144243730Srwatson
145243730Srwatson    /**
146243730Srwatson     * Find or create an invoker which passes unchanged a given number of arguments
147243730Srwatson     * and spreads the rest from a trailing array argument.
148243730Srwatson     * The invoker target type is the post-spread type {@code (TYPEOF(uarg*), TYPEOF(sarg*))=>RT}.
149243730Srwatson     * All the {@code sarg}s must have a common type {@code C}.  (If there are none, {@code Object} is assumed.}
150243730Srwatson     * @param leadingArgCount the number of unchanged (non-spread) arguments
151243730Srwatson     * @return {@code invoker.invokeExact(mh, uarg*, C[]{sarg*}) := (RT)mh.invoke(uarg*, sarg*)}
152243730Srwatson     */
153243730Srwatson    /*non-public*/ MethodHandle spreadInvoker(int leadingArgCount) {
154243730Srwatson        int spreadArgCount = targetType.parameterCount() - leadingArgCount;
155243730Srwatson        MethodType postSpreadType = targetType;
156243730Srwatson        Class<?> argArrayType = impliedRestargType(postSpreadType, leadingArgCount);
157243730Srwatson        if (postSpreadType.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY) {
158243730Srwatson            return genericInvoker().asSpreader(argArrayType, spreadArgCount);
159243730Srwatson        }
160243730Srwatson        // Cannot build a generic invoker here of type ginvoker.invoke(mh, a*[254]).
161243730Srwatson        // Instead, factor sinvoker.invoke(mh, a) into ainvoker.invoke(filter(mh), a)
162243730Srwatson        // where filter(mh) == mh.asSpreader(Object[], spreadArgCount)
163243730Srwatson        MethodType preSpreadType = postSpreadType
164243730Srwatson            .replaceParameterTypes(leadingArgCount, postSpreadType.parameterCount(), argArrayType);
165243730Srwatson        MethodHandle arrayInvoker = MethodHandles.invoker(preSpreadType);
166243730Srwatson        MethodHandle makeSpreader = MethodHandles.insertArguments(Lazy.MH_asSpreader, 1, argArrayType, spreadArgCount);
167243730Srwatson        return MethodHandles.filterArgument(arrayInvoker, 0, makeSpreader);
168243730Srwatson    }
169243730Srwatson
170243730Srwatson    private static Class<?> impliedRestargType(MethodType restargType, int fromPos) {
171243730Srwatson        if (restargType.isGeneric())  return Object[].class;  // can be nothing else
172243730Srwatson        int maxPos = restargType.parameterCount();
173243730Srwatson        if (fromPos >= maxPos)  return Object[].class;  // reasonable default
174243730Srwatson        Class<?> argType = restargType.parameterType(fromPos);
175243730Srwatson        for (int i = fromPos+1; i < maxPos; i++) {
176243730Srwatson            if (argType != restargType.parameterType(i))
177243730Srwatson                throw newIllegalArgumentException("need homogeneous rest arguments", restargType);
178243730Srwatson        }
179243730Srwatson        if (argType == Object.class)  return Object[].class;
180243730Srwatson        return Array.newInstance(argType, 0).getClass();
181243730Srwatson    }
182243730Srwatson
183243730Srwatson    public String toString() {
184243730Srwatson        return "Invokers"+targetType;
185243730Srwatson    }
186243730Srwatson
187243730Srwatson    static MemberName methodHandleInvokeLinkerMethod(String name,
188243730Srwatson                                                     MethodType mtype,
189                                                     Object[] appendixResult) {
190        int which;
191        switch (name) {
192        case "invokeExact":  which = MethodTypeForm.LF_EX_LINKER; break;
193        case "invoke":       which = MethodTypeForm.LF_GEN_LINKER; break;
194        default:             throw new InternalError("not invoker: "+name);
195        }
196        LambdaForm lform;
197        if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - MH_LINKER_ARG_APPENDED) {
198            lform = invokeHandleForm(mtype, false, which);
199            appendixResult[0] = mtype;
200        } else {
201            lform = invokeHandleForm(mtype, true, which);
202        }
203        return lform.vmentry;
204    }
205
206    // argument count to account for trailing "appendix value" (typically the mtype)
207    private static final int MH_LINKER_ARG_APPENDED = 1;
208
209    /** Returns an adapter for invokeExact or generic invoke, as a MH or constant pool linker.
210     * If !customized, caller is responsible for supplying, during adapter execution,
211     * a copy of the exact mtype.  This is because the adapter might be generalized to
212     * a basic type.
213     * @param mtype the caller's method type (either basic or full-custom)
214     * @param customized whether to use a trailing appendix argument (to carry the mtype)
215     * @param which bit-encoded 0x01 whether it is a CP adapter ("linker") or MHs.invoker value ("invoker");
216     *                          0x02 whether it is for invokeExact or generic invoke
217     */
218    private static LambdaForm invokeHandleForm(MethodType mtype, boolean customized, int which) {
219        boolean isCached;
220        if (!customized) {
221            mtype = mtype.basicType();  // normalize Z to I, String to Object, etc.
222            isCached = true;
223        } else {
224            isCached = false;  // maybe cache if mtype == mtype.basicType()
225        }
226        boolean isLinker, isGeneric;
227        String debugName;
228        switch (which) {
229        case MethodTypeForm.LF_EX_LINKER:   isLinker = true;  isGeneric = false; debugName = "invokeExact_MT"; break;
230        case MethodTypeForm.LF_EX_INVOKER:  isLinker = false; isGeneric = false; debugName = "exactInvoker"; break;
231        case MethodTypeForm.LF_GEN_LINKER:  isLinker = true;  isGeneric = true;  debugName = "invoke_MT"; break;
232        case MethodTypeForm.LF_GEN_INVOKER: isLinker = false; isGeneric = true;  debugName = "invoker"; break;
233        default: throw new InternalError();
234        }
235        LambdaForm lform;
236        if (isCached) {
237            lform = mtype.form().cachedLambdaForm(which);
238            if (lform != null)  return lform;
239        }
240        // exactInvokerForm (Object,Object)Object
241        //   link with java.lang.invoke.MethodHandle.invokeBasic(MethodHandle,Object,Object)Object/invokeSpecial
242        final int THIS_MH      = 0;
243        final int CALL_MH      = THIS_MH + (isLinker ? 0 : 1);
244        final int ARG_BASE     = CALL_MH + 1;
245        final int OUTARG_LIMIT = ARG_BASE + mtype.parameterCount();
246        final int INARG_LIMIT  = OUTARG_LIMIT + (isLinker && !customized ? 1 : 0);
247        int nameCursor = OUTARG_LIMIT;
248        final int MTYPE_ARG    = customized ? -1 : nameCursor++;  // might be last in-argument
249        final int CHECK_TYPE   = nameCursor++;
250        final int CHECK_CUSTOM = (CUSTOMIZE_THRESHOLD >= 0) ? nameCursor++ : -1;
251        final int LINKER_CALL  = nameCursor++;
252        MethodType invokerFormType = mtype.invokerType();
253        if (isLinker) {
254            if (!customized)
255                invokerFormType = invokerFormType.appendParameterTypes(MemberName.class);
256        } else {
257            invokerFormType = invokerFormType.invokerType();
258        }
259        Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType);
260        assert(names.length == nameCursor)
261                : Arrays.asList(mtype, customized, which, nameCursor, names.length);
262        if (MTYPE_ARG >= INARG_LIMIT) {
263            assert(names[MTYPE_ARG] == null);
264            BoundMethodHandle.SpeciesData speciesData = BoundMethodHandle.speciesData_L();
265            names[THIS_MH] = names[THIS_MH].withConstraint(speciesData);
266            NamedFunction getter = speciesData.getterFunction(0);
267            names[MTYPE_ARG] = new Name(getter, names[THIS_MH]);
268            // else if isLinker, then MTYPE is passed in from the caller (e.g., the JVM)
269        }
270
271        // Make the final call.  If isGeneric, then prepend the result of type checking.
272        MethodType outCallType = mtype.basicType();
273        Object[] outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT, Object[].class);
274        Object mtypeArg = (customized ? mtype : names[MTYPE_ARG]);
275        if (!isGeneric) {
276            names[CHECK_TYPE] = new Name(NF_checkExactType, names[CALL_MH], mtypeArg);
277            // mh.invokeExact(a*):R => checkExactType(mh, TYPEOF(a*:R)); mh.invokeBasic(a*)
278        } else {
279            names[CHECK_TYPE] = new Name(NF_checkGenericType, names[CALL_MH], mtypeArg);
280            // mh.invokeGeneric(a*):R => checkGenericType(mh, TYPEOF(a*:R)).invokeBasic(a*)
281            outArgs[0] = names[CHECK_TYPE];
282        }
283        if (CHECK_CUSTOM != -1) {
284            names[CHECK_CUSTOM] = new Name(NF_checkCustomized, outArgs[0]);
285        }
286        names[LINKER_CALL] = new Name(outCallType, outArgs);
287        lform = new LambdaForm(debugName, INARG_LIMIT, names);
288        if (isLinker)
289            lform.compileToBytecode();  // JVM needs a real methodOop
290        if (isCached)
291            lform = mtype.form().setCachedLambdaForm(which, lform);
292        return lform;
293    }
294
295    /*non-public*/ static
296    WrongMethodTypeException newWrongMethodTypeException(MethodType actual, MethodType expected) {
297        // FIXME: merge with JVM logic for throwing WMTE
298        return new WrongMethodTypeException("expected "+expected+" but found "+actual);
299    }
300
301    /** Static definition of MethodHandle.invokeExact checking code. */
302    /*non-public*/ static
303    @ForceInline
304    void checkExactType(Object mhObj, Object expectedObj) {
305        MethodHandle mh = (MethodHandle) mhObj;
306        MethodType expected = (MethodType) expectedObj;
307        MethodType actual = mh.type();
308        if (actual != expected)
309            throw newWrongMethodTypeException(expected, actual);
310    }
311
312    /** Static definition of MethodHandle.invokeGeneric checking code.
313     * Directly returns the type-adjusted MH to invoke, as follows:
314     * {@code (R)MH.invoke(a*) => MH.asType(TYPEOF(a*:R)).invokeBasic(a*)}
315     */
316    /*non-public*/ static
317    @ForceInline
318    Object checkGenericType(Object mhObj, Object expectedObj) {
319        MethodHandle mh = (MethodHandle) mhObj;
320        MethodType expected = (MethodType) expectedObj;
321        return mh.asType(expected);
322        /* Maybe add more paths here.  Possible optimizations:
323         * for (R)MH.invoke(a*),
324         * let MT0 = TYPEOF(a*:R), MT1 = MH.type
325         *
326         * if MT0==MT1 or MT1 can be safely called by MT0
327         *  => MH.invokeBasic(a*)
328         * if MT1 can be safely called by MT0[R := Object]
329         *  => MH.invokeBasic(a*) & checkcast(R)
330         * if MT1 can be safely called by MT0[* := Object]
331         *  => checkcast(A)* & MH.invokeBasic(a*) & checkcast(R)
332         * if a big adapter BA can be pulled out of (MT0,MT1)
333         *  => BA.invokeBasic(MT0,MH,a*)
334         * if a local adapter LA can cached on static CS0 = new GICS(MT0)
335         *  => CS0.LA.invokeBasic(MH,a*)
336         * else
337         *  => MH.asType(MT0).invokeBasic(A*)
338         */
339    }
340
341    static MemberName linkToCallSiteMethod(MethodType mtype) {
342        LambdaForm lform = callSiteForm(mtype, false);
343        return lform.vmentry;
344    }
345
346    static MemberName linkToTargetMethod(MethodType mtype) {
347        LambdaForm lform = callSiteForm(mtype, true);
348        return lform.vmentry;
349    }
350
351    // skipCallSite is true if we are optimizing a ConstantCallSite
352    private static LambdaForm callSiteForm(MethodType mtype, boolean skipCallSite) {
353        mtype = mtype.basicType();  // normalize Z to I, String to Object, etc.
354        final int which = (skipCallSite ? MethodTypeForm.LF_MH_LINKER : MethodTypeForm.LF_CS_LINKER);
355        LambdaForm lform = mtype.form().cachedLambdaForm(which);
356        if (lform != null)  return lform;
357        // exactInvokerForm (Object,Object)Object
358        //   link with java.lang.invoke.MethodHandle.invokeBasic(MethodHandle,Object,Object)Object/invokeSpecial
359        final int ARG_BASE     = 0;
360        final int OUTARG_LIMIT = ARG_BASE + mtype.parameterCount();
361        final int INARG_LIMIT  = OUTARG_LIMIT + 1;
362        int nameCursor = OUTARG_LIMIT;
363        final int APPENDIX_ARG = nameCursor++;  // the last in-argument
364        final int CSITE_ARG    = skipCallSite ? -1 : APPENDIX_ARG;
365        final int CALL_MH      = skipCallSite ? APPENDIX_ARG : nameCursor++;  // result of getTarget
366        final int LINKER_CALL  = nameCursor++;
367        MethodType invokerFormType = mtype.appendParameterTypes(skipCallSite ? MethodHandle.class : CallSite.class);
368        Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType);
369        assert(names.length == nameCursor);
370        assert(names[APPENDIX_ARG] != null);
371        if (!skipCallSite)
372            names[CALL_MH] = new Name(NF_getCallSiteTarget, names[CSITE_ARG]);
373        // (site.)invokedynamic(a*):R => mh = site.getTarget(); mh.invokeBasic(a*)
374        final int PREPEND_MH = 0, PREPEND_COUNT = 1;
375        Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, OUTARG_LIMIT + PREPEND_COUNT, Object[].class);
376        // prepend MH argument:
377        System.arraycopy(outArgs, 0, outArgs, PREPEND_COUNT, outArgs.length - PREPEND_COUNT);
378        outArgs[PREPEND_MH] = names[CALL_MH];
379        names[LINKER_CALL] = new Name(mtype, outArgs);
380        lform = new LambdaForm((skipCallSite ? "linkToTargetMethod" : "linkToCallSite"), INARG_LIMIT, names);
381        lform.compileToBytecode();  // JVM needs a real methodOop
382        lform = mtype.form().setCachedLambdaForm(which, lform);
383        return lform;
384    }
385
386    /** Static definition of MethodHandle.invokeGeneric checking code. */
387    /*non-public*/ static
388    @ForceInline
389    Object getCallSiteTarget(Object site) {
390        return ((CallSite)site).getTarget();
391    }
392
393    /*non-public*/ static
394    @ForceInline
395    void checkCustomized(Object o) {
396        MethodHandle mh = (MethodHandle)o;
397        if (MethodHandleImpl.isCompileConstant(mh)) return;
398        if (mh.form.customized == null) {
399            maybeCustomize(mh);
400        }
401    }
402
403    /*non-public*/ static
404    @DontInline
405    void maybeCustomize(MethodHandle mh) {
406        byte count = mh.customizationCount;
407        if (count >= CUSTOMIZE_THRESHOLD) {
408            mh.customize();
409        } else {
410            mh.customizationCount = (byte)(count+1);
411        }
412    }
413
414    // Local constant functions:
415    private static final NamedFunction
416        NF_checkExactType,
417        NF_checkGenericType,
418        NF_getCallSiteTarget,
419        NF_checkCustomized;
420    static {
421        try {
422            NamedFunction nfs[] = {
423                NF_checkExactType = new NamedFunction(Invokers.class
424                        .getDeclaredMethod("checkExactType", Object.class, Object.class)),
425                NF_checkGenericType = new NamedFunction(Invokers.class
426                        .getDeclaredMethod("checkGenericType", Object.class, Object.class)),
427                NF_getCallSiteTarget = new NamedFunction(Invokers.class
428                        .getDeclaredMethod("getCallSiteTarget", Object.class)),
429                NF_checkCustomized = new NamedFunction(Invokers.class
430                        .getDeclaredMethod("checkCustomized", Object.class))
431            };
432            for (NamedFunction nf : nfs) {
433                // Each nf must be statically invocable or we get tied up in our bootstraps.
434                assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf.member)) : nf;
435                nf.resolve();
436            }
437        } catch (ReflectiveOperationException ex) {
438            throw newInternalError(ex);
439        }
440    }
441
442    private static class Lazy {
443        private static final MethodHandle MH_asSpreader;
444
445        static {
446            try {
447                MH_asSpreader = IMPL_LOOKUP.findVirtual(MethodHandle.class, "asSpreader",
448                        MethodType.methodType(MethodHandle.class, Class.class, int.class));
449            } catch (ReflectiveOperationException ex) {
450                throw newInternalError(ex);
451            }
452        }
453    }
454}
455