Skip to content

Commit

Permalink
Add WASI support to runtime-c-api
Browse files Browse the repository at this point in the history
  • Loading branch information
Mark McCaskey committed Oct 2, 2019
1 parent b74e62a commit b45b1c1
Show file tree
Hide file tree
Showing 6 changed files with 195 additions and 1 deletion.
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.

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.7.0"

[dependencies.wasmer-wasi]
default-features = false
path = "../wasi"
version = "0.7.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"
104 changes: 104 additions & 0 deletions lib/runtime-c-api/src/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,110 @@ 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 {
use super::*;
use std::path::PathBuf;

/// Opens a directory that's visible to the WASI module as `alias` but
/// is backed by the host file at `host_file_path`
#[repr(C)]
pub struct wasmer_wasi_map_dir_entry_t {
/// What the WASI module will see in its virtual root
pub alias: wasmer_byte_array,
/// The backing file that the WASI module will interact with via the alias
pub host_file_path: wasmer_byte_array,
}

impl wasmer_wasi_map_dir_entry_t {
/// Converts the data into owned, Rust types
pub unsafe fn as_tuple(&self) -> Result<(String, PathBuf), std::str::Utf8Error> {
let alias = self.alias.as_str()?.to_owned();
let host_path = std::path::PathBuf::from(self.host_file_path.as_str()?);

Ok((alias, host_path))
}
}

/// Creates a WASI import object
#[no_mangle]
pub unsafe extern "C" fn wasmer_wasi_generate_import_object(
args: *const wasmer_byte_array,
args_len: c_uint,
envs: *const wasmer_byte_array,
envs_len: c_uint,
preopened_files: *const wasmer_byte_array,
preopened_files_len: c_uint,
mapped_dirs: *const wasmer_wasi_map_dir_entry_t,
mapped_dirs_len: c_uint,
) -> *mut wasmer_import_object_t {
let arg_list = std::slice::from_raw_parts(args, args_len as usize);
let env_list = std::slice::from_raw_parts(envs, envs_len as usize);
let preopened_file_list =
std::slice::from_raw_parts(preopened_files, preopened_files_len as usize);
let mapped_dir_list = std::slice::from_raw_parts(mapped_dirs, mapped_dirs_len as usize);

wasmer_wasi_generate_import_object_inner(
arg_list,
env_list,
preopened_file_list,
mapped_dir_list,
)
.unwrap_or(std::ptr::null_mut())
}

/// Inner function that wraps error handling
fn wasmer_wasi_generate_import_object_inner(
arg_list: &[wasmer_byte_array],
env_list: &[wasmer_byte_array],
preopened_file_list: &[wasmer_byte_array],
mapped_dir_list: &[wasmer_wasi_map_dir_entry_t],
) -> Result<*mut wasmer_import_object_t, std::str::Utf8Error> {
let arg_vec = arg_list.iter().map(|arg| unsafe { arg.as_vec() }).collect();
let env_vec = env_list
.iter()
.map(|env_var| unsafe { env_var.as_vec() })
.collect();
let po_file_vec = preopened_file_list
.iter()
.map(|po_file| Ok(unsafe { po_file.as_str()? }.to_owned()))
.collect::<Result<Vec<_>, _>>()?;
let mapped_dir_vec = mapped_dir_list
.iter()
.map(|entry| unsafe { entry.as_tuple() })
.collect::<Result<Vec<_>, _>>()?;

let import_object = Box::new(wasmer_wasi::generate_import_object(
arg_vec,
env_vec,
po_file_vec,
mapped_dir_vec,
));
Ok(Box::into_raw(import_object) as *mut wasmer_import_object_t)
}

/// Convenience function that creates a WASI import object with no arguments,
/// environment variables, preopened files, or mapped directories.
///
/// This function is the same as calling [`wasmer_wasi_generate_import_object`] with all
/// empty values.
#[no_mangle]
pub unsafe extern "C" fn wasmer_wasi_generate_default_import_object(
) -> *mut wasmer_import_object_t {
let import_object = Box::new(wasmer_wasi::generate_import_object(
vec![],
vec![],
vec![],
vec![],
));

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

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

/// Extends an existing import object with new imports
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
Expand Down
20 changes: 20 additions & 0 deletions lib/runtime-c-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,23 @@ pub struct wasmer_byte_array {
pub bytes: *const u8,
pub bytes_len: u32,
}

impl wasmer_byte_array {
/// Get the data as a slice
pub unsafe fn as_slice<'a>(&self) -> &'a [u8] {
std::slice::from_raw_parts(self.bytes, self.bytes_len as usize)
}

/// Copy the data into an owned Vec
pub unsafe fn as_vec(&self) -> Vec<u8> {
let mut out = Vec::with_capacity(self.bytes_len as usize);
out.extend_from_slice(self.as_slice());

out
}

/// Read the data as a &str, returns an error if the string is not valid UTF8
pub unsafe fn as_str<'a>(&self) -> Result<&'a str, std::str::Utf8Error> {
std::str::from_utf8(self.as_slice())
}
}
36 changes: 36 additions & 0 deletions lib/runtime-c-api/wasmer.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,21 @@ typedef struct {

} wasmer_trampoline_buffer_t;

/**
* Opens a directory that's visible to the WASI module as `alias` but
* is backed by the host file at `host_file_path`
*/
typedef struct {
/**
* What the WASI module will see in its virtual root
*/
wasmer_byte_array alias;
/**
* The backing file that the WASI module will interact with via the alias
*/
wasmer_byte_array host_file_path;
} wasmer_wasi_map_dir_entry_t;

/**
* Creates a new Module from the given wasm bytes.
*
Expand Down Expand Up @@ -756,4 +771,25 @@ void *wasmer_trampoline_get_context(void);
*/
bool wasmer_validate(const uint8_t *wasm_bytes, uint32_t wasm_bytes_len);

/**
* Convenience function that creates a WASI import object with no arguments,
* environment variables, preopened files, or mapped directories.
*
* This function is the same as calling [`wasmer_wasi_generate_import_object`] with all
* empty values.
*/
wasmer_import_object_t *wasmer_wasi_generate_default_import_object(void);

/**
* Creates a WASI import object
*/
wasmer_import_object_t *wasmer_wasi_generate_import_object(const wasmer_byte_array *args,
unsigned int args_len,
const wasmer_byte_array *envs,
unsigned int envs_len,
const wasmer_byte_array *preopened_files,
unsigned int preopened_files_len,
const wasmer_wasi_map_dir_entry_t *mapped_dirs,
unsigned int mapped_dirs_len);

#endif /* WASMER_H */
26 changes: 26 additions & 0 deletions lib/runtime-c-api/wasmer.hh
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,15 @@ struct wasmer_trampoline_buffer_t {

};

/// Opens a directory that's visible to the WASI module as `alias` but
/// is backed by the host file at `host_file_path`
struct wasmer_wasi_map_dir_entry_t {
/// What the WASI module will see in its virtual root
wasmer_byte_array alias;
/// The backing file that the WASI module will interact with via the alias
wasmer_byte_array host_file_path;
};

extern "C" {

/// Creates a new Module from the given wasm bytes.
Expand Down Expand Up @@ -590,6 +599,23 @@ void *wasmer_trampoline_get_context();
/// Returns true for valid wasm bytes and false for invalid bytes
bool wasmer_validate(const uint8_t *wasm_bytes, uint32_t wasm_bytes_len);

/// Convenience function that creates a WASI import object with no arguments,
/// environment variables, preopened files, or mapped directories.
///
/// This function is the same as calling [`wasmer_wasi_generate_import_object`] with all
/// empty values.
wasmer_import_object_t *wasmer_wasi_generate_default_import_object();

/// Creates a WASI import object
wasmer_import_object_t *wasmer_wasi_generate_import_object(const wasmer_byte_array *args,
unsigned int args_len,
const wasmer_byte_array *envs,
unsigned int envs_len,
const wasmer_byte_array *preopened_files,
unsigned int preopened_files_len,
const wasmer_wasi_map_dir_entry_t *mapped_dirs,
unsigned int mapped_dirs_len);

} // extern "C"

#endif // WASMER_H

0 comments on commit b45b1c1

Please sign in to comment.