From 22890c53fe78cdaa17dc542d0864fbd21a02b4aa Mon Sep 17 00:00:00 2001 From: Brooks Rady Date: Wed, 30 Dec 2020 08:59:32 +0000 Subject: [PATCH] fix(plugins): fully Working WebAssembly Loading! (#125) * Fully Working WebAssembly Loading! * Move some wasm code to it's own module --- Cargo.lock | 101 +++++++++++++++++++++++++++++++++---------------- Cargo.toml | 4 +- src/main.rs | 66 ++++++++++++-------------------- src/wasm_vm.rs | 41 ++++++++++++++++++++ 4 files changed, 136 insertions(+), 76 deletions(-) create mode 100644 src/wasm_vm.rs diff --git a/Cargo.lock b/Cargo.lock index 3c7bf2c6..27c91846 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -110,7 +110,7 @@ dependencies = [ "cfg-if 1.0.0", "libc", "miniz_oxide", - "object 0.22.0", + "object", "rustc-demangle", ] @@ -329,7 +329,7 @@ dependencies = [ "const_fn", "crossbeam-utils 0.8.0", "lazy_static", - "memoffset", + "memoffset 0.5.6", "scopeguard", ] @@ -832,6 +832,15 @@ version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" +[[package]] +name = "memmap2" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e73be3b7d04a0123e933fea1d50d126cc7196bbc0362c0ce426694f777194eee" +dependencies = [ + "libc", +] + [[package]] name = "memoffset" version = "0.5.6" @@ -841,6 +850,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "memoffset" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87" +dependencies = [ + "autocfg", +] + [[package]] name = "miniz_oxide" version = "0.4.3" @@ -915,20 +933,14 @@ dependencies = [ [[package]] name = "object" -version = "0.21.1" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37fd5004feb2ce328a52b0b3d01dbf4ffff72583493900ed15f22d4111c51693" +checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" dependencies = [ "crc32fast", "indexmap", ] -[[package]] -name = "object" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" - [[package]] name = "once_cell" version = "1.4.0" @@ -1678,8 +1690,9 @@ checksum = "93b162580e34310e5931c4b792560108b10fd14d64915d7fff8ff00180e70092" [[package]] name = "wasmer" -version = "1.0.0-alpha5" -source = "git+https://github.com/wasmerio/wasmer.git#5e2dc65463a49b08c14bf9fb48eb45fa7d79d4c2" +version = "1.0.0-rc1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe7fb8734c3e522aea0bed12315115e4c5d684c3d312db5f3ef6a8a312b1b47" dependencies = [ "cfg-if 0.1.10", "indexmap", @@ -1688,6 +1701,7 @@ dependencies = [ "thiserror", "wasmer-compiler", "wasmer-compiler-cranelift", + "wasmer-derive", "wasmer-engine", "wasmer-engine-jit", "wasmer-engine-native", @@ -1699,8 +1713,9 @@ dependencies = [ [[package]] name = "wasmer-compiler" -version = "1.0.0-alpha5" -source = "git+https://github.com/wasmerio/wasmer.git#5e2dc65463a49b08c14bf9fb48eb45fa7d79d4c2" +version = "1.0.0-rc1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97789fdc5968ea3d29528648dc2422e0c795ca195b88a59c30a56f0e52805690" dependencies = [ "enumset", "raw-cpuid", @@ -1716,8 +1731,9 @@ dependencies = [ [[package]] name = "wasmer-compiler-cranelift" -version = "1.0.0-alpha5" -source = "git+https://github.com/wasmerio/wasmer.git#5e2dc65463a49b08c14bf9fb48eb45fa7d79d4c2" +version = "1.0.0-rc1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e80c86796019ef6d4519e1a66f2b99ab73b937a4e43e723772956b3e8c8df23" dependencies = [ "cranelift-codegen", "cranelift-frontend", @@ -1732,14 +1748,28 @@ dependencies = [ "wasmer-vm", ] +[[package]] +name = "wasmer-derive" +version = "1.0.0-rc1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c74a84dc4ba0d60e9419f335734fa807097caf4938b2b44bc0703688a42b467" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "wasmer-engine" -version = "1.0.0-alpha5" -source = "git+https://github.com/wasmerio/wasmer.git#5e2dc65463a49b08c14bf9fb48eb45fa7d79d4c2" +version = "1.0.0-rc1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e787fb8e42b5ad32c1c8dcf105e42d2919dfb3ea4b8e286de3e43f306ae1457b" dependencies = [ "backtrace", "bincode", "lazy_static", + "memmap2", "more-asserts", "rustc-demangle", "serde", @@ -1753,8 +1783,9 @@ dependencies = [ [[package]] name = "wasmer-engine-jit" -version = "1.0.0-alpha5" -source = "git+https://github.com/wasmerio/wasmer.git#5e2dc65463a49b08c14bf9fb48eb45fa7d79d4c2" +version = "1.0.0-rc1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552f4252f8d7984279c55df0970ca1d42b1e4c63d918e7af1cd004e427e5008c" dependencies = [ "bincode", "cfg-if 0.1.10", @@ -1770,8 +1801,9 @@ dependencies = [ [[package]] name = "wasmer-engine-native" -version = "1.0.0-alpha5" -source = "git+https://github.com/wasmerio/wasmer.git#5e2dc65463a49b08c14bf9fb48eb45fa7d79d4c2" +version = "1.0.0-rc1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5264031a9b398a071fa128fe89fb55bc75f9c0ac5eaa7f1f9ef9efcee08afa1c" dependencies = [ "bincode", "cfg-if 0.1.10", @@ -1790,10 +1822,11 @@ dependencies = [ [[package]] name = "wasmer-object" -version = "1.0.0-alpha5" -source = "git+https://github.com/wasmerio/wasmer.git#5e2dc65463a49b08c14bf9fb48eb45fa7d79d4c2" +version = "1.0.0-rc1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22ccf03052d73b3588bd30de94db9ee949957a543d0c317122f2b87b7d1f309" dependencies = [ - "object 0.21.1", + "object", "thiserror", "wasmer-compiler", "wasmer-types", @@ -1801,24 +1834,27 @@ dependencies = [ [[package]] name = "wasmer-types" -version = "1.0.0-alpha5" -source = "git+https://github.com/wasmerio/wasmer.git#5e2dc65463a49b08c14bf9fb48eb45fa7d79d4c2" +version = "1.0.0-rc1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3ea5b135db86baf39ce45f6cf98cc97d6e4234d3f75ac56a026f94bd8b68b1" dependencies = [ "cranelift-entity", "serde", + "thiserror", ] [[package]] name = "wasmer-vm" -version = "1.0.0-alpha5" -source = "git+https://github.com/wasmerio/wasmer.git#5e2dc65463a49b08c14bf9fb48eb45fa7d79d4c2" +version = "1.0.0-rc1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d766b8db150b7e524c83b244e14a1180bf919b4f8bea6f063bae9a8e8d4156" dependencies = [ "backtrace", "cc", "cfg-if 0.1.10", "indexmap", "libc", - "memoffset", + "memoffset 0.6.1", "more-asserts", "region", "serde", @@ -1829,8 +1865,9 @@ dependencies = [ [[package]] name = "wasmer-wasi" -version = "1.0.0-alpha5" -source = "git+https://github.com/wasmerio/wasmer.git#5e2dc65463a49b08c14bf9fb48eb45fa7d79d4c2" +version = "1.0.0-rc1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b9e383c0a20fb697080b8e87613a0bb2e901a9f06ca710030b4a521ebcc398" dependencies = [ "bincode", "byteorder", diff --git a/Cargo.toml b/Cargo.toml index 41dd3175..792792e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,11 +27,11 @@ version = "1.3.0" features = ["unstable"] [dependencies.wasmer] -git = "https://github.com/wasmerio/wasmer.git" +version = "1.0.0-rc" optional = true [dependencies.wasmer-wasi] -git = "https://github.com/wasmerio/wasmer.git" +version = "1.0.0-rc" optional = true [features] diff --git a/src/main.rs b/src/main.rs index c59fe1c4..7ec9475c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,6 +12,8 @@ mod screen; mod tab; mod terminal_pane; mod utils; +#[cfg(feature = "wasm-wip")] +mod wasm_vm; use std::io::Write; use std::os::unix::net::UnixStream; @@ -396,51 +398,39 @@ pub fn start(mut os_input: Box, opts: Opt) { .spawn(move || { // TODO: Clone shared state here move || -> Result<(), Box> { + use crate::wasm_vm::{mosaic_imports, wasi_stdout}; use std::io; - use std::sync::{Arc, Mutex}; - use wasmer::{Exports, Function, Instance, Module, Store, Value}; - use wasmer_wasi::WasiState; + use wasmer::{ChainableNamedResolver, Instance, Module, Store, Value}; + use wasmer_wasi::{Pipe, WasiState}; + let store = Store::default(); println!("Compiling module..."); - // FIXME: Switch to a higher performance compiler (`Store::default()`) and cache this on disk - // I could use `(de)serialize_to_file()` for that + // FIXME: Cache this compiled module on disk. I could use `(de)serialize_to_file()` for that let module = if let Ok(m) = Module::from_file(&store, "strider.wasm") { m } else { return Ok(()); // Just abort this thread quietly if the WASM isn't found }; - // FIXME: Upstream the `Pipe` struct - //let output = fluff::Pipe::new(); - //let input = fluff::Pipe::new(); + let output = Pipe::new(); + let input = Pipe::new(); let mut wasi_env = WasiState::new("mosaic") .env("CLICOLOR_FORCE", "1") .preopen(|p| { - p.directory(".") // TODO: Change this to a more meaningful dir + p.directory(".") // FIXME: Change this to a more meaningful dir .alias(".") .read(true) .write(true) .create(true) })? - //.stdin(Box::new(input)) - //.stdout(Box::new(output)) + .stdin(Box::new(input)) + .stdout(Box::new(output)) .finalize()?; - let mut import_object = wasi_env.import_object(&module)?; - // FIXME: Upstream an `ImportObject` merge method - let mut host_exports = Exports::new(); - /* host_exports.insert( - "host_open_file", - Function::new_native_with_env(&store, Arc::clone(&wasi_env.state), host_open_file), - ); */ - fn noop() {} - host_exports.insert("host_open_file", Function::new_native(&store, noop)); - import_object.register("mosaic", host_exports); - let instance = Instance::new(&module, &import_object)?; - - // WASI requires to explicitly set the memory for the `WasiEnv` - wasi_env.set_memory(instance.exports.get_memory("memory")?.clone()); + let wasi = wasi_env.import_object(&module)?; + let mosaic = mosaic_imports(&store, &wasi_env); + let instance = Instance::new(&module, &mosaic.chain_back(wasi))?; let start = instance.exports.get_function("_start")?; let handle_key = instance.exports.get_function("handle_key")?; @@ -451,39 +441,31 @@ pub fn start(mut os_input: Box, opts: Opt) { #[warn(clippy::never_loop)] loop { - break; - //let (cols, rows) = terminal::size()?; - //draw.call(&[Value::I32(rows as i32), Value::I32(cols as i32)])?; + let (cols, rows) = (80, 24); //terminal::size()?; + draw.call(&[Value::I32(rows), Value::I32(cols)])?; - // FIXME: This downcasting mess needs to be abstracted away - /* let mut state = wasi_env.state(); - let wasi_file = state.fs.stdout_mut()?.as_mut().unwrap(); - let output: &mut fluff::Pipe = wasi_file.downcast_mut().unwrap(); // Needed because raw mode doesn't implicitly return to the start of the line write!( io::stdout(), "{}\n\r", - output.to_string().lines().collect::>().join("\n\r") + wasi_stdout(&wasi_env) + .lines() + .collect::>() + .join("\n\r") )?; - output.clear(); - let wasi_file = state.fs.stdin_mut()?.as_mut().unwrap(); - let input: &mut fluff::Pipe = wasi_file.downcast_mut().unwrap(); - input.clear(); */ - - /* match event::read()? { + /* match event::read().unwrap() { Event::Key(KeyEvent { code: KeyCode::Char('q'), .. }) => break, Event::Key(e) => { - writeln!(input, "{}\r", serde_json::to_string(&e)?)?; - drop(state); - // Need to release the implicit `state` mutex or I deadlock! + wasi_write_string(&wasi_env, serde_json::to_string(&e).unwrap()); handle_key.call(&[])?; } _ => (), } */ + break; } debug_log_to_file("WASM module loaded and exited cleanly :)".to_string())?; Ok(()) diff --git a/src/wasm_vm.rs b/src/wasm_vm.rs new file mode 100644 index 00000000..334ad0b1 --- /dev/null +++ b/src/wasm_vm.rs @@ -0,0 +1,41 @@ +use std::process::{Command, Stdio}; +use wasmer::{imports, Function, ImportObject, Store}; +use wasmer_wasi::WasiEnv; + +// Plugin API ----------------------------------------------------------------- + +pub fn mosaic_imports(store: &Store, wasi_env: &WasiEnv) -> ImportObject { + imports! { + "mosaic" => { + "host_open_file" => Function::new_native_with_env(store, wasi_env.clone(), host_open_file) + } + } +} + +fn host_open_file(wasi_env: &WasiEnv) { + Command::new("xdg-open") + .arg(format!( + "./{}", + wasi_stdout(wasi_env).lines().next().unwrap() + )) + .stderr(Stdio::null()) + .spawn() + .unwrap(); +} + +// Helper Functions ----------------------------------------------------------- + +// FIXME: Unwrap city +pub fn wasi_stdout(wasi_env: &WasiEnv) -> String { + let mut state = wasi_env.state(); + let wasi_file = state.fs.stdout_mut().unwrap().as_mut().unwrap(); + let mut buf = String::new(); + wasi_file.read_to_string(&mut buf).unwrap(); + buf +} + +pub fn _wasi_write_string(wasi_env: &WasiEnv, buf: &str) { + let mut state = wasi_env.state(); + let wasi_file = state.fs.stdin_mut().unwrap().as_mut().unwrap(); + writeln!(wasi_file, "{}\r", buf).unwrap(); +}