jdk/src/share/classes/java/lang/invoke/Invokers.java
changeset 8822 8145ab9f5f86
parent 8821 2836ee97ee27
child 9645 dabb5e4edc4c
equal deleted inserted replaced
8821:2836ee97ee27 8822:8145ab9f5f86
       
     1 /*
       
     2  * Copyright (c) 2008, 2011, 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 sun.invoke.empty.Empty;
       
    29 import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
       
    30 
       
    31 /**
       
    32  * Construction and caching of often-used invokers.
       
    33  * @author jrose
       
    34  */
       
    35 class Invokers {
       
    36     // exact type (sans leading taget MH) for the outgoing call
       
    37     private final MethodType targetType;
       
    38 
       
    39     // exact invoker for the outgoing call
       
    40     private /*lazy*/ MethodHandle exactInvoker;
       
    41 
       
    42     // erased (partially untyped but with primitives) invoker for the outgoing call
       
    43     private /*lazy*/ MethodHandle erasedInvoker;
       
    44     /*lazy*/ MethodHandle erasedInvokerWithDrops;  // for InvokeGeneric
       
    45 
       
    46     // generic (untyped) invoker for the outgoing call
       
    47     private /*lazy*/ MethodHandle genericInvoker;
       
    48 
       
    49     // generic (untyped) invoker for the outgoing call; accepts a single Object[]
       
    50     private final /*lazy*/ MethodHandle[] spreadInvokers;
       
    51 
       
    52     // invoker for an unbound callsite
       
    53     private /*lazy*/ MethodHandle uninitializedCallSite;
       
    54 
       
    55     /** Compute and cache information common to all collecting adapters
       
    56      *  that implement members of the erasure-family of the given erased type.
       
    57      */
       
    58     /*non-public*/ Invokers(MethodType targetType) {
       
    59         this.targetType = targetType;
       
    60         this.spreadInvokers = new MethodHandle[targetType.parameterCount()+1];
       
    61     }
       
    62 
       
    63     /*non-public*/ static MethodType invokerType(MethodType targetType) {
       
    64         return targetType.insertParameterTypes(0, MethodHandle.class);
       
    65     }
       
    66 
       
    67     /*non-public*/ MethodHandle exactInvoker() {
       
    68         MethodHandle invoker = exactInvoker;
       
    69         if (invoker != null)  return invoker;
       
    70         try {
       
    71             invoker = IMPL_LOOKUP.findVirtual(MethodHandle.class, "invokeExact", targetType);
       
    72         } catch (ReflectiveOperationException ex) {
       
    73             throw new InternalError("JVM cannot find invoker for "+targetType);
       
    74         }
       
    75         assert(invokerType(targetType) == invoker.type());
       
    76         exactInvoker = invoker;
       
    77         return invoker;
       
    78     }
       
    79 
       
    80     /*non-public*/ MethodHandle genericInvoker() {
       
    81         MethodHandle invoker1 = exactInvoker();
       
    82         MethodHandle invoker = genericInvoker;
       
    83         if (invoker != null)  return invoker;
       
    84         MethodType genericType = targetType.generic();
       
    85         invoker = MethodHandles.convertArguments(invoker1, invokerType(genericType));
       
    86         genericInvoker = invoker;
       
    87         return invoker;
       
    88     }
       
    89 
       
    90     /*non-public*/ MethodHandle erasedInvoker() {
       
    91         MethodHandle invoker1 = exactInvoker();
       
    92         MethodHandle invoker = erasedInvoker;
       
    93         if (invoker != null)  return invoker;
       
    94         MethodType erasedType = targetType.erase();
       
    95         if (erasedType == targetType.generic())
       
    96             invoker = genericInvoker();
       
    97         else
       
    98             invoker = MethodHandles.convertArguments(invoker1, invokerType(erasedType));
       
    99         erasedInvoker = invoker;
       
   100         return invoker;
       
   101     }
       
   102 
       
   103     /*non-public*/ MethodHandle spreadInvoker(int objectArgCount) {
       
   104         MethodHandle vaInvoker = spreadInvokers[objectArgCount];
       
   105         if (vaInvoker != null)  return vaInvoker;
       
   106         MethodHandle gInvoker = genericInvoker();
       
   107         vaInvoker = gInvoker.asSpreader(Object[].class, targetType.parameterCount() - objectArgCount);
       
   108         spreadInvokers[objectArgCount] = vaInvoker;
       
   109         return vaInvoker;
       
   110     }
       
   111 
       
   112     private static MethodHandle THROW_UCS = null;
       
   113 
       
   114     /*non-public*/ MethodHandle uninitializedCallSite() {
       
   115         MethodHandle invoker = uninitializedCallSite;
       
   116         if (invoker != null)  return invoker;
       
   117         if (targetType.parameterCount() > 0) {
       
   118             MethodType type0 = targetType.dropParameterTypes(0, targetType.parameterCount());
       
   119             Invokers invokers0 = type0.invokers();
       
   120             invoker = MethodHandles.dropArguments(invokers0.uninitializedCallSite(),
       
   121                                                   0, targetType.parameterList());
       
   122             assert(invoker.type().equals(targetType));
       
   123             uninitializedCallSite = invoker;
       
   124             return invoker;
       
   125         }
       
   126         if (THROW_UCS == null) {
       
   127             try {
       
   128                 THROW_UCS = IMPL_LOOKUP
       
   129                     .findStatic(CallSite.class, "uninitializedCallSite",
       
   130                                 MethodType.methodType(Empty.class));
       
   131             } catch (ReflectiveOperationException ex) {
       
   132                 throw new RuntimeException(ex);
       
   133             }
       
   134         }
       
   135         invoker = AdapterMethodHandle.makeRetypeRaw(targetType, THROW_UCS);
       
   136         assert(invoker.type().equals(targetType));
       
   137         uninitializedCallSite = invoker;
       
   138         return invoker;
       
   139     }
       
   140 
       
   141     public String toString() {
       
   142         return "Invokers"+targetType;
       
   143     }
       
   144 }