From 92ff24f5a2e7dd15a741ce3291f959328a30fe97 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Fri, 15 Mar 2019 11:39:21 +0100 Subject: [PATCH 01/13] feat(runtime) Make `default_compiler` public. This is required to be able to deserialize a serialized module in `runtime-c-api`. --- lib/runtime/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index 4ad74c34595..fb8d2d80f34 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -152,7 +152,8 @@ pub fn instantiate(wasm: &[u8], import_object: &ImportObject) -> error::Result &'static dyn Compiler { +/// Get a single instance of the default compiler to use. +pub fn default_compiler() -> &'static dyn Compiler { use lazy_static::lazy_static; #[cfg(feature = "llvm")] From f57f8bc0cb7eef445085e96fe950fd029818708b Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Fri, 15 Mar 2019 11:40:39 +0100 Subject: [PATCH 02/13] fix(runtime-c-api) Use imported symbols. `std::slice` is already imported. This patch then rewrites `::std::slice::` into `slice::`. --- lib/runtime-c-api/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index a66f584e422..6318147f9d6 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -165,7 +165,7 @@ pub unsafe extern "C" fn wasmer_validate( if wasm_bytes.is_null() { return false; } - let bytes: &[u8] = ::std::slice::from_raw_parts(wasm_bytes, wasm_bytes_len as usize); + let bytes: &[u8] = slice::from_raw_parts_mut(wasm_bytes, wasm_bytes_len as usize); wasmer_runtime_core::validate(bytes) } @@ -391,7 +391,7 @@ pub unsafe extern "C" fn wasmer_compile( wasm_bytes: *mut uint8_t, wasm_bytes_len: uint32_t, ) -> wasmer_result_t { - let bytes: &[u8] = ::std::slice::from_raw_parts_mut(wasm_bytes, wasm_bytes_len as usize); + let bytes: &[u8] = slice::from_raw_parts_mut(wasm_bytes, wasm_bytes_len as usize); let result = wasmer_runtime::compile(bytes); let new_module = match result { Ok(instance) => instance, @@ -831,7 +831,7 @@ pub unsafe extern "C" fn wasmer_instantiate( import_object.register(module_name, namespace); } - let bytes: &[u8] = ::std::slice::from_raw_parts_mut(wasm_bytes, wasm_bytes_len as usize); + let bytes: &[u8] = slice::from_raw_parts_mut(wasm_bytes, wasm_bytes_len as usize); let result = wasmer_runtime::instantiate(bytes, &import_object); let new_instance = match result { Ok(instance) => instance, From c142e16d12ad4e72f3a01ade9e870ace9ff2b595 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Fri, 15 Mar 2019 11:48:26 +0100 Subject: [PATCH 03/13] feat(runtime-c-api) Implement the `wasmer_module_(de)?serialize` functions. This patch implements 2 functions: 1. `wasmer_module_serialize`, and 2. `wasmer_module_deserialize`. --- lib/runtime-c-api/src/lib.rs | 100 ++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 1 deletion(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 6318147f9d6..6c98afb93b4 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -7,12 +7,17 @@ use std::collections::HashMap; use std::error::Error; use std::ffi::CStr; use std::fmt; +use std::mem; use std::slice; use std::sync::Arc; use std::{ffi::c_void, ptr}; -use wasmer_runtime::{Ctx, Global, ImportObject, Instance, Memory, Module, Table, Value}; +use wasmer_runtime::{ + default_compiler, Ctx, Global, ImportObject, Instance, Memory, Module, Table, Value, +}; +use wasmer_runtime_core::cache::Artifact; use wasmer_runtime_core::export::{Context, Export, FuncPointer}; use wasmer_runtime_core::import::Namespace; +use wasmer_runtime_core::load_cache_with; use wasmer_runtime_core::module::{ExportIndex, ImportName}; use wasmer_runtime_core::types::{ElementType, FuncSig, MemoryDescriptor, TableDescriptor, Type}; use wasmer_runtime_core::units::{Bytes, Pages}; @@ -569,6 +574,99 @@ pub unsafe extern "C" fn wasmer_export_descriptor_kind( named_export_descriptor.kind.clone() } +/// Serialize the given Module. +/// +/// It's up to the caller to free the memory of the +/// `serialized_module` byte array (both the `bytes` field and the +/// structure). +/// +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub unsafe extern "C" fn wasmer_module_serialize( + serialized_module: *mut *mut wasmer_byte_array, + module: *const wasmer_module_t, +) -> wasmer_result_t { + let module = &*(module as *const Module); + + match module.cache() { + Ok(artifact) => match artifact.serialize() { + Ok(serialized_artifact) => { + *serialized_module = Box::into_raw(Box::new(wasmer_byte_array { + bytes: serialized_artifact.as_ptr(), + bytes_len: serialized_artifact.len() as u32, + })) as *mut wasmer_byte_array; + + mem::forget(serialized_artifact); + + wasmer_result_t::WASMER_OK + } + Err(_) => { + update_last_error(CApiError { + msg: "Failed to serialize the module artifact".to_string(), + }); + wasmer_result_t::WASMER_ERROR + } + }, + Err(_) => { + update_last_error(CApiError { + msg: "Failed to serialize the module".to_string(), + }); + wasmer_result_t::WASMER_ERROR + } + } +} + +/// Deserialize the given Module. +/// +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub unsafe extern "C" fn wasmer_module_deserialize( + module: *mut *mut wasmer_module_t, + serialized_module_bytes: *const uint8_t, + serialized_module_bytes_len: uint32_t, +) -> wasmer_result_t { + if serialized_module_bytes.is_null() { + update_last_error(CApiError { + msg: "`serialized_module_bytes` pointer is null".to_string(), + }); + return wasmer_result_t::WASMER_ERROR; + } + + let serialized_module: &[u8] = slice::from_raw_parts( + serialized_module_bytes, + serialized_module_bytes_len as usize, + ); + + match Artifact::deserialize(serialized_module) { + Ok(artifact) => match load_cache_with(artifact, default_compiler()) { + Ok(deserialized_module) => { + *module = Box::into_raw(Box::new(deserialized_module)) as _; + wasmer_result_t::WASMER_OK + } + Err(_) => { + update_last_error(CApiError { + msg: "Failed to compile the serialized module".to_string(), + }); + wasmer_result_t::WASMER_ERROR + } + }, + Err(_) => { + update_last_error(CApiError { + msg: "Failed to deserialize the module".to_string(), + }); + wasmer_result_t::WASMER_ERROR + } + } +} + /// Frees memory for the given Module #[allow(clippy::cast_ptr_alignment)] #[no_mangle] From f2760249b61c68c874b0cf556b4d9b09f7723e21 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Fri, 15 Mar 2019 11:52:34 +0100 Subject: [PATCH 04/13] fix(runtime-c-api) Reorganize the tests by alphabetic order. --- lib/runtime-c-api/tests/.gitignore | 12 ++++---- lib/runtime-c-api/tests/CMakeLists.txt | 38 +++++++++++++------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/lib/runtime-c-api/tests/.gitignore b/lib/runtime-c-api/tests/.gitignore index 15e33d2cf6e..7b8c0645b30 100644 --- a/lib/runtime-c-api/tests/.gitignore +++ b/lib/runtime-c-api/tests/.gitignore @@ -9,15 +9,15 @@ install_manifest.txt compile_commands.json CTestTestfile.cmake _deps -test-globals +rust-build test-exports -test-instantiate -test-imports +test-globals test-import-function +test-imports +test-instantiate test-memory -test-module-imports test-module test-module-exports +test-module-imports test-tables -test-validate -rust-build \ No newline at end of file +test-validate \ 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 c94c748e15d..16526141893 100644 --- a/lib/runtime-c-api/tests/CMakeLists.txt +++ b/lib/runtime-c-api/tests/CMakeLists.txt @@ -1,17 +1,17 @@ cmake_minimum_required (VERSION 2.6) project (WasmerRuntimeCApiTests) -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) add_executable(test-import-function test-import-function.c) +add_executable(test-imports test-imports.c) +add_executable(test-instantiate test-instantiate.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-module-exports test-module-exports.c) -add_executable(test-validate test-validate.c) +add_executable(test-module-imports test-module-imports.c) add_executable(test-tables test-tables.c) +add_executable(test-validate test-validate.c) find_library( WASMER_LIB NAMES libwasmer_runtime_c_api.dylib libwasmer_runtime_c_api.so libwasmer_runtime_c_api.dll @@ -34,10 +34,6 @@ set( "/WX" > ) -target_link_libraries(test-imports general ${WASMER_LIB}) -target_compile_options(test-imports PRIVATE ${COMPILER_OPTIONS}) -add_test(test-imports test-imports) - target_link_libraries(test-exports general ${WASMER_LIB}) target_compile_options(test-exports PRIVATE ${COMPILER_OPTIONS}) add_test(test-exports test-exports) @@ -46,22 +42,22 @@ target_link_libraries(test-globals general ${WASMER_LIB}) target_compile_options(test-globals PRIVATE ${COMPILER_OPTIONS}) add_test(test-globals test-globals) -target_link_libraries(test-instantiate general ${WASMER_LIB}) -target_compile_options(test-instantiate PRIVATE ${COMPILER_OPTIONS}) -add_test(test-instantiate test-instantiate) - target_link_libraries(test-import-function general ${WASMER_LIB}) target_compile_options(test-import-function PRIVATE ${COMPILER_OPTIONS}) add_test(test-import-function test-import-function) +target_link_libraries(test-imports general ${WASMER_LIB}) +target_compile_options(test-imports PRIVATE ${COMPILER_OPTIONS}) +add_test(test-imports test-imports) + +target_link_libraries(test-instantiate general ${WASMER_LIB}) +target_compile_options(test-instantiate PRIVATE ${COMPILER_OPTIONS}) +add_test(test-instantiate test-instantiate) + target_link_libraries(test-memory general ${WASMER_LIB}) target_compile_options(test-memory PRIVATE ${COMPILER_OPTIONS}) add_test(test-memory test-memory) -target_link_libraries(test-module-imports general ${WASMER_LIB}) -target_compile_options(test-module-imports PRIVATE ${COMPILER_OPTIONS}) -add_test(test-module-imports test-module-imports) - target_link_libraries(test-module general ${WASMER_LIB}) target_compile_options(test-module PRIVATE ${COMPILER_OPTIONS}) add_test(test-module test-module) @@ -70,10 +66,14 @@ target_link_libraries(test-module-exports general ${WASMER_LIB}) target_compile_options(test-module-exports PRIVATE ${COMPILER_OPTIONS}) add_test(test-module-exports test-module-exports) -target_link_libraries(test-validate general ${WASMER_LIB}) -target_compile_options(test-validate PRIVATE ${COMPILER_OPTIONS}) -add_test(test-validate test-validate) +target_link_libraries(test-module-imports general ${WASMER_LIB}) +target_compile_options(test-module-imports PRIVATE ${COMPILER_OPTIONS}) +add_test(test-module-imports test-module-imports) target_link_libraries(test-tables general ${WASMER_LIB}) target_compile_options(test-tables PRIVATE ${COMPILER_OPTIONS}) add_test(test-tables test-tables) + +target_link_libraries(test-validate general ${WASMER_LIB}) +target_compile_options(test-validate PRIVATE ${COMPILER_OPTIONS}) +add_test(test-validate test-validate) From c8872f1a6fec2d1d650a7d191036f36377a7fbb4 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Fri, 15 Mar 2019 11:53:24 +0100 Subject: [PATCH 05/13] test(runtime-c-api) Test the new `wasmer_module_(de)?serialize` functions. This test suite compiles a module, then serializes it, deserializes it, and continues by creating an instance and calling a function on it. It allows to test the entire roundtrip. --- lib/runtime-c-api/tests/.gitignore | 1 + lib/runtime-c-api/tests/CMakeLists.txt | 5 ++ .../tests/test-module-serialize.c | 75 +++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 lib/runtime-c-api/tests/test-module-serialize.c diff --git a/lib/runtime-c-api/tests/.gitignore b/lib/runtime-c-api/tests/.gitignore index 7b8c0645b30..b8f6888c2a7 100644 --- a/lib/runtime-c-api/tests/.gitignore +++ b/lib/runtime-c-api/tests/.gitignore @@ -19,5 +19,6 @@ test-memory test-module test-module-exports test-module-imports +test-module-serialize test-tables test-validate \ 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 16526141893..136c0c1e919 100644 --- a/lib/runtime-c-api/tests/CMakeLists.txt +++ b/lib/runtime-c-api/tests/CMakeLists.txt @@ -10,6 +10,7 @@ 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-module-imports test-module-imports.c) +add_executable(test-module-serialize test-module-serialize.c) add_executable(test-tables test-tables.c) add_executable(test-validate test-validate.c) @@ -70,6 +71,10 @@ target_link_libraries(test-module-imports general ${WASMER_LIB}) target_compile_options(test-module-imports PRIVATE ${COMPILER_OPTIONS}) add_test(test-module-imports test-module-imports) +target_link_libraries(test-module-serialize general ${WASMER_LIB}) +target_compile_options(test-module-serialize PRIVATE ${COMPILER_OPTIONS}) +add_test(test-module-serialize test-module-serialize) + target_link_libraries(test-tables general ${WASMER_LIB}) target_compile_options(test-tables PRIVATE ${COMPILER_OPTIONS}) add_test(test-tables test-tables) diff --git a/lib/runtime-c-api/tests/test-module-serialize.c b/lib/runtime-c-api/tests/test-module-serialize.c new file mode 100644 index 00000000000..7c1ac092e41 --- /dev/null +++ b/lib/runtime-c-api/tests/test-module-serialize.c @@ -0,0 +1,75 @@ +#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_one = NULL; + wasmer_result_t compile_result = wasmer_compile(&module_one, bytes, len); + printf("Compile result: %d\n", compile_result); + assert(compile_result == WASMER_OK); + + wasmer_byte_array *serialized_module = NULL; + wasmer_result_t serialize_result = wasmer_module_serialize(&serialized_module, module_one); + printf("Serialize result: %d\n", serialize_result); + printf("Serialized module pointer: %p\n", serialized_module->bytes); + printf("Serialized module length: %d\n", serialized_module->bytes_len); + assert(serialize_result == WASMER_OK); + assert(serialized_module->bytes != NULL); + assert(serialized_module->bytes_len > 8); + assert(serialized_module->bytes[0] == 'W'); + assert(serialized_module->bytes[1] == 'A'); + assert(serialized_module->bytes[2] == 'S'); + assert(serialized_module->bytes[3] == 'M'); + assert(serialized_module->bytes[4] == 'E'); + assert(serialized_module->bytes[5] == 'R'); + + wasmer_module_t *module_two = NULL; + wasmer_result_t unserialize_result = wasmer_module_deserialize(&module_two, serialized_module->bytes, serialized_module->bytes_len); + assert(unserialize_result == WASMER_OK); + + wasmer_import_t imports[] = {}; + wasmer_instance_t *instance = NULL; + wasmer_result_t instantiate_result = wasmer_module_instantiate(module_two, &instance, imports, 0); + printf("Instantiate result: %d\n", compile_result); + assert(instantiate_result == WASMER_OK); + + wasmer_value_t param_one; + param_one.tag = WASM_I32; + param_one.value.I32 = 7; + wasmer_value_t param_two; + param_two.tag = WASM_I32; + param_two.value.I32 = 8; + wasmer_value_t params[] = {param_one, param_two}; + + wasmer_value_t result_one; + wasmer_value_t results[] = {result_one}; + + wasmer_result_t call_result = wasmer_instance_call(instance, "sum", params, 2, results, 1); + printf("Call result: %d\n", call_result); + printf("Result: %d\n", results[0].value.I32); + assert(results[0].value.I32 == 15); + assert(call_result == WASMER_OK); + + printf("Destroy the serialized module\n"); + free((uint8_t *) serialized_module->bytes); + free(serialized_module); + + printf("Destroy instance\n"); + wasmer_instance_destroy(instance); + + printf("Destroy modules\n"); + wasmer_module_destroy(module_one); + wasmer_module_destroy(module_two); + return 0; +} From 2368ce3a2005c69be1b0b134debffdd707df45b4 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Fri, 15 Mar 2019 11:55:30 +0100 Subject: [PATCH 06/13] chore(runtime-c-api) Regenerate the `wasmer.hh?` files. --- lib/runtime-c-api/wasmer.h | 22 ++++++++++++++++++++++ lib/runtime-c-api/wasmer.hh | 18 ++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 9a49d761787..c3a5d7122cc 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -488,6 +488,16 @@ uint32_t wasmer_memory_length(const wasmer_memory_t *memory); */ wasmer_result_t wasmer_memory_new(wasmer_memory_t **memory, wasmer_limits_t limits); +/** + * Deserialize the given Module. + * Returns `wasmer_result_t::WASMER_OK` upon success. + * Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` + * and `wasmer_last_error_message` to get an error message. + */ +wasmer_result_t wasmer_module_deserialize(wasmer_module_t **module, + const uint8_t *serialized_module_bytes, + uint32_t serialized_module_bytes_len); + /** * Frees memory for the given Module */ @@ -504,6 +514,18 @@ wasmer_result_t wasmer_module_instantiate(const wasmer_module_t *module, wasmer_import_t *imports, int imports_len); +/** + * Serialize the given Module. + * It's up to the caller to free the memory of the + * `serialized_module` byte array (both the `bytes` field and the + * structure). + * Returns `wasmer_result_t::WASMER_OK` upon success. + * Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` + * and `wasmer_last_error_message` to get an error message. + */ +wasmer_result_t wasmer_module_serialize(wasmer_byte_array **serialized_module, + const wasmer_module_t *module); + /** * Frees memory for the given Table */ diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 97260fe4bfa..850d185fa72 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -385,6 +385,14 @@ uint32_t wasmer_memory_length(const wasmer_memory_t *memory); /// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_memory_new(wasmer_memory_t **memory, wasmer_limits_t limits); +/// Deserialize the given Module. +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. +wasmer_result_t wasmer_module_deserialize(wasmer_module_t **module, + const uint8_t *serialized_module_bytes, + uint32_t serialized_module_bytes_len); + /// Frees memory for the given Module void wasmer_module_destroy(wasmer_module_t *module); @@ -397,6 +405,16 @@ wasmer_result_t wasmer_module_instantiate(const wasmer_module_t *module, wasmer_import_t *imports, int imports_len); +/// Serialize the given Module. +/// It's up to the caller to free the memory of the +/// `serialized_module` byte array (both the `bytes` field and the +/// structure). +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. +wasmer_result_t wasmer_module_serialize(wasmer_byte_array **serialized_module, + const wasmer_module_t *module); + /// Frees memory for the given Table void wasmer_table_destroy(wasmer_table_t *table); From 082c93ceba0aa0c93df5f862f1903fda9bcf63d5 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Fri, 15 Mar 2019 12:01:02 +0100 Subject: [PATCH 07/13] chore(runtime-c-api) Fix a merging error. --- lib/runtime-c-api/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 6c98afb93b4..8b241ffab7d 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -170,7 +170,7 @@ pub unsafe extern "C" fn wasmer_validate( if wasm_bytes.is_null() { return false; } - let bytes: &[u8] = slice::from_raw_parts_mut(wasm_bytes, wasm_bytes_len as usize); + let bytes: &[u8] = slice::from_raw_parts(wasm_bytes, wasm_bytes_len as usize); wasmer_runtime_core::validate(bytes) } From aac5c88b58ad06185c0fba1d6bacdfa53531a796 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Fri, 15 Mar 2019 12:18:52 +0100 Subject: [PATCH 08/13] doc(runtime-c-api) Update the documentation of `wasmer_module_deserialize`. --- lib/runtime-c-api/src/lib.rs | 2 +- lib/runtime-c-api/wasmer.h | 2 +- lib/runtime-c-api/wasmer.hh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 8b241ffab7d..2543e8fd820 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -620,7 +620,7 @@ pub unsafe extern "C" fn wasmer_module_serialize( } } -/// Deserialize the given Module. +/// Deserialize the given bytes into a Module. /// /// Returns `wasmer_result_t::WASMER_OK` upon success. /// diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index c3a5d7122cc..add281466a9 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -489,7 +489,7 @@ uint32_t wasmer_memory_length(const wasmer_memory_t *memory); wasmer_result_t wasmer_memory_new(wasmer_memory_t **memory, wasmer_limits_t limits); /** - * Deserialize the given Module. + * Deserialize the given bytes into a Module. * Returns `wasmer_result_t::WASMER_OK` upon success. * Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` * and `wasmer_last_error_message` to get an error message. diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 850d185fa72..d3619dd9a99 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -385,7 +385,7 @@ uint32_t wasmer_memory_length(const wasmer_memory_t *memory); /// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_memory_new(wasmer_memory_t **memory, wasmer_limits_t limits); -/// Deserialize the given Module. +/// Deserialize the given bytes into a Module. /// Returns `wasmer_result_t::WASMER_OK` upon success. /// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` /// and `wasmer_last_error_message` to get an error message. From 6605a02316b27abbdf2bd4c403d33d9512a106e3 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 18 Mar 2019 16:05:04 +0100 Subject: [PATCH 09/13] feat(runtime-c-api) Add the `wasmer_module_serialization_destroy` function. --- lib/runtime-c-api/src/lib.rs | 13 ++++++++++--- lib/runtime-c-api/tests/test-module-serialize.c | 3 +-- lib/runtime-c-api/wasmer.h | 9 ++++++--- lib/runtime-c-api/wasmer.hh | 7 ++++--- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 2543e8fd820..421b44ab21c 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -576,9 +576,7 @@ pub unsafe extern "C" fn wasmer_export_descriptor_kind( /// Serialize the given Module. /// -/// It's up to the caller to free the memory of the -/// `serialized_module` byte array (both the `bytes` field and the -/// structure). +/// The caller owns the object and should call `wasmer_memory_serialization_destroy` to free it. /// /// Returns `wasmer_result_t::WASMER_OK` upon success. /// @@ -620,6 +618,15 @@ pub unsafe extern "C" fn wasmer_module_serialize( } } +/// Frees memory for the given serialized Module. +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub extern "C" fn wasmer_module_serialization_destroy(serialized_module: *mut wasmer_byte_array) { + if !serialized_module.is_null() { + unsafe { Box::from_raw(serialized_module as *mut wasmer_byte_array) }; + } +} + /// Deserialize the given bytes into a Module. /// /// Returns `wasmer_result_t::WASMER_OK` upon success. diff --git a/lib/runtime-c-api/tests/test-module-serialize.c b/lib/runtime-c-api/tests/test-module-serialize.c index 7c1ac092e41..badcebd4683 100644 --- a/lib/runtime-c-api/tests/test-module-serialize.c +++ b/lib/runtime-c-api/tests/test-module-serialize.c @@ -62,8 +62,7 @@ int main() assert(call_result == WASMER_OK); printf("Destroy the serialized module\n"); - free((uint8_t *) serialized_module->bytes); - free(serialized_module); + wasmer_module_serialization_destroy(serialized_module); printf("Destroy instance\n"); wasmer_instance_destroy(instance); diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index add281466a9..758590a37de 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -514,11 +514,14 @@ wasmer_result_t wasmer_module_instantiate(const wasmer_module_t *module, wasmer_import_t *imports, int imports_len); +/** + * Frees memory for the given serialized Module. + */ +void wasmer_module_serialization_destroy(wasmer_byte_array *serialized_module); + /** * Serialize the given Module. - * It's up to the caller to free the memory of the - * `serialized_module` byte array (both the `bytes` field and the - * structure). + * The caller owns the object and should call `wasmer_memory_serialization_destroy` to free it. * Returns `wasmer_result_t::WASMER_OK` upon success. * Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` * and `wasmer_last_error_message` to get an error message. diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index d3619dd9a99..e05f78a533f 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -405,10 +405,11 @@ wasmer_result_t wasmer_module_instantiate(const wasmer_module_t *module, wasmer_import_t *imports, int imports_len); +/// Frees memory for the given serialized Module. +void wasmer_module_serialization_destroy(wasmer_byte_array *serialized_module); + /// Serialize the given Module. -/// It's up to the caller to free the memory of the -/// `serialized_module` byte array (both the `bytes` field and the -/// structure). +/// The caller owns the object and should call `wasmer_memory_serialization_destroy` to free it. /// Returns `wasmer_result_t::WASMER_OK` upon success. /// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` /// and `wasmer_last_error_message` to get an error message. From f049e9b0b378ae52b6cef467364f25fcff5ec2d8 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 18 Mar 2019 16:09:02 +0100 Subject: [PATCH 10/13] fix(runtime-c-api) Remove explicity `drop`. When the value goes out-of-scope, `drop` is called utomatically. --- lib/runtime-c-api/src/lib.rs | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 421b44ab21c..75c9acc8456 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -315,7 +315,7 @@ pub extern "C" fn wasmer_table_length(table: *mut wasmer_table_t) -> uint32_t { #[no_mangle] pub extern "C" fn wasmer_table_destroy(table: *mut wasmer_table_t) { if !table.is_null() { - drop(unsafe { Box::from_raw(table as *mut Table) }); + unsafe { Box::from_raw(table as *mut Table) }; } } @@ -370,7 +370,7 @@ pub extern "C" fn wasmer_global_get_descriptor( #[no_mangle] pub extern "C" fn wasmer_global_destroy(global: *mut wasmer_global_t) { if !global.is_null() { - drop(unsafe { Box::from_raw(global as *mut Global) }); + unsafe { Box::from_raw(global as *mut Global) }; } } @@ -379,7 +379,7 @@ pub extern "C" fn wasmer_global_destroy(global: *mut wasmer_global_t) { #[no_mangle] pub extern "C" fn wasmer_memory_destroy(memory: *mut wasmer_memory_t) { if !memory.is_null() { - drop(unsafe { Box::from_raw(memory as *mut Memory) }); + unsafe { Box::from_raw(memory as *mut Memory) }; } } @@ -514,13 +514,11 @@ 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( +pub extern "C" fn wasmer_export_descriptors_destroy( export_descriptors: *mut wasmer_export_descriptors_t, ) { if !export_descriptors.is_null() { - drop(Box::from_raw( - export_descriptors as *mut NamedExportDescriptors, - )); + unsafe { Box::from_raw(export_descriptors as *mut NamedExportDescriptors) }; } } @@ -679,7 +677,7 @@ pub unsafe extern "C" fn wasmer_module_deserialize( #[no_mangle] pub extern "C" fn wasmer_module_destroy(module: *mut wasmer_module_t) { if !module.is_null() { - drop(unsafe { Box::from_raw(module as *mut Module) }); + unsafe { Box::from_raw(module as *mut Module) }; } } @@ -787,13 +785,11 @@ 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( +pub extern "C" fn wasmer_import_descriptors_destroy( import_descriptors: *mut wasmer_import_descriptors_t, ) { if !import_descriptors.is_null() { - drop(Box::from_raw( - import_descriptors as *mut NamedImportDescriptors, - )); + unsafe { Box::from_raw(import_descriptors as *mut NamedImportDescriptors) }; } } @@ -1069,9 +1065,9 @@ 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) { +pub extern "C" fn wasmer_exports_destroy(exports: *mut wasmer_exports_t) { if !exports.is_null() { - drop(Box::from_raw(exports as *mut NamedExports)); + unsafe { Box::from_raw(exports as *mut NamedExports) }; } } @@ -1360,7 +1356,7 @@ pub unsafe extern "C" fn wasmer_import_func_returns_arity( #[no_mangle] pub extern "C" fn wasmer_import_func_destroy(func: *mut wasmer_import_func_t) { if !func.is_null() { - drop(unsafe { Box::from_raw(func as *mut Export) }); + unsafe { Box::from_raw(func as *mut Export) }; } } @@ -1500,7 +1496,7 @@ pub extern "C" fn wasmer_memory_data_length(mem: *mut wasmer_memory_t) -> uint32 #[no_mangle] pub extern "C" fn wasmer_instance_destroy(instance: *mut wasmer_instance_t) { if !instance.is_null() { - drop(unsafe { Box::from_raw(instance as *mut Instance) }); + unsafe { Box::from_raw(instance as *mut Instance) }; } } From 5e31a1b6d175d70ad9df7d017974e7ad3df205e3 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 19 Mar 2019 10:04:31 +0100 Subject: [PATCH 11/13] feat(runtime-c-api) Introduce the `wasmer_serialized_module_t` struct type. The `wasmer_module_serialize` function now computes a `wasmer_serialized_module_t` value. The `wasmer_module_deserialize` function takes this value as an input. Same for `wasmer_serialized_module_destroy`. The new function `wasmer_serialized_module_bytes` allows to read the bytes inside the `wasmer_serialized_mdule_t` structure. --- lib/runtime-c-api/src/lib.rs | 53 +++++++++++-------- .../tests/test-module-serialize.c | 28 +++++----- lib/runtime-c-api/wasmer.h | 28 ++++++---- lib/runtime-c-api/wasmer.hh | 22 +++++--- 4 files changed, 78 insertions(+), 53 deletions(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 75c9acc8456..56be1366dea 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -7,7 +7,6 @@ use std::collections::HashMap; use std::error::Error; use std::ffi::CStr; use std::fmt; -use std::mem; use std::slice; use std::sync::Arc; use std::{ffi::c_void, ptr}; @@ -25,6 +24,9 @@ use wasmer_runtime_core::units::{Bytes, Pages}; #[repr(C)] pub struct wasmer_module_t; +#[repr(C)] +pub struct wasmer_serialized_module_t; + #[repr(C)] pub struct wasmer_instance_t; @@ -574,7 +576,7 @@ pub unsafe extern "C" fn wasmer_export_descriptor_kind( /// Serialize the given Module. /// -/// The caller owns the object and should call `wasmer_memory_serialization_destroy` to free it. +/// The caller owns the object and should call `wasmer_serialized_module_destroy` to free it. /// /// Returns `wasmer_result_t::WASMER_OK` upon success. /// @@ -583,7 +585,7 @@ pub unsafe extern "C" fn wasmer_export_descriptor_kind( #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub unsafe extern "C" fn wasmer_module_serialize( - serialized_module: *mut *mut wasmer_byte_array, + serialized_module: *mut *mut wasmer_serialized_module_t, module: *const wasmer_module_t, ) -> wasmer_result_t { let module = &*(module as *const Module); @@ -591,12 +593,7 @@ pub unsafe extern "C" fn wasmer_module_serialize( match module.cache() { Ok(artifact) => match artifact.serialize() { Ok(serialized_artifact) => { - *serialized_module = Box::into_raw(Box::new(wasmer_byte_array { - bytes: serialized_artifact.as_ptr(), - bytes_len: serialized_artifact.len() as u32, - })) as *mut wasmer_byte_array; - - mem::forget(serialized_artifact); + *serialized_module = Box::into_raw(Box::new(serialized_artifact)) as _; wasmer_result_t::WASMER_OK } @@ -616,16 +613,21 @@ pub unsafe extern "C" fn wasmer_module_serialize( } } -/// Frees memory for the given serialized Module. +/// Get bytes of the serialized module. #[allow(clippy::cast_ptr_alignment)] #[no_mangle] -pub extern "C" fn wasmer_module_serialization_destroy(serialized_module: *mut wasmer_byte_array) { - if !serialized_module.is_null() { - unsafe { Box::from_raw(serialized_module as *mut wasmer_byte_array) }; +pub unsafe extern "C" fn wasmer_serialized_module_bytes( + serialized_module: *const wasmer_serialized_module_t, +) -> wasmer_byte_array { + let serialized_module = &*(serialized_module as *const &[u8]); + + wasmer_byte_array { + bytes: serialized_module.as_ptr(), + bytes_len: serialized_module.len() as u32, } } -/// Deserialize the given bytes into a Module. +/// Deserialize the given serialized module. /// /// Returns `wasmer_result_t::WASMER_OK` upon success. /// @@ -635,20 +637,16 @@ pub extern "C" fn wasmer_module_serialization_destroy(serialized_module: *mut wa #[no_mangle] pub unsafe extern "C" fn wasmer_module_deserialize( module: *mut *mut wasmer_module_t, - serialized_module_bytes: *const uint8_t, - serialized_module_bytes_len: uint32_t, + serialized_module: *const wasmer_serialized_module_t, ) -> wasmer_result_t { - if serialized_module_bytes.is_null() { + if serialized_module.is_null() { update_last_error(CApiError { - msg: "`serialized_module_bytes` pointer is null".to_string(), + msg: "`serialized_module` pointer is null".to_string(), }); return wasmer_result_t::WASMER_ERROR; } - let serialized_module: &[u8] = slice::from_raw_parts( - serialized_module_bytes, - serialized_module_bytes_len as usize, - ); + let serialized_module: &[u8] = &*(serialized_module as *const &[u8]); match Artifact::deserialize(serialized_module) { Ok(artifact) => match load_cache_with(artifact, default_compiler()) { @@ -672,6 +670,17 @@ pub unsafe extern "C" fn wasmer_module_deserialize( } } +/// Frees memory for the given serialized Module. +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub extern "C" fn wasmer_serialized_module_destroy( + serialized_module: *mut wasmer_serialized_module_t, +) { + if !serialized_module.is_null() { + unsafe { Box::from_raw(serialized_module as *mut &[u8]) }; + } +} + /// Frees memory for the given Module #[allow(clippy::cast_ptr_alignment)] #[no_mangle] diff --git a/lib/runtime-c-api/tests/test-module-serialize.c b/lib/runtime-c-api/tests/test-module-serialize.c index badcebd4683..e1b8db79e8f 100644 --- a/lib/runtime-c-api/tests/test-module-serialize.c +++ b/lib/runtime-c-api/tests/test-module-serialize.c @@ -19,23 +19,25 @@ int main() printf("Compile result: %d\n", compile_result); assert(compile_result == WASMER_OK); - wasmer_byte_array *serialized_module = NULL; + wasmer_serialized_module_t *serialized_module = NULL; wasmer_result_t serialize_result = wasmer_module_serialize(&serialized_module, module_one); printf("Serialize result: %d\n", serialize_result); - printf("Serialized module pointer: %p\n", serialized_module->bytes); - printf("Serialized module length: %d\n", serialized_module->bytes_len); assert(serialize_result == WASMER_OK); - assert(serialized_module->bytes != NULL); - assert(serialized_module->bytes_len > 8); - assert(serialized_module->bytes[0] == 'W'); - assert(serialized_module->bytes[1] == 'A'); - assert(serialized_module->bytes[2] == 'S'); - assert(serialized_module->bytes[3] == 'M'); - assert(serialized_module->bytes[4] == 'E'); - assert(serialized_module->bytes[5] == 'R'); + + wasmer_byte_array serialized_module_bytes = wasmer_serialized_module_bytes(serialized_module); + printf("Serialized module pointer: %p\n", serialized_module_bytes.bytes); + printf("Serialized module length: %d\n", serialized_module_bytes.bytes_len); + assert(serialized_module_bytes.bytes != NULL); + assert(serialized_module_bytes.bytes_len > 8); + assert(serialized_module_bytes.bytes[0] == 'W'); + assert(serialized_module_bytes.bytes[1] == 'A'); + assert(serialized_module_bytes.bytes[2] == 'S'); + assert(serialized_module_bytes.bytes[3] == 'M'); + assert(serialized_module_bytes.bytes[4] == 'E'); + assert(serialized_module_bytes.bytes[5] == 'R'); wasmer_module_t *module_two = NULL; - wasmer_result_t unserialize_result = wasmer_module_deserialize(&module_two, serialized_module->bytes, serialized_module->bytes_len); + wasmer_result_t unserialize_result = wasmer_module_deserialize(&module_two, serialized_module); assert(unserialize_result == WASMER_OK); wasmer_import_t imports[] = {}; @@ -62,7 +64,7 @@ int main() assert(call_result == WASMER_OK); printf("Destroy the serialized module\n"); - wasmer_module_serialization_destroy(serialized_module); + wasmer_serialized_module_destroy(serialized_module); printf("Destroy instance\n"); wasmer_instance_destroy(instance); diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 758590a37de..04d583d49a8 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -129,6 +129,10 @@ typedef struct { wasmer_limit_option_t max; } wasmer_limits_t; +typedef struct { + +} wasmer_serialized_module_t; + /** * Creates a new Module from the given wasm bytes. * Returns `wasmer_result_t::WASMER_OK` upon success. @@ -489,14 +493,13 @@ uint32_t wasmer_memory_length(const wasmer_memory_t *memory); wasmer_result_t wasmer_memory_new(wasmer_memory_t **memory, wasmer_limits_t limits); /** - * Deserialize the given bytes into a Module. + * Deserialize the given serialized module. * Returns `wasmer_result_t::WASMER_OK` upon success. * Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` * and `wasmer_last_error_message` to get an error message. */ wasmer_result_t wasmer_module_deserialize(wasmer_module_t **module, - const uint8_t *serialized_module_bytes, - uint32_t serialized_module_bytes_len); + const wasmer_serialized_module_t *serialized_module); /** * Frees memory for the given Module @@ -514,21 +517,26 @@ wasmer_result_t wasmer_module_instantiate(const wasmer_module_t *module, wasmer_import_t *imports, int imports_len); -/** - * Frees memory for the given serialized Module. - */ -void wasmer_module_serialization_destroy(wasmer_byte_array *serialized_module); - /** * Serialize the given Module. - * The caller owns the object and should call `wasmer_memory_serialization_destroy` to free it. + * The caller owns the object and should call `wasmer_serialized_module_destroy` to free it. * Returns `wasmer_result_t::WASMER_OK` upon success. * Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` * and `wasmer_last_error_message` to get an error message. */ -wasmer_result_t wasmer_module_serialize(wasmer_byte_array **serialized_module, +wasmer_result_t wasmer_module_serialize(wasmer_serialized_module_t **serialized_module, const wasmer_module_t *module); +/** + * Get bytes of the serialized module. + */ +wasmer_byte_array wasmer_serialized_module_bytes(const wasmer_serialized_module_t *serialized_module); + +/** + * Frees memory for the given serialized Module. + */ +void wasmer_serialized_module_destroy(wasmer_serialized_module_t *serialized_module); + /** * Frees memory for the given Table */ diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index e05f78a533f..a4447258535 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -126,6 +126,10 @@ struct wasmer_limits_t { wasmer_limit_option_t max; }; +struct wasmer_serialized_module_t { + +}; + extern "C" { /// Creates a new Module from the given wasm bytes. @@ -385,13 +389,12 @@ uint32_t wasmer_memory_length(const wasmer_memory_t *memory); /// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_memory_new(wasmer_memory_t **memory, wasmer_limits_t limits); -/// Deserialize the given bytes into a Module. +/// Deserialize the given serialized module. /// Returns `wasmer_result_t::WASMER_OK` upon success. /// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` /// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_module_deserialize(wasmer_module_t **module, - const uint8_t *serialized_module_bytes, - uint32_t serialized_module_bytes_len); + const wasmer_serialized_module_t *serialized_module); /// Frees memory for the given Module void wasmer_module_destroy(wasmer_module_t *module); @@ -405,17 +408,20 @@ wasmer_result_t wasmer_module_instantiate(const wasmer_module_t *module, wasmer_import_t *imports, int imports_len); -/// Frees memory for the given serialized Module. -void wasmer_module_serialization_destroy(wasmer_byte_array *serialized_module); - /// Serialize the given Module. -/// The caller owns the object and should call `wasmer_memory_serialization_destroy` to free it. +/// The caller owns the object and should call `wasmer_serialized_module_destroy` to free it. /// Returns `wasmer_result_t::WASMER_OK` upon success. /// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` /// and `wasmer_last_error_message` to get an error message. -wasmer_result_t wasmer_module_serialize(wasmer_byte_array **serialized_module, +wasmer_result_t wasmer_module_serialize(wasmer_serialized_module_t **serialized_module, const wasmer_module_t *module); +/// Get bytes of the serialized module. +wasmer_byte_array wasmer_serialized_module_bytes(const wasmer_serialized_module_t *serialized_module); + +/// Frees memory for the given serialized Module. +void wasmer_serialized_module_destroy(wasmer_serialized_module_t *serialized_module); + /// Frees memory for the given Table void wasmer_table_destroy(wasmer_table_t *table); From 46edd20725454f2399378d24f76710701118f582 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 19 Mar 2019 10:51:43 +0100 Subject: [PATCH 12/13] feat(runtime-c-api) Add the `wasmer_serialized_module_from_bytes` function. This function is required to transform a `wasmer_byte_array` into a `wasmer_serialized_module_t`. This is the complementary function of `wasmer_serialized_module_bytes`. --- lib/runtime-c-api/src/lib.rs | 30 +++++++++++++++++++ .../tests/test-module-serialize.c | 13 ++++++++ lib/runtime-c-api/wasmer.h | 10 +++++++ lib/runtime-c-api/wasmer.hh | 8 +++++ 4 files changed, 61 insertions(+) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 56be1366dea..d53938f14ca 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -627,6 +627,36 @@ pub unsafe extern "C" fn wasmer_serialized_module_bytes( } } +/// Transform a sequence of bytes into a serialized module. +/// +/// The caller owns the object and should call `wasmer_serialized_module_destroy` to free it. +/// +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub unsafe extern "C" fn wasmer_serialized_module_from_bytes( + serialized_module: *mut *mut wasmer_serialized_module_t, + serialized_module_bytes: *const wasmer_byte_array, +) -> wasmer_result_t { + if serialized_module.is_null() { + update_last_error(CApiError { + msg: "`serialized_module_bytes` pointer is null".to_string(), + }); + return wasmer_result_t::WASMER_ERROR; + } + + let serialized_module_bytes: &[u8] = slice::from_raw_parts( + (*serialized_module_bytes).bytes, + (*serialized_module_bytes).bytes_len as usize, + ); + + *serialized_module = Box::into_raw(Box::new(serialized_module_bytes)) as _; + wasmer_result_t::WASMER_OK +} + /// Deserialize the given serialized module. /// /// Returns `wasmer_result_t::WASMER_OK` upon success. diff --git a/lib/runtime-c-api/tests/test-module-serialize.c b/lib/runtime-c-api/tests/test-module-serialize.c index e1b8db79e8f..a6edfc4adc5 100644 --- a/lib/runtime-c-api/tests/test-module-serialize.c +++ b/lib/runtime-c-api/tests/test-module-serialize.c @@ -63,8 +63,21 @@ int main() assert(results[0].value.I32 == 15); assert(call_result == WASMER_OK); + wasmer_serialized_module_t *serialized_module_two = NULL; + wasmer_result_t serialized_module_from_bytes_result = wasmer_serialized_module_from_bytes(&serialized_module_two, &serialized_module_bytes); + assert(serialized_module_from_bytes_result == WASMER_OK); + + wasmer_module_t *module_three = NULL; + wasmer_result_t unserialized_result_two = wasmer_module_deserialize(&module_three, serialized_module_two); + assert(unserialized_result_two == WASMER_OK); + + wasmer_instance_t *instance_two = NULL; + wasmer_result_t instantiate_result_two = wasmer_module_instantiate(module_three, &instance, imports, 0); + assert(instantiate_result_two == WASMER_OK); + printf("Destroy the serialized module\n"); wasmer_serialized_module_destroy(serialized_module); + wasmer_serialized_module_destroy(serialized_module_two); printf("Destroy instance\n"); wasmer_instance_destroy(instance); diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 04d583d49a8..2c52613022b 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -537,6 +537,16 @@ wasmer_byte_array wasmer_serialized_module_bytes(const wasmer_serialized_module_ */ void wasmer_serialized_module_destroy(wasmer_serialized_module_t *serialized_module); +/** + * Transform a sequence of bytes into a serialized module. + * The caller owns the object and should call `wasmer_serialized_module_destroy` to free it. + * Returns `wasmer_result_t::WASMER_OK` upon success. + * Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` + * and `wasmer_last_error_message` to get an error message. + */ +wasmer_result_t wasmer_serialized_module_from_bytes(wasmer_serialized_module_t **serialized_module, + const wasmer_byte_array *serialized_module_bytes); + /** * Frees memory for the given Table */ diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index a4447258535..ab2bca3af3e 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -422,6 +422,14 @@ wasmer_byte_array wasmer_serialized_module_bytes(const wasmer_serialized_module_ /// Frees memory for the given serialized Module. void wasmer_serialized_module_destroy(wasmer_serialized_module_t *serialized_module); +/// Transform a sequence of bytes into a serialized module. +/// The caller owns the object and should call `wasmer_serialized_module_destroy` to free it. +/// Returns `wasmer_result_t::WASMER_OK` upon success. +/// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` +/// and `wasmer_last_error_message` to get an error message. +wasmer_result_t wasmer_serialized_module_from_bytes(wasmer_serialized_module_t **serialized_module, + const wasmer_byte_array *serialized_module_bytes); + /// Frees memory for the given Table void wasmer_table_destroy(wasmer_table_t *table); From 57a82fa5cff57c30ef50ad8cfbf61811e64ffc69 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 19 Mar 2019 16:24:59 +0100 Subject: [PATCH 13/13] fix(runtime-c-api) `wasmer_serialized_module_from_bytes` accepts bytes + length instead of `wasmer_byte_array`. --- lib/runtime-c-api/src/lib.rs | 7 ++++--- lib/runtime-c-api/tests/test-module-serialize.c | 6 +++++- lib/runtime-c-api/wasmer.h | 3 ++- lib/runtime-c-api/wasmer.hh | 3 ++- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index d53938f14ca..e83d54bf37c 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -639,7 +639,8 @@ pub unsafe extern "C" fn wasmer_serialized_module_bytes( #[no_mangle] pub unsafe extern "C" fn wasmer_serialized_module_from_bytes( serialized_module: *mut *mut wasmer_serialized_module_t, - serialized_module_bytes: *const wasmer_byte_array, + serialized_module_bytes: *const uint8_t, + serialized_module_bytes_length: uint32_t, ) -> wasmer_result_t { if serialized_module.is_null() { update_last_error(CApiError { @@ -649,8 +650,8 @@ pub unsafe extern "C" fn wasmer_serialized_module_from_bytes( } let serialized_module_bytes: &[u8] = slice::from_raw_parts( - (*serialized_module_bytes).bytes, - (*serialized_module_bytes).bytes_len as usize, + serialized_module_bytes, + serialized_module_bytes_length as usize, ); *serialized_module = Box::into_raw(Box::new(serialized_module_bytes)) as _; diff --git a/lib/runtime-c-api/tests/test-module-serialize.c b/lib/runtime-c-api/tests/test-module-serialize.c index a6edfc4adc5..6f6a918813f 100644 --- a/lib/runtime-c-api/tests/test-module-serialize.c +++ b/lib/runtime-c-api/tests/test-module-serialize.c @@ -64,7 +64,11 @@ int main() assert(call_result == WASMER_OK); wasmer_serialized_module_t *serialized_module_two = NULL; - wasmer_result_t serialized_module_from_bytes_result = wasmer_serialized_module_from_bytes(&serialized_module_two, &serialized_module_bytes); + wasmer_result_t serialized_module_from_bytes_result = wasmer_serialized_module_from_bytes( + &serialized_module_two, + serialized_module_bytes.bytes, + serialized_module_bytes.bytes_len + ); assert(serialized_module_from_bytes_result == WASMER_OK); wasmer_module_t *module_three = NULL; diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 2c52613022b..7461b4d1fa8 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -545,7 +545,8 @@ void wasmer_serialized_module_destroy(wasmer_serialized_module_t *serialized_mod * and `wasmer_last_error_message` to get an error message. */ wasmer_result_t wasmer_serialized_module_from_bytes(wasmer_serialized_module_t **serialized_module, - const wasmer_byte_array *serialized_module_bytes); + const uint8_t *serialized_module_bytes, + uint32_t serialized_module_bytes_length); /** * Frees memory for the given Table diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index ab2bca3af3e..d90c22910f5 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -428,7 +428,8 @@ void wasmer_serialized_module_destroy(wasmer_serialized_module_t *serialized_mod /// Returns `wasmer_result_t::WASMER_ERROR` upon failure. Use `wasmer_last_error_length` /// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_serialized_module_from_bytes(wasmer_serialized_module_t **serialized_module, - const wasmer_byte_array *serialized_module_bytes); + const uint8_t *serialized_module_bytes, + uint32_t serialized_module_bytes_length); /// Frees memory for the given Table void wasmer_table_destroy(wasmer_table_t *table);