An excerpt from the repository, fetched Nov 13, 2026.
Read the project’s introduction
Binaryen
Binaryen is a compiler and toolchain infrastructure library for WebAssembly,
written in C++. It aims to make compiling to WebAssembly easy, fast, and
effective:
Easy: Binaryen has a simple C API in a single header, and can also be
used from JavaScript. It accepts input in WebAssembly-like
form but also accepts a general control flow graph for
compilers that prefer that.
Fast: Binaryen's internal IR uses compact data structures and is designed
for completely parallel codegen and optimization, using all available CPU
cores. Binaryen's IR also compiles down to WebAssembly extremely easily and
quickly because it is essentially a subset of WebAssembly.
Effective: Binaryen's optimizer has many passes (see an overview later
down) that can improve code size and speed. These optimizations aim to make
Binaryen powerful enough to be used as a compiler backend by
itself. One specific area of focus is on WebAssembly-specific optimizations
(that general-purpose compilers might not do), which you can think of as
wasm minification, similar to minification for JavaScript, CSS, etc., all
of which are language-specific.
Toolchains using Binaryen as a component (typically running wasm-opt) include:
Emscripten (C/C++)
wasm-pack (Rust)
J2CL (Java; J2Wasm)
Kotlin (Kotlin/Wasm)
Dart (Flutter)
wasm_of_ocaml (OCaml)
For more on how some of those work, see the toolchain architecture parts of
the V8 WasmGC porting blogpost.
Compilers using Binaryen as a library include:
AssemblyScript which compiles a variant of TypeScript to WebAssembly
wasm2js which compiles WebAssembly to JS
Asterius which compiles Haskell to WebAssembly
Grain which compiles Grain to WebAssembly
Binaryen also provides a set of toolchain utilities that can
Parse and emit WebAssembly. In particular this lets you load
WebAssembly, optimize it using Binaryen, and re-emit it, thus implementing a
wasm-to-wasm optimizer in a single command.
Interpret WebAssembly as well as run the WebAssembly spec tests.
Integrate with Emscripten in order to provide a
complete compiler toolchain from C and C++ to WebAssembly.
Polyfill WebAssembly by running it in the interpreter compiled to
JavaScript, if the browser does not yet have native support (useful for
testing).
Consult the contributing instructions if you're interested in
participating.
Binaryen IR
Binaryen's internal IR is designed to be
Flexible and fast for optimization.
As close as possible to WebAssembly so it is simple and fast to convert
it to and from WebAssembly.
There are a few differences between Binaryen IR and the WebAssembly language:
Tree structure
Binaryen IR is a tree, i.e., it has hierarchical structure,
for convenience of optimization. This differs from the WebAssembly binary
format which is a stack machine.
Binaryen uses Stack IR to optimize "stacky" code (that can't be
represented in structured form).
When stacky code must be represented in Binaryen IR, such as with
multivalue instructions and blocks, it is represented with tuple types that
do not exist in the WebAssembly language. In addition to multivalue
instructions, locals and globals can also have tuple types in Binaryen IR
but not in WebAssembly. Experiments show that better support for
multivalue could enable useful but small code size savings of 1-3%, so it
has not been worth changing the core IR structure to support it better.
Block input values (currently only supported in catch blocks in the
exception handling feature) are represented as pop subexpressions.
pops must appear as the first instruction in a catch block (ignoring
unnamed blocks around them, as those are not emitted in the binary
format).
Types and unreachable code
WebAssembly limits block/if/loop types to none and the concrete value types
(i32, i64, f32, f64). Binaryen IR has an unreachable type, and it allows
block/if/loop to take it, allowing local transforms that don't need to
know the global context. As a result, Binaryen's default
text output is not necessarily valid wasm text. (To get valid wasm text,
you can do --generate-stack-ir --print-stack-ir, which prints Stack IR,
this is guaranteed to be valid for wasm parsers.)
Binaryen supports a stringref type. This is similar to the currently-
inactive stringref proposal, with the difference that the string type is a
subtype of externref rather than anyref. Doing so allows toolchains to
emit code in a form that uses js string builtins which Binaryen can then
"lift" into stringref in its internal IR, optimize (for example, a
concatenation of "a" and "b" can be optimized at compile time to "ab"), and
then "lower" that into js string builtins once more.
Blocks
Binaryen IR has only one control flow structure that contains a
variable-length list of children: the block. WebAssembly on the other hand
allows all control flow structures, such as loops, if arms, and function
bodies, to have multiple children. In Binaryen IR, these other control flow
structures have a single child. This child may of course be a block. The
motivation for this property is that many passes need special code for
iterating on lists of instructions, so having a single IR node with a list
simplifies them.
As in the Wasm text format, blocks and loops may have names. Branch targets
in the IR are resolved by name (as opposed to nesting depth). This has 2
consequences:
Blocks without names may not be branch targets.
Names are required to be unique. (Reading .wat files with duplicate names
is supported; the names are modified when the IR is constructed).
As an optimization, a block with no name, which can never be a branch
target, will not be emitted when generating wasm. Instead its list of
children will be directly used in the containing control flow structure.
Such a block is sometimes called an "implicit block".
Reference Types
The wasm text and binary formats require that a function whose address is
taken by ref.func must be either in the table, or declared via an
(elem declare fun
Read the full README on GitHub