Skip to content

Commit

Permalink
Try #856:
Browse files Browse the repository at this point in the history
  • Loading branch information
bors[bot] authored Oct 25, 2019
2 parents 8653216 + aa82df7 commit de6269a
Show file tree
Hide file tree
Showing 20 changed files with 1,046 additions and 19 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## **[Unreleased]**

- [#883](https://github.com/wasmerio/wasmer/pull/883) Allow floating point operations to have arbitrary inputs, even including SNaNs.
- [#856](https://github.com/wasmerio/wasmer/pull/856) Expose methods in the runtime C API to get a WASI import object

## 0.9.0 - 2019-10-23

Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ capi:
test-capi: capi
cargo test -p wasmer-runtime-c-api --release

capi-test: test-capi

test-rest:
cargo test --release --all --exclude wasmer-runtime-c-api --exclude wasmer-emscripten --exclude wasmer-spectests --exclude wasmer-wasi --exclude wasmer-middleware-common --exclude wasmer-middleware-common-tests --exclude wasmer-singlepass-backend --exclude wasmer-clif-backend --exclude wasmer-llvm-backend --exclude wasmer-wasi-tests --exclude wasmer-emscripten-tests

Expand Down
9 changes: 8 additions & 1 deletion lib/runtime-c-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,19 @@ default-features = false
path = "../runtime-core"
version = "0.9.0"

[dependencies.wasmer-wasi]
default-features = false
path = "../wasi"
version = "0.9.0"
optional = true

[features]
default = ["cranelift-backend"]
default = ["cranelift-backend", "wasi"]
debug = ["wasmer-runtime/debug"]
cranelift-backend = ["wasmer-runtime/cranelift", "wasmer-runtime/default-backend-cranelift"]
llvm-backend = ["wasmer-runtime/llvm", "wasmer-runtime/default-backend-llvm"]
singlepass-backend = ["wasmer-runtime/singlepass", "wasmer-runtime/default-backend-singlepass"]
wasi = ["wasmer-wasi"]

[build-dependencies]
cbindgen = "0.9"
39 changes: 34 additions & 5 deletions lib/runtime-c-api/src/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,41 @@ pub union wasmer_import_export_value {
/// List of export/import kinds.
#[allow(non_camel_case_types)]
#[repr(u32)]
#[derive(Clone)]
#[derive(Clone, PartialEq, Eq)]
// ================
// ! DANGER !
// ================
// Do not modify these values without updating the `TryFrom` implementation below
pub enum wasmer_import_export_kind {
WASM_FUNCTION,
WASM_GLOBAL,
WASM_MEMORY,
WASM_TABLE,
WASM_FUNCTION = 0,
WASM_GLOBAL = 1,
WASM_MEMORY = 2,
WASM_TABLE = 3,
}

impl wasmer_import_export_kind {
pub fn to_str(&self) -> &'static str {
match self {
Self::WASM_FUNCTION => "function",
Self::WASM_GLOBAL => "global",
Self::WASM_MEMORY => "memory",
Self::WASM_TABLE => "table",
}
}
}

impl std::convert::TryFrom<u32> for wasmer_import_export_kind {
type Error = ();

fn try_from(value: u32) -> Result<Self, Self::Error> {
Ok(match value {
0 => Self::WASM_FUNCTION,
1 => Self::WASM_GLOBAL,
2 => Self::WASM_MEMORY,
3 => Self::WASM_TABLE,
_ => return Err(()),
})
}
}

/// Gets export descriptors for the given module
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{
wasmer_byte_array, wasmer_result_t,
};
use libc::c_uint;
use std::{ffi::c_void, ptr, slice, sync::Arc};
use std::{convert::TryFrom, ffi::c_void, ptr, slice, sync::Arc};
use wasmer_runtime::{Global, Memory, Module, Table};
use wasmer_runtime_core::{
export::{Context, Export, FuncPointer},
Expand Down Expand Up @@ -51,12 +51,252 @@ pub unsafe extern "C" fn wasmer_import_object_new() -> *mut wasmer_import_object
Box::into_raw(import_object) as *mut wasmer_import_object_t
}

#[cfg(feature = "wasi")]
mod wasi;

#[cfg(feature = "wasi")]
pub use self::wasi::*;

/// Gets an entry from an ImportObject at the name and namespace.
/// Stores an immutable reference to `name` and `namespace` in `import`.
///
/// The caller owns all data involved.
/// `import_export_value` will be written to based on `tag`, `import_export_value` must be
/// initialized to point to the type specified by `tag`. Failure to do so may result
/// in data corruption or undefined behavior.
#[no_mangle]
pub unsafe extern "C" fn wasmer_import_object_get_import(
import_object: *const wasmer_import_object_t,
namespace: wasmer_byte_array,
name: wasmer_byte_array,
import: *mut wasmer_import_t,
import_export_value: *mut wasmer_import_export_value,
tag: u32,
) -> wasmer_result_t {
let tag: wasmer_import_export_kind = if let Ok(t) = TryFrom::try_from(tag) {
t
} else {
update_last_error(CApiError {
msg: "wasmer_import_export_tag out of range".to_string(),
});
return wasmer_result_t::WASMER_ERROR;
};
let import_object: &mut ImportObject = &mut *(import_object as *mut ImportObject);
let namespace_str = if let Ok(ns) = namespace.as_str() {
ns
} else {
update_last_error(CApiError {
msg: "error converting namespace to UTF-8 string".to_string(),
});
return wasmer_result_t::WASMER_ERROR;
};
let name_str = if let Ok(name) = name.as_str() {
name
} else {
update_last_error(CApiError {
msg: "error converting name to UTF-8 string".to_string(),
});
return wasmer_result_t::WASMER_ERROR;
};
if import.is_null() || import_export_value.is_null() {
update_last_error(CApiError {
msg: "pointers to import and import_export_value must not be null".to_string(),
});
return wasmer_result_t::WASMER_ERROR;
}
let import_out = &mut *import;
let import_export_value_out = &mut *import_export_value;
if let Some(export) =
import_object.maybe_with_namespace(namespace_str, |ns| ns.get_export(name_str))
{
match export {
Export::Function { .. } => {
if tag != wasmer_import_export_kind::WASM_FUNCTION {
update_last_error(CApiError {
msg: format!("Found function, expected {}", tag.to_str()),
});
return wasmer_result_t::WASMER_ERROR;
}
import_out.tag = wasmer_import_export_kind::WASM_FUNCTION;
let writer = import_export_value_out.func as *mut Export;
*writer = export.clone();
}
Export::Memory(memory) => {
if tag != wasmer_import_export_kind::WASM_MEMORY {
update_last_error(CApiError {
msg: format!("Found memory, expected {}", tag.to_str()),
});
return wasmer_result_t::WASMER_ERROR;
}
import_out.tag = wasmer_import_export_kind::WASM_MEMORY;
let writer = import_export_value_out.func as *mut Memory;
*writer = memory.clone();
}
Export::Table(table) => {
if tag != wasmer_import_export_kind::WASM_TABLE {
update_last_error(CApiError {
msg: format!("Found table, expected {}", tag.to_str()),
});
return wasmer_result_t::WASMER_ERROR;
}
import_out.tag = wasmer_import_export_kind::WASM_TABLE;
let writer = import_export_value_out.func as *mut Table;
*writer = table.clone();
}
Export::Global(global) => {
if tag != wasmer_import_export_kind::WASM_GLOBAL {
update_last_error(CApiError {
msg: format!("Found global, expected {}", tag.to_str()),
});
return wasmer_result_t::WASMER_ERROR;
}
import_out.tag = wasmer_import_export_kind::WASM_GLOBAL;
let writer = import_export_value_out.func as *mut Global;
*writer = global.clone();
}
}

import_out.value = *import_export_value;
import_out.module_name = namespace;
import_out.import_name = name;

wasmer_result_t::WASMER_OK
} else {
update_last_error(CApiError {
msg: format!("Export {} {} not found", namespace_str, name_str),
});
wasmer_result_t::WASMER_ERROR
}
}

#[no_mangle]
/// Get the number of functions that an import object contains.
/// The result of this is useful as an argument to `wasmer_import_object_get_functions`.
/// This function returns -1 on error.
pub unsafe extern "C" fn wasmer_import_object_get_num_functions(
import_object: *const wasmer_import_object_t,
) -> i32 {
if import_object.is_null() {
update_last_error(CApiError {
msg: "import_object must not be null".to_owned(),
});
return -1;
}
let import_object: &ImportObject = &*(import_object as *const ImportObject);
import_object
.clone_ref()
.into_iter()
.filter(|(_, _, e)| {
if let Export::Function { .. } = e {
true
} else {
false
}
})
.count() as i32
}

#[no_mangle]
/// Call `wasmer_import_object_imports_destroy` to free the memory allocated by this function.
/// This function return -1 on error.
pub unsafe extern "C" fn wasmer_import_object_get_functions(
import_object: *const wasmer_import_object_t,
imports: *mut wasmer_import_t,
imports_len: u32,
) -> i32 {
if import_object.is_null() || imports.is_null() {
update_last_error(CApiError {
msg: "import_object and imports must not be null".to_owned(),
});
return -1;
}
let import_object: &ImportObject = &*(import_object as *const ImportObject);

let mut i = 0;
for (namespace, name, export) in import_object.clone_ref().into_iter() {
if i + 1 > imports_len {
return i as i32;
}
match export {
Export::Function { .. } => {
let ns = namespace.clone().into_bytes();
let ns_bytes = wasmer_byte_array {
bytes: ns.as_ptr(),
bytes_len: ns.len() as u32,
};
std::mem::forget(ns);

let name = name.clone().into_bytes();
let name_bytes = wasmer_byte_array {
bytes: name.as_ptr(),
bytes_len: name.len() as u32,
};
std::mem::forget(name);

let func = Box::new(export.clone());

let new_entry = wasmer_import_t {
module_name: ns_bytes,
import_name: name_bytes,
tag: wasmer_import_export_kind::WASM_FUNCTION,
value: wasmer_import_export_value {
func: Box::into_raw(func) as *mut _ as *const _,
},
};
*imports.add(i as usize) = new_entry;
i += 1;
}
_ => (),
}
}

return i as i32;
}

#[no_mangle]
/// Frees the memory acquired in `wasmer_import_object_get_functions`
///
/// This function does not free the memory in `wasmer_import_object_t`;
/// it only frees memory allocated while querying a `wasmer_import_object_t`.
pub unsafe extern "C" fn wasmer_import_object_imports_destroy(
imports: *mut wasmer_import_t,
imports_len: u32,
) {
let imports: &[wasmer_import_t] = &*slice::from_raw_parts_mut(imports, imports_len as usize);
for import in imports {
let _namespace: Vec<u8> = Vec::from_raw_parts(
import.module_name.bytes as *mut u8,
import.module_name.bytes_len as usize,
import.module_name.bytes_len as usize,
);
let _name: Vec<u8> = Vec::from_raw_parts(
import.import_name.bytes as *mut u8,
import.import_name.bytes_len as usize,
import.import_name.bytes_len as usize,
);
match import.tag {
wasmer_import_export_kind::WASM_FUNCTION => {
let _: Box<Export> = Box::from_raw(import.value.func as *mut _);
}
wasmer_import_export_kind::WASM_GLOBAL => {
let _: Box<Global> = Box::from_raw(import.value.global as *mut _);
}
wasmer_import_export_kind::WASM_MEMORY => {
let _: Box<Memory> = Box::from_raw(import.value.memory as *mut _);
}
wasmer_import_export_kind::WASM_TABLE => {
let _: Box<Table> = Box::from_raw(import.value.table as *mut _);
}
}
}
}

/// 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: *const wasmer_import_t,
imports_len: c_uint,
) -> wasmer_result_t {
let import_object: &mut ImportObject = &mut *(import_object as *mut ImportObject);
Expand Down
Loading

0 comments on commit de6269a

Please sign in to comment.