Background: I maintain a package dealing with Web and native multithreading and recently ported it to Wasm. I've come across various issues especially in terms of type management (how to reenter Dart-land and regain strong types after a payload was sent with postMessage()) but eventually managed to complete the migration. Some articles were very helpful eg. https://github.com/dart-lang/sdk/issues/55203.
Issue: recently, a user reported a bug where they're sending a Map<int, double> to a WASM Web worker, causing the worker to fail with exception message JSString is not a subtype of type num in type cast.
At first, I thought the issue was likely in user-code because I didn't understand why a Map<int, double> payload would cause a problem related to some JSString.
It turns out it's a real issue and Map<int, double> is effectively received by the worker as a Map<Object?, Object?> (that is expected) with values of type double (OK also) but with keys of type JSStringImpl (not OK).
Turns out the keys of a Map<bool, bool> are also received by the worker as JSStringImpl in WASM (String in JS).
Does anyone know whether this is a Dart issue, or by design per postMessage() / structured-clone spec, or maybe due to some browser-specific implementation? Will keys of a map always materialize as Strings or JSStrings after going through postMessage()?
I managed to implement a quick fix for this issue, but it really looks like a hack IMHO. I would like to know if there's a better way to go to ensure key types are preserved, or maybe if this is a bug in Dart's runtime that could be fixed?
Summary: WebAssembly worker receives Map keys as JSStringImpl instead of their original type after using postMessage(), causing type errors. A workaround exists, but a proper solution is needed.
Background: I maintain a package dealing with Web and native multithreading and recently ported it to Wasm. I've come across various issues especially in terms of type management (how to reenter Dart-land and regain strong types after a payload was sent with
postMessage()
) but eventually managed to complete the migration. Some articles were very helpful eg. https://github.com/dart-lang/sdk/issues/55203.Issue: recently, a user reported a bug where they're sending a
Map<int, double>
to a WASM Web worker, causing the worker to fail with exception messageJSString is not a subtype of type num in type cast
.At first, I thought the issue was likely in user-code because I didn't understand why a
Map<int, double>
payload would cause a problem related to someJSString
.It turns out it's a real issue and
Map<int, double>
is effectively received by the worker as aMap<Object?, Object?>
(that is expected) with values of typedouble
(OK also) but with keys of typeJSStringImpl
(not OK).I've implemented a quick test to reproduce --> https://github.com/d-markey/wasm-test
Turns out the keys of a
Map<bool, bool>
are also received by the worker asJSStringImpl
in WASM (String
in JS).Does anyone know whether this is a Dart issue, or by design per
postMessage()
/ structured-clone spec, or maybe due to some browser-specific implementation? Will keys of a map always materialize asString
s orJSString
s after going throughpostMessage()
?I managed to implement a quick fix for this issue, but it really looks like a hack IMHO. I would like to know if there's a better way to go to ensure key types are preserved, or maybe if this is a bug in Dart's runtime that could be fixed?
All comments welcome!