Commit Graph
3302 Commits
Author SHA1 Message Date
Chris Tate a0894cc488 Give constructor functions native stream state over the stream classes (#1533) 2026-10-20 13:21:25 -05:00
Chris Tate 5344367219 Read constructor-function stream hooks when they run
A constructor-function stream now reads `_final` and `_flush` when its
writable side finishes, and `_transform` for each chunk, as Node does. A hook
assigned after `Writable.call(this)` or `Transform.call(this)` runs, and an
override of a PassThrough's `_transform` replaces the pass-through. Without
`_final` or `_flush` the finish continues as Node's does.

A runtime stream passed to a constructor-function stream's listeners, such
as the source of a 'pipe' event, is the view whose pipe and unpipe accept
constructor-function streams, so `src.unpipe(this)` in a 'pipe' listener
unpipes instead of throwing.
2026-10-20 13:16:29 -05:00
Chris Tate 178e524662 Compile events.once with an AbortSignal and over streams, and combine Promise.race entries around it (#1531) 2026-10-20 13:04:20 -05:00
Chris Tate 3751afa51f Merge main 2026-10-20 13:02:01 -05:00
Chris Tate 24c73ac7fb Compile any crossings: destructuring, namespace patterns, any parameters and async callbacks (#1503) 2026-10-20 12:58:51 -05:00
Chris Tate e181687405 Merge main 2026-10-20 12:55:10 -05:00
Chris Tate 54e419f89a Declare the WebAssembly W5 and stream-slot entry points in the runtime headers (#1535) 2026-10-20 12:54:23 -05:00
Chris Tate 97bf98cd89 Declare the WebAssembly W5 and stream-slot entry points in the runtime headers
The backend can emit scr_wasm_memory_construct, scr_wasm_table_construct,
scr_wasm_global_construct, scr_wasm_construct_without_new,
scr_wasm_module_imports, scr_wasm_module_exports,
scr_wasm_module_custom_sections and scr_wasm_value_of (#1410), and
scr_stream_dyn_native, scr_stream_pipe_dyn and scr_stream_unpipe_dyn
(#1524). Their prototypes were in scr_wasm.c or nowhere, so the runtime
ABI guard failed. They are now in scr_wasm.h and scr_stream.h, and
scr_wasm.c no longer repeats the header's declarations.

The speculative-hoisting test relied on `v instanceof Num` in a
JavaScript function failing, which constructor-function instanceof now
compiles (#1512). Its hoisted function reads the prototype through
Reflect.getPrototypeOf instead, which still fences.
2026-10-20 12:50:19 -05:00
Malte UblandClaude Opus 5.5 5f3efe314c Format the runtime-pack matrix entry
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 10:35:49 -07:00
Chris Tate 73a595692f Let NodeJS stream interface slots hold JavaScript stream objects (#1524) 2026-10-20 12:32:16 -05:00
Malte UblandClaude Opus 5.5 b89594c276 Keep the legacy Stream constructor on the EventEmitter unit
Programs whose only stream value is the legacy Stream do not need the
stream half.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 10:31:10 -07:00
Chris Tate 28f1646461 Unpipe JavaScript destinations on unpipe() without a destination
With checked-dynamic stream slots, readable.unpipe() also unpipes every
JavaScript destination stream.pipeDyn registered from the source, oldest
pipe first. Each destination hears 'unpipe' and the source pauses, as in
Node's unpipe(), which empties every pipe. Before, those pipes stayed
attached and later chunks still reached them.
2026-10-20 12:29:12 -05:00
Chris Tate a8ee60d5fa Write invisible characters in the WebAssembly spec data as escapes (#1532) 2026-10-20 12:24:37 -05:00
Chris Tate cf003870ee Write invisible characters in the WebAssembly spec data as escapes 2026-10-20 12:18:55 -05:00
Chris Tate 8ac2d854cf WebAssembly W5: the Memory, Table and Global constructors, Module.imports/exports/customSections, and function references from tables (#1410) 2026-10-20 12:12:19 -05:00
Chris Tate cfb94177e9 Adapt method overrides across ABI differences, write Error codes, and close wrapper-reachable gaps (#1497) 2026-10-20 12:10:19 -05:00
Chris Tate ae3642d1bb Merge main 2026-10-20 12:08:37 -05:00
Chris Tate 76227c86c8 Merge main 2026-10-20 12:07:23 -05:00
Chris Tate cb8eb5972e Merge main 2026-10-20 12:04:40 -05:00
Malte UblandClaude Opus 5.5 2a9328cc5c Pipe a runtime stream into constructor-function streams in the transform corpus program
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 09:54:08 -07:00
Chris Tate eea3bc5447 Specialize variadic generic wrappers to the wrapped function's signature (#1413) 2026-10-20 11:52:34 -05:00
Malte UblandClaude Opus 5.5 73e40f4196 Merge main
pipe() into an untyped destination now comes from main's pipeIntoDyn
(stream.unboxDyn); programs with constructor-function streams unbox
through scr_dyn_builtin_stream.c, which also takes those streams, so the
separate dyn.builtinStreamPipe entry point is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 09:49:43 -07:00
Chris Tate 0d82842725 Read memarg flags through a function so the compiler compiles itself (#1530) 2026-10-20 11:48:40 -05:00
Chris Tate f4f2baf1a9 Treat optional members an index signature covers as keys, erase 'as never', and keep fromEntries objects asserted to records (#1496) 2026-10-20 11:46:21 -05:00
Malte UblandClaude Opus 5.5 507610b90d Give constructor functions native stream state over the stream classes
Bundled npm code (from2, bl, tar-stream, yazl, multistream) builds its
streams as ES5 constructor functions: util.inherits(Ctor, Readable) and
Readable.call(this, opts), with _read/_write/_transform on the
prototype. Readable.call(this) threw SC2020.

A new runtime unit, scr_dyn_builtin_stream.c (feature
dynBuiltinStream), gives the untyped stream constructors their stream
half. Base.call(this, opts) creates a runtime stream over the receiver
and keeps it in a hidden slot; the runtime calls the receiver's
underscore methods through its property lookup; the stream prototypes
carry Node's methods and accessors over the hidden stream; and
EventEmitter's methods register listeners with the runtime stream's
emitter, so runtime events and pipes reach JavaScript listeners with the
receiver as this. _readableState/_writableState are live views.

Stream class values now come from dyn.builtinStreamClass, so only
programs that use them link the stream half. Typed code sees these
objects as their runtime streams: checked casts to the stream classes
take them, readable.pipe() into an untyped destination pipes into them,
and runtime streams crossing into JavaScript answer the constructor
object.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 09:46:05 -07:00
Chris Tate 9cfadc5e5e Bake mixed-scalar JSON tables and destructure unions of arrays and tuples (#1455) 2026-10-20 11:42:50 -05:00
Chris Tate 08a3a7cf06 Read memarg flags through a function so the compiler compiles itself
readMemargFlags took its reader as a `{ u32(): number }` record, and the
validator (Reader) and translator (WasmCursor) pass class instances. The
self-hosted compiler refuses a class instance in a record-typed parameter
(SC2002), so the self-hosted LLVM emitter, the native frontend programs
and the bootstrap seed builds failed. readMemargFlags now takes the
reader's u32 function, and each caller passes `() => r.u32()`.
2026-10-20 11:41:40 -05:00
Chris Tate f7287e30ff Keep the fromEntries assertion bridge to entries without native arrays or records
Object.fromEntries(...) as T passed the entries through the
checked-dynamic bridge, which copies native arrays and records: an array
shared by two entries, or held elsewhere, became separate copies, and
writes through the asserted object no longer reached it. The bridge now
applies only when the entries' values are scalars or checked-dynamic
values, which pass by value or by identity; other entries keep the
exact-shape fence (SC2002). Corpus 6467 checks that entries held as
unknown keep their identity; diagnostics fixture
fromentries-aliased-entries.ts pins the fence.
2026-10-20 11:40:52 -05:00
Chris Tate 437dc1163f Refuse recursive unions in comptime baking
The bakeability check tracks the unions it is inside as well as the
records, so a union reachable from itself through an array
(`type Tree = number | Tree[]`) reports SC1090 instead of recursing without
end. The message names both recursive records and recursive unions.
2026-10-20 11:39:23 -05:00
Chris Tate a43f0a71a6 Merge main 2026-10-20 11:36:33 -05:00
Chris Tate f41ca8bbd8 Update tests for the EvalError and builtin module changes (#1529) 2026-10-20 11:35:19 -05:00
Chris Tate 8823556a84 Let constructor functions inherit from EventEmitter and the stream classes (#1512) 2026-10-20 11:32:22 -05:00
Chris Tate ba73b5236e Compile compound assignment, ++/-- and ??= through literal-union and index-signature record keys (#1527) 2026-10-20 11:31:26 -05:00
Chris Tate 99af5c878b Merge main and cover a block-local arguments alias that shadows an outer one
- Merge origin/main (e9fb01603); the import lines at the top of
  lowerer.ts conflicted and both are kept.
- Corpus 6385 gains a wrapper whose block-local `args` alias shadows an
  outer one in the same function; each call forwards its own arguments.
2026-10-20 11:30:11 -05:00
Chris Tate 5aa4ccc3f2 Update tests for the EvalError and builtin module changes 2026-10-20 11:28:48 -05:00
Chris Tate 447f56e5c3 Share defaultMaxListeners with the typed EventEmitter, link instanceof alone, and clean up a pipe once
- EventEmitter.defaultMaxListeners on the untyped constructor is Node's
  accessor over the default the typed EventEmitter reads: assignments
  validate as validateNumber(arg, 'defaultMaxListeners', 0) does, and
  getMaxListeners() of emitters without their own limit answers the new
  value.
- dyn.builtinInstanceOf and dyn.functionInstanceOf link the
  constructor-function unit and the units it calls (dyn-invoke, inspect,
  symbol, emitter), so a program whose only use is `this instanceof F`
  links.
- The legacy pipe's cleanup runs once: when the destination emits
  'close' from end(), the cleanup still queued on the source's 'end'
  finds the listeners removed and emit('end') answers true.
2026-10-20 11:28:28 -05:00
Chris Tate e9fb01603f Compile NodeJS.ReadableStream and NodeJS.WritableStream as general streams when a program mixes stream producers (#1518) 2026-10-20 11:24:09 -05:00
Chris Tate 324f173f65 Merge main 2026-10-20 11:23:45 -05:00
Chris Tate 1818faef10 Keep a process stream open when JavaScript pipes into it
pipe() called from untyped JavaScript on a native stream went through
scr_stream_pipe directly, so a helper that piped into the converted
process.stdout or process.stderr ended it at the source's end, and later
writes through the program's NodeJS.WritableStream slots failed. The
stream view's pipe now calls scr_stream_pipe_general, which keeps end off
for those Writables, as Node's pipe() does for process.stdout and
process.stderr.

Adds corpus 6469.
2026-10-20 11:20:28 -05:00
Chris Tate 19e2da69a3 Compile Transform option callbacks and loosely typed child-process listeners (#1519) 2026-10-20 11:16:08 -05:00
Chris Tate 68dac76fdc Treat setEncoding's return value as the stream it was called on
A method call declared to return `this`, such as setEncoding, resolves to
its receiver's access path, so a 'data' listener on the stream that
`const out = child.stdout.setEncoding("utf8")` returns receives strings.
A setEncoding call that a preceding statement always evaluates (its
expression, a variable initializer, or the receiver of a method chain in
one of those) counts as preceding the listener. Only `new` and the
child_process factories (spawn, fork, exec, execFile) count as creating a
separate stream; any other call result may be a stream another binding
already holds.
2026-10-20 11:11:59 -05:00
Chris Tate 73778e8496 WebAssembly W3–W4: translate modules to native code at build time, implement the JavaScript API over them, and send modules to workers (#1395) 2026-10-20 11:06:25 -05:00
Chris Tate 25780d9231 Merge main 2026-10-20 11:03:09 -05:00
Chris Tate 8eb5ad28e5 Keep WebAssembly references and memory storage alive while they are in use; merge main
Externrefs a guest holds are borrowed pointers. An import's result was
kept only until the outermost call returned, which was before the export
call converted its results to JavaScript, so a result created by an
import was freed before conversion. A table or global slot released the
reference it replaced at once, although the guest may still hold it in a
local after reading the slot. The kept references are now released after
the outermost caller has converted its results (scr_wasm_leave), and a
table or global store during a call keeps the reference it replaces until
then.

Checked memories (explicit bounds checks: sanitized builds, Windows)
grew with realloc, which can move the storage that memory.buffer and its
views alias. They now reserve the address space for their largest size
(mmap on POSIX hosts, VirtualAlloc on Windows) and commit pages as they
grow, so the base never moves. Hosts without address-space reservation
grow in place only until a buffer has been handed out; after that,
growth that would move the storage fails.

Tests: webassembly-externref-lifetimes.mjs (import results through an
export, table and global references replaced by the guest and by
JavaScript), webassembly-memory-growth.test.ts (views written after
growth from JavaScript and from the guest), and translate.test.ts cases
for memargs naming memory 0 explicitly and for local.tee operand types,
which b3bcbaaf7 made consistent with validation. Under SCRIPTC_SAN=1 the
two runtime tests report heap-use-after-free without these changes.

Merges main; internal/compatibility/generated/node-v24-backlog.json is
regenerated with pnpm node-compat.
2026-10-20 10:58:34 -05:00
Malte UblandClaude Opus 5.5 d883c84752 Add corpus programs for events.once with a signal, over streams, and in races
6490 covers events.once with an AbortSignal: abort, an aborted signal, an
undefined signal, abort-listener order, 'removeListener' events, a
throwing 'newListener' listener and the settlement turns. 6491 covers
stream receivers (file streams, Readable.from, a destroyed PassThrough, a
Writable) and a NodeJS.ReadableStream part raced against its destination.
6492 covers races over events.once results with entries that only reject
and entries of different value types. 6493 covers stream subclasses whose
completion callbacks are typed `Function`. 6494 covers events.once over
checked-dynamic stream slots. The node-types fixture runs the race shapes
under @types/node, where events.once returns Promise<any[]>.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 08:48:00 -07:00
Malte UblandClaude Opus 5.5 e865594089 Accept NodeJS stream interfaces in the fallback events.once and document its boundary
The fallback declaration of events.once takes NodeJS.ReadableStream and
NodeJS.WritableStream emitters like @types/node does. The diagnostics
fixture now pins the forms that stay refused (options that are not an
object literal, a computed name, a stream's 'data' event), and the
limitations page states the supported events.once forms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 08:47:59 -07:00
Malte UblandClaude Opus 5.5 67ace26573 Unbox native streams for events.once over checked-dynamic stream slots
Under checked-dynamic NodeJS stream slots, events.once over a
NodeJS.ReadableStream or NodeJS.WritableStream slot unboxes a native
stream by identity and takes the stream path; any other value throws the
not-supported Error that for await and pipeline stages already throw for
JavaScript stream objects.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 08:47:53 -07:00
Malte UblandClaude Opus 5.5 09f427c4fe Accept Function-typed completion callbacks in stream underscore methods
A stream subclass that declares `_transform(chunk, encoding, cb: Function)`
(or _write, _final, _destroy, _flush with a broad `Function` callback) was
rejected because 'Function' has no lowering, which also blocked every
construction of the class. The callback parameter now takes the
checked-dynamic callable the runtime already passes implicitly typed
callbacks, and calls through it are dynamic calls.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 08:47:52 -07:00
Malte UblandClaude Opus 5.5 2630e8438a Combine Promise.race entries whose combined type has no representation
When the checker's combined type has no representation (events.once's
any[] arrays, or 'void | any[]'), the race result takes the one type the
entries that can fulfill share, or 'unknown' when each of them widens into
it; Promise<never> entries do not take part. An entry whose payload widens
into the result type converts through the checked promise payload
widening, which keeps its settlement turn.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 08:47:52 -07:00
Malte UblandClaude Opus 5.5 2429eaf556 Admit Promise<never> race entries (the race part of main's 465abda81)
The Promise.race portion of 465abda81 on main, applied unchanged so the
race changes that follow build on it and merge with main cleanly: a
Promise<never> entry can only reject, so it races under any result type
and its fulfillment adapter traps; a Promise<never> executor's
one-parameter resolve validates against the void inner. Includes that
commit's corpus program 6450.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 08:47:52 -07:00