Previous: , Up: Toolchain reference   [Contents][Index]


3.8 Interpreter

The (wasm vm) module provides a virtual machine for interpreting WASM functions. To use the interpreter, a WASM module is first validated for type safety (among other things) and then instantiated, at which point exported functions become callable from Scheme.

The interpreter only accepts validated WASM. The validate-wasm procedure validates and wraps a WASM module to indicate successful validation:

(use-modules (wasm vm) (wasm resolve))

(define validated-wasm
  (validate-wasm
   (wat->wasm
    '(module
      (func (export "main") (result i32)
            (i32.const 42))))))

When starting with a WASM binary, the convenient load-and-validate-wasm procedure parses the binary and then performs validation:

(call-with-input-file "hello.wasm" load-and-validate-wasm)

Once the WASM module has been validated, the runtime data needed for interpretation can be created by instantiating the module:

(define instance (instantiate-wasm validated-wasm))

Exported WASM functions then become usable as Scheme procedures:

(define wasm-main (wasm-instance-export-ref instance "main"))
(wasm-main) ;; => 42

WASM functions are statically typed, which means that calls from Scheme to WASM require runtime type checking for each call.

3.8.1 Validation

Procedure: validate-wasm wasm

Validate the WASM module wasm and return a validated WASM object.

Procedure: load-and-validate-wasm obj

Load and validate the WASM module within obj then return a validated WASM object. obj may be a <wasm> record as produced by resolve-wasm(see Resolver), a bytevector containing a WASM binary, or an input port from which to read a WASM binary.

Procedure: validated-wasm? obj

Return #t if obj is a validated WASM object.

Procedure: validated-wasm-ref validated-wasm

Unbox and return the WASM module within validated-wasm.

3.8.2 Instantiation

Procedure: instantiate-wasm wasm [#:imports '()]

Return a new WASM instance for the validated WASM module wasm.

imports is a nested association list of imported functions, globals, memories, and tables. WASM imports are identified by a module name and an object name. Consider the following WASM module that computes 2D polar coordinates and prints them to a log:

(use-modules (wasm resolve) (wasm vm) (wasm wat))

(define the-module
  (resolve-wasm
   (wat->wasm
    '(module
      (func $logf64 (import "debug" "logf64") (param f64))
      (func $cos (import "math" "cos") (param f64) (result f64))
      (func $sin (import "math" "sin") (param f64) (result f64))
      (func (export "polar") (param $r f64) (param $theta f64)
            (call $logf64 (f64.mul (local.get $r)
                                   (call $cos (local.get $theta))))
            (call $logf64 (f64.mul (local.get $r)
                                   (call $sin (local.get $theta)))))))))

This module requires three imported functions from two modules. Thus the module instantiation code would look like this:

(define (logf64 x)
  (format #t "f64: ~a\n" x))

(define the-instance
  (instantiate-wasm (validate-wasm the-module)
                    #:imports `(("debug" . (("logf64" . ,logf64)))
                                ("math" . (("cos" . ,cos)
                                           ("sin" . ,sin))))))

3.8.3 Globals

Procedure: make-wasm-global value mutable?

Return a new WASM global containing value. When mutable? is #f, the value cannot be modified later.

Procedure: wasm-global? obj

Return #t if obj is a WASM global.

Procedure: wasm-global-ref global

Return the current value within global.

Procedure: wasm-global-set! global val

Set the value within global to val. An exception is raised if global is immutable.

Procedure: wasm-global-mutable? global

Return #t if global is mutable.

3.8.4 Memories

Procedure: make-wasm-memory size [#:limits (make-limits 1 #f)]

Return a new WASM linear memory containing size 64KiB pages. limits determines the lower and upper bounds of how many pages this memory can store. The default limits are a minimum of 1 page and no maximum page limit. See Data types for more information on limit objects.

Procedure: wasm-memory? obj

Return #t if obj is a WASM memory.

Procedure: wasm-memory-bytes memory

Return the current bytevector representing the pages of memory.

Procedure: wasm-memory-size memory

Return the size of memory in 64KiB pages.

Procedure: wasm-memory-limits memory

Return the limits of memory

Procedure: wasm-memory-grow! memory n

Increase the size of memory by n pages. An exception is raised if growing by n exceeds the limits of memory.

3.8.5 Tables

Procedure: make-wasm-table size [#:limits (make-limits 1 #f)]

Return a new WASM reference table containing size element slots. limits determines the lower and upper bounds of how many elements this table can store. The default limits are a minimum of 1 element and no maximum element limit. See Data types for more information on limit objects.

Procedure: wasm-table?

Return #t if obj is a WASM table.

Procedure: wasm-table-size table

Return the size of table.

Procedure: wasm-table-ref table i

Return the reference at the ith index in table.

Procedure: wasm-table-set! table i x

Set the ith element of table to x, a WASM reference type.

Procedure: wasm-table-fill! table start fill length

Fill the elements of table from start to start + length, exclusive, with the value fill.

Procedure: wasm-table-copy! table at elems start length

Copy the block of elements from vector elems, from start to start + length, exclusive, to table, starting at at.

Procedure: wasm-table-grow! table n init

Increase the size of table by n elements. An exception is raised if growing by n exceeds the limits of table.

3.8.6 Observation

Every WASM instruction evaluated by interpreter can be observed via the current-instruction-listener parameter. Use this hook to instrument WASM modules.

The following instruction listener would print every instruction’s name on a separate line:

(define (log-instr instr path instance stack blocks locals)
  (display (car instr))
  (newline))

(parameterize ((current-instruction-listener log-instr))
  ...)
Variable: Variable current-instruction-listener

The current instruction observation hook which is invoked before each instruction evaluation. Must be a procedure that accepts the following arguments:

  1. Instruction: The symbolic WASM instruction to be evaluated.
  2. Path: The symbolic location of the instruction within the WASM module.
  3. Instance: The instance that is evaluating the instruction.
  4. Stack: The WASM value stack.
  5. Blocks: The WASM block stack, which is just a list of prompt tags.
  6. Locals: The WASM function locals.

The WASM value stack is a special data type with the following API:

Procedure: wasm-stack? obj

Return #t if obj is a WASM value stack.

Procedure: wasm-stack-items stack

Return the values on stack as a list.


Previous: Printer, Up: Toolchain reference   [Contents][Index]