Commit Graph
6750 Commits
Author SHA1 Message Date
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 e792cf4771 Test RSA-PSS verification with an automatic salt length on restricted keys
Node recovers the salt length under RSA_PSS_SALTLEN_AUTO without
enforcing the minimum in an RSA-PSS key's parameters, while an explicit
saltLength below it throws and the default saltLength requires the
key's. The corpus program pins that behavior for MGF1 digests equal to
and different from the message digest, through crypto.verify and
createVerify.
2026-10-24 09:49:01 -05:00
Chris Tate 537dfbeb68 Evaluate assert.fail's value messages after declaring them, with Node's defaults
assert.fail with a message that is not a string read the message's
hidden locals before they were declared: the call stored the message and
its generated flag in temporaries ahead of the message's declarations,
so `assert.fail(new RangeError('re'))` crashed. Arguments computed from
the message now read it after the declarations.

assert.fail also follows Node's defaults for such values: null and
undefined report "Failed" with generatedMessage true, an Error is thrown
as is, and any other value, falsy ones included, becomes the message as
its string, with generatedMessage set to !value.
2026-10-24 09:37:24 -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 48cbf3a89e Verify runtime pack artifacts once per file identity, and store pack selections
Every native exe build that the executable cache does not restore hashed
each selected runtime artifact before staging it, and every exe build
parsed and validated the whole runtime-pack.json manifest to select its
artifacts.

- Staging still copies each artifact. It skips the SHA-256 of an artifact
  when the file's identity (device, inode, size, mtime, ctime) is the one
  recorded the last time that path matched the same size and digest, and
  the identity does not change while the file is read. Other artifacts are
  hashed as before, and their identities are recorded after they match.
- A pack's selection for a target, compiler version, feature set, flavor
  and mode is stored, keyed by the file identities of package.json and
  runtime-pack.json. A stored selection skips parsing and validating the
  manifest; the manifest is parsed only when a caller needs it, through
  runtimePackManifest.
- The native compiler keeps both in its cache, in the runtime-pack family,
  which prune covers.
2026-10-24 09:20:05 -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
Chris Tate f2e710d65f Answer stream, StringDecoder and handle-object members in untyped code as Node does 2026-10-24 09:05:16 -05:00
Chris Tate 6aec284766 Inline the array release fast path under --optimization=speed
Speed builds now release arrays through the inline fast path the other
RC families use: an array that stays alive and has no cycle header is
decremented in place, and only the last release or a headered array
calls scr_arr_release.
2026-10-24 08:50:22 -05:00
Chris Tate 35a1576ba8 Merge main 2026-10-24 08:46:27 -05:00
Chris Tate 0dab283512 Cut repeated work in LLVM module emission (#2097) 2026-10-24 08:41:40 -05:00
Chris Tate 878f032886 Crypto parity: RSA key generation lengths, RSA-PSS keys and encrypted private keys 2026-10-24 08:35:30 -05:00
Chris Tate 427e383b5e Cache untyped property access in programs that declare classes (reland)
Reapplies #2017, which #2038 reverted after effect's observability-otlp
fixture crashed in plain builds. The crash was the candidate-buffer
corruption that the previous commit fixes: the cached property sites
change when the collector runs, and with enough environment variables a
pass buffered a string box that was later pooled while still buffered.
2026-10-24 08:22:30 -05:00
Chris Tate cd3c48d2b0 Fence fs.readSyncDyn with fs.readSync
The readSync form whose arguments are checked at run time lowers to
fs.readSyncDyn, which the determinism attestation demotes on. List it as
an alias of fs.readSync so the readSync fence witnesses it.
2026-10-24 08:19:25 -05:00
Chris Tate 6a8c7056ca Run the int32 slot analysis once per module the emitter emits (#2086) 2026-10-24 08:18:58 -05:00
Chris Tate cc27555171 Dispatch untyped calls on plain arrays without the method ladder (#2085) 2026-10-24 08:18:16 -05:00
Chris Tate d9f1457cd5 Run CommonJS top-level return, untyped assert forms, and untyped instanceof Object as Node does 2026-10-24 08:07:52 -05:00
Chris Tate ab9cfd7e91 Speculate integer loops through pure helper calls, powers of two and byte reads
- A speculated write may call a function whose body is one return of
  arithmetic, Math.floor and Math.pow over its number parameters. The fast
  copy evaluates the expanded body; the double copy still calls the
  function. Union tests on the parameters (`number | undefined`) fold
  against the wrapped argument.
- `Math.pow(2, n)` and `Math.floor(a / 2^n)` run as checked i64 shifts:
  with n an integer in [0, 52], both equal the double results for every
  safe integer a.
- Element reads of integer typed arrays are speculative leaves, read before
  any check, as string and array reads are.
- A write's other calls of program functions are hoisted: the fast copy
  evaluates each once into a local of its own, and a failed check resumes
  at a copy of the write that re-runs only the arithmetic over those
  locals. This applies only when no call can write a local the write reads.
- k-nucleotide's key chain (`key = bitwiseTrimLeft(key, m) * 4 + seq[i]`)
  now runs in i64.
2026-10-24 07:53:04 -05:00
Chris Tate 5ad3576c1e Hold a Map.get result as the entry's reference until the map can change
A local initialized from Map.get of a reference value retained the
value and released it at the end of its scope. In the common update

  const cur = counts.get(key);
  if (cur === undefined) counts.set(key, new Counter());
  else cur.num++;

the map is written only on the branch that does not read the local, so
the entry keeps the value alive for every read. A stable local whose
every use comes before any statement that may change a reference edge
(ReferenceEffects) now holds the entry's own reference: no retain on the
read and no release at scope exit. An if statement passes its
condition's state to both branches and joins them; any other statement
that names the local is judged whole. Number keys and inline string keys
take this path, for nullable results and for the stack-boxed results of
union locals.
2026-10-24 07:39:14 -05:00
Chris Tate a5eca18f1e Read fs.promises as a module, end CommonJS entries at a top-level return, and check fs read and write arguments as Node does
fs.promises read as a member of the fs module (a binding, an inline
require('fs').promises, destructuring) is the node:fs/promises namespace,
as in Node. It failed at run time before.

A return at the top level of the entry CommonJS module ends its
evaluation, as in Node's module wrapper: preflight admits TS1108 in
CommonJS JavaScript files. A CommonJS module the program requires with a
top-level return is refused with SC1090, because the exports assigned
after the return would stay undefined, which their storage cannot hold.

fs.ReadStream(...) and fs.WriteStream(...) called without new construct
their stream, as Node's stream constructors do.

fs.read, fs.readSync and fs.write check their arguments in Node's order
and with Node's errors: the fd, the buffer, the offset, `length |= 0`,
number and bigint positions (validatePosition), the empty-buffer error
and the buffer window. fs.read accepts a Proxy options object. A
readSync call whose JavaScript arguments are untyped or bigint takes the
same checks at run time (fs.readSyncDyn). fs.write threw no error for an
invalid fd, offset or length before.
2026-10-24 07:22:00 -05:00
Chris Tate 21570a963c Cut repeated work in LLVM module emission
Emitting the LLVM text of large programs spent seconds rebuilding the same
sets, rescanning the finished text and walking every function for passes
that change a few of them. The output is unchanged.

- computeMayThrow builds the set of temporal-dead-zone globals once per
  module instead of copying it into a new set for every function.
- limitInlineReleases finds the release sites of every family in one walk
  over the module text, and rewrites only the parts that hold a function
  over its limit.
- The mentioned-function and node:test checks of parking analysis scan the
  text with indexOf instead of global regular expressions.
- resolveSelfCaptures rewrites only the functions it changes,
  specializeCallbackCalls appends to its write lists instead of copying
  them and counts nodes in a walk it already makes, and CaptureFlow reuses
  one callback for nested statements.
2026-10-24 07:07:20 -05:00
Chris Tate 7ba3827bd4 Merge main 2026-10-24 06:54:25 -05:00
Chris Tate 73389fd513 Merge main 2026-10-24 06:53:30 -05:00
Chris Tate 5517139b0e Merge main 2026-10-24 06:52:59 -05:00
Chris Tate f23447dc99 Merge main 2026-10-24 06:50:53 -05:00
Chris Tate 102c86b6d2 Merge main 2026-10-24 06:50:08 -05:00
Chris Tate f505e8a044 Merge main 2026-10-24 06:49:45 -05:00
Chris Tate 76611d1151 Merge main 2026-10-24 06:49:23 -05:00
Chris Tate 702265e4ce Merge main 2026-10-24 06:48:58 -05:00
Chris Tate 1f05743053 Merge main 2026-10-24 06:48:26 -05:00
Chris Tate 1d5a7ff48a Merge main 2026-10-24 06:47:59 -05:00
Chris Tate ead125a5c5 Merge main 2026-10-24 06:47:32 -05:00
Chris Tate dfc3b42a42 Merge main 2026-10-24 06:47:02 -05:00
Chris Tate f00113563e Merge main 2026-10-24 06:46:34 -05:00
Chris Tate 6a4a1bdec9 Collect the supplied files' global names only for programs with scripts (#2092) 2026-10-24 06:46:07 -05:00
Chris Tate 38c30d2e91 Merge main 2026-10-24 06:45:47 -05:00
Chris Tate 184f9e0615 Merge main 2026-10-24 06:45:19 -05:00
Chris Tate fe3f52d14c Merge main 2026-10-24 06:44:55 -05:00
Chris Tate 854f3ae810 Construct readline.Interface and builtin classes bound through require() members in JavaScript 2026-10-24 06:41:00 -05:00
Chris Tate b6050f96bd Read the runtime ABI marker in the native toolchain fixture from the compiler
- The native toolchain test's fixture runtime pack hard-coded ABI v37, so
  with this branch's marker (v40) the toolchain refused the pack and the
  test saw exit status 1. It now takes RUNTIME_ABI_VERSION and
  RUNTIME_ABI_MARKER from runtime-abi.ts, as the native driver test does.
2026-10-24 06:40:00 -05:00
Chris Tate b17268ff74 Take number and string boxes out of the candidate buffers before pooling them (#2091) 2026-10-24 06:30:38 -05:00
Chris Tate 314024a8c7 Copy typed array sets of the same element kind on shared memory as bytes
TypedArray.prototype.set with a SharedArrayBuffer view as its source or
target converted every element through a double, even when both arrays
had the same element kind. That cost about 5 ns per byte, and it changed
NaN payloads: a Float32Array signaling NaN came back quieted (7fa00001
became 7fe00001), where Node copies the bytes.

The same element kind now copies the source's bytes with the relaxed
shared stores. A source that overlaps the target range, a view of the
same buffer in a program without workers, is copied out first. Different
element kinds still convert each element.
2026-10-24 06:29:47 -05:00
Chris Tate 4c0572c49e Decode an undefined TextDecoder input as no bytes
In Node, `decoder.decode(undefined)` returns "" like `decode()`, and
flushes bytes pending from streamed input. scriptc refused a statically
undefined argument and an argument typed `Uint8Array | undefined` with
SC2020, and `decode(x!)` on an undefined value threw a TypeError.

The decode input lowering now evaluates a statically undefined argument
for its effects and decodes an empty Uint8Array, and reads the undefined
arm of `Uint8Array | undefined` as an empty Uint8Array, in both the
decoder-value and the `new TextDecoder(label).decode(...)` paths. A
non-null assertion passed to decode keeps the undefined it removes,
instead of the checked narrowing other optional standard library
parameters keep. Inputs that may be null are refused as before (`decode(null)`
throws a TypeError in Node).
2026-10-24 06:25:57 -05:00
Chris Tate 486e92a628 Collect the supplied files' global names only for programs with scripts
Reusing the stored diagnostics of the declaration files scriptc supplies
(lib-diagnostics.ts) needs those files' global names to tell whether a
program's scripts could change what checking them reports. The first build
that stored an answer collected them by reading every supplied file's
syntax tree, which a program made only of modules does not otherwise read,
and that build is every cold build. A program of modules cannot collide
with those names, so its answer is now stored without them, and the first
program with scripts that uses the answer collects them and stores them
with it. The entry schema is scriptc.lib-diagnostics.v2.

A cold dev build of the 17-module build benchmark takes 676 ms instead of
689 ms, and of the log-summary benchmark 375 ms instead of 396 ms, with
peak RSS 5.7 MiB and 4.5 MiB lower.
2026-10-24 06:11:16 -05:00
Chris Tate d66564ca69 Keep class methods native when element writes store data under their names (#2026) 2026-10-24 05:59:00 -05:00
Chris Tate 8a02468073 Take number and string boxes out of the candidate buffers before pooling them
scr_dyn_release returned the last reference of a number or string box to
the free list without scr_cyc_dead, because the release paths never buffer
those boxes. A collector pass can: capture boxes trace their payload, and
scr_xg_release, which settles the cross-generation edges a restricted pass
skipped, calls scr_cyc_on_release on the target whatever its kind. The
pooled block then stayed in its candidate buffer, and the next box that
reused it carried the stale buffer position. Its death swapped another
object into that slot, which corrupted the buffers and crashed a later
scr_cyc_on_dead.

The fast path now takes a buffered box out of its buffer first. The
sanitized runtime does not pool boxes, so only plain builds were affected.
2026-10-24 05:57:26 -05:00
Chris Tate 1d1fccccd5 Compare identical references and accept any message in the test262 adapter
assert.sameValue, assert.notSameValue and assert.compareArray elements treat identical references as the same value and a reference as different from every primitive. Only two distinct references still refuse, because a conversion at the native boundary can copy a reference but never merge two. Assertion messages may be any value and convert with String, as in the upstream helpers.
2026-10-24 05:56:14 -05:00
Chris Tate 43e6ed4655 Merge main 2026-10-24 05:29:02 -05:00