| OLD | NEW |
| 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" show UnmodifiableListView, UnmodifiableMapView; |
| 8 import "dart:_internal" show LRUMap; |
| 8 | 9 |
| 9 final emptyList = new UnmodifiableListView([]); | 10 final emptyList = new UnmodifiableListView([]); |
| 10 final emptyMap = new UnmodifiableMapView({}); | 11 final emptyMap = new UnmodifiableMapView({}); |
| 11 | 12 |
| 12 class _InternalMirrorError { | 13 class _InternalMirrorError { |
| 13 final String _msg; | 14 final String _msg; |
| 14 const _InternalMirrorError(String this._msg); | 15 const _InternalMirrorError(String this._msg); |
| 15 String toString() => _msg; | 16 String toString() => _msg; |
| 16 } | 17 } |
| 17 | 18 |
| (...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 291 return other is _LocalInstanceMirror && | 292 return other is _LocalInstanceMirror && |
| 292 identical(_reflectee, other._reflectee); | 293 identical(_reflectee, other._reflectee); |
| 293 } | 294 } |
| 294 | 295 |
| 295 int get hashCode { | 296 int get hashCode { |
| 296 // Avoid hash collisions with the reflectee. This constant is in Smi range | 297 // Avoid hash collisions with the reflectee. This constant is in Smi range |
| 297 // and happens to be the inner padding from RFC 2104. | 298 // and happens to be the inner padding from RFC 2104. |
| 298 return identityHashCode(_reflectee) ^ 0x36363636; | 299 return identityHashCode(_reflectee) ^ 0x36363636; |
| 299 } | 300 } |
| 300 | 301 |
| 301 // TODO(18445): Use an LRU cache. | 302 static var _getFieldClosures = new LRUMap.withShift(7); |
| 302 static var _getFieldClosures = new HashMap(); | 303 static var _setFieldClosures = new LRUMap.withShift(7); |
| 303 static var _setFieldClosures = new HashMap(); | 304 static var _getFieldCallCounts = new LRUMap.withShift(8); |
| 304 static var _getFieldCallCounts = new HashMap(); | 305 static var _setFieldCallCounts = new LRUMap.withShift(8); |
| 305 static var _setFieldCallCounts = new HashMap(); | |
| 306 static const _closureThreshold = 20; | 306 static const _closureThreshold = 20; |
| 307 static const _cacheSizeLimit = 255; | |
| 308 | 307 |
| 309 _getFieldSlow(unwrapped) { | 308 _getFieldSlow(unwrapped) { |
| 310 // Slow path factored out to give the fast path a better chance at being | 309 // Slow path factored out to give the fast path a better chance at being |
| 311 // inlined. | 310 // inlined. |
| 312 if (_getFieldCallCounts.length == 2 * _cacheSizeLimit) { | |
| 313 // Prevent unbounded cache growth. | |
| 314 _getFieldCallCounts = new HashMap(); | |
| 315 } | |
| 316 var callCount = _getFieldCallCounts[unwrapped]; | 311 var callCount = _getFieldCallCounts[unwrapped]; |
| 317 if (callCount == null) { | 312 if (callCount == null) { |
| 318 callCount = 0; | 313 callCount = 0; |
| 319 } | 314 } |
| 320 if (callCount == _closureThreshold) { | 315 if (callCount == _closureThreshold) { |
| 321 // We've seen a successful setter invocation a few times: time to invest | 316 // We've seen a successful setter invocation a few times: time to invest |
| 322 // in a closure. | 317 // in a closure. |
| 323 var f; | 318 var f; |
| 324 var atPosition = unwrapped.indexOf('@'); | 319 var atPosition = unwrapped.indexOf('@'); |
| 325 if (atPosition == -1) { | 320 if (atPosition == -1) { |
| 326 // Public symbol. | 321 // Public symbol. |
| 327 f = _eval('(x) => x.$unwrapped', null); | 322 f = _eval('(x) => x.$unwrapped', null); |
| 328 } else { | 323 } else { |
| 329 // Private symbol. | 324 // Private symbol. |
| 330 var withoutKey = unwrapped.substring(0, atPosition); | 325 var withoutKey = unwrapped.substring(0, atPosition); |
| 331 var privateKey = unwrapped.substring(atPosition); | 326 var privateKey = unwrapped.substring(atPosition); |
| 332 f = _eval('(x) => x.$withoutKey', privateKey); | 327 f = _eval('(x) => x.$withoutKey', privateKey); |
| 333 } | 328 } |
| 334 if (_getFieldClosures.length == _cacheSizeLimit) { | |
| 335 // Prevent unbounded cache growth. | |
| 336 _getFieldClosures = new HashMap(); | |
| 337 } | |
| 338 _getFieldClosures[unwrapped] = f; | 329 _getFieldClosures[unwrapped] = f; |
| 339 _getFieldCallCounts.remove(unwrapped); // We won't look for this again. | |
| 340 return reflect(f(_reflectee)); | 330 return reflect(f(_reflectee)); |
| 341 } | 331 } |
| 342 var result = reflect(_invokeGetter(_reflectee, unwrapped)); | 332 var result = reflect(_invokeGetter(_reflectee, unwrapped)); |
| 343 // Only update call count if we don't throw to avoid creating closures for | 333 // Only update call count if we don't throw to avoid creating closures for |
| 344 // non-existent getters. | 334 // non-existent getters. |
| 345 _getFieldCallCounts[unwrapped] = callCount + 1; | 335 _getFieldCallCounts[unwrapped] = callCount + 1; |
| 346 return result; | 336 return result; |
| 347 } | 337 } |
| 348 | 338 |
| 349 InstanceMirror getField(Symbol memberName) { | 339 InstanceMirror getField(Symbol memberName) { |
| 350 var unwrapped = _n(memberName); | 340 var unwrapped = _n(memberName); |
| 351 var f = _getFieldClosures[unwrapped]; | 341 var f = _getFieldClosures[unwrapped]; |
| 352 return (f == null) ? _getFieldSlow(unwrapped) : reflect(f(_reflectee)); | 342 return (f == null) ? _getFieldSlow(unwrapped) : reflect(f(_reflectee)); |
| 353 } | 343 } |
| 354 | 344 |
| 355 _setFieldSlow(unwrapped, arg) { | 345 _setFieldSlow(unwrapped, arg) { |
| 356 // Slow path factored out to give the fast path a better chance at being | 346 // Slow path factored out to give the fast path a better chance at being |
| 357 // inlined. | 347 // inlined. |
| 358 if (_setFieldCallCounts.length == 2 * _cacheSizeLimit) { | |
| 359 _setFieldCallCounts = new HashMap(); | |
| 360 } | |
| 361 var callCount = _setFieldCallCounts[unwrapped]; | 348 var callCount = _setFieldCallCounts[unwrapped]; |
| 362 if (callCount == null) { | 349 if (callCount == null) { |
| 363 callCount = 0; | 350 callCount = 0; |
| 364 } | 351 } |
| 365 if (callCount == _closureThreshold) { | 352 if (callCount == _closureThreshold) { |
| 366 // We've seen a successful getter invocation a few times: time to invest | 353 // We've seen a successful getter invocation a few times: time to invest |
| 367 // in a closure. | 354 // in a closure. |
| 368 var f; | 355 var f; |
| 369 var atPosition = unwrapped.indexOf('@'); | 356 var atPosition = unwrapped.indexOf('@'); |
| 370 if (atPosition == -1) { | 357 if (atPosition == -1) { |
| 371 // Public symbol. | 358 // Public symbol. |
| 372 f = _eval('(x, v) => x.$unwrapped = v', null); | 359 f = _eval('(x, v) => x.$unwrapped = v', null); |
| 373 } else { | 360 } else { |
| 374 // Private symbol. | 361 // Private symbol. |
| 375 var withoutKey = unwrapped.substring(0, atPosition); | 362 var withoutKey = unwrapped.substring(0, atPosition); |
| 376 var privateKey = unwrapped.substring(atPosition); | 363 var privateKey = unwrapped.substring(atPosition); |
| 377 f = _eval('(x, v) => x.$withoutKey = v', privateKey); | 364 f = _eval('(x, v) => x.$withoutKey = v', privateKey); |
| 378 } | 365 } |
| 379 if (_setFieldClosures.length == _cacheSizeLimit) { | |
| 380 // Prevent unbounded cache growth. | |
| 381 _setFieldClosures = new HashMap(); | |
| 382 } | |
| 383 _setFieldClosures[unwrapped] = f; | 366 _setFieldClosures[unwrapped] = f; |
| 384 _setFieldCallCounts.remove(unwrapped); | |
| 385 return reflect(f(_reflectee, arg)); | 367 return reflect(f(_reflectee, arg)); |
| 386 } | 368 } |
| 387 _invokeSetter(_reflectee, unwrapped, arg); | 369 _invokeSetter(_reflectee, unwrapped, arg); |
| 388 var result = reflect(arg); | 370 var result = reflect(arg); |
| 389 // Only update call count if we don't throw to avoid creating closures for | 371 // Only update call count if we don't throw to avoid creating closures for |
| 390 // non-existent setters. | 372 // non-existent setters. |
| 391 _setFieldCallCounts[unwrapped] = callCount + 1; | 373 _setFieldCallCounts[unwrapped] = callCount + 1; |
| 392 return result; | 374 return result; |
| 393 } | 375 } |
| 394 | 376 |
| (...skipping 1192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1587 if (typeMirror == null) { | 1569 if (typeMirror == null) { |
| 1588 typeMirror = makeLocalTypeMirror(key); | 1570 typeMirror = makeLocalTypeMirror(key); |
| 1589 _instanitationCache[key] = typeMirror; | 1571 _instanitationCache[key] = typeMirror; |
| 1590 if (typeMirror is ClassMirror && !typeMirror._isGeneric) { | 1572 if (typeMirror is ClassMirror && !typeMirror._isGeneric) { |
| 1591 _declarationCache[key] = typeMirror; | 1573 _declarationCache[key] = typeMirror; |
| 1592 } | 1574 } |
| 1593 } | 1575 } |
| 1594 return typeMirror; | 1576 return typeMirror; |
| 1595 } | 1577 } |
| 1596 } | 1578 } |
| OLD | NEW |