70 /** The number of elements in this scope. |
70 /** The number of elements in this scope. |
71 * This includes deleted elements, whose value is the sentinel. |
71 * This includes deleted elements, whose value is the sentinel. |
72 */ |
72 */ |
73 int nelems = 0; |
73 int nelems = 0; |
74 |
74 |
75 /** A timestamp - useful to quickly check whether a scope has changed or not |
|
76 */ |
|
77 public ScopeCounter scopeCounter; |
|
78 |
|
79 static ScopeCounter dummyCounter = new ScopeCounter() { |
|
80 @Override |
|
81 public void inc() { |
|
82 //do nothing |
|
83 } |
|
84 }; |
|
85 |
|
86 /** A list of scopes to be notified if items are to be removed from this scope. |
75 /** A list of scopes to be notified if items are to be removed from this scope. |
87 */ |
76 */ |
88 List<Scope> listeners = List.nil(); |
77 List<Scope> listeners = List.nil(); |
89 |
|
90 public static class ScopeCounter { |
|
91 protected static final Context.Key<ScopeCounter> scopeCounterKey = |
|
92 new Context.Key<ScopeCounter>(); |
|
93 |
|
94 public static ScopeCounter instance(Context context) { |
|
95 ScopeCounter instance = context.get(scopeCounterKey); |
|
96 if (instance == null) |
|
97 instance = new ScopeCounter(context); |
|
98 return instance; |
|
99 } |
|
100 |
|
101 protected ScopeCounter(Context context) { |
|
102 context.put(scopeCounterKey, this); |
|
103 } |
|
104 |
|
105 private ScopeCounter() {}; |
|
106 |
|
107 private long val = 0; |
|
108 |
|
109 public void inc() { |
|
110 val++; |
|
111 } |
|
112 |
|
113 public long val() { |
|
114 return val; |
|
115 } |
|
116 } |
|
117 |
78 |
118 /** Use as a "not-found" result for lookup. |
79 /** Use as a "not-found" result for lookup. |
119 * Also used to mark deleted entries in the table. |
80 * Also used to mark deleted entries in the table. |
120 */ |
81 */ |
121 private static final Entry sentinel = new Entry(null, null, null, null); |
82 private static final Entry sentinel = new Entry(null, null, null, null); |
124 */ |
85 */ |
125 private static final int INITIAL_SIZE = 0x10; |
86 private static final int INITIAL_SIZE = 0x10; |
126 |
87 |
127 /** A value for the empty scope. |
88 /** A value for the empty scope. |
128 */ |
89 */ |
129 public static final Scope emptyScope = new Scope(null, null, new Entry[]{}, dummyCounter); |
90 public static final Scope emptyScope = new Scope(null, null, new Entry[]{}); |
130 |
91 |
131 /** Construct a new scope, within scope next, with given owner, using |
92 /** Construct a new scope, within scope next, with given owner, using |
132 * given table. The table's length must be an exponent of 2. |
93 * given table. The table's length must be an exponent of 2. |
133 */ |
94 */ |
134 private Scope(Scope next, Symbol owner, Entry[] table, ScopeCounter scopeCounter) { |
95 private Scope(Scope next, Symbol owner, Entry[] table) { |
135 this.next = next; |
96 this.next = next; |
136 Assert.check(emptyScope == null || owner != null); |
97 Assert.check(emptyScope == null || owner != null); |
137 this.owner = owner; |
98 this.owner = owner; |
138 this.table = table; |
99 this.table = table; |
139 this.hashMask = table.length - 1; |
100 this.hashMask = table.length - 1; |
140 this.scopeCounter = scopeCounter; |
|
141 } |
101 } |
142 |
102 |
143 /** Convenience constructor used for dup and dupUnshared. */ |
103 /** Convenience constructor used for dup and dupUnshared. */ |
144 private Scope(Scope next, Symbol owner, Entry[] table) { |
104 private Scope(Scope next, Symbol owner, Entry[] table, int nelems) { |
145 this(next, owner, table, next.scopeCounter); |
105 this(next, owner, table); |
146 this.nelems = next.nelems; |
106 this.nelems = nelems; |
147 } |
107 } |
148 |
108 |
149 /** Construct a new scope, within scope next, with given owner, |
109 /** Construct a new scope, within scope next, with given owner, |
150 * using a fresh table of length INITIAL_SIZE. |
110 * using a fresh table of length INITIAL_SIZE. |
151 */ |
111 */ |
152 public Scope(Symbol owner) { |
112 public Scope(Symbol owner) { |
153 this(owner, dummyCounter); |
113 this(null, owner, new Entry[INITIAL_SIZE]); |
154 } |
|
155 |
|
156 protected Scope(Symbol owner, ScopeCounter scopeCounter) { |
|
157 this(null, owner, new Entry[INITIAL_SIZE], scopeCounter); |
|
158 } |
114 } |
159 |
115 |
160 /** Construct a fresh scope within this scope, with same owner, |
116 /** Construct a fresh scope within this scope, with same owner, |
161 * which shares its table with the outer scope. Used in connection with |
117 * which shares its table with the outer scope. Used in connection with |
162 * method leave if scope access is stack-like in order to avoid allocation |
118 * method leave if scope access is stack-like in order to avoid allocation |
170 * which shares its table with the outer scope. Used in connection with |
126 * which shares its table with the outer scope. Used in connection with |
171 * method leave if scope access is stack-like in order to avoid allocation |
127 * method leave if scope access is stack-like in order to avoid allocation |
172 * of fresh tables. |
128 * of fresh tables. |
173 */ |
129 */ |
174 public Scope dup(Symbol newOwner) { |
130 public Scope dup(Symbol newOwner) { |
175 Scope result = new Scope(this, newOwner, this.table); |
131 Scope result = new Scope(this, newOwner, this.table, this.nelems); |
176 shared++; |
132 shared++; |
177 // System.out.println("====> duping scope " + this.hashCode() + " owned by " + newOwner + " to " + result.hashCode()); |
133 // System.out.println("====> duping scope " + this.hashCode() + " owned by " + newOwner + " to " + result.hashCode()); |
178 // new Error().printStackTrace(System.out); |
134 // new Error().printStackTrace(System.out); |
179 return result; |
135 return result; |
180 } |
136 } |
182 /** Construct a fresh scope within this scope, with same owner, |
138 /** Construct a fresh scope within this scope, with same owner, |
183 * with a new hash table, whose contents initially are those of |
139 * with a new hash table, whose contents initially are those of |
184 * the table of its outer scope. |
140 * the table of its outer scope. |
185 */ |
141 */ |
186 public Scope dupUnshared() { |
142 public Scope dupUnshared() { |
187 return new Scope(this, this.owner, this.table.clone()); |
143 return new Scope(this, this.owner, this.table.clone(), this.nelems); |
188 } |
144 } |
189 |
145 |
190 /** Remove all entries of this scope from its table, if shared |
146 /** Remove all entries of this scope from its table, if shared |
191 * with next. |
147 * with next. |
192 */ |
148 */ |
261 nelems++; |
217 nelems++; |
262 } |
218 } |
263 Entry e = makeEntry(sym, old, elems, s, origin); |
219 Entry e = makeEntry(sym, old, elems, s, origin); |
264 table[hash] = e; |
220 table[hash] = e; |
265 elems = e; |
221 elems = e; |
266 scopeCounter.inc(); |
|
267 } |
222 } |
268 |
223 |
269 Entry makeEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) { |
224 Entry makeEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) { |
270 return new Entry(sym, shadowed, sibling, scope); |
225 return new Entry(sym, shadowed, sibling, scope); |
271 } |
226 } |
580 public void remove(Symbol sym) { |
533 public void remove(Symbol sym) { |
581 throw new AssertionError(sym); |
534 throw new AssertionError(sym); |
582 } |
535 } |
583 public Entry lookup(Name name) { |
536 public Entry lookup(Name name) { |
584 return delegatee.lookup(name); |
537 return delegatee.lookup(name); |
585 } |
|
586 } |
|
587 |
|
588 /** A class scope, for which a scope counter should be provided */ |
|
589 public static class ClassScope extends Scope { |
|
590 |
|
591 ClassScope(Scope next, Symbol owner, Entry[] table, ScopeCounter scopeCounter) { |
|
592 super(next, owner, table, scopeCounter); |
|
593 } |
|
594 |
|
595 public ClassScope(Symbol owner, ScopeCounter scopeCounter) { |
|
596 super(owner, scopeCounter); |
|
597 } |
538 } |
598 } |
539 } |
599 |
540 |
600 /** An error scope, for which the owner should be an error symbol. */ |
541 /** An error scope, for which the owner should be an error symbol. */ |
601 public static class ErrorScope extends Scope { |
542 public static class ErrorScope extends Scope { |
602 ErrorScope(Scope next, Symbol errSymbol, Entry[] table) { |
543 ErrorScope(Scope next, Symbol errSymbol, Entry[] table) { |
603 super(next, /*owner=*/errSymbol, table, dummyCounter); |
544 super(next, /*owner=*/errSymbol, table); |
604 } |
545 } |
605 public ErrorScope(Symbol errSymbol) { |
546 public ErrorScope(Symbol errSymbol) { |
606 super(errSymbol); |
547 super(errSymbol); |
607 } |
548 } |
608 public Scope dup() { |
549 public Scope dup() { |