Reduce boilerplate in wasmtime-wasi (#707)

This commit uses the `*.witx` files describing the current wasi API to
reduce the boilerplate used to define implementations in the
`wasmtime-wasi` crate. Eventually I'd like to remove lots of boilerplate
in the `wasi-common` crate too, but this should at least be a good start!

The boilerplate removed here is:

* No need to list each function to add it to the
  `wasmtime_runtime::Module` being created

* No need to list the signature of the function in a separate
  `syscalls.rs` file.

Instead the `*.witx` file is processed in a single-use macro inside the
`wasmtime-wasi` crate. This macro uses the signatures known from
`*.witx` to automatically register with the right type in the wasm
module as well as define a wrapper that the wasm module will call into.
Functionally this is all the same as before, it's just defined in a
different way now!

The shim generated by this macro which wasmtime calls into only uses
`i32`/`i64`/etc wasm types, and it internally uses `as` casts to convert
to the right wasi types when delegating into the `wasi-common` crate.

One change was necessary to get this implemented, however. The functions
in `wasi-common` sometimes took `WasiCtx` and sometimes took a slice of
memory. After this PR they uniformly all require both `WasiCtx` and
memory so the wrappers can be auto-generated. The arguments are ignored
if they weren't previously required.
This commit is contained in:
Alex Crichton
2019-12-16 16:37:20 -06:00
committed by GitHub
parent c2ba419409
commit cc4be18119
13 changed files with 343 additions and 1067 deletions

View File

@@ -199,7 +199,7 @@ impl<'ctx> Drop for Dir<'ctx> {
// the file descriptor was closed or not, and if we retried (for // the file descriptor was closed or not, and if we retried (for
// something like EINTR), we might close another valid file descriptor // something like EINTR), we might close another valid file descriptor
// opened after we closed ours. // opened after we closed ours.
let _ = unsafe { hostcalls::fd_close(self.ctx, self.fd) }; let _ = unsafe { hostcalls::fd_close(self.ctx, &mut [], self.fd) };
} }
} }

View File

@@ -35,7 +35,7 @@ impl<'ctx> File<'ctx> {
/// ///
/// [`std::fs::File::sync_all`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.sync_all /// [`std::fs::File::sync_all`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.sync_all
pub fn sync_all(&self) -> io::Result<()> { pub fn sync_all(&self) -> io::Result<()> {
wasi_errno_to_io_error(unsafe { hostcalls::fd_sync(self.ctx, self.fd) }) wasi_errno_to_io_error(unsafe { hostcalls::fd_sync(self.ctx, &mut [], self.fd) })
} }
/// This function is similar to `sync_all`, except that it may not synchronize /// This function is similar to `sync_all`, except that it may not synchronize
@@ -45,7 +45,7 @@ impl<'ctx> File<'ctx> {
/// ///
/// [`std::fs::File::sync_data`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.sync_data /// [`std::fs::File::sync_data`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.sync_data
pub fn sync_data(&self) -> io::Result<()> { pub fn sync_data(&self) -> io::Result<()> {
wasi_errno_to_io_error(unsafe { hostcalls::fd_datasync(self.ctx, self.fd) }) wasi_errno_to_io_error(unsafe { hostcalls::fd_datasync(self.ctx, &mut [], self.fd) })
} }
/// Truncates or extends the underlying file, updating the size of this file /// Truncates or extends the underlying file, updating the size of this file
@@ -55,7 +55,9 @@ impl<'ctx> File<'ctx> {
/// ///
/// [`std::fs::File::set_len`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.set_len /// [`std::fs::File::set_len`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.set_len
pub fn set_len(&self, size: u64) -> io::Result<()> { pub fn set_len(&self, size: u64) -> io::Result<()> {
wasi_errno_to_io_error(unsafe { hostcalls::fd_filestat_set_size(self.ctx, self.fd, size) }) wasi_errno_to_io_error(unsafe {
hostcalls::fd_filestat_set_size(self.ctx, &mut [], self.fd, size)
})
} }
/// Queries metadata about the underlying file. /// Queries metadata about the underlying file.
@@ -75,7 +77,7 @@ impl<'ctx> Drop for File<'ctx> {
// the file descriptor was closed or not, and if we retried (for // the file descriptor was closed or not, and if we retried (for
// something like EINTR), we might close another valid file descriptor // something like EINTR), we might close another valid file descriptor
// opened after we closed ours. // opened after we closed ours.
let _ = unsafe { hostcalls::fd_close(self.ctx, self.fd) }; let _ = unsafe { hostcalls::fd_close(self.ctx, &mut [], self.fd) };
} }
} }

View File

@@ -3,9 +3,9 @@ use crate::ctx::WasiCtx;
use crate::{hostcalls_impl, wasi, wasi32}; use crate::{hostcalls_impl, wasi, wasi32};
hostcalls! { hostcalls! {
pub unsafe fn fd_close(wasi_ctx: &mut WasiCtx, fd: wasi::__wasi_fd_t,) -> wasi::__wasi_errno_t; pub unsafe fn fd_close(wasi_ctx: &mut WasiCtx, memory: &mut [u8], fd: wasi::__wasi_fd_t,) -> wasi::__wasi_errno_t;
pub unsafe fn fd_datasync(wasi_ctx: &WasiCtx, fd: wasi::__wasi_fd_t,) -> wasi::__wasi_errno_t; pub unsafe fn fd_datasync(wasi_ctx: &WasiCtx, memory: &mut [u8], fd: wasi::__wasi_fd_t,) -> wasi::__wasi_errno_t;
pub unsafe fn fd_pread( pub unsafe fn fd_pread(
wasi_ctx: &WasiCtx, wasi_ctx: &WasiCtx,
@@ -38,6 +38,7 @@ hostcalls! {
pub unsafe fn fd_renumber( pub unsafe fn fd_renumber(
wasi_ctx: &mut WasiCtx, wasi_ctx: &mut WasiCtx,
memory: &mut [u8],
from: wasi::__wasi_fd_t, from: wasi::__wasi_fd_t,
to: wasi::__wasi_fd_t, to: wasi::__wasi_fd_t,
) -> wasi::__wasi_errno_t; ) -> wasi::__wasi_errno_t;
@@ -67,18 +68,20 @@ hostcalls! {
pub unsafe fn fd_fdstat_set_flags( pub unsafe fn fd_fdstat_set_flags(
wasi_ctx: &WasiCtx, wasi_ctx: &WasiCtx,
memory: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
fdflags: wasi::__wasi_fdflags_t, fdflags: wasi::__wasi_fdflags_t,
) -> wasi::__wasi_errno_t; ) -> wasi::__wasi_errno_t;
pub unsafe fn fd_fdstat_set_rights( pub unsafe fn fd_fdstat_set_rights(
wasi_ctx: &mut WasiCtx, wasi_ctx: &mut WasiCtx,
memory: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
fs_rights_base: wasi::__wasi_rights_t, fs_rights_base: wasi::__wasi_rights_t,
fs_rights_inheriting: wasi::__wasi_rights_t, fs_rights_inheriting: wasi::__wasi_rights_t,
) -> wasi::__wasi_errno_t; ) -> wasi::__wasi_errno_t;
pub unsafe fn fd_sync(wasi_ctx: &WasiCtx, fd: wasi::__wasi_fd_t,) -> wasi::__wasi_errno_t; pub unsafe fn fd_sync(wasi_ctx: &WasiCtx, memory: &mut [u8], fd: wasi::__wasi_fd_t,) -> wasi::__wasi_errno_t;
pub unsafe fn fd_write( pub unsafe fn fd_write(
wasi_ctx: &mut WasiCtx, wasi_ctx: &mut WasiCtx,
@@ -91,6 +94,7 @@ hostcalls! {
pub unsafe fn fd_advise( pub unsafe fn fd_advise(
wasi_ctx: &WasiCtx, wasi_ctx: &WasiCtx,
memory: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
offset: wasi::__wasi_filesize_t, offset: wasi::__wasi_filesize_t,
len: wasi::__wasi_filesize_t, len: wasi::__wasi_filesize_t,
@@ -99,6 +103,7 @@ hostcalls! {
pub unsafe fn fd_allocate( pub unsafe fn fd_allocate(
wasi_ctx: &WasiCtx, wasi_ctx: &WasiCtx,
memory: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
offset: wasi::__wasi_filesize_t, offset: wasi::__wasi_filesize_t,
len: wasi::__wasi_filesize_t, len: wasi::__wasi_filesize_t,
@@ -179,6 +184,7 @@ hostcalls! {
pub unsafe fn fd_filestat_set_times( pub unsafe fn fd_filestat_set_times(
wasi_ctx: &WasiCtx, wasi_ctx: &WasiCtx,
memory: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
st_atim: wasi::__wasi_timestamp_t, st_atim: wasi::__wasi_timestamp_t,
st_mtim: wasi::__wasi_timestamp_t, st_mtim: wasi::__wasi_timestamp_t,
@@ -187,6 +193,7 @@ hostcalls! {
pub unsafe fn fd_filestat_set_size( pub unsafe fn fd_filestat_set_size(
wasi_ctx: &WasiCtx, wasi_ctx: &WasiCtx,
memory: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
st_size: wasi::__wasi_filesize_t, st_size: wasi::__wasi_filesize_t,
) -> wasi::__wasi_errno_t; ) -> wasi::__wasi_errno_t;

View File

@@ -5,7 +5,7 @@ use log::trace;
use wasi_common_cbindgen::wasi_common_cbindgen; use wasi_common_cbindgen::wasi_common_cbindgen;
#[wasi_common_cbindgen] #[wasi_common_cbindgen]
pub unsafe fn proc_exit(rval: wasi::__wasi_exitcode_t) { pub unsafe fn proc_exit(_wasi_ctx: &WasiCtx, _memory: &mut [u8], rval: wasi::__wasi_exitcode_t) {
trace!("proc_exit(rval={:?})", rval); trace!("proc_exit(rval={:?})", rval);
// TODO: Rather than call std::process::exit here, we should trigger a // TODO: Rather than call std::process::exit here, we should trigger a
// stack unwind similar to a trap. // stack unwind similar to a trap.
@@ -51,18 +51,21 @@ hostcalls! {
) -> wasi::__wasi_errno_t; ) -> wasi::__wasi_errno_t;
pub unsafe fn random_get( pub unsafe fn random_get(
wasi_ctx: &WasiCtx,
memory: &mut [u8], memory: &mut [u8],
buf_ptr: wasi32::uintptr_t, buf_ptr: wasi32::uintptr_t,
buf_len: wasi32::size_t, buf_len: wasi32::size_t,
) -> wasi::__wasi_errno_t; ) -> wasi::__wasi_errno_t;
pub unsafe fn clock_res_get( pub unsafe fn clock_res_get(
wasi_ctx: &WasiCtx,
memory: &mut [u8], memory: &mut [u8],
clock_id: wasi::__wasi_clockid_t, clock_id: wasi::__wasi_clockid_t,
resolution_ptr: wasi32::uintptr_t, resolution_ptr: wasi32::uintptr_t,
) -> wasi::__wasi_errno_t; ) -> wasi::__wasi_errno_t;
pub unsafe fn clock_time_get( pub unsafe fn clock_time_get(
wasi_ctx: &WasiCtx,
memory: &mut [u8], memory: &mut [u8],
clock_id: wasi::__wasi_clockid_t, clock_id: wasi::__wasi_clockid_t,
precision: wasi::__wasi_timestamp_t, precision: wasi::__wasi_timestamp_t,
@@ -78,5 +81,8 @@ hostcalls! {
nevents: wasi32::uintptr_t, nevents: wasi32::uintptr_t,
) -> wasi::__wasi_errno_t; ) -> wasi::__wasi_errno_t;
pub unsafe fn sched_yield() -> wasi::__wasi_errno_t; pub unsafe fn sched_yield(
wasi_ctx: &WasiCtx,
memory: &mut [u8],
) -> wasi::__wasi_errno_t;
} }

View File

@@ -14,7 +14,11 @@ use std::fs::File;
use std::io::{self, Read, Seek, SeekFrom, Write}; use std::io::{self, Read, Seek, SeekFrom, Write};
use std::time::{Duration, SystemTime, UNIX_EPOCH}; use std::time::{Duration, SystemTime, UNIX_EPOCH};
pub(crate) unsafe fn fd_close(wasi_ctx: &mut WasiCtx, fd: wasi::__wasi_fd_t) -> Result<()> { pub(crate) unsafe fn fd_close(
wasi_ctx: &mut WasiCtx,
_memory: &mut [u8],
fd: wasi::__wasi_fd_t,
) -> Result<()> {
trace!("fd_close(fd={:?})", fd); trace!("fd_close(fd={:?})", fd);
if let Ok(fe) = wasi_ctx.get_fd_entry(fd) { if let Ok(fe) = wasi_ctx.get_fd_entry(fd) {
@@ -28,7 +32,11 @@ pub(crate) unsafe fn fd_close(wasi_ctx: &mut WasiCtx, fd: wasi::__wasi_fd_t) ->
Ok(()) Ok(())
} }
pub(crate) unsafe fn fd_datasync(wasi_ctx: &WasiCtx, fd: wasi::__wasi_fd_t) -> Result<()> { pub(crate) unsafe fn fd_datasync(
wasi_ctx: &WasiCtx,
_memory: &mut [u8],
fd: wasi::__wasi_fd_t,
) -> Result<()> {
trace!("fd_datasync(fd={:?})", fd); trace!("fd_datasync(fd={:?})", fd);
let fd = wasi_ctx let fd = wasi_ctx
@@ -173,6 +181,7 @@ pub(crate) unsafe fn fd_read(
pub(crate) unsafe fn fd_renumber( pub(crate) unsafe fn fd_renumber(
wasi_ctx: &mut WasiCtx, wasi_ctx: &mut WasiCtx,
_memory: &mut [u8],
from: wasi::__wasi_fd_t, from: wasi::__wasi_fd_t,
to: wasi::__wasi_fd_t, to: wasi::__wasi_fd_t,
) -> Result<()> { ) -> Result<()> {
@@ -289,6 +298,7 @@ pub(crate) unsafe fn fd_fdstat_get(
pub(crate) unsafe fn fd_fdstat_set_flags( pub(crate) unsafe fn fd_fdstat_set_flags(
wasi_ctx: &WasiCtx, wasi_ctx: &WasiCtx,
_memory: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
fdflags: wasi::__wasi_fdflags_t, fdflags: wasi::__wasi_fdflags_t,
) -> Result<()> { ) -> Result<()> {
@@ -304,6 +314,7 @@ pub(crate) unsafe fn fd_fdstat_set_flags(
pub(crate) unsafe fn fd_fdstat_set_rights( pub(crate) unsafe fn fd_fdstat_set_rights(
wasi_ctx: &mut WasiCtx, wasi_ctx: &mut WasiCtx,
_memory: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
fs_rights_base: wasi::__wasi_rights_t, fs_rights_base: wasi::__wasi_rights_t,
fs_rights_inheriting: wasi::__wasi_rights_t, fs_rights_inheriting: wasi::__wasi_rights_t,
@@ -327,7 +338,11 @@ pub(crate) unsafe fn fd_fdstat_set_rights(
Ok(()) Ok(())
} }
pub(crate) unsafe fn fd_sync(wasi_ctx: &WasiCtx, fd: wasi::__wasi_fd_t) -> Result<()> { pub(crate) unsafe fn fd_sync(
wasi_ctx: &WasiCtx,
_memory: &mut [u8],
fd: wasi::__wasi_fd_t,
) -> Result<()> {
trace!("fd_sync(fd={:?})", fd); trace!("fd_sync(fd={:?})", fd);
let fd = wasi_ctx let fd = wasi_ctx
@@ -381,6 +396,7 @@ pub(crate) unsafe fn fd_write(
pub(crate) unsafe fn fd_advise( pub(crate) unsafe fn fd_advise(
wasi_ctx: &WasiCtx, wasi_ctx: &WasiCtx,
_memory: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
offset: wasi::__wasi_filesize_t, offset: wasi::__wasi_filesize_t,
len: wasi::__wasi_filesize_t, len: wasi::__wasi_filesize_t,
@@ -404,6 +420,7 @@ pub(crate) unsafe fn fd_advise(
pub(crate) unsafe fn fd_allocate( pub(crate) unsafe fn fd_allocate(
wasi_ctx: &WasiCtx, wasi_ctx: &WasiCtx,
_memory: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
offset: wasi::__wasi_filesize_t, offset: wasi::__wasi_filesize_t,
len: wasi::__wasi_filesize_t, len: wasi::__wasi_filesize_t,
@@ -687,6 +704,7 @@ pub(crate) unsafe fn fd_filestat_get(
pub(crate) unsafe fn fd_filestat_set_times( pub(crate) unsafe fn fd_filestat_set_times(
wasi_ctx: &WasiCtx, wasi_ctx: &WasiCtx,
_memory: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
st_atim: wasi::__wasi_timestamp_t, st_atim: wasi::__wasi_timestamp_t,
st_mtim: wasi::__wasi_timestamp_t, st_mtim: wasi::__wasi_timestamp_t,
@@ -746,6 +764,7 @@ pub(crate) fn fd_filestat_set_times_impl(
pub(crate) unsafe fn fd_filestat_set_size( pub(crate) unsafe fn fd_filestat_set_size(
wasi_ctx: &WasiCtx, wasi_ctx: &WasiCtx,
_memory: &mut [u8],
fd: wasi::__wasi_fd_t, fd: wasi::__wasi_fd_t,
st_size: wasi::__wasi_filesize_t, st_size: wasi::__wasi_filesize_t,
) -> Result<()> { ) -> Result<()> {

View File

@@ -128,6 +128,7 @@ pub(crate) fn environ_sizes_get(
} }
pub(crate) fn random_get( pub(crate) fn random_get(
_wasi_ctx: &WasiCtx,
memory: &mut [u8], memory: &mut [u8],
buf_ptr: wasi32::uintptr_t, buf_ptr: wasi32::uintptr_t,
buf_len: wasi32::size_t, buf_len: wasi32::size_t,
@@ -143,6 +144,7 @@ pub(crate) fn random_get(
} }
pub(crate) fn clock_res_get( pub(crate) fn clock_res_get(
_wasi_ctx: &WasiCtx,
memory: &mut [u8], memory: &mut [u8],
clock_id: wasi::__wasi_clockid_t, clock_id: wasi::__wasi_clockid_t,
resolution_ptr: wasi32::uintptr_t, resolution_ptr: wasi32::uintptr_t,
@@ -161,6 +163,7 @@ pub(crate) fn clock_res_get(
} }
pub(crate) fn clock_time_get( pub(crate) fn clock_time_get(
_wasi_ctx: &WasiCtx,
memory: &mut [u8], memory: &mut [u8],
clock_id: wasi::__wasi_clockid_t, clock_id: wasi::__wasi_clockid_t,
precision: wasi::__wasi_timestamp_t, precision: wasi::__wasi_timestamp_t,
@@ -180,7 +183,7 @@ pub(crate) fn clock_time_get(
enc_timestamp_byref(memory, time_ptr, time) enc_timestamp_byref(memory, time_ptr, time)
} }
pub(crate) fn sched_yield() -> Result<()> { pub(crate) fn sched_yield(_wasi_ctx: &WasiCtx, _memory: &mut [u8]) -> Result<()> {
trace!("sched_yield()"); trace!("sched_yield()");
std::thread::yield_now(); std::thread::yield_now();

View File

@@ -2,6 +2,7 @@ extern crate proc_macro;
mod raw_types; mod raw_types;
mod utils; mod utils;
mod wasi;
use proc_macro::TokenStream; use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2; use proc_macro2::TokenStream as TokenStream2;
@@ -29,3 +30,9 @@ pub fn witx_wasi32_types(args: TokenStream) -> TokenStream {
raw_types::Mode::Wasi32, raw_types::Mode::Wasi32,
)) ))
} }
/// A single-use macro in the `wasmtime-wasi` crate.
#[proc_macro]
pub fn define_add_wrappers_to_module(args: TokenStream) -> TokenStream {
wasi::add_wrappers_to_module(args.into()).into()
}

View File

@@ -1,4 +1,5 @@
use proc_macro2::{Literal, TokenStream, TokenTree}; use proc_macro2::{Literal, TokenStream, TokenTree};
/// Given the input tokens to a macro invocation, return the path to the /// Given the input tokens to a macro invocation, return the path to the
/// witx file to process. /// witx file to process.
pub(crate) fn witx_path_from_args(args: TokenStream) -> (String, String) { pub(crate) fn witx_path_from_args(args: TokenStream) -> (String, String) {
@@ -26,8 +27,8 @@ pub(crate) fn witx_path_from_args(args: TokenStream) -> (String, String) {
} }
fn witx_path(phase: &str, id: &str) -> String { fn witx_path(phase: &str, id: &str) -> String {
let root = std::env::var("CARGO_MANIFEST_DIR").unwrap_or(".".into()); let root = env!("CARGO_MANIFEST_DIR");
format!("{}/WASI/phases/{}/witx/{}.witx", root, phase, id) format!("{}/../WASI/phases/{}/witx/{}.witx", root, phase, id)
} }
// Convert a `Literal` holding a string literal into the `String`. // Convert a `Literal` holding a string literal into the `String`.

View File

@@ -0,0 +1,231 @@
use crate::utils;
use proc_macro2::{Ident, Span, TokenStream};
use quote::{format_ident, quote};
enum Abi {
I32,
I64,
F32,
F64,
}
/// This is a single-use macro intended to be used in the `wasmtime-wasi` crate.
///
/// This macro will generate a function, `add_wrappers_to_module`, which will
/// use the input arguments to register all wasi functions inside of a `Module`
/// instance. This will automatically assign the wasm underlying types and
/// perform conversions from the wasm type to the underlying wasi type (often
/// unsigned or of a smaller width).
///
/// The generated shim functions here will also `trace!` their arguments for
/// logging purposes. Otherwise this is hopefully somewhat straightforward!
///
/// I'd recommend using `cargo +nightly expand` to explore the output of this
/// macro some more.
pub fn add_wrappers_to_module(args: TokenStream) -> TokenStream {
let (path, _phase) = utils::witx_path_from_args(args);
let doc = match witx::load(&[&path]) {
Ok(doc) => doc,
Err(e) => {
panic!("error opening file {}: {}", path, e);
}
};
let mut add = Vec::new();
for module in doc.modules() {
for func in module.funcs() {
let name = func.name.as_str();
let name_ident = Ident::new(func.name.as_str(), Span::call_site());
let mut shim_arg_decls = Vec::new();
let mut params = Vec::new();
let mut formats = Vec::new();
let mut format_args = Vec::new();
let mut hostcall_args = Vec::new();
for param in func.params.iter() {
let name = format_ident!(
"{}",
match param.name.as_str() {
"in" | "type" => format!("r#{}", param.name.as_str()),
s => s.to_string(),
}
);
// Registers a new parameter to the shim we're making with the
// given `name`, the `abi_ty` wasm type and `hex` defines
// whether it's debug-printed in a hex format or not.
//
// This will register a whole bunch of things:
//
// * The cranelift type for the parameter
// * Syntax to specify the actual function parameter
// * How to log the parameter value in a call to `trace!`
// * How to actually pass this argument to the host
// implementation, converting as necessary.
let mut add_param = |name: &Ident, abi_ty: Abi, hex: bool| {
match abi_ty {
Abi::I32 => {
params.push(quote! { types::I32 });
shim_arg_decls.push(quote! { #name: i32 });
}
Abi::I64 => {
params.push(quote! { types::I64 });
shim_arg_decls.push(quote! { #name: i64 });
}
Abi::F32 => {
params.push(quote! { types::F32 });
shim_arg_decls.push(quote! { #name: f32 });
}
Abi::F64 => {
params.push(quote! { types::F64 });
shim_arg_decls.push(quote! { #name: f64 });
}
}
formats.push(format!("{}={}", name, if hex { "{:#x}" } else { "{}" },));
format_args.push(name.clone());
hostcall_args.push(quote! { #name as _ });
};
match &*param.tref.type_() {
witx::Type::Enum(e) => match e.repr {
witx::IntRepr::U64 => add_param(&name, Abi::I64, false),
_ => add_param(&name, Abi::I32, false),
},
witx::Type::Flags(f) => match f.repr {
witx::IntRepr::U64 => add_param(&name, Abi::I64, true),
_ => add_param(&name, Abi::I32, true),
},
witx::Type::Builtin(witx::BuiltinType::S8)
| witx::Type::Builtin(witx::BuiltinType::U8)
| witx::Type::Builtin(witx::BuiltinType::S16)
| witx::Type::Builtin(witx::BuiltinType::U16)
| witx::Type::Builtin(witx::BuiltinType::S32)
| witx::Type::Builtin(witx::BuiltinType::U32) => {
add_param(&name, Abi::I32, false);
}
witx::Type::Builtin(witx::BuiltinType::S64)
| witx::Type::Builtin(witx::BuiltinType::U64) => {
add_param(&name, Abi::I64, false);
}
witx::Type::Builtin(witx::BuiltinType::F32) => {
add_param(&name, Abi::F32, false);
}
witx::Type::Builtin(witx::BuiltinType::F64) => {
add_param(&name, Abi::F64, false);
}
// strings/arrays have an extra ABI parameter for the length
// of the array passed.
witx::Type::Builtin(witx::BuiltinType::String) | witx::Type::Array(_) => {
add_param(&name, Abi::I32, true);
let len = format_ident!("{}_len", name);
add_param(&len, Abi::I32, false);
}
witx::Type::ConstPointer(_)
| witx::Type::Handle(_)
| witx::Type::Pointer(_) => {
add_param(&name, Abi::I32, true);
}
witx::Type::Struct(_) | witx::Type::Union(_) => {
panic!("unsupported argument type")
}
}
}
let mut results = func.results.iter();
let mut ret_ty = quote! { () };
let mut cvt_ret = quote! {};
let mut returns = Vec::new();
let mut handle_early_error = quote! { panic!("error: {:?}", e) };
// The first result is returned bare right now...
if let Some(ret) = results.next() {
handle_early_error = quote! { return e.into() };
match &*ret.tref.type_() {
// Eventually we'll want to add support for more returned
// types, but for now let's just conform to what `*.witx`
// definitions currently use.
witx::Type::Enum(e) => match e.repr {
witx::IntRepr::U16 => {
returns.push(quote! { types::I32 });
ret_ty = quote! { i32 };
cvt_ret = quote! { .into() }
}
other => panic!("unsupported ret enum repr {:?}", other),
},
other => panic!("unsupported first return {:?}", other),
}
}
// ... and all remaining results are returned via out-poiners
for result in results {
let name = format_ident!("{}", result.name.as_str());
params.push(quote! { types::I32 });
shim_arg_decls.push(quote! { #name: i32 });
formats.push(format!("{}={{:#x}}", name));
format_args.push(name.clone());
hostcall_args.push(quote! { #name as u32 });
}
let format_str = format!("{}({})", name, formats.join(", "));
add.push(quote! {
let sig = module.signatures.push(translate_signature(
ir::Signature {
params: vec![#(cranelift_codegen::ir::AbiParam::new(#params)),*],
returns: vec![#(cranelift_codegen::ir::AbiParam::new(#returns)),*],
call_conv,
},
pointer_type,
));
let func = module.functions.push(sig);
module
.exports
.insert(#name.to_owned(), Export::Function(func));
unsafe extern "C" fn #name_ident(
ctx: *mut wasmtime_runtime::VMContext,
#(#shim_arg_decls),*
) -> #ret_ty {
log::trace!(
#format_str,
#(#format_args),*
);
let wasi_ctx = match get_wasi_ctx(&mut *ctx) {
Ok(e) => e,
Err(e) => #handle_early_error,
};
let memory = match get_memory(&mut *ctx) {
Ok(e) => e,
Err(e) => #handle_early_error,
};
wasi_common::hostcalls::#name_ident(
wasi_ctx,
memory,
#(#hostcall_args),*
) #cvt_ret
}
finished_functions.push(#name_ident as *const _);
});
}
}
quote! {
pub fn add_wrappers_to_module(
module: &mut Module,
finished_functions: &mut PrimaryMap<DefinedFuncIndex, *const wasmtime_runtime::VMFunctionBody>,
call_conv: isa::CallConv,
pointer_type: types::Type,
) {
#(#add)*
}
}
}

View File

@@ -21,6 +21,7 @@ cranelift-entity = { version = "0.50.0", features = ["enable-serde"] }
cranelift-wasm = { version = "0.50.0", features = ["enable-serde"] } cranelift-wasm = { version = "0.50.0", features = ["enable-serde"] }
target-lexicon = "0.9.0" target-lexicon = "0.9.0"
log = { version = "0.4.8", default-features = false } log = { version = "0.4.8", default-features = false }
wig = { path = "../wasi-common/wig" }
[badges] [badges]
maintenance = { status = "actively-developed" } maintenance = { status = "actively-developed" }

View File

@@ -1,4 +1,3 @@
use super::syscalls;
use cranelift_codegen::ir::types; use cranelift_codegen::ir::types;
use cranelift_codegen::{ir, isa}; use cranelift_codegen::{ir, isa};
use cranelift_entity::PrimaryMap; use cranelift_entity::PrimaryMap;
@@ -8,9 +7,10 @@ use std::collections::HashMap;
use std::fs::File; use std::fs::File;
use std::rc::Rc; use std::rc::Rc;
use target_lexicon::HOST; use target_lexicon::HOST;
use wasi_common::wasi;
use wasi_common::{WasiCtx, WasiCtxBuilder}; use wasi_common::{WasiCtx, WasiCtxBuilder};
use wasmtime_environ::{translate_signature, Export, Module}; use wasmtime_environ::{translate_signature, Export, Module};
use wasmtime_runtime::{Imports, InstanceHandle, InstantiationError, VMFunctionBody}; use wasmtime_runtime::{Imports, InstanceHandle, InstantiationError, VMContext};
/// Creates `wasmtime::Instance` object implementing the "wasi" interface. /// Creates `wasmtime::Instance` object implementing the "wasi" interface.
pub fn create_wasi_instance( pub fn create_wasi_instance(
@@ -64,79 +64,19 @@ pub fn instantiate_wasi_with_context(
) -> Result<InstanceHandle, InstantiationError> { ) -> Result<InstanceHandle, InstantiationError> {
let pointer_type = types::Type::triple_pointer_type(&HOST); let pointer_type = types::Type::triple_pointer_type(&HOST);
let mut module = Module::new(); let mut module = Module::new();
let mut finished_functions: PrimaryMap<DefinedFuncIndex, *const VMFunctionBody> = let mut finished_functions = PrimaryMap::new();
PrimaryMap::new();
let call_conv = isa::CallConv::triple_default(&HOST); let call_conv = isa::CallConv::triple_default(&HOST);
macro_rules! signature { // This function is defined in the macro invocation of
($name:ident) => {{ // `define_add_wrappers_to_module` below. For more information about how
let sig = module.signatures.push(translate_signature( // this works it'd recommended to read the source in
ir::Signature { // `crates/wasi-common/wig/src/wasi.rs`.
params: syscalls::$name::params() add_wrappers_to_module(
.into_iter() &mut module,
.map(ir::AbiParam::new) &mut finished_functions,
.collect(), call_conv,
returns: syscalls::$name::results() pointer_type,
.into_iter() );
.map(ir::AbiParam::new)
.collect(),
call_conv,
},
pointer_type,
));
let func = module.functions.push(sig);
module
.exports
.insert(stringify!($name).to_owned(), Export::Function(func));
finished_functions.push(syscalls::$name::SHIM as *const VMFunctionBody);
}};
}
signature!(args_get);
signature!(args_sizes_get);
signature!(clock_res_get);
signature!(clock_time_get);
signature!(environ_get);
signature!(environ_sizes_get);
signature!(fd_prestat_get);
signature!(fd_prestat_dir_name);
signature!(fd_close);
signature!(fd_datasync);
signature!(fd_pread);
signature!(fd_pwrite);
signature!(fd_read);
signature!(fd_renumber);
signature!(fd_seek);
signature!(fd_tell);
signature!(fd_fdstat_get);
signature!(fd_fdstat_set_flags);
signature!(fd_fdstat_set_rights);
signature!(fd_sync);
signature!(fd_write);
signature!(fd_advise);
signature!(fd_allocate);
signature!(path_create_directory);
signature!(path_link);
signature!(path_open);
signature!(fd_readdir);
signature!(path_readlink);
signature!(path_rename);
signature!(fd_filestat_get);
signature!(fd_filestat_set_times);
signature!(fd_filestat_set_size);
signature!(path_filestat_get);
signature!(path_filestat_set_times);
signature!(path_symlink);
signature!(path_unlink_file);
signature!(path_remove_directory);
signature!(poll_oneoff);
signature!(proc_exit);
signature!(proc_raise);
signature!(random_get);
signature!(sched_yield);
signature!(sock_recv);
signature!(sock_send);
signature!(sock_shutdown);
let imports = Imports::none(); let imports = Imports::none();
let data_initializers = Vec::new(); let data_initializers = Vec::new();
@@ -153,3 +93,40 @@ pub fn instantiate_wasi_with_context(
Box::new(wasi_ctx), Box::new(wasi_ctx),
) )
} }
wig::define_add_wrappers_to_module!(
"snapshot" "wasi_snapshot_preview1"
);
// Used by `add_wrappers_to_module` defined in the macro above
fn get_wasi_ctx(vmctx: &mut VMContext) -> Result<&mut WasiCtx, wasi::__wasi_errno_t> {
unsafe {
vmctx
.host_state()
.downcast_mut::<WasiCtx>()
.ok_or_else(|| panic!("no host state named WasiCtx available"))
}
}
// Used by `add_wrappers_to_module` defined in the macro above
fn get_memory(vmctx: &mut VMContext) -> Result<&mut [u8], wasi::__wasi_errno_t> {
unsafe {
match vmctx.lookup_global_export("memory") {
Some(wasmtime_runtime::Export::Memory {
definition,
vmctx: _,
memory: _,
}) => Ok(std::slice::from_raw_parts_mut(
(*definition).base,
(*definition).current_length,
)),
x => {
log::error!(
"no export named \"memory\", or the export isn't a mem: {:?}",
x
);
Err(wasi::__WASI_ERRNO_INVAL)
}
}
}
}

View File

@@ -2,7 +2,6 @@
mod instantiate; mod instantiate;
pub mod old; pub mod old;
mod syscalls;
pub use instantiate::{create_wasi_instance, instantiate_wasi, instantiate_wasi_with_context}; pub use instantiate::{create_wasi_instance, instantiate_wasi, instantiate_wasi_with_context};

View File

@@ -1,977 +0,0 @@
use cranelift_codegen::ir::types::{Type, I32, I64};
use log::{error, trace};
use wasi_common::{hostcalls, wasi, wasi32, WasiCtx};
use wasmtime_runtime::{Export, VMContext};
pub trait AbiRet {
type Abi;
fn convert(self) -> Self::Abi;
fn codegen_tys() -> Vec<Type>;
}
pub trait AbiParam {
type Abi;
fn convert(arg: Self::Abi) -> Self;
fn codegen_ty() -> Type;
}
macro_rules! cast32 {
($($i:ident)*) => ($(
impl AbiRet for $i {
type Abi = i32;
fn convert(self) -> Self::Abi {
self as i32
}
fn codegen_tys() -> Vec<Type> { vec![I32] }
}
impl AbiParam for $i {
type Abi = i32;
fn convert(param: i32) -> Self {
param as $i
}
fn codegen_ty() -> Type { I32 }
}
)*)
}
macro_rules! cast64 {
($($i:ident)*) => ($(
impl AbiRet for $i {
type Abi = i64;
fn convert(self) -> Self::Abi {
self as i64
}
fn codegen_tys() -> Vec<Type> { vec![I64] }
}
impl AbiParam for $i {
type Abi = i64;
fn convert(param: i64) -> Self {
param as $i
}
fn codegen_ty() -> Type { I64 }
}
)*)
}
cast32!(i8 i16 i32 u8 u16 u32);
cast64!(i64 u64);
impl AbiRet for () {
type Abi = ();
fn convert(self) {}
fn codegen_tys() -> Vec<Type> {
Vec::new()
}
}
fn get_wasi_ctx(vmctx: &mut VMContext) -> Result<&mut WasiCtx, wasi::__wasi_errno_t> {
unsafe {
vmctx
.host_state()
.downcast_mut::<WasiCtx>()
.ok_or_else(|| panic!("no host state named WasiCtx available"))
}
}
fn get_memory(vmctx: &mut VMContext) -> Result<&mut [u8], wasi::__wasi_errno_t> {
unsafe {
match vmctx.lookup_global_export("memory") {
Some(Export::Memory {
definition,
vmctx: _,
memory: _,
}) => Ok(std::slice::from_raw_parts_mut(
(*definition).base,
(*definition).current_length,
)),
x => {
error!(
"no export named \"memory\", or the export isn't a mem: {:?}",
x
);
Err(wasi::__WASI_ERRNO_INVAL)
}
}
}
}
macro_rules! ok_or_errno {
($expr:expr) => {
match $expr {
Ok(v) => v,
Err(e) => {
trace!(" -> errno={}", wasi::strerror(e));
return e;
}
}
};
}
macro_rules! syscalls {
($(pub unsafe extern "C" fn $name:ident($ctx:ident: *mut VMContext $(, $arg:ident: $ty:ty)*,) -> $ret:ty {
$($body:tt)*
})*) => ($(
pub mod $name {
use super::*;
/// Returns the codegen types of all the parameters to the shim
/// generated
pub fn params() -> Vec<Type> {
vec![$(<$ty as AbiParam>::codegen_ty()),*]
}
/// Returns the codegen types of all the results of the shim
/// generated
pub fn results() -> Vec<Type> {
<$ret as AbiRet>::codegen_tys()
}
/// The actual function pointer to the shim for a syscall.
///
/// NB: ideally we'd expose `shim` below, but it seems like there's
/// a compiler bug which prvents that from being cast to a `usize`.
pub static SHIM: unsafe extern "C" fn(
*mut VMContext,
$(<$ty as AbiParam>::Abi),*
) -> <$ret as AbiRet>::Abi = shim;
unsafe extern "C" fn shim(
$ctx: *mut VMContext,
$($arg: <$ty as AbiParam>::Abi,)*
) -> <$ret as AbiRet>::Abi {
let r = super::$name($ctx, $(<$ty as AbiParam>::convert($arg),)*);
<$ret as AbiRet>::convert(r)
}
}
pub unsafe extern "C" fn $name($ctx: *mut VMContext, $($arg: $ty,)*) -> $ret {
$($body)*
}
)*)
}
syscalls! {
pub unsafe extern "C" fn args_get(
vmctx: *mut VMContext,
argv: wasi32::uintptr_t,
argv_buf: wasi32::uintptr_t,
) -> wasi::__wasi_errno_t {
trace!(
"args_get(argv={:#x?}, argv_buf={:#x?})",
argv,
argv_buf,
);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::args_get(wasi_ctx, memory, argv, argv_buf)
}
pub unsafe extern "C" fn args_sizes_get(
vmctx: *mut VMContext,
argc: wasi32::uintptr_t,
argv_buf_size: wasi32::uintptr_t,
) -> wasi::__wasi_errno_t {
trace!(
"args_sizes_get(argc={:#x?}, argv_buf_size={:#x?})",
argc,
argv_buf_size,
);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::args_sizes_get(wasi_ctx, memory, argc, argv_buf_size)
}
pub unsafe extern "C" fn clock_res_get(
vmctx: *mut VMContext,
clock_id: wasi::__wasi_clockid_t,
resolution: wasi32::uintptr_t,
) -> wasi::__wasi_errno_t {
trace!(
"clock_res_get(clock_id={:?}, resolution={:#x?})",
clock_id,
resolution,
);
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::clock_res_get(memory, clock_id, resolution)
}
pub unsafe extern "C" fn clock_time_get(
vmctx: *mut VMContext,
clock_id: wasi::__wasi_clockid_t,
precision: wasi::__wasi_timestamp_t,
time: wasi32::uintptr_t,
) -> wasi::__wasi_errno_t {
trace!(
"clock_time_get(clock_id={:?}, precision={:?}, time={:#x?})",
clock_id,
precision,
time,
);
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::clock_time_get(memory, clock_id, precision, time)
}
pub unsafe extern "C" fn environ_get(
vmctx: *mut VMContext,
environ: wasi32::uintptr_t,
environ_buf: wasi32::uintptr_t,
) -> wasi::__wasi_errno_t {
trace!(
"environ_get(environ={:#x?}, environ_buf={:#x?})",
environ,
environ_buf,
);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::environ_get(wasi_ctx, memory, environ, environ_buf)
}
pub unsafe extern "C" fn environ_sizes_get(
vmctx: *mut VMContext,
environ_count: wasi32::uintptr_t,
environ_buf_size: wasi32::uintptr_t,
) -> wasi::__wasi_errno_t {
trace!(
"environ_sizes_get(environ_count={:#x?}, environ_buf_size={:#x?})",
environ_count,
environ_buf_size,
);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::environ_sizes_get(wasi_ctx, memory, environ_count, environ_buf_size)
}
pub unsafe extern "C" fn fd_prestat_get(
vmctx: *mut VMContext,
fd: wasi::__wasi_fd_t,
buf: wasi32::uintptr_t,
) -> wasi::__wasi_errno_t {
trace!("fd_prestat_get(fd={:?}, buf={:#x?})", fd, buf);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::fd_prestat_get(wasi_ctx, memory, fd, buf)
}
pub unsafe extern "C" fn fd_prestat_dir_name(
vmctx: *mut VMContext,
fd: wasi::__wasi_fd_t,
path: wasi32::uintptr_t,
path_len: wasi32::size_t,
) -> wasi::__wasi_errno_t {
trace!("fd_prestat_dir_name(fd={:?}, path={:#x?}, path_len={})", fd, path, path_len);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::fd_prestat_dir_name(wasi_ctx, memory, fd, path, path_len)
}
pub unsafe extern "C" fn fd_close(
vmctx: *mut VMContext,
fd: wasi::__wasi_fd_t,
) -> wasi::__wasi_errno_t {
trace!("fd_close(fd={:?})", fd);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
hostcalls::fd_close(wasi_ctx, fd)
}
pub unsafe extern "C" fn fd_datasync(
vmctx: *mut VMContext,
fd: wasi::__wasi_fd_t,
) -> wasi::__wasi_errno_t {
trace!("fd_datasync(fd={:?})", fd);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
hostcalls::fd_datasync(wasi_ctx, fd)
}
pub unsafe extern "C" fn fd_pread(
vmctx: *mut VMContext,
fd: wasi::__wasi_fd_t,
iovs: wasi32::uintptr_t,
iovs_len: wasi32::size_t,
offset: wasi::__wasi_filesize_t,
nread: wasi32::uintptr_t,
) -> wasi::__wasi_errno_t {
trace!(
"fd_pread(fd={:?}, iovs={:#x?}, iovs_len={:?}, offset={}, nread={:#x?})",
fd,
iovs,
iovs_len,
offset,
nread
);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::fd_pread(
wasi_ctx,
memory,
fd,
iovs,
iovs_len,
offset,
nread
)
}
pub unsafe extern "C" fn fd_pwrite(
vmctx: *mut VMContext,
fd: wasi::__wasi_fd_t,
iovs: wasi32::uintptr_t,
iovs_len: wasi32::size_t,
offset: wasi::__wasi_filesize_t,
nwritten: wasi32::uintptr_t,
) -> wasi::__wasi_errno_t {
trace!(
"fd_pwrite(fd={:?}, iovs={:#x?}, iovs_len={:?}, offset={}, nwritten={:#x?})",
fd,
iovs,
iovs_len,
offset,
nwritten
);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::fd_pwrite(
wasi_ctx,
memory,
fd,
iovs,
iovs_len,
offset,
nwritten
)
}
pub unsafe extern "C" fn fd_read(
vmctx: *mut VMContext,
fd: wasi::__wasi_fd_t,
iovs: wasi32::uintptr_t,
iovs_len: wasi32::size_t,
nread: wasi32::uintptr_t,
) -> wasi::__wasi_errno_t {
trace!(
"fd_read(fd={:?}, iovs={:#x?}, iovs_len={:?}, nread={:#x?})",
fd,
iovs,
iovs_len,
nread
);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::fd_read(wasi_ctx, memory, fd, iovs, iovs_len, nread)
}
pub unsafe extern "C" fn fd_renumber(
vmctx: *mut VMContext,
from: wasi::__wasi_fd_t,
to: wasi::__wasi_fd_t,
) -> wasi::__wasi_errno_t {
trace!("fd_renumber(from={:?}, to={:?})", from, to);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
hostcalls::fd_renumber(wasi_ctx, from, to)
}
pub unsafe extern "C" fn fd_seek(
vmctx: *mut VMContext,
fd: wasi::__wasi_fd_t,
offset: wasi::__wasi_filedelta_t,
whence: wasi::__wasi_whence_t,
newoffset: wasi32::uintptr_t,
) -> wasi::__wasi_errno_t {
trace!(
"fd_seek(fd={:?}, offset={:?}, whence={}, newoffset={:#x?})",
fd,
offset,
wasi::whence_to_str(whence),
newoffset
);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::fd_seek(wasi_ctx, memory, fd, offset, whence, newoffset)
}
pub unsafe extern "C" fn fd_tell(
vmctx: *mut VMContext,
fd: wasi::__wasi_fd_t,
newoffset: wasi32::uintptr_t,
) -> wasi::__wasi_errno_t {
trace!("fd_tell(fd={:?}, newoffset={:#x?})", fd, newoffset);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::fd_tell(wasi_ctx, memory, fd, newoffset)
}
pub unsafe extern "C" fn fd_fdstat_get(
vmctx: *mut VMContext,
fd: wasi::__wasi_fd_t,
buf: wasi32::uintptr_t,
) -> wasi::__wasi_errno_t {
trace!("fd_fdstat_get(fd={:?}, buf={:#x?})", fd, buf);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::fd_fdstat_get(wasi_ctx, memory, fd, buf)
}
pub unsafe extern "C" fn fd_fdstat_set_flags(
vmctx: *mut VMContext,
fd: wasi::__wasi_fd_t,
flags: wasi::__wasi_fdflags_t,
) -> wasi::__wasi_errno_t {
trace!(
"fd_fdstat_set_flags(fd={:?}, flags={:#x?})",
fd,
flags
);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
hostcalls::fd_fdstat_set_flags(wasi_ctx, fd, flags)
}
pub unsafe extern "C" fn fd_fdstat_set_rights(
vmctx: *mut VMContext,
fd: wasi::__wasi_fd_t,
fs_rights_base: wasi::__wasi_rights_t,
fs_rights_inheriting: wasi::__wasi_rights_t,
) -> wasi::__wasi_errno_t {
trace!(
"fd_fdstat_set_rights(fd={:?}, fs_rights_base={:#x?}, fs_rights_inheriting={:#x?})",
fd,
fs_rights_base,
fs_rights_inheriting
);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
hostcalls::fd_fdstat_set_rights(
wasi_ctx,
fd,
fs_rights_base,
fs_rights_inheriting
)
}
pub unsafe extern "C" fn fd_sync(
vmctx: *mut VMContext,
fd: wasi::__wasi_fd_t,
) -> wasi::__wasi_errno_t {
trace!("fd_sync(fd={:?})", fd);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
hostcalls::fd_sync(wasi_ctx, fd)
}
pub unsafe extern "C" fn fd_write(
vmctx: *mut VMContext,
fd: wasi::__wasi_fd_t,
iovs: wasi32::uintptr_t,
iovs_len: wasi32::size_t,
nwritten: wasi32::uintptr_t,
) -> wasi::__wasi_errno_t {
trace!(
"fd_write(fd={:?}, iovs={:#x?}, iovs_len={:?}, nwritten={:#x?})",
fd,
iovs,
iovs_len,
nwritten
);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::fd_write(wasi_ctx, memory, fd, iovs, iovs_len, nwritten)
}
pub unsafe extern "C" fn fd_advise(
vmctx: *mut VMContext,
fd: wasi::__wasi_fd_t,
offset: wasi::__wasi_filesize_t,
len: wasi::__wasi_filesize_t,
advice: wasi::__wasi_advice_t,
) -> wasi::__wasi_errno_t {
trace!(
"fd_advise(fd={:?}, offset={}, len={}, advice={:?})",
fd,
offset,
len,
advice
);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
hostcalls::fd_advise(wasi_ctx, fd, offset, len, advice)
}
pub unsafe extern "C" fn fd_allocate(
vmctx: *mut VMContext,
fd: wasi::__wasi_fd_t,
offset: wasi::__wasi_filesize_t,
len: wasi::__wasi_filesize_t,
) -> wasi::__wasi_errno_t {
trace!("fd_allocate(fd={:?}, offset={}, len={})", fd, offset, len);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
hostcalls::fd_allocate(wasi_ctx, fd, offset, len)
}
pub unsafe extern "C" fn path_create_directory(
vmctx: *mut VMContext,
fd: wasi::__wasi_fd_t,
path: wasi32::uintptr_t,
path_len: wasi32::size_t,
) -> wasi::__wasi_errno_t {
trace!(
"path_create_directory(fd={:?}, path={:#x?}, path_len={})",
fd,
path,
path_len,
);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::path_create_directory(wasi_ctx, memory, fd, path, path_len)
}
pub unsafe extern "C" fn path_link(
vmctx: *mut VMContext,
fd0: wasi::__wasi_fd_t,
flags0: wasi::__wasi_lookupflags_t,
path0: wasi32::uintptr_t,
path_len0: wasi32::size_t,
fd1: wasi::__wasi_fd_t,
path1: wasi32::uintptr_t,
path_len1: wasi32::size_t,
) -> wasi::__wasi_errno_t {
trace!(
"path_link(fd0={:?}, flags0={:?}, path0={:#x?}, path_len0={}, fd1={:?}, path1={:#x?}, path_len1={})",
fd0,
flags0,
path0,
path_len0,
fd1,
path1,
path_len1
);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::path_link(
wasi_ctx,
memory,
fd0,
flags0,
path0,
path_len0,
fd1,
path1,
path_len1
)
}
// TODO: When multi-value happens, switch to that instead of passing
// the `fd` by reference?
pub unsafe extern "C" fn path_open(
vmctx: *mut VMContext,
dirfd: wasi::__wasi_fd_t,
dirflags: wasi::__wasi_lookupflags_t,
path: wasi32::uintptr_t,
path_len: wasi32::size_t,
oflags: wasi::__wasi_oflags_t,
fs_rights_base: wasi::__wasi_rights_t,
fs_rights_inheriting: wasi::__wasi_rights_t,
fs_flags: wasi::__wasi_fdflags_t,
fd: wasi32::uintptr_t,
) -> wasi::__wasi_errno_t {
trace!(
"path_open(dirfd={:?}, dirflags={:?}, path={:#x?}, path_len={:?}, oflags={:#x?}, fs_rights_base={:#x?}, fs_rights_inheriting={:#x?}, fs_flags={:#x?}, fd={:#x?})",
dirfd,
dirflags,
path,
path_len,
oflags,
fs_rights_base,
fs_rights_inheriting,
fs_flags,
fd
);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::path_open(
wasi_ctx,
memory,
dirfd,
dirflags,
path,
path_len,
oflags,
fs_rights_base,
fs_rights_inheriting,
fs_flags,
fd
)
}
pub unsafe extern "C" fn fd_readdir(
vmctx: *mut VMContext,
fd: wasi::__wasi_fd_t,
buf: wasi32::uintptr_t,
buf_len: wasi32::size_t,
cookie: wasi::__wasi_dircookie_t,
buf_used: wasi32::uintptr_t,
) -> wasi::__wasi_errno_t {
trace!(
"fd_readdir(fd={:?}, buf={:#x?}, buf_len={}, cookie={:#x?}, buf_used={:#x?})",
fd,
buf,
buf_len,
cookie,
buf_used,
);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::fd_readdir(
wasi_ctx,
memory,
fd,
buf,
buf_len,
cookie,
buf_used
)
}
pub unsafe extern "C" fn path_readlink(
vmctx: *mut VMContext,
fd: wasi::__wasi_fd_t,
path: wasi32::uintptr_t,
path_len: wasi32::size_t,
buf: wasi32::uintptr_t,
buf_len: wasi32::size_t,
buf_used: wasi32::uintptr_t,
) -> wasi::__wasi_errno_t {
trace!(
"path_readlink(fd={:?}, path={:#x?}, path_len={:?}, buf={:#x?}, buf_len={}, buf_used={:#x?})",
fd,
path,
path_len,
buf,
buf_len,
buf_used,
);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::path_readlink(
wasi_ctx,
memory,
fd,
path,
path_len,
buf,
buf_len,
buf_used
)
}
pub unsafe extern "C" fn path_rename(
vmctx: *mut VMContext,
fd0: wasi::__wasi_fd_t,
path0: wasi32::uintptr_t,
path_len0: wasi32::size_t,
fd1: wasi::__wasi_fd_t,
path1: wasi32::uintptr_t,
path_len1: wasi32::size_t,
) -> wasi::__wasi_errno_t {
trace!(
"path_rename(fd0={:?}, path0={:#x?}, path_len0={:?}, fd1={:?}, path1={:#x?}, path_len1={:?})",
fd0,
path0,
path_len0,
fd1,
path1,
path_len1,
);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::path_rename(
wasi_ctx,
memory,
fd0,
path0,
path_len0,
fd1,
path1,
path_len1
)
}
pub unsafe extern "C" fn fd_filestat_get(
vmctx: *mut VMContext,
fd: wasi::__wasi_fd_t,
buf: wasi32::uintptr_t,
) -> wasi::__wasi_errno_t {
trace!("fd_filestat_get(fd={:?}, buf={:#x?})", fd, buf);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::fd_filestat_get(wasi_ctx, memory, fd, buf)
}
pub unsafe extern "C" fn fd_filestat_set_times(
vmctx: *mut VMContext,
fd: wasi::__wasi_fd_t,
st_atim: wasi::__wasi_timestamp_t,
st_mtim: wasi::__wasi_timestamp_t,
fstflags: wasi::__wasi_fstflags_t,
) -> wasi::__wasi_errno_t {
trace!(
"fd_filestat_set_times(fd={:?}, st_atim={}, st_mtim={}, fstflags={:#x?})",
fd,
st_atim, st_mtim,
fstflags
);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
hostcalls::fd_filestat_set_times(wasi_ctx, fd, st_atim, st_mtim, fstflags)
}
pub unsafe extern "C" fn fd_filestat_set_size(
vmctx: *mut VMContext,
fd: wasi::__wasi_fd_t,
size: wasi::__wasi_filesize_t,
) -> wasi::__wasi_errno_t {
trace!(
"fd_filestat_set_size(fd={:?}, size={})",
fd,
size
);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
hostcalls::fd_filestat_set_size(wasi_ctx, fd, size)
}
pub unsafe extern "C" fn path_filestat_get(
vmctx: *mut VMContext,
fd: wasi::__wasi_fd_t,
flags: wasi::__wasi_lookupflags_t,
path: wasi32::uintptr_t,
path_len: wasi32::size_t,
buf: wasi32::uintptr_t,
) -> wasi::__wasi_errno_t {
trace!(
"path_filestat_get(fd={:?}, flags={:?}, path={:#x?}, path_len={}, buf={:#x?})",
fd,
flags,
path,
path_len,
buf
);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::path_filestat_get(wasi_ctx, memory, fd, flags, path, path_len, buf)
}
pub unsafe extern "C" fn path_filestat_set_times(
vmctx: *mut VMContext,
fd: wasi::__wasi_fd_t,
flags: wasi::__wasi_lookupflags_t,
path: wasi32::uintptr_t,
path_len: wasi32::size_t,
st_atim: wasi::__wasi_timestamp_t,
st_mtim: wasi::__wasi_timestamp_t,
fstflags: wasi::__wasi_fstflags_t,
) -> wasi::__wasi_errno_t {
trace!(
"path_filestat_set_times(fd={:?}, flags={:?}, path={:#x?}, path_len={}, st_atim={}, st_mtim={}, fstflags={:#x?})",
fd,
flags,
path,
path_len,
st_atim, st_mtim,
fstflags
);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::path_filestat_set_times(
wasi_ctx,
memory,
fd,
flags,
path,
path_len,
st_atim,
st_mtim,
fstflags
)
}
pub unsafe extern "C" fn path_symlink(
vmctx: *mut VMContext,
path0: wasi32::uintptr_t,
path_len0: wasi32::size_t,
fd: wasi::__wasi_fd_t,
path1: wasi32::uintptr_t,
path_len1: wasi32::size_t,
) -> wasi::__wasi_errno_t {
trace!(
"path_symlink(path0={:#x?}, path_len0={}, fd={:?}, path1={:#x?}, path_len1={})",
path0,
path_len0,
fd,
path1,
path_len1
);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::path_symlink(
wasi_ctx,
memory,
path0,
path_len0,
fd,
path1,
path_len1
)
}
pub unsafe extern "C" fn path_unlink_file(
vmctx: *mut VMContext,
fd: wasi::__wasi_fd_t,
path: wasi32::uintptr_t,
path_len: wasi32::size_t,
) -> wasi::__wasi_errno_t {
trace!(
"path_unlink_file(fd={:?}, path={:#x?}, path_len={})",
fd,
path,
path_len
);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::path_unlink_file(wasi_ctx, memory, fd, path, path_len)
}
pub unsafe extern "C" fn path_remove_directory(
vmctx: *mut VMContext,
fd: wasi::__wasi_fd_t,
path: wasi32::uintptr_t,
path_len: wasi32::size_t,
) -> wasi::__wasi_errno_t {
trace!(
"path_remove_directory(fd={:?}, path={:#x?}, path_len={})",
fd,
path,
path_len
);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::path_remove_directory(wasi_ctx, memory, fd, path, path_len)
}
pub unsafe extern "C" fn poll_oneoff(
vmctx: *mut VMContext,
in_: wasi32::uintptr_t,
out: wasi32::uintptr_t,
nsubscriptions: wasi32::size_t,
nevents: wasi32::uintptr_t,
) -> wasi::__wasi_errno_t {
trace!(
"poll_oneoff(in={:#x?}, out={:#x?}, nsubscriptions={}, nevents={:#x?})",
in_,
out,
nsubscriptions,
nevents,
);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::poll_oneoff(wasi_ctx, memory, in_, out, nsubscriptions, nevents)
}
pub unsafe extern "C" fn proc_exit(_vmctx: *mut VMContext, rval: u32,) -> () {
trace!("proc_exit(rval={:?})", rval);
hostcalls::proc_exit(rval)
}
pub unsafe extern "C" fn proc_raise(
vmctx: *mut VMContext,
sig: wasi::__wasi_signal_t,
) -> wasi::__wasi_errno_t {
trace!("proc_raise(sig={:?})", sig);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::proc_raise(wasi_ctx, memory, sig)
}
pub unsafe extern "C" fn random_get(
vmctx: *mut VMContext,
buf: wasi32::uintptr_t,
buf_len: wasi32::size_t,
) -> wasi::__wasi_errno_t {
trace!("random_get(buf={:#x?}, buf_len={:?})", buf, buf_len);
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::random_get(memory, buf, buf_len)
}
pub unsafe extern "C" fn sched_yield(_vmctx: *mut VMContext,) -> wasi::__wasi_errno_t {
trace!("sched_yield(void)");
hostcalls::sched_yield()
}
pub unsafe extern "C" fn sock_recv(
vmctx: *mut VMContext,
sock: wasi::__wasi_fd_t,
ri_data: wasi32::uintptr_t,
ri_data_len: wasi32::size_t,
ri_flags: wasi::__wasi_riflags_t,
ro_datalen: wasi32::uintptr_t,
ro_flags: wasi32::uintptr_t,
) -> wasi::__wasi_errno_t {
trace!(
"sock_recv(sock={:?}, ri_data={:#x?}, ri_data_len={}, ri_flags={:#x?}, ro_datalen={:#x?}, ro_flags={:#x?})",
sock,
ri_data, ri_data_len, ri_flags,
ro_datalen, ro_flags
);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::sock_recv(
wasi_ctx,
memory,
sock,
ri_data,
ri_data_len,
ri_flags,
ro_datalen,
ro_flags
)
}
pub unsafe extern "C" fn sock_send(
vmctx: *mut VMContext,
sock: wasi::__wasi_fd_t,
si_data: wasi32::uintptr_t,
si_data_len: wasi32::size_t,
si_flags: wasi::__wasi_siflags_t,
so_datalen: wasi32::uintptr_t,
) -> wasi::__wasi_errno_t {
trace!(
"sock_send(sock={:?}, si_data={:#x?}, si_data_len={}, si_flags={:#x?}, so_datalen={:#x?})",
sock,
si_data, si_data_len, si_flags, so_datalen,
);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::sock_send(
wasi_ctx,
memory,
sock,
si_data,
si_data_len,
si_flags,
so_datalen
)
}
pub unsafe extern "C" fn sock_shutdown(
vmctx: *mut VMContext,
sock: wasi::__wasi_fd_t,
how: wasi::__wasi_sdflags_t,
) -> wasi::__wasi_errno_t {
trace!("sock_shutdown(sock={:?}, how={:?})", sock, how);
let wasi_ctx = ok_or_errno!(get_wasi_ctx(&mut *vmctx));
let memory = ok_or_errno!(get_memory(&mut *vmctx));
hostcalls::sock_shutdown(wasi_ctx, memory, sock, how)
}
}