-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ffi/js-interop/wasm] Unified API for using dart:ffi and JS Interop with WASM #46690
Comments
Thanks @dcharkes ! The browser case is what I'm especially interested in. I wonder if the codegen for rust typescript bindings could be useful here? It's a somewhat indirect approach (ie targetted code must be wrapped w/ rust first), but might be a way to approach the goal? |
dart-archive/wasm#34 is tracking package:wasm's support for web. No ETA on that, but the more user interest there is, the sooner we'll start working on it. |
I'm fairly interested in getting this right. A few dozen hours of research led me to believe a truly unified ffi might be possible and could bring additional benefits. Here is my imagination of the lifecycle: Packaging and distribution
Building
Running
Before going deeper, I wanted to share this excerpt to find out whether I'm moving in the right direction. @dcharkes @mraleph @mit-mit @askeksa-google would love your thoughts. |
I don't think that's a good way - WASM gives you certain degree of portability, but it abstracts you from the underlying platform and puts your code into a sandbox - meaning that your code can no longer access specific platform features or APIs. This is rather limiting e.g. cryptographic library might contain hand written platform specific assembly for performance and security reasons, or library might be talking to OS specific APIs. Source code (or platform specific binaries) is a much more flexible distribution format for arbitrary libraries than WASM. |
@mraleph thanks.
This can be (partially) resolved by linking with WASI-libc (and WASI polyfills for the web). It won't support OS specific APIs.
Hand-written assembly is a no-go, but most SIMD intrinsics can be ported. I was able to compile the complete dart sdk with all dependencies (boringssl, zlib etc) through emscripten, with simd intrinsics where supported. Unable to run anything, but it compiles.
No doubt. However, in case of pub, distributing binaries is a problem (#36712) and distributing source code means additional compiler dependencies and a wrapping build-runner (https://crates.io/crates/cc). Hence, I was wondering whether a unified wasm+ffi approach might cover a good percentage of use cases to be preferable. |
This project already supports generating dart and js for rust projects [0]. I'd suggest going with compiling flutter/dart to wasm and then linking using the wasm linker is probably a better long term solution. Once flutter/dart compile to wasm I can add support to ffi-gen. For this to work nicely there needs to be a way to link flutter/dart binaries using the system linker as in #47718 |
We have a use case for a unified API for using Ideally, we could make this work for the web as well by compiling the C++ code to WASM, while being able to use the existing There's a very interesting third party approach to do exactly that: https://github.com/EPNW/web_ffi/ Sadly, it has a few (minor) limitations, e.g. no struct returns. But the basic principle is exactly what'd we'd expect it to work like. We can't currently use |
Now that there is experimental support for Wasm as a target in Flutter, I wanted to ask if there is any updates on being able to use FFI from Dart targeted to Wasm. The use case I have in mind is that I have an open source C library (audio synth) that I currently use via FFI in a Flutter app on Linux, MacOS, Android, iOS and would now love to be able to try to target web as well, but currently I don't think there is any support for doing FFI from Dart (running compiled to wasm) to call a C lib also compiled to Wasm. |
I don't know anything about using FFI from Dart that's been compiled to wasm, but I do know about doing audio on the web. I think the limitation you're going to run into is that the only API your library could be wrapping is the Web Audio API, which is pretty high level (you wire up graphs of audio processing nodes to produce effects). There's no low level audio API like on the other OSs (where you just have to fill an audio buffer every N milliseconds) for your C library to wrap. Wasm doesn't give you any access to any APIs other than what the browser provides, so the audio library you're calling would have to have explicit support for wasm via the web audio API. |
@liamappelbe its quite off topic here, but just actually I've spent a bit of time myself looking into WebAudio API and there is in fact functionality in the API to do exactly that: low level, per frame low latency audio generation with audio worklets and a great example of doing so is Peter Salomonsens excellent work which actually already uses assemblyscript compiled to wasm to do exactly that. But as I said, while the above is quite off-topic, its actually possible already right now to have C libs compiled to wasm generate low latency audio via WebAudio. However what I'm asking about is future support for this once Dart's wasm support progresses further and it becomes the preferred deployment target for Flutter webapps, it would be nice to have support for FFI interop. |
Also @liamappelbe I think you might be pulling my leg a bit about not knowing about FFI with Dart Wasm since you literally (co)wrote the article about Darts initial wasm support 👍🏻 with Michael 🙂 and about Webaudio as I've come across your cool work before with https://onlinesequencer.net. |
There's a lot of aspects to Dart/wasm interop, and I only really know about calling into wasm from Dart 🙃 . Calling into FFI from Dart that has been compiled to wasm is sort of the opposite. It's an interesting idea, but would need a lot of implementation work, and AFAIK no one is working on this. |
Actually, we already use However, at this point, it is not clear how we can generalize that to more than one module to interface with. dart2wasm compiles to wasmGC. The FFI is able to interop with a single wasm-non-gc module. More than one wasm-non-gc module would require the multiple linear memory proposal or some way to have multiple memories collaborate with a single linear memory. I don't know the details, but @askeksa-google who is working on dart2wasm will know them. |
@eyebrowsoffire and I had a fruitful discussion yesterday. Our long term vision would be to have There are however a bunch of complications with regards to linear memory when there are two "dylibs" that both have a separate linear memory. Which could be addressed with the wasm multi memory proposal, which is still in flux. (At some point we'll have to come up with an API that allows one to specify which linear memory should be used for pointer loads and stores, possibly using the (The alternative to multi-memory would be having to compile multiple native libraries in one compilation with emscripten, or to compile one of them as the "main" module and the others as non-main. Which would require coordination between the dart packages wrapping those native libraries. This would break composition.) For now, the first step is likely that we will only support The current way to use a single emscripten compiled library in Dart standalone can be found here: https://github.com/dart-lang/sdk/wiki/Dart-GSoC-2024-Project-Ideas#idea-ffigenpad We will likely expose that at some point through the build hook integration with Wasm assets: |
@dcharkes thanks for the update on this! 👍🏻 |
Dart compiled to WASM is targeting WASM-GC not ordinary WASM. GC-ed memory is not the same as linear memory. Ordinary WASM is using linear memory (like C memory), and WASM-GC is using GCed memory (like Java/Kotlin/C#/etc.) |
Thanks @dcharkes ! That makes sense, I didnt realise that WASM-GC meant that there was separate memory apart from that linear memory of the "mvp" WASM. I clearly need to read up a bit more on the WASM-GC to get a better idea of how this works together with the existing WASM spec, thanks again! 👍🏻 |
When developers have native code that lends itself to compilation to WASM, this native code could be used in Dart Web through JS interop.
However, we do not have a unified API for interacting with the same native library on Dart Native through
dart:ffi
, and on Dart Web through JS interop.We envision such native libraries to be used in the following way:
Compile to WASM only for Dart Web, and keep using C dynamic libraries for Dart Native:
JS interop
-> JS <-> WASMdart:ffi
-> C (package:ffigen
can auto-generate bindings)First, it would convenient if we would have a code generator that would generate the JS interop bindings for a package compiled to WASM.
Second, it would be convenient if we had some kind of unified API that could both target
dart:ffi
's types and the generated WASM bindings, if it would be at all possible to have a unified API. The language runtimes of C and Assembly are different, so it might not fully be possible. So this requires exploration.(An alternative approach would be to also combine the C libraries to WASM for Dart Native:
JS interop
-> JS <-> WASMpackage:wasm
-> WASM (package:wasm
internally does: Dart <-dart:ffi
-> C <-Wasmer runtime
-> WASM.)The downsides of this approach is having to ship a WASM runtime such as Wasmer with the Dart Native apps, and it might be slower than just using the native library. The potential upside is that the native library does not have to be cross-compiled.)
Community contributions are welcome.
Filing an issue because we don't have one tracking this yet.
The text was updated successfully, but these errors were encountered: