Merge branch 'master' into add-validate

This commit is contained in:
Mark McCaskey
2019-04-03 21:35:23 -07:00
committed by GitHub
20 changed files with 2788 additions and 260 deletions

422
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -30,9 +30,10 @@ wasmer-runtime-abi = { path = "lib/runtime-abi", optional = true }
wasmer-runtime-core = { path = "lib/runtime-core" } wasmer-runtime-core = { path = "lib/runtime-core" }
wasmer-emscripten = { path = "lib/emscripten" } wasmer-emscripten = { path = "lib/emscripten" }
wasmer-llvm-backend = { path = "lib/llvm-backend", optional = true } wasmer-llvm-backend = { path = "lib/llvm-backend", optional = true }
wasmer-wasi = { path = "lib/wasi", optional = true }
[workspace] [workspace]
members = ["lib/clif-backend", "lib/dynasm-backend", "lib/runtime", "lib/runtime-abi", "lib/runtime-core", "lib/emscripten", "lib/spectests", "lib/win-exception-handler", "lib/runtime-c-api", "lib/llvm-backend"] members = ["lib/clif-backend", "lib/dynasm-backend", "lib/runtime", "lib/runtime-abi", "lib/runtime-core", "lib/emscripten", "lib/spectests", "lib/win-exception-handler", "lib/runtime-c-api", "lib/llvm-backend", "lib/wasi"]
[build-dependencies] [build-dependencies]
wabt = "0.7.2" wabt = "0.7.2"
@ -45,4 +46,5 @@ debug = ["wasmer-clif-backend/debug", "wasmer-runtime-core/debug"]
fast-tests = [] fast-tests = []
llvm = ["wasmer-llvm-backend"] llvm = ["wasmer-llvm-backend"]
dynasm = ["wasmer-dynasm-backend"] dynasm = ["wasmer-dynasm-backend"]
wasi = ["wasmer-wasi"]
vfs = ["wasmer-runtime-abi"] vfs = ["wasmer-runtime-abi"]

View File

@ -119,7 +119,6 @@ impl std::error::Error for LinkError {}
/// The main way to do this is `Instance.call`. /// The main way to do this is `Instance.call`.
/// ///
/// Comparing two `RuntimeError`s always evaluates to false. /// Comparing two `RuntimeError`s always evaluates to false.
#[derive(Debug)]
pub enum RuntimeError { pub enum RuntimeError {
Trap { msg: Box<str> }, Trap { msg: Box<str> },
Exception { data: Box<[Value]> }, Exception { data: Box<[Value]> },
@ -141,9 +140,25 @@ impl std::fmt::Display for RuntimeError {
RuntimeError::Exception { ref data } => { RuntimeError::Exception { ref data } => {
write!(f, "Uncaught WebAssembly exception: {:?}", data) write!(f, "Uncaught WebAssembly exception: {:?}", data)
} }
RuntimeError::Panic { data: _ } => write!(f, "User-defined \"panic\""), RuntimeError::Panic { data } => {
let msg = if let Some(s) = data.downcast_ref::<String>() {
s
} else if let Some(s) = data.downcast_ref::<&str>() {
s
} else {
"user-defined, opaque"
};
write!(f, "{}", msg)
} }
} }
}
}
impl std::fmt::Debug for RuntimeError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self)
}
} }
impl std::error::Error for RuntimeError {} impl std::error::Error for RuntimeError {}
@ -197,7 +212,6 @@ impl std::error::Error for ResolveError {}
/// be the `CallError::Runtime(RuntimeError)` variant. /// be the `CallError::Runtime(RuntimeError)` variant.
/// ///
/// Comparing two `CallError`s always evaluates to false. /// Comparing two `CallError`s always evaluates to false.
#[derive(Debug)]
pub enum CallError { pub enum CallError {
Resolve(ResolveError), Resolve(ResolveError),
Runtime(RuntimeError), Runtime(RuntimeError),
@ -218,6 +232,15 @@ impl std::fmt::Display for CallError {
} }
} }
impl std::fmt::Debug for CallError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
CallError::Resolve(resolve_err) => write!(f, "ResolveError: {:?}", resolve_err),
CallError::Runtime(runtime_err) => write!(f, "RuntimeError: {:?}", runtime_err),
}
}
}
impl std::error::Error for CallError {} impl std::error::Error for CallError {}
/// This error type is produced when creating something, /// This error type is produced when creating something,

View File

@ -3,6 +3,7 @@ use hashbrown::{hash_map::Entry, HashMap};
use std::collections::VecDeque; use std::collections::VecDeque;
use std::{ use std::{
cell::{Ref, RefCell}, cell::{Ref, RefCell},
ffi::c_void,
rc::Rc, rc::Rc,
}; };
@ -45,6 +46,7 @@ impl IsExport for Export {
/// ``` /// ```
pub struct ImportObject { pub struct ImportObject {
map: Rc<RefCell<HashMap<String, Box<dyn LikeNamespace>>>>, map: Rc<RefCell<HashMap<String, Box<dyn LikeNamespace>>>>,
state_creator: Option<Rc<Fn() -> (*mut c_void, fn(*mut c_void))>>,
} }
impl ImportObject { impl ImportObject {
@ -52,9 +54,24 @@ impl ImportObject {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
map: Rc::new(RefCell::new(HashMap::new())), map: Rc::new(RefCell::new(HashMap::new())),
state_creator: None,
} }
} }
pub fn new_with_data<F>(state_creator: F) -> Self
where
F: Fn() -> (*mut c_void, fn(*mut c_void)) + 'static,
{
Self {
map: Rc::new(RefCell::new(HashMap::new())),
state_creator: Some(Rc::new(state_creator)),
}
}
pub(crate) fn call_state_creator(&self) -> Option<(*mut c_void, fn(*mut c_void))> {
self.state_creator.as_ref().map(|state_gen| state_gen())
}
/// Register anything that implements `LikeNamespace` as a namespace. /// Register anything that implements `LikeNamespace` as a namespace.
/// ///
/// # Usage: /// # Usage:
@ -98,6 +115,7 @@ impl ImportObject {
pub fn clone_ref(&self) -> Self { pub fn clone_ref(&self) -> Self {
Self { Self {
map: Rc::clone(&self.map), map: Rc::clone(&self.map),
state_creator: self.state_creator.clone(),
} }
} }

View File

@ -63,7 +63,16 @@ impl Instance {
// Initialize the vm::Ctx in-place after the backing // Initialize the vm::Ctx in-place after the backing
// has been boxed. // has been boxed.
unsafe { unsafe {
*inner.vmctx = vm::Ctx::new(&mut inner.backing, &mut inner.import_backing, &module) *inner.vmctx = match imports.call_state_creator() {
Some((data, dtor)) => vm::Ctx::new_with_data(
&mut inner.backing,
&mut inner.import_backing,
&module,
data,
dtor,
),
None => vm::Ctx::new(&mut inner.backing, &mut inner.import_backing, &module),
};
}; };
let instance = Instance { let instance = Instance {

View File

@ -38,6 +38,13 @@ macro_rules! func {
/// }, /// },
/// }; /// };
/// ///
/// let imports_with_state = imports! {
/// || (0 as _, |_a| {}),
/// "env" => {
/// "foo" => func!(foo),
/// },
/// };
///
/// fn foo(_: &mut Ctx, n: i32) -> i32 { /// fn foo(_: &mut Ctx, n: i32) -> i32 {
/// n /// n
/// } /// }
@ -57,6 +64,21 @@ macro_rules! imports {
import_object.register($ns_name, ns); import_object.register($ns_name, ns);
})* })*
import_object
}};
($state_gen:expr, $( $ns_name:expr => $ns:tt, )* ) => {{
use $crate::{
import::{ImportObject, Namespace},
};
let mut import_object = ImportObject::new_with_data($state_gen);
$({
let ns = $crate::__imports_internal!($ns);
import_object.register($ns_name, ns);
})*
import_object import_object
}}; }};
} }

View File

@ -77,6 +77,19 @@ where
{ {
const TYPE: Type; const TYPE: Type;
} }
unsafe impl WasmExternType for i8 {
const TYPE: Type = Type::I32;
}
unsafe impl WasmExternType for u8 {
const TYPE: Type = Type::I32;
}
unsafe impl WasmExternType for i16 {
const TYPE: Type = Type::I32;
}
unsafe impl WasmExternType for u16 {
const TYPE: Type = Type::I32;
}
unsafe impl WasmExternType for i32 { unsafe impl WasmExternType for i32 {
const TYPE: Type = Type::I32; const TYPE: Type = Type::I32;
} }
@ -113,34 +126,15 @@ unsafe impl WasmExternType for f64 {
// fn swap(&self, other: Self::Primitive) -> Self::Primitive; // fn swap(&self, other: Self::Primitive) -> Self::Primitive;
// } // }
pub enum ValueError { pub unsafe trait ValueType: Copy
BufferTooSmall,
}
pub trait ValueType: Copy
where where
Self: Sized, Self: Sized,
{ {
fn into_le(self, buffer: &mut [u8]);
fn from_le(buffer: &[u8]) -> Result<Self, ValueError>;
} }
macro_rules! convert_value_impl { macro_rules! convert_value_impl {
($t:ty) => { ($t:ty) => {
impl ValueType for $t { unsafe impl ValueType for $t {}
fn into_le(self, buffer: &mut [u8]) {
buffer[..mem::size_of::<Self>()].copy_from_slice(&self.to_le_bytes());
}
fn from_le(buffer: &[u8]) -> Result<Self, ValueError> {
if buffer.len() >= mem::size_of::<Self>() {
let mut array = [0u8; mem::size_of::<Self>()];
array.copy_from_slice(&buffer[..mem::size_of::<Self>()]);
Ok(Self::from_le_bytes(array))
} else {
Err(ValueError::BufferTooSmall)
}
}
}
}; };
( $($t:ty),* ) => { ( $($t:ty),* ) => {
$( $(
@ -149,25 +143,7 @@ macro_rules! convert_value_impl {
}; };
} }
convert_value_impl!(u8, i8, u16, i16, u32, i32, u64, i64); convert_value_impl!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64);
impl ValueType for f32 {
fn into_le(self, buffer: &mut [u8]) {
self.to_bits().into_le(buffer);
}
fn from_le(buffer: &[u8]) -> Result<Self, ValueError> {
Ok(f32::from_bits(<u32 as ValueType>::from_le(buffer)?))
}
}
impl ValueType for f64 {
fn into_le(self, buffer: &mut [u8]) {
self.to_bits().into_le(buffer);
}
fn from_le(buffer: &[u8]) -> Result<Self, ValueError> {
Ok(f64::from_bits(<u64 as ValueType>::from_le(buffer)?))
}
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)] #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub enum ElementType { pub enum ElementType {

View File

@ -25,7 +25,7 @@ pub struct Ctx {
module: *const ModuleInner, module: *const ModuleInner,
pub data: *mut c_void, pub data: *mut c_void,
pub data_finalizer: Option<extern "C" fn(data: *mut c_void)>, pub data_finalizer: Option<fn(data: *mut c_void)>,
} }
/// The internal context of the currently running WebAssembly instance. /// The internal context of the currently running WebAssembly instance.
@ -100,7 +100,7 @@ impl Ctx {
import_backing: &mut ImportBacking, import_backing: &mut ImportBacking,
module: &ModuleInner, module: &ModuleInner,
data: *mut c_void, data: *mut c_void,
data_finalizer: extern "C" fn(*mut c_void), data_finalizer: fn(*mut c_void),
) -> Self { ) -> Self {
Self { Self {
internal: InternalCtx { internal: InternalCtx {
@ -481,7 +481,7 @@ mod vm_ctx_tests {
str: String, str: String,
} }
extern "C" fn test_data_finalizer(data: *mut c_void) { fn test_data_finalizer(data: *mut c_void) {
let test_data: &mut TestData = unsafe { &mut *(data as *mut TestData) }; let test_data: &mut TestData = unsafe { &mut *(data as *mut TestData) };
assert_eq!(test_data.x, 10); assert_eq!(test_data.x, 10);
assert_eq!(test_data.y, true); assert_eq!(test_data.y, true);

22
lib/wasi/Cargo.toml Normal file
View File

@ -0,0 +1,22 @@
[package]
name = "wasmer-wasi"
version = "0.2.1"
license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
repository = "https://github.com/wasmerio/wasmer"
edition = "2018"
[dependencies]
wasmer-runtime-core = { path = "../runtime-core", version = "0.2.1" }
libc = "0.2.50"
rand = "0.6.5"
# wasmer-runtime-abi = { path = "../runtime-abi" }
hashbrown = "0.1.8"
generational-arena = "0.2.2"
log = "0.4.6"
byteorder = "1.3.1"
[dependencies.zbox]
git = "https://github.com/wasmerio/zbox"
branch = "bundle-libsodium"
features = ["libsodium-bundled"]

90
lib/wasi/src/lib.rs Normal file
View File

@ -0,0 +1,90 @@
#[macro_use]
extern crate log;
#[macro_use]
mod macros;
mod ptr;
mod state;
mod syscalls;
mod utils;
use self::state::{WasiFs, WasiState};
use self::syscalls::*;
use std::ffi::c_void;
pub use self::utils::is_wasi_module;
use wasmer_runtime_core::{func, import::ImportObject, imports};
pub fn generate_import_object(args: Vec<Vec<u8>>, envs: Vec<Vec<u8>>) -> ImportObject {
let state_gen = move || {
fn state_destructor(data: *mut c_void) {
unsafe {
drop(Box::from_raw(data as *mut WasiState));
}
}
let state = Box::new(WasiState {
fs: WasiFs::new().unwrap(),
args: &args[..],
envs: &envs[..],
});
(
Box::leak(state) as *mut WasiState as *mut c_void,
state_destructor as fn(*mut c_void),
)
};
imports! {
// This generates the wasi state.
state_gen,
"wasi_unstable" => {
"args_get" => func!(args_get),
"args_sizes_get" => func!(args_sizes_get),
"clock_res_get" => func!(clock_res_get),
"clock_time_get" => func!(clock_time_get),
"environ_get" => func!(environ_get),
"environ_sizes_get" => func!(environ_sizes_get),
"fd_advise" => func!(fd_advise),
"fd_allocate" => func!(fd_allocate),
"fd_close" => func!(fd_close),
"fd_datasync" => func!(fd_datasync),
"fd_fdstat_get" => func!(fd_fdstat_get),
"fd_fdstat_set_flags" => func!(fd_fdstat_set_flags),
"fd_fdstat_set_rights" => func!(fd_fdstat_set_rights),
"fd_filestat_get" => func!(fd_filestat_get),
"fd_filestat_set_size" => func!(fd_filestat_set_size),
"fd_filestat_set_times" => func!(fd_filestat_set_times),
"fd_pread" => func!(fd_pread),
"fd_prestat_get" => func!(fd_prestat_get),
"fd_prestat_dir_name" => func!(fd_prestat_dir_name),
"fd_pwrite" => func!(fd_pwrite),
"fd_read" => func!(fd_read),
"fd_readdir" => func!(fd_readdir),
"fd_renumber" => func!(fd_renumber),
"fd_seek" => func!(fd_seek),
"fd_sync" => func!(fd_sync),
"fd_tell" => func!(fd_tell),
"fd_write" => func!(fd_write),
"path_create_directory" => func!(path_create_directory),
"path_filestat_get" => func!(path_filestat_get),
"path_filestat_set_times" => func!(path_filestat_set_times),
"path_link" => func!(path_link),
"path_open" => func!(path_open),
"path_readlink" => func!(path_readlink),
"path_remove_directory" => func!(path_remove_directory),
"path_rename" => func!(path_rename),
"path_symlink" => func!(path_symlink),
"path_unlink_file" => func!(path_unlink_file),
"poll_oneoff" => func!(poll_oneoff),
"proc_exit" => func!(proc_exit),
"proc_raise" => func!(proc_raise),
"random_get" => func!(random_get),
"sched_yield" => func!(sched_yield),
"sock_recv" => func!(sock_recv),
"sock_send" => func!(sock_send),
"sock_shutdown" => func!(sock_shutdown),
},
}
}

13
lib/wasi/src/macros.rs Normal file
View File

@ -0,0 +1,13 @@
macro_rules! wasi_try {
($expr:expr) => {{
let res: Result<_, crate::syscalls::types::__wasi_errno_t> = $expr;
match res {
Ok(val) => val,
Err(err) => return err,
}
}};
($expr:expr; $e:expr) => {{
let opt: Option<_> = $expr;
wasi_try!(opt.ok_or($e))
}};
}

102
lib/wasi/src/ptr.rs Normal file
View File

@ -0,0 +1,102 @@
use crate::syscalls::types::{__wasi_errno_t, __WASI_EFAULT};
use std::{cell::Cell, fmt, marker::PhantomData, mem};
use wasmer_runtime_core::{
memory::Memory,
types::{Type, ValueType, WasmExternType},
};
pub struct Array;
pub struct Item;
#[repr(transparent)]
pub struct WasmPtr<T: Copy, Ty = Item> {
offset: u32,
_phantom: PhantomData<(T, Ty)>,
}
impl<T: Copy, Ty> WasmPtr<T, Ty> {
#[inline]
pub fn new(offset: u32) -> Self {
Self {
offset,
_phantom: PhantomData,
}
}
#[inline]
pub fn offset(self) -> u32 {
self.offset
}
}
impl<T: Copy + ValueType> WasmPtr<T, Item> {
#[inline]
pub fn deref<'a>(self, memory: &'a Memory) -> Result<&'a Cell<T>, __wasi_errno_t> {
if (self.offset as usize) + mem::size_of::<T>() >= memory.size().bytes().0 {
return Err(__WASI_EFAULT);
}
unsafe {
let cell_ptr = memory
.view::<T>()
.get_unchecked((self.offset() as usize) / mem::size_of::<T>())
as *const _;
Ok(&*cell_ptr)
}
}
}
impl<T: Copy + ValueType> WasmPtr<T, Array> {
#[inline]
pub fn deref<'a>(
self,
memory: &'a Memory,
index: u32,
length: u32,
) -> Result<&'a [Cell<T>], __wasi_errno_t> {
if (self.offset as usize) + (mem::size_of::<T>() * ((index + length) as usize))
>= memory.size().bytes().0
{
return Err(__WASI_EFAULT);
}
unsafe {
let cell_ptrs = memory.view::<T>().get_unchecked(
((self.offset as usize) / mem::size_of::<T>()) + (index as usize)
..((self.offset() as usize) / mem::size_of::<T>())
+ ((index + length) as usize),
) as *const _;
Ok(&*cell_ptrs)
}
}
}
unsafe impl<T: Copy, Ty> WasmExternType for WasmPtr<T, Ty> {
const TYPE: Type = Type::I32;
}
unsafe impl<T: Copy, Ty> ValueType for WasmPtr<T, Ty> {}
impl<T: Copy, Ty> Clone for WasmPtr<T, Ty> {
fn clone(&self) -> Self {
Self {
offset: self.offset,
_phantom: PhantomData,
}
}
}
impl<T: Copy, Ty> Copy for WasmPtr<T, Ty> {}
impl<T: Copy, Ty> PartialEq for WasmPtr<T, Ty> {
fn eq(&self, other: &Self) -> bool {
self.offset == other.offset
}
}
impl<T: Copy, Ty> Eq for WasmPtr<T, Ty> {}
impl<T: Copy, Ty> fmt::Debug for WasmPtr<T, Ty> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "WasmPtr({:#x})", self.offset)
}
}

272
lib/wasi/src/state.rs Normal file
View File

@ -0,0 +1,272 @@
// use wasmer_runtime_abi::vfs::{
// vfs::Vfs,
// file_like::{FileLike, Metadata};
// };
use crate::syscalls::types::*;
use generational_arena::{Arena, Index as Inode};
use hashbrown::hash_map::{Entry, HashMap};
use std::{
cell::Cell,
io::{self, Write},
time::SystemTime,
};
use zbox::{init_env as zbox_init_env, File, FileType, OpenOptions, Repo, RepoOpener};
pub const MAX_SYMLINKS: usize = 100;
pub struct InodeVal {
pub stat: __wasi_filestat_t,
pub is_preopened: bool,
pub name: String,
pub kind: Kind,
}
#[allow(dead_code)]
pub enum Kind {
File {
handle: File,
},
Dir {
handle: File,
/// The entries of a directory are lazily filled.
entries: HashMap<String, Inode>,
},
Symlink {
forwarded: Inode,
},
Buffer {
buffer: Vec<u8>,
},
}
#[derive(Clone)]
pub struct Fd {
pub rights: __wasi_rights_t,
pub rights_inheriting: __wasi_rights_t,
pub flags: __wasi_fdflags_t,
pub offset: u64,
pub inode: Inode,
}
pub struct WasiFs {
pub repo: Repo,
pub name_map: HashMap<String, Inode>,
pub inodes: Arena<InodeVal>,
pub fd_map: HashMap<u32, Fd>,
pub next_fd: Cell<u32>,
pub inode_counter: Cell<u64>,
}
impl WasiFs {
pub fn new() -> Result<Self, String> {
zbox_init_env();
Ok(Self {
repo: RepoOpener::new()
.create(true)
.open("mem://wasmer-test-fs", "")
.map_err(|e| e.to_string())?,
name_map: HashMap::new(),
inodes: Arena::new(),
fd_map: HashMap::new(),
next_fd: Cell::new(3),
inode_counter: Cell::new(1000),
})
}
#[allow(dead_code)]
fn get_inode(&mut self, path: &str) -> Option<Inode> {
Some(match self.name_map.entry(path.to_string()) {
Entry::Occupied(o) => *o.get(),
Entry::Vacant(v) => {
let file = if let Ok(file) = OpenOptions::new()
.read(true)
.write(true)
.create(false)
.open(&mut self.repo, path)
{
file
} else {
return None;
};
let metadata = file.metadata().unwrap();
let inode_index = {
let index = self.inode_counter.get();
self.inode_counter.replace(index + 1)
};
let systime_to_nanos = |systime: SystemTime| {
let duration = systime
.duration_since(SystemTime::UNIX_EPOCH)
.expect("should always be after unix epoch");
duration.as_nanos() as u64
};
let inode = self.inodes.insert(InodeVal {
stat: __wasi_filestat_t {
st_dev: 0,
st_ino: inode_index,
st_filetype: match metadata.file_type() {
FileType::File => __WASI_FILETYPE_REGULAR_FILE,
FileType::Dir => __WASI_FILETYPE_DIRECTORY,
},
st_nlink: 0,
st_size: metadata.content_len() as u64,
st_atim: systime_to_nanos(SystemTime::now()),
st_mtim: systime_to_nanos(metadata.modified_at()),
st_ctim: systime_to_nanos(metadata.created_at()),
},
is_preopened: false,
name: path.to_string(),
kind: match metadata.file_type() {
FileType::File => Kind::File { handle: file },
FileType::Dir => Kind::Dir {
handle: file,
entries: HashMap::new(),
},
},
});
v.insert(inode);
inode
}
})
}
#[allow(dead_code)]
fn filestat_inode(
&self,
inode: Inode,
flags: __wasi_lookupflags_t,
) -> Result<__wasi_filestat_t, __wasi_errno_t> {
let inode_val = &self.inodes[inode];
if let (true, Kind::Symlink { mut forwarded }) =
(flags & __WASI_LOOKUP_SYMLINK_FOLLOW != 0, &inode_val.kind)
{
// Time to follow the symlink.
let mut counter = 0;
while counter <= MAX_SYMLINKS {
let inode_val = &self.inodes[forwarded];
if let &Kind::Symlink {
forwarded: new_forwarded,
} = &inode_val.kind
{
counter += 1;
forwarded = new_forwarded;
} else {
return Ok(inode_val.stat);
}
}
Err(__WASI_EMLINK)
} else {
Ok(inode_val.stat)
}
}
#[allow(dead_code)]
pub fn filestat_path(
&mut self,
preopened_fd: __wasi_fd_t,
flags: __wasi_lookupflags_t,
path: &str,
) -> Result<__wasi_filestat_t, __wasi_errno_t> {
warn!("Should use preopned_fd: {}", preopened_fd);
let inode = self.get_inode(path).ok_or(__WASI_EINVAL)?;
self.filestat_inode(inode, flags)
}
pub fn filestat_fd(&self, fd: __wasi_fd_t) -> Result<__wasi_filestat_t, __wasi_errno_t> {
let fd = self.fd_map.get(&fd).ok_or(__WASI_EBADF)?;
Ok(self.inodes[fd.inode].stat)
}
pub fn fdstat(&self, fd: __wasi_fd_t) -> Result<__wasi_fdstat_t, __wasi_errno_t> {
let fd = self.fd_map.get(&fd).ok_or(__WASI_EBADF)?;
Ok(__wasi_fdstat_t {
fs_filetype: match self.inodes[fd.inode].kind {
Kind::File { .. } => __WASI_FILETYPE_REGULAR_FILE,
Kind::Dir { .. } => __WASI_FILETYPE_DIRECTORY,
Kind::Symlink { .. } => __WASI_FILETYPE_SYMBOLIC_LINK,
_ => __WASI_FILETYPE_UNKNOWN,
},
fs_flags: fd.flags,
fs_rights_base: fd.rights,
fs_rights_inheriting: fd.rights, // TODO(lachlan): Is this right?
})
}
pub fn prestat_fd(&self, fd: __wasi_fd_t) -> Result<__wasi_prestat_t, __wasi_errno_t> {
let fd = self.fd_map.get(&fd).ok_or(__WASI_EBADF)?;
let inode_val = &self.inodes[fd.inode];
if inode_val.is_preopened {
Ok(__wasi_prestat_t {
pr_type: __WASI_PREOPENTYPE_DIR,
u: PrestatEnum::Dir {
pr_name_len: inode_val.name.len() as u32,
}
.untagged(),
})
} else {
Err(__WASI_EBADF)
}
}
pub fn flush(&mut self, fd: __wasi_fd_t) -> Result<(), __wasi_errno_t> {
match fd {
0 => (),
1 => io::stdout().flush().map_err(|_| __WASI_EIO)?,
2 => io::stderr().flush().map_err(|_| __WASI_EIO)?,
_ => {
let fd = self.fd_map.get(&fd).ok_or(__WASI_EBADF)?;
if fd.rights & __WASI_RIGHT_FD_DATASYNC == 0 {
return Err(__WASI_EACCES);
}
let inode = &mut self.inodes[fd.inode];
match &mut inode.kind {
Kind::File { handle } => handle.flush().map_err(|_| __WASI_EIO)?,
// TODO: verify this behavior
Kind::Dir { .. } => return Err(__WASI_EISDIR),
Kind::Symlink { .. } => unimplemented!(),
Kind::Buffer { .. } => (),
}
}
}
Ok(())
}
pub fn create_fd(
&mut self,
rights: __wasi_rights_t,
rights_inheriting: __wasi_rights_t,
flags: __wasi_fdflags_t,
inode: Inode,
) -> Result<u32, __wasi_errno_t> {
let idx = self.next_fd.get();
self.next_fd.set(idx + 1);
self.fd_map.insert(
idx,
Fd {
rights,
rights_inheriting,
flags,
offset: 0,
inode,
},
);
Ok(idx)
}
}
pub struct WasiState<'a> {
pub fs: WasiFs,
pub args: &'a [Vec<u8>],
pub envs: &'a [Vec<u8>],
}

1378
lib/wasi/src/syscalls/mod.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,452 @@
#![allow(non_camel_case_types)]
use crate::ptr::{Array, WasmPtr};
use byteorder::{ReadBytesExt, WriteBytesExt, LE};
use std::mem;
use wasmer_runtime_core::types::ValueType;
pub type __wasi_advice_t = u8;
pub const __WASI_ADVICE_DONTNEED: u8 = 0;
pub const __WASI_ADVICE_NOREUSE: u8 = 1;
pub const __WASI_ADVICE_NORMAL: u8 = 2;
pub const __WASI_ADVICE_RANDOM: u8 = 3;
pub const __WASI_ADVICE_SEQUENTIAL: u8 = 4;
pub const __WASI_ADVICE_WILLNEED: u8 = 5;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(C)]
pub struct __wasi_ciovec_t {
pub buf: WasmPtr<u8, Array>,
pub buf_len: u32,
}
unsafe impl ValueType for __wasi_ciovec_t {}
pub type __wasi_clockid_t = u32;
pub const __WASI_CLOCK_MONOTONIC: u32 = 0;
pub const __WASI_CLOCK_PROCESS_CPUTIME_ID: u32 = 1;
pub const __WASI_CLOCK_REALTIME: u32 = 2;
pub const __WASI_CLOCK_THREAD_CPUTIME_ID: u32 = 3;
pub type __wasi_device_t = u64;
pub type __wasi_dircookie_t = u64;
pub const __WASI_DIRCOOKIE_START: u64 = 0;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(C)]
pub struct __wasi_dirent_t {
pub d_next: __wasi_dircookie_t,
pub d_ino: __wasi_inode_t,
pub d_namlen: u32,
pub d_type: __wasi_filetype_t,
}
pub type __wasi_errno_t = u16;
pub const __WASI_ESUCCESS: u16 = 0;
pub const __WASI_E2BIG: u16 = 1;
pub const __WASI_EACCES: u16 = 2;
pub const __WASI_EADDRINUSE: u16 = 3;
pub const __WASI_EADDRNOTAVAIL: u16 = 4;
pub const __WASI_EAFNOSUPPORT: u16 = 5;
pub const __WASI_EAGAIN: u16 = 6;
pub const __WASI_EALREADY: u16 = 7;
pub const __WASI_EBADF: u16 = 8;
pub const __WASI_EBADMSG: u16 = 9;
pub const __WASI_EBUSY: u16 = 10;
pub const __WASI_ECANCELED: u16 = 11;
pub const __WASI_ECHILD: u16 = 12;
pub const __WASI_ECONNABORTED: u16 = 13;
pub const __WASI_ECONNREFUSED: u16 = 14;
pub const __WASI_ECONNRESET: u16 = 15;
pub const __WASI_EDEADLK: u16 = 16;
pub const __WASI_EDESTADDRREQ: u16 = 17;
pub const __WASI_EDOM: u16 = 18;
pub const __WASI_EDQUOT: u16 = 19;
pub const __WASI_EEXIST: u16 = 20;
pub const __WASI_EFAULT: u16 = 21;
pub const __WASI_EFBIG: u16 = 22;
pub const __WASI_EHOSTUNREACH: u16 = 23;
pub const __WASI_EIDRM: u16 = 24;
pub const __WASI_EILSEQ: u16 = 25;
pub const __WASI_EINPROGRESS: u16 = 26;
pub const __WASI_EINTR: u16 = 27;
pub const __WASI_EINVAL: u16 = 28;
pub const __WASI_EIO: u16 = 29;
pub const __WASI_EISCONN: u16 = 30;
pub const __WASI_EISDIR: u16 = 31;
pub const __WASI_ELOOP: u16 = 32;
pub const __WASI_EMFILE: u16 = 33;
pub const __WASI_EMLINK: u16 = 34;
pub const __WASI_EMSGSIZE: u16 = 35;
pub const __WASI_EMULTIHOP: u16 = 36;
pub const __WASI_ENAMETOOLONG: u16 = 37;
pub const __WASI_ENETDOWN: u16 = 38;
pub const __WASI_ENETRESET: u16 = 39;
pub const __WASI_ENETUNREACH: u16 = 40;
pub const __WASI_ENFILE: u16 = 41;
pub const __WASI_ENOBUFS: u16 = 42;
pub const __WASI_ENODEV: u16 = 43;
pub const __WASI_ENOENT: u16 = 44;
pub const __WASI_ENOEXEC: u16 = 45;
pub const __WASI_ENOLCK: u16 = 46;
pub const __WASI_ENOLINK: u16 = 47;
pub const __WASI_ENOMEM: u16 = 48;
pub const __WASI_ENOMSG: u16 = 49;
pub const __WASI_ENOPROTOOPT: u16 = 50;
pub const __WASI_ENOSPC: u16 = 51;
pub const __WASI_ENOSYS: u16 = 52;
pub const __WASI_ENOTCONN: u16 = 53;
pub const __WASI_ENOTDIR: u16 = 54;
pub const __WASI_ENOTEMPTY: u16 = 55;
pub const __WASI_ENOTRECOVERABLE: u16 = 56;
pub const __WASI_ENOTSOCK: u16 = 57;
pub const __WASI_ENOTSUP: u16 = 58;
pub const __WASI_ENOTTY: u16 = 59;
pub const __WASI_ENXIO: u16 = 60;
pub const __WASI_EOVERFLOW: u16 = 61;
pub const __WASI_EOWNERDEAD: u16 = 62;
pub const __WASI_EPERM: u16 = 63;
pub const __WASI_EPIPE: u16 = 64;
pub const __WASI_EPROTO: u16 = 65;
pub const __WASI_EPROTONOSUPPORT: u16 = 66;
pub const __WASI_EPROTOTYPE: u16 = 67;
pub const __WASI_ERANGE: u16 = 68;
pub const __WASI_EROFS: u16 = 69;
pub const __WASI_ESPIPE: u16 = 70;
pub const __WASI_ESRCH: u16 = 71;
pub const __WASI_ESTALE: u16 = 72;
pub const __WASI_ETIMEDOUT: u16 = 73;
pub const __WASI_ETXTBSY: u16 = 74;
pub const __WASI_EXDEV: u16 = 75;
pub const __WASI_ENOTCAPABLE: u16 = 76;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(C)]
pub struct __wasi_event_fd_readwrite_t {
pub nbytes: __wasi_filesize_t,
pub flags: __wasi_eventrwflags_t,
}
#[derive(Copy, Clone)]
#[repr(C)]
pub union __wasi_event_u {
fd_readwrite: __wasi_event_fd_readwrite_t,
}
#[derive(Copy, Clone)]
pub enum EventEnum {
FdReadWrite {
nbytes: __wasi_filesize_t,
flags: __wasi_eventrwflags_t,
},
}
impl EventEnum {
pub fn untagged(self) -> __wasi_event_u {
match self {
EventEnum::FdReadWrite { nbytes, flags } => __wasi_event_u {
fd_readwrite: __wasi_event_fd_readwrite_t { nbytes, flags },
},
}
}
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct __wasi_event_t {
pub userdata: __wasi_userdata_t,
pub error: __wasi_errno_t,
pub type_: __wasi_eventtype_t,
pub u: __wasi_event_u,
}
impl __wasi_event_t {
pub fn tagged(&self) -> Option<EventEnum> {
match self.type_ {
__WASI_EVENTTYPE_FD_READ | __WASI_EVENTTYPE_FD_WRITE => Some(EventEnum::FdReadWrite {
nbytes: unsafe { self.u.fd_readwrite.nbytes },
flags: unsafe { self.u.fd_readwrite.flags },
}),
_ => None,
}
}
}
pub type __wasi_eventrwflags_t = u16;
pub const __WASI_EVENT_FD_READWRITE_HANGUP: u16 = 1 << 0;
pub type __wasi_eventtype_t = u8;
pub const __WASI_EVENTTYPE_CLOCK: u8 = 0;
pub const __WASI_EVENTTYPE_FD_READ: u8 = 1;
pub const __WASI_EVENTTYPE_FD_WRITE: u8 = 2;
pub type __wasi_exitcode_t = u32;
pub type __wasi_fd_t = u32;
pub const __WASI_STDIN_FILENO: u32 = 0;
pub const __WASI_STDOUT_FILENO: u32 = 1;
pub const __WASI_STDERR_FILENO: u32 = 2;
pub type __wasi_fdflags_t = u16;
pub const __WASI_FDFLAG_APPEND: u16 = 1 << 0;
pub const __WASI_FDFLAG_DSYNC: u16 = 1 << 1;
pub const __WASI_FDFLAG_NONBLOCK: u16 = 1 << 2;
pub const __WASI_FDFLAG_RSYNC: u16 = 1 << 3;
pub const __WASI_FDFLAG_SYNC: u16 = 1 << 4;
pub type __wasi_preopentype_t = u8;
pub const __WASI_PREOPENTYPE_DIR: u8 = 0;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(C)]
pub struct __wasi_prestat_u_dir_t {
pub pr_name_len: u32,
}
unsafe impl ValueType for __wasi_prestat_u_dir_t {}
#[derive(Copy, Clone)]
#[repr(C)]
pub union __wasi_prestat_u {
dir: __wasi_prestat_u_dir_t,
}
unsafe impl ValueType for __wasi_prestat_u {}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct __wasi_prestat_t {
pub pr_type: __wasi_preopentype_t,
pub u: __wasi_prestat_u,
}
#[derive(Copy, Clone)]
pub enum PrestatEnum {
Dir { pr_name_len: u32 },
}
impl PrestatEnum {
pub fn untagged(self) -> __wasi_prestat_u {
match self {
PrestatEnum::Dir { pr_name_len } => __wasi_prestat_u {
dir: __wasi_prestat_u_dir_t { pr_name_len },
},
}
}
}
impl __wasi_prestat_t {
pub fn tagged(&self) -> Option<PrestatEnum> {
match self.pr_type {
__WASI_PREOPENTYPE_DIR => Some(PrestatEnum::Dir {
pr_name_len: unsafe { self.u.dir.pr_name_len },
}),
_ => None,
}
}
}
unsafe impl ValueType for __wasi_prestat_t {}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(C)]
pub struct __wasi_fdstat_t {
pub fs_filetype: __wasi_filetype_t,
pub fs_flags: __wasi_fdflags_t,
pub fs_rights_base: __wasi_rights_t,
pub fs_rights_inheriting: __wasi_rights_t,
}
unsafe impl ValueType for __wasi_fdstat_t {}
pub type __wasi_filedelta_t = i64;
pub type __wasi_filesize_t = u64;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(C)]
pub struct __wasi_filestat_t {
pub st_dev: __wasi_device_t,
pub st_ino: __wasi_inode_t,
pub st_filetype: __wasi_filetype_t,
pub st_nlink: __wasi_linkcount_t,
pub st_size: __wasi_filesize_t,
pub st_atim: __wasi_timestamp_t,
pub st_mtim: __wasi_timestamp_t,
pub st_ctim: __wasi_timestamp_t,
}
unsafe impl ValueType for __wasi_filestat_t {}
pub type __wasi_filetype_t = u8;
pub const __WASI_FILETYPE_UNKNOWN: u8 = 0;
pub const __WASI_FILETYPE_BLOCK_DEVICE: u8 = 1;
pub const __WASI_FILETYPE_CHARACTER_DEVICE: u8 = 2;
pub const __WASI_FILETYPE_DIRECTORY: u8 = 3;
pub const __WASI_FILETYPE_REGULAR_FILE: u8 = 4;
pub const __WASI_FILETYPE_SOCKET_DGRAM: u8 = 5;
pub const __WASI_FILETYPE_SOCKET_STREAM: u8 = 6;
pub const __WASI_FILETYPE_SYMBOLIC_LINK: u8 = 7;
pub type __wasi_fstflags_t = u16;
pub const __WASI_FILESTAT_SET_ATIM: u16 = 1 << 0;
pub const __WASI_FILESTAT_SET_ATIM_NOW: u16 = 1 << 1;
pub const __WASI_FILESTAT_SET_MTIM: u16 = 1 << 2;
pub const __WASI_FILESTAT_SET_MTIM_NOW: u16 = 1 << 3;
pub type __wasi_inode_t = u64;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(C)]
pub struct __wasi_iovec_t {
pub buf: WasmPtr<u8, Array>,
pub buf_len: u32,
}
unsafe impl ValueType for __wasi_iovec_t {}
pub type __wasi_linkcount_t = u32;
pub type __wasi_lookupflags_t = u32;
pub const __WASI_LOOKUP_SYMLINK_FOLLOW: u32 = 1 << 0;
pub type __wasi_oflags_t = u16;
pub const __WASI_O_CREAT: u16 = 1 << 0;
pub const __WASI_O_DIRECTORY: u16 = 1 << 1;
pub const __WASI_O_EXCL: u16 = 1 << 2;
pub const __WASI_O_TRUNC: u16 = 1 << 3;
pub type __wasi_riflags_t = u16;
pub const __WASI_SOCK_RECV_PEEK: u16 = 1 << 0;
pub const __WASI_SOCK_RECV_WAITALL: u16 = 1 << 1;
pub type __wasi_rights_t = u64;
pub const __WASI_RIGHT_FD_DATASYNC: u64 = 1 << 0;
pub const __WASI_RIGHT_FD_READ: u64 = 1 << 1;
pub const __WASI_RIGHT_FD_SEEK: u64 = 1 << 2;
pub const __WASI_RIGHT_FD_FDSTAT_SET_FLAGS: u64 = 1 << 3;
pub const __WASI_RIGHT_FD_SYNC: u64 = 1 << 4;
pub const __WASI_RIGHT_FD_TELL: u64 = 1 << 5;
pub const __WASI_RIGHT_FD_WRITE: u64 = 1 << 6;
pub const __WASI_RIGHT_FD_ADVISE: u64 = 1 << 7;
pub const __WASI_RIGHT_FD_ALLOCATE: u64 = 1 << 8;
pub const __WASI_RIGHT_PATH_CREATE_DIRECTORY: u64 = 1 << 9;
pub const __WASI_RIGHT_PATH_CREATE_FILE: u64 = 1 << 10;
pub const __WASI_RIGHT_PATH_LINK_SOURCE: u64 = 1 << 11;
pub const __WASI_RIGHT_PATH_LINK_TARGET: u64 = 1 << 12;
pub const __WASI_RIGHT_PATH_OPEN: u64 = 1 << 13;
pub const __WASI_RIGHT_FD_READDIR: u64 = 1 << 14;
pub const __WASI_RIGHT_PATH_READLINK: u64 = 1 << 15;
pub const __WASI_RIGHT_PATH_RENAME_SOURCE: u64 = 1 << 16;
pub const __WASI_RIGHT_PATH_RENAME_TARGET: u64 = 1 << 17;
pub const __WASI_RIGHT_PATH_FILESTAT_GET: u64 = 1 << 18;
pub const __WASI_RIGHT_PATH_FILESTAT_SET_SIZE: u64 = 1 << 19;
pub const __WASI_RIGHT_PATH_FILESTAT_SET_TIMES: u64 = 1 << 20;
pub const __WASI_RIGHT_FD_FILESTAT_GET: u64 = 1 << 21;
pub const __WASI_RIGHT_FD_FILESTAT_SET_SIZE: u64 = 1 << 22;
pub const __WASI_RIGHT_FD_FILESTAT_SET_TIMES: u64 = 1 << 23;
pub const __WASI_RIGHT_PATH_SYMLINK: u64 = 1 << 24;
pub const __WASI_RIGHT_PATH_UNLINK_FILE: u64 = 1 << 25;
pub const __WASI_RIGHT_PATH_REMOVE_DIRECTORY: u64 = 1 << 26;
pub const __WASI_RIGHT_POLL_FD_READWRITE: u64 = 1 << 27;
pub const __WASI_RIGHT_SOCK_SHUTDOWN: u64 = 1 << 28;
pub type __wasi_roflags_t = u16;
pub const __WASI_SOCK_RECV_DATA_TRUNCATED: u16 = 1 << 0;
pub type __wasi_sdflags_t = u8;
pub const __WASI_SHUT_RD: u8 = 1 << 0;
pub const __WASI_SHUT_WR: u8 = 1 << 1;
pub type __wasi_siflags_t = u16;
pub type __wasi_signal_t = u8;
pub const __WASI_SIGABRT: u8 = 0;
pub const __WASI_SIGALRM: u8 = 1;
pub const __WASI_SIGBUS: u8 = 2;
pub const __WASI_SIGCHLD: u8 = 3;
pub const __WASI_SIGCONT: u8 = 4;
pub const __WASI_SIGFPE: u8 = 5;
pub const __WASI_SIGHUP: u8 = 6;
pub const __WASI_SIGILL: u8 = 7;
pub const __WASI_SIGINT: u8 = 8;
pub const __WASI_SIGKILL: u8 = 9;
pub const __WASI_SIGPIPE: u8 = 10;
pub const __WASI_SIGQUIT: u8 = 11;
pub const __WASI_SIGSEGV: u8 = 12;
pub const __WASI_SIGSTOP: u8 = 13;
pub const __WASI_SIGSYS: u8 = 14;
pub const __WASI_SIGTERM: u8 = 15;
pub const __WASI_SIGTRAP: u8 = 16;
pub const __WASI_SIGTSTP: u8 = 17;
pub const __WASI_SIGTTIN: u8 = 18;
pub const __WASI_SIGTTOU: u8 = 19;
pub const __WASI_SIGURG: u8 = 20;
pub const __WASI_SIGUSR1: u8 = 21;
pub const __WASI_SIGUSR2: u8 = 22;
pub const __WASI_SIGVTALRM: u8 = 23;
pub const __WASI_SIGXCPU: u8 = 24;
pub const __WASI_SIGXFSZ: u8 = 25;
pub type __wasi_subclockflags_t = u16;
pub const __WASI_SUBSCRIPTION_CLOCK_ABSTIME: u16 = 1 << 0;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(C)]
pub struct __wasi_subscription_clock_t {
pub userdata: __wasi_userdata_t,
pub clock_id: __wasi_clockid_t,
pub timeout: __wasi_timestamp_t,
pub precision: __wasi_timestamp_t,
pub flags: __wasi_subclockflags_t,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(C)]
pub struct __wasi_subscription_fs_readwrite_t {
pub fd: __wasi_fd_t,
}
#[derive(Copy, Clone)]
#[repr(C)]
pub union __wasi_subscription_u {
clock: __wasi_subscription_clock_t,
fd_readwrite: __wasi_subscription_fs_readwrite_t,
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct __wasi_subscription_t {
pub userdata: __wasi_userdata_t,
pub type_: __wasi_eventtype_t,
pub u: __wasi_subscription_u,
}
pub enum SubscriptionEnum {
Clock(__wasi_subscription_clock_t),
FdReadWrite(__wasi_subscription_fs_readwrite_t),
}
impl __wasi_subscription_t {
pub fn tagged(&self) -> Option<SubscriptionEnum> {
match self.type_ {
__WASI_EVENTTYPE_CLOCK => Some(SubscriptionEnum::Clock(unsafe { self.u.clock })),
__WASI_EVENTTYPE_FD_READ | __WASI_EVENTTYPE_FD_WRITE => {
Some(SubscriptionEnum::FdReadWrite(unsafe {
self.u.fd_readwrite
}))
}
_ => None,
}
}
}
pub type __wasi_timestamp_t = u64;
pub type __wasi_userdata_t = u64;
pub type __wasi_whence_t = u8;
pub const __WASI_WHENCE_CUR: u8 = 0;
pub const __WASI_WHENCE_END: u8 = 1;
pub const __WASI_WHENCE_SET: u8 = 2;

View File

@ -0,0 +1,59 @@
use crate::syscalls::types::*;
use libc::{
clock_getres, clock_gettime, timespec, CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID,
CLOCK_REALTIME, CLOCK_THREAD_CPUTIME_ID,
};
use std::cell::Cell;
use std::mem;
pub fn platform_clock_res_get(
clock_id: __wasi_clockid_t,
resolution: &Cell<__wasi_timestamp_t>,
) -> __wasi_errno_t {
let unix_clock_id = match clock_id {
__WASI_CLOCK_MONOTONIC => CLOCK_MONOTONIC,
__WASI_CLOCK_PROCESS_CPUTIME_ID => CLOCK_PROCESS_CPUTIME_ID,
__WASI_CLOCK_REALTIME => CLOCK_REALTIME,
__WASI_CLOCK_THREAD_CPUTIME_ID => CLOCK_THREAD_CPUTIME_ID,
_ => return __WASI_EINVAL,
};
let (output, timespec_out) = unsafe {
let mut timespec_out: timespec = mem::uninitialized();
(clock_getres(unix_clock_id, &mut timespec_out), timespec_out)
};
resolution.set(timespec_out.tv_nsec as __wasi_timestamp_t);
// TODO: map output of clock_getres to __wasi_errno_t
__WASI_ESUCCESS
}
pub fn platform_clock_time_get(
clock_id: __wasi_clockid_t,
precision: __wasi_timestamp_t,
time: &Cell<__wasi_timestamp_t>,
) -> __wasi_errno_t {
let unix_clock_id = match clock_id {
__WASI_CLOCK_MONOTONIC => CLOCK_MONOTONIC,
__WASI_CLOCK_PROCESS_CPUTIME_ID => CLOCK_PROCESS_CPUTIME_ID,
__WASI_CLOCK_REALTIME => CLOCK_REALTIME,
__WASI_CLOCK_THREAD_CPUTIME_ID => CLOCK_THREAD_CPUTIME_ID,
_ => return __WASI_EINVAL,
};
let (output, timespec_out) = unsafe {
let mut timespec_out: timespec = mem::uninitialized();
(
clock_gettime(unix_clock_id, &mut timespec_out),
timespec_out,
)
};
// TODO: adjust output by precision...
time.set(timespec_out.tv_nsec as __wasi_timestamp_t);
// TODO: map output of clock_gettime to __wasi_errno_t
__WASI_ESUCCESS
}

View File

@ -0,0 +1,17 @@
use crate::syscalls::types::*;
use std::cell::Cell;
pub fn platform_clock_res_get(
clock_id: __wasi_clockid_t,
resolution: &Cell<__wasi_timestamp_t>,
) -> __wasi_errno_t {
__WASI_EINVAL
}
pub fn platform_clock_time_get(
clock_id: __wasi_clockid_t,
precision: __wasi_timestamp_t,
time: &Cell<__wasi_timestamp_t>,
) -> __wasi_errno_t {
unimplemented!()
}

15
lib/wasi/src/utils.rs Normal file
View File

@ -0,0 +1,15 @@
use wasmer_runtime_core::module::Module;
/// Check if a provided module is compiled with WASI support
pub fn is_wasi_module(module: &Module) -> bool {
for (_, import_name) in &module.info().imported_functions {
let namespace = module
.info()
.namespace_table
.get(import_name.namespace_index);
if namespace == "wasi_unstable" {
return true;
}
}
false
}

View File

@ -12,9 +12,10 @@ use structopt::StructOpt;
use wasmer::webassembly::InstanceABI; use wasmer::webassembly::InstanceABI;
use wasmer::*; use wasmer::*;
use wasmer_emscripten;
use wasmer_runtime::cache::{Cache as BaseCache, FileSystemCache, WasmHash, WASMER_VERSION_HASH}; use wasmer_runtime::cache::{Cache as BaseCache, FileSystemCache, WasmHash, WASMER_VERSION_HASH};
use wasmer_runtime_core::{self, backend::CompilerConfig}; use wasmer_runtime_core::{self, backend::CompilerConfig};
#[cfg(feature = "wasi")]
use wasmer_wasi;
#[derive(Debug, StructOpt)] #[derive(Debug, StructOpt)]
#[structopt(name = "wasmer", about = "Wasm execution runtime.")] #[structopt(name = "wasmer", about = "Wasm execution runtime.")]
@ -211,7 +212,9 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
.map_err(|e| format!("Can't compile module: {:?}", e))? .map_err(|e| format!("Can't compile module: {:?}", e))?
}; };
let (_abi, import_object, _em_globals) = if wasmer_emscripten::is_emscripten_module(&module) { // TODO: refactor this
#[cfg(not(feature = "wasi"))]
let (abi, import_object, _em_globals) = if wasmer_emscripten::is_emscripten_module(&module) {
let mut emscripten_globals = wasmer_emscripten::EmscriptenGlobals::new(&module); let mut emscripten_globals = wasmer_emscripten::EmscriptenGlobals::new(&module);
( (
InstanceABI::Emscripten, InstanceABI::Emscripten,
@ -226,6 +229,29 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
) )
}; };
#[cfg(feature = "wasi")]
let (abi, import_object) = if wasmer_wasi::is_wasi_module(&module) {
(
InstanceABI::WASI,
wasmer_wasi::generate_import_object(
[options.path.to_str().unwrap().to_owned()]
.iter()
.chain(options.args.iter())
.cloned()
.map(|arg| arg.into_bytes())
.collect(),
env::vars()
.map(|(k, v)| format!("{}={}", k, v).into_bytes())
.collect(),
),
)
} else {
(
InstanceABI::None,
wasmer_runtime_core::import::ImportObject::new(),
)
};
let mut instance = module let mut instance = module
.instantiate(&import_object) .instantiate(&import_object)
.map_err(|e| format!("Can't instantiate module: {:?}", e))?; .map_err(|e| format!("Can't instantiate module: {:?}", e))?;
@ -233,6 +259,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
webassembly::run_instance( webassembly::run_instance(
&module, &module,
&mut instance, &mut instance,
abi,
options.path.to_str().unwrap(), options.path.to_str().unwrap(),
options.args.iter().map(|arg| arg.as_str()).collect(), options.args.iter().map(|arg| arg.as_str()).collect(),
) )

View File

@ -7,7 +7,7 @@ use wasmer_runtime::{
use wasmer_runtime_core::backend::CompilerConfig; use wasmer_runtime_core::backend::CompilerConfig;
use wasmer_runtime_core::types::Value; use wasmer_runtime_core::types::Value;
use wasmer_emscripten::{is_emscripten_module, run_emscripten_instance}; use wasmer_emscripten::run_emscripten_instance;
pub struct ResultObject { pub struct ResultObject {
/// A webassembly::Module object representing the compiled WebAssembly module. /// A webassembly::Module object representing the compiled WebAssembly module.
@ -21,6 +21,7 @@ pub struct ResultObject {
#[derive(PartialEq)] #[derive(PartialEq)]
pub enum InstanceABI { pub enum InstanceABI {
Emscripten, Emscripten,
WASI,
None, None,
} }
@ -92,18 +93,24 @@ pub fn compile_with_config(
pub fn run_instance( pub fn run_instance(
module: &Module, module: &Module,
instance: &mut Instance, instance: &mut Instance,
abi: InstanceABI,
path: &str, path: &str,
args: Vec<&str>, args: Vec<&str>,
) -> CallResult<()> { ) -> CallResult<()> {
if is_emscripten_module(module) { match abi {
InstanceABI::Emscripten => {
run_emscripten_instance(module, instance, path, args)?; run_emscripten_instance(module, instance, path, args)?;
} else { }
InstanceABI::WASI => {
instance.call("_start", &[])?;
}
InstanceABI::None => {
let args: Vec<Value> = args let args: Vec<Value> = args
.into_iter() .into_iter()
.map(|x| Value::I32(x.parse().unwrap())) .map(|x| Value::I32(x.parse().unwrap()))
.collect(); .collect();
instance.call("main", &args)?; instance.call("main", &args)?;
}; }
}
Ok(()) Ok(())
} }