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);
     }