1510 Commits
Author SHA1 Message Date
Chris Tate 35ab79ecc3 Merge pull request #890 from vercel-labs/ctate/prepare-v0-2-f94a93
Prepare v0.2.10
v0.2.10
2026-10-12 10:37:12 -05:00
Chris Tate d75d7a22f0 Prepare v0.2.10 2026-10-12 10:31:02 -05:00
Chris Tate a968b15166 Merge pull request #881 from vercel-labs/feat/program-lifetime-publication
Publish ProgramLifetime graphs: program-lifetime instances count 2^63 until published
2026-10-12 10:29:17 -05:00
Chris Tate 043c656bbd Merge main into feat/program-lifetime-publication 2026-10-12 09:38:24 -05:00
Chris Tate 91bd61f6c9 Merge pull request #888 from vercel-labs/perf/codegen9
Keep runtime throw paths out of line; signed conversions for array counters
2026-10-12 09:27:29 -05:00
Chris Tate bfbe047cbb Read SCR_COLD as an attribute in the runtime ABI guard 2026-10-12 09:21:23 -05:00
Chris Tate 2391b0ebf3 Merge pull request #869 from vercel-labs/perf/parse-round4
Read charCodeAt at proven integer indices without a double round trip
2026-10-12 08:59:12 -05:00
Chris Tate 1f98312881 Merge pull request #880 from vercel-labs/feat/acyclic-contract
Acyclic contract type
2026-10-12 08:58:49 -05:00
Chris Tate bc9a33c9c7 Expect the runtime string-length bound in the bitwise range test 2026-10-12 08:54:54 -05:00
Chris Tate 936e9c5dae Merge main into perf/parse-round4 2026-10-12 08:51:31 -05:00
Chris Tate da309e1655 Identity bitwise forms over proven int32 operands return the operand (#878) 2026-10-12 08:49:35 -05:00
Chris Tate 7cf57f9ed5 Merge main into feat/acyclic-contract 2026-10-12 08:43:05 -05:00
Chris Tate d836ce0b83 try/catch discharges NoThrow (#879) 2026-10-12 08:41:35 -05: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
Malte Ubl b5e4bcb54e runtime: keep throw entry points cold and out of line
With runtime bitcode import, scr_throw_obj, scr_error_new and the other
throw entry points were inlined into the error paths of small compiled
functions. The inlined bodies needed callee-saved registers that every
call then saved and restored, and they made the helpers too large to
inline into their callers (1047 inlined throw bodies in tsc-ts).

Mark the 25 functions that only run while raising a JS exception
cold and noinline. The LLVM helper never imports noinline bodies, so
the throw paths stay calls. tsc-ts Excalidraw: -0.44% instructions.
2026-10-12 06:40:50 -07:00
Chris Tate 0b239089e7 Cover the integer-index charCodeAt helper in the borrowed-input ABI test 2026-10-12 08:25:43 -05:00
Chris Tate 85736170ae Merge main into feat/program-lifetime-publication 2026-10-12 08:13:15 -05:00
Chris Tate 0d2bcf9d97 Merge main into feat/acyclic-contract 2026-10-12 08:10:24 -05:00
Chris Tate 88b4e89e55 Merge main into feat/nothrow-try-catch 2026-10-12 08:07:54 -05:00
Chris Tate 0a4bf78d4a Merge main into perf/int32-or-zero-peephole 2026-10-12 08:05:16 -05:00
Chris Tate 44d22d785c Merge pull request #870 from vercel-labs/feat/contract-types
Contract types: NoThrow, Int32 and Immutable as checked type annotations
2026-10-12 07:57:28 -05:00
Chris Tate 83248651e2 Publish Immutable factory arrays only after provable index writes 2026-10-12 02:33:29 -05:00
Chris Tate f77d68f600 Keep the RC entry points of array elements in one shared descriptor (#882) 2026-10-12 01:59:44 -05:00
Chris Tate 48b5935337 Unshare repeated IR nodes before emission and contract checks 2026-10-12 01:47:05 -05:00
Chris Tate c5c6657c4e Drop guards on private constructor stores and borrow construction-only fields (#838) 2026-10-12 01:20:56 -05:00
Chris Tate 72cc828ab0 Merge main into perf/compact-array-header-2 2026-10-12 01:12:21 -05:00
Chris Tate 2ea30ede5b Merge main into perf/static-immutability 2026-10-12 01:09:18 -05:00
Chris Tate 0dee8207bb Keep self-hosting emission tests from blocking the test worker (#883) 2026-10-12 01:06:52 -05:00
Chris Tate 8ba3de7685 Merge pull request #884 from vercel-labs/ctate/store-order-parity-6abc93
Store order-parity baselines one file per fixture
2026-10-12 00:43:33 -05:00
Chris Tate 5e5ec89c76 Run the emission test's compiler passes off the test worker 2026-10-12 00:32:48 -05:00
Chris Tate 2933ebc985 Store order-parity baselines one file per fixture 2026-10-12 00:08:53 -05:00
Chris Tate 0874739c02 Run the frontend services test's compiler and processes off the test worker 2026-10-12 00:07:55 -05:00
Chris Tate 3be37b4ab3 Merge pull request #873 from vercel-labs/perf/locality
Give glibc's large blocks transparent huge pages
2026-10-11 23:53:50 -05:00
Chris Tate 4184028663 Keep self-hosting emission tests from blocking the test worker 2026-10-11 23:39:43 -05:00
Chris Tate a2a6a52522 Merge pull request #846 from vercel-labs/fix/narrowed-property-calls
Check narrowed member reads that a call can invalidate
2026-10-11 23:00:18 -05:00
Chris Tate b1f3b31546 Order the heap page size before huge page advice 2026-10-11 22:58:10 -05:00
Chris Tate 1c4b34d2da Keep publication guards after self-stores and own borrowed-result call arguments 2026-10-11 22:40:27 -05:00
Chris Tate 063a3c7956 Merge main into fix/narrowed-property-calls 2026-10-11 22:29:21 -05:00
Chris Tate f1fe105f18 Merge pull request #857 from vercel-labs/perf/map-get-inline-retain
Retain string-keyed map reads inline
2026-10-11 22:27:36 -05:00
Malte Ubl fa55ce6b07 Keep the RC entry points of array elements in one shared descriptor
Every SCR_ELEM_REF array stored its element type's retain, release and trace entry points in its own header (24 bytes), so ScrArr was 80 bytes: an 80-byte block for arrays of acyclic elements and a 96-byte block for cycle-capable ones. The three pointers now live in one constant ScrArrOps descriptor per element type, which the compiler emits once per module (@sc_arrops.*) and the runtime keeps static, and the header holds a pointer to it plus a 4-byte `cyc` flag beside `elem` that the inline RC fast paths test. ScrArr is 64 bytes: arrays take 64- and 80-byte blocks.

scr_arr_new_ref(retain, release, trace, cap) becomes scr_arr_new_ops(ops, cap); scr_set_to_arr_ref takes the result's descriptor from its caller instead of building an array from the set's key adapters. The backend names the %ScrArr fields in SCR_ARR_FIELD. The layout change bumps the runtime ABI marker to scr_runtime_abi_v13.
2026-10-11 19:46:48 -07:00
Chris Tate aa4fa790a3 Merge main into fix/narrowed-property-calls 2026-10-11 21:37:45 -05:00
Chris Tate 31aaefb4c6 Merge main into perf/map-get-inline-retain 2026-10-11 21:31:11 -05:00
Chris Tate 6b708b2e3e Merge pull request #876 from vercel-labs/perf/array-growth
Size small arrays exactly and keep map storage on the runtime allocator
2026-10-11 20:14:17 -05:00
Chris Tate 2ca61fea97 Merge pull request #872 from vercel-labs/perf/codegen
Dispatch literal switches without range tests and inline indexed-read helpers
2026-10-11 19:40:47 -05:00
Chris Tate 0755c81a3c Merge pull request #871 from vercel-labs/perf/offthread-prefault
Pre-fault allocator memory on a helper thread (Linux)
2026-10-11 19:40:24 -05:00
Malte Ubl 2ccb018004 Publish ProgramLifetime graphs with @scriptc/threads: program-lifetime instances count 2^63 until published
Program-lifetime instances were created with rc == SIZE_MAX, which every runtime contract reads as "published": the frozen-object guards throw on stores, postMessage and workerData share the object by pointer instead of cloning it, and the publish walker stops there. So programs that publish could not use ProgramLifetime (SC7007 refused it), and an unpublished instance posted to a worker would have been shared instead of cloned.

They are now created with the midpoint count 2^63 (2^31 on 32-bit targets). Only the class's empty retain and release helpers count references on these types, so nothing ever changes or frees that count; the midpoint keeps even an unpaired generic retain or release away from 0 and SIZE_MAX. Until the program publishes an instance it is an ordinary mutable, thread-local object to every runtime contract: stores succeed, postMessage clones it. Publication marks it SIZE_MAX like any object it reaches (the visited mark, logged and restored when a refusal undoes the publish), after which the frozen guards throw Node's TypeErrors and other threads read it by pointer. No header, extra word, runtime change or new instruction: the count itself is the published mark. The cycle analysis keeps the hierarchies untraced, so the collector never visits an instance, as for every untraced class.

SC7007 no longer refuses program-lifetime classes reachable from a publish() call; it still requires a root class in an executable. Without the marker nothing changes: tsc-ts best-v7 built with and without this change is byte-identical.

Tests: corpus 4634-contract-program-lifetime-publish (Node vs native): program-lifetime hierarchies with parent cycles, maps and sets of them, maps keyed by them and mortal scopes around them, published on the main thread and a worker and read on the other; writes after publication throw on both threads; unpublished instances stay writable; a refused publish leaves visited instances writable; a later publish reaches published and fresh instances; an unpublished instance in workerData is cloned. With the old SIZE_MAX count the program dies at its first constructor store. classes.test.ts covers the count on both pointer widths, the walker and the frozen guard. The contract-program-lifetime-publish diagnostics fixture is removed (the program now compiles). Docs: contracts and limitations pages, @scriptc/types.
2026-10-11 17:07:22 -07:00
Malte Ubl 40a2c2adf2 ProgramLifetime in sanitized builds: skip the RC audit's leak report and scan instances as LeakSanitizer roots
Program-lifetime instances are never freed, and neither is anything they hold, so the RC audit of --sanitize builds reported every one of them, and every string, array and map they reference, as live at exit (4633-contract-program-lifetime failed the sanitized differential lane: 306 strings, 15 arrays, 338 objects). Like a program that abandons fibers, a program that keeps program-lifetime objects now skips the leak report with "scriptc RC audit skipped: N program-lifetime object(s) never freed", which the harnesses already filter.

Sanitized constructors call scr_obj_lifetime_note(obj), which counts the instance and registers it with LeakSanitizer as an intentional root, as publication does for published objects: once the audit no longer exits early, LeakSanitizer would otherwise report the instances the program drops. Plain builds emit nothing.
2026-10-11 17:07:03 -07:00
Malte Ubl 3c26a85d9c Merge branch 'feat/contract-types' into feat/acyclic-contract 2026-10-11 16:32:31 -07:00
Malte Ubl 3d7e8e731c Merge branch 'feat/contract-types' into feat/nothrow-try-catch 2026-10-11 16:32:27 -07:00
Malte Ubl f00e312d76 Merge branch 'feat/contract-types' into perf/int32-or-zero-peephole 2026-10-11 16:32:24 -07:00