diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index f52076d28..ea56cf7f5 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -13,6 +13,7 @@ use std::{ffi::c_void, ptr}; use wasmer_runtime::{Ctx, Global, ImportObject, Instance, Memory, Module, Table, Value}; use wasmer_runtime_core::export::{Context, Export, FuncPointer}; use wasmer_runtime_core::import::Namespace; +use wasmer_runtime_core::module::ExportIndex; use wasmer_runtime_core::types::{ElementType, FuncSig, MemoryDescriptor, TableDescriptor, Type}; use wasmer_runtime_core::units::{Bytes, Pages}; @@ -120,6 +121,14 @@ pub struct wasmer_export_t; #[derive(Clone)] pub struct wasmer_exports_t; +#[repr(C)] +#[derive(Clone)] +pub struct wasmer_export_descriptor_t; + +#[repr(C)] +#[derive(Clone)] +pub struct wasmer_export_descriptors_t; + #[repr(u32)] #[derive(Clone)] pub enum wasmer_import_export_kind { @@ -468,6 +477,91 @@ pub unsafe extern "C" fn wasmer_module_instantiate( wasmer_result_t::WASMER_OK } +/// Gets export descriptors for the given module +/// +/// The caller owns the object and should call `wasmer_export_descriptors_destroy` to free it. +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub unsafe extern "C" fn wasmer_export_descriptors( + module: *mut wasmer_module_t, + export_descriptors: *mut *mut wasmer_export_descriptors_t, +) { + let mut module = unsafe { &*(module as *mut Module) }; + + let named_export_descriptors: Box = Box::new(NamedExportDescriptors( + module.info().exports.iter().map(|e| e.into()).collect(), + )); + unsafe { + *export_descriptors = + Box::into_raw(named_export_descriptors) as *mut wasmer_export_descriptors_t + }; +} + +pub struct NamedExportDescriptors(Vec); + +/// Frees the memory for the given export descriptors +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub unsafe extern "C" fn wasmer_export_descriptors_destroy( + export_descriptors: *mut wasmer_export_descriptors_t, +) { + if !export_descriptors.is_null() { + drop(unsafe { Box::from_raw(export_descriptors as *mut NamedExportDescriptors) }); + } +} + +/// Gets the length of the export descriptors +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub unsafe extern "C" fn wasmer_export_descriptors_len( + exports: *mut wasmer_export_descriptors_t, +) -> c_int { + if exports.is_null() { + return 0; + } + (*(exports as *mut NamedExportDescriptors)).0.len() as c_int +} + +/// Gets export descriptor by index +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub unsafe extern "C" fn wasmer_export_descriptors_get( + export_descriptors: *mut wasmer_export_descriptors_t, + idx: c_int, +) -> *mut wasmer_export_descriptor_t { + if export_descriptors.is_null() { + return ptr::null_mut(); + } + let mut named_export_descriptors = + unsafe { &mut *(export_descriptors as *mut NamedExportDescriptors) }; + let ptr = &mut (*named_export_descriptors).0[idx as usize] as *mut NamedExportDescriptor + as *mut wasmer_export_descriptor_t; + ptr +} + +/// Gets name for the export descriptor +#[no_mangle] +#[allow(clippy::cast_ptr_alignment)] +pub unsafe extern "C" fn wasmer_export_descriptor_name( + export_descriptor: *mut wasmer_export_descriptor_t, +) -> wasmer_byte_array { + let named_export_descriptor = &*(export_descriptor as *mut NamedExportDescriptor); + wasmer_byte_array { + bytes: named_export_descriptor.name.as_ptr(), + bytes_len: named_export_descriptor.name.len() as u32, + } +} + +/// Gets export descriptor kind +#[no_mangle] +#[allow(clippy::cast_ptr_alignment)] +pub unsafe extern "C" fn wasmer_export_descriptor_kind( + export: *mut wasmer_export_descriptor_t, +) -> wasmer_import_export_kind { + let named_export_descriptor = &*(export as *mut NamedExportDescriptor); + named_export_descriptor.kind.clone() +} + /// Frees memory for the given Module #[allow(clippy::cast_ptr_alignment)] #[no_mangle] @@ -1075,6 +1169,21 @@ impl From<&wasmer_runtime::wasm::Type> for wasmer_value_tag { } } +impl From<(&std::string::String, &ExportIndex)> for NamedExportDescriptor { + fn from((name, export_index): (&String, &ExportIndex)) -> Self { + let kind = match *export_index { + ExportIndex::Memory(_) => wasmer_import_export_kind::WASM_MEMORY, + ExportIndex::Global(_) => wasmer_import_export_kind::WASM_GLOBAL, + ExportIndex::Table(_) => wasmer_import_export_kind::WASM_TABLE, + ExportIndex::Func(_) => wasmer_import_export_kind::WASM_FUNCTION, + }; + NamedExportDescriptor { + name: name.clone(), + kind, + } + } +} + // Error reporting thread_local! { @@ -1173,3 +1282,8 @@ struct NamedExport { name: String, export: Export, } + +struct NamedExportDescriptor { + name: String, + kind: wasmer_import_export_kind, +} diff --git a/lib/runtime-c-api/tests/.gitignore b/lib/runtime-c-api/tests/.gitignore index 6ea57c28d..6ddd85f73 100644 --- a/lib/runtime-c-api/tests/.gitignore +++ b/lib/runtime-c-api/tests/.gitignore @@ -15,6 +15,7 @@ test-instantiate test-import-function test-memory test-module +test-module-exports test-tables test-validate rust-build \ No newline at end of file diff --git a/lib/runtime-c-api/tests/CMakeLists.txt b/lib/runtime-c-api/tests/CMakeLists.txt index 788ee1c6a..111b374e4 100644 --- a/lib/runtime-c-api/tests/CMakeLists.txt +++ b/lib/runtime-c-api/tests/CMakeLists.txt @@ -7,6 +7,7 @@ add_executable(test-instantiate test-instantiate.c) add_executable(test-import-function test-import-function.c) add_executable(test-memory test-memory.c) add_executable(test-module test-module.c) +add_executable(test-module-exports test-module-exports.c) add_executable(test-validate test-validate.c) add_executable(test-tables test-tables.c) @@ -31,6 +32,8 @@ target_link_libraries(test-memory general ${WASMER_LIB}) target_link_libraries(test-module general ${WASMER_LIB}) +target_link_libraries(test-module-exports + general ${WASMER_LIB}) target_link_libraries(test-validate general ${WASMER_LIB}) target_link_libraries(test-tables @@ -43,6 +46,7 @@ add_test(test-instantiate test-instantiate) add_test(test-import-function test-import-function) add_test(test-memory test-memory) add_test(test-module test-module) +add_test(test-module-exports test-module-exports) add_test(test-validate test-validate) add_test(test-tables test-tables) diff --git a/lib/runtime-c-api/tests/test-module-exports.c b/lib/runtime-c-api/tests/test-module-exports.c new file mode 100644 index 000000000..48fe6f25b --- /dev/null +++ b/lib/runtime-c-api/tests/test-module-exports.c @@ -0,0 +1,53 @@ +#include +#include "../wasmer.h" +#include +#include + +int main() +{ + // 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_module_t *module = NULL; + wasmer_result_t compile_result = wasmer_compile(&module, bytes, len); + printf("Compile result: %d\n", compile_result); + assert(compile_result == WASMER_OK); + + wasmer_import_t imports[] = {}; + wasmer_instance_t *instance = NULL; + wasmer_result_t instantiate_result = wasmer_module_instantiate(module, &instance, imports, 0); + printf("Instantiate result: %d\n", compile_result); + assert(instantiate_result == WASMER_OK); + + wasmer_export_descriptors_t *exports = NULL; + wasmer_export_descriptors(module, &exports); + + int exports_len = wasmer_export_descriptors_len(exports); + printf("exports_len: %d\n", exports_len); + assert(exports_len == 1); + + wasmer_export_descriptor_t *export = wasmer_export_descriptors_get(exports, 0); + + wasmer_import_export_kind kind = wasmer_export_descriptor_kind(export); + assert(kind == WASM_FUNCTION); + + wasmer_byte_array name_bytes = wasmer_export_descriptor_name(export); + assert(name_bytes.bytes_len == 3); + char expected[] = {'s', 'u', 'm'}; + for(int idx = 0; idx < 3; idx++){ + printf("%c\n", name_bytes.bytes[idx]); + assert(name_bytes.bytes[idx] == expected[idx]); + } + + printf("Destroy module\n"); + wasmer_module_destroy(module); + printf("Destroy exports\n"); + wasmer_export_descriptors_destroy(exports); + 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 6c0494e01..f1d2245c0 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -35,7 +35,7 @@ typedef struct wasmer_module_t wasmer_module_t; typedef struct { -} wasmer_export_t; +} wasmer_export_descriptor_t; typedef struct { const uint8_t *bytes; @@ -44,6 +44,14 @@ typedef struct { typedef struct { +} wasmer_export_descriptors_t; + +typedef struct { + +} wasmer_export_t; + +typedef struct { + } wasmer_func_t; typedef struct { @@ -113,6 +121,39 @@ wasmer_result_t wasmer_compile(wasmer_module_t **module, uint8_t *wasm_bytes, uint32_t wasm_bytes_len); +/** + * Gets export descriptor kind + */ +wasmer_import_export_kind wasmer_export_descriptor_kind(wasmer_export_descriptor_t *export_); + +/** + * Gets name for the export descriptor + */ +wasmer_byte_array wasmer_export_descriptor_name(wasmer_export_descriptor_t *export_descriptor); + +/** + * Gets export descriptors for the given module + * The caller owns the object and should call `wasmer_export_descriptors_destroy` to free it. + */ +void wasmer_export_descriptors(wasmer_module_t *module, + wasmer_export_descriptors_t **export_descriptors); + +/** + * Frees the memory for the given export descriptors + */ +void wasmer_export_descriptors_destroy(wasmer_export_descriptors_t *export_descriptors); + +/** + * Gets export descriptor by index + */ +wasmer_export_descriptor_t *wasmer_export_descriptors_get(wasmer_export_descriptors_t *export_descriptors, + int idx); + +/** + * Gets the length of the export descriptors + */ +int wasmer_export_descriptors_len(wasmer_export_descriptors_t *exports); + /** * Gets wasmer_export kind */ diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 2bb55de45..c0f2234f5 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -30,7 +30,7 @@ struct wasmer_instance_t; struct wasmer_module_t; -struct wasmer_export_t { +struct wasmer_export_descriptor_t { }; @@ -39,6 +39,14 @@ struct wasmer_byte_array { uint32_t bytes_len; }; +struct wasmer_export_descriptors_t { + +}; + +struct wasmer_export_t { + +}; + struct wasmer_func_t { }; @@ -110,6 +118,27 @@ wasmer_result_t wasmer_compile(wasmer_module_t **module, uint8_t *wasm_bytes, uint32_t wasm_bytes_len); +/// Gets export descriptor kind +wasmer_import_export_kind wasmer_export_descriptor_kind(wasmer_export_descriptor_t *export_); + +/// Gets name for the export descriptor +wasmer_byte_array wasmer_export_descriptor_name(wasmer_export_descriptor_t *export_descriptor); + +/// Gets export descriptors for the given module +/// The caller owns the object and should call `wasmer_export_descriptors_destroy` to free it. +void wasmer_export_descriptors(wasmer_module_t *module, + wasmer_export_descriptors_t **export_descriptors); + +/// Frees the memory for the given export descriptors +void wasmer_export_descriptors_destroy(wasmer_export_descriptors_t *export_descriptors); + +/// Gets export descriptor by index +wasmer_export_descriptor_t *wasmer_export_descriptors_get(wasmer_export_descriptors_t *export_descriptors, + int idx); + +/// Gets the length of the export descriptors +int wasmer_export_descriptors_len(wasmer_export_descriptors_t *exports); + /// Gets wasmer_export kind wasmer_import_export_kind wasmer_export_kind(wasmer_export_t *export_);