Skip to content

Host Profiles

The toolchain supports two host profiles and an alternative compilation mode:

Flag Output When to use
--host wasi single .wasm WASI runtimes (wasmtime, etc.) — default
--host browser .wasm + .js + .d.ts import from a web application
--aot wasm without embedded VM experimental ZoloIR→wasm backend

--host browser mode generates JavaScript glue and TypeScript types alongside the .wasm, letting you import the module directly in TS/JS. --aot mode swaps the VM-embedded payload for the experimental native backend: supports integer arithmetic, recursion, if/while, string literals, and print.

The following example demonstrates all three modes with a simple recursive fib function, ideal for verifying that control-flow logic works correctly in each profile:

fib(10) with the three modes: WASI, browser, and AOT.

02-host-profiles.zolo
// Feature: wasm host profiles & AOT — `--host` / `--aot`

// Syntax: `zolo build file.zolo --emit wasm --host wasi|browser [--aot]`

// When to use: target a WASI runtime vs the browser, or opt into the

//   experimental ahead-of-time ZoloIR->wasm backend.


// Run:

//   zolo build 32-webassembly/02-host-profiles.zolo --emit wasm --host wasi

//     # -> 02-host-profiles-0.0.0.wasm   (WASI host profile, the default)

//

//   zolo build 32-webassembly/02-host-profiles.zolo --emit wasm --host browser

//     # -> .wasm + .js + .d.ts  (browser glue for import in a web app)

//

//   zolo build 32-webassembly/02-host-profiles.zolo --emit wasm --aot --host browser

//     # pure-wasm AOT (no embedded VM). Runs the supported subset: int math,

//     # recursion, if/while, string literals, and print. Serve over http and

//     # import the generated .js, or run with node:

//     #   node crates/zolo-wasm-aot/tests/run_wasm.mjs <file>.wasm   -> fib(10) =\t55

//

// host=wasi   -> a single .wasm wired for a WASI runtime (wasmtime, etc.)

// host=browser-> .wasm plus generated `.js` loader and `.d.ts` types so

//                you can `import` it from TypeScript/JS.

// --aot       -> swaps the VM-embedded payload for the experimental

//                ZoloIR-native wasm backend.


fn fib(n: int) -> int {
  if n < 2 { return n }
  return fib(n - 1) + fib(n - 2)
}

print("fib(10) =", fib(10))
// expected (run natively): fib(10) =	55

Requires the Zolo CLI/host — open in the playground or run locally.

To explore the AOT performance ceiling, the fibonacci.zolo file pushes the computation to Fibonacci of very large numbers via matrix exponentiation with BigInt — and also uses std::os::clock() to measure time:

O(log n) Fibonacci with BigInt and timing; illustrates std::os as the only wasm-safe API.

fibonacci.zolo
// Feature: wasm host profiles & AOT — `--host` / `--aot`
// Syntax: `zolo build file.zolo --emit wasm --host wasi|browser [--aot]`
// When to use: target a WASI runtime vs the browser, or opt into the
//   experimental ahead-of-time ZoloIR->wasm backend.

// Run:
//   zolo build 32-webassembly/02-host-profiles.zolo --emit wasm --host wasi
//     # -> 02-host-profiles-0.0.0.wasm   (WASI host profile, the default)
//
//   zolo build 32-webassembly/02-host-profiles.zolo --emit wasm --host browser
//     # -> .wasm + .js + .d.ts  (browser glue for import in a web app)
//
//   zolo build 32-webassembly/02-host-profiles.zolo --emit wasm --aot --host browser
//     # pure-wasm AOT (no embedded VM). Runs the supported subset: int math,
//     # recursion, if/while, string literals, and print. Serve over http and
//     # import the generated .js, or run with node:
//     #   node crates/zolo-wasm-aot/tests/run_wasm.mjs <file>.wasm   -> fib(10) =\t55
//
// host=wasi   -> a single .wasm wired for a WASI runtime (wasmtime, etc.)
// host=browser-> .wasm plus generated `.js` loader and `.d.ts` types so
//                you can `import` it from TypeScript/JS.
// --aot       -> swaps the VM-embedded payload for the experimental
//                ZoloIR-native wasm backend.

// Fibonacci via matrix exponentiation (O(log n)) with BigInt
//
// Matrix [[a,b],[c,d]] stored as flat array [a, b, c, d]

// Multiply matrix a by matrix b, store result in a
fn mat_mul(a, b) {
  let x = a[0] * b[0] + a[1] * b[2]
  let y = a[0] * b[1] + a[1] * b[3]
  let z = a[2] * b[0] + a[3] * b[2]
  let w = a[2] * b[1] + a[3] * b[3]

  a[0] = x
  a[1] = y
  a[2] = z
  a[3] = w
}

// Square matrix a in-place
fn mat_square(a) {
  let x = a[0] * a[0] + a[1] * a[2]
  let y = a[0] * a[1] + a[1] * a[3]
  let z = a[2] * a[0] + a[3] * a[2]
  let w = a[2] * a[1] + a[3] * a[3]

  a[0] = x
  a[1] = y
  a[2] = z
  a[3] = w
}

// Raise matrix f to the power n using fast exponentiation
fn mat_power(f, n) {
  if n <= 1 {
    return
  }

  let one = 1n
  let zero = 0n
  let m = [one, one, one, zero]

  mat_power(f, n ~/ 2)
  mat_square(f)
  if n % 2 != 0 {
    mat_mul(f, m)
  }
}

// Compute the n-th Fibonacci number using BigInt
fn fibonacci(n) {
  if n == 0 {
    return 0n
  }

  let one = 1n
  let zero = 0n
  let f = [one, one, one, zero]
  mat_power(f, n - 1)
  return f[0]
}

// --- Main ---

struct Console() {
  fn new() {
    Self { start: #{} }
  }

  fn time(self, name) {
    self.start[name] = std::os::clock()
  }

  fn time_end(self, name) {
    print("time = ", std::os::clock() - self.start[name])
  }
}

fn main() {
  let console = Console::new()
  console.time("fibo")

  300_000_000
    |> fibonacci()
    |> tostring()
    |> .len()
    |> |v| "len: {v}"
    |> print()

  console.time_end("fibo")
}

Requires the Zolo CLI/host — open in the playground or run locally.

Challenge

Compile 02-host-profiles.zolo with --host browser and inspect the three generated files (.wasm, .js, .d.ts). What TypeScript signature is generated for the fib function?

enespt-br