dart-sdk/pkg/dart2wasm
Ömer Sinan Ağacan 7fec037b6b [dart2wasm] Split more patch files into patch + implementation files
Following the refactoring we started in previous CLs, this splits string
and int patch files into (1) patch files that only patch and don't add
implementation classes (2) files for implementation classes (3) helpers.

Changes:

- `string_patch` is split into `string.dart` and `string_patch.dart`.

- VM's `integers_patch.dart` copied as `int_patch.dart` and updated.
  This was needed as `integers_patch` requires VM's library paths in
  imports.

  We needed to copy this file to be able to optimize based on
  dart2wasm's implementation classes. However in this CL we copy the
  file as-is and update import paths.

- VM's `string_buffer_patch.dart` copied to be able to use the string
  implementation classes from the new library.
  `string_buffer_create.dart` is merged ino `string_buffer_patch.dart`.

- `getHash` and `setHash` to set object identity moved to
  `object_helper.dart`, to be able to use in string implementations.

- Redundant `new` keywords in copied files removed.

One TODO added in `string_buffer_patch.dart` when allocating a new
string to the buffer:

    // _parts = _GrowableList.withCapacity(10)..add(str);
    // TODO(omersa): Uncomment the line above after moving list
    // implementations to a library.
    _parts = [str];

We can enable the old code again after moving list implementations to a
library.

Change-Id: Ice5dba40b3ba894797028987d4b42cb0c0f0c230
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/315821
Commit-Queue: Ömer Ağacan <omersa@google.com>
Reviewed-by: Joshua Litt <joshualitt@google.com>
2023-07-24 16:58:52 +00:00
..
bin [dart2wasm] Implement micro-task scheduling 2023-06-19 10:21:35 +00:00
lib [dart2wasm] Split more patch files into patch + implementation files 2023-07-24 16:58:52 +00:00
tool [dart2wasm] New typed data implementation 2023-07-20 09:47:39 +00:00
analysis_options.yaml [pkg/dart2wasm] use package:lints for analysis 2022-07-07 00:16:01 +00:00
OWNERS
pubspec.yaml [dart2wasm] Support --multi-root and --multi-root-scheme flags. 2022-12-08 00:59:23 +00:00
README.md [dart2wasm|jscm] Move typed data to JS. 2023-07-20 20:31:38 +00:00

Compiling Dart to WebAssembly

WebAssembly (commonly abbreviated to Wasm) is a "binary instruction format for a stack-based virtual machine". Although Wasm was originally designed for running native code on the web, Wasm has since evolved into a general technology for running compiled code across multiple platforms.

The Dart team is currently investigating support for compiling Dart to Wasm, in conjunction with support in Flutter.

Note: This feature is under active development, and is currently considered experimental. The tracking issue is #32894.

Running dart2wasm

You don't need to build the Dart SDK to run dart2wasm, as long as you have a Dart SDK installed and have the Dart SDK repository checked out. NB: the SDK must be checked out using depot tools and not just cloned from this repo.

To compile a Dart file to Wasm, in a checkout of the Dart SDK repository, run:

dart --enable-asserts pkg/dart2wasm/bin/dart2wasm.dart options infile.dart outfile.wasm

where options include:

Option Default Description
--dart-sdk=path relative to script The location of the sdk directory inside the Dart SDK, containing the core library sources.
--platform=path none The location of the platform dill file containing the compiled core libraries.
--depfile=path none Write a Ninja depfile listing the input sources for the compilation.
--[no-]export-all no Export all functions; otherwise, just export main.
--[no-]import-shared-memory no Import a shared memory buffer. If this is on, --shared-memory-max-pages must also be specified.
--[no-]inlining yes Enable function inlining.
--inlining-limit size 0 Always inline functions no larger than this number of AST nodes, if inlining is enabled.
--[no-]name-section yes Emit Name Section with function names.
--[no-]omit-type-checks no Omit runtime type checks, such as covariance checks and downcasts.
--[no-]polymorphic-specialization no Do virtual calls by switching on the class ID instead of using call_indirect.
--[no-]print-kernel no Print IR for each function before compiling it.
--[no-]print-wasm no Print Wasm instructions of each compiled function.
--[no-]stringref no Use the experimental stringref Wasm proposal.
--[no-]enable-asserts no Enable assertions at runtime.
--[no-]js-compatibility no Enable JS compatibility mode.
--shared-memory-max-pages pagecount Max size of the imported memory buffer. If --shared-import-memory is specified, this must also be specified.
--watch offset Print stack trace leading to the byte at offset offset in the .wasm output file. Can be specified multiple times.

Dart2Wasm will output a wasm file, containing Dart compiled to Wasm, as well as an mjs file containing the runtime. The result can be run with:

d8 --experimental-wasm-gc --experimental-wasm-type-reflection pkg/dart2wasm/bin/run_wasm.js -- outfile.wasm /abs/path/to/*outfile*.mjs

Where d8 is the V8 developer shell.

Imports and exports

To import a function, declare it as a global, external function and mark it with a wasm:import pragma indicating the imported name (which must be two identifiers separated by a dot):

@pragma("wasm:import", "foo.bar")
external void fooBar(Object object);

which will call foo.bar on the host side:

var foo = {
    bar: function(object) { /* implementation here */ }
};

To export a function, mark it with a wasm:export pragma:

@pragma("wasm:export")
void foo(double x) { /* implementation here */  }

@pragma("wasm:export", "baz")
void bar(double x) { /* implementation here */  }

With the Wasm module instance in inst, these can be called as:

inst.exports.foo(1);
inst.exports.baz(2);

Types to use for interop

In the signatures of imported and exported functions, use the following types:

  • For numbers, use double.
  • For JS objects, use a JS interop type, e.g. JSAny, which translates to the Wasm externref type. These can be passed around and stored as opaque values on the Dart side.
  • For Dart objects, use the corresponding Dart type. This will be emitted as anyref and automatically converted to and from the Dart type at the boundary.