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(_cacheSizeLimit); |
302 static var _getFieldClosures = new HashMap(); | 303 static var _setFieldClosures = new LRUMap(_cacheSizeLimit); |
303 static var _setFieldClosures = new HashMap(); | 304 static var _getFieldCallCounts = new LRUMap(_cacheSizeLimit*2); |
304 static var _getFieldCallCounts = new HashMap(); | 305 static var _setFieldCallCounts = new LRUMap(_cacheSizeLimit*2); |
305 static var _setFieldCallCounts = new HashMap(); | |
306 static const _closureThreshold = 20; | 306 static const _closureThreshold = 20; |
307 static const _cacheSizeLimit = 255; | 307 static const _cacheSizeLimit = 127; |
308 | 308 |
309 _getFieldSlow(unwrapped) { | 309 _getFieldSlow(unwrapped) { |
310 // 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 |
311 // inlined. | 311 // inlined. |
312 if (_getFieldCallCounts.length == 2 * _cacheSizeLimit) { | |
313 // Prevent unbounded cache growth. | |
314 _getFieldCallCounts = new HashMap(); | |
315 } | |
316 var callCount = _getFieldCallCounts[unwrapped]; | 312 var callCount = _getFieldCallCounts[unwrapped]; |
317 if (callCount == null) { | 313 if (callCount == null) { |
318 callCount = 0; | 314 callCount = 0; |
319 } | 315 } |
320 if (callCount == _closureThreshold) { | 316 if (callCount == _closureThreshold) { |
321 // We've seen a successful setter invocation a few times: time to invest | 317 // We've seen a successful setter invocation a few times: time to invest |
322 // in a closure. | 318 // in a closure. |
323 var f; | 319 var f; |
324 var atPosition = unwrapped.indexOf('@'); | 320 var atPosition = unwrapped.indexOf('@'); |
325 if (atPosition == -1) { | 321 if (atPosition == -1) { |
326 // Public symbol. | 322 // Public symbol. |
327 f = _eval('(x) => x.$unwrapped', null); | 323 f = _eval('(x) => x.$unwrapped', null); |
328 } else { | 324 } else { |
329 // Private symbol. | 325 // Private symbol. |
330 var withoutKey = unwrapped.substring(0, atPosition); | 326 var withoutKey = unwrapped.substring(0, atPosition); |
331 var privateKey = unwrapped.substring(atPosition); | 327 var privateKey = unwrapped.substring(atPosition); |
332 f = _eval('(x) => x.$withoutKey', privateKey); | 328 f = _eval('(x) => x.$withoutKey', privateKey); |
333 } | 329 } |
334 if (_getFieldClosures.length == _cacheSizeLimit) { | |
335 // Prevent unbounded cache growth. | |
336 _getFieldClosures = new HashMap(); | |
337 } | |
338 _getFieldClosures[unwrapped] = f; | 330 _getFieldClosures[unwrapped] = f; |
339 _getFieldCallCounts.remove(unwrapped); // We won't look for this again. | |
340 return reflect(f(_reflectee)); | 331 return reflect(f(_reflectee)); |
341 } | 332 } |
342 var result = reflect(_invokeGetter(_reflectee, unwrapped)); | 333 var result = reflect(_invokeGetter(_reflectee, unwrapped)); |
343 // Only update call count if we don't throw to avoid creating closures for | 334 // Only update call count if we don't throw to avoid creating closures for |
344 // non-existent getters. | 335 // non-existent getters. |
345 _getFieldCallCounts[unwrapped] = callCount + 1; | 336 _getFieldCallCounts[unwrapped] = callCount + 1; |
346 return result; | 337 return result; |
347 } | 338 } |
348 | 339 |
349 InstanceMirror getField(Symbol memberName) { | 340 InstanceMirror getField(Symbol memberName) { |
350 var unwrapped = _n(memberName); | 341 var unwrapped = _n(memberName); |
351 var f = _getFieldClosures[unwrapped]; | 342 var f = _getFieldClosures[unwrapped]; |
352 return (f == null) ? _getFieldSlow(unwrapped) : reflect(f(_reflectee)); | 343 return (f == null) ? _getFieldSlow(unwrapped) : reflect(f(_reflectee)); |
353 } | 344 } |
354 | 345 |
355 _setFieldSlow(unwrapped, arg) { | 346 _setFieldSlow(unwrapped, arg) { |
356 // Slow path factored out to give the fast path a better chance at being | 347 // Slow path factored out to give the fast path a better chance at being |
357 // inlined. | 348 // inlined. |
358 if (_setFieldCallCounts.length == 2 * _cacheSizeLimit) { | |
359 _setFieldCallCounts = new HashMap(); | |
360 } | |
361 var callCount = _setFieldCallCounts[unwrapped]; | 349 var callCount = _setFieldCallCounts[unwrapped]; |
362 if (callCount == null) { | 350 if (callCount == null) { |
363 callCount = 0; | 351 callCount = 0; |
364 } | 352 } |
365 if (callCount == _closureThreshold) { | 353 if (callCount == _closureThreshold) { |
366 // We've seen a successful getter invocation a few times: time to invest | 354 // We've seen a successful getter invocation a few times: time to invest |
367 // in a closure. | 355 // in a closure. |
368 var f; | 356 var f; |
369 var atPosition = unwrapped.indexOf('@'); | 357 var atPosition = unwrapped.indexOf('@'); |
370 if (atPosition == -1) { | 358 if (atPosition == -1) { |
371 // Public symbol. | 359 // Public symbol. |
372 f = _eval('(x, v) => x.$unwrapped = v', null); | 360 f = _eval('(x, v) => x.$unwrapped = v', null); |
373 } else { | 361 } else { |
374 // Private symbol. | 362 // Private symbol. |
375 var withoutKey = unwrapped.substring(0, atPosition); | 363 var withoutKey = unwrapped.substring(0, atPosition); |
376 var privateKey = unwrapped.substring(atPosition); | 364 var privateKey = unwrapped.substring(atPosition); |
377 f = _eval('(x, v) => x.$withoutKey = v', privateKey); | 365 f = _eval('(x, v) => x.$withoutKey = v', privateKey); |
378 } | 366 } |
379 if (_setFieldClosures.length == _cacheSizeLimit) { | |
380 // Prevent unbounded cache growth. | |
381 _setFieldClosures = new HashMap(); | |
382 } | |
383 _setFieldClosures[unwrapped] = f; | 367 _setFieldClosures[unwrapped] = f; |
384 _setFieldCallCounts.remove(unwrapped); | |
385 return reflect(f(_reflectee, arg)); | 368 return reflect(f(_reflectee, arg)); |
386 } | 369 } |
387 _invokeSetter(_reflectee, unwrapped, arg); | 370 _invokeSetter(_reflectee, unwrapped, arg); |
388 var result = reflect(arg); | 371 var result = reflect(arg); |
389 // Only update call count if we don't throw to avoid creating closures for | 372 // Only update call count if we don't throw to avoid creating closures for |
390 // non-existent setters. | 373 // non-existent setters. |
391 _setFieldCallCounts[unwrapped] = callCount + 1; | 374 _setFieldCallCounts[unwrapped] = callCount + 1; |
392 return result; | 375 return result; |
393 } | 376 } |
394 | 377 |
(...skipping 1211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1606 if (typeMirror == null) { | 1589 if (typeMirror == null) { |
1607 typeMirror = makeLocalTypeMirror(key); | 1590 typeMirror = makeLocalTypeMirror(key); |
1608 _instanitationCache[key] = typeMirror; | 1591 _instanitationCache[key] = typeMirror; |
1609 if (typeMirror is ClassMirror && !typeMirror._isGeneric) { | 1592 if (typeMirror is ClassMirror && !typeMirror._isGeneric) { |
1610 _declarationCache[key] = typeMirror; | 1593 _declarationCache[key] = typeMirror; |
1611 } | 1594 } |
1612 } | 1595 } |
1613 return typeMirror; | 1596 return typeMirror; |
1614 } | 1597 } |
1615 } | 1598 } |
OLD | NEW |