From 5bc8c0a21ba4905a8794cb7786217a43d3b1b3f4 Mon Sep 17 00:00:00 2001 From: jubianchi Date: Mon, 23 Nov 2020 12:13:07 +0100 Subject: [PATCH] chore: Add C examples --- lib/c-api/examples/.gitignore | 1 + lib/c-api/examples/Makefile | 27 ++++ lib/c-api/examples/exports-function.c | 83 ++++++++++++ lib/c-api/examples/exports-global.c | 116 ++++++++++++++++ lib/c-api/examples/imports-exports.c | 133 +++++++++++++++++++ lib/c-api/examples/instance.c | 81 +++++++++++ lib/c-api/examples/memory.c | 108 +++++++++++++++ lib/c-api/src/wasm_c_api/externals/global.rs | 74 +++++++++++ 8 files changed, 623 insertions(+) create mode 100644 lib/c-api/examples/.gitignore create mode 100644 lib/c-api/examples/Makefile create mode 100644 lib/c-api/examples/exports-function.c create mode 100644 lib/c-api/examples/exports-global.c create mode 100644 lib/c-api/examples/imports-exports.c create mode 100644 lib/c-api/examples/instance.c create mode 100644 lib/c-api/examples/memory.c diff --git a/lib/c-api/examples/.gitignore b/lib/c-api/examples/.gitignore new file mode 100644 index 00000000000..5761abcfdf0 --- /dev/null +++ b/lib/c-api/examples/.gitignore @@ -0,0 +1 @@ +*.o diff --git a/lib/c-api/examples/Makefile b/lib/c-api/examples/Makefile new file mode 100644 index 00000000000..407450bb225 --- /dev/null +++ b/lib/c-api/examples/Makefile @@ -0,0 +1,27 @@ +CFLAGS = -g -I$(shell $(WASMER_C_API)/bin/wasmer config --includedir) +LDFLAGS = -Wl,-rpath,$(shell $(WASMER_C_API)/bin/wasmer config --libdir) +LDLIBS = $(shell $(WASMER_C_API)/bin/wasmer config --libs) + +.SILENT: instance instance.o +instance: instance.o + +.SILENT: imports-exports imports-exports.o +imports-exports: imports-exports.o + +.SILENT: exports-function exports-function.o +exports-function: exports-function.o + +.SILENT: exports-global exports-global.o +exports-global: exports-global.o + +.SILENT: memory memory.o +memory: memory.o + +.SILENT: clean +.PHONY: clean +clean: + rm -f \ + instance instance.o \ + imports-exports imports-exports.o \ + exports-function exports-function.o \ + memory memory.o diff --git a/lib/c-api/examples/exports-function.c b/lib/c-api/examples/exports-function.c new file mode 100644 index 00000000000..b2fb4019772 --- /dev/null +++ b/lib/c-api/examples/exports-function.c @@ -0,0 +1,83 @@ +#include +#include "wasmer_wasm.h" + +int main(int argc, const char* argv[]) { + const char *wat_string = + "(module\n" + " (type $sum_t (func (param i32 i32) (result i32)))\n" + " (func $sum_f (type $sum_t) (param $x i32) (param $y i32) (result i32)\n" + " local.get $x\n" + " local.get $y\n" + " i32.add)\n" + " (export \"sum\" (func $sum_f)))"; + + wasm_byte_vec_t wat; + wasm_byte_vec_new(&wat, strlen(wat_string), wat_string); + wasm_byte_vec_t* wasm_bytes = wat2wasm(&wat); + + printf("Creating the store...\n"); + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + + printf("Compiling module...\n"); + wasm_module_t* module = wasm_module_new(store, wasm_bytes); + + if (!module) { + printf("> Error compiling module!\n"); + + return 1; + } + + wasm_byte_vec_delete(wasm_bytes); + + printf("Creating imports...\n"); + wasm_extern_vec_t import_object = WASM_EMPTY_VEC; + + printf("Instantiating module...\n"); + wasm_instance_t* instance = wasm_instance_new(store, module, &import_object, NULL); + + if (!instance) { + printf("> Error instantiating module!\n"); + + return 1; + } + + printf("Retrieving exports...\n"); + wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + + if (exports.size == 0) { + printf("> Error accessing exports!\n"); + + return 1; + } + + printf("Retrieving the `sum` function...\n"); + wasm_func_t* sum_func = wasm_extern_as_func(exports.data[0]); + + if (sum_func == NULL) { + printf("> Failed to get the `sum` function!\n"); + + return 1; + } + + printf("Calling `sum` function...\n"); + wasm_val_t args_val[2] = { WASM_I32_VAL(3), WASM_I32_VAL(4) }; + wasm_val_t results_val[1] = { WASM_INIT_VAL }; + wasm_val_vec_t args = WASM_ARRAY_VEC(args_val); + wasm_val_vec_t results = WASM_ARRAY_VEC(results_val); + + if (wasm_func_call(sum_func, &args, &results)) { + printf("> Error calling the `sum` function!\n"); + + return 1; + } + + printf("Results of `sum`: %d\n", results_val[0].of.i32); + + wasm_func_delete(sum_func); + wasm_module_delete(module); + wasm_instance_delete(instance); + wasm_store_delete(store); + wasm_engine_delete(engine); +} diff --git a/lib/c-api/examples/exports-global.c b/lib/c-api/examples/exports-global.c new file mode 100644 index 00000000000..672ec62ea4e --- /dev/null +++ b/lib/c-api/examples/exports-global.c @@ -0,0 +1,116 @@ +#include +#include "wasmer_wasm.h" + +int main(int argc, const char* argv[]) { + const char *wat_string = + "(module\n" + " (global $one (export \"one\") f32 (f32.const 1))\n" + " (global $some (export \"some\") (mut f32) (f32.const 0))\n" + " (func (export \"get_one\") (result f32) (global.get $one))\n" + " (func (export \"get_some\") (result f32) (global.get $some))\n" + " (func (export \"set_some\") (param f32) (global.set $some (local.get 0))))"; + + wasm_byte_vec_t wat; + wasm_byte_vec_new(&wat, strlen(wat_string), wat_string); + wasm_byte_vec_t* wasm_bytes = wat2wasm(&wat); + + printf("Creating the store...\n"); + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + + printf("Compiling module...\n"); + wasm_module_t* module = wasm_module_new(store, wasm_bytes); + + if (!module) { + printf("> Error compiling module!\n"); + + return 1; + } + + wasm_byte_vec_delete(wasm_bytes); + + printf("Creating imports...\n"); + wasm_extern_vec_t import_object = WASM_EMPTY_VEC; + + printf("Instantiating module...\n"); + wasm_instance_t* instance = wasm_instance_new(store, module, &import_object, NULL); + + if (!instance) { + printf("> Error instantiating module!\n"); + + return 1; + } + + printf("Retrieving exports...\n"); + wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + + if (exports.size == 0) { + printf("> Error accessing exports!\n"); + + return 1; + } + + wasm_global_t* one = wasm_extern_as_global(exports.data[0]); + + if (one == NULL) { + printf("> Failed to get the `one` global!\n"); + + return 1; + } + + wasm_global_t* some = wasm_extern_as_global(exports.data[1]); + + if (some == NULL) { + printf("> Failed to get the `some` global!\n"); + + return 1; + } + + printf("Getting globals types information...\n"); + wasm_globaltype_t* one_type = wasm_global_type(one); + wasm_globaltype_t* some_type = wasm_global_type(some); + + wasm_mutability_t one_mutability = wasm_globaltype_mutability(one_type); + const wasm_valtype_t* one_content = wasm_globaltype_content(one_type); + wasm_valkind_t one_kind = wasm_valtype_kind(one_content); + + wasm_mutability_t some_mutability = wasm_globaltype_mutability(some_type); + const wasm_valtype_t* some_content = wasm_globaltype_content(some_type); + wasm_valkind_t some_kind = wasm_valtype_kind(some_content); + + printf("`one` type: %s %hhu\n", one_mutability == WASM_CONST ? "const" : "", one_kind); + printf("`some` type: %s %hhu\n", some_mutability == WASM_CONST ? "const" : "", some_kind); + + printf("Getting global values..."); + wasm_val_t one_value; + wasm_global_get(one, &one_value); + printf("`one` value: %.1f\n", one_value.of.f32); + + wasm_val_t some_value; + wasm_global_get(some, &some_value); + printf("`some` value: %.1f\n", some_value.of.f32); + + printf("Setting global values...\n"); + wasm_val_t one_set_value = WASM_F32_VAL(42); + wasm_global_set(one, &one_set_value); + + int error_length = wasmer_last_error_length(); + if (error_length > 0) { + char *error_message = malloc(error_length); + wasmer_last_error_message(error_message, error_length); + + printf("Attempted to set an immutable global: `%s`\n", error_message); + } + + wasm_val_t some_set_value = WASM_F32_VAL(21); + wasm_global_set(some, &some_set_value); + printf("`some` value: %.1f\n", some_value.of.f32); + + wasm_global_delete(some); + wasm_global_delete(one); + wasm_module_delete(module); + wasm_instance_delete(instance); + wasm_store_delete(store); + wasm_engine_delete(engine); +} diff --git a/lib/c-api/examples/imports-exports.c b/lib/c-api/examples/imports-exports.c new file mode 100644 index 00000000000..256ba03aa6a --- /dev/null +++ b/lib/c-api/examples/imports-exports.c @@ -0,0 +1,133 @@ +#include +#include "wasmer_wasm.h" + +wasm_trap_t* host_func_callback(const wasm_val_vec_t* args, wasm_val_vec_t* results) { + printf("Calling back...\n> "); + + wasm_val_t val = WASM_I32_VAL(42); + wasm_val_copy(&results->data[0], &val); + + wasm_val_delete(&val); + + return NULL; +} + +int main(int argc, const char* argv[]) { + const char *wat_string = + "(module\n" + " (func $host_function (import \"\" \"host_function\") (result i32))\n" + " (global $host_global (import \"env\" \"host_global\") i32)\n" + " (func $function (export \"guest_function\") (result i32) (global.get $global))\n" + " (global $global (export \"guest_global\") i32 (i32.const 42))\n" + " (table $table (export \"guest_table\") 1 1 funcref)\n" + " (memory $memory (export \"guest_memory\") 1))"; + + wasm_byte_vec_t wat; + wasm_byte_vec_new(&wat, strlen(wat_string), wat_string); + wasm_byte_vec_t* wasm_bytes = wat2wasm(&wat); + + printf("Creating the store...\n"); + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + + printf("Compiling module...\n"); + wasm_module_t* module = wasm_module_new(store, wasm_bytes); + + if (!module) { + printf("> Error compiling module!\n"); + + return 1; + } + + wasm_byte_vec_delete(wasm_bytes); + + printf("Creating the imported function...\n"); + wasm_functype_t* host_func_type = wasm_functype_new_0_1(wasm_valtype_new_i32()); + wasm_func_t* host_func = wasm_func_new(store, host_func_type, host_func_callback); + wasm_functype_delete(host_func_type); + + printf("Creating the imported global...\n"); + wasm_globaltype_t* host_global_type = wasm_globaltype_new(wasm_valtype_new(WASM_F32), WASM_CONST); + wasm_val_t host_global_val = WASM_I32_VAL(42); + wasm_global_t* host_global = wasm_global_new(store, host_global_type, &host_global_val); + wasm_globaltype_delete(host_global_type); + + wasm_extern_t* externs[] = { + wasm_func_as_extern(host_func), + wasm_global_as_extern(host_global) + }; + + wasm_extern_vec_t import_object = WASM_ARRAY_VEC(externs); + + printf("Instantiating module...\n"); + wasm_instance_t* instance = wasm_instance_new(store, module, &import_object, NULL); + + if (!instance) { + printf("> Error instantiating module!\n"); + + return 1; + } + + printf("Retrieving exports...\n"); + wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + + if (exports.size == 0) { + printf("> Error accessing exports!\n"); + + return 1; + } + + printf("Retrieving the exported function...\n"); + wasm_func_t* func = wasm_extern_as_func(exports.data[0]); + + if (func == NULL) { + printf("> Failed to get the exported function!\n"); + + return 1; + } + + printf("Got the exported function: %p\n", func); + + printf("Retrieving the exported global...\n"); + wasm_global_t* global = wasm_extern_as_global(exports.data[1]); + + if (global == NULL) { + printf("> Failed to get the exported global!\n"); + + return 1; + } + + printf("Got the exported global: %p\n", global); + + printf("Retrieving the exported table...\n"); + wasm_table_t* table = wasm_extern_as_table(exports.data[2]); + + if (table == NULL) { + printf("> Failed to get the exported table!\n"); + + return 1; + } + + printf("Got the exported table: %p\n", table); + + printf("Retrieving the exported memory...\n"); + wasm_memory_t* memory = wasm_extern_as_memory(exports.data[3]); + + if (memory == NULL) { + printf("> Failed to get the exported memory!\n"); + + return 1; + } + + printf("Got the exported memory: %p\n", memory); + + wasm_func_delete(func); + wasm_global_delete(global); + wasm_table_delete(table); + wasm_memory_delete(memory); + wasm_module_delete(module); + wasm_instance_delete(instance); + wasm_store_delete(store); + wasm_engine_delete(engine); +} diff --git a/lib/c-api/examples/instance.c b/lib/c-api/examples/instance.c new file mode 100644 index 00000000000..2936b33ca51 --- /dev/null +++ b/lib/c-api/examples/instance.c @@ -0,0 +1,81 @@ +#include +#include "wasmer_wasm.h" + +int main(int argc, const char* argv[]) { + const char *wat_string = + "(module\n" + " (type $add_one_t (func (param i32) (result i32)))\n" + " (func $add_one_f (type $add_one_t) (param $value i32) (result i32)\n" + " local.get $value\n" + " i32.const 1\n" + " i32.add)\n" + " (export \"add_one\" (func $add_one_f)))"; + + wasm_byte_vec_t wat; + wasm_byte_vec_new(&wat, strlen(wat_string), wat_string); + wasm_byte_vec_t* wasm_bytes = wat2wasm(&wat); + + printf("Creating the store...\n"); + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + + printf("Compiling module...\n"); + wasm_module_t* module = wasm_module_new(store, wasm_bytes); + + if (!module) { + printf("> Error compiling module!\n"); + + return 1; + } + + wasm_byte_vec_delete(wasm_bytes); + + printf("Creating imports...\n"); + wasm_extern_vec_t imports = WASM_EMPTY_VEC; + + printf("Instantiating module...\n"); + wasm_instance_t* instance = wasm_instance_new(store, module, &imports, NULL); + + if (!instance) { + printf("> Error instantiating module!\n"); + + return 1; + } + + printf("Retrieving exports...\n"); + wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + + if (exports.size == 0) { + printf("> Error accessing exports!\n"); + + return 1; + } + + const wasm_func_t* add_one_func = wasm_extern_as_func(exports.data[0]); + if (add_one_func == NULL) { + printf("> Error accessing export!\n"); + + return 1; + } + + wasm_module_delete(module); + wasm_instance_delete(instance); + + printf("Calling `add_one` function...\n"); + wasm_val_t args_val[1] = { WASM_I32_VAL(1) }; + wasm_val_t results_val[1] = { WASM_INIT_VAL }; + wasm_val_vec_t args = WASM_ARRAY_VEC(args_val); + wasm_val_vec_t results = WASM_ARRAY_VEC(results_val); + + if (wasm_func_call(add_one_func, &args, &results)) { + printf("> Error calling function!\n"); + + return 1; + } + + printf("Results of `add_one`: %d\n", results_val[0].of.i32); + + wasm_store_delete(store); + wasm_engine_delete(engine); +} diff --git a/lib/c-api/examples/memory.c b/lib/c-api/examples/memory.c new file mode 100644 index 00000000000..794acae8630 --- /dev/null +++ b/lib/c-api/examples/memory.c @@ -0,0 +1,108 @@ +#include +#include "wasmer_wasm.h" + +int main(int argc, const char* argv[]) { + const char *wat_string = + "(module\n" + " (type $mem_size_t (func (result i32)))\n" + " (type $get_at_t (func (param i32) (result i32)))\n" + " (type $set_at_t (func (param i32) (param i32)))\n" + " (memory $mem 1)\n" + " (func $get_at (type $get_at_t) (param $idx i32) (result i32)\n" + " (i32.load (local.get $idx)))\n" + " (func $set_at (type $set_at_t) (param $idx i32) (param $val i32)\n" + " (i32.store (local.get $idx) (local.get $val)))\n" + " (func $mem_size (type $mem_size_t) (result i32)\n" + " (memory.size))\n" + " (export \"get_at\" (func $get_at))\n" + " (export \"set_at\" (func $set_at))\n" + " (export \"mem_size\" (func $mem_size))\n" + " (export \"memory\" (memory $mem)))"; + + wasm_byte_vec_t wat; + wasm_byte_vec_new(&wat, strlen(wat_string), wat_string); + wasm_byte_vec_t* wasm_bytes = wat2wasm(&wat); + + printf("Creating the store...\n"); + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + + printf("Compiling module...\n"); + wasm_module_t* module = wasm_module_new(store, wasm_bytes); + + if (!module) { + printf("> Error compiling module!\n"); + + return 1; + } + + wasm_byte_vec_delete(wasm_bytes); + + printf("Creating imports...\n"); + wasm_extern_vec_t import_object = WASM_EMPTY_VEC; + + printf("Instantiating module...\n"); + wasm_instance_t* instance = wasm_instance_new(store, module, &import_object, NULL); + + if (!instance) { + printf("> Error instantiating module!\n"); + + return 1; + } + + printf("Retrieving exports...\n"); + wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + + if (exports.size == 0) { + printf("> Error accessing exports!\n"); + + return 1; + } + + wasm_func_t* get_at = wasm_extern_as_func(exports.data[0]); + wasm_func_t* set_at = wasm_extern_as_func(exports.data[1]); + wasm_func_t* mem_size = wasm_extern_as_func(exports.data[2]); + wasm_memory_t* memory = wasm_extern_as_memory(exports.data[3]); + + printf("Querying memory size...\n"); + wasm_memory_pages_t pages = wasm_memory_size(memory); + size_t data_size = wasm_memory_data_size(memory); + printf("Memory size (pages): %d\n", pages); + printf("Memory size (bytes): %d\n", (int) data_size); + + printf("Growing memory...\n"); + if (!wasm_memory_grow(memory, 2)) { + printf("> Error growing memory!\n"); + + return 1; + } + + wasm_memory_pages_t new_pages = wasm_memory_size(memory); + printf("New memory size (pages): %d\n", new_pages); + + int mem_addr = 0x2220; + int val = 0xFEFEFFE; + + wasm_val_t set_at_args_val[2] = { WASM_I32_VAL(mem_addr), WASM_I32_VAL(val) }; + wasm_val_vec_t set_at_args = WASM_ARRAY_VEC(set_at_args_val); + wasm_val_vec_t set_at_results = WASM_EMPTY_VEC; + wasm_func_call(set_at, &set_at_args, &set_at_results); + + wasm_val_t get_at_args_val[1] = { WASM_I32_VAL(mem_addr) }; + wasm_val_vec_t get_at_args = WASM_ARRAY_VEC(get_at_args_val); + wasm_val_t get_at_results_val[1] = { WASM_INIT_VAL }; + wasm_val_vec_t get_at_results = WASM_ARRAY_VEC(get_at_results_val); + wasm_func_call(get_at, &get_at_args, &get_at_results); + + printf("Value at 0x%04x: %d\n", mem_addr, get_at_results_val[0].of.i32); + + wasm_memory_delete(memory); + wasm_func_delete(mem_size); + wasm_func_delete(set_at); + wasm_func_delete(get_at); + wasm_module_delete(module); + wasm_instance_delete(instance); + wasm_store_delete(store); + wasm_engine_delete(engine); +} diff --git a/lib/c-api/src/wasm_c_api/externals/global.rs b/lib/c-api/src/wasm_c_api/externals/global.rs index 1908e36c091..c83bb2b60cb 100644 --- a/lib/c-api/src/wasm_c_api/externals/global.rs +++ b/lib/c-api/src/wasm_c_api/externals/global.rs @@ -78,3 +78,77 @@ pub unsafe extern "C" fn wasm_global_same( pub extern "C" fn wasm_global_type(global: &wasm_global_t) -> Box { Box::new(wasm_globaltype_t::new(global.inner.ty().clone())) } + +#[cfg(test)] +mod tests { + use inline_c::assert_c; + + #[test] + fn test_set_host_global_immutable() { + (assert_c! { + #include "tests/wasmer_wasm.h" + + int main() { + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + + wasm_val_t forty_two = WASM_F32_VAL(42); + wasm_val_t forty_three = WASM_F32_VAL(43); + + wasm_valtype_t* type = wasm_valtype_new_i32(); + wasm_globaltype_t* global_type = wasm_globaltype_new(type, WASM_CONST); + wasm_global_t* global = wasm_global_new(store, global_type, &forty_two); + + wasm_global_set(global, &forty_three); + + assert(wasmer_last_error_length() > 0); + + wasm_globaltype_delete(global_type); + wasm_valtype_delete(type); + wasm_store_delete(store); + wasm_engine_delete(engine); + + return 0; + } + }) + .success(); + } + + #[test] + fn test_set_guest_global_immutable() { + (assert_c! { + #include "tests/wasmer_wasm.h" + + int main() { + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + + wasm_byte_vec_t wat; + wasmer_byte_vec_new_from_string(&wat, "(module (global $global (export \"global\") f32 (f32.const 1)))"); + wasm_byte_vec_t* wasm_bytes = wat2wasm(&wat); + wasm_module_t* module = wasm_module_new(store, wasm_bytes); + wasm_extern_vec_t import_object = WASM_EMPTY_VEC; + wasm_instance_t* instance = wasm_instance_new(store, module, &import_object, NULL); + + wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + wasm_global_t* global = wasm_extern_as_global(exports.data[0]); + + wasm_val_t forty_two = WASM_F32_VAL(42); + wasm_global_set(global, &forty_two); + + printf("%d", wasmer_last_error_length()); + assert(wasmer_last_error_length() > 0); + + wasm_instance_delete(instance); + wasm_byte_vec_delete(wasm_bytes); + wasm_byte_vec_delete(&wat); + wasm_store_delete(store); + wasm_engine_delete(engine); + + return 0; + } + }) + .success(); + } +}