Back to top

Wascap Specification - Communications

In WebAssembly, communication between a guest module and the host is what most developers would call primitive. WebAssembly 1.0 only supports 32- and 64-bit integers and floating point numbers. So any high-level communication performed between the guest and the host must somehow, underneath it all, use nothing but these primitive parameter types.

Some tools designed specifically for integration with JavaScript and the browser will auto-generate strongly typed methods for each call, as well as generate wrapper classes to allow JavaScript to instantiate (and hold onto the reference for) structs. This requires a complex juggling act where both sides of the communication exchange must maintain and expose their own memory management systems. In the case of the early Wascap specification–which was inspired by wasm-bindgen–this memory management system bled out into the interface contract.

Wasm-bindgen allows for both sides to create instances of things that will persist between function calls. This makes sense if you are trying to allow a seamless language integration with JavaScript, but this is not Wascap’s goal. The wascap standard is about the facilitation of function calls, and it does not presume to support any kind of arbitrary object allocation across the guest<–>host boundary.

WebAssembly Interface Specification

WebAssembly Interfaces are a text format for clearly defining the set of imports and exports that define a particular interface. The text format itself is inspired by the lisp-like WebAssembly text format (wat). For example, the WASI interface contains a fairly lengthy set of imports that correspond to low-level system calls, and manually checking whether or not a given module has the right set of them would be impractical and error-prone.

Thankfully, the folks at Wasmer have added support for WebAssembly Interfaces to wapm.io and the accompanying CLI tooling. With this tooling you can quickly check to see if a given Wasm file conforms to the WASI interface or the Wascap interface (or any interface that may potentially be recognized in the future).

The following is the formal definition of the current Wascap interface:

(interface "wascap"
    ;; Mandatory wascap imports
    (func (import "wascap" "__host_call" )          (param i32 i32 i32 i32) (result i32))    
    (func (import "wascap" "__host_response")       (param i32))
    (func (import "wascap" "__host_response_len")   (result i32))
    (func (import "wascap" "__host_error_len")      (result i32))
    (func (import "wascap" "__host_error")          (param i32))
    (func (import "wascap" "__guest_response")      (param i32 i32))
    (func (import "wascap" "__guest_error")         (param i32 i32))
    (func (import "wascap" "__guest_request")       (param i32 i32))           
    (func (import "wascap" "__console_log")         (param i32 i32))

    ;; Mandatory wascap guest module exports    
    (func (export "__guest_call")                   (param i32 i32) (result i32))    
)

Note - there is a useful tutorial on Publishing to the Wapm Registry that relies on wapm.io’s ability to support multiple interfaces and illustrates how this interface specification can be used.

Required Guest Functions

This function is mandatory and must be implemented by any Wascap-compliant guest module.
FunctionParametersDescription
__guest_callop_len - usize
len - usize
returns usize
This function is called by the host to execute a function contained within the Wasm module. It takes two parameters–The length of the operation name and the length of the opaque payload. It returns a boolean (0=false, 1=true) indicating successful execution.

Required Host Functions

These functions are mandatory and must be implemented by any Wascap-compliant host.
They must be made available to the guest in the import namespace wascap. Note that while type signatures may indicate a pointer to const u8 or i32, but all of those types are converted into i32 before marshalling between host and guest. The preceding specification shows what the compiled Wasm module must import and export.
FunctionParametersDescription
__host_callop_ptr - *const u8
op-len - usize
ptr - *const u8
len - usize
returns usize
Called by the guest to invoke a host function.
The parameters indicate the pointer (start) and length of an arbitrary blob of bytes containing the opaque payload for the request and the pointer/length of the operation name (UTF-8 encoded string). Returns a boolean (0=false,1=true) indicating call success
__host_responseptr - *const u8After __host_call terminates without error, the guest module invokes this function to tell the host to populate the response at the given pointer
__host_response_lenreturns usizeThe guest module calls this function to determine the size of the host response after __host_call terminates. Guest module should only call this if __host_error_len returned 0. If the host failed to process the request, this value will be 0
__host_error_lenreturns usizeThe guest module calls this function to determine if an error occurred during a __host_call. If the value is >0, an error did occur and this is the length of the UTF-8 encoded string representing that error
__host_errorptr - *const u8The guest module calls this function to tell the host module to populate the error string at the given pointer
__guest_responseptr - *const u8
len - usize
Sets the value of the response the host will use once the __guest_call function returns. While this function can be called as many times as you like per invocation, you should try and only call it once for performance reasons
__guest_errorptr - *const u8
len - usize
Sets the UTF-8 encoded string value of an error that occurred while the guest module was in the middle of a __guest_call. If this is set, the host will assume the function call failed and use the string in log output
__guest_requestop_ptr - *const u8
ptr - *const u8
Asks the host to populate the operation name and the opaque guest request payload at the given pointer addresses
__console_logptr - *const u8
len - usize
While executing code within __guest_call, the guest module can log arbitrary strings (UTF-8 encoding) to whatever output device is chosen by the host