Skip to content

Share modules between a program and its Node islands through loader hooks (NI-6) - #1902

Open
cramforce wants to merge 19 commits into
ni/i4-deferredfrom
ni/i5-shared-modules
Open

cramforce wants to merge 19 commits into
ni/i4-deferredfrom
ni/i5-shared-modules

Conversation

@cramforce

@cramforce cramforce commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #1901. Fifth of nine Node islands PRs.

What it does

A module that both the program and island code import must exist once.

  • Ownership (frontend/lowering/lower-shared-modules.ts). Island code is made of requireModule() targets, the JS files of island packages, and the uncompiled files they import. A specifier that resolves to a compiled module makes that module a candidate.
    • Program modules are shared.
    • npm packages are shared when stateful and duplicated when pure. scriptc.packages.<name>.share overrides this, and duplicating a stateful package is SC8020.
    • Island code that subclasses a module's class makes an npm package Node-owned (SC8022, then rebuilt as an island). For a program module, SC8022 is a refusal.
  • Registration. The entry's %init header calls nodeIsland.share(realpath, exports, accessor) per shared module. Exported let/const read a TDZ flag. Exported classes get method tables and a construct helper.
  • Runtime. A registry plus host callbacks shared_table, shared_get and shared_tdz. scr_ni_shared_refresh pushes changed bindings at every boundary crossing. Class representatives answer Symbol.hasInstance. Export tables, class tables and the registry are released at exit.
  • Bridge (ABI 7). Adds natives sharedTable/sharedGet/sharedTdz and the shared_push entry.
  • Hooks (scr_node_island_hooks.cjs, appended to the embedded bootstrap). module.registerHooks({resolve, load}) serves a generated ES module at the shared module's own file URL, so require() and import see the same instance. Cycles that hit a TDZ go through an entry module, so V8 throws its own ReferenceError.
  • The deferred-evaluation probe's bootstrap answers sharedPush.

Evidence

  • Corpus programs 6850–6854, byte-identical with Node:
    • a singleton mutated from both sides, with a live let and require(...) === ns;
    • a shared class, with instances from either side and instanceof both ways;
    • a native package → island → native package cycle with Node's TDZ errors;
    • the registry scenario in two forms: Node-owned through SC8022, and shared over native exports.

Shortcuts

  • Island code is found by a regex scan of its specifiers, not by parsing. A false positive only adds a shared module.
  • Island subclasses of scriptc-owned classes are not supported. A runtime construct with a foreign new.target throws a TypeError.
  • Re-exports, export default <expression> and CommonJS modules are not shared (SC8020 when stateful).
  • Refresh calls each bound module's accessor at every crossing, which is linear in the number of exports.

Gate results

  • Island set in a Vercel Sandbox, with the libnode dev pack rebuilt from this branch's bridge (node-island*.test.ts, npm.test.ts, packages/compiler/src/node-islands, differential 68xx): plain 223/223 + diff 57/57; sanitized 223/223 + 57/57.
  • pnpm lint, pnpm format:check and pnpm test:ts7 --baselines-only pass.
  • The self-hosted compiler (packages/compiler/src/native/cli.ts --emit=llvm) builds.
  • Zero-cost gate: 2838 programs identical (benchmarks, self-hosted compiler, TypeScript corpus) against the base branch. The only DIFFERS is corpus/fs-extra-package (%m0.settleVoid). It differs in every gate of the stack, including Bound V8's stack scan by Node's own stack in Node islands #1898, which does not touch the compiler, so it is nondeterministic on the base. both-fail covers only the island programs, because the gate host has no libnode pack. Compile time stays within tolerance.

CI on the first push found failures outside the focused island set: the ABI in bridge.test.ts, the runtime ABI header declarations, the effect gate on the ts7 allowlist, weak collections in the compiler, the pipeline scout and the Node version line. The fixes are folded into the PRs that introduce each piece, and they are re-checked in a Sandbox on the final tree.

Stack

#1898
#1899
#1900
#1901
→ #1902
#1903
#1904
#1905
#1906
#1907
#1908

🤖 Generated with Claude Code

@vercel

vercel Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
scriptc Ready Ready Preview, v0 Oct 26, 2026 11:38pm UTC

Comment thread packages/compiler/src/frontend/lowering/lower-shared-modules.ts
Comment on lines +81 to +86
} else if (e.kind === "let" || e.kind === "var") {
lines.push(`let ${local} = __s.bind(${mod}, ${slot}, (v) => { ${local} = v; });`);
lines.push(`export { ${local} as ${name} };`);
} else {
lines.push(`const ${local} = __s.get(${mod}, ${slot});`);
lines.push(`export { ${local} as ${name} };`);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reassigning an exported function declaration leaves island imports pointing at the original function because function exports are snapshotted rather than bound for refresh.

Fix on Vercel

Comment thread packages/compiler/src/frontend/lowering/lower-shared-modules.ts
…ooks (NI-6)

Node islands stack, part 5 of 11 (scriptc-perf/results/islands-prs/PLAN.md).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	packages/compiler/src/backend/llvm/lib-shared.ts
#	packages/compiler/src/ir/builtin-effects.ts
#	packages/compiler/src/ir/builtin-signatures.ts
#	packages/libnode-common/bridge/scr_node_bridge.cc
cramforce and others added 2 commits October 23, 2026 06:42
…uires

ABI 7 takes sharedPush from the bootstrap's dispatcher as well.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel-security-reviewer

Copy link
Copy Markdown

Security review details

# Conflicts:
#	packages/compiler/src/frontend/lowering/lower-modules.ts
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
Preview — fd7a9179 Deployed Oct 26, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants