Ash ash
HashLink Bytecode Runtime

A faster Runner for
HashLink bytecode.

Ash runs HashLink (.hl) bytecode compiled from Haxe. Execution is tiered: an interpreter runs everything, hot functions are promoted to Cranelift, and the hottest are recompiled by LLVM.

Get Started → View on GitHub
Cranelift + LLVM 21·aarch64 & x86_64·ISC licensed
ash — shell
$ ash --mode hybrid mandelbrot.hl
tier1 cranelift  12 functions promoted
tier2 llvm       3 functions promoted
checksum: 112798515
$
Features

The ash approach to running HashLink

Two compiler backends over a typed SSA IR, an Immix collector, cooperative fibers for sys.thread, and the HashLink standard library rewritten in Rust.

01

Tiered execution

Interpreter → Cranelift → LLVM. Functions climb the ladder as they get hot, and compilation happens off the main thread.

02

AIR

A typed phi-SSA IR over HashLink bytecode, with first-class trap regions, an effect lattice, and an alias model.

03

Optimization passes

Null-check elimination, GVN/CSE, LICM, FMA fusion, DCE, tail-recursion elimination, inlining, and scalar replacement of aggregates.

04

Immix collector

Conservative stack-scanning Immix with a demand-committed heap, adaptive triggers, and external-pressure accounting.

05

Fibers

sys.thread threads run as cooperative stackful fibers, so code blocking on locks, deques or Sys.sleep still makes progress on one OS thread.

06

Shared symbol table

One canonical lib@symbol → address map, built at startup and consumed by the interpreter and both compiled tiers.

07

HDLL support

External HashLink dynamic libraries via the standard DEFINE_PRIM resolver protocol.

08

Embedded standard library

The HashLink standard library implemented in Rust, built as a cdylib and embedded in the binary.

Execution tiers

Three rungs, one ladder

Promotion is brokered by beadie, which counts invocations, compiles on background threads, and publishes code pointers atomically. ash --jit-tier pins a single rung for testing.

0
Interpreter
Runs everything, on NaN-boxed values.
1
Cranelift
Fast compilation — about 0.04 ms per function — for warm functions at opt_level=speed.
2
LLVM 21 (MCJIT)
Full codegen for the hottest functions. Whatever the Cranelift tier declines to lower falls through here rather than staying interpreted.
Quick Setup

Install, compile, run

One script, no toolchain. Prebuilt binaries for macOS and Linux on aarch64 and x86_64.

01

Install Ash

Drops the ash binary into ~/.ash/bin and adds them to your PATH. Ash requires a 64-bit target.

$ curl -fsSL https://raw.githubusercontent.com/rayzor-blade/ash/main/install.sh | sh
02

Compile Haxe to bytecode

Ash runs HashLink bytecode, so build a .hl file with Haxe — or use one you already have.

$ haxe -main Main -hl main.hl
03

Run it

One binary, one flag set: --mode interp|hybrid|jit, --jit-tier auto|cranelift|llvm|off, promotion thresholds, and --jit-log.

$ ash --mode hybrid main.hl
$ ash --mode hybrid --jit-tier cranelift --jit-log main.hl
$ ash --mode jit main.hl # compile everything up front
Building from source instead? That's the contributor path — Rust nightly and LLVM 21, with the std/ rebuild steps spelled out in the README.
Benchmarks

Faster than HashLink's JIT

Across fib(40), Mandelbrot, n-body, inlined calls, method calls, and free-function calls, Ash's tiered JIT is measured against HashLink's released JIT, its in-development hl2-ir JIT, and its ahead-of-time HL/C output — same bytecode, every engine in a row timed on the same runner, every run checksum-verified. Numbers land fresh from CI with each push to main.

HashLink JIT Ash HashLink hl2-ir HashLink/C Haxe JVM
lower is better · median ms · 1.00× = HashLink JIT total
Loading benchmark results…
Every bar is the pure wall time of one run. HashLink/C's ahead-of-time build is excluded; every row is verified against the benchmark's accepted checksums before it is published. Each benchmark is measured in its own CI job, so the engines within a row share a machine but different rows may not — compare engines within a row, not milliseconds across sweeps. Hover a number for the CPU that produced it.

Conformance

Measured against Haxe's own test suite

Being fast is worth nothing if the answers are wrong. Ash runs the official Haxe test suite unmodified, from CI on every push.

assertions passed across all suites
suites fully passing
stdlib natives unresolved
Loading conformance results…
The official Haxe test suite, unmodified, run on every push.

Platforms

Supported platforms

Ash compiles natively for aarch64 and x86_64. One binary per platform, with the full interpreter → Cranelift → LLVM ladder on each.

macOS · Apple silicon
aarch64
macOS · Intel
x86_64
Linux · x86_64
validated continuously in CI
Benchmark numbers are published from Linux x86_64 CI.