A nested entry below the mark makes its context with ni_make_context,
so macOS clears only the top slice of the range instead of the whole of
Node's stack below the mark on every nested call (17 ms per call, and
the cross-heap GC test ran past its timeout).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The libnode-linux action becomes .github/actions/libnode, which serves
the Linux x64 and macOS lanes: the libnode-packs cache for the runner's
platform, else the development pack.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
macOS binds libnode's own calls to v8::base::Stack inside libnode, so the
bridge's definitions cannot give V8 Node's stack as they do on Linux; V8
took the main thread's stack start and its conservative scan faulted in
the gap above Node's stack. While Node starts on its stack, the main
thread's pthread record now names that stack, which V8 reads once and
keeps.
macOS's makecontext clears the whole stack it is given, so it gets only
the top slice of Node's stack (no 64 MiB pass per context).
CI: dev-pack.json pins mirrored darwin-arm64 and darwin-x64 libnode
builds of the pinned Node 24.22.0 from the libnode-packs workflow, the
dev-pack action serves either platform, and the macOS lanes provision it,
so island tests fail rather than skip on macOS CI. The arm64 LLVM job
runs the island harness; the Intel job runs it and the island corpus.
bridge-smoke loads the .dylib bridge on macOS.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ABI 5 takes a load function from the bootstrap's dispatcher; without it
the smoke program's start fails with an incomplete dispatcher.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main's FinalizationRegistry took handle tag 72, so the Node island
handle moves to 73. Island handles keep their instanceof path in the
new scr_bytes_instanceof_at.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The libnode packs' smoke program (#1684) still used the pump/alive/
backend_fd entries that the hosted loop (#1696) replaced, so every
Build libnode pack job failed to compile it. It now provides the full
host table and dispatcher and runs Node's event loop once after starting
the asynchronous calls, as the runtime does at the end of a program.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
structuredClone in an island of a value holding native records, class
instances or objects (interceptor objects V8's serializer cannot clone)
clones a plain copy of that data, as Node clones the objects themselves.
An island array of primitives or strings (or arrays of those) returned
directly or through a promise crosses as a copy, which the checked cast
then meets, instead of failing the cast as an object handle.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A plain object a program passes into an island is an object-template
instance, which inherits from its implicit constructor's prototype object;
island code that checks for plain objects (jose's isObject:
Object.getPrototypeOf(o) === Object.prototype) rejected it. The instance now
inherits Object.prototype directly. Corpus 6826 checks it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CI's island lanes fall back to the development pack (dev-pack.json: Node
24.22.1, no package.json) until the libnode-packs cache exists, so the
smoke test, which verifies a @scriptc/libnode-<platform> package against
the 24.22.0 pin, failed there. It now runs only when SCRIPTC_LIBNODE names
a package directory. The pack package versions follow the 0.4.2 release
(scripts/sync-versions.mjs), which pin.test.ts checks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>