586 Commits
Author SHA1 Message Date
Chris Tate 733ab38a0c v0.3.1 2026-10-13 13:26:10 -05:00
Chris Tate cbae29834a Speed up BigInt arithmetic, text conversion and small-value code (#928) 2026-10-13 13:07:19 -05:00
Chris Tate 9ed57127e5 Fix native self-host of bigint trees and guard BigInt text sizes 2026-10-13 12:29:07 -05:00
Chris Tate ac64b1d7fd Compile regex literals to native matchers (#931) 2026-10-13 11:58:36 -05:00
Chris Tate 67f59798d2 Support node:console Console instances (#923) 2026-10-13 11:57:56 -05:00
Chris Tate 0bcf9d3fdc Run synchronous generators as stackless coroutines (#930) 2026-10-13 11:48:53 -05:00
Chris Tate bf40cf4255 Compile regex literals to native matchers 2026-10-13 11:30:19 -05:00
Chris Tate 22f73444e2 Run synchronous generators as stackless coroutines 2026-10-13 11:19:03 -05:00
Chris Tate 284eb17938 Lend arguments to closure bodies and comparators (#929) 2026-10-13 11:04:20 -05:00
Chris Tate 2b280dd25c Merge main into node:console Console support 2026-10-13 10:54:25 -05:00
Chris Tate 462d2c3151 Answer reflective reads of typed records without snapshots (#925) 2026-10-13 10:47:53 -05:00
Chris Tate 1334a8acd2 Lend arguments to closure bodies and comparators 2026-10-13 10:35:18 -05:00
Chris Tate 7763bd8927 Speed up BigInt arithmetic, text conversion and small-value code 2026-10-13 10:26:49 -05:00
Chris Tate a4bb3ff3ce Keep hole-free prefix and int32 parameter upkeep off hot paths (#922) 2026-10-13 09:43:22 -05:00
Chris Tate e04b701c1c Answer reflective reads of typed records without snapshots 2026-10-13 09:40:38 -05:00
Chris Tate e70d2693a6 Support stream/consumers arrayBuffer (#920) 2026-10-13 09:39:58 -05:00
Chris Tate 8056aafa37 Support node:console Console instances
- Support `new Console(...)` over process stdio and writable streams
- Write `log`/`info`/`debug`/`error`/`warn` output like Node, including `ignoreErrors`
- Mark the `Console` class as partially supported in the compatibility data
2026-10-13 09:15:07 -05:00
Chris Tate 6790082742 Keep hole-free prefix and int32 parameter upkeep off hot paths 2026-10-13 09:11:57 -05:00
Chris Tate 9153285118 Probe bypassed collector types and tear down typed children directly 2026-10-13 08:50:06 -05:00
Chris Tate 5a7fc7225b Support stream/consumers arrayBuffer
- Support `arrayBuffer()` from `node:stream/consumers`
- Print ArrayBuffer and SharedArrayBuffer values like Node
- Mark the stream consumers as partially supported in the compatibility data
2026-10-13 08:33:55 -05:00
Chris Tate ad3dedb546 Reuse regex literal sites and scan plain patterns directly (#918) 2026-10-13 08:17:34 -05:00
Chris Tate 1aeb04241f Reuse regex literal sites and scan plain patterns and string replacements directly 2026-10-13 07:48:24 -05:00
Chris Tate 35cf7efe55 Make short async calls and awaits cheap 2026-10-13 07:29:48 -05:00
Chris Tate 5df589706b Skip array state bytes below a hole-free prefix 2026-10-13 02:13:46 -05:00
Chris Tate 55626fb233 Merge pull request #897 from vercel-labs/ctate/run-pr-test-f6809a
Run the PR test shards on Linux
2026-10-12 20:22:19 -05:00
Chris Tate ff799bd3c5 Sort dense arrays without the comparator sort snapshot (#908) 2026-10-12 19:25:54 -05:00
Chris Tate b10c0af911 Sort dense arrays without the comparator sort snapshot 2026-10-12 18:01:14 -05:00
Chris Tate 5ab2defc85 Keep the allocator's untouched reservation out of core dumps 2026-10-12 17:26:24 -05:00
Chris Tate 59932f3af4 Leave glibc's heap to the huge-page policy instead of prefaulting it (#899) 2026-10-12 16:38:26 -05:00
Chris Tate 31c0530337 Keep integers visible to LLVM and take the ASCII fast paths of text conversion (#898) 2026-10-12 16:21:02 -05:00
Chris Tate ef25cf119d Prepare v0.3.0 2026-10-12 15:57:06 -05:00
Malte Ubl 0086716250 Widen utf16le ASCII runs eight bytes at a time
Buffer writes and conversions to UTF-16LE stored each ASCII byte as two
byte stores; the compiler cannot vectorize the loop because source and
destination may alias. On little-endian targets an ASCII run of eight
bytes is now widened with two 64-bit stores.
2026-10-12 13:28:30 -07:00
Malte Ubl bcad9b3892 Inline the ASCII paths of UTF-16 and byte offset conversion
scr_u16_to_byte_c and scr_byte_to_u16_c run on every native charCodeAt,
substring and search result. Most calls are the identity of an ASCII
string or a hit in the cached ASCII run, but every call paid the prologue
of the full walk. Those two cases are now static inline, and the walk is a
separate function. A forward access up to 4 KiB past the cached run first
extends the run word by word (with 256 bytes of lookahead) instead of
walking from the cursor and re-centring a 128-byte window, which made a
scanner reading a long ASCII stretch of a non-ASCII text walk repeatedly.
2026-10-12 13:28:30 -07:00
Chris Tate 644722e696 Run the PR test shards on Linux 2026-10-12 15:21:39 -05:00
Chris Tate bbf2c34778 process.constrainedMemory() and availableMemory() read the process's own cgroup, like libuv (#893) 2026-10-12 14:21:30 -05:00
Chris Tate cca079d705 Find multi-byte needles without a memchr call per first-byte hit (#892) 2026-10-12 14:20:36 -05:00
Malte Ubl 9f6a11c3fe Correct the reason the prefault helper leaves a huge-page heap alone
The previous commit said the helper and the owner cleared the same huge
pages twice. Clean per-run page counters don't show that: with and without
the helper's heap mode a Sentry type check allocates the same number of
pages (1.07M). The cost is the page size: heap ranges the helper populates
before the owner advises them, and the partial huge pages at the ends of
each extension, stay on 4 KiB pages (Sentry 1816 instead of 1930 huge
pages, VS Code 2740 instead of 3051), next to the mmap-lock waits and the
smaller top pad. Also splits the THP-mode ternary to fit the line width.
2026-10-12 11:32:33 -07:00
Chris Tate 8c035be7de Merge main into fix/constrained-memory-libuv 2026-10-12 13:18:23 -05:00
Chris Tate 8c4bb3277c Merge main into perf/string-search-pairs 2026-10-12 13:16:39 -05:00
Chris Tate 829a326bb7 Merge main into perf/string-maps 2026-10-12 13:14:33 -05:00
Chris Tate 7e6294ca0f Make scriptc compilation native-only 2026-10-12 12:25:30 -05:00
Malte Ubl 6db7962aae Leave glibc's heap to the huge-page policy instead of prefaulting it
Where THP is in madvise mode the heap policy (#873) moves glibc's brk heap
to huge pages once it has grown 32 MiB, the same point at which the prefault
helper (#871) starts faulting in every heap extension. Together they cost
more than they save: the helper populates an extension from its start, where
the owner is already carving, so both threads clear the same 2 MiB pages and
the kernel drops one copy; slab requests queue behind the multi-megabyte
heap populates; the owner's brk and madvise wait for the mmap lock those
populates hold; and the helper's 16 MiB top pad replaces the policy's 32 MiB.
In madvise mode the helper now leaves the heap alone (no polling, no top
pad, no heap populate) and keeps faulting ahead in the allocator's slices.
Heaps on small pages (THP never or absent, or always) keep the heap mode.
2026-10-12 10:22:46 -07:00
Chris Tate d75d7a22f0 Prepare v0.2.10 2026-10-12 10:31:02 -05:00
Chris Tate 043c656bbd Merge main into feat/program-lifetime-publication 2026-10-12 09:38:24 -05:00
Malte Ubl 09118a3c25 Read the process's own cgroup in process.constrainedMemory() like libuv
scr_constrained_memory read /sys/fs/cgroup/memory.max, the root of the cgroup mount, and answered
0 for "max". Node's process.constrainedMemory() is libuv's uv_get_constrained_memory (libuv 1.51
in Node 24.15): the cgroup named by /proc/self/cgroup, the smaller of memory.max and memory.high
(v2) or of memory.limit_in_bytes and memory.soft_limit_in_bytes (v1, falling back to the
controller's root), with "max" and v1's page-aligned LONG_MAX read as UINT64_MAX and an unreadable
file making the answer 0. The two only agreed inside a cgroup namespace; in a nested cgroup or a
systemd scope the native build reported the root's limit (17179869184 in a 16 GB sandbox where Node
answers 18446744073709552000, or 2147483648 under memory.high=2G), so programs that size
themselves by it ran out of memory.

process.availableMemory() follows uv_get_available_memory too: under a constraint no larger than the
machine's memory, the constraint minus the cgroup's current usage; otherwise MemAvailable, then
sysinfo's freeram.

The corpus program prints the exact constraint, so Node and the native build must read the same
cgroup.
2026-10-12 07:22:54 -07:00
Malte Ubl 5201ab9340 Find multi-byte needles without a memchr call per first-byte hit
scr_byte_find called memchr for the needle's first byte and memcmp at
every hit. Path searches such as indexOf('/./') or indexOf('//') hit the
first byte at every separator, so each search paid two library calls per
path segment.

Haystacks of up to 256 bytes now test eight candidate starts per step for
the first two needle bytes with a SWAR zero-byte test (no false negatives;
false positives are rejected by the byte checks) and compare the rest only
at real two-byte matches. Longer haystacks keep memchr but check the
second byte inline before memcmp.

The tsc-ts parser (tRPC, parse only) runs 1.1% fewer instructions; string
search there drops from 111M to 82M instructions.

The new corpus program covers both strategies, every match offset around
the 8-byte steps and the 256-byte cut, near misses, the 0x01 false
positive pattern, and non-ASCII needles and haystacks.
2026-10-12 07:22:54 -07:00
Malte Ubl b0fec9e55c Find string map keys without a stack frame
scr_map_entry_str serves every string-key Map/Set read of generated code.
For a key with a cached hash in linear or compact-bucket storage it is now
a leaf: the filter test, the probe and the identity comparison run without
saving registers. A hash match on another string object tail-calls the
byte comparison; uncached hashes and wide tables take the complete lookup.
2026-10-12 07:22:52 -07:00
Malte Ubl 726dc34971 Keep the map filter without extra passes
Growth rebuilds the bucket table from unchanged entries, so the filter it
already has stays valid; only compaction drops entries, and it now
recomputes the filter in its copy loop instead of a second pass.
2026-10-12 07:22:52 -07:00
Malte Ubl f04681f0b6 Reject absent map keys through a filter in the map header
Every live entry's hash sets two bits of a new 64-bit ScrMap.filter, so a
lookup whose bits are not both set is absent without loading the bucket
table or the entries. String-keyed lookups in tsc-ts are mostly misses
(Map.get 67% on Excalidraw, has 87%), and the filter rejects 84-88% of
the misses on non-empty maps. Deletions leave their bits; rebuilds,
compaction and clear recompute the filter from the live entries.

Lookups also return the entry index straight from the probe instead of
reading the bucket again. The filter sits after nlive, so the backend's
%ScrMapIx fields for entries and the direct index move by one.
2026-10-12 07:22:52 -07:00
Malte Ubl e1ccfeeb84 codegen: signed conversions for array counters and lengths
Integer induction counters live in unsigned 64-bit slots, so every read
as a number was a uitofp i64 (a 6-7 instruction sequence on x86-64) and
every nested start an fptoui. The runtime's push path also round-tripped
the array length through a double for its bound check.

The values are at most 2^32 - 1: on 64-bit targets convert counters with
sitofp and loop starts with fptosi, convert array lengths and validated
indices through int64_t in scr_array.c, and test the push bound on the
integer length. 32-bit targets keep the unsigned conversions.

tsc-ts Excalidraw: uitofp i64 sequences 32.5 M -> 4.0 M, -0.66%
instructions on top of the throw-path change.
2026-10-12 06:40:50 -07:00