Racket binaryen bindings
1 Getting Started
1.1 Reading Web  Assembly
1.2 Writing Web  Assembly
1.3 Optimization
1.4 A Longer Example
2 API
2.1 Types
type?
type-none
type-int32
type-int64
type-float32
type-float64
type-vec128
type-funcref
type-externref
type-anyref
type-eqref
type-i31ref
type-dataref
type-unreachable
type-auto
2.2 Optimizations
optimize-level?
shrink-level?
optimize-level
shrink-level
set-optimize-level!
set-shrink-level!
with-optimize-level
with-shrink-level
2.3 Modules
module?
current-module
module-create
module-valid?
module-print
module-optimize!
module-read
module-parse
module-write
2.4 Features
feature?
feature-mvp
feature-atomics
feature-bulk-memory
feature-mutable-globals
feature-nontrapping-fptoint
feature-sign-extension
feature-simd128
feature-exception-handling
feature-tail-call
feature-reference-types
feature-multivalue
feature-gc
feature-memory64
feature-typed-function-references
feature-all
module-features
set-module-features!
2.5 Functions
module-add-function
module-function-count
module-function
function-name
function-parameter-types
function-result-types
function-variable-count
function-variable-type
function-get-locals-count
function-local-has-name?
2.6 Literals
2.7 Exports
export?
module-export-function
2.8 Expressions
expression?
2.8.1 Unary expressions
2.8.2 Binary Expressions
binary-expression?
make-add-int32
make-sub-int32
make-mult-int32
2.8.3 Load expression
make-load
load-atomic?
set-load-atomic!
8.3.0.2

Racket binaryen bindings

 (require binaryen) package: racket-binaryen

This is a wrapper for the Binaryen suite of WebAssembly tools. WebAssembly (or Wasm) is a binary instruction format for a stack-based virtual machine. More information can be found in its webpage.

    1 Getting Started

      1.1 Reading WebAssembly

      1.2 Writing WebAssembly

      1.3 Optimization

      1.4 A Longer Example

    2 API

      2.1 Types

      2.2 Optimizations

      2.3 Modules

      2.4 Features

      2.5 Functions

      2.6 Literals

      2.7 Exports

      2.8 Expressions

        2.8.1 Unary expressions

        2.8.2 Binary Expressions

        2.8.3 Load expression

1 Getting Started

You are interested in Racket and WebAssembly and somehow found this package? However, you have no idea where to start... well, you came to the right place!

This package is a set of (experimental) safe high level bindings for binaryen. Binaryen itself is a library written in C++ with a C API, that aims to make compiling to WebAssembly easy, fast, and effective. It is very versatile allowing you to read wasm files, do some transformation and spit it out again, or create your own WebAssembly module from scratch.

There will be times when a binaryen function is not available yet in this package. I add more support on a regular basis but might have not done so for the functions you need. In that case, open an issue and I will prioritize your requirements.

1.1 Reading WebAssembly

Consider the following Wasm module in text format:

(module
  (func $double (export "wasm_double")
        (param $x i32) (result i32)
    (i32.mul (i32.const 2) (local.get $x)))
  (func $collatz_iteration (export "wasm_col_iter")
        (param $x i32) (result i32)
    (i32.add (i32.const 1)
             (i32.mul (i32.const 3) (local.get $x)))))

This example defines two functions that are exported from the module: double and collatz_iteration. The function double is exported with the name wasm_double and the function collatz_iteration is exported with the name wasm_col_iter.

To parse a module from a string, use the function module-parse.

Examples:
> (require binaryen
           racket/port)
> (define wasm-mod
    '(module
       (func $double (export "wasm_double")
             (param $x i32) (result i32)
         (i32.mul (i32.const 2) (local.get $x)))
       (func $collatz_iteration (export "wasm_col_iter")
             (param $x i32) (result i32)
         (i32.add (i32.const 1)
                  (i32.mul (i32.const 3) (local.get $x))))))
> (define mod (module-parse (with-output-to-string
                               (lambda () (write wasm-mod)))))
> (module-valid? mod)

#t

We have read the module in, and checked it’s valid. We can perform a number of queries on the module.

Example:

You can see how it is printed to standard output.

Example:
> (module-print mod)

(module

 (type $i32_=>_i32 (func (param i32) (result i32)))

 (export "wasm_double" (func $double))

 (export "wasm_col_iter" (func $collatz_iteration))

 (func $double (param $x i32) (result i32)

  (i32.mul

   (i32.const 2)

   (local.get $x)

  )

 )

 (func $collatz_iteration (param $x i32) (result i32)

  (i32.add

   (i32.const 1)

   (i32.mul

    (i32.const 3)

    (local.get $x)

   )

  )

 )

)

1.2 Writing WebAssembly

You can also create WebAssembly on the fly, have it optimized and write it to a file. Lets say that we want to manually create a module that contains a function square, that multiplies a number with itself.

What we want to create is something like this:

(module
  (func $square (export "square")
        (param $x i32)
        (result $i32)
   (i32.mul (local.get $x) (local.get $x))))

Most functions in this library will receive an optional module to use as last parameter. If not provided, they will the value of current-module which is useful to create WebAssembly code since you tend to work on a module at a time.

The racket code will take this shape:

(require racket/contract
         binaryen)
 
(define/contract (create-square)
  (-> module?)
  (parameterize ([current-module (module-create)])
    (module-add-function "square"
                         (list type-int32)
                         (list type-int32)
                         '()
                         (make-mul-int32 (make-localget 0 type-int32)
                                         (make-localget 0 type-int32)))
    (module-export-function "$square" "square")
    (current-module)))

In this example we create an empty module with (module-create) and set it as the current-module so that we don’t need to pass it around. Then we add a function withe name "square", receiving one 32bit integer, returning one 32bit integer, and without any locals. The body is created in-place and passed into the function. The function module-add-function creates the function and adds it to the current-module.

1.3 Optimization

1.4 A Longer Example

2 API

2.1 Types

Types refer to WebAssembly types such as int32, int64, etc. There are basic types and ways to aggregate a type from these basic types.

procedure

(type? x)  boolean?

  x : any/c
Predicate to check if value x is a WebAssembly type.

value

type-none : type?

The type None.

value

type-int32 : type?

The type Int32.

value

type-int64 : type?

The type Int64.

value

type-float32 : type?

The type Float32.

value

type-float64 : type?

The type Float64.

value

type-vec128 : type?

The type Vec128.

value

type-funcref : type?

The type Funcref.

value

type-externref : type?

The type Externref.

value

type-anyref : type?

The type Anyref.

value

type-eqref : type?

The type Eqref.

value

type-i31ref : type?

The type I31ref.

value

type-dataref : type?

The type Dataref.

value

type-unreachable : type?

The type Unreachable.

value

type-auto : type?

The type Auto.

2.2 Optimizations

Binaryen can optimize your webassembly program and many functions depends on the global optimization levels set. This API section describes which levels can be tuned and which facilities are provided to change the levels.

procedure

(optimize-level? x)  boolean?

  x : any/c
Checks if the value x is a valid optimize level.

procedure

(shrink-level? x)  boolean?

  x : any/c
Checks if the value x is a valid shrink level.

procedure

(optimize-level)  exact-nonnegative-integer?

Returns the current global optimize level.

procedure

(shrink-level)  exact-nonnegative-integer?

Returns the current global shrink level.

procedure

(set-optimize-level! n)  void?

  n : exact-nonnegative-integer?
Sets the current optimize level to n. Any positive value is positive but it only makes a different until 4, inclusive. So 0 stands for the usual -O0, 1 for -O1, etc, until 4 standing for -O4.

procedure

(set-shrink-level! n)  void?

  n : exact-nonnegative-integer?
Sets the current shrink level to n. Any positive value is positive but it only makes a different until 2, inclusive. So 0 stands for the usual -O0, 1 for -Os, and 2 for -Oz.

syntax

(with-optimize-level n body ...)

Evaluates the body ... forms in sequence with the optimize level set to n. After the evaluation of all the forms or if the control jumps out of this form, the optimize level is reset to its old value.

syntax

(with-shrink-level n body ...)

Evaluates the body ... forms in sequence with the shrink level set to n. After the evaluation of all the forms or if the control jumps out of this form, the shrink level is reset to its old value.

2.3 Modules

A module is the representation of a WebAssembly module into which you add functions, etc.

procedure

(module? x)  boolean?

  x : any/c
Checks if the value x is a WebAssembly module.

parameter

(current-module)  module?

(current-module module)  void?
  module : module?
 = #false
A parameter that defines the current module to use.

procedure

(module-create)  void?

Creates an empty WebAssembly module.

procedure

(module-valid? [mod])  boolean?

  mod : module? = (current-module)
Validates the Wasm module mod, returning #true if it is a valid module and #false otherwise.

procedure

(module-print [mod])  void?

  mod : module? = (current-module)
Prints the Wasm module mod to standard output.

procedure

(module-optimize! [mod])  void?

  mod : module? = (current-module)
Optimizes the Wasm module mod in-place.

procedure

(module-read in)  module?

  in : bytes?
Reads a module in binary format from bytes in and returns a Wasm module.

procedure

(module-parse s)  module?

  s : string?
Reads a module from string s and returns a Wasm module.

procedure

(module-write mod textual? [#:source-map sm])  bytes?

  mod : module?
  textual? : boolean?
  sm : (or/c string? #false) = #false
Writes module mod to a byte string using source map sm, if provided. Returns the byte string. The module is read in text format if textual? is true, and in binary format otherwise.

2.4 Features

Features refer to WebAssembly features that are enabled in a module and generally refer to which WebAssembly proposals have been implemented in Binaryen.

procedure

(feature? x)  boolean?

  x : any/c
Predicate to check if value x is a feature.

value

feature-mvp : feature?

This feature refers to the language implemented in the WebAssembly MVP.

value

feature-atomics : feature?

This feature refers to the Threads and Atomics WebAssembly proposal.

value

feature-bulk-memory : feature?

This feature refers to the Bulk Memory proposal.

value

feature-mutable-globals : feature?

value

feature-nontrapping-fptoint : feature?

value

feature-sign-extension : feature?

This feature refers to the Sign extension proposal.

value

feature-simd128 : feature?

This feature refers to the SIMD proposal.

value

feature-exception-handling : feature?

This feature refers to the Exception Handling proposal.

value

feature-tail-call : feature?

This feature refers to the Tail calls proposal.

value

feature-reference-types : feature?

This feature refers to the Reference Types proposal.

value

feature-multivalue : feature?

This feature refers to the Multivalue proposal.

value

feature-gc : feature?

This feature refers to the Garbage Collection proposal.

value

feature-memory64 : feature?

This feature refers to the Memory with 64bit indexes proposal.

value

feature-typed-function-references : feature?

This feature refers to the Typed Function References proposal.

value

feature-all : (listof feature?)

List containing all supported features.

procedure

(module-features [mod])  (listof feature?)

  mod : module? = (current-module)
Returns the list of WebAssembly features required by module mod.

procedure

(set-module-features! features    
  [#:module mod])  void?
  features : (listof feature?)
  mod : module? = (current-module)
Sets the required features by module mod to be features.

2.5 Functions

A function is the representation of a WebAssembly function.

procedure

(module-add-function name    
  arg-types    
  result-types    
  var-types    
  body    
  [#:module mod])  function?
  name : string?
  arg-types : (listof type?)
  result-types : (listof type?)
  var-types : (listof type?)
  body : expression?
  mod : module? = (current-module)
Adds a function to module mod. The function’s name is name and its argument types are given by the types in the list arg-types. It returns as many results as there are elements in result-types, and its elements describe the type of each of the result values. The expression body is the expression that computes the result of the function. The list var-types contains the types of the local variables of the body of the function. It might seem strange that var-types is required at this point but take into consideration that in WebAssembly variables share an index space with arguments. So the locals in the function are arguments whose index starts at 0, followed by the the variables whose index starts at (length arg-types). To setup this index space, we need to know the variable types at the point the function is created.

procedure

(module-function-count [#:module mod])  exact-positive-integer?

  mod : module? = (current-module)
Takes a module as an argument and it returns the number of functions in the module.

procedure

(module-function idx [#:module mod])  function?

  idx : exact-nonnegative-integer?
  mod : module? = (current-module)
Returns the function in mod indexed by idx, where idx < (module-function-count mod).

procedure

(function-name f)  string?

  f : function?
Returns the name of function f.

procedure

(function-parameter-types f)  (listof type?)

  f : function?
Returns the list of types corresponding to the parameters of function f.

procedure

(function-result-types f)  (listof type?)

  f : function?
Returns the list of types corresponding to the results of function f.

procedure

(function-variable-count f)  exact-positive-integer?

  f : function?
Returns the number of variables in function f.

procedure

(function-variable-type f n)  type?

  f : function?
  n : exact-positive-integer?
Returns the type of the variable with index n - 1 of function f.

procedure

(function-get-locals-count f)  exact-nonnegative-integer?

  f : function?
Returns the number of locals in function f, including parameters.

procedure

(function-local-has-name? f n)  boolean?

  f : function?
  n : exact-nonnegtive-integer?
Returns true if the local indexed by n in function f has a name, and false otherwise.

2.6 Literals

2.7 Exports

An export represent a value that is exported from a WebAssembly module.

procedure

(export? x)  boolean?

  x : any/c
Checks if the value x is a WebAssembly export.

procedure

(module-export-function in out [#:module mod])  export?

  in : string?
  out : string?
  mod : module? = (current-module)
Exports the function with internal name in in module mod as out, returning a reference to the export.

2.8 Expressions

An expression is a way to transform Wasm values through computation.

procedure

(expression? x)  boolean?

  x : any/c
Checks if the value x is an expression.

2.8.1 Unary expressions

A unary expression is an expression that operates on one value. Constructors for unary operations will take the form make-<name>-<type>, where <name> is the operation name, and <type> is the type of the value expected by the operation. Value types are not checked at the compile time, therefore it is possible to create invalid WebAssembly modules. Use module-valid? to validate your modules.

2.8.2 Binary Expressions

A binary expression is an expression that operates on two values.

procedure

(binary-expression? x)  boolean?

  x : any/c
Checks if the value x is a binary expression.

procedure

(make-add-int32 a b [#:module mod])  binary-expression?

  a : expression?
  b : expression?
  mod : module? = (current-module)
Creates a binary expression that represents the addition of a to b, both of which must have type type-int32.

procedure

(make-sub-int32 a b [#:module mod])  binary-expression?

  a : expression?
  b : expression?
  mod : module? = (current-module)
Creates a binary expression that represents the subtraction of b from a, both of which must have type type-int32.

procedure

(make-mult-int32 a b [#:module mod])  binary-expression?

  a : expression?
  b : expression?
  mod : module? = (current-module)
Creates a binary expression that represents the multiplication between a and b, both of which must have type type-int32.

2.8.3 Load expression

A load expression is an expression that loads a value from memory.

procedure

(make-load bytes    
  signed?    
  offset    
  align    
  type    
  ptr    
  [#:module mod])  load-expression?
  bytes : exact-nonnegative-integer?
  signed? : boolean?
  offset : exact-nonnegative-integer?
  align : exact-nonnegative-integer?
  type : type?
  ptr : expression?
  mod : module? = (current-module)
Creates a load expression that represents the load of bytes bytes from memory. The expression ptr evaluates to a value through which to access memory, and the loaded value is specified as having type type.

procedure

(load-atomic? ld)  boolean?

  ld : load-expression?
Returns #true if the load-expression ld is atomic, #false otherwise.

procedure

(set-load-atomic! ld atomic?)  void?

  ld : load-expression?
  atomic? : boolean
Turns the load expression ld into an atomic load conditional on the value of atomic?.