提交 63570fb6 编写于 作者: M mcimadamore

6980862: too aggressive compiler optimization causes stale results of Types.implementation()

Summary: use a scope counter in order to determine when/if the implementation cache entries are stale
Reviewed-by: jjg
上级 36b0934e
...@@ -70,6 +70,45 @@ public class Scope { ...@@ -70,6 +70,45 @@ public class Scope {
*/ */
public int nelems = 0; public int nelems = 0;
/** A timestamp - useful to quickly check whether a scope has changed or not
*/
public ScopeCounter scopeCounter;
static ScopeCounter dummyCounter = new ScopeCounter() {
@Override
public void inc() {
//do nothing
}
};
public static class ScopeCounter {
protected static final Context.Key<ScopeCounter> scopeCounterKey =
new Context.Key<ScopeCounter>();
public static ScopeCounter instance(Context context) {
ScopeCounter instance = context.get(scopeCounterKey);
if (instance == null)
instance = new ScopeCounter(context);
return instance;
}
protected ScopeCounter(Context context) {
context.put(scopeCounterKey, this);
}
private ScopeCounter() {};
private long val = 0;
public void inc() {
val++;
}
public long val() {
return val;
}
}
/** Every hash bucket is a list of Entry's which ends in sentinel. /** Every hash bucket is a list of Entry's which ends in sentinel.
*/ */
private static final Entry sentinel = new Entry(null, null, null, null); private static final Entry sentinel = new Entry(null, null, null, null);
...@@ -80,12 +119,12 @@ public class Scope { ...@@ -80,12 +119,12 @@ public class Scope {
/** A value for the empty scope. /** A value for the empty scope.
*/ */
public static final Scope emptyScope = new Scope(null, null, new Entry[]{}); public static final Scope emptyScope = new Scope(null, null, new Entry[]{}, dummyCounter);
/** Construct a new scope, within scope next, with given owner, using /** Construct a new scope, within scope next, with given owner, using
* given table. The table's length must be an exponent of 2. * given table. The table's length must be an exponent of 2.
*/ */
Scope(Scope next, Symbol owner, Entry[] table) { private Scope(Scope next, Symbol owner, Entry[] table, ScopeCounter scopeCounter) {
this.next = next; this.next = next;
assert emptyScope == null || owner != null; assert emptyScope == null || owner != null;
this.owner = owner; this.owner = owner;
...@@ -94,13 +133,18 @@ public class Scope { ...@@ -94,13 +133,18 @@ public class Scope {
this.elems = null; this.elems = null;
this.nelems = 0; this.nelems = 0;
this.shared = 0; this.shared = 0;
this.scopeCounter = scopeCounter;
} }
/** Construct a new scope, within scope next, with given owner, /** Construct a new scope, within scope next, with given owner,
* using a fresh table of length INITIAL_SIZE. * using a fresh table of length INITIAL_SIZE.
*/ */
public Scope(Symbol owner) { public Scope(Symbol owner) {
this(null, owner, new Entry[INITIAL_SIZE]); this(owner, dummyCounter);
}
protected Scope(Symbol owner, ScopeCounter scopeCounter) {
this(null, owner, new Entry[INITIAL_SIZE], scopeCounter);
for (int i = 0; i < INITIAL_SIZE; i++) table[i] = sentinel; for (int i = 0; i < INITIAL_SIZE; i++) table[i] = sentinel;
} }
...@@ -110,7 +154,7 @@ public class Scope { ...@@ -110,7 +154,7 @@ public class Scope {
* of fresh tables. * of fresh tables.
*/ */
public Scope dup() { public Scope dup() {
Scope result = new Scope(this, this.owner, this.table); Scope result = new Scope(this, this.owner, this.table, scopeCounter);
shared++; shared++;
// System.out.println("====> duping scope " + this.hashCode() + " owned by " + this.owner + " to " + result.hashCode()); // System.out.println("====> duping scope " + this.hashCode() + " owned by " + this.owner + " to " + result.hashCode());
// new Error().printStackTrace(System.out); // new Error().printStackTrace(System.out);
...@@ -123,7 +167,7 @@ public class Scope { ...@@ -123,7 +167,7 @@ public class Scope {
* of fresh tables. * of fresh tables.
*/ */
public Scope dup(Symbol newOwner) { public Scope dup(Symbol newOwner) {
Scope result = new Scope(this, newOwner, this.table); Scope result = new Scope(this, newOwner, this.table, scopeCounter);
shared++; shared++;
// System.out.println("====> duping scope " + this.hashCode() + " owned by " + newOwner + " to " + result.hashCode()); // System.out.println("====> duping scope " + this.hashCode() + " owned by " + newOwner + " to " + result.hashCode());
// new Error().printStackTrace(System.out); // new Error().printStackTrace(System.out);
...@@ -135,7 +179,7 @@ public class Scope { ...@@ -135,7 +179,7 @@ public class Scope {
* the table of its outer scope. * the table of its outer scope.
*/ */
public Scope dupUnshared() { public Scope dupUnshared() {
return new Scope(this, this.owner, this.table.clone()); return new Scope(this, this.owner, this.table.clone(), scopeCounter);
} }
/** Remove all entries of this scope from its table, if shared /** Remove all entries of this scope from its table, if shared
...@@ -211,6 +255,7 @@ public class Scope { ...@@ -211,6 +255,7 @@ public class Scope {
table[hash] = e; table[hash] = e;
elems = e; elems = e;
nelems++; nelems++;
scopeCounter.inc();
} }
Entry makeEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) { Entry makeEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) {
...@@ -226,6 +271,8 @@ public class Scope { ...@@ -226,6 +271,8 @@ public class Scope {
while (e.scope == this && e.sym != sym) e = e.next(); while (e.scope == this && e.sym != sym) e = e.next();
if (e.scope == null) return; if (e.scope == null) return;
scopeCounter.inc();
// remove e from table and shadowed list; // remove e from table and shadowed list;
Entry te = table[sym.name.hashCode() & hashMask]; Entry te = table[sym.name.hashCode() & hashMask];
if (te == e) if (te == e)
...@@ -472,7 +519,7 @@ public class Scope { ...@@ -472,7 +519,7 @@ public class Scope {
public static final Entry[] emptyTable = new Entry[0]; public static final Entry[] emptyTable = new Entry[0];
public DelegatedScope(Scope outer) { public DelegatedScope(Scope outer) {
super(outer, outer.owner, emptyTable); super(outer, outer.owner, emptyTable, outer.scopeCounter);
delegatee = outer; delegatee = outer;
} }
public Scope dup() { public Scope dup() {
...@@ -498,10 +545,22 @@ public class Scope { ...@@ -498,10 +545,22 @@ public class Scope {
} }
} }
/** A class scope, for which a scope counter should be provided */
public static class ClassScope extends Scope {
ClassScope(Scope next, Symbol owner, Entry[] table, ScopeCounter scopeCounter) {
super(next, owner, table, scopeCounter);
}
public ClassScope(Symbol owner, ScopeCounter scopeCounter) {
super(owner, scopeCounter);
}
}
/** An error scope, for which the owner should be an error symbol. */ /** An error scope, for which the owner should be an error symbol. */
public static class ErrorScope extends Scope { public static class ErrorScope extends Scope {
ErrorScope(Scope next, Symbol errSymbol, Entry[] table) { ErrorScope(Scope next, Symbol errSymbol, Entry[] table) {
super(next, /*owner=*/errSymbol, table); super(next, /*owner=*/errSymbol, table, dummyCounter);
} }
public ErrorScope(Symbol errSymbol) { public ErrorScope(Symbol errSymbol) {
super(errSymbol); super(errSymbol);
......
...@@ -74,6 +74,7 @@ public class Symtab { ...@@ -74,6 +74,7 @@ public class Symtab {
public final JCNoType voidType = new JCNoType(TypeTags.VOID); public final JCNoType voidType = new JCNoType(TypeTags.VOID);
private final Names names; private final Names names;
private final Scope.ScopeCounter scopeCounter;
private final ClassReader reader; private final ClassReader reader;
private final Target target; private final Target target;
...@@ -340,6 +341,7 @@ public class Symtab { ...@@ -340,6 +341,7 @@ public class Symtab {
context.put(symtabKey, this); context.put(symtabKey, this);
names = Names.instance(context); names = Names.instance(context);
scopeCounter = Scope.ScopeCounter.instance(context);
target = Target.instance(context); target = Target.instance(context);
// Create the unknown type // Create the unknown type
...@@ -386,7 +388,7 @@ public class Symtab { ...@@ -386,7 +388,7 @@ public class Symtab {
// Create class to hold all predefined constants and operations. // Create class to hold all predefined constants and operations.
predefClass = new ClassSymbol(PUBLIC|ACYCLIC, names.empty, rootPackage); predefClass = new ClassSymbol(PUBLIC|ACYCLIC, names.empty, rootPackage);
Scope scope = new Scope(predefClass); Scope scope = new Scope.ClassScope(predefClass, scopeCounter);
predefClass.members_field = scope; predefClass.members_field = scope;
// Enter symbols for basic types. // Enter symbols for basic types.
...@@ -476,7 +478,7 @@ public class Symtab { ...@@ -476,7 +478,7 @@ public class Symtab {
proprietarySymbol.completer = null; proprietarySymbol.completer = null;
proprietarySymbol.flags_field = PUBLIC|ACYCLIC|ANNOTATION|INTERFACE; proprietarySymbol.flags_field = PUBLIC|ACYCLIC|ANNOTATION|INTERFACE;
proprietarySymbol.erasure_field = proprietaryType; proprietarySymbol.erasure_field = proprietaryType;
proprietarySymbol.members_field = new Scope(proprietarySymbol); proprietarySymbol.members_field = new Scope.ClassScope(proprietarySymbol, scopeCounter);
proprietaryType.typarams_field = List.nil(); proprietaryType.typarams_field = List.nil();
proprietaryType.allparams_field = List.nil(); proprietaryType.allparams_field = List.nil();
proprietaryType.supertype_field = annotationType; proprietaryType.supertype_field = annotationType;
...@@ -488,7 +490,7 @@ public class Symtab { ...@@ -488,7 +490,7 @@ public class Symtab {
ClassType arrayClassType = (ClassType)arrayClass.type; ClassType arrayClassType = (ClassType)arrayClass.type;
arrayClassType.supertype_field = objectType; arrayClassType.supertype_field = objectType;
arrayClassType.interfaces_field = List.of(cloneableType, serializableType); arrayClassType.interfaces_field = List.of(cloneableType, serializableType);
arrayClass.members_field = new Scope(arrayClass); arrayClass.members_field = new Scope.ClassScope(arrayClass, scopeCounter);
lengthVar = new VarSymbol( lengthVar = new VarSymbol(
PUBLIC | FINAL, PUBLIC | FINAL,
names.length, names.length,
......
...@@ -69,6 +69,7 @@ public class Types { ...@@ -69,6 +69,7 @@ public class Types {
new Context.Key<Types>(); new Context.Key<Types>();
final Symtab syms; final Symtab syms;
final Scope.ScopeCounter scopeCounter;
final JavacMessages messages; final JavacMessages messages;
final Names names; final Names names;
final boolean allowBoxing; final boolean allowBoxing;
...@@ -89,6 +90,7 @@ public class Types { ...@@ -89,6 +90,7 @@ public class Types {
protected Types(Context context) { protected Types(Context context) {
context.put(typesKey, this); context.put(typesKey, this);
syms = Symtab.instance(context); syms = Symtab.instance(context);
scopeCounter = Scope.ScopeCounter.instance(context);
names = Names.instance(context); names = Names.instance(context);
allowBoxing = Source.instance(context).allowBoxing(); allowBoxing = Source.instance(context).allowBoxing();
reader = ClassReader.instance(context); reader = ClassReader.instance(context);
...@@ -1984,22 +1986,26 @@ public class Types { ...@@ -1984,22 +1986,26 @@ public class Types {
final MethodSymbol cachedImpl; final MethodSymbol cachedImpl;
final Filter<Symbol> implFilter; final Filter<Symbol> implFilter;
final boolean checkResult; final boolean checkResult;
final Scope.ScopeCounter scopeCounter;
public Entry(MethodSymbol cachedImpl, public Entry(MethodSymbol cachedImpl,
Filter<Symbol> scopeFilter, Filter<Symbol> scopeFilter,
boolean checkResult) { boolean checkResult,
Scope.ScopeCounter scopeCounter) {
this.cachedImpl = cachedImpl; this.cachedImpl = cachedImpl;
this.implFilter = scopeFilter; this.implFilter = scopeFilter;
this.checkResult = checkResult; this.checkResult = checkResult;
this.scopeCounter = scopeCounter;
} }
boolean matches(Filter<Symbol> scopeFilter, boolean checkResult) { boolean matches(Filter<Symbol> scopeFilter, boolean checkResult, Scope.ScopeCounter scopeCounter) {
return this.implFilter == scopeFilter && return this.implFilter == scopeFilter &&
this.checkResult == checkResult; this.checkResult == checkResult &&
this.scopeCounter.val() >= scopeCounter.val();
} }
} }
MethodSymbol get(MethodSymbol ms, TypeSymbol origin, boolean checkResult, Filter<Symbol> implFilter) { MethodSymbol get(MethodSymbol ms, TypeSymbol origin, boolean checkResult, Filter<Symbol> implFilter, Scope.ScopeCounter scopeCounter) {
SoftReference<Map<TypeSymbol, Entry>> ref_cache = _map.get(ms); SoftReference<Map<TypeSymbol, Entry>> ref_cache = _map.get(ms);
Map<TypeSymbol, Entry> cache = ref_cache != null ? ref_cache.get() : null; Map<TypeSymbol, Entry> cache = ref_cache != null ? ref_cache.get() : null;
if (cache == null) { if (cache == null) {
...@@ -2008,9 +2014,9 @@ public class Types { ...@@ -2008,9 +2014,9 @@ public class Types {
} }
Entry e = cache.get(origin); Entry e = cache.get(origin);
if (e == null || if (e == null ||
!e.matches(implFilter, checkResult)) { !e.matches(implFilter, checkResult, scopeCounter)) {
MethodSymbol impl = implementationInternal(ms, origin, Types.this, checkResult, implFilter); MethodSymbol impl = implementationInternal(ms, origin, Types.this, checkResult, implFilter);
cache.put(origin, new Entry(impl, implFilter, checkResult)); cache.put(origin, new Entry(impl, implFilter, checkResult, scopeCounter));
return impl; return impl;
} }
else { else {
...@@ -2038,7 +2044,7 @@ public class Types { ...@@ -2038,7 +2044,7 @@ public class Types {
private ImplementationCache implCache = new ImplementationCache(); private ImplementationCache implCache = new ImplementationCache();
public MethodSymbol implementation(MethodSymbol ms, TypeSymbol origin, Types types, boolean checkResult, Filter<Symbol> implFilter) { public MethodSymbol implementation(MethodSymbol ms, TypeSymbol origin, Types types, boolean checkResult, Filter<Symbol> implFilter) {
return implCache.get(ms, origin, checkResult, implFilter); return implCache.get(ms, origin, checkResult, implFilter, scopeCounter);
} }
// </editor-fold> // </editor-fold>
......
...@@ -94,6 +94,7 @@ public class Enter extends JCTree.Visitor { ...@@ -94,6 +94,7 @@ public class Enter extends JCTree.Visitor {
Log log; Log log;
Symtab syms; Symtab syms;
Scope.ScopeCounter scopeCounter;
Check chk; Check chk;
TreeMaker make; TreeMaker make;
ClassReader reader; ClassReader reader;
...@@ -121,6 +122,7 @@ public class Enter extends JCTree.Visitor { ...@@ -121,6 +122,7 @@ public class Enter extends JCTree.Visitor {
reader = ClassReader.instance(context); reader = ClassReader.instance(context);
make = TreeMaker.instance(context); make = TreeMaker.instance(context);
syms = Symtab.instance(context); syms = Symtab.instance(context);
scopeCounter = Scope.ScopeCounter.instance(context);
chk = Check.instance(context); chk = Check.instance(context);
memberEnter = MemberEnter.instance(context); memberEnter = MemberEnter.instance(context);
types = Types.instance(context); types = Types.instance(context);
...@@ -189,7 +191,7 @@ public class Enter extends JCTree.Visitor { ...@@ -189,7 +191,7 @@ public class Enter extends JCTree.Visitor {
*/ */
public Env<AttrContext> classEnv(JCClassDecl tree, Env<AttrContext> env) { public Env<AttrContext> classEnv(JCClassDecl tree, Env<AttrContext> env) {
Env<AttrContext> localEnv = Env<AttrContext> localEnv =
env.dup(tree, env.info.dup(new Scope(tree.sym))); env.dup(tree, env.info.dup(new Scope.ClassScope(tree.sym, scopeCounter)));
localEnv.enclClass = tree; localEnv.enclClass = tree;
localEnv.outer = env; localEnv.outer = env;
localEnv.info.isSelfCall = false; localEnv.info.isSelfCall = false;
...@@ -325,7 +327,7 @@ public class Enter extends JCTree.Visitor { ...@@ -325,7 +327,7 @@ public class Enter extends JCTree.Visitor {
c.flatname = names.fromString(tree.packge + "." + name); c.flatname = names.fromString(tree.packge + "." + name);
c.sourcefile = tree.sourcefile; c.sourcefile = tree.sourcefile;
c.completer = null; c.completer = null;
c.members_field = new Scope(c); c.members_field = new Scope.ClassScope(c, scopeCounter);
tree.packge.package_info = c; tree.packge.package_info = c;
} }
classEnter(tree.defs, topEnv); classEnter(tree.defs, topEnv);
...@@ -393,7 +395,7 @@ public class Enter extends JCTree.Visitor { ...@@ -393,7 +395,7 @@ public class Enter extends JCTree.Visitor {
c.completer = memberEnter; c.completer = memberEnter;
c.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, c, tree); c.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, c, tree);
c.sourcefile = env.toplevel.sourcefile; c.sourcefile = env.toplevel.sourcefile;
c.members_field = new Scope(c); c.members_field = new Scope.ClassScope(c, scopeCounter);
ClassType ct = (ClassType)c.type; ClassType ct = (ClassType)c.type;
if (owner.kind != PCK && (c.flags_field & STATIC) == 0) { if (owner.kind != PCK && (c.flags_field & STATIC) == 0) {
......
...@@ -68,6 +68,7 @@ public class Lower extends TreeTranslator { ...@@ -68,6 +68,7 @@ public class Lower extends TreeTranslator {
private Names names; private Names names;
private Log log; private Log log;
private Symtab syms; private Symtab syms;
private Scope.ScopeCounter scopeCounter;
private Resolve rs; private Resolve rs;
private Check chk; private Check chk;
private Attr attr; private Attr attr;
...@@ -90,6 +91,7 @@ public class Lower extends TreeTranslator { ...@@ -90,6 +91,7 @@ public class Lower extends TreeTranslator {
names = Names.instance(context); names = Names.instance(context);
log = Log.instance(context); log = Log.instance(context);
syms = Symtab.instance(context); syms = Symtab.instance(context);
scopeCounter = Scope.ScopeCounter.instance(context);
rs = Resolve.instance(context); rs = Resolve.instance(context);
chk = Check.instance(context); chk = Check.instance(context);
attr = Attr.instance(context); attr = Attr.instance(context);
...@@ -569,7 +571,7 @@ public class Lower extends TreeTranslator { ...@@ -569,7 +571,7 @@ public class Lower extends TreeTranslator {
c.flatname = chk.localClassName(c); c.flatname = chk.localClassName(c);
c.sourcefile = owner.sourcefile; c.sourcefile = owner.sourcefile;
c.completer = null; c.completer = null;
c.members_field = new Scope(c); c.members_field = new Scope.ClassScope(c, scopeCounter);
c.flags_field = flags; c.flags_field = flags;
ClassType ctype = (ClassType) c.type; ClassType ctype = (ClassType) c.type;
ctype.supertype_field = syms.objectType; ctype.supertype_field = syms.objectType;
......
...@@ -67,6 +67,7 @@ public class MemberEnter extends JCTree.Visitor implements Completer { ...@@ -67,6 +67,7 @@ public class MemberEnter extends JCTree.Visitor implements Completer {
private final Check chk; private final Check chk;
private final Attr attr; private final Attr attr;
private final Symtab syms; private final Symtab syms;
private final Scope.ScopeCounter scopeCounter;
private final TreeMaker make; private final TreeMaker make;
private final ClassReader reader; private final ClassReader reader;
private final Todo todo; private final Todo todo;
...@@ -92,6 +93,7 @@ public class MemberEnter extends JCTree.Visitor implements Completer { ...@@ -92,6 +93,7 @@ public class MemberEnter extends JCTree.Visitor implements Completer {
chk = Check.instance(context); chk = Check.instance(context);
attr = Attr.instance(context); attr = Attr.instance(context);
syms = Symtab.instance(context); syms = Symtab.instance(context);
scopeCounter = Scope.ScopeCounter.instance(context);
make = TreeMaker.instance(context); make = TreeMaker.instance(context);
reader = ClassReader.instance(context); reader = ClassReader.instance(context);
todo = Todo.instance(context); todo = Todo.instance(context);
...@@ -1087,7 +1089,7 @@ public class MemberEnter extends JCTree.Visitor implements Completer { ...@@ -1087,7 +1089,7 @@ public class MemberEnter extends JCTree.Visitor implements Completer {
private Env<AttrContext> baseEnv(JCClassDecl tree, Env<AttrContext> env) { private Env<AttrContext> baseEnv(JCClassDecl tree, Env<AttrContext> env) {
Scope baseScope = new Scope(tree.sym); Scope baseScope = new Scope.ClassScope(tree.sym, scopeCounter);
//import already entered local classes into base scope //import already entered local classes into base scope
for (Scope.Entry e = env.outer.info.scope.elems ; e != null ; e = e.sibling) { for (Scope.Entry e = env.outer.info.scope.elems ; e != null ; e = e.sibling) {
if (e.sym.isLocal()) { if (e.sym.isLocal()) {
......
...@@ -122,6 +122,9 @@ public class ClassReader implements Completer { ...@@ -122,6 +122,9 @@ public class ClassReader implements Completer {
/** The symbol table. */ /** The symbol table. */
Symtab syms; Symtab syms;
/** The scope counter */
Scope.ScopeCounter scopeCounter;
Types types; Types types;
/** The name table. */ /** The name table. */
...@@ -244,6 +247,7 @@ public class ClassReader implements Completer { ...@@ -244,6 +247,7 @@ public class ClassReader implements Completer {
names = Names.instance(context); names = Names.instance(context);
syms = Symtab.instance(context); syms = Symtab.instance(context);
scopeCounter = Scope.ScopeCounter.instance(context);
types = Types.instance(context); types = Types.instance(context);
fileManager = context.get(JavaFileManager.class); fileManager = context.get(JavaFileManager.class);
if (fileManager == null) if (fileManager == null)
...@@ -1984,7 +1988,7 @@ public class ClassReader implements Completer { ...@@ -1984,7 +1988,7 @@ public class ClassReader implements Completer {
ClassType ct = (ClassType)c.type; ClassType ct = (ClassType)c.type;
// allocate scope for members // allocate scope for members
c.members_field = new Scope(c); c.members_field = new Scope.ClassScope(c, scopeCounter);
// prepare type variable table // prepare type variable table
typevars = typevars.dup(currentOwner); typevars = typevars.dup(currentOwner);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册