Skip to content

Commit

Permalink
Merge #616
Browse files Browse the repository at this point in the history
616: runtime-c-api: create the import object separately from instance instantiation  r=bjfish a=YaronWittenstein

Creating an `import object` separately from the `wasmer` instance, let's us build the import object incrementally and support the use-case of having import functions (a.k.a `vmcalls`) implemented in 2 programming languages (Rust and Golang for example) and consumed by the same `wasmer` instance.

Co-authored-by: Yaron Wittenstein <[email protected]>
Co-authored-by: Brandon Fish <[email protected]>
  • Loading branch information
3 people committed Aug 2, 2019
2 parents 315c72e + 2a5aaee commit 9489af4
Show file tree
Hide file tree
Showing 11 changed files with 364 additions and 18 deletions.
91 changes: 90 additions & 1 deletion lib/runtime-c-api/src/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ use crate::{
};
use libc::c_uint;
use std::{ffi::c_void, ptr, slice, sync::Arc};
use wasmer_runtime::Module;
use wasmer_runtime::{Global, Memory, Module, Table};
use wasmer_runtime_core::{
export::{Context, Export, FuncPointer},
import::ImportObject,
module::ImportName,
types::{FuncSig, Type},
};
Expand All @@ -25,6 +26,9 @@ pub struct wasmer_import_t {
pub value: wasmer_import_export_value,
}

#[repr(C)]
pub struct wasmer_import_object_t;

#[repr(C)]
#[derive(Clone)]
pub struct wasmer_import_func_t;
Expand All @@ -37,6 +41,83 @@ pub struct wasmer_import_descriptor_t;
#[derive(Clone)]
pub struct wasmer_import_descriptors_t;

/// Creates a new empty import object.
/// See also `wasmer_import_object_append`
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
pub unsafe extern "C" fn wasmer_import_object_new() -> *mut wasmer_import_object_t {
let import_object = Box::new(ImportObject::new());

Box::into_raw(import_object) as *mut wasmer_import_object_t
}

/// Extends an existing import object with new imports
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
pub unsafe extern "C" fn wasmer_import_object_extend(
import_object: *mut wasmer_import_object_t,
imports: *mut wasmer_import_t,
imports_len: c_uint,
) -> wasmer_result_t {
let import_object: &mut ImportObject = &mut *(import_object as *mut ImportObject);

let mut extensions: Vec<(String, String, Export)> = Vec::new();

let imports: &[wasmer_import_t] = slice::from_raw_parts(imports, imports_len as usize);
for import in imports {
let module_name = slice::from_raw_parts(
import.module_name.bytes,
import.module_name.bytes_len as usize,
);
let module_name = if let Ok(s) = std::str::from_utf8(module_name) {
s
} else {
update_last_error(CApiError {
msg: "error converting module name to string".to_string(),
});
return wasmer_result_t::WASMER_ERROR;
};
let import_name = slice::from_raw_parts(
import.import_name.bytes,
import.import_name.bytes_len as usize,
);
let import_name = if let Ok(s) = std::str::from_utf8(import_name) {
s
} else {
update_last_error(CApiError {
msg: "error converting import_name to string".to_string(),
});
return wasmer_result_t::WASMER_ERROR;
};

let export = match import.tag {
wasmer_import_export_kind::WASM_MEMORY => {
let mem = import.value.memory as *mut Memory;
Export::Memory((&*mem).clone())
}
wasmer_import_export_kind::WASM_FUNCTION => {
let func_export = import.value.func as *mut Export;
(&*func_export).clone()
}
wasmer_import_export_kind::WASM_GLOBAL => {
let global = import.value.global as *mut Global;
Export::Global((&*global).clone())
}
wasmer_import_export_kind::WASM_TABLE => {
let table = import.value.table as *mut Table;
Export::Table((&*table).clone())
}
};

let extension = (module_name.to_string(), import_name.to_string(), export);
extensions.push(extension)
}

import_object.extend(extensions);

return wasmer_result_t::WASMER_OK;
}

/// Gets import descriptors for the given module
///
/// The caller owns the object and should call `wasmer_import_descriptors_destroy` to free it.
Expand Down Expand Up @@ -352,6 +433,14 @@ pub extern "C" fn wasmer_import_func_destroy(func: *mut wasmer_import_func_t) {
}
}

/// Frees memory of the given ImportObject
#[no_mangle]
pub extern "C" fn wasmer_import_object_destroy(import_object: *mut wasmer_import_object_t) {
if !import_object.is_null() {
unsafe { Box::from_raw(import_object as *mut ImportObject) };
}
}

struct NamedImportDescriptor {
module: String,
name: String,
Expand Down
36 changes: 33 additions & 3 deletions lib/runtime-c-api/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@
use crate::{
error::{update_last_error, CApiError},
export::{wasmer_exports_t, wasmer_import_export_kind, NamedExport, NamedExports},
import::wasmer_import_t,
import::{wasmer_import_object_t, wasmer_import_t},
memory::wasmer_memory_t,
module::wasmer_module_t,
value::{wasmer_value, wasmer_value_t, wasmer_value_tag},
wasmer_result_t,
};
use libc::{c_char, c_int, c_void};
use std::{collections::HashMap, ffi::CStr, slice};
use wasmer_runtime::{Ctx, Global, ImportObject, Instance, Memory, Table, Value};
use wasmer_runtime_core::{export::Export, import::Namespace};
use wasmer_runtime::{Ctx, Global, Instance, Memory, Module, Table, Value};
use wasmer_runtime_core::{
export::Export,
import::{ImportObject, Namespace},
};

#[repr(C)]
pub struct wasmer_instance_t;
Expand Down Expand Up @@ -108,6 +112,32 @@ pub unsafe extern "C" fn wasmer_instantiate(
wasmer_result_t::WASMER_OK
}

/// Given:
/// * A prepared `wasmer` import-object
/// * A compiled wasmer module
///
/// Instantiates a wasmer instance
#[no_mangle]
pub unsafe extern "C" fn wasmer_module_import_instantiate(
instance: *mut *mut wasmer_instance_t,
module: *const wasmer_module_t,
import_object: *const wasmer_import_object_t,
) -> wasmer_result_t {
let import_object: &ImportObject = &*(import_object as *const ImportObject);
let module: &Module = &*(module as *const Module);

let new_instance: Instance = match module.instantiate(import_object) {
Ok(instance) => instance,
Err(error) => {
update_last_error(error);
return wasmer_result_t::WASMER_ERROR;
}
};
*instance = Box::into_raw(Box::new(new_instance)) as *mut wasmer_instance_t;

return wasmer_result_t::WASMER_OK;
}

/// Extracts the instance's context and returns it.
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
Expand Down
1 change: 1 addition & 0 deletions lib/runtime-c-api/tests/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ test-module-serialize
test-tables
test-validate
test-context
test-module-import-instantiate
5 changes: 5 additions & 0 deletions lib/runtime-c-api/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ add_executable(test-module-serialize test-module-serialize.c)
add_executable(test-tables test-tables.c)
add_executable(test-validate test-validate.c)
add_executable(test-context test-context.c)
add_executable(test-module-import-instantiate test-module-import-instantiate.c)

find_library(
WASMER_LIB NAMES libwasmer_runtime_c_api.dylib libwasmer_runtime_c_api.so libwasmer_runtime_c_api.dll
Expand Down Expand Up @@ -92,3 +93,7 @@ add_test(test-validate test-validate)
target_link_libraries(test-context general ${WASMER_LIB})
target_compile_options(test-context PRIVATE ${COMPILER_OPTIONS})
add_test(test-context test-context)

target_link_libraries(test-module-import-instantiate general ${WASMER_LIB})
target_compile_options(test-module-import-instantiate PRIVATE ${COMPILER_OPTIONS})
add_test(test-module-import-instantiate test-module-import-instantiate)
Binary file modified lib/runtime-c-api/tests/assets/inc.wasm
Binary file not shown.
5 changes: 5 additions & 0 deletions lib/runtime-c-api/tests/assets/inc.wast
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
(module
(func $inc (import "env" "inc"))
(func $mul (import "env" "mul"))
(func $get (import "env" "get") (result i32))

(func (export "inc_and_get") (result i32)
call $inc
call $get)

(func (export "mul_and_get") (result i32)
call $mul
call $get))
17 changes: 14 additions & 3 deletions lib/runtime-c-api/tests/test-context.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ void inc_counter(wasmer_instance_context_t *ctx) {
data->value = data->value + data->amount;
}

void mul_counter(wasmer_instance_context_t *ctx) {
counter_data* data = (counter_data*)wasmer_instance_context_data_get(ctx);
data->value = data->value * data->amount;
}

int32_t get_counter(wasmer_instance_context_t *ctx) {
counter_data* data = (counter_data*)wasmer_instance_context_data_get(ctx);
return data->value;
Expand Down Expand Up @@ -90,21 +95,27 @@ int main()
wasmer_import_func_t *inc_func = wasmer_import_func_new((void (*)(void *)) inc_counter, inc_params_sig, 0, inc_returns_sig, 0);
wasmer_import_t inc_import = create_import("env", "inc", inc_func);

wasmer_value_tag mul_params_sig[] = {};
wasmer_value_tag mul_returns_sig[] = {};
wasmer_import_func_t *mul_func = wasmer_import_func_new((void (*)(void *)) mul_counter, mul_params_sig, 0, mul_returns_sig, 0);
wasmer_import_t mul_import = create_import("env", "mul", mul_func);

wasmer_value_tag get_params_sig[] = {};
wasmer_value_tag get_returns_sig[] = {WASM_I32};
wasmer_import_func_t *get_func = wasmer_import_func_new((void (*)(void *)) get_counter, get_params_sig, 0, get_returns_sig, 1);
wasmer_import_t get_import = create_import("env", "get", get_func);

wasmer_import_t imports[] = {inc_import, get_import};
wasmer_import_t imports[] = {inc_import, mul_import, get_import};

// Read the wasm file
wasm_file_t wasm_file = read_wasm_file("assets/inc.wasm");

// Instantiate instance
printf("Instantiating\n");
wasmer_instance_t *instance = NULL;
wasmer_result_t compile_result = wasmer_instantiate(&instance, wasm_file.bytes, wasm_file.bytes_len, imports, 2);
printf("Compile result: %d\n", compile_result);
wasmer_result_t instantiate_res = wasmer_instantiate(&instance, wasm_file.bytes, wasm_file.bytes_len, imports, 3);
printf("Compile result: %d\n", instantiate_res);
assert(instantiate_res == WASMER_OK);

// Init counter
counter_data *counter = init_counter(2, 5);
Expand Down
Loading

0 comments on commit 9489af4

Please sign in to comment.