2009-05-05 22:40:09 -07:00
|
|
|
/*
|
2011-02-11 01:26:24 -08:00
|
|
|
* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
|
2009-05-05 22:40:09 -07:00
|
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
|
|
*
|
|
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License version 2 only, as
|
2010-05-25 15:58:33 -07:00
|
|
|
* published by the Free Software Foundation. Oracle designates this
|
2009-05-05 22:40:09 -07:00
|
|
|
* particular file as subject to the "Classpath" exception as provided
|
2010-05-25 15:58:33 -07:00
|
|
|
* by Oracle in the LICENSE file that accompanied this code.
|
2009-05-05 22:40:09 -07:00
|
|
|
*
|
|
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
|
|
* accompanied this code).
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License version
|
|
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
*
|
2010-05-25 15:58:33 -07:00
|
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
|
|
* questions.
|
2009-05-05 22:40:09 -07:00
|
|
|
*/
|
|
|
|
|
2011-03-23 23:02:31 -07:00
|
|
|
package java.lang.invoke;
|
2009-05-05 22:40:09 -07:00
|
|
|
|
2012-07-24 10:47:44 -07:00
|
|
|
import java.util.Arrays;
|
2011-03-23 23:02:31 -07:00
|
|
|
import sun.invoke.empty.Empty;
|
2012-10-19 17:04:35 -07:00
|
|
|
import static java.lang.invoke.MethodHandleStatics.*;
|
2012-07-24 10:47:44 -07:00
|
|
|
import static java.lang.invoke.MethodHandleNatives.Constants.*;
|
2011-03-23 23:02:31 -07:00
|
|
|
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
2012-07-24 10:47:44 -07:00
|
|
|
import static java.lang.invoke.LambdaForm.*;
|
2009-05-05 22:40:09 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Construction and caching of often-used invokers.
|
|
|
|
* @author jrose
|
|
|
|
*/
|
2011-03-18 00:03:24 -07:00
|
|
|
class Invokers {
|
2009-05-05 22:40:09 -07:00
|
|
|
// exact type (sans leading taget MH) for the outgoing call
|
|
|
|
private final MethodType targetType;
|
|
|
|
|
2012-07-24 10:47:44 -07:00
|
|
|
// FIXME: Get rid of the invokers that are not useful.
|
|
|
|
|
2009-05-05 22:40:09 -07:00
|
|
|
// exact invoker for the outgoing call
|
|
|
|
private /*lazy*/ MethodHandle exactInvoker;
|
|
|
|
|
2010-10-30 21:02:30 -07:00
|
|
|
// erased (partially untyped but with primitives) invoker for the outgoing call
|
2012-07-24 10:47:44 -07:00
|
|
|
// FIXME: get rid of
|
2010-10-30 21:02:30 -07:00
|
|
|
private /*lazy*/ MethodHandle erasedInvoker;
|
2012-07-24 10:47:44 -07:00
|
|
|
// FIXME: get rid of
|
2010-10-30 21:02:30 -07:00
|
|
|
/*lazy*/ MethodHandle erasedInvokerWithDrops; // for InvokeGeneric
|
|
|
|
|
2011-05-12 19:27:33 -07:00
|
|
|
// general invoker for the outgoing call
|
|
|
|
private /*lazy*/ MethodHandle generalInvoker;
|
2009-05-05 22:40:09 -07:00
|
|
|
|
2011-05-26 17:37:36 -07:00
|
|
|
// general invoker for the outgoing call, uses varargs
|
|
|
|
private /*lazy*/ MethodHandle varargsInvoker;
|
|
|
|
|
|
|
|
// general invoker for the outgoing call; accepts a trailing Object[]
|
2011-02-11 01:26:24 -08:00
|
|
|
private final /*lazy*/ MethodHandle[] spreadInvokers;
|
2010-01-07 16:16:45 -08:00
|
|
|
|
2010-10-30 21:08:23 -07:00
|
|
|
// invoker for an unbound callsite
|
|
|
|
private /*lazy*/ MethodHandle uninitializedCallSite;
|
|
|
|
|
2009-05-05 22:40:09 -07:00
|
|
|
/** Compute and cache information common to all collecting adapters
|
|
|
|
* that implement members of the erasure-family of the given erased type.
|
|
|
|
*/
|
2011-02-11 01:26:24 -08:00
|
|
|
/*non-public*/ Invokers(MethodType targetType) {
|
2009-05-05 22:40:09 -07:00
|
|
|
this.targetType = targetType;
|
2011-02-11 01:26:24 -08:00
|
|
|
this.spreadInvokers = new MethodHandle[targetType.parameterCount()+1];
|
2009-05-05 22:40:09 -07:00
|
|
|
}
|
|
|
|
|
2011-03-18 00:03:24 -07:00
|
|
|
/*non-public*/ MethodHandle exactInvoker() {
|
2009-05-05 22:40:09 -07:00
|
|
|
MethodHandle invoker = exactInvoker;
|
|
|
|
if (invoker != null) return invoker;
|
2012-07-24 10:47:44 -07:00
|
|
|
MethodType mtype = targetType;
|
2012-08-17 13:42:25 -07:00
|
|
|
MethodType invokerType = mtype.invokerType();
|
|
|
|
LambdaForm lform;
|
|
|
|
final int MTYPE_ARG_APPENDED = 1; // argument count for appended mtype value
|
|
|
|
if (mtype.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY - MTYPE_ARG_APPENDED) {
|
|
|
|
lform = invokeForm(mtype, false, MethodTypeForm.LF_EX_INVOKER);
|
|
|
|
invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype);
|
|
|
|
} else {
|
|
|
|
// At maximum arity, we cannot afford an extra mtype argument,
|
|
|
|
// so build a fully customized (non-cached) invoker form.
|
|
|
|
lform = invokeForm(mtype, true, MethodTypeForm.LF_EX_INVOKER);
|
|
|
|
invoker = SimpleMethodHandle.make(invokerType, lform);
|
|
|
|
}
|
2012-07-24 10:47:44 -07:00
|
|
|
assert(checkInvoker(invoker));
|
2009-05-05 22:40:09 -07:00
|
|
|
exactInvoker = invoker;
|
|
|
|
return invoker;
|
|
|
|
}
|
|
|
|
|
2011-05-12 19:27:33 -07:00
|
|
|
/*non-public*/ MethodHandle generalInvoker() {
|
|
|
|
MethodHandle invoker = generalInvoker;
|
2009-05-05 22:40:09 -07:00
|
|
|
if (invoker != null) return invoker;
|
2012-07-24 10:47:44 -07:00
|
|
|
MethodType mtype = targetType;
|
2012-08-17 13:42:25 -07:00
|
|
|
MethodType invokerType = mtype.invokerType();
|
|
|
|
LambdaForm lform;
|
|
|
|
final int MTYPE_ARG_APPENDED = 1; // argument count for appended mtype value
|
|
|
|
assert(GENERIC_INVOKER_SLOP >= MTYPE_ARG_APPENDED);
|
|
|
|
if (mtype.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY - GENERIC_INVOKER_SLOP) {
|
|
|
|
prepareForGenericCall(mtype);
|
|
|
|
lform = invokeForm(mtype, false, MethodTypeForm.LF_GEN_INVOKER);
|
|
|
|
invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype);
|
|
|
|
} else {
|
|
|
|
// At maximum arity, we cannot afford an extra mtype argument,
|
|
|
|
// so build a fully customized (non-cached) invoker form.
|
|
|
|
lform = invokeForm(mtype, true, MethodTypeForm.LF_GEN_INVOKER);
|
|
|
|
invoker = SimpleMethodHandle.make(invokerType, lform);
|
|
|
|
}
|
2012-07-24 10:47:44 -07:00
|
|
|
assert(checkInvoker(invoker));
|
2011-05-12 19:27:33 -07:00
|
|
|
generalInvoker = invoker;
|
2009-05-05 22:40:09 -07:00
|
|
|
return invoker;
|
|
|
|
}
|
|
|
|
|
2012-07-24 10:47:44 -07:00
|
|
|
/*non-public*/ MethodHandle makeBasicInvoker() {
|
|
|
|
MethodHandle invoker = DirectMethodHandle.make(invokeBasicMethod(targetType));
|
|
|
|
assert(targetType == targetType.basicType());
|
|
|
|
// Note: This is not cached here. It is cached by the calling MethodTypeForm.
|
|
|
|
assert(checkInvoker(invoker));
|
|
|
|
return invoker;
|
|
|
|
}
|
|
|
|
|
|
|
|
static MemberName invokeBasicMethod(MethodType type) {
|
2012-08-17 13:42:25 -07:00
|
|
|
type = type.basicType();
|
2012-07-24 10:47:44 -07:00
|
|
|
String name = "invokeBasic";
|
2011-05-26 17:37:36 -07:00
|
|
|
try {
|
2012-07-24 10:47:44 -07:00
|
|
|
//Lookup.findVirtual(MethodHandle.class, name, type);
|
|
|
|
return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, name, type);
|
2011-05-26 17:37:36 -07:00
|
|
|
} catch (ReflectiveOperationException ex) {
|
2012-10-19 17:04:35 -07:00
|
|
|
throw newInternalError("JVM cannot find invoker for "+type, ex);
|
2011-05-26 17:37:36 -07:00
|
|
|
}
|
2012-07-24 10:47:44 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
private boolean checkInvoker(MethodHandle invoker) {
|
|
|
|
assert(targetType.invokerType().equals(invoker.type()))
|
|
|
|
: java.util.Arrays.asList(targetType, targetType.invokerType(), invoker);
|
|
|
|
assert(invoker.internalMemberName() == null ||
|
|
|
|
invoker.internalMemberName().getMethodType().equals(targetType));
|
2011-05-26 17:37:36 -07:00
|
|
|
assert(!invoker.isVarargsCollector());
|
2012-07-24 10:47:44 -07:00
|
|
|
return true;
|
2011-05-26 17:37:36 -07:00
|
|
|
}
|
|
|
|
|
2012-07-24 10:47:44 -07:00
|
|
|
// FIXME: get rid of
|
2011-03-18 00:03:24 -07:00
|
|
|
/*non-public*/ MethodHandle erasedInvoker() {
|
2011-05-26 17:37:36 -07:00
|
|
|
MethodHandle xinvoker = exactInvoker();
|
2010-10-30 21:02:30 -07:00
|
|
|
MethodHandle invoker = erasedInvoker;
|
|
|
|
if (invoker != null) return invoker;
|
|
|
|
MethodType erasedType = targetType.erase();
|
2012-07-24 10:47:44 -07:00
|
|
|
invoker = xinvoker.asType(erasedType.invokerType());
|
2010-10-30 21:02:30 -07:00
|
|
|
erasedInvoker = invoker;
|
|
|
|
return invoker;
|
|
|
|
}
|
|
|
|
|
2011-05-26 17:37:36 -07:00
|
|
|
/*non-public*/ MethodHandle spreadInvoker(int leadingArgCount) {
|
|
|
|
MethodHandle vaInvoker = spreadInvokers[leadingArgCount];
|
2010-01-07 16:16:45 -08:00
|
|
|
if (vaInvoker != null) return vaInvoker;
|
2011-05-26 17:37:36 -07:00
|
|
|
int spreadArgCount = targetType.parameterCount() - leadingArgCount;
|
2012-08-17 13:42:25 -07:00
|
|
|
MethodType spreadInvokerType = targetType
|
|
|
|
.replaceParameterTypes(leadingArgCount, targetType.parameterCount(), Object[].class);
|
|
|
|
if (targetType.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY) {
|
|
|
|
// Factor sinvoker.invoke(mh, a) into ginvoker.asSpreader().invoke(mh, a)
|
|
|
|
// where ginvoker.invoke(mh, a*) => mh.invoke(a*).
|
|
|
|
MethodHandle genInvoker = generalInvoker();
|
|
|
|
vaInvoker = genInvoker.asSpreader(Object[].class, spreadArgCount);
|
|
|
|
} else {
|
|
|
|
// Cannot build a general invoker here of type ginvoker.invoke(mh, a*[254]).
|
|
|
|
// Instead, factor sinvoker.invoke(mh, a) into ainvoker.invoke(filter(mh), a)
|
|
|
|
// where filter(mh) == mh.asSpreader(Object[], spreadArgCount)
|
|
|
|
MethodHandle arrayInvoker = MethodHandles.exactInvoker(spreadInvokerType);
|
|
|
|
MethodHandle makeSpreader;
|
|
|
|
try {
|
|
|
|
makeSpreader = IMPL_LOOKUP
|
|
|
|
.findVirtual(MethodHandle.class, "asSpreader",
|
|
|
|
MethodType.methodType(MethodHandle.class, Class.class, int.class));
|
|
|
|
} catch (ReflectiveOperationException ex) {
|
2012-10-19 17:04:35 -07:00
|
|
|
throw newInternalError(ex);
|
2012-08-17 13:42:25 -07:00
|
|
|
}
|
|
|
|
makeSpreader = MethodHandles.insertArguments(makeSpreader, 1, Object[].class, spreadArgCount);
|
|
|
|
vaInvoker = MethodHandles.filterArgument(arrayInvoker, 0, makeSpreader);
|
|
|
|
}
|
|
|
|
assert(vaInvoker.type().equals(spreadInvokerType.invokerType()));
|
2011-05-26 17:37:36 -07:00
|
|
|
spreadInvokers[leadingArgCount] = vaInvoker;
|
|
|
|
return vaInvoker;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*non-public*/ MethodHandle varargsInvoker() {
|
|
|
|
MethodHandle vaInvoker = varargsInvoker;
|
|
|
|
if (vaInvoker != null) return vaInvoker;
|
2012-07-24 10:47:44 -07:00
|
|
|
vaInvoker = spreadInvoker(0).asType(MethodType.genericMethodType(0, true).invokerType());
|
2011-05-26 17:37:36 -07:00
|
|
|
varargsInvoker = vaInvoker;
|
2010-01-07 16:16:45 -08:00
|
|
|
return vaInvoker;
|
2009-05-05 22:40:09 -07:00
|
|
|
}
|
|
|
|
|
2010-10-30 21:08:23 -07:00
|
|
|
private static MethodHandle THROW_UCS = null;
|
|
|
|
|
2011-03-18 00:03:24 -07:00
|
|
|
/*non-public*/ MethodHandle uninitializedCallSite() {
|
2010-10-30 21:08:23 -07:00
|
|
|
MethodHandle invoker = uninitializedCallSite;
|
|
|
|
if (invoker != null) return invoker;
|
|
|
|
if (targetType.parameterCount() > 0) {
|
|
|
|
MethodType type0 = targetType.dropParameterTypes(0, targetType.parameterCount());
|
2011-03-18 00:03:24 -07:00
|
|
|
Invokers invokers0 = type0.invokers();
|
2010-10-30 21:08:23 -07:00
|
|
|
invoker = MethodHandles.dropArguments(invokers0.uninitializedCallSite(),
|
|
|
|
0, targetType.parameterList());
|
|
|
|
assert(invoker.type().equals(targetType));
|
|
|
|
uninitializedCallSite = invoker;
|
|
|
|
return invoker;
|
|
|
|
}
|
2012-07-24 10:47:44 -07:00
|
|
|
invoker = THROW_UCS;
|
|
|
|
if (invoker == null) {
|
2010-10-30 21:08:23 -07:00
|
|
|
try {
|
2012-07-24 10:47:44 -07:00
|
|
|
THROW_UCS = invoker = IMPL_LOOKUP
|
2010-10-30 21:08:23 -07:00
|
|
|
.findStatic(CallSite.class, "uninitializedCallSite",
|
|
|
|
MethodType.methodType(Empty.class));
|
2011-02-11 01:26:32 -08:00
|
|
|
} catch (ReflectiveOperationException ex) {
|
2012-10-19 17:04:35 -07:00
|
|
|
throw newInternalError(ex);
|
2010-10-30 21:08:23 -07:00
|
|
|
}
|
|
|
|
}
|
2012-07-24 10:47:44 -07:00
|
|
|
invoker = MethodHandles.explicitCastArguments(invoker, MethodType.methodType(targetType.returnType()));
|
|
|
|
invoker = invoker.dropArguments(targetType, 0, targetType.parameterCount());
|
2010-10-30 21:08:23 -07:00
|
|
|
assert(invoker.type().equals(targetType));
|
|
|
|
uninitializedCallSite = invoker;
|
|
|
|
return invoker;
|
|
|
|
}
|
|
|
|
|
2009-05-05 22:40:09 -07:00
|
|
|
public String toString() {
|
|
|
|
return "Invokers"+targetType;
|
|
|
|
}
|
2012-07-24 10:47:44 -07:00
|
|
|
|
2012-08-17 13:42:25 -07:00
|
|
|
static MemberName exactInvokerMethod(MethodType mtype, Object[] appendixResult) {
|
|
|
|
LambdaForm lform;
|
|
|
|
final int MTYPE_ARG_APPENDED = 1; // argument count for appended mtype value
|
|
|
|
if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - MTYPE_ARG_APPENDED) {
|
|
|
|
lform = invokeForm(mtype, false, MethodTypeForm.LF_EX_LINKER);
|
|
|
|
appendixResult[0] = mtype;
|
|
|
|
} else {
|
|
|
|
lform = invokeForm(mtype, true, MethodTypeForm.LF_EX_LINKER);
|
|
|
|
}
|
2012-07-24 10:47:44 -07:00
|
|
|
return lform.vmentry;
|
|
|
|
}
|
|
|
|
|
2012-08-17 13:42:25 -07:00
|
|
|
static MemberName genericInvokerMethod(MethodType mtype, Object[] appendixResult) {
|
|
|
|
LambdaForm lform;
|
|
|
|
final int MTYPE_ARG_APPENDED = 1; // argument count for appended mtype value
|
|
|
|
if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - (MTYPE_ARG_APPENDED + GENERIC_INVOKER_SLOP)) {
|
|
|
|
lform = invokeForm(mtype, false, MethodTypeForm.LF_GEN_LINKER);
|
|
|
|
appendixResult[0] = mtype;
|
|
|
|
prepareForGenericCall(mtype);
|
|
|
|
} else {
|
|
|
|
lform = invokeForm(mtype, true, MethodTypeForm.LF_GEN_LINKER);
|
|
|
|
}
|
2012-07-24 10:47:44 -07:00
|
|
|
return lform.vmentry;
|
|
|
|
}
|
|
|
|
|
2012-08-17 13:42:25 -07:00
|
|
|
private static LambdaForm invokeForm(MethodType mtype, boolean customized, int which) {
|
|
|
|
boolean isCached;
|
|
|
|
if (!customized) {
|
|
|
|
mtype = mtype.basicType(); // normalize Z to I, String to Object, etc.
|
|
|
|
isCached = true;
|
|
|
|
} else {
|
|
|
|
isCached = false; // maybe cache if mtype == mtype.basicType()
|
|
|
|
}
|
2012-07-24 10:47:44 -07:00
|
|
|
boolean isLinker, isGeneric;
|
|
|
|
String debugName;
|
|
|
|
switch (which) {
|
|
|
|
case MethodTypeForm.LF_EX_LINKER: isLinker = true; isGeneric = false; debugName = "invokeExact_MT"; break;
|
|
|
|
case MethodTypeForm.LF_EX_INVOKER: isLinker = false; isGeneric = false; debugName = "exactInvoker"; break;
|
|
|
|
case MethodTypeForm.LF_GEN_LINKER: isLinker = true; isGeneric = true; debugName = "invoke_MT"; break;
|
|
|
|
case MethodTypeForm.LF_GEN_INVOKER: isLinker = false; isGeneric = true; debugName = "invoker"; break;
|
|
|
|
default: throw new InternalError();
|
|
|
|
}
|
2012-08-17 13:42:25 -07:00
|
|
|
LambdaForm lform;
|
|
|
|
if (isCached) {
|
|
|
|
lform = mtype.form().cachedLambdaForm(which);
|
|
|
|
if (lform != null) return lform;
|
|
|
|
}
|
2012-07-24 10:47:44 -07:00
|
|
|
// exactInvokerForm (Object,Object)Object
|
|
|
|
// link with java.lang.invoke.MethodHandle.invokeBasic(MethodHandle,Object,Object)Object/invokeSpecial
|
|
|
|
final int THIS_MH = 0;
|
|
|
|
final int CALL_MH = THIS_MH + (isLinker ? 0 : 1);
|
|
|
|
final int ARG_BASE = CALL_MH + 1;
|
|
|
|
final int OUTARG_LIMIT = ARG_BASE + mtype.parameterCount();
|
2012-08-17 13:42:25 -07:00
|
|
|
final int INARG_LIMIT = OUTARG_LIMIT + (isLinker && !customized ? 1 : 0);
|
2012-07-24 10:47:44 -07:00
|
|
|
int nameCursor = OUTARG_LIMIT;
|
2012-08-17 13:42:25 -07:00
|
|
|
final int MTYPE_ARG = customized ? -1 : nameCursor++; // might be last in-argument
|
2012-07-24 10:47:44 -07:00
|
|
|
final int CHECK_TYPE = nameCursor++;
|
|
|
|
final int LINKER_CALL = nameCursor++;
|
|
|
|
MethodType invokerFormType = mtype.invokerType();
|
|
|
|
if (isLinker) {
|
2012-08-17 13:42:25 -07:00
|
|
|
if (!customized)
|
|
|
|
invokerFormType = invokerFormType.appendParameterTypes(MemberName.class);
|
2012-07-24 10:47:44 -07:00
|
|
|
} else {
|
|
|
|
invokerFormType = invokerFormType.invokerType();
|
|
|
|
}
|
|
|
|
Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType);
|
2012-08-17 13:42:25 -07:00
|
|
|
assert(names.length == nameCursor)
|
|
|
|
: Arrays.asList(mtype, customized, which, nameCursor, names.length);
|
2012-07-24 10:47:44 -07:00
|
|
|
if (MTYPE_ARG >= INARG_LIMIT) {
|
|
|
|
assert(names[MTYPE_ARG] == null);
|
|
|
|
names[MTYPE_ARG] = BoundMethodHandle.getSpeciesData("L").getterName(names[THIS_MH], 0);
|
|
|
|
// else if isLinker, then MTYPE is passed in from the caller (e.g., the JVM)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make the final call. If isGeneric, then prepend the result of type checking.
|
|
|
|
MethodType outCallType;
|
|
|
|
Object[] outArgs;
|
2012-08-17 13:42:25 -07:00
|
|
|
Object mtypeArg = (customized ? mtype : names[MTYPE_ARG]);
|
2012-07-24 10:47:44 -07:00
|
|
|
if (!isGeneric) {
|
2012-08-17 13:42:25 -07:00
|
|
|
names[CHECK_TYPE] = new Name(NF_checkExactType, names[CALL_MH], mtypeArg);
|
2012-07-24 10:47:44 -07:00
|
|
|
// mh.invokeExact(a*):R => checkExactType(mh, TYPEOF(a*:R)); mh.invokeBasic(a*)
|
|
|
|
outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT, Object[].class);
|
|
|
|
outCallType = mtype;
|
2012-08-17 13:42:25 -07:00
|
|
|
} else if (customized) {
|
|
|
|
names[CHECK_TYPE] = new Name(NF_asType, names[CALL_MH], mtypeArg);
|
|
|
|
// mh.invokeGeneric(a*):R =>
|
|
|
|
// let mt=TYPEOF(a*:R), tmh=asType(mh, mt);
|
|
|
|
// tmh.invokeBasic(a*)
|
|
|
|
outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT, Object[].class);
|
|
|
|
outCallType = mtype;
|
2012-07-24 10:47:44 -07:00
|
|
|
} else {
|
2012-08-17 13:42:25 -07:00
|
|
|
names[CHECK_TYPE] = new Name(NF_checkGenericType, names[CALL_MH], mtypeArg);
|
2012-07-24 10:47:44 -07:00
|
|
|
// mh.invokeGeneric(a*):R =>
|
|
|
|
// let mt=TYPEOF(a*:R), gamh=checkGenericType(mh, mt);
|
|
|
|
// gamh.invokeBasic(mt, mh, a*)
|
|
|
|
final int PREPEND_GAMH = 0, PREPEND_MT = 1, PREPEND_COUNT = 2;
|
2012-08-17 13:42:25 -07:00
|
|
|
assert(GENERIC_INVOKER_SLOP == PREPEND_COUNT);
|
2012-07-24 10:47:44 -07:00
|
|
|
outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT + PREPEND_COUNT, Object[].class);
|
|
|
|
// prepend arguments:
|
|
|
|
System.arraycopy(outArgs, 0, outArgs, PREPEND_COUNT, outArgs.length - PREPEND_COUNT);
|
|
|
|
outArgs[PREPEND_GAMH] = names[CHECK_TYPE];
|
2012-08-17 13:42:25 -07:00
|
|
|
outArgs[PREPEND_MT] = mtypeArg;
|
2012-07-24 10:47:44 -07:00
|
|
|
outCallType = mtype.insertParameterTypes(0, MethodType.class, MethodHandle.class);
|
|
|
|
}
|
|
|
|
names[LINKER_CALL] = new Name(invokeBasicMethod(outCallType), outArgs);
|
|
|
|
lform = new LambdaForm(debugName, INARG_LIMIT, names);
|
|
|
|
if (isLinker)
|
|
|
|
lform.compileToBytecode(); // JVM needs a real methodOop
|
2012-08-17 13:42:25 -07:00
|
|
|
if (isCached)
|
|
|
|
lform = mtype.form().setCachedLambdaForm(which, lform);
|
2012-07-24 10:47:44 -07:00
|
|
|
return lform;
|
|
|
|
}
|
2012-08-17 13:42:25 -07:00
|
|
|
private static final int GENERIC_INVOKER_SLOP = 2; // used elsewhere to avoid arity problems
|
2012-07-24 10:47:44 -07:00
|
|
|
|
|
|
|
/*non-public*/ static
|
|
|
|
WrongMethodTypeException newWrongMethodTypeException(MethodType actual, MethodType expected) {
|
|
|
|
// FIXME: merge with JVM logic for throwing WMTE
|
|
|
|
return new WrongMethodTypeException("expected "+expected+" but found "+actual);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Static definition of MethodHandle.invokeExact checking code. */
|
|
|
|
/*non-public*/ static
|
|
|
|
@ForceInline
|
|
|
|
void checkExactType(Object mhObj, Object expectedObj) {
|
|
|
|
MethodHandle mh = (MethodHandle) mhObj;
|
|
|
|
MethodType expected = (MethodType) expectedObj;
|
|
|
|
MethodType actual = mh.type();
|
|
|
|
if (actual != expected)
|
|
|
|
throw newWrongMethodTypeException(expected, actual);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Static definition of MethodHandle.invokeGeneric checking code. */
|
|
|
|
/*non-public*/ static
|
|
|
|
@ForceInline
|
|
|
|
Object checkGenericType(Object mhObj, Object expectedObj) {
|
|
|
|
MethodHandle mh = (MethodHandle) mhObj;
|
|
|
|
MethodType expected = (MethodType) expectedObj;
|
|
|
|
//MethodType actual = mh.type();
|
|
|
|
MethodHandle gamh = expected.form().genericInvoker;
|
|
|
|
if (gamh != null) return gamh;
|
|
|
|
return prepareForGenericCall(expected);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns an adapter GA for invoking a MH with type adjustments.
|
|
|
|
* The MethodType of the generic invocation site is prepended to MH
|
|
|
|
* and its arguments as follows:
|
|
|
|
* {@code (R)MH.invoke(A*) => GA.invokeBasic(TYPEOF<A*,R>, MH, A*)}
|
|
|
|
*/
|
|
|
|
/*non-public*/ static MethodHandle prepareForGenericCall(MethodType mtype) {
|
|
|
|
// force any needed adapters to be preconstructed
|
|
|
|
MethodTypeForm form = mtype.form();
|
|
|
|
MethodHandle gamh = form.genericInvoker;
|
|
|
|
if (gamh != null) return gamh;
|
|
|
|
try {
|
|
|
|
// Trigger adapter creation.
|
|
|
|
gamh = InvokeGeneric.generalInvokerOf(form.erasedType);
|
|
|
|
form.genericInvoker = gamh;
|
|
|
|
return gamh;
|
|
|
|
} catch (Exception ex) {
|
2012-10-19 17:04:35 -07:00
|
|
|
throw newInternalError("Exception while resolving inexact invoke", ex);
|
2012-07-24 10:47:44 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static MemberName linkToCallSiteMethod(MethodType mtype) {
|
|
|
|
LambdaForm lform = callSiteForm(mtype);
|
|
|
|
return lform.vmentry;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static LambdaForm callSiteForm(MethodType mtype) {
|
|
|
|
mtype = mtype.basicType(); // normalize Z to I, String to Object, etc.
|
|
|
|
LambdaForm lform = mtype.form().cachedLambdaForm(MethodTypeForm.LF_CS_LINKER);
|
|
|
|
if (lform != null) return lform;
|
|
|
|
// exactInvokerForm (Object,Object)Object
|
|
|
|
// link with java.lang.invoke.MethodHandle.invokeBasic(MethodHandle,Object,Object)Object/invokeSpecial
|
|
|
|
final int ARG_BASE = 0;
|
|
|
|
final int OUTARG_LIMIT = ARG_BASE + mtype.parameterCount();
|
|
|
|
final int INARG_LIMIT = OUTARG_LIMIT + 1;
|
|
|
|
int nameCursor = OUTARG_LIMIT;
|
|
|
|
final int CSITE_ARG = nameCursor++; // the last in-argument
|
|
|
|
final int CALL_MH = nameCursor++; // result of getTarget
|
|
|
|
final int LINKER_CALL = nameCursor++;
|
|
|
|
MethodType invokerFormType = mtype.appendParameterTypes(CallSite.class);
|
|
|
|
Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType);
|
|
|
|
assert(names.length == nameCursor);
|
|
|
|
assert(names[CSITE_ARG] != null);
|
|
|
|
names[CALL_MH] = new Name(NF_getCallSiteTarget, names[CSITE_ARG]);
|
|
|
|
// (site.)invokedynamic(a*):R => mh = site.getTarget(); mh.invokeBasic(a*)
|
|
|
|
final int PREPEND_MH = 0, PREPEND_COUNT = 1;
|
|
|
|
Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, OUTARG_LIMIT + PREPEND_COUNT, Object[].class);
|
|
|
|
// prepend MH argument:
|
|
|
|
System.arraycopy(outArgs, 0, outArgs, PREPEND_COUNT, outArgs.length - PREPEND_COUNT);
|
|
|
|
outArgs[PREPEND_MH] = names[CALL_MH];
|
|
|
|
names[LINKER_CALL] = new Name(invokeBasicMethod(mtype), outArgs);
|
|
|
|
lform = new LambdaForm("linkToCallSite", INARG_LIMIT, names);
|
|
|
|
lform.compileToBytecode(); // JVM needs a real methodOop
|
|
|
|
lform = mtype.form().setCachedLambdaForm(MethodTypeForm.LF_CS_LINKER, lform);
|
|
|
|
return lform;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Static definition of MethodHandle.invokeGeneric checking code. */
|
|
|
|
/*non-public*/ static
|
|
|
|
@ForceInline
|
|
|
|
Object getCallSiteTarget(Object site) {
|
|
|
|
return ((CallSite)site).getTarget();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Local constant functions:
|
|
|
|
private static final NamedFunction NF_checkExactType;
|
|
|
|
private static final NamedFunction NF_checkGenericType;
|
2012-08-17 13:42:25 -07:00
|
|
|
private static final NamedFunction NF_asType;
|
2012-07-24 10:47:44 -07:00
|
|
|
private static final NamedFunction NF_getCallSiteTarget;
|
|
|
|
static {
|
|
|
|
try {
|
|
|
|
NF_checkExactType = new NamedFunction(Invokers.class
|
|
|
|
.getDeclaredMethod("checkExactType", Object.class, Object.class));
|
|
|
|
NF_checkGenericType = new NamedFunction(Invokers.class
|
|
|
|
.getDeclaredMethod("checkGenericType", Object.class, Object.class));
|
2012-08-17 13:42:25 -07:00
|
|
|
NF_asType = new NamedFunction(MethodHandle.class
|
|
|
|
.getDeclaredMethod("asType", MethodType.class));
|
2012-07-24 10:47:44 -07:00
|
|
|
NF_getCallSiteTarget = new NamedFunction(Invokers.class
|
|
|
|
.getDeclaredMethod("getCallSiteTarget", Object.class));
|
|
|
|
NF_checkExactType.resolve();
|
|
|
|
NF_checkGenericType.resolve();
|
|
|
|
NF_getCallSiteTarget.resolve();
|
|
|
|
// bound
|
|
|
|
} catch (ReflectiveOperationException ex) {
|
2012-10-19 17:04:35 -07:00
|
|
|
throw newInternalError(ex);
|
2012-07-24 10:47:44 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-05 22:40:09 -07:00
|
|
|
}
|