Files
scriptc/packages/cli
Chris Tate 1d6bd1ea04 Shrink the array header to 48 bytes
ScrArr stores len and cap as 32-bit fields and no longer stores the
state pointer. The dense states share the values' allocation and run
backward from its end: the state of slot i is at
data + cap * (slot width + 1) - 1 - i. Removing slots from the front
(shift, splice(0, n)) advances data and lowers cap, which leaves every
remaining state at its address; the head room size, needed only to free
or reallocate the block, is kept in the vacated slot before data. On
64-bit targets the header goes from 64 to 48 bytes, and from 36 to 32
bytes on wasm32. Array lengths were already limited to 2^32 - 1.

The emitted code loads len and cap as i32 and zero-extends them, and
computes state addresses from data and cap. Runtime loops compute the
end of the states once per call. Local array reads load data once for
both the state and value paths. A local or strict element read whose
index is a loop's induction variable reads slots above the hole-free
prefix through the runtime: an inline state check there makes LLVM keep
-1 - i as a second induction variable, which costs a register in the
loop.

Bulk operations do not read back states they just wrote: an append to
an array whose hole-free prefix reaches its length moves the prefix bound
to the new length, a copy from below the source's prefix writes value
states without reading the source's, and releasing a string array skips
the state checks below the prefix. Copies of up to eight slots and of
short state runs use overlapping word moves instead of a call. Emitted
element access computes the state address only on the state-checked
path. Without these, programs that build many small arrays with split or
slice ran 2-4% slower than with the separate state pointer.

Integer loops over an array's length compare the counter with the i32
length field in 32 bits; the counter never exceeds 2^32 - 1 there. The
array-length stability proof accepts Map and Set reads (get, has, size)
and checked union extractions (`x!`), which run no user code, so loops
that look up maps keep the dense fast copy, which tests the hole-free
prefix once before the loop.

Small constructions with the small allocator request 6 slots, so their
blocks stay 112 bytes, now with 7 inline slots (6 after a collector
header). With 96-byte blocks of 5 slots, programs that free and reuse
many small arrays ran 15-20% slower.

RUNTIME_ABI_VERSION goes from 22 to 23.
2026-10-20 00:21:45 -05:00
..
2026-10-12 12:25:30 -05:00
2026-10-20 00:21:45 -05:00
2026-07-22 18:08:04 -05:00
2026-10-17 13:47:41 -05:00
2026-07-22 18:08:04 -05:00

scriptc

Compile TypeScript and JavaScript to native executables or WASI WebAssembly modules that run without Node.js installed.

$ cat fib.ts
function fib(n: number): number {
  return n < 2 ? n : fib(n - 1) + fib(n - 2);
}
console.log(fib(30));

$ scriptc run fib.ts
832040

$ scriptc build fib.ts -o fib >/dev/null && ./fib
832040

scriptc compiles the same TypeScript you run on Node.js, type-checked by the TypeScript compiler. npm packages your program imports compile along with it. Code scriptc can't compile fails the build with an error code and, where available, a rewrite hint.

scriptc is experimental. See the limitations and the Node.js compatibility reference.

Install

$ npm install -g scriptc

npm installs the native compiler for your platform (macOS, Linux, or Windows). Node.js 24 or later is needed to install it and to run WASI modules with scriptc run; compiling and running executables doesn't need Node.js.

Building executables needs a linker and the platform SDK or sysroot, such as the Xcode Command Line Tools on macOS. Set SCRIPTC_LINKER to choose the linker driver. --emit=ir|llvm|asm|obj needs no external tools. See the quickstart for details.

Commands

  • scriptc build <file.ts>: compile to a native executable or another artifact selected with --emit.
  • scriptc run <file.ts>: compile and run.
  • scriptc coverage <file.ts>: report what compiles, and explain what doesn't.
  • scriptc build --lib --profile <profile.json>: compile a static library, or a Wasm reactor on wasm32-wasi.

See the CLI reference for every option.

Cross-compilation and WebAssembly

Set SCRIPTC_TARGET to build for another platform, for example SCRIPTC_TARGET=aarch64-linux-gnu.2.36 or SCRIPTC_TARGET=wasm32-wasi. Install the matching @scriptc/runtime-<target> package in your project, at the same version as scriptc --version, or set SCRIPTC_RUNTIME_PACK to a runtime pack directory. See platform support and WebAssembly modules.

Native code

Call C functions by declaring their signatures in TypeScript and binding them to C symbols in a manifest passed with --ffi <manifest.json>. See the Native FFI guide.

Build cache

Builds reuse a bounded persistent cache. Set SCRIPTC_NO_CACHE=1 to bypass it or SCRIPTC_CACHE_DIR to choose its location.

Docs: scriptc.dev