summaryrefslogtreecommitdiff
path: root/wasm2c
diff options
context:
space:
mode:
Diffstat (limited to 'wasm2c')
-rw-r--r--wasm2c/.gitignore4
-rw-r--r--wasm2c/README.md62
-rw-r--r--wasm2c/examples/callback/Makefile19
-rw-r--r--wasm2c/examples/callback/callback.wat19
-rw-r--r--wasm2c/examples/callback/main.c39
-rw-r--r--wasm2c/examples/fac/fac.c59
-rw-r--r--wasm2c/examples/fac/fac.h2
-rw-r--r--wasm2c/examples/fac/main.c4
-rw-r--r--wasm2c/examples/rot13/main.c3
-rw-r--r--wasm2c/wasm-rt-impl.c72
-rw-r--r--wasm2c/wasm-rt.h36
11 files changed, 157 insertions, 162 deletions
diff --git a/wasm2c/.gitignore b/wasm2c/.gitignore
index 5d665f06..094559b6 100644
--- a/wasm2c/.gitignore
+++ b/wasm2c/.gitignore
@@ -5,3 +5,7 @@ examples/rot13/rot13
examples/rot13/rot13.c
examples/rot13/rot13.h
examples/rot13/rot13.wasm
+examples/callback/callback
+examples/callback/callback.c
+examples/callback/callback.h
+examples/callback/callback.wasm
diff --git a/wasm2c/README.md b/wasm2c/README.md
index b4fbe5fa..80a86952 100644
--- a/wasm2c/README.md
+++ b/wasm2c/README.md
@@ -49,8 +49,8 @@ files.
To actually use our `fac` module, we'll use create a new file, `main.c`, that
include `fac.h`, initializes the module, and calls `fac`.
-`wasm2c` generates a few C symbols based on the `fac.wasm` module: `Z_fac_init_module`, `Z_fac_instantiate`
-and `Z_facZ_fac`. The first initializes the module, the second constructs an instance of the module, and the third is the
+`wasm2c` generates a few C symbols based on the `fac.wasm` module: `Z_fac_instantiate`
+and `Z_facZ_fac`. The first constructs an instance of the module, and the second is the
exported `fac` function.
All the exported symbols shared a common prefix (`Z_fac`) which, by default, is
@@ -80,10 +80,6 @@ int main(int argc, char** argv) {
/* Initialize the Wasm runtime. */
wasm_rt_init();
- /* Initialize the `fac` module (this registers the module's function types in
- * a global data structure) */
- Z_fac_init_module();
-
/* Declare an instance of the `fac` module. */
Z_fac_instance_t instance;
@@ -170,7 +166,6 @@ typedef struct Z_fac_instance_t {
char dummy_member;
} Z_fac_instance_t;
-void Z_fac_init_module(void);
void Z_fac_instantiate(Z_fac_instance_t*);
void Z_fac_free(Z_fac_instance_t*);
@@ -210,7 +205,7 @@ typedef enum {
```
Next is the `wasm_rt_type_t` enum, which is used for specifying function
-signatures. The four WebAssembly value types are included:
+signatures. Six WebAssembly value types are included:
```c
typedef enum {
@@ -218,28 +213,35 @@ typedef enum {
WASM_RT_I64,
WASM_RT_F32,
WASM_RT_F64,
+ WASM_RT_FUNCREF,
+ WASM_RT_EXTERNREF,
} wasm_rt_type_t;
-```
-Next is `wasm_rt_funcref_t`, the function signature for a generic function
+Next is `wasm_rt_function_ptr_t`, the function signature for a generic function
callback. Since a WebAssembly table can contain functions of any given
signature, it is necessary to convert them to a canonical form:
```c
-typedef void (*wasm_rt_funcref_t)(void);
+typedef void (*wasm_rt_function_ptr_t)(void);
```
-Next are the definitions for a table element. `func_type` is a function index
-as returned by `wasm_rt_register_func_type` described below. `module_instance`
-is the pointer to the module instance that should be passed in when the func is
+Next is the definition for a function reference (in WebAssembly 1.0,
+this was the type of all table elements, but funcrefs can now also be
+used as ordinary values, and tables can alternately be declared as
+type externref). In this structure, `wasm_rt_func_type_t` is an opaque
+256-bit ID that can be looked up via the `Z_[modname]_get_func_type`
+function. (A demonstration of this can be found in the `callback`
+example.) `module_instance` is the pointer to the function's
+originating module instance, which will be passed in when the func is
called.
```c
typedef struct {
- uint32_t func_type;
- wasm_rt_funcref_t func;
+ wasm_rt_func_type_t func_type;
+ wasm_rt_function_ptr_t func;
void* module_instance;
-} wasm_rt_elem_t;
+} wasm_rt_funcref_t;
+
```
Next is the definition of a memory instance. The `data` field is a pointer to
@@ -263,10 +265,10 @@ limit.
```c
typedef struct {
- wasm_rt_elem_t* data;
+ wasm_rt_funcref_t* data;
uint32_t max_size;
uint32_t size;
-} wasm_rt_table_t;
+} wasm_rt_funcref_table_t;
```
## Symbols that must be defined by the embedder
@@ -283,7 +285,6 @@ bool wasm_rt_is_initialized(void);
void wasm_rt_free(void);
void wasm_rt_trap(wasm_rt_trap_t) __attribute__((noreturn));
const char* wasm_rt_strerror(wasm_rt_trap_t trap);
-uint32_t wasm_rt_register_func_type(uint32_t params, uint32_t results, ...);
void wasm_rt_allocate_memory(wasm_rt_memory_t*, uint32_t initial_pages, uint32_t max_pages, bool is64);
uint32_t wasm_rt_grow_memory(wasm_rt_memory_t*, uint32_t pages);
void wasm_rt_free_memory(wasm_rt_memory_t*);
@@ -310,13 +311,6 @@ wasm2c_custom_trap_handler`. It is recommended that you add this macro
definition via a compiler flag
(`-DWASM_RT_MEMCHECK_SIGNAL_HANDLER=wasm2c_custom_trap_handler` on clang/gcc).
-`wasm_rt_register_func_type` is a function that registers a function type. It
-is a variadic function where the first two arguments give the number of
-parameters and results, and the following arguments are the types. For example,
-the function `func (param i32 f32) (result f64)` would register the function
-type as
-`wasm_rt_register_func_type(2, 1, WASM_RT_I32, WASM_RT_F32, WASM_RT_F64)`.
-
`wasm_rt_allocate_memory` initializes a memory instance, and allocates at least
enough space for the given number of initial pages. The memory must be cleared
to zero. The `is64` parameter indicates if the memory is indexed with
@@ -386,21 +380,26 @@ must be of type `WASM_RT_UNWIND_TARGET`.
Finally, `fac.h` defines the module instance type (which in the case
of `fac` is essentially empty), and the exported symbols provided by
the module. In our example, the only function we exported was
-`fac`. `Z_fac_init_module()` initializes the whole module and must be
-called before any instance of the module is used.
+`fac`.
`Z_fac_instantiate(Z_fac_instance_t*)` creates an instance of
the module and must be called before the module instance can be
used. `Z_fac_free(Z_fac_instance_t*)` frees the instance.
+`Z_fac_get_func_type` can be used to look up a function type ID
+at runtime. It is a variadic function where the first two arguments
+give the number of parameters and results, and the following arguments
+are the types from the wasm_rt_type_t enum described above. The
+`callback` example demonstrates using this to pass a host function to
+a WebAssembly module dynamically at runtime.
```c
typedef struct Z_fac_instance_t {
char dummy_member;
} Z_fac_instance_t;
-void Z_fac_init_module(void);
void Z_fac_instantiate(Z_fac_instance_t*);
void Z_fac_free(Z_fac_instance_t*);
+wasm_rt_func_type_t Z_fac_get_func_type(uint32_t param_count, uint32_t result_count, ...);
/* export: 'fac' */
u32 Z_facZ_fac(Z_fac_instance_t*, u32);
@@ -578,9 +577,6 @@ int main(int argc, char** argv) {
/* Initialize the Wasm runtime. */
wasm_rt_init();
- /* Initialize the rot13 module. */
- Z_rot13_init_module();
-
/* Declare two instances of the `rot13` module. */
Z_rot13_instance_t rot13_instance_1;
Z_rot13_instance_t rot13_instance_2;
diff --git a/wasm2c/examples/callback/Makefile b/wasm2c/examples/callback/Makefile
new file mode 100644
index 00000000..c226ff31
--- /dev/null
+++ b/wasm2c/examples/callback/Makefile
@@ -0,0 +1,19 @@
+# Use implicit rules for compiling C files.
+CFLAGS=-I../..
+
+all: callback
+
+callback: main.o callback.o ../../wasm-rt-impl.o
+
+clean:
+ rm -rf callback callback.wasm callback.c callback.h *.o
+
+callback: main.o callback.o ../../wasm-rt-impl.o -lm
+
+callback.wasm: callback.wat ../../../bin/wat2wasm
+ ../../../bin/wat2wasm --debug-names $< -o $@
+
+callback.c: callback.wasm ../../../bin/wasm2c
+ ../../../bin/wasm2c $< -o $@
+
+.PHONY: all clean
diff --git a/wasm2c/examples/callback/callback.wat b/wasm2c/examples/callback/callback.wat
new file mode 100644
index 00000000..6a8ab233
--- /dev/null
+++ b/wasm2c/examples/callback/callback.wat
@@ -0,0 +1,19 @@
+;; Module demonstrating use of a host-installed callback function.
+
+;; The type of the callback function. The type ID can be looked up outside the module by calling
+;; Z_[modname]_get_func_type(1, 0, WASM_RT_I32) (indicating 1 param, 0 results, param type is i32).
+(type $print_type (func (param i32)))
+
+;; An indirect function table to hold the callback function
+(table $table 1 funcref)
+
+;; A memory holding the string to be printed
+(memory (export "memory") (data "Hello, world.\00"))
+
+;; Allow the host to set the callback function
+(func (export "set_print_function") (param funcref)
+ (table.set $table (i32.const 0) (local.get 0)))
+
+;; Call the callback function with the location of "Hello, world."
+(func (export "say_hello")
+ (call_indirect (type $print_type) (i32.const 0) (i32.const 0)))
diff --git a/wasm2c/examples/callback/main.c b/wasm2c/examples/callback/main.c
new file mode 100644
index 00000000..b0b37d46
--- /dev/null
+++ b/wasm2c/examples/callback/main.c
@@ -0,0 +1,39 @@
+#include <stdio.h>
+
+#include "callback.h"
+
+/*
+ * The callback function. Prints the null-terminated string at the given
+ * location in the instance's exported memory.
+ */
+void print(Z_callback_instance_t* instance, uint32_t ptr) {
+ puts(Z_callbackZ_memory(instance)->data + ptr);
+}
+
+int main(int argc, char** argv) {
+ /* Initialize the Wasm runtime. */
+ wasm_rt_init();
+
+ /* Instantiate the callback module. */
+ Z_callback_instance_t inst;
+ Z_callback_instantiate(&inst);
+
+ /*
+ * Call the module's "set_print_function" function, which takes a funcref to
+ * the callback. A funcref has three members: the function type (which can be
+ * looked up with "Z_callback_get_func_type"), a pointer to the function, and
+ * a module instance pointer that will be passed to the function when called.
+ */
+ wasm_rt_func_type_t fn_type = Z_callback_get_func_type(1, 0, WASM_RT_I32);
+ wasm_rt_funcref_t fn_ref = {fn_type, (wasm_rt_function_ptr_t)print, &inst};
+ Z_callbackZ_set_print_function(&inst, fn_ref);
+
+ /* "say_hello" uses the previously installed callback. */
+ Z_callbackZ_say_hello(&inst);
+
+ /* Free the module instance and the Wasm runtime state. */
+ Z_callback_free(&inst);
+ wasm_rt_free();
+
+ return 0;
+}
diff --git a/wasm2c/examples/fac/fac.c b/wasm2c/examples/fac/fac.c
index fd2fd3b9..bdc9e63f 100644
--- a/wasm2c/examples/fac/fac.c
+++ b/wasm2c/examples/fac/fac.c
@@ -1,6 +1,7 @@
/* Automatically generated by wasm2c */
#include <assert.h>
#include <math.h>
+#include <stdarg.h>
#include <stddef.h>
#include <string.h>
#if defined(_MSC_VER)
@@ -29,10 +30,15 @@
#define UNREACHABLE TRAP(UNREACHABLE)
-#define CALL_INDIRECT(table, t, ft, x, ...) \
- (LIKELY((x) < table.size && table.data[x].func && \
- table.data[x].func_type == func_types[ft]) || \
- TRAP(CALL_INDIRECT), \
+static inline bool func_types_eq(const wasm_rt_func_type_t a,
+ const wasm_rt_func_type_t b) {
+ return (a == b) || LIKELY(a && b && !memcmp(a, b, 32));
+}
+
+#define CALL_INDIRECT(table, t, ft, x, ...) \
+ (LIKELY((x) < table.size && table.data[x].func && \
+ func_types_eq(ft, table.data[x].func_type)) || \
+ TRAP(CALL_INDIRECT), \
((t)table.data[x].func)(__VA_ARGS__))
#ifdef SUPPORT_MEMORY64
@@ -494,7 +500,7 @@ static inline void memory_init(wasm_rt_memory_t* dest,
}
typedef struct {
- uint32_t func_type_index;
+ wasm_rt_func_type_t type;
wasm_rt_function_ptr_t func;
size_t module_offset;
} wasm_elem_segment_expr_t;
@@ -505,17 +511,16 @@ static inline void funcref_table_init(wasm_rt_funcref_table_t* dest,
u32 dest_addr,
u32 src_addr,
u32 n,
- void* module_instance,
- const u32* func_types) {
+ void* module_instance) {
if (UNLIKELY(src_addr + (uint64_t)n > src_size))
TRAP(OOB);
if (UNLIKELY(dest_addr + (uint64_t)n > dest->size))
TRAP(OOB);
for (u32 i = 0; i < n; i++) {
const wasm_elem_segment_expr_t* src_expr = &src[src_addr + i];
- dest->data[dest_addr + i] = (wasm_rt_funcref_t){
- func_types[src_expr->func_type_index], src_expr->func,
- (char*)module_instance + src_expr->module_offset};
+ dest->data[dest_addr + i] =
+ (wasm_rt_funcref_t){src_expr->type, src_expr->func,
+ (char*)module_instance + src_expr->module_offset};
}
}
@@ -586,13 +591,13 @@ DEFINE_TABLE_SET(externref)
DEFINE_TABLE_FILL(funcref)
DEFINE_TABLE_FILL(externref)
-static bool s_module_initialized = false;
-
-static u32 func_types[1];
+#if defined(__GNUC__) || defined(__clang__)
+#define FUNC_TYPE_T(x) static const char* const x
+#else
+#define FUNC_TYPE_T(x) static const char x[]
+#endif
-static void init_func_types(void) {
- func_types[0] = wasm_rt_register_func_type(1, 1, WASM_RT_I32, WASM_RT_I32);
-}
+FUNC_TYPE_T(w2c_t0) = "\x07\x80\x96\x7a\x42\xf7\x3e\xe6\x70\x5c\x2f\xac\x83\xf5\x67\xd2\xa2\xa0\x69\x41\x5f\xf8\xe7\x96\x7f\x23\xab\x00\x03\x5f\x4a\x3c";
static u32 w2c_fac(Z_fac_instance_t*, u32);
@@ -621,16 +626,24 @@ u32 Z_facZ_fac(Z_fac_instance_t* instance, u32 w2c_p0) {
return w2c_fac(instance, w2c_p0);
}
-void Z_fac_init_module(void) {
- assert(wasm_rt_is_initialized());
- s_module_initialized = true;
- init_func_types();
-}
-
void Z_fac_instantiate(Z_fac_instance_t* instance) {
assert(wasm_rt_is_initialized());
- assert(s_module_initialized);
}
void Z_fac_free(Z_fac_instance_t* instance) {
}
+
+wasm_rt_func_type_t Z_fac_get_func_type(uint32_t param_count, uint32_t result_count, ...) {
+ va_list args;
+
+ if (param_count == 1 && result_count == 1) {
+ va_start(args, result_count);
+ if (true && va_arg(args, wasm_rt_type_t) == WASM_RT_I32 && va_arg(args, wasm_rt_type_t) == WASM_RT_I32) {
+ va_end(args);
+ return w2c_t0;
+ }
+ va_end(args);
+ }
+
+ return NULL;
+}
diff --git a/wasm2c/examples/fac/fac.h b/wasm2c/examples/fac/fac.h
index 6e36ada2..7700bc42 100644
--- a/wasm2c/examples/fac/fac.h
+++ b/wasm2c/examples/fac/fac.h
@@ -29,9 +29,9 @@ typedef struct Z_fac_instance_t {
char dummy_member;
} Z_fac_instance_t;
-void Z_fac_init_module(void);
void Z_fac_instantiate(Z_fac_instance_t*);
void Z_fac_free(Z_fac_instance_t*);
+wasm_rt_func_type_t Z_fac_get_func_type(uint32_t param_count, uint32_t result_count, ...);
/* export: 'fac' */
u32 Z_facZ_fac(Z_fac_instance_t*, u32);
diff --git a/wasm2c/examples/fac/main.c b/wasm2c/examples/fac/main.c
index 30bf5d0a..37593f6e 100644
--- a/wasm2c/examples/fac/main.c
+++ b/wasm2c/examples/fac/main.c
@@ -17,10 +17,6 @@ int main(int argc, char** argv) {
/* Initialize the Wasm runtime. */
wasm_rt_init();
- /* Initialize the `fac` module (this registers the module's function types in
- * a global data structure) */
- Z_fac_init_module();
-
/* Declare an instance of the `fac` module. */
Z_fac_instance_t instance;
diff --git a/wasm2c/examples/rot13/main.c b/wasm2c/examples/rot13/main.c
index 7348d005..d6517f39 100644
--- a/wasm2c/examples/rot13/main.c
+++ b/wasm2c/examples/rot13/main.c
@@ -53,9 +53,6 @@ int main(int argc, char** argv) {
/* Initialize the Wasm runtime. */
wasm_rt_init();
- /* Initialize the rot13 module. */
- Z_rot13_init_module();
-
/* Declare an instance of the `rot13` module. */
Z_rot13_instance_t rot13_instance;
diff --git a/wasm2c/wasm-rt-impl.c b/wasm2c/wasm-rt-impl.c
index dbd7ce41..0430e5f3 100644
--- a/wasm2c/wasm-rt-impl.c
+++ b/wasm2c/wasm-rt-impl.c
@@ -45,13 +45,6 @@
#define PAGE_SIZE 65536
#define MAX_EXCEPTION_SIZE PAGE_SIZE
-typedef struct FuncType {
- wasm_rt_type_t* params;
- wasm_rt_type_t* results;
- uint32_t param_count;
- uint32_t result_count;
-} FuncType;
-
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER && !WASM_RT_SKIP_SIGNAL_RECOVERY
static bool g_signal_handler_installed = false;
#ifdef _WIN32
@@ -66,9 +59,6 @@ WASM_RT_THREAD_LOCAL uint32_t wasm_rt_call_stack_depth;
WASM_RT_THREAD_LOCAL uint32_t wasm_rt_saved_call_stack_depth;
#endif
-static FuncType* g_func_types;
-static uint32_t g_func_type_count;
-
WASM_RT_THREAD_LOCAL wasm_rt_jmp_buf g_wasm_rt_jmp_buf;
static WASM_RT_THREAD_LOCAL wasm_rt_tag_t g_active_exception_tag;
@@ -91,59 +81,6 @@ void wasm_rt_trap(wasm_rt_trap_t code) {
#endif
}
-static bool func_types_are_equal(FuncType* a, FuncType* b) {
- if (a->param_count != b->param_count || a->result_count != b->result_count)
- return 0;
- uint32_t i;
- for (i = 0; i < a->param_count; ++i)
- if (a->params[i] != b->params[i])
- return 0;
- for (i = 0; i < a->result_count; ++i)
- if (a->results[i] != b->results[i])
- return 0;
- return 1;
-}
-
-uint32_t wasm_rt_register_func_type(uint32_t param_count,
- uint32_t result_count,
- ...) {
- size_t param_size = param_count * sizeof(wasm_rt_type_t);
- size_t result_size = result_count * sizeof(wasm_rt_type_t);
- FuncType func_type;
- func_type.param_count = param_count;
- func_type.params = alloca(param_size);
- func_type.result_count = result_count;
- func_type.results = alloca(result_size);
-
- va_list args;
- va_start(args, result_count);
-
- uint32_t i;
- for (i = 0; i < param_count; ++i)
- func_type.params[i] = va_arg(args, wasm_rt_type_t);
- for (i = 0; i < result_count; ++i)
- func_type.results[i] = va_arg(args, wasm_rt_type_t);
- va_end(args);
-
- for (i = 0; i < g_func_type_count; ++i)
- if (func_types_are_equal(&g_func_types[i], &func_type))
- return i + 1;
-
- // This is a new/unseed type. Copy our stack allocated params/results into
- // permanent heap allocated space.
- wasm_rt_type_t* params = malloc(param_size);
- wasm_rt_type_t* results = malloc(result_size);
- memcpy(params, func_type.params, param_size);
- memcpy(results, func_type.results, result_size);
- func_type.params = params;
- func_type.results = results;
-
- uint32_t idx = g_func_type_count++;
- g_func_types = realloc(g_func_types, g_func_type_count * sizeof(FuncType));
- g_func_types[idx] = func_type;
- return idx + 1;
-}
-
void wasm_rt_load_exception(const wasm_rt_tag_t tag,
uint32_t size,
const void* values) {
@@ -346,15 +283,6 @@ bool wasm_rt_is_initialized(void) {
}
void wasm_rt_free(void) {
- for (uint32_t i = 0; i < g_func_type_count; ++i) {
- free(g_func_types[i].params);
- free(g_func_types[i].results);
- }
-
- g_func_type_count = 0;
- free(g_func_types);
- g_func_types = NULL;
-
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER && !WASM_RT_SKIP_SIGNAL_RECOVERY
os_cleanup_signal_handler();
#endif
diff --git a/wasm2c/wasm-rt.h b/wasm2c/wasm-rt.h
index 64e6f972..871fb8ce 100644
--- a/wasm2c/wasm-rt.h
+++ b/wasm2c/wasm-rt.h
@@ -179,11 +179,17 @@ typedef enum {
*/
typedef void (*wasm_rt_function_ptr_t)(void);
+/**
+ * The type of a function (an arbitrary number of param and result types).
+ * This is represented as an opaque 256-bit ID.
+ */
+typedef const char* wasm_rt_func_type_t;
+
/** A function instance (the runtime representation of a function).
* These can be stored in tables of type funcref, or used as values. */
typedef struct {
- /** The index as returned from `wasm_rt_register_func_type`. */
- uint32_t func_type;
+ /** The function's type. */
+ wasm_rt_func_type_t func_type;
/** The function. The embedder must know the actual C signature of the
* function and cast to it before calling. */
wasm_rt_function_ptr_t func;
@@ -194,7 +200,7 @@ typedef struct {
} wasm_rt_funcref_t;
/** Default (null) value of a funcref */
-static const wasm_rt_funcref_t wasm_rt_funcref_null_value = {0, NULL, NULL};
+static const wasm_rt_funcref_t wasm_rt_funcref_null_value = {NULL, NULL, NULL};
/** The type of an external reference (opaque to WebAssembly). */
typedef void* wasm_rt_externref_t;
@@ -260,29 +266,7 @@ WASM_RT_NO_RETURN void wasm_rt_trap(wasm_rt_trap_t);
const char* wasm_rt_strerror(wasm_rt_trap_t trap);
/**
- * Register a function type with the given signature. The returned function
- * index is guaranteed to be the same for all calls with the same signature.
- * The following varargs must all be of type `wasm_rt_type_t`, first the
- * params` and then the `results`.
- *
- * ```
- * // Register (func (param i32 f32) (result i64)).
- * wasm_rt_register_func_type(2, 1, WASM_RT_I32, WASM_RT_F32, WASM_RT_I64);
- * => returns 1
- *
- * // Register (func (result i64)).
- * wasm_rt_register_func_type(0, 1, WASM_RT_I32);
- * => returns 2
- *
- * // Register (func (param i32 f32) (result i64)) again.
- * wasm_rt_register_func_type(2, 1, WASM_RT_I32, WASM_RT_F32, WASM_RT_I64);
- * => returns 1
- * ```
- */
-uint32_t wasm_rt_register_func_type(uint32_t params, uint32_t results, ...);
-
-/**
- * An tag is represented as an arbitrary pointer.
+ * A tag is represented as an arbitrary pointer.
*/
typedef const void* wasm_rt_tag_t;