An ahead-of-time compiler that turns JavaScript into a native executable.
bronze build app.js -o app
./app
bronze compiles JavaScript to machine code through LLVM. It follows imports
from your entry file, compiles the whole program, and links a standalone binary.
The test suite compiles three.js r160 and pixi.js v8 from unmodified source.
A standalone executable. bronze build app.js -o app produces a single
binary with bronze's runtime linked in.
An app embedded in a larger program. --emit-obj produces an object
file for your own build to link, and --host-globals lists the globals your
host provides (document, requestAnimationFrame, and so on).
--emit-shared produces a module your host opens at run time instead, linked
against a shared bronze runtime so one process can load several. The bro
engine uses this to run compiled three.js apps against its DOM and WebGL.
The app's scene graph and render loop run as machine code while the engine
supplies the browser surface. src/embed is the C++ API a host uses to
drive the compiled program, register globals, and hold GC-safe handles.
bronze infers types by analysing the whole program: each binding's type at
each point, the shape of each object site, each function's signature across
its call sites. Where inference proves a type, the compiler emits direct
native code; everywhere else it uses boxed dynamic values with inline
caches, which keeps every program correct while the proven parts run fast.
bronze types app.js prints what inference concluded about your code.
TypeScript annotations are accepted and treated as hints. When inference confirms an annotation, the code takes the native path; when it can't, the annotation is dropped with a warning and the code runs with its actual JavaScript behaviour.
The performance target is concrete: compiled output should beat nodejs on the same program, and benchmarks that fall short are treated as bugs.
bronze implements enough of ECMA-262 to compile large real-world libraries
(three.js and pixi.js are the pinned milestones). Programs are compiled
ahead of time, so eval and new Function are out of scope. When a program
uses a language feature bronze hasn't implemented yet, compilation stops
with an error naming the feature.
bronze build <entry.js> -o <exe> compile and link an executable
bronze build <entry.js> -o <obj> \
--emit-obj \
--host-globals <manifest> compile to an object for a host build
bronze build <entry.js> -o <lib> \
--emit-shared compile a module a host loads at run time
bronze build <entry.js> -o <exe> \
--keep-objs <dir> keep the partition objects behind
bronze link <dir> -o <exe> \
--link-seed <n> relink those objects in a seeded
order, without recompiling
bronze types <entry.js> show what inference proved
bronze il <entry.js> dump the typed IL
bronze lex / bronze parse earlier pipeline stages
bronze version print the version
<entry.js> is the entry of a module graph: import/export with relative
specifiers pull in the rest. --no-infer compiles everything on the dynamic
path; it exists as a debugging tool for isolating inference bugs
(docs/internals.md has the details).
Nightly builds are
published for Windows x64, Linux x64, and macOS arm64 — each zip is the
compiler plus the runtime libraries it links into compiled programs, tested
against the full suite before publishing. Unzip anywhere and run
bronze build app.js -o app. You need a system linker on your machine
(Windows: MSVC's link.exe; Linux/macOS: clang++ or g++); bronze does
not ship one.
Prereqs: CMake ≥ 3.24, Ninja, a C++20 compiler, and vcpkg. On Windows,
dev.cmd wraps the MSVC environment: .\dev.cmd cmake ....
cmake --preset dev -DBRONZE_WITH_LLVM=ON
cmake --build --preset dev
ctest --preset dev
-DBRONZE_WITH_LLVM=ON enables the backend that emits objects and
executables. vcpkg builds LLVM from source the first time (hours,
binary-cached afterwards). Configuring without the flag builds the compiler
front half (lexer, parser, inference, IL) with a fast test loop for
frontend work. docs/internals.md has the full
build-and-iteration workflow.
Correctness rests on a differential suite
(tests/oracle/README.md): JavaScript programs
whose exact stdout is pinned in committed files derived from ECMA-262. Every
case compiles and runs twice (with inference and with --no-infer) and
both runs must produce identical bytes, so the analysis and the dynamic
fallback check each other. Compiled objects carry an ABI fingerprint the
runtime verifies at startup, so an object built against an older runtime
fails at launch with both versions named.
- docs/internals.md the pipeline, repository layout,
inference and
--no-inferin depth, embedding details, and the iteration workflow. - docs/pin-census.md
--census: how a--pinsmanifest gets written by a run of the program instead of by hand. - docs/slot-representation.md per-slot representation: what lets a shape say a slot holds a raw double, and what keeps that true.
- tests/oracle/README.md how the differential suite works and how to add a case.