Skip to content

Commit ba07466

Browse files
joshualittCommit Queue
authored and
Commit Queue
committed
[js_interop] Make dartify / jsify a bit more efficient.
CoreLibraryReviewExempt: Minor refactor of the implementation of helpers in `js_util`. Change-Id: I584bd4efbc8f4aff81f3bb62da9029ffdac3eb5f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/287669 Reviewed-by: Srujan Gaddam <[email protected]> Commit-Queue: Joshua Litt <[email protected]>
1 parent c617049 commit ba07466

File tree

6 files changed

+106
-40
lines changed

6 files changed

+106
-40
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@
161161
- Added several helper functions to access more JavaScript operator, like
162162
`delete` and the `typeof` functionality.
163163
- `jsify` is now permissive and has inverse semantics to `dartify`.
164+
- `jsify` and `dartify` both handle types they understand natively more
165+
efficiently.
164166

165167
### Tools
166168

sdk/lib/_internal/js_shared/lib/js_interop_patch.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import 'dart:_foreign_helper' show JS;
66
import 'dart:_internal' show patch;
77
import 'dart:_js_types';
88
import 'dart:js_util';
9-
import 'dart:js_util';
109
import 'dart:typed_data';
1110

1211
/// Helper for working with the [JSAny?] top type in a backend agnostic way.

sdk/lib/_internal/js_shared/lib/js_util_patch.dart

Lines changed: 82 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,49 @@ import 'dart:_js_helper'
88
show convertDartClosureToJS, assertInterop, assertInteropArgs;
99
import 'dart:collection' show HashMap;
1010
import 'dart:async' show Completer;
11+
import 'dart:typed_data';
12+
13+
bool _noJsifyRequired(Object? o) =>
14+
o == null ||
15+
o is bool ||
16+
o is num ||
17+
o is String ||
18+
o is Int8List ||
19+
o is Uint8List ||
20+
o is Uint8ClampedList ||
21+
o is Int16List ||
22+
o is Uint16List ||
23+
o is Int32List ||
24+
o is Uint32List ||
25+
o is Float32List ||
26+
o is Float64List ||
27+
o is ByteBuffer ||
28+
o is ByteData;
1129

1230
@patch
1331
dynamic jsify(Object? object) {
14-
var _convertedObjects = HashMap.identity();
32+
if (_noJsifyRequired(object)) {
33+
return object;
34+
}
35+
final _convertedObjects = HashMap<Object?, Object?>.identity();
1536

1637
Object? _convert(Object? o) {
1738
// Fast path for primitives.
18-
if (o == null || o is bool || o is num || o is String) return o;
39+
if (_noJsifyRequired(o)) {
40+
return o;
41+
}
1942
if (_convertedObjects.containsKey(o)) {
2043
return _convertedObjects[o];
2144
}
22-
if (o is Map) {
45+
if (o is Map<Object?, Object?>) {
2346
final convertedMap = JS('=Object', '{}');
2447
_convertedObjects[o] = convertedMap;
2548
for (var key in o.keys) {
2649
JS('=Object', '#[#]=#', convertedMap, key, _convert(o[key]));
2750
}
2851
return convertedMap;
29-
} else if (o is Iterable) {
30-
var convertedList = [];
52+
} else if (o is Iterable<Object?>) {
53+
final convertedList = [];
3154
_convertedObjects[o] = convertedList;
3255
convertedList.addAll(o.map(_convert));
3356
return convertedList;
@@ -505,14 +528,54 @@ DateTime _dateToDateTime(date) {
505528
return new DateTime.fromMillisecondsSinceEpoch(millisSinceEpoch, isUtc: true);
506529
}
507530

531+
bool _noDartifyRequired(Object? o) =>
532+
o == null ||
533+
JS(
534+
'bool',
535+
'''typeof # === 'boolean' ||
536+
typeof # === 'number' ||
537+
typeof # === 'string' ||
538+
# instanceof Int8Array ||
539+
# instanceof Uint8Array ||
540+
# instanceof Uint8ClampedArray ||
541+
# instanceof Int16Array ||
542+
# instanceof Uint16Array ||
543+
# instanceof Int32Array ||
544+
# instanceof Uint32Array ||
545+
# instanceof Float32Array ||
546+
# instanceof Float64Array ||
547+
# instanceof ArrayBuffer ||
548+
# instanceof DataView''',
549+
o,
550+
o,
551+
o,
552+
o,
553+
o,
554+
o,
555+
o,
556+
o,
557+
o,
558+
o,
559+
o,
560+
o,
561+
o,
562+
o);
563+
508564
@patch
509565
Object? dartify(Object? o) {
510-
var _convertedObjects = HashMap.identity();
566+
if (_noDartifyRequired(o)) {
567+
return o;
568+
}
569+
570+
final _convertedObjects = HashMap<Object?, Object?>.identity();
511571

512572
Object? convert(Object? o) {
513573
// Fast path for primitives.
514-
if (o == null || o is bool || o is num || o is String) return o;
515-
if (_convertedObjects.containsKey(o)) {
574+
if (_noDartifyRequired(o)) {
575+
return o;
576+
}
577+
578+
if (_convertedObjects.containsKey(o!)) {
516579
return _convertedObjects[o];
517580
}
518581

@@ -527,32 +590,32 @@ Object? dartify(Object? o) {
527590
}
528591

529592
if (_isJavaScriptPromise(o)) {
530-
return promiseToFuture(o);
593+
return promiseToFuture<Object?>(o);
531594
}
532595

533596
if (isJavaScriptSimpleObject(o)) {
534-
Map<Object?, Object?> dartObject = {};
597+
final dartObject = <Object?, Object?>{};
535598
_convertedObjects[o] = dartObject;
536-
List<Object?> originalKeys = objectKeys(o);
537-
List<Object?> dartKeys = [];
538-
for (Object? key in originalKeys) {
599+
final originalKeys = objectKeys(o);
600+
final dartKeys = <Object?>[];
601+
for (final key in originalKeys) {
539602
dartKeys.add(dartify(key));
540603
}
541604
for (int i = 0; i < originalKeys.length; i++) {
542-
Object? jsKey = originalKeys[i];
543-
Object? dartKey = dartKeys[i];
605+
final jsKey = originalKeys[i];
606+
final dartKey = dartKeys[i];
544607
if (jsKey != null) {
545-
dartObject[dartKey] = convert(getProperty(o, jsKey));
608+
dartObject[dartKey] = convert(getProperty<Object?>(o, jsKey));
546609
}
547610
}
548611
return dartObject;
549612
}
550613

551614
if (isJavaScriptArray(o)) {
552-
var l = JS<List>('returns:List;creates:;', '#', o);
553-
List<Object?> dartObject = [];
615+
final l = JS<List<Object?>>('returns:List;creates:;', '#', o);
616+
final dartObject = <Object?>[];
554617
_convertedObjects[o] = dartObject;
555-
int length = getProperty(o, 'length');
618+
final length = getProperty<int>(o, 'length');
556619
for (int i = 0; i < length; i++) {
557620
dartObject.add(convert(l[i]));
558621
}

sdk/lib/_internal/wasm/lib/js_helper.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ class JSValue {
2929
JSValue(this._ref);
3030

3131
// This is currently only used in js_util.
32-
// TODO(joshualitt): Investigate migrating `js_util` to js types. It should be
33-
// non-breaking for js backends, and a tractable migration for wasm backends.
32+
// TODO(joshualitt): Remove [box] and [unbox] once `JSNull` is boxed and users
33+
// have been migrated over to the helpers in `dart:js_interop`.
3434
static JSValue? box(WasmExternRef? ref) =>
3535
isDartNull(ref) ? null : JSValue(ref);
3636

sdk/lib/_internal/wasm/lib/js_util_patch.dart

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ import "dart:wasm";
1515

1616
@patch
1717
dynamic jsify(Object? object) {
18-
HashMap<Object?, Object?> convertedObjects =
19-
HashMap<Object?, Object?>.identity();
18+
final convertedObjects = HashMap<Object?, Object?>.identity();
2019
Object? convert(Object? o) {
2120
if (convertedObjects.containsKey(o)) {
2221
return convertedObjects[o];
@@ -25,7 +24,6 @@ dynamic jsify(Object? object) {
2524
if (o == null ||
2625
o is num ||
2726
o is bool ||
28-
o is Function ||
2927
o is JSValue ||
3028
o is String ||
3129
o is Int8List ||
@@ -42,19 +40,19 @@ dynamic jsify(Object? object) {
4240
return JSValue(jsifyRaw(o));
4341
}
4442

45-
if (o is Map) {
46-
JSValue convertedMap = newObject<JSValue>();
43+
if (o is Map<Object?, Object?>) {
44+
final convertedMap = newObject<JSValue>();
4745
convertedObjects[o] = convertedMap;
4846
for (final key in o.keys) {
49-
JSValue? convertedKey = convert(key) as JSValue?;
47+
final convertedKey = convert(key) as JSValue?;
5048
setPropertyRaw(convertedMap.toExternRef(), convertedKey?.toExternRef(),
5149
(convert(o[key]) as JSValue?)?.toExternRef());
5250
}
5351
return convertedMap;
54-
} else if (o is Iterable) {
55-
JSValue convertedIterable = _newArray();
52+
} else if (o is Iterable<Object?>) {
53+
final convertedIterable = _newArray();
5654
convertedObjects[o] = convertedIterable;
57-
for (Object? item in o) {
55+
for (final item in o) {
5856
callMethod(convertedIterable, 'push', [convert(item)]);
5957
}
6058
return convertedIterable;
@@ -188,8 +186,7 @@ List<Object?> objectKeys(Object? o) =>
188186

189187
@patch
190188
Object? dartify(Object? object) {
191-
HashMap<Object?, Object?> convertedObjects =
192-
HashMap<Object?, Object?>.identity();
189+
final convertedObjects = HashMap<Object?, Object?>.identity();
193190
Object? convert(Object? o) {
194191
if (convertedObjects.containsKey(o)) {
195192
return convertedObjects[o];
@@ -198,8 +195,8 @@ Object? dartify(Object? object) {
198195
// Because [List] needs to be shallowly converted across the interop
199196
// boundary, we have to double check for the case where a shallowly
200197
// converted [List] is passed back into [dartify].
201-
if (o is List) {
202-
List<Object?> converted = [];
198+
if (o is List<Object?>) {
199+
final converted = <Object?>[];
203200
for (final item in o) {
204201
converted.add(convert(item));
205202
}
@@ -236,22 +233,22 @@ Object? dartify(Object? object) {
236233
// TODO(joshualitt) handle Date and Promise.
237234

238235
if (isJSSimpleObject(ref)) {
239-
Map<Object?, Object?> dartMap = {};
236+
final dartMap = <Object?, Object?>{};
240237
convertedObjects[o] = dartMap;
241238
// Keys will be a list of Dart [String]s.
242-
List<Object?> keys = objectKeys(o);
239+
final keys = objectKeys(o);
243240
for (int i = 0; i < keys.length; i++) {
244-
Object? key = keys[i];
241+
final key = keys[i];
245242
if (key != null) {
246243
dartMap[key] = convert(
247244
JSValue.box(getPropertyRaw(ref, (key as String).toExternRef())));
248245
}
249246
}
250247
return dartMap;
251248
} else if (isJSArray(ref)) {
252-
List<Object?> dartList = [];
249+
final dartList = <Object?>[];
253250
convertedObjects[o] = dartList;
254-
int length = getProperty<double>(o, 'length').toInt();
251+
final length = getProperty<double>(o, 'length').toInt();
255252
for (int i = 0; i < length; i++) {
256253
dartList.add(convert(JSValue.box(objectReadIndex(ref, i.toDouble()))));
257254
}

sdk/lib/js_interop/js_interop.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,11 @@ extension DoubleToJSNumber on double {
265265
external JSNumber get toJS;
266266
}
267267

268+
/// [num] -> [JSNumber].
269+
extension NumToJSExtension on num {
270+
JSNumber get toJS => DoubleToJSNumber(toDouble()).toJS;
271+
}
272+
268273
/// [JSBoolean] <-> [bool]
269274
extension JSBooleanToBool on JSBoolean {
270275
external bool get toDart;

0 commit comments

Comments
 (0)