下面列出了java.lang.invoke.VolatileCallSite#java.lang.invoke.MutableCallSite 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
public static CallSite gwtBootstrap(Lookup ignored, String name, MethodType type) throws Throwable {
Lookup lookup = lookup();
MethodHandle double_string = lookup.findStatic(BootstrapMethods.class, "dup", methodType(String.class, String.class));
MethodHandle double_integer = lookup.findStatic(BootstrapMethods.class, "dup", methodType(String.class, Integer.class));
MethodHandle double_object = lookup.findStatic(BootstrapMethods.class, "dup", methodType(String.class, Object.class));
MethodHandle isInteger = lookup.findStatic(BootstrapMethods.class, "isInteger", methodType(boolean.class, Object.class));
MethodHandle isString = lookup.findStatic(BootstrapMethods.class, "isString", methodType(boolean.class, Object.class));
MethodHandle handle = guardWithTest(
isString,
double_string.asType(methodType(String.class, Object.class)),
double_object);
handle = guardWithTest(
isInteger,
double_integer.asType(methodType(String.class, Object.class)),
handle);
return new MutableCallSite(handle);
}
private static void registerCallSitePlugins(InvocationPlugins plugins) {
InvocationPlugin plugin = new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
ValueNode callSite = receiver.get();
ValueNode folded = CallSiteTargetNode.tryFold(GraphUtil.originalValue(callSite), b.getMetaAccess(), b.getAssumptions());
if (folded != null) {
b.addPush(JavaKind.Object, folded);
} else {
b.addPush(JavaKind.Object, new CallSiteTargetNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()), callSite));
}
return true;
}
@Override
public boolean inlineOnly() {
return true;
}
};
plugins.register(plugin, ConstantCallSite.class, "getTarget", Receiver.class);
plugins.register(plugin, MutableCallSite.class, "getTarget", Receiver.class);
plugins.register(plugin, VolatileCallSite.class, "getTarget", Receiver.class);
}
public static void testNonBoundCallSite() throws Throwable {
mcs = new MutableCallSite(LOOKUP.findStatic(T.class, "f1", TYPE));
// mcs.context == null
MethodHandle mh = mcs.dynamicInvoker();
execute(1, mh);
// mcs.context == cls1
Class<?> cls1 = UNSAFE.defineAnonymousClass(CallSiteDepContextTest.class, getClassFile("NonBound_1"), null);
MethodHandle mh1 = LOOKUP.findStatic(cls1, METHOD_NAME, TYPE);
execute(1, mh1);
mcs.setTarget(LOOKUP.findStatic(T.class, "f2", TYPE));
execute(2, mh, mh1);
}
/**
* Returns the Selector
*/
public static Selector getSelector(MutableCallSite callSite, Class<?> sender, String methodName, int callID, boolean safeNavigation, boolean thisCall, boolean spreadCall, Object[] arguments) {
CallType callType = CALL_TYPE_VALUES[callID];
switch (callType) {
case INIT:
return new InitSelector(callSite, sender, methodName, callType, safeNavigation, thisCall, spreadCall, arguments);
case METHOD:
return new MethodSelector(callSite, sender, methodName, callType, safeNavigation, thisCall, spreadCall, arguments);
case GET:
return new PropertySelector(callSite, sender, methodName, callType, safeNavigation, thisCall, spreadCall, arguments);
case SET:
throw new GroovyBugError("your call tried to do a property set, which is not supported.");
case CAST:
return new CastSelector(callSite, arguments);
default:
throw new GroovyBugError("unexpected call type");
}
}
/**
* Core method for indy method selection using runtime types.
*/
public static Object selectMethod(MutableCallSite callSite, Class<?> sender, String methodName, int callID, Boolean safeNavigation, Boolean thisCall, Boolean spreadCall, Object dummyReceiver, Object[] arguments) throws Throwable {
final MethodHandleWrapper mhw = fallback(callSite, sender, methodName, callID, safeNavigation, thisCall, spreadCall, dummyReceiver, arguments);
if (callSite instanceof CacheableCallSite) {
CacheableCallSite cacheableCallSite = (CacheableCallSite) callSite;
final MethodHandle defaultTarget = cacheableCallSite.getDefaultTarget();
final long fallbackCount = cacheableCallSite.incrementFallbackCount();
if ((fallbackCount > INDY_FALLBACK_THRESHOLD) && (cacheableCallSite.getTarget() != defaultTarget)) {
cacheableCallSite.setTarget(defaultTarget);
if (LOG_ENABLED) LOG.info("call site target reset to default, preparing outside invocation");
cacheableCallSite.resetFallbackCount();
}
if (defaultTarget == cacheableCallSite.getTarget()) {
// correct the stale methodhandle in the inline cache of callsite
// it is important but impacts the performance somehow when cache misses frequently
doWithCallSite(callSite, arguments, (cs, receiver) -> cs.put(receiver.getClass().getName(), mhw));
}
}
return mhw.getCachedMethodHandle().invokeExact(arguments);
}
@SuppressWarnings("unused")
private static MethodHandle nativeCallSetup(MutableCallSite callsite, String name, ExecutionContext cx) {
RuntimeContext context = cx.getRuntimeContext();
MethodHandle target;
try {
MethodHandle mh = context.getNativeCallResolver().apply(name, callsite.type());
if (mh == null) {
throw new IllegalArgumentException();
}
target = adaptNativeMethodHandle(mh);
target = adaptMethodHandle(name, callsite.type(), target);
} catch (IllegalArgumentException e) {
target = invalidCallHandle(name, callsite.type());
}
callsite.setTarget(target);
return target;
}
private static void concatSetup(MutableCallSite callsite, MethodType type) {
MethodHandle target, test, generic;
int numberOfStrings = type.parameterCount() - 1; // CharSequence..., ExecutionContext
if (numberOfStrings <= CONCAT_MAX_SPECIALIZATION) {
assert numberOfStrings >= CONCAT_MIN_PARAMS;
int index = numberOfStrings - CONCAT_MIN_PARAMS;
target = concatMH[index];
test = testConcatMH[index];
generic = concatConsMH[index];
} else {
final int index = CONCAT_MAX_SPECIALIZATION - CONCAT_MIN_PARAMS + 1;
target = concatMH[index].asCollector(CharSequence[].class, numberOfStrings);
test = testConcatMH[index].asCollector(CharSequence[].class, numberOfStrings);
generic = concatConsMH[index].asCollector(CharSequence[].class, numberOfStrings);
}
setCallSiteTarget(callsite, target, test, generic);
}
private static MethodHandle setCallSiteTarget(MutableCallSite callsite, MethodHandle target, MethodHandle test,
MethodHandle generic) {
MethodHandle callSiteTarget;
if (target != null) {
target = target.asType(callsite.type());
if (test != null) {
MethodHandle fallback = createFallback(callsite, generic);
callSiteTarget = MethodHandles.guardWithTest(test, target, fallback);
} else {
callSiteTarget = target;
}
} else {
callSiteTarget = target = generic;
}
callsite.setTarget(callSiteTarget);
return target;
}
private static void loadBuiltins(TypeImpl ti, ClassLoader cl, Map<String, JCasClassInfo> type2jcci, ArrayList<MutableCallSite> callSites_toSync) {
String typeName = ti.getName();
if (BuiltinTypeKinds.creatableBuiltinJCas.contains(typeName) || typeName.equals(CAS.TYPE_NAME_SOFA)) {
JCasClassInfo jcci = getOrCreateJCasClassInfo(ti, cl, type2jcci, defaultLookup);
assert jcci != null;
// done while beginning to commit the staticTsi (before committed flag is set), for builtins
updateOrValidateAllCallSitesForJCasClass(jcci.jcasClass, ti, callSites_toSync);
jcasClassesInfoForBuiltins[ti.getCode()] = jcci;
// Class<?> builtinClass = maybeLoadJCas(ti, cl);
// assert (builtinClass != null); // builtin types must be present
// // copy down to subtypes, if needed, done later
// int jcasType = Misc.getStaticIntFieldNoInherit(builtinClass, "typeIndexID");
// JCasClassInfo jcasClassInfo = createJCasClassInfo(builtinClass, ti, jcasType);
// jcasClassesInfoForBuiltins[ti.getCode()] = jcasClassInfo;
}
for (TypeImpl subType : ti.getDirectSubtypes()) {
loadBuiltins(subType, cl, type2jcci, callSites_toSync);
}
}
public static void main(String[] args) throws ReflectiveOperationException {
// Objects
test(new Object());
test("TEST");
test(new VMAnonymousClasses());
test(null);
// Class
test(String.class);
// Arrays
test(new boolean[0]);
test(new byte[0]);
test(new char[0]);
test(new short[0]);
test(new int[0]);
test(new long[0]);
test(new float[0]);
test(new double[0]);
test(new Object[0]);
// Multi-dimensional arrays
test(new byte[0][0]);
test(new Object[0][0]);
// MethodHandle-related
MethodType mt = MethodType.methodType(void.class, String[].class);
MethodHandle mh = MethodHandles.lookup().findStatic(VMAnonymousClasses.class, "main", mt);
test(mt);
test(mh);
test(new ConstantCallSite(mh));
test(new MutableCallSite(MethodType.methodType(void.class)));
test(new VolatileCallSite(MethodType.methodType(void.class)));
System.out.println("TEST PASSED");
}
private MethodHandle createComposableInvoker(final boolean isConstructor) {
final MethodHandle handle = getInvokerOrConstructor(isConstructor);
// If compiled function is not optimistic, it can't ever change its invoker/constructor, so just return them
// directly.
if(!canBeDeoptimized()) {
return handle;
}
// Otherwise, we need a new level of indirection; need to introduce a mutable call site that can relink itself
// to the compiled function's changed target whenever the optimistic assumptions are invalidated.
final CallSite cs = new MutableCallSite(handle.type());
relinkComposableInvoker(cs, this, isConstructor);
return cs.dynamicInvoker();
}
public static void main(String[] args) throws ReflectiveOperationException {
// Objects
test(new Object());
test("TEST");
test(new VMAnonymousClasses());
test(null);
// Class
test(String.class);
// Arrays
test(new boolean[0]);
test(new byte[0]);
test(new char[0]);
test(new short[0]);
test(new int[0]);
test(new long[0]);
test(new float[0]);
test(new double[0]);
test(new Object[0]);
// Multi-dimensional arrays
test(new byte[0][0]);
test(new Object[0][0]);
// MethodHandle-related
MethodType mt = MethodType.methodType(void.class, String[].class);
MethodHandle mh = MethodHandles.lookup().findStatic(VMAnonymousClasses.class, "main", mt);
test(mt);
test(mh);
test(new ConstantCallSite(mh));
test(new MutableCallSite(MethodType.methodType(void.class)));
test(new VolatileCallSite(MethodType.methodType(void.class)));
System.out.println("TEST PASSED");
}
private MethodHandle createComposableInvoker(final boolean isConstructor) {
final MethodHandle handle = getInvokerOrConstructor(isConstructor);
// If compiled function is not optimistic, it can't ever change its invoker/constructor, so just return them
// directly.
if(!canBeDeoptimized()) {
return handle;
}
// Otherwise, we need a new level of indirection; need to introduce a mutable call site that can relink itslef
// to the compiled function's changed target whenever the optimistic assumptions are invalidated.
final CallSite cs = new MutableCallSite(handle.type());
relinkComposableInvoker(cs, this, isConstructor);
return cs.dynamicInvoker();
}
public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, MethodType type) {
try {
_callSite = new MutableCallSite(lookup.findStatic(
FastPathGuardsBench.class,
"expensiveCalculation",
methodType(int.class, int.class, int.class, int.class)));
return _callSite;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) throws ReflectiveOperationException {
// Objects
test(new Object());
test("TEST");
test(new VMAnonymousClasses());
test(null);
// Class
test(String.class);
// Arrays
test(new boolean[0]);
test(new byte[0]);
test(new char[0]);
test(new short[0]);
test(new int[0]);
test(new long[0]);
test(new float[0]);
test(new double[0]);
test(new Object[0]);
// Multi-dimensional arrays
test(new byte[0][0]);
test(new Object[0][0]);
// MethodHandle-related
MethodType mt = MethodType.methodType(void.class, String[].class);
MethodHandle mh = MethodHandles.lookup().findStatic(VMAnonymousClasses.class, "main", mt);
test(mt);
test(mh);
test(new ConstantCallSite(mh));
test(new MutableCallSite(MethodType.methodType(void.class)));
test(new VolatileCallSite(MethodType.methodType(void.class)));
System.out.println("TEST PASSED");
}
private MethodHandle createComposableInvoker(final boolean isConstructor) {
final MethodHandle handle = getInvokerOrConstructor(isConstructor);
// If compiled function is not optimistic, it can't ever change its invoker/constructor, so just return them
// directly.
if(!canBeDeoptimized()) {
return handle;
}
// Otherwise, we need a new level of indirection; need to introduce a mutable call site that can relink itself
// to the compiled function's changed target whenever the optimistic assumptions are invalidated.
final CallSite cs = new MutableCallSite(handle.type());
relinkComposableInvoker(cs, this, isConstructor);
return cs.dynamicInvoker();
}
public static void main(String[] args) throws ReflectiveOperationException {
// Objects
test(new Object());
test("TEST");
test(new VMAnonymousClasses());
test(null);
// Class
test(String.class);
// Arrays
test(new boolean[0]);
test(new byte[0]);
test(new char[0]);
test(new short[0]);
test(new int[0]);
test(new long[0]);
test(new float[0]);
test(new double[0]);
test(new Object[0]);
// Multi-dimensional arrays
test(new byte[0][0]);
test(new Object[0][0]);
// MethodHandle-related
MethodType mt = MethodType.methodType(void.class, String[].class);
MethodHandle mh = MethodHandles.lookup().findStatic(VMAnonymousClasses.class, "main", mt);
test(mt);
test(mh);
test(new ConstantCallSite(mh));
test(new MutableCallSite(MethodType.methodType(void.class)));
test(new VolatileCallSite(MethodType.methodType(void.class)));
System.out.println("TEST PASSED");
}
private MethodHandle createComposableInvoker(final boolean isConstructor) {
final MethodHandle handle = getInvokerOrConstructor(isConstructor);
// If compiled function is not optimistic, it can't ever change its invoker/constructor, so just return them
// directly.
if(!canBeDeoptimized()) {
return handle;
}
// Otherwise, we need a new level of indirection; need to introduce a mutable call site that can relink itself
// to the compiled function's changed target whenever the optimistic assumptions are invalidated.
final CallSite cs = new MutableCallSite(handle.type());
relinkComposableInvoker(cs, this, isConstructor);
return cs.dynamicInvoker();
}
public static void main(String[] args) throws ReflectiveOperationException {
// Objects
test(new Object());
test("TEST");
test(new VMAnonymousClasses());
test(null);
// Class
test(String.class);
// Arrays
test(new boolean[0]);
test(new byte[0]);
test(new char[0]);
test(new short[0]);
test(new int[0]);
test(new long[0]);
test(new float[0]);
test(new double[0]);
test(new Object[0]);
// Multi-dimensional arrays
test(new byte[0][0]);
test(new Object[0][0]);
// MethodHandle-related
MethodType mt = MethodType.methodType(void.class, String[].class);
MethodHandle mh = MethodHandles.lookup().findStatic(VMAnonymousClasses.class, "main", mt);
test(mt);
test(mh);
test(new ConstantCallSite(mh));
test(new MutableCallSite(MethodType.methodType(void.class)));
test(new VolatileCallSite(MethodType.methodType(void.class)));
System.out.println("TEST PASSED");
}
public static void testSharedCallSite() throws Throwable {
Class<?> cls1 = UNSAFE.defineAnonymousClass(CallSiteDepContextTest.class, getClassFile("CS_1"), null);
Class<?> cls2 = UNSAFE.defineAnonymousClass(CallSiteDepContextTest.class, getClassFile("CS_2"), null);
MethodHandle[] mhs = new MethodHandle[] {
LOOKUP.findStatic(cls1, METHOD_NAME, TYPE),
LOOKUP.findStatic(cls2, METHOD_NAME, TYPE)
};
mcs = new MutableCallSite(LOOKUP.findStatic(T.class, "f1", TYPE));
execute(1, mhs);
mcs.setTarget(LOOKUP.findStatic(T.class, "f2", TYPE));
execute(2, mhs);
}
private MethodHandle createComposableInvoker(final boolean isConstructor) {
final MethodHandle handle = getInvokerOrConstructor(isConstructor);
// If compiled function is not optimistic, it can't ever change its invoker/constructor, so just return them
// directly.
if(!canBeDeoptimized()) {
return handle;
}
// Otherwise, we need a new level of indirection; need to introduce a mutable call site that can relink itself
// to the compiled function's changed target whenever the optimistic assumptions are invalidated.
final CallSite cs = new MutableCallSite(handle.type());
relinkComposableInvoker(cs, this, isConstructor);
return cs.dynamicInvoker();
}
/**
* Relinks a call site conforming to the invocation arguments.
*
* @param callSite the call site itself
* @param arguments arguments to the invocation
*
* @return return the method handle for the invocation
*
* @throws Exception rethrows any exception thrown by the linkers
*/
@SuppressWarnings("unused")
private MethodHandle relink(final RelinkableCallSite callSite, final int relinkCount, final Object... arguments) throws Exception {
final CallSiteDescriptor callSiteDescriptor = callSite.getDescriptor();
final boolean unstableDetectionEnabled = unstableRelinkThreshold > 0;
final boolean callSiteUnstable = unstableDetectionEnabled && relinkCount >= unstableRelinkThreshold;
final LinkRequest linkRequest = new SimpleLinkRequest(callSiteDescriptor, callSiteUnstable, arguments);
GuardedInvocation guardedInvocation = linkerServices.getGuardedInvocation(linkRequest);
// None found - throw an exception
if(guardedInvocation == null) {
throw new NoSuchDynamicMethodException(callSiteDescriptor.toString());
}
// Make sure we transform the invocation before linking it into the call site. This is typically used to match the
// return type of the invocation to the call site.
guardedInvocation = prelinkTransformer.filter(guardedInvocation, linkRequest, linkerServices);
Objects.requireNonNull(guardedInvocation);
int newRelinkCount = relinkCount;
// Note that the short-circuited "&&" evaluation below ensures we'll increment the relinkCount until
// threshold + 1 but not beyond that. Threshold + 1 is treated as a special value to signal that resetAndRelink
// has already executed once for the unstable call site; we only want the call site to throw away its current
// linkage once, when it transitions to unstable.
if(unstableDetectionEnabled && newRelinkCount <= unstableRelinkThreshold && newRelinkCount++ == unstableRelinkThreshold) {
callSite.resetAndRelink(guardedInvocation, createRelinkAndInvokeMethod(callSite, newRelinkCount));
} else {
callSite.relink(guardedInvocation, createRelinkAndInvokeMethod(callSite, newRelinkCount));
}
if(syncOnRelink) {
MutableCallSite.syncAll(new MutableCallSite[] { (MutableCallSite)callSite });
}
return guardedInvocation.getInvocation();
}
public static void main(String[] args) throws ReflectiveOperationException {
// Objects
test(new Object());
test("TEST");
test(new VMAnonymousClasses());
test(null);
// Class
test(String.class);
// Arrays
test(new boolean[0]);
test(new byte[0]);
test(new char[0]);
test(new short[0]);
test(new int[0]);
test(new long[0]);
test(new float[0]);
test(new double[0]);
test(new Object[0]);
// Multi-dimensional arrays
test(new byte[0][0]);
test(new Object[0][0]);
// MethodHandle-related
MethodType mt = MethodType.methodType(void.class, String[].class);
MethodHandle mh = MethodHandles.lookup().findStatic(VMAnonymousClasses.class, "main", mt);
test(mt);
test(mh);
test(new ConstantCallSite(mh));
test(new MutableCallSite(MethodType.methodType(void.class)));
test(new VolatileCallSite(MethodType.methodType(void.class)));
System.out.println("TEST PASSED");
}
private MethodHandle createComposableInvoker(final boolean isConstructor) {
final MethodHandle handle = getInvokerOrConstructor(isConstructor);
// If compiled function is not optimistic, it can't ever change its invoker/constructor, so just return them
// directly.
if(!canBeDeoptimized()) {
return handle;
}
// Otherwise, we need a new level of indirection; need to introduce a mutable call site that can relink itself
// to the compiled function's changed target whenever the optimistic assumptions are invalidated.
final CallSite cs = new MutableCallSite(handle.type());
relinkComposableInvoker(cs, this, isConstructor);
return cs.dynamicInvoker();
}
private MethodHandle createComposableInvoker(final boolean isConstructor) {
final MethodHandle handle = getInvokerOrConstructor(isConstructor);
// If compiled function is not optimistic, it can't ever change its invoker/constructor, so just return them
// directly.
if(!canBeDeoptimized()) {
return handle;
}
// Otherwise, we need a new level of indirection; need to introduce a mutable call site that can relink itself
// to the compiled function's changed target whenever the optimistic assumptions are invalidated.
final CallSite cs = new MutableCallSite(handle.type());
relinkComposableInvoker(cs, this, isConstructor);
return cs.dynamicInvoker();
}
public MethodSelector(MutableCallSite callSite, Class<?> sender, String methodName, CallType callType, Boolean safeNavigation, Boolean thisCall, Boolean spreadCall, Object[] arguments) {
this.callType = callType;
this.targetType = callSite.type();
this.name = methodName;
this.originalArguments = arguments;
this.args = spread(arguments, spreadCall);
this.callSite = callSite;
this.sender = sender;
this.safeNavigationOrig = safeNavigation;
this.safeNavigation = safeNavigation && arguments[0] == null;
this.thisCall = thisCall;
this.spread = spreadCall;
this.cache = !spread;
if (LOG_ENABLED) {
StringBuilder msg =
new StringBuilder("----------------------------------------------------" +
"\n\t\tinvocation of method '" + methodName + "'" +
"\n\t\tinvocation type: " + callType +
"\n\t\tsender: " + sender +
"\n\t\ttargetType: " + targetType +
"\n\t\tsafe navigation: " + safeNavigation +
"\n\t\tthisCall: " + thisCall +
"\n\t\tspreadCall: " + spreadCall +
"\n\t\twith " + arguments.length + " arguments");
for (int i = 0; i < arguments.length; i++) {
msg.append("\n\t\t\targument[").append(i).append("] = ");
if (arguments[i] == null) {
msg.append("null");
} else {
msg.append(arguments[i].getClass().getName()).append("@").append(Integer.toHexString(System.identityHashCode(arguments[i])));
}
}
LOG.info(msg.toString());
}
}
FallbackSupplier(MutableCallSite callSite, Class<?> sender, String methodName, int callID, Boolean safeNavigation, Boolean thisCall, Boolean spreadCall, Object dummyReceiver, Object[] arguments) {
this.callSite = callSite;
this.sender = sender;
this.methodName = methodName;
this.callID = callID;
this.safeNavigation = safeNavigation;
this.thisCall = thisCall;
this.spreadCall = spreadCall;
this.dummyReceiver = dummyReceiver;
this.arguments = arguments;
}
/**
* Get the cached methodhandle. if the related methodhandle is not found in the inline cache, cache and return it.
*/
public static Object fromCache(MutableCallSite callSite, Class<?> sender, String methodName, int callID, Boolean safeNavigation, Boolean thisCall, Boolean spreadCall, Object dummyReceiver, Object[] arguments) throws Throwable {
FallbackSupplier fallbackSupplier = new FallbackSupplier(callSite, sender, methodName, callID, safeNavigation, thisCall, spreadCall, dummyReceiver, arguments);
MethodHandleWrapper mhw =
doWithCallSite(
callSite, arguments,
(cs, receiver) ->
cs.getAndPut(
receiver.getClass().getName(),
c -> {
MethodHandleWrapper fbMhw = fallbackSupplier.get();
return fbMhw.isCanSetTarget() ? fbMhw : NULL_METHOD_HANDLE_WRAPPER;
}
)
);
if (NULL_METHOD_HANDLE_WRAPPER == mhw) {
mhw = fallbackSupplier.get();
}
if (mhw.isCanSetTarget() && (callSite.getTarget() != mhw.getTargetMethodHandle()) && (mhw.getLatestHitCount() > INDY_OPTIMIZE_THRESHOLD)) {
callSite.setTarget(mhw.getTargetMethodHandle());
if (LOG_ENABLED) LOG.info("call site target set, preparing outside invocation");
mhw.resetLatestHitCount();
}
return mhw.getCachedMethodHandle().invokeExact(arguments);
}
private static MethodHandleWrapper fallback(MutableCallSite callSite, Class<?> sender, String methodName, int callID, Boolean safeNavigation, Boolean thisCall, Boolean spreadCall, Object dummyReceiver, Object[] arguments) {
Selector selector = Selector.getSelector(callSite, sender, methodName, callID, safeNavigation, thisCall, spreadCall, arguments);
selector.setCallSiteTarget();
return new MethodHandleWrapper(
selector.handle.asSpreader(Object[].class, arguments.length).asType(MethodType.methodType(Object.class, Object[].class)),
selector.handle,
selector.cache
);
}
private static <T> T doWithCallSite(MutableCallSite callSite, Object[] arguments, BiFunction<? super CacheableCallSite, ? super Object, ? extends T> f) {
if (callSite instanceof CacheableCallSite) {
CacheableCallSite cacheableCallSite = (CacheableCallSite) callSite;
Object receiver = arguments[0];
if (null == receiver) receiver = NullObject.getNullObject();
return f.apply(cacheableCallSite, receiver);
}
throw new GroovyBugError("CacheableCallSite is expected, but the actual callsite is: " + callSite);
}