blob: 29cc430f877f2047144c5fb6a0892ef25be52ff4 [file] [log] [blame]
John R Rosefb6164c2009-05-05 22:40:09 -07001/*
Shilpi Rastogiff976592016-02-10 11:04:13 +01002 * Copyright (c) 2008, 2016, 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
Paul Sandozc464a9d2015-12-03 11:17:31 +010028import jdk.internal.vm.annotation.DontInline;
29import jdk.internal.vm.annotation.ForceInline;
30import jdk.internal.vm.annotation.Stable;
31
John Rose6a177f42014-09-10 19:19:48 +040032import java.lang.reflect.Array;
Christian Thalinger360d5122012-07-24 10:47:44 -070033import java.util.Arrays;
John Rose6a177f42014-09-10 19:19:48 +040034
Christian Thalinger01d0ba62012-10-19 17:04:35 -070035import static java.lang.invoke.MethodHandleStatics.*;
Christian Thalinger360d5122012-07-24 10:47:44 -070036import static java.lang.invoke.MethodHandleNatives.Constants.*;
John R Rose37188242011-03-23 23:02:31 -070037import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
Christian Thalinger360d5122012-07-24 10:47:44 -070038import static java.lang.invoke.LambdaForm.*;
John R Rosefb6164c2009-05-05 22:40:09 -070039
40/**
41 * Construction and caching of often-used invokers.
42 * @author jrose
43 */
John R Rosee7ebd472011-03-18 00:03:24 -070044class Invokers {
Pavel Rappo7075a992014-08-11 21:03:59 +010045 // exact type (sans leading target MH) for the outgoing call
John R Rosefb6164c2009-05-05 22:40:09 -070046 private final MethodType targetType;
47
John Rose6a177f42014-09-10 19:19:48 +040048 // Cached adapter information:
49 private final @Stable MethodHandle[] invokers = new MethodHandle[INV_LIMIT];
50 // Indexes into invokers:
51 static final int
52 INV_EXACT = 0, // MethodHandles.exactInvoker
53 INV_GENERIC = 1, // MethodHandles.invoker (generic invocation)
54 INV_BASIC = 2, // MethodHandles.basicInvoker
55 INV_LIMIT = 3;
John R Rose4f508ab2010-10-30 21:08:23 -070056
John R Rosefb6164c2009-05-05 22:40:09 -070057 /** Compute and cache information common to all collecting adapters
58 * that implement members of the erasure-family of the given erased type.
59 */
John R Roseeedbeda2011-02-11 01:26:24 -080060 /*non-public*/ Invokers(MethodType targetType) {
John R Rosefb6164c2009-05-05 22:40:09 -070061 this.targetType = targetType;
62 }
63
John R Rosee7ebd472011-03-18 00:03:24 -070064 /*non-public*/ MethodHandle exactInvoker() {
John Rose6a177f42014-09-10 19:19:48 +040065 MethodHandle invoker = cachedInvoker(INV_EXACT);
John R Rosefb6164c2009-05-05 22:40:09 -070066 if (invoker != null) return invoker;
John R Rose62ee2112013-10-05 05:30:38 -070067 invoker = makeExactOrGeneralInvoker(true);
John Rose6a177f42014-09-10 19:19:48 +040068 return setCachedInvoker(INV_EXACT, invoker);
John R Rosefb6164c2009-05-05 22:40:09 -070069 }
70
John Rose6a177f42014-09-10 19:19:48 +040071 /*non-public*/ MethodHandle genericInvoker() {
72 MethodHandle invoker = cachedInvoker(INV_GENERIC);
John R Rosefb6164c2009-05-05 22:40:09 -070073 if (invoker != null) return invoker;
John R Rose62ee2112013-10-05 05:30:38 -070074 invoker = makeExactOrGeneralInvoker(false);
John Rose6a177f42014-09-10 19:19:48 +040075 return setCachedInvoker(INV_GENERIC, invoker);
76 }
77
78 /*non-public*/ MethodHandle basicInvoker() {
79 MethodHandle invoker = cachedInvoker(INV_BASIC);
80 if (invoker != null) return invoker;
81 MethodType basicType = targetType.basicType();
82 if (basicType != targetType) {
83 // double cache; not used significantly
84 return setCachedInvoker(INV_BASIC, basicType.invokers().basicInvoker());
85 }
86 invoker = basicType.form().cachedMethodHandle(MethodTypeForm.MH_BASIC_INV);
87 if (invoker == null) {
88 MemberName method = invokeBasicMethod(basicType);
89 invoker = DirectMethodHandle.make(method);
90 assert(checkInvoker(invoker));
91 invoker = basicType.form().setCachedMethodHandle(MethodTypeForm.MH_BASIC_INV, invoker);
92 }
93 return setCachedInvoker(INV_BASIC, invoker);
94 }
95
Paul Sandoz9fb30a32016-03-24 11:21:21 +010096 /*non-public*/ MethodHandle varHandleMethodInvoker(VarHandle.AccessMode ak) {
97 // TODO cache invoker
98 return makeVarHandleMethodInvoker(ak);
99 }
100
101 /*non-public*/ MethodHandle varHandleMethodExactInvoker(VarHandle.AccessMode ak) {
102 // TODO cache invoker
103 return makeVarHandleMethodExactInvoker(ak);
104 }
105
John Rose6a177f42014-09-10 19:19:48 +0400106 private MethodHandle cachedInvoker(int idx) {
107 return invokers[idx];
108 }
109
110 private synchronized MethodHandle setCachedInvoker(int idx, final MethodHandle invoker) {
111 // Simulate a CAS, to avoid racy duplication of results.
112 MethodHandle prev = invokers[idx];
113 if (prev != null) return prev;
114 return invokers[idx] = invoker;
John R Rosefb6164c2009-05-05 22:40:09 -0700115 }
116
John R Rose62ee2112013-10-05 05:30:38 -0700117 private MethodHandle makeExactOrGeneralInvoker(boolean isExact) {
118 MethodType mtype = targetType;
119 MethodType invokerType = mtype.invokerType();
120 int which = (isExact ? MethodTypeForm.LF_EX_INVOKER : MethodTypeForm.LF_GEN_INVOKER);
121 LambdaForm lform = invokeHandleForm(mtype, false, which);
122 MethodHandle invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype);
123 String whichName = (isExact ? "invokeExact" : "invoke");
John Rosefb7b2ac2014-09-10 19:19:49 +0400124 invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke(whichName, mtype), false);
Christian Thalinger360d5122012-07-24 10:47:44 -0700125 assert(checkInvoker(invoker));
John R Rose62ee2112013-10-05 05:30:38 -0700126 maybeCompileToBytecode(invoker);
John R Rose025d0ae2011-05-26 17:37:36 -0700127 return invoker;
128 }
129
Paul Sandoz9fb30a32016-03-24 11:21:21 +0100130 private MethodHandle makeVarHandleMethodInvoker(VarHandle.AccessMode ak) {
131 MethodType mtype = targetType;
132 MethodType invokerType = mtype.insertParameterTypes(0, VarHandle.class);
133
Paul Sandoza7aff442016-04-13 15:05:48 +0200134 LambdaForm lform = varHandleMethodGenericInvokerHandleForm(ak.methodName(), mtype);
Paul Sandoz9fb30a32016-03-24 11:21:21 +0100135 VarHandle.AccessDescriptor ad = new VarHandle.AccessDescriptor(mtype, ak.at.ordinal(), ak.ordinal());
136 MethodHandle invoker = BoundMethodHandle.bindSingle(invokerType, lform, ad);
137
Paul Sandoza7aff442016-04-13 15:05:48 +0200138 invoker = invoker.withInternalMemberName(MemberName.makeVarHandleMethodInvoke(ak.methodName(), mtype), false);
Paul Sandoz9fb30a32016-03-24 11:21:21 +0100139 assert(checkVarHandleInvoker(invoker));
140
141 maybeCompileToBytecode(invoker);
142 return invoker;
143 }
144
145 private MethodHandle makeVarHandleMethodExactInvoker(VarHandle.AccessMode ak) {
146 MethodType mtype = targetType;
147 MethodType invokerType = mtype.insertParameterTypes(0, VarHandle.class);
148
Paul Sandoza7aff442016-04-13 15:05:48 +0200149 LambdaForm lform = varHandleMethodExactInvokerHandleForm(ak.methodName(), mtype);
Paul Sandoz9fb30a32016-03-24 11:21:21 +0100150 VarHandle.AccessDescriptor ad = new VarHandle.AccessDescriptor(mtype, ak.at.ordinal(), ak.ordinal());
151 MethodHandle invoker = BoundMethodHandle.bindSingle(invokerType, lform, ad);
152
Paul Sandoza7aff442016-04-13 15:05:48 +0200153 invoker = invoker.withInternalMemberName(MemberName.makeVarHandleMethodInvoke(ak.methodName(), mtype), false);
Paul Sandoz9fb30a32016-03-24 11:21:21 +0100154 assert(checkVarHandleInvoker(invoker));
155
156 maybeCompileToBytecode(invoker);
157 return invoker;
158 }
159
John R Rose62ee2112013-10-05 05:30:38 -0700160 /** If the target type seems to be common enough, eagerly compile the invoker to bytecodes. */
161 private void maybeCompileToBytecode(MethodHandle invoker) {
162 final int EAGER_COMPILE_ARITY_LIMIT = 10;
163 if (targetType == targetType.erase() &&
164 targetType.parameterCount() < EAGER_COMPILE_ARITY_LIMIT) {
165 invoker.form.compileToBytecode();
166 }
167 }
168
John R Rose62ee2112013-10-05 05:30:38 -0700169 // This next one is called from LambdaForm.NamedFunction.<init>.
170 /*non-public*/ static MemberName invokeBasicMethod(MethodType basicType) {
171 assert(basicType == basicType.basicType());
Christian Thalinger360d5122012-07-24 10:47:44 -0700172 try {
173 //Lookup.findVirtual(MethodHandle.class, name, type);
John R Rose62ee2112013-10-05 05:30:38 -0700174 return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, "invokeBasic", basicType);
Christian Thalinger360d5122012-07-24 10:47:44 -0700175 } catch (ReflectiveOperationException ex) {
John R Rose62ee2112013-10-05 05:30:38 -0700176 throw newInternalError("JVM cannot find invoker for "+basicType, ex);
Christian Thalinger360d5122012-07-24 10:47:44 -0700177 }
178 }
179
180 private boolean checkInvoker(MethodHandle invoker) {
181 assert(targetType.invokerType().equals(invoker.type()))
182 : java.util.Arrays.asList(targetType, targetType.invokerType(), invoker);
183 assert(invoker.internalMemberName() == null ||
184 invoker.internalMemberName().getMethodType().equals(targetType));
185 assert(!invoker.isVarargsCollector());
186 return true;
187 }
188
Paul Sandoz9fb30a32016-03-24 11:21:21 +0100189 private boolean checkVarHandleInvoker(MethodHandle invoker) {
190 MethodType invokerType = targetType.insertParameterTypes(0, VarHandle.class);
191 assert(invokerType.equals(invoker.type()))
192 : java.util.Arrays.asList(targetType, invokerType, invoker);
193 assert(invoker.internalMemberName() == null ||
194 invoker.internalMemberName().getMethodType().equals(targetType));
195 assert(!invoker.isVarargsCollector());
196 return true;
197 }
198
John Rose6a177f42014-09-10 19:19:48 +0400199 /**
200 * Find or create an invoker which passes unchanged a given number of arguments
201 * and spreads the rest from a trailing array argument.
202 * The invoker target type is the post-spread type {@code (TYPEOF(uarg*), TYPEOF(sarg*))=>RT}.
203 * All the {@code sarg}s must have a common type {@code C}. (If there are none, {@code Object} is assumed.}
204 * @param leadingArgCount the number of unchanged (non-spread) arguments
205 * @return {@code invoker.invokeExact(mh, uarg*, C[]{sarg*}) := (RT)mh.invoke(uarg*, sarg*)}
206 */
John R Rose025d0ae2011-05-26 17:37:36 -0700207 /*non-public*/ MethodHandle spreadInvoker(int leadingArgCount) {
John R Rose025d0ae2011-05-26 17:37:36 -0700208 int spreadArgCount = targetType.parameterCount() - leadingArgCount;
John Rose6a177f42014-09-10 19:19:48 +0400209 MethodType postSpreadType = targetType;
210 Class<?> argArrayType = impliedRestargType(postSpreadType, leadingArgCount);
211 if (postSpreadType.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY) {
212 return genericInvoker().asSpreader(argArrayType, spreadArgCount);
John R Rose9d9d7872012-08-17 13:42:25 -0700213 }
John Rose6a177f42014-09-10 19:19:48 +0400214 // Cannot build a generic invoker here of type ginvoker.invoke(mh, a*[254]).
215 // Instead, factor sinvoker.invoke(mh, a) into ainvoker.invoke(filter(mh), a)
216 // where filter(mh) == mh.asSpreader(Object[], spreadArgCount)
217 MethodType preSpreadType = postSpreadType
218 .replaceParameterTypes(leadingArgCount, postSpreadType.parameterCount(), argArrayType);
219 MethodHandle arrayInvoker = MethodHandles.invoker(preSpreadType);
220 MethodHandle makeSpreader = MethodHandles.insertArguments(Lazy.MH_asSpreader, 1, argArrayType, spreadArgCount);
221 return MethodHandles.filterArgument(arrayInvoker, 0, makeSpreader);
John R Rose025d0ae2011-05-26 17:37:36 -0700222 }
223
John Rose6a177f42014-09-10 19:19:48 +0400224 private static Class<?> impliedRestargType(MethodType restargType, int fromPos) {
225 if (restargType.isGeneric()) return Object[].class; // can be nothing else
226 int maxPos = restargType.parameterCount();
227 if (fromPos >= maxPos) return Object[].class; // reasonable default
228 Class<?> argType = restargType.parameterType(fromPos);
229 for (int i = fromPos+1; i < maxPos; i++) {
230 if (argType != restargType.parameterType(i))
231 throw newIllegalArgumentException("need homogeneous rest arguments", restargType);
John R Rose4f508ab2010-10-30 21:08:23 -0700232 }
John Rose6a177f42014-09-10 19:19:48 +0400233 if (argType == Object.class) return Object[].class;
234 return Array.newInstance(argType, 0).getClass();
John R Rose4f508ab2010-10-30 21:08:23 -0700235 }
236
John R Rosefb6164c2009-05-05 22:40:09 -0700237 public String toString() {
238 return "Invokers"+targetType;
239 }
Christian Thalinger360d5122012-07-24 10:47:44 -0700240
John R Rose62ee2112013-10-05 05:30:38 -0700241 static MemberName methodHandleInvokeLinkerMethod(String name,
242 MethodType mtype,
243 Object[] appendixResult) {
244 int which;
245 switch (name) {
Paul Sandoz9fb30a32016-03-24 11:21:21 +0100246 case "invokeExact": which = MethodTypeForm.LF_EX_LINKER; break;
247 case "invoke": which = MethodTypeForm.LF_GEN_LINKER; break;
248 default: throw new InternalError("not invoker: "+name);
John R Rose62ee2112013-10-05 05:30:38 -0700249 }
John R Rose9d9d7872012-08-17 13:42:25 -0700250 LambdaForm lform;
John R Rose62ee2112013-10-05 05:30:38 -0700251 if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - MH_LINKER_ARG_APPENDED) {
252 lform = invokeHandleForm(mtype, false, which);
John R Rose9d9d7872012-08-17 13:42:25 -0700253 appendixResult[0] = mtype;
254 } else {
John R Rose62ee2112013-10-05 05:30:38 -0700255 lform = invokeHandleForm(mtype, true, which);
John R Rose9d9d7872012-08-17 13:42:25 -0700256 }
Christian Thalinger360d5122012-07-24 10:47:44 -0700257 return lform.vmentry;
258 }
259
John R Rose62ee2112013-10-05 05:30:38 -0700260 // argument count to account for trailing "appendix value" (typically the mtype)
261 private static final int MH_LINKER_ARG_APPENDED = 1;
Christian Thalinger360d5122012-07-24 10:47:44 -0700262
John R Rose62ee2112013-10-05 05:30:38 -0700263 /** Returns an adapter for invokeExact or generic invoke, as a MH or constant pool linker.
264 * If !customized, caller is responsible for supplying, during adapter execution,
265 * a copy of the exact mtype. This is because the adapter might be generalized to
266 * a basic type.
267 * @param mtype the caller's method type (either basic or full-custom)
268 * @param customized whether to use a trailing appendix argument (to carry the mtype)
269 * @param which bit-encoded 0x01 whether it is a CP adapter ("linker") or MHs.invoker value ("invoker");
270 * 0x02 whether it is for invokeExact or generic invoke
271 */
272 private static LambdaForm invokeHandleForm(MethodType mtype, boolean customized, int which) {
John R Rose9d9d7872012-08-17 13:42:25 -0700273 boolean isCached;
274 if (!customized) {
275 mtype = mtype.basicType(); // normalize Z to I, String to Object, etc.
276 isCached = true;
277 } else {
278 isCached = false; // maybe cache if mtype == mtype.basicType()
279 }
Christian Thalinger360d5122012-07-24 10:47:44 -0700280 boolean isLinker, isGeneric;
281 String debugName;
282 switch (which) {
283 case MethodTypeForm.LF_EX_LINKER: isLinker = true; isGeneric = false; debugName = "invokeExact_MT"; break;
284 case MethodTypeForm.LF_EX_INVOKER: isLinker = false; isGeneric = false; debugName = "exactInvoker"; break;
285 case MethodTypeForm.LF_GEN_LINKER: isLinker = true; isGeneric = true; debugName = "invoke_MT"; break;
286 case MethodTypeForm.LF_GEN_INVOKER: isLinker = false; isGeneric = true; debugName = "invoker"; break;
287 default: throw new InternalError();
288 }
John R Rose9d9d7872012-08-17 13:42:25 -0700289 LambdaForm lform;
290 if (isCached) {
291 lform = mtype.form().cachedLambdaForm(which);
292 if (lform != null) return lform;
293 }
Christian Thalinger360d5122012-07-24 10:47:44 -0700294 // exactInvokerForm (Object,Object)Object
295 // link with java.lang.invoke.MethodHandle.invokeBasic(MethodHandle,Object,Object)Object/invokeSpecial
296 final int THIS_MH = 0;
297 final int CALL_MH = THIS_MH + (isLinker ? 0 : 1);
298 final int ARG_BASE = CALL_MH + 1;
299 final int OUTARG_LIMIT = ARG_BASE + mtype.parameterCount();
John R Rose9d9d7872012-08-17 13:42:25 -0700300 final int INARG_LIMIT = OUTARG_LIMIT + (isLinker && !customized ? 1 : 0);
Christian Thalinger360d5122012-07-24 10:47:44 -0700301 int nameCursor = OUTARG_LIMIT;
John R Rose9d9d7872012-08-17 13:42:25 -0700302 final int MTYPE_ARG = customized ? -1 : nameCursor++; // might be last in-argument
Christian Thalinger360d5122012-07-24 10:47:44 -0700303 final int CHECK_TYPE = nameCursor++;
Vladimir Ivanovbfc51932015-01-29 10:27:30 -0800304 final int CHECK_CUSTOM = (CUSTOMIZE_THRESHOLD >= 0) ? nameCursor++ : -1;
Christian Thalinger360d5122012-07-24 10:47:44 -0700305 final int LINKER_CALL = nameCursor++;
306 MethodType invokerFormType = mtype.invokerType();
307 if (isLinker) {
John R Rose9d9d7872012-08-17 13:42:25 -0700308 if (!customized)
309 invokerFormType = invokerFormType.appendParameterTypes(MemberName.class);
Christian Thalinger360d5122012-07-24 10:47:44 -0700310 } else {
311 invokerFormType = invokerFormType.invokerType();
312 }
313 Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType);
John R Rose9d9d7872012-08-17 13:42:25 -0700314 assert(names.length == nameCursor)
315 : Arrays.asList(mtype, customized, which, nameCursor, names.length);
Christian Thalinger360d5122012-07-24 10:47:44 -0700316 if (MTYPE_ARG >= INARG_LIMIT) {
317 assert(names[MTYPE_ARG] == null);
John Roseafe2dd82014-09-10 19:19:51 +0400318 BoundMethodHandle.SpeciesData speciesData = BoundMethodHandle.speciesData_L();
319 names[THIS_MH] = names[THIS_MH].withConstraint(speciesData);
320 NamedFunction getter = speciesData.getterFunction(0);
John R Rose62ee2112013-10-05 05:30:38 -0700321 names[MTYPE_ARG] = new Name(getter, names[THIS_MH]);
Christian Thalinger360d5122012-07-24 10:47:44 -0700322 // else if isLinker, then MTYPE is passed in from the caller (e.g., the JVM)
323 }
324
325 // Make the final call. If isGeneric, then prepend the result of type checking.
John R Rose62ee2112013-10-05 05:30:38 -0700326 MethodType outCallType = mtype.basicType();
327 Object[] outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT, Object[].class);
John R Rose9d9d7872012-08-17 13:42:25 -0700328 Object mtypeArg = (customized ? mtype : names[MTYPE_ARG]);
Christian Thalinger360d5122012-07-24 10:47:44 -0700329 if (!isGeneric) {
John R Rose9d9d7872012-08-17 13:42:25 -0700330 names[CHECK_TYPE] = new Name(NF_checkExactType, names[CALL_MH], mtypeArg);
Christian Thalinger360d5122012-07-24 10:47:44 -0700331 // mh.invokeExact(a*):R => checkExactType(mh, TYPEOF(a*:R)); mh.invokeBasic(a*)
Christian Thalinger360d5122012-07-24 10:47:44 -0700332 } else {
John R Rose9d9d7872012-08-17 13:42:25 -0700333 names[CHECK_TYPE] = new Name(NF_checkGenericType, names[CALL_MH], mtypeArg);
John R Rose62ee2112013-10-05 05:30:38 -0700334 // mh.invokeGeneric(a*):R => checkGenericType(mh, TYPEOF(a*:R)).invokeBasic(a*)
335 outArgs[0] = names[CHECK_TYPE];
Christian Thalinger360d5122012-07-24 10:47:44 -0700336 }
Vladimir Ivanovbfc51932015-01-29 10:27:30 -0800337 if (CHECK_CUSTOM != -1) {
Vladimir Ivanovad2c8372015-04-21 21:06:06 +0300338 names[CHECK_CUSTOM] = new Name(NF_checkCustomized, outArgs[0]);
Vladimir Ivanovbfc51932015-01-29 10:27:30 -0800339 }
John R Rose62ee2112013-10-05 05:30:38 -0700340 names[LINKER_CALL] = new Name(outCallType, outArgs);
Christian Thalinger360d5122012-07-24 10:47:44 -0700341 lform = new LambdaForm(debugName, INARG_LIMIT, names);
342 if (isLinker)
343 lform.compileToBytecode(); // JVM needs a real methodOop
John R Rose9d9d7872012-08-17 13:42:25 -0700344 if (isCached)
345 lform = mtype.form().setCachedLambdaForm(which, lform);
Christian Thalinger360d5122012-07-24 10:47:44 -0700346 return lform;
347 }
348
Paul Sandoz9fb30a32016-03-24 11:21:21 +0100349
350 static MemberName varHandleInvokeLinkerMethod(String name,
351 MethodType mtype) {
352 LambdaForm lform;
353 if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - MH_LINKER_ARG_APPENDED) {
354 lform = varHandleMethodGenericLinkerHandleForm(name, mtype);
355 } else {
356 // TODO
357 throw newInternalError("Unsupported parameter slot count " + mtype.parameterSlotCount());
358 }
359 return lform.vmentry;
360 }
361
362 private static LambdaForm varHandleMethodGenericLinkerHandleForm(String name, MethodType mtype) {
363 // TODO Cache form?
364
365 final int THIS_VH = 0;
366 final int ARG_BASE = THIS_VH + 1;
367 final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
368 int nameCursor = ARG_LIMIT;
369 final int VAD_ARG = nameCursor++;
370 final int CHECK_TYPE = nameCursor++;
371 final int CHECK_CUSTOM = (CUSTOMIZE_THRESHOLD >= 0) ? nameCursor++ : -1;
372 final int LINKER_CALL = nameCursor++;
373
374 Name[] names = new Name[LINKER_CALL + 1];
375 names[THIS_VH] = argument(THIS_VH, BasicType.basicType(Object.class));
376 for (int i = 0; i < mtype.parameterCount(); i++) {
377 names[ARG_BASE + i] = argument(ARG_BASE + i, BasicType.basicType(mtype.parameterType(i)));
378 }
379 names[VAD_ARG] = new Name(ARG_LIMIT, BasicType.basicType(Object.class));
380
381 names[CHECK_TYPE] = new Name(NF_checkVarHandleGenericType, names[THIS_VH], names[VAD_ARG]);
382
383 Object[] outArgs = new Object[ARG_LIMIT + 1];
384 outArgs[0] = names[CHECK_TYPE];
385 for (int i = 0; i < ARG_LIMIT; i++) {
386 outArgs[i + 1] = names[i];
387 }
388
389 if (CHECK_CUSTOM != -1) {
390 names[CHECK_CUSTOM] = new Name(NF_checkCustomized, outArgs[0]);
391 }
392
393 MethodType outCallType = mtype.insertParameterTypes(0, VarHandle.class)
394 .basicType();
395 names[LINKER_CALL] = new Name(outCallType, outArgs);
396 LambdaForm lform = new LambdaForm(name + ":VarHandle_invoke_MT_" + shortenSignature(basicTypeSignature(mtype)),
397 ARG_LIMIT + 1, names);
398
Paul Sandoz37445182016-05-05 11:39:08 -0700399 lform.compileToBytecode();
Paul Sandoz9fb30a32016-03-24 11:21:21 +0100400 return lform;
401 }
402
403 private static LambdaForm varHandleMethodExactInvokerHandleForm(String name, MethodType mtype) {
404 // TODO Cache form?
405
406 final int THIS_MH = 0;
407 final int CALL_VH = THIS_MH + 1;
408 final int ARG_BASE = CALL_VH + 1;
409 final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
410 int nameCursor = ARG_LIMIT;
411 final int VAD_ARG = nameCursor++;
412 final int CHECK_TYPE = nameCursor++;
413 final int GET_MEMBER = nameCursor++;
414 final int LINKER_CALL = nameCursor++;
415
416 MethodType invokerFormType = mtype.insertParameterTypes(0, VarHandle.class)
417 .basicType()
418 .appendParameterTypes(MemberName.class);
419
420 MemberName linker = new MemberName(MethodHandle.class, "linkToStatic", invokerFormType, REF_invokeStatic);
421 try {
422 linker = MemberName.getFactory().resolveOrFail(REF_invokeStatic, linker, null, NoSuchMethodException.class);
423 } catch (ReflectiveOperationException ex) {
424 throw newInternalError(ex);
425 }
426
427 Name[] names = new Name[LINKER_CALL + 1];
428 names[THIS_MH] = argument(THIS_MH, BasicType.basicType(Object.class));
429 names[CALL_VH] = argument(CALL_VH, BasicType.basicType(Object.class));
430 for (int i = 0; i < mtype.parameterCount(); i++) {
431 names[ARG_BASE + i] = argument(ARG_BASE + i, BasicType.basicType(mtype.parameterType(i)));
432 }
433
434 BoundMethodHandle.SpeciesData speciesData = BoundMethodHandle.speciesData_L();
435 names[THIS_MH] = names[THIS_MH].withConstraint(speciesData);
436
437 NamedFunction getter = speciesData.getterFunction(0);
438 names[VAD_ARG] = new Name(getter, names[THIS_MH]);
439
440 Object[] outArgs = Arrays.copyOfRange(names, CALL_VH, ARG_LIMIT + 1, Object[].class);
441
442 names[CHECK_TYPE] = new Name(NF_checkVarHandleExactType, names[CALL_VH], names[VAD_ARG]);
443
444 names[GET_MEMBER] = new Name(NF_getVarHandleMemberName, names[CALL_VH], names[VAD_ARG]);
445 outArgs[outArgs.length - 1] = names[GET_MEMBER];
446
447 names[LINKER_CALL] = new Name(linker, outArgs);
448 LambdaForm lform = new LambdaForm(name + ":VarHandle_exactInvoker" + shortenSignature(basicTypeSignature(mtype)),
449 ARG_LIMIT, names);
450
Paul Sandoz37445182016-05-05 11:39:08 -0700451 lform.compileToBytecode();
Paul Sandoz9fb30a32016-03-24 11:21:21 +0100452 return lform;
453 }
454
455 private static LambdaForm varHandleMethodGenericInvokerHandleForm(String name, MethodType mtype) {
456 // TODO Cache form?
457
458 final int THIS_MH = 0;
459 final int CALL_VH = THIS_MH + 1;
460 final int ARG_BASE = CALL_VH + 1;
461 final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
462 int nameCursor = ARG_LIMIT;
463 final int VAD_ARG = nameCursor++;
464 final int CHECK_TYPE = nameCursor++;
465 final int LINKER_CALL = nameCursor++;
466
467 Name[] names = new Name[LINKER_CALL + 1];
468 names[THIS_MH] = argument(THIS_MH, BasicType.basicType(Object.class));
469 names[CALL_VH] = argument(CALL_VH, BasicType.basicType(Object.class));
470 for (int i = 0; i < mtype.parameterCount(); i++) {
471 names[ARG_BASE + i] = argument(ARG_BASE + i, BasicType.basicType(mtype.parameterType(i)));
472 }
473
474 BoundMethodHandle.SpeciesData speciesData = BoundMethodHandle.speciesData_L();
475 names[THIS_MH] = names[THIS_MH].withConstraint(speciesData);
476
477 NamedFunction getter = speciesData.getterFunction(0);
478 names[VAD_ARG] = new Name(getter, names[THIS_MH]);
479
480 names[CHECK_TYPE] = new Name(NF_checkVarHandleGenericType, names[CALL_VH], names[VAD_ARG]);
481
482 Object[] outArgs = new Object[ARG_LIMIT];
483 outArgs[0] = names[CHECK_TYPE];
484 for (int i = 1; i < ARG_LIMIT; i++) {
485 outArgs[i] = names[i];
486 }
487
488 MethodType outCallType = mtype.insertParameterTypes(0, VarHandle.class)
489 .basicType();
490 names[LINKER_CALL] = new Name(outCallType, outArgs);
491 LambdaForm lform = new LambdaForm(name + ":VarHandle_invoker" + shortenSignature(basicTypeSignature(mtype)),
492 ARG_LIMIT, names);
493
494 lform.prepare();
495 return lform;
496 }
497
498 /*non-public*/ static
499 @ForceInline
Paul Sandoz37445182016-05-05 11:39:08 -0700500 MethodHandle checkVarHandleGenericType(VarHandle handle, VarHandle.AccessDescriptor ad) {
501 // Test for exact match on invoker types
502 // TODO match with erased types and add cast of return value to lambda form
503 MethodHandle mh = handle.getMethodHandle(ad.mode);
504 if (mh.type() == ad.symbolicMethodTypeInvoker) {
Paul Sandoz9fb30a32016-03-24 11:21:21 +0100505 return mh;
506 }
507 else {
Paul Sandoz37445182016-05-05 11:39:08 -0700508 return mh.asType(ad.symbolicMethodTypeInvoker);
Paul Sandoz9fb30a32016-03-24 11:21:21 +0100509 }
510 }
511
512 /*non-public*/ static
513 @ForceInline
Paul Sandoz37445182016-05-05 11:39:08 -0700514 void checkVarHandleExactType(VarHandle handle, VarHandle.AccessDescriptor ad) {
515 MethodType erasedTarget = handle.vform.methodType_table[ad.type];
516 MethodType erasedSymbolic = ad.symbolicMethodTypeErased;
517 if (erasedTarget != erasedSymbolic)
518 throw newWrongMethodTypeException(erasedTarget, erasedSymbolic);
Paul Sandoz9fb30a32016-03-24 11:21:21 +0100519 }
520
521 /*non-public*/ static
522 @ForceInline
Paul Sandoz37445182016-05-05 11:39:08 -0700523 MemberName getVarHandleMemberName(VarHandle handle, VarHandle.AccessDescriptor ad) {
524 MemberName mn = handle.vform.memberName_table[ad.mode];
Paul Sandoz9fb30a32016-03-24 11:21:21 +0100525 if (mn == null) {
Paul Sandoz37445182016-05-05 11:39:08 -0700526 throw handle.unsupported();
Paul Sandoz9fb30a32016-03-24 11:21:21 +0100527 }
528 return mn;
529 }
530
Christian Thalinger360d5122012-07-24 10:47:44 -0700531 /*non-public*/ static
532 WrongMethodTypeException newWrongMethodTypeException(MethodType actual, MethodType expected) {
533 // FIXME: merge with JVM logic for throwing WMTE
534 return new WrongMethodTypeException("expected "+expected+" but found "+actual);
535 }
536
537 /** Static definition of MethodHandle.invokeExact checking code. */
538 /*non-public*/ static
539 @ForceInline
Shilpi Rastogiff976592016-02-10 11:04:13 +0100540 void checkExactType(MethodHandle mh, MethodType expected) {
Christian Thalinger360d5122012-07-24 10:47:44 -0700541 MethodType actual = mh.type();
542 if (actual != expected)
543 throw newWrongMethodTypeException(expected, actual);
544 }
545
John R Rose62ee2112013-10-05 05:30:38 -0700546 /** Static definition of MethodHandle.invokeGeneric checking code.
547 * Directly returns the type-adjusted MH to invoke, as follows:
548 * {@code (R)MH.invoke(a*) => MH.asType(TYPEOF(a*:R)).invokeBasic(a*)}
549 */
Christian Thalinger360d5122012-07-24 10:47:44 -0700550 /*non-public*/ static
551 @ForceInline
Shilpi Rastogiff976592016-02-10 11:04:13 +0100552 MethodHandle checkGenericType(MethodHandle mh, MethodType expected) {
John R Rose62ee2112013-10-05 05:30:38 -0700553 return mh.asType(expected);
554 /* Maybe add more paths here. Possible optimizations:
555 * for (R)MH.invoke(a*),
556 * let MT0 = TYPEOF(a*:R), MT1 = MH.type
557 *
558 * if MT0==MT1 or MT1 can be safely called by MT0
559 * => MH.invokeBasic(a*)
560 * if MT1 can be safely called by MT0[R := Object]
561 * => MH.invokeBasic(a*) & checkcast(R)
562 * if MT1 can be safely called by MT0[* := Object]
563 * => checkcast(A)* & MH.invokeBasic(a*) & checkcast(R)
564 * if a big adapter BA can be pulled out of (MT0,MT1)
565 * => BA.invokeBasic(MT0,MH,a*)
566 * if a local adapter LA can cached on static CS0 = new GICS(MT0)
567 * => CS0.LA.invokeBasic(MH,a*)
568 * else
569 * => MH.asType(MT0).invokeBasic(A*)
570 */
Christian Thalinger360d5122012-07-24 10:47:44 -0700571 }
572
573 static MemberName linkToCallSiteMethod(MethodType mtype) {
John R Rose62ee2112013-10-05 05:30:38 -0700574 LambdaForm lform = callSiteForm(mtype, false);
Christian Thalinger360d5122012-07-24 10:47:44 -0700575 return lform.vmentry;
576 }
577
John R Rose62ee2112013-10-05 05:30:38 -0700578 static MemberName linkToTargetMethod(MethodType mtype) {
579 LambdaForm lform = callSiteForm(mtype, true);
580 return lform.vmentry;
581 }
582
583 // skipCallSite is true if we are optimizing a ConstantCallSite
584 private static LambdaForm callSiteForm(MethodType mtype, boolean skipCallSite) {
Christian Thalinger360d5122012-07-24 10:47:44 -0700585 mtype = mtype.basicType(); // normalize Z to I, String to Object, etc.
John R Rose62ee2112013-10-05 05:30:38 -0700586 final int which = (skipCallSite ? MethodTypeForm.LF_MH_LINKER : MethodTypeForm.LF_CS_LINKER);
587 LambdaForm lform = mtype.form().cachedLambdaForm(which);
Christian Thalinger360d5122012-07-24 10:47:44 -0700588 if (lform != null) return lform;
589 // exactInvokerForm (Object,Object)Object
590 // link with java.lang.invoke.MethodHandle.invokeBasic(MethodHandle,Object,Object)Object/invokeSpecial
591 final int ARG_BASE = 0;
592 final int OUTARG_LIMIT = ARG_BASE + mtype.parameterCount();
593 final int INARG_LIMIT = OUTARG_LIMIT + 1;
594 int nameCursor = OUTARG_LIMIT;
John R Rose62ee2112013-10-05 05:30:38 -0700595 final int APPENDIX_ARG = nameCursor++; // the last in-argument
596 final int CSITE_ARG = skipCallSite ? -1 : APPENDIX_ARG;
597 final int CALL_MH = skipCallSite ? APPENDIX_ARG : nameCursor++; // result of getTarget
Christian Thalinger360d5122012-07-24 10:47:44 -0700598 final int LINKER_CALL = nameCursor++;
John R Rose62ee2112013-10-05 05:30:38 -0700599 MethodType invokerFormType = mtype.appendParameterTypes(skipCallSite ? MethodHandle.class : CallSite.class);
Christian Thalinger360d5122012-07-24 10:47:44 -0700600 Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType);
601 assert(names.length == nameCursor);
John R Rose62ee2112013-10-05 05:30:38 -0700602 assert(names[APPENDIX_ARG] != null);
603 if (!skipCallSite)
604 names[CALL_MH] = new Name(NF_getCallSiteTarget, names[CSITE_ARG]);
Christian Thalinger360d5122012-07-24 10:47:44 -0700605 // (site.)invokedynamic(a*):R => mh = site.getTarget(); mh.invokeBasic(a*)
606 final int PREPEND_MH = 0, PREPEND_COUNT = 1;
607 Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, OUTARG_LIMIT + PREPEND_COUNT, Object[].class);
608 // prepend MH argument:
609 System.arraycopy(outArgs, 0, outArgs, PREPEND_COUNT, outArgs.length - PREPEND_COUNT);
610 outArgs[PREPEND_MH] = names[CALL_MH];
John R Rose62ee2112013-10-05 05:30:38 -0700611 names[LINKER_CALL] = new Name(mtype, outArgs);
612 lform = new LambdaForm((skipCallSite ? "linkToTargetMethod" : "linkToCallSite"), INARG_LIMIT, names);
Christian Thalinger360d5122012-07-24 10:47:44 -0700613 lform.compileToBytecode(); // JVM needs a real methodOop
John R Rose62ee2112013-10-05 05:30:38 -0700614 lform = mtype.form().setCachedLambdaForm(which, lform);
Christian Thalinger360d5122012-07-24 10:47:44 -0700615 return lform;
616 }
617
618 /** Static definition of MethodHandle.invokeGeneric checking code. */
619 /*non-public*/ static
620 @ForceInline
Shilpi Rastogiff976592016-02-10 11:04:13 +0100621 MethodHandle getCallSiteTarget(CallSite site) {
622 return site.getTarget();
Christian Thalinger360d5122012-07-24 10:47:44 -0700623 }
624
Vladimir Ivanovbfc51932015-01-29 10:27:30 -0800625 /*non-public*/ static
626 @ForceInline
Shilpi Rastogiff976592016-02-10 11:04:13 +0100627 void checkCustomized(MethodHandle mh) {
Vladimir Ivanov71020f92015-03-20 11:42:31 -0700628 if (MethodHandleImpl.isCompileConstant(mh)) return;
Vladimir Ivanovbfc51932015-01-29 10:27:30 -0800629 if (mh.form.customized == null) {
630 maybeCustomize(mh);
631 }
632 }
633
634 /*non-public*/ static
635 @DontInline
636 void maybeCustomize(MethodHandle mh) {
637 byte count = mh.customizationCount;
638 if (count >= CUSTOMIZE_THRESHOLD) {
639 mh.customize();
640 } else {
641 mh.customizationCount = (byte)(count+1);
642 }
643 }
644
Christian Thalinger360d5122012-07-24 10:47:44 -0700645 // Local constant functions:
John Roseda56d3f2014-09-10 19:19:47 +0400646 private static final NamedFunction
647 NF_checkExactType,
648 NF_checkGenericType,
Vladimir Ivanovbfc51932015-01-29 10:27:30 -0800649 NF_getCallSiteTarget,
Paul Sandoz9fb30a32016-03-24 11:21:21 +0100650 NF_checkCustomized,
651 NF_checkVarHandleGenericType,
652 NF_checkVarHandleExactType,
653 NF_getVarHandleMemberName;
Christian Thalinger360d5122012-07-24 10:47:44 -0700654 static {
655 try {
John Roseda56d3f2014-09-10 19:19:47 +0400656 NamedFunction nfs[] = {
657 NF_checkExactType = new NamedFunction(Invokers.class
Shilpi Rastogiff976592016-02-10 11:04:13 +0100658 .getDeclaredMethod("checkExactType", MethodHandle.class, MethodType.class)),
John Roseda56d3f2014-09-10 19:19:47 +0400659 NF_checkGenericType = new NamedFunction(Invokers.class
Shilpi Rastogiff976592016-02-10 11:04:13 +0100660 .getDeclaredMethod("checkGenericType", MethodHandle.class, MethodType.class)),
John Roseda56d3f2014-09-10 19:19:47 +0400661 NF_getCallSiteTarget = new NamedFunction(Invokers.class
Shilpi Rastogiff976592016-02-10 11:04:13 +0100662 .getDeclaredMethod("getCallSiteTarget", CallSite.class)),
Vladimir Ivanovbfc51932015-01-29 10:27:30 -0800663 NF_checkCustomized = new NamedFunction(Invokers.class
Paul Sandoz9fb30a32016-03-24 11:21:21 +0100664 .getDeclaredMethod("checkCustomized", MethodHandle.class)),
665 NF_checkVarHandleGenericType = new NamedFunction(Invokers.class
666 .getDeclaredMethod("checkVarHandleGenericType", VarHandle.class, VarHandle.AccessDescriptor.class)),
667 NF_checkVarHandleExactType = new NamedFunction(Invokers.class
668 .getDeclaredMethod("checkVarHandleExactType", VarHandle.class, VarHandle.AccessDescriptor.class)),
669 NF_getVarHandleMemberName = new NamedFunction(Invokers.class
670 .getDeclaredMethod("getVarHandleMemberName", VarHandle.class, VarHandle.AccessDescriptor.class))
John Roseda56d3f2014-09-10 19:19:47 +0400671 };
Claes Redestad30545d62015-11-17 11:51:45 +0100672 // Each nf must be statically invocable or we get tied up in our bootstraps.
673 assert(InvokerBytecodeGenerator.isStaticallyInvocable(nfs));
Christian Thalinger360d5122012-07-24 10:47:44 -0700674 } catch (ReflectiveOperationException ex) {
Christian Thalinger01d0ba62012-10-19 17:04:35 -0700675 throw newInternalError(ex);
Christian Thalinger360d5122012-07-24 10:47:44 -0700676 }
677 }
678
John Rose6a177f42014-09-10 19:19:48 +0400679 private static class Lazy {
680 private static final MethodHandle MH_asSpreader;
681
682 static {
683 try {
684 MH_asSpreader = IMPL_LOOKUP.findVirtual(MethodHandle.class, "asSpreader",
685 MethodType.methodType(MethodHandle.class, Class.class, int.class));
686 } catch (ReflectiveOperationException ex) {
687 throw newInternalError(ex);
688 }
689 }
690 }
John R Rosefb6164c2009-05-05 22:40:09 -0700691}