Skip to content

islands: a value an island made passes the checked conversions - #3029

Merged
ctate merged 4 commits into
mainfrom
ctate/islands-value-island-a1a34a
Nov 8, 2026
Merged

ctate merged 4 commits into
mainfrom
ctate/islands-value-island-a1a34a

Conversation

@ctate

@ctate ctate commented Nov 5, 2026

Copy link
Copy Markdown
Collaborator
  • A checked conversion accepts an island handle: a record reads each field through the handle, and an array, tuple or index-signature record walks a native view of the value that is released at every exit.
  • JSON.stringify, Object.keys and object spread and rest read an island object's own properties in Node, so toJSON, accessors and function-valued members keep their meaning.
  • A program without islands emits exactly the code it emitted before.

A checked conversion accepts an island handle. A record reads each field
through the handle, as Node reads a property; an array, tuple or
index-signature record takes a native view of the value, with the view
released at every exit. JSON.stringify, Object.keys and object spread and
rest read the island object's own enumerable properties in Node, so a
toJSON method, an accessor and a function-valued member keep their
meaning. A program without islands emits the same code as before.
@vercel

vercel Bot commented Nov 5, 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 Nov 8, 2026 12:45am UTC

Comment thread packages/runtime/src/scr_json.c Resolved
Comment thread packages/runtime/src/scr_json.c Resolved
cramforce added a commit that referenced this pull request Nov 7, 2026
#3029 (ctate/islands-value-island-a1a34a) already serializes an island
value in JSON.stringify inside the existing protocol walk: the island
object's kind from an `is_array` slot in ScrNiDynOps, its keys and
members through scr_dyn_obj_keys and scr_dyn_obj_read, an array's
length read in Node, its toJSON with the real key, and cycles by the
handle's referent. This branch carried a second walk for the same thing
(scr_json_island_write, its own `is_array` slot with another signature,
a member-read branch, a toJSON branch and an entry in the compact
walker). Both together would leave two live paths and one struct slot
declared twice, so this merge deletes ours and builds on #3029's. This
PR is now stacked on #3029 and merges after it.

What stays is what #3029's walk does not do, each a small addition on
top of it under SCR_NODE_ISLANDS. Measured with this branch's 37
JSON.stringify cases against #3029 merged with main: 27 match, and
these four behaviours account for the other 10.

- A replacer that is an island function or an island array is honoured
  (scr_json_stringify_value tested the native kinds only and ignored
  it, for island and native values alike), with the boxed String and
  Number keys of an island property list.
- A boxed primitive or a raw JSON object an island made writes V8's
  text. Walked as an object it printed `{}`, `{"0":"s"}` or
  `{"rawJSON":"…"}`. The `scriptc:json` host helper answers it through
  the `json_query` slot, which is kept; the walk asks before it enters
  an island object that is not an array.
- An island symbol is omitted like a native one: `[Symbol()]` inside an
  island object printed `[{}]` where Node prints `[null]`.
- The circular-structure TypeError names an island object's constructor
  (`'Link'`, not `'Object'`): the walk marks the entry it pushes for an
  island object.

Corpus 8886 gains a line for the symbol, with a Map, a Set, a hole,
NaN and -0 beside it. The receiver two-arm call and its tests are
untouched by the merge.

Co-Authored-By: Claude Code <noreply@anthropic.com>
cramforce added a commit that referenced this pull request Nov 7, 2026
Merging #3029 with main changes how most kinds of value cross an island
boundary, and the value matrix main gained after #3029 branched pins the
old answers: 107 of its 239 programs fail on #3029 merged with main, and
the same 107 on this branch.

The table is regenerated here for this tree (SCRIPTC_ISLAND_MATRIX=update,
then a pinned run: 239 of 239). Of its change against main, 4213 entries
to 3509, all but two entries are #3029's and are the same on #3029 merged
with main alone, whose own regenerated table has 3511 entries: 856 gone,
154 new, 172 with another status. This PR's part is two entries gone and
none new: reading a native Map-holding record back by key through an
island (map-obj.p, n2i2n/N.read.getByKey with and without the island
callee) threw and now matches Node.

Co-Authored-By: Claude Code <noreply@anthropic.com>
cramforce added a commit that referenced this pull request Nov 7, 2026
#3029 gained a commit (3787c75) after this branch merged it: its
walk now omits an island symbol like a native one, a toJSON that is an
island function on a native object is called, a handle is tracked by the
value behind its box in the conversion visit, and Array.isArray follows
a proxy in the bridge.

The symbol was one of the four things this branch added on top of that
walk, so the addition here (scr_json_island_symbol and its test in
scr_json_omitted) is deleted and both conflicts resolve to #3029's
side. Three remain on top: island replacers, the text of a boxed
primitive or a raw JSON object, and the constructor name in the
circular-structure TypeError.

Co-Authored-By: Claude Code <noreply@anthropic.com>
cramforce added a commit that referenced this pull request Nov 7, 2026
#3029's new commit changes a few more cells (a proxied array, symbols).
Regenerated for this tree and rerun pinned: 239 of 239. The table has
3515 entries; #3029 merged with main alone regenerates to 3517, and
the difference is the same two entries as before, both gone here
(map-obj.p, n2i2n/N.read.getByKey with and without the island callee).

Co-Authored-By: Claude Code <noreply@anthropic.com>
cramforce added a commit that referenced this pull request Nov 7, 2026
#3124 now merges #3029 and builds on its JSON.stringify walk for island
values, and has current main. This merge had no textual conflicts.

Co-Authored-By: Claude Code <noreply@anthropic.com>
cramforce added a commit that referenced this pull request Nov 7, 2026
#3124 merged #3029's review fixes (3787c75) and recorded the island
value matrix for its tree.

Co-Authored-By: Claude Code <noreply@anthropic.com>
cramforce added a commit that referenced this pull request Nov 7, 2026
35384b2 recorded the island value matrix for this branch before
#3124 took #3029. Both sides rewrote the table; this merge keeps
#3124's, and the next commit records it for this tree.

Co-Authored-By: Claude Code <noreply@anthropic.com>
@ctate
ctate merged commit 1496042 into main Nov 8, 2026
29 checks passed
@ctate
ctate deleted the ctate/islands-value-island-a1a34a branch November 8, 2026 00:47
cramforce added a commit that referenced this pull request Nov 8, 2026
…, train perf-2, #2719) into train/pi-1

lowerer.ts, the start of finishModule: main adds the variadic function check
after the generic identity pins call that #3101 deletes. The check stays, the
pins call stays deleted.

Co-Authored-By: Claude Code <noreply@anthropic.com>
cramforce added a commit that referenced this pull request Nov 8, 2026
No conflict. Main brings trains perf-2 and cli-2, #3029 and #3380; lowerer.ts keeps main's checkVariadicFunctions call at the start of finishModule beside the train's code. Regenerating the refusal baseline and the compatibility files on the merged tree changes nothing.

Co-Authored-By: Claude Code <noreply@anthropic.com>
yowainwright pushed a commit to yowainwright/scriptc that referenced this pull request Nov 8, 2026
  import { Type } from "schema-pkg";                  // an island package
  const item = Type.Object({ id: Type.String() });
  export const list = Type.Array(item);

Lowered call by call, each initializer crosses into the island once per
call with its literal arguments, and the first of them starts Node while
the program's modules still initialize, whatever the build deferred. An
initializer built only from literals, island imports, other such
constants, and member reads, calls and `new` on those holds no native
value, so the island can evaluate it itself.

The build writes the initializers of each run of consecutive such
constants into an island module of the shipped tree
(.scriptc/closed/<module>.<digest>.<n>.mjs), loads it where the run's
first constant is declared through nodeIsland.defer, and each constant's
initializer becomes a read of the module's export, met with the conversion
the original expression's value met. The rest is the deferral of a static
island import: the probe decides, the interface snapshot stands in until
Node starts, reconciliation keeps identity. The native constant keeps its
global, type, exports and initialization flag. One module per run: a
native statement between two closed constants still runs between them.

A constant is closed when its value is the island's own on both sides (a
handle or an immutable primitive) and every operand is initialized before
it in every execution; anything else keeps the call-by-call lowering.

A generated module computes from state other island code left behind, so:
- it defers only where the program reaches it at one fixed point of its
  start (before any await, outside conditions, in an initializer only the
  static import graph calls), where the modules probed before it are the
  ones evaluated before it; elsewhere it evaluates at its position;
- a program with generated modules does not use per-module mode, where a
  snapshot would answer for a module while Node runs;
- the probe withholds the effects and inputs of these modules instead of
  performing them: the build does not run the program's effects.

A literal in a closed initializer is now made by the island. On main an
island-made object fails the checked conversion when the program receives
it through an untyped value and asserts it to a native record type; that
case becomes a TypeError until island-made values pass checked
conversions (vercel-labs#3029). Reads typed by the island's declarations are views.

No runtime change.

Co-Authored-By: Claude Code <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
Preview — 9e965b95 Deployed Nov 8, 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.

1 participant