diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index 90afbc408a0..44511bb8289 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -481,7 +481,7 @@ mod vm_ctx_tests { 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) }; assert_eq!(test_data.x, 10); assert_eq!(test_data.y, true); diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index cade0133297..edbd54aeb72 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -1,14 +1,33 @@ +mod state; mod syscalls; -use syscalls::*; +use self::state::WasiState; +use self::syscalls::*; + +use std::ffi::c_void; use wasmer_runtime_core::{func, import::ImportObject, imports}; -pub fn generate_import_object() -> ImportObject { +pub fn generate_import_object(args: Vec>, envs: Vec>) -> ImportObject { + let state_gen = move || { + fn state_dtor(data: *mut c_void) { + unsafe { + drop(Box::from_raw(data as *mut WasiState)); + } + } + + let state = Box::new(WasiState { + args: &args[..], + envs: &envs[..], + }); + + ( + Box::leak(state) as *mut WasiState as *mut c_void, + state_dtor as fn(*mut c_void), + ) + }; imports! { // This generates the wasi state. - || { - // returns (pointer to state, function that can destruct the state). - }, + state_gen, "wasi_unstable" => { "__wasi_args_get" => func!(__wasi_args_get), "__wasi_args_sizes_get" => func!(__wasi_args_sizes_get), diff --git a/lib/wasi/src/state.rs b/lib/wasi/src/state.rs new file mode 100644 index 00000000000..e7cafc1baf7 --- /dev/null +++ b/lib/wasi/src/state.rs @@ -0,0 +1,5 @@ +pub struct WasiState<'a> { + // vfs: Vfs, + pub args: &'a [Vec], + pub envs: &'a [Vec], +} diff --git a/lib/wasi/src/syscalls/mod.rs b/lib/wasi/src/syscalls/mod.rs index f765e9c8763..a05c41cea32 100644 --- a/lib/wasi/src/syscalls/mod.rs +++ b/lib/wasi/src/syscalls/mod.rs @@ -1,23 +1,104 @@ -use wasmer_runtime_core::vm::Ctx; +use crate::state::WasiState; +use wasmer_runtime_core::{memory::Memory, vm::Ctx}; -pub fn __wasi_args_get(ctx: &mut Ctx) { - unimplemented!() +#[allow(clippy::mut_from_ref)] +fn get_wasi_state(ctx: &Ctx) -> &mut WasiState { + unsafe { &mut *(ctx.data as *mut WasiState) } } -pub fn __wasi_args_sizes_get(ctx: &mut Ctx) { - unimplemented!() + +fn write_buffer_array( + memory: &Memory, + from: &[Vec], + ptr_buffer_offset: u32, + buffer_offset: u32, +) { + let mut current_buffer_offset = buffer_offset; + for (i, sub_buffer) in from.iter().enumerate() { + memory.view::()[(ptr_buffer_offset as usize)..][i].set(current_buffer_offset); + for (cell, &byte) in memory.view()[(current_buffer_offset as usize)..] + .iter() + .zip(sub_buffer.iter()) + { + cell.set(byte); + } + current_buffer_offset += sub_buffer.len() as u32; + } +} + +/// ### `__wasi_args_get()` +/// Read command-line argument data. +/// The sizes of the buffers should match that returned by [`__wasi_args_sizes_get()`](#args_sizes_get). +/// Inputs: +/// - `char **argv` +/// A pointer to a buffer to write the argument pointers. +/// - `char *argv_buf` +/// A pointer to a buffer to write the argument string data. +/// +pub fn __wasi_args_get(ctx: &mut Ctx, ptr_buffer_offset: u32, buffer_offset: u32) { + let state = get_wasi_state(ctx); + let memory = ctx.memory(0); + + write_buffer_array(memory, &*state.args, ptr_buffer_offset, buffer_offset); +} + +/// ### `__wasi_args_sizes_get()` +/// Return command-line argument data sizes. +/// Outputs: +/// - `size_t *argc` +/// The number of arguments. +/// - `size_t *argv_buf_size` +/// The size of the argument string data. +pub fn __wasi_args_sizes_get(ctx: &mut Ctx, argc_out: u32, argv_buf_size_out: u32) { + let state = get_wasi_state(ctx); + let memory = ctx.memory(0); + + let arg_count = state.args.len(); + let total_arg_size: usize = state.args.iter().map(|v| v.len()).sum(); + + memory.view::()[(argc_out / 4) as usize].set(arg_count as u32); + memory.view::()[(argv_buf_size_out / 4) as usize].set(total_arg_size as u32); } + pub fn __wasi_clock_res_get(ctx: &mut Ctx) { unimplemented!() } pub fn __wasi_clock_time_get(ctx: &mut Ctx) { unimplemented!() } -pub fn __wasi_environ_get(ctx: &mut Ctx) { - unimplemented!() + +/// ### `__wasi_environ_get()` +/// Read environment variable data. +/// The sizes of the buffers should match that returned by [`__wasi_environ_sizes_get()`](#environ_sizes_get). +/// Inputs: +/// - `char **environ` +/// A pointer to a buffer to write the environment variable pointers. +/// - `char *environ_buf` +/// A pointer to a buffer to write the environment variable string data. +pub fn __wasi_environ_get(ctx: &mut Ctx, environ: u32, environ_buf: u32) { + let state = get_wasi_state(ctx); + let memory = ctx.memory(0); + + write_buffer_array(memory, &*state.args, environ, environ_buf); } -pub fn __wasi_environ_sizes_get(ctx: &mut Ctx) { - unimplemented!() + +/// ### `__wasi_environ_sizes_get()` +/// Return command-line argument data sizes. +/// Outputs: +/// - `size_t *environ_count` +/// The number of environment variables. +/// - `size_t *environ_buf_size` +/// The size of the environment variable string data. +pub fn __wasi_environ_sizes_get(ctx: &mut Ctx, environ_count_out: u32, environ_buf_size_out: u32) { + let state = get_wasi_state(ctx); + let memory = ctx.memory(0); + + let env_count = state.envs.len(); + let total_env_size: usize = state.envs.iter().map(|v| v.len()).sum(); + + memory.view::()[(environ_count_out / 4) as usize].set(env_count as u32); + memory.view::()[(environ_buf_size_out / 4) as usize].set(total_env_size as u32); } + pub fn __wasi_fd_advise(ctx: &mut Ctx) { unimplemented!() }