dart-lang / sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
10.31k stars 1.59k forks source link

[dart2wasm] Support non-JS wasm runtimes #53884

Open eyebrowsoffire opened 1 year ago

eyebrowsoffire commented 1 year ago

We eventually may want dart2wasm to actually work in non-JavaScript environments (wasmtime, wasmer, etc). @askeksa had mentioned a list of a few things that would definitly need to be addressed in order to remove the dependency on a JS/browser environment:

We are currently dependent on JS for the following components:

  • Event loop
  • Printing
  • OS-level timer features, such as current time
  • Weak maps, weak references, finalizers
  • Stack traces
  • Conversions between double and String
  • Regexps
  • Math functions (sin, pow, exp, etc.)

For each of these, we'll have to either:

  • (1) implement the feature in Dart (or intrinsically in the compiler),
  • (2) link to an implementation compiled to Wasm, or
  • (3) import an external implementation from the host.
kripken commented 1 year ago

Can existing JS solutions for those environments help here? That is, Javy and spidermonkey.wasm and similar projects compile a JS VM into wasm, so it can run in a non-JS wasm environment. If that JS happens to use wasm, it seems like that wasm could be bundled alongside the compiled JS VM, and "just work" with some glue (e.g. spidermonkey already has wasm support; it would just need to be "pointed" to the bundled wasm rather than to interpret it).

The wasm would run at full speed, and the JS is apparently fast enough for those environments, so this seems viable. Perhaps someone has already done it?

If that existed, then dart2wasm and other toolchains would not need to do any special work to port to non-JS environments (no more than people wanting to run JS there, which is considered a solved problem).

edit: stack traces would not fully work, but all the other bullet points above should be fine (math, regexes, etc., are all in the compiled JS VM).

eyebrowsoffire commented 1 year ago

Yeah I contemplated something like the spidermonkey.wasm might be an interesting idea. Off-hand, it might be even more effective for WasmGC modules with a thin JS support runtime attached, rather than a large blob of JS. I don't know what kind of optimizations are done for the JS VM snapshot build, but a "whole world analysis" on the JS support runtime could probably lead to pruning a lot of code out of the JS VM.

yjbanov commented 1 year ago
askeksa commented 1 year ago

Stack traces could be a good candidate for (5), since it will be difficult to do without support from the engine.

lesnitsky commented 11 months ago

Add the feature as a standard to either Wasm or WASI

@yjbanov does this remark mean that Dart will support WASI as a compilation target?

zacharypuulsedev commented 10 months ago

This would be amazing to support better serverless, and general flexible compute, using Dart.

Being able to easily deploy dart applications that are a collection of WASM modules would be revolutionary. Dart is a great language for glueing together libraries quickly, and leveraging existing libraries across languages (esp. rust) that can be compiled to WASM would expand the ecosystem so tremendously.

While this is already possible with https://pub.dev/packages/wasm_run, it would be great to further the interoperability and deployment process. This would be especially useful when trying to deploy cross platform applications that currently use FFI and native compiled libraries for each supported platform. In the highest performance applications, FFI and native code may still be desirable, but for a vast majority of applications, the ease of quickly composing applications and innovating has huge value.

Advantages

Implementation:

  1. SpiderMonkey.wasm (mentioned above seems like a great start)
  2. Use rust crates to implement missing functionality; Either compile with binary, or link via WASM modules if the wasm module boundary doesn't have too high of a performance penalty.
  3. Upstream support into WASM/WASI spec for managed languages (Go, Python, Typescript, etc..)

--

Regardless of approach taken, facilitating the deployment of applications that are collections of Wasm modules seems like the natural evolution of docker containerization, with even greater platform flexibility, and a higher degree of composability into ever larger applications or pipelines (eg. langchains, llms, sandboxed user code, etc)

bivens-dev commented 6 months ago

I saw some mention of SpiderMonkey from @yjbanov and others. I was wondering if this offshoot helps move things any closer as a possibility at all.

StarlingMonkey is a SpiderMonkey based JS runtime optimized for use in WebAssembly Components. StarlingMonkey's core builtins target WASI 0.2.0 to support a Component Model based event loop and standards-compliant implementations of key web builtins, including the fetch API, WHATWG Streams, text encoding, and others. To support tailoring for specific use cases, it's designed to be highly modular, and can be readily extended with custom builtins and host APIs.

source: https://github.com/bytecodealliance/StarlingMonkey

iapicca commented 6 months ago

I saw some mention of SpiderMonkey from @yjbanov and others. I was wondering if this offshoot helps move things any closer as a possibility at all.

StarlingMonkey is a SpiderMonkey based JS runtime optimized for use in WebAssembly Components. StarlingMonkey's core builtins target WASI 0.2.0 to support a Component Model based event loop and standards-compliant implementations of key web builtins, including the fetch API, WHATWG Streams, text encoding, and others. To support tailoring for specific use cases, it's designed to be highly modular, and can be readily extended with custom builtins and host APIs.

source: https://github.com/bytecodealliance/StarlingMonkey

is there a way to use dart2JS to compile a non-web target? it would be very useful to use dart in fermyon

maks commented 6 months ago

Yes 💯 @iapicca I have just run into an almost identical use case myself. For my product, I need to compile Dart to JS to run in a embedded JS engine, initially I'm targeting Duktape. I was actually trying to use the DDC for this but the removal of the ability to use it directly via the dart cli command in favour of webserve is very annoying and the best I've found so far is to use --no-release with the build command.

I'm very open to even some pointers from the Dart team about where to go look for underlying Dart compiler APIs thar could used as ideally I want to be able to just compile sets of stand alone functions from one or several Dart libraries (ie. files) and not use a main() entry point at all.

sigmundch commented 6 months ago

Yes, Dart supports running the JS generated from Dart in JavaScript engines outside browsers. We use this for testing, some teams use it to run Dart applications in node.js too. Some details:

compiler We don't recommend using the DDC compiler for that. Our recommended approach to use dart2js via dart compile js --server-mode. The --server-mode flag makes browser based libraries like dart:html inaccessible and allows you to use the output of dart2js more easily in those environments. Technically the flag is not required, but it's good practice.

preambles Code generated by the compiler requires a couple APIs to be available from the engine (imagine APIs like setTimeout, critical to schedule microtasks and other low-level features in Dart). Some of these APIs are usually found in browsers, but may need to be polyfilled for standalone engines.

For that purpose we require a "preamble" file that is customized for the engine that you will be using. We already provide preambles in the Dart SDK for two common engines js-shell and d8. The community currently maintains a preamble for node.js in package:node_preamble.

examples sass is written in Dart but runs in node.js and is distributed as a npm package. It is a great example that uses node_preamble.

Our team wrote the generator of package:web to run in node. This program needed very little from the Dart language, so we ended up creating a custom and over-simplified preamble for it. It may not be the best example of a preamble, but it illustrates how it all gets integrated together.

maks commented 6 months ago

Thanks so much for all that information @sigmundch ! 👍🏻 to say that it is super useful is an understatement!

I didn't know about --server-mode, thats very helpful too. Nor about the preambles, again very useful!

yanglaolee commented 6 months ago

We need to run Flutter/Dart code directly on WASI, this is the future. I prefer method (1)

It has broad application scenarios in the blockchain field. We use wasmer as the smart contract engine of the blockchain. Currently, the assets it manages are billions of dollars.

Once Flutter supports compilation to WASI, we can develop a unified front-end on any device, and the underlying layer is your assets protected by the blockchain.

Can we implement this feature as soon as possible?