Open-Source Wikis

/

Kotlin

/

Compiler

/

Wasm backend

JetBrains/kotlin

Wasm backend

Active contributors: Ilya Goncharov, Artem Kobzar, Sergej Jaskiewicz

The WebAssembly backend compiles Kotlin to .wasm modules. Two output flavors are supported: Wasm/JS (Wasm module designed to run inside a JS runtime — the default in browsers) and Wasm/WASI (Wasm with the WASI system interface for non-browser hosts). The backend lives in compiler/ir/backend.wasm/ with the Wasm IR proper in wasm/wasm.ir.

Purpose

Take lowered Kotlin IR and produce a Wasm module that runs on the host runtime. Handle Wasm-specific concerns: linear memory, function tables, GC types (when targeting Wasm GC), and the JS bridge for browser-targeted output.

Directory layout

compiler/ir/backend.wasm/      Wasm-specific lowerings + driver
wasm/
├── wasm.config/               Wasm-specific compiler configuration
├── wasm.frontend/             Wasm-specific frontend extensions
├── wasm.ir/                   Wasm IR types and emitters
├── wasm.tests/                Wasm test runners + test data
└── wasm.debug.browsers/       Helpers for running tests in browser

Key abstractions

Type Where Role
WasmIrModuleSerializer compiler/ir/backend.wasm/... Serializes Wasm IR for klib.
WasmModule, WasmFunction, WasmInstr* wasm/wasm.ir/... The Wasm IR types. Cover both function-section and type-section concepts.
WasmCompiledModuleFragment compiler/ir/backend.wasm/... Per-file output of the backend; merged at link time.
WasmBackendContext compiler/ir/backend.wasm/... Shared backend state.

How Wasm compilation works

graph LR
    IR["Lowered IR"] --> WasmLower["Wasm lowerings"]
    WasmLower --> WasmIR["wasm.ir"]
    WasmIR --> Link["Wasm linker"]
    Link --> Module[".wasm module"]
    Link --> JsGlue[".uninstantiated.mjs<br/>(JS adapter)"]

Like JS, Wasm is multi-module: each Kotlin compilation unit produces an IR klib plus per-file Wasm AST fragments. A final link step combines the fragments into one .wasm module.

Wasm/GC

Wasm GC types are first-class in this backend. Instead of representing Kotlin objects in linear memory, the backend uses Wasm's typed reference ((ref ...)) and struct/array ((struct ...), (array ...)) instructions. This significantly reduces output size and runtime cost compared to the older "boxed in linear memory" approach.

Wasm/WASI vs Wasm/JS

  • Wasm/JS — the default. Produces a Wasm module plus a JS adapter (.uninstantiated.mjs) that handles imports, JS interop, and exception bridging.
  • Wasm/WASI — produces a Wasm module that uses the WASI system interface for I/O. Used for non-browser hosts (e.g., Wasmtime). Has restricted JS interop.

The selection happens via compiler arguments and via the kotlin("multiplatform") Gradle DSL (wasmJs { ... } vs wasmWasi { ... }).

Browser tests

wasm/wasm.debug.browsers/ configures running Wasm test suites in real browsers (Chrome, Firefox) for end-to-end regression. The CI pipeline exercises this on Wasm-enabled browser releases.

Integration points

  • Input: lowered IR.
  • Output: .wasm modules, Wasm klibs, optional JS adapter.
  • Used by: compiler/cli/cli-js/ (Wasm uses the same CLI shape as JS for historical reasons), KGP's wasmJs/wasmWasi targets.
  • Tested by: wasm/wasm.tests/ — runs box tests through Node.js and the browsers.

Where to start

Wasm-specific lowerings live in compiler/ir/backend.wasm/.../lower/. The Wasm IR types in wasm/wasm.ir/ are the most useful entry point if you're investigating output. A failing test usually leaves a .wat (WebAssembly Text Format) dump next to the test data — that's the easiest way to inspect what the backend produced.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Wasm backend – Kotlin wiki | Factory