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