Skip to content

Commit d179033

Browse files
committed
refactor(runtime): isolate test262 host feature
1 parent b0074de commit d179033

23 files changed

Lines changed: 308 additions & 31 deletions

‎.github/workflows/ci.yml‎

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,16 +65,28 @@ jobs:
6565
run: |
6666
cargo fmt --all -- --check
6767
./scripts/check-no-test262-special-casing.sh
68+
./scripts/check-test262-host-boundary.sh
6869
./scripts/test-test262.sh --spec dev-support/test262/current.conf --check
6970
./scripts/check-rust-only.sh
7071
7172
- name: Run fast engine tests
7273
run: |
7374
cargo test --locked --workspace --lib --bins
74-
cargo test --locked --test cli --test unsupported_diagnostics
75+
cargo test --locked -p quickjs-oxide --features test262-host --lib --bins
76+
cargo test --locked --test cli
77+
cargo test --locked --features test262-host \
78+
--test unsupported_diagnostics \
79+
--test oracle_create_realm --test oracle_host_gc --test oracle_is_html_dda
7580
7681
- name: Lint production targets
77-
run: cargo clippy --locked --workspace --lib --bins -- -D warnings
82+
run: |
83+
cargo clippy --locked --workspace --lib --bins -- -D warnings
84+
cargo clippy --locked -p quickjs-oxide --features test262-host \
85+
--lib --bins -- -D warnings
86+
cargo clippy --locked -p quickjs-oxide --features test262-host \
87+
--test unsupported_diagnostics \
88+
--test oracle_create_realm --test oracle_host_gc --test oracle_is_html_dda \
89+
-- -D warnings
7890
7991
quickjs-differential:
8092
if: >-
@@ -117,7 +129,8 @@ jobs:
117129
- name: Run the pinned QuickJS differential corpus
118130
run: |
119131
oracle=$(./scripts/build-quickjs-oracle.sh)
120-
QJS_ORACLE="$oracle" cargo test --locked --workspace --all-targets
132+
QJS_ORACLE="$oracle" cargo test --locked --workspace --all-targets \
133+
--features test262-host
121134
122135
test262-full:
123136
if: >-

‎Cargo.toml‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ num-bigint = "=0.5.1"
1717
num-traits = "=0.2.19"
1818
tz-rs = "=0.7.3"
1919

20+
[features]
21+
default = []
22+
test262-host = []
23+
2024
[lib]
2125
name = "quickjs_oxide"
2226
path = "src/lib.rs"
@@ -28,6 +32,22 @@ path = "src/main.rs"
2832
[[bin]]
2933
name = "run-test262"
3034
path = "src/bin/run_test262.rs"
35+
required-features = ["test262-host"]
36+
37+
[[test]]
38+
name = "oracle_create_realm"
39+
path = "tests/oracle_create_realm.rs"
40+
required-features = ["test262-host"]
41+
42+
[[test]]
43+
name = "oracle_host_gc"
44+
path = "tests/oracle_host_gc.rs"
45+
required-features = ["test262-host"]
46+
47+
[[test]]
48+
name = "oracle_is_html_dda"
49+
path = "tests/oracle_is_html_dda.rs"
50+
required-features = ["test262-host"]
3151

3252
[lints.rust]
3353
unsafe_code = "forbid"

‎dev-support/test262/README.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ status ledgers are preserved in the public
2020
[`test262-history-r3ed`](https://github.com/pocket-stack/quickjs-oxide/releases/tag/test262-history-r3ed)
2121
release asset. Its authenticated inventory is in `archive/index.tsv`.
2222

23+
The `$262` realm and agent host is excluded from default library, CLI, and
24+
WASM builds. The central gate explicitly enables the non-default
25+
`test262-host` feature when it builds `run-test262`. Feature-specific checks
26+
can be run with `cargo test --locked --features test262-host --lib --bins`.
27+
2328
Official progress reports lead with full pass and eligible coverage. Runnable
2429
pass rate is secondary. A new admission must be expressed in profile data and
2530
must validate the correct negative phase/type and QuickJS diagnostic rule; the

‎docs/status.md‎

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ The exact profile, inputs, summary, line counts, and report hashes live in
2929
- native command-line execution and a Rust/WASM browser playground
3030

3131
The public API and Test262 runner now report the same engine diagnostics.
32-
Detached public bytecode/VM execution has been retired, and the Test262 runner
33-
loads a data profile instead of compiling historical milestone identity tables.
32+
Detached public bytecode/VM execution has been retired, the Test262 runner
33+
loads a data profile instead of compiling historical milestone identity tables,
34+
and its `$262` realm/agent host is isolated behind a non-default feature.
3435

3536
## Remaining parity work
3637

@@ -40,14 +41,15 @@ recorded by the current Test262 vector. A Feature Parity claim additionally
4041
requires the acceptance contract in [`parity.md`](parity.md), including QuickJS
4142
differential evidence and non-Test262 behavior.
4243

43-
Architecture hygiene remains ahead of new admission batches: move the `$262`
44-
host behind a non-default dev-support feature, consolidate integration targets
45-
and oracle helpers, and strengthen negative diagnostic comparison.
44+
Architecture hygiene remains ahead of new admission batches: consolidate
45+
integration targets and oracle helpers, then strengthen negative diagnostic
46+
comparison.
4647

4748
## Verification
4849

4950
```sh
5051
cargo test --locked --workspace --all-targets
52+
cargo test --locked --features test262-host --lib --bins
5153
./scripts/test-test262.sh --check
5254
./scripts/test-test262.sh --focused
5355
TEST262_WORKERS=2 ./scripts/test-test262.sh --full
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
#!/usr/bin/env bash
2+
# Keep the Test262 host out of default library, CLI, and WASM builds.
3+
4+
set -euo pipefail
5+
export LC_ALL=C
6+
7+
script_dir=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)
8+
root=$(CDPATH='' cd -- "$script_dir/.." && pwd)
9+
cd "$root"
10+
11+
die() {
12+
echo "error: $*" >&2
13+
exit 1
14+
}
15+
16+
command -v cargo >/dev/null 2>&1 || die "cargo is required"
17+
command -v python3 >/dev/null 2>&1 || die "python3 is required"
18+
19+
metadata=$(mktemp "${TMPDIR:-/tmp}/quickjs-oxide-metadata.XXXXXX")
20+
trap 'rm -f -- "$metadata"' EXIT
21+
cargo metadata --locked --format-version 1 --no-deps > "$metadata"
22+
23+
python3 - "$metadata" <<'PY'
24+
import json
25+
from pathlib import Path
26+
import sys
27+
28+
29+
def fail(message: str) -> None:
30+
raise SystemExit(f"error: {message}")
31+
32+
33+
metadata = json.loads(Path(sys.argv[1]).read_text())
34+
packages = {package["name"]: package for package in metadata["packages"]}
35+
36+
engine = packages.get("quickjs-oxide")
37+
if engine is None:
38+
fail("cargo metadata omitted the quickjs-oxide package")
39+
if engine["features"].get("default") != []:
40+
fail("quickjs-oxide default feature set must stay empty")
41+
if engine["features"].get("test262-host") != []:
42+
fail("quickjs-oxide must expose an empty, opt-in test262-host feature")
43+
44+
runner = [target for target in engine["targets"] if target["name"] == "run-test262"]
45+
if len(runner) != 1:
46+
fail("cargo metadata must contain exactly one run-test262 target")
47+
if runner[0].get("required-features") != ["test262-host"]:
48+
fail("run-test262 must require exactly the test262-host feature")
49+
50+
host_tests = {
51+
"oracle_create_realm",
52+
"oracle_host_gc",
53+
"oracle_is_html_dda",
54+
}
55+
for target_name in host_tests:
56+
targets = [target for target in engine["targets"] if target["name"] == target_name]
57+
if len(targets) != 1:
58+
fail(f"cargo metadata must contain exactly one {target_name} target")
59+
if targets[0].get("required-features") != ["test262-host"]:
60+
fail(f"{target_name} must require exactly the test262-host feature")
61+
62+
web = packages.get("quickjs-oxide-web")
63+
if web is None:
64+
fail("cargo metadata omitted the quickjs-oxide-web package")
65+
engine_dependencies = [
66+
dependency
67+
for dependency in web["dependencies"]
68+
if dependency["name"] == "quickjs-oxide"
69+
]
70+
if len(engine_dependencies) != 1:
71+
fail("WASM wrapper must have exactly one quickjs-oxide dependency")
72+
dependency = engine_dependencies[0]
73+
if dependency["uses_default_features"] or dependency["features"]:
74+
fail("WASM wrapper must disable default features and enable no dev-support feature")
75+
76+
feature = '#[cfg(feature = "test262-host")]'
77+
78+
79+
def require_gated(path: str, declarations: tuple[str, ...]) -> None:
80+
lines = Path(path).read_text().splitlines()
81+
for declaration in declarations:
82+
matches = [index for index, line in enumerate(lines) if line == declaration]
83+
if len(matches) != 1:
84+
fail(f"{path} must contain exactly one declaration: {declaration.strip()}")
85+
index = matches[0]
86+
attributes = []
87+
cursor = index - 1
88+
while cursor >= 0 and lines[cursor].strip().startswith("#["):
89+
attributes.append(lines[cursor].strip())
90+
cursor -= 1
91+
if feature not in attributes:
92+
fail(f"{path} must gate {declaration.strip()} with test262-host")
93+
94+
95+
require_gated(
96+
"src/runtime.rs",
97+
(
98+
"mod test262_agent;",
99+
"mod test262_host;",
100+
"pub use self::test262_agent::{Test262AgentError, Test262AgentSession};",
101+
"use crate::heap::Test262AgentKind;",
102+
" fn call_test262_gc(&self, invocation: NativeInvocation) -> Result<Completion, RuntimeError> {",
103+
" fn set_object_is_html_dda(&self, object: &ObjectRef) -> Result<(), RuntimeError> {",
104+
" pub fn new_code_point_range_function(&mut self) -> Result<CallableRef, RuntimeError> {",
105+
" pub fn new_test262_gc_function(&mut self) -> Result<CallableRef, RuntimeError> {",
106+
),
107+
)
108+
require_gated(
109+
"src/lib.rs",
110+
("pub use runtime::{Test262AgentError, Test262AgentSession};",),
111+
)
112+
require_gated(
113+
"src/heap.rs",
114+
(
115+
"pub enum Test262AgentKind {",
116+
" StringCodePointRange,",
117+
" Test262DetachArrayBuffer,",
118+
" Test262EvalScript,",
119+
" Test262CreateRealm,",
120+
" Test262IsHtmlDda,",
121+
" Test262Gc,",
122+
" Test262Agent(Test262AgentKind),",
123+
" pub(crate) fn set_object_is_html_dda(&mut self, id: ObjectId) -> Result<(), HeapError> {",
124+
),
125+
)
126+
require_gated(
127+
"src/runtime/native_dispatch.rs",
128+
(
129+
" NativeFunctionId::StringCodePointRange => {",
130+
" NativeFunctionId::Test262DetachArrayBuffer => {",
131+
" NativeFunctionId::Test262EvalScript => {",
132+
" NativeFunctionId::Test262CreateRealm => self.call_test262_create_realm(invocation),",
133+
" NativeFunctionId::Test262IsHtmlDda => self.call_test262_is_html_dda(invocation),",
134+
" NativeFunctionId::Test262Gc => self.call_test262_gc(invocation),",
135+
" NativeFunctionId::Test262Agent(kind) => {",
136+
),
137+
)
138+
require_gated(
139+
"src/runtime/intrinsics/array_buffer.rs",
140+
(
141+
" pub(in crate::runtime) fn call_test262_detach_array_buffer(",
142+
" pub fn new_detach_array_buffer_function(&mut self) -> Result<CallableRef, RuntimeError> {",
143+
),
144+
)
145+
require_gated(
146+
"src/runtime/intrinsics/string.rs",
147+
(" pub(in crate::runtime) fn call_string_code_point_range(",),
148+
)
149+
require_gated(
150+
"src/value.rs",
151+
(
152+
" pub(crate) fn try_with_exact_capacity(capacity: usize) -> Result<Self, JsStringError> {",
153+
),
154+
)
155+
156+
gate = Path("scripts/test-test262.sh").read_text()
157+
if "--features test262-host --bin run-test262" not in gate:
158+
fail("central Test262 gate must build run-test262 with test262-host")
159+
160+
gc_gate = Path("scripts/test-host-gc-reentrant-oracle.sh").read_text()
161+
if "--features test262-host" not in gc_gate:
162+
fail("host GC differential must enable test262-host")
163+
164+
parity_gate = Path("scripts/test-parity-slice.sh").read_text()
165+
if parity_gate.count("--features test262-host") < 2:
166+
fail("parity slice must test and lint the Test262 host feature")
167+
168+
workflow = Path(".github/workflows/ci.yml").read_text()
169+
if "./scripts/check-test262-host-boundary.sh" not in workflow:
170+
fail("public fast CI must enforce the Test262 host boundary")
171+
172+
print("Test262 host feature boundary passed.")
173+
PY

‎scripts/test-host-gc-reentrant-oracle.sh‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ fi
9494

9595
if [[ "$run_oxide" == true ]]; then
9696
cargo test --locked --manifest-path "$root/Cargo.toml" \
97+
--features test262-host \
9798
--test oracle_host_gc \
9899
test262_gc_reentry_matches_pinned_quickjs_lifecycle_transcript \
99100
-- --exact

‎scripts/test-parity-slice.sh‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,18 @@ trap - EXIT HUP INT TERM
6262

6363
cargo fmt --all -- --check
6464
QJS_ORACLE="$oracle" cargo test --locked --workspace --all-targets
65+
QJS_ORACLE="$oracle" cargo test --locked -p quickjs-oxide \
66+
--features test262-host --lib --bins \
67+
--test unsupported_diagnostics \
68+
--test oracle_create_realm --test oracle_host_gc --test oracle_is_html_dda
6569
./scripts/test-r3g-class-public-init-oracle.sh --oxide ./target/debug/qjs
6670
./scripts/test-test262.sh --check
6771
./scripts/test-test262.sh --focused
6872
./scripts/test-r3z-async-function-core-oracle.sh --oxide ./target/debug/qjs
6973
./scripts/test-test262.sh --full
7074
cargo clippy --locked --workspace --all-targets -- -D warnings
75+
cargo clippy --locked -p quickjs-oxide --features test262-host \
76+
--lib --bins --test unsupported_diagnostics \
77+
--test oracle_create_realm --test oracle_host_gc --test oracle_is_html_dda \
78+
-- -D warnings
7179
./scripts/check-rust-only.sh

‎scripts/test-test262.sh‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ else
416416
esac
417417
build_host=$(rustc -vV | awk '$1=="host:" { print $2; found++ } END { if (found!=1) exit 1 }')
418418
cargo build --locked --release --target "$build_host" \
419-
--target-dir "$target_dir" --bin run-test262
419+
--target-dir "$target_dir" --features test262-host --bin run-test262
420420
runner=$target_dir/$build_host/release/run-test262
421421
fi
422422
[[ -f "$runner" && -x "$runner" && ! -L "$runner" ]] \

‎scripts/test-web-playground.sh‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ if ! command -v rg >/dev/null 2>&1; then
1818
exit 1
1919
fi
2020

21-
if ! grep -Fqx 'quickjs-oxide = { path = "../.." }' web/wasm/Cargo.toml; then
22-
echo "web wrapper must path-depend on the repository's quickjs-oxide crate" >&2
21+
if ! grep -Fqx \
22+
'quickjs-oxide = { path = "../..", default-features = false }' \
23+
web/wasm/Cargo.toml; then
24+
echo "web wrapper must path-depend on quickjs-oxide without dev-support features" >&2
2325
exit 1
2426
fi
2527

0 commit comments

Comments
 (0)