Commit Graph
4405 Commits
Author SHA1 Message Date
Chris Tate e771de1cfb Check cycle bindings only where early code can reach the reading function (#1882) 2026-10-23 10:02:29 -05:00
Chris Tate dddcb339aa Revert "Cache untyped property access in programs that declare classes" (#1996) 2026-10-23 09:35:24 -05:00
Chris Tate 0f8dd276d9 Reach a class's methods from its class expression's inner name in static initializers
A named class expression's own name (const C = class Impl { static x =
Impl.m(); }) names the class inside its body as the binding it is stored
in names it outside. The reachability walk followed only stored binding
names, so a static initializer calling a method through the inner name
did not reach that method, and its early reads of the other cycle
member's bindings lost their TDZ checks: the program read the binding
before its declaration ran (a crash), where Node throws ReferenceError.
The inner name now maps to its class expression.
2026-10-23 09:24:28 -05:00
Chris Tate 885a829959 Compile minified npm packages such as marked (#1989) 2026-10-23 09:07:41 -05:00
Chris Tate a10c183b13 Revert "Cache untyped property access in programs that declare classes (#1995)" 2026-10-23 09:05:55 -05:00
Chris Tate 17c069667e Settle a var declared by a for-in or for-of loop only inside the loop body
A for-in or for-of loop stores its var binding only when it iterates. The
early-read analysis counted the loop as an unconditional store for every
later statement, so after a loop that ran zero times a closure read the
binding as initialized (typeof answered "string" where Node answers
"undefined"). The loop now settles the reads in its body; later reads
settle at the next unconditional store.
2026-10-23 09:03:59 -05:00
Chris Tate da2173d54b Cache untyped property access in programs that declare classes (#1995) 2026-10-23 08:47:07 -05:00
Chris Tate 4b60ac0de9 Copy class-view property bags entry by entry (#1976) 2026-10-23 08:43:19 -05:00
Chris Tate fa22b991cc Return ASCII header values as their own ByteString (#1978) 2026-10-23 08:42:17 -05:00
Chris Tate 8eedab9fde Cache untyped property access in programs that declare classes
A program that declares a class reads and writes untyped properties
through helpers that first select the receiver's property bag. The bag
helpers return jsvals, so the helpers read the bag through js.toDyn;
keyed helpers test each class's key table between the key's coercion and
the read; and a program with subclasses normalizes the receiver
(value = %dyn.class.normalize(value)) at the start of each helper. The
inline-cache recognizer accepted none of these forms, so every property
site in such a program called its helper. It now looks through dyn/jsval
conversions of the receiver, accepts capsule branches before a keyed
helper's final read, and accepts a rebinding of the receiver to a bag of
itself. Plain objects and arrays then read and write through the site's
cache, as they do in programs without classes.

bench/dynamic-properties (new) exercises these sites.
2026-10-23 08:41:40 -05:00
Malte Ubl 3be0a1e468 Merge remote-tracking branch 'origin/main' into HEAD 2026-10-23 06:38:28 -07:00
Malte Ubl 2365c04417 Merge remote-tracking branch 'origin/main' into HEAD 2026-10-23 06:38:10 -07:00
Malte Ubl be7a194bfd Merge remote-tracking branch 'origin/main' into HEAD 2026-10-23 06:33:24 -07:00
Chris Tate 8476f68136 Support writev on Transform and PassThrough, and runtime stream option values (#1944) 2026-10-23 07:53:59 -05:00
Chris Tate d1b63c782c Keep every field when an object converts to a union with an empty-record arm (#1992) 2026-10-23 07:53:37 -05:00
Chris Tate 1221104388 Merge main and fix CI 2026-10-23 07:50:09 -05:00
Chris Tate 5c015be6be Try wider record arms first when a dyn value converts to a union
Records are width-tolerant, and a union's arms were tried in canonical
order, which sorts record arms by shape id. When a `{}` arm, or an arm
whose fields are all optional, came first, it took every object, so a
value converted to the union lost the fields only a wider arm has:

    const pairs = [["a", { publicKeyEncoding: 5 }], ["b", {}]];
    for (const [, v] of pairs) console.log(Object.keys(v));

printed [] twice, where Node prints [ 'publicKeyEncoding' ] and [].
A checked cast to `{ p: number; q: string } | { p?: number }` dropped
`q` the same way.

The checked conversion now tries record arms with more required fields
first, then those with more fields, and keeps the canonical order
otherwise. The union's tags are unchanged.
2026-10-23 07:47:26 -05:00
Chris Tate b8a6a6a939 Expect an untyped dependency of an opted-in library package to compile
The test refused unchecked-dependency only because its one-line index.js
looked minified. A dependency another package's JavaScript imports needs
no declarations of its own (npmStaticIneligibleReason's untypedDependency),
so with the minified refusal gone it compiles; the test now builds it and
checks the library's result.
2026-10-23 06:59:05 -05: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 ba5d73e90b Recognize esbuild's __commonJS helper under a minified name
Refs #1777

An identifier-minified esbuild bundle renames the __commonJS helper
(var j=(u,t)=>()=>(t||u((t={exports:{}}).exports,t),t.exports)). The
recognizer already compared the helper's shape independently of its
parameter names, but only used a renamed match to refuse the package.
A stable top-level declaration with the helper's shape now splits the
bundle's chunks like the named helper, so lru-cache's CommonJS build is
no longer refused.
2026-10-23 06:20:02 -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 967f2ec85d Compile minified npm entries and untyped regex arguments
Refs #1777

npm packages are no longer refused up front for minified JavaScript. A
bundle whose interop helpers lost their names is still refused by the
bundle recognizers, and a package whose attempt fails is still refused on
its own.

A `var` read in a later declarator of the statement that stores it
(`var a = {...}, b = {...a}`) runs after the store. A read in a function
body is now located at the body's own statement instead of the body, so
JavaScript `var` bindings read after their store in a function keep their
type instead of gaining undefined.

`replace` and `replaceAll` with an untyped search value and a callback
call the regex callback replacement for a RegExp and the string-search
helper otherwise. That helper now accepts untyped callback parameters,
passes undefined to parameters after the subject, and converts number,
boolean and untyped results with ToString.

In JavaScript, `||` and `&&` over primitives of different types whose
result tsc types `any` evaluate in the checked domain.
2026-10-23 05:55:39 -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 945a519036 Match Node for typed pipeline callbacks and rl.cursor on non-terminal interfaces 2026-10-23 03:49:51 -05:00