Commit Graph
6750 Commits
Author SHA1 Message Date
Chris Tate acfa46a919 Decide a Date's zone name at the instant, not from the offset cache
- Date toString and toTimeString now decide the zone name's daylight flag at the instant itself, as V8's LocalTimezone does. The offset cache's segments hold offsets only, as V8's do. Before, a merged segment kept the DST flag of the read that created it, so a zone that left daylight time without changing its offset could print the summer name after the change: Africa/Algiers on 21 October 1977, at +0100 on both sides.
- Corpus date-zone-intervals.ts reads Algiers across that day in three orders; the names match Node.
2026-10-21 00:11:47 -05:00
Chris Tate 2c502c0a27 Answer 511 for an empty event-loop-delay histogram's percentiles (#1618) 2026-10-21 00:10:13 -05:00
Chris Tate 00840aaca6 Merge main 2026-10-21 00:08:02 -05:00
Chris Tate 4004d4c9d0 Answer 511 for an empty event-loop-delay histogram's percentiles
Node creates monitorEventLoopDelay's histogram with a lowest discernible
value of 1000 ns, so an empty histogram's percentile() returns 511, the
highest value its first bucket holds. The runtime returned 0.

6397-event-loop-metrics.ts now skips a sampling window that has no
recorded delta. A delta needs two samples after reset(), and a loop that
wakes late runs only one sample in a window, so on a loaded machine the
program printed an empty window under Node and compiled alike. The
program also prints percentile(50) after each reset.
2026-10-21 00:06:54 -05:00
Chris Tate 0c27def467 Run child accessors on the child, and find child property writes in every JavaScript file
- A getter or setter that JavaScript defines on a child process now runs with the child as `this`, instead of the hidden object that holds the child's added properties, for reads, writes and member calls. A write to a getter-only accessor throws "Cannot set property x of #<ChildProcess> which has only a getter".
- The scan for properties JavaScript writes onto children now covers every JavaScript file of a program that loads child_process, so a module that patches a child it received counts even when it never names child_process.
- The scan's cache and the program's "writes onto children" flag live on the Lowerer instead of a WeakMap and a WeakSet.
- Corpus 6611 covers a module that adds a replaced method, an accessor pair and a getter-only accessor to a child it did not spawn.
2026-10-20 23:41:21 -05:00
Chris Tate 19c88fedb4 Iterate untyped values with for await, and delegate with yield* in async generators (#1564) 2026-10-20 23:25:24 -05:00
Chris Tate a1c55207fc Merge main 2026-10-20 23:21:29 -05:00
Chris Tate 99c63271e9 Cache zone offsets with V8's date-cache algorithm
- The zone-offset cache now follows Node's V8 date cache (DateCache::LocalOffsetInMs): 32 segments of instants with one offset each, the 19-day lookahead, merges of segments with the same offset, a binary search of up to five probes for a change point, and least-recently-used replacement. Local Date getters then answer as Node's do in every order of reads, including the order-dependent answers around Tucumán's two offset changes in June 2004. The previous single-interval cache differed from Node in about half of the seeded orders tried.
- Scattered reads hit a cached segment more often: a getter benchmark over consecutive and scattered instants runs in 169 ms instead of 314 ms (America/New_York; Node 567 ms).
- Corpus date-zone-intervals.ts adds seeded orders of reads around the Tucumán changes and across three years in four zones.
2026-10-20 23:12:10 -05:00
Chris Tate ddc7fe8b0d Store number-key map entries in 16 bytes and size the direct index near the largest key 2026-10-20 23:01:43 -05:00
Chris Tate 4dd62802c8 Bound loop counters compared as i + c with a bound (#1463) 2026-10-20 22:56:44 -05:00
Chris Tate 2783b96100 Round a loop bound to an integer before taking the counter's offset off it
- Narrowing `x + c < b` and its other comparison forms subtracted the offset from the bound in floating point. A fractional bound could then round across an integer: `x + 2147483648 > -(2 ** -60)` gave the minimum -2147483647, which leaves out -2147483648. The bound now rounds to an integer first, and the offset comes off in exact integer arithmetic. Integer bounds give the same facts as before.
- A unit test covers that comparison.
2026-10-20 22:54:32 -05:00
Chris Tate f31b97ee64 Pin the zone-offset cache's answers across a double offset change to Node's
- The zone-offset cache keeps an offset over 19 days when both ends agree, as V8's date cache does. America/Argentina/Tucuman changed its offset twice within 12 days in June 2004, so in Node the answers between the two changes depend on the order of the reads: ascending reads keep the May offset through June 12, and descending reads see the June offset.
- The cache's comment now states that behavior, and corpus date-zone-intervals.ts reads those days in both orders. Its output matches Node for each order.
2026-10-20 22:32:08 -05:00
Chris Tate 43f1c445e8 Keep counters a for loop bounds in integer shadows (#1491) 2026-10-20 22:31:47 -05:00
Chris Tate 6bf550e11f Treat bindings a for loop's condition or update writes as unbounded
- The bounded-loop analysis collected writes from the loop body only. A binding the condition writes (`i < ((source = values[i]), values).length`) then passed as stable, so a cursor copied from it took the source's entry range, and its integer shadow truncated fractional values. The condition and the update are now scanned too, and a binding either one writes is neither a stable bound nor a copy source.
- Corpus 5686 adds a copy whose source the condition writes with fractional values.
2026-10-20 22:29:56 -05:00
Chris Tate 7ef3011f6c Start small arrays with three inline slots (#1613) 2026-10-20 22:06:12 -05:00
Chris Tate b602cdc76e Start small arrays with three inline slots 2026-10-20 22:01:41 -05:00
Chris Tate e5af4def98 Promisify untyped functions at run time (#1502) 2026-10-20 21:54:51 -05:00
Chris Tate 012fdb3fb0 Merge main 2026-10-20 21:52:19 -05:00
Chris Tate 69ef7da7f8 Run death-triggered full collections at the event loop's idle moments (#1522) 2026-10-20 21:48:02 -05:00
Chris Tate 44c586b1ee Run a waiting death pass at the idle moment even after the heap shrank 2026-10-20 21:44:46 -05:00
Chris Tate 0cb4c3ffea Give the deep fs.cp test a per-process scratch directory (#1612) 2026-10-20 21:32:43 -05:00
Chris Tate a4f9b1f66e Give the deep fs.cp test a per-process scratch directory 2026-10-20 21:30:01 -05:00
Chris Tate 24eb054395 Compile the hot-shots StatsD client over UDP (#1568) 2026-10-20 21:29:48 -05:00
Chris Tate 79f98f4684 Regenerate the compatibility files offline, and after merges (#1609) 2026-10-20 21:25:47 -05:00
Chris Tate b811317f26 Keep String method arguments read before another argument's conversion runs
concat, substr and the other typed String and Number extra methods
convert their arguments after evaluating all of them. When an argument's
conversion can run program code (an object's toString or valueOf), a
variable read of the receiver or another argument is now kept in a local
as well, so a conversion that assigns the variable leaves the
already-evaluated argument unchanged, as in Node.
2026-10-20 21:22:29 -05:00
Chris Tate 100e7738a0 Keep generated-file conflicts until regeneration succeeds, and take the side for the merged pin
regen-generated.mjs resolved each conflicted generated file with
`git checkout <ref> --`, which also staged it, so a failing generator left
the conflict resolved with the branch's stale file. It now writes the
chosen side's file to the working tree only and stages it after both
generators succeed.

It also always took MERGE_HEAD's ledger, so merging a branch with an older
Node pin into one with a newer pin regenerated from a ledger for the older
pin and failed. It now takes the side (index stage 2 or 3) whose ledger is
for the merged pin in node-v24.json, and when neither is, stops and says
to run pnpm node-compat, which fetches the pinned docs.
2026-10-20 21:21:14 -05:00
Chris Tate 7dd9fc3b9f Put each limitations sentence on its own line (#1611) 2026-10-20 21:15:00 -05:00
Chris Tate bde7afa980 Compile undici from a built-in implementation (#1425) 2026-10-20 21:14:37 -05:00
Chris Tate 36a5ff72d2 Put each limitations sentence on its own line 2026-10-20 21:12:48 -05:00
Chris Tate 3abf43affd Use the events module and EventEmitter as untyped constructor values (#1544) 2026-10-20 21:12:06 -05:00
Chris Tate d59d8ff6f2 Merge main and count declaration writes to parameters 2026-10-20 21:05:19 -05:00
Chris Tate eb8a148605 Merge main 2026-10-20 21:01:40 -05:00
Chris Tate 115a763df8 Check that the limitations partials keep one sentence per line (#1571) 2026-10-20 20:59:02 -05:00
Chris Tate adf4912d83 Run the partials check before oxlint in pnpm lint
pnpm appends forwarded arguments to the end of a script, so with the
partials check last, `pnpm lint:fix` and `pnpm lint --format=json` passed
their flags to the check instead of oxlint. The check now runs first; it
prints nothing when the partials are split, so oxlint's output, JSON
included, is unchanged.
2026-10-20 20:56:56 -05:00
Chris Tate 53171c282d Read and write dynamic-tier properties through shapes and inline caches (#1396) 2026-10-20 20:52:12 -05:00
Chris Tate 9c24e64ee2 Regenerate the compatibility files offline, and after merges
pnpm node-compat fetched Node's docs on every run, even though only the
classification changes between pins. pnpm node-compat --local now
reclassifies the committed ledger rows from the current sources and
rewrites the ledger and the public artifact, the same files a fetching
run writes while the pin is unchanged. scripts/regen-generated.mjs uses
it after a merge: for each generated file still in conflict it takes the
merged-in branch's version, regenerates the surface manifest and the
compatibility files from the merged sources, and stages them, so these
files never need a hand merge.
2026-10-20 20:50:04 -05:00
Chris Tate 9a802fe635 Leave the per-chapter status counts out of the compatibility files (#1608) 2026-10-20 20:48:27 -05:00
Chris Tate 06e202a126 Leave the per-chapter status counts out of the compatibility files
The ledger and the public artifact held a block of status counts for
every chapter. Nothing reads them (the docs page uses a chapter's slug
and title), and every classification change rewrote its chapter's block,
so concurrent compatibility changes conflicted there. The rows they were
counted from are unchanged.
2026-10-20 20:46:25 -05:00
Chris Tate 5e2e65a805 Build the Node compatibility backlog from the ledger instead of committing it (#1576) 2026-10-20 20:44:36 -05:00
Chris Tate 70e0af8094 Keep shapes off objects that threads share
A published graph is immortal and shared by pointer across threads, but a
shape names a node of one thread's transition tree, which ends with that
thread. A worker that read a published object through a cache left its
shape in the object; after the worker exited, the main thread's reads
followed it into freed memory. Immortal objects now stay unshaped, and
publishing (postMessage's shared graphs and @scriptc/threads publish)
clears a shape the object already has.
2026-10-20 20:44:14 -05:00
Chris Tate 3ef1b9f7be Merge main 2026-10-20 20:40:58 -05:00
Malte UblandClaude Opus 5.5 3b4ddd4c8d Keep object literals' key order through IR rewrites and on shapes typed JSON.parse also builds
The key-order witness pass chose a shape's enumeration table from the
order its object literals write their keys, but two gaps sent literal
values back to the declaration order (JSON.stringify, Object.keys and
inspect then differed from Node, silently):

- Witness notes are keyed by node identity, and frontend passes that run
  before the witness pass (the caught-value dispatch, the class dynamic
  dispatch) rebuild whole function bodies through mapExprChildren, so
  every record literal in such a function became an unnoted construction
  that pins its shape. The mapper now reports rebuilt record literals to
  an observer, and the notes follow them to the rebuilt node.
- A shape a checked conversion (typed JSON.parse) also builds stayed
  pinned to today's table even when the program's own literals build it
  in another order, such as a message sent to a child and parsed back. It
  now takes its literals' order; parsed values in another order keep
  their own through the record-source view, and a shape only checked
  conversions build keeps today's table.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 18:34:38 -07:00
Chris Tate 94aa7065f1 Compile the remaining corpus programs with the native compiler (#1418) 2026-10-20 20:29:41 -05:00
Malte UblandClaude Opus 5.5 da13375a8b Keep properties JavaScript adds to a child process, and await it as a thenable
execa 5 mixes then/catch/finally into a real ChildProcess with
Reflect.defineProperty, replaces kill and adds cancel by assignment, and
awaits the child.

- A new optional runtime unit, scr_dyn_handle_props.c, keeps those
  properties in a side table keyed by the native child. Wrapper ops for
  the child tag look there first for reads, member calls and writes.
  defineProperty and getOwnPropertyDescriptor use it, and await adopts a
  child with a callable then. Class methods read as values call the
  class's own method.
- In JavaScript files, writes onto typed children, reads and calls of
  added names, method values for bind/call/apply, and members no typed
  lowering claims go through the child's checked-dynamic box.
- Only programs whose JavaScript adds properties to children link the
  unit and install the table; everything else compiles as before.
- A setTimeout delay that may be a boolean converts with ToNumber, and
  `if (t.unref)` over a timer handle folds to true (execa's lib/kill.js).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 18:28:00 -07:00
Chris Tate 6e278b8487 Name the spread expression in not-iterable errors for values held as any (#1587) 2026-10-20 20:25:52 -05:00
Chris Tate af502aab45 Revert "Check the optional-record path test's cast at the cast" (#1605) 2026-10-20 20:24:56 -05:00
Malte UblandClaude Opus 5.5 3a27a92cb4 Forward at most four emit arguments through EventEmitter method values
The dispatch instantiates one bridged emit per argument count and emitter
class; capping it at four keeps programs that only read emitter members
through computed keys from growing by the full table.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 18:22:43 -07:00
Chris Tate 97d6ebac6a Revert "Check the optional-record path test's cast at the cast (#1592)" 2026-10-20 20:22:18 -05:00
Chris Tate 5a1882957d Convert Promise and record results and record arguments in function adapters (#1556) 2026-10-20 20:21:38 -05:00
Chris Tate 81bc045524 Spin briefly before a mailbox wait blocks, and signal after the unlock (#1400) 2026-10-20 20:20:14 -05:00