blob: 6214aad86205aa38e9475966a2d5742ee6ed5bb0 [file] [log] [blame]
John R Rosefb6164c2009-05-05 22:40:09 -07001/*
Alan Bateman430592a2012-11-02 15:50:11 +00002 * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
John R Rosefb6164c2009-05-05 22:40:09 -07003 * 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'Hairfe008ae2010-05-25 15:58:33 -07007 * published by the Free Software Foundation. Oracle designates this
John R Rosefb6164c2009-05-05 22:40:09 -07008 * particular file as subject to the "Classpath" exception as provided
Kelly O'Hairfe008ae2010-05-25 15:58:33 -07009 * by Oracle in the LICENSE file that accompanied this code.
John R Rosefb6164c2009-05-05 22:40:09 -070010 *
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'Hairfe008ae2010-05-25 15:58:33 -070021 * 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 Rosefb6164c2009-05-05 22:40:09 -070024 */
25
John R Rose37188242011-03-23 23:02:31 -070026package java.lang.invoke;
John R Rosefb6164c2009-05-05 22:40:09 -070027
Christian Thalinger360d5122012-07-24 10:47:44 -070028import java.util.Arrays;
John R Rose37188242011-03-23 23:02:31 -070029import sun.invoke.empty.Empty;
Christian Thalinger01d0ba62012-10-19 17:04:35 -070030import static java.lang.invoke.MethodHandleStatics.*;
Christian Thalinger360d5122012-07-24 10:47:44 -070031import static java.lang.invoke.MethodHandleNatives.Constants.*;
John R Rose37188242011-03-23 23:02:31 -070032import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
Christian Thalinger360d5122012-07-24 10:47:44 -070033import static java.lang.invoke.LambdaForm.*;
John R Rosefb6164c2009-05-05 22:40:09 -070034
35/**
36 * Construction and caching of often-used invokers.
37 * @author jrose
38 */
John R Rosee7ebd472011-03-18 00:03:24 -070039class Invokers {
John R Rosefb6164c2009-05-05 22:40:09 -070040 // exact type (sans leading taget MH) for the outgoing call
41 private final MethodType targetType;
42
Christian Thalinger360d5122012-07-24 10:47:44 -070043 // FIXME: Get rid of the invokers that are not useful.
44
John R Rosefb6164c2009-05-05 22:40:09 -070045 // exact invoker for the outgoing call
46 private /*lazy*/ MethodHandle exactInvoker;
John R Rose62ee2112013-10-05 05:30:38 -070047 private /*lazy*/ MethodHandle basicInvoker; // invokeBasic (unchecked exact)
John R Rosefb6164c2009-05-05 22:40:09 -070048
John R Rose2a322bb2010-10-30 21:02:30 -070049 // erased (partially untyped but with primitives) invoker for the outgoing call
Christian Thalinger360d5122012-07-24 10:47:44 -070050 // FIXME: get rid of
John R Rose2a322bb2010-10-30 21:02:30 -070051 private /*lazy*/ MethodHandle erasedInvoker;
Christian Thalinger360d5122012-07-24 10:47:44 -070052 // FIXME: get rid of
John R Rose2a322bb2010-10-30 21:02:30 -070053 /*lazy*/ MethodHandle erasedInvokerWithDrops; // for InvokeGeneric
54
John R Roseeb963252011-05-12 19:27:33 -070055 // general invoker for the outgoing call
56 private /*lazy*/ MethodHandle generalInvoker;
John R Rosefb6164c2009-05-05 22:40:09 -070057
John R Rose025d0ae2011-05-26 17:37:36 -070058 // 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 Roseeedbeda2011-02-11 01:26:24 -080062 private final /*lazy*/ MethodHandle[] spreadInvokers;
John R Rose020e5502010-01-07 16:16:45 -080063
John R Rose4f508ab2010-10-30 21:08:23 -070064 // invoker for an unbound callsite
65 private /*lazy*/ MethodHandle uninitializedCallSite;
66
John R Rosefb6164c2009-05-05 22:40:09 -070067 /** 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 Roseeedbeda2011-02-11 01:26:24 -080070 /*non-public*/ Invokers(MethodType targetType) {
John R Rosefb6164c2009-05-05 22:40:09 -070071 this.targetType = targetType;
John R Roseeedbeda2011-02-11 01:26:24 -080072 this.spreadInvokers = new MethodHandle[targetType.parameterCount()+1];
John R Rosefb6164c2009-05-05 22:40:09 -070073 }
74
John R Rosee7ebd472011-03-18 00:03:24 -070075 /*non-public*/ MethodHandle exactInvoker() {
John R Rosefb6164c2009-05-05 22:40:09 -070076 MethodHandle invoker = exactInvoker;
77 if (invoker != null) return invoker;
John R Rose62ee2112013-10-05 05:30:38 -070078 invoker = makeExactOrGeneralInvoker(true);
John R Rosefb6164c2009-05-05 22:40:09 -070079 exactInvoker = invoker;
80 return invoker;
81 }
82
John R Roseeb963252011-05-12 19:27:33 -070083 /*non-public*/ MethodHandle generalInvoker() {
John R Roseeb963252011-05-12 19:27:33 -070084 MethodHandle invoker = generalInvoker;
John R Rosefb6164c2009-05-05 22:40:09 -070085 if (invoker != null) return invoker;
John R Rose62ee2112013-10-05 05:30:38 -070086 invoker = makeExactOrGeneralInvoker(false);
John R Roseeb963252011-05-12 19:27:33 -070087 generalInvoker = invoker;
John R Rosefb6164c2009-05-05 22:40:09 -070088 return invoker;
89 }
90
John R Rose62ee2112013-10-05 05:30:38 -070091 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 Thalinger360d5122012-07-24 10:47:44 -070099 assert(checkInvoker(invoker));
John R Rose62ee2112013-10-05 05:30:38 -0700100 maybeCompileToBytecode(invoker);
John R Rose025d0ae2011-05-26 17:37:36 -0700101 return invoker;
102 }
103
John R Rose62ee2112013-10-05 05:30:38 -0700104 /** 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 Thalinger360d5122012-07-24 10:47:44 -0700131 try {
132 //Lookup.findVirtual(MethodHandle.class, name, type);
John R Rose62ee2112013-10-05 05:30:38 -0700133 return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, "invokeBasic", basicType);
Christian Thalinger360d5122012-07-24 10:47:44 -0700134 } catch (ReflectiveOperationException ex) {
John R Rose62ee2112013-10-05 05:30:38 -0700135 throw newInternalError("JVM cannot find invoker for "+basicType, ex);
Christian Thalinger360d5122012-07-24 10:47:44 -0700136 }
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 Rosee7ebd472011-03-18 00:03:24 -0700149 /*non-public*/ MethodHandle erasedInvoker() {
John R Rose025d0ae2011-05-26 17:37:36 -0700150 MethodHandle xinvoker = exactInvoker();
John R Rose2a322bb2010-10-30 21:02:30 -0700151 MethodHandle invoker = erasedInvoker;
152 if (invoker != null) return invoker;
153 MethodType erasedType = targetType.erase();
Christian Thalinger360d5122012-07-24 10:47:44 -0700154 invoker = xinvoker.asType(erasedType.invokerType());
John R Rose2a322bb2010-10-30 21:02:30 -0700155 erasedInvoker = invoker;
156 return invoker;
157 }
158
John R Rose025d0ae2011-05-26 17:37:36 -0700159 /*non-public*/ MethodHandle spreadInvoker(int leadingArgCount) {
160 MethodHandle vaInvoker = spreadInvokers[leadingArgCount];
John R Rose020e5502010-01-07 16:16:45 -0800161 if (vaInvoker != null) return vaInvoker;
John R Rose025d0ae2011-05-26 17:37:36 -0700162 int spreadArgCount = targetType.parameterCount() - leadingArgCount;
John R Rose9d9d7872012-08-17 13:42:25 -0700163 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 Thalinger01d0ba62012-10-19 17:04:35 -0700181 throw newInternalError(ex);
John R Rose9d9d7872012-08-17 13:42:25 -0700182 }
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 Rose62ee2112013-10-05 05:30:38 -0700187 maybeCompileToBytecode(vaInvoker);
John R Rose025d0ae2011-05-26 17:37:36 -0700188 spreadInvokers[leadingArgCount] = vaInvoker;
189 return vaInvoker;
190 }
191
192 /*non-public*/ MethodHandle varargsInvoker() {
193 MethodHandle vaInvoker = varargsInvoker;
194 if (vaInvoker != null) return vaInvoker;
Christian Thalinger360d5122012-07-24 10:47:44 -0700195 vaInvoker = spreadInvoker(0).asType(MethodType.genericMethodType(0, true).invokerType());
John R Rose025d0ae2011-05-26 17:37:36 -0700196 varargsInvoker = vaInvoker;
John R Rose020e5502010-01-07 16:16:45 -0800197 return vaInvoker;
John R Rosefb6164c2009-05-05 22:40:09 -0700198 }
199
John R Rose4f508ab2010-10-30 21:08:23 -0700200 private static MethodHandle THROW_UCS = null;
201
John R Rosee7ebd472011-03-18 00:03:24 -0700202 /*non-public*/ MethodHandle uninitializedCallSite() {
John R Rose4f508ab2010-10-30 21:08:23 -0700203 MethodHandle invoker = uninitializedCallSite;
204 if (invoker != null) return invoker;
205 if (targetType.parameterCount() > 0) {
206 MethodType type0 = targetType.dropParameterTypes(0, targetType.parameterCount());
John R Rosee7ebd472011-03-18 00:03:24 -0700207 Invokers invokers0 = type0.invokers();
John R Rose4f508ab2010-10-30 21:08:23 -0700208 invoker = MethodHandles.dropArguments(invokers0.uninitializedCallSite(),
209 0, targetType.parameterList());
210 assert(invoker.type().equals(targetType));
211 uninitializedCallSite = invoker;
212 return invoker;
213 }
Christian Thalinger360d5122012-07-24 10:47:44 -0700214 invoker = THROW_UCS;
215 if (invoker == null) {
John R Rose4f508ab2010-10-30 21:08:23 -0700216 try {
Christian Thalinger360d5122012-07-24 10:47:44 -0700217 THROW_UCS = invoker = IMPL_LOOKUP
John R Rose4f508ab2010-10-30 21:08:23 -0700218 .findStatic(CallSite.class, "uninitializedCallSite",
219 MethodType.methodType(Empty.class));
John R Rosef485ab52011-02-11 01:26:32 -0800220 } catch (ReflectiveOperationException ex) {
Christian Thalinger01d0ba62012-10-19 17:04:35 -0700221 throw newInternalError(ex);
John R Rose4f508ab2010-10-30 21:08:23 -0700222 }
223 }
Christian Thalinger360d5122012-07-24 10:47:44 -0700224 invoker = MethodHandles.explicitCastArguments(invoker, MethodType.methodType(targetType.returnType()));
225 invoker = invoker.dropArguments(targetType, 0, targetType.parameterCount());
John R Rose4f508ab2010-10-30 21:08:23 -0700226 assert(invoker.type().equals(targetType));
227 uninitializedCallSite = invoker;
228 return invoker;
229 }
230
John R Rosefb6164c2009-05-05 22:40:09 -0700231 public String toString() {
232 return "Invokers"+targetType;
233 }
Christian Thalinger360d5122012-07-24 10:47:44 -0700234
John R Rose62ee2112013-10-05 05:30:38 -0700235 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 Rose9d9d7872012-08-17 13:42:25 -0700244 LambdaForm lform;
John R Rose62ee2112013-10-05 05:30:38 -0700245 if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - MH_LINKER_ARG_APPENDED) {
246 lform = invokeHandleForm(mtype, false, which);
John R Rose9d9d7872012-08-17 13:42:25 -0700247 appendixResult[0] = mtype;
248 } else {
John R Rose62ee2112013-10-05 05:30:38 -0700249 lform = invokeHandleForm(mtype, true, which);
John R Rose9d9d7872012-08-17 13:42:25 -0700250 }
Christian Thalinger360d5122012-07-24 10:47:44 -0700251 return lform.vmentry;
252 }
253
John R Rose62ee2112013-10-05 05:30:38 -0700254 // argument count to account for trailing "appendix value" (typically the mtype)
255 private static final int MH_LINKER_ARG_APPENDED = 1;
Christian Thalinger360d5122012-07-24 10:47:44 -0700256
John R Rose62ee2112013-10-05 05:30:38 -0700257 /** 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 Rose9d9d7872012-08-17 13:42:25 -0700267 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 Thalinger360d5122012-07-24 10:47:44 -0700274 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 Rose9d9d7872012-08-17 13:42:25 -0700283 LambdaForm lform;
284 if (isCached) {
285 lform = mtype.form().cachedLambdaForm(which);
286 if (lform != null) return lform;
287 }
Christian Thalinger360d5122012-07-24 10:47:44 -0700288 // 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 Rose9d9d7872012-08-17 13:42:25 -0700294 final int INARG_LIMIT = OUTARG_LIMIT + (isLinker && !customized ? 1 : 0);
Christian Thalinger360d5122012-07-24 10:47:44 -0700295 int nameCursor = OUTARG_LIMIT;
John R Rose9d9d7872012-08-17 13:42:25 -0700296 final int MTYPE_ARG = customized ? -1 : nameCursor++; // might be last in-argument
Christian Thalinger360d5122012-07-24 10:47:44 -0700297 final int CHECK_TYPE = nameCursor++;
298 final int LINKER_CALL = nameCursor++;
299 MethodType invokerFormType = mtype.invokerType();
300 if (isLinker) {
John R Rose9d9d7872012-08-17 13:42:25 -0700301 if (!customized)
302 invokerFormType = invokerFormType.appendParameterTypes(MemberName.class);
Christian Thalinger360d5122012-07-24 10:47:44 -0700303 } else {
304 invokerFormType = invokerFormType.invokerType();
305 }
306 Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType);
John R Rose9d9d7872012-08-17 13:42:25 -0700307 assert(names.length == nameCursor)
308 : Arrays.asList(mtype, customized, which, nameCursor, names.length);
Christian Thalinger360d5122012-07-24 10:47:44 -0700309 if (MTYPE_ARG >= INARG_LIMIT) {
310 assert(names[MTYPE_ARG] == null);
John R Rose62ee2112013-10-05 05:30:38 -0700311 NamedFunction getter = BoundMethodHandle.getSpeciesData("L").getterFunction(0);
312 names[MTYPE_ARG] = new Name(getter, names[THIS_MH]);
Christian Thalinger360d5122012-07-24 10:47:44 -0700313 // 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 Rose62ee2112013-10-05 05:30:38 -0700317 MethodType outCallType = mtype.basicType();
318 Object[] outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT, Object[].class);
John R Rose9d9d7872012-08-17 13:42:25 -0700319 Object mtypeArg = (customized ? mtype : names[MTYPE_ARG]);
Christian Thalinger360d5122012-07-24 10:47:44 -0700320 if (!isGeneric) {
John R Rose9d9d7872012-08-17 13:42:25 -0700321 names[CHECK_TYPE] = new Name(NF_checkExactType, names[CALL_MH], mtypeArg);
Christian Thalinger360d5122012-07-24 10:47:44 -0700322 // mh.invokeExact(a*):R => checkExactType(mh, TYPEOF(a*:R)); mh.invokeBasic(a*)
Christian Thalinger360d5122012-07-24 10:47:44 -0700323 } else {
John R Rose9d9d7872012-08-17 13:42:25 -0700324 names[CHECK_TYPE] = new Name(NF_checkGenericType, names[CALL_MH], mtypeArg);
John R Rose62ee2112013-10-05 05:30:38 -0700325 // mh.invokeGeneric(a*):R => checkGenericType(mh, TYPEOF(a*:R)).invokeBasic(a*)
326 outArgs[0] = names[CHECK_TYPE];
Christian Thalinger360d5122012-07-24 10:47:44 -0700327 }
John R Rose62ee2112013-10-05 05:30:38 -0700328 names[LINKER_CALL] = new Name(outCallType, outArgs);
Christian Thalinger360d5122012-07-24 10:47:44 -0700329 lform = new LambdaForm(debugName, INARG_LIMIT, names);
330 if (isLinker)
331 lform.compileToBytecode(); // JVM needs a real methodOop
John R Rose9d9d7872012-08-17 13:42:25 -0700332 if (isCached)
333 lform = mtype.form().setCachedLambdaForm(which, lform);
Christian Thalinger360d5122012-07-24 10:47:44 -0700334 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 Rose62ee2112013-10-05 05:30:38 -0700354 /** 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 Thalinger360d5122012-07-24 10:47:44 -0700358 /*non-public*/ static
359 @ForceInline
360 Object checkGenericType(Object mhObj, Object expectedObj) {
361 MethodHandle mh = (MethodHandle) mhObj;
362 MethodType expected = (MethodType) expectedObj;
John R Rose62ee2112013-10-05 05:30:38 -0700363 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 Thalinger360d5122012-07-24 10:47:44 -0700384 }
385
386 static MemberName linkToCallSiteMethod(MethodType mtype) {
John R Rose62ee2112013-10-05 05:30:38 -0700387 LambdaForm lform = callSiteForm(mtype, false);
Christian Thalinger360d5122012-07-24 10:47:44 -0700388 return lform.vmentry;
389 }
390
John R Rose62ee2112013-10-05 05:30:38 -0700391 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 Thalinger360d5122012-07-24 10:47:44 -0700398 mtype = mtype.basicType(); // normalize Z to I, String to Object, etc.
John R Rose62ee2112013-10-05 05:30:38 -0700399 final int which = (skipCallSite ? MethodTypeForm.LF_MH_LINKER : MethodTypeForm.LF_CS_LINKER);
400 LambdaForm lform = mtype.form().cachedLambdaForm(which);
Christian Thalinger360d5122012-07-24 10:47:44 -0700401 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 Rose62ee2112013-10-05 05:30:38 -0700408 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 Thalinger360d5122012-07-24 10:47:44 -0700411 final int LINKER_CALL = nameCursor++;
John R Rose62ee2112013-10-05 05:30:38 -0700412 MethodType invokerFormType = mtype.appendParameterTypes(skipCallSite ? MethodHandle.class : CallSite.class);
Christian Thalinger360d5122012-07-24 10:47:44 -0700413 Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType);
414 assert(names.length == nameCursor);
John R Rose62ee2112013-10-05 05:30:38 -0700415 assert(names[APPENDIX_ARG] != null);
416 if (!skipCallSite)
417 names[CALL_MH] = new Name(NF_getCallSiteTarget, names[CSITE_ARG]);
Christian Thalinger360d5122012-07-24 10:47:44 -0700418 // (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 Rose62ee2112013-10-05 05:30:38 -0700424 names[LINKER_CALL] = new Name(mtype, outArgs);
425 lform = new LambdaForm((skipCallSite ? "linkToTargetMethod" : "linkToCallSite"), INARG_LIMIT, names);
Christian Thalinger360d5122012-07-24 10:47:44 -0700426 lform.compileToBytecode(); // JVM needs a real methodOop
John R Rose62ee2112013-10-05 05:30:38 -0700427 lform = mtype.form().setCachedLambdaForm(which, lform);
Christian Thalinger360d5122012-07-24 10:47:44 -0700428 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 Rose9d9d7872012-08-17 13:42:25 -0700441 private static final NamedFunction NF_asType;
Christian Thalinger360d5122012-07-24 10:47:44 -0700442 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 Rose9d9d7872012-08-17 13:42:25 -0700449 NF_asType = new NamedFunction(MethodHandle.class
450 .getDeclaredMethod("asType", MethodType.class));
Christian Thalinger360d5122012-07-24 10:47:44 -0700451 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 Thalinger01d0ba62012-10-19 17:04:35 -0700458 throw newInternalError(ex);
Christian Thalinger360d5122012-07-24 10:47:44 -0700459 }
460 }
461
John R Rosefb6164c2009-05-05 22:40:09 -0700462}