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

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


The following commit(s) were added to refs/heads/master by this push:
     new 1fc8d99837 Avoid finding same variable declaration repeatedly
1fc8d99837 is described below

commit 1fc8d998377039ea2c2e4b1c76e25c092f0cd9d4
Author: Daniel Sun <[email protected]>
AuthorDate: Sun Mar 30 19:11:58 2025 +0900

    Avoid finding same variable declaration repeatedly
---
 .../groovy/classgen/VariableScopeVisitor.java      | 146 +++++++++++++--------
 1 file changed, 91 insertions(+), 55 deletions(-)

diff --git 
a/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java 
b/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
index b54b693966..3ce83726a2 100644
--- a/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
+++ b/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
@@ -64,8 +64,11 @@ import org.codehaus.groovy.control.SourceUnit;
 import org.codehaus.groovy.syntax.Types;
 
 import java.util.Deque;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedList;
+import java.util.Map;
+import java.util.Objects;
 import java.util.function.BiConsumer;
 import java.util.function.Supplier;
 
@@ -235,71 +238,77 @@ public class VariableScopeVisitor extends 
ClassCodeVisitorSupport {
         return null;
     }
 
+    private final Map<VariableCacheKey, Variable> variableCache = new 
HashMap<>(64);
     private Variable findVariableDeclaration(final String name) {
-        if ("super".equals(name) || "this".equals(name)) return null;
-
-        Variable variable = null;
-        VariableScope scope = currentScope;
-        boolean crossingStaticContext = false;
-        // try to find a declaration of a variable
-        while (true) {
-            crossingStaticContext = (crossingStaticContext || 
scope.isInStaticContext());
-
-            Variable var = scope.getDeclaredVariable(name);
-            if (var != null) {
-                variable = var;
-                break;
-            }
-
-            var = scope.getReferencedLocalVariable(name);
-            if (var != null) {
-                variable = var;
-                break;
-            }
+        if ("this".equals(name) || "super".equals(name)) return null;
+        return variableCache.computeIfAbsent(new VariableCacheKey(name, 
currentScope, inSpecialConstructorCall), k -> {
+            final String variableName = k.name;
+            final VariableScope currentScope = k.scope;
+            final boolean inSpecialConstructorCall = 
k.inSpecialConstructorCall;
+
+            Variable variable = null;
+            VariableScope scope = currentScope;
+            boolean crossingStaticContext = false;
+            // try to find a declaration of a variable
+            while (true) {
+                crossingStaticContext = (crossingStaticContext || 
scope.isInStaticContext());
+
+                Variable var = scope.getDeclaredVariable(variableName);
+                if (var != null) {
+                    variable = var;
+                    break;
+                }
 
-            var = scope.getReferencedClassVariable(name);
-            if (var != null) {
-                variable = var;
-                break;
-            }
+                var = scope.getReferencedLocalVariable(variableName);
+                if (var != null) {
+                    variable = var;
+                    break;
+                }
 
-            ClassNode node = scope.getClassScope();
-            if (node != null) {
-                Variable member = findClassMember(node, name);
-                boolean requireStatic = (crossingStaticContext || 
inSpecialConstructorCall);
-                while (member == null && node.getOuterClass() != null && 
!isAnonymous(node)) {
-                    requireStatic = requireStatic || 
isStatic(node.getModifiers());
-                    member = findClassMember((node = node.getOuterClass()), 
name);
+                var = scope.getReferencedClassVariable(variableName);
+                if (var != null) {
+                    variable = var;
+                    break;
                 }
-                if (member != null) {
-                    // prevent a static context (e.g. a static method) from 
accessing a non-static member (e.g. a non-static field)
-                    if (requireStatic ? member.isInStaticContext() : 
!node.isScript()) {
-                        variable = member;
+
+                ClassNode node = scope.getClassScope();
+                if (node != null) {
+                    Variable member = findClassMember(node, variableName);
+                    boolean requireStatic = (crossingStaticContext || 
inSpecialConstructorCall);
+                    while (member == null && node.getOuterClass() != null && 
!isAnonymous(node)) {
+                        requireStatic = requireStatic || 
isStatic(node.getModifiers());
+                        member = findClassMember((node = 
node.getOuterClass()), variableName);
+                    }
+                    if (member != null) {
+                        // prevent a static context (e.g. a static method) 
from accessing a non-static member (e.g. a non-static field)
+                        if (requireStatic ? member.isInStaticContext() : 
!node.isScript()) {
+                            variable = member;
+                        }
                     }
-                }
 
-                if (!isAnonymous(scope.getClassScope())) break; // GROOVY-5961
+                    if (!isAnonymous(scope.getClassScope())) break; // 
GROOVY-5961
+                }
+                scope = scope.getParent();
+            }
+            if (variable == null) {
+                variable = new DynamicVariable(variableName, 
crossingStaticContext);
             }
-            scope = scope.getParent();
-        }
-        if (variable == null) {
-            variable = new DynamicVariable(name, crossingStaticContext);
-        }
 
-        boolean isClassVariable = (scope.isClassScope() && 
!scope.isReferencedLocalVariable(name))
-            || (scope.isReferencedClassVariable(name) && 
scope.getDeclaredVariable(name) == null);
-        VariableScope end = scope;
-        scope = currentScope;
-        while (scope != end) {
-            if (isClassVariable) {
-                scope.putReferencedClassVariable(variable);
-            } else {
-                scope.putReferencedLocalVariable(variable);
+            boolean isClassVariable = (scope.isClassScope() && 
!scope.isReferencedLocalVariable(variableName))
+                || (scope.isReferencedClassVariable(variableName) && 
scope.getDeclaredVariable(variableName) == null);
+            VariableScope end = scope;
+            scope = currentScope;
+            while (scope != end) {
+                if (isClassVariable) {
+                    scope.putReferencedClassVariable(variable);
+                } else {
+                    scope.putReferencedLocalVariable(variable);
+                }
+                scope = scope.getParent();
             }
-            scope = scope.getParent();
-        }
 
-        return variable;
+            return variable;
+        });
     }
 
     private void visitTypeVariables(final GenericsType[] types) {
@@ -758,4 +767,31 @@ public class VariableScopeVisitor extends 
ClassCodeVisitorSupport {
             checkVariableContextAccess(variable, expression);
         }
     }
+
+    private static class VariableCacheKey {
+        private static final int DEFAULT_HASH = 0;
+        private final String name;
+        private final VariableScope scope;
+        private final boolean inSpecialConstructorCall;
+        private int hash = DEFAULT_HASH;
+
+        VariableCacheKey(final String name, final VariableScope scope, boolean 
inSpecialConstructorCall) {
+            this.name = name;
+            this.scope = scope;
+            this.inSpecialConstructorCall = inSpecialConstructorCall;
+        }
+
+        @Override
+        public boolean equals(final Object obj) {
+            if (this == obj) return true;
+            if (!(obj instanceof VariableCacheKey)) return false;
+            VariableCacheKey that = (VariableCacheKey) obj;
+            return name.equals(that.name) && scope.equals(that.scope) && 
inSpecialConstructorCall == that.inSpecialConstructorCall;
+        }
+
+        @Override
+        public int hashCode() {
+            return DEFAULT_HASH != hash ? hash : (hash = Objects.hash(name, 
scope, inSpecialConstructorCall));
+        }
+    }
 }

Reply via email to