rt/emul/compact/src/main/java/java/lang/invoke/Invokers.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sat, 09 Aug 2014 11:11:13 +0200
branchjdk8-b132
changeset 1646 c880a8a8803b
permissions -rw-r--r--
Batch of classes necessary to implement invoke dynamic interfaces. Taken from JDK8 build 132
jaroslav@1646
     1
/*
jaroslav@1646
     2
 * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
jaroslav@1646
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jaroslav@1646
     4
 *
jaroslav@1646
     5
 * This code is free software; you can redistribute it and/or modify it
jaroslav@1646
     6
 * under the terms of the GNU General Public License version 2 only, as
jaroslav@1646
     7
 * published by the Free Software Foundation.  Oracle designates this
jaroslav@1646
     8
 * particular file as subject to the "Classpath" exception as provided
jaroslav@1646
     9
 * by Oracle in the LICENSE file that accompanied this code.
jaroslav@1646
    10
 *
jaroslav@1646
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
jaroslav@1646
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jaroslav@1646
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
jaroslav@1646
    14
 * version 2 for more details (a copy is included in the LICENSE file that
jaroslav@1646
    15
 * accompanied this code).
jaroslav@1646
    16
 *
jaroslav@1646
    17
 * You should have received a copy of the GNU General Public License version
jaroslav@1646
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
jaroslav@1646
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jaroslav@1646
    20
 *
jaroslav@1646
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jaroslav@1646
    22
 * or visit www.oracle.com if you need additional information or have any
jaroslav@1646
    23
 * questions.
jaroslav@1646
    24
 */
jaroslav@1646
    25
jaroslav@1646
    26
package java.lang.invoke;
jaroslav@1646
    27
jaroslav@1646
    28
import java.util.Arrays;
jaroslav@1646
    29
import sun.invoke.empty.Empty;
jaroslav@1646
    30
import static java.lang.invoke.MethodHandleStatics.*;
jaroslav@1646
    31
import static java.lang.invoke.MethodHandleNatives.Constants.*;
jaroslav@1646
    32
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
jaroslav@1646
    33
import static java.lang.invoke.LambdaForm.*;
jaroslav@1646
    34
jaroslav@1646
    35
/**
jaroslav@1646
    36
 * Construction and caching of often-used invokers.
jaroslav@1646
    37
 * @author jrose
jaroslav@1646
    38
 */
jaroslav@1646
    39
class Invokers {
jaroslav@1646
    40
    // exact type (sans leading taget MH) for the outgoing call
jaroslav@1646
    41
    private final MethodType targetType;
jaroslav@1646
    42
jaroslav@1646
    43
    // FIXME: Get rid of the invokers that are not useful.
jaroslav@1646
    44
jaroslav@1646
    45
    // exact invoker for the outgoing call
jaroslav@1646
    46
    private /*lazy*/ MethodHandle exactInvoker;
jaroslav@1646
    47
    private /*lazy*/ MethodHandle basicInvoker;  // invokeBasic (unchecked exact)
jaroslav@1646
    48
jaroslav@1646
    49
    // erased (partially untyped but with primitives) invoker for the outgoing call
jaroslav@1646
    50
    // FIXME: get rid of
jaroslav@1646
    51
    private /*lazy*/ MethodHandle erasedInvoker;
jaroslav@1646
    52
    // FIXME: get rid of
jaroslav@1646
    53
    /*lazy*/ MethodHandle erasedInvokerWithDrops;  // for InvokeGeneric
jaroslav@1646
    54
jaroslav@1646
    55
    // general invoker for the outgoing call
jaroslav@1646
    56
    private /*lazy*/ MethodHandle generalInvoker;
jaroslav@1646
    57
jaroslav@1646
    58
    // general invoker for the outgoing call, uses varargs
jaroslav@1646
    59
    private /*lazy*/ MethodHandle varargsInvoker;
jaroslav@1646
    60
jaroslav@1646
    61
    // general invoker for the outgoing call; accepts a trailing Object[]
jaroslav@1646
    62
    private final /*lazy*/ MethodHandle[] spreadInvokers;
jaroslav@1646
    63
jaroslav@1646
    64
    // invoker for an unbound callsite
jaroslav@1646
    65
    private /*lazy*/ MethodHandle uninitializedCallSite;
jaroslav@1646
    66
jaroslav@1646
    67
    /** Compute and cache information common to all collecting adapters
jaroslav@1646
    68
     *  that implement members of the erasure-family of the given erased type.
jaroslav@1646
    69
     */
jaroslav@1646
    70
    /*non-public*/ Invokers(MethodType targetType) {
jaroslav@1646
    71
        this.targetType = targetType;
jaroslav@1646
    72
        this.spreadInvokers = new MethodHandle[targetType.parameterCount()+1];
jaroslav@1646
    73
    }
jaroslav@1646
    74
jaroslav@1646
    75
    /*non-public*/ MethodHandle exactInvoker() {
jaroslav@1646
    76
        MethodHandle invoker = exactInvoker;
jaroslav@1646
    77
        if (invoker != null)  return invoker;
jaroslav@1646
    78
        invoker = makeExactOrGeneralInvoker(true);
jaroslav@1646
    79
        exactInvoker = invoker;
jaroslav@1646
    80
        return invoker;
jaroslav@1646
    81
    }
jaroslav@1646
    82
jaroslav@1646
    83
    /*non-public*/ MethodHandle generalInvoker() {
jaroslav@1646
    84
        MethodHandle invoker = generalInvoker;
jaroslav@1646
    85
        if (invoker != null)  return invoker;
jaroslav@1646
    86
        invoker = makeExactOrGeneralInvoker(false);
jaroslav@1646
    87
        generalInvoker = invoker;
jaroslav@1646
    88
        return invoker;
jaroslav@1646
    89
    }
jaroslav@1646
    90
jaroslav@1646
    91
    private MethodHandle makeExactOrGeneralInvoker(boolean isExact) {
jaroslav@1646
    92
        MethodType mtype = targetType;
jaroslav@1646
    93
        MethodType invokerType = mtype.invokerType();
jaroslav@1646
    94
        int which = (isExact ? MethodTypeForm.LF_EX_INVOKER : MethodTypeForm.LF_GEN_INVOKER);
jaroslav@1646
    95
        LambdaForm lform = invokeHandleForm(mtype, false, which);
jaroslav@1646
    96
        MethodHandle invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype);
jaroslav@1646
    97
        String whichName = (isExact ? "invokeExact" : "invoke");
jaroslav@1646
    98
        invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke(whichName, mtype));
jaroslav@1646
    99
        assert(checkInvoker(invoker));
jaroslav@1646
   100
        maybeCompileToBytecode(invoker);
jaroslav@1646
   101
        return invoker;
jaroslav@1646
   102
    }
jaroslav@1646
   103
jaroslav@1646
   104
    /** If the target type seems to be common enough, eagerly compile the invoker to bytecodes. */
jaroslav@1646
   105
    private void maybeCompileToBytecode(MethodHandle invoker) {
jaroslav@1646
   106
        final int EAGER_COMPILE_ARITY_LIMIT = 10;
jaroslav@1646
   107
        if (targetType == targetType.erase() &&
jaroslav@1646
   108
            targetType.parameterCount() < EAGER_COMPILE_ARITY_LIMIT) {
jaroslav@1646
   109
            invoker.form.compileToBytecode();
jaroslav@1646
   110
        }
jaroslav@1646
   111
    }
jaroslav@1646
   112
jaroslav@1646
   113
    /*non-public*/ MethodHandle basicInvoker() {
jaroslav@1646
   114
        MethodHandle invoker = basicInvoker;
jaroslav@1646
   115
        if (invoker != null)  return invoker;
jaroslav@1646
   116
        MethodType basicType = targetType.basicType();
jaroslav@1646
   117
        if (basicType != targetType) {
jaroslav@1646
   118
            // double cache; not used significantly
jaroslav@1646
   119
            return basicInvoker = basicType.invokers().basicInvoker();
jaroslav@1646
   120
        }
jaroslav@1646
   121
        MemberName method = invokeBasicMethod(basicType);
jaroslav@1646
   122
        invoker = DirectMethodHandle.make(method);
jaroslav@1646
   123
        assert(checkInvoker(invoker));
jaroslav@1646
   124
        basicInvoker = invoker;
jaroslav@1646
   125
        return invoker;
jaroslav@1646
   126
    }
jaroslav@1646
   127
jaroslav@1646
   128
    // This next one is called from LambdaForm.NamedFunction.<init>.
jaroslav@1646
   129
    /*non-public*/ static MemberName invokeBasicMethod(MethodType basicType) {
jaroslav@1646
   130
        assert(basicType == basicType.basicType());
jaroslav@1646
   131
        try {
jaroslav@1646
   132
            //Lookup.findVirtual(MethodHandle.class, name, type);
jaroslav@1646
   133
            return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, "invokeBasic", basicType);
jaroslav@1646
   134
        } catch (ReflectiveOperationException ex) {
jaroslav@1646
   135
            throw newInternalError("JVM cannot find invoker for "+basicType, ex);
jaroslav@1646
   136
        }
jaroslav@1646
   137
    }
jaroslav@1646
   138
jaroslav@1646
   139
    private boolean checkInvoker(MethodHandle invoker) {
jaroslav@1646
   140
        assert(targetType.invokerType().equals(invoker.type()))
jaroslav@1646
   141
                : java.util.Arrays.asList(targetType, targetType.invokerType(), invoker);
jaroslav@1646
   142
        assert(invoker.internalMemberName() == null ||
jaroslav@1646
   143
               invoker.internalMemberName().getMethodType().equals(targetType));
jaroslav@1646
   144
        assert(!invoker.isVarargsCollector());
jaroslav@1646
   145
        return true;
jaroslav@1646
   146
    }
jaroslav@1646
   147
jaroslav@1646
   148
    // FIXME: get rid of
jaroslav@1646
   149
    /*non-public*/ MethodHandle erasedInvoker() {
jaroslav@1646
   150
        MethodHandle xinvoker = exactInvoker();
jaroslav@1646
   151
        MethodHandle invoker = erasedInvoker;
jaroslav@1646
   152
        if (invoker != null)  return invoker;
jaroslav@1646
   153
        MethodType erasedType = targetType.erase();
jaroslav@1646
   154
        invoker = xinvoker.asType(erasedType.invokerType());
jaroslav@1646
   155
        erasedInvoker = invoker;
jaroslav@1646
   156
        return invoker;
jaroslav@1646
   157
    }
jaroslav@1646
   158
jaroslav@1646
   159
    /*non-public*/ MethodHandle spreadInvoker(int leadingArgCount) {
jaroslav@1646
   160
        MethodHandle vaInvoker = spreadInvokers[leadingArgCount];
jaroslav@1646
   161
        if (vaInvoker != null)  return vaInvoker;
jaroslav@1646
   162
        int spreadArgCount = targetType.parameterCount() - leadingArgCount;
jaroslav@1646
   163
        MethodType spreadInvokerType = targetType
jaroslav@1646
   164
            .replaceParameterTypes(leadingArgCount, targetType.parameterCount(), Object[].class);
jaroslav@1646
   165
        if (targetType.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY) {
jaroslav@1646
   166
            // Factor sinvoker.invoke(mh, a) into ginvoker.asSpreader().invoke(mh, a)
jaroslav@1646
   167
            // where ginvoker.invoke(mh, a*) => mh.invoke(a*).
jaroslav@1646
   168
            MethodHandle genInvoker = generalInvoker();
jaroslav@1646
   169
            vaInvoker = genInvoker.asSpreader(Object[].class, spreadArgCount);
jaroslav@1646
   170
        } else {
jaroslav@1646
   171
            // Cannot build a general invoker here of type ginvoker.invoke(mh, a*[254]).
jaroslav@1646
   172
            // Instead, factor sinvoker.invoke(mh, a) into ainvoker.invoke(filter(mh), a)
jaroslav@1646
   173
            // where filter(mh) == mh.asSpreader(Object[], spreadArgCount)
jaroslav@1646
   174
            MethodHandle arrayInvoker = MethodHandles.exactInvoker(spreadInvokerType);
jaroslav@1646
   175
            MethodHandle makeSpreader;
jaroslav@1646
   176
            try {
jaroslav@1646
   177
                makeSpreader = IMPL_LOOKUP
jaroslav@1646
   178
                    .findVirtual(MethodHandle.class, "asSpreader",
jaroslav@1646
   179
                        MethodType.methodType(MethodHandle.class, Class.class, int.class));
jaroslav@1646
   180
            } catch (ReflectiveOperationException ex) {
jaroslav@1646
   181
                throw newInternalError(ex);
jaroslav@1646
   182
            }
jaroslav@1646
   183
            makeSpreader = MethodHandles.insertArguments(makeSpreader, 1, Object[].class, spreadArgCount);
jaroslav@1646
   184
            vaInvoker = MethodHandles.filterArgument(arrayInvoker, 0, makeSpreader);
jaroslav@1646
   185
        }
jaroslav@1646
   186
        assert(vaInvoker.type().equals(spreadInvokerType.invokerType()));
jaroslav@1646
   187
        maybeCompileToBytecode(vaInvoker);
jaroslav@1646
   188
        spreadInvokers[leadingArgCount] = vaInvoker;
jaroslav@1646
   189
        return vaInvoker;
jaroslav@1646
   190
    }
jaroslav@1646
   191
jaroslav@1646
   192
    /*non-public*/ MethodHandle varargsInvoker() {
jaroslav@1646
   193
        MethodHandle vaInvoker = varargsInvoker;
jaroslav@1646
   194
        if (vaInvoker != null)  return vaInvoker;
jaroslav@1646
   195
        vaInvoker = spreadInvoker(0).asType(MethodType.genericMethodType(0, true).invokerType());
jaroslav@1646
   196
        varargsInvoker = vaInvoker;
jaroslav@1646
   197
        return vaInvoker;
jaroslav@1646
   198
    }
jaroslav@1646
   199
jaroslav@1646
   200
    private static MethodHandle THROW_UCS = null;
jaroslav@1646
   201
jaroslav@1646
   202
    /*non-public*/ MethodHandle uninitializedCallSite() {
jaroslav@1646
   203
        MethodHandle invoker = uninitializedCallSite;
jaroslav@1646
   204
        if (invoker != null)  return invoker;
jaroslav@1646
   205
        if (targetType.parameterCount() > 0) {
jaroslav@1646
   206
            MethodType type0 = targetType.dropParameterTypes(0, targetType.parameterCount());
jaroslav@1646
   207
            Invokers invokers0 = type0.invokers();
jaroslav@1646
   208
            invoker = MethodHandles.dropArguments(invokers0.uninitializedCallSite(),
jaroslav@1646
   209
                                                  0, targetType.parameterList());
jaroslav@1646
   210
            assert(invoker.type().equals(targetType));
jaroslav@1646
   211
            uninitializedCallSite = invoker;
jaroslav@1646
   212
            return invoker;
jaroslav@1646
   213
        }
jaroslav@1646
   214
        invoker = THROW_UCS;
jaroslav@1646
   215
        if (invoker == null) {
jaroslav@1646
   216
            try {
jaroslav@1646
   217
                THROW_UCS = invoker = IMPL_LOOKUP
jaroslav@1646
   218
                    .findStatic(CallSite.class, "uninitializedCallSite",
jaroslav@1646
   219
                                MethodType.methodType(Empty.class));
jaroslav@1646
   220
            } catch (ReflectiveOperationException ex) {
jaroslav@1646
   221
                throw newInternalError(ex);
jaroslav@1646
   222
            }
jaroslav@1646
   223
        }
jaroslav@1646
   224
        invoker = MethodHandles.explicitCastArguments(invoker, MethodType.methodType(targetType.returnType()));
jaroslav@1646
   225
        invoker = invoker.dropArguments(targetType, 0, targetType.parameterCount());
jaroslav@1646
   226
        assert(invoker.type().equals(targetType));
jaroslav@1646
   227
        uninitializedCallSite = invoker;
jaroslav@1646
   228
        return invoker;
jaroslav@1646
   229
    }
jaroslav@1646
   230
jaroslav@1646
   231
    public String toString() {
jaroslav@1646
   232
        return "Invokers"+targetType;
jaroslav@1646
   233
    }
jaroslav@1646
   234
jaroslav@1646
   235
    static MemberName methodHandleInvokeLinkerMethod(String name,
jaroslav@1646
   236
                                                     MethodType mtype,
jaroslav@1646
   237
                                                     Object[] appendixResult) {
jaroslav@1646
   238
        int which;
jaroslav@1646
   239
        switch (name) {
jaroslav@1646
   240
        case "invokeExact":  which = MethodTypeForm.LF_EX_LINKER; break;
jaroslav@1646
   241
        case "invoke":       which = MethodTypeForm.LF_GEN_LINKER; break;
jaroslav@1646
   242
        default:             throw new InternalError("not invoker: "+name);
jaroslav@1646
   243
        }
jaroslav@1646
   244
        LambdaForm lform;
jaroslav@1646
   245
        if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - MH_LINKER_ARG_APPENDED) {
jaroslav@1646
   246
            lform = invokeHandleForm(mtype, false, which);
jaroslav@1646
   247
            appendixResult[0] = mtype;
jaroslav@1646
   248
        } else {
jaroslav@1646
   249
            lform = invokeHandleForm(mtype, true, which);
jaroslav@1646
   250
        }
jaroslav@1646
   251
        return lform.vmentry;
jaroslav@1646
   252
    }
jaroslav@1646
   253
jaroslav@1646
   254
    // argument count to account for trailing "appendix value" (typically the mtype)
jaroslav@1646
   255
    private static final int MH_LINKER_ARG_APPENDED = 1;
jaroslav@1646
   256
jaroslav@1646
   257
    /** Returns an adapter for invokeExact or generic invoke, as a MH or constant pool linker.
jaroslav@1646
   258
     * If !customized, caller is responsible for supplying, during adapter execution,
jaroslav@1646
   259
     * a copy of the exact mtype.  This is because the adapter might be generalized to
jaroslav@1646
   260
     * a basic type.
jaroslav@1646
   261
     * @param mtype the caller's method type (either basic or full-custom)
jaroslav@1646
   262
     * @param customized whether to use a trailing appendix argument (to carry the mtype)
jaroslav@1646
   263
     * @param which bit-encoded 0x01 whether it is a CP adapter ("linker") or MHs.invoker value ("invoker");
jaroslav@1646
   264
     *                          0x02 whether it is for invokeExact or generic invoke
jaroslav@1646
   265
     */
jaroslav@1646
   266
    private static LambdaForm invokeHandleForm(MethodType mtype, boolean customized, int which) {
jaroslav@1646
   267
        boolean isCached;
jaroslav@1646
   268
        if (!customized) {
jaroslav@1646
   269
            mtype = mtype.basicType();  // normalize Z to I, String to Object, etc.
jaroslav@1646
   270
            isCached = true;
jaroslav@1646
   271
        } else {
jaroslav@1646
   272
            isCached = false;  // maybe cache if mtype == mtype.basicType()
jaroslav@1646
   273
        }
jaroslav@1646
   274
        boolean isLinker, isGeneric;
jaroslav@1646
   275
        String debugName;
jaroslav@1646
   276
        switch (which) {
jaroslav@1646
   277
        case MethodTypeForm.LF_EX_LINKER:   isLinker = true;  isGeneric = false; debugName = "invokeExact_MT"; break;
jaroslav@1646
   278
        case MethodTypeForm.LF_EX_INVOKER:  isLinker = false; isGeneric = false; debugName = "exactInvoker"; break;
jaroslav@1646
   279
        case MethodTypeForm.LF_GEN_LINKER:  isLinker = true;  isGeneric = true;  debugName = "invoke_MT"; break;
jaroslav@1646
   280
        case MethodTypeForm.LF_GEN_INVOKER: isLinker = false; isGeneric = true;  debugName = "invoker"; break;
jaroslav@1646
   281
        default: throw new InternalError();
jaroslav@1646
   282
        }
jaroslav@1646
   283
        LambdaForm lform;
jaroslav@1646
   284
        if (isCached) {
jaroslav@1646
   285
            lform = mtype.form().cachedLambdaForm(which);
jaroslav@1646
   286
            if (lform != null)  return lform;
jaroslav@1646
   287
        }
jaroslav@1646
   288
        // exactInvokerForm (Object,Object)Object
jaroslav@1646
   289
        //   link with java.lang.invoke.MethodHandle.invokeBasic(MethodHandle,Object,Object)Object/invokeSpecial
jaroslav@1646
   290
        final int THIS_MH      = 0;
jaroslav@1646
   291
        final int CALL_MH      = THIS_MH + (isLinker ? 0 : 1);
jaroslav@1646
   292
        final int ARG_BASE     = CALL_MH + 1;
jaroslav@1646
   293
        final int OUTARG_LIMIT = ARG_BASE + mtype.parameterCount();
jaroslav@1646
   294
        final int INARG_LIMIT  = OUTARG_LIMIT + (isLinker && !customized ? 1 : 0);
jaroslav@1646
   295
        int nameCursor = OUTARG_LIMIT;
jaroslav@1646
   296
        final int MTYPE_ARG    = customized ? -1 : nameCursor++;  // might be last in-argument
jaroslav@1646
   297
        final int CHECK_TYPE   = nameCursor++;
jaroslav@1646
   298
        final int LINKER_CALL  = nameCursor++;
jaroslav@1646
   299
        MethodType invokerFormType = mtype.invokerType();
jaroslav@1646
   300
        if (isLinker) {
jaroslav@1646
   301
            if (!customized)
jaroslav@1646
   302
                invokerFormType = invokerFormType.appendParameterTypes(MemberName.class);
jaroslav@1646
   303
        } else {
jaroslav@1646
   304
            invokerFormType = invokerFormType.invokerType();
jaroslav@1646
   305
        }
jaroslav@1646
   306
        Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType);
jaroslav@1646
   307
        assert(names.length == nameCursor)
jaroslav@1646
   308
                : Arrays.asList(mtype, customized, which, nameCursor, names.length);
jaroslav@1646
   309
        if (MTYPE_ARG >= INARG_LIMIT) {
jaroslav@1646
   310
            assert(names[MTYPE_ARG] == null);
jaroslav@1646
   311
            NamedFunction getter = BoundMethodHandle.getSpeciesData("L").getterFunction(0);
jaroslav@1646
   312
            names[MTYPE_ARG] = new Name(getter, names[THIS_MH]);
jaroslav@1646
   313
            // else if isLinker, then MTYPE is passed in from the caller (e.g., the JVM)
jaroslav@1646
   314
        }
jaroslav@1646
   315
jaroslav@1646
   316
        // Make the final call.  If isGeneric, then prepend the result of type checking.
jaroslav@1646
   317
        MethodType outCallType = mtype.basicType();
jaroslav@1646
   318
        Object[] outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT, Object[].class);
jaroslav@1646
   319
        Object mtypeArg = (customized ? mtype : names[MTYPE_ARG]);
jaroslav@1646
   320
        if (!isGeneric) {
jaroslav@1646
   321
            names[CHECK_TYPE] = new Name(NF_checkExactType, names[CALL_MH], mtypeArg);
jaroslav@1646
   322
            // mh.invokeExact(a*):R => checkExactType(mh, TYPEOF(a*:R)); mh.invokeBasic(a*)
jaroslav@1646
   323
        } else {
jaroslav@1646
   324
            names[CHECK_TYPE] = new Name(NF_checkGenericType, names[CALL_MH], mtypeArg);
jaroslav@1646
   325
            // mh.invokeGeneric(a*):R => checkGenericType(mh, TYPEOF(a*:R)).invokeBasic(a*)
jaroslav@1646
   326
            outArgs[0] = names[CHECK_TYPE];
jaroslav@1646
   327
        }
jaroslav@1646
   328
        names[LINKER_CALL] = new Name(outCallType, outArgs);
jaroslav@1646
   329
        lform = new LambdaForm(debugName, INARG_LIMIT, names);
jaroslav@1646
   330
        if (isLinker)
jaroslav@1646
   331
            lform.compileToBytecode();  // JVM needs a real methodOop
jaroslav@1646
   332
        if (isCached)
jaroslav@1646
   333
            lform = mtype.form().setCachedLambdaForm(which, lform);
jaroslav@1646
   334
        return lform;
jaroslav@1646
   335
    }
jaroslav@1646
   336
jaroslav@1646
   337
    /*non-public*/ static
jaroslav@1646
   338
    WrongMethodTypeException newWrongMethodTypeException(MethodType actual, MethodType expected) {
jaroslav@1646
   339
        // FIXME: merge with JVM logic for throwing WMTE
jaroslav@1646
   340
        return new WrongMethodTypeException("expected "+expected+" but found "+actual);
jaroslav@1646
   341
    }
jaroslav@1646
   342
jaroslav@1646
   343
    /** Static definition of MethodHandle.invokeExact checking code. */
jaroslav@1646
   344
    /*non-public*/ static
jaroslav@1646
   345
    @ForceInline
jaroslav@1646
   346
    void checkExactType(Object mhObj, Object expectedObj) {
jaroslav@1646
   347
        MethodHandle mh = (MethodHandle) mhObj;
jaroslav@1646
   348
        MethodType expected = (MethodType) expectedObj;
jaroslav@1646
   349
        MethodType actual = mh.type();
jaroslav@1646
   350
        if (actual != expected)
jaroslav@1646
   351
            throw newWrongMethodTypeException(expected, actual);
jaroslav@1646
   352
    }
jaroslav@1646
   353
jaroslav@1646
   354
    /** Static definition of MethodHandle.invokeGeneric checking code.
jaroslav@1646
   355
     * Directly returns the type-adjusted MH to invoke, as follows:
jaroslav@1646
   356
     * {@code (R)MH.invoke(a*) => MH.asType(TYPEOF(a*:R)).invokeBasic(a*)}
jaroslav@1646
   357
     */
jaroslav@1646
   358
    /*non-public*/ static
jaroslav@1646
   359
    @ForceInline
jaroslav@1646
   360
    Object checkGenericType(Object mhObj, Object expectedObj) {
jaroslav@1646
   361
        MethodHandle mh = (MethodHandle) mhObj;
jaroslav@1646
   362
        MethodType expected = (MethodType) expectedObj;
jaroslav@1646
   363
        if (mh.type() == expected)  return mh;
jaroslav@1646
   364
        MethodHandle atc = mh.asTypeCache;
jaroslav@1646
   365
        if (atc != null && atc.type() == expected)  return atc;
jaroslav@1646
   366
        return mh.asType(expected);
jaroslav@1646
   367
        /* Maybe add more paths here.  Possible optimizations:
jaroslav@1646
   368
         * for (R)MH.invoke(a*),
jaroslav@1646
   369
         * let MT0 = TYPEOF(a*:R), MT1 = MH.type
jaroslav@1646
   370
         *
jaroslav@1646
   371
         * if MT0==MT1 or MT1 can be safely called by MT0
jaroslav@1646
   372
         *  => MH.invokeBasic(a*)
jaroslav@1646
   373
         * if MT1 can be safely called by MT0[R := Object]
jaroslav@1646
   374
         *  => MH.invokeBasic(a*) & checkcast(R)
jaroslav@1646
   375
         * if MT1 can be safely called by MT0[* := Object]
jaroslav@1646
   376
         *  => checkcast(A)* & MH.invokeBasic(a*) & checkcast(R)
jaroslav@1646
   377
         * if a big adapter BA can be pulled out of (MT0,MT1)
jaroslav@1646
   378
         *  => BA.invokeBasic(MT0,MH,a*)
jaroslav@1646
   379
         * if a local adapter LA can cached on static CS0 = new GICS(MT0)
jaroslav@1646
   380
         *  => CS0.LA.invokeBasic(MH,a*)
jaroslav@1646
   381
         * else
jaroslav@1646
   382
         *  => MH.asType(MT0).invokeBasic(A*)
jaroslav@1646
   383
         */
jaroslav@1646
   384
    }
jaroslav@1646
   385
jaroslav@1646
   386
    static MemberName linkToCallSiteMethod(MethodType mtype) {
jaroslav@1646
   387
        LambdaForm lform = callSiteForm(mtype, false);
jaroslav@1646
   388
        return lform.vmentry;
jaroslav@1646
   389
    }
jaroslav@1646
   390
jaroslav@1646
   391
    static MemberName linkToTargetMethod(MethodType mtype) {
jaroslav@1646
   392
        LambdaForm lform = callSiteForm(mtype, true);
jaroslav@1646
   393
        return lform.vmentry;
jaroslav@1646
   394
    }
jaroslav@1646
   395
jaroslav@1646
   396
    // skipCallSite is true if we are optimizing a ConstantCallSite
jaroslav@1646
   397
    private static LambdaForm callSiteForm(MethodType mtype, boolean skipCallSite) {
jaroslav@1646
   398
        mtype = mtype.basicType();  // normalize Z to I, String to Object, etc.
jaroslav@1646
   399
        final int which = (skipCallSite ? MethodTypeForm.LF_MH_LINKER : MethodTypeForm.LF_CS_LINKER);
jaroslav@1646
   400
        LambdaForm lform = mtype.form().cachedLambdaForm(which);
jaroslav@1646
   401
        if (lform != null)  return lform;
jaroslav@1646
   402
        // exactInvokerForm (Object,Object)Object
jaroslav@1646
   403
        //   link with java.lang.invoke.MethodHandle.invokeBasic(MethodHandle,Object,Object)Object/invokeSpecial
jaroslav@1646
   404
        final int ARG_BASE     = 0;
jaroslav@1646
   405
        final int OUTARG_LIMIT = ARG_BASE + mtype.parameterCount();
jaroslav@1646
   406
        final int INARG_LIMIT  = OUTARG_LIMIT + 1;
jaroslav@1646
   407
        int nameCursor = OUTARG_LIMIT;
jaroslav@1646
   408
        final int APPENDIX_ARG = nameCursor++;  // the last in-argument
jaroslav@1646
   409
        final int CSITE_ARG    = skipCallSite ? -1 : APPENDIX_ARG;
jaroslav@1646
   410
        final int CALL_MH      = skipCallSite ? APPENDIX_ARG : nameCursor++;  // result of getTarget
jaroslav@1646
   411
        final int LINKER_CALL  = nameCursor++;
jaroslav@1646
   412
        MethodType invokerFormType = mtype.appendParameterTypes(skipCallSite ? MethodHandle.class : CallSite.class);
jaroslav@1646
   413
        Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType);
jaroslav@1646
   414
        assert(names.length == nameCursor);
jaroslav@1646
   415
        assert(names[APPENDIX_ARG] != null);
jaroslav@1646
   416
        if (!skipCallSite)
jaroslav@1646
   417
            names[CALL_MH] = new Name(NF_getCallSiteTarget, names[CSITE_ARG]);
jaroslav@1646
   418
        // (site.)invokedynamic(a*):R => mh = site.getTarget(); mh.invokeBasic(a*)
jaroslav@1646
   419
        final int PREPEND_MH = 0, PREPEND_COUNT = 1;
jaroslav@1646
   420
        Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, OUTARG_LIMIT + PREPEND_COUNT, Object[].class);
jaroslav@1646
   421
        // prepend MH argument:
jaroslav@1646
   422
        System.arraycopy(outArgs, 0, outArgs, PREPEND_COUNT, outArgs.length - PREPEND_COUNT);
jaroslav@1646
   423
        outArgs[PREPEND_MH] = names[CALL_MH];
jaroslav@1646
   424
        names[LINKER_CALL] = new Name(mtype, outArgs);
jaroslav@1646
   425
        lform = new LambdaForm((skipCallSite ? "linkToTargetMethod" : "linkToCallSite"), INARG_LIMIT, names);
jaroslav@1646
   426
        lform.compileToBytecode();  // JVM needs a real methodOop
jaroslav@1646
   427
        lform = mtype.form().setCachedLambdaForm(which, lform);
jaroslav@1646
   428
        return lform;
jaroslav@1646
   429
    }
jaroslav@1646
   430
jaroslav@1646
   431
    /** Static definition of MethodHandle.invokeGeneric checking code. */
jaroslav@1646
   432
    /*non-public*/ static
jaroslav@1646
   433
    @ForceInline
jaroslav@1646
   434
    Object getCallSiteTarget(Object site) {
jaroslav@1646
   435
        return ((CallSite)site).getTarget();
jaroslav@1646
   436
    }
jaroslav@1646
   437
jaroslav@1646
   438
    // Local constant functions:
jaroslav@1646
   439
    private static final NamedFunction NF_checkExactType;
jaroslav@1646
   440
    private static final NamedFunction NF_checkGenericType;
jaroslav@1646
   441
    private static final NamedFunction NF_asType;
jaroslav@1646
   442
    private static final NamedFunction NF_getCallSiteTarget;
jaroslav@1646
   443
    static {
jaroslav@1646
   444
        try {
jaroslav@1646
   445
            NF_checkExactType = new NamedFunction(Invokers.class
jaroslav@1646
   446
                    .getDeclaredMethod("checkExactType", Object.class, Object.class));
jaroslav@1646
   447
            NF_checkGenericType = new NamedFunction(Invokers.class
jaroslav@1646
   448
                    .getDeclaredMethod("checkGenericType", Object.class, Object.class));
jaroslav@1646
   449
            NF_asType = new NamedFunction(MethodHandle.class
jaroslav@1646
   450
                    .getDeclaredMethod("asType", MethodType.class));
jaroslav@1646
   451
            NF_getCallSiteTarget = new NamedFunction(Invokers.class
jaroslav@1646
   452
                    .getDeclaredMethod("getCallSiteTarget", Object.class));
jaroslav@1646
   453
            NF_checkExactType.resolve();
jaroslav@1646
   454
            NF_checkGenericType.resolve();
jaroslav@1646
   455
            NF_getCallSiteTarget.resolve();
jaroslav@1646
   456
            // bound
jaroslav@1646
   457
        } catch (ReflectiveOperationException ex) {
jaroslav@1646
   458
            throw newInternalError(ex);
jaroslav@1646
   459
        }
jaroslav@1646
   460
    }
jaroslav@1646
   461
jaroslav@1646
   462
}