Commit Graph
4880 Commits
Author SHA1 Message Date
Chris Tate fce38bcbcf Merge base branch and fix 2026-10-25 07:35:31 -05:00
Chris Tate 8752390f65 Merge base branch and fix 2026-10-25 07:27:31 -05:00
Chris Tate 4f07fbd66f Merge base branch and fix 2026-10-25 07:22:16 -05:00
Chris Tate 5cfcc8fb51 Merge base branch and fix 2026-10-25 07:18:13 -05:00
Chris Tate 7d17f2a758 Merge base branch and fix 2026-10-25 07:13:36 -05:00
Chris Tate 89f8b39e5b Merge base branch and fix 2026-10-25 07:08:45 -05:00
Chris Tate 6157fa93ab Merge base branch and fix 2026-10-25 07:02:48 -05:00
Chris Tate 5fc6fea249 Merge base branch 2026-10-25 06:57:33 -05:00
Chris Tate 365d14ee1c Merge base branch 2026-10-25 06:52:17 -05:00
Chris Tate 928aad993d Add island packages to the judged set without a union spread
The self-hosted compiler refuses spreading 'number[] | Set<string>' into
a string[] literal (SC1090), so pnpm build:native-compiler failed on
loadFrontend. The judged set now starts from the library packages and
adds each island package in a loop.
2026-10-25 06:40:14 -05:00
Chris Tate 22e11114bf Merge base branch 2026-10-25 02:59:59 -05:00
Chris Tate 0f7fd1bdb6 Merge base and fix 2026-10-25 02:27:42 -05:00
Chris Tate 0b4301bc3e Merge base and fix 2026-10-25 02:21:39 -05:00
Chris Tate f3750ef976 Merge base and fix 2026-10-25 02:16:24 -05:00
Chris Tate e6790def72 Merge main 2026-10-24 20:06:31 -05:00
Chris Tate d60cdcc843 Merge the base branch 2026-10-24 16:49:25 -05:00
Chris Tate 02c2c89fd6 Merge main 2026-10-24 14:18:51 -05:00
Chris Tate 4efcbbdfe4 Report inferred shapes for untyped npm JavaScript (#2036) 2026-10-24 13:49:30 -05:00
Chris Tate bf02b9d7cc Write a number-keyed Map update through the entry its read found (#2130) 2026-10-24 13:38:20 -05:00
Chris Tate 3896957230 Report JSON.parse syntax errors with V8's messages and positions (#2129) 2026-10-24 13:34:12 -05:00
Chris Tate c33d693775 Answer instanceof against the primitive wrapper constructors (#2126) 2026-10-24 13:28:00 -05:00
Chris Tate 9dfaddf7bc Check unchanged frontend inputs by file identity before hashing them (#2128) 2026-10-24 13:24:46 -05:00
Chris Tate b78520559f Follow values through shadowed members, unknown keys on arrays, JSON callbacks and proxies
- Named loads also read what was written under that name or an unknown key where an own field
  shadows a builtin: an instance's constructor, a function's call, apply, bind, prototype, name
  and length, a class's prototype and name, an array's methods. Named loads of arrays read what
  was written under unknown keys, which computed stores on arrays now record.
- Computed stores into builtins, promises and collections escape, as named stores there do.
- JSON.stringify calls toJSON on arrays, functions and classes, and on values written under
  unknown keys. A JSON.parse reviver's results are part of the result and of later calls' values.
- Reflect.construct(Proxy, ...) and globalThis.Proxy record a proxy operation, as new Proxy does.
2026-10-24 13:20:02 -05:00
Chris Tate 29a78af70b Merge main 2026-10-24 13:13:07 -05:00
Chris Tate 7ca5bd465b Keep while-loop counters bounded by a typed array length in integers (#2124) 2026-10-24 13:08:15 -05:00
Chris Tate 94c650a9c2 Write a number-keyed Map update through the entry its read found
m.set(k, f(m.get(k))) and a get followed by a set of the same key, with a
number or boolean value, now reuse the entry the read resolved, as
string-keyed maps already do: the write overwrites the value in place
when the map is the same and the key has the read's bits, and takes the
ordinary set otherwise. Before, the write probed the table again: the two
lookups were not merged, because each sits behind its own direct-index
test.
2026-10-24 13:07:38 -05:00
Chris Tate 50b7c806ce Check unchanged frontend inputs by file identity before hashing them
A warm native build validates its frontend cache entry by reading and
SHA-256 hashing every source and declaration file the frontend read.

A tracked read now also records the file's identity (device, inode,
size, modification and change time) when the identity is the same before
and after the read and the file had been unchanged for two seconds. A
later check accepts a file whose identity is unchanged without reading
it, and hashes it otherwise. A write always gives a file a newer change
time, which tools cannot set back, so an unchanged identity means the
content hashed with it. The equivalent-edit check uses the same identity
for the unchanged sources.
2026-10-24 12:52:54 -05:00
Chris Tate 0ea0707861 Reuse dev builds' frontend output after edits that keep token positions (#2123) 2026-10-24 12:51:02 -05:00
Malte UblandClaude Opus 5.5 b11cd04ce9 Answer instanceof against the primitive wrapper constructors
`value instanceof Boolean` (or Number, String, BigInt, Symbol) died at run
time in JavaScript with Node's TypeError for a function without a prototype
object, because those constructors are compiled as plain conversion
closures; in TypeScript the right-hand side was refused (SC1090). A
compiled program never creates a boxed primitive (`new Boolean(...)` has
no lowering) and a primitive is never an instance, so the test is false
for every value. It now folds to false after evaluating the operand.

typebox's value guards (IsBoolean, IsNumber, IsString) test this way, so
pi's tool-schema construction and validation died at its first guard.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 10:50:43 -07:00
Chris Tate 8796e91f5e Keep while-loop counters bounded by a typed array length in integers 2026-10-24 12:37:29 -05:00
Chris Tate 71646287b2 Divide one-limb BigInt quotients in one pass and chain limb carries (#2121) 2026-10-24 12:30:30 -05:00
Chris Tate 31d3ba07ca Reuse dev builds' frontend output after edits that keep token positions
A native build reuses its stale frontend cache entry when every changed
source is token-equivalent to the text the entry was built from, but dev
builds never did: their debug information records source lines and
columns, which a token-equivalent edit can move.

Builds with debug information (dev builds without --strip) now reuse the
entry when every changed source is token-equivalent and every token keeps
its line and column (tokenPositionEquivalentSource): edits to a comment's
text within its line, comments and whitespace after the last token, and
trailing whitespace. Edits that move a token still rebuild.

The token scanner also reads a `/` after a non-null assertion as division
(`data[i]! / 7`). It used to read it as the start of a regular expression
and give up on the file, so comment edits in files with that pattern
always rebuilt. A `!` after a line break, or after an operator or a
keyword such as `return`, still starts a negated regular expression, and
a `!` after `)`, `}`, `++` or `--` gives up.
2026-10-24 12:22:19 -05:00
Chris Tate aa4e046046 Emit function bodies on up to eight workers (#2118) 2026-10-24 12:04:33 -05:00
Chris Tate ff70c33e38 Divide one-limb BigInt quotients in one pass and chain limb carries
Dividing BigInts of the same limb count, where the quotient is one limb,
takes Knuth's quotient estimate from the top limbs as they read
normalized and settles it with one pass of a - q * b over the operands,
instead of copying both operands shifted and running algorithm D. The
remainder, when wanted, is that pass's result.

The limb loops for add, subtract, multiply by a limb, and multiply-add
and multiply-subtract by a limb process four limbs a pass, with the
carries in add-with-carry chains (__builtin_addcll and __builtin_subcll
where the compiler has them).
2026-10-24 11:59:33 -05:00
Chris Tate fe394f8c30 Keep an unchanged executable on its first Linux rebuild (#2112) 2026-10-24 11:57:52 -05:00
Malte UblandClaude Opus 5.5 d037c66e8c Report JSON.parse syntax errors with V8's messages and positions
JSON.parse's SyntaxError messages were shaped like V8's but differed from
Node's in several ways:
- Every positional message now ends with V8's "(line L column C)", where
  \n, \r and \r\n end lines.
- Positions are UTF-16 offsets, as in Node, not byte offsets.
- An object or array cut off after '{', a property name, a value or an
  array element reports the token V8 expected ("Expected property name or
  '}'", "Expected ':' after property name", "Expected ',' or '}' after
  property value", "Expected ',' or ']' after array element") instead of
  "Unexpected end of JSON input".
- After a comma in an object the message is "Expected double-quoted
  property name".
- An unterminated string reports the end of the input, and a truncated
  \u escape is a "Bad Unicode escape" there.
- A leading zero followed by a digit is an "Unexpected number".
- A misspelled literal names the first differing character, or the end of
  the input.
- An unexpected character is named with the source as V8 does: whole when
  it is under 21 units, otherwise ten units of context on each side; the
  sources "NaN", "Infinity", "undefined" and "[object Object]" name only
  themselves; a quote or a number there is an "Unexpected string" or
  "Unexpected number".

The new corpus program 7993-json-parse-error-messages pins 76 inputs
against Node, including non-ASCII text before the error, line breaks, and
long sources with split surrogate pairs at the context edges.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 09:55:05 -07:00
Chris Tate 40f0b6d9e0 Refresh the native compiler's optimization profile (#2120) 2026-10-24 11:51:12 -05:00
Chris Tate 557daa3e9d Refresh the native compiler's optimization profile
The committed profile was collected before about 200 commits that changed
12,800 lines of the compiler. Functions whose control flow changed since are
optimized as without a profile, so its gain had mostly gone: a cold tsc-ts
speed build was 2.7% faster with it than with no profile, against 5% to 6%
with a fresh one.

Regenerated with scripts/refresh-cli-profile.mjs on this commit.
2026-10-24 11:47:19 -05:00
Chris Tate c09385c7ab Emit function bodies on up to eight workers
The native compiler forked four worker processes to emit the function
bodies of a large module. It now forks one per available core, up to
eight. SCRIPTC_EMIT_WORKERS still sets the count. The output is the same
text at any count.
2026-10-24 11:29:56 -05:00
Chris Tate 022428ead6 Write the first stdin chunk after both readers start in the 'readable' EOF test (#2109) 2026-10-24 10:30:31 -05:00
Chris Tate 205f099957 Keep an unchanged executable on its first Linux rebuild
On Linux the executable cache stored an executable only from a key's second
link on, so the first unchanged rebuild after a build linked again, and only
the build after that restored the executable.

- A key's first link on Linux is traced, in the same verbose link. Instead
  of storing the executable, the cache records the output's file identity
  together with the link's inputs once the output is in place.
- keep() answers an unchanged rebuild whose output still has that identity
  and whose inputs are unchanged. The build then neither links nor copies:
  the output stays as it is.
- A rebuild whose output changed or is missing links again; from that second
  link on, the executable is stored as before and restored where needed.
- The cache records the output after every Linux build that places one, so
  the next unchanged rebuild keeps it.

darwin keeps its existing behavior.
2026-10-24 10:26:38 -05:00
Chris Tate 7406ec63f4 Read the node index in more LLVM emission analyses (#2108) 2026-10-24 10:19:42 -05:00
Chris Tate 72eb9318bf Analyze int32 slots in queue order, after fixing an order-dependent narrowing (#2107) 2026-10-24 10:02:34 -05:00
Chris Tate 38730910c8 Write the first stdin chunk after both readers start in the 'readable' EOF case
A reader that starts after the second chunk arrives reads both chunks in
one 'readable' event. On loaded test workers Node started that late while
the compiled program did not, so the two outputs differed. The first chunk
now waits 500 ms.
2026-10-24 09:56:15 -05:00
Chris Tate aa1c26845c Cache untyped property access in programs that declare classes (reland) (#2102) 2026-10-24 09:55:54 -05:00
Chris Tate 648e8e05c6 Read the node index in more LLVM emission analyses
Several analyses the emitter runs per function or per module walked whole
bodies to collect facts from a few node kinds. They now read those kinds
from the module's node index (ir/node-index.ts), which records every node
once in walk order, and the output is unchanged.

- numberGlobalWriters, readsLoopMetrics, closure creation sites
  (LazyCaptures) and the ambient receiver readers visit only the kinds
  they inspect.
- findLoopArrayBorrows visits only loop statements, and findIntegerViews
  returns at once for a function without a loop, where it wants no view.
- foldConstantGlobals records which candidates each function reads during
  its write walk instead of walking every function again.
2026-10-24 09:50:02 -05:00
Chris Tate 580e8ac723 Analyze int32 slots in queue order, after fixing an order-dependent narrowing 2026-10-24 09:34:59 -05:00
Chris Tate e579f62556 Inline the array release fast path in speed builds (#2104) 2026-10-24 09:18:35 -05:00
Chris Tate 15e8c0cfac Place each source file's functions in the same partitions (#2083) 2026-10-24 09:08:38 -05:00
Chris Tate 905a290817 Copy typed array sets of the same element kind on shared memory as bytes (#2094) 2026-10-24 09:07:57 -05:00