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