XCX 4.2 — The HIR & Fast Path Update


XCX 4.2 introduces a new intermediate compilation layer, HIR, along with a substantial JIT optimization pass. Function ASTs are now lowered to HIR before being compiled to bytecode, unlocking HIR-level inlining. The JIT gains fast paths for arrays and BoolArray, JSON gets a parse cache, string concatenation gets new StrAppend* opcodes, and table.join moves to Hash-Join O(N+M).


~12x faster string append

~21x faster table.join (500x500)

97.8ms sieve under JIT


Available on Linux (Ubuntu, Arch/Manjaro, and other major distros), Windows, and macOS.


What's new

New Compilation Layer: HIR

Function ASTs are now lowered to HIR before being compiled to bytecode. HIR-level function inlining was introduced, excluding fibers, recursion, return inside a loop, and overly costly functions. Full compilation of TableLiteral, DatabaseLiteral, DateLiteral, and Tuple literals was added, eliminating the default Int initialization that used to cause method dispatch errors.


JIT: New Optimizations

Added a fast path bounds check for arrays (int[], bool[]) — the index < len comparison now happens directly in JIT code, with a runtime fallback for out-of-range access. A dedicated BoolArray fast path now bypasses FFI and RwLock. Fixed a type inference bug that failed to recognize array:b constants as BoolArray. Added constant tracking in registers (register_const), division/modulo by a power of 2 without guards, and typed JumpIfFalse reducing the comparison to a simple icmp.


JSON: Caching and Fast Access Paths

New thread-local cache for json.parse() (up to 128 entries). Fast path for simple keys in getters, has(), and keys()/len(). Fixed a thread-unsafe dirty: AtomicBool flag, replacing it with a version/cached_version counter pair, eliminating the risk of reading a corrupted JSON string under concurrent JIT/VM access.


String Concatenation: New StrAppend* Opcodes

StrAppendVar/StrAppendLocal/StrAppendMember/StrAppendElement mutate the string buffer in place when Arc ownership is unique, instead of three allocations per iteration. Results (100k iterations): global variable 1300ms → 2.2-3.5ms; array element 86ms → ~3-4ms; general append under JIT 10790ms → 5.5ms.


Table Queries

table.join with Hash-Join O(N+M) (500x500 rows: 215ms → 10ms). New row_cache on RowObj for table.where, auto-invalidated on modification. count()/len()/size() with an active sql_where now computed directly in the database.


Networking: HTTP

TCP/TLS connection pooling via a global agent (HTTP_AGENT) — 100 sequential HTTPS requests: 195ms/req → 63ms/req.


CLI

Reorganized --help, short flags -h/-v now working anywhere, combining options with |.


Bug Fixes

Fixed hangs on @step loops with bare backward jumps, a panic on JsonPush against a JSON object, missing argument propagation in table.where(...), an incorrect bitcast in Float + Int arithmetic, a missing SSA block switch in GetIndex for BoolArray, and a register allocation bug in closures/captures for table.where(...).


Performance results

New benchmark suite (more stable lcg/sieve measurements, more accurate json sampling):


Variant fib(30) lcg(100m) sieve json

XCX 4.1, JIT13.119ms107.706ms201.003ms0.272ms
XCX 4.2, JIT12.303ms106.480ms97.814ms0.238ms


Test system: AMD Ryzen 7 5800X, 32 GB RAM, Windows 11