68 |
68 |
69 /** The number of elements in this scope. |
69 /** The number of elements in this scope. |
70 */ |
70 */ |
71 public int nelems = 0; |
71 public int nelems = 0; |
72 |
72 |
|
73 /** A timestamp - useful to quickly check whether a scope has changed or not |
|
74 */ |
|
75 public ScopeCounter scopeCounter; |
|
76 |
|
77 static ScopeCounter dummyCounter = new ScopeCounter() { |
|
78 @Override |
|
79 public void inc() { |
|
80 //do nothing |
|
81 } |
|
82 }; |
|
83 |
|
84 public static class ScopeCounter { |
|
85 protected static final Context.Key<ScopeCounter> scopeCounterKey = |
|
86 new Context.Key<ScopeCounter>(); |
|
87 |
|
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 } |
|
94 |
|
95 protected ScopeCounter(Context context) { |
|
96 context.put(scopeCounterKey, this); |
|
97 } |
|
98 |
|
99 private ScopeCounter() {}; |
|
100 |
|
101 private long val = 0; |
|
102 |
|
103 public void inc() { |
|
104 val++; |
|
105 } |
|
106 |
|
107 public long val() { |
|
108 return val; |
|
109 } |
|
110 } |
|
111 |
73 /** Every hash bucket is a list of Entry's which ends in sentinel. |
112 /** Every hash bucket is a list of Entry's which ends in sentinel. |
74 */ |
113 */ |
75 private static final Entry sentinel = new Entry(null, null, null, null); |
114 private static final Entry sentinel = new Entry(null, null, null, null); |
76 |
115 |
77 /** The hash table's initial size. |
116 /** The hash table's initial size. |
78 */ |
117 */ |
79 private static final int INITIAL_SIZE = 0x10; |
118 private static final int INITIAL_SIZE = 0x10; |
80 |
119 |
81 /** A value for the empty scope. |
120 /** A value for the empty scope. |
82 */ |
121 */ |
83 public static final Scope emptyScope = new Scope(null, null, new Entry[]{}); |
122 public static final Scope emptyScope = new Scope(null, null, new Entry[]{}, dummyCounter); |
84 |
123 |
85 /** Construct a new scope, within scope next, with given owner, using |
124 /** Construct a new scope, within scope next, with given owner, using |
86 * given table. The table's length must be an exponent of 2. |
125 * given table. The table's length must be an exponent of 2. |
87 */ |
126 */ |
88 Scope(Scope next, Symbol owner, Entry[] table) { |
127 private Scope(Scope next, Symbol owner, Entry[] table, ScopeCounter scopeCounter) { |
89 this.next = next; |
128 this.next = next; |
90 assert emptyScope == null || owner != null; |
129 assert emptyScope == null || owner != null; |
91 this.owner = owner; |
130 this.owner = owner; |
92 this.table = table; |
131 this.table = table; |
93 this.hashMask = table.length - 1; |
132 this.hashMask = table.length - 1; |
94 this.elems = null; |
133 this.elems = null; |
95 this.nelems = 0; |
134 this.nelems = 0; |
96 this.shared = 0; |
135 this.shared = 0; |
|
136 this.scopeCounter = scopeCounter; |
97 } |
137 } |
98 |
138 |
99 /** Construct a new scope, within scope next, with given owner, |
139 /** Construct a new scope, within scope next, with given owner, |
100 * using a fresh table of length INITIAL_SIZE. |
140 * using a fresh table of length INITIAL_SIZE. |
101 */ |
141 */ |
102 public Scope(Symbol owner) { |
142 public Scope(Symbol owner) { |
103 this(null, owner, new Entry[INITIAL_SIZE]); |
143 this(owner, dummyCounter); |
|
144 } |
|
145 |
|
146 protected Scope(Symbol owner, ScopeCounter scopeCounter) { |
|
147 this(null, owner, new Entry[INITIAL_SIZE], scopeCounter); |
104 for (int i = 0; i < INITIAL_SIZE; i++) table[i] = sentinel; |
148 for (int i = 0; i < INITIAL_SIZE; i++) table[i] = sentinel; |
105 } |
149 } |
106 |
150 |
107 /** Construct a fresh scope within this scope, with same owner, |
151 /** Construct a fresh scope within this scope, with same owner, |
108 * which shares its table with the outer scope. Used in connection with |
152 * 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 |
153 * method leave if scope access is stack-like in order to avoid allocation |
110 * of fresh tables. |
154 * of fresh tables. |
111 */ |
155 */ |
112 public Scope dup() { |
156 public Scope dup() { |
113 Scope result = new Scope(this, this.owner, this.table); |
157 Scope result = new Scope(this, this.owner, this.table, scopeCounter); |
114 shared++; |
158 shared++; |
115 // System.out.println("====> duping scope " + this.hashCode() + " owned by " + this.owner + " to " + result.hashCode()); |
159 // System.out.println("====> duping scope " + this.hashCode() + " owned by " + this.owner + " to " + result.hashCode()); |
116 // new Error().printStackTrace(System.out); |
160 // new Error().printStackTrace(System.out); |
117 return result; |
161 return result; |
118 } |
162 } |
133 /** Construct a fresh scope within this scope, with same owner, |
177 /** Construct a fresh scope within this scope, with same owner, |
134 * with a new hash table, whose contents initially are those of |
178 * with a new hash table, whose contents initially are those of |
135 * the table of its outer scope. |
179 * the table of its outer scope. |
136 */ |
180 */ |
137 public Scope dupUnshared() { |
181 public Scope dupUnshared() { |
138 return new Scope(this, this.owner, this.table.clone()); |
182 return new Scope(this, this.owner, this.table.clone(), scopeCounter); |
139 } |
183 } |
140 |
184 |
141 /** Remove all entries of this scope from its table, if shared |
185 /** Remove all entries of this scope from its table, if shared |
142 * with next. |
186 * with next. |
143 */ |
187 */ |
209 int hash = sym.name.hashCode() & hashMask; |
253 int hash = sym.name.hashCode() & hashMask; |
210 Entry e = makeEntry(sym, table[hash], elems, s, origin); |
254 Entry e = makeEntry(sym, table[hash], elems, s, origin); |
211 table[hash] = e; |
255 table[hash] = e; |
212 elems = e; |
256 elems = e; |
213 nelems++; |
257 nelems++; |
|
258 scopeCounter.inc(); |
214 } |
259 } |
215 |
260 |
216 Entry makeEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) { |
261 Entry makeEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) { |
217 return new Entry(sym, shadowed, sibling, scope); |
262 return new Entry(sym, shadowed, sibling, scope); |
218 } |
263 } |
493 public void remove(Symbol sym) { |
540 public void remove(Symbol sym) { |
494 throw new AssertionError(sym); |
541 throw new AssertionError(sym); |
495 } |
542 } |
496 public Entry lookup(Name name) { |
543 public Entry lookup(Name name) { |
497 return delegatee.lookup(name); |
544 return delegatee.lookup(name); |
|
545 } |
|
546 } |
|
547 |
|
548 /** A class scope, for which a scope counter should be provided */ |
|
549 public static class ClassScope extends Scope { |
|
550 |
|
551 ClassScope(Scope next, Symbol owner, Entry[] table, ScopeCounter scopeCounter) { |
|
552 super(next, owner, table, scopeCounter); |
|
553 } |
|
554 |
|
555 public ClassScope(Symbol owner, ScopeCounter scopeCounter) { |
|
556 super(owner, scopeCounter); |
498 } |
557 } |
499 } |
558 } |
500 |
559 |
501 /** An error scope, for which the owner should be an error symbol. */ |
560 /** An error scope, for which the owner should be an error symbol. */ |
502 public static class ErrorScope extends Scope { |
561 public static class ErrorScope extends Scope { |
503 ErrorScope(Scope next, Symbol errSymbol, Entry[] table) { |
562 ErrorScope(Scope next, Symbol errSymbol, Entry[] table) { |
504 super(next, /*owner=*/errSymbol, table); |
563 super(next, /*owner=*/errSymbol, table, dummyCounter); |
505 } |
564 } |
506 public ErrorScope(Symbol errSymbol) { |
565 public ErrorScope(Symbol errSymbol) { |
507 super(errSymbol); |
566 super(errSymbol); |
508 } |
567 } |
509 public Scope dup() { |
568 public Scope dup() { |