langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Scope.java
changeset 32454 b0ac04e0fefe
parent 32059 ea04f56aeacd
child 40235 fe6c00618434
equal deleted inserted replaced
32453:8eebd1f0b8ea 32454:b0ac04e0fefe
    24  */
    24  */
    25 
    25 
    26 package com.sun.tools.javac.code;
    26 package com.sun.tools.javac.code;
    27 
    27 
    28 import com.sun.tools.javac.code.Kinds.Kind;
    28 import com.sun.tools.javac.code.Kinds.Kind;
       
    29 import java.lang.ref.WeakReference;
    29 import java.util.*;
    30 import java.util.*;
    30 import java.util.function.BiConsumer;
    31 import java.util.function.BiConsumer;
    31 import java.util.stream.Stream;
    32 import java.util.stream.Stream;
    32 import java.util.stream.StreamSupport;
    33 import java.util.stream.StreamSupport;
    33 
    34 
   160 
   161 
   161     private static final Filter<Symbol> noFilter = null;
   162     private static final Filter<Symbol> noFilter = null;
   162 
   163 
   163     /** A list of scopes to be notified if items are to be removed from this scope.
   164     /** A list of scopes to be notified if items are to be removed from this scope.
   164      */
   165      */
   165     List<ScopeListener> listeners = List.nil();
   166     ScopeListenerList listeners = new ScopeListenerList();
   166 
       
   167     public void addScopeListener(ScopeListener sl) {
       
   168         listeners = listeners.prepend(sl);
       
   169     }
       
   170 
   167 
   171     public interface ScopeListener {
   168     public interface ScopeListener {
   172         public void symbolAdded(Symbol sym, Scope s);
   169         void symbolAdded(Symbol sym, Scope s);
   173         public void symbolRemoved(Symbol sym, Scope s);
   170         void symbolRemoved(Symbol sym, Scope s);
       
   171     }
       
   172 
       
   173     /**
       
   174      * A list of scope listeners; listeners are stored in weak references, to avoid memory leaks.
       
   175      * When the listener list is scanned (upon notification), elements corresponding to GC-ed
       
   176      * listeners are removed so that the listener list size is kept in check.
       
   177      */
       
   178     public static class ScopeListenerList {
       
   179 
       
   180         List<WeakReference<ScopeListener>> listeners = List.nil();
       
   181 
       
   182         void add(ScopeListener sl) {
       
   183             listeners = listeners.prepend(new WeakReference<>(sl));
       
   184         }
       
   185 
       
   186         void symbolAdded(Symbol sym, Scope scope) {
       
   187             walkReferences(sym, scope, false);
       
   188         }
       
   189 
       
   190         void symbolRemoved(Symbol sym, Scope scope) {
       
   191             walkReferences(sym, scope, true);
       
   192         }
       
   193 
       
   194         private void walkReferences(Symbol sym, Scope scope, boolean isRemove) {
       
   195             ListBuffer<WeakReference<ScopeListener>> newListeners = new ListBuffer<>();
       
   196             for (WeakReference<ScopeListener> wsl : listeners) {
       
   197                 ScopeListener sl = wsl.get();
       
   198                 if (sl != null) {
       
   199                     if (isRemove) {
       
   200                         sl.symbolRemoved(sym, scope);
       
   201                     } else {
       
   202                         sl.symbolAdded(sym, scope);
       
   203                     }
       
   204                     newListeners.add(wsl);
       
   205                 }
       
   206             }
       
   207             listeners = newListeners.toList();
       
   208         }
   174     }
   209     }
   175 
   210 
   176     public enum LookupKind {
   211     public enum LookupKind {
   177         RECURSIVE,
   212         RECURSIVE,
   178         NON_RECURSIVE;
   213         NON_RECURSIVE;
   402             Entry e = new Entry(sym, old, elems, this);
   437             Entry e = new Entry(sym, old, elems, this);
   403             table[hash] = e;
   438             table[hash] = e;
   404             elems = e;
   439             elems = e;
   405 
   440 
   406             //notify listeners
   441             //notify listeners
   407             for (List<ScopeListener> l = listeners; l.nonEmpty(); l = l.tail) {
   442             listeners.symbolAdded(sym, this);
   408                 l.head.symbolAdded(sym, this);
       
   409             }
       
   410         }
   443         }
   411 
   444 
   412         /** Remove symbol from this scope.
   445         /** Remove symbol from this scope.
   413          */
   446          */
   414         public void remove(Symbol sym) {
   447         public void remove(Symbol sym) {
   440                 }
   473                 }
   441                 te = te.sibling;
   474                 te = te.sibling;
   442             }
   475             }
   443 
   476 
   444             //notify listeners
   477             //notify listeners
   445             for (List<ScopeListener> l = listeners; l.nonEmpty(); l = l.tail) {
   478             listeners.symbolRemoved(sym, this);
   446                 l.head.symbolRemoved(sym, this);
       
   447             }
       
   448         }
   479         }
   449 
   480 
   450         /** Enter symbol sym in this scope if not already there.
   481         /** Enter symbol sym in this scope if not already there.
   451          */
   482          */
   452         public void enterIfAbsent(Symbol sym) {
   483         public void enterIfAbsent(Symbol sym) {
   696 
   727 
   697                     for (Symbol sym : impScope.getSymbols()) {
   728                     for (Symbol sym : impScope.getSymbols()) {
   698                         finalized.enter(sym);
   729                         finalized.enter(sym);
   699                     }
   730                     }
   700 
   731 
   701                     finalized.addScopeListener(new ScopeListener() {
   732                     finalized.listeners.add(new ScopeListener() {
   702                         @Override
   733                         @Override
   703                         public void symbolAdded(Symbol sym, Scope s) {
   734                         public void symbolAdded(Symbol sym, Scope s) {
   704                             Assert.error("The scope is sealed.");
   735                             Assert.error("The scope is sealed.");
   705                         }
   736                         }
       
   737 
   706                         @Override
   738                         @Override
   707                         public void symbolRemoved(Symbol sym, Scope s) {
   739                         public void symbolRemoved(Symbol sym, Scope s) {
   708                             Assert.error("The scope is sealed.");
   740                             Assert.error("The scope is sealed.");
   709                         }
   741                         }
   710                     });
   742                     });
   927         }
   959         }
   928 
   960 
   929         public void prependSubScope(Scope that) {
   961         public void prependSubScope(Scope that) {
   930            if (that != null) {
   962            if (that != null) {
   931                 subScopes = subScopes.prepend(that);
   963                 subScopes = subScopes.prepend(that);
   932                 that.addScopeListener(this);
   964                 that.listeners.add(this);
   933                 mark++;
   965                 mark++;
   934                 for (ScopeListener sl : listeners) {
   966                 listeners.symbolAdded(null, this);
   935                     sl.symbolAdded(null, this); //propagate upwards in case of nested CompoundScopes
       
   936                 }
       
   937            }
   967            }
   938         }
   968         }
   939 
   969 
   940         public void symbolAdded(Symbol sym, Scope s) {
   970         public void symbolAdded(Symbol sym, Scope s) {
   941             mark++;
   971             mark++;
   942             for (ScopeListener sl : listeners) {
   972             listeners.symbolAdded(sym, s);
   943                 sl.symbolAdded(sym, s);
       
   944             }
       
   945         }
   973         }
   946 
   974 
   947         public void symbolRemoved(Symbol sym, Scope s) {
   975         public void symbolRemoved(Symbol sym, Scope s) {
   948             mark++;
   976             mark++;
   949             for (ScopeListener sl : listeners) {
   977             listeners.symbolRemoved(sym, s);
   950                 sl.symbolRemoved(sym, s);
       
   951             }
       
   952         }
   978         }
   953 
   979 
   954         public int getMark() {
   980         public int getMark() {
   955             return mark;
   981             return mark;
   956         }
   982         }