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" show UnmodifiableListView, UnmodifiableMapView; | 7 import "dart:collection"; |
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 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
292 return other is _LocalInstanceMirror && | 291 return other is _LocalInstanceMirror && |
293 identical(_reflectee, other._reflectee); | 292 identical(_reflectee, other._reflectee); |
294 } | 293 } |
295 | 294 |
296 int get hashCode { | 295 int get hashCode { |
297 // 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 |
298 // and happens to be the inner padding from RFC 2104. | 297 // and happens to be the inner padding from RFC 2104. |
299 return identityHashCode(_reflectee) ^ 0x36363636; | 298 return identityHashCode(_reflectee) ^ 0x36363636; |
300 } | 299 } |
301 | 300 |
302 static var _getFieldClosures = new LRUMap.withShift(7); | 301 // TODO(18445): Use an LRU cache. |
303 static var _setFieldClosures = new LRUMap.withShift(7); | 302 static var _getFieldClosures = new HashMap(); |
304 static var _getFieldCallCounts = new LRUMap.withShift(8); | 303 static var _setFieldClosures = new HashMap(); |
305 static var _setFieldCallCounts = new LRUMap.withShift(8); | 304 static var _getFieldCallCounts = 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 successful setter invocation a few times: time to invest | 321 // We've seen a successful setter invocation a few times: time to invest |
317 // in a 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; |
| 339 _getFieldCallCounts.remove(unwrapped); // We won't look for this again. |
330 return reflect(f(_reflectee)); | 340 return reflect(f(_reflectee)); |
331 } | 341 } |
332 var result = reflect(_invokeGetter(_reflectee, unwrapped)); | 342 var result = reflect(_invokeGetter(_reflectee, unwrapped)); |
333 // 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 |
334 // non-existent getters. | 344 // non-existent getters. |
335 _getFieldCallCounts[unwrapped] = callCount + 1; | 345 _getFieldCallCounts[unwrapped] = callCount + 1; |
336 return result; | 346 return result; |
337 } | 347 } |
338 | 348 |
339 InstanceMirror getField(Symbol memberName) { | 349 InstanceMirror getField(Symbol memberName) { |
340 var unwrapped = _n(memberName); | 350 var unwrapped = _n(memberName); |
341 var f = _getFieldClosures[unwrapped]; | 351 var f = _getFieldClosures[unwrapped]; |
342 return (f == null) ? _getFieldSlow(unwrapped) : reflect(f(_reflectee)); | 352 return (f == null) ? _getFieldSlow(unwrapped) : reflect(f(_reflectee)); |
343 } | 353 } |
344 | 354 |
345 _setFieldSlow(unwrapped, arg) { | 355 _setFieldSlow(unwrapped, arg) { |
346 // 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 |
347 // inlined. | 357 // inlined. |
| 358 if (_setFieldCallCounts.length == 2 * _cacheSizeLimit) { |
| 359 _setFieldCallCounts = new HashMap(); |
| 360 } |
348 var callCount = _setFieldCallCounts[unwrapped]; | 361 var callCount = _setFieldCallCounts[unwrapped]; |
349 if (callCount == null) { | 362 if (callCount == null) { |
350 callCount = 0; | 363 callCount = 0; |
351 } | 364 } |
352 if (callCount == _closureThreshold) { | 365 if (callCount == _closureThreshold) { |
353 // We've seen a successful getter invocation a few times: time to invest | 366 // We've seen a successful getter invocation a few times: time to invest |
354 // in a closure. | 367 // in a closure. |
355 var f; | 368 var f; |
356 var atPosition = unwrapped.indexOf('@'); | 369 var atPosition = unwrapped.indexOf('@'); |
357 if (atPosition == -1) { | 370 if (atPosition == -1) { |
358 // Public symbol. | 371 // Public symbol. |
359 f = _eval('(x, v) => x.$unwrapped = v', null); | 372 f = _eval('(x, v) => x.$unwrapped = v', null); |
360 } else { | 373 } else { |
361 // Private symbol. | 374 // Private symbol. |
362 var withoutKey = unwrapped.substring(0, atPosition); | 375 var withoutKey = unwrapped.substring(0, atPosition); |
363 var privateKey = unwrapped.substring(atPosition); | 376 var privateKey = unwrapped.substring(atPosition); |
364 f = _eval('(x, v) => x.$withoutKey = v', privateKey); | 377 f = _eval('(x, v) => x.$withoutKey = v', privateKey); |
365 } | 378 } |
| 379 if (_setFieldClosures.length == _cacheSizeLimit) { |
| 380 // Prevent unbounded cache growth. |
| 381 _setFieldClosures = new HashMap(); |
| 382 } |
366 _setFieldClosures[unwrapped] = f; | 383 _setFieldClosures[unwrapped] = f; |
| 384 _setFieldCallCounts.remove(unwrapped); |
367 return reflect(f(_reflectee, arg)); | 385 return reflect(f(_reflectee, arg)); |
368 } | 386 } |
369 _invokeSetter(_reflectee, unwrapped, arg); | 387 _invokeSetter(_reflectee, unwrapped, arg); |
370 var result = reflect(arg); | 388 var result = reflect(arg); |
371 // 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 |
372 // non-existent setters. | 390 // non-existent setters. |
373 _setFieldCallCounts[unwrapped] = callCount + 1; | 391 _setFieldCallCounts[unwrapped] = callCount + 1; |
374 return result; | 392 return result; |
375 } | 393 } |
376 | 394 |
(...skipping 1192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1569 if (typeMirror == null) { | 1587 if (typeMirror == null) { |
1570 typeMirror = makeLocalTypeMirror(key); | 1588 typeMirror = makeLocalTypeMirror(key); |
1571 _instanitationCache[key] = typeMirror; | 1589 _instanitationCache[key] = typeMirror; |
1572 if (typeMirror is ClassMirror && !typeMirror._isGeneric) { | 1590 if (typeMirror is ClassMirror && !typeMirror._isGeneric) { |
1573 _declarationCache[key] = typeMirror; | 1591 _declarationCache[key] = typeMirror; |
1574 } | 1592 } |
1575 } | 1593 } |
1576 return typeMirror; | 1594 return typeMirror; |
1577 } | 1595 } |
1578 } | 1596 } |
OLD | NEW |