Thu, 30 Jul 2009 10:29:53 +0100
6827648: Extremely slow compilation time for visitor pattern code + generics
Summary: Javac unnecessarily recomputates type-substitutions multiple times
Reviewed-by: jjg
1.1 --- a/src/share/classes/com/sun/tools/javac/code/Symbol.java Wed Jul 29 13:26:26 2009 -0700 1.2 +++ b/src/share/classes/com/sun/tools/javac/code/Symbol.java Thu Jul 30 10:29:53 2009 +0100 1.3 @@ -1197,21 +1197,9 @@ 1.4 * as possible implementations. 1.5 */ 1.6 public MethodSymbol implementation(TypeSymbol origin, Types types, boolean checkResult) { 1.7 - for (Type t = origin.type; t.tag == CLASS || t.tag == TYPEVAR; t = types.supertype(t)) { 1.8 - while (t.tag == TYPEVAR) 1.9 - t = t.getUpperBound(); 1.10 - TypeSymbol c = t.tsym; 1.11 - for (Scope.Entry e = c.members().lookup(name); 1.12 - e.scope != null; 1.13 - e = e.next()) { 1.14 - if (e.sym.kind == MTH) { 1.15 - MethodSymbol m = (MethodSymbol) e.sym; 1.16 - if (m.overrides(this, origin, types, checkResult) && 1.17 - (m.flags() & SYNTHETIC) == 0) 1.18 - return m; 1.19 - } 1.20 - } 1.21 - } 1.22 + MethodSymbol res = types.implementation(this, origin, types, checkResult); 1.23 + if (res != null) 1.24 + return res; 1.25 // if origin is derived from a raw type, we might have missed 1.26 // an implementation because we do not know enough about instantiations. 1.27 // in this case continue with the supertype as origin.
2.1 --- a/src/share/classes/com/sun/tools/javac/code/Types.java Wed Jul 29 13:26:26 2009 -0700 2.2 +++ b/src/share/classes/com/sun/tools/javac/code/Types.java Thu Jul 30 10:29:53 2009 +0100 2.3 @@ -25,10 +25,9 @@ 2.4 2.5 package com.sun.tools.javac.code; 2.6 2.7 +import java.lang.ref.SoftReference; 2.8 import java.util.*; 2.9 2.10 -import com.sun.tools.javac.api.Messages; 2.11 - 2.12 import com.sun.tools.javac.util.*; 2.13 import com.sun.tools.javac.util.List; 2.14 2.15 @@ -1442,7 +1441,7 @@ 2.16 return (sym.flags() & STATIC) != 0 2.17 ? sym.type 2.18 : memberType.visit(t, sym); 2.19 - } 2.20 + } 2.21 // where 2.22 private SimpleVisitor<Type,Symbol> memberType = new SimpleVisitor<Type,Symbol>() { 2.23 2.24 @@ -1552,7 +1551,7 @@ 2.25 return t; /* fast special case */ 2.26 else 2.27 return erasure.visit(t, recurse); 2.28 - } 2.29 + } 2.30 // where 2.31 private SimpleVisitor<Type, Boolean> erasure = new SimpleVisitor<Type, Boolean>() { 2.32 public Type visitType(Type t, Boolean recurse) { 2.33 @@ -1946,6 +1945,45 @@ 2.34 hasSameArgs(t, erasure(s)) || hasSameArgs(erasure(t), s); 2.35 } 2.36 2.37 + private WeakHashMap<MethodSymbol, SoftReference<Map<TypeSymbol, MethodSymbol>>> implCache_check = 2.38 + new WeakHashMap<MethodSymbol, SoftReference<Map<TypeSymbol, MethodSymbol>>>(); 2.39 + 2.40 + private WeakHashMap<MethodSymbol, SoftReference<Map<TypeSymbol, MethodSymbol>>> implCache_nocheck = 2.41 + new WeakHashMap<MethodSymbol, SoftReference<Map<TypeSymbol, MethodSymbol>>>(); 2.42 + 2.43 + public MethodSymbol implementation(MethodSymbol ms, TypeSymbol origin, Types types, boolean checkResult) { 2.44 + Map<MethodSymbol, SoftReference<Map<TypeSymbol, MethodSymbol>>> implCache = checkResult ? 2.45 + implCache_check : implCache_nocheck; 2.46 + SoftReference<Map<TypeSymbol, MethodSymbol>> ref_cache = implCache.get(ms); 2.47 + Map<TypeSymbol, MethodSymbol> cache = ref_cache != null ? ref_cache.get() : null; 2.48 + if (cache == null) { 2.49 + cache = new HashMap<TypeSymbol, MethodSymbol>(); 2.50 + implCache.put(ms, new SoftReference<Map<TypeSymbol, MethodSymbol>>(cache)); 2.51 + } 2.52 + MethodSymbol impl = cache.get(origin); 2.53 + if (impl == null) { 2.54 + for (Type t = origin.type; t.tag == CLASS || t.tag == TYPEVAR; t = types.supertype(t)) { 2.55 + while (t.tag == TYPEVAR) 2.56 + t = t.getUpperBound(); 2.57 + TypeSymbol c = t.tsym; 2.58 + for (Scope.Entry e = c.members().lookup(ms.name); 2.59 + e.scope != null; 2.60 + e = e.next()) { 2.61 + if (e.sym.kind == Kinds.MTH) { 2.62 + MethodSymbol m = (MethodSymbol) e.sym; 2.63 + if (m.overrides(ms, origin, types, checkResult) && 2.64 + (m.flags() & SYNTHETIC) == 0) { 2.65 + impl = m; 2.66 + cache.put(origin, m); 2.67 + return impl; 2.68 + } 2.69 + } 2.70 + } 2.71 + } 2.72 + } 2.73 + return impl; 2.74 + } 2.75 + 2.76 /** 2.77 * Does t have the same arguments as s? It is assumed that both 2.78 * types are (possibly polymorphic) method types. Monomorphic