diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 2fbf36cf8ea..5512c0287a9 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -454,12 +454,24 @@ pub unsafe extern "C" fn wasmer_module_instantiate( .or_insert_with(|| Namespace::new()); let export = match import.tag { - wasmer_import_export_kind::WASM_MEMORY => import.value.memory as *mut Export, - wasmer_import_export_kind::WASM_FUNCTION => import.value.func as *mut Export, - wasmer_import_export_kind::WASM_GLOBAL => import.value.global as *mut Export, - wasmer_import_export_kind::WASM_TABLE => import.value.table as *mut Export, + wasmer_import_export_kind::WASM_MEMORY => { + let mem = import.value.memory as *mut Memory; + Export::Memory((&*mem).clone()) + } + wasmer_import_export_kind::WASM_FUNCTION => { + let func_export = import.value.func as *mut Export; + (&*func_export).clone() + } + wasmer_import_export_kind::WASM_GLOBAL => { + let global = import.value.global as *mut Global; + Export::Global((&*global).clone()) + } + wasmer_import_export_kind::WASM_TABLE => { + let table = import.value.table as *mut Table; + Export::Table((&*table).clone()) + } }; - namespace.insert(import_name, unsafe { (&*export).clone() }); + namespace.insert(import_name, export); } for (module_name, namespace) in namespaces.into_iter() { import_object.register(module_name, namespace); @@ -806,12 +818,24 @@ pub unsafe extern "C" fn wasmer_instantiate( .or_insert_with(|| Namespace::new()); let export = match import.tag { - wasmer_import_export_kind::WASM_MEMORY => import.value.memory as *mut Export, - wasmer_import_export_kind::WASM_FUNCTION => import.value.func as *mut Export, - wasmer_import_export_kind::WASM_GLOBAL => import.value.global as *mut Export, - wasmer_import_export_kind::WASM_TABLE => import.value.table as *mut Export, + wasmer_import_export_kind::WASM_MEMORY => { + let mem = import.value.memory as *mut Memory; + Export::Memory((&*mem).clone()) + } + wasmer_import_export_kind::WASM_FUNCTION => { + let func_export = import.value.func as *mut Export; + (&*func_export).clone() + } + wasmer_import_export_kind::WASM_GLOBAL => { + let global = import.value.global as *mut Global; + Export::Global((&*global).clone()) + } + wasmer_import_export_kind::WASM_TABLE => { + let table = import.value.table as *mut Table; + Export::Table((&*table).clone()) + } }; - namespace.insert(import_name, unsafe { (&*export).clone() }); + namespace.insert(import_name, unsafe { export }); } for (module_name, namespace) in namespaces.into_iter() { import_object.register(module_name, namespace); diff --git a/lib/runtime-c-api/tests/.gitignore b/lib/runtime-c-api/tests/.gitignore index a39c1325017..15e33d2cf6e 100644 --- a/lib/runtime-c-api/tests/.gitignore +++ b/lib/runtime-c-api/tests/.gitignore @@ -12,6 +12,7 @@ _deps test-globals test-exports test-instantiate +test-imports test-import-function test-memory test-module-imports diff --git a/lib/runtime-c-api/tests/CMakeLists.txt b/lib/runtime-c-api/tests/CMakeLists.txt index 6977295808f..6f899b5b570 100644 --- a/lib/runtime-c-api/tests/CMakeLists.txt +++ b/lib/runtime-c-api/tests/CMakeLists.txt @@ -1,6 +1,7 @@ cmake_minimum_required (VERSION 2.6) project (WasmerCApiTests) +add_executable(test-imports test-imports.c) add_executable(test-exports test-exports.c) add_executable(test-globals test-globals.c) add_executable(test-instantiate test-instantiate.c) @@ -21,6 +22,8 @@ if(NOT WASMER_LIB) message(FATAL_ERROR "wasmer library not found") endif() +target_link_libraries(test-imports + general ${WASMER_LIB}) target_link_libraries(test-exports general ${WASMER_LIB}) target_link_libraries(test-globals @@ -43,6 +46,7 @@ target_link_libraries(test-tables general ${WASMER_LIB}) enable_testing() +add_test(test-imports test-imports) add_test(test-exports test-exports) add_test(test-globals test-globals) add_test(test-instantiate test-instantiate) diff --git a/lib/runtime-c-api/tests/hello_wasm.wasm b/lib/runtime-c-api/tests/hello_wasm.wasm new file mode 100644 index 00000000000..b2287be036e Binary files /dev/null and b/lib/runtime-c-api/tests/hello_wasm.wasm differ diff --git a/lib/runtime-c-api/tests/test-imports.c b/lib/runtime-c-api/tests/test-imports.c new file mode 100644 index 00000000000..4410c4dd6df --- /dev/null +++ b/lib/runtime-c-api/tests/test-imports.c @@ -0,0 +1,154 @@ +#include +#include "../wasmer.h" +#include +#include + +static print_str_called = false; + +// Host function that will be imported into the Web Assembly Instance +void print_str(wasmer_instance_context_t *ctx, int32_t ptr, int32_t len) +{ + print_str_called = true; + wasmer_memory_t *memory = wasmer_instance_context_memory(ctx, 0); + uint32_t mem_len = wasmer_memory_length(memory); + uint8_t *mem_bytes = wasmer_memory_data(memory); + printf("%.*s", len, mem_bytes + ptr); +} + +// Use the last_error API to retrieve error messages +void print_wasmer_error() +{ + int error_len = wasmer_last_error_length(); + printf("Error len: `%d`\n", error_len); + char *error_str = malloc(error_len); + wasmer_last_error_message(error_str, error_len); + printf("Error str: `%s`\n", error_str); +} + +int main() +{ + // Create a new func to hold the parameter and signature + // of our `print_str` host function + wasmer_value_tag params_sig[] = {WASM_I32, WASM_I32}; + wasmer_value_tag returns_sig[] = {}; + wasmer_import_func_t *func = wasmer_import_func_new(print_str, params_sig, 2, returns_sig, 0); + + // Create module name for our imports + // represented in bytes for UTF-8 compatability + char *module_name = "env"; + wasmer_byte_array module_name_bytes; + module_name_bytes.bytes = module_name; + module_name_bytes.bytes_len = strlen(module_name); + + // Define a function import + char *import_name = "_print_str"; + wasmer_byte_array import_name_bytes; + import_name_bytes.bytes = import_name; + import_name_bytes.bytes_len = strlen(import_name); + wasmer_import_t func_import; + func_import.module_name = module_name_bytes; + func_import.import_name = import_name_bytes; + func_import.tag = WASM_FUNCTION; + func_import.value.func = func; + + // Define a memory import + char *import_memory_name = "memory"; + wasmer_byte_array import_memory_name_bytes; + import_memory_name_bytes.bytes = import_memory_name; + import_memory_name_bytes.bytes_len = strlen(import_memory_name); + wasmer_import_t memory_import; + memory_import.module_name = module_name_bytes; + memory_import.import_name = import_memory_name_bytes; + memory_import.tag = WASM_MEMORY; + wasmer_memory_t *memory = NULL; + wasmer_limits_t descriptor; + descriptor.min = 256; + wasmer_limit_option_t max; + max.has_some = true; + max.some = 256; + descriptor.max = max; + wasmer_result_t memory_result = wasmer_memory_new(&memory, descriptor); + if (memory_result != WASMER_OK) + { + print_wasmer_error(); + } + memory_import.value.memory = memory; + + // Define a global import + char *import_global_name = "__memory_base"; + wasmer_byte_array import_global_name_bytes; + import_global_name_bytes.bytes = import_global_name; + import_global_name_bytes.bytes_len = strlen(import_global_name); + wasmer_import_t global_import; + global_import.module_name = module_name_bytes; + global_import.import_name = import_global_name_bytes; + global_import.tag = WASM_GLOBAL; + wasmer_value_t val; + val.tag = WASM_I32; + val.value.I32 = 1024; + wasmer_global_t *global = wasmer_global_new(val, false); + global_import.value.global = global; + + // Define a table import + char *import_table_name = "table"; + wasmer_byte_array import_table_name_bytes; + import_table_name_bytes.bytes = import_table_name; + import_table_name_bytes.bytes_len = strlen(import_table_name); + wasmer_import_t table_import; + table_import.module_name = module_name_bytes; + table_import.import_name = import_table_name_bytes; + table_import.tag = WASM_TABLE; + wasmer_table_t *table = NULL; + wasmer_limits_t table_descriptor; + table_descriptor.min = 256; + wasmer_limit_option_t table_max; + table_max.has_some = true; + table_max.some = 256; + table_descriptor.max = table_max; + wasmer_result_t table_result = wasmer_table_new(&table, table_descriptor); + if (table_result != WASMER_OK) + { + print_wasmer_error(); + } + table_import.value.table = table; + + // Define an array containing our imports + wasmer_import_t imports[] = {func_import, global_import, memory_import, table_import}; + + // Read the wasm file bytes + FILE *file = fopen("hello_wasm.wasm", "r"); + fseek(file, 0, SEEK_END); + long len = ftell(file); + uint8_t *bytes = malloc(len); + fseek(file, 0, SEEK_SET); + fread(bytes, 1, len, file); + fclose(file); + + // Creates a WebAssembly Instance from wasm bytes and imports + wasmer_instance_t *instance = NULL; + wasmer_result_t compile_result = wasmer_instantiate(&instance, bytes, len, imports, 3); + printf("Compile result: %d\n", compile_result); + if (compile_result != WASMER_OK) + { + print_wasmer_error(); + } + assert(compile_result == WASMER_OK); + + // Call the exported "hello_wasm" function of our instance + wasmer_value_t params[] = {}; + wasmer_value_t result_one; + wasmer_value_t results[] = {result_one}; + wasmer_result_t call_result = wasmer_instance_call(instance, "_hello_wasm", params, 0, results, 1); + printf("Call result: %d\n", call_result); + assert(call_result == WASMER_OK); + assert(print_str_called); + + // Use *_destroy methods to cleanup as specified in the header documentation + wasmer_import_func_destroy(func); + wasmer_global_destroy(global); + wasmer_memory_destroy(memory); + wasmer_table_destroy(table); + wasmer_instance_destroy(instance); + + return 0; +}