The hosted loop's scheduling entries (a tick, a timer or an immediate goes
through the bootstrap's helpers; a checkpoint drains ticks and microtasks)
and island process-event listeners called the bridge on whatever stack the
runtime was on: the main thread's for the first checkpoint, or an async
fiber's. JavaScript then ran there, and a collection it triggered failed
V8's "Check failed: isolate_->IsOnCentralStack()" (node-island-handles,
about 1 run in 15 sanitized: promise reactions run by the first checkpoint
on the main stack allocated a microtask). They now run on Node's stack like
every other entry, below the mark when they come from a fiber.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dyn.mathFold steps the iterator of an untyped iterable, so the generator
dispatch pass now counts it among the runtime entry points that step
iterators. A generator whose only consumer is Math.min or Math.max then has
its step hooks registered, and the spread folds its values instead of
throwing "Reading this native iterator result has no lowering".
A CCM decipher skipped its one update() when the data was empty, and
final() accepted when an update had run without failing, so it never
compared the tag. setAuthTag() with any tag of the right length, then
update() with empty data, then final(), succeeded: anyone could forge an
empty message, or one with different AAD or a different declared
plaintextLength, without the key.
A decipher's update() now runs the authenticated decryption for empty
data too. As in OpenSSL, the tag covers the nonce, the AAD and the
length, so the right tag still opens an empty message and any other
tag, AAD or length fails in final() with "Unsupported state or unable to
authenticate data". final() succeeds only after a tag comparison has
succeeded. A cipher's empty update() is unchanged.
A fresh TypeScript data literal passed to a checked-dynamic slot became a
typed view whose record layout requires every property, so a JavaScript
callee deleting one (zod 4's `normalizeParams` deletes `params.message`
from `.refine(fn, { message })`) threw "Cannot delete property". When
the callee is implemented in JavaScript (a call through an untyped value,
an untyped parameter of a JavaScript function, or a non-library `.d.ts`
signature whose parameter is untyped or makes one of the literal's
properties optional), the literal has no typed alias and is now built as
the plain object the callee receives. Standard-library and TypeScript
callees, and literals with methods or accessors, keep their native
storage.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The self-hosted compiler spreads only known record shapes and tests a
value against null with == or != only as a plain read (SC1090).
rewriteCandidates in int32-arrays.ts spread whole IR statement and
expression unions: each spread now names one kind. The loop and block
cases spread per kind, the hoisted read and sequence rewrites narrow with
an if, switch cases spread through a typed helper, and the inlined
ternary, a fresh copy, takes the call's location directly. The checked
int32 array test in int32-slots.ts binds the range it reads first.
tsc-ts 0.0.8's API server serves on the named pipe the Node host
connects over on Windows (tsc-ts --api --pipe), and the native compiler
already starts it over its standard streams there, so tsc-ts is the
default checker on every platform. SCRIPTC_CHECKER=tsgo still selects
tsgo.
The compiler depends on tsc-ts 0.0.8, which the release-age exclusions
admit with its platform packages and @scriptc/threads 0.4.2.
The Windows CLI smoke test runs with both checkers, and
verify-native-cli.mjs --run checks that a distribution's tsc-ts runs on
its platform (tsc-ts.exe on Windows).
A method whose name an untyped write can replace is called through the
instance's property lookup: a ternary between the dynamic call of an
installed replacement and the native call, both boxed into a dynamic
value and converted back to the method's result type. A result with no
dynamic form, such as an Iterable<T> (its generator arm does not box),
stayed unboxed in the dynamic ternary, which failed IR validation with
"ternary else-branch: expected dyn, got union". Methods of generic class
instantiations always take this path once any write can replace their
name, because their prototype data is not modeled, so importing zod
(whose JavaScript has unknown-key writes) broke every such call.
Such a result now keeps its native type: the native call's value is used
as it is, and only a replacement's dynamic result takes the checked
conversion into the result type. Results that box are lowered as before.
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>
The shim compiles inside each program that imports the package, and under
some lib and @types/node settings ReadableStreamReadResult<Uint8Array>
lowered as unknown while reader.read() produced a record, so the
buffered-read path refused (SC2003). The shim spells out its read-result
record and types the body reader.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
BigInt(typedArray) compiled in JavaScript but stopped at run time with
SC2020. Node converts the typed array through ToPrimitive to its elements
joined with "," and parses that text: one element reads as its value, an
empty array as 0n, and several elements, fractions, NaN, Infinity or an
exponent form throw the SyntaxError for the joined text.
- BigInt of a typed array lowers to bigint.parse of its "," join, the same
conversion Node performs.
- A union whose arms are typed arrays and other BigInt sources dispatches
each typed-array arm the same way.
Corpus 7403 covers every supported element kind, negative and clamped
values, float formatting (2 ** 60 reads through its shortest decimal
text), empty arrays and views, the SyntaxError cases and results in
arithmetic, and matches Node.
Refs #1647
Co-authored-by: Quino Terrasa <26749475+espetro@users.noreply.github.com>