You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2021/06/19 05:51:37 UTC
[groovy] 02/02: Cache special methods
This is an automated email from the ASF dual-hosted git repository.
sunlan pushed a commit to branch danielsun/tweak-build
in repository https://gitbox.apache.org/repos/asf/groovy.git
commit eb48c592444667aada9d18f84c4f9b7d361971bd
Author: Daniel Sun <su...@apache.org>
AuthorDate: Sat Jun 19 13:49:34 2021 +0800
Cache special methods
---
src/main/java/groovy/lang/MetaClassImpl.java | 47 +++++++++++++++++++---
.../groovy/reflection/ReflectionUtils.java | 38 ++++++++++-------
2 files changed, 65 insertions(+), 20 deletions(-)
diff --git a/src/main/java/groovy/lang/MetaClassImpl.java b/src/main/java/groovy/lang/MetaClassImpl.java
index 83a0e1d..4e2d1e9 100644
--- a/src/main/java/groovy/lang/MetaClassImpl.java
+++ b/src/main/java/groovy/lang/MetaClassImpl.java
@@ -104,6 +104,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
@@ -121,6 +122,7 @@ import static java.lang.Character.isUpperCase;
import static org.apache.groovy.util.Arrays.concat;
import static org.codehaus.groovy.ast.tools.GeneralUtils.inSamePackage;
import static org.codehaus.groovy.reflection.ReflectionCache.isAssignableFrom;
+import static org.codehaus.groovy.reflection.ReflectionUtils.parameterTypeMatches;
/**
* Allows methods to be dynamically added to existing classes at runtime
@@ -1152,6 +1154,13 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
private MethodHolder() {}
}
+ private static final ClassValue<Map<String, Set<Method>>> SPECIAL_METHODS_MAP = new ClassValue<Map<String, Set<Method>>>() {
+ @Override
+ protected Map<String, Set<Method>> computeValue(Class<?> type) {
+ return new ConcurrentHashMap<>(4);
+ }
+ };
+
private Object doInvokeMethodFallback(Class sender, Object object, String methodName, Object[] originalArguments, boolean isCallToSuper, MissingMethodException mme) {
MethodHandles.Lookup lookup = null;
if (object instanceof GroovyObject) {
@@ -1163,7 +1172,8 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
final Class<?> receiverClass = object.getClass();
if (isCallToSuper) {
if (null == lookup) throw mme;
- Method superMethod = findMethod(sender, methodName, originalArguments);
+ Class[] argTypes = MetaClassHelper.castArgumentsToClassArray(originalArguments);
+ Method superMethod = findMethod(sender, methodName, argTypes);
if (null == superMethod) throw mme;
MethodHandle superMethodHandle;
try {
@@ -1171,6 +1181,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
} catch (IllegalAccessException e) {
throw mme;
}
+ cacheMethod(sender, superMethod);
try {
return superMethodHandle.bindTo(object).invokeWithArguments(originalArguments);
} catch (Throwable t) {
@@ -1203,7 +1214,8 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
throw mme;
}
}
- Method thisMethod = findMethod(receiverClass, methodName, originalArguments);
+ Class[] argTypes = MetaClassHelper.castArgumentsToClassArray(originalArguments);
+ Method thisMethod = findMethod(receiverClass, methodName, argTypes);
if (null == thisMethod) throw mme;
MethodHandle thisMethodHandle;
try {
@@ -1211,6 +1223,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
} catch (IllegalAccessException e) {
throw mme;
}
+ cacheMethod(receiverClass, thisMethod);
try {
return thisMethodHandle.bindTo(object).invokeWithArguments(originalArguments);
} catch (Throwable t) {
@@ -1219,10 +1232,34 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
}
}
- private static Method findMethod(Class clazz, String messageName, Object[] messageArguments) {
- Class[] parameterTypes = MetaClassHelper.castArgumentsToClassArray(messageArguments);
+ private static void cacheMethod(Class clazz, Method method) {
+ Map<String, Set<Method>> methods = SPECIAL_METHODS_MAP.get(clazz);
+ methods.compute(method.getName(), (k, v) -> {
+ if (null == v) {
+ v = new HashSet<>();
+ }
+ v.add(method);
+ return v;
+ });
+ }
+
+ private static Method findMethod(Class clazz, String messageName, Class[] argTypes) {
+ Set<Method> methods = SPECIAL_METHODS_MAP.get(clazz).get(messageName);
+
+ if (null != methods) {
+ for (Method method : methods) {
+ if (method.getName().equals(messageName) && parameterTypeMatches(method.getParameterTypes(), argTypes)) {
+ return method;
+ }
+ }
+ }
+
+ return doFindMethod(clazz, messageName, argTypes);
+ }
+
+ private static Method doFindMethod(Class clazz, String messageName, Class[] argTypes) {
for (Class<?> c = clazz; null != c; c = c.getSuperclass()) {
- List<Method> declaredMethodList = ReflectionUtils.getDeclaredMethods(c, messageName, parameterTypes);
+ List<Method> declaredMethodList = ReflectionUtils.getDeclaredMethods(c, messageName, argTypes);
if (!declaredMethodList.isEmpty()) {
Method superMethod = declaredMethodList.get(0);
if (Modifier.isAbstract(superMethod.getModifiers())) {
diff --git a/src/main/java/org/codehaus/groovy/reflection/ReflectionUtils.java b/src/main/java/org/codehaus/groovy/reflection/ReflectionUtils.java
index e83b3d9..b87917c 100644
--- a/src/main/java/org/codehaus/groovy/reflection/ReflectionUtils.java
+++ b/src/main/java/org/codehaus/groovy/reflection/ReflectionUtils.java
@@ -145,35 +145,43 @@ public class ReflectionUtils {
private static List<Method> doGetMethods(final Class<?> type, final String name, final Class<?>[] parameterTypes, final Function<? super Class<?>, ? extends Method[]> f) {
List<Method> methodList = new LinkedList<>();
- out:
for (Method m : f.apply(type)) {
if (!m.getName().equals(name)) {
continue;
}
-
Class<?>[] methodParameterTypes = m.getParameterTypes();
- if (methodParameterTypes.length != parameterTypes.length) {
+ if (!parameterTypeMatches(methodParameterTypes, parameterTypes)) {
continue;
}
- for (int i = 0, n = methodParameterTypes.length; i < n; i += 1) {
- Class<?> parameterType = TypeUtil.autoboxType(parameterTypes[i]);
- if (null == parameterType) {
- continue out;
- }
-
- Class<?> methodParameterType = TypeUtil.autoboxType(methodParameterTypes[i]);
- if (!methodParameterType.isAssignableFrom(parameterType)) {
- continue out;
- }
- }
-
methodList.add(m);
}
return methodList;
}
+ public static boolean parameterTypeMatches(final Class<?>[] parameterTypes, final Class<?>[] argTypes) {
+ if (parameterTypes.length != argTypes.length) {
+ return false;
+ }
+
+ for (int i = 0, n = parameterTypes.length; i < n; i += 1) {
+ Class<?> argType = argTypes[i];
+ Class<?> parameterType = parameterTypes[i];
+
+ if (null == argType) return false;
+ if (parameterType == argType) continue;
+
+ Class<?> boxedArgType = TypeUtil.autoboxType(argType);
+ Class<?> boxedParameterType = TypeUtil.autoboxType(parameterType);
+ if (!boxedParameterType.isAssignableFrom(boxedArgType)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
public static boolean checkCanSetAccessible(final AccessibleObject accessibleObject, final Class<?> caller) {
return VM_PLUGIN.checkCanSetAccessible(accessibleObject, caller);
}