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

Thu, 30 Sep 2010 10:47:12 -0700

author
jjg
date
Thu, 30 Sep 2010 10:47:12 -0700
changeset 700
7b413ac1a720
parent 688
50f9ac2f4730
child 725
601160d857ef
permissions
-rw-r--r--

6988436: Cleanup javac option handling
Reviewed-by: darcy

     1 /*
     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.
     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.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package com.sun.tools.javac.code;
    28 import com.sun.tools.javac.util.*;
    29 import java.util.Iterator;
    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 supported API.
    38  *  If 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 {
    44     /** The number of scopes that share this scope's hash table.
    45      */
    46     private int shared;
    48     /** Next enclosing scope (with whom this scope may share a hashtable)
    49      */
    50     public Scope next;
    52     /** The scope's owner.
    53      */
    54     public Symbol owner;
    56     /** A hash table for the scope's entries.
    57      */
    58     public Entry[] table;
    60     /** Mask for hash codes, always equal to (table.length - 1).
    61      */
    62     int hashMask;
    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;
    69     /** The number of elements in this scope.
    70      */
    71     public int nelems = 0;
    73     /** A timestamp - useful to quickly check whether a scope has changed or not
    74      */
    75     public ScopeCounter scopeCounter;
    77     static ScopeCounter dummyCounter = new ScopeCounter() {
    78         @Override
    79         public void inc() {
    80             //do nothing
    81         }
    82     };
    84     public static class ScopeCounter {
    85         protected static final Context.Key<ScopeCounter> scopeCounterKey =
    86             new Context.Key<ScopeCounter>();
    88         public static ScopeCounter instance(Context context) {
    89             ScopeCounter instance = context.get(scopeCounterKey);
    90             if (instance == null)
    91                 instance = new ScopeCounter(context);
    92             return instance;
    93         }
    95         protected ScopeCounter(Context context) {
    96             context.put(scopeCounterKey, this);
    97         }
    99         private ScopeCounter() {};
   101         private long val = 0;
   103         public void inc() {
   104             val++;
   105         }
   107         public long val() {
   108             return val;
   109         }
   110     }
   112     /** Every hash bucket is a list of Entry's which ends in sentinel.
   113      */
   114     private static final Entry sentinel = new Entry(null, null, null, null);
   116     /** The hash table's initial size.
   117      */
   118     private static final int INITIAL_SIZE = 0x10;
   120     /** A value for the empty scope.
   121      */
   122     public static final Scope emptyScope = new Scope(null, null, new Entry[]{}, dummyCounter);
   124     /** Construct a new scope, within scope next, with given owner, using
   125      *  given table. The table's length must be an exponent of 2.
   126      */
   127     private Scope(Scope next, Symbol owner, Entry[] table, ScopeCounter scopeCounter) {
   128         this.next = next;
   129         assert emptyScope == null || owner != null;
   130         this.owner = owner;
   131         this.table = table;
   132         this.hashMask = table.length - 1;
   133         this.elems = null;
   134         this.nelems = 0;
   135         this.shared = 0;
   136         this.scopeCounter = scopeCounter;
   137     }
   139     /** Construct a new scope, within scope next, with given owner,
   140      *  using a fresh table of length INITIAL_SIZE.
   141      */
   142     public Scope(Symbol owner) {
   143         this(owner, dummyCounter);
   144     }
   146     protected Scope(Symbol owner, ScopeCounter scopeCounter) {
   147         this(null, owner, new Entry[INITIAL_SIZE], scopeCounter);
   148         for (int i = 0; i < INITIAL_SIZE; i++) table[i] = sentinel;
   149     }
   151     /** Construct a fresh scope within this scope, with same owner,
   152      *  which shares its table with the outer scope. Used in connection with
   153      *  method leave if scope access is stack-like in order to avoid allocation
   154      *  of fresh tables.
   155      */
   156     public Scope dup() {
   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;
   162     }
   164     /** Construct a fresh scope within this scope, with new owner,
   165      *  which shares its table with the outer scope. Used in connection with
   166      *  method leave if scope access is stack-like in order to avoid allocation
   167      *  of fresh tables.
   168      */
   169     public Scope dup(Symbol newOwner) {
   170         Scope result = new Scope(this, newOwner, this.table, scopeCounter);
   171         shared++;
   172         // System.out.println("====> duping scope " + this.hashCode() + " owned by " + newOwner + " to " + result.hashCode());
   173         // new Error().printStackTrace(System.out);
   174         return result;
   175     }
   177     /** Construct a fresh scope within this scope, with same owner,
   178      *  with a new hash table, whose contents initially are those of
   179      *  the table of its outer scope.
   180      */
   181     public Scope dupUnshared() {
   182         return new Scope(this, this.owner, this.table.clone(), scopeCounter);
   183     }
   185     /** Remove all entries of this scope from its table, if shared
   186      *  with next.
   187      */
   188     public Scope leave() {
   189         assert shared == 0;
   190         if (table != next.table) return next;
   191         while (elems != null) {
   192             int hash = elems.sym.name.hashCode() & hashMask;
   193             Entry e = table[hash];
   194             assert e == elems : elems.sym;
   195             table[hash] = elems.shadowed;
   196             elems = elems.sibling;
   197         }
   198         assert next.shared > 0;
   199         next.shared--;
   200         // System.out.println("====> leaving scope " + this.hashCode() + " owned by " + this.owner + " to " + next.hashCode());
   201         // new Error().printStackTrace(System.out);
   202         return next;
   203     }
   205     /** Double size of hash table.
   206      */
   207     private void dble() {
   208         assert shared == 0;
   209         Entry[] oldtable = table;
   210         Entry[] newtable = new Entry[oldtable.length * 2];
   211         for (Scope s = this; s != null; s = s.next) {
   212             if (s.table == oldtable) {
   213                 assert s == this || s.shared != 0;
   214                 s.table = newtable;
   215                 s.hashMask = newtable.length - 1;
   216             }
   217         }
   218         for (int i = 0; i < newtable.length; i++) newtable[i] = sentinel;
   219         for (int i = 0; i < oldtable.length; i++) copy(oldtable[i]);
   220     }
   222     /** Copy the given entry and all entries shadowed by it to table
   223      */
   224     private void copy(Entry e) {
   225         if (e.sym != null) {
   226             copy(e.shadowed);
   227             int hash = e.sym.name.hashCode() & hashMask;
   228             e.shadowed = table[hash];
   229             table[hash] = e;
   230         }
   231     }
   233     /** Enter symbol sym in this scope.
   234      */
   235     public void enter(Symbol sym) {
   236         assert shared == 0;
   237         enter(sym, this);
   238     }
   240     public void enter(Symbol sym, Scope s) {
   241         enter(sym, s, s);
   242     }
   244     /**
   245      * Enter symbol sym in this scope, but mark that it comes from
   246      * given scope `s' accessed through `origin'.  The last two
   247      * arguments are only used in import scopes.
   248      */
   249     public void enter(Symbol sym, Scope s, Scope origin) {
   250         assert shared == 0;
   251         // Temporarily disabled (bug 6460352):
   252         // if (nelems * 3 >= hashMask * 2) dble();
   253         int hash = sym.name.hashCode() & hashMask;
   254         Entry e = makeEntry(sym, table[hash], elems, s, origin);
   255         table[hash] = e;
   256         elems = e;
   257         nelems++;
   258         scopeCounter.inc();
   259     }
   261     Entry makeEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) {
   262         return new Entry(sym, shadowed, sibling, scope);
   263     }
   265     /** Remove symbol from this scope.  Used when an inner class
   266      *  attribute tells us that the class isn't a package member.
   267      */
   268     public void remove(Symbol sym) {
   269         assert shared == 0;
   270         Entry e = lookup(sym.name);
   271         while (e.scope == this && e.sym != sym) e = e.next();
   272         if (e.scope == null) return;
   274         scopeCounter.inc();
   276         // remove e from table and shadowed list;
   277         Entry te = table[sym.name.hashCode() & hashMask];
   278         if (te == e)
   279             table[sym.name.hashCode() & hashMask] = e.shadowed;
   280         else while (true) {
   281             if (te.shadowed == e) {
   282                 te.shadowed = e.shadowed;
   283                 break;
   284             }
   285             te = te.shadowed;
   286         }
   288         // remove e from elems and sibling list
   289         te = elems;
   290         if (te == e)
   291             elems = e.sibling;
   292         else while (true) {
   293             if (te.sibling == e) {
   294                 te.sibling = e.sibling;
   295                 break;
   296             }
   297             te = te.sibling;
   298         }
   299     }
   301     /** Enter symbol sym in this scope if not already there.
   302      */
   303     public void enterIfAbsent(Symbol sym) {
   304         assert shared == 0;
   305         Entry e = lookup(sym.name);
   306         while (e.scope == this && e.sym.kind != sym.kind) e = e.next();
   307         if (e.scope != this) enter(sym);
   308     }
   310     /** Given a class, is there already a class with same fully
   311      *  qualified name in this (import) scope?
   312      */
   313     public boolean includes(Symbol c) {
   314         for (Scope.Entry e = lookup(c.name);
   315              e.scope == this;
   316              e = e.next()) {
   317             if (e.sym == c) return true;
   318         }
   319         return false;
   320     }
   322     static final Filter<Symbol> noFilter = new Filter<Symbol>() {
   323         public boolean accepts(Symbol s) {
   324             return true;
   325         }
   326     };
   328     /** Return the entry associated with given name, starting in
   329      *  this scope and proceeding outwards. If no entry was found,
   330      *  return the sentinel, which is characterized by having a null in
   331      *  both its scope and sym fields, whereas both fields are non-null
   332      *  for regular entries.
   333      */
   334     public Entry lookup(Name name) {
   335         return lookup(name, noFilter);
   336     }
   337     public Entry lookup(Name name, Filter<Symbol> sf) {
   338         Entry e = table[name.hashCode() & hashMask];
   339         while (e.scope != null && (e.sym.name != name || !sf.accepts(e.sym)))
   340             e = e.shadowed;
   341         return e;
   342     }
   344     public Iterable<Symbol> getElements() {
   345         return getElements(noFilter);
   346     }
   348     public Iterable<Symbol> getElements(final Filter<Symbol> sf) {
   349         return new Iterable<Symbol>() {
   350             public Iterator<Symbol> iterator() {
   351                 return new Iterator<Symbol>() {
   352                     private Scope currScope = Scope.this;
   353                     private Scope.Entry currEntry = elems;
   354                     {
   355                         update();
   356                     }
   358                     public boolean hasNext() {
   359                         return currEntry != null;
   360                     }
   362                     public Symbol next() {
   363                         Symbol sym = (currEntry == null ? null : currEntry.sym);
   364                         if (currEntry != null) {
   365                             currEntry = currEntry.sibling;
   366                         }
   367                         update();
   368                         return sym;
   369                     }
   371                     public void remove() {
   372                         throw new UnsupportedOperationException();
   373                     }
   375                     private void update() {
   376                         skipToNextMatchingEntry();
   377                         while (currEntry == null && currScope.next != null) {
   378                             currScope = currScope.next;
   379                             currEntry = currScope.elems;
   380                             skipToNextMatchingEntry();
   381                         }
   382                     }
   384                     void skipToNextMatchingEntry() {
   385                         while (currEntry != null && !sf.accepts(currEntry.sym)) {
   386                             currEntry = currEntry.sibling;
   387                         }
   388                     }
   389                 };
   390             }
   391         };
   393     }
   395     public String toString() {
   396         StringBuilder result = new StringBuilder();
   397         result.append("Scope[");
   398         for (Scope s = this; s != null ; s = s.next) {
   399             if (s != this) result.append(" | ");
   400             for (Entry e = s.elems; e != null; e = e.sibling) {
   401                 if (e != s.elems) result.append(", ");
   402                 result.append(e.sym);
   403             }
   404         }
   405         result.append("]");
   406         return result.toString();
   407     }
   409     /** A class for scope entries.
   410      */
   411     public static class Entry {
   413         /** The referenced symbol.
   414          *  sym == null   iff   this == sentinel
   415          */
   416         public Symbol sym;
   418         /** An entry with the same hash code, or sentinel.
   419          */
   420         private Entry shadowed;
   422         /** Next entry in same scope.
   423          */
   424         public Entry sibling;
   426         /** The entry's scope.
   427          *  scope == null   iff   this == sentinel
   428          *  for an entry in an import scope, this is the scope
   429          *  where the entry came from (i.e. was imported from).
   430          */
   431         public Scope scope;
   433         public Entry(Symbol sym, Entry shadowed, Entry sibling, Scope scope) {
   434             this.sym = sym;
   435             this.shadowed = shadowed;
   436             this.sibling = sibling;
   437             this.scope = scope;
   438         }
   440         /** Return next entry with the same name as this entry, proceeding
   441          *  outwards if not found in this scope.
   442          */
   443         public Entry next() {
   444             Entry e = shadowed;
   445             while (e.scope != null && e.sym.name != sym.name)
   446                 e = e.shadowed;
   447             return e;
   448         }
   450         public Scope getOrigin() {
   451             // The origin is only recorded for import scopes.  For all
   452             // other scope entries, the "enclosing" type is available
   453             // from other sources.  See Attr.visitSelect and
   454             // Attr.visitIdent.  Rather than throwing an assertion
   455             // error, we return scope which will be the same as origin
   456             // in many cases.
   457             return scope;
   458         }
   459     }
   461     public static class ImportScope extends Scope {
   463         public ImportScope(Symbol owner) {
   464             super(owner);
   465         }
   467         @Override
   468         Entry makeEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) {
   469             return new ImportEntry(sym, shadowed, sibling, scope, origin);
   470         }
   472         public Entry lookup(Name name) {
   473             Entry e = table[name.hashCode() & hashMask];
   474             while (e.scope != null &&
   475                    (e.sym.name != name ||
   476                     /* Since an inner class will show up in package and
   477                      * import scopes until its inner class attribute has
   478                      * been processed, we have to weed it out here.  This
   479                      * is done by comparing the owners of the entry's
   480                      * scope and symbol fields.  The scope field's owner
   481                      * points to where the class originally was imported
   482                      * from.  The symbol field's owner points to where the
   483                      * class is situated now.  This can change when an
   484                      * inner class is read (see ClassReader.enterClass).
   485                      * By comparing the two fields we make sure that we do
   486                      * not accidentally import an inner class that started
   487                      * life as a flat class in a package. */
   488                     e.sym.owner != e.scope.owner))
   489                 e = e.shadowed;
   490             return e;
   491         }
   493         static class ImportEntry extends Entry {
   494             private Scope origin;
   496             ImportEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) {
   497                 super(sym, shadowed, sibling, scope);
   498                 this.origin = origin;
   499             }
   500             public Entry next() {
   501                 Entry e = super.shadowed;
   502                 while (e.scope != null &&
   503                        (e.sym.name != sym.name ||
   504                         e.sym.owner != e.scope.owner)) // see lookup()
   505                     e = e.shadowed;
   506                 return e;
   507             }
   509             @Override
   510             public Scope getOrigin() { return origin; }
   511         }
   512     }
   514     /** An empty scope, into which you can't place anything.  Used for
   515      *  the scope for a variable initializer.
   516      */
   517     public static class DelegatedScope extends Scope {
   518         Scope delegatee;
   519         public static final Entry[] emptyTable = new Entry[0];
   521         public DelegatedScope(Scope outer) {
   522             super(outer, outer.owner, emptyTable, outer.scopeCounter);
   523             delegatee = outer;
   524         }
   525         public Scope dup() {
   526             return new DelegatedScope(next);
   527         }
   528         public Scope dupUnshared() {
   529             return new DelegatedScope(next);
   530         }
   531         public Scope leave() {
   532             return next;
   533         }
   534         public void enter(Symbol sym) {
   535             // only anonymous classes could be put here
   536         }
   537         public void enter(Symbol sym, Scope s) {
   538             // only anonymous classes could be put here
   539         }
   540         public void remove(Symbol sym) {
   541             throw new AssertionError(sym);
   542         }
   543         public Entry lookup(Name name) {
   544             return delegatee.lookup(name);
   545         }
   546     }
   548     /** A class scope, for which a scope counter should be provided */
   549     public static class ClassScope extends Scope {
   551         ClassScope(Scope next, Symbol owner, Entry[] table, ScopeCounter scopeCounter) {
   552             super(next, owner, table, scopeCounter);
   553         }
   555         public ClassScope(Symbol owner, ScopeCounter scopeCounter) {
   556             super(owner, scopeCounter);
   557         }
   558     }
   560     /** An error scope, for which the owner should be an error symbol. */
   561     public static class ErrorScope extends Scope {
   562         ErrorScope(Scope next, Symbol errSymbol, Entry[] table) {
   563             super(next, /*owner=*/errSymbol, table, dummyCounter);
   564         }
   565         public ErrorScope(Symbol errSymbol) {
   566             super(errSymbol);
   567         }
   568         public Scope dup() {
   569             return new ErrorScope(this, owner, table);
   570         }
   571         public Scope dupUnshared() {
   572             return new ErrorScope(this, owner, table.clone());
   573         }
   574         public Entry lookup(Name name) {
   575             Entry e = super.lookup(name);
   576             if (e.scope == null)
   577                 return new Entry(owner, null, null, null);
   578             else
   579                 return e;
   580         }
   581     }
   582 }

mercurial