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

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: 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 = false;
Ivan Posva 2014/08/08 19:09:35 Allocating a new association marks it immediately
96 }
97
98 /**
99 * A map that will grow as associations are added but will prefer to evict
100 * associations that have not been used since the last growth when needing to
101 * grow again. Implemented as an open addressing hash table.
102 */
103 class _AccessorCache {
104 List table;
105 int shift;
106 int mask;
107 int capacity; // Max number of associations before we start evicting/growing.
108 int size = 0; // Current number of associations.
109
110 /**
111 * Create a cache whose capacity is 75% of 2^shift.
112 */
113 _AccessorCache.withInitialShift(int shift) {
114 // The scheme used here for handling collisions relies on there always
115 // being at least one empty slot.
116 if (shift < 1) throw new Exception("_AccessorCache requires a shift >= 1");
117 initWithShift(shift);
118 }
119
120 void initWithShift(int shift) {
121 this.shift = shift;
122 this.mask = (1 << shift) - 1;
123 this.capacity = (1 << shift) * 3 ~/ 4;
124 this.table = new List(1 << shift);
125 assert(table.length > capacity);
126 }
127
128 int scanFor(String key) {
129 var start = key.hashCode & mask;
130 var index = start;
131 do {
132 var assoc = table[index];
133 if (null == assoc || assoc.key == key) {
134 return index;
135 }
136 index = (index + 1) & mask;
137 } while (index != start);
138 // Should never happen because we start evicting associations before the
139 // table is full.
140 throw new Exception("Internal error: _AccessorCache table full");
141 }
142
143 int scanForEmpty(String key) {
144 var start = key.hashCode & mask;
145 var index = start;
146 do {
147 if (null == table[index]) {
148 return index;
149 }
150 index = (index + 1) & mask;
151 } while (index != start);
152 // Should never happen because we start evicting associations before the
153 // table is full.
154 throw new Exception("Internal error: _AccessorCache table full");
155 }
156
157 void fixCollisionsAfter(int start) {
158 var assoc;
159 var index = (start + 1) & mask;
160 while (null != (assoc = table[index])) {
161 var newIndex = scanFor(assoc.key);
162 if (newIndex != index) {
163 assert(table[newIndex] == null);
164 table[newIndex] = assoc;
165 table[index] = null;
166 }
167 index = (index + 1) & mask;
168 }
169 }
170
171 void grow() {
172 var oldTable = table;
173
174 initWithShift(shift + 1);
175
176 for (int oldIndex = 0; oldIndex < oldTable.length; oldIndex++) {
177 var assoc = oldTable[oldIndex];
178 if (assoc != null) {
179 var newIndex = scanForEmpty(assoc.key);
180 assoc.usedSinceGrowth = false;
181 table[newIndex] = assoc;
182 }
183 }
184 }
185
186 void tryToShrinkOtherwiseGrow() {
187 // Remove any associations not accessed since the last growth. If we are
188 // unable to free any slots, grow.
189 bool needToGrow = true;
190 for (int i = 0; i < table.length; i++) {
191 var assoc = table[i];
192 if (null != assoc && (!assoc.usedSinceGrowth || null == assoc.value)) {
193 table[i] = null;
194 size--;
195 fixCollisionsAfter(i);
196 needToGrow = false;
197 }
198 }
199 if (needToGrow) grow();
200 }
201
202 operator []=(String key, Function value) {
203 int index = scanFor(key);
204 var assoc = table[index];
205 if (null != assoc) {
206 // Existing key, replace value.
207 assert(assoc.key == key);
208 assoc.value = value;
209 assoc.usedSinceGrowth = true;
210 } else {
211 // New key.
212 var newAssoc = new _AccessorCacheAssociation();
Ivan Posva 2014/08/08 19:09:36 var newAssoc = new _AccessorCacheAssociation(key,
213 if (size == capacity) {
214 // No free slots.
215 tryToShrinkOtherwiseGrow();
216 index = scanFor(key);
217 assert(table[index] == null);
218 }
219 newAssoc.key = key;
220 newAssoc.value = value;
221 newAssoc.usedSinceGrowth = true;
Ivan Posva 2014/08/08 19:09:36 These three lines can be move to the constructor.
222 table[index] = newAssoc;
223 size++;
224 }
225 }
226
227 Function operator [](String key) {
228 var index = scanFor(key);
229 var assoc = table[index];
230 if (null == assoc) return null;
231 assoc.usedSinceGrowth = true;
232 return assoc.value;
233 }
234 }
235
236
93 class _LocalMirrorSystem extends MirrorSystem { 237 class _LocalMirrorSystem extends MirrorSystem {
94 final Map<Uri, LibraryMirror> libraries; 238 final Map<Uri, LibraryMirror> libraries;
95 final IsolateMirror isolate; 239 final IsolateMirror isolate;
96 240
97 _LocalMirrorSystem(List<LibraryMirror> libraries, this.isolate) 241 _LocalMirrorSystem(List<LibraryMirror> libraries, this.isolate)
98 : this.libraries = new Map<Uri, LibraryMirror>.fromIterable( 242 : this.libraries = new Map<Uri, LibraryMirror>.fromIterable(
99 libraries, key: (e) => e.uri); 243 libraries, key: (e) => e.uri);
100 244
101 TypeMirror _dynamicType = null; 245 TypeMirror _dynamicType = null;
102 TypeMirror get dynamicType { 246 TypeMirror get dynamicType {
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after
292 return other is _LocalInstanceMirror && 436 return other is _LocalInstanceMirror &&
293 identical(_reflectee, other._reflectee); 437 identical(_reflectee, other._reflectee);
294 } 438 }
295 439
296 int get hashCode { 440 int get hashCode {
297 // Avoid hash collisions with the reflectee. This constant is in Smi range 441 // Avoid hash collisions with the reflectee. This constant is in Smi range
298 // and happens to be the inner padding from RFC 2104. 442 // and happens to be the inner padding from RFC 2104.
299 return identityHashCode(_reflectee) ^ 0x36363636; 443 return identityHashCode(_reflectee) ^ 0x36363636;
300 } 444 }
301 445
302 static var _getFieldClosures = new LRUMap.withShift(9); 446 static var _getFieldClosures = new _AccessorCache.withInitialShift(4);
303 static var _setFieldClosures = new LRUMap.withShift(9); 447 static var _setFieldClosures = new _AccessorCache.withInitialShift(4);
304 static var _getFieldCallCounts = new LRUMap.withShift(10); 448
305 static var _setFieldCallCounts = new LRUMap.withShift(10); 449 _createGetterClosure(unwrapped) {
306 static const _closureThreshold = 20; 450 var atPosition = unwrapped.indexOf('@');
451 if (atPosition == -1) {
452 // Public symbol.
453 return _eval('(x) => x.$unwrapped', null);
454 } else {
455 // Private symbol.
456 var withoutKey = unwrapped.substring(0, atPosition);
457 var privateKey = unwrapped.substring(atPosition);
458 return _eval('(x) => x.$withoutKey', privateKey);
459 }
460 }
307 461
308 _getFieldSlow(unwrapped) { 462 _getFieldSlow(unwrapped) {
309 // Slow path factored out to give the fast path a better chance at being 463 // Slow path factored out to give the fast path a better chance at being
310 // inlined. 464 // 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)); 465 var result = reflect(_invokeGetter(_reflectee, unwrapped));
333 // Only update call count if we don't throw to avoid creating closures for 466 // Wait until success to avoid creating closures for non-existent getters.
334 // non-existent getters. 467 _getFieldClosures[unwrapped] = (r) {
335 _getFieldCallCounts[unwrapped] = callCount + 1; 468 return (_getFieldClosures[unwrapped] =
469 _createGetterClosure(unwrapped))(r);
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 _setFieldClosures[unwrapped] = (r, v) {
373 _setFieldCallCounts[unwrapped] = callCount + 1; 500 return (_setFieldClosures[unwrapped] =
501 _createSetterClosure(unwrapped))(r, v);
502 };
374 return result; 503 return result;
375 } 504 }
376 505
377 InstanceMirror setField(Symbol memberName, arg) { 506 InstanceMirror setField(Symbol memberName, arg) {
378 var unwrapped = _n(memberName); 507 var unwrapped = _n(memberName);
379 var f = _setFieldClosures[unwrapped]; 508 var f = _setFieldClosures[unwrapped];
380 return (f == null) 509 return (f == null)
381 ? _setFieldSlow(unwrapped, arg) 510 ? _setFieldSlow(unwrapped, arg)
382 : reflect(f(_reflectee, arg)); 511 : reflect(f(_reflectee, arg));
383 } 512 }
(...skipping 1185 matching lines...) Expand 10 before | Expand all | Expand 10 after
1569 if (typeMirror == null) { 1698 if (typeMirror == null) {
1570 typeMirror = makeLocalTypeMirror(key); 1699 typeMirror = makeLocalTypeMirror(key);
1571 _instanitationCache[key] = typeMirror; 1700 _instanitationCache[key] = typeMirror;
1572 if (typeMirror is ClassMirror && !typeMirror._isGeneric) { 1701 if (typeMirror is ClassMirror && !typeMirror._isGeneric) {
1573 _declarationCache[key] = typeMirror; 1702 _declarationCache[key] = typeMirror;
1574 } 1703 }
1575 } 1704 }
1576 return typeMirror; 1705 return typeMirror;
1577 } 1706 }
1578 } 1707 }
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