Skip to content

gertvv/gl_wasm

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

29 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

gl_wasm

Package Version Hex Docs

Create binary WebAssembly modules in Gleam.

Goals

  • Support for the WebAssembly 2.0 (draft) specification, giving priority to features that are useful for functional languages, such as GC and return call.
  • Make it as difficult as is reasonably possible to generate invalid WebAssembly.
  • Eliminate unnecessary ceremony and performance bottlenecks.

Possible goals

  • Parsing binary WebAssembly modules.
  • Debugging support, e.g. DWARF.
  • Component Model and WASI support.

Non-goals

  • WASM optimization.
  • Support for WAT (WebAssembly Text format).

Progress

Features

  • Building modules
  • Registering types
  • Building functions
  • Importing functions
  • Exporting functions
  • Type validation
  • Type recursion and subtyping
  • Global initialization
  • Validation for global initialization
  • Advanced validation for break/return
  • Features related to unimplemented sections
  • Use bytes_tree instead of byte_array.concat & friends
  • JavaScript target support (primarily number type encoding)
  • Output stream abstraction

Sections

  • Type
  • Function/code
  • Table
  • Memory
  • Global
  • Element
  • Data/data count
  • Start
  • Export
  • Import
  • Custom
  • Name

Instructions

  • General control flow
  • Function calls
  • General reference instructions
  • Struct
  • Array
  • i31
  • Extern
  • Table
  • Memory
  • i32 and i64 encoding
  • f32 and f64 encoding
  • Common i32, i64, f32, f64 instructions
  • Numeric conversions, truncations, etc.
  • v128

Usage

gleam add gl_wasm

This example generates a module that imports an "add" function and uses that to implement a "double" function which it exports.

import gl_wasm/wasm
import gleam/io
import gleam/list
import gleam/option.{Some}
import gleam/result
import simplifile

pub fn main() {
  case generate_wasm() {
    Error(message) -> io.println_error(message)
    Ok(_) -> Nil
  }
}

fn file_output_stream(fname) {
  let output_stream =
    wasm.OutputStream(
      stream: fname,
      write_bytes: fn(fname, bytes) {
        simplifile.append_bits(fname, bytes)
        |> result.replace(fname)
      },
      close: fn(fname) { Ok(fname) },
    )
  let _ = simplifile.write_bits(fname, <<>>)
  output_stream
}

fn generate_wasm() {
  // Create a ModuleBuilder that writes to the file "out.wasm"
  let mb = wasm.create_module_builder(Some("Doubler"))
  // Register the "add" function type and import "math.add"
  use #(mb, type_index_add) <- result.try(wasm.add_type(
    mb,
    wasm.Func(Some("add_type"), [wasm.I64, wasm.I64], [wasm.I64]),
  ))
  use mb <- result.try(wasm.import_function(
    mb,
    type_index_add,
    Some("add"),
    wasm.ImportSource("math", "add"),
  ))
  // Register the "double" function type and generate its code
  use #(mb, type_index_double) <- result.try(wasm.add_type(
    mb,
    wasm.Func(Some("double_type"), [wasm.I64], [wasm.I64]),
  ))
  use #(mb, fb) <- result.try(wasm.create_function_builder(
    mb,
    wasm.FunctionSignature(type_index_double, Some("double"), Some(["n"])),
  ))
  use fb <- result.try(list.try_fold(
    over: [wasm.LocalGet(0), wasm.LocalGet(0), wasm.Call(0), wasm.End],
    from: fb,
    with: wasm.add_instruction,
  ))
  use mb <- result.try(wasm.finalize_function(mb, fb))
  // Export the "double" function
  use mb <- result.try(wasm.add_export(mb, wasm.ExportFunction("double", 1)))
  // Write the WebAssembly to file
  wasm.emit_module(mb, file_output_stream("out.wasm"))
  |> result.replace_error("Error writing to file")
}

The disassembled WebAssembly Text (WAT) representation looks like this:

(module $Doubler
 (type $add_type (func (param f64 f64) (result f64)))
 (type $double_type (func (param f64) (result f64)))
 (import "math" "add" (func $add (type $add_type) (param f64 f64) (result f64)))
 (export "double" (func $double))
 (func $double (type $double_type) (param $n f64) (result f64)
  (call $add
   (local.get $n)
   (local.get $n)
  )
 )
)

Further documentation can be found at https://hexdocs.pm/gl_wasm.

Development

gleam run   # Run the project
gleam test  # Run the tests

About

Create binary WebAssembly modules in Gleam

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages