From 1dfa106850ef5d4b3e16368fc2fa2078c51d9d31 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sat, 23 Feb 2019 18:25:51 -0600 Subject: [PATCH 1/2] Add C API module import descriptors --- lib/runtime-c-api/src/lib.rs | 194 ++++++++++++++++++ lib/runtime-c-api/tests/.gitignore | 1 + lib/runtime-c-api/tests/CMakeLists.txt | 4 + lib/runtime-c-api/tests/test-module-imports.c | 56 +++++ lib/runtime-c-api/wasmer.h | 46 +++++ lib/runtime-c-api/wasmer.hh | 32 +++ 6 files changed, 333 insertions(+) create mode 100644 lib/runtime-c-api/tests/test-module-imports.c diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index f52076d28..ec19b249c 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::ImportName; use wasmer_runtime_core::types::{ElementType, FuncSig, MemoryDescriptor, TableDescriptor, Type}; use wasmer_runtime_core::units::{Bytes, Pages}; @@ -112,6 +113,14 @@ pub struct wasmer_import_t { value: wasmer_import_export_value, } +#[repr(C)] +#[derive(Clone)] +pub struct wasmer_import_descriptor_t; + +#[repr(C)] +#[derive(Clone)] +pub struct wasmer_import_descriptors_t; + #[repr(C)] #[derive(Clone)] pub struct wasmer_export_t; @@ -477,6 +486,185 @@ pub extern "C" fn wasmer_module_destroy(module: *mut wasmer_module_t) { } } +/// Gets import descriptors for the given module +/// +/// The caller owns the object and should call `wasmer_import_descriptors_destroy` to free it. +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub unsafe extern "C" fn wasmer_import_descriptors( + module: *mut wasmer_module_t, + import_descriptors: *mut *mut wasmer_import_descriptors_t, +) { + let mut module = unsafe { &*(module as *mut Module) }; + let total_imports = module.info().imported_functions.len() + + module.info().imported_tables.len() + + module.info().imported_globals.len() + + module.info().imported_memories.len(); + let mut descriptors: Vec = Vec::with_capacity(total_imports); + + for ( + index, + ImportName { + namespace_index, + name_index, + }, + ) in &module.info().imported_functions + { + let namespace = module.info().namespace_table.get(*namespace_index); + let name = module.info().name_table.get(*name_index); + descriptors.push(NamedImportDescriptor { + module: namespace.to_string(), + name: name.to_string(), + kind: wasmer_import_export_kind::WASM_FUNCTION, + }); + } + + for ( + index, + ( + ImportName { + namespace_index, + name_index, + }, + _, + ), + ) in &module.info().imported_tables + { + let namespace = module.info().namespace_table.get(*namespace_index); + let name = module.info().name_table.get(*name_index); + descriptors.push(NamedImportDescriptor { + module: namespace.to_string(), + name: name.to_string(), + kind: wasmer_import_export_kind::WASM_TABLE, + }); + } + + for ( + index, + ( + ImportName { + namespace_index, + name_index, + }, + _, + ), + ) in &module.info().imported_globals + { + let namespace = module.info().namespace_table.get(*namespace_index); + let name = module.info().name_table.get(*name_index); + descriptors.push(NamedImportDescriptor { + module: namespace.to_string(), + name: name.to_string(), + kind: wasmer_import_export_kind::WASM_GLOBAL, + }); + } + + for ( + index, + ( + ImportName { + namespace_index, + name_index, + }, + _, + ), + ) in &module.info().imported_memories + { + let namespace = module.info().namespace_table.get(*namespace_index); + let name = module.info().name_table.get(*name_index); + descriptors.push(NamedImportDescriptor { + module: namespace.to_string(), + name: name.to_string(), + kind: wasmer_import_export_kind::WASM_MEMORY, + }); + } + + let named_import_descriptors: Box = + Box::new(NamedImportDescriptors(descriptors)); + unsafe { + *import_descriptors = + Box::into_raw(named_import_descriptors) as *mut wasmer_import_descriptors_t + }; +} + +pub struct NamedImportDescriptors(Vec); + +/// Frees the memory for the given import descriptors +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub unsafe extern "C" fn wasmer_import_descriptors_destroy( + import_descriptors: *mut wasmer_import_descriptors_t, +) { + if !import_descriptors.is_null() { + drop(unsafe { Box::from_raw(import_descriptors as *mut NamedImportDescriptors) }); + } +} + +/// Gets the length of the import descriptors +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub unsafe extern "C" fn wasmer_import_descriptors_len( + exports: *mut wasmer_import_descriptors_t, +) -> c_int { + if exports.is_null() { + return 0; + } + (*(exports as *mut NamedImportDescriptors)).0.len() as c_int +} + +/// Gets import descriptor by index +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub unsafe extern "C" fn wasmer_import_descriptors_get( + import_descriptors: *mut wasmer_import_descriptors_t, + idx: c_int, +) -> *mut wasmer_import_descriptor_t { + if import_descriptors.is_null() { + return ptr::null_mut(); + } + let mut named_import_descriptors = + unsafe { &mut *(import_descriptors as *mut NamedImportDescriptors) }; + let ptr = &mut (*named_import_descriptors).0[idx as usize] as *mut NamedImportDescriptor + as *mut wasmer_import_descriptor_t; + ptr +} + +/// Gets name for the import descriptor +#[no_mangle] +#[allow(clippy::cast_ptr_alignment)] +pub unsafe extern "C" fn wasmer_import_descriptor_name( + import_descriptor: *mut wasmer_import_descriptor_t, +) -> wasmer_byte_array { + let named_import_descriptor = &*(import_descriptor as *mut NamedImportDescriptor); + wasmer_byte_array { + bytes: named_import_descriptor.name.as_ptr(), + bytes_len: named_import_descriptor.name.len() as u32, + } +} + +/// Gets module name for the import descriptor +#[no_mangle] +#[allow(clippy::cast_ptr_alignment)] +pub unsafe extern "C" fn wasmer_import_descriptor_module_name( + import_descriptor: *mut wasmer_import_descriptor_t, +) -> wasmer_byte_array { + let named_import_descriptor = &*(import_descriptor as *mut NamedImportDescriptor); + wasmer_byte_array { + bytes: named_import_descriptor.module.as_ptr(), + bytes_len: named_import_descriptor.module.len() as u32, + } +} + +/// Gets export descriptor kind +#[no_mangle] +#[allow(clippy::cast_ptr_alignment)] +pub unsafe extern "C" fn wasmer_import_descriptor_kind( + export: *mut wasmer_import_descriptor_t, +) -> wasmer_import_export_kind { + let named_import_descriptor = &*(export as *mut NamedImportDescriptor); + named_import_descriptor.kind.clone() +} + /// Creates a new Instance from the given wasm bytes and imports. /// /// Returns `wasmer_result_t::WASMER_OK` upon success. @@ -1169,6 +1357,12 @@ impl fmt::Display for CApiError { impl Error for CApiError {} +struct NamedImportDescriptor { + module: String, + name: String, + kind: wasmer_import_export_kind, +} + struct NamedExport { name: String, export: Export, diff --git a/lib/runtime-c-api/tests/.gitignore b/lib/runtime-c-api/tests/.gitignore index 6ea57c28d..773d7f43d 100644 --- a/lib/runtime-c-api/tests/.gitignore +++ b/lib/runtime-c-api/tests/.gitignore @@ -14,6 +14,7 @@ test-exports test-instantiate test-import-function test-memory +test-module-imports test-module test-tables test-validate diff --git a/lib/runtime-c-api/tests/CMakeLists.txt b/lib/runtime-c-api/tests/CMakeLists.txt index 788ee1c6a..2db4f219a 100644 --- a/lib/runtime-c-api/tests/CMakeLists.txt +++ b/lib/runtime-c-api/tests/CMakeLists.txt @@ -6,6 +6,7 @@ add_executable(test-globals test-globals.c) 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-imports test-module-imports.c) add_executable(test-module test-module.c) add_executable(test-validate test-validate.c) add_executable(test-tables test-tables.c) @@ -29,6 +30,8 @@ target_link_libraries(test-import-function general ${WASMER_LIB}) target_link_libraries(test-memory general ${WASMER_LIB}) +target_link_libraries(test-module-imports + general ${WASMER_LIB}) target_link_libraries(test-module general ${WASMER_LIB}) target_link_libraries(test-validate @@ -42,6 +45,7 @@ add_test(test-globals test-globals) add_test(test-instantiate test-instantiate) add_test(test-import-function test-import-function) add_test(test-memory test-memory) +add_test(test-module-imports test-module-imports) add_test(test-module test-module) add_test(test-validate test-validate) add_test(test-tables test-tables) diff --git a/lib/runtime-c-api/tests/test-module-imports.c b/lib/runtime-c-api/tests/test-module-imports.c new file mode 100644 index 000000000..47757c58c --- /dev/null +++ b/lib/runtime-c-api/tests/test-module-imports.c @@ -0,0 +1,56 @@ +#include +#include "../wasmer.h" +#include +#include + +int main() +{ + // Read the wasm file bytes + FILE *file = fopen("wasm_sample_app.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_descriptors_t *imports = NULL; + wasmer_import_descriptors(module, &imports); + + int imports_len = wasmer_import_descriptors_len(imports); + printf("imports_len: %d\n", imports_len); + assert(imports_len == 1); + + wasmer_import_descriptor_t *import = wasmer_import_descriptors_get(imports, 0); + + wasmer_import_export_kind kind = wasmer_import_descriptor_kind(import); + assert(kind == WASM_FUNCTION); + + wasmer_byte_array name_bytes = wasmer_import_descriptor_name(import); + assert(name_bytes.bytes_len == 9); + char expected[] = {'p', 'r', 'i', 'n', 't', '_', 's', 't', 'r'}; + + for(int idx = 0; idx < 9; idx++){ + printf("%c\n", name_bytes.bytes[idx]); + assert(name_bytes.bytes[idx] == expected[idx]); + } + + wasmer_byte_array module_name_bytes = wasmer_import_descriptor_module_name(import); + assert(module_name_bytes.bytes_len == 3); + char module_expected[] = {'e', 'n', 'v'}; + for(int idx = 0; idx < 3; idx++){ + printf("%c\n", module_name_bytes.bytes[idx]); + assert(module_name_bytes.bytes[idx] == module_expected[idx]); + } + + printf("Destroy module\n"); + wasmer_module_destroy(module); + printf("Destroy imports\n"); + wasmer_import_descriptors_destroy(imports); + 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..5f01ad65a 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -73,6 +73,14 @@ typedef struct { typedef struct { +} wasmer_import_descriptor_t; + +typedef struct { + +} wasmer_import_descriptors_t; + +typedef struct { + } wasmer_memory_t; typedef struct { @@ -231,6 +239,44 @@ wasmer_global_t *wasmer_global_new(wasmer_value_t value, bool mutable_); */ void wasmer_global_set(wasmer_global_t *global, wasmer_value_t value); +/** + * Gets export descriptor kind + */ +wasmer_import_export_kind wasmer_import_descriptor_kind(wasmer_import_descriptor_t *export_); + +/** + * Gets module name for the import descriptor + */ +wasmer_byte_array wasmer_import_descriptor_module_name(wasmer_import_descriptor_t *import_descriptor); + +/** + * Gets name for the import descriptor + */ +wasmer_byte_array wasmer_import_descriptor_name(wasmer_import_descriptor_t *import_descriptor); + +/** + * Gets import descriptors for the given module + * The caller owns the object and should call `wasmer_import_descriptors_destroy` to free it. + */ +void wasmer_import_descriptors(wasmer_module_t *module, + wasmer_import_descriptors_t **import_descriptors); + +/** + * Frees the memory for the given import descriptors + */ +void wasmer_import_descriptors_destroy(wasmer_import_descriptors_t *import_descriptors); + +/** + * Gets import descriptor by index + */ +wasmer_import_descriptor_t *wasmer_import_descriptors_get(wasmer_import_descriptors_t *import_descriptors, + int idx); + +/** + * Gets the length of the import descriptors + */ +int wasmer_import_descriptors_len(wasmer_import_descriptors_t *exports); + /** * Calls an instances exported function by `name` with the provided parameters. * Results are set using the provided `results` pointer. diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 2bb55de45..2af93433d 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -68,6 +68,14 @@ struct wasmer_global_descriptor_t { wasmer_value_tag kind; }; +struct wasmer_import_descriptor_t { + +}; + +struct wasmer_import_descriptors_t { + +}; + struct wasmer_memory_t { }; @@ -192,6 +200,30 @@ wasmer_global_t *wasmer_global_new(wasmer_value_t value, bool mutable_); /// Sets the value stored by the given Global void wasmer_global_set(wasmer_global_t *global, wasmer_value_t value); +/// Gets export descriptor kind +wasmer_import_export_kind wasmer_import_descriptor_kind(wasmer_import_descriptor_t *export_); + +/// Gets module name for the import descriptor +wasmer_byte_array wasmer_import_descriptor_module_name(wasmer_import_descriptor_t *import_descriptor); + +/// Gets name for the import descriptor +wasmer_byte_array wasmer_import_descriptor_name(wasmer_import_descriptor_t *import_descriptor); + +/// Gets import descriptors for the given module +/// The caller owns the object and should call `wasmer_import_descriptors_destroy` to free it. +void wasmer_import_descriptors(wasmer_module_t *module, + wasmer_import_descriptors_t **import_descriptors); + +/// Frees the memory for the given import descriptors +void wasmer_import_descriptors_destroy(wasmer_import_descriptors_t *import_descriptors); + +/// Gets import descriptor by index +wasmer_import_descriptor_t *wasmer_import_descriptors_get(wasmer_import_descriptors_t *import_descriptors, + int idx); + +/// Gets the length of the import descriptors +int wasmer_import_descriptors_len(wasmer_import_descriptors_t *exports); + /// Calls an instances exported function by `name` with the provided parameters. /// Results are set using the provided `results` pointer. /// Returns `wasmer_result_t::WASMER_OK` upon success. From 2a7a8c0069917d1ce5a8738f8ff99f989418167a Mon Sep 17 00:00:00 2001 From: Mackenzie Clark Date: Wed, 27 Feb 2019 10:41:22 -0800 Subject: [PATCH 2/2] newline in test-module-imports.c --- lib/runtime-c-api/tests/test-module-imports.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/runtime-c-api/tests/test-module-imports.c b/lib/runtime-c-api/tests/test-module-imports.c index 47757c58c..b63d308f2 100644 --- a/lib/runtime-c-api/tests/test-module-imports.c +++ b/lib/runtime-c-api/tests/test-module-imports.c @@ -53,4 +53,4 @@ int main() printf("Destroy imports\n"); wasmer_import_descriptors_destroy(imports); return 0; -} \ No newline at end of file +}