Skip to content

Commit 75d1366

Browse files
committed
Use WeakMap to support Expando if available.
Retains the existing code as fallback for settings without WeakMap for now. Fixes issue #5144 BUG= http://dartbug.com/5144 [email protected] Review URL: https://codereview.chromium.org/1599393003 .
1 parent cabf28c commit 75d1366

File tree

3 files changed

+48
-23
lines changed

3 files changed

+48
-23
lines changed

runtime/lib/expando_patch.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,8 @@ patch class Expando<T> {
131131
(object is bool) ||
132132
(object is num) ||
133133
(object is String)) {
134-
throw new ArgumentError(object);
134+
throw new ArgumentError.value(object,
135+
"Expandos are not allowed on strings, numbers, booleans or null");
135136
}
136137
}
137138

sdk/lib/_internal/js_runtime/lib/core_patch.dart

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -106,37 +106,61 @@ class Function {
106106
// Patch for Expando implementation.
107107
@patch
108108
class Expando<T> {
109+
static const String _EXPANDO_PROPERTY_NAME = 'expando\$values';
110+
111+
// Incremented to make unique keys.
112+
static int _keyCount = 0;
113+
114+
// Stores either a JS WeakMap or a "unique" string key.
115+
final Object _jsWeakMapOrKey;
116+
109117
@patch
110-
Expando([String name]) : this.name = name;
118+
Expando([String name])
119+
: this.name = name,
120+
_jsWeakMapOrKey = JS('bool', 'typeof WeakMap == "function"')
121+
? JS('=Object|Null', 'new WeakMap()')
122+
: _createKey();
111123

112124
@patch
113125
T operator[](Object object) {
114-
var values = Primitives.getProperty(object, _EXPANDO_PROPERTY_NAME);
115-
return (values == null) ? null : Primitives.getProperty(values, _getKey());
126+
if (_jsWeakMapOrKey is! String) {
127+
_checkType(object); // WeakMap doesn't check on reading, only writing.
128+
return JS('', '#.get(#)', _jsWeakMapOrKey, object);
129+
}
130+
return _getFromObject(_jsWeakMapOrKey, object);
116131
}
117132

118133
@patch
119134
void operator[]=(Object object, T value) {
135+
if (_jsWeakMapOrKey is! String) {
136+
JS('void', '#.set(#, #)', _jsWeakMapOrKey, object, value);
137+
} else {
138+
_setOnObject(_jsWeakMapOrKey, object, value);
139+
}
140+
}
141+
142+
static Object _getFromObject(String key, Object object) {
143+
var values = Primitives.getProperty(object, _EXPANDO_PROPERTY_NAME);
144+
return (values == null) ? null : Primitives.getProperty(values, key);
145+
}
146+
147+
static void _setOnObject(String key, Object object, Object value) {
120148
var values = Primitives.getProperty(object, _EXPANDO_PROPERTY_NAME);
121149
if (values == null) {
122150
values = new Object();
123151
Primitives.setProperty(object, _EXPANDO_PROPERTY_NAME, values);
124152
}
125-
Primitives.setProperty(values, _getKey(), value);
153+
Primitives.setProperty(values, key, value);
126154
}
127155

128-
String _getKey() {
129-
String key = Primitives.getProperty(this, _KEY_PROPERTY_NAME);
130-
if (key == null) {
131-
key = "expando\$key\$${_keyCount++}";
132-
Primitives.setProperty(this, _KEY_PROPERTY_NAME, key);
156+
static String _createKey() => "expando\$key\$${_keyCount++}";
157+
158+
static _checkType(object) {
159+
if (object == null || object is bool || object is num || object is String) {
160+
throw new ArgumentError.value(object,
161+
"Expandos are not allowed on strings, numbers, booleans or null");
133162
}
134-
return key;
135163
}
136-
137-
static const String _KEY_PROPERTY_NAME = 'expando\$key';
138-
static const String _EXPANDO_PROPERTY_NAME = 'expando\$values';
139-
static int _keyCount = 0;
140164
}
141165

142166
@patch

tests/corelib/expando_test.dart

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class ExpandoTest {
1818
testUnnamedExpando(object);
1919
}
2020
for (var object in legal) {
21-
Expect.equals(2, visits[object]);
21+
Expect.equals(2, visits[object], "$object");
2222
}
2323
testIllegal();
2424
testIdentity();
@@ -65,19 +65,19 @@ class ExpandoTest {
6565
static testIllegal() {
6666
Expando<int> expando = new Expando<int>();
6767
Expect.throws(() => expando[null], (exception)
68-
=> exception is ArgumentError);
68+
=> exception is ArgumentError, "null");
6969
Expect.throws(() => expando['string'], (exception)
70-
=> exception is ArgumentError);
70+
=> exception is ArgumentError, "'string'");
7171
Expect.throws(() => expando['string'], (exception)
72-
=> exception is ArgumentError);
72+
=> exception is ArgumentError, "'string'");
7373
Expect.throws(() => expando[42], (exception)
74-
=> exception is ArgumentError);
74+
=> exception is ArgumentError, "42");
7575
Expect.throws(() => expando[42.87], (exception)
76-
=> exception is ArgumentError);
76+
=> exception is ArgumentError, "42.87");
7777
Expect.throws(() => expando[true], (exception)
78-
=> exception is ArgumentError);
78+
=> exception is ArgumentError, "true");
7979
Expect.throws(() => expando[false], (exception)
80-
=> exception is ArgumentError);
80+
=> exception is ArgumentError, "false");
8181
}
8282

8383
static testIdentity() {

0 commit comments

Comments
 (0)