Tue, 07 Sep 2010 17:31:54 +0100
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 }