Commit Graph
4606 Commits
Author SHA1 Message Date
Chris Tate 5d8804db38 Version string scans over the UTF-16 units of strings that are not ASCII
`for (let i = 0; i < s.length; i++) if (s.charCodeAt(i) === 32) n++`
over a text with any non-ASCII character failed the loop version's ASCII
guard and ran the checked loop. Each read tested the ASCII bit, compared
the string with the runtime's published scan receiver, tested the
bounds, loaded the units pointer, and kept the opaque fallback.

The guard now also accepts a version's one string receiver when it is
not ASCII. One runtime read publishes the string as the scan receiver
(ScrStrScan), whose UTF-16 units the runtime holds once a scan has
read it enough. The guard then tests the accesses against the published
unit count, and a third copy of the loop reads each unit with one
16-bit load from the units pointer taken in the guard.

The guard takes that path only while the runtime publishes the receiver
itself, so the length it took is the receiver's UTF-16 length on both
fast paths. Both fast copies read it for the receiver's `length`, which
a while loop's condition otherwise asks the runtime for on every
iteration.

The runtime drops a string's units when the string is released or
appended to in place, or when its index entry is evicted because
another non-ASCII string is indexed. The receiver is a binding the loop
does not write, so the first two cannot happen while the loop runs. A
units copy is emitted only for a loop that uses unit-safe operations
(string-unit-versions.ts): numbers, locals, records and class fields,
typed arrays, number arrays, Math, the receiver's charCodeAt and length,
and calls of functions made of the same operations that read no string.

Tests of `s.charAt(i)` against one-unit literals now become charCodeAt
compares in the IR pass (char-unit-locals.ts), so a version sees one
kind of read.
2026-10-23 22:40:04 -05:00
Chris Tate 260cf6e8c0 Answer builtin prototype reflection in untyped code as Node does (#2054) 2026-10-23 22:26:47 -05:00
Chris Tate 5c131cba35 Report dictionary copies of {} views, and keep method calls direct after writes into dictionaries of dictionaries (#1855) 2026-10-23 22:18:05 -05:00
Chris Tate 9e07382bcd Merge main 2026-10-23 21:48:59 -05:00
Chris Tate 1df99a8414 Convert checked-dynamic expected errors in assert.throws and assert.match (#2066) 2026-10-23 21:41:23 -05:00
Chris Tate 43b0f29011 Guard direct calls after dot-property method writes through dictionary views 2026-10-23 21:34:14 -05:00
Chris Tate ee237c3276 Keep literal key order through self copies and conversions that build no records (#1982) 2026-10-23 21:21:37 -05:00
Chris Tate 10e3476a55 Convert checked-dynamic expected errors in assert.throws and assert.match
An expected regex or string read from a JavaScript object literal's
field is a checked-dynamic value while its checker type is RegExp or
string. assert.throws chose its regex comparison from the checker type
and passed the value unconverted, an internal compiler error, and
assert.match and the expected-object form refused it. Such a value now
converts to the regex or string its type names.
2026-10-23 21:12:15 -05:00
Chris Tate a294403acd Version while loops only for accesses at their counters (#2056) 2026-10-23 21:02:55 -05:00
Chris Tate 02aa5d4184 Keep the run-time result of overloaded calls with untyped arguments (#2064) 2026-10-23 21:00:49 -05:00
Chris Tate e59fdca0f4 Search TypedArrays, read stdin through 'readable', and assign constructor-function globals (#1974) 2026-10-23 20:57:24 -05:00
Chris Tate f9e9f3cb52 Keep an error's name and message where a JavaScript factory created them (#2055) 2026-10-23 20:55:51 -05:00
Chris Tate cecab7fc0f Keep null and undefined through non-null assertions into nullable destinations (#2050) 2026-10-23 20:48:03 -05:00
Chris Tate 0392a032c5 Merge main and fix the self-copy key order 2026-10-23 20:47:40 -05:00
Chris Tate 6dfde9919c Keep checked dictionary protocols and invalidate direct calls after method writes 2026-10-23 20:45:37 -05:00
Chris Tate 0f75f5b952 Keep the run-time result of overloaded calls with untyped arguments
The checker resolves an overloaded call whose argument is `any` to the
first overload that argument satisfies, but in JavaScript the value can
select another one: generateKeyPairSync("ec", options) returns KeyObjects
or PEM strings by the options, and digest(encoding) returns a Buffer when
the encoding is undefined. The result was converted to the first
overload's return type, so such calls threw a TypeError where Node
returns the other overload's value.

When a checked-dynamic argument could take another overload whose return
type differs (trailing untyped or undefined arguments may also be
absent), the call's result in a JavaScript source is checked-dynamic. So
are the unannotated bindings it initializes, destructured or not, and
the unannotated functions that return it. fs.globSync keeps choosing its
result form from the resolved overload, since the runtime checks that
withFileTypes agrees with it.
2026-10-23 20:31:12 -05:00
Chris Tate a5db27a5a7 Merge main and fix the review comments 2026-10-23 20:24:35 -05:00
Chris Tate e813250813 Keep a constructor's name ahead of later properties in the runtime fallback 2026-10-23 20:22:14 -05:00
Chris Tate b2e609d73e Merge main 2026-10-23 20:20:34 -05:00
Chris Tate 01e802ff9d Box JavaScript class instances at their exact class (#2047) 2026-10-23 20:18:12 -05:00
Chris Tate d06e6ab0a5 Keep checked narrowing for optional standard library parameters, and merge main 2026-10-23 20:11:11 -05:00
Chris Tate e9833e3260 Add --target-cpu for x86-64 microarchitecture levels (#2025) 2026-10-23 20:00:33 -05:00
Chris Tate 1af3a86370 Compile unions of typed-array classes (#2011) 2026-10-23 20:00:12 -05:00
Chris Tate 37df3c4dfd Support split CommonJS require bindings (#1945) 2026-10-23 19:50:13 -05:00
Chris Tate 9ab731bf66 Version while loops only for accesses at their counters
A while loop over typed arrays also versioned when its only checks were
thread-owned receivers or static indices. A worker's job loop such as
`while ((job = Atomics.load(next, 0)) < count) { ...; run(job) }` then
got a second copy whose guard fails whenever the array is shared, and
the doubled call kept the job function from being inlined. A while loop
now versions only when it has an access at one of its counters. Other
while loops compile as they did before they could version.
2026-10-23 19:42:52 -05:00
Malte UblandClaude Opus 5.5 c9f1f95d5b Box JavaScript class instances at their exact class
A class instance converted to an untyped value was boxed in a capsule of
its static class. Before any member table read it,
%dyn.class.normalize tested it against each subclass and boxed it again
at the instance's own class: two capsules per crossing for every value
of a class with subclasses, and the subclass tests on every member read.

After the dispatch tables settle, each conversion of a value whose static
JavaScript class has a normalization branch now calls
%dyn.class.boxExact:<Class>, which runs the same subclass tests in the
same order once, at the conversion. The capsule is created at the exact
class, and normalization falls through for it. TypeScript hierarchies,
classes that are never boxed, and hierarchies without subclasses are
untouched.

zod 3, z.array(Order).parse over 500 orders: 178.5M -> 174.4M
instructions per round (-2.3%).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 17:41:28 -07:00
Chris Tate a4e7a03761 Address review comments 2026-10-23 19:37:04 -05:00
Chris Tate 3a613c31a8 Merge main 2026-10-23 19:33:44 -05:00
Chris Tate d56a884011 Merge main 2026-10-23 19:28:30 -05:00
Chris Tate 4206155ac9 Convert non-null asserted operands that hold undefined or null as Node does (#2049) 2026-10-23 19:25:15 -05:00
Chris Tate cc325de274 Merge main 2026-10-23 19:24:16 -05:00
Chris Tate bf68b3860c Skip split require calls by identity and climb parentheses in early-read checks 2026-10-23 19:05:58 -05:00
Chris Tate fbaf51c032 Decide string or number concatenation at run time for untyped partners 2026-10-23 18:53:36 -05:00
Chris Tate 9adb9692cd Accept file URL paths in existsSync and fs.promises (#2042) 2026-10-23 18:47:49 -05:00
Malte UblandClaude Opus 5.5 f896786ef4 Give the zod4-record npm case the zod 4 cases' timeout
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 16:42:23 -07:00
Malte UblandClaude Opus 5.5 e81c9ddaa4 Give the hono-zod-default-hook npm case the zod 4 cases' timeout
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 16:42:19 -07:00
Malte UblandClaude Opus 5.5 09f0342641 Keep an error's name and message where a JavaScript factory created them
zValidator's default failure hook serializes zod 4's ZodError with
`name` after `message` natively, and with the first `name` zod's factory
assigns ("$ZodError") when the second assignment took the typed slot.
ZodError instances are views of a JavaScript class extending Error: each
view rebuilds `message` and `name` from the error slots at fixed
positions (after `stack`, and after every other property), and the
property bag that holds the dynamically added properties copied its
committed, possibly stale, values over them.

A JavaScript Error subclass with a property bag now marks its class
(errorBagOrder), and its view calls scr_error_dyn_follow_bag after the
bag is copied: `name` and `message` move to follow the property they
followed when the bag was committed, and data values come from the
slots. TypeScript classes keep their views.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 16:40:35 -07:00
Malte UblandClaude Opus 5.5 17721bae55 Answer builtin prototype reflection in untyped code as Node does
zod 4's z.record rejected every plain object natively ("expected record,
received object"): its isPlainObject reads o.constructor.prototype, which
was undefined, and asks whether that prototype has its own isPrototypeOf,
which Object.prototype answered false.

- The Object, Array and Error constructors held as values have their
  builtin prototype as a non-writable, non-enumerable, non-configurable
  own `prototype`; reading Function's constructor value's prototype
  throws SC2020 instead of answering undefined.
- hasOwnProperty / Object.hasOwn on Object.prototype answer its builtin
  members, and on Array.prototype its constructor;
  Object.getOwnPropertyNames lists them in Node's order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 16:40:07 -07:00
Chris Tate 6dace8e40b Compare and index with the integer beside a sum's double (#2040) 2026-10-23 18:34:30 -05:00
Chris Tate 6b1a56a49a Check target CPU levels in the native CLI and honor them for assembly and object builds 2026-10-23 18:26:12 -05:00
Chris Tate 79feeb9a56 Store the frontend cache's LLVM placeholder as an empty array (#2051) 2026-10-23 18:19:25 -05:00
Chris Tate b7f86b9bb5 Run TypedArray methods on typed arrays held as untyped values (#2043) 2026-10-23 18:14:18 -05:00
Chris Tate 3e73eee0c4 Evaluate fs.promises URL arguments once and fence the new fs entries 2026-10-23 18:12:45 -05:00
Chris Tate 39bb8a5b7e Require integer views to stay below 2^53 exactly, and fix corpus 1420 2026-10-23 18:05:10 -05:00
Chris Tate 5a4935ed9e Settle Promise.all over different entry types on Node's turns (#1843) 2026-10-23 17:49:52 -05:00
Chris Tate 398930e7de Store the frontend cache's LLVM placeholder as an empty array
A native frontend cache entry stores the input's LLVM text after its
metadata, with an empty placeholder in the input itself. The placeholder
was an empty string where NativeExecutableInput declares an array of
parts. Under Node the reader's cast of the parsed entry is not checked,
but the native compiler checks it, so every read threw "expected array
at $.input.llvm, got string". The reader treated that as a miss: no
native build ever reused its frontend output, and an unchanged rebuild
ran the frontend, lowering and LLVM emission again.

The placeholder is now an empty array, and the cache test checks the
stored member types.
2026-10-23 17:48:22 -05:00
Chris Tate 537710f61d buffer: fromArrayBuffer ranges, the deprecated constructor, Buffer as a value (#1970) 2026-10-23 17:46:42 -05:00
Chris Tate b09d5c6862 Merge main 2026-10-23 17:43:25 -05:00
Chris Tate 47d573d216 Pass undefined as this to strict callbacks and read Symbol.iterator once 2026-10-23 17:41:37 -05:00
Chris Tate a095565bc8 Project zod 4 and @hono/zod-validator values at the declaration boundary (#2046) 2026-10-23 17:41:12 -05:00