mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 04:08:19 +00:00
wasm_interp: implement WASI random_get & refactor default imports
This commit is contained in:
parent
eaa3f14fb0
commit
b7fef386ee
8 changed files with 112 additions and 31 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -4525,6 +4525,7 @@ dependencies = [
|
|||
"bitvec 1.0.1",
|
||||
"bumpalo",
|
||||
"clap 3.2.20",
|
||||
"rand",
|
||||
"roc_wasm_module",
|
||||
]
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
use bumpalo::Bump;
|
||||
use roc_wasm_interp::{
|
||||
wasi, DefaultImportDispatcher, ImportDispatcher, Instance, WasiDispatcher, DEFAULT_IMPORTS,
|
||||
};
|
||||
use roc_wasm_interp::{wasi, DefaultImportDispatcher, ImportDispatcher, Instance, WasiDispatcher};
|
||||
use roc_wasm_module::{Value, WasmModule};
|
||||
|
||||
const COMPILER_BYTES: &[u8] =
|
||||
|
@ -24,6 +22,8 @@ impl<'a> ImportDispatcher for CompilerDispatcher<'a> {
|
|||
arguments: &[Value],
|
||||
compiler_memory: &mut [u8],
|
||||
) -> Option<Value> {
|
||||
dbg!(module_name, function_name);
|
||||
|
||||
let unknown = || {
|
||||
panic!(
|
||||
"TestDispatcher does not implement {}.{}",
|
||||
|
@ -48,9 +48,13 @@ impl<'a> ImportDispatcher for CompilerDispatcher<'a> {
|
|||
let module = WasmModule::preload(self.arena, app_bytes, require_reloc).unwrap();
|
||||
|
||||
let is_debug_mode = false;
|
||||
let instance =
|
||||
Instance::for_module(self.arena, &module, DEFAULT_IMPORTS, is_debug_mode)
|
||||
.unwrap();
|
||||
let instance = Instance::for_module(
|
||||
self.arena,
|
||||
&module,
|
||||
DefaultImportDispatcher::default(),
|
||||
is_debug_mode,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
self.app = Some((module, instance));
|
||||
let ok = Value::I32(true as i32);
|
||||
|
@ -133,17 +137,18 @@ fn run(src: &'static str) -> Result<String, String> {
|
|||
arena: &arena,
|
||||
src,
|
||||
answer: String::new(),
|
||||
wasi: WasiDispatcher { args: &[] },
|
||||
wasi: WasiDispatcher::default(),
|
||||
app: None,
|
||||
result_addr: None,
|
||||
};
|
||||
|
||||
let is_debug_mode = false;
|
||||
let is_debug_mode = false; // logs every instruction!
|
||||
Instance::for_module(&arena, &module, dispatcher, is_debug_mode).unwrap()
|
||||
};
|
||||
|
||||
let len = Value::I32(src.len() as i32);
|
||||
let wasm_ok: i32 = instance
|
||||
.call_export(&module, "entrypoint_from_test", [])
|
||||
.call_export(&module, "entrypoint_from_test", [len])
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.expect_i32()
|
||||
|
|
|
@ -12,7 +12,7 @@ path = "src/main.rs"
|
|||
|
||||
[dependencies]
|
||||
roc_wasm_module = { path = "../wasm_module" }
|
||||
|
||||
rand = "0.8.4"
|
||||
bitvec.workspace = true
|
||||
bumpalo.workspace = true
|
||||
clap.workspace = true
|
||||
|
|
|
@ -8,6 +8,7 @@ pub mod wasi;
|
|||
pub use instance::Instance;
|
||||
pub use wasi::WasiDispatcher;
|
||||
|
||||
use rand::prelude::*;
|
||||
use roc_wasm_module::{Value, ValueType, WasmModule};
|
||||
use value_stack::ValueStack;
|
||||
|
||||
|
@ -22,9 +23,16 @@ pub trait ImportDispatcher {
|
|||
) -> Option<Value>;
|
||||
}
|
||||
|
||||
pub const DEFAULT_IMPORTS: DefaultImportDispatcher = DefaultImportDispatcher {
|
||||
wasi: WasiDispatcher { args: &[] },
|
||||
};
|
||||
impl Default for DefaultImportDispatcher<'_> {
|
||||
fn default() -> Self {
|
||||
DefaultImportDispatcher {
|
||||
wasi: WasiDispatcher {
|
||||
args: &[],
|
||||
rng: thread_rng(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DefaultImportDispatcher<'a> {
|
||||
wasi: WasiDispatcher<'a>,
|
||||
|
@ -33,7 +41,10 @@ pub struct DefaultImportDispatcher<'a> {
|
|||
impl<'a> DefaultImportDispatcher<'a> {
|
||||
pub fn new(args: &'a [&'a String]) -> Self {
|
||||
DefaultImportDispatcher {
|
||||
wasi: WasiDispatcher { args },
|
||||
wasi: WasiDispatcher {
|
||||
args,
|
||||
rng: thread_rng(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ mod test_i32;
|
|||
mod test_i64;
|
||||
mod test_mem;
|
||||
|
||||
use crate::{DefaultImportDispatcher, Instance, DEFAULT_IMPORTS};
|
||||
use crate::{DefaultImportDispatcher, Instance};
|
||||
use bumpalo::{collections::Vec, Bump};
|
||||
use roc_wasm_module::{
|
||||
opcodes::OpCode, Export, ExportType, SerialBuffer, Signature, Value, ValueType, WasmModule,
|
||||
|
@ -18,7 +18,13 @@ pub fn default_state(arena: &Bump) -> Instance<DefaultImportDispatcher> {
|
|||
let pages = 1;
|
||||
let program_counter = 0;
|
||||
let globals = [];
|
||||
Instance::new(arena, pages, program_counter, globals, DEFAULT_IMPORTS)
|
||||
Instance::new(
|
||||
arena,
|
||||
pages,
|
||||
program_counter,
|
||||
globals,
|
||||
DefaultImportDispatcher::default(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn const_value(buf: &mut Vec<'_, u8>, value: Value) {
|
||||
|
@ -85,7 +91,8 @@ where
|
|||
std::fs::write(&filename, outfile_buf).unwrap();
|
||||
}
|
||||
|
||||
let mut inst = Instance::for_module(&arena, &module, DEFAULT_IMPORTS, true).unwrap();
|
||||
let mut inst =
|
||||
Instance::for_module(&arena, &module, DefaultImportDispatcher::default(), false).unwrap();
|
||||
|
||||
let return_val = inst.call_export(&module, "test", []).unwrap().unwrap();
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#![cfg(test)]
|
||||
|
||||
use super::{const_value, create_exported_function_no_locals, default_state};
|
||||
use crate::{instance::Action, ImportDispatcher, Instance, ValueStack, DEFAULT_IMPORTS};
|
||||
use crate::{instance::Action, DefaultImportDispatcher, ImportDispatcher, Instance, ValueStack};
|
||||
use bumpalo::{collections::Vec, Bump};
|
||||
use roc_wasm_module::sections::{Import, ImportDesc};
|
||||
use roc_wasm_module::{
|
||||
|
@ -623,7 +623,8 @@ fn test_call_return_no_args() {
|
|||
println!("Wrote to {}", filename);
|
||||
}
|
||||
|
||||
let mut inst = Instance::for_module(&arena, &module, DEFAULT_IMPORTS, true).unwrap();
|
||||
let mut inst =
|
||||
Instance::for_module(&arena, &module, DefaultImportDispatcher::default(), true).unwrap();
|
||||
|
||||
let return_val = inst
|
||||
.call_export(&module, start_fn_name, [])
|
||||
|
@ -762,7 +763,13 @@ fn test_call_indirect_help(table_index: u32, elem_index: u32) -> Value {
|
|||
.unwrap();
|
||||
}
|
||||
|
||||
let mut inst = Instance::for_module(&arena, &module, DEFAULT_IMPORTS, is_debug_mode).unwrap();
|
||||
let mut inst = Instance::for_module(
|
||||
&arena,
|
||||
&module,
|
||||
DefaultImportDispatcher::default(),
|
||||
is_debug_mode,
|
||||
)
|
||||
.unwrap();
|
||||
inst.call_export(&module, start_fn_name, [])
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use super::create_exported_function_no_locals;
|
||||
use crate::{Instance, DEFAULT_IMPORTS};
|
||||
use crate::{DefaultImportDispatcher, Instance};
|
||||
use bumpalo::{collections::Vec, Bump};
|
||||
use roc_wasm_module::{
|
||||
opcodes::OpCode,
|
||||
|
@ -18,7 +18,7 @@ fn test_currentmemory() {
|
|||
module.code.bytes.push(OpCode::CURRENTMEMORY as u8);
|
||||
module.code.bytes.encode_i32(0);
|
||||
|
||||
let mut state = Instance::new(&arena, pages, pc, [], DEFAULT_IMPORTS);
|
||||
let mut state = Instance::new(&arena, pages, pc, [], DefaultImportDispatcher::default());
|
||||
state.execute_next_instruction(&module).unwrap();
|
||||
assert_eq!(state.value_stack.pop(), Value::I32(3))
|
||||
}
|
||||
|
@ -37,7 +37,13 @@ fn test_growmemory() {
|
|||
module.code.bytes.push(OpCode::GROWMEMORY as u8);
|
||||
module.code.bytes.encode_i32(0);
|
||||
|
||||
let mut state = Instance::new(&arena, existing_pages, pc, [], DEFAULT_IMPORTS);
|
||||
let mut state = Instance::new(
|
||||
&arena,
|
||||
existing_pages,
|
||||
pc,
|
||||
[],
|
||||
DefaultImportDispatcher::default(),
|
||||
);
|
||||
state.execute_next_instruction(&module).unwrap();
|
||||
state.execute_next_instruction(&module).unwrap();
|
||||
assert_eq!(state.memory.len(), 5 * MemorySection::PAGE_SIZE as usize);
|
||||
|
@ -79,7 +85,13 @@ fn test_load(load_op: OpCode, ty: ValueType, data: &[u8], addr: u32, offset: u32
|
|||
std::fs::write("/tmp/roc/interp_load_test.wasm", outfile_buf).unwrap();
|
||||
}
|
||||
|
||||
let mut inst = Instance::for_module(&arena, &module, DEFAULT_IMPORTS, is_debug_mode).unwrap();
|
||||
let mut inst = Instance::for_module(
|
||||
&arena,
|
||||
&module,
|
||||
DefaultImportDispatcher::default(),
|
||||
is_debug_mode,
|
||||
)
|
||||
.unwrap();
|
||||
inst.call_export(&module, start_fn_name, [])
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
|
@ -276,7 +288,13 @@ fn test_store<'a>(
|
|||
buf.append_u8(OpCode::END as u8);
|
||||
});
|
||||
|
||||
let mut inst = Instance::for_module(arena, module, DEFAULT_IMPORTS, is_debug_mode).unwrap();
|
||||
let mut inst = Instance::for_module(
|
||||
arena,
|
||||
module,
|
||||
DefaultImportDispatcher::default(),
|
||||
is_debug_mode,
|
||||
)
|
||||
.unwrap();
|
||||
inst.call_export(module, start_fn_name, []).unwrap();
|
||||
|
||||
inst.memory
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use rand::prelude::*;
|
||||
use roc_wasm_module::Value;
|
||||
use std::io::{self, Write};
|
||||
use std::process::exit;
|
||||
|
@ -6,6 +7,13 @@ pub const MODULE_NAME: &str = "wasi_snapshot_preview1";
|
|||
|
||||
pub struct WasiDispatcher<'a> {
|
||||
pub args: &'a [&'a String],
|
||||
pub rng: ThreadRng,
|
||||
}
|
||||
|
||||
impl Default for WasiDispatcher<'_> {
|
||||
fn default() -> Self {
|
||||
WasiDispatcher::new(&[])
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation of WASI syscalls
|
||||
|
@ -14,7 +22,10 @@ pub struct WasiDispatcher<'a> {
|
|||
/// https://github.com/wasm3/wasm3/blob/045040a97345e636b8be4f3086e6db59cdcc785f/source/extra/wasi_core.h
|
||||
impl<'a> WasiDispatcher<'a> {
|
||||
pub fn new(args: &'a [&'a String]) -> Self {
|
||||
WasiDispatcher { args }
|
||||
WasiDispatcher {
|
||||
args,
|
||||
rng: thread_rng(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dispatch(
|
||||
|
@ -61,8 +72,8 @@ impl<'a> WasiDispatcher<'a> {
|
|||
}
|
||||
"environ_get" => todo!("WASI {}({:?})", function_name, arguments),
|
||||
"environ_sizes_get" => todo!("WASI {}({:?})", function_name, arguments),
|
||||
"clock_res_get" => success_code, // this dummy implementation seems to be good enough
|
||||
"clock_time_get" => success_code, // this dummy implementation seems to be good enough
|
||||
"clock_res_get" => success_code, // this dummy implementation seems to be good enough for some functions
|
||||
"clock_time_get" => success_code,
|
||||
"fd_advise" => todo!("WASI {}({:?})", function_name, arguments),
|
||||
"fd_allocate" => todo!("WASI {}({:?})", function_name, arguments),
|
||||
"fd_close" => todo!("WASI {}({:?})", function_name, arguments),
|
||||
|
@ -74,8 +85,20 @@ impl<'a> WasiDispatcher<'a> {
|
|||
"fd_filestat_set_size" => todo!("WASI {}({:?})", function_name, arguments),
|
||||
"fd_filestat_set_times" => todo!("WASI {}({:?})", function_name, arguments),
|
||||
"fd_pread" => todo!("WASI {}({:?})", function_name, arguments),
|
||||
"fd_prestat_get" => todo!("WASI {}({:?})", function_name, arguments),
|
||||
"fd_prestat_dir_name" => todo!("WASI {}({:?})", function_name, arguments),
|
||||
"fd_prestat_get" => {
|
||||
// The preopened file descriptor to query
|
||||
let fd = arguments[0].expect_i32().unwrap();
|
||||
// Where the metadata will be written
|
||||
let _ptr_buf = arguments[1].expect_i32().unwrap() as usize;
|
||||
match fd {
|
||||
0 | 1 | 2 => success_code,
|
||||
_ => {
|
||||
println!("WASI warning: file descriptor {} does not exist", fd);
|
||||
Some(Value::I32(Errno::Badf as i32))
|
||||
}
|
||||
}
|
||||
}
|
||||
"fd_prestat_dir_name" => success_code,
|
||||
"fd_pwrite" => todo!("WASI {}({:?})", function_name, arguments),
|
||||
"fd_read" => todo!("WASI {}({:?})", function_name, arguments),
|
||||
"fd_readdir" => todo!("WASI {}({:?})", function_name, arguments),
|
||||
|
@ -156,7 +179,16 @@ impl<'a> WasiDispatcher<'a> {
|
|||
}
|
||||
"proc_raise" => todo!("WASI {}({:?})", function_name, arguments),
|
||||
"sched_yield" => todo!("WASI {}({:?})", function_name, arguments),
|
||||
"random_get" => todo!("WASI {}({:?})", function_name, arguments),
|
||||
"random_get" => {
|
||||
// A pointer to a buffer where the random bytes will be written
|
||||
let ptr_buf = arguments[1].expect_i32().unwrap() as usize;
|
||||
// The number of bytes that will be written
|
||||
let buf_len = arguments[1].expect_i32().unwrap() as usize;
|
||||
for i in 0..buf_len {
|
||||
memory[ptr_buf + i] = self.rng.gen();
|
||||
}
|
||||
success_code
|
||||
}
|
||||
"sock_recv" => todo!("WASI {}({:?})", function_name, arguments),
|
||||
"sock_send" => todo!("WASI {}({:?})", function_name, arguments),
|
||||
"sock_shutdown" => todo!("WASI {}({:?})", function_name, arguments),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue