Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ jobs:
- 'release'
- 'debug'
- 'weval'
- 'nightmonkey'
steps:
- uses: actions/checkout@v4
with:
Expand Down Expand Up @@ -154,6 +155,9 @@ jobs:
npm run clean
npm run build:${{matrix.build-type}}

nightmonkey-compilers:
uses: ./.github/workflows/nightmonkey-compilers.yml

########
# Test #
########
Expand All @@ -162,6 +166,7 @@ jobs:
runs-on: ${{ matrix.os }}
needs:
- build
- nightmonkey-compilers
strategy:
fail-fast: false
matrix:
Expand All @@ -176,6 +181,7 @@ jobs:
- 'release'
- 'debug'
- 'weval'
- 'nightmonkey'
steps:
- uses: actions/checkout@v4

Expand All @@ -200,6 +206,14 @@ jobs:
lib
target

- name: Download NightMonkey compilers
if: matrix.build-type == 'nightmonkey'
uses: actions/download-artifact@v4
with:
pattern: nightmonkey-*
path: lib/nightmonkey
merge-multiple: true

- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: ${{matrix.node-version}}
Expand Down
80 changes: 80 additions & 0 deletions .github/workflows/nightmonkey-compilers.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
name: nightmonkey-compilers

# Builds the NightMonkey compiler for each supported host from the NightMonkey
# revision and engine version the StarlingMonkey submodule pins, and uploads
# each as an artifact named after its file in lib/nightmonkey/ (see
# NIGHTMONKEY_HOST_ASSETS in src/componentize.js). The compiler is a native
# binary, so unlike the engine it cannot be built once on Linux.
on:
workflow_call:

defaults:
run:
shell: bash

jobs:
build:
name: NightMonkey compiler (${{ matrix.asset }})
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
asset: nightmonkey-x86_64-linux
binary: nightmonkey
- os: ubuntu-24.04-arm
asset: nightmonkey-aarch64-linux
binary: nightmonkey
- os: macos-14
asset: nightmonkey-aarch64-macos
binary: nightmonkey
- os: windows-2022
asset: nightmonkey-x86_64-windows.exe
binary: nightmonkey.exe
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
with:
submodules: true

- name: Read NightMonkey pins
id: pins
run: |
file=StarlingMonkey/cmake/nightmonkey.cmake
revision="$(awk '/^set\(NIGHTMONKEY_TAG / {gsub(/set\(NIGHTMONKEY_TAG |\)/, ""); print}' "$file")"
engine="$(awk '/^set\(NIGHTMONKEY_ENGINE_VERSION / {gsub(/"/, "", $2); print $2}' "$file")"
echo "revision=$revision" >> "$GITHUB_OUTPUT"
echo "engine=$engine" >> "$GITHUB_OUTPUT"

- uses: actions/cache@v4
id: cache
with:
key: ${{ matrix.asset }}-${{ steps.pins.outputs.revision }}-${{ steps.pins.outputs.engine }}
path: ${{ matrix.asset }}

- uses: actions/checkout@v4
if: steps.cache.outputs.cache-hit != 'true'
with:
repository: bytecodealliance/nightmonkey
ref: ${{ steps.pins.outputs.revision }}
path: nightmonkey

- name: Build compiler
if: steps.cache.outputs.cache-hit != 'true'
# Run from the StarlingMonkey tree so that rustup uses its toolchain, as
# the engine build does.
working-directory: StarlingMonkey
run: |
cargo build --release -p nightmonkey --manifest-path ../nightmonkey/Cargo.toml \
--target-dir ../nightmonkey-target \
--no-default-features --features "${{ steps.pins.outputs.engine }}"
cp "../nightmonkey-target/release/${{ matrix.binary }}" "../${{ matrix.asset }}"

- name: Check compiler
run: ./${{ matrix.asset }} --help

- uses: actions/upload-artifact@v4
with:
name: ${{ matrix.asset }}
path: ${{ matrix.asset }}
if-no-files-found: error
15 changes: 15 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,16 @@ jobs:
export PRERELEASE_TAG=$(node scripts/semver-get-prerelease.mjs $NEXT_VERSION);
echo -e "prerelease-tag=$PRERELEASE_TAG" >> $GITHUB_OUTPUT;

nightmonkey-compilers:
needs:
- meta
uses: ./.github/workflows/nightmonkey-compilers.yml

pack-npm-release:
runs-on: ubuntu-24.04
needs:
- meta
- nightmonkey-compilers
strategy:
matrix:
rust-version:
Expand Down Expand Up @@ -138,6 +144,15 @@ jobs:
run: |
npm install

# The engines are built by `npm pack` below; the NightMonkey compilers
# for every host are built natively by the job above.
- name: Download NightMonkey compilers
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
pattern: nightmonkey-*
path: lib/nightmonkey
merge-multiple: true

- name: Create release package
working-directory: ${{ needs.meta.outputs.project-dir }}
run: |
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ examples/hello-world/guest/hello.component.wasm
/build-debug
/build-release
/build-release-weval
/build-release-nightmonkey
/deps
.vscode
/package-lock.json
.idea
Expand Down
30 changes: 30 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,16 @@ set(EMBEDDING_DEP "starling-raw.wasm")
set(OUTPUT_NAME_RELEASE "starlingmonkey_embedding.wasm")
set(OUTPUT_NAME_DEBUG "starlingmonkey_embedding.debug.wasm")
set(OUTPUT_NAME_WEVAL "starlingmonkey_embedding_weval.wasm")
set(OUTPUT_NAME_NIGHTMONKEY "starlingmonkey_embedding_nightmonkey.wasm")

# Set the appropriate name based on current configuration
if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
set(OUTPUT_FILENAME ${OUTPUT_NAME_DEBUG})
elseif(WEVAL)
set(OUTPUT_FILENAME ${OUTPUT_NAME_WEVAL})
set(EMBEDDING_DEP "starling-ics.wevalcache")
elseif(NIGHTMONKEY)
set(OUTPUT_FILENAME ${OUTPUT_NAME_NIGHTMONKEY})
else()
set(OUTPUT_FILENAME ${OUTPUT_NAME_RELEASE})
endif()
Expand All @@ -47,6 +50,33 @@ add_custom_target(starlingmonkey_embedding
${OUTPUT_FILENAME}
)

# The NightMonkey compiler is a native binary that must match the engine
# exactly. The package ships one per supported host (built by CI from the
# NightMonkey revision StarlingMonkey pins) in lib/nightmonkey/, named as in
# NIGHTMONKEY_HOST_ASSETS in src/componentize.js; a local build puts the one
# it built there for the host.
if(NIGHTMONKEY)
set(NIGHTMONKEY_HOST_ASSET "")
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "^(x86_64|AMD64)$")
set(NIGHTMONKEY_HOST_ASSET "nightmonkey-x86_64-linux")
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64)$")
set(NIGHTMONKEY_HOST_ASSET "nightmonkey-aarch64-linux")
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64")
set(NIGHTMONKEY_HOST_ASSET "nightmonkey-aarch64-macos")
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows" AND CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "^(x86_64|AMD64)$")
set(NIGHTMONKEY_HOST_ASSET "nightmonkey-x86_64-windows.exe")
endif()
if(NIGHTMONKEY_HOST_ASSET)
add_dependencies(starlingmonkey_embedding nightmonkey_compiler)
add_custom_command(TARGET starlingmonkey_embedding POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${NIGHTMONKEY_BIN}
${CMAKE_CURRENT_SOURCE_DIR}/lib/nightmonkey/${NIGHTMONKEY_HOST_ASSET}
VERBATIM
)
endif()
endif()

if(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
add_custom_command(TARGET starlingmonkey_embedding POST_BUILD
COMMAND ${WASM_TOOLS_BIN} strip ${OUTPUT_FILENAME} -d ".debug_(info|loc|ranges|abbrev|line|str)" -o ${OUTPUT_FILENAME}
Expand Down
9 changes: 9 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ all: release
debug: lib/starlingmonkey_embedding.debug.wasm lib/spidermonkey-embedding-splicer.js
release: lib/starlingmonkey_embedding.wasm lib/spidermonkey-embedding-splicer.js
release-weval: lib/starlingmonkey_ics.wevalcache lib/spidermonkey-embedding-splicer.js
release-nightmonkey: lib/starlingmonkey_embedding_nightmonkey.wasm lib/spidermonkey-embedding-splicer.js

lib/spidermonkey-embedding-splicer.js: target/wasm32-wasip1/release/splicer_component.wasm crates/spidermonkey-embedding-splicer/wit/spidermonkey-embedding-splicer.wit | obj lib
@$(JCO) new target/wasm32-wasip1/release/splicer_component.wasm -o obj/spidermonkey-embedding-splicer.wasm --wasi-reactor
Expand All @@ -32,6 +33,12 @@ lib/starlingmonkey_embedding_weval.wasm: $(STARLINGMONKEY_DEPS) | lib
cmake -B build-release-weval -DCMAKE_BUILD_TYPE=Release -DUSE_WASM_OPT=OFF -DWEVAL=ON
make -j16 -C build-release-weval starlingmonkey_embedding

# Also puts the NightMonkey compiler this build made for the host in
# lib/nightmonkey/ (CI adds those for the other hosts when packaging).
lib/starlingmonkey_embedding_nightmonkey.wasm: $(STARLINGMONKEY_DEPS) | lib
cmake -B build-release-nightmonkey -DCMAKE_BUILD_TYPE=Release -DNIGHTMONKEY=ON
make -j16 -C build-release-nightmonkey starlingmonkey_embedding

lib/starlingmonkey_ics.wevalcache: lib/starlingmonkey_embedding_weval.wasm
@cp build-release-weval/starling-raw.wasm/starling-ics.wevalcache $@

Expand All @@ -55,6 +62,8 @@ clean:
rm lib/spidermonkey-embedding-splicer.js || true
rm lib/starlingmonkey_embedding.wasm || true
rm lib/starlingmonkey_embedding.debug.wasm || true
rm -r lib/starlingmonkey_embedding_nightmonkey.wasm lib/nightmonkey || true
echo "removing cmake outputs"
rm build-debug || true
rm build-release || true
rm build-release-nightmonkey || true
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,21 @@ AOT compilation can also be configured with the following options:

To use a custom (pre-downloaded) [`weval`][weval] binary, set the `wevalBin` option to the path to your desired weval binary.

### NightMonkey AOT Compilation

[NightMonkey][nightmonkey] is an ahead-of-time JS-to-Wasm compiler: after the Wizer snapshot is taken, it compiles the JS functions in the snapshot to WebAssembly, using a whole-program type analysis with dynamic guards (and falling back to the interpreter where it cannot compile).

To enable it, set the `enableNightmonkey: true` option or use the `--nightmonkey` CLI flag. It cannot be combined with weval AOT compilation.

NightMonkey compiles with a native `nightmonkey` binary that must match the engine exactly, so the package includes one for each supported host (Linux x86-64 and AArch64, macOS AArch64 and Windows x86-64), built alongside the engine. A local engine build (`npm run build:nightmonkey`) adds the one it built for the host. It can also be configured with the following options:

| Option | Type | Example | Description |
|-------------------|------------|---------------|----------------------------------------------------------------|
| `nightmonkeyBin` | `string` | `./nightmonkey` | Path to the NightMonkey compiler matching the engine (CLI: `--nightmonkey-bin`) |
| `nightmonkeyArgs` | `string[]` | `['--stats']` | Extra arguments to pass to the compiler |

[nightmonkey]: https://github.com/bytecodealliance/nightmonkey

## Platform APIs

The following APIs are available:
Expand Down Expand Up @@ -241,6 +256,19 @@ export function componentize(opts: {
* Use a pre-existing path to the `weval` binary, if present
*/
wevalBin?: string;
/**
* Enable AoT using NightMonkey (cannot be combined with `enableAot`)
*/
enableNightmonkey?: boolean;
/**
* Path to the NightMonkey compiler; it must match the engine. Defaults to
* the one for the host that ships with the NightMonkey engine.
*/
nightmonkeyBin?: string;
/**
* Extra arguments to pass to the NightMonkey compiler (e.g. `['--stats']`)
*/
nightmonkeyArgs?: string[];
/**
* Use a pre-existing path to the `wizer` binary, if present
*/
Expand Down
2 changes: 1 addition & 1 deletion StarlingMonkey
Submodule StarlingMonkey updated 47 files
+72 −4 .github/workflows/main.yml
+57 −0 .github/workflows/release-please.yml
+8 −1 CMakeLists.txt
+44 −12 builtins/web/abort/abort-signal.cpp
+51 −51 builtins/web/blob.cpp
+1 −0 builtins/web/blob.h
+2 −2 builtins/web/console.cpp
+3 −4 builtins/web/event/event-target.cpp
+1 −1 builtins/web/event/event-target.h
+8 −0 builtins/web/fetch/fetch_event.cpp
+462 −4 builtins/web/fetch/request-response.cpp
+1 −0 builtins/web/fetch/request-response.h
+4 −1 builtins/web/form-data/form-data-parser.cpp
+3 −1 builtins/web/text-codec/text-decoder.cpp
+5 −2 builtins/web/url.cpp
+81 −26 cmake/manage-git-source.cmake
+106 −0 cmake/night-runtime-compile.cmake
+160 −0 cmake/nightmonkey.cmake
+40 −11 cmake/spidermonkey.cmake
+82 −2 componentize.sh.in
+3 −3 justfile
+14 −0 runtime/engine.cpp
+8 −0 runtime/js.cpp
+15 −0 runtime/script_loader.cpp
+16 −0 tests/e2e/console-assert/console-assert.js
+7 −0 tests/e2e/console-assert/expect_serve_stdout.txt
+1 −0 tests/e2e/nightmonkey-fallback/expect_serve_body.txt
+7 −0 tests/e2e/nightmonkey-fallback/nightmonkey-fallback.js
+4 −0 tests/e2e/runtime-err/expect_serve_stderr_nightmonkey.txt
+38 −0 tests/integration/formdata/formdata.js
+3 −0 tests/integration/handlers.js
+30 −0 tests/integration/textdecoder/textdecoder.js
+36 −0 tests/integration/urlsearchparams/urlsearchparams.js
+3 −0 tests/test.sh
+13 −2 tests/tests.cmake
+17 −0 tests/wpt-harness/expectations/dom/abort/AbortSignal.any.js.json
+44 −0 tests/wpt-harness/expectations/dom/abort/abort-signal-any.any.js.json
+50 −0 tests/wpt-harness/expectations/dom/abort/event.any.js.json
+3 −3 tests/wpt-harness/expectations/fetch/api/abort/general.any.js.json
+1 −1 tests/wpt-harness/expectations/fetch/api/body/formdata.any.js.json
+62 −0 tests/wpt-harness/expectations/fetch/api/body/mime-type.any.js.json
+1 −1 tests/wpt-harness/expectations/fetch/api/request/request-disturbed.any.js.json
+65 −0 tests/wpt-harness/expectations/fetch/api/response/response-clone.any.js.json
+5 −5 tests/wpt-harness/expectations/fetch/api/response/response-stream-disturbed-6.any.js.json
+2 −2 tests/wpt-harness/expectations/fetch/api/response/response-stream-disturbed-by-pipe.any.js.json
+3 −0 tests/wpt-harness/tests.json
+2 −0 tests/wpt-harness/wpt.cmake
10 changes: 10 additions & 0 deletions embedding/embedding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
#include "debugger.h"
#include "builtins/web/performance.h"
#include "js/Conversions.h"
#ifdef ENABLE_JS_NIGHTMONKEY
#include "runtime/NightRegistration.h"
#endif

namespace builtins::web::console {

Expand Down Expand Up @@ -161,6 +164,13 @@ cabi_realloc(void *ptr, size_t orig_size, size_t org_align, size_t new_size) {
__attribute__((export_name("call"))) uint32_t call(uint32_t fn_idx,
void *argptr) {
if (Runtime.first_call) {
#ifdef ENABLE_JS_NIGHTMONKEY
// Enable the AOT-compiled bodies the NightMonkey snapshot transform
// added, if any; they are not dispatched to before this.
if (!JS::NightActivate(Runtime.cx)) {
Runtime.engine->abort("(call) unable to activate NightMonkey");
}
#endif
content_debugger::maybe_init_debugger(Runtime.engine, true);
js::ResetMathRandomSeed(Runtime.cx);
Runtime.first_call = false;
Expand Down
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,15 @@
"scripts": {
"clean": "npm run clean:starlingmonkey",
"clean:starlingmonkey": "rm -rf build-release",
"build": "npm run build:release && npm run build:debug && npm run build:weval",
"build": "npm run build:release && npm run build:debug && npm run build:weval && npm run build:nightmonkey",
"build:release": "make release",
"build:debug": "make debug",
"build:weval": "make release-weval",
"build:nightmonkey": "make release-nightmonkey",
"test": "vitest run -c test/vitest.ts",
"test:release": "vitest run -c test/vitest.ts",
"test:weval": "cross-env WEVAL_TEST=1 vitest run -c test/vitest.ts",
"test:nightmonkey": "cross-env NIGHTMONKEY_TEST=1 vitest run -c test/vitest.ts",
"test:debug": "cross-env DEBUG_TEST=1 vitest run -c test/vitest.ts",
"prepack": "node scripts/prepack.mjs"
},
Expand All @@ -48,6 +50,8 @@
"lib/starlingmonkey_embedding.debug.wasm",
"lib/starlingmonkey_embedding_weval.wasm",
"lib/starlingmonkey_ics.wevalcache",
"lib/starlingmonkey_embedding_nightmonkey.wasm",
"lib/nightmonkey",
"src",
"types.d.ts"
],
Expand Down
7 changes: 7 additions & 0 deletions src/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export async function componentizeCmd(jsSource, opts) {
worldName: opts.worldName,
runtimeArgs: opts.runtimeArgs,
enableAot: opts.aot,
enableNightmonkey: opts.nightmonkey,
nightmonkeyBin: opts.nightmonkeyBin,
engine: opts.engine,
disableFeatures: opts.disable,
preview2Adapter: opts.preview2Adapter,
Expand All @@ -35,6 +37,7 @@ program
.option('-n, --world-name <name>', 'WIT world to build')
.option('--runtime-args <string>', 'arguments to pass to the runtime')
.option('--aot', 'enable AOT compilation')
.option('--nightmonkey', 'enable NightMonkey AOT compilation')
.option(
'--engine <path>',
'provide a custom ComponentizeJS engine build path',
Expand Down Expand Up @@ -62,6 +65,10 @@ program
'--weval-bin <path>',
'specify a path to a local weval binary',
)
.option(
'--nightmonkey-bin <path>',
'specify a path to the NightMonkey compiler matching the engine',
)
.option(
'--aot-cache-dir <path>',
'specify a custom AOT weval cache path',
Expand Down
Loading
Loading