fix(plugins): fully Working WebAssembly Loading! (#125)

* Fully Working WebAssembly Loading!

* Move some wasm code to it's own module
This commit is contained in:
Brooks Rady 2020-12-30 08:59:32 +00:00 committed by GitHub
parent f196726dab
commit 22890c53fe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 136 additions and 76 deletions

101
Cargo.lock generated
View file

@ -110,7 +110,7 @@ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"libc", "libc",
"miniz_oxide", "miniz_oxide",
"object 0.22.0", "object",
"rustc-demangle", "rustc-demangle",
] ]
@ -329,7 +329,7 @@ dependencies = [
"const_fn", "const_fn",
"crossbeam-utils 0.8.0", "crossbeam-utils 0.8.0",
"lazy_static", "lazy_static",
"memoffset", "memoffset 0.5.6",
"scopeguard", "scopeguard",
] ]
@ -832,6 +832,15 @@ version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
[[package]]
name = "memmap2"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e73be3b7d04a0123e933fea1d50d126cc7196bbc0362c0ce426694f777194eee"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "memoffset" name = "memoffset"
version = "0.5.6" version = "0.5.6"
@ -841,6 +850,15 @@ dependencies = [
"autocfg", "autocfg",
] ]
[[package]]
name = "memoffset"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.4.3" version = "0.4.3"
@ -915,20 +933,14 @@ dependencies = [
[[package]] [[package]]
name = "object" name = "object"
version = "0.21.1" version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37fd5004feb2ce328a52b0b3d01dbf4ffff72583493900ed15f22d4111c51693" checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397"
dependencies = [ dependencies = [
"crc32fast", "crc32fast",
"indexmap", "indexmap",
] ]
[[package]]
name = "object"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397"
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.4.0" version = "1.4.0"
@ -1678,8 +1690,9 @@ checksum = "93b162580e34310e5931c4b792560108b10fd14d64915d7fff8ff00180e70092"
[[package]] [[package]]
name = "wasmer" name = "wasmer"
version = "1.0.0-alpha5" version = "1.0.0-rc1"
source = "git+https://github.com/wasmerio/wasmer.git#5e2dc65463a49b08c14bf9fb48eb45fa7d79d4c2" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffe7fb8734c3e522aea0bed12315115e4c5d684c3d312db5f3ef6a8a312b1b47"
dependencies = [ dependencies = [
"cfg-if 0.1.10", "cfg-if 0.1.10",
"indexmap", "indexmap",
@ -1688,6 +1701,7 @@ dependencies = [
"thiserror", "thiserror",
"wasmer-compiler", "wasmer-compiler",
"wasmer-compiler-cranelift", "wasmer-compiler-cranelift",
"wasmer-derive",
"wasmer-engine", "wasmer-engine",
"wasmer-engine-jit", "wasmer-engine-jit",
"wasmer-engine-native", "wasmer-engine-native",
@ -1699,8 +1713,9 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-compiler" name = "wasmer-compiler"
version = "1.0.0-alpha5" version = "1.0.0-rc1"
source = "git+https://github.com/wasmerio/wasmer.git#5e2dc65463a49b08c14bf9fb48eb45fa7d79d4c2" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97789fdc5968ea3d29528648dc2422e0c795ca195b88a59c30a56f0e52805690"
dependencies = [ dependencies = [
"enumset", "enumset",
"raw-cpuid", "raw-cpuid",
@ -1716,8 +1731,9 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-compiler-cranelift" name = "wasmer-compiler-cranelift"
version = "1.0.0-alpha5" version = "1.0.0-rc1"
source = "git+https://github.com/wasmerio/wasmer.git#5e2dc65463a49b08c14bf9fb48eb45fa7d79d4c2" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e80c86796019ef6d4519e1a66f2b99ab73b937a4e43e723772956b3e8c8df23"
dependencies = [ dependencies = [
"cranelift-codegen", "cranelift-codegen",
"cranelift-frontend", "cranelift-frontend",
@ -1732,14 +1748,28 @@ dependencies = [
"wasmer-vm", "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]] [[package]]
name = "wasmer-engine" name = "wasmer-engine"
version = "1.0.0-alpha5" version = "1.0.0-rc1"
source = "git+https://github.com/wasmerio/wasmer.git#5e2dc65463a49b08c14bf9fb48eb45fa7d79d4c2" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e787fb8e42b5ad32c1c8dcf105e42d2919dfb3ea4b8e286de3e43f306ae1457b"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"bincode", "bincode",
"lazy_static", "lazy_static",
"memmap2",
"more-asserts", "more-asserts",
"rustc-demangle", "rustc-demangle",
"serde", "serde",
@ -1753,8 +1783,9 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-engine-jit" name = "wasmer-engine-jit"
version = "1.0.0-alpha5" version = "1.0.0-rc1"
source = "git+https://github.com/wasmerio/wasmer.git#5e2dc65463a49b08c14bf9fb48eb45fa7d79d4c2" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "552f4252f8d7984279c55df0970ca1d42b1e4c63d918e7af1cd004e427e5008c"
dependencies = [ dependencies = [
"bincode", "bincode",
"cfg-if 0.1.10", "cfg-if 0.1.10",
@ -1770,8 +1801,9 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-engine-native" name = "wasmer-engine-native"
version = "1.0.0-alpha5" version = "1.0.0-rc1"
source = "git+https://github.com/wasmerio/wasmer.git#5e2dc65463a49b08c14bf9fb48eb45fa7d79d4c2" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5264031a9b398a071fa128fe89fb55bc75f9c0ac5eaa7f1f9ef9efcee08afa1c"
dependencies = [ dependencies = [
"bincode", "bincode",
"cfg-if 0.1.10", "cfg-if 0.1.10",
@ -1790,10 +1822,11 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-object" name = "wasmer-object"
version = "1.0.0-alpha5" version = "1.0.0-rc1"
source = "git+https://github.com/wasmerio/wasmer.git#5e2dc65463a49b08c14bf9fb48eb45fa7d79d4c2" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e22ccf03052d73b3588bd30de94db9ee949957a543d0c317122f2b87b7d1f309"
dependencies = [ dependencies = [
"object 0.21.1", "object",
"thiserror", "thiserror",
"wasmer-compiler", "wasmer-compiler",
"wasmer-types", "wasmer-types",
@ -1801,24 +1834,27 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-types" name = "wasmer-types"
version = "1.0.0-alpha5" version = "1.0.0-rc1"
source = "git+https://github.com/wasmerio/wasmer.git#5e2dc65463a49b08c14bf9fb48eb45fa7d79d4c2" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c3ea5b135db86baf39ce45f6cf98cc97d6e4234d3f75ac56a026f94bd8b68b1"
dependencies = [ dependencies = [
"cranelift-entity", "cranelift-entity",
"serde", "serde",
"thiserror",
] ]
[[package]] [[package]]
name = "wasmer-vm" name = "wasmer-vm"
version = "1.0.0-alpha5" version = "1.0.0-rc1"
source = "git+https://github.com/wasmerio/wasmer.git#5e2dc65463a49b08c14bf9fb48eb45fa7d79d4c2" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88d766b8db150b7e524c83b244e14a1180bf919b4f8bea6f063bae9a8e8d4156"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"cc", "cc",
"cfg-if 0.1.10", "cfg-if 0.1.10",
"indexmap", "indexmap",
"libc", "libc",
"memoffset", "memoffset 0.6.1",
"more-asserts", "more-asserts",
"region", "region",
"serde", "serde",
@ -1829,8 +1865,9 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-wasi" name = "wasmer-wasi"
version = "1.0.0-alpha5" version = "1.0.0-rc1"
source = "git+https://github.com/wasmerio/wasmer.git#5e2dc65463a49b08c14bf9fb48eb45fa7d79d4c2" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28b9e383c0a20fb697080b8e87613a0bb2e901a9f06ca710030b4a521ebcc398"
dependencies = [ dependencies = [
"bincode", "bincode",
"byteorder", "byteorder",

View file

@ -27,11 +27,11 @@ version = "1.3.0"
features = ["unstable"] features = ["unstable"]
[dependencies.wasmer] [dependencies.wasmer]
git = "https://github.com/wasmerio/wasmer.git" version = "1.0.0-rc"
optional = true optional = true
[dependencies.wasmer-wasi] [dependencies.wasmer-wasi]
git = "https://github.com/wasmerio/wasmer.git" version = "1.0.0-rc"
optional = true optional = true
[features] [features]

View file

@ -12,6 +12,8 @@ mod screen;
mod tab; mod tab;
mod terminal_pane; mod terminal_pane;
mod utils; mod utils;
#[cfg(feature = "wasm-wip")]
mod wasm_vm;
use std::io::Write; use std::io::Write;
use std::os::unix::net::UnixStream; use std::os::unix::net::UnixStream;
@ -396,51 +398,39 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: Opt) {
.spawn(move || { .spawn(move || {
// TODO: Clone shared state here // TODO: Clone shared state here
move || -> Result<(), Box<dyn std::error::Error>> { move || -> Result<(), Box<dyn std::error::Error>> {
use crate::wasm_vm::{mosaic_imports, wasi_stdout};
use std::io; use std::io;
use std::sync::{Arc, Mutex}; use wasmer::{ChainableNamedResolver, Instance, Module, Store, Value};
use wasmer::{Exports, Function, Instance, Module, Store, Value}; use wasmer_wasi::{Pipe, WasiState};
use wasmer_wasi::WasiState;
let store = Store::default(); let store = Store::default();
println!("Compiling module..."); println!("Compiling module...");
// FIXME: Switch to a higher performance compiler (`Store::default()`) and cache this on disk // FIXME: Cache this compiled module on disk. I could use `(de)serialize_to_file()` for that
// I could use `(de)serialize_to_file()` for that
let module = if let Ok(m) = Module::from_file(&store, "strider.wasm") { let module = if let Ok(m) = Module::from_file(&store, "strider.wasm") {
m m
} else { } else {
return Ok(()); // Just abort this thread quietly if the WASM isn't found return Ok(()); // Just abort this thread quietly if the WASM isn't found
}; };
// FIXME: Upstream the `Pipe` struct let output = Pipe::new();
//let output = fluff::Pipe::new(); let input = Pipe::new();
//let input = fluff::Pipe::new();
let mut wasi_env = WasiState::new("mosaic") let mut wasi_env = WasiState::new("mosaic")
.env("CLICOLOR_FORCE", "1") .env("CLICOLOR_FORCE", "1")
.preopen(|p| { .preopen(|p| {
p.directory(".") // TODO: Change this to a more meaningful dir p.directory(".") // FIXME: Change this to a more meaningful dir
.alias(".") .alias(".")
.read(true) .read(true)
.write(true) .write(true)
.create(true) .create(true)
})? })?
//.stdin(Box::new(input)) .stdin(Box::new(input))
//.stdout(Box::new(output)) .stdout(Box::new(output))
.finalize()?; .finalize()?;
let mut import_object = wasi_env.import_object(&module)?; let wasi = wasi_env.import_object(&module)?;
// FIXME: Upstream an `ImportObject` merge method let mosaic = mosaic_imports(&store, &wasi_env);
let mut host_exports = Exports::new(); let instance = Instance::new(&module, &mosaic.chain_back(wasi))?;
/* 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 start = instance.exports.get_function("_start")?; let start = instance.exports.get_function("_start")?;
let handle_key = instance.exports.get_function("handle_key")?; let handle_key = instance.exports.get_function("handle_key")?;
@ -451,39 +441,31 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: Opt) {
#[warn(clippy::never_loop)] #[warn(clippy::never_loop)]
loop { loop {
break; let (cols, rows) = (80, 24); //terminal::size()?;
//let (cols, rows) = terminal::size()?; draw.call(&[Value::I32(rows), Value::I32(cols)])?;
//draw.call(&[Value::I32(rows as i32), Value::I32(cols as i32)])?;
// 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 // Needed because raw mode doesn't implicitly return to the start of the line
write!( write!(
io::stdout(), io::stdout(),
"{}\n\r", "{}\n\r",
output.to_string().lines().collect::<Vec<_>>().join("\n\r") wasi_stdout(&wasi_env)
.lines()
.collect::<Vec<_>>()
.join("\n\r")
)?; )?;
output.clear();
let wasi_file = state.fs.stdin_mut()?.as_mut().unwrap(); /* match event::read().unwrap() {
let input: &mut fluff::Pipe = wasi_file.downcast_mut().unwrap();
input.clear(); */
/* match event::read()? {
Event::Key(KeyEvent { Event::Key(KeyEvent {
code: KeyCode::Char('q'), code: KeyCode::Char('q'),
.. ..
}) => break, }) => break,
Event::Key(e) => { Event::Key(e) => {
writeln!(input, "{}\r", serde_json::to_string(&e)?)?; wasi_write_string(&wasi_env, serde_json::to_string(&e).unwrap());
drop(state);
// Need to release the implicit `state` mutex or I deadlock!
handle_key.call(&[])?; handle_key.call(&[])?;
} }
_ => (), _ => (),
} */ } */
break;
} }
debug_log_to_file("WASM module loaded and exited cleanly :)".to_string())?; debug_log_to_file("WASM module loaded and exited cleanly :)".to_string())?;
Ok(()) Ok(())

41
src/wasm_vm.rs Normal file
View file

@ -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();
}