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 2022/05/14 12:54:25 UTC

[groovy] branch GROOVY_4_0_X updated: Tweak guards for receiver and parameters further

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

sunlan pushed a commit to branch GROOVY_4_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/GROOVY_4_0_X by this push:
     new d471d3d507 Tweak guards for receiver and parameters further
d471d3d507 is described below

commit d471d3d507a8c7c9ea95c8e93a1fe2dd878e85db
Author: Daniel Sun <su...@apache.org>
AuthorDate: Sat May 14 20:34:44 2022 +0800

    Tweak guards for receiver and parameters further
---
 .../org/codehaus/groovy/vmplugin/v8/Selector.java  |  37 +++++++-
 src/test/groovy/bugs/Groovy10535.groovy            | 101 +++++++++++----------
 2 files changed, 88 insertions(+), 50 deletions(-)

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 99a67ea3b5..12b45d4f3b 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java
@@ -63,6 +63,7 @@ import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
 
@@ -85,6 +86,7 @@ import static org.codehaus.groovy.vmplugin.v8.IndyGuardsFiltersAndSignatures.MOP
 import static org.codehaus.groovy.vmplugin.v8.IndyGuardsFiltersAndSignatures.MOP_INVOKE_CONSTRUCTOR;
 import static org.codehaus.groovy.vmplugin.v8.IndyGuardsFiltersAndSignatures.MOP_INVOKE_METHOD;
 import static org.codehaus.groovy.vmplugin.v8.IndyGuardsFiltersAndSignatures.NULL_REF;
+import static org.codehaus.groovy.vmplugin.v8.IndyGuardsFiltersAndSignatures.SAME_CLASS;
 import static org.codehaus.groovy.vmplugin.v8.IndyGuardsFiltersAndSignatures.SAME_CLASSES;
 import static org.codehaus.groovy.vmplugin.v8.IndyGuardsFiltersAndSignatures.SAME_MC;
 import static org.codehaus.groovy.vmplugin.v8.IndyGuardsFiltersAndSignatures.SAM_CONVERSION;
@@ -923,10 +925,37 @@ public abstract class Selector {
 
             // guards for receiver and parameter
             Class<?>[] pt = handle.type().parameterArray();
-            MethodHandle test = SAME_CLASSES.bindTo(args)
-                    .asCollector(Object[].class, pt.length)
-                    .asType(MethodType.methodType(boolean.class, pt));
-            handle = MethodHandles.guardWithTest(test, handle, fallback);
+            if (Arrays.stream(args).anyMatch(arg -> null == arg)) {
+                for (int i = 0; i < args.length; i++) {
+                    Object arg = args[i];
+                    Class<?> paramType = pt[i];
+                    MethodHandle test;
+
+                    if (arg == null) {
+                        test = IS_NULL.asType(MethodType.methodType(boolean.class, paramType));
+                        if (LOG_ENABLED) LOG.info("added null argument check at pos " + i);
+                    } else {
+                        if (Modifier.isFinal(paramType.getModifiers())) {
+                            // primitive types are also `final`
+                            continue;
+                        }
+                        test = SAME_CLASS.
+                                bindTo(arg.getClass()).
+                                asType(MethodType.methodType(boolean.class, paramType));
+                        if (LOG_ENABLED) LOG.info("added same class check at pos " + i);
+                    }
+                    Class<?>[] drops = new Class[i];
+                    System.arraycopy(pt, 0, drops, 0, drops.length);
+                    test = MethodHandles.dropArguments(test, 0, drops);
+                    handle = MethodHandles.guardWithTest(test, handle, fallback);
+                }
+            } else {
+                // Avoid guards as possible as we could
+                MethodHandle test = SAME_CLASSES.bindTo(args)
+                        .asCollector(Object[].class, pt.length)
+                        .asType(MethodType.methodType(boolean.class, pt));
+                handle = MethodHandles.guardWithTest(test, handle, fallback);
+            }
         }
 
         /**
diff --git a/src/test/groovy/bugs/Groovy10535.groovy b/src/test/groovy/bugs/Groovy10535.groovy
index 0e85c00f8b..3e989014f3 100644
--- a/src/test/groovy/bugs/Groovy10535.groovy
+++ b/src/test/groovy/bugs/Groovy10535.groovy
@@ -26,62 +26,71 @@ final class Groovy10535 {
 
     @Test
     void testBooleanTypecast_invokeDynamicOptimization1() {
-        assertScript '''
-            @groovy.transform.CompileStatic
-            class C {
-                static main(args) {
-                    Collection<String> strings = null
-                    for (int i = 0; i <= 200_000; i += 1) { // vs groovy.indy.optimize.threshold
-                        assert test(strings) === null
+        for (String stcAnn : ['@groovy.transform.CompileStatic', '']) {
+            assertScript(
+                    stcAnn + '''
+                    class C {
+                        static main(args) {
+                            Collection<String> strings = null
+                            for (int i = 0; i <= 200_000; i += 1) { // vs groovy.indy.optimize.threshold
+                                assert test(strings) === null
+                            }
+                            strings = ['x']
+                            assert test(strings) !== null
+                        }
+                        static test(Collection<String> values) {
+                            if (values) return 'thing'
+                        }
                     }
-                    strings = ['x']
-                    assert test(strings) !== null
-                }
-                static test(Collection<String> values) {
-                    if (values) return 'thing'
-                }
-            }
-        '''
+                '''
+            )
+        }
     }
 
     @Test
     void testBooleanTypecast_invokeDynamicOptimization2() {
-        assertScript '''
-            @groovy.transform.CompileStatic
-            class C {
-                static main(args) {
-                    Collection<String> strings = ['x']
-                    for (int i = 0; i <= 200_000; i += 1) {
-                        assert test(strings) !== null
+        for (String stcAnn : ['@groovy.transform.CompileStatic', '']) {
+            assertScript (
+                    stcAnn + '''
+                    class C {
+                        static main(args) {
+                            Collection<String> strings = ['x']
+                            for (int i = 0; i <= 200_000; i += 1) {
+                                assert test(strings) !== null
+                            }
+                            strings = null
+                            assert test(strings) === null
+                        }
+                        static test(Collection<String> values) {
+                            if (values) return 'thing'
+                        }
                     }
-                    strings = null
-                    assert test(strings) === null
-                }
-                static test(Collection<String> values) {
-                    if (values) return 'thing'
-                }
-            }
-        '''
+                '''
+            )
+        }
     }
 
     @Test
     void testBooleanTypecast_invokeDynamicOptimization3() {
-        assertScript '''
-            @groovy.transform.CompileStatic
-            class C {
-                static main(args) {
-                    Collection<String> strings
-                    for (int i = 0; i <= 200_000; i += 1) {
-                        strings = [i as String]
-                        assert test(strings) !== null
+        for (String stcAnn : ['@groovy.transform.CompileStatic', '']) {
+            assertScript (
+                    stcAnn + '''
+                    class C {
+                        static main(args) {
+                            Collection<String> strings
+                            for (int i = 0; i <= 200_000; i += 1) {
+                                strings = [i as String]
+                                assert test(strings) !== null
+                            }
+                            strings = null
+                            assert test(strings) === null
+                        }
+                        static test(Collection<String> values) {
+                            if (values) return 'thing'
+                        }
                     }
-                    strings = null
-                    assert test(strings) === null
-                }
-                static test(Collection<String> values) {
-                    if (values) return 'thing'
-                }
-            }
-        '''
+                '''
+            )
+        }
     }
 }