On 64-bit little-endian targets ScrStr's capacity word is split into a
32-bit cap and a 32-bit cached Map key hash (header stays 24 bytes).
Heap strings fill the hash on first lookup; every in-place mutation path
(unique concat, split scratch reuse, regrow, spare reuse) clears it.
Immortal strings are never written: compiler literals and the runtime's
one-character/empty statics carry the hash precomputed (string-key-hash.ts
mirrors scr_key_hash; both sides pin the same vectors).
scr_key_hash seeds by length multiplicatively: XORing the length into the
low bits cancelled against the last byte ("ab" and "abc" collided).
Map string lookups inline the probe into each getter and reject linear
entries by hash; set specializes its probe/overwrite by lookup kind with a
shared append path.
Tests: runtime map.test.ts (pinned vectors, statics, in-place append
invalidation), string-key-hash.test.ts, corpus 3141-map-string-key-hash
(plain + sanitized; mutation-checked against both invalidation paths).
After the union fix, records-sort spent most of its time in the IR merge
sort's element moves: every src[i] read retained the swapped `src` array
and the element (scr_arr_get_ref), every dst[k] write released the old
slot, and `dst` grew from an empty array.
scr_arr_sort_values runs the IR helper's exact algorithm (same comparator
call order) over borrowed slot copies of the private, compacted snapshot:
- comparator calls use the callValue ABI (owned element arguments, an
undefined `this` window, pending-exception check);
- the array keeps owning every element and is untouched while user code
runs, so the cycle collector and a throwing comparator see the original
snapshot; the sorted permutation is published only after success;
- f64 and reference-counted element types qualify (isSortValuesElement);
unions with an undefined arm and checked/island values keep the IR.
The new internal arrIntrinsic `sortValues` is validated, may throw, and
is not reference-preserving.
scr_union_release buffered every union box left alive by a release as a
cycle-collector candidate, including boxes whose arm_trace is NULL (scalar
arms, and ref arms whose type the compiler proved acyclic, such as
TreeNode | null once TreeNode is constructor-only). Such a box's trace visits
nothing, so it can never be on a collectable cycle: skip the candidate
buffer for it. Deaths check the header's buffered bit inline before calling
scr_cyc_on_dead, because typed-ref cache commits swap arm contents between
boxes of one union type, so a box can have been buffered under an earlier
arm.
test_closure.c checks that string- and f64-armed boxes are never buffered,
that closure-armed boxes are, and that a closure -> box -> union -> closure
cycle is still collected under the RC audit.
libregexp compiles every non-sticky pattern with a `.*?` search prefix and
interprets its bytecode one opcode at a time, so an unanchored search pays a
backtrack push/pop and ~7 dispatches per subject position, and each `x+`
iteration pushes a backtrack state. Profiles of regex-logs and
template-render showed 65-85% of samples inside lre_exec.
scr_regex_native.h translates the compiled bytecode body (the bytecode stays
the source of truth for parsing, flags, case folding and capture numbering)
into a small program for one-byte subjects:
- single-character opcodes become 128-entry tables computed by evaluating the
interpreter's own predicate (lre_canonicalize, lre_is_space, range pairs)
for each ASCII code unit, so /i and /u are exact on these subjects;
- quantifiers over one character become counted loops that backtrack by
count; greedy loops whose continuation cannot start with a byte of the
loop's class (or is just saves + match) are possessive;
- runs of literal bytes become one memcmp;
- splits, gotos, saves, capture resets, counted group loops and empty-check
registers keep libregexp's exact backtracking order and undo semantics;
- unanchored searches start only at bytes that can begin a match (memchr for
a single byte) and only at 0 for non-multiline `^` patterns.
Lookaround and back references, and all non-ASCII subjects, keep lre_exec.
scr_exec is the single dispatch point, so every match loop is shared. The
program is built with the bytecode and cached on ScrRegex (new `native` slot;
the emitter's %ScrRegex type and literal initializer gain one null pointer).
Tests: packages/runtime/test/test_regex_native.c fuzzes the matcher against
lre_exec (random patterns over the subset and its bail-outs, every start
index, all capture slots; ASan+UBSan), wired into regex.test.ts; a sweep of
8 seeds x 100k patterns (~575k translated, ~70.7M checks) found no mismatch.
tests/corpus/regex-native-matcher.ts pins each construct through the public
APIs on ASCII subjects and non-ASCII twins.
Squashes 1d210a03: build the fuzz test with -D_GNU_SOURCE on Linux; the
vendored cutils.h needs CLOCK_MONOTONIC, which strict -std=c11 hides on glibc.
Move the allocator into scr_alloc.c with inline fast paths in scr_runtime.h;
strings, array headers/slot buffers, and emitted acyclic records/classes
(scr_rt_calloc/scr_rt_free) now use it. Adds scr_alloc.test.{c,ts}.
* Remove the large-array cliff past 2^20 elements
Arrays longer than 2^20 kept every element beyond the cutoff in a sorted
side store, and each indexed write to an existing entry deleted and
reinserted it, so fill + indexed read/write loops went quadratic
(n=1.2M: 10.4s on macOS arm64, 12.6s on Linux x64).
- Rewrite existing sparse entries in place.
- Let dense storage grow past the cutoff for contiguous extension of a
populated prefix, bulk range writes, and sparse tails that reach 3/16
density, migrating side-store entries so index < cap stays dense.
- Make the side store a deque with front slack so descending first-touch
writes and prefix migration are amortized O(1).
- Bound range-derived slice/splice capacity hints for hole runs.
scr_arr_new now reserves the live count, so a 2^20+3 element Set
converts into dense storage instead of a sparse tail; the white-box
test_lib check that pinned the old policy now asserts dense storage.
* Share immortal boolean union boxes
Maybe-undefined reads of boolean[] elements (`if (composite[i])` in a
sieve) box the element in a boolean|undefined union and free it at once:
one calloc/free pair per read, about a quarter of numeric-kernels samples
at large scales. Unions are immutable and boolean arms own no payload, so
low tags now return headerless immortal instances, the same convention as
the compiler's static unit-arm constants.
* Record preflight/order baselines for corpus 3138
- Preserve callback identity, receiver binding, and class references across unions and collections.
- Track record field presence independently of undefined values and improve native runtime behavior.
- Expand differential coverage and streamline CI bootstrap and compiler rebuild checks.
- Add native worker execution with isolated module state, structured messages, and lifecycle controls.
- Support shared buffers and integer atomics with coordinated runtime ownership and cancellation.
- Extend compiler, runtime-pack, differential, and compatibility coverage for native concurrency.
- Avoid materializing scalar string slices and preserve index metadata.
- Specialize known callbacks and numeric call boundaries.
- Lower proved integer remainders without changing number semantics.
- Sort primitive arrays with stable native ordering and pure conversion keys.
- Preserve sparse semantics and argument effects while avoiding callback overhead.
- Verify Unicode ordering and ownership across native and WASI paths.
- Reuse bounded local spans and process Unicode index conversions in chunks.
- Share slice extraction and avoid unnecessary work in positioned searches.
- Preserve cached receiver state across suffix checks and cover navigation lifetimes.
- Lower literal switches to guarded native dispatch while preserving control flow and evaluation order.
- Reduce repeated AST lookup, traversal ownership, and source classification work.
- Share UTF-8 validation and decode spans directly into final string storage.
- Share regex input preparation and bound capture storage to each result.
- Batch replacement output and avoid rebuilding unchanged strings.
- Accelerate case conversion and normalization while preserving Unicode and ownership behavior.
- Share dense array storage and move owned ranges without rebuilding containers.
- Batch array construction and insertion while preserving evaluation order and bounded temporary storage.
- Lower indexed mutations natively and preserve typed-array reversal across numeric element types.
- Borrow rooted collection receivers across safe helpers and typed updates.
- Keep small Maps and Sets compact through cloning, growth, and live iteration.
- Preserve ownership at reassignment, exception, and capture boundaries.
- Enforce oxlint and oxfmt for owned JavaScript and TypeScript with independent CI checks.
- Preserve compiler import boundaries and protected fixtures while cleaning up lint findings.
- Standardize source formatting and validate import, fixture, and embedded-source protections.
- Read binary and text files into owned storage across filesystem entry points.
- Extend integer inference through module initialization and filtered processing loops.
- Preserve shared bindings, byte views, and filesystem error behavior.
- Support boolean, bigint, and mixed value keys in native Maps and Sets.
- Reuse key hashes and copy collections directly into compact storage.
- Preserve collection identity, ordering, iteration, and ownership behavior.
- Combine bounded string concatenations while preserving evaluation and ownership.
- Build array joins and raw strings directly in their final storage.
- Support literal null and undefined string conversions with preserved effects.
- Infer safe input lifetimes across checked reads, calls, conversions, and comparisons.
- Reuse immutable primitive values during construction and JSON parsing.
- Preserve callback ordering, result ownership, and exception cleanup.
- Reduce allocation and reference-management overhead in native array loops.
- Enable vectorization while preserving numeric behavior.
- Preserve live tuple iteration and cover reference lifetimes and missing values.
* feat: support Node 24 filesystem timestamp operations
* test: record frontend baselines for timestamp fixtures
* test: link timestamp validation into the runtime smoke test
* Expand static compilation for common Effect 4 patterns
* Run every Effect 4 fixture slice in CI
* Preserve existing corpus behavior across Effect 4 lowering
* Preserve Effect platform callbacks and native stream state
* Record new corpus baselines and retain child stdin refusals
* Retire the obsolete stateful regex diagnostic
* Preserve promise reference count layout for cycle collection
* Make native installs portable and smaller
- Support glibc 2.34 with portable compiler binaries and static LLVM helpers.
- Bundle the host runtime and discover optional cross-target packs from project dependencies.
- Add application build benchmarks covering latency, executable size, and memory.
* Keep bootstrap tools available in Sandbox validation
- Isolate Zig for native compiler bootstrap and glibc entropy contracts.
- Preserve the existing toolchain scope for cache and corpus tests.
* Fix portable compiler bootstrap linking
- Keep native support objects compatible with the destination host linker.
- Resolve installed targets using the host declared by the toolchain manifest.
* feat: support static buffer constructors and prototype methods
- Preserve typed-array constructor identity and shared storage across JavaScript class APIs.
- Support chained indexed assignments and mutable prototype methods with native receiver dispatch.
- Compile Three.js geometry merging, instancing, and keyframe interpolation without a JavaScript engine.
* fix: preserve native collection and dispatch semantics
- Preserve typed-array identity in collections and JavaScript argument evaluation.
- Keep symbol-backed fields and unreachable methods on their existing static paths.
- Restore compiler bootstrapping and deferred class diagnostics.
* fix: preserve inferred returns in native compilation
- Update recorded return statements in place so native compilation preserves mixed JavaScript return values.
* test: update inferred array coverage expectations
- Recognize heterogeneous writes supported by shared JavaScript array storage.
- Remove C emission, debugging options, and automatic backend fallback.
- Complete LLVM lowering and native bootstrap coverage across supported targets.
- Link executables and libraries with precompiled C runtime packs, including iOS and Android.
- Share frontend loading, package selection, contracts, and FFI parsing between Node and native clients.
- Preserve collection layouts and optional method returns while lowering long nullish chains without recursive stack growth.
- Rebuild the frontend from TypeScript through native lowering and C emission with matching output.
- Carry BigInts, Sets, and regular expressions through checked native storage without a JavaScript engine.
- Preserve dictionary aliases, spreads, frozen metadata, and fluent initialization helpers.
- Collect checked object and closure cycles while preserving live references.
- Preserve fresh constructor identity and shared captures across local class instances.
- Carry constructors through unknown values without a JavaScript engine.
- Support runtime-length spreads into fixed and rest parameters.
- Run production scope and closure capture logic with native TypeScript 7 symbols.
- Give lowering caches explicit pass ownership and stable symbol identities.
- Support reference collection arrays and optional Set seeds on both native backends.
- Share program creation, checker queries, virtual files, and snapshot lifetimes between Node and native compiler clients.
- Preserve typed async-context results and opaque compiler objects through checked native boundaries.
- Support native realpath and Unicode Windows filesystem operations needed by the compiler host.
- Store checked values in native collections while preserving supported object identities and JavaScript key equality.
- Support collection iteration and reject reference conversions that would copy or adapt stored objects.
* feat(compiler): advance self-hosting with identity collections
- Support reference identity in Maps and Sets, including unions and cycle cleanup.
- Run production integer-range analysis natively with typed IR traversal.
- Add differential coverage for native analyses and collection behavior.
* chore: ignore generated output directories
- Exclude generated output directories from version control.
- Compile production IR serialization and runtime dependency scans on both native backends
- Support native JSON callbacks and checked records with unknown payloads
- Verify native IR round trips and executable generation with focused sanitizer coverage
* Handle static lastIndexOf position semantics
* Record TS7 baseline for positioned string search corpus
* Stabilize HTTP timeout differential fixtures
* Order proxy fixture server shutdown
Represent ordinary JavaScript arrays with hole, value, and explicit-undefined states; add sparse side storage and carry missing values through the frontend, native backends, runtime, and Node-facing consumers.