Commit Graph
6750 Commits
Author SHA1 Message Date
Chris Tate eb2fa3c829 Fire spawn listeners for a child that exits before its first poll pass
A child spawned from a listener that runs during a poll pass, such as a
'close' listener, can exit before the next pass fires its 'spawn'
listeners. The same pass's waitpid loop then settled it with 'spawn' never
emitted. Settling an exited child now fires its pending 'spawn' listeners
first, before its stream data and 'exit', as Node emits them.
2026-10-23 05:14:51 -05:00
Chris Tate 6dfef89863 Record a class's bag initializer only when its class-table branches agree (#1985) 2026-10-23 05:10:42 -05:00
Chris Tate ed1786869b Record a class's bag initializer only when its class-table branches agree
A per-class field-creation helper creates an instance's property bag with
the class's recorded initializer. A class can carry several: three.js's
Material bag is created with Material's own prototype for Material
instances and through the per-instance prototype dispatch for subclass
instances, and the first one was recorded. MeshStandardMaterial instances
then got bags with Material's prototype, and writes to their own fields
(roughness, metalness, color) through setValues stored into the bag. The
initializer is now recorded only when every branch's initializer is the
same; other classes create their bags through the class tables.
2026-10-23 05:06:48 -05:00
Chris Tate 952e01d2ed Stream request bodies in the Node server adapter 2026-10-23 05:03:12 -05:00
Malte UblandClaude Opus 5.5 ec833b9a02 Record the handle method values fixture's baseline and cost
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 02:57:19 -07:00
Chris Tate 0222bb1058 Keep fiber stacks across short event-loop sleeps (#1977) 2026-10-23 04:52:57 -05:00
Chris Tateandblurname d1f3eda732 Freeze arrays, Maps and Sets that other references still hold
Object.freeze of an array that another reference may still hold stopped at
compile time with SC2020, and freezing an array, Map or Set held in an
untyped value threw SC2020 at run time. Node freezes the object itself: a
frozen array refuses every later write through any reference with the
TypeError of the operation's first write, and a frozen Map or Set only
stops being extensible, since its entries are not properties.

- An array a program may freeze keeps a frozen bit in its storage flags.
  An array type is freezable when a typed Object.freeze names it, or, in a
  program that freezes untyped values, when a value of it can be held as a
  live untyped reference. The writes of those types test the bit with the
  guard published arrays already use; other array types are unchanged.
- The guard's errors follow Node for every operation: splice, fill,
  copyWithin, sort and reverse throw at their first write, and do not
  throw when they would write nothing. Published arrays get the same
  errors, and a statement splice of a published array is now guarded.
- A Map or Set records that it is not extensible, for Object.freeze, seal
  and preventExtensions, typed or untyped. Object.isFrozen, isSealed and
  isExtensible report it, and its entries stay writable.
- Writes to a frozen array through an untyped value are refused with the
  same errors, as are writes to frozen checked arrays and objects, which
  now name the property and the object as Node does.
- Programs that neither freeze nor publish arrays compile to the same IR
  and LLVM.

Corpus 7406 covers typed and untyped freezes of arrays, Maps and Sets,
every array write on frozen arrays of zero, one and three elements,
comparator sorts, nested arrays, and frozen arrays that are released, and
matches Node.

Refs #1374

Co-authored-by: blurname <50226652+blurname@users.noreply.github.com>
2026-10-23 04:50:06 -05:00
Chris Tate 50c8e1c693 Assign private fields through untyped receivers with logical assignment (#1983) 2026-10-23 04:46:35 -05:00
Chris Tate 900bd2cf01 Check generateKeyPair arguments and RSA parameters as Node does (#1973) 2026-10-23 04:39:34 -05:00
Malte UblandClaude Opus 5.5 72736211b1 Assign private fields through untyped receivers with logical assignment
`other.#x ??= value` (and `||=`, `&&=`) on a receiver JavaScript leaves
untyped read and wrote an ordinary property named "#x" instead of the
brand-checked private field, so the field kept its old value. Hono's
RegExpRouter numbers its parameter nodes with `next.#varIndex ??=
context.varIndex++`; without the stored index its regular expression lost
every parameter capture, and `c.req.param("id")` answered undefined.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 02:38:34 -07:00
Malte UblandClaude Opus 5.5 0e0458f292 Keep literal key order through self copies and conversions that build no records
A literal that starts by spreading a value of its own type, such as
`{ ...current, ...patch, updatedAt }`, made the key-order witness give up
on the type: the copy's source order was the type's own order, seeded
with the declared table, so it conflicted with the literals that build
the values. While no checked conversion builds the type, every value has
the one chosen order and the copy adds no witness.

Checked conversions also counted as builders of records they cannot
create: a class instance's field records, a checked function's record
parameters, a boxed primitive (the undefined a dynamic construction
passes for a missing argument), and the result of a typed call of a
method the program may replace on its instance, which without a
replacement is the method's own native value boxed and checked back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 02:38:33 -07:00
Chris Tate 53838b39ec Call methods of bag-tracked class instances without building their views (#1979) 2026-10-23 04:37:54 -05:00
Chris Tate 58d3603549 Accept a callable Proxy as the generateKeyPair callback
generateKeyPair tested its callback, and a function in the options
position, by the checked-dynamic kind, so a Proxy whose target is a
function threw ERR_INVALID_ARG_TYPE. Node checks typeof, which answers
"function" for such a Proxy. Both tests now ask whether the value is
callable.
2026-10-23 04:33:56 -05:00
Chris Tate 695a90b0c1 Reuse the bundled declaration files' diagnostics across builds (#1981) 2026-10-23 04:32:18 -05:00
Chris Tate d8139c7bdb Test the function tag before comparing a class constructor's key (#1980) 2026-10-23 04:27:37 -05:00
Chris Tate fb200c1240 Reuse the bundled declaration files' diagnostics across builds 2026-10-23 04:27:14 -05:00
Chris Tate 03807c0c35 Run private members and super calls over foreign receivers like Node
A JavaScript class's prototype method called with a receiver that is not an
instance of its class (`C.prototype.m.call(other)`, or an object that
inherits the method) now behaves as in Node when it uses private members or
calls super methods, instead of throwing "expected C" for the receiver.

- Private fields keep their brand check: reading or writing `this.#x` throws
  "Cannot read private member #x from an object whose class did not declare
  it" (or the write message), and `#x in this` answers false.
- `this.#m()` brand-checks the receiver through a new `call` use of the
  private brand helpers and throws "Receiver must be an instance of class C"
  (V8's wording: the class's own identifier, "anonymous" without one, and
  "Cannot read properties of undefined (reading 'C')" for a nullish
  receiver). It also applies to private method calls on other
  checked-dynamic values.
- `super.m(...)` looks the method up on the base class's complete prototype
  object and calls it with the receiver, as `super` reads
  [[HomeObject]].[[Prototype]].

Methods that use `super` in other positions, static methods with private
names, and classes whose base chain includes a function-local, generic,
mixin, Date or runtime-provided class keep the native receiver check. The
receiver-independent method lowering and the prototype reflection now mark
their frames as `this` boundaries, so lowering one class's members on top of
another method's frames (a super call reflecting the base) never reaches the
caller's `this`.
2026-10-23 04:11:54 -05:00
Chris Tate 029845e9c0 Keep values written through unknown[] views in typed arrays 2026-10-23 04:07:06 -05:00
Chris Tate a1df13a73b Merge main 2026-10-23 03:55:00 -05:00
Chris Tate fb3806ce42 Search TypedArrays, read stdin through 'readable', and assign constructor-function globals
- TypedArray indexOf, lastIndexOf and includes on every element kind, typed
  and checked-dynamic: strict equality (SameValueZero for includes) and
  fromIndex as ToIntegerOrInfinity. A Buffer reached through a Uint8Array
  value keeps Buffer's search.
- process.stdin 'readable' with read() and read(size), including sizes
  above the read-ahead mark and input a once('readable') listener leaves
  for a later 'data' listener. for await over process.stdin yields Buffers.
- Module bindings holding `new F()` of a constructor function can be read
  and reassigned from other functions.
2026-10-23 03:54:26 -05:00
Chris Tate 945a519036 Match Node for typed pipeline callbacks and rl.cursor on non-terminal interfaces 2026-10-23 03:49:51 -05:00
Chris Tate 91e15f3426 Run child_process and http2 events in Node's AsyncLocalStorage contexts
child_process and http2 events ran with no store, or with the context of
whichever socket dispatch delivered them. Node runs them in the context
of the handle or request that produces them.

child_process: a child, its piped stdout, stderr and stdin, and its IPC
channel keep the context of the spawn() or fork() call. 'spawn',
'error', 'exit', 'close', stdout's and stderr's 'data' and 'end', and the
channel's 'message' and 'disconnect' run in it, in the POSIX and the
Windows implementations. stdin's 'drain' and 'error' run in the context
of the latest write() call, its 'finish' in the context of its end()
call, and a send() callback in the context of its send() call.

http2: a session keeps the context it was created in, the
http2.connect() call for a client and the server's listen() context for
a server session, and the session's socket callbacks and deferred emits
run in it. A client stream keeps the context of its request() call, and
the frames that drive a stream's events (DATA, WINDOW_UPDATE, RST_STREAM,
and a client's HEADERS) and its deferred emits run in the stream's
context. A session remembers the stream its last lookup by id found, so
the context lookup and the frame's own handling share one search.
A server stream and its compatibility request and response run with no
store, as Node's do. An accepted h2c socket's own events run with no
store, as an accepted net socket's do, so a server.close() that waits for
its sessions calls back with no store; a TLS server's sockets keep the
listen() context, as before.

Corpus 7385 to 7389.
2026-10-23 03:40:52 -05:00
Chris Tate 8bb9ee8c57 Check generateKeyPair arguments and RSA parameters as Node does 2026-10-23 03:38:18 -05:00
Chris Tate 64db69aefc Declare the property-bag helpers in the runtime header (#1972) 2026-10-23 03:33:07 -05:00
Chris Tate 9e41d505b6 Declare the property-bag helpers in the runtime header
scr_dyn_bag_create_field and scr_dyn_is_class_capsule are declared by
the LLVM backend; their prototypes move from scr_json.c into scr_dyn.h,
which llvm-runtime-abi.test.ts checks the backend's declares against.
2026-10-23 03:30:06 -05:00
Malte UblandClaude Opus 5.5 5aef6597ab Test the function tag before comparing a class constructor's key
dyn.classIs went through the generic library call: retain the receiver,
call scr_dyn_class_is_key, release it (and buffer it as a cycle candidate).
A class's static property bag dispatch (%dyn.class.staticProperties) runs
one probe per compiled class for every untyped property read, so this cost
about 500 instructions per read in a Hono app. The probe now tests the
value's function tag inline, as the capsule probes test theirs, so LLVM
skips the chain for every other value, and borrows the receiver across a
literal key.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 01:28:47 -07:00
Malte UblandClaude Opus 5.5 3cbd1740a8 Call methods of bag-tracked class instances without building their views
Untyped code calling a method on an instance of a compiled JavaScript class
whose own properties live in a property bag materialized the instance's
whole checked view on every call (copying the bag, boxing each field and
attaching the prototype) only to read one member. Hono's Context declares
its methods as arrow-function fields, so every c.header() or c.json() from
middleware rebuilt an 18-property view.

The materializer of such a class gives the view exactly the bag's
string-keyed properties, the declared fields among them with their native
slot values, and the class's prototype. The compiler now emits those parts
as ScrDynTypedBagClassOps (bag, prototype, declared field names, field
getter) and binds them to the class's capsules, and scr_dyn_invoke resolves
a member that is an ordinary data property, own or inherited, from them,
calling it with the capsule as this. Accessors, read-only fields, capsule
prototype links and everything else still build the view.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 01:28:46 -07:00
Chris Tate 892758e86b Test catch bindings against class bindings (#1968) 2026-10-23 03:26:31 -05:00
Chris Tate 8d6bb60847 Test caught values against the class a class binding holds
A class binding may hold a subclass of the class it was declared with.
When the declared class has subclasses, a caught payload of that class is
now tested against the class the binding holds, as for other operands, so
a base-class instance no longer passes a test against a subclass.
2026-10-23 03:20:31 -05:00
Chris Tate e7bced94fd Let LLVM merge the comparisons of a three-way string comparator 2026-10-23 03:20:04 -05:00
Malte UblandClaude Opus 5.5 2f903f0255 Read native handle methods as function values
Methods of Web objects held in untyped code (Request, Response, Headers,
ReadableStream, its reader, AbortSignal) answered member calls only by
static name, so a property read such as hono's `raw[key]()` or
`typeof req.json` saw undefined. A handle class now lists the methods its
invoke answers; a read returns one shared function per method that calls
invoke on its `this` and raises Node's ERR_INVALID_THIS TypeError (or a
rejected promise for the async operations) on another receiver. The in
operator sees the methods and the modeled properties.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 01:13:24 -07:00
Chris Tate 4511be6307 Give rebuilt property-bag stores their prototype (#1967) 2026-10-23 03:09:00 -05:00
Chris Tate 9c9fb6531a Replay class objects with their base names, and restore the inspector after a refusal
- The emitter journal that forked workers merge (#1919) records each class
  object entry whole, and the entries carry baseNameSym beside nameSym.
  The replay cast named only nameSym, which the native compiler refuses
  (SC1090), so the self-hosted LLVM emitter did not build.
- An inspection refusal (the 'not supported yet' Error of insp.dyn)
  propagates out of the emitted inspect helpers before they close their
  frames and before util.inspect's layout options are restored. The open
  frames, their indentation and the custom layout then shaped every later
  console.log and util.inspect. A top-level render through helpers that
  can reach a checked-dynamic view, a generator or a class instance now
  runs in a lifted wrapper that takes insp.mark first and calls
  insp.unwind in a finally. A render under breakLength, compact or sorted
  restores the default layout in a finally the same way.
- A non-enumerable accessor that %o shows, and any accessor of a
  checked-dynamic object, renders as [Getter], [Setter] or
  [Getter/Setter], as Node prints it, instead of its value slot.
- Under %o, an array's non-enumerable own properties follow its named
  ones in brackets (`[ 1, 2, [length]: 2, foo: 'x', [hid]: 3 ]`), as Node
  prints them; corpus 6357 covers [length] ahead of named properties.
2026-10-23 03:07:29 -05:00
Chris Tate b9275c2693 buffer: fromArrayBuffer ranges, the deprecated constructor, Buffer as a value 2026-10-23 03:05:19 -05:00
Chris Tate 6e9023ed1f Merge main 2026-10-23 03:04:14 -05:00
Chris Tate ac40773362 Excuse date.fromTime in the attestation parity test
date.fromTime makes a Date from the time value a Date local holds and
reads no ambient state. The local's initializer is the Date expression
the fences witness.
2026-10-23 02:54:19 -05:00
Chris Tate 88d15a8ea7 Call own accessors over an Error's name and message from typed code (#1957) 2026-10-23 02:48:44 -05:00
Chris Tate 4d83db26bd Index strings through checker-any receivers (#1965) 2026-10-23 02:44:28 -05:00
Chris Tate a474ff7e8d Check for Error accessors after definitions over object-typed targets
The reflection gate turned on only for an untyped or Error-shaped
defineProperty target, so a helper taking `target: object` (or `{}`,
`Object`, a weak type, or a type parameter) installed a message or name
accessor that typed Error reads then skipped, returning the old slot
value. The gate now turns on for any target an Error may flow into: an
untyped or generic type, a type Error is assignable to, or an
Error-shaped type, alone or in a union or intersection.
2026-10-23 02:43:57 -05:00
Chris Tate b948d7946b Run match and search with untyped patterns (#1966) 2026-10-23 02:43:38 -05:00
Chris Tate 6318d35679 Iterate untyped Headers values (#1969) 2026-10-23 02:42:23 -05:00
Malte UblandClaude Opus 5.5 b1214f7607 Test catch bindings against class bindings
e instanceof E where e is a catch binding and E a binding holding a class expression (var E = class extends Error {}) refused with "'instanceof' right-hand sides other than classes declared in the program". The binding holds exactly that class, so the test is the class's caught test (hono's SmartRouter fallback on UnsupportedPathError).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 00:37:51 -07:00
Malte UblandClaude Opus 5.5 e269262d73 Iterate untyped Headers values
entries(), keys() and values() on a checked-dynamic Headers value threw 'is not a function'. They now return live native iterators over the sorted header list, re-read on every step with set-cookie values one by one, as Node's Headers iterator does (hono's Context copies response headers this way).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 00:37:51 -07:00
Malte UblandClaude Opus 5.5 fdcee191da Give rebuilt property-bag stores their prototype
Worklist passes that transform every function (the class-construction dispatch rewriting dyn.classBasePrototype) rebuild statement objects, so a recorded lazy bag store could be a detached copy. When the class gained prototype data later, only the copy was upgraded and the live store kept creating a bare {} bag: inherited methods read as undefined through the property bag (hono's SmartRouter.match once zod was in the program). Upgrades now also reach the stores as they stand in the generated bodies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 00:37:50 -07:00
Malte UblandClaude Opus 5.5 be6e63735a Index strings through checker-any receivers
An implicit-any package function specialized for a string argument lowered base?.[0] to the element-access refusal: the checker types the receiver any, so only the lowered string reached the string-index path. Hono's mergePath failed at startup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 00:37:49 -07:00
Malte UblandClaude Opus 5.5 b8d442e3ae Run match and search with untyped patterns
s.match(p) and s.search(p) with an untyped pattern now choose at run time, as Node does: a RegExp is used as is (with its lastIndex state), any other value builds new RegExp(value). The checked-dynamic receiver form previously threw 'method calls like path.match on a string are not supported yet' (hono's RegExpRouter matcher).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 00:37:49 -07:00
Chris Tate 3c8ccc7b97 Keep package results that pass their argument through out of the declaration boundary (#1964) 2026-10-23 02:30:41 -05:00
Malte UblandClaude Opus 5.5 bcd506fc8b Return ASCII header values as their own ByteString
Converting a header value to a ByteString read it one UTF-16 code unit at a
time through scr_str_char_code_at into a fresh buffer. An all-ASCII value,
which nearly every header is, is already its own ByteString, so it is now
returned as is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 00:29:28 -07:00
Malte UblandClaude Opus 5.5 1edb2fe92d Keep fiber stacks across short event-loop sleeps
Finished fiber stacks went back to a spare pool that the event loop
unmapped whenever it was about to sleep. A server's loop sleeps between
nearly every pair of requests, so each request that awaited mapped, faulted
in and unmapped a fresh 512 KiB stack: on a Hono server mmap, munmap and the
page faults were about a fifth of its CPU time. Spares now outlive short
sleeps. At most once a second a sleep unmaps the spares that no fiber took
since the previous trim, and a sleep longer than two seconds unmaps them
all, so an idle program still returns the memory.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 00:29:27 -07:00
Malte UblandClaude Opus 5.5 342cf3a063 Copy class-view property bags entry by entry
Materializing the checked view of a JavaScript class instance copies its
property bag through scr_dyn_copy_property_descriptors, which built a key
string and a descriptor object per property and defined each through
scr_dyn_define_property (about 2k instructions per property). Plain objects
on both sides now copy each entry directly with the attributes, value or
accessor pair and own-key order the definition gives; properties the target
already has, non-extensible targets and other receivers keep the general
path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 00:29:22 -07:00