John R Rose | fb6164c | 2009-05-05 22:40:09 -0700 | [diff] [blame] | 1 | /* |
Alan Bateman | 430592a | 2012-11-02 15:50:11 +0000 | [diff] [blame] | 2 | * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. |
John R Rose | fb6164c | 2009-05-05 22:40:09 -0700 | [diff] [blame] | 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 |
Kelly O'Hair | fe008ae | 2010-05-25 15:58:33 -0700 | [diff] [blame] | 7 | * published by the Free Software Foundation. Oracle designates this |
John R Rose | fb6164c | 2009-05-05 22:40:09 -0700 | [diff] [blame] | 8 | * particular file as subject to the "Classpath" exception as provided |
Kelly O'Hair | fe008ae | 2010-05-25 15:58:33 -0700 | [diff] [blame] | 9 | * by Oracle in the LICENSE file that accompanied this code. |
John R Rose | fb6164c | 2009-05-05 22:40:09 -0700 | [diff] [blame] | 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 | * |
Kelly O'Hair | fe008ae | 2010-05-25 15:58:33 -0700 | [diff] [blame] | 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. |
John R Rose | fb6164c | 2009-05-05 22:40:09 -0700 | [diff] [blame] | 24 | */ |
| 25 | |
John R Rose | 3718824 | 2011-03-23 23:02:31 -0700 | [diff] [blame] | 26 | package java.lang.invoke; |
John R Rose | fb6164c | 2009-05-05 22:40:09 -0700 | [diff] [blame] | 27 | |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 28 | import java.util.Arrays; |
John R Rose | 3718824 | 2011-03-23 23:02:31 -0700 | [diff] [blame] | 29 | import sun.invoke.empty.Empty; |
Christian Thalinger | 01d0ba6 | 2012-10-19 17:04:35 -0700 | [diff] [blame] | 30 | import static java.lang.invoke.MethodHandleStatics.*; |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 31 | import static java.lang.invoke.MethodHandleNatives.Constants.*; |
John R Rose | 3718824 | 2011-03-23 23:02:31 -0700 | [diff] [blame] | 32 | import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 33 | import static java.lang.invoke.LambdaForm.*; |
John R Rose | fb6164c | 2009-05-05 22:40:09 -0700 | [diff] [blame] | 34 | |
| 35 | /** |
| 36 | * Construction and caching of often-used invokers. |
| 37 | * @author jrose |
| 38 | */ |
John R Rose | e7ebd47 | 2011-03-18 00:03:24 -0700 | [diff] [blame] | 39 | class Invokers { |
John R Rose | fb6164c | 2009-05-05 22:40:09 -0700 | [diff] [blame] | 40 | // exact type (sans leading taget MH) for the outgoing call |
| 41 | private final MethodType targetType; |
| 42 | |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 43 | // FIXME: Get rid of the invokers that are not useful. |
| 44 | |
John R Rose | fb6164c | 2009-05-05 22:40:09 -0700 | [diff] [blame] | 45 | // exact invoker for the outgoing call |
| 46 | private /*lazy*/ MethodHandle exactInvoker; |
John R Rose | 62ee211 | 2013-10-05 05:30:38 -0700 | [diff] [blame^] | 47 | private /*lazy*/ MethodHandle basicInvoker; // invokeBasic (unchecked exact) |
John R Rose | fb6164c | 2009-05-05 22:40:09 -0700 | [diff] [blame] | 48 | |
John R Rose | 2a322bb | 2010-10-30 21:02:30 -0700 | [diff] [blame] | 49 | // erased (partially untyped but with primitives) invoker for the outgoing call |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 50 | // FIXME: get rid of |
John R Rose | 2a322bb | 2010-10-30 21:02:30 -0700 | [diff] [blame] | 51 | private /*lazy*/ MethodHandle erasedInvoker; |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 52 | // FIXME: get rid of |
John R Rose | 2a322bb | 2010-10-30 21:02:30 -0700 | [diff] [blame] | 53 | /*lazy*/ MethodHandle erasedInvokerWithDrops; // for InvokeGeneric |
| 54 | |
John R Rose | eb96325 | 2011-05-12 19:27:33 -0700 | [diff] [blame] | 55 | // general invoker for the outgoing call |
| 56 | private /*lazy*/ MethodHandle generalInvoker; |
John R Rose | fb6164c | 2009-05-05 22:40:09 -0700 | [diff] [blame] | 57 | |
John R Rose | 025d0ae | 2011-05-26 17:37:36 -0700 | [diff] [blame] | 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[] |
John R Rose | eedbeda | 2011-02-11 01:26:24 -0800 | [diff] [blame] | 62 | private final /*lazy*/ MethodHandle[] spreadInvokers; |
John R Rose | 020e550 | 2010-01-07 16:16:45 -0800 | [diff] [blame] | 63 | |
John R Rose | 4f508ab | 2010-10-30 21:08:23 -0700 | [diff] [blame] | 64 | // invoker for an unbound callsite |
| 65 | private /*lazy*/ MethodHandle uninitializedCallSite; |
| 66 | |
John R Rose | fb6164c | 2009-05-05 22:40:09 -0700 | [diff] [blame] | 67 | /** Compute and cache information common to all collecting adapters |
| 68 | * that implement members of the erasure-family of the given erased type. |
| 69 | */ |
John R Rose | eedbeda | 2011-02-11 01:26:24 -0800 | [diff] [blame] | 70 | /*non-public*/ Invokers(MethodType targetType) { |
John R Rose | fb6164c | 2009-05-05 22:40:09 -0700 | [diff] [blame] | 71 | this.targetType = targetType; |
John R Rose | eedbeda | 2011-02-11 01:26:24 -0800 | [diff] [blame] | 72 | this.spreadInvokers = new MethodHandle[targetType.parameterCount()+1]; |
John R Rose | fb6164c | 2009-05-05 22:40:09 -0700 | [diff] [blame] | 73 | } |
| 74 | |
John R Rose | e7ebd47 | 2011-03-18 00:03:24 -0700 | [diff] [blame] | 75 | /*non-public*/ MethodHandle exactInvoker() { |
John R Rose | fb6164c | 2009-05-05 22:40:09 -0700 | [diff] [blame] | 76 | MethodHandle invoker = exactInvoker; |
| 77 | if (invoker != null) return invoker; |
John R Rose | 62ee211 | 2013-10-05 05:30:38 -0700 | [diff] [blame^] | 78 | invoker = makeExactOrGeneralInvoker(true); |
John R Rose | fb6164c | 2009-05-05 22:40:09 -0700 | [diff] [blame] | 79 | exactInvoker = invoker; |
| 80 | return invoker; |
| 81 | } |
| 82 | |
John R Rose | eb96325 | 2011-05-12 19:27:33 -0700 | [diff] [blame] | 83 | /*non-public*/ MethodHandle generalInvoker() { |
John R Rose | eb96325 | 2011-05-12 19:27:33 -0700 | [diff] [blame] | 84 | MethodHandle invoker = generalInvoker; |
John R Rose | fb6164c | 2009-05-05 22:40:09 -0700 | [diff] [blame] | 85 | if (invoker != null) return invoker; |
John R Rose | 62ee211 | 2013-10-05 05:30:38 -0700 | [diff] [blame^] | 86 | invoker = makeExactOrGeneralInvoker(false); |
John R Rose | eb96325 | 2011-05-12 19:27:33 -0700 | [diff] [blame] | 87 | generalInvoker = invoker; |
John R Rose | fb6164c | 2009-05-05 22:40:09 -0700 | [diff] [blame] | 88 | return invoker; |
| 89 | } |
| 90 | |
John R Rose | 62ee211 | 2013-10-05 05:30:38 -0700 | [diff] [blame^] | 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)); |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 99 | assert(checkInvoker(invoker)); |
John R Rose | 62ee211 | 2013-10-05 05:30:38 -0700 | [diff] [blame^] | 100 | maybeCompileToBytecode(invoker); |
John R Rose | 025d0ae | 2011-05-26 17:37:36 -0700 | [diff] [blame] | 101 | return invoker; |
| 102 | } |
| 103 | |
John R Rose | 62ee211 | 2013-10-05 05:30:38 -0700 | [diff] [blame^] | 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()); |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 131 | try { |
| 132 | //Lookup.findVirtual(MethodHandle.class, name, type); |
John R Rose | 62ee211 | 2013-10-05 05:30:38 -0700 | [diff] [blame^] | 133 | return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, "invokeBasic", basicType); |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 134 | } catch (ReflectiveOperationException ex) { |
John R Rose | 62ee211 | 2013-10-05 05:30:38 -0700 | [diff] [blame^] | 135 | throw newInternalError("JVM cannot find invoker for "+basicType, ex); |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 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 |
John R Rose | e7ebd47 | 2011-03-18 00:03:24 -0700 | [diff] [blame] | 149 | /*non-public*/ MethodHandle erasedInvoker() { |
John R Rose | 025d0ae | 2011-05-26 17:37:36 -0700 | [diff] [blame] | 150 | MethodHandle xinvoker = exactInvoker(); |
John R Rose | 2a322bb | 2010-10-30 21:02:30 -0700 | [diff] [blame] | 151 | MethodHandle invoker = erasedInvoker; |
| 152 | if (invoker != null) return invoker; |
| 153 | MethodType erasedType = targetType.erase(); |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 154 | invoker = xinvoker.asType(erasedType.invokerType()); |
John R Rose | 2a322bb | 2010-10-30 21:02:30 -0700 | [diff] [blame] | 155 | erasedInvoker = invoker; |
| 156 | return invoker; |
| 157 | } |
| 158 | |
John R Rose | 025d0ae | 2011-05-26 17:37:36 -0700 | [diff] [blame] | 159 | /*non-public*/ MethodHandle spreadInvoker(int leadingArgCount) { |
| 160 | MethodHandle vaInvoker = spreadInvokers[leadingArgCount]; |
John R Rose | 020e550 | 2010-01-07 16:16:45 -0800 | [diff] [blame] | 161 | if (vaInvoker != null) return vaInvoker; |
John R Rose | 025d0ae | 2011-05-26 17:37:36 -0700 | [diff] [blame] | 162 | int spreadArgCount = targetType.parameterCount() - leadingArgCount; |
John R Rose | 9d9d787 | 2012-08-17 13:42:25 -0700 | [diff] [blame] | 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) { |
Christian Thalinger | 01d0ba6 | 2012-10-19 17:04:35 -0700 | [diff] [blame] | 181 | throw newInternalError(ex); |
John R Rose | 9d9d787 | 2012-08-17 13:42:25 -0700 | [diff] [blame] | 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())); |
John R Rose | 62ee211 | 2013-10-05 05:30:38 -0700 | [diff] [blame^] | 187 | maybeCompileToBytecode(vaInvoker); |
John R Rose | 025d0ae | 2011-05-26 17:37:36 -0700 | [diff] [blame] | 188 | spreadInvokers[leadingArgCount] = vaInvoker; |
| 189 | return vaInvoker; |
| 190 | } |
| 191 | |
| 192 | /*non-public*/ MethodHandle varargsInvoker() { |
| 193 | MethodHandle vaInvoker = varargsInvoker; |
| 194 | if (vaInvoker != null) return vaInvoker; |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 195 | vaInvoker = spreadInvoker(0).asType(MethodType.genericMethodType(0, true).invokerType()); |
John R Rose | 025d0ae | 2011-05-26 17:37:36 -0700 | [diff] [blame] | 196 | varargsInvoker = vaInvoker; |
John R Rose | 020e550 | 2010-01-07 16:16:45 -0800 | [diff] [blame] | 197 | return vaInvoker; |
John R Rose | fb6164c | 2009-05-05 22:40:09 -0700 | [diff] [blame] | 198 | } |
| 199 | |
John R Rose | 4f508ab | 2010-10-30 21:08:23 -0700 | [diff] [blame] | 200 | private static MethodHandle THROW_UCS = null; |
| 201 | |
John R Rose | e7ebd47 | 2011-03-18 00:03:24 -0700 | [diff] [blame] | 202 | /*non-public*/ MethodHandle uninitializedCallSite() { |
John R Rose | 4f508ab | 2010-10-30 21:08:23 -0700 | [diff] [blame] | 203 | MethodHandle invoker = uninitializedCallSite; |
| 204 | if (invoker != null) return invoker; |
| 205 | if (targetType.parameterCount() > 0) { |
| 206 | MethodType type0 = targetType.dropParameterTypes(0, targetType.parameterCount()); |
John R Rose | e7ebd47 | 2011-03-18 00:03:24 -0700 | [diff] [blame] | 207 | Invokers invokers0 = type0.invokers(); |
John R Rose | 4f508ab | 2010-10-30 21:08:23 -0700 | [diff] [blame] | 208 | invoker = MethodHandles.dropArguments(invokers0.uninitializedCallSite(), |
| 209 | 0, targetType.parameterList()); |
| 210 | assert(invoker.type().equals(targetType)); |
| 211 | uninitializedCallSite = invoker; |
| 212 | return invoker; |
| 213 | } |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 214 | invoker = THROW_UCS; |
| 215 | if (invoker == null) { |
John R Rose | 4f508ab | 2010-10-30 21:08:23 -0700 | [diff] [blame] | 216 | try { |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 217 | THROW_UCS = invoker = IMPL_LOOKUP |
John R Rose | 4f508ab | 2010-10-30 21:08:23 -0700 | [diff] [blame] | 218 | .findStatic(CallSite.class, "uninitializedCallSite", |
| 219 | MethodType.methodType(Empty.class)); |
John R Rose | f485ab5 | 2011-02-11 01:26:32 -0800 | [diff] [blame] | 220 | } catch (ReflectiveOperationException ex) { |
Christian Thalinger | 01d0ba6 | 2012-10-19 17:04:35 -0700 | [diff] [blame] | 221 | throw newInternalError(ex); |
John R Rose | 4f508ab | 2010-10-30 21:08:23 -0700 | [diff] [blame] | 222 | } |
| 223 | } |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 224 | invoker = MethodHandles.explicitCastArguments(invoker, MethodType.methodType(targetType.returnType())); |
| 225 | invoker = invoker.dropArguments(targetType, 0, targetType.parameterCount()); |
John R Rose | 4f508ab | 2010-10-30 21:08:23 -0700 | [diff] [blame] | 226 | assert(invoker.type().equals(targetType)); |
| 227 | uninitializedCallSite = invoker; |
| 228 | return invoker; |
| 229 | } |
| 230 | |
John R Rose | fb6164c | 2009-05-05 22:40:09 -0700 | [diff] [blame] | 231 | public String toString() { |
| 232 | return "Invokers"+targetType; |
| 233 | } |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 234 | |
John R Rose | 62ee211 | 2013-10-05 05:30:38 -0700 | [diff] [blame^] | 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 | } |
John R Rose | 9d9d787 | 2012-08-17 13:42:25 -0700 | [diff] [blame] | 244 | LambdaForm lform; |
John R Rose | 62ee211 | 2013-10-05 05:30:38 -0700 | [diff] [blame^] | 245 | if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - MH_LINKER_ARG_APPENDED) { |
| 246 | lform = invokeHandleForm(mtype, false, which); |
John R Rose | 9d9d787 | 2012-08-17 13:42:25 -0700 | [diff] [blame] | 247 | appendixResult[0] = mtype; |
| 248 | } else { |
John R Rose | 62ee211 | 2013-10-05 05:30:38 -0700 | [diff] [blame^] | 249 | lform = invokeHandleForm(mtype, true, which); |
John R Rose | 9d9d787 | 2012-08-17 13:42:25 -0700 | [diff] [blame] | 250 | } |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 251 | return lform.vmentry; |
| 252 | } |
| 253 | |
John R Rose | 62ee211 | 2013-10-05 05:30:38 -0700 | [diff] [blame^] | 254 | // argument count to account for trailing "appendix value" (typically the mtype) |
| 255 | private static final int MH_LINKER_ARG_APPENDED = 1; |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 256 | |
John R Rose | 62ee211 | 2013-10-05 05:30:38 -0700 | [diff] [blame^] | 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) { |
John R Rose | 9d9d787 | 2012-08-17 13:42:25 -0700 | [diff] [blame] | 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 | } |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 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 | } |
John R Rose | 9d9d787 | 2012-08-17 13:42:25 -0700 | [diff] [blame] | 283 | LambdaForm lform; |
| 284 | if (isCached) { |
| 285 | lform = mtype.form().cachedLambdaForm(which); |
| 286 | if (lform != null) return lform; |
| 287 | } |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 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(); |
John R Rose | 9d9d787 | 2012-08-17 13:42:25 -0700 | [diff] [blame] | 294 | final int INARG_LIMIT = OUTARG_LIMIT + (isLinker && !customized ? 1 : 0); |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 295 | int nameCursor = OUTARG_LIMIT; |
John R Rose | 9d9d787 | 2012-08-17 13:42:25 -0700 | [diff] [blame] | 296 | final int MTYPE_ARG = customized ? -1 : nameCursor++; // might be last in-argument |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 297 | final int CHECK_TYPE = nameCursor++; |
| 298 | final int LINKER_CALL = nameCursor++; |
| 299 | MethodType invokerFormType = mtype.invokerType(); |
| 300 | if (isLinker) { |
John R Rose | 9d9d787 | 2012-08-17 13:42:25 -0700 | [diff] [blame] | 301 | if (!customized) |
| 302 | invokerFormType = invokerFormType.appendParameterTypes(MemberName.class); |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 303 | } else { |
| 304 | invokerFormType = invokerFormType.invokerType(); |
| 305 | } |
| 306 | Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType); |
John R Rose | 9d9d787 | 2012-08-17 13:42:25 -0700 | [diff] [blame] | 307 | assert(names.length == nameCursor) |
| 308 | : Arrays.asList(mtype, customized, which, nameCursor, names.length); |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 309 | if (MTYPE_ARG >= INARG_LIMIT) { |
| 310 | assert(names[MTYPE_ARG] == null); |
John R Rose | 62ee211 | 2013-10-05 05:30:38 -0700 | [diff] [blame^] | 311 | NamedFunction getter = BoundMethodHandle.getSpeciesData("L").getterFunction(0); |
| 312 | names[MTYPE_ARG] = new Name(getter, names[THIS_MH]); |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 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. |
John R Rose | 62ee211 | 2013-10-05 05:30:38 -0700 | [diff] [blame^] | 317 | MethodType outCallType = mtype.basicType(); |
| 318 | Object[] outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT, Object[].class); |
John R Rose | 9d9d787 | 2012-08-17 13:42:25 -0700 | [diff] [blame] | 319 | Object mtypeArg = (customized ? mtype : names[MTYPE_ARG]); |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 320 | if (!isGeneric) { |
John R Rose | 9d9d787 | 2012-08-17 13:42:25 -0700 | [diff] [blame] | 321 | names[CHECK_TYPE] = new Name(NF_checkExactType, names[CALL_MH], mtypeArg); |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 322 | // mh.invokeExact(a*):R => checkExactType(mh, TYPEOF(a*:R)); mh.invokeBasic(a*) |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 323 | } else { |
John R Rose | 9d9d787 | 2012-08-17 13:42:25 -0700 | [diff] [blame] | 324 | names[CHECK_TYPE] = new Name(NF_checkGenericType, names[CALL_MH], mtypeArg); |
John R Rose | 62ee211 | 2013-10-05 05:30:38 -0700 | [diff] [blame^] | 325 | // mh.invokeGeneric(a*):R => checkGenericType(mh, TYPEOF(a*:R)).invokeBasic(a*) |
| 326 | outArgs[0] = names[CHECK_TYPE]; |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 327 | } |
John R Rose | 62ee211 | 2013-10-05 05:30:38 -0700 | [diff] [blame^] | 328 | names[LINKER_CALL] = new Name(outCallType, outArgs); |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 329 | lform = new LambdaForm(debugName, INARG_LIMIT, names); |
| 330 | if (isLinker) |
| 331 | lform.compileToBytecode(); // JVM needs a real methodOop |
John R Rose | 9d9d787 | 2012-08-17 13:42:25 -0700 | [diff] [blame] | 332 | if (isCached) |
| 333 | lform = mtype.form().setCachedLambdaForm(which, lform); |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 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 | |
John R Rose | 62ee211 | 2013-10-05 05:30:38 -0700 | [diff] [blame^] | 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 | */ |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 358 | /*non-public*/ static |
| 359 | @ForceInline |
| 360 | Object checkGenericType(Object mhObj, Object expectedObj) { |
| 361 | MethodHandle mh = (MethodHandle) mhObj; |
| 362 | MethodType expected = (MethodType) expectedObj; |
John R Rose | 62ee211 | 2013-10-05 05:30:38 -0700 | [diff] [blame^] | 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 | */ |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 384 | } |
| 385 | |
| 386 | static MemberName linkToCallSiteMethod(MethodType mtype) { |
John R Rose | 62ee211 | 2013-10-05 05:30:38 -0700 | [diff] [blame^] | 387 | LambdaForm lform = callSiteForm(mtype, false); |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 388 | return lform.vmentry; |
| 389 | } |
| 390 | |
John R Rose | 62ee211 | 2013-10-05 05:30:38 -0700 | [diff] [blame^] | 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) { |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 398 | mtype = mtype.basicType(); // normalize Z to I, String to Object, etc. |
John R Rose | 62ee211 | 2013-10-05 05:30:38 -0700 | [diff] [blame^] | 399 | final int which = (skipCallSite ? MethodTypeForm.LF_MH_LINKER : MethodTypeForm.LF_CS_LINKER); |
| 400 | LambdaForm lform = mtype.form().cachedLambdaForm(which); |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 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; |
John R Rose | 62ee211 | 2013-10-05 05:30:38 -0700 | [diff] [blame^] | 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 |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 411 | final int LINKER_CALL = nameCursor++; |
John R Rose | 62ee211 | 2013-10-05 05:30:38 -0700 | [diff] [blame^] | 412 | MethodType invokerFormType = mtype.appendParameterTypes(skipCallSite ? MethodHandle.class : CallSite.class); |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 413 | Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType); |
| 414 | assert(names.length == nameCursor); |
John R Rose | 62ee211 | 2013-10-05 05:30:38 -0700 | [diff] [blame^] | 415 | assert(names[APPENDIX_ARG] != null); |
| 416 | if (!skipCallSite) |
| 417 | names[CALL_MH] = new Name(NF_getCallSiteTarget, names[CSITE_ARG]); |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 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]; |
John R Rose | 62ee211 | 2013-10-05 05:30:38 -0700 | [diff] [blame^] | 424 | names[LINKER_CALL] = new Name(mtype, outArgs); |
| 425 | lform = new LambdaForm((skipCallSite ? "linkToTargetMethod" : "linkToCallSite"), INARG_LIMIT, names); |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 426 | lform.compileToBytecode(); // JVM needs a real methodOop |
John R Rose | 62ee211 | 2013-10-05 05:30:38 -0700 | [diff] [blame^] | 427 | lform = mtype.form().setCachedLambdaForm(which, lform); |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 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; |
John R Rose | 9d9d787 | 2012-08-17 13:42:25 -0700 | [diff] [blame] | 441 | private static final NamedFunction NF_asType; |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 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)); |
John R Rose | 9d9d787 | 2012-08-17 13:42:25 -0700 | [diff] [blame] | 449 | NF_asType = new NamedFunction(MethodHandle.class |
| 450 | .getDeclaredMethod("asType", MethodType.class)); |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 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) { |
Christian Thalinger | 01d0ba6 | 2012-10-19 17:04:35 -0700 | [diff] [blame] | 458 | throw newInternalError(ex); |
Christian Thalinger | 360d512 | 2012-07-24 10:47:44 -0700 | [diff] [blame] | 459 | } |
| 460 | } |
| 461 | |
John R Rose | fb6164c | 2009-05-05 22:40:09 -0700 | [diff] [blame] | 462 | } |