test(c-api) Split the test suites (deprecated and wasm-c-api).

This commit is contained in:
Ivan Enderlin
2020-09-28 17:09:44 +02:00
parent 570b174fb5
commit ffd1e6eddf
104 changed files with 54 additions and 161 deletions

View File

@@ -0,0 +1,704 @@
// WebAssembly C API
#ifndef WASM_H
#define WASM_H
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <assert.h>
#ifndef WASM_API_EXTERN
#ifdef _WIN32
#define WASM_API_EXTERN __declspec(dllimport)
#else
#define WASM_API_EXTERN
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
///////////////////////////////////////////////////////////////////////////////
// Auxiliaries
// Machine types
inline void assertions() {
static_assert(sizeof(float) == sizeof(uint32_t), "incompatible float type");
static_assert(sizeof(double) == sizeof(uint64_t), "incompatible double type");
static_assert(sizeof(intptr_t) == sizeof(uint32_t) ||
sizeof(intptr_t) == sizeof(uint64_t),
"incompatible pointer type");
}
typedef char byte_t;
typedef float float32_t;
typedef double float64_t;
// Ownership
#define own
// The qualifier `own` is used to indicate ownership of data in this API.
// It is intended to be interpreted similar to a `const` qualifier:
//
// - `own wasm_xxx_t*` owns the pointed-to data
// - `own wasm_xxx_t` distributes to all fields of a struct or union `xxx`
// - `own wasm_xxx_vec_t` owns the vector as well as its elements(!)
// - an `own` function parameter passes ownership from caller to callee
// - an `own` function result passes ownership from callee to caller
// - an exception are `own` pointer parameters named `out`, which are copy-back
// output parameters passing back ownership from callee to caller
//
// Own data is created by `wasm_xxx_new` functions and some others.
// It must be released with the corresponding `wasm_xxx_delete` function.
//
// Deleting a reference does not necessarily delete the underlying object,
// it merely indicates that this owner no longer uses it.
//
// For vectors, `const wasm_xxx_vec_t` is used informally to indicate that
// neither the vector nor its elements should be modified.
// TODO: introduce proper `wasm_xxx_const_vec_t`?
#define WASM_DECLARE_OWN(name) \
typedef struct wasm_##name##_t wasm_##name##_t; \
\
WASM_API_EXTERN void wasm_##name##_delete(own wasm_##name##_t*);
// Vectors
#define WASM_DECLARE_VEC(name, ptr_or_none) \
typedef struct wasm_##name##_vec_t { \
size_t size; \
wasm_##name##_t ptr_or_none* data; \
} wasm_##name##_vec_t; \
\
WASM_API_EXTERN void wasm_##name##_vec_new_empty(own wasm_##name##_vec_t* out); \
WASM_API_EXTERN void wasm_##name##_vec_new_uninitialized( \
own wasm_##name##_vec_t* out, size_t); \
WASM_API_EXTERN void wasm_##name##_vec_new( \
own wasm_##name##_vec_t* out, \
size_t, own wasm_##name##_t ptr_or_none const[]); \
WASM_API_EXTERN void wasm_##name##_vec_copy( \
own wasm_##name##_vec_t* out, const wasm_##name##_vec_t*); \
WASM_API_EXTERN void wasm_##name##_vec_delete(own wasm_##name##_vec_t*);
// Byte vectors
typedef byte_t wasm_byte_t;
WASM_DECLARE_VEC(byte, )
typedef wasm_byte_vec_t wasm_name_t;
#define wasm_name wasm_byte_vec
#define wasm_name_new wasm_byte_vec_new
#define wasm_name_new_empty wasm_byte_vec_new_empty
#define wasm_name_new_new_uninitialized wasm_byte_vec_new_uninitialized
#define wasm_name_copy wasm_byte_vec_copy
#define wasm_name_delete wasm_byte_vec_delete
static inline void wasm_name_new_from_string(
own wasm_name_t* out, const char* s
) {
wasm_name_new(out, strlen(s) + 1, s);
}
///////////////////////////////////////////////////////////////////////////////
// Runtime Environment
// Configuration
WASM_DECLARE_OWN(config)
WASM_API_EXTERN own wasm_config_t* wasm_config_new();
// Embedders may provide custom functions for manipulating configs.
// Engine
WASM_DECLARE_OWN(engine)
WASM_API_EXTERN own wasm_engine_t* wasm_engine_new();
WASM_API_EXTERN own wasm_engine_t* wasm_engine_new_with_config(own wasm_config_t*);
// Store
WASM_DECLARE_OWN(store)
WASM_API_EXTERN own wasm_store_t* wasm_store_new(wasm_engine_t*);
///////////////////////////////////////////////////////////////////////////////
// Type Representations
// Type attributes
typedef uint8_t wasm_mutability_t;
enum wasm_mutability_enum {
WASM_CONST,
WASM_VAR,
};
typedef struct wasm_limits_t {
uint32_t min;
uint32_t max;
} wasm_limits_t;
static const uint32_t wasm_limits_max_default = 0xffffffff;
// Generic
#define WASM_DECLARE_TYPE(name) \
WASM_DECLARE_OWN(name) \
WASM_DECLARE_VEC(name, *) \
\
WASM_API_EXTERN own wasm_##name##_t* wasm_##name##_copy(wasm_##name##_t*);
// Value Types
WASM_DECLARE_TYPE(valtype)
typedef uint8_t wasm_valkind_t;
enum wasm_valkind_enum {
WASM_I32,
WASM_I64,
WASM_F32,
WASM_F64,
WASM_ANYREF = 128,
WASM_FUNCREF,
};
WASM_API_EXTERN own wasm_valtype_t* wasm_valtype_new(wasm_valkind_t);
WASM_API_EXTERN wasm_valkind_t wasm_valtype_kind(const wasm_valtype_t*);
static inline bool wasm_valkind_is_num(wasm_valkind_t k) {
return k < WASM_ANYREF;
}
static inline bool wasm_valkind_is_ref(wasm_valkind_t k) {
return k >= WASM_ANYREF;
}
static inline bool wasm_valtype_is_num(const wasm_valtype_t* t) {
return wasm_valkind_is_num(wasm_valtype_kind(t));
}
static inline bool wasm_valtype_is_ref(const wasm_valtype_t* t) {
return wasm_valkind_is_ref(wasm_valtype_kind(t));
}
// Function Types
WASM_DECLARE_TYPE(functype)
WASM_API_EXTERN own wasm_functype_t* wasm_functype_new(
own wasm_valtype_vec_t* params, own wasm_valtype_vec_t* results);
WASM_API_EXTERN const wasm_valtype_vec_t* wasm_functype_params(const wasm_functype_t*);
WASM_API_EXTERN const wasm_valtype_vec_t* wasm_functype_results(const wasm_functype_t*);
// Global Types
WASM_DECLARE_TYPE(globaltype)
WASM_API_EXTERN own wasm_globaltype_t* wasm_globaltype_new(
own wasm_valtype_t*, wasm_mutability_t);
WASM_API_EXTERN const wasm_valtype_t* wasm_globaltype_content(const wasm_globaltype_t*);
WASM_API_EXTERN wasm_mutability_t wasm_globaltype_mutability(const wasm_globaltype_t*);
// Table Types
WASM_DECLARE_TYPE(tabletype)
WASM_API_EXTERN own wasm_tabletype_t* wasm_tabletype_new(
own wasm_valtype_t*, const wasm_limits_t*);
WASM_API_EXTERN const wasm_valtype_t* wasm_tabletype_element(const wasm_tabletype_t*);
WASM_API_EXTERN const wasm_limits_t* wasm_tabletype_limits(const wasm_tabletype_t*);
// Memory Types
WASM_DECLARE_TYPE(memorytype)
WASM_API_EXTERN own wasm_memorytype_t* wasm_memorytype_new(const wasm_limits_t*);
WASM_API_EXTERN const wasm_limits_t* wasm_memorytype_limits(const wasm_memorytype_t*);
// Extern Types
WASM_DECLARE_TYPE(externtype)
typedef uint8_t wasm_externkind_t;
enum wasm_externkind_enum {
WASM_EXTERN_FUNC,
WASM_EXTERN_GLOBAL,
WASM_EXTERN_TABLE,
WASM_EXTERN_MEMORY,
};
WASM_API_EXTERN wasm_externkind_t wasm_externtype_kind(const wasm_externtype_t*);
WASM_API_EXTERN wasm_externtype_t* wasm_functype_as_externtype(wasm_functype_t*);
WASM_API_EXTERN wasm_externtype_t* wasm_globaltype_as_externtype(wasm_globaltype_t*);
WASM_API_EXTERN wasm_externtype_t* wasm_tabletype_as_externtype(wasm_tabletype_t*);
WASM_API_EXTERN wasm_externtype_t* wasm_memorytype_as_externtype(wasm_memorytype_t*);
WASM_API_EXTERN wasm_functype_t* wasm_externtype_as_functype(wasm_externtype_t*);
WASM_API_EXTERN wasm_globaltype_t* wasm_externtype_as_globaltype(wasm_externtype_t*);
WASM_API_EXTERN wasm_tabletype_t* wasm_externtype_as_tabletype(wasm_externtype_t*);
WASM_API_EXTERN wasm_memorytype_t* wasm_externtype_as_memorytype(wasm_externtype_t*);
WASM_API_EXTERN const wasm_externtype_t* wasm_functype_as_externtype_const(const wasm_functype_t*);
WASM_API_EXTERN const wasm_externtype_t* wasm_globaltype_as_externtype_const(const wasm_globaltype_t*);
WASM_API_EXTERN const wasm_externtype_t* wasm_tabletype_as_externtype_const(const wasm_tabletype_t*);
WASM_API_EXTERN const wasm_externtype_t* wasm_memorytype_as_externtype_const(const wasm_memorytype_t*);
WASM_API_EXTERN const wasm_functype_t* wasm_externtype_as_functype_const(const wasm_externtype_t*);
WASM_API_EXTERN const wasm_globaltype_t* wasm_externtype_as_globaltype_const(const wasm_externtype_t*);
WASM_API_EXTERN const wasm_tabletype_t* wasm_externtype_as_tabletype_const(const wasm_externtype_t*);
WASM_API_EXTERN const wasm_memorytype_t* wasm_externtype_as_memorytype_const(const wasm_externtype_t*);
// Import Types
WASM_DECLARE_TYPE(importtype)
WASM_API_EXTERN own wasm_importtype_t* wasm_importtype_new(
own wasm_name_t* module, own wasm_name_t* name, own wasm_externtype_t*);
WASM_API_EXTERN const wasm_name_t* wasm_importtype_module(const wasm_importtype_t*);
WASM_API_EXTERN const wasm_name_t* wasm_importtype_name(const wasm_importtype_t*);
WASM_API_EXTERN const wasm_externtype_t* wasm_importtype_type(const wasm_importtype_t*);
// Export Types
WASM_DECLARE_TYPE(exporttype)
WASM_API_EXTERN own wasm_exporttype_t* wasm_exporttype_new(
own wasm_name_t*, own wasm_externtype_t*);
WASM_API_EXTERN const wasm_name_t* wasm_exporttype_name(const wasm_exporttype_t*);
WASM_API_EXTERN const wasm_externtype_t* wasm_exporttype_type(const wasm_exporttype_t*);
///////////////////////////////////////////////////////////////////////////////
// Runtime Objects
// Values
struct wasm_ref_t;
typedef struct wasm_val_t {
wasm_valkind_t kind;
union {
int32_t i32;
int64_t i64;
float32_t f32;
float64_t f64;
struct wasm_ref_t* ref;
} of;
} wasm_val_t;
WASM_API_EXTERN void wasm_val_delete(own wasm_val_t* v);
WASM_API_EXTERN void wasm_val_copy(own wasm_val_t* out, const wasm_val_t*);
WASM_DECLARE_VEC(val, )
// References
#define WASM_DECLARE_REF_BASE(name) \
WASM_DECLARE_OWN(name) \
\
WASM_API_EXTERN own wasm_##name##_t* wasm_##name##_copy(const wasm_##name##_t*); \
WASM_API_EXTERN bool wasm_##name##_same(const wasm_##name##_t*, const wasm_##name##_t*); \
\
WASM_API_EXTERN void* wasm_##name##_get_host_info(const wasm_##name##_t*); \
WASM_API_EXTERN void wasm_##name##_set_host_info(wasm_##name##_t*, void*); \
WASM_API_EXTERN void wasm_##name##_set_host_info_with_finalizer( \
wasm_##name##_t*, void*, void (*)(void*));
#define WASM_DECLARE_REF(name) \
WASM_DECLARE_REF_BASE(name) \
\
WASM_API_EXTERN wasm_ref_t* wasm_##name##_as_ref(wasm_##name##_t*); \
WASM_API_EXTERN wasm_##name##_t* wasm_ref_as_##name(wasm_ref_t*); \
WASM_API_EXTERN const wasm_ref_t* wasm_##name##_as_ref_const(const wasm_##name##_t*); \
WASM_API_EXTERN const wasm_##name##_t* wasm_ref_as_##name##_const(const wasm_ref_t*);
#define WASM_DECLARE_SHARABLE_REF(name) \
WASM_DECLARE_REF(name) \
WASM_DECLARE_OWN(shared_##name) \
\
WASM_API_EXTERN own wasm_shared_##name##_t* wasm_##name##_share(const wasm_##name##_t*); \
WASM_API_EXTERN own wasm_##name##_t* wasm_##name##_obtain(wasm_store_t*, const wasm_shared_##name##_t*);
WASM_DECLARE_REF_BASE(ref)
// Frames
WASM_DECLARE_OWN(frame)
WASM_DECLARE_VEC(frame, *)
WASM_API_EXTERN own wasm_frame_t* wasm_frame_copy(const wasm_frame_t*);
WASM_API_EXTERN struct wasm_instance_t* wasm_frame_instance(const wasm_frame_t*);
WASM_API_EXTERN uint32_t wasm_frame_func_index(const wasm_frame_t*);
WASM_API_EXTERN size_t wasm_frame_func_offset(const wasm_frame_t*);
WASM_API_EXTERN size_t wasm_frame_module_offset(const wasm_frame_t*);
// Traps
typedef wasm_name_t wasm_message_t; // null terminated
WASM_DECLARE_REF(trap)
WASM_API_EXTERN own wasm_trap_t* wasm_trap_new(wasm_store_t* store, const wasm_message_t*);
WASM_API_EXTERN void wasm_trap_message(const wasm_trap_t*, own wasm_message_t* out);
WASM_API_EXTERN own wasm_frame_t* wasm_trap_origin(const wasm_trap_t*);
WASM_API_EXTERN void wasm_trap_trace(const wasm_trap_t*, own wasm_frame_vec_t* out);
// Foreign Objects
WASM_DECLARE_REF(foreign)
WASM_API_EXTERN own wasm_foreign_t* wasm_foreign_new(wasm_store_t*);
// Modules
WASM_DECLARE_SHARABLE_REF(module)
WASM_API_EXTERN own wasm_module_t* wasm_module_new(
wasm_store_t*, const wasm_byte_vec_t* binary);
WASM_API_EXTERN bool wasm_module_validate(wasm_store_t*, const wasm_byte_vec_t* binary);
WASM_API_EXTERN void wasm_module_imports(const wasm_module_t*, own wasm_importtype_vec_t* out);
WASM_API_EXTERN void wasm_module_exports(const wasm_module_t*, own wasm_exporttype_vec_t* out);
WASM_API_EXTERN void wasm_module_serialize(const wasm_module_t*, own wasm_byte_vec_t* out);
WASM_API_EXTERN own wasm_module_t* wasm_module_deserialize(wasm_store_t*, const wasm_byte_vec_t*);
// Function Instances
WASM_DECLARE_REF(func)
typedef own wasm_trap_t* (*wasm_func_callback_t)(
const wasm_val_t args[], wasm_val_t results[]);
typedef own wasm_trap_t* (*wasm_func_callback_with_env_t)(
void* env, const wasm_val_t args[], wasm_val_t results[]);
WASM_API_EXTERN own wasm_func_t* wasm_func_new(
wasm_store_t*, const wasm_functype_t*, wasm_func_callback_t);
WASM_API_EXTERN own wasm_func_t* wasm_func_new_with_env(
wasm_store_t*, const wasm_functype_t* type, wasm_func_callback_with_env_t,
void* env, void (*finalizer)(void*));
WASM_API_EXTERN own wasm_functype_t* wasm_func_type(const wasm_func_t*);
WASM_API_EXTERN size_t wasm_func_param_arity(const wasm_func_t*);
WASM_API_EXTERN size_t wasm_func_result_arity(const wasm_func_t*);
WASM_API_EXTERN own wasm_trap_t* wasm_func_call(
const wasm_func_t*, const wasm_val_t args[], wasm_val_t results[]);
// Global Instances
WASM_DECLARE_REF(global)
WASM_API_EXTERN own wasm_global_t* wasm_global_new(
wasm_store_t*, const wasm_globaltype_t*, const wasm_val_t*);
WASM_API_EXTERN own wasm_globaltype_t* wasm_global_type(const wasm_global_t*);
WASM_API_EXTERN void wasm_global_get(const wasm_global_t*, own wasm_val_t* out);
WASM_API_EXTERN void wasm_global_set(wasm_global_t*, const wasm_val_t*);
// Table Instances
WASM_DECLARE_REF(table)
typedef uint32_t wasm_table_size_t;
WASM_API_EXTERN own wasm_table_t* wasm_table_new(
wasm_store_t*, const wasm_tabletype_t*, wasm_ref_t* init);
WASM_API_EXTERN own wasm_tabletype_t* wasm_table_type(const wasm_table_t*);
WASM_API_EXTERN own wasm_ref_t* wasm_table_get(const wasm_table_t*, wasm_table_size_t index);
WASM_API_EXTERN bool wasm_table_set(wasm_table_t*, wasm_table_size_t index, wasm_ref_t*);
WASM_API_EXTERN wasm_table_size_t wasm_table_size(const wasm_table_t*);
WASM_API_EXTERN bool wasm_table_grow(wasm_table_t*, wasm_table_size_t delta, wasm_ref_t* init);
// Memory Instances
WASM_DECLARE_REF(memory)
typedef uint32_t wasm_memory_pages_t;
static const size_t MEMORY_PAGE_SIZE = 0x10000;
WASM_API_EXTERN own wasm_memory_t* wasm_memory_new(wasm_store_t*, const wasm_memorytype_t*);
WASM_API_EXTERN own wasm_memorytype_t* wasm_memory_type(const wasm_memory_t*);
WASM_API_EXTERN byte_t* wasm_memory_data(wasm_memory_t*);
WASM_API_EXTERN size_t wasm_memory_data_size(const wasm_memory_t*);
WASM_API_EXTERN wasm_memory_pages_t wasm_memory_size(const wasm_memory_t*);
WASM_API_EXTERN bool wasm_memory_grow(wasm_memory_t*, wasm_memory_pages_t delta);
// Externals
WASM_DECLARE_REF(extern)
WASM_DECLARE_VEC(extern, *)
WASM_API_EXTERN wasm_externkind_t wasm_extern_kind(const wasm_extern_t*);
WASM_API_EXTERN own wasm_externtype_t* wasm_extern_type(const wasm_extern_t*);
WASM_API_EXTERN wasm_extern_t* wasm_func_as_extern(wasm_func_t*);
WASM_API_EXTERN wasm_extern_t* wasm_global_as_extern(wasm_global_t*);
WASM_API_EXTERN wasm_extern_t* wasm_table_as_extern(wasm_table_t*);
WASM_API_EXTERN wasm_extern_t* wasm_memory_as_extern(wasm_memory_t*);
WASM_API_EXTERN wasm_func_t* wasm_extern_as_func(wasm_extern_t*);
WASM_API_EXTERN wasm_global_t* wasm_extern_as_global(wasm_extern_t*);
WASM_API_EXTERN wasm_table_t* wasm_extern_as_table(wasm_extern_t*);
WASM_API_EXTERN wasm_memory_t* wasm_extern_as_memory(wasm_extern_t*);
WASM_API_EXTERN const wasm_extern_t* wasm_func_as_extern_const(const wasm_func_t*);
WASM_API_EXTERN const wasm_extern_t* wasm_global_as_extern_const(const wasm_global_t*);
WASM_API_EXTERN const wasm_extern_t* wasm_table_as_extern_const(const wasm_table_t*);
WASM_API_EXTERN const wasm_extern_t* wasm_memory_as_extern_const(const wasm_memory_t*);
WASM_API_EXTERN const wasm_func_t* wasm_extern_as_func_const(const wasm_extern_t*);
WASM_API_EXTERN const wasm_global_t* wasm_extern_as_global_const(const wasm_extern_t*);
WASM_API_EXTERN const wasm_table_t* wasm_extern_as_table_const(const wasm_extern_t*);
WASM_API_EXTERN const wasm_memory_t* wasm_extern_as_memory_const(const wasm_extern_t*);
// Module Instances
WASM_DECLARE_REF(instance)
WASM_API_EXTERN own wasm_instance_t* wasm_instance_new(
wasm_store_t*, const wasm_module_t*, const wasm_extern_t* const imports[],
own wasm_trap_t**
);
WASM_API_EXTERN void wasm_instance_exports(const wasm_instance_t*, own wasm_extern_vec_t* out);
///////////////////////////////////////////////////////////////////////////////
// Convenience
// Value Type construction short-hands
static inline own wasm_valtype_t* wasm_valtype_new_i32() {
return wasm_valtype_new(WASM_I32);
}
static inline own wasm_valtype_t* wasm_valtype_new_i64() {
return wasm_valtype_new(WASM_I64);
}
static inline own wasm_valtype_t* wasm_valtype_new_f32() {
return wasm_valtype_new(WASM_F32);
}
static inline own wasm_valtype_t* wasm_valtype_new_f64() {
return wasm_valtype_new(WASM_F64);
}
static inline own wasm_valtype_t* wasm_valtype_new_anyref() {
return wasm_valtype_new(WASM_ANYREF);
}
static inline own wasm_valtype_t* wasm_valtype_new_funcref() {
return wasm_valtype_new(WASM_FUNCREF);
}
// Function Types construction short-hands
static inline own wasm_functype_t* wasm_functype_new_0_0() {
wasm_valtype_vec_t params, results;
wasm_valtype_vec_new_empty(&params);
wasm_valtype_vec_new_empty(&results);
return wasm_functype_new(&params, &results);
}
static inline own wasm_functype_t* wasm_functype_new_1_0(
own wasm_valtype_t* p
) {
wasm_valtype_t* ps[1] = {p};
wasm_valtype_vec_t params, results;
wasm_valtype_vec_new(&params, 1, ps);
wasm_valtype_vec_new_empty(&results);
return wasm_functype_new(&params, &results);
}
static inline own wasm_functype_t* wasm_functype_new_2_0(
own wasm_valtype_t* p1, own wasm_valtype_t* p2
) {
wasm_valtype_t* ps[2] = {p1, p2};
wasm_valtype_vec_t params, results;
wasm_valtype_vec_new(&params, 2, ps);
wasm_valtype_vec_new_empty(&results);
return wasm_functype_new(&params, &results);
}
static inline own wasm_functype_t* wasm_functype_new_3_0(
own wasm_valtype_t* p1, own wasm_valtype_t* p2, own wasm_valtype_t* p3
) {
wasm_valtype_t* ps[3] = {p1, p2, p3};
wasm_valtype_vec_t params, results;
wasm_valtype_vec_new(&params, 3, ps);
wasm_valtype_vec_new_empty(&results);
return wasm_functype_new(&params, &results);
}
static inline own wasm_functype_t* wasm_functype_new_0_1(
own wasm_valtype_t* r
) {
wasm_valtype_t* rs[1] = {r};
wasm_valtype_vec_t params, results;
wasm_valtype_vec_new_empty(&params);
wasm_valtype_vec_new(&results, 1, rs);
return wasm_functype_new(&params, &results);
}
static inline own wasm_functype_t* wasm_functype_new_1_1(
own wasm_valtype_t* p, own wasm_valtype_t* r
) {
wasm_valtype_t* ps[1] = {p};
wasm_valtype_t* rs[1] = {r};
wasm_valtype_vec_t params, results;
wasm_valtype_vec_new(&params, 1, ps);
wasm_valtype_vec_new(&results, 1, rs);
return wasm_functype_new(&params, &results);
}
static inline own wasm_functype_t* wasm_functype_new_2_1(
own wasm_valtype_t* p1, own wasm_valtype_t* p2, own wasm_valtype_t* r
) {
wasm_valtype_t* ps[2] = {p1, p2};
wasm_valtype_t* rs[1] = {r};
wasm_valtype_vec_t params, results;
wasm_valtype_vec_new(&params, 2, ps);
wasm_valtype_vec_new(&results, 1, rs);
return wasm_functype_new(&params, &results);
}
static inline own wasm_functype_t* wasm_functype_new_3_1(
own wasm_valtype_t* p1, own wasm_valtype_t* p2, own wasm_valtype_t* p3,
own wasm_valtype_t* r
) {
wasm_valtype_t* ps[3] = {p1, p2, p3};
wasm_valtype_t* rs[1] = {r};
wasm_valtype_vec_t params, results;
wasm_valtype_vec_new(&params, 3, ps);
wasm_valtype_vec_new(&results, 1, rs);
return wasm_functype_new(&params, &results);
}
static inline own wasm_functype_t* wasm_functype_new_0_2(
own wasm_valtype_t* r1, own wasm_valtype_t* r2
) {
wasm_valtype_t* rs[2] = {r1, r2};
wasm_valtype_vec_t params, results;
wasm_valtype_vec_new_empty(&params);
wasm_valtype_vec_new(&results, 2, rs);
return wasm_functype_new(&params, &results);
}
static inline own wasm_functype_t* wasm_functype_new_1_2(
own wasm_valtype_t* p, own wasm_valtype_t* r1, own wasm_valtype_t* r2
) {
wasm_valtype_t* ps[1] = {p};
wasm_valtype_t* rs[2] = {r1, r2};
wasm_valtype_vec_t params, results;
wasm_valtype_vec_new(&params, 1, ps);
wasm_valtype_vec_new(&results, 2, rs);
return wasm_functype_new(&params, &results);
}
static inline own wasm_functype_t* wasm_functype_new_2_2(
own wasm_valtype_t* p1, own wasm_valtype_t* p2,
own wasm_valtype_t* r1, own wasm_valtype_t* r2
) {
wasm_valtype_t* ps[2] = {p1, p2};
wasm_valtype_t* rs[2] = {r1, r2};
wasm_valtype_vec_t params, results;
wasm_valtype_vec_new(&params, 2, ps);
wasm_valtype_vec_new(&results, 2, rs);
return wasm_functype_new(&params, &results);
}
static inline own wasm_functype_t* wasm_functype_new_3_2(
own wasm_valtype_t* p1, own wasm_valtype_t* p2, own wasm_valtype_t* p3,
own wasm_valtype_t* r1, own wasm_valtype_t* r2
) {
wasm_valtype_t* ps[3] = {p1, p2, p3};
wasm_valtype_t* rs[2] = {r1, r2};
wasm_valtype_vec_t params, results;
wasm_valtype_vec_new(&params, 3, ps);
wasm_valtype_vec_new(&results, 2, rs);
return wasm_functype_new(&params, &results);
}
// Value construction short-hands
static inline void wasm_val_init_ptr(own wasm_val_t* out, void* p) {
#if UINTPTR_MAX == UINT32_MAX
out->kind = WASM_I32;
out->of.i32 = (intptr_t)p;
#elif UINTPTR_MAX == UINT64_MAX
out->kind = WASM_I64;
out->of.i64 = (intptr_t)p;
#endif
}
static inline void* wasm_val_ptr(const wasm_val_t* val) {
#if UINTPTR_MAX == UINT32_MAX
return (void*)(intptr_t)val->of.i32;
#elif UINTPTR_MAX == UINT64_MAX
return (void*)(intptr_t)val->of.i64;
#endif
}
///////////////////////////////////////////////////////////////////////////////
#undef own
#ifdef __cplusplus
} // extern "C"
#endif
#endif // #ifdef WASM_H

View File

@@ -0,0 +1,746 @@
// WebAssembly C++ API
#ifndef WASM_HH
#define WASM_HH
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <memory>
#include <limits>
#include <string>
#ifndef WASM_API_EXTERN
#ifdef _WIN32
#define WASM_API_EXTERN __declspec(dllimport)
#else
#define WASM_API_EXTERN
#endif
#endif
///////////////////////////////////////////////////////////////////////////////
// Auxiliaries
// Machine types
static_assert(sizeof(float) == sizeof(int32_t), "incompatible float type");
static_assert(sizeof(double) == sizeof(int64_t), "incompatible double type");
static_assert(sizeof(intptr_t) == sizeof(int32_t) ||
sizeof(intptr_t) == sizeof(int64_t), "incompatible pointer type");
using byte_t = char;
using float32_t = float;
using float64_t = double;
namespace wasm {
// Vectors
template<class T>
class vec {
static const size_t invalid_size = SIZE_MAX;
size_t size_;
std::unique_ptr<T[]> data_;
#ifdef WASM_API_DEBUG
WASM_API_EXTERN void make_data();
WASM_API_EXTERN void free_data();
#else
void make_data() {}
void free_data() {}
#endif
vec(size_t size) : vec(size, size ? new(std::nothrow) T[size] : nullptr) {
make_data();
}
vec(size_t size, T* data) : size_(size), data_(data) {
assert(!!size_ == !!data_ || size_ == invalid_size);
}
public:
using elem_type = T;
vec(vec<T>&& that) : vec(that.size_, that.data_.release()) {
that.size_ = invalid_size;
}
~vec() {
free_data();
}
operator bool() const {
return bool(size_ != invalid_size);
}
auto size() const -> size_t {
return size_;
}
auto get() const -> const T* {
return data_.get();
}
auto get() -> T* {
return data_.get();
}
auto release() -> T* {
size_ = invalid_size;
return data_.release();
}
void reset() {
free_data();
size_ = invalid_size;
data_.reset();
}
void reset(vec& that) {
free_data();
size_ = that.size_;
data_.reset(that.data_.release());
that.size_ = invalid_size;
}
auto operator=(vec&& that) -> vec& {
reset(that);
return *this;
}
auto operator[](size_t i) -> T& {
assert(i < size_);
return data_[i];
}
auto operator[](size_t i) const -> const T& {
assert(i < size_);
return data_[i];
}
auto copy() const -> vec {
auto v = vec(size_);
if (v) for (size_t i = 0; i < size_; ++i) v.data_[i] = data_[i];
return v;
}
// TODO: This can't be used for e.g. vec<Val>
auto deep_copy() const -> vec {
auto v = vec(size_);
if (v) for (size_t i = 0; i < size_; ++i) v.data_[i] = data_[i]->copy();
return v;
}
static auto make_uninitialized(size_t size = 0) -> vec {
return vec(size);
}
static auto make(size_t size, T init[]) -> vec {
auto v = vec(size);
if (v) for (size_t i = 0; i < size; ++i) v.data_[i] = std::move(init[i]);
return v;
}
static auto make(std::string s) -> vec<char> {
auto v = vec(s.length() + 1);
if (v) std::strcpy(v.get(), s.data());
return v;
}
// TODO(mvsc): MVSC requires this special case:
static auto make() -> vec {
return vec(0);
}
template<class... Ts>
static auto make(Ts&&... args) -> vec {
T data[] = { std::forward<Ts>(args)... };
return make(sizeof...(Ts), data);
}
static auto adopt(size_t size, T data[]) -> vec {
return vec(size, data);
}
static auto invalid() -> vec {
return vec(invalid_size, nullptr);
}
};
// Ownership
template<class T> using own = std::unique_ptr<T>;
template<class T> using ownvec = vec<own<T>>;
template<class T>
auto make_own(T* x) -> own<T> { return own<T>(x); }
///////////////////////////////////////////////////////////////////////////////
// Runtime Environment
// Configuration
class WASM_API_EXTERN Config {
public:
Config() = delete;
~Config();
void operator delete(void*);
static auto make() -> own<Config>;
// Implementations may provide custom methods for manipulating Configs.
};
// Engine
class WASM_API_EXTERN Engine {
public:
Engine() = delete;
~Engine();
void operator delete(void*);
static auto make(own<Config>&& = Config::make()) -> own<Engine>;
};
// Store
class WASM_API_EXTERN Store {
public:
Store() = delete;
~Store();
void operator delete(void*);
static auto make(Engine*) -> own<Store>;
};
///////////////////////////////////////////////////////////////////////////////
// Type Representations
// Type attributes
enum class Mutability : uint8_t { CONST, VAR };
struct Limits {
uint32_t min;
uint32_t max;
Limits(uint32_t min, uint32_t max = std::numeric_limits<uint32_t>::max()) :
min(min), max(max) {}
};
// Value Types
enum class ValKind : uint8_t {
I32, I64, F32, F64,
ANYREF = 128, FUNCREF,
};
inline bool is_num(ValKind k) { return k < ValKind::ANYREF; }
inline bool is_ref(ValKind k) { return k >= ValKind::ANYREF; }
class WASM_API_EXTERN ValType {
public:
ValType() = delete;
~ValType();
void operator delete(void*);
static auto make(ValKind) -> own<ValType>;
auto copy() const -> own<ValType>;
auto kind() const -> ValKind;
auto is_num() const -> bool { return wasm::is_num(kind()); }
auto is_ref() const -> bool { return wasm::is_ref(kind()); }
};
// External Types
enum class ExternKind : uint8_t {
FUNC, GLOBAL, TABLE, MEMORY
};
class FuncType;
class GlobalType;
class TableType;
class MemoryType;
class WASM_API_EXTERN ExternType {
public:
ExternType() = delete;
~ExternType();
void operator delete(void*);
auto copy() const-> own<ExternType>;
auto kind() const -> ExternKind;
auto func() -> FuncType*;
auto global() -> GlobalType*;
auto table() -> TableType*;
auto memory() -> MemoryType*;
auto func() const -> const FuncType*;
auto global() const -> const GlobalType*;
auto table() const -> const TableType*;
auto memory() const -> const MemoryType*;
};
// Function Types
class WASM_API_EXTERN FuncType : public ExternType {
public:
FuncType() = delete;
~FuncType();
static auto make(
ownvec<ValType>&& params = ownvec<ValType>::make(),
ownvec<ValType>&& results = ownvec<ValType>::make()
) -> own<FuncType>;
auto copy() const -> own<FuncType>;
auto params() const -> const ownvec<ValType>&;
auto results() const -> const ownvec<ValType>&;
};
// Global Types
class WASM_API_EXTERN GlobalType : public ExternType {
public:
GlobalType() = delete;
~GlobalType();
static auto make(own<ValType>&&, Mutability) -> own<GlobalType>;
auto copy() const -> own<GlobalType>;
auto content() const -> const ValType*;
auto mutability() const -> Mutability;
};
// Table Types
class WASM_API_EXTERN TableType : public ExternType {
public:
TableType() = delete;
~TableType();
static auto make(own<ValType>&&, Limits) -> own<TableType>;
auto copy() const -> own<TableType>;
auto element() const -> const ValType*;
auto limits() const -> const Limits&;
};
// Memory Types
class WASM_API_EXTERN MemoryType : public ExternType {
public:
MemoryType() = delete;
~MemoryType();
static auto make(Limits) -> own<MemoryType>;
auto copy() const -> own<MemoryType>;
auto limits() const -> const Limits&;
};
// Import Types
using Name = vec<byte_t>;
class WASM_API_EXTERN ImportType {
public:
ImportType() = delete;
~ImportType();
void operator delete(void*);
static auto make(Name&& module, Name&& name, own<ExternType>&&) ->
own<ImportType>;
auto copy() const -> own<ImportType>;
auto module() const -> const Name&;
auto name() const -> const Name&;
auto type() const -> const ExternType*;
};
// Export Types
class WASM_API_EXTERN ExportType {
public:
ExportType() = delete;
~ExportType();
void operator delete(void*);
static auto make(Name&&, own<ExternType>&&) -> own<ExportType>;
auto copy() const -> own<ExportType>;
auto name() const -> const Name&;
auto type() const -> const ExternType*;
};
///////////////////////////////////////////////////////////////////////////////
// Runtime Objects
// References
class WASM_API_EXTERN Ref {
public:
Ref() = delete;
~Ref();
void operator delete(void*);
auto copy() const -> own<Ref>;
auto same(const Ref*) const -> bool;
auto get_host_info() const -> void*;
void set_host_info(void* info, void (*finalizer)(void*) = nullptr);
};
// Values
class Val {
ValKind kind_;
union impl {
int32_t i32;
int64_t i64;
float32_t f32;
float64_t f64;
Ref* ref;
} impl_;
Val(ValKind kind, impl impl) : kind_(kind), impl_(impl) {}
public:
Val() : kind_(ValKind::ANYREF) { impl_.ref = nullptr; }
Val(int32_t i) : kind_(ValKind::I32) { impl_.i32 = i; }
Val(int64_t i) : kind_(ValKind::I64) { impl_.i64 = i; }
Val(float32_t z) : kind_(ValKind::F32) { impl_.f32 = z; }
Val(float64_t z) : kind_(ValKind::F64) { impl_.f64 = z; }
Val(own<Ref>&& r) : kind_(ValKind::ANYREF) { impl_.ref = r.release(); }
Val(Val&& that) : kind_(that.kind_), impl_(that.impl_) {
if (is_ref()) that.impl_.ref = nullptr;
}
~Val() {
reset();
}
auto is_num() const -> bool { return wasm::is_num(kind_); }
auto is_ref() const -> bool { return wasm::is_ref(kind_); }
static auto i32(int32_t x) -> Val { return Val(x); }
static auto i64(int64_t x) -> Val { return Val(x); }
static auto f32(float32_t x) -> Val { return Val(x); }
static auto f64(float64_t x) -> Val { return Val(x); }
static auto ref(own<Ref>&& x) -> Val { return Val(std::move(x)); }
template<class T> inline static auto make(T x) -> Val;
template<class T> inline static auto make(own<T>&& x) -> Val;
void reset() {
if (is_ref() && impl_.ref) {
delete impl_.ref;
impl_.ref = nullptr;
}
}
void reset(Val& that) {
reset();
kind_ = that.kind_;
impl_ = that.impl_;
if (is_ref()) that.impl_.ref = nullptr;
}
auto operator=(Val&& that) -> Val& {
reset(that);
return *this;
}
auto kind() const -> ValKind { return kind_; }
auto i32() const -> int32_t { assert(kind_ == ValKind::I32); return impl_.i32; }
auto i64() const -> int64_t { assert(kind_ == ValKind::I64); return impl_.i64; }
auto f32() const -> float32_t { assert(kind_ == ValKind::F32); return impl_.f32; }
auto f64() const -> float64_t { assert(kind_ == ValKind::F64); return impl_.f64; }
auto ref() const -> Ref* { assert(is_ref()); return impl_.ref; }
template<class T> inline auto get() const -> T;
auto release_ref() -> own<Ref> {
assert(is_ref());
auto ref = impl_.ref;
impl_.ref = nullptr;
return own<Ref>(ref);
}
auto copy() const -> Val {
if (is_ref() && impl_.ref != nullptr) {
// TODO(mvsc): MVSC cannot handle this:
// impl impl = {.ref = impl_.ref->copy().release()};
impl impl;
impl.ref = impl_.ref->copy().release();
return Val(kind_, impl);
} else {
return Val(kind_, impl_);
}
}
};
template<> inline auto Val::make<int32_t>(int32_t x) -> Val { return Val(x); }
template<> inline auto Val::make<int64_t>(int64_t x) -> Val { return Val(x); }
template<> inline auto Val::make<float32_t>(float32_t x) -> Val { return Val(x); }
template<> inline auto Val::make<float64_t>(float64_t x) -> Val { return Val(x); }
template<> inline auto Val::make<Ref>(own<Ref>&& x) -> Val {
return Val(std::move(x));
}
template<> inline auto Val::make<uint32_t>(uint32_t x) -> Val {
return Val(static_cast<int32_t>(x));
}
template<> inline auto Val::make<uint64_t>(uint64_t x) -> Val {
return Val(static_cast<int64_t>(x));
}
template<> inline auto Val::get<int32_t>() const -> int32_t { return i32(); }
template<> inline auto Val::get<int64_t>() const -> int64_t { return i64(); }
template<> inline auto Val::get<float32_t>() const -> float32_t { return f32(); }
template<> inline auto Val::get<float64_t>() const -> float64_t { return f64(); }
template<> inline auto Val::get<Ref*>() const -> Ref* { return ref(); }
template<> inline auto Val::get<uint32_t>() const -> uint32_t {
return static_cast<uint32_t>(i32());
}
template<> inline auto Val::get<uint64_t>() const -> uint64_t {
return static_cast<uint64_t>(i64());
}
// Traps
using Message = vec<byte_t>; // null terminated
class Instance;
class WASM_API_EXTERN Frame {
public:
Frame() = delete;
~Frame();
void operator delete(void*);
auto copy() const -> own<Frame>;
auto instance() const -> Instance*;
auto func_index() const -> uint32_t;
auto func_offset() const -> size_t;
auto module_offset() const -> size_t;
};
class WASM_API_EXTERN Trap : public Ref {
public:
Trap() = delete;
~Trap();
static auto make(Store*, const Message& msg) -> own<Trap>;
auto copy() const -> own<Trap>;
auto message() const -> Message;
auto origin() const -> own<Frame>; // may be null
auto trace() const -> ownvec<Frame>; // may be empty, origin first
};
// Shared objects
template<class T>
class WASM_API_EXTERN Shared {
public:
Shared() = delete;
~Shared();
void operator delete(void*);
};
// Modules
class WASM_API_EXTERN Module : public Ref {
public:
Module() = delete;
~Module();
static auto validate(Store*, const vec<byte_t>& binary) -> bool;
static auto make(Store*, const vec<byte_t>& binary) -> own<Module>;
auto copy() const -> own<Module>;
auto imports() const -> ownvec<ImportType>;
auto exports() const -> ownvec<ExportType>;
auto share() const -> own<Shared<Module>>;
static auto obtain(Store*, const Shared<Module>*) -> own<Module>;
auto serialize() const -> vec<byte_t>;
static auto deserialize(Store*, const vec<byte_t>&) -> own<Module>;
};
// Foreign Objects
class WASM_API_EXTERN Foreign : public Ref {
public:
Foreign() = delete;
~Foreign();
static auto make(Store*) -> own<Foreign>;
auto copy() const -> own<Foreign>;
};
// Externals
class Func;
class Global;
class Table;
class Memory;
class WASM_API_EXTERN Extern : public Ref {
public:
Extern() = delete;
~Extern();
auto copy() const -> own<Extern>;
auto kind() const -> ExternKind;
auto type() const -> own<ExternType>;
auto func() -> Func*;
auto global() -> Global*;
auto table() -> Table*;
auto memory() -> Memory*;
auto func() const -> const Func*;
auto global() const -> const Global*;
auto table() const -> const Table*;
auto memory() const -> const Memory*;
};
// Function Instances
class WASM_API_EXTERN Func : public Extern {
public:
Func() = delete;
~Func();
using callback = auto (*)(const Val[], Val[]) -> own<Trap>;
using callback_with_env = auto (*)(void*, const Val[], Val[]) -> own<Trap>;
static auto make(Store*, const FuncType*, callback) -> own<Func>;
static auto make(Store*, const FuncType*, callback_with_env,
void*, void (*finalizer)(void*) = nullptr) -> own<Func>;
auto copy() const -> own<Func>;
auto type() const -> own<FuncType>;
auto param_arity() const -> size_t;
auto result_arity() const -> size_t;
auto call(const Val[] = nullptr, Val[] = nullptr) const -> own<Trap>;
};
// Global Instances
class WASM_API_EXTERN Global : public Extern {
public:
Global() = delete;
~Global();
static auto make(Store*, const GlobalType*, const Val&) -> own<Global>;
auto copy() const -> own<Global>;
auto type() const -> own<GlobalType>;
auto get() const -> Val;
void set(const Val&);
};
// Table Instances
class WASM_API_EXTERN Table : public Extern {
public:
Table() = delete;
~Table();
using size_t = uint32_t;
static auto make(
Store*, const TableType*, const Ref* init = nullptr) -> own<Table>;
auto copy() const -> own<Table>;
auto type() const -> own<TableType>;
auto get(size_t index) const -> own<Ref>;
auto set(size_t index, const Ref*) -> bool;
auto size() const -> size_t;
auto grow(size_t delta, const Ref* init = nullptr) -> bool;
};
// Memory Instances
class WASM_API_EXTERN Memory : public Extern {
public:
Memory() = delete;
~Memory();
static auto make(Store*, const MemoryType*) -> own<Memory>;
auto copy() const -> own<Memory>;
using pages_t = uint32_t;
static const size_t page_size = 0x10000;
auto type() const -> own<MemoryType>;
auto data() const -> byte_t*;
auto data_size() const -> size_t;
auto size() const -> pages_t;
auto grow(pages_t delta) -> bool;
};
// Module Instances
class WASM_API_EXTERN Instance : public Ref {
public:
Instance() = delete;
~Instance();
static auto make(
Store*, const Module*, const Extern* const[], own<Trap>* = nullptr
) -> own<Instance>;
auto copy() const -> own<Instance>;
auto exports() const -> ownvec<Extern>;
};
///////////////////////////////////////////////////////////////////////////////
} // namespace wasm
#endif // #ifdef WASM_HH