Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add arg and env support to wasi #301

Merged
merged 4 commits into from
Mar 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/runtime-core/src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
29 changes: 24 additions & 5 deletions lib/wasi/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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<Vec<u8>>, envs: Vec<Vec<u8>>) -> 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),
Expand Down
5 changes: 5 additions & 0 deletions lib/wasi/src/state.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pub struct WasiState<'a> {
// vfs: Vfs,
pub args: &'a [Vec<u8>],
pub envs: &'a [Vec<u8>],
}
99 changes: 90 additions & 9 deletions lib/wasi/src/syscalls/mod.rs
Original file line number Diff line number Diff line change
@@ -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<u8>],
ptr_buffer_offset: u32,
buffer_offset: u32,
) {
let mut current_buffer_offset = buffer_offset;
for (i, sub_buffer) in from.iter().enumerate() {
memory.view::<u32>()[(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::<u32>()[(argc_out / 4) as usize].set(arg_count as u32);
memory.view::<u32>()[(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::<u32>()[(environ_count_out / 4) as usize].set(env_count as u32);
memory.view::<u32>()[(environ_buf_size_out / 4) as usize].set(total_env_size as u32);
}

pub fn __wasi_fd_advise(ctx: &mut Ctx) {
unimplemented!()
}
Expand Down