Commit Graph
401 Commits
Author SHA1 Message Date
Malte Ubl 2625ae9c9e Keep data writes out of the class method replacement census
The method-replacement census marks a method name as an observed slot
when some write might replace it, and calls of observed methods go
through a checked property lookup whose result converts back to the
declared return type. Two kinds of data writes over-approximated that:

- A computed write into a string-keyed dictionary marked every method in
  the program unless the dictionary's values were primitives. Class
  instances have no implicit index signature, so such a dictionary is a
  class view only when the class declares the index signature, and then
  every method must be assignable to its value type. Any value type no
  function can inhabit now qualifies: primitives, or non-callable object
  types that require a property functions lack, or weak types sharing no
  property with functions.
- A named write like `this.literal = token` marked `literal` for every
  class. The write can only replace a method when the written property
  can hold a function, so property writes are now judged by the written
  property's type (prefetched in one batch).

Compiling vercel-labs/tsc-ts failed after the canary promotion: one
`changedProjects[id] = {...}` write marked every method, OptionNameMap.get
and the JSON parser's literal() calls returned unknown, and their Map-typed
results could not convert back (SC1100/SC1101, 61 errors).

Also skip abstract methods when materializing observed prototype slots.
An abstract declaration emits no prototype member, so lookup continues
to the ancestors; building its value instead threw an uncaught
PoisonError out of the reachability fixed point (the tsc-ts crash).

Tests: corpus 3171 (fails with SC1100/SC1101 before this change) matches
Node in the plain and sanitized lanes; the 112 corpus programs matching
abstract|prototype|method|callback pass; class-dynamic-dispatch unit
tests pass. tsc-ts now builds and type-checks itself with output
identical to tsgo 7.0.2.
2026-10-08 14:32:33 -07:00
Malte Ubl 4c1cc612be Record the preflight/order baseline for corpus 3170
The TypeScript 7 parity job reported tests/corpus/3170-number-conversion-
fast-paths.ts as missing a baseline. Recorded with
SCRIPTC_UPDATE_BASELINES=1 pnpm exec vitest run
packages/compiler/test/ts7/order-parity.test.ts: the re-recorded file
added only this program (and the later stack's console programs, which
belong to #764), with no existing entry changed. The entry is inserted
at its sorted position in the stack's baseline block so it does not
overlap the #764 entries when the stack is rebased.

node scripts/test-ts7.mjs --baselines-only passes.
2026-10-08 15:49:53 -05:00
Malte Ubl 66e82da225 Record preflight/order baselines for corpus 4032 2026-10-08 15:46:34 -05:00
Malte Ubl 9cf183e053 Record preflight/order baselines for corpus in-array-runtime-index, regex-exec-long-subject, regexp-constructor-repeat, timers-clear-many 2026-10-08 15:44:26 -05:00
Malte Ubl 93b4994220 Lower runtime-key in over arrays and dictionaries to presence probes
`i in arr` with a non-literal number key boxed the typed array into the
checked-dynamic tree and materialized every element per evaluation, so
`for (...) if (i in arr)` loops were quadratic (1e4 elements: 5.3 s vs
Node 0.7 ms). A number key over an array receiver now lowers to arrayHas
(scr_arr_has), the query the literal fold and Object.hasOwn already use;
the key is stabilized first to keep JS evaluation order.

`k in dict` with a runtime string key over an index-signature record
snapshotted and scanned every overflow key per probe (1e4 keys: 436 ms,
1e5: timeout). The helper now ends in recordOvfHas (scr_map_has_str).
2026-10-08 15:44:26 -05:00
Malte Ubl 4daa362e55 Record preflight/order baselines for corpus 3141 2026-10-08 15:40:53 -05:00
Malte Ubl 520dc20711 Record preflight/order baselines for corpus 4140, 4141, 4142 2026-10-08 15:38:45 -05:00
Malte Ubl 88dfc2ebde Record preflight/order baselines for corpus 4410 2026-10-08 15:36:07 -05:00
Malte Ubl cabfbe1f14 Keep inline allocation out of worker programs
Upstream native workers (095b6193) compile the runtime with -DSCR_WORKERS,
which makes scr_cyc_live and scr_weak_dispose_hook thread-local, and the
small-object allocator is compiled out there. The inline allocation paths
address those as ordinary globals, so worker programs keep the out-of-line
runtime calls, exactly like thread-instanced libraries.

A worker-threads test pins that worker LLVM references neither the
allocator state nor the thread-local counters, and that worker programs
keep the fiber path for async bodies (the entry 07 adaptation).
2026-10-08 15:36:07 -05:00
Malte Ubl 439964a693 Inline the small-object allocator into emitted constructors and releases
Emitted record and class constructors called scr_rt_calloc/scr_cyc_alloc
with a constant size, so the size class, the zeroing length and the
collector header setup were recomputed per object behind a call (plus an
empty scr_obj_alloc_note call and a variable-length memset). llvm/alloc.ts
now emits the fast paths inline: pop the class free list (clearing only
the bytes the helper does not store itself) or bump, with the old calls as
the cold slow path. Releases inline the weak-dispose hook check, the live
count, and the free-list push; blocks outside the reservation still go to
scr_rt_free.

The emitted IR does not know which runtime it links against (the sanitized
lane only differs at link time), so the runtime now defines scr_sa in
every build. Where the allocator is compiled out (ASan, SCR_RC_AUDIT,
wasm32, Windows, 32-bit, thread-instanced libraries) it stays all-zero and
the inline paths always take the slow path, which keeps the RC-audit
object notes. ScrSaState's layout is pinned with static asserts. Inline
emission is additionally gated off for 32-bit, WASI, Windows triples and
thread-instanced libraries.

Runtime callers with hot constant-size allocations (union boxes, arrays,
boxes, closures, dyn nodes) use new static inline twins
scr_cyc_alloc_inline/scr_cyc_free_inline; scr_cyc_live is exported.

The ABI guard now recognizes function-pointer extern data
(scr_weak_dispose_hook). New corpus program 4410 pins recycled-block
clearing, size classes, objects above the largest class, cycles and weak
observers.
2026-10-08 15:36:07 -05:00
Malte Ubl efae7de476 Expect borrowed constructor bodies in the call-lifetimes test
`new Item()` now calls the borrowed constructor body, so no retain transfers the fresh instance into it: the snapshot body retains twice, not three times.
2026-10-08 15:34:37 -05:00
Malte Ubl 0207eb658c Record preflight/order baselines for corpus 4060, 4061 2026-10-08 15:34:37 -05:00
Malte Ubl 0d0a94b86d Record preflight/order baselines for corpus array-sort-runtime-comparator, closure-union-locals 2026-10-08 15:31:04 -05:00
Malte Ubl c5bd41b3c5 Update lifetime tests for closure-body locals and borrowing union equality
The cleanup fixture runs as a closure body; its literal binding is now a
stable immortal value without cleanup, so the test uses an owned value.
Whole-union string equality is a borrowing use, so its caller passes a
stack box instead of a heap union.
2026-10-08 15:31:04 -05:00
Malte Ubl 6902bf3cb3 Record preflight/order baselines for corpus 3150, 3151 2026-10-08 15:28:05 -05:00
Malte Ubl 7ac8f23019 Integer remainder fast path for unproven operands and inline array push
% now checks at run time whether both operands are integers (dividend
|x| <= 2^53, nonzero integer divisor) when the integer-range analysis
cannot prove it, and then uses i64 srem with JS sign-of-zero semantics;
fractions, NaN, Infinity, zero divisors and huge dividends keep frem.
Proven integers whose divisor may be zero now only check for zero.

push() appends inline while len < cap (the runtime append is exactly a
dense store at len plus len+1 there) and keeps a cold runtime call that
grows storage otherwise. Element writes were already inlined by H04.

Built on the H04 commits cherry-picked from perf/h04-array-reads
(d88b58a1, a6057a52, 9109cb5a, 657aa3fb). New corpus programs
3150-integer-remainder and 3151-array-push-writes.

Marginal vs perf/h04-array-reads, 15 runs:
| workload            | macOS   | Linux (focused) |
| numeric-kernels     | -18.3%  | -10.3%          |
| functional-pipeline |  -8.8%  |  -4.3%          |
| template-render     |  -2.9%  |  (layout, sweep -0.6%) |
| alloc-trees         |  -2.0%  |  (layout, sweep +0.3%) |
| records-sort        |  -1.5%  |  -0.3%          |
| csv-numbers         |  -0.3%  |  +0.1%          |
geomean marginal: macOS -2.8%, Linux full -0.6%.
vs perf/harness (incl. H04): macOS -14.4% (1.222x Node),
Linux -16.0% (1.160x Node). Linux .text growth <= 3.6%.
Tests: LLVM differential corpus 2008/2008 (Linux, 6 shards, release+dev),
sanitized 3140/3150/3151 pass, backend+ir unit tests pass except one
load-flaky zig COFF cache test that passes in isolation.
2026-10-08 15:28:05 -05:00
Malte Ubl d51bbc2137 Record preflight/order baselines for corpus 4290, 4291, 4292, 4293 2026-10-08 15:26:31 -05:00
Malte Ubl 6d44486def Record preflight/order baselines for corpus fiber-switch-stress, fiberless-async-ordering, fiberless-async-unhandled 2026-10-08 15:22:27 -05:00
Malte Ubl 167cb93440 Record preflight/order baselines for corpus regex-native-matcher, 3139 2026-10-08 15:19:12 -05:00
Malte Ubl 3c54f2ff60 Record preflight/order baselines for corpus 3140 2026-10-08 15:06:48 -05:00
Malte Ubl 198d993fed Record preflight/order baselines for corpus json-typed-parse-direct 2026-10-08 15:05:00 -05:00
Malte Ubl 0c2232deb0 Parse typed JSON straight into native records
`JSON.parse(text) as T` used to build a checked-dynamic ScrDyn tree, copy
it into the native layout with the generated dynCheck builder, and then
dispose the tree. Together that was about 68% of json-records.

For record/array targets with number, boolean and string leaves, the
backend now emits a ScrJsonSchema (field offsets in declaration order,
constructors, releases) and a wrapper. The wrapper calls the new
scr_json_parse_schema, a one-pass parser that writes directly into native
records and arrays. Whenever it declines (syntax errors anywhere, kind
mismatches, missing or duplicate declared keys, excess depth) it releases
its partial value without throwing, and the wrapper reruns the unchanged
scr_json_parse + dynCheck route. Every error message and position stays
byte-identical. The lexer helpers are shared through a quiet mode and a
factored number scanner, so values decode bit-identically.

Tests: new differential corpus program json-typed-parse-direct.ts; a
dyncheck harness case comparing typed and untyped error messages through
the fused path; white-box C tests for accept/decline and leak-freedom in
scr_json.test.c; an LLVM emission test (64-bit and wasm32).

Linux (sandbox x86_64, runs=15):
| workload | baseline ms | candidate ms | change | 95% CI | verdict | size | node ms | candidate/node |
| --- | ---: | ---: | ---: | --- | --- | ---: | ---: | ---: |
| json-records | 713.2 | 249.3 | -65.0% | -65.6% .. -64.1% | faster | +2.2% | 439.04 | 0.57x |
| regex-logs | 350.8 | 353.7 | +0.8% | -0.9% .. +2.3% | neutral | +0.0% | 238.42 | 1.48x |
| ast-interp | 379.1 | 376.8 | -0.6% | -1.8% .. +0.4% | neutral | +0.0% | 227.45 | 1.66x |
| records-sort | 1200.5 | 1207.8 | +0.6% | -2.4% .. +5.7% | neutral | +0.0% | 232.17 | 5.20x |
| template-render | 248.3 | 248.1 | -0.1% | -2.3% .. +1.0% | neutral | +0.0% | 202.16 | 1.23x |
| functional-pipeline | 402.0 | 395.3 | -1.6% | -3.8% .. +0.5% | neutral | +0.0% | 254.57 | 1.55x |
| async-pipeline | 202.4 | 201.7 | -0.3% | -1.4% .. +2.0% | neutral | +0.0% | 90.14 | 2.24x |
| word-graph | 366.9 | 348.2 | -5.1% | -12.9% .. +4.3% | neutral | +0.0% | 576.56 | 0.60x |
| alloc-trees | 513.5 | 525.5 | +2.3% | -2.1% .. +4.0% | neutral | +0.0% | 132.99 | 3.95x |
| numeric-kernels | 121.4 | 122.5 | +0.8% | -1.9% .. +3.6% | neutral | +0.0% | 135.91 | 0.90x |
| validate-errors | 206.0 | 209.2 | +1.5% | -3.6% .. +4.1% | neutral | +0.0% | 703.47 | 0.30x |
| csv-numbers | 450.9 | 448.6 | -0.5% | -2.2% .. +2.0% | neutral | +0.0% | 499.25 | 0.90x |
| log-summary | 253.5 | 252.6 | -0.3% | -1.5% .. +2.0% | neutral | +0.0% | 279.67 | 0.90x |
| inventory-report | 433.7 | 433.2 | -0.1% | -6.0% .. +3.6% | neutral | +0.0% | 413.79 | 1.05x |
geomean change -7.4%; geomean candidate/node 1.321x -> 1.223x

macOS (arm64, runs=15):
| workload | baseline ms | candidate ms | change | 95% CI | verdict | size | node ms | candidate/node |
| --- | ---: | ---: | ---: | --- | --- | ---: | ---: | ---: |
| json-records | 292.3 | 153.0 | -47.7% | -50.1% .. -46.6% | faster | +0.4% | 248.7 | 0.61x |
| (all 13 other workloads neutral; see results/h16-typed-json/local-1.json) |
geomean change -4.8%; geomean candidate/node 1.497x -> 1.425x
2026-10-08 15:05:00 -05:00
Malte Ubl 8a9b1948e0 Let the runtime ABI guard skip calls inside static inline header bodies 2026-10-08 15:01:26 -05:00
Malte Ubl ecd9643eb0 Remove the large-array cliff (1.2M-element fill and update: 10.4 s to 0.03 s) (#743)
* 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
2026-10-08 15:01:21 -05:00
Chris Tate 1f10e83720 Promote canary to main (#738)
- 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.
2026-10-08 11:00:13 -05:00
Chris Tate 095b619330 Add native workers and shared memory
- 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.
2026-10-07 19:07:02 -05:00
Chris Tate a8bc0f6abf Optimize scalar string access and numeric calls
- Avoid materializing scalar string slices and preserve index metadata.
- Specialize known callbacks and numeric call boundaries.
- Lower proved integer remainders without changing number semantics.
2026-10-07 15:39:05 -05:00
Chris Tate 0b168d5c23 Borrow stable loop references and bound deep cleanup
- Borrow stable loop references and share guarded dense array reads.
- Bound recursive cleanup across generated objects and runtime containers.
- Preserve ownership through mutation, callbacks, sparse reads, and abrupt exits.
2026-10-07 14:31:14 -05:00
Chris Tate 13291c68d3 Preserve interface identity and extend native library calls
- Preserve live class identity through interface receivers and object methods.
- Extend synchronous text reads and regular expression replacement callbacks.
- Keep unsupported generic dispatch boundaries explicit.
2026-10-07 13:55:11 -05:00
Chris Tate 6aa48c111a Strengthen generic type and class boundaries
- Support concrete generic inheritance, forward references, and nullable substitutions.
- Bound recursive specialization demands while preserving independent concrete uses.
- Preserve class identity through checked assertions and contextual lowering.
2026-10-07 11:47:54 -05:00
Chris Tate e936346215 Parallelize large native builds and adapt cycle collection (#722) 2026-10-07 10:47:31 -05:00
Chris Tate 4ec55cdf64 Accelerate default primitive array ordering (#721)
- 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.
2026-10-07 08:15:08 -05:00
Chris Tate 4443271578 Optimize synchronous callback ownership (#720) 2026-10-07 06:48:58 -05:00
Chris Tate ec9376d48e Streamline semantic analysis and AST caching (#719) 2026-10-07 04:21:51 -05:00
Chris Tate c484422113 Optimize split keys and Map storage (#718) 2026-10-07 01:57:01 -05:00
Chris Tate b8ce03cc4c Streamline source discovery and checker metadata (#716) 2026-10-07 00:19:01 -05:00
Chris Tate f94e9b199d Optimize native byte record processing (#715)
- Infer complete byte-record extents and bounded output cursors for ordinary Buffer, DataView, and typed-array loops.
- Emit proved numeric fields directly while preserving checked fallbacks, error ordering, and debugger-visible storage.
- Cover aliases, partial records, expanding output, and numeric boundaries across native and WASI execution.
2026-10-06 22:19:41 -05:00
Chris Tate 763541b433 Stream string split loops
- Stream eligible split loops while preserving snapshots, bindings, and cleanup.
- Reuse unescaped piece storage and batch materialized results.
- Cover limits, Unicode, debugging, and native/WASI behavior.
2026-10-06 19:01:30 -05:00
Chris Tate 25b7fd266a Streamline structured text output
- Share bulk string writes and JSON formatting paths.
- Append scalar values directly and streamline exact integer formatting.
- Cover output boundaries and clarify runtime-pack identity failures.
2026-10-06 17:25:57 -05:00
Chris Tate 9482cbadcb Optimize typed-array numeric processing (#709)
- Streamline typed-array conversion, copying, and filling.
- Share exact integer coercion across typed storage and scalar operators.
- Cover numeric boundaries, aliased buffers, and portable execution.
2026-10-06 13:07:11 -05:00
Chris Tate 0ba86b289a Optimize keyed collection and object processing
- Speed up string-keyed collections and wide object property lookup.
- Share scalable numeric-key ordering across typed and checked objects.
- Preserve property, iteration, and ownership behavior across native and WASI targets.
2026-10-06 11:49:04 -05:00
Chris Tate e0bb196a73 Optimize text and byte conversion paths
- Reduce temporary storage and per-byte overhead across Buffer conversions, bounded writes, and text encoding.
- Support runtime Buffer string encodings with consistent defaults, aliases, and catchable errors.
- Cover conversion boundaries, partial writes, malformed inputs, and retained outputs across native and WASI execution.
2026-10-06 10:27:25 -05:00
Chris Tate 0b52b24d30 Optimize stable collection ordering
- Share adaptive stable sorting across arrays and byte arrays, reusing captured values and merge inputs.
- Use bounded-domain ordering for default byte sorting.
- Preserve sparse values, stable ties, callback effects, and reference lifetimes with native and portable coverage.
2026-10-06 09:28:35 -05:00
Chris Tate 88e6e6dcd0 Streamline class callbacks and compiler source access
- Defer empty callback storage while preserving method and prototype updates.
- Reuse source and node-handle information within compiler snapshots.
- Coalesce small checker requests and avoid response copies.
2026-10-06 08:10:34 -05:00
Chris Tate 05c24f6a41 Streamline local tagged values and collection reads
- Keep projection-only tagged values in local storage across branches and reassignment.
- Fuse optional array reads and avoid temporary wrappers for tag and string conversions.
- Preserve payload ownership across mutation, sparse iteration, and exception cleanup.
2026-10-06 06:51:14 -05:00
Chris Tate d3a165997b Optimize literal dispatch and source processing
- 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.
2026-10-06 04:19:01 -05:00
Chris Tate 3608a88602 Streamline regular expression and text transformations
- 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.
2026-10-06 02:17:01 -05:00
Chris Tate f22013f177 Improve array storage and bulk transformations
- 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.
2026-10-06 01:05:40 -05:00
Chris Tate 150e529d84 Streamline structured text scanning and serialization
- Share bounded JSON scanning and copy string spans in chunks.
- Avoid temporary key snapshots for primitive containers.
- Preserve Unicode, property ordering, and callback behavior.
2026-10-05 23:41:57 -05:00
Chris Tate 30e72eff79 Reduce checked-value allocation and lookup overhead
- Reuse bounded property-key and small-integer storage.
- Cache validated property positions and avoid tracing primitive object members.
- Cover storage transitions, numeric edge cases, and shared-value lifetimes.
2026-10-05 22:43:29 -05:00