Commit Graph
4378 Commits
Author SHA1 Message Date
Malte UblandClaude Opus 5.5 e84f656172 Clone Response and Request bodies by teeing their streams
Response.clone() and Request.clone() on checked-dynamic handles answered
'res.clone is not a function' (hono's etag middleware hashes
res.clone().body). The runtime now implements the streams spec's
ReadableStreamDefaultTee over native streams and clones the body with it,
so the original and the clone each read every chunk. A used or locked body
throws undici's TypeErrors, the clone's headers are a copy with the same
guard, and a cloned Request's signal follows the original's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 08:47:43 -07:00
Chris Tate c08ef7aa29 Read emitter analyses from one recorded walk of the module (#1990) 2026-10-23 06:29:19 -05:00
Chris Tate 45de4233de Declare every http2 listener event for once and addListener (#1831) 2026-10-23 06:28:54 -05:00
Chris Tate efc351f202 Read emitter analyses from one recorded walk of the module
The LLVM emitter's constructor runs many analyses that each walk every
function body to collect facts from a few node kinds. IrNodeIndex
(ir/node-index.ts) walks the bodies once, before those analyses, and
records each body's nodes in everyStmtList's order with a kind code per
node and the kinds present per function. An analysis names the kinds it
reads and receives exactly those nodes, in the same order, without
recursing through the tree; a function the index does not hold (a
rewritten copy) is walked as before. The index also lists the distinct
type objects of the module, which the boxed-union and runtime-feature
scans read instead of walking every expression's type tree.

These read the index: walk borrows, appended array literals, constant
callbacks and the rebinding census, int32 slots (dynamic field stores,
call facts, the box census, candidate writes and the range walks),
initializer bindings, stack observations, the may-throw call-graph
census, published types and construction facts, final fields, stable
globals, reference writes (private arrays, call targets, definitions,
fresh constructors), boxed unions and runtime features. Analyses whose
walks track their position (statement lists, nesting, ordered
dataflow) keep their own walks.

Callers outside the emitter pass no index and walk as before. The
emitted LLVM IR is unchanged.

packages/compiler/native/cli.profdata.gz is refreshed with
scripts/refresh-cli-profile.mjs on this change, so the native
compiler's optimization profile covers the rewritten analyses.
2026-10-23 06:22:00 -05:00
Chris Tate a85c7c0a3b Read native handle methods as function values (#1984) 2026-10-23 06:02:41 -05:00
Chris Tate d9544bb71d Release EventTarget's shared method values at exit when only a signal read them
The EventTarget method values are cached for the program, and exit
released them only when an EventTarget, an event or a listener had
registered the unit's teardown. A program that read an AbortSignal's
addEventListener and never added a listener or made a target left the
cached functions live, and RC-audit builds exited with 99. Caching a
method value now registers the teardown too.
2026-10-23 05:57:37 -05:00
Chris Tate 8d17fe4e57 Support crypto.getCipherInfo, AES-CCM and AES key wrap (#1873) 2026-10-23 05:36:21 -05:00
Chris Tate 8ec8423510 Keep package-created values of interfaces extending package interfaces dynamic (#1988) 2026-10-23 05:33:44 -05:00
Chris Tate 19e0fe8bcd Merge main and read cipher options through getters and prototypes 2026-10-23 05:33:14 -05:00
Chris Tate 40c3f69b40 Read an AbortSignal's EventTarget methods as EventTarget's own
An AbortSignal answered addEventListener, removeEventListener and
dispatchEvent read as values with functions of its own, which only ran on
AbortSignal handles: calling one on a plain EventTarget threw
ERR_INVALID_THIS. In Node they are EventTarget.prototype's methods,
shared with every target. The signal's property read now answers the
EventTarget method values (scr_event_target_method_value), which run on
any EventTarget receiver, AbortSignal included, so
signal.addEventListener === new EventTarget().addEventListener holds.
The signal's own method table keeps throwIfAborted.
2026-10-23 05:31:21 -05:00
Chris Tate 61bae8c5e0 Keep package-created values of interfaces extending package interfaces dynamic
The declaration boundary projected a user-declared interface as plain
data even when it extends a package interface. effect's Request.tagged
constructors create such values (interface Double extends
Request.Request<number>) with a prototype, so the boundary cast threw
"expected a plain object (this value has a prototype)". A user
interface now projects only when every interface it extends is
user-declared too; other values keep their JavaScript-world typing, so
the package finds its prototype members when the value goes back to it.
2026-10-23 05:30:24 -05:00
Chris Tate 63fd3cecb7 Build @hono/node-server 2.x into scriptc (#1886) 2026-10-23 05:25:14 -05:00
Chris Tate 2ee25d026f Fire spawn listeners for a child that exits before its first poll pass (#1986) 2026-10-23 05:23:16 -05:00
Chris Tate f0d0384b6d Revert "Reuse the bundled declaration files' diagnostics across builds" (#1987) 2026-10-23 05:22:55 -05:00
Chris Tate a8484aea07 Address review feedback on request-body streaming 2026-10-23 05:22:01 -05:00
Chris Tate 47490f0bca Revert "Reuse the bundled declaration files' diagnostics across builds (#1981)" 2026-10-23 05:16:33 -05:00
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 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
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 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
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 6e9023ed1f Merge main 2026-10-23 03:04:14 -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