| 1 | /* | 
| 2 |  * Copyright 1999-2006 Sun Microsystems, Inc.  All Rights Reserved. | 
| 3 |  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 
| 4 |  * | 
| 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 | 
| 7 |  * published by the Free Software Foundation.  Sun designates this | 
| 8 |  * particular file as subject to the "Classpath" exception as provided | 
| 9 |  * by Sun in the LICENSE file that accompanied this code. | 
| 10 |  * | 
| 11 |  * This code is distributed in the hope that it will be useful, but WITHOUT | 
| 12 |  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
| 13 |  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License | 
| 14 |  * version 2 for more details (a copy is included in the LICENSE file that | 
| 15 |  * accompanied this code). | 
| 16 |  * | 
| 17 |  * You should have received a copy of the GNU General Public License version | 
| 18 |  * 2 along with this work; if not, write to the Free Software Foundation, | 
| 19 |  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | 
| 20 |  * | 
| 21 |  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | 
| 22 |  * CA 95054 USA or visit www.sun.com if you need additional information or | 
| 23 |  * have any questions. | 
| 24 |  */ | 
| 25 |   | 
| 26 | package com.sun.tools.javac.code; | 
| 27 |   | 
| 28 | import com.sun.tools.javac.util.*; | 
| 29 | import java.util.Iterator; | 
| 30 |   | 
| 31 | /** A scope represents an area of visibility in a Java program. The | 
| 32 |  *  Scope class is a container for symbols which provides | 
| 33 |  *  efficient access to symbols given their names. Scopes are implemented | 
| 34 |  *  as hash tables. Scopes can be nested; the next field of a scope points | 
| 35 |  *  to its next outer scope. Nested scopes can share their hash tables. | 
| 36 |  * | 
| 37 |  *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If | 
| 38 |  *  you write code that depends on this, you do so at your own risk. | 
| 39 |  *  This code and its internal interfaces are subject to change or | 
| 40 |  *  deletion without notice.</b> | 
| 41 |  */ | 
| 42 | public class Scope { | 
| 43 |   | 
| 44 |     /** The number of scopes that share this scope's hash table. | 
| 45 |      */ | 
| 46 |     private int shared; | 
| 47 |   | 
| 48 |     /** Next enclosing scope (with whom this scope may share a hashtable) | 
| 49 |      */ | 
| 50 |     public Scope next; | 
| 51 |   | 
| 52 |     /** The scope's owner. | 
| 53 |      */ | 
| 54 |     public Symbol owner; | 
| 55 |   | 
| 56 |     /** A hash table for the scope's entries. | 
| 57 |      */ | 
| 58 |     public Entry[] table; | 
| 59 |   | 
| 60 |     /** Mask for hash codes, always equal to (table.length - 1). | 
| 61 |      */ | 
| 62 |     int hashMask; | 
| 63 |   | 
| 64 |     /** A linear list that also contains all entries in | 
| 65 |      *  reverse order of appearance (i.e later entries are pushed on top). | 
| 66 |      */ | 
| 67 |     public Entry elems; | 
| 68 |   | 
| 69 |     /** The number of elements in this scope. | 
| 70 |      */ | 
| 71 |     public int nelems = 0; | 
| 72 |   | 
| 73 |     /** Every hash bucket is a list of Entry's which ends in sentinel. | 
| 74 |      */ | 
| 75 |     private static final Entry sentinel = new Entry(null, null, null, null); | 
| 76 |   | 
| 77 |     /** The hash table's initial size. | 
| 78 |      */ | 
| 79 |     private static final int INITIAL_SIZE = 0x10; | 
| 80 |   | 
| 81 |     /** A value for the empty scope. | 
| 82 |      */ | 
| 83 |     public static final Scope emptyScope = new Scope(null, null, new Entry[]{}); | 
| 84 |   | 
| 85 |     /** Construct a new scope, within scope next, with given owner, using | 
| 86 |      *  given table. The table's length must be an exponent of 2. | 
| 87 |      */ | 
| 88 |     Scope(Scope next, Symbol owner, Entry[] table) { | 
| 89 |         this.next = next; | 
| 90 |         assert emptyScope == null || owner != null; | 
| 91 |         this.owner = owner; | 
| 92 |         this.table = table; | 
| 93 |         this.hashMask = table.length - 1; | 
| 94 |         this.elems = null; | 
| 95 |         this.nelems = 0; | 
| 96 |         this.shared = 0; | 
| 97 |     } | 
| 98 |   | 
| 99 |     /** Construct a new scope, within scope next, with given owner, | 
| 100 |      *  using a fresh table of length INITIAL_SIZE. | 
| 101 |      */ | 
| 102 |     public Scope(Symbol owner) { | 
| 103 |         this(null, owner, new Entry[INITIAL_SIZE]); | 
| 104 |         for (int i = 0; i < INITIAL_SIZE; i++) table[i] = sentinel; | 
| 105 |     } | 
| 106 |   | 
| 107 |     /** Construct a fresh scope within this scope, with same owner, | 
| 108 |      *  which shares its table with the outer scope. Used in connection with | 
| 109 |      *  method leave if scope access is stack-like in order to avoid allocation | 
| 110 |      *  of fresh tables. | 
| 111 |      */ | 
| 112 |     public Scope dup() { | 
| 113 |         Scope result = new Scope(this, this.owner, this.table); | 
| 114 |         shared++; | 
| 115 |         // System.out.println("====> duping scope " + this.hashCode() + " owned by " + this.owner + " to " + result.hashCode()); | 
| 116 |         // new Error().printStackTrace(System.out); | 
| 117 |         return result; | 
| 118 |     } | 
| 119 |   | 
| 120 |     /** Construct a fresh scope within this scope, with new owner, | 
| 121 |      *  which shares its table with the outer scope. Used in connection with | 
| 122 |      *  method leave if scope access is stack-like in order to avoid allocation | 
| 123 |      *  of fresh tables. | 
| 124 |      */ | 
| 125 |     public Scope dup(Symbol newOwner) { | 
| 126 |         Scope result = new Scope(this, newOwner, this.table); | 
| 127 |         shared++; | 
| 128 |         // System.out.println("====> duping scope " + this.hashCode() + " owned by " + newOwner + " to " + result.hashCode()); | 
| 129 |         // new Error().printStackTrace(System.out); | 
| 130 |         return result; | 
| 131 |     } | 
| 132 |   | 
| 133 |     /** Construct a fresh scope within this scope, with same owner, | 
| 134 |      *  with a new hash table, whose contents initially are those of | 
| 135 |      *  the table of its outer scope. | 
| 136 |      */ | 
| 137 |     public Scope dupUnshared() { | 
| 138 |         return new Scope(this, this.owner, this.table.clone()); | 
| 139 |     } | 
| 140 |   | 
| 141 |     /** Remove all entries of this scope from its table, if shared | 
| 142 |      *  with next. | 
| 143 |      */ | 
| 144 |     public Scope leave() { | 
| 145 |         assert shared == 0; | 
| 146 |         if (table != next.table) return next; | 
| 147 |         while (elems != null) { | 
| 148 |             int hash = elems.sym.name.index & hashMask; | 
| 149 |             Entry e = table[hash]; | 
| 150 |             assert e == elems : elems.sym; | 
| 151 |             table[hash] = elems.shadowed; | 
| 152 |             elems = elems.sibling; | 
| 153 |         } | 
| 154 |         assert next.shared > 0; | 
| 155 |         next.shared--; | 
| 156 |         // System.out.println("====> leaving scope " + this.hashCode() + " owned by " + this.owner + " to " + next.hashCode()); | 
| 157 |         // new Error().printStackTrace(System.out); | 
| 158 |         return next; | 
| 159 |     } | 
| 160 |   | 
| 161 |     /** Double size of hash table. | 
| 162 |      */ | 
| 163 |     private void dble() { | 
| 164 |         assert shared == 0; | 
| 165 |         Entry[] oldtable = table; | 
| 166 |         Entry[] newtable = new Entry[oldtable.length * 2]; | 
| 167 |         for (Scope s = this; s != null; s = s.next) { | 
| 168 |             if (s.table == oldtable) { | 
| 169 |                 assert s == this || s.shared != 0; | 
| 170 |                 s.table = newtable; | 
| 171 |                 s.hashMask = newtable.length - 1; | 
| 172 |             } | 
| 173 |         } | 
| 174 |         for (int i = 0; i < newtable.length; i++) newtable[i] = sentinel; | 
| 175 |         for (int i = 0; i < oldtable.length; i++) copy(oldtable[i]); | 
| 176 |     } | 
| 177 |   | 
| 178 |     /** Copy the given entry and all entries shadowed by it to table | 
| 179 |      */ | 
| 180 |     private void copy(Entry e) { | 
| 181 |         if (e.sym != null) { | 
| 182 |             copy(e.shadowed); | 
| 183 |             int hash = e.sym.name.index & hashMask; | 
| 184 |             e.shadowed = table[hash]; | 
| 185 |             table[hash] = e; | 
| 186 |         } | 
| 187 |     } | 
| 188 |   | 
| 189 |     /** Enter symbol sym in this scope. | 
| 190 |      */ | 
| 191 |     public void enter(Symbol sym) { | 
| 192 |         assert shared == 0; | 
| 193 |         enter(sym, this); | 
| 194 |     } | 
| 195 |   | 
| 196 |     public void enter(Symbol sym, Scope s) { | 
| 197 |         enter(sym, s, s); | 
| 198 |     } | 
| 199 |   | 
| 200 |     /** | 
| 201 |      * Enter symbol sym in this scope, but mark that it comes from | 
| 202 |      * given scope `s' accessed through `origin'.  The last two | 
| 203 |      * arguments are only used in import scopes. | 
| 204 |      */ | 
| 205 |     public void enter(Symbol sym, Scope s, Scope origin) { | 
| 206 |         assert shared == 0; | 
| 207 |         // Temporarily disabled (bug 6460352): | 
| 208 |         // if (nelems * 3 >= hashMask * 2) dble(); | 
| 209 |         int hash = sym.name.index & hashMask; | 
| 210 |         Entry e = makeEntry(sym, table[hash], elems, s, origin); | 
| 211 |         table[hash] = e; | 
| 212 |         elems = e; | 
| 213 |         nelems++; | 
| 214 |     } | 
| 215 |   | 
| 216 |     Entry makeEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) { | 
| 217 |         return new Entry(sym, shadowed, sibling, scope); | 
| 218 |     } | 
| 219 |   | 
| 220 |     /** Remove symbol from this scope.  Used when an inner class | 
| 221 |      *  attribute tells us that the class isn't a package member. | 
| 222 |      */ | 
| 223 |     public void remove(Symbol sym) { | 
| 224 |         assert shared == 0; | 
| 225 |         Entry e = lookup(sym.name); | 
| 226 |         while (e.scope == this && e.sym != sym) e = e.next(); | 
| 227 |         if (e.scope == null) return; | 
| 228 |   | 
| 229 |         // remove e from table and shadowed list; | 
| 230 |         Entry te = table[sym.name.index & hashMask]; | 
| 231 |         if (te == e) | 
| 232 |             table[sym.name.index & hashMask] = e.shadowed; | 
| 233 |         else while (true) { | 
| 234 |             if (te.shadowed == e) { | 
| 235 |                 te.shadowed = e.shadowed; | 
| 236 |                 break; | 
| 237 |             } | 
| 238 |             te = te.shadowed; | 
| 239 |         } | 
| 240 |   | 
| 241 |         // remove e from elems and sibling list | 
| 242 |         te = elems; | 
| 243 |         if (te == e) | 
| 244 |             elems = e.sibling; | 
| 245 |         else while (true) { | 
| 246 |             if (te.sibling == e) { | 
| 247 |                 te.sibling = e.sibling; | 
| 248 |                 break; | 
| 249 |             } | 
| 250 |             te = te.sibling; | 
| 251 |         } | 
| 252 |     } | 
| 253 |   | 
| 254 |     /** Enter symbol sym in this scope if not already there. | 
| 255 |      */ | 
| 256 |     public void enterIfAbsent(Symbol sym) { | 
| 257 |         assert shared == 0; | 
| 258 |         Entry e = lookup(sym.name); | 
| 259 |         while (e.scope == this && e.sym.kind != sym.kind) e = e.next(); | 
| 260 |         if (e.scope != this) enter(sym); | 
| 261 |     } | 
| 262 |   | 
| 263 |     /** Given a class, is there already a class with same fully | 
| 264 |      *  qualified name in this (import) scope? | 
| 265 |      */ | 
| 266 |     public boolean includes(Symbol c) { | 
| 267 |         for (Scope.Entry e = lookup(c.name); | 
| 268 |              e.scope == this; | 
| 269 |              e = e.next()) { | 
| 270 |             if (e.sym == c) return true; | 
| 271 |         } | 
| 272 |         return false; | 
| 273 |     } | 
| 274 |   | 
| 275 |     /** Return the entry associated with given name, starting in | 
| 276 |      *  this scope and proceeding outwards. If no entry was found, | 
| 277 |      *  return the sentinel, which is characterized by having a null in | 
| 278 |      *  both its scope and sym fields, whereas both fields are non-null | 
| 279 |      *  for regular entries. | 
| 280 |      */ | 
| 281 |     public Entry lookup(Name name) { | 
| 282 |         Entry e = table[name.index & hashMask]; | 
| 283 |         while (e.scope != null && e.sym.name != name) | 
| 284 |             e = e.shadowed; | 
| 285 |         return e; | 
| 286 |     } | 
| 287 |   | 
| 288 |     public Iterable<Symbol> getElements() { | 
| 289 |         return new Iterable<Symbol>() { | 
| 290 |             public Iterator<Symbol> iterator() { | 
| 291 |                 return new Iterator<Symbol>() { | 
| 292 |                     private Scope currScope = Scope.this; | 
| 293 |                     private Scope.Entry currEntry = elems; | 
| 294 |                     { | 
| 295 |                         update(); | 
| 296 |                     } | 
| 297 |   | 
| 298 |                     public boolean hasNext() { | 
| 299 |                         return currEntry != null; | 
| 300 |                     } | 
| 301 |   | 
| 302 |                     public Symbol next() { | 
| 303 |                         Symbol sym = (currEntry == null ? null : currEntry.sym); | 
| 304 |                         currEntry = currEntry.sibling; | 
| 305 |                         update(); | 
| 306 |                         return sym; | 
| 307 |                     } | 
| 308 |   | 
| 309 |                     public void remove() { | 
| 310 |                         throw new UnsupportedOperationException(); | 
| 311 |                     } | 
| 312 |   | 
| 313 |                     private void update() { | 
| 314 |                         while (currEntry == null && currScope.next != null) { | 
| 315 |                             currScope = currScope.next; | 
| 316 |                             currEntry = currScope.elems; | 
| 317 |                         } | 
| 318 |                     } | 
| 319 |                 }; | 
| 320 |             } | 
| 321 |         }; | 
| 322 |   | 
| 323 |     } | 
| 324 |   | 
| 325 |     public String toString() { | 
| 326 |         StringBuilder result = new StringBuilder(); | 
| 327 |         result.append("Scope["); | 
| 328 |         for (Scope s = this; s != null ; s = s.next) { | 
| 329 |             if (s != this) result.append(" | "); | 
| 330 |             for (Entry e = s.elems; e != null; e = e.sibling) { | 
| 331 |                 if (e != s.elems) result.append(", "); | 
| 332 |                 result.append(e.sym); | 
| 333 |             } | 
| 334 |         } | 
| 335 |         result.append("]"); | 
| 336 |         return result.toString(); | 
| 337 |     } | 
| 338 |   | 
| 339 |     /** A class for scope entries. | 
| 340 |      */ | 
| 341 |     public static class Entry { | 
| 342 |   | 
| 343 |         /** The referenced symbol. | 
| 344 |          *  sym == null   iff   this == sentinel | 
| 345 |          */ | 
| 346 |         public Symbol sym; | 
| 347 |   | 
| 348 |         /** An entry with the same hash code, or sentinel. | 
| 349 |          */ | 
| 350 |         private Entry shadowed; | 
| 351 |   | 
| 352 |         /** Next entry in same scope. | 
| 353 |          */ | 
| 354 |         public Entry sibling; | 
| 355 |   | 
| 356 |         /** The entry's scope. | 
| 357 |          *  scope == null   iff   this == sentinel | 
| 358 |          *  for an entry in an import scope, this is the scope | 
| 359 |          *  where the entry came from (i.e. was imported from). | 
| 360 |          */ | 
| 361 |         public Scope scope; | 
| 362 |   | 
| 363 |         public Entry(Symbol sym, Entry shadowed, Entry sibling, Scope scope) { | 
| 364 |             this.sym = sym; | 
| 365 |             this.shadowed = shadowed; | 
| 366 |             this.sibling = sibling; | 
| 367 |             this.scope = scope; | 
| 368 |         } | 
| 369 |   | 
| 370 |         /** Return next entry with the same name as this entry, proceeding | 
| 371 |          *  outwards if not found in this scope. | 
| 372 |          */ | 
| 373 |         public Entry next() { | 
| 374 |             Entry e = shadowed; | 
| 375 |             while (e.scope != null && e.sym.name != sym.name) | 
| 376 |                 e = e.shadowed; | 
| 377 |             return e; | 
| 378 |         } | 
| 379 |   | 
| 380 |         public Scope getOrigin() { | 
| 381 |             // The origin is only recorded for import scopes.  For all | 
| 382 |             // other scope entries, the "enclosing" type is available | 
| 383 |             // from other sources.  See Attr.visitSelect and | 
| 384 |             // Attr.visitIdent.  Rather than throwing an assertion | 
| 385 |             // error, we return scope which will be the same as origin | 
| 386 |             // in many cases. | 
| 387 |             return scope; | 
| 388 |         } | 
| 389 |     } | 
| 390 |   | 
| 391 |     public static class ImportScope extends Scope { | 
| 392 |   | 
| 393 |         public ImportScope(Symbol owner) { | 
| 394 |             super(owner); | 
| 395 |         } | 
| 396 |   | 
| 397 |         @Override | 
| 398 |         Entry makeEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) { | 
| 399 |             return new ImportEntry(sym, shadowed, sibling, scope, origin); | 
| 400 |         } | 
| 401 |   | 
| 402 |         public Entry lookup(Name name) { | 
| 403 |             Entry e = table[name.index & hashMask]; | 
| 404 |             while (e.scope != null && | 
| 405 |                    (e.sym.name != name || | 
| 406 |                     /* Since an inner class will show up in package and | 
| 407 |                      * import scopes until its inner class attribute has | 
| 408 |                      * been processed, we have to weed it out here.  This | 
| 409 |                      * is done by comparing the owners of the entry's | 
| 410 |                      * scope and symbol fields.  The scope field's owner | 
| 411 |                      * points to where the class originally was imported | 
| 412 |                      * from.  The symbol field's owner points to where the | 
| 413 |                      * class is situated now.  This can change when an | 
| 414 |                      * inner class is read (see ClassReader.enterClass). | 
| 415 |                      * By comparing the two fields we make sure that we do | 
| 416 |                      * not accidentally import an inner class that started | 
| 417 |                      * life as a flat class in a package. */ | 
| 418 |                     e.sym.owner != e.scope.owner)) | 
| 419 |                 e = e.shadowed; | 
| 420 |             return e; | 
| 421 |         } | 
| 422 |   | 
| 423 |         static class ImportEntry extends Entry { | 
| 424 |             private Scope origin; | 
| 425 |   | 
| 426 |             ImportEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) { | 
| 427 |                 super(sym, shadowed, sibling, scope); | 
| 428 |                 this.origin = origin; | 
| 429 |             } | 
| 430 |             public Entry next() { | 
| 431 |                 Entry e = super.shadowed; | 
| 432 |                 while (e.scope != null && | 
| 433 |                        (e.sym.name != sym.name || | 
| 434 |                         e.sym.owner != e.scope.owner)) // see lookup() | 
| 435 |                     e = e.shadowed; | 
| 436 |                 return e; | 
| 437 |             } | 
| 438 |   | 
| 439 |             @Override | 
| 440 |             public Scope getOrigin() { return origin; } | 
| 441 |         } | 
| 442 |     } | 
| 443 |   | 
| 444 |     /** An empty scope, into which you can't place anything.  Used for | 
| 445 |      *  the scope for a variable initializer. | 
| 446 |      */ | 
| 447 |     public static class DelegatedScope extends Scope { | 
| 448 |         Scope delegatee; | 
| 449 |         public static final Entry[] emptyTable = new Entry[0]; | 
| 450 |   | 
| 451 |         public DelegatedScope(Scope outer) { | 
| 452 |             super(outer, outer.owner, emptyTable); | 
| 453 |             delegatee = outer; | 
| 454 |         } | 
| 455 |         public Scope dup() { | 
| 456 |             return new DelegatedScope(next); | 
| 457 |         } | 
| 458 |         public Scope dupUnshared() { | 
| 459 |             return new DelegatedScope(next); | 
| 460 |         } | 
| 461 |         public Scope leave() { | 
| 462 |             return next; | 
| 463 |         } | 
| 464 |         public void enter(Symbol sym) { | 
| 465 |             // only anonymous classes could be put here | 
| 466 |         } | 
| 467 |         public void enter(Symbol sym, Scope s) { | 
| 468 |             // only anonymous classes could be put here | 
| 469 |         } | 
| 470 |         public void remove(Symbol sym) { | 
| 471 |             throw new AssertionError(sym); | 
| 472 |         } | 
| 473 |         public Entry lookup(Name name) { | 
| 474 |             return delegatee.lookup(name); | 
| 475 |         } | 
| 476 |     } | 
| 477 |   | 
| 478 |     /** An error scope, for which the owner should be an error symbol. */ | 
| 479 |     public static class ErrorScope extends Scope { | 
| 480 |         ErrorScope(Scope next, Symbol errSymbol, Entry[] table) { | 
| 481 |             super(next, /*owner=*/errSymbol, table); | 
| 482 |         } | 
| 483 |         public ErrorScope(Symbol errSymbol) { | 
| 484 |             super(errSymbol); | 
| 485 |         } | 
| 486 |         public Scope dup() { | 
| 487 |             return new ErrorScope(this, owner, table); | 
| 488 |         } | 
| 489 |         public Scope dupUnshared() { | 
| 490 |             return new ErrorScope(this, owner, table.clone()); | 
| 491 |         } | 
| 492 |         public Entry lookup(Name name) { | 
| 493 |             Entry e = super.lookup(name); | 
| 494 |             if (e.scope == null) | 
| 495 |                 return new Entry(owner, null, null, null); | 
| 496 |             else | 
| 497 |                 return e; | 
| 498 |         } | 
| 499 |     } | 
| 500 | } |