You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by bl...@apache.org on 2023/09/29 19:51:17 UTC
[groovy] branch feature/GROOVY-8299/default_methods updated: GRPPVY-8299: implement dynamic path for default interface methods
This is an automated email from the ASF dual-hosted git repository.
blackdrag pushed a commit to branch feature/GROOVY-8299/default_methods
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/feature/GROOVY-8299/default_methods by this push:
new 0817795573 GRPPVY-8299: implement dynamic path for default interface methods
0817795573 is described below
commit 08177955736e9ed0952be3f2343b87e370dec346
Author: Jochen Theodorou <bl...@gmx.org>
AuthorDate: Fri Sep 29 21:51:08 2023 +0200
GRPPVY-8299: implement dynamic path for default interface methods
---
.../classgen/asm/indy/InvokeDynamicWriter.java | 22 ++++++-
.../codehaus/groovy/vmplugin/v7/IndyInterface.java | 6 +-
.../groovy/vmplugin/v8/CacheableCallSite.java | 9 ++-
.../codehaus/groovy/vmplugin/v8/IndyInterface.java | 41 +++++++-----
.../org/codehaus/groovy/vmplugin/v8/Selector.java | 74 +++++++++++++---------
5 files changed, 103 insertions(+), 49 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/indy/InvokeDynamicWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/indy/InvokeDynamicWriter.java
index 74aee3209d..041b177c3a 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/indy/InvokeDynamicWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/indy/InvokeDynamicWriter.java
@@ -25,6 +25,7 @@ import org.codehaus.groovy.ast.expr.ConstantExpression;
import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
import org.codehaus.groovy.ast.expr.EmptyExpression;
import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
import org.codehaus.groovy.ast.tools.WideningCategories;
import org.codehaus.groovy.classgen.AsmClassGenerator;
import org.codehaus.groovy.classgen.asm.CompileStack;
@@ -35,6 +36,7 @@ import org.codehaus.groovy.classgen.asm.WriterController;
import org.codehaus.groovy.runtime.wrappers.Wrapper;
import org.codehaus.groovy.vmplugin.v8.IndyInterface;
import org.objectweb.asm.Handle;
+import org.objectweb.asm.Opcodes;
import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandles.Lookup;
@@ -47,6 +49,7 @@ import static org.codehaus.groovy.ast.ClassHelper.boolean_TYPE;
import static org.codehaus.groovy.ast.ClassHelper.getWrapper;
import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveBoolean;
import static org.codehaus.groovy.ast.ClassHelper.isWrapperBoolean;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.bytecodeX;
import static org.codehaus.groovy.classgen.asm.BytecodeHelper.doCast;
import static org.codehaus.groovy.classgen.asm.BytecodeHelper.getTypeDescription;
import static org.codehaus.groovy.vmplugin.v8.IndyInterface.GROOVY_OBJECT;
@@ -57,6 +60,7 @@ import static org.codehaus.groovy.vmplugin.v8.IndyInterface.THIS_CALL;
import static org.codehaus.groovy.vmplugin.v8.IndyInterface.CallType.CAST;
import static org.codehaus.groovy.vmplugin.v8.IndyInterface.CallType.GET;
import static org.codehaus.groovy.vmplugin.v8.IndyInterface.CallType.INIT;
+import static org.codehaus.groovy.vmplugin.v8.IndyInterface.CallType.INTERFACE;
import static org.codehaus.groovy.vmplugin.v8.IndyInterface.CallType.METHOD;
import static org.objectweb.asm.Opcodes.H_INVOKESTATIC;
@@ -122,9 +126,10 @@ public class InvokeDynamicWriter extends InvocationWriter {
compileStack.popLHS();
}
- private void makeIndyCall(final MethodCallerMultiAdapter adapter, final Expression receiver, final boolean implicitThis, final boolean safe, final String methodName, final Expression arguments) {
+ private void makeIndyCall(final MethodCallerMultiAdapter adapter, final Expression origReceiver, final boolean implicitThis, final boolean safe, final String methodName, final Expression arguments) {
OperandStack operandStack = controller.getOperandStack();
+ Expression receiver = correctReceiverForInterfaceCall(origReceiver, operandStack);
StringBuilder sig = new StringBuilder(prepareIndyCall(receiver, implicitThis));
// load arguments
@@ -150,12 +155,27 @@ public class InvokeDynamicWriter extends InvocationWriter {
}
sig.append(")Ljava/lang/Object;");
+
String callSiteName = METHOD.getCallSiteName();
if (adapter == null) callSiteName = INIT.getCallSiteName();
+ // receiver != origReceiver interface default method call
+ if (receiver != origReceiver) callSiteName = INTERFACE.getCallSiteName();
+
int flags = getMethodCallFlags(adapter, safe, containsSpreadExpression);
+
finishIndyCall(BSM, callSiteName, sig.toString(), numberOfArguments, methodName, flags);
}
+ private Expression correctReceiverForInterfaceCall(Expression exp, OperandStack operandStack) {
+ if (exp instanceof PropertyExpression) {
+ PropertyExpression pexp = (PropertyExpression) exp;
+ if (pexp.getObjectExpression() instanceof ClassExpression && "super".equals(pexp.getPropertyAsString())) {
+ return bytecodeX(pexp.getObjectExpression().getType(), mv -> mv.visitIntInsn(Opcodes.ALOAD, 0));
+ }
+ }
+ return exp;
+ }
+
private static int getMethodCallFlags(final MethodCallerMultiAdapter adapter, final boolean safe, final boolean spread) {
int flags = 0;
if (safe) flags |= SAFE_NAVIGATION;
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v7/IndyInterface.java b/src/main/java/org/codehaus/groovy/vmplugin/v7/IndyInterface.java
index 2583aeaf68..57e8da6e18 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v7/IndyInterface.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v7/IndyInterface.java
@@ -18,6 +18,8 @@
*/
package org.codehaus.groovy.vmplugin.v7;
+import org.codehaus.groovy.vmplugin.v8.CacheableCallSite;
+
import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
@@ -121,14 +123,14 @@ public class IndyInterface {
* 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 {
- return org.codehaus.groovy.vmplugin.v8.IndyInterface.fromCache(callSite, sender, methodName, callID, safeNavigation, thisCall, spreadCall, dummyReceiver, arguments);
+ return org.codehaus.groovy.vmplugin.v8.IndyInterface.fromCache((CacheableCallSite)callSite, sender, methodName, callID, safeNavigation, thisCall, spreadCall, dummyReceiver, arguments);
}
/**
* 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 {
- return org.codehaus.groovy.vmplugin.v8.IndyInterface.selectMethod(callSite, sender, methodName, callID, safeNavigation, thisCall, spreadCall, dummyReceiver, arguments);
+ return org.codehaus.groovy.vmplugin.v8.IndyInterface.selectMethod((CacheableCallSite)callSite, sender, methodName, callID, safeNavigation, thisCall, spreadCall, dummyReceiver, arguments);
}
/**
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v8/CacheableCallSite.java b/src/main/java/org/codehaus/groovy/vmplugin/v8/CacheableCallSite.java
index a356f0a20c..9e00ccfa8e 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v8/CacheableCallSite.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v8/CacheableCallSite.java
@@ -22,6 +22,7 @@ import org.apache.groovy.util.SystemUtil;
import org.codehaus.groovy.runtime.memoize.MemoizeCache;
import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.MutableCallSite;
import java.lang.ref.SoftReference;
@@ -38,6 +39,7 @@ public class CacheableCallSite extends MutableCallSite {
private static final int CACHE_SIZE = SystemUtil.getIntegerSafe("groovy.indy.callsite.cache.size", 4);
private static final float LOAD_FACTOR = 0.75f;
private static final int INITIAL_CAPACITY = (int) Math.ceil(CACHE_SIZE / LOAD_FACTOR) + 1;
+ private final MethodHandles.Lookup lookup;
private volatile SoftReference<MethodHandleWrapper> latestHitMethodHandleWrapperSoftReference = null;
private final AtomicLong fallbackCount = new AtomicLong();
private MethodHandle defaultTarget;
@@ -52,8 +54,9 @@ public class CacheableCallSite extends MutableCallSite {
}
};
- public CacheableCallSite(MethodType type) {
+ public CacheableCallSite(MethodType type, MethodHandles.Lookup lookup) {
super(type);
+ this.lookup = lookup;
}
public MethodHandleWrapper getAndPut(String className, MemoizeCache.ValueProvider<? super String, ? extends MethodHandleWrapper> valueProvider) {
@@ -124,4 +127,8 @@ public class CacheableCallSite extends MutableCallSite {
public void setFallbackTarget(MethodHandle fallbackTarget) {
this.fallbackTarget = fallbackTarget;
}
+
+ public MethodHandles.Lookup getLookup() {
+ return lookup;
+ }
}
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v8/IndyInterface.java b/src/main/java/org/codehaus/groovy/vmplugin/v8/IndyInterface.java
index 04a2d2d94a..b719d5e641 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v8/IndyInterface.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v8/IndyInterface.java
@@ -67,23 +67,28 @@ public class IndyInterface {
/**
* Method invocation type
*/
- METHOD("invoke"),
+ METHOD("invoke", 0),
/**
* Constructor invocation type
*/
- INIT("init"),
+ INIT("init", 1),
/**
* Get property invocation type
*/
- GET("getProperty"),
+ GET("getProperty", 2),
/**
* Set property invocation type
*/
- SET("setProperty"),
+ SET("setProperty", 3),
/**
* Cast invocation type
*/
- CAST("cast");
+ CAST("cast", 4),
+
+ /**
+ * call to interface method
+ */
+ INTERFACE("interface", 5);
private static final Map<String, CallType> NAME_CALLTYPE_MAP =
Stream.of(CallType.values()).collect(Collectors.toMap(CallType::getCallSiteName, Function.identity()));
@@ -92,8 +97,10 @@ public class IndyInterface {
* The name of the call site type
*/
private final String name;
+ private final int orderNumber;
- CallType(String callSiteName) {
+ CallType(String callSiteName, int orderNumber) {
+ this.orderNumber = orderNumber;
this.name = callSiteName;
}
@@ -107,6 +114,10 @@ public class IndyInterface {
public static CallType fromCallSiteName(String callSiteName) {
return NAME_CALLTYPE_MAP.get(callSiteName);
}
+
+ public int getOrderNumber() {
+ return this.orderNumber;
+ }
}
/**
@@ -153,14 +164,14 @@ public class IndyInterface {
static {
try {
- MethodType mt = MethodType.methodType(Object.class, MutableCallSite.class, Class.class, String.class, int.class, Boolean.class, Boolean.class, Boolean.class, Object.class, Object[].class);
+ MethodType mt = MethodType.methodType(Object.class, CacheableCallSite.class, Class.class, String.class, int.class, Boolean.class, Boolean.class, Boolean.class, Object.class, Object[].class);
FROM_CACHE_METHOD = LOOKUP.findStatic(IndyInterface.class, "fromCache", mt);
} catch (Exception e) {
throw new GroovyBugError(e);
}
try {
- MethodType mt = MethodType.methodType(Object.class, MutableCallSite.class, Class.class, String.class, int.class, Boolean.class, Boolean.class, Boolean.class, Object.class, Object[].class);
+ MethodType mt = MethodType.methodType(Object.class, CacheableCallSite.class, Class.class, String.class, int.class, Boolean.class, Boolean.class, Boolean.class, Object.class, Object[].class);
SELECT_METHOD = LOOKUP.findStatic(IndyInterface.class, "selectMethod", mt);
} catch (Exception e) {
throw new GroovyBugError(e);
@@ -208,7 +219,7 @@ public class IndyInterface {
CallType ct = CallType.fromCallSiteName(callType);
if (null == ct) throw new GroovyBugError("Unknown call type: " + callType);
- int callID = ct.ordinal();
+ int callID = ct.getOrderNumber();
boolean safe = (flags & SAFE_NAVIGATION) != 0;
boolean thisCall = (flags & THIS_CALL) != 0;
boolean spreadCall = (flags & SPREAD_CALL) != 0;
@@ -223,7 +234,7 @@ public class IndyInterface {
// first produce a dummy call site, since indy doesn't give the runtime types;
// the site then changes to the target when INDY_OPTIMIZE_THRESHOLD is reached
// that does the method selection including the direct call to the real method
- CacheableCallSite mc = new CacheableCallSite(type);
+ CacheableCallSite mc = new CacheableCallSite(type, caller);
Class<?> sender = caller.lookupClass();
if (thisCall) {
while (GeneratedClosure.class.isAssignableFrom(sender)) {
@@ -258,7 +269,7 @@ public class IndyInterface {
}
private static class FallbackSupplier {
- private final MutableCallSite callSite;
+ private final CacheableCallSite callSite;
private final Class<?> sender;
private final String methodName;
private final int callID;
@@ -269,7 +280,7 @@ public class IndyInterface {
private final Object[] arguments;
private MethodHandleWrapper result;
- FallbackSupplier(MutableCallSite callSite, Class<?> sender, String methodName, int callID, Boolean safeNavigation, Boolean thisCall, Boolean spreadCall, Object dummyReceiver, Object[] arguments) {
+ FallbackSupplier(CacheableCallSite 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;
@@ -293,7 +304,7 @@ public class IndyInterface {
/**
* 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 {
+ public static Object fromCache(CacheableCallSite 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 =
@@ -334,7 +345,7 @@ public class IndyInterface {
/**
* 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 {
+ public static Object selectMethod(CacheableCallSite 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) {
@@ -359,7 +370,7 @@ public class IndyInterface {
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) {
+ private static MethodHandleWrapper fallback(CacheableCallSite 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();
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java b/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java
index 7585f70c8d..b7cbbff9c8 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java
@@ -18,7 +18,6 @@
*/
package org.codehaus.groovy.vmplugin.v8;
-import groovy.lang.AdaptingMetaClass;
import groovy.lang.Closure;
import groovy.lang.ExpandoMetaClass;
import groovy.lang.GroovyInterceptable;
@@ -57,7 +56,6 @@ import org.codehaus.groovy.vmplugin.VMPluginFactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
-import java.lang.invoke.MutableCallSite;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
@@ -108,7 +106,7 @@ public abstract class Selector {
public String name;
public MethodHandle handle;
public boolean useMetaClass = false, cache = true;
- public MutableCallSite callSite;
+ public CacheableCallSite callSite;
public Class<?> sender;
public boolean isVargs;
public boolean safeNavigation, safeNavigationOrig, spread;
@@ -126,7 +124,7 @@ public abstract class Selector {
/**
* Returns the Selector
*/
- public static Selector getSelector(MutableCallSite callSite, Class<?> sender, String methodName, int callID, boolean safeNavigation, boolean thisCall, boolean spreadCall, Object[] arguments) {
+ public static Selector getSelector(CacheableCallSite 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:
@@ -139,6 +137,8 @@ public abstract class Selector {
throw new GroovyBugError("your call tried to do a property set, which is not supported.");
case CAST:
return new CastSelector(callSite, arguments);
+ case INTERFACE:
+ return new InterfaceSelector(callSite, sender, methodName, callType, safeNavigation, thisCall, spreadCall, arguments);
default:
throw new GroovyBugError("unexpected call type");
}
@@ -165,7 +165,7 @@ public abstract class Selector {
private static class CastSelector extends MethodSelector {
private final Class<?> staticSourceType, staticTargetType;
- public CastSelector(MutableCallSite callSite, Object[] arguments) {
+ public CastSelector(CacheableCallSite callSite, Object[] arguments) {
super(callSite, Selector.class, "", CallType.CAST, Boolean.FALSE, Boolean.FALSE, Boolean.FALSE, arguments);
this.staticSourceType = callSite.type().parameterType(0);
this.staticTargetType = callSite.type().returnType();
@@ -284,7 +284,7 @@ public abstract class Selector {
private static class PropertySelector extends MethodSelector {
private boolean insertName;
- public PropertySelector(MutableCallSite callSite, Class<?> sender, String methodName, CallType callType, boolean safeNavigation, boolean thisCall, boolean spreadCall, Object[] arguments) {
+ public PropertySelector(CacheableCallSite callSite, Class<?> sender, String methodName, CallType callType, boolean safeNavigation, boolean thisCall, boolean spreadCall, Object[] arguments) {
super(callSite, sender, methodName, callType, safeNavigation, thisCall, spreadCall, arguments);
}
@@ -384,7 +384,7 @@ public abstract class Selector {
private static final MethodType MT_OBJECT = MethodType.methodType(Object.class);
private boolean beanConstructor;
- public InitSelector(MutableCallSite callSite, Class<?> sender, String methodName, CallType callType, boolean safeNavigation, boolean thisCall, boolean spreadCall, Object[] arguments) {
+ public InitSelector(CacheableCallSite callSite, Class<?> sender, String methodName, CallType callType, boolean safeNavigation, boolean thisCall, boolean spreadCall, Object[] arguments) {
super(callSite, sender, methodName, callType, safeNavigation, thisCall, spreadCall, arguments);
}
@@ -434,7 +434,7 @@ public abstract class Selector {
if (LOG_ENABLED) LOG.info("meta method is MetaConstructor instance");
MetaConstructor mc = (MetaConstructor) method;
isVargs = mc.isVargsMethod();
- Constructor con = mc.getCachedConstrcutor().getCachedConstructor();
+ Constructor<?> con = mc.getCachedConstrcutor().getCachedConstructor();
try {
handle = LOOKUP.unreflectConstructor(con);
if (LOG_ENABLED) LOG.info("successfully unreflected constructor");
@@ -466,7 +466,7 @@ public abstract class Selector {
/**
* In case of a bean constructor we don't do any varags or implicit null argument
- * transformations. Otherwise we do the same as for {@link MethodSelector#correctParameterLength()}
+ * transformations. Otherwise, we do the same as for {@link MethodSelector#correctParameterLength()}
*/
@Override
public void correctParameterLength() {
@@ -499,6 +499,31 @@ public abstract class Selector {
}
}
+ private static class InterfaceSelector extends MethodSelector {
+ public InterfaceSelector(CacheableCallSite callSite, Class<?> sender, String methodName, CallType callType, boolean safeNavigation, boolean thisCall, boolean spreadCall, Object[] arguments) {
+ super(callSite, sender, methodName, callType, safeNavigation, thisCall, spreadCall, arguments);
+ }
+
+ @Override
+ public MetaClass getMetaClass() {
+ mc = GroovySystem.getMetaClassRegistry().getMetaClass(targetType.parameterType(0));
+ mc.initialize();
+ if (LOG_ENABLED) LOG.info("meta class is " + mc);
+ return mc;
+ }
+
+ @Override
+ public void setSelectionBase() {
+ selectionBase = mc.getTheClass();
+ if (LOG_ENABLED) LOG.info("selectionBase set to " + selectionBase);
+ }
+
+ @Override
+ public MethodHandle unreflect(Method cachedMethod) throws IllegalAccessException {
+ return this.callSite.getLookup().unreflectSpecial(cachedMethod, this.sender); // throws if sender cannot invoke method
+ }
+ }
+
/**
* Method invocation based {@link Selector}.
* This Selector is called for method invocations and is base for constructor
@@ -509,7 +534,7 @@ public abstract class Selector {
private boolean isCategoryMethod;
protected MetaClass mc;
- public MethodSelector(MutableCallSite callSite, Class<?> sender, String methodName, CallType callType, Boolean safeNavigation, Boolean thisCall, Boolean spreadCall, Object[] arguments) {
+ public MethodSelector(CacheableCallSite 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;
@@ -654,8 +679,7 @@ public abstract class Selector {
} else if (parameterCount == 1 && name.equals("forName") && declaringClass == Class.class) {
handle = MethodHandles.insertArguments(CLASS_FOR_NAME, 1, Boolean.TRUE, sender.getClassLoader());
} else {
- MethodHandles.Lookup lookup = cm.isPublic() ? LOOKUP : ((Java8)vmplugin).newLookup(sender); // GROOVY-10070, et al.
- handle = lookup.unreflect(cm.getCachedMethod()); // throws if sender cannot invoke method
+ handle = unreflect(cm.getCachedMethod());
}
} catch (ReflectiveOperationException e) {
throw new GroovyBugError(e);
@@ -686,6 +710,10 @@ public abstract class Selector {
}
}
+ protected MethodHandle unreflect(Method cachedMethod) throws IllegalAccessException {
+ return this.callSite.getLookup().unreflect(cachedMethod); // throws if sender cannot invoke method
+ }
+
/**
* Helper method to manipulate the given type to replace Wrapper with Object.
*/
@@ -834,10 +862,10 @@ public abstract class Selector {
// equal in terms of an assignment in Java. That means according to Java widening rules, or
// a subclass, interface, superclass relation, this case then handles also
- // primitive to primitive conversion. Those case are also solved by explicitCastArguments.
+ // primitive to primitive conversion. Those cases are also solved by explicitCastArguments.
if (parameterType.isAssignableFrom(got)) continue;
- // to aid explicitCastArguments we convert to the wrapper type to let is only unbox
+ // to aid explicitCastArguments we convert to the wrapper type to let it only unbox
handle = TypeTransformers.addTransformer(handle, i, arg, wrappedPara);
if (LOG_ENABLED)
LOG.info("added transformer at pos " + i + " for type " + got + " to type " + wrappedPara);
@@ -885,12 +913,7 @@ public abstract class Selector {
if (handle == null) return;
if (!cache) return;
- MethodHandle fallback;
- if (callSite instanceof CacheableCallSite) {
- fallback = ((CacheableCallSite) callSite).getFallbackTarget();
- } else {
- throw new GroovyBugError("CacheableCallSite is expected, but the actual callsite is: " + callSite);
- }
+ MethodHandle fallback = callSite.getFallbackTarget();
// special guards for receiver
if (receiver instanceof GroovyObject) {
@@ -970,14 +993,6 @@ public abstract class Selector {
*/
public void doCallSiteTargetSet() {
if (LOG_ENABLED) LOG.info("call site stays uncached");
- /*
- if (!cache) {
- if (LOG_ENABLED) LOG.info("call site stays uncached");
- } else {
- callSite.setTarget(handle);
- if (LOG_ENABLED) LOG.info("call site target set, preparing outside invocation");
- }
- */
}
/**
@@ -1049,11 +1064,10 @@ public abstract class Selector {
private static MetaClassImpl getMetaClassImpl(final MetaClass mc, final boolean includeEMC) {
Class<?> mcc = mc.getClass();
boolean valid = mcc == MetaClassImpl.class
- || mcc == AdaptingMetaClass.class
|| mcc == ClosureMetaClass.class
|| (includeEMC && mcc == ExpandoMetaClass.class);
if (!valid) {
- if (LOG_ENABLED) LOG.info("meta class is neither MetaClassImpl, nor AdoptingMetaClass, nor ClosureMetaClass, normal method selection path disabled.");
+ if (LOG_ENABLED) LOG.info("meta class is neither MetaClassImpl, nor ClosureMetaClass, normal method selection path disabled.");
return null;
}
if (LOG_ENABLED) LOG.info("meta class is a recognized MetaClassImpl");