From b4cfeb109376479b12bbc9d1ba5411680c4433d4 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Thu, 19 Mar 2026 01:25:57 -0700 Subject: [PATCH] dart2wasm: Prepare standalone target When compiled to WebAssembly, the Dart SDK needs access to external host functions to implement regular expressions, stack traces, timers and more. Currently, `dart2wasm` relies on `js_interop` definition to implement these functions in JavaScript. As discussed in https://github.com/dart-lang/sdk/issues/53884, an alternative is to use `wasm:import` annotations to let an arbitrary embedder that doesn't necessarily run in a JavaScript context inject implementations for these host functions. This would allow running `dart2wasm` apps by e.g. - using a runtime like wasmtime and defining host functions in Rust. - defining a wrapper module implementing required functions by delegating to WASI definitions, and then using say `wasm-merge` to run the app in any WASI-compatible runtime. This prepares the `--standalone` flag on `dart2wasm` to do just that. When enabled, the compiler uses a different SDK platform to use imports instead of JS interop. For now, these platforms are almost identical: I've ported the timer logic to use wasm imports as a demo, but the rest is still based on existing patch files. We can revisit in subsequent CLs to incrementally reduce `js_interop` dependencies before removing that library from the `dart2wasm_standalone` target entirely. Change-Id: I3f406afbf2dab65506094de5c3f4067f4db66f3e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/486380 Reviewed-by: Slava Egorov Reviewed-by: Martin Kustermann Commit-Queue: Martin Kustermann --- BUILD.gn | 1 + pkg/dart2wasm/lib/compile.dart | 2 + pkg/dart2wasm/lib/dart2wasm.dart | 4 + pkg/dart2wasm/lib/target.dart | 7 +- pkg/dart2wasm/lib/translator.dart | 3 + pkg/dart2wasm/tool/compile_benchmark | 6 + pkg/front_end/lib/src/codes/diagnostic.g.dart | 2 +- pkg/front_end/messages.yaml | 2 +- .../test/spell_checking_list_common.txt | 1 + pkg/front_end/tool/additional_targets.dart | 2 + pkg/test_runner/lib/src/browser.dart | 29 +++- pkg/test_runner/lib/src/test_suite.dart | 7 +- sdk/lib/_internal/wasm/lib/async_patch.dart | 6 +- sdk/lib/_internal/wasm/lib/timer_patch.dart | 4 +- sdk/lib/_internal/wasm_standalone/OWNERS | 1 + .../wasm_standalone/lib/embedder.dart | 57 ++++++++ .../wasm_standalone/lib/timer_patch.dart | 124 ++++++++++++++++++ sdk/lib/libraries.json | 94 +++++++++++-- sdk/lib/libraries.yaml | 71 +++++++++- tools/bots/test_matrix.json | 44 +++++++ utils/dart2wasm/BUILD.gn | 16 +++ 21 files changed, 454 insertions(+), 29 deletions(-) create mode 100644 sdk/lib/_internal/wasm_standalone/OWNERS create mode 100644 sdk/lib/_internal/wasm_standalone/lib/embedder.dart create mode 100644 sdk/lib/_internal/wasm_standalone/lib/timer_patch.dart diff --git a/BUILD.gn b/BUILD.gn index f8411f94213..50a09ec8ede 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -162,6 +162,7 @@ group("dart2wasm_platform") { ":runtime_precompiled", "utils/dart2wasm:compile_dart2wasm_js_compatibility_platform", "utils/dart2wasm:compile_dart2wasm_platform", + "utils/dart2wasm:compile_dart2wasm_standalone_platform", "utils/dart2wasm:dart2wasm_snapshot", ] if (defined(is_product)) { diff --git a/pkg/dart2wasm/lib/compile.dart b/pkg/dart2wasm/lib/compile.dart index 948261dd70d..ed6180f3f19 100644 --- a/pkg/dart2wasm/lib/compile.dart +++ b/pkg/dart2wasm/lib/compile.dart @@ -215,6 +215,8 @@ Future compile( final wasm.Mode mode; if (options.translatorOptions.jsCompatibility) { mode = wasm.Mode.jsCompatibility; + } else if (options.translatorOptions.standalone) { + mode = wasm.Mode.standalone; } else { mode = wasm.Mode.regular; } diff --git a/pkg/dart2wasm/lib/dart2wasm.dart b/pkg/dart2wasm/lib/dart2wasm.dart index fda4f0c9adc..319e23dc854 100644 --- a/pkg/dart2wasm/lib/dart2wasm.dart +++ b/pkg/dart2wasm/lib/dart2wasm.dart @@ -43,6 +43,10 @@ final List