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

Mon, 07 Feb 2011 18:10:13 +0000

author
mcimadamore
date
Mon, 07 Feb 2011 18:10:13 +0000
changeset 858
96d4226bdd60
parent 816
7c537f4298fb
child 877
351027202f60
permissions
-rw-r--r--

7007615: java_util/generics/phase2/NameClashTest02 fails since jdk7/pit/b123.
Summary: override clash algorithm is not implemented correctly
Reviewed-by: jjg

     1 /*
     2  * Copyright (c) 1999, 2011, 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 with "open addressing" and "double hashing".
    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.
    37  *
    38  *  <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.
    40  *  This code and its internal interfaces are subject to change or
    41  *  deletion without notice.</b>
    42  */
    43 public class Scope {
    45     /** The number of scopes that share this scope's hash table.
    46      */
    47     private int shared;
    49     /** Next enclosing scope (with whom this scope may share a hashtable)
    50      */
    51     public Scope next;
    53     /** The scope's owner.
    54      */
    55     public Symbol owner;
    57     /** A hash table for the scope's entries.
    58      */
    59     Entry[] table;
    61     /** Mask for hash codes, always equal to (table.length - 1).
    62      */
    63     int hashMask;
    65     /** A linear list that also contains all entries in
    66      *  reverse order of appearance (i.e later entries are pushed on top).
    67      */
    68     public Entry elems;
    70     /** The number of elements in this scope.
    71      * This includes deleted elements, whose value is the sentinel.
    72      */
    73     int nelems = 0;
    75     /** A list of scopes to be notified if items are to be removed from this scope.
    76      */
    77     List<Scope> listeners = List.nil();
    79     /** Use as a "not-found" result for lookup.
    80      * Also used to mark deleted entries in the table.
    81      */
    82     private static final Entry sentinel = new Entry(null, null, null, null);
    84     /** The hash table's initial size.
    85      */
    86     private static final int INITIAL_SIZE = 0x10;
    88     /** A value for the empty scope.
    89      */
    90     public static final Scope emptyScope = new Scope(null, null, new Entry[]{});
    92     /** Construct a new scope, within scope next, with given owner, using
    93      *  given table. The table's length must be an exponent of 2.
    94      */
    95     private Scope(Scope next, Symbol owner, Entry[] table) {
    96         this.next = next;
    97         Assert.check(emptyScope == null || owner != null);
    98         this.owner = owner;
    99         this.table = table;
   100         this.hashMask = table.length - 1;
   101     }
   103     /** Convenience constructor used for dup and dupUnshared. */
   104     private Scope(Scope next, Symbol owner, Entry[] table, int nelems) {
   105         this(next, owner, table);
   106         this.nelems = nelems;
   107     }
   109     /** Construct a new scope, within scope next, with given owner,
   110      *  using a fresh table of length INITIAL_SIZE.
   111      */
   112     public Scope(Symbol owner) {
   113         this(null, owner, new Entry[INITIAL_SIZE]);
   114     }
   116     /** Construct a fresh scope within this scope, with same owner,
   117      *  which shares its table with the outer scope. Used in connection with
   118      *  method leave if scope access is stack-like in order to avoid allocation
   119      *  of fresh tables.
   120      */
   121     public Scope dup() {
   122         return dup(this.owner);
   123     }
   125     /** Construct a fresh scope within this scope, with new owner,
   126      *  which shares its table with the outer scope. Used in connection with
   127      *  method leave if scope access is stack-like in order to avoid allocation
   128      *  of fresh tables.
   129      */
   130     public Scope dup(Symbol newOwner) {
   131         Scope result = new Scope(this, newOwner, this.table, this.nelems);
   132         shared++;
   133         // System.out.println("====> duping scope " + this.hashCode() + " owned by " + newOwner + " to " + result.hashCode());
   134         // new Error().printStackTrace(System.out);
   135         return result;
   136     }
   138     /** Construct a fresh scope within this scope, with same owner,
   139      *  with a new hash table, whose contents initially are those of
   140      *  the table of its outer scope.
   141      */
   142     public Scope dupUnshared() {
   143         return new Scope(this, this.owner, this.table.clone(), this.nelems);
   144     }
   146     /** Remove all entries of this scope from its table, if shared
   147      *  with next.
   148      */
   149     public Scope leave() {
   150         Assert.check(shared == 0);
   151         if (table != next.table) return next;
   152         while (elems != null) {
   153             int hash = getIndex(elems.sym.name);
   154             Entry e = table[hash];
   155             Assert.check(e == elems, elems.sym);
   156             table[hash] = elems.shadowed;
   157             elems = elems.sibling;
   158         }
   159         Assert.check(next.shared > 0);
   160         next.shared--;
   161         next.nelems = nelems;
   162         // System.out.println("====> leaving scope " + this.hashCode() + " owned by " + this.owner + " to " + next.hashCode());
   163         // new Error().printStackTrace(System.out);
   164         return next;
   165     }
   167     /** Double size of hash table.
   168      */
   169     private void dble() {
   170         Assert.check(shared == 0);
   171         Entry[] oldtable = table;
   172         Entry[] newtable = new Entry[oldtable.length * 2];
   173         for (Scope s = this; s != null; s = s.next) {
   174             if (s.table == oldtable) {
   175                 Assert.check(s == this || s.shared != 0);
   176                 s.table = newtable;
   177                 s.hashMask = newtable.length - 1;
   178             }
   179         }
   180         int n = 0;
   181         for (int i = oldtable.length; --i >= 0; ) {
   182             Entry e = oldtable[i];
   183             if (e != null && e != sentinel) {
   184                 table[getIndex(e.sym.name)] = e;
   185                 n++;
   186             }
   187         }
   188         // We don't need to update nelems for shared inherited scopes,
   189         // since that gets handled by leave().
   190         nelems = n;
   191     }
   193     /** Enter symbol sym in this scope.
   194      */
   195     public void enter(Symbol sym) {
   196         Assert.check(shared == 0);
   197         enter(sym, this);
   198     }
   200     public void enter(Symbol sym, Scope s) {
   201         enter(sym, s, s);
   202     }
   204     /**
   205      * Enter symbol sym in this scope, but mark that it comes from
   206      * given scope `s' accessed through `origin'.  The last two
   207      * arguments are only used in import scopes.
   208      */
   209     public void enter(Symbol sym, Scope s, Scope origin) {
   210         Assert.check(shared == 0);
   211         if (nelems * 3 >= hashMask * 2)
   212             dble();
   213         int hash = getIndex(sym.name);
   214         Entry old = table[hash];
   215         if (old == null) {
   216             old = sentinel;
   217             nelems++;
   218         }
   219         Entry e = makeEntry(sym, old, elems, s, origin);
   220         table[hash] = e;
   221         elems = e;
   222     }
   224     Entry makeEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) {
   225         return new Entry(sym, shadowed, sibling, scope);
   226     }
   228     /** Remove symbol from this scope.  Used when an inner class
   229      *  attribute tells us that the class isn't a package member.
   230      */
   231     public void remove(Symbol sym) {
   232         Assert.check(shared == 0);
   233         Entry e = lookup(sym.name);
   234         if (e.scope == null) return;
   236         // remove e from table and shadowed list;
   237         int i = getIndex(sym.name);
   238         Entry te = table[i];
   239         if (te == e)
   240             table[i] = e.shadowed;
   241         else while (true) {
   242             if (te.shadowed == e) {
   243                 te.shadowed = e.shadowed;
   244                 break;
   245             }
   246             te = te.shadowed;
   247         }
   249         // remove e from elems and sibling list
   250         te = elems;
   251         if (te == e)
   252             elems = e.sibling;
   253         else while (true) {
   254             if (te.sibling == e) {
   255                 te.sibling = e.sibling;
   256                 break;
   257             }
   258             te = te.sibling;
   259         }
   261         // remove items from scopes that have done importAll
   262         for (List<Scope> l = listeners; l.nonEmpty(); l = l.tail) {
   263             l.head.remove(sym);
   264         }
   265     }
   267     /** Enter symbol sym in this scope if not already there.
   268      */
   269     public void enterIfAbsent(Symbol sym) {
   270         Assert.check(shared == 0);
   271         Entry e = lookup(sym.name);
   272         while (e.scope == this && e.sym.kind != sym.kind) e = e.next();
   273         if (e.scope != this) enter(sym);
   274     }
   276     /** Given a class, is there already a class with same fully
   277      *  qualified name in this (import) scope?
   278      */
   279     public boolean includes(Symbol c) {
   280         for (Scope.Entry e = lookup(c.name);
   281              e.scope == this;
   282              e = e.next()) {
   283             if (e.sym == c) return true;
   284         }
   285         return false;
   286     }
   288     static final Filter<Symbol> noFilter = new Filter<Symbol>() {
   289         public boolean accepts(Symbol s) {
   290             return true;
   291         }
   292     };
   294     /** Return the entry associated with given name, starting in
   295      *  this scope and proceeding outwards. If no entry was found,
   296      *  return the sentinel, which is characterized by having a null in
   297      *  both its scope and sym fields, whereas both fields are non-null
   298      *  for regular entries.
   299      */
   300     public Entry lookup(Name name) {
   301         return lookup(name, noFilter);
   302     }
   303     public Entry lookup(Name name, Filter<Symbol> sf) {
   304         Entry e = table[getIndex(name)];
   305         if (e == null || e == sentinel)
   306             return sentinel;
   307         while (e.scope != null && (e.sym.name != name || !sf.accepts(e.sym)))
   308             e = e.shadowed;
   309         return e;
   310     }
   312     /*void dump (java.io.PrintStream out) {
   313         out.println(this);
   314         for (int l=0; l < table.length; l++) {
   315             Entry le = table[l];
   316             out.print("#"+l+": ");
   317             if (le==sentinel) out.println("sentinel");
   318             else if(le == null) out.println("null");
   319             else out.println(""+le+" s:"+le.sym);
   320         }
   321     }*/
   323     /** Look for slot in the table.
   324      *  We use open addressing with double hashing.
   325      */
   326     int getIndex (Name name) {
   327         int h = name.hashCode();
   328         int i = h & hashMask;
   329         // The expression below is always odd, so it is guaranteed
   330         // to be mutually prime with table.length, a power of 2.
   331         int x = hashMask - ((h + (h >> 16)) << 1);
   332         int d = -1; // Index of a deleted item.
   333         for (;;) {
   334             Entry e = table[i];
   335             if (e == null)
   336                 return d >= 0 ? d : i;
   337             if (e == sentinel) {
   338                 // We have to keep searching even if we see a deleted item.
   339                 // However, remember the index in case we fail to find the name.
   340                 if (d < 0)
   341                     d = i;
   342             } else if (e.sym.name == name)
   343                 return i;
   344             i = (i + x) & hashMask;
   345         }
   346     }
   348     public Iterable<Symbol> getElements() {
   349         return getElements(noFilter);
   350     }
   352     public Iterable<Symbol> getElements(final Filter<Symbol> sf) {
   353         return new Iterable<Symbol>() {
   354             public Iterator<Symbol> iterator() {
   355                 return new Iterator<Symbol>() {
   356                     private Scope currScope = Scope.this;
   357                     private Scope.Entry currEntry = elems;
   358                     {
   359                         update();
   360                     }
   362                     public boolean hasNext() {
   363                         return currEntry != null;
   364                     }
   366                     public Symbol next() {
   367                         Symbol sym = (currEntry == null ? null : currEntry.sym);
   368                         if (currEntry != null) {
   369                             currEntry = currEntry.sibling;
   370                         }
   371                         update();
   372                         return sym;
   373                     }
   375                     public void remove() {
   376                         throw new UnsupportedOperationException();
   377                     }
   379                     private void update() {
   380                         skipToNextMatchingEntry();
   381                         while (currEntry == null && currScope.next != null) {
   382                             currScope = currScope.next;
   383                             currEntry = currScope.elems;
   384                             skipToNextMatchingEntry();
   385                         }
   386                     }
   388                     void skipToNextMatchingEntry() {
   389                         while (currEntry != null && !sf.accepts(currEntry.sym)) {
   390                             currEntry = currEntry.sibling;
   391                         }
   392                     }
   393                 };
   394             }
   395         };
   397     }
   399     public String toString() {
   400         StringBuilder result = new StringBuilder();
   401         result.append("Scope[");
   402         for (Scope s = this; s != null ; s = s.next) {
   403             if (s != this) result.append(" | ");
   404             for (Entry e = s.elems; e != null; e = e.sibling) {
   405                 if (e != s.elems) result.append(", ");
   406                 result.append(e.sym);
   407             }
   408         }
   409         result.append("]");
   410         return result.toString();
   411     }
   413     /** A class for scope entries.
   414      */
   415     public static class Entry {
   417         /** The referenced symbol.
   418          *  sym == null   iff   this == sentinel
   419          */
   420         public Symbol sym;
   422         /** An entry with the same hash code, or sentinel.
   423          */
   424         private Entry shadowed;
   426         /** Next entry in same scope.
   427          */
   428         public Entry sibling;
   430         /** The entry's scope.
   431          *  scope == null   iff   this == sentinel
   432          *  for an entry in an import scope, this is the scope
   433          *  where the entry came from (i.e. was imported from).
   434          */
   435         public Scope scope;
   437         public Entry(Symbol sym, Entry shadowed, Entry sibling, Scope scope) {
   438             this.sym = sym;
   439             this.shadowed = shadowed;
   440             this.sibling = sibling;
   441             this.scope = scope;
   442         }
   444         /** Return next entry with the same name as this entry, proceeding
   445          *  outwards if not found in this scope.
   446          */
   447         public Entry next() {
   448             return shadowed;
   449         }
   451         public Entry next(Filter<Symbol> sf) {
   452             if (shadowed.sym == null || sf.accepts(shadowed.sym)) return shadowed;
   453             else return shadowed.next(sf);
   454         }
   456         public Scope getOrigin() {
   457             // The origin is only recorded for import scopes.  For all
   458             // other scope entries, the "enclosing" type is available
   459             // from other sources.  See Attr.visitSelect and
   460             // Attr.visitIdent.  Rather than throwing an assertion
   461             // error, we return scope which will be the same as origin
   462             // in many cases.
   463             return scope;
   464         }
   465     }
   467     public static class ImportScope extends Scope {
   469         public ImportScope(Symbol owner) {
   470             super(owner);
   471         }
   473         @Override
   474         Entry makeEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) {
   475             return new ImportEntry(sym, shadowed, sibling, scope, origin);
   476         }
   478         static class ImportEntry extends Entry {
   479             private Scope origin;
   481             ImportEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) {
   482                 super(sym, shadowed, sibling, scope);
   483                 this.origin = origin;
   484             }
   486             @Override
   487             public Scope getOrigin() { return origin; }
   488         }
   489     }
   491     public static class StarImportScope extends ImportScope {
   493         public StarImportScope(Symbol owner) {
   494             super(owner);
   495         }
   497         public void importAll (Scope fromScope) {
   498             for (Scope.Entry e = fromScope.elems; e != null; e = e.sibling) {
   499                 if (e.sym.kind == Kinds.TYP && !includes(e.sym))
   500                     enter(e.sym, fromScope);
   501             }
   502             // Register to be notified when imported items are removed
   503             fromScope.listeners = fromScope.listeners.prepend(this);
   504         }
   505     }
   507     /** An empty scope, into which you can't place anything.  Used for
   508      *  the scope for a variable initializer.
   509      */
   510     public static class DelegatedScope extends Scope {
   511         Scope delegatee;
   512         public static final Entry[] emptyTable = new Entry[0];
   514         public DelegatedScope(Scope outer) {
   515             super(outer, outer.owner, emptyTable);
   516             delegatee = outer;
   517         }
   518         public Scope dup() {
   519             return new DelegatedScope(next);
   520         }
   521         public Scope dupUnshared() {
   522             return new DelegatedScope(next);
   523         }
   524         public Scope leave() {
   525             return next;
   526         }
   527         public void enter(Symbol sym) {
   528             // only anonymous classes could be put here
   529         }
   530         public void enter(Symbol sym, Scope s) {
   531             // only anonymous classes could be put here
   532         }
   533         public void remove(Symbol sym) {
   534             throw new AssertionError(sym);
   535         }
   536         public Entry lookup(Name name) {
   537             return delegatee.lookup(name);
   538         }
   539     }
   541     /** An error scope, for which the owner should be an error symbol. */
   542     public static class ErrorScope extends Scope {
   543         ErrorScope(Scope next, Symbol errSymbol, Entry[] table) {
   544             super(next, /*owner=*/errSymbol, table);
   545         }
   546         public ErrorScope(Symbol errSymbol) {
   547             super(errSymbol);
   548         }
   549         public Scope dup() {
   550             return new ErrorScope(this, owner, table);
   551         }
   552         public Scope dupUnshared() {
   553             return new ErrorScope(this, owner, table.clone());
   554         }
   555         public Entry lookup(Name name) {
   556             Entry e = super.lookup(name);
   557             if (e.scope == null)
   558                 return new Entry(owner, null, null, null);
   559             else
   560                 return e;
   561         }
   562     }
   563 }

mercurial