/wasm-c-api

Wasm C API prototype

Primary LanguageC++Apache License 2.0Apache-2.0

WebAssembly C and C++ API

Work in progress! No docs yet.

Design Goals

  • Provide a "black box" API for embedding a Wasm engine in other C/C++ applications.

    • Be completely agnostic to VM specifics.

    • Non-goal: "white box" interoperability with embedder (such as combined GC instead of mere finalisation) -- much more difficult to achieve.

  • Allow creation of bindings for other languages through typical C foreign function interfaces.

    • Support a plain C API.

    • Stick to mostly manual memory management of interface objects.

  • Avoid language features that raise barrier to use.

    • E.g., no exceptions or post-C++11 features in C++ API.

    • E.g., no passing of structs by-value or post-C99 features in C API.

  • Achieve link-time compatibility between different implementations.

    • All implementation-dependent API classes are abstract and can be instantiated through factory methods only.

Interfaces

  • C++ API:

    • See include/wasm.hh for interface.

    • See example/*.cc for example usages.

  • C API:

    • See include/wasm.h for interface.

    • See example/*.c for example usages.

Some random explanations:

  • The VM must be initialised by creating an instance of an engine (wasm::Engine/wasm_engine_t) and is shut down by deleting it. Such an instance may only be created once per process.

  • All runtime objects are tied to a specific store (wasm::Store/wasm_store_t). Multiple stores can be created, but their objects cannot interact. Every store and its objects must only be accessed in a single thread.

  • To exchange module objects between threads, create a shared module (wasm::Shared<Module>/wasm_shared_module_t). Other objects cannot be shared in current Wasm.

  • Vector structures (wasm::vec<X>/wasm_x_vec_t) are lightweight abstractions of a pair of a plain array and its length. The C++ API does not use std::vector because that does not support adopting pre-existing arrays.

  • References point to runtime objects, but may involve internal indirections, which may or may not be cached. Thus, pointer equality on Ref* or subclasses cannot be used to compare identity of the underlying objects (Ref::eq may be added later). However, nullptr/NULL uniquely represents null references.

  • The API already encompasses current proposals like multiple return values and reference types, but not yet threads.

Prototype Implementation

  • This repo contains a prototype implementation based on V8 is in src.

    • Note that this requires adding a module to V8, so it patches V8's build file.
  • The C API is implemented on top of the C++ API.

  • See Makefile for build recipe. Canonical steps to run examples:

    1. make v8-checkout
    2. make v8
    3. make all

Limitations

V8 implementation:

  • Currently requires patching V8 by adding a module.

  • Host functions (Func::make) create a JavaScript function internally, since V8 cannot handle raw C imports yet.

  • As a consequence, does not support multiple results in external calls or host functions.

  • Host functions and host globals are created through auxiliary modules constructed on the fly, to work around limitations in JS API.

  • Shared<Module> is currently implemented via serialisation, since V8 does not currently have direct support for cross-isolate sharing.

Other Implementations

Currently, known implementations of this API are included in

  • V8 natively (both C and C++)
  • Wabt (only C?)
  • Wasmtime (only C?)
  • Wasmer (only C, C++ coming soon)

TODO

Possible API tweaks:

  • Add Ref::eq (or better, a subclass EqRef::eq) for reference equality?

  • Add a way to return error messages from Module::make and Module::validate.

  • Use restrict in C API?

  • Find a way to perform C callbacks through C++ without extra wrapper?

  • Add iterators to vec class?