# HG changeset patch # User mcimadamore # Date 1248946193 -3600 # Node ID 3c265cb6f4e0cac1c94f7c71d1d5d8a123dc6b45 # Parent f2f87f1bc5ad4e430d75ddb78a042d76a5a9b01b 6827648: Extremely slow compilation time for visitor pattern code + generics Summary: Javac unnecessarily recomputates type-substitutions multiple times Reviewed-by: jjg diff -r f2f87f1bc5ad -r 3c265cb6f4e0 langtools/src/share/classes/com/sun/tools/javac/code/Symbol.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. diff -r f2f87f1bc5ad -r 3c265cb6f4e0 langtools/src/share/classes/com/sun/tools/javac/code/Types.java --- 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 memberType = new SimpleVisitor() { @@ -1552,7 +1551,7 @@ return t; /* fast special case */ else return erasure.visit(t, recurse); - } + } // where private SimpleVisitor erasure = new SimpleVisitor() { public Type visitType(Type t, Boolean recurse) { @@ -1946,6 +1945,45 @@ hasSameArgs(t, erasure(s)) || hasSameArgs(erasure(t), s); } + private WeakHashMap>> implCache_check = + new WeakHashMap>>(); + + private WeakHashMap>> implCache_nocheck = + new WeakHashMap>>(); + + public MethodSymbol implementation(MethodSymbol ms, TypeSymbol origin, Types types, boolean checkResult) { + Map>> implCache = checkResult ? + implCache_check : implCache_nocheck; + SoftReference> ref_cache = implCache.get(ms); + Map cache = ref_cache != null ? ref_cache.get() : null; + if (cache == null) { + cache = new HashMap(); + implCache.put(ms, new SoftReference>(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