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

Tue, 07 Sep 2010 17:31:54 +0100

author
mcimadamore
date
Tue, 07 Sep 2010 17:31:54 +0100
changeset 673
7ae4016c5938
parent 581
f2fdd52e4e87
child 688
50f9ac2f4730
permissions
-rw-r--r--

6337171: javac should create bridge methods when type variable bounds restricted
Summary: javac should add synthetic overrides for inherited abstract methods in order to preserve binary compatibility
Reviewed-by: jjg

     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     /** 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     static final Filter<Symbol> noFilter = new Filter<Symbol>() {
   276         public boolean accepts(Symbol s) {
   277             return true;
   278         }
   279     };
   281     /** Return the entry associated with given name, starting in
   282      *  this scope and proceeding outwards. If no entry was found,
   283      *  return the sentinel, which is characterized by having a null in
   284      *  both its scope and sym fields, whereas both fields are non-null
   285      *  for regular entries.
   286      */
   287     public Entry lookup(Name name) {
   288         return lookup(name, noFilter);
   289     }
   290     public Entry lookup(Name name, Filter<Symbol> sf) {
   291         Entry e = table[name.hashCode() & hashMask];
   292         while (e.scope != null && (e.sym.name != name || !sf.accepts(e.sym)))
   293             e = e.shadowed;
   294         return e;
   295     }
   297     public Iterable<Symbol> getElements() {
   298         return getElements(noFilter);
   299     }
   301     public Iterable<Symbol> getElements(final Filter<Symbol> sf) {
   302         return new Iterable<Symbol>() {
   303             public Iterator<Symbol> iterator() {
   304                 return new Iterator<Symbol>() {
   305                     private Scope currScope = Scope.this;
   306                     private Scope.Entry currEntry = elems;
   307                     {
   308                         update();
   309                     }
   311                     public boolean hasNext() {
   312                         return currEntry != null;
   313                     }
   315                     public Symbol next() {
   316                         Symbol sym = (currEntry == null ? null : currEntry.sym);
   317                         if (currEntry != null) {
   318                             currEntry = currEntry.sibling;
   319                         }
   320                         update();
   321                         return sym;
   322                     }
   324                     public void remove() {
   325                         throw new UnsupportedOperationException();
   326                     }
   328                     private void update() {
   329                         skipToNextMatchingEntry();
   330                         while (currEntry == null && currScope.next != null) {
   331                             currScope = currScope.next;
   332                             currEntry = currScope.elems;
   333                             skipToNextMatchingEntry();
   334                         }
   335                     }
   337                     void skipToNextMatchingEntry() {
   338                         while (currEntry != null && !sf.accepts(currEntry.sym)) {
   339                             currEntry = currEntry.sibling;
   340                         }
   341                     }
   342                 };
   343             }
   344         };
   346     }
   348     public String toString() {
   349         StringBuilder result = new StringBuilder();
   350         result.append("Scope[");
   351         for (Scope s = this; s != null ; s = s.next) {
   352             if (s != this) result.append(" | ");
   353             for (Entry e = s.elems; e != null; e = e.sibling) {
   354                 if (e != s.elems) result.append(", ");
   355                 result.append(e.sym);
   356             }
   357         }
   358         result.append("]");
   359         return result.toString();
   360     }
   362     /** A class for scope entries.
   363      */
   364     public static class Entry {
   366         /** The referenced symbol.
   367          *  sym == null   iff   this == sentinel
   368          */
   369         public Symbol sym;
   371         /** An entry with the same hash code, or sentinel.
   372          */
   373         private Entry shadowed;
   375         /** Next entry in same scope.
   376          */
   377         public Entry sibling;
   379         /** The entry's scope.
   380          *  scope == null   iff   this == sentinel
   381          *  for an entry in an import scope, this is the scope
   382          *  where the entry came from (i.e. was imported from).
   383          */
   384         public Scope scope;
   386         public Entry(Symbol sym, Entry shadowed, Entry sibling, Scope scope) {
   387             this.sym = sym;
   388             this.shadowed = shadowed;
   389             this.sibling = sibling;
   390             this.scope = scope;
   391         }
   393         /** Return next entry with the same name as this entry, proceeding
   394          *  outwards if not found in this scope.
   395          */
   396         public Entry next() {
   397             Entry e = shadowed;
   398             while (e.scope != null && e.sym.name != sym.name)
   399                 e = e.shadowed;
   400             return e;
   401         }
   403         public Scope getOrigin() {
   404             // The origin is only recorded for import scopes.  For all
   405             // other scope entries, the "enclosing" type is available
   406             // from other sources.  See Attr.visitSelect and
   407             // Attr.visitIdent.  Rather than throwing an assertion
   408             // error, we return scope which will be the same as origin
   409             // in many cases.
   410             return scope;
   411         }
   412     }
   414     public static class ImportScope extends Scope {
   416         public ImportScope(Symbol owner) {
   417             super(owner);
   418         }
   420         @Override
   421         Entry makeEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) {
   422             return new ImportEntry(sym, shadowed, sibling, scope, origin);
   423         }
   425         public Entry lookup(Name name) {
   426             Entry e = table[name.hashCode() & hashMask];
   427             while (e.scope != null &&
   428                    (e.sym.name != name ||
   429                     /* Since an inner class will show up in package and
   430                      * import scopes until its inner class attribute has
   431                      * been processed, we have to weed it out here.  This
   432                      * is done by comparing the owners of the entry's
   433                      * scope and symbol fields.  The scope field's owner
   434                      * points to where the class originally was imported
   435                      * from.  The symbol field's owner points to where the
   436                      * class is situated now.  This can change when an
   437                      * inner class is read (see ClassReader.enterClass).
   438                      * By comparing the two fields we make sure that we do
   439                      * not accidentally import an inner class that started
   440                      * life as a flat class in a package. */
   441                     e.sym.owner != e.scope.owner))
   442                 e = e.shadowed;
   443             return e;
   444         }
   446         static class ImportEntry extends Entry {
   447             private Scope origin;
   449             ImportEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) {
   450                 super(sym, shadowed, sibling, scope);
   451                 this.origin = origin;
   452             }
   453             public Entry next() {
   454                 Entry e = super.shadowed;
   455                 while (e.scope != null &&
   456                        (e.sym.name != sym.name ||
   457                         e.sym.owner != e.scope.owner)) // see lookup()
   458                     e = e.shadowed;
   459                 return e;
   460             }
   462             @Override
   463             public Scope getOrigin() { return origin; }
   464         }
   465     }
   467     /** An empty scope, into which you can't place anything.  Used for
   468      *  the scope for a variable initializer.
   469      */
   470     public static class DelegatedScope extends Scope {
   471         Scope delegatee;
   472         public static final Entry[] emptyTable = new Entry[0];
   474         public DelegatedScope(Scope outer) {
   475             super(outer, outer.owner, emptyTable);
   476             delegatee = outer;
   477         }
   478         public Scope dup() {
   479             return new DelegatedScope(next);
   480         }
   481         public Scope dupUnshared() {
   482             return new DelegatedScope(next);
   483         }
   484         public Scope leave() {
   485             return next;
   486         }
   487         public void enter(Symbol sym) {
   488             // only anonymous classes could be put here
   489         }
   490         public void enter(Symbol sym, Scope s) {
   491             // only anonymous classes could be put here
   492         }
   493         public void remove(Symbol sym) {
   494             throw new AssertionError(sym);
   495         }
   496         public Entry lookup(Name name) {
   497             return delegatee.lookup(name);
   498         }
   499     }
   501     /** An error scope, for which the owner should be an error symbol. */
   502     public static class ErrorScope extends Scope {
   503         ErrorScope(Scope next, Symbol errSymbol, Entry[] table) {
   504             super(next, /*owner=*/errSymbol, table);
   505         }
   506         public ErrorScope(Symbol errSymbol) {
   507             super(errSymbol);
   508         }
   509         public Scope dup() {
   510             return new ErrorScope(this, owner, table);
   511         }
   512         public Scope dupUnshared() {
   513             return new ErrorScope(this, owner, table.clone());
   514         }
   515         public Entry lookup(Name name) {
   516             Entry e = super.lookup(name);
   517             if (e.scope == null)
   518                 return new Entry(owner, null, null, null);
   519             else
   520                 return e;
   521         }
   522     }
   523 }

mercurial