src/share/classes/java/lang/invoke/Invokers.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File jdk Sdiff src/share/classes/java/lang/invoke

src/share/classes/java/lang/invoke/Invokers.java

Print this page
rev 10274 : 8050052: Small cleanups in java.lang.invoke code
Reviewed-by: ?
rev 10275 : imported patch invokers


   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         }




   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 
  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     // general invoker for the outgoing call, uses varargs
  46     private /*lazy*/ MethodHandle varargsInvoker;
  47 
  48     // general invoker for the outgoing call; accepts a trailing Object[]
  49     private final /*lazy*/ MethodHandle[] spreadInvokers;
  50 
  51     // Cached adapter information:
  52     private final @Stable MethodHandle[] invokers = new MethodHandle[INV_LIMIT];
  53     // Indexes into invokers:
  54     static final int
  55             INV_EXACT          =  0,  // MethodHandles.exactInvoker
  56             INV_GENERIC        =  1,  // MethodHandles.invoker (generic invocation)
  57             INV_BASIC          =  2,  // MethodHandles.basicInvoker
  58             INV_LIMIT          =  3;
  59 
  60     /** Compute and cache information common to all collecting adapters
  61      *  that implement members of the erasure-family of the given erased type.
  62      */
  63     /*non-public*/ Invokers(MethodType targetType) {
  64         this.targetType = targetType;
  65         this.spreadInvokers = new MethodHandle[targetType.parameterCount()+1];
  66     }
  67 
  68     /*non-public*/ MethodHandle exactInvoker() {
  69         MethodHandle invoker = cachedInvoker(INV_EXACT);
  70         if (invoker != null)  return invoker;
  71         invoker = makeExactOrGeneralInvoker(true);
  72         return setCachedInvoker(INV_EXACT, invoker);

  73     }
  74 
  75     /*non-public*/ MethodHandle genericInvoker() {
  76         MethodHandle invoker = cachedInvoker(INV_GENERIC);
  77         if (invoker != null)  return invoker;
  78         invoker = makeExactOrGeneralInvoker(false);
  79         return setCachedInvoker(INV_GENERIC, invoker);
  80     }
  81 
  82     /*non-public*/ MethodHandle basicInvoker() {
  83         MethodHandle invoker = cachedInvoker(INV_BASIC);
  84         if (invoker != null)  return invoker;
  85         MethodType basicType = targetType.basicType();
  86         if (basicType != targetType) {
  87             // double cache; not used significantly
  88             return setCachedInvoker(INV_BASIC, basicType.invokers().basicInvoker());
  89         }
  90         invoker = basicType.form().cachedMethodHandle(MethodTypeForm.MH_BASIC_INV);
  91         if (invoker == null) {
  92             MemberName method = invokeBasicMethod(basicType);
  93             invoker = DirectMethodHandle.make(method);
  94             assert(checkInvoker(invoker));
  95             invoker = basicType.form().setCachedMethodHandle(MethodTypeForm.MH_BASIC_INV, invoker);
  96         }
  97         return setCachedInvoker(INV_BASIC, invoker);
  98     }
  99 
 100     private MethodHandle cachedInvoker(int idx) {
 101         return invokers[idx];
 102     }
 103 
 104     private synchronized MethodHandle setCachedInvoker(int idx, final MethodHandle invoker) {
 105         // Simulate a CAS, to avoid racy duplication of results.
 106         MethodHandle prev = invokers[idx];
 107         if (prev != null)  return prev;
 108         return invokers[idx] = invoker;
 109     }
 110 
 111     private MethodHandle makeExactOrGeneralInvoker(boolean isExact) {
 112         MethodType mtype = targetType;
 113         MethodType invokerType = mtype.invokerType();
 114         int which = (isExact ? MethodTypeForm.LF_EX_INVOKER : MethodTypeForm.LF_GEN_INVOKER);
 115         LambdaForm lform = invokeHandleForm(mtype, false, which);
 116         MethodHandle invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype);
 117         String whichName = (isExact ? "invokeExact" : "invoke");
 118         invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke(whichName, mtype));
 119         assert(checkInvoker(invoker));
 120         maybeCompileToBytecode(invoker);
 121         return invoker;
 122     }
 123 
 124     /** If the target type seems to be common enough, eagerly compile the invoker to bytecodes. */
 125     private void maybeCompileToBytecode(MethodHandle invoker) {
 126         final int EAGER_COMPILE_ARITY_LIMIT = 10;
 127         if (targetType == targetType.erase() &&
 128             targetType.parameterCount() < EAGER_COMPILE_ARITY_LIMIT) {
 129             invoker.form.compileToBytecode();
 130         }
 131     }
 132 















 133     // This next one is called from LambdaForm.NamedFunction.<init>.
 134     /*non-public*/ static MemberName invokeBasicMethod(MethodType basicType) {
 135         assert(basicType == basicType.basicType());
 136         try {
 137             //Lookup.findVirtual(MethodHandle.class, name, type);
 138             return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, "invokeBasic", basicType);
 139         } catch (ReflectiveOperationException ex) {
 140             throw newInternalError("JVM cannot find invoker for "+basicType, ex);
 141         }
 142     }
 143 
 144     private boolean checkInvoker(MethodHandle invoker) {
 145         assert(targetType.invokerType().equals(invoker.type()))
 146                 : java.util.Arrays.asList(targetType, targetType.invokerType(), invoker);
 147         assert(invoker.internalMemberName() == null ||
 148                invoker.internalMemberName().getMethodType().equals(targetType));
 149         assert(!invoker.isVarargsCollector());
 150         return true;
 151     }
 152 











 153     /*non-public*/ MethodHandle spreadInvoker(int leadingArgCount) {
 154         MethodHandle vaInvoker = spreadInvokers[leadingArgCount];
 155         if (vaInvoker != null)  return vaInvoker;
 156         int spreadArgCount = targetType.parameterCount() - leadingArgCount;
 157         MethodType spreadInvokerType = targetType
 158             .replaceParameterTypes(leadingArgCount, targetType.parameterCount(), Object[].class);
 159         if (targetType.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY) {
 160             // Factor sinvoker.invoke(mh, a) into ginvoker.asSpreader().invoke(mh, a)
 161             // where ginvoker.invoke(mh, a*) => mh.invoke(a*).
 162             MethodHandle genInvoker = genericInvoker();
 163             vaInvoker = genInvoker.asSpreader(Object[].class, spreadArgCount);
 164         } else {
 165             // Cannot build a general invoker here of type ginvoker.invoke(mh, a*[254]).
 166             // Instead, factor sinvoker.invoke(mh, a) into ainvoker.invoke(filter(mh), a)
 167             // where filter(mh) == mh.asSpreader(Object[], spreadArgCount)
 168             MethodHandle arrayInvoker = MethodHandles.exactInvoker(spreadInvokerType);
 169             MethodHandle makeSpreader;
 170             try {
 171                 makeSpreader = IMPL_LOOKUP
 172                     .findVirtual(MethodHandle.class, "asSpreader",
 173                         MethodType.methodType(MethodHandle.class, Class.class, int.class));
 174             } catch (ReflectiveOperationException ex) {
 175                 throw newInternalError(ex);
 176             }
 177             makeSpreader = MethodHandles.insertArguments(makeSpreader, 1, Object[].class, spreadArgCount);
 178             vaInvoker = MethodHandles.filterArgument(arrayInvoker, 0, makeSpreader);
 179         }
 180         assert(vaInvoker.type().equals(spreadInvokerType.invokerType()));
 181         maybeCompileToBytecode(vaInvoker);
 182         spreadInvokers[leadingArgCount] = vaInvoker;
 183         return vaInvoker;
 184     }
 185 
 186     /*non-public*/ MethodHandle varargsInvoker() {
 187         MethodHandle vaInvoker = varargsInvoker;
 188         if (vaInvoker != null)  return vaInvoker;
 189         vaInvoker = spreadInvoker(0).asType(MethodType.genericMethodType(0, true).invokerType());
 190         varargsInvoker = vaInvoker;
 191         return vaInvoker;
 192     }
 193 































 194     public String toString() {
 195         return "Invokers"+targetType;
 196     }
 197 
 198     static MemberName methodHandleInvokeLinkerMethod(String name,
 199                                                      MethodType mtype,
 200                                                      Object[] appendixResult) {
 201         int which;
 202         switch (name) {
 203         case "invokeExact":  which = MethodTypeForm.LF_EX_LINKER; break;
 204         case "invoke":       which = MethodTypeForm.LF_GEN_LINKER; break;
 205         default:             throw new InternalError("not invoker: "+name);
 206         }
 207         LambdaForm lform;
 208         if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - MH_LINKER_ARG_APPENDED) {
 209             lform = invokeHandleForm(mtype, false, which);
 210             appendixResult[0] = mtype;
 211         } else {
 212             lform = invokeHandleForm(mtype, true, which);
 213         }


src/share/classes/java/lang/invoke/Invokers.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File