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) { |
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 } |