6980862: too aggressive compiler optimization causes stale results of Types.implementation()
authormcimadamore
Sat, 18 Sep 2010 09:54:51 -0700
changeset 6709 ade773eb432d
parent 6601 90c4a1a64217
child 6710 b14e6fe7b290
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
langtools/src/share/classes/com/sun/tools/javac/code/Scope.java
langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java
langtools/src/share/classes/com/sun/tools/javac/code/Types.java
langtools/src/share/classes/com/sun/tools/javac/comp/Enter.java
langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java
langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java
langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Scope.java	Thu Sep 16 09:57:37 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Scope.java	Sat Sep 18 09:54:51 2010 -0700
@@ -70,6 +70,45 @@
      */
     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 @@
 
     /** 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 @@
         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 @@
      *  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 @@
      *  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 @@
      *  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 @@
         table[hash] = e;
         elems = e;
         nelems++;
+        scopeCounter.inc();
     }
 
     Entry makeEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) {
@@ -226,6 +271,8 @@
         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 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 @@
         }
     }
 
+    /** 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);
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java	Thu Sep 16 09:57:37 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java	Sat Sep 18 09:54:51 2010 -0700
@@ -74,6 +74,7 @@
     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 @@
         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 @@
 
         // 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 @@
         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 @@
         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,
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java	Thu Sep 16 09:57:37 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java	Sat Sep 18 09:54:51 2010 -0700
@@ -69,6 +69,7 @@
         new Context.Key<Types>();
 
     final Symtab syms;
+    final Scope.ScopeCounter scopeCounter;
     final JavacMessages messages;
     final Names names;
     final boolean allowBoxing;
@@ -89,6 +90,7 @@
     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 @@
             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 @@
             }
             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 @@
     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>
 
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Enter.java	Thu Sep 16 09:57:37 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Enter.java	Sat Sep 18 09:54:51 2010 -0700
@@ -94,6 +94,7 @@
 
     Log log;
     Symtab syms;
+    Scope.ScopeCounter scopeCounter;
     Check chk;
     TreeMaker make;
     ClassReader reader;
@@ -121,6 +122,7 @@
         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 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 @@
             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 @@
         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) {
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java	Thu Sep 16 09:57:37 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java	Sat Sep 18 09:54:51 2010 -0700
@@ -68,6 +68,7 @@
     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 @@
         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 @@
         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;
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Thu Sep 16 09:57:37 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Sat Sep 18 09:54:51 2010 -0700
@@ -67,6 +67,7 @@
     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 @@
         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 @@
 
 
     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()) {
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Thu Sep 16 09:57:37 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Sat Sep 18 09:54:51 2010 -0700
@@ -122,6 +122,9 @@
     /** The symbol table. */
     Symtab syms;
 
+    /** The scope counter */
+    Scope.ScopeCounter scopeCounter;
+
     Types types;
 
     /** The name table. */
@@ -244,6 +247,7 @@
 
         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 @@
         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);