src/share/classes/com/sun/tools/javac/code/Scope.java

changeset 729
6ce6ee1b831a
parent 725
601160d857ef
child 738
9427a3c795fc
equal deleted inserted replaced
728:895bea45a3e8 729:6ce6ee1b831a
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

mercurial