Commit Graph
415 Commits
Author SHA1 Message Date
Chris Tate 8bd17409db Sync runtime and compiler updates into canary
- Merge main's runtime optimizations and CI changes with canary's frontend improvements.
- Preserve adaptive cycle reclamation with inline allocation and deallocation.
- Repair native bootstrap callback narrowing and emitter expectations.
2026-10-08 17:41:20 -05:00
Chris Tate 13633c08b6 Merge pull request #772 from vercel-labs/fix/method-census-data-writes
Fix compiling tsc-ts: keep data writes out of the method replacement census
2026-10-08 16:48:36 -05:00
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 3fe49589ee Record preflight/order baselines for corpus 4294-4296
The TypeScript 7 parity job needs baselines for the console corpus
programs this PR adds (4294-console-line-sizes, 4295-console-template-
parts, and 4296-console-glued-long-parts from the overflow fix).
Recorded with SCRIPTC_UPDATE_BASELINES=1 pnpm exec vitest run
packages/compiler/test/ts7/order-parity.test.ts. The re-recorded file
added only these three and #763's 3170, with no existing entry changed.
The 3170 entry is left to #763. These are inserted at their sorted
position, apart from 3170, so the hunks stay independent when the stack
is rebased.

node scripts/test-ts7.mjs --baselines-only now reports only 3170, which
the rebased base branch provides.
2026-10-08 15:51:42 -05: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 66b773fd7f Read optional elements and captured parameters without boxing (#767) 2026-10-08 12:52:53 -05:00
Chris Tate c903daefcf Back off cycle scans for long-lived object graphs (#741) 2026-10-08 11:54:45 -05:00
Chris Tate 4795ddd1dd Initialize import cycles in module evaluation order (#740) 2026-10-08 11:29:07 -05:00
Chris Tate f6390d878b Carry optional values, never-returning calls and native iterators through typed returns (#739) 2026-10-08 11:04:59 -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 fcee23f398 Preserve function identity through adapted callbacks (#737) 2026-10-08 10:15:30 -05:00
Chris Tate 8a9497cfa2 Track record field presence separately from undefined values (#736) 2026-10-08 09:47:45 -05:00
Chris Tate 06b03f06a9 Compose class references across unions and collections (#734)
* Compose class references across unions and collections

- Compare class, function and native references held in differently represented unions with `===`, `!==` and `Object.is` while preserving subclass identity, and refuse comparisons that a structural union arm leaves undecidable
- Keep subclass values intact through base-typed array and Set insertion spreads, `concat`, and inferred class-predicate `filter`/`find`/`findLast`, and allow checked class refinement of captured optional values with several class arms
- Split the sanitized compiler self-rebuild CI job at the IR boundary, after giving sort helpers distinct IR nodes so serialized and in-memory IR emit the same LLVM

* Keep compact comparisons for plain union arms

- Compare a plain operand with a union that already holds its type through the existing inline union comparison, preserving established parameter representations
- Update the coverage expectation for the accepted class refinement
2026-10-08 07:35:21 -05:00
Chris Tate 08772d01c8 Preserve narrowed class values and collection composition
- Preserve narrowed class and generic values, abstract properties, and standalone caught-class identity.
- Support identity-preserving array concatenation and typed-array collection values, with focused differential and sanitizer coverage.
- Share revision-matched bootstrap seeds across CI jobs while retaining command, rebuild, packaging, and sanitizer checks.
2026-10-08 01:21:43 -05:00
Chris Tate 25703ddbbf Preserve spread calls and explicit receiver signatures
- Preserve argument order and receiver binding for replaceable method spreads.
- Accept typed callback signatures with an explicit receiver parameter.
2026-10-08 00:24:20 -05:00
Chris Tate fe2a903757 Preserve native class views and numeric updates
- Keep narrowed class fields and shared union writes native.
- Support covariant returns and method extraction through abstract class views.
- Preserve missing numeric values through local, static, and namespace updates.
2026-10-07 23:57:49 -05:00
Chris Tate c48e5bea09 Improve native callbacks, value narrowing, and runtime metadata
- Keep typed callbacks on native paths while preserving receivers, evaluation order, and method replacement.
- Preserve caught class identity, collection narrowing, and missing indexed values across typed code.
- Add standard terminal access and filesystem error metadata with differential coverage and versioned runtime compatibility.
2026-10-07 21:54:58 -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