6827648: Extremely slow compilation time for visitor pattern code + generics
authormcimadamore
Thu, 30 Jul 2009 10:29:53 +0100
changeset 3539 3c265cb6f4e0
parent 3538 f2f87f1bc5ad
child 3540 dceac8629a56
6827648: Extremely slow compilation time for visitor pattern code + generics Summary: Javac unnecessarily recomputates type-substitutions multiple times Reviewed-by: jjg
langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java
langtools/src/share/classes/com/sun/tools/javac/code/Types.java
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java	Wed Jul 29 13:26:26 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java	Thu Jul 30 10:29:53 2009 +0100
@@ -1197,21 +1197,9 @@
          *  as possible implementations.
          */
         public MethodSymbol implementation(TypeSymbol origin, Types types, boolean checkResult) {
-            for (Type t = origin.type; t.tag == CLASS || t.tag == TYPEVAR; t = types.supertype(t)) {
-                while (t.tag == TYPEVAR)
-                    t = t.getUpperBound();
-                TypeSymbol c = t.tsym;
-                for (Scope.Entry e = c.members().lookup(name);
-                     e.scope != null;
-                     e = e.next()) {
-                    if (e.sym.kind == MTH) {
-                        MethodSymbol m = (MethodSymbol) e.sym;
-                        if (m.overrides(this, origin, types, checkResult) &&
-                            (m.flags() & SYNTHETIC) == 0)
-                            return m;
-                    }
-                }
-            }
+            MethodSymbol res = types.implementation(this, origin, types, checkResult);
+            if (res != null)
+                return res;
             // if origin is derived from a raw type, we might have missed
             // an implementation because we do not know enough about instantiations.
             // in this case continue with the supertype as origin.
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java	Wed Jul 29 13:26:26 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java	Thu Jul 30 10:29:53 2009 +0100
@@ -25,10 +25,9 @@
 
 package com.sun.tools.javac.code;
 
+import java.lang.ref.SoftReference;
 import java.util.*;
 
-import com.sun.tools.javac.api.Messages;
-
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.List;
 
@@ -1442,7 +1441,7 @@
         return (sym.flags() & STATIC) != 0
             ? sym.type
             : memberType.visit(t, sym);
-    }
+        }
     // where
         private SimpleVisitor<Type,Symbol> memberType = new SimpleVisitor<Type,Symbol>() {
 
@@ -1552,7 +1551,7 @@
             return t; /* fast special case */
         else
             return erasure.visit(t, recurse);
-    }
+        }
     // where
         private SimpleVisitor<Type, Boolean> erasure = new SimpleVisitor<Type, Boolean>() {
             public Type visitType(Type t, Boolean recurse) {
@@ -1946,6 +1945,45 @@
             hasSameArgs(t, erasure(s)) || hasSameArgs(erasure(t), s);
     }
 
+    private WeakHashMap<MethodSymbol, SoftReference<Map<TypeSymbol, MethodSymbol>>> implCache_check =
+            new WeakHashMap<MethodSymbol, SoftReference<Map<TypeSymbol, MethodSymbol>>>();
+
+    private WeakHashMap<MethodSymbol, SoftReference<Map<TypeSymbol, MethodSymbol>>> implCache_nocheck =
+            new WeakHashMap<MethodSymbol, SoftReference<Map<TypeSymbol, MethodSymbol>>>();
+
+    public MethodSymbol implementation(MethodSymbol ms, TypeSymbol origin, Types types, boolean checkResult) {
+        Map<MethodSymbol, SoftReference<Map<TypeSymbol, MethodSymbol>>> implCache = checkResult ?
+            implCache_check : implCache_nocheck;
+        SoftReference<Map<TypeSymbol, MethodSymbol>> ref_cache = implCache.get(ms);
+        Map<TypeSymbol, MethodSymbol> cache = ref_cache != null ? ref_cache.get() : null;
+        if (cache == null) {
+            cache = new HashMap<TypeSymbol, MethodSymbol>();
+            implCache.put(ms, new SoftReference<Map<TypeSymbol, MethodSymbol>>(cache));
+        }
+        MethodSymbol impl = cache.get(origin);
+        if (impl == null) {
+            for (Type t = origin.type; t.tag == CLASS || t.tag == TYPEVAR; t = types.supertype(t)) {
+                while (t.tag == TYPEVAR)
+                    t = t.getUpperBound();
+                TypeSymbol c = t.tsym;
+                for (Scope.Entry e = c.members().lookup(ms.name);
+                     e.scope != null;
+                     e = e.next()) {
+                    if (e.sym.kind == Kinds.MTH) {
+                        MethodSymbol m = (MethodSymbol) e.sym;
+                        if (m.overrides(ms, origin, types, checkResult) &&
+                            (m.flags() & SYNTHETIC) == 0) {
+                            impl = m;
+                            cache.put(origin, m);
+                            return impl;
+                        }
+                    }
+                }
+            }
+        }
+        return impl;
+    }
+
     /**
      * Does t have the same arguments as s?  It is assumed that both
      * types are (possibly polymorphic) method types.  Monomorphic