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.
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.
`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).
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).
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.
`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.
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.
% 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.
* 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.