Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(173)

Side by Side Diff: runtime/lib/mirrors_impl.dart

Issue 420713008: Remove hard limit from mirrors accessor caches. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: unpack dense expression setting up closure generation Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/lib/mirrors.cc ('k') | sdk/lib/internal/internal.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 // VM-specific implementation of the dart:mirrors library. 5 // VM-specific implementation of the dart:mirrors library.
6 6
7 import "dart:collection" show UnmodifiableListView, UnmodifiableMapView; 7 import "dart:collection" show UnmodifiableListView, UnmodifiableMapView;
8 import "dart:_internal" show LRUMap;
9 8
10 final emptyList = new UnmodifiableListView([]); 9 final emptyList = new UnmodifiableListView([]);
11 final emptyMap = new UnmodifiableMapView({}); 10 final emptyMap = new UnmodifiableMapView({});
12 11
13 class _InternalMirrorError { 12 class _InternalMirrorError {
14 final String _msg; 13 final String _msg;
15 const _InternalMirrorError(String this._msg); 14 const _InternalMirrorError(String this._msg);
16 String toString() => _msg; 15 String toString() => _msg;
17 } 16 }
18 17
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
83 82
84 List _metadata(reflectee) 83 List _metadata(reflectee)
85 native 'DeclarationMirror_metadata'; 84 native 'DeclarationMirror_metadata';
86 85
87 bool _subtypeTest(Type a, Type b) 86 bool _subtypeTest(Type a, Type b)
88 native 'TypeMirror_subtypeTest'; 87 native 'TypeMirror_subtypeTest';
89 88
90 bool _moreSpecificTest(Type a, Type b) 89 bool _moreSpecificTest(Type a, Type b)
91 native 'TypeMirror_moreSpecificTest'; 90 native 'TypeMirror_moreSpecificTest';
92 91
92 class _AccessorCacheAssociation {
93 String key;
94 Function value;
95 bool usedSinceGrowth = true;
96 _AccessorCacheAssociation(this.key, this.value);
97 }
98
99 /**
100 * A map that will grow as associations are added but will prefer to evict
101 * associations that have not been used since the last growth when needing to
102 * grow again. Implemented as an open addressing hash table.
103 */
104 class _AccessorCache {
105 List table;
106 int shift;
107 int mask;
108 int capacity; // Max number of associations before we start evicting/growing.
109 int size = 0; // Current number of associations.
110
111 /**
112 * Create a cache whose capacity is 75% of 2^shift.
113 */
114 _AccessorCache.withInitialShift(int shift) {
115 // The scheme used here for handling collisions relies on there always
116 // being at least one empty slot.
117 if (shift < 1) throw new Exception("_AccessorCache requires a shift >= 1");
118 initWithShift(shift);
119 }
120
121 void initWithShift(int shift) {
122 this.shift = shift;
123 this.mask = (1 << shift) - 1;
124 this.capacity = (1 << shift) * 3 ~/ 4;
125 this.table = new List(1 << shift);
126 assert(table.length > capacity);
127 }
128
129 int scanFor(String key) {
130 var start = key.hashCode & mask;
131 var index = start;
132 do {
133 var assoc = table[index];
134 if (null == assoc || assoc.key == key) {
135 return index;
136 }
137 index = (index + 1) & mask;
138 } while (index != start);
139 // Should never happen because we start evicting associations before the
140 // table is full.
141 throw new Exception("Internal error: _AccessorCache table full");
142 }
143
144 int scanForEmpty(String key) {
145 var start = key.hashCode & mask;
146 var index = start;
147 do {
148 if (null == table[index]) {
149 return index;
150 }
151 index = (index + 1) & mask;
152 } while (index != start);
153 // Should never happen because we start evicting associations before the
154 // table is full.
155 throw new Exception("Internal error: _AccessorCache table full");
156 }
157
158 void fixCollisionsAfter(int start) {
159 var assoc;
160 var index = (start + 1) & mask;
161 while (null != (assoc = table[index])) {
162 var newIndex = scanFor(assoc.key);
163 if (newIndex != index) {
164 assert(table[newIndex] == null);
165 table[newIndex] = assoc;
166 table[index] = null;
167 }
168 index = (index + 1) & mask;
169 }
170 }
171
172 void grow() {
173 var oldTable = table;
174
175 initWithShift(shift + 1);
176
177 for (int oldIndex = 0; oldIndex < oldTable.length; oldIndex++) {
178 var assoc = oldTable[oldIndex];
179 if (assoc != null) {
180 var newIndex = scanForEmpty(assoc.key);
181 assoc.usedSinceGrowth = false;
182 table[newIndex] = assoc;
183 }
184 }
185 }
186
187 void tryToShrinkOtherwiseGrow() {
188 // Remove any associations not accessed since the last growth. If we are
189 // unable to free any slots, grow.
190 bool needToGrow = true;
191 for (int i = 0; i < table.length; i++) {
192 var assoc = table[i];
193 if (null != assoc && (!assoc.usedSinceGrowth || null == assoc.value)) {
194 table[i] = null;
195 size--;
196 fixCollisionsAfter(i);
197 needToGrow = false;
198 }
199 }
200 if (needToGrow) grow();
201 }
202
203 operator []=(String key, Function value) {
204 int index = scanFor(key);
205 var assoc = table[index];
206 if (null != assoc) {
207 // Existing key, replace value.
208 assert(assoc.key == key);
209 assoc.value = value;
210 assoc.usedSinceGrowth = true;
211 } else {
212 // New key.
213 var newAssoc = new _AccessorCacheAssociation(key, value);
214 if (size == capacity) {
215 // No free slots.
216 tryToShrinkOtherwiseGrow();
217 index = scanFor(key);
218 assert(table[index] == null);
219 }
220 table[index] = newAssoc;
221 size++;
222 }
223 }
224
225 Function operator [](String key) {
226 var index = scanFor(key);
227 var assoc = table[index];
228 if (null == assoc) return null;
229 assoc.usedSinceGrowth = true;
230 return assoc.value;
231 }
232 }
233
234
93 class _LocalMirrorSystem extends MirrorSystem { 235 class _LocalMirrorSystem extends MirrorSystem {
94 final Map<Uri, LibraryMirror> libraries; 236 final Map<Uri, LibraryMirror> libraries;
95 final IsolateMirror isolate; 237 final IsolateMirror isolate;
96 238
97 _LocalMirrorSystem(List<LibraryMirror> libraries, this.isolate) 239 _LocalMirrorSystem(List<LibraryMirror> libraries, this.isolate)
98 : this.libraries = new Map<Uri, LibraryMirror>.fromIterable( 240 : this.libraries = new Map<Uri, LibraryMirror>.fromIterable(
99 libraries, key: (e) => e.uri); 241 libraries, key: (e) => e.uri);
100 242
101 TypeMirror _dynamicType = null; 243 TypeMirror _dynamicType = null;
102 TypeMirror get dynamicType { 244 TypeMirror get dynamicType {
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after
292 return other is _LocalInstanceMirror && 434 return other is _LocalInstanceMirror &&
293 identical(_reflectee, other._reflectee); 435 identical(_reflectee, other._reflectee);
294 } 436 }
295 437
296 int get hashCode { 438 int get hashCode {
297 // Avoid hash collisions with the reflectee. This constant is in Smi range 439 // Avoid hash collisions with the reflectee. This constant is in Smi range
298 // and happens to be the inner padding from RFC 2104. 440 // and happens to be the inner padding from RFC 2104.
299 return identityHashCode(_reflectee) ^ 0x36363636; 441 return identityHashCode(_reflectee) ^ 0x36363636;
300 } 442 }
301 443
302 static var _getFieldClosures = new LRUMap.withShift(9); 444 static var _getFieldClosures = new _AccessorCache.withInitialShift(4);
303 static var _setFieldClosures = new LRUMap.withShift(9); 445 static var _setFieldClosures = new _AccessorCache.withInitialShift(4);
304 static var _getFieldCallCounts = new LRUMap.withShift(10); 446
305 static var _setFieldCallCounts = new LRUMap.withShift(10); 447 _createGetterClosure(unwrapped) {
306 static const _closureThreshold = 20; 448 var atPosition = unwrapped.indexOf('@');
449 if (atPosition == -1) {
450 // Public symbol.
451 return _eval('(x) => x.$unwrapped', null);
452 } else {
453 // Private symbol.
454 var withoutKey = unwrapped.substring(0, atPosition);
455 var privateKey = unwrapped.substring(atPosition);
456 return _eval('(x) => x.$withoutKey', privateKey);
457 }
458 }
307 459
308 _getFieldSlow(unwrapped) { 460 _getFieldSlow(unwrapped) {
309 // Slow path factored out to give the fast path a better chance at being 461 // Slow path factored out to give the fast path a better chance at being
310 // inlined. 462 // inlined.
311 var callCount = _getFieldCallCounts[unwrapped];
312 if (callCount == null) {
313 callCount = 0;
314 }
315 if (callCount == _closureThreshold) {
316 // We've seen a successful setter invocation a few times: time to invest
317 // in a closure.
318 var f;
319 var atPosition = unwrapped.indexOf('@');
320 if (atPosition == -1) {
321 // Public symbol.
322 f = _eval('(x) => x.$unwrapped', null);
323 } else {
324 // Private symbol.
325 var withoutKey = unwrapped.substring(0, atPosition);
326 var privateKey = unwrapped.substring(atPosition);
327 f = _eval('(x) => x.$withoutKey', privateKey);
328 }
329 _getFieldClosures[unwrapped] = f;
330 return reflect(f(_reflectee));
331 }
332 var result = reflect(_invokeGetter(_reflectee, unwrapped)); 463 var result = reflect(_invokeGetter(_reflectee, unwrapped));
333 // Only update call count if we don't throw to avoid creating closures for 464 // Wait until success to avoid creating closures for non-existent getters,
334 // non-existent getters. 465 // and defer the creation until the next getField invocation.
335 _getFieldCallCounts[unwrapped] = callCount + 1; 466 _getFieldClosures[unwrapped] = (receiver) {
467 var getterClosure = _createGetterClosure(unwrapped);
468 _getFieldClosures[unwrapped] = getterClosure;
469 return getterClosure(receiver);
470 };
336 return result; 471 return result;
337 } 472 }
338 473
339 InstanceMirror getField(Symbol memberName) { 474 InstanceMirror getField(Symbol memberName) {
340 var unwrapped = _n(memberName); 475 var unwrapped = _n(memberName);
341 var f = _getFieldClosures[unwrapped]; 476 var f = _getFieldClosures[unwrapped];
342 return (f == null) ? _getFieldSlow(unwrapped) : reflect(f(_reflectee)); 477 return (f == null) ? _getFieldSlow(unwrapped) : reflect(f(_reflectee));
343 } 478 }
344 479
480 _createSetterClosure(unwrapped) {
481 var atPosition = unwrapped.indexOf('@');
482 if (atPosition == -1) {
483 // Public symbol.
484 return _eval('(x, v) => x.$unwrapped = v', null);
485 } else {
486 // Private symbol.
487 var withoutKey = unwrapped.substring(0, atPosition);
488 var privateKey = unwrapped.substring(atPosition);
489 return _eval('(x, v) => x.$withoutKey = v', privateKey);
490 }
491 }
492
345 _setFieldSlow(unwrapped, arg) { 493 _setFieldSlow(unwrapped, arg) {
346 // Slow path factored out to give the fast path a better chance at being 494 // Slow path factored out to give the fast path a better chance at being
347 // inlined. 495 // inlined.
348 var callCount = _setFieldCallCounts[unwrapped];
349 if (callCount == null) {
350 callCount = 0;
351 }
352 if (callCount == _closureThreshold) {
353 // We've seen a successful getter invocation a few times: time to invest
354 // in a closure.
355 var f;
356 var atPosition = unwrapped.indexOf('@');
357 if (atPosition == -1) {
358 // Public symbol.
359 f = _eval('(x, v) => x.$unwrapped = v', null);
360 } else {
361 // Private symbol.
362 var withoutKey = unwrapped.substring(0, atPosition);
363 var privateKey = unwrapped.substring(atPosition);
364 f = _eval('(x, v) => x.$withoutKey = v', privateKey);
365 }
366 _setFieldClosures[unwrapped] = f;
367 return reflect(f(_reflectee, arg));
368 }
369 _invokeSetter(_reflectee, unwrapped, arg); 496 _invokeSetter(_reflectee, unwrapped, arg);
370 var result = reflect(arg); 497 var result = reflect(arg);
371 // Only update call count if we don't throw to avoid creating closures for 498 // Wait until success to avoid creating closures for non-existent setters.
372 // non-existent setters. 499 // and defer the creation until the next setField invocation.
373 _setFieldCallCounts[unwrapped] = callCount + 1; 500 _setFieldClosures[unwrapped] = (receiver, argument) {
501 var setterClosure = _createSetterClosure(unwrapped);
502 _setFieldClosures[unwrapped] = setterClosure;
503 return setterClosure(receiver, argument);
504 };
374 return result; 505 return result;
375 } 506 }
376 507
377 InstanceMirror setField(Symbol memberName, arg) { 508 InstanceMirror setField(Symbol memberName, arg) {
378 var unwrapped = _n(memberName); 509 var unwrapped = _n(memberName);
379 var f = _setFieldClosures[unwrapped]; 510 var f = _setFieldClosures[unwrapped];
380 return (f == null) 511 return (f == null)
381 ? _setFieldSlow(unwrapped, arg) 512 ? _setFieldSlow(unwrapped, arg)
382 : reflect(f(_reflectee, arg)); 513 : reflect(f(_reflectee, arg));
383 } 514 }
(...skipping 1185 matching lines...) Expand 10 before | Expand all | Expand 10 after
1569 if (typeMirror == null) { 1700 if (typeMirror == null) {
1570 typeMirror = makeLocalTypeMirror(key); 1701 typeMirror = makeLocalTypeMirror(key);
1571 _instanitationCache[key] = typeMirror; 1702 _instanitationCache[key] = typeMirror;
1572 if (typeMirror is ClassMirror && !typeMirror._isGeneric) { 1703 if (typeMirror is ClassMirror && !typeMirror._isGeneric) {
1573 _declarationCache[key] = typeMirror; 1704 _declarationCache[key] = typeMirror;
1574 } 1705 }
1575 } 1706 }
1576 return typeMirror; 1707 return typeMirror;
1577 } 1708 }
1578 } 1709 }
OLDNEW
« no previous file with comments | « runtime/lib/mirrors.cc ('k') | sdk/lib/internal/internal.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698