diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index d5443ba7f..e6e82dc0d 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -5,6 +5,7 @@ use libc::{c_char, c_int, int32_t, int64_t, uint32_t, uint8_t}; use std::cell::RefCell; use std::error::Error; use std::ffi::CStr; +use std::ffi::CString; use std::fmt; use std::slice; use std::str; @@ -75,6 +76,10 @@ pub struct wasmer_memory_t(); #[derive(Clone)] pub struct wasmer_table_t(); +#[repr(C)] +#[derive(Clone)] +pub struct wasmer_func_t(); + #[repr(C)] #[derive(Clone)] pub struct wasmer_global_t(); @@ -85,6 +90,47 @@ pub struct wasmer_limits_t { pub max: uint32_t, } +#[repr(C)] +pub struct wasmer_func_signature { + pub params: *const wasmer_value_tag, + pub params_len: c_int, + pub returns: *const wasmer_value_tag, + pub returns_len: c_int, +} + +#[repr(C)] +#[derive(Clone)] +pub struct wasmer_import { + tag: wasmer_import_export_kind, + value: wasmer_import_export_value, +} + +#[repr(C)] +#[derive(Clone)] +pub struct wasmer_export_t; + +#[repr(C)] +#[derive(Clone)] +pub struct wasmer_exports_t; + +#[repr(u32)] +#[derive(Clone)] +pub enum wasmer_import_export_kind { + WASM_FUNCTION, + WASM_GLOBAL, + WASM_MEMORY, + WASM_TABLE, +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub union wasmer_import_export_value { + func: *const wasmer_func_t, + table: *const wasmer_table_t, + memory: *const wasmer_memory_t, + global: *const wasmer_global_t, +} + /// Returns true for valid wasm bytes and false for invalid bytes #[allow(clippy::cast_ptr_alignment)] #[no_mangle] @@ -413,7 +459,6 @@ pub unsafe extern "C" fn wasmer_instance_call( Box::into_raw(instance); match result { Ok(results_vec) => { - println!("Call Res: {:?}", results_vec); if results_vec.len() > 0 { let ret = match results_vec[0] { Value::I32(x) => wasmer_value_t { @@ -444,6 +489,83 @@ pub unsafe extern "C" fn wasmer_instance_call( } } +/// Gets Exports for the given instance +/// +/// The caller owns the object and should call `wasmer_exports_destroy` to free it. +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub unsafe extern "C" fn wasmer_instance_exports( + instance: *mut wasmer_instance_t, + exports: *mut *mut wasmer_exports_t, +) { + let mut instance = unsafe { Box::from_raw(instance as *mut Instance) }; + let named_exports: Box = + Box::new(NamedExports(instance.exports().map(|e| e.into()).collect())); + unsafe { *exports = Box::into_raw(named_exports) as *mut wasmer_exports_t }; + Box::into_raw(instance); +} + +pub struct NamedExports(Vec); + +/// Frees the memory for the given exports +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub unsafe extern "C" fn wasmer_exports_destroy(exports: *mut wasmer_exports_t) { + if !exports.is_null() { + drop(unsafe { Box::from_raw(exports as *mut NamedExports) }); + } +} + +/// Gets the length of the exports +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub unsafe extern "C" fn wasmer_exports_len(exports: *mut wasmer_exports_t) -> c_int { + if exports.is_null() { + return 0; + } + (*(exports as *mut NamedExports)).0.len() as c_int +} + +/// Gets wasmer_export by index +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub unsafe extern "C" fn wasmer_exports_get( + exports: *mut wasmer_exports_t, + idx: c_int, +) -> *mut wasmer_export_t { + if exports.is_null() { + return ptr::null_mut(); + } + let mut named_exports = unsafe { Box::from_raw(exports as *mut NamedExports) }; + let ptr = &mut (*named_exports).0[idx as usize] as *mut NamedExport as *mut wasmer_export_t; + Box::into_raw(named_exports); + ptr +} + +/// Gets wasmer_export kind +#[no_mangle] +#[allow(clippy::cast_ptr_alignment)] +pub unsafe extern "C" fn wasmer_export_kind( + export: *mut wasmer_export_t, +) -> wasmer_import_export_kind { + let named_export = &*(export as *mut NamedExport); + match named_export.export { + Export::Table(_) => wasmer_import_export_kind::WASM_TABLE, + Export::Function { .. } => wasmer_import_export_kind::WASM_FUNCTION, + Export::Global(_) => wasmer_import_export_kind::WASM_GLOBAL, + Export::Memory(_) => wasmer_import_export_kind::WASM_MEMORY, + } +} + +///// Gets wasmer_export func +//#[no_mangle] +//pub unsafe extern "C" fn wasmer_export_name(export: *mut wasmer_export_t) { +// if exports.is_null() { +// return ptr::null_mut(); +// } +// let named_export = &*(export as *mut NamedExport); +//} + /// Registers a `func` with provided `name` and `namespace` into the ImportObject. /// /// Returns `wasmer_result_t::WASMER_OK` upon success. @@ -606,6 +728,12 @@ impl From for Type { } } +impl From<(std::string::String, wasmer_runtime_core::export::Export)> for NamedExport { + fn from((name, export): (String, Export)) -> Self { + NamedExport { name, export } + } +} + // Error reporting thread_local! { @@ -699,3 +827,8 @@ impl fmt::Display for CApiError { } impl Error for CApiError {} + +struct NamedExport { + name: String, + export: Export, +} diff --git a/lib/runtime-c-api/tests/.gitignore b/lib/runtime-c-api/tests/.gitignore index 6a96cd53f..c8dfca857 100644 --- a/lib/runtime-c-api/tests/.gitignore +++ b/lib/runtime-c-api/tests/.gitignore @@ -10,6 +10,7 @@ compile_commands.json CTestTestfile.cmake _deps test-globals +test-exports test-instantiate test-import-function test-memory diff --git a/lib/runtime-c-api/tests/CMakeLists.txt b/lib/runtime-c-api/tests/CMakeLists.txt index d15934df5..ce970d4bf 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-exports test-exports.c) add_executable(test-globals test-globals.c) add_executable(test-instantiate test-instantiate.c) add_executable(test-import-function test-import-function.c) @@ -17,6 +18,8 @@ if(NOT WASMER_LIB) message(FATAL_ERROR "wasmer library not found") endif() +target_link_libraries(test-exports + general ${WASMER_LIB}) target_link_libraries(test-globals general ${WASMER_LIB}) target_link_libraries(test-instantiate @@ -31,6 +34,7 @@ target_link_libraries(test-tables general ${WASMER_LIB}) enable_testing() +add_test(test-exports test-exports) add_test(test-globals test-globals) add_test(test-instantiate test-instantiate) add_test(test-import-function test-import-function) diff --git a/lib/runtime-c-api/tests/test-exports.c b/lib/runtime-c-api/tests/test-exports.c new file mode 100644 index 000000000..8516d562b --- /dev/null +++ b/lib/runtime-c-api/tests/test-exports.c @@ -0,0 +1,43 @@ +#include +#include "../wasmer.h" +#include +#include + +int main() +{ + wasmer_import_object_t *import_object = wasmer_import_object_new(); + + // Read the wasm file bytes + FILE *file = fopen("sum.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); + + wasmer_instance_t *instance = NULL; + wasmer_result_t compile_result = wasmer_instantiate(&instance, bytes, len, import_object); + printf("Compile result: %d\n", compile_result); + assert(compile_result == WASMER_OK); + + wasmer_exports_t *exports = NULL; + wasmer_instance_exports(instance, &exports); + + int exports_len = wasmer_exports_len(exports); + printf("exports_len: %d\n", exports_len); + assert(exports_len == 1); + + wasmer_export_t *export = wasmer_exports_get(exports, 0); + + wasmer_import_export_kind kind = wasmer_export_kind(export); + assert(kind == WASM_FUNCTION); + + 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; +} \ No newline at end of file diff --git a/lib/runtime-c-api/tests/test-import-function.c b/lib/runtime-c-api/tests/test-import-function.c index f0ca17504..b42817abc 100644 --- a/lib/runtime-c-api/tests/test-import-function.c +++ b/lib/runtime-c-api/tests/test-import-function.c @@ -8,11 +8,13 @@ static memory_len = 0; static ptr_len = 0; static char actual_str[14] = {}; -void print_str(int32_t ptr, int32_t len, wasmer_instance_context_t *ctx) { +void print_str(int32_t ptr, int32_t len, wasmer_instance_context_t *ctx) +{ 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); - for(int32_t idx = 0; idx < len; idx++){ + for (int32_t idx = 0; idx < len; idx++) + { actual_str[idx] = mem_bytes[ptr + idx]; } actual_str[13] = '\0'; @@ -54,8 +56,8 @@ int main() assert(ptr_len == 13); assert(0 == strcmp(actual_str, "Hello, World!")); - printf("Destroy instance\n"); - wasmer_instance_destroy(instance); + // printf("Destroy instance\n"); + // wasmer_instance_destroy(instance); printf("Destroy import object\n"); wasmer_import_object_destroy(import_object); return 0; diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 6b855404a..86230de1c 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -6,6 +6,14 @@ #include #include +enum wasmer_import_export_kind { + WASM_FUNCTION, + WASM_GLOBAL, + WASM_MEMORY, + WASM_TABLE, +}; +typedef uint32_t wasmer_import_export_kind; + typedef enum { WASMER_OK = 1, WASMER_ERROR = 2, @@ -27,6 +35,14 @@ typedef struct wasmer_instance_t wasmer_instance_t; typedef struct { +} wasmer_export_t; + +typedef struct { + +} wasmer_exports_t; + +typedef struct { + } wasmer_global_t; typedef union { @@ -59,6 +75,26 @@ typedef struct { } wasmer_table_t; +/** + * Gets wasmer_export kind + */ +wasmer_import_export_kind wasmer_export_kind(wasmer_export_t *export_); + +/** + * Frees the memory for the given exports + */ +void wasmer_exports_destroy(wasmer_exports_t *exports); + +/** + * Gets wasmer_export by index + */ +wasmer_export_t *wasmer_exports_get(wasmer_exports_t *exports, int idx); + +/** + * Gets the length of the exports + */ +int wasmer_exports_len(wasmer_exports_t *exports); + /** * Frees memory for the given Global */ @@ -137,6 +173,12 @@ const wasmer_memory_t *wasmer_instance_context_memory(wasmer_instance_context_t */ void wasmer_instance_destroy(wasmer_instance_t *instance); +/** + * Gets Exports for the given instance + * The caller owns the object and should call `wasmer_exports_destroy` to free it. + */ +void wasmer_instance_exports(wasmer_instance_t *instance, wasmer_exports_t **exports); + /** * Creates a new Instance from the given wasm bytes and imports. * Returns `wasmer_result_t::WASMER_OK` upon success. diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 24c4f3f14..32b6e435f 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -5,6 +5,13 @@ #include #include +enum class wasmer_import_export_kind : uint32_t { + WASM_FUNCTION, + WASM_GLOBAL, + WASM_MEMORY, + WASM_TABLE, +}; + enum class wasmer_result_t { WASMER_OK = 1, WASMER_ERROR = 2, @@ -23,6 +30,14 @@ struct wasmer_instance_context_t; struct wasmer_instance_t; +struct wasmer_export_t { + +}; + +struct wasmer_exports_t { + +}; + struct wasmer_global_t { }; @@ -59,6 +74,18 @@ struct wasmer_table_t { extern "C" { +/// Gets wasmer_export kind +wasmer_import_export_kind wasmer_export_kind(wasmer_export_t *export_); + +/// Frees the memory for the given exports +void wasmer_exports_destroy(wasmer_exports_t *exports); + +/// Gets wasmer_export by index +wasmer_export_t *wasmer_exports_get(wasmer_exports_t *exports, int idx); + +/// Gets the length of the exports +int wasmer_exports_len(wasmer_exports_t *exports); + /// Frees memory for the given Global void wasmer_global_destroy(wasmer_global_t *global); @@ -115,6 +142,10 @@ const wasmer_memory_t *wasmer_instance_context_memory(wasmer_instance_context_t /// Frees memory for the given Instance void wasmer_instance_destroy(wasmer_instance_t *instance); +/// Gets Exports for the given instance +/// The caller owns the object and should call `wasmer_exports_destroy` to free it. +void wasmer_instance_exports(wasmer_instance_t *instance, wasmer_exports_t **exports); + /// Creates a new Instance from the given wasm bytes and imports. /// Returns `wasmer_result_t::WASMER_OK` upon success. /// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length`