Skip to content

Commit b61ca02

Browse files
committed
feat: bytecode and code_cache support
1 parent 621ab19 commit b61ca02

140 files changed

Lines changed: 2514 additions & 185434 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
name: Build bytecode compilers
2+
3+
# Builds the per-host bytecode compiler CLIs for every engine that supports
4+
# ahead-of-time bytecode, by cloning each engine's UPSTREAM repo (not the
5+
# android-runtime vendored sources) and building the CLI there.
6+
#
7+
# Output: one artifact per (engine, host), named `bytecode-compiler-<engine>-<host>`,
8+
# each containing `<engine>/<host>/<binary>` so the downloads merge straight into
9+
# tools/bytecode-compiler/bin/.
10+
#
11+
# NOTE ON COMPATIBILITY: the produced bytecode must be loadable by the engine
12+
# library the runtime ships. Hermes/PrimJS runtimes link prebuilt .so's and
13+
# QuickJS/QuickJS-NG compile from vendored source, so the refs below must be kept
14+
# in step with what the runtime actually bundles. Pin these to exact commits once
15+
# validated instead of moving branches.
16+
on:
17+
workflow_dispatch:
18+
inputs:
19+
hermes_ref:
20+
description: "facebook/hermes ref"
21+
default: "10a40b5f1de81d007cba6afe567c4ba7a0b45f5d"
22+
quickjs_ref:
23+
# MUST match the quickjs submodule pin (BC_VERSION must agree with the
24+
# runtime). See .gitmodules / scripts/vendor-engines-as-submodules.sh.
25+
description: "bellard/quickjs ref (match the submodule pin)"
26+
default: "04be246001599f5995fa2f2d8c91a0f198d3f34c"
27+
quickjs_ng_ref:
28+
# MUST match the quickjs_ng submodule pin (BC_VERSION must agree with the
29+
# runtime, or JS_ReadObject rejects the blob). See .gitmodules /
30+
# scripts/vendor-engines-as-submodules.sh.
31+
description: "quickjs-ng/quickjs ref (match the submodule pin)"
32+
default: "d950d55e950dd7994a96c669c31efa967b8b79f3"
33+
primjs_ref:
34+
description: "lynx-family/primjs ref"
35+
default: "9c1fe150179b86f0ae5c6fbe670af7d76eca9df6"
36+
37+
env:
38+
HERMES_REPO: https://github.com/facebook/hermes
39+
QUICKJS_REPO: https://github.com/bellard/quickjs
40+
QUICKJS_NG_REPO: https://github.com/quickjs-ng/quickjs
41+
PRIMJS_REPO: https://github.com/lynx-family/primjs
42+
43+
jobs:
44+
# ---------------------------------------------------------------------------
45+
# Hermes — `hermesc` already emits a loadable HBC blob; no shim needed.
46+
# ---------------------------------------------------------------------------
47+
hermes:
48+
name: hermes (${{ matrix.host }})
49+
runs-on: ${{ matrix.runner }}
50+
strategy:
51+
fail-fast: false
52+
matrix:
53+
include:
54+
- { host: linux-x64, runner: ubuntu-24.04 }
55+
- { host: linux-arm64, runner: ubuntu-24.04-arm }
56+
- { host: darwin-x64, runner: macos-13 }
57+
- { host: darwin-arm64, runner: macos-14 }
58+
- { host: win32-x64, runner: windows-2022 }
59+
- { host: win32-arm64, runner: windows-11-arm }
60+
steps:
61+
- name: Install toolchain (Linux)
62+
if: runner.os == 'Linux'
63+
run: sudo apt-get update && sudo apt-get install -y cmake ninja-build build-essential python3
64+
- name: Install toolchain (macOS)
65+
if: runner.os == 'macOS'
66+
run: brew install cmake ninja
67+
- name: Install toolchain (Windows)
68+
if: runner.os == 'Windows'
69+
run: choco install ninja -y
70+
71+
- name: Clone Hermes
72+
shell: bash
73+
run: git clone --depth 1 --branch "${{ github.event.inputs.hermes_ref || 'master' }}" "$HERMES_REPO" hermes
74+
75+
- name: Build hermesc (Unix)
76+
if: runner.os != 'Windows'
77+
shell: bash
78+
run: |
79+
set -euxo pipefail
80+
cmake -S hermes -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DHERMES_BUILD_APPLE_FRAMEWORK=OFF
81+
cmake --build build --target hermesc
82+
83+
- name: Build hermesc (Windows)
84+
if: runner.os == 'Windows'
85+
shell: bash
86+
run: |
87+
set -euxo pipefail
88+
# Use the default (Visual Studio) generator; Ninja+MSVC also works if the
89+
# VS dev environment is on PATH.
90+
cmake -S hermes -B build -DCMAKE_BUILD_TYPE=Release
91+
cmake --build build --target hermesc --config Release
92+
93+
- name: Stage binary
94+
shell: bash
95+
run: |
96+
set -euxo pipefail
97+
mkdir -p "out/hermes/${{ matrix.host }}"
98+
bin="$(find build -type f \( -name hermesc -o -name hermesc.exe \) | head -n1)"
99+
test -n "$bin"
100+
cp "$bin" "out/hermes/${{ matrix.host }}/"
101+
102+
- uses: actions/upload-artifact@v4
103+
with:
104+
name: bytecode-compiler-hermes-${{ matrix.host }}
105+
path: out/hermes/${{ matrix.host }}
106+
if-no-files-found: error
107+
108+
# ---------------------------------------------------------------------------
109+
# QuickJS (bellard) — build the engine lib, then our blob-emitting shim.
110+
# ---------------------------------------------------------------------------
111+
quickjs:
112+
name: quickjs (${{ matrix.host }})
113+
runs-on: ${{ matrix.runner }}
114+
strategy:
115+
fail-fast: false
116+
matrix:
117+
include:
118+
- { host: linux-x64, runner: ubuntu-24.04 }
119+
- { host: linux-arm64, runner: ubuntu-24.04-arm }
120+
- { host: darwin-x64, runner: macos-13 }
121+
- { host: darwin-arm64, runner: macos-14 }
122+
- { host: win32-x64, runner: windows-2022 }
123+
- { host: win32-arm64, runner: windows-11-arm }
124+
steps:
125+
- uses: actions/checkout@v4
126+
- name: Install toolchain (Linux)
127+
if: runner.os == 'Linux'
128+
run: sudo apt-get update && sudo apt-get install -y build-essential
129+
- name: Install toolchain (Windows)
130+
if: runner.os == 'Windows'
131+
run: choco install llvm -y
132+
133+
- name: Clone QuickJS
134+
shell: bash
135+
run: git clone --depth 1 --branch "${{ github.event.inputs.quickjs_ref || 'master' }}" "$QUICKJS_REPO" quickjs
136+
137+
- name: Build shim
138+
shell: bash
139+
env:
140+
SHIM: ${{ github.workspace }}/tools/bytecode-compiler/native/qjs-compile.c
141+
run: |
142+
set -euxo pipefail
143+
cd quickjs
144+
CC="cc"; [ "${{ runner.os }}" = "Windows" ] && CC="clang"
145+
# Compile the lib sources directly (avoids qjs/qjsc main() collisions).
146+
# If bellard changes the source set, adjust this list.
147+
libsrc="quickjs.c cutils.c libregexp.c libunicode.c"
148+
[ -f dtoa.c ] && libsrc="$libsrc dtoa.c"
149+
out="../out/quickjs/${{ matrix.host }}"; mkdir -p "$out"
150+
bin="$out/nsbc-quickjs"; [ "${{ runner.os }}" = "Windows" ] && bin="$bin.exe"
151+
$CC -O2 -DNSBC_MAGIC='"NSBCQJS"' -I. -o "$bin" "$SHIM" $libsrc -lm
152+
"$bin" || true # usage line (exit 2) proves it links & runs
153+
154+
- uses: actions/upload-artifact@v4
155+
with:
156+
name: bytecode-compiler-quickjs-${{ matrix.host }}
157+
path: out/quickjs/${{ matrix.host }}
158+
if-no-files-found: error
159+
160+
# ---------------------------------------------------------------------------
161+
# QuickJS-NG — CMake build of libqjs, then our shim (same JS_* API).
162+
# ---------------------------------------------------------------------------
163+
quickjs-ng:
164+
name: quickjs-ng (${{ matrix.host }})
165+
runs-on: ${{ matrix.runner }}
166+
strategy:
167+
fail-fast: false
168+
matrix:
169+
include:
170+
- { host: linux-x64, runner: ubuntu-24.04 }
171+
- { host: linux-arm64, runner: ubuntu-24.04-arm }
172+
- { host: darwin-x64, runner: macos-13 }
173+
- { host: darwin-arm64, runner: macos-14 }
174+
- { host: win32-x64, runner: windows-2022 }
175+
- { host: win32-arm64, runner: windows-11-arm }
176+
steps:
177+
- uses: actions/checkout@v4
178+
- name: Install toolchain (Linux)
179+
if: runner.os == 'Linux'
180+
run: sudo apt-get update && sudo apt-get install -y cmake ninja-build build-essential
181+
- name: Install toolchain (macOS)
182+
if: runner.os == 'macOS'
183+
run: brew install cmake ninja
184+
- name: Install toolchain (Windows)
185+
if: runner.os == 'Windows'
186+
run: choco install ninja llvm -y
187+
188+
- name: Clone QuickJS-NG
189+
shell: bash
190+
run: git clone --depth 1 --branch "${{ github.event.inputs.quickjs_ng_ref || 'master' }}" "$QUICKJS_NG_REPO" quickjs-ng
191+
192+
- name: Build lib + shim
193+
shell: bash
194+
env:
195+
SHIM: ${{ github.workspace }}/tools/bytecode-compiler/native/qjs-compile.c
196+
run: |
197+
set -euxo pipefail
198+
cmake -S quickjs-ng -B quickjs-ng/build -DCMAKE_BUILD_TYPE=Release -DBUILD_QJS_LIBC=OFF
199+
cmake --build quickjs-ng/build --config Release
200+
lib="$(find quickjs-ng/build -type f \( -name 'libqjs.a' -o -name 'qjs.lib' \) | head -n1)"
201+
test -n "$lib"
202+
CC="cc"; [ "${{ runner.os }}" = "Windows" ] && CC="clang"
203+
out="out/quickjs-ng/${{ matrix.host }}"; mkdir -p "$out"
204+
bin="$out/nsbc-quickjs-ng"; [ "${{ runner.os }}" = "Windows" ] && bin="$bin.exe"
205+
$CC -O2 -DNSBC_MAGIC='"NSBCNGS"' -I quickjs-ng -o "$bin" "$SHIM" "$lib" -lm
206+
"$bin" || true
207+
208+
- uses: actions/upload-artifact@v4
209+
with:
210+
name: bytecode-compiler-quickjs-ng-${{ matrix.host }}
211+
path: out/quickjs-ng/${{ matrix.host }}
212+
if-no-files-found: error
213+
214+
# ---------------------------------------------------------------------------
215+
# PrimJS — build the engine, then our LEPUS_* shim.
216+
# NOTE: PrimJS's build system is nonstandard; the steps below are best-effort
217+
# and will very likely need adjustment against lynx-family/primjs@develop
218+
# (its actual CMake targets / include + lib paths). Treat the first CI run as
219+
# the source of truth and pin once green.
220+
# ---------------------------------------------------------------------------
221+
primjs:
222+
name: primjs (${{ matrix.host }})
223+
runs-on: ${{ matrix.runner }}
224+
strategy:
225+
fail-fast: false
226+
matrix:
227+
include:
228+
- { host: linux-x64, runner: ubuntu-24.04 }
229+
- { host: linux-arm64, runner: ubuntu-24.04-arm }
230+
- { host: darwin-x64, runner: macos-13 }
231+
- { host: darwin-arm64, runner: macos-14 }
232+
- { host: win32-x64, runner: windows-2022 }
233+
- { host: win32-arm64, runner: windows-11-arm }
234+
steps:
235+
- uses: actions/checkout@v4
236+
- name: Install toolchain (Linux)
237+
if: runner.os == 'Linux'
238+
run: sudo apt-get update && sudo apt-get install -y cmake ninja-build build-essential python3
239+
- name: Install toolchain (macOS)
240+
if: runner.os == 'macOS'
241+
run: brew install cmake ninja
242+
- name: Install toolchain (Windows)
243+
if: runner.os == 'Windows'
244+
run: choco install ninja llvm -y
245+
246+
- name: Clone PrimJS
247+
shell: bash
248+
run: |
249+
git clone --depth 1 --branch "${{ github.event.inputs.primjs_ref || 'develop' }}" "$PRIMJS_REPO" primjs
250+
# PrimJS vendors deps via a script in some layouts; run it if present.
251+
if [ -f primjs/tools/hooks/generate_gni.py ]; then python3 primjs/tools/hooks/generate_gni.py || true; fi
252+
253+
- name: Build engine + shim
254+
shell: bash
255+
env:
256+
SHIM: ${{ github.workspace }}/tools/bytecode-compiler/native/primjs-compile.c
257+
run: |
258+
set -euxo pipefail
259+
# Best-effort CMake build of the PrimJS/quickjs static lib. Adjust the
260+
# target and include/lib paths to match the repo once observed in CI.
261+
cmake -S primjs -B primjs/build -DCMAKE_BUILD_TYPE=Release || {
262+
echo "::warning::PrimJS cmake configure needs adjustment for this repo layout"; exit 1; }
263+
cmake --build primjs/build --config Release
264+
lib="$(find primjs/build -type f \( -name 'libquick*.a' -o -name 'libprimjs*.a' -o -name '*.lib' \) | head -n1)"
265+
inc="$(dirname "$(find primjs -name quickjs.h | head -n1)")"
266+
test -n "$lib" && test -n "$inc"
267+
CC="cc"; [ "${{ runner.os }}" = "Windows" ] && CC="clang"
268+
out="out/primjs/${{ matrix.host }}"; mkdir -p "$out"
269+
bin="$out/nsbc-primjs"; [ "${{ runner.os }}" = "Windows" ] && bin="$bin.exe"
270+
$CC -O2 -I"$inc" -o "$bin" "$SHIM" "$lib" -lm
271+
"$bin" || true
272+
273+
- uses: actions/upload-artifact@v4
274+
with:
275+
name: bytecode-compiler-primjs-${{ matrix.host }}
276+
path: out/primjs/${{ matrix.host }}
277+
if-no-files-found: error

.github/workflows/npm_trusted_release.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ jobs:
123123
distribution: "temurin"
124124
- name: Install root dependencies
125125
run: npm install
126+
- name: Set up engine submodules, patches, and jsparser
127+
run: npm run setup
126128
- name: Resolve engine target
127129
id: target
128130
shell: bash
@@ -200,9 +202,6 @@ jobs:
200202
echo "NPM_VERSION=$NPM_VERSION" >> "$GITHUB_OUTPUT"
201203
echo "NPM_TAG=$NPM_TAG" >> "$GITHUB_OUTPUT"
202204
echo "Resolved $PACKAGE_NAME@$NPM_VERSION (tag: $NPM_TAG)"
203-
- name: Install jsparser dependencies
204-
working-directory: ${{ env.JS_PARSER_DIR }}
205-
run: npm ci
206205
- name: Grant execute permission for gradlew
207206
run: chmod +x gradlew
208207
- name: Build (-Pengine=${{ steps.target.outputs.GRADLE_ENGINE }})

.gitmodules

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[submodule "test-app/runtime/src/main/cpp/napi/quickjs/source"]
2+
path = test-app/runtime/src/main/cpp/napi/quickjs/source
3+
url = https://github.com/bellard/quickjs
4+
ignore = dirty
5+
[submodule "test-app/runtime/src/main/cpp/napi/quickjs/source_ng"]
6+
path = test-app/runtime/src/main/cpp/napi/quickjs/source_ng
7+
url = https://github.com/quickjs-ng/quickjs
8+
ignore = dirty

build.gradle

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@ def DIST_PATH = "$rootDir/dist_${jsEngine.toLowerCase()}"
3939
def TEST_APP_PATH = "$rootDir/test-app"
4040
def BUILD_TOOLS_PATH = "$TEST_APP_PATH/build-tools"
4141
def DIST_FRAMEWORK_PATH = "$DIST_PATH/framework"
42+
def BYTECODE_TOOLS_PATH = "$rootDir/tools/bytecode-compiler"
43+
44+
// Maps an ns_engine value to its bytecode-compiler bin/<dir>. Engines with no
45+
// bytecode compiler (V8*, JSC) are absent, so no binaries are shipped for them.
46+
def bytecodeEngineDir = [
47+
"HERMES" : "hermes",
48+
"QUICKJS" : "quickjs",
49+
"QUICKJS_NG": "quickjs-ng",
50+
"PRIMJS" : "primjs",
51+
].get(jsEngine)
4252

4353
task checkEnvironmentVariables {
4454
if ("$System.env.JAVA_HOME" == "" || "$System.env.JAVA_HOME" == "null") {
@@ -298,6 +308,20 @@ task copyFilesToProjectTemeplate {
298308
from "$BUILD_TOOLS_PATH/android-metadata-generator/build/libs/android-metadata-generator.jar"
299309
into "$DIST_FRAMEWORK_PATH/build-tools"
300310
}
311+
// Ship the engine-generic bytecode compiler (driver + adapters). The
312+
// per-host compiler binaries under bin/ are shipped only for the engine
313+
// this framework is built for, so a V8 template doesn't carry hermesc.
314+
copy {
315+
from "$BYTECODE_TOOLS_PATH"
316+
into "$DIST_FRAMEWORK_PATH/build-tools/bytecode-compiler"
317+
exclude "bin/**"
318+
}
319+
if (bytecodeEngineDir != null) {
320+
copy {
321+
from "$BYTECODE_TOOLS_PATH/bin/${bytecodeEngineDir}"
322+
into "$DIST_FRAMEWORK_PATH/build-tools/bytecode-compiler/bin/${bytecodeEngineDir}"
323+
}
324+
}
301325
copy {
302326
from "$TEST_APP_PATH/runtime/build/outputs/aar/runtime-regular-release.aar"
303327
into "$DIST_FRAMEWORK_PATH/app/libs/runtime-libs"

0 commit comments

Comments
 (0)