blob: 0e40396a96fb447c3d2d4eba8ae7f159686dbd4a [file] [log] [blame]
John R Rosefb6164c2009-05-05 22:40:09 -07001/*
John R Roseeedbeda2011-02-11 01:26:24 -08002 * Copyright (c) 2008, 2011, 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;
47
John R Rose2a322bb2010-10-30 21:02:30 -070048 // erased (partially untyped but with primitives) invoker for the outgoing call
Christian Thalinger360d5122012-07-24 10:47:44 -070049 // FIXME: get rid of
John R Rose2a322bb2010-10-30 21:02:30 -070050 private /*lazy*/ MethodHandle erasedInvoker;
Christian Thalinger360d5122012-07-24 10:47:44 -070051 // FIXME: get rid of
John R Rose2a322bb2010-10-30 21:02:30 -070052 /*lazy*/ MethodHandle erasedInvokerWithDrops; // for InvokeGeneric
53
John R Roseeb963252011-05-12 19:27:33 -070054 // general invoker for the outgoing call
55 private /*lazy*/ MethodHandle generalInvoker;
John R Rosefb6164c2009-05-05 22:40:09 -070056
John R Rose025d0ae2011-05-26 17:37:36 -070057 // general invoker for the outgoing call, uses varargs
58 private /*lazy*/ MethodHandle varargsInvoker;
59
60 // general invoker for the outgoing call; accepts a trailing Object[]
John R Roseeedbeda2011-02-11 01:26:24 -080061 private final /*lazy*/ MethodHandle[] spreadInvokers;
John R Rose020e5502010-01-07 16:16:45 -080062
John R Rose4f508ab2010-10-30 21:08:23 -070063 // invoker for an unbound callsite
64 private /*lazy*/ MethodHandle uninitializedCallSite;
65
John R Rosefb6164c2009-05-05 22:40:09 -070066 /** Compute and cache information common to all collecting adapters
67 * that implement members of the erasure-family of the given erased type.
68 */
John R Roseeedbeda2011-02-11 01:26:24 -080069 /*non-public*/ Invokers(MethodType targetType) {
John R Rosefb6164c2009-05-05 22:40:09 -070070 this.targetType = targetType;
John R Roseeedbeda2011-02-11 01:26:24 -080071 this.spreadInvokers = new MethodHandle[targetType.parameterCount()+1];
John R Rosefb6164c2009-05-05 22:40:09 -070072 }
73
John R Rosee7ebd472011-03-18 00:03:24 -070074 /*non-public*/ MethodHandle exactInvoker() {
John R Rosefb6164c2009-05-05 22:40:09 -070075 MethodHandle invoker = exactInvoker;
76 if (invoker != null) return invoker;
Christian Thalinger360d5122012-07-24 10:47:44 -070077 MethodType mtype = targetType;
John R Rose9d9d7872012-08-17 13:42:25 -070078 MethodType invokerType = mtype.invokerType();
79 LambdaForm lform;
80 final int MTYPE_ARG_APPENDED = 1; // argument count for appended mtype value
81 if (mtype.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY - MTYPE_ARG_APPENDED) {
82 lform = invokeForm(mtype, false, MethodTypeForm.LF_EX_INVOKER);
83 invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype);
84 } else {
85 // At maximum arity, we cannot afford an extra mtype argument,
86 // so build a fully customized (non-cached) invoker form.
87 lform = invokeForm(mtype, true, MethodTypeForm.LF_EX_INVOKER);
88 invoker = SimpleMethodHandle.make(invokerType, lform);
89 }
Christian Thalinger360d5122012-07-24 10:47:44 -070090 assert(checkInvoker(invoker));
John R Rosefb6164c2009-05-05 22:40:09 -070091 exactInvoker = invoker;
92 return invoker;
93 }
94
John R Roseeb963252011-05-12 19:27:33 -070095 /*non-public*/ MethodHandle generalInvoker() {
John R Roseeb963252011-05-12 19:27:33 -070096 MethodHandle invoker = generalInvoker;
John R Rosefb6164c2009-05-05 22:40:09 -070097 if (invoker != null) return invoker;
Christian Thalinger360d5122012-07-24 10:47:44 -070098 MethodType mtype = targetType;
John R Rose9d9d7872012-08-17 13:42:25 -070099 MethodType invokerType = mtype.invokerType();
100 LambdaForm lform;
101 final int MTYPE_ARG_APPENDED = 1; // argument count for appended mtype value
102 assert(GENERIC_INVOKER_SLOP >= MTYPE_ARG_APPENDED);
103 if (mtype.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY - GENERIC_INVOKER_SLOP) {
104 prepareForGenericCall(mtype);
105 lform = invokeForm(mtype, false, MethodTypeForm.LF_GEN_INVOKER);
106 invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype);
107 } else {
108 // At maximum arity, we cannot afford an extra mtype argument,
109 // so build a fully customized (non-cached) invoker form.
110 lform = invokeForm(mtype, true, MethodTypeForm.LF_GEN_INVOKER);
111 invoker = SimpleMethodHandle.make(invokerType, lform);
112 }
Christian Thalinger360d5122012-07-24 10:47:44 -0700113 assert(checkInvoker(invoker));
John R Roseeb963252011-05-12 19:27:33 -0700114 generalInvoker = invoker;
John R Rosefb6164c2009-05-05 22:40:09 -0700115 return invoker;
116 }
117
Christian Thalinger360d5122012-07-24 10:47:44 -0700118 /*non-public*/ MethodHandle makeBasicInvoker() {
119 MethodHandle invoker = DirectMethodHandle.make(invokeBasicMethod(targetType));
120 assert(targetType == targetType.basicType());
121 // Note: This is not cached here. It is cached by the calling MethodTypeForm.
122 assert(checkInvoker(invoker));
John R Rose025d0ae2011-05-26 17:37:36 -0700123 return invoker;
124 }
125
Christian Thalinger360d5122012-07-24 10:47:44 -0700126 static MemberName invokeBasicMethod(MethodType type) {
John R Rose9d9d7872012-08-17 13:42:25 -0700127 type = type.basicType();
Christian Thalinger360d5122012-07-24 10:47:44 -0700128 String name = "invokeBasic";
129 try {
130 //Lookup.findVirtual(MethodHandle.class, name, type);
131 return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, name, type);
Christian Thalinger360d5122012-07-24 10:47:44 -0700132 } catch (ReflectiveOperationException ex) {
Christian Thalinger01d0ba62012-10-19 17:04:35 -0700133 throw newInternalError("JVM cannot find invoker for "+type, ex);
Christian Thalinger360d5122012-07-24 10:47:44 -0700134 }
135 }
136
137 private boolean checkInvoker(MethodHandle invoker) {
138 assert(targetType.invokerType().equals(invoker.type()))
139 : java.util.Arrays.asList(targetType, targetType.invokerType(), invoker);
140 assert(invoker.internalMemberName() == null ||
141 invoker.internalMemberName().getMethodType().equals(targetType));
142 assert(!invoker.isVarargsCollector());
143 return true;
144 }
145
146 // FIXME: get rid of
John R Rosee7ebd472011-03-18 00:03:24 -0700147 /*non-public*/ MethodHandle erasedInvoker() {
John R Rose025d0ae2011-05-26 17:37:36 -0700148 MethodHandle xinvoker = exactInvoker();
John R Rose2a322bb2010-10-30 21:02:30 -0700149 MethodHandle invoker = erasedInvoker;
150 if (invoker != null) return invoker;
151 MethodType erasedType = targetType.erase();
Christian Thalinger360d5122012-07-24 10:47:44 -0700152 invoker = xinvoker.asType(erasedType.invokerType());
John R Rose2a322bb2010-10-30 21:02:30 -0700153 erasedInvoker = invoker;
154 return invoker;
155 }
156
John R Rose025d0ae2011-05-26 17:37:36 -0700157 /*non-public*/ MethodHandle spreadInvoker(int leadingArgCount) {
158 MethodHandle vaInvoker = spreadInvokers[leadingArgCount];
John R Rose020e5502010-01-07 16:16:45 -0800159 if (vaInvoker != null) return vaInvoker;
John R Rose025d0ae2011-05-26 17:37:36 -0700160 int spreadArgCount = targetType.parameterCount() - leadingArgCount;
John R Rose9d9d7872012-08-17 13:42:25 -0700161 MethodType spreadInvokerType = targetType
162 .replaceParameterTypes(leadingArgCount, targetType.parameterCount(), Object[].class);
163 if (targetType.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY) {
164 // Factor sinvoker.invoke(mh, a) into ginvoker.asSpreader().invoke(mh, a)
165 // where ginvoker.invoke(mh, a*) => mh.invoke(a*).
166 MethodHandle genInvoker = generalInvoker();
167 vaInvoker = genInvoker.asSpreader(Object[].class, spreadArgCount);
168 } else {
169 // Cannot build a general invoker here of type ginvoker.invoke(mh, a*[254]).
170 // Instead, factor sinvoker.invoke(mh, a) into ainvoker.invoke(filter(mh), a)
171 // where filter(mh) == mh.asSpreader(Object[], spreadArgCount)
172 MethodHandle arrayInvoker = MethodHandles.exactInvoker(spreadInvokerType);
173 MethodHandle makeSpreader;
174 try {
175 makeSpreader = IMPL_LOOKUP
176 .findVirtual(MethodHandle.class, "asSpreader",
177 MethodType.methodType(MethodHandle.class, Class.class, int.class));
178 } catch (ReflectiveOperationException ex) {
Christian Thalinger01d0ba62012-10-19 17:04:35 -0700179 throw newInternalError(ex);
John R Rose9d9d7872012-08-17 13:42:25 -0700180 }
181 makeSpreader = MethodHandles.insertArguments(makeSpreader, 1, Object[].class, spreadArgCount);
182 vaInvoker = MethodHandles.filterArgument(arrayInvoker, 0, makeSpreader);
183 }
184 assert(vaInvoker.type().equals(spreadInvokerType.invokerType()));
John R Rose025d0ae2011-05-26 17:37:36 -0700185 spreadInvokers[leadingArgCount] = vaInvoker;
186 return vaInvoker;
187 }
188
189 /*non-public*/ MethodHandle varargsInvoker() {
190 MethodHandle vaInvoker = varargsInvoker;
191 if (vaInvoker != null) return vaInvoker;
Christian Thalinger360d5122012-07-24 10:47:44 -0700192 vaInvoker = spreadInvoker(0).asType(MethodType.genericMethodType(0, true).invokerType());
John R Rose025d0ae2011-05-26 17:37:36 -0700193 varargsInvoker = vaInvoker;
John R Rose020e5502010-01-07 16:16:45 -0800194 return vaInvoker;
John R Rosefb6164c2009-05-05 22:40:09 -0700195 }
196
John R Rose4f508ab2010-10-30 21:08:23 -0700197 private static MethodHandle THROW_UCS = null;
198
John R Rosee7ebd472011-03-18 00:03:24 -0700199 /*non-public*/ MethodHandle uninitializedCallSite() {
John R Rose4f508ab2010-10-30 21:08:23 -0700200 MethodHandle invoker = uninitializedCallSite;
201 if (invoker != null) return invoker;
202 if (targetType.parameterCount() > 0) {
203 MethodType type0 = targetType.dropParameterTypes(0, targetType.parameterCount());
John R Rosee7ebd472011-03-18 00:03:24 -0700204 Invokers invokers0 = type0.invokers();
John R Rose4f508ab2010-10-30 21:08:23 -0700205 invoker = MethodHandles.dropArguments(invokers0.uninitializedCallSite(),
206 0, targetType.parameterList());
207 assert(invoker.type().equals(targetType));
208 uninitializedCallSite = invoker;
209 return invoker;
210 }
Christian Thalinger360d5122012-07-24 10:47:44 -0700211 invoker = THROW_UCS;
212 if (invoker == null) {
John R Rose4f508ab2010-10-30 21:08:23 -0700213 try {
Christian Thalinger360d5122012-07-24 10:47:44 -0700214 THROW_UCS = invoker = IMPL_LOOKUP
John R Rose4f508ab2010-10-30 21:08:23 -0700215 .findStatic(CallSite.class, "uninitializedCallSite",
216 MethodType.methodType(Empty.class));
John R Rosef485ab52011-02-11 01:26:32 -0800217 } catch (ReflectiveOperationException ex) {
Christian Thalinger01d0ba62012-10-19 17:04:35 -0700218 throw newInternalError(ex);
John R Rose4f508ab2010-10-30 21:08:23 -0700219 }
220 }
Christian Thalinger360d5122012-07-24 10:47:44 -0700221 invoker = MethodHandles.explicitCastArguments(invoker, MethodType.methodType(targetType.returnType()));
222 invoker = invoker.dropArguments(targetType, 0, targetType.parameterCount());
John R Rose4f508ab2010-10-30 21:08:23 -0700223 assert(invoker.type().equals(targetType));
224 uninitializedCallSite = invoker;
225 return invoker;
226 }
227
John R Rosefb6164c2009-05-05 22:40:09 -0700228 public String toString() {
229 return "Invokers"+targetType;
230 }
Christian Thalinger360d5122012-07-24 10:47:44 -0700231
John R Rose9d9d7872012-08-17 13:42:25 -0700232 static MemberName exactInvokerMethod(MethodType mtype, Object[] appendixResult) {
233 LambdaForm lform;
234 final int MTYPE_ARG_APPENDED = 1; // argument count for appended mtype value
235 if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - MTYPE_ARG_APPENDED) {
236 lform = invokeForm(mtype, false, MethodTypeForm.LF_EX_LINKER);
237 appendixResult[0] = mtype;
238 } else {
239 lform = invokeForm(mtype, true, MethodTypeForm.LF_EX_LINKER);
240 }
Christian Thalinger360d5122012-07-24 10:47:44 -0700241 return lform.vmentry;
242 }
243
John R Rose9d9d7872012-08-17 13:42:25 -0700244 static MemberName genericInvokerMethod(MethodType mtype, Object[] appendixResult) {
245 LambdaForm lform;
246 final int MTYPE_ARG_APPENDED = 1; // argument count for appended mtype value
247 if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - (MTYPE_ARG_APPENDED + GENERIC_INVOKER_SLOP)) {
248 lform = invokeForm(mtype, false, MethodTypeForm.LF_GEN_LINKER);
249 appendixResult[0] = mtype;
250 prepareForGenericCall(mtype);
251 } else {
252 lform = invokeForm(mtype, true, MethodTypeForm.LF_GEN_LINKER);
253 }
Christian Thalinger360d5122012-07-24 10:47:44 -0700254 return lform.vmentry;
255 }
256
John R Rose9d9d7872012-08-17 13:42:25 -0700257 private static LambdaForm invokeForm(MethodType mtype, boolean customized, int which) {
258 boolean isCached;
259 if (!customized) {
260 mtype = mtype.basicType(); // normalize Z to I, String to Object, etc.
261 isCached = true;
262 } else {
263 isCached = false; // maybe cache if mtype == mtype.basicType()
264 }
Christian Thalinger360d5122012-07-24 10:47:44 -0700265 boolean isLinker, isGeneric;
266 String debugName;
267 switch (which) {
268 case MethodTypeForm.LF_EX_LINKER: isLinker = true; isGeneric = false; debugName = "invokeExact_MT"; break;
269 case MethodTypeForm.LF_EX_INVOKER: isLinker = false; isGeneric = false; debugName = "exactInvoker"; break;
270 case MethodTypeForm.LF_GEN_LINKER: isLinker = true; isGeneric = true; debugName = "invoke_MT"; break;
271 case MethodTypeForm.LF_GEN_INVOKER: isLinker = false; isGeneric = true; debugName = "invoker"; break;
272 default: throw new InternalError();
273 }
John R Rose9d9d7872012-08-17 13:42:25 -0700274 LambdaForm lform;
275 if (isCached) {
276 lform = mtype.form().cachedLambdaForm(which);
277 if (lform != null) return lform;
278 }
Christian Thalinger360d5122012-07-24 10:47:44 -0700279 // exactInvokerForm (Object,Object)Object
280 // link with java.lang.invoke.MethodHandle.invokeBasic(MethodHandle,Object,Object)Object/invokeSpecial
281 final int THIS_MH = 0;
282 final int CALL_MH = THIS_MH + (isLinker ? 0 : 1);
283 final int ARG_BASE = CALL_MH + 1;
284 final int OUTARG_LIMIT = ARG_BASE + mtype.parameterCount();
John R Rose9d9d7872012-08-17 13:42:25 -0700285 final int INARG_LIMIT = OUTARG_LIMIT + (isLinker && !customized ? 1 : 0);
Christian Thalinger360d5122012-07-24 10:47:44 -0700286 int nameCursor = OUTARG_LIMIT;
John R Rose9d9d7872012-08-17 13:42:25 -0700287 final int MTYPE_ARG = customized ? -1 : nameCursor++; // might be last in-argument
Christian Thalinger360d5122012-07-24 10:47:44 -0700288 final int CHECK_TYPE = nameCursor++;
289 final int LINKER_CALL = nameCursor++;
290 MethodType invokerFormType = mtype.invokerType();
291 if (isLinker) {
John R Rose9d9d7872012-08-17 13:42:25 -0700292 if (!customized)
293 invokerFormType = invokerFormType.appendParameterTypes(MemberName.class);
Christian Thalinger360d5122012-07-24 10:47:44 -0700294 } else {
295 invokerFormType = invokerFormType.invokerType();
296 }
297 Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType);
John R Rose9d9d7872012-08-17 13:42:25 -0700298 assert(names.length == nameCursor)
299 : Arrays.asList(mtype, customized, which, nameCursor, names.length);
Christian Thalinger360d5122012-07-24 10:47:44 -0700300 if (MTYPE_ARG >= INARG_LIMIT) {
301 assert(names[MTYPE_ARG] == null);
302 names[MTYPE_ARG] = BoundMethodHandle.getSpeciesData("L").getterName(names[THIS_MH], 0);
303 // else if isLinker, then MTYPE is passed in from the caller (e.g., the JVM)
304 }
305
306 // Make the final call. If isGeneric, then prepend the result of type checking.
307 MethodType outCallType;
308 Object[] outArgs;
John R Rose9d9d7872012-08-17 13:42:25 -0700309 Object mtypeArg = (customized ? mtype : names[MTYPE_ARG]);
Christian Thalinger360d5122012-07-24 10:47:44 -0700310 if (!isGeneric) {
John R Rose9d9d7872012-08-17 13:42:25 -0700311 names[CHECK_TYPE] = new Name(NF_checkExactType, names[CALL_MH], mtypeArg);
Christian Thalinger360d5122012-07-24 10:47:44 -0700312 // mh.invokeExact(a*):R => checkExactType(mh, TYPEOF(a*:R)); mh.invokeBasic(a*)
313 outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT, Object[].class);
314 outCallType = mtype;
John R Rose9d9d7872012-08-17 13:42:25 -0700315 } else if (customized) {
316 names[CHECK_TYPE] = new Name(NF_asType, names[CALL_MH], mtypeArg);
317 // mh.invokeGeneric(a*):R =>
318 // let mt=TYPEOF(a*:R), tmh=asType(mh, mt);
319 // tmh.invokeBasic(a*)
320 outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT, Object[].class);
321 outCallType = mtype;
Christian Thalinger360d5122012-07-24 10:47:44 -0700322 } else {
John R Rose9d9d7872012-08-17 13:42:25 -0700323 names[CHECK_TYPE] = new Name(NF_checkGenericType, names[CALL_MH], mtypeArg);
Christian Thalinger360d5122012-07-24 10:47:44 -0700324 // mh.invokeGeneric(a*):R =>
325 // let mt=TYPEOF(a*:R), gamh=checkGenericType(mh, mt);
326 // gamh.invokeBasic(mt, mh, a*)
327 final int PREPEND_GAMH = 0, PREPEND_MT = 1, PREPEND_COUNT = 2;
John R Rose9d9d7872012-08-17 13:42:25 -0700328 assert(GENERIC_INVOKER_SLOP == PREPEND_COUNT);
Christian Thalinger360d5122012-07-24 10:47:44 -0700329 outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT + PREPEND_COUNT, Object[].class);
330 // prepend arguments:
331 System.arraycopy(outArgs, 0, outArgs, PREPEND_COUNT, outArgs.length - PREPEND_COUNT);
332 outArgs[PREPEND_GAMH] = names[CHECK_TYPE];
John R Rose9d9d7872012-08-17 13:42:25 -0700333 outArgs[PREPEND_MT] = mtypeArg;
Christian Thalinger360d5122012-07-24 10:47:44 -0700334 outCallType = mtype.insertParameterTypes(0, MethodType.class, MethodHandle.class);
335 }
336 names[LINKER_CALL] = new Name(invokeBasicMethod(outCallType), outArgs);
337 lform = new LambdaForm(debugName, INARG_LIMIT, names);
338 if (isLinker)
339 lform.compileToBytecode(); // JVM needs a real methodOop
John R Rose9d9d7872012-08-17 13:42:25 -0700340 if (isCached)
341 lform = mtype.form().setCachedLambdaForm(which, lform);
Christian Thalinger360d5122012-07-24 10:47:44 -0700342 return lform;
343 }
John R Rose9d9d7872012-08-17 13:42:25 -0700344 private static final int GENERIC_INVOKER_SLOP = 2; // used elsewhere to avoid arity problems
Christian Thalinger360d5122012-07-24 10:47:44 -0700345
346 /*non-public*/ static
347 WrongMethodTypeException newWrongMethodTypeException(MethodType actual, MethodType expected) {
348 // FIXME: merge with JVM logic for throwing WMTE
349 return new WrongMethodTypeException("expected "+expected+" but found "+actual);
350 }
351
352 /** Static definition of MethodHandle.invokeExact checking code. */
353 /*non-public*/ static
354 @ForceInline
355 void checkExactType(Object mhObj, Object expectedObj) {
356 MethodHandle mh = (MethodHandle) mhObj;
357 MethodType expected = (MethodType) expectedObj;
358 MethodType actual = mh.type();
359 if (actual != expected)
360 throw newWrongMethodTypeException(expected, actual);
361 }
362
363 /** Static definition of MethodHandle.invokeGeneric checking code. */
364 /*non-public*/ static
365 @ForceInline
366 Object checkGenericType(Object mhObj, Object expectedObj) {
367 MethodHandle mh = (MethodHandle) mhObj;
368 MethodType expected = (MethodType) expectedObj;
369 //MethodType actual = mh.type();
370 MethodHandle gamh = expected.form().genericInvoker;
371 if (gamh != null) return gamh;
372 return prepareForGenericCall(expected);
373 }
374
375 /**
376 * Returns an adapter GA for invoking a MH with type adjustments.
377 * The MethodType of the generic invocation site is prepended to MH
378 * and its arguments as follows:
379 * {@code (R)MH.invoke(A*) => GA.invokeBasic(TYPEOF<A*,R>, MH, A*)}
380 */
381 /*non-public*/ static MethodHandle prepareForGenericCall(MethodType mtype) {
382 // force any needed adapters to be preconstructed
383 MethodTypeForm form = mtype.form();
384 MethodHandle gamh = form.genericInvoker;
385 if (gamh != null) return gamh;
386 try {
387 // Trigger adapter creation.
388 gamh = InvokeGeneric.generalInvokerOf(form.erasedType);
389 form.genericInvoker = gamh;
390 return gamh;
391 } catch (Exception ex) {
Christian Thalinger01d0ba62012-10-19 17:04:35 -0700392 throw newInternalError("Exception while resolving inexact invoke", ex);
Christian Thalinger360d5122012-07-24 10:47:44 -0700393 }
394 }
395
396 static MemberName linkToCallSiteMethod(MethodType mtype) {
397 LambdaForm lform = callSiteForm(mtype);
398 return lform.vmentry;
399 }
400
401 private static LambdaForm callSiteForm(MethodType mtype) {
402 mtype = mtype.basicType(); // normalize Z to I, String to Object, etc.
403 LambdaForm lform = mtype.form().cachedLambdaForm(MethodTypeForm.LF_CS_LINKER);
404 if (lform != null) return lform;
405 // exactInvokerForm (Object,Object)Object
406 // link with java.lang.invoke.MethodHandle.invokeBasic(MethodHandle,Object,Object)Object/invokeSpecial
407 final int ARG_BASE = 0;
408 final int OUTARG_LIMIT = ARG_BASE + mtype.parameterCount();
409 final int INARG_LIMIT = OUTARG_LIMIT + 1;
410 int nameCursor = OUTARG_LIMIT;
411 final int CSITE_ARG = nameCursor++; // the last in-argument
412 final int CALL_MH = nameCursor++; // result of getTarget
413 final int LINKER_CALL = nameCursor++;
414 MethodType invokerFormType = mtype.appendParameterTypes(CallSite.class);
415 Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType);
416 assert(names.length == nameCursor);
417 assert(names[CSITE_ARG] != null);
418 names[CALL_MH] = new Name(NF_getCallSiteTarget, names[CSITE_ARG]);
419 // (site.)invokedynamic(a*):R => mh = site.getTarget(); mh.invokeBasic(a*)
420 final int PREPEND_MH = 0, PREPEND_COUNT = 1;
421 Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, OUTARG_LIMIT + PREPEND_COUNT, Object[].class);
422 // prepend MH argument:
423 System.arraycopy(outArgs, 0, outArgs, PREPEND_COUNT, outArgs.length - PREPEND_COUNT);
424 outArgs[PREPEND_MH] = names[CALL_MH];
425 names[LINKER_CALL] = new Name(invokeBasicMethod(mtype), outArgs);
426 lform = new LambdaForm("linkToCallSite", INARG_LIMIT, names);
427 lform.compileToBytecode(); // JVM needs a real methodOop
428 lform = mtype.form().setCachedLambdaForm(MethodTypeForm.LF_CS_LINKER, lform);
429 return lform;
430 }
431
432 /** Static definition of MethodHandle.invokeGeneric checking code. */
433 /*non-public*/ static
434 @ForceInline
435 Object getCallSiteTarget(Object site) {
436 return ((CallSite)site).getTarget();
437 }
438
439 // Local constant functions:
440 private static final NamedFunction NF_checkExactType;
441 private static final NamedFunction NF_checkGenericType;
John R Rose9d9d7872012-08-17 13:42:25 -0700442 private static final NamedFunction NF_asType;
Christian Thalinger360d5122012-07-24 10:47:44 -0700443 private static final NamedFunction NF_getCallSiteTarget;
444 static {
445 try {
446 NF_checkExactType = new NamedFunction(Invokers.class
447 .getDeclaredMethod("checkExactType", Object.class, Object.class));
448 NF_checkGenericType = new NamedFunction(Invokers.class
449 .getDeclaredMethod("checkGenericType", Object.class, Object.class));
John R Rose9d9d7872012-08-17 13:42:25 -0700450 NF_asType = new NamedFunction(MethodHandle.class
451 .getDeclaredMethod("asType", MethodType.class));
Christian Thalinger360d5122012-07-24 10:47:44 -0700452 NF_getCallSiteTarget = new NamedFunction(Invokers.class
453 .getDeclaredMethod("getCallSiteTarget", Object.class));
454 NF_checkExactType.resolve();
455 NF_checkGenericType.resolve();
456 NF_getCallSiteTarget.resolve();
457 // bound
458 } catch (ReflectiveOperationException ex) {
Christian Thalinger01d0ba62012-10-19 17:04:35 -0700459 throw newInternalError(ex);
Christian Thalinger360d5122012-07-24 10:47:44 -0700460 }
461 }
462
John R Rosefb6164c2009-05-05 22:40:09 -0700463}