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

Thu, 02 Oct 2008 19:58:40 -0700

author
xdono
date
Thu, 02 Oct 2008 19:58:40 -0700
changeset 117
24a47c3062fe
parent 113
eff38cc97183
child 554
9d9f26857129
permissions
-rw-r--r--

6754988: Update copyright year
Summary: Update for files that have been modified starting July 2008
Reviewed-by: ohair, tbell

     1 /*
     2  * Copyright 1999-2008 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  */
    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 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 {
    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     /** 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);
    77     /** The hash table's initial size.
    78      */
    79     private static final int INITIAL_SIZE = 0x10;
    81     /** A value for the empty scope.
    82      */
    83     public static final Scope emptyScope = new Scope(null, null, new Entry[]{});
    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     }
    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     }
   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     }
   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     }
   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     }
   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.hashCode() & 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     }
   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     }
   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.hashCode() & hashMask;
   184             e.shadowed = table[hash];
   185             table[hash] = e;
   186         }
   187     }
   189     /** Enter symbol sym in this scope.
   190      */
   191     public void enter(Symbol sym) {
   192         assert shared == 0;
   193         enter(sym, this);
   194     }
   196     public void enter(Symbol sym, Scope s) {
   197         enter(sym, s, s);
   198     }
   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.hashCode() & hashMask;
   210         Entry e = makeEntry(sym, table[hash], elems, s, origin);
   211         table[hash] = e;
   212         elems = e;
   213         nelems++;
   214     }
   216     Entry makeEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) {
   217         return new Entry(sym, shadowed, sibling, scope);
   218     }
   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;
   229         // remove e from table and shadowed list;
   230         Entry te = table[sym.name.hashCode() & hashMask];
   231         if (te == e)
   232             table[sym.name.hashCode() & 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         }
   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     }
   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     }
   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     }
   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.hashCode() & hashMask];
   283         while (e.scope != null && e.sym.name != name)
   284             e = e.shadowed;
   285         return e;
   286     }
   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                     }
   298                     public boolean hasNext() {
   299                         return currEntry != null;
   300                     }
   302                     public Symbol next() {
   303                         Symbol sym = (currEntry == null ? null : currEntry.sym);
   304                         currEntry = currEntry.sibling;
   305                         update();
   306                         return sym;
   307                     }
   309                     public void remove() {
   310                         throw new UnsupportedOperationException();
   311                     }
   313                     private void update() {
   314                         while (currEntry == null && currScope.next != null) {
   315                             currScope = currScope.next;
   316                             currEntry = currScope.elems;
   317                         }
   318                     }
   319                 };
   320             }
   321         };
   323     }
   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     }
   339     /** A class for scope entries.
   340      */
   341     public static class Entry {
   343         /** The referenced symbol.
   344          *  sym == null   iff   this == sentinel
   345          */
   346         public Symbol sym;
   348         /** An entry with the same hash code, or sentinel.
   349          */
   350         private Entry shadowed;
   352         /** Next entry in same scope.
   353          */
   354         public Entry sibling;
   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;
   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         }
   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         }
   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     }
   391     public static class ImportScope extends Scope {
   393         public ImportScope(Symbol owner) {
   394             super(owner);
   395         }
   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         }
   402         public Entry lookup(Name name) {
   403             Entry e = table[name.hashCode() & 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         }
   423         static class ImportEntry extends Entry {
   424             private Scope origin;
   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             }
   439             @Override
   440             public Scope getOrigin() { return origin; }
   441         }
   442     }
   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];
   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     }
   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 }

mercurial