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