Index: sdk/lib/_internal/js_runtime/lib/core_patch.dart |
diff --git a/sdk/lib/_internal/js_runtime/lib/core_patch.dart b/sdk/lib/_internal/js_runtime/lib/core_patch.dart |
index dfed0dfa4116521e1ef191569ee08505fb762a42..8a3cc9d17bdb8c9dba3523c1fcdff142b3eafa0e 100644 |
--- a/sdk/lib/_internal/js_runtime/lib/core_patch.dart |
+++ b/sdk/lib/_internal/js_runtime/lib/core_patch.dart |
@@ -106,37 +106,61 @@ class Function { |
// Patch for Expando implementation. |
@patch |
class Expando<T> { |
+ static const String _EXPANDO_PROPERTY_NAME = 'expando\$values'; |
+ |
+ // Incremented to make unique keys. |
+ static int _keyCount = 0; |
+ |
+ // Stores either a JS WeakMap or a "unique" string key. |
+ final Object _jsWeakMapOrKey; |
+ |
@patch |
- Expando([String name]) : this.name = name; |
+ Expando([String name]) |
+ : this.name = name, |
+ _jsWeakMapOrKey = JS('bool', 'typeof WeakMap == "function"') |
+ ? JS('=Object|Null', 'new WeakMap()') |
+ : _createKey(); |
@patch |
T operator[](Object object) { |
- var values = Primitives.getProperty(object, _EXPANDO_PROPERTY_NAME); |
- return (values == null) ? null : Primitives.getProperty(values, _getKey()); |
+ if (_jsWeakMapOrKey is! String) { |
+ _checkType(object); // WeakMap doesn't check on reading, only writing. |
+ return JS('', '#.get(#)', _jsWeakMapOrKey, object); |
+ } |
+ return _getFromObject(_jsWeakMapOrKey, object); |
} |
@patch |
void operator[]=(Object object, T value) { |
+ if (_jsWeakMapOrKey is! String) { |
+ JS('void', '#.set(#, #)', _jsWeakMapOrKey, object, value); |
+ } else { |
+ _setOnObject(_jsWeakMapOrKey, object, value); |
+ } |
+ } |
+ |
+ static Object _getFromObject(String key, Object object) { |
+ var values = Primitives.getProperty(object, _EXPANDO_PROPERTY_NAME); |
+ return (values == null) ? null : Primitives.getProperty(values, key); |
+ } |
+ |
+ static void _setOnObject(String key, Object object, Object value) { |
var values = Primitives.getProperty(object, _EXPANDO_PROPERTY_NAME); |
if (values == null) { |
values = new Object(); |
Primitives.setProperty(object, _EXPANDO_PROPERTY_NAME, values); |
} |
- Primitives.setProperty(values, _getKey(), value); |
+ Primitives.setProperty(values, key, value); |
} |
- String _getKey() { |
- String key = Primitives.getProperty(this, _KEY_PROPERTY_NAME); |
- if (key == null) { |
- key = "expando\$key\$${_keyCount++}"; |
- Primitives.setProperty(this, _KEY_PROPERTY_NAME, key); |
+ static String _createKey() => "expando\$key\$${_keyCount++}"; |
+ |
+ static _checkType(object) { |
+ if (object == null || object is bool || object is num || object is String) { |
+ throw new ArgumentError.value(object, |
+ "Expandos are not allowed on strings, numbers, booleans or null"); |
} |
- return key; |
} |
- |
- static const String _KEY_PROPERTY_NAME = 'expando\$key'; |
- static const String _EXPANDO_PROPERTY_NAME = 'expando\$values'; |
- static int _keyCount = 0; |
} |
@patch |