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