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

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

Issue 241703002: Prevent unbounded growth of the getField/setField closure caches. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: document test purpose and need for LRU cache Created 6 years, 8 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 | « no previous file | tests/lib/mirrors/accessor_cache_overflow_test.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"; 7 import "dart:collection";
8 8
9 final emptyList = new UnmodifiableListView([]); 9 final emptyList = new UnmodifiableListView([]);
10 final emptyMap = new UnmodifiableMapView({}); 10 final emptyMap = new UnmodifiableMapView({});
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after
291 return other is _LocalInstanceMirror && 291 return other is _LocalInstanceMirror &&
292 identical(_reflectee, other._reflectee); 292 identical(_reflectee, other._reflectee);
293 } 293 }
294 294
295 int get hashCode { 295 int get hashCode {
296 // Avoid hash collisions with the reflectee. This constant is in Smi range 296 // Avoid hash collisions with the reflectee. This constant is in Smi range
297 // and happens to be the inner padding from RFC 2104. 297 // and happens to be the inner padding from RFC 2104.
298 return identityHashCode(_reflectee) ^ 0x36363636; 298 return identityHashCode(_reflectee) ^ 0x36363636;
299 } 299 }
300 300
301 // TODO(16539): Make these weak or soft. 301 // TODO(18445): Use an LRU cache.
302 static var _getFieldClosures = new HashMap(); 302 static var _getFieldClosures = new HashMap();
303 static var _setFieldClosures = new HashMap(); 303 static var _setFieldClosures = new HashMap();
304 static var _getFieldCallCounts = new HashMap(); 304 static var _getFieldCallCounts = new HashMap();
305 static var _setFieldCallCounts = new HashMap(); 305 static var _setFieldCallCounts = new HashMap();
306 static const _closureThreshold = 20; 306 static const _closureThreshold = 20;
307 static const _cacheSizeLimit = 255;
307 308
308 _getFieldSlow(unwrapped) { 309 _getFieldSlow(unwrapped) {
309 // Slow path factored out to give the fast path a better chance at being 310 // Slow path factored out to give the fast path a better chance at being
310 // inlined. 311 // inlined.
312 if (_getFieldCallCounts.length == 2 * _cacheSizeLimit) {
313 // Prevent unbounded cache growth.
314 _getFieldCallCounts = new HashMap();
315 }
311 var callCount = _getFieldCallCounts[unwrapped]; 316 var callCount = _getFieldCallCounts[unwrapped];
312 if (callCount == null) { 317 if (callCount == null) {
313 callCount = 0; 318 callCount = 0;
314 } 319 }
315 if (callCount == _closureThreshold) { 320 if (callCount == _closureThreshold) {
316 // We've seen a success getter invocation a few times: time to invest in a 321 // We've seen a successful setter invocation a few times: time to invest
317 // closure. 322 // in a closure.
318 var f; 323 var f;
319 var atPosition = unwrapped.indexOf('@'); 324 var atPosition = unwrapped.indexOf('@');
320 if (atPosition == -1) { 325 if (atPosition == -1) {
321 // Public symbol. 326 // Public symbol.
322 f = _eval('(x) => x.$unwrapped', null); 327 f = _eval('(x) => x.$unwrapped', null);
323 } else { 328 } else {
324 // Private symbol. 329 // Private symbol.
325 var withoutKey = unwrapped.substring(0, atPosition); 330 var withoutKey = unwrapped.substring(0, atPosition);
326 var privateKey = unwrapped.substring(atPosition); 331 var privateKey = unwrapped.substring(atPosition);
327 f = _eval('(x) => x.$withoutKey', privateKey); 332 f = _eval('(x) => x.$withoutKey', privateKey);
328 } 333 }
334 if (_getFieldClosures.length == _cacheSizeLimit) {
335 // Prevent unbounded cache growth.
336 _getFieldClosures = new HashMap();
337 }
329 _getFieldClosures[unwrapped] = f; 338 _getFieldClosures[unwrapped] = f;
330 _getFieldCallCounts.remove(unwrapped); // We won't look for this again. 339 _getFieldCallCounts.remove(unwrapped); // We won't look for this again.
331 return reflect(f(_reflectee)); 340 return reflect(f(_reflectee));
332 } 341 }
333 var result = reflect(_invokeGetter(_reflectee, unwrapped)); 342 var result = reflect(_invokeGetter(_reflectee, unwrapped));
334 // Only update call count if we don't throw to avoid creating closures for 343 // Only update call count if we don't throw to avoid creating closures for
335 // non-existent getters. 344 // non-existent getters.
336 _getFieldCallCounts[unwrapped] = callCount + 1; 345 _getFieldCallCounts[unwrapped] = callCount + 1;
337 return result; 346 return result;
338 } 347 }
339 348
340 InstanceMirror getField(Symbol memberName) { 349 InstanceMirror getField(Symbol memberName) {
341 var unwrapped = _n(memberName); 350 var unwrapped = _n(memberName);
342 var f = _getFieldClosures[unwrapped]; 351 var f = _getFieldClosures[unwrapped];
343 return (f == null) ? _getFieldSlow(unwrapped) : reflect(f(_reflectee)); 352 return (f == null) ? _getFieldSlow(unwrapped) : reflect(f(_reflectee));
344 } 353 }
345 354
346 _setFieldSlow(unwrapped, arg) { 355 _setFieldSlow(unwrapped, arg) {
347 // Slow path factored out to give the fast path a better chance at being 356 // Slow path factored out to give the fast path a better chance at being
348 // inlined. 357 // inlined.
358 if (_setFieldCallCounts.length == 2 * _cacheSizeLimit) {
359 _setFieldCallCounts = new HashMap();
360 }
349 var callCount = _setFieldCallCounts[unwrapped]; 361 var callCount = _setFieldCallCounts[unwrapped];
350 if (callCount == null) { 362 if (callCount == null) {
351 callCount = 0; 363 callCount = 0;
352 } 364 }
353 if (callCount == _closureThreshold) { 365 if (callCount == _closureThreshold) {
354 // We've seen a success getter invocation a few times: time to invest in a 366 // We've seen a successful getter invocation a few times: time to invest
355 // closure. 367 // in a closure.
356 var f; 368 var f;
357 var atPosition = unwrapped.indexOf('@'); 369 var atPosition = unwrapped.indexOf('@');
358 if (atPosition == -1) { 370 if (atPosition == -1) {
359 // Public symbol. 371 // Public symbol.
360 f = _eval('(x, v) => x.$unwrapped = v', null); 372 f = _eval('(x, v) => x.$unwrapped = v', null);
361 } else { 373 } else {
362 // Private symbol. 374 // Private symbol.
363 var withoutKey = unwrapped.substring(0, atPosition); 375 var withoutKey = unwrapped.substring(0, atPosition);
364 var privateKey = unwrapped.substring(atPosition); 376 var privateKey = unwrapped.substring(atPosition);
365 f = _eval('(x, v) => x.$withoutKey = v', privateKey); 377 f = _eval('(x, v) => x.$withoutKey = v', privateKey);
366 } 378 }
379 if (_setFieldClosures.length == _cacheSizeLimit) {
380 // Prevent unbounded cache growth.
381 _setFieldClosures = new HashMap();
382 }
367 _setFieldClosures[unwrapped] = f; 383 _setFieldClosures[unwrapped] = f;
368 _setFieldCallCounts.remove(unwrapped); 384 _setFieldCallCounts.remove(unwrapped);
369 return reflect(f(_reflectee, arg)); 385 return reflect(f(_reflectee, arg));
370 } 386 }
371 _invokeSetter(_reflectee, unwrapped, arg); 387 _invokeSetter(_reflectee, unwrapped, arg);
372 var result = reflect(arg); 388 var result = reflect(arg);
373 // Only update call count if we don't throw to avoid creating closures for 389 // Only update call count if we don't throw to avoid creating closures for
374 // non-existent setters. 390 // non-existent setters.
375 _setFieldCallCounts[unwrapped] = callCount + 1; 391 _setFieldCallCounts[unwrapped] = callCount + 1;
376 return result; 392 return result;
(...skipping 1215 matching lines...) Expand 10 before | Expand all | Expand 10 after
1592 if (typeMirror == null) { 1608 if (typeMirror == null) {
1593 typeMirror = makeLocalTypeMirror(key); 1609 typeMirror = makeLocalTypeMirror(key);
1594 _instanitationCache[key] = typeMirror; 1610 _instanitationCache[key] = typeMirror;
1595 if (typeMirror is ClassMirror && !typeMirror._isGeneric) { 1611 if (typeMirror is ClassMirror && !typeMirror._isGeneric) {
1596 _declarationCache[key] = typeMirror; 1612 _declarationCache[key] = typeMirror;
1597 } 1613 }
1598 } 1614 }
1599 return typeMirror; 1615 return typeMirror;
1600 } 1616 }
1601 } 1617 }
OLDNEW
« no previous file with comments | « no previous file | tests/lib/mirrors/accessor_cache_overflow_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698