diff options
author | Alon Zakai <azakai@google.com> | 2022-02-03 14:12:45 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-03 14:12:45 -0800 |
commit | e6f15747d1e3557cfff87c3149e91e3dbd0ff6c7 (patch) | |
tree | 5d26b6def557a45a3165ed8a7493ab3eb4a22b23 | |
parent | 9800178d7cfdb336fb5bac34f0d9844639f3a9cc (diff) | |
download | binaryen-e6f15747d1e3557cfff87c3149e91e3dbd0ff6c7.tar.gz binaryen-e6f15747d1e3557cfff87c3149e91e3dbd0ff6c7.tar.bz2 binaryen-e6f15747d1e3557cfff87c3149e91e3dbd0ff6c7.zip |
[Docs] Document wasm-ctor-eval (#4493)
-rw-r--r-- | README.md | 84 | ||||
-rw-r--r-- | src/tools/wasm-ctor-eval.cpp | 5 | ||||
-rw-r--r-- | test/lit/help/wasm-ctor-eval.test | 2 |
3 files changed, 85 insertions, 6 deletions
@@ -202,8 +202,8 @@ This repository contains code that builds the following tools in `bin/`: also run the spec test suite. * **wasm-emscripten-finalize**: Takes a wasm binary produced by llvm+lld and performs emscripten-specific passes over it. - * **wasm-ctor-eval**: A tool that can execute C++ global constructors ahead of - time. Used by Emscripten. + * **wasm-ctor-eval**: A tool that can execute functions (or parts of functions) + at compile time. * **binaryen.js**: A standalone JavaScript library that exposes Binaryen methods for [creating and optimizing WASM modules](https://github.com/WebAssembly/binaryen/blob/main/test/binaryen.js/hello-world.js). For builds, see [binaryen.js on npm](https://www.npmjs.com/package/binaryen) (or download it directly from [github](https://raw.githubusercontent.com/AssemblyScript/binaryen.js/master/index.js), [rawgit](https://cdn.rawgit.com/AssemblyScript/binaryen.js/master/index.js), or [unpkg](https://unpkg.com/binaryen@latest/index.js)). Usage instructions for each are below. @@ -458,6 +458,86 @@ Things keep to in mind with wasm2js's output: int/float conversions do not trap, and so forth. There may also be slight differences in corner cases of conversions, like non-trapping float to int. +### wasm-ctor-eval + +`wasm-ctor-eval` executes functions, or parts of them, at compile time. +After doing so it serializes the runtime state into the wasm, which is like +taking a "snapshot". When the wasm is later loaded and run in a VM, it will +continue execution from that point, without re-doing the work that was already +executed. + +For example, consider this small program: + +```wat +(module + ;; A global variable that begins at 0. + (global $global (mut i32) (i32.const 0)) + + (import "import" "import" (func $import)) + + (func "main" + ;; Set the global to 1. + (global.set $global + (i32.const 1)) + + ;; Call the imported function. This *cannot* be executed at + ;; compile time. + (call $import) + + ;; We will never get to this point, since we stop at the + ;; import. + (global.set $global + (i32.const 2)) + ) +) +``` + +We can evaluate part of it at compile time like this: + +``` +wasm-ctor-eval input.wat --ctors=main -S -o - +``` + +This tells it that there is a single function that we want to execute ("ctor" +is short for "global constructor", a name that comes from code that is executed +before a program's entry point) and then to print it as text to `stdout`. The +result is this: + +```wat +trying to eval main + ...partial evalling successful, but stopping since could not eval: call import: import.import + ...stopping +(module + (type $none_=>_none (func)) + (import "import" "import" (func $import)) + (global $global (mut i32) (i32.const 1)) + (export "main" (func $0_0)) + (func $0_0 + (call $import) + (global.set $global + (i32.const 2) + ) + ) +) +``` + +The logging shows us managing to eval part of `main()`, but not all of it, as +expected: We can eval the first `global.get`, but then we stop at the call to +the imported function (because we don't know what that function will be when the +wasm is actually run in a VM later). Note how in the output wasm the global's +value has been updated from 0 to 1, and that the first `global.get` has been +removed: the wasm is now in a state that, when we run it in a VM, will seamlessly +continue to run from the point at which `wasm-ctor-eval` stopped. + +In this tiny example we just saved a small amount of work. How much work can be +saved depends on your program. (It can help to do pure computation up front, and +leave calls to imports to as late as possible.) + +Note that `wasm-ctor-eval`'s name is related to global constructor functions, +as mentioned earlier, but there is no limitation on what you can execute here. +Any export from the wasm can be executed, if its contents are suitable. For +example, in Emscripten `wasm-ctor-eval` is even run on `main()` when possible. + ## Testing ``` diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 271e96037..0bcf42f9c 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -17,7 +17,7 @@ // // Loads wasm plus a list of functions that are global ctors, i.e., // are to be executed. It then executes as many of them as it can, -// applying their changes to memory as needed, then writes it. In +// applying their changes to memory etc as needed, then writes it. In // other words, this executes code at compile time to speed up // startup later. // @@ -705,8 +705,7 @@ int main(int argc, const char* argv[]) { const std::string WasmCtorEvalOption = "wasm-ctor-eval options"; - ToolOptions options("wasm-ctor-eval", - "Execute C++ global constructors ahead of time"); + ToolOptions options("wasm-ctor-eval", "Execute code at compile time"); options .add("--output", "-o", diff --git a/test/lit/help/wasm-ctor-eval.test b/test/lit/help/wasm-ctor-eval.test index 626a49557..183094f8f 100644 --- a/test/lit/help/wasm-ctor-eval.test +++ b/test/lit/help/wasm-ctor-eval.test @@ -2,7 +2,7 @@ ;; CHECK: ================================================================================ ;; CHECK-NEXT: wasm-ctor-eval INFILE ;; CHECK-NEXT: -;; CHECK-NEXT: Execute C++ global constructors ahead of time +;; CHECK-NEXT: Execute code at compile time ;; CHECK-NEXT: ================================================================================ ;; CHECK-NEXT: ;; CHECK-NEXT: |