-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Description
import 'dart:js_interop';
@JS()
external String getString();
void main() {
final string = getString();
}Currently we generate this for getString:
(func $getString (;798;) (result (ref $Object))
call $dart2wasm._311 (import)
ref.null none
call $dartifyRaw
call $<obj> as String
return)dartifyRaw is a large function that considers all kinds of cases that will all result in an error:
sdk/sdk/lib/_internal/wasm/lib/js_helper.dart
Lines 461 to 493 in e87c93b
| Object? dartifyRaw(WasmExternRef? ref, [int? refType]) { | |
| refType ??= externRefType(ref); | |
| return switch (refType) { | |
| ExternRefType.null_ || ExternRefType.undefined => null, | |
| ExternRefType.boolean => toDartBool(ref), | |
| ExternRefType.number => toDartNumber(ref), | |
| ExternRefType.string => JSStringImpl.box(ref), | |
| ExternRefType.array => toDartList(ref), | |
| ExternRefType.int8Array => js_types.JSInt8ArrayImpl.fromJSArray(ref), | |
| ExternRefType.uint8Array => js_types.JSUint8ArrayImpl.fromJSArray(ref), | |
| ExternRefType.uint8ClampedArray => js_types | |
| .JSUint8ClampedArrayImpl.fromJSArray(ref), | |
| ExternRefType.int16Array => js_types.JSInt16ArrayImpl.fromJSArray(ref), | |
| ExternRefType.uint16Array => js_types.JSUint16ArrayImpl.fromJSArray(ref), | |
| ExternRefType.int32Array => js_types.JSInt32ArrayImpl.fromJSArray(ref), | |
| ExternRefType.uint32Array => js_types.JSUint32ArrayImpl.fromJSArray(ref), | |
| ExternRefType.float32Array => js_types.JSFloat32ArrayImpl.fromJSArray(ref), | |
| ExternRefType.float64Array => js_types.JSFloat64ArrayImpl.fromJSArray(ref), | |
| ExternRefType.arrayBuffer => js_types.JSArrayBufferImpl.fromRef(ref), | |
| ExternRefType.dataView => js_types.JSDataViewImpl.fromRef(ref), | |
| ExternRefType.unknown => | |
| isJSWrappedDartFunction(ref) | |
| ? unwrapJSWrappedDartFunction(ref) | |
| : isWasmGCStruct(ref) | |
| ? jsObjectToDartObject(ref) | |
| : JSValue(ref), | |
| _ => () { | |
| // Assert that we've handled everything in the range. | |
| assert(refType! >= 0 && refType >= ExternRefType.unknown); | |
| throw 'Unhandled dartifyRaw type case: $refType'; | |
| }(), | |
| }; | |
| } |
Instead of dartifyRaw, we could generate a dartifyString (or similar) that will only consider the string case, with improved type signature: (not tested)
JSStringImpl? dartifyString(WasmExternRef? ref) {
refType ??= externRefType(ref);
return switch (refType) {
ExternRefType.string => JSStringImpl.box(ref),
_ => null,
}
}This function is smaller and more efficient in the failing case. In the successful case it doesn't require a type test and ref.cast. It can be easily inlined as it's small, and inlining would allow follow-up optimizations when we do something like:
final s = getString();
final len = s.length;Where inlining getString and length both would avoid boxing the externref in JStringImpl.
We should consider doing the same for all of the types that are allowed in js_interop.