Skip to content

JS calls with js_interop could be improved based on the expected typeΒ #59683

@osa1

Description

@osa1
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:

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-dart2wasmIssues for the dart2wasm compiler.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions