Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Implement wasmer_module_serialize and wasmer_module_deserialize functions in runtime-c-api #271

Merged
merged 17 commits into from
Mar 19, 2019
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 102 additions & 4 deletions lib/runtime-c-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -165,7 +170,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(wasm_bytes, wasm_bytes_len as usize);

wasmer_runtime_core::validate(bytes)
}
Expand Down Expand Up @@ -391,7 +396,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,
Expand Down Expand Up @@ -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);
Hywan marked this conversation as resolved.
Show resolved Hide resolved

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 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.
Hywan marked this conversation as resolved.
Show resolved Hide resolved
#[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()) {
Hywan marked this conversation as resolved.
Show resolved Hide resolved
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]
Expand Down Expand Up @@ -831,7 +929,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,
Expand Down
13 changes: 7 additions & 6 deletions lib/runtime-c-api/tests/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ 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-module-serialize
test-tables
test-validate
rust-build
test-validate
43 changes: 24 additions & 19 deletions lib/runtime-c-api/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
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-module-serialize test-module-serialize.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
Expand All @@ -34,10 +35,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)
Expand All @@ -46,22 +43,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)
Expand All @@ -70,10 +67,18 @@ 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-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)

target_link_libraries(test-validate general ${WASMER_LIB})
target_compile_options(test-validate PRIVATE ${COMPILER_OPTIONS})
add_test(test-validate test-validate)
75 changes: 75 additions & 0 deletions lib/runtime-c-api/tests/test-module-serialize.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#include <stdio.h>
#include "../wasmer.h"
#include <assert.h>
#include <stdint.h>

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;
}
22 changes: 22 additions & 0 deletions lib/runtime-c-api/wasmer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 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.
*/
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
*/
Expand All @@ -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
*/
Expand Down
Loading