1 /* |
1 /* |
2 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
5 * This code is free software; you can redistribute it and/or modify it |
6 * under the terms of the GNU General Public License version 2 only, as |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. Oracle designates this |
7 * published by the Free Software Foundation. Oracle designates this |
29 import java.util.Iterator; |
29 import java.util.Iterator; |
30 |
30 |
31 /** A scope represents an area of visibility in a Java program. The |
31 /** A scope represents an area of visibility in a Java program. The |
32 * Scope class is a container for symbols which provides |
32 * Scope class is a container for symbols which provides |
33 * efficient access to symbols given their names. Scopes are implemented |
33 * efficient access to symbols given their names. Scopes are implemented |
34 * as hash tables with "open addressing" and "double hashing". |
34 * as hash tables. Scopes can be nested; the next field of a scope points |
35 * Scopes can be nested; the next field of a scope points |
|
36 * to its next outer scope. Nested scopes can share their hash tables. |
35 * to its next outer scope. Nested scopes can share their hash tables. |
37 * |
36 * |
38 * <p><b>This is NOT part of any supported API. |
37 * <p><b>This is NOT part of any supported API. |
39 * If you write code that depends on this, you do so at your own risk. |
38 * If you write code that depends on this, you do so at your own risk. |
40 * This code and its internal interfaces are subject to change or |
39 * This code and its internal interfaces are subject to change or |
66 * reverse order of appearance (i.e later entries are pushed on top). |
65 * reverse order of appearance (i.e later entries are pushed on top). |
67 */ |
66 */ |
68 public Entry elems; |
67 public Entry elems; |
69 |
68 |
70 /** The number of elements in this scope. |
69 /** The number of elements in this scope. |
71 * This includes deleted elements, whose value is the sentinel. |
|
72 */ |
70 */ |
73 public int nelems = 0; |
71 public int nelems = 0; |
74 |
72 |
75 /** A timestamp - useful to quickly check whether a scope has changed or not |
73 /** A timestamp - useful to quickly check whether a scope has changed or not |
76 */ |
74 */ |
109 public long val() { |
107 public long val() { |
110 return val; |
108 return val; |
111 } |
109 } |
112 } |
110 } |
113 |
111 |
114 /** Use as a "not-found" result for lookup. |
112 /** Every hash bucket is a list of Entry's which ends in sentinel. |
115 * Also used to mark deleted entries in the table. |
|
116 */ |
113 */ |
117 private static final Entry sentinel = new Entry(null, null, null, null); |
114 private static final Entry sentinel = new Entry(null, null, null, null); |
118 |
115 |
119 /** The hash table's initial size. |
116 /** The hash table's initial size. |
120 */ |
117 */ |
131 this.next = next; |
128 this.next = next; |
132 assert emptyScope == null || owner != null; |
129 assert emptyScope == null || owner != null; |
133 this.owner = owner; |
130 this.owner = owner; |
134 this.table = table; |
131 this.table = table; |
135 this.hashMask = table.length - 1; |
132 this.hashMask = table.length - 1; |
|
133 this.elems = null; |
|
134 this.nelems = 0; |
|
135 this.shared = 0; |
136 this.scopeCounter = scopeCounter; |
136 this.scopeCounter = scopeCounter; |
137 } |
|
138 |
|
139 /** Convenience constructor used for dup and dupUnshared. */ |
|
140 private Scope(Scope next, Symbol owner, Entry[] table) { |
|
141 this(next, owner, table, next.scopeCounter); |
|
142 this.nelems = next.nelems; |
|
143 } |
137 } |
144 |
138 |
145 /** Construct a new scope, within scope next, with given owner, |
139 /** Construct a new scope, within scope next, with given owner, |
146 * using a fresh table of length INITIAL_SIZE. |
140 * using a fresh table of length INITIAL_SIZE. |
147 */ |
141 */ |
149 this(owner, dummyCounter); |
143 this(owner, dummyCounter); |
150 } |
144 } |
151 |
145 |
152 protected Scope(Symbol owner, ScopeCounter scopeCounter) { |
146 protected Scope(Symbol owner, ScopeCounter scopeCounter) { |
153 this(null, owner, new Entry[INITIAL_SIZE], scopeCounter); |
147 this(null, owner, new Entry[INITIAL_SIZE], scopeCounter); |
|
148 for (int i = 0; i < INITIAL_SIZE; i++) table[i] = sentinel; |
154 } |
149 } |
155 |
150 |
156 /** Construct a fresh scope within this scope, with same owner, |
151 /** Construct a fresh scope within this scope, with same owner, |
157 * which shares its table with the outer scope. Used in connection with |
152 * which shares its table with the outer scope. Used in connection with |
158 * method leave if scope access is stack-like in order to avoid allocation |
153 * method leave if scope access is stack-like in order to avoid allocation |
159 * of fresh tables. |
154 * of fresh tables. |
160 */ |
155 */ |
161 public Scope dup() { |
156 public Scope dup() { |
162 return dup(this.owner); |
157 Scope result = new Scope(this, this.owner, this.table, scopeCounter); |
|
158 shared++; |
|
159 // System.out.println("====> duping scope " + this.hashCode() + " owned by " + this.owner + " to " + result.hashCode()); |
|
160 // new Error().printStackTrace(System.out); |
|
161 return result; |
163 } |
162 } |
164 |
163 |
165 /** Construct a fresh scope within this scope, with new owner, |
164 /** Construct a fresh scope within this scope, with new owner, |
166 * which shares its table with the outer scope. Used in connection with |
165 * which shares its table with the outer scope. Used in connection with |
167 * method leave if scope access is stack-like in order to avoid allocation |
166 * method leave if scope access is stack-like in order to avoid allocation |
168 * of fresh tables. |
167 * of fresh tables. |
169 */ |
168 */ |
170 public Scope dup(Symbol newOwner) { |
169 public Scope dup(Symbol newOwner) { |
171 Scope result = new Scope(this, newOwner, this.table); |
170 Scope result = new Scope(this, newOwner, this.table, scopeCounter); |
172 shared++; |
171 shared++; |
173 // System.out.println("====> duping scope " + this.hashCode() + " owned by " + newOwner + " to " + result.hashCode()); |
172 // System.out.println("====> duping scope " + this.hashCode() + " owned by " + newOwner + " to " + result.hashCode()); |
174 // new Error().printStackTrace(System.out); |
173 // new Error().printStackTrace(System.out); |
175 return result; |
174 return result; |
176 } |
175 } |
178 /** Construct a fresh scope within this scope, with same owner, |
177 /** Construct a fresh scope within this scope, with same owner, |
179 * with a new hash table, whose contents initially are those of |
178 * with a new hash table, whose contents initially are those of |
180 * the table of its outer scope. |
179 * the table of its outer scope. |
181 */ |
180 */ |
182 public Scope dupUnshared() { |
181 public Scope dupUnshared() { |
183 return new Scope(this, this.owner, this.table.clone()); |
182 return new Scope(this, this.owner, this.table.clone(), scopeCounter); |
184 } |
183 } |
185 |
184 |
186 /** Remove all entries of this scope from its table, if shared |
185 /** Remove all entries of this scope from its table, if shared |
187 * with next. |
186 * with next. |
188 */ |
187 */ |
189 public Scope leave() { |
188 public Scope leave() { |
190 assert shared == 0; |
189 assert shared == 0; |
191 if (table != next.table) return next; |
190 if (table != next.table) return next; |
192 while (elems != null) { |
191 while (elems != null) { |
193 int hash = getIndex(elems.sym.name); |
192 int hash = elems.sym.name.hashCode() & hashMask; |
194 Entry e = table[hash]; |
193 Entry e = table[hash]; |
195 assert e == elems : elems.sym; |
194 assert e == elems : elems.sym; |
196 table[hash] = elems.shadowed; |
195 table[hash] = elems.shadowed; |
197 elems = elems.sibling; |
196 elems = elems.sibling; |
198 } |
197 } |
199 assert next.shared > 0; |
198 assert next.shared > 0; |
200 next.shared--; |
199 next.shared--; |
201 next.nelems = nelems; |
|
202 // System.out.println("====> leaving scope " + this.hashCode() + " owned by " + this.owner + " to " + next.hashCode()); |
200 // System.out.println("====> leaving scope " + this.hashCode() + " owned by " + this.owner + " to " + next.hashCode()); |
203 // new Error().printStackTrace(System.out); |
201 // new Error().printStackTrace(System.out); |
204 return next; |
202 return next; |
205 } |
203 } |
206 |
204 |
215 assert s == this || s.shared != 0; |
213 assert s == this || s.shared != 0; |
216 s.table = newtable; |
214 s.table = newtable; |
217 s.hashMask = newtable.length - 1; |
215 s.hashMask = newtable.length - 1; |
218 } |
216 } |
219 } |
217 } |
220 int n = 0; |
218 for (int i = 0; i < newtable.length; i++) newtable[i] = sentinel; |
221 for (int i = oldtable.length; --i >= 0; ) { |
219 for (int i = 0; i < oldtable.length; i++) copy(oldtable[i]); |
222 Entry e = oldtable[i]; |
220 } |
223 if (e != null && e != sentinel) { |
221 |
224 table[getIndex(e.sym.name)] = e; |
222 /** Copy the given entry and all entries shadowed by it to table |
225 n++; |
223 */ |
226 } |
224 private void copy(Entry e) { |
227 } |
225 if (e.sym != null) { |
228 // We don't need to update nelems for shared inherited scopes, |
226 copy(e.shadowed); |
229 // since that gets handled by leave(). |
227 int hash = e.sym.name.hashCode() & hashMask; |
230 nelems = n; |
228 e.shadowed = table[hash]; |
|
229 table[hash] = e; |
|
230 } |
231 } |
231 } |
232 |
232 |
233 /** Enter symbol sym in this scope. |
233 /** Enter symbol sym in this scope. |
234 */ |
234 */ |
235 public void enter(Symbol sym) { |
235 public void enter(Symbol sym) { |
246 * given scope `s' accessed through `origin'. The last two |
246 * given scope `s' accessed through `origin'. The last two |
247 * arguments are only used in import scopes. |
247 * arguments are only used in import scopes. |
248 */ |
248 */ |
249 public void enter(Symbol sym, Scope s, Scope origin) { |
249 public void enter(Symbol sym, Scope s, Scope origin) { |
250 assert shared == 0; |
250 assert shared == 0; |
251 if (nelems * 3 >= hashMask * 2) |
251 // Temporarily disabled (bug 6460352): |
252 dble(); |
252 // if (nelems * 3 >= hashMask * 2) dble(); |
253 int hash = getIndex(sym.name); |
253 int hash = sym.name.hashCode() & hashMask; |
254 Entry old = table[hash]; |
254 Entry e = makeEntry(sym, table[hash], elems, s, origin); |
255 if (old == null) { |
|
256 old = sentinel; |
|
257 nelems++; |
|
258 } |
|
259 Entry e = makeEntry(sym, old, elems, s, origin); |
|
260 table[hash] = e; |
255 table[hash] = e; |
261 elems = e; |
256 elems = e; |
|
257 nelems++; |
262 scopeCounter.inc(); |
258 scopeCounter.inc(); |
263 } |
259 } |
264 |
260 |
265 Entry makeEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) { |
261 Entry makeEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) { |
266 return new Entry(sym, shadowed, sibling, scope); |
262 return new Entry(sym, shadowed, sibling, scope); |
270 * attribute tells us that the class isn't a package member. |
266 * attribute tells us that the class isn't a package member. |
271 */ |
267 */ |
272 public void remove(Symbol sym) { |
268 public void remove(Symbol sym) { |
273 assert shared == 0; |
269 assert shared == 0; |
274 Entry e = lookup(sym.name); |
270 Entry e = lookup(sym.name); |
|
271 while (e.scope == this && e.sym != sym) e = e.next(); |
275 if (e.scope == null) return; |
272 if (e.scope == null) return; |
276 |
273 |
277 scopeCounter.inc(); |
274 scopeCounter.inc(); |
278 |
275 |
279 // remove e from table and shadowed list; |
276 // remove e from table and shadowed list; |
280 int i = getIndex(sym.name); |
277 Entry te = table[sym.name.hashCode() & hashMask]; |
281 Entry te = table[i]; |
|
282 if (te == e) |
278 if (te == e) |
283 table[i] = e.shadowed; |
279 table[sym.name.hashCode() & hashMask] = e.shadowed; |
284 else while (true) { |
280 else while (true) { |
285 if (te.shadowed == e) { |
281 if (te.shadowed == e) { |
286 te.shadowed = e.shadowed; |
282 te.shadowed = e.shadowed; |
287 break; |
283 break; |
288 } |
284 } |
337 */ |
333 */ |
338 public Entry lookup(Name name) { |
334 public Entry lookup(Name name) { |
339 return lookup(name, noFilter); |
335 return lookup(name, noFilter); |
340 } |
336 } |
341 public Entry lookup(Name name, Filter<Symbol> sf) { |
337 public Entry lookup(Name name, Filter<Symbol> sf) { |
342 Entry e = table[getIndex(name)]; |
338 Entry e = table[name.hashCode() & hashMask]; |
343 if (e == null || e == sentinel) |
|
344 return sentinel; |
|
345 while (e.scope != null && (e.sym.name != name || !sf.accepts(e.sym))) |
339 while (e.scope != null && (e.sym.name != name || !sf.accepts(e.sym))) |
346 e = e.shadowed; |
340 e = e.shadowed; |
347 return e; |
341 return e; |
348 } |
|
349 |
|
350 /*void dump (java.io.PrintStream out) { |
|
351 out.println(this); |
|
352 for (int l=0; l < table.length; l++) { |
|
353 Entry le = table[l]; |
|
354 out.print("#"+l+": "); |
|
355 if (le==sentinel) out.println("sentinel"); |
|
356 else if(le == null) out.println("null"); |
|
357 else out.println(""+le+" s:"+le.sym); |
|
358 } |
|
359 }*/ |
|
360 |
|
361 /** Look for slot in the table. |
|
362 * We use open addressing with double hashing. |
|
363 */ |
|
364 int getIndex (Name name) { |
|
365 int h = name.hashCode(); |
|
366 int i = h & hashMask; |
|
367 // The expression below is always odd, so it is guaranteed |
|
368 // be be mutually prime with table.length, a power of 2. |
|
369 int x = hashMask - ((h + (h >> 16)) << 1); |
|
370 int d = -1; // Index of a deleted item. |
|
371 for (;;) { |
|
372 Entry e = table[i]; |
|
373 if (e == null) |
|
374 return d >= 0 ? d : i; |
|
375 if (e == sentinel) { |
|
376 // We have to keep searching even if we see a deleted item. |
|
377 // However, remember the index in case we fail to find the name. |
|
378 if (d < 0) |
|
379 d = i; |
|
380 } else if (e.sym.name == name) |
|
381 return i; |
|
382 i = (i + x) & hashMask; |
|
383 } |
|
384 } |
342 } |
385 |
343 |
386 public Iterable<Symbol> getElements() { |
344 public Iterable<Symbol> getElements() { |
387 return getElements(noFilter); |
345 return getElements(noFilter); |
388 } |
346 } |
510 Entry makeEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) { |
468 Entry makeEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) { |
511 return new ImportEntry(sym, shadowed, sibling, scope, origin); |
469 return new ImportEntry(sym, shadowed, sibling, scope, origin); |
512 } |
470 } |
513 |
471 |
514 public Entry lookup(Name name) { |
472 public Entry lookup(Name name) { |
515 Entry e = table[getIndex(name)]; |
473 Entry e = table[name.hashCode() & hashMask]; |
516 if (e == null) |
|
517 return sentinel; |
|
518 while (e.scope != null && |
474 while (e.scope != null && |
519 (/* Since an inner class will show up in package and |
475 (e.sym.name != name || |
|
476 /* Since an inner class will show up in package and |
520 * import scopes until its inner class attribute has |
477 * import scopes until its inner class attribute has |
521 * been processed, we have to weed it out here. This |
478 * been processed, we have to weed it out here. This |
522 * is done by comparing the owners of the entry's |
479 * is done by comparing the owners of the entry's |
523 * scope and symbol fields. The scope field's owner |
480 * scope and symbol fields. The scope field's owner |
524 * points to where the class originally was imported |
481 * points to where the class originally was imported |