diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 1931656e7..511f4304a 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -3,6 +3,7 @@ extern crate wasmer_runtime_core; use libc::{c_char, c_int, int32_t, int64_t, uint32_t, uint8_t}; use std::cell::RefCell; +use std::collections::HashMap; use std::error::Error; use std::ffi::CStr; use std::ffi::CString; @@ -99,8 +100,9 @@ pub struct wasmer_func_signature { } #[repr(C)] -#[derive(Clone)] -pub struct wasmer_import { +pub struct wasmer_import_t { + module_name: wasmer_byte_array, + import_name: wasmer_byte_array, tag: wasmer_import_export_kind, value: wasmer_import_export_value, } @@ -389,18 +391,63 @@ pub unsafe extern "C" fn wasmer_instantiate( mut instance: *mut *mut wasmer_instance_t, wasm_bytes: *mut uint8_t, wasm_bytes_len: uint32_t, - import_object: *mut wasmer_import_object_t, + imports: *mut wasmer_import_t, + imports_len: c_int, ) -> wasmer_result_t { - let import_object = unsafe { Box::from_raw(import_object as *mut ImportObject) }; if wasm_bytes.is_null() { update_last_error(CApiError { msg: "wasm bytes ptr is null".to_string(), }); return wasmer_result_t::WASMER_ERROR; } + let imports: &[wasmer_import_t] = slice::from_raw_parts(imports, imports_len as usize); + let mut import_object = ImportObject::new(); + let mut namespaces = HashMap::new(); + for import in imports { + let module_name = slice::from_raw_parts( + import.module_name.bytes, + import.module_name.bytes_len as usize, + ); + let module_name = if let Ok(s) = std::str::from_utf8(module_name) { + s + } else { + update_last_error(CApiError { + msg: "error converting module name to string".to_string(), + }); + return wasmer_result_t::WASMER_ERROR; + }; + let import_name = slice::from_raw_parts( + import.import_name.bytes, + import.import_name.bytes_len as usize, + ); + let import_name = if let Ok(s) = std::str::from_utf8(import_name) { + s + } else { + update_last_error(CApiError { + msg: "error converting import_name to string".to_string(), + }); + return wasmer_result_t::WASMER_ERROR; + }; + + let namespace = namespaces + .entry(module_name) + .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, + }; + namespace.insert(import_name, unsafe { *Box::from_raw(export) }); + } + for (module_name, namespace) in namespaces.into_iter() { + import_object.register(module_name, namespace); + } + let bytes: &[u8] = unsafe { ::std::slice::from_raw_parts_mut(wasm_bytes, wasm_bytes_len as usize) }; - let result = wasmer_runtime::instantiate(bytes, &*import_object); + let result = wasmer_runtime::instantiate(bytes, &import_object); let new_instance = match result { Ok(instance) => instance, Err(error) => { @@ -413,7 +460,7 @@ pub unsafe extern "C" fn wasmer_instantiate( } }; unsafe { *instance = Box::into_raw(Box::new(new_instance)) as *mut wasmer_instance_t }; - Box::into_raw(import_object); + Box::into_raw(Box::new(import_object)); wasmer_result_t::WASMER_OK } @@ -563,6 +610,40 @@ pub unsafe extern "C" fn wasmer_export_kind( } } +/// Creates new func +/// +/// The caller owns the object and should call `wasmer_func_destroy` to free it. +#[no_mangle] +#[allow(clippy::cast_ptr_alignment)] +pub unsafe extern "C" fn wasmer_func_new( + func: extern "C" fn(data: *mut c_void), + params: *const wasmer_value_tag, + params_len: c_int, + returns: *const wasmer_value_tag, + returns_len: c_int, +) -> *const wasmer_func_t { + let params: &[wasmer_value_tag] = slice::from_raw_parts(params, params_len as usize); + let params: Vec = params.iter().cloned().map(|x| x.into()).collect(); + let returns: &[wasmer_value_tag] = slice::from_raw_parts(returns, returns_len as usize); + let returns: Vec = returns.iter().cloned().map(|x| x.into()).collect(); + + let export = Box::new(Export::Function { + func: unsafe { FuncPointer::new(func as _) }, + ctx: Context::Internal, + signature: Arc::new(FuncSig::new(params, returns)), + }); + Box::into_raw(export) as *mut wasmer_func_t +} + +/// Frees memory for the given Func +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub extern "C" fn wasmer_func_destroy(func: *mut wasmer_func_t) { + if !func.is_null() { + drop(unsafe { Box::from_raw(func as *mut Export) }); + } +} + /// Gets func from wasm_export #[no_mangle] #[allow(clippy::cast_ptr_alignment)] diff --git a/lib/runtime-c-api/tests/test-exports.c b/lib/runtime-c-api/tests/test-exports.c index b00adb790..c0c6a4a7b 100644 --- a/lib/runtime-c-api/tests/test-exports.c +++ b/lib/runtime-c-api/tests/test-exports.c @@ -5,7 +5,7 @@ int main() { - wasmer_import_object_t *import_object = wasmer_import_object_new(); +// wasmer_import_object_t *import_object = wasmer_import_object_new(); // Read the wasm file bytes FILE *file = fopen("sum.wasm", "r"); @@ -16,8 +16,9 @@ int main() fread(bytes, 1, len, file); fclose(file); + wasmer_import_t imports[] = {}; wasmer_instance_t *instance = NULL; - wasmer_result_t compile_result = wasmer_instantiate(&instance, bytes, len, import_object); + wasmer_result_t compile_result = wasmer_instantiate(&instance, bytes, len, imports, 0); printf("Compile result: %d\n", compile_result); assert(compile_result == WASMER_OK); @@ -61,8 +62,6 @@ int main() printf("Destroy instance\n"); wasmer_instance_destroy(instance); - printf("Destroy import object\n"); - wasmer_import_object_destroy(import_object); printf("Destroy exports\n"); wasmer_exports_destroy(exports); return 0; diff --git a/lib/runtime-c-api/tests/test-import-function.c b/lib/runtime-c-api/tests/test-import-function.c index b42817abc..2c241be55 100644 --- a/lib/runtime-c-api/tests/test-import-function.c +++ b/lib/runtime-c-api/tests/test-import-function.c @@ -2,6 +2,7 @@ #include "../wasmer.h" #include #include +#include static print_str_called = false; static memory_len = 0; @@ -26,10 +27,32 @@ void print_str(int32_t ptr, int32_t len, wasmer_instance_context_t *ctx) int main() { - wasmer_import_object_t *import_object = wasmer_import_object_new(); +// wasmer_import_object_t *import_object = wasmer_import_object_new(); wasmer_value_tag params_sig[] = {WASM_I32, WASM_I32}; wasmer_value_tag returns_sig[] = {}; - wasmer_imports_set_import_func(import_object, "env", "print_str", print_str, params_sig, 2, returns_sig, 0); + + printf("Creating new func\n"); + wasmer_func_t *func = wasmer_func_new(print_str, params_sig, 2, returns_sig, 0); + wasmer_import_t import; + + char *module_name = "env"; + wasmer_byte_array module_name_bytes; + module_name_bytes.bytes = module_name; + module_name_bytes.bytes_len = strlen(module_name); + 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); + + import.module_name = module_name_bytes; + import.import_name = import_name_bytes; + import.tag = WASM_FUNCTION; + import.value.func = func; + wasmer_import_t imports[] = {import}; + + +// wasmer_imports_set_import_func(import_object, "env", "print_str", print_str, params_sig, 2, returns_sig, 0); + // Read the wasm file bytes FILE *file = fopen("wasm_sample_app.wasm", "r"); @@ -40,9 +63,15 @@ int main() fread(bytes, 1, len, file); fclose(file); + printf("Instantiating\n"); wasmer_instance_t *instance = NULL; - wasmer_result_t compile_result = wasmer_instantiate(&instance, bytes, len, import_object); + wasmer_result_t compile_result = wasmer_instantiate(&instance, bytes, len, imports, 1); printf("Compile result: %d\n", compile_result); + 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); assert(compile_result == WASMER_OK); wasmer_value_t params[] = {}; @@ -56,9 +85,11 @@ int main() assert(ptr_len == 13); assert(0 == strcmp(actual_str, "Hello, World!")); + printf("Destroying func\n"); + // wasmer_func_destroy(func); // printf("Destroy instance\n"); // wasmer_instance_destroy(instance); - printf("Destroy import object\n"); - wasmer_import_object_destroy(import_object); +// printf("Destroy import object\n"); +// wasmer_import_object_destroy(import_object); return 0; } \ No newline at end of file diff --git a/lib/runtime-c-api/tests/test-instantiate.c b/lib/runtime-c-api/tests/test-instantiate.c index db24544f4..63adf11c1 100644 --- a/lib/runtime-c-api/tests/test-instantiate.c +++ b/lib/runtime-c-api/tests/test-instantiate.c @@ -5,7 +5,6 @@ int main() { - wasmer_import_object_t *import_object = wasmer_import_object_new(); // Read the wasm file bytes FILE *file = fopen("sum.wasm", "r"); @@ -16,8 +15,9 @@ int main() fread(bytes, 1, len, file); fclose(file); + wasmer_import_t imports[] = {}; wasmer_instance_t *instance = NULL; - wasmer_result_t compile_result = wasmer_instantiate(&instance, bytes, len, import_object); + wasmer_result_t compile_result = wasmer_instantiate(&instance, bytes, len, imports, 0); printf("Compile result: %d\n", compile_result); assert(compile_result == WASMER_OK); @@ -53,7 +53,5 @@ int main() printf("Destroy instance\n"); wasmer_instance_destroy(instance); - printf("Destroy import object\n"); - wasmer_import_object_destroy(import_object); return 0; } \ No newline at end of file diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index f55014bee..efc840400 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -75,22 +75,36 @@ typedef struct { } wasmer_memory_t; +typedef struct { + +} wasmer_table_t; + +typedef union { + const wasmer_func_t *func; + const wasmer_table_t *table; + const wasmer_memory_t *memory; + const wasmer_global_t *global; +} wasmer_import_export_value; + +typedef struct { + wasmer_byte_array module_name; + wasmer_byte_array import_name; + wasmer_import_export_kind tag; + wasmer_import_export_value value; +} wasmer_import_t; + typedef struct { uint32_t min; uint32_t max; } wasmer_limits_t; -typedef struct { - -} wasmer_table_t; - /** * Gets wasmer_export kind */ wasmer_import_export_kind wasmer_export_kind(wasmer_export_t *export_); /** - * Gets func from wasm_export + * Gets name from wasmer_export */ wasmer_byte_array wasmer_export_name(wasmer_export_t *export_); @@ -127,6 +141,21 @@ wasmer_result_t wasmer_func_call(wasmer_func_t *func, wasmer_value_t *results, int results_len); +/** + * Frees memory for the given Func + */ +void wasmer_func_destroy(wasmer_func_t *func); + +/** + * Creates new func + * The caller owns the object and should call `wasmer_func_destroy` to free it. + */ +const wasmer_func_t *wasmer_func_new(void (*func)(void *data), + const wasmer_value_tag *params, + int params_len, + const wasmer_value_tag *returns, + int returns_len); + /** * Frees memory for the given Global */ @@ -220,7 +249,8 @@ void wasmer_instance_exports(wasmer_instance_t *instance, wasmer_exports_t **exp wasmer_result_t wasmer_instantiate(wasmer_instance_t **instance, uint8_t *wasm_bytes, uint32_t wasm_bytes_len, - wasmer_import_object_t *import_object); + wasmer_import_t *imports, + int imports_len); /** * Gets the length in bytes of the last error. diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 02de6f52b..0192e8555 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -72,21 +72,35 @@ struct wasmer_memory_t { }; +struct wasmer_table_t { + +}; + +union wasmer_import_export_value { + const wasmer_func_t *func; + const wasmer_table_t *table; + const wasmer_memory_t *memory; + const wasmer_global_t *global; +}; + +struct wasmer_import_t { + wasmer_byte_array module_name; + wasmer_byte_array import_name; + wasmer_import_export_kind tag; + wasmer_import_export_value value; +}; + struct wasmer_limits_t { uint32_t min; uint32_t max; }; -struct wasmer_table_t { - -}; - extern "C" { /// Gets wasmer_export kind wasmer_import_export_kind wasmer_export_kind(wasmer_export_t *export_); -/// Gets func from wasm_export +/// Gets name from wasmer_export wasmer_byte_array wasmer_export_name(wasmer_export_t *export_); /// Gets func from wasm_export @@ -112,6 +126,17 @@ wasmer_result_t wasmer_func_call(wasmer_func_t *func, wasmer_value_t *results, int results_len); +/// Frees memory for the given Func +void wasmer_func_destroy(wasmer_func_t *func); + +/// Creates new func +/// The caller owns the object and should call `wasmer_func_destroy` to free it. +const wasmer_func_t *wasmer_func_new(void (*func)(void *data), + const wasmer_value_tag *params, + int params_len, + const wasmer_value_tag *returns, + int returns_len); + /// Frees memory for the given Global void wasmer_global_destroy(wasmer_global_t *global); @@ -179,7 +204,8 @@ void wasmer_instance_exports(wasmer_instance_t *instance, wasmer_exports_t **exp wasmer_result_t wasmer_instantiate(wasmer_instance_t **instance, uint8_t *wasm_bytes, uint32_t wasm_bytes_len, - wasmer_import_object_t *import_object); + wasmer_import_t *imports, + int imports_len); /// Gets the length in bytes of the last error. /// This can be used to dynamically allocate a buffer with the correct number of