This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch GROOVY-11568
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 63bfb667122dc1c8df5029034a0238adbd439f75
Author: Eric Milles <[email protected]>
AuthorDate: Sun Feb 16 20:25:26 2025 -0600

    GROOVY-11568: try `invokeMethod(Class,Object,Object[],boolean,boolean)`
---
 .../groovy/runtime/metaclass/ClosureMetaClass.java |  2 +-
 .../v8/IndyGuardsFiltersAndSignatures.java         | 66 ++++++++++-----------
 .../org/codehaus/groovy/vmplugin/v8/Selector.java  | 25 +++++++-
 src/test/groovy/bugs/Groovy11568.groovy            | 67 ++++++++++++++++++++++
 4 files changed, 123 insertions(+), 37 deletions(-)

diff --git 
a/src/main/java/org/codehaus/groovy/runtime/metaclass/ClosureMetaClass.java 
b/src/main/java/org/codehaus/groovy/runtime/metaclass/ClosureMetaClass.java
index 2d7332d332..479c6b20e9 100644
--- a/src/main/java/org/codehaus/groovy/runtime/metaclass/ClosureMetaClass.java
+++ b/src/main/java/org/codehaus/groovy/runtime/metaclass/ClosureMetaClass.java
@@ -365,7 +365,7 @@ public final class ClosureMetaClass extends MetaClassImpl {
         }
         Class thisType = sender;
         while (GeneratedClosure.class.isAssignableFrom(thisType)) thisType = 
thisType.getEnclosingClass();
-        if (thisType != sender && thisType != object.getClass() && 
thisType.isInstance(object)) { // GROOVY-2433, GROOVY-11128
+        if (thisType != object.getClass() && thisType.isInstance(object)) { // 
GROOVY-2433, GROOVY-11128
             try {
                 return ((GroovyObject) 
object).getMetaClass().invokeMethod(thisType, object, methodName, arguments, 
false, true);
             } catch (GroovyRuntimeException gre) {
diff --git 
a/src/main/java/org/codehaus/groovy/vmplugin/v8/IndyGuardsFiltersAndSignatures.java
 
b/src/main/java/org/codehaus/groovy/vmplugin/v8/IndyGuardsFiltersAndSignatures.java
index db2d6307bc..a992f38c21 100644
--- 
a/src/main/java/org/codehaus/groovy/vmplugin/v8/IndyGuardsFiltersAndSignatures.java
+++ 
b/src/main/java/org/codehaus/groovy/vmplugin/v8/IndyGuardsFiltersAndSignatures.java
@@ -56,15 +56,14 @@ public class IndyGuardsFiltersAndSignatures {
 
     private static final MethodType
             OBJECT_FILTER = MethodType.methodType(Object.class, Object.class),
-            OBJECT_GUARD = MethodType.methodType(boolean.class, Object.class),
-            INVOKER = MethodType.methodType(Object.class, Object.class, 
String.class, Object[].class);
+            OBJECT_GUARD = MethodType.methodType(boolean.class, Object.class);
 
     protected static final MethodHandle
             SAME_CLASS, SAME_CLASSES, SAME_MC, IS_NULL, NON_NULL,
             UNWRAP_METHOD, UNWRAP_EXCEPTION,
             HAS_CATEGORY_IN_CURRENT_THREAD_GUARD,
-            META_METHOD_INVOKER, GROOVY_OBJECT_INVOKER, 
GROOVY_OBJECT_GET_PROPERTY,
-            META_CLASS_INVOKE_STATIC_METHOD,
+            GROOVY_OBJECT_INVOKER, 
GROOVY_OBJECT_GET_PROPERTY,META_METHOD_INVOKER,
+            META_CLASS_INVOKE_METHOD, META_CLASS_INVOKE_STATIC_METHOD,
             BEAN_CONSTRUCTOR_PROPERTY_SETTER,
             META_PROPERTY_GETTER,
             SLOW_META_CLASS_FIND,
@@ -78,35 +77,36 @@ public class IndyGuardsFiltersAndSignatures {
 
     static {
         try {
-            SAME_CLASS = 
LOOKUP.findStatic(IndyGuardsFiltersAndSignatures.class, "sameClass", 
MethodType.methodType(boolean.class, Class.class, Object.class));
-            SAME_CLASSES = 
LOOKUP.findStatic(IndyGuardsFiltersAndSignatures.class, "sameClasses", 
MethodType.methodType(boolean.class, Class[].class, Object[].class));
-            SAME_MC = LOOKUP.findStatic(IndyGuardsFiltersAndSignatures.class, 
"isSameMetaClass", MethodType.methodType(boolean.class, MetaClass.class, 
Object.class));
-            IS_NULL = LOOKUP.findStatic(IndyGuardsFiltersAndSignatures.class, 
"isNull", OBJECT_GUARD);
-            NON_NULL = LOOKUP.findStatic(Objects.class, "nonNull", 
MethodType.methodType(boolean.class, Object.class));
-            UNWRAP_METHOD = 
LOOKUP.findStatic(IndyGuardsFiltersAndSignatures.class, "unwrap", 
OBJECT_FILTER);
-            UNWRAP_EXCEPTION = 
LOOKUP.findStatic(IndyGuardsFiltersAndSignatures.class, "unwrap", 
MethodType.methodType(Object.class, GroovyRuntimeException.class));
-            HAS_CATEGORY_IN_CURRENT_THREAD_GUARD = 
LOOKUP.findStatic(GroovyCategorySupport.class, "hasCategoryInCurrentThread", 
MethodType.methodType(boolean.class));
-            META_METHOD_INVOKER = LOOKUP.findVirtual(MetaMethod.class, 
"doMethodInvoke", MethodType.methodType(Object.class, Object.class, 
Object[].class));
-            GROOVY_OBJECT_INVOKER = 
LOOKUP.findStatic(IndyGuardsFiltersAndSignatures.class, 
"invokeGroovyObjectInvoker", INVOKER.insertParameterTypes(0, 
MissingMethodException.class));
-            GROOVY_OBJECT_GET_PROPERTY = 
LOOKUP.findVirtual(GroovyObject.class, "getProperty", 
MethodType.methodType(Object.class, String.class));
-            META_CLASS_INVOKE_STATIC_METHOD = 
LOOKUP.findVirtual(MetaObjectProtocol.class, "invokeStaticMethod", INVOKER);
-            BEAN_CONSTRUCTOR_PROPERTY_SETTER = 
LOOKUP.findStatic(IndyGuardsFiltersAndSignatures.class, "setBeanProperties", 
MethodType.methodType(Object.class, MetaClass.class, Object.class, Map.class));
-            META_PROPERTY_GETTER = LOOKUP.findVirtual(MetaProperty.class, 
"getProperty", OBJECT_FILTER);
-            SLOW_META_CLASS_FIND = LOOKUP.findStatic(InvokerHelper.class, 
"getMetaClass", MethodType.methodType(MetaClass.class, Object.class));
-            MOP_GET = LOOKUP.findVirtual(MetaObjectProtocol.class, 
"getProperty", MethodType.methodType(Object.class, Object.class, String.class));
-            MOP_INVOKE_CONSTRUCTOR = 
LOOKUP.findVirtual(MetaObjectProtocol.class, "invokeConstructor", 
MethodType.methodType(Object.class, Object[].class));
-            MOP_INVOKE_METHOD = LOOKUP.findVirtual(MetaObjectProtocol.class, 
"invokeMethod", INVOKER);
-            INTERCEPTABLE_INVOKER = LOOKUP.findVirtual(GroovyObject.class, 
"invokeMethod", MethodType.methodType(Object.class, String.class, 
Object.class));
-
-            BOOLEAN_IDENTITY = MethodHandles.identity(Boolean.class);
-            CLASS_FOR_NAME = LOOKUP.findStatic(Class.class, "forName", 
MethodType.methodType(Class.class, String.class, boolean.class, 
ClassLoader.class));
-            DTT_CAST_TO_TYPE = 
LOOKUP.findStatic(DefaultTypeTransformation.class, "castToType", 
MethodType.methodType(Object.class, Object.class, Class.class));
-            SAM_CONVERSION = LOOKUP.findStatic(CachedSAMClass.class, 
"coerceToSAM", MethodType.methodType(Object.class, Closure.class, Method.class, 
Class.class));
-            HASHSET_CONSTRUCTOR = LOOKUP.findConstructor(HashSet.class, 
MethodType.methodType(void.class, Collection.class));
-            ARRAYLIST_CONSTRUCTOR = LOOKUP.findConstructor(ArrayList.class, 
MethodType.methodType(void.class, Collection.class));
-            GROOVY_CAST_EXCEPTION = 
LOOKUP.findConstructor(GroovyCastException.class, 
MethodType.methodType(void.class, Object.class, Class.class));
-
-            EQUALS = LOOKUP.findVirtual(Object.class, "equals", OBJECT_GUARD);
+            SAME_CLASS                           = LOOKUP.findStatic 
(IndyGuardsFiltersAndSignatures.class, "sameClass", 
MethodType.methodType(boolean.class, Class.class, Object.class));
+            SAME_CLASSES                         = LOOKUP.findStatic 
(IndyGuardsFiltersAndSignatures.class, "sameClasses", 
MethodType.methodType(boolean.class, Class[].class, Object[].class));
+            SAME_MC                              = LOOKUP.findStatic 
(IndyGuardsFiltersAndSignatures.class, "isSameMetaClass", 
MethodType.methodType(boolean.class, MetaClass.class, Object.class));
+            IS_NULL                              = LOOKUP.findStatic 
(IndyGuardsFiltersAndSignatures.class, "isNull", OBJECT_GUARD);
+            NON_NULL                             = LOOKUP.findStatic 
(Objects.class, "nonNull", MethodType.methodType(boolean.class, Object.class));
+            UNWRAP_METHOD                        = LOOKUP.findStatic 
(IndyGuardsFiltersAndSignatures.class, "unwrap", OBJECT_FILTER);
+            UNWRAP_EXCEPTION                     = LOOKUP.findStatic 
(IndyGuardsFiltersAndSignatures.class, "unwrap", 
MethodType.methodType(Object.class, GroovyRuntimeException.class));
+            HAS_CATEGORY_IN_CURRENT_THREAD_GUARD = LOOKUP.findStatic 
(GroovyCategorySupport.class, "hasCategoryInCurrentThread", 
MethodType.methodType(boolean.class));
+            GROOVY_OBJECT_INVOKER                = LOOKUP.findStatic 
(IndyGuardsFiltersAndSignatures.class, "invokeGroovyObjectInvoker", 
MethodType.methodType(Object.class, MissingMethodException.class, Object.class, 
String.class, Object[].class));
+            GROOVY_OBJECT_GET_PROPERTY           = 
LOOKUP.findVirtual(GroovyObject.class, "getProperty", 
MethodType.methodType(Object.class, String.class));
+            META_METHOD_INVOKER                  = 
LOOKUP.findVirtual(MetaMethod.class, "doMethodInvoke", 
MethodType.methodType(Object.class, Object.class, Object[].class));
+            META_CLASS_INVOKE_METHOD             = 
LOOKUP.findVirtual(MetaClass.class, "invokeMethod", 
MethodType.methodType(Object.class, Class.class, Object.class, String.class, 
Object[].class, boolean.class, boolean.class));
+            META_CLASS_INVOKE_STATIC_METHOD      = 
LOOKUP.findVirtual(MetaObjectProtocol.class, "invokeStaticMethod", 
MethodType.methodType(Object.class, Object.class, String.class, 
Object[].class));
+            BEAN_CONSTRUCTOR_PROPERTY_SETTER     = LOOKUP.findStatic 
(IndyGuardsFiltersAndSignatures.class, "setBeanProperties", 
MethodType.methodType(Object.class, MetaClass.class, Object.class, Map.class));
+            META_PROPERTY_GETTER                 = 
LOOKUP.findVirtual(MetaProperty.class, "getProperty", OBJECT_FILTER);
+            SLOW_META_CLASS_FIND                 = LOOKUP.findStatic 
(InvokerHelper.class, "getMetaClass", MethodType.methodType(MetaClass.class, 
Object.class));
+            MOP_GET                              = 
LOOKUP.findVirtual(MetaObjectProtocol.class, "getProperty", 
MethodType.methodType(Object.class, Object.class, String.class));
+            MOP_INVOKE_CONSTRUCTOR               = 
LOOKUP.findVirtual(MetaObjectProtocol.class, "invokeConstructor", 
MethodType.methodType(Object.class, Object[].class));
+            MOP_INVOKE_METHOD                    = 
LOOKUP.findVirtual(MetaObjectProtocol.class, "invokeMethod", 
MethodType.methodType(Object.class, Object.class, String.class, 
Object[].class));
+            INTERCEPTABLE_INVOKER                = 
LOOKUP.findVirtual(GroovyObject.class, "invokeMethod", 
MethodType.methodType(Object.class, String.class, Object.class));
+
+            BOOLEAN_IDENTITY                     = 
MethodHandles.identity(Boolean.class);
+            CLASS_FOR_NAME                       = 
LOOKUP.findStatic(Class.class, "forName", MethodType.methodType(Class.class, 
String.class, boolean.class, ClassLoader.class));
+            DTT_CAST_TO_TYPE                     = 
LOOKUP.findStatic(DefaultTypeTransformation.class, "castToType", 
MethodType.methodType(Object.class, Object.class, Class.class));
+            SAM_CONVERSION                       = 
LOOKUP.findStatic(CachedSAMClass.class, "coerceToSAM", 
MethodType.methodType(Object.class, Closure.class, Method.class, Class.class));
+            HASHSET_CONSTRUCTOR                  = 
LOOKUP.findConstructor(HashSet.class, MethodType.methodType(void.class, 
Collection.class));
+            ARRAYLIST_CONSTRUCTOR                = 
LOOKUP.findConstructor(ArrayList.class, MethodType.methodType(void.class, 
Collection.class));
+            GROOVY_CAST_EXCEPTION                = 
LOOKUP.findConstructor(GroovyCastException.class, 
MethodType.methodType(void.class, Object.class, Class.class));
+
+            EQUALS                               = 
LOOKUP.findVirtual(Object.class, "equals", OBJECT_GUARD);
         } catch (Exception e) {
             throw new GroovyBugError(e);
         }
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 b9da452a7e..59bd28fb56 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java
@@ -79,6 +79,7 @@ import static 
org.codehaus.groovy.vmplugin.v8.IndyGuardsFiltersAndSignatures.HAS
 import static 
org.codehaus.groovy.vmplugin.v8.IndyGuardsFiltersAndSignatures.HAS_CATEGORY_IN_CURRENT_THREAD_GUARD;
 import static 
org.codehaus.groovy.vmplugin.v8.IndyGuardsFiltersAndSignatures.INTERCEPTABLE_INVOKER;
 import static 
org.codehaus.groovy.vmplugin.v8.IndyGuardsFiltersAndSignatures.IS_NULL;
+import static 
org.codehaus.groovy.vmplugin.v8.IndyGuardsFiltersAndSignatures.META_CLASS_INVOKE_METHOD;
 import static 
org.codehaus.groovy.vmplugin.v8.IndyGuardsFiltersAndSignatures.META_CLASS_INVOKE_STATIC_METHOD;
 import static 
org.codehaus.groovy.vmplugin.v8.IndyGuardsFiltersAndSignatures.META_METHOD_INVOKER;
 import static 
org.codehaus.groovy.vmplugin.v8.IndyGuardsFiltersAndSignatures.META_PROPERTY_GETTER;
@@ -727,6 +728,14 @@ public abstract class Selector {
             return targetType;
         }
 
+        private Method metaClassMethod(String name, Class... signature) {
+            try {
+                return mc.getClass().getMethod(name, signature);
+            } catch (ReflectiveOperationException e) {
+                throw new GroovyBugError(e);
+            }
+        }
+
         /**
          * Creates a MethodHandle, which will use the metaclass path.
          * This method is called only if no handle has been created before. 
This
@@ -741,9 +750,19 @@ public abstract class Selector {
                 handle = META_CLASS_INVOKE_STATIC_METHOD.bindTo(mc);
                 if (LOG_ENABLED) LOG.info("use invokeStaticMethod with bound 
meta class");
             } else {
-                handle = MOP_INVOKE_METHOD.bindTo(mc);
-                if (LOG_ENABLED) LOG.info("use invokeMethod with bound meta 
class");
-
+                if (standardMetaClass
+//                    || metaClassMethod("invokeMethod", Object.class, 
String.class, Object[].class).getDeclaringClass()
+//                    == metaClassMethod("invokeMethod", Class.class, 
Object.class, String.class, Object[].class, boolean.class, 
boolean.class).getDeclaringClass()
+                ) {
+                    // GROOVY-11568: use 
MetaClass#invokeMethod(Class,Object,Object[],boolean,boolean)
+                    handle = META_CLASS_INVOKE_METHOD;
+                    handle = handle.bindTo(mc).bindTo(sender);
+                    handle = MethodHandles.insertArguments(handle, 3, 
Boolean.FALSE, Boolean.FALSE);
+                    if (LOG_ENABLED) LOG.info("use invokeMethod with bound 
meta class and sender class");
+                } else {
+                    handle = MOP_INVOKE_METHOD.bindTo(mc);
+                    if (LOG_ENABLED) LOG.info("use invokeMethod with bound 
meta class");
+                }
                 if (receiver instanceof GroovyObject) {
                     // if the metaclass call fails we may still want to fall 
back to call
                     // GroovyObject#invokeMethod if the receiver is a 
GroovyObject
diff --git a/src/test/groovy/bugs/Groovy11568.groovy 
b/src/test/groovy/bugs/Groovy11568.groovy
new file mode 100644
index 0000000000..a9b9405c5e
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy11568.groovy
@@ -0,0 +1,67 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package groovy.bugs
+
+import org.junit.jupiter.api.Test
+
+import static groovy.test.GroovyAssert.assertScript
+
+final class Groovy11568 {
+    @Test
+    void testPrivateMethodWithCustomMetaClass() {
+        assertScript '''
+            class CMC extends MetaClassImpl {
+                CMC(Class theClass) {
+                    super(theClass)
+                }
+                @Override
+                Object invokeMethod(Object object, String methodName, Object 
arguments) {
+                    super.invokeMethod(object, methodName, arguments)
+                }
+                @Override
+                Object invokeMethod(Object object, String methodName, Object[] 
originalArguments) {
+                    super.invokeMethod(object, methodName, originalArguments)
+                }
+                @Override
+                Object invokeMethod(Class sender, Object object, String 
methodName, Object[] arguments, boolean isCallToSuper, boolean fromInsideClass) 
{
+                    super.invokeMethod(sender, object, methodName, arguments, 
isCallToSuper, fromInsideClass)
+                }
+            }
+
+            class C {
+                def publicMethod() {
+                    privateMethod()
+                }
+                private privateMethod() {
+                    'C#privateMethod()'
+                }
+            }
+
+            class D extends C {
+            }
+
+            def cmc = new CMC(D.class)
+            cmc.initialize()
+            def obj = new D()
+            obj.setMetaClass(cmc)
+            def str = obj.publicMethod()
+            assert str == 'C#privateMethod()'
+        '''
+    }
+}

Reply via email to