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 2026/08/22 16:28:31 UTC
(groovy) 01/01: GROOVY-12288: Cache ClassWriter getCommonSuperClass lookups per class pair
This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits pushed a commit to branch GROOVY-12288
in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 2e0da3d79d22b7a5ad1d25dbaaec47fa26c03402
Author: Daniel Sun <su...@apache.org>
AuthorDate: Sat Aug 15 17:32:22 2026 +0900
GROOVY-12288: Cache ClassWriter getCommonSuperClass lookups per class pair
---
.../codehaus/groovy/control/CompilationUnit.java | 65 +++++++++++++++-------
1 file changed, 44 insertions(+), 21 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
index 5aad7ece5b..d9d2a3a09a 100644
--- a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
+++ b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
@@ -62,6 +62,7 @@ import java.security.CodeSource;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Deque;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
@@ -905,8 +906,34 @@ public class CompilationUnit extends ProcessingUnit {
* @return the class visitor used to emit bytecode
*/
protected ClassVisitor createClassVisitor() {
- return new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
- private ClassNode getClassNode(String name) {
+ return new CachingClassWriter();
+ }
+
+ /**
+ * Per-class {@link ClassWriter} that memoizes {@link #getCommonSuperClass}.
+ * {@code COMPUTE_FRAMES} repeats the same internal-name pairs at merge points;
+ * the writer (and its maps) live for one generated class and are then discarded.
+ */
+ private final class CachingClassWriter extends ClassWriter {
+ private final Map<String, ClassNode> classNodeByInternalName = new HashMap<>();
+ private final Map<Set<String>, String> commonSuperByPair = new HashMap<>();
+
+ private CachingClassWriter() {
+ super(COMPUTE_MAXS | COMPUTE_FRAMES);
+ }
+
+ @Override
+ protected String getCommonSuperClass(final String type1, final String type2) {
+ return commonSuperByPair.computeIfAbsent(Set.of(type1, type2), k -> {
+ ClassNode class1 = getClassNode(type1);
+ ClassNode class2 = getClassNode(type2);
+ return getCommonSuperClassNode(class1, class2).getName().replace('.', '/');
+ });
+ }
+
+ private ClassNode getClassNode(final String internalName) {
+ return classNodeByInternalName.computeIfAbsent(internalName, k -> {
+ String name = k.replace('/', '.');
// try classes under compilation
CompileUnit cu = getAST();
ClassNode cn = cu.getClass(name);
@@ -916,25 +943,21 @@ public class CompilationUnit extends ProcessingUnit {
if (cn != null) return cn;
ClassNodeResolver.LookupResult lookupResult = getClassNodeResolver().resolveName(name, CompilationUnit.this);
return lookupResult == null ? null : lookupResult.getClassNode();
- }
- private ClassNode getCommonSuperClassNode(ClassNode c, ClassNode d) {
- // adapted from ClassWriter code
- if (c.isDerivedFrom(d)) return d;
- if (d.isDerivedFrom(c)) return c;
- if (c.isInterface() || d.isInterface()) return ClassHelper.OBJECT_TYPE;
- do {
- c = c.getSuperClass();
- } while (c != null && !d.isDerivedFrom(c));
- if (c == null) return ClassHelper.OBJECT_TYPE;
- return c;
- }
- @Override
- protected String getCommonSuperClass(String arg1, String arg2) {
- ClassNode a = getClassNode(arg1.replace('/', '.'));
- ClassNode b = getClassNode(arg2.replace('/', '.'));
- return getCommonSuperClassNode(a,b).getName().replace('.','/');
- }
- };
+ });
+ }
+
+ private ClassNode getCommonSuperClassNode(ClassNode c, ClassNode d) {
+ if (c == null || d == null) throw new GroovyBugError("Unable to determine common super class of " + c + " and " + d);
+
+ // adapted from ClassWriter code
+ if (c.isDerivedFrom(d)) return d;
+ if (d.isDerivedFrom(c)) return c;
+ if (c.isInterface() || d.isInterface()) return ClassHelper.OBJECT_TYPE;
+ do {
+ c = c.getSuperClass();
+ } while (c != null && !d.isDerivedFrom(c));
+ return c == null ? ClassHelper.OBJECT_TYPE : c;
+ }
}
//---------------------------------------------------------------------------