From d9cd4fc3e01333a260ea5935e1fe72ed3140a6cf Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 12 May 2019 11:05:26 -0500 Subject: [PATCH 01/33] Add scaffold to use new code generator API for Cranelift --- lib/clif-backend/src/code.rs | 91 ++++++++++++++++++++++++++++++++++++ lib/clif-backend/src/lib.rs | 16 +++++-- 2 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 lib/clif-backend/src/code.rs diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs new file mode 100644 index 000000000..28257621e --- /dev/null +++ b/lib/clif-backend/src/code.rs @@ -0,0 +1,91 @@ +use crate::signal::Caller; +use wasmer_runtime_core::{ + backend::{Backend, CacheGen, Token}, + cache::{Artifact, Error as CacheError}, + codegen::*, + module::{ModuleInfo, ModuleInner}, + structures::Map, + types::{FuncIndex, FuncSig, SigIndex}, +}; +use wasmparser::Type as WpType; + +pub struct CraneliftModuleCodeGenerator {} + +impl ModuleCodeGenerator + for CraneliftModuleCodeGenerator +{ + fn new() -> Self { + unimplemented!() + } + + fn backend_id() -> Backend { + unimplemented!() + } + + fn check_precondition(&mut self, _module_info: &ModuleInfo) -> Result<(), CodegenError> { + unimplemented!() + } + + fn next_function(&mut self) -> Result<&mut CraneliftFunctionCodeGenerator, CodegenError> { + unimplemented!() + } + + fn finalize( + self, + _module_info: &ModuleInfo, + ) -> Result<(Caller, Box), CodegenError> { + unimplemented!() + } + + fn feed_signatures(&mut self, _signatures: Map) -> Result<(), CodegenError> { + unimplemented!() + } + + fn feed_function_signatures( + &mut self, + _assoc: Map, + ) -> Result<(), CodegenError> { + unimplemented!() + } + + fn feed_import_function(&mut self) -> Result<(), CodegenError> { + unimplemented!() + } + + unsafe fn from_cache(_cache: Artifact, _: Token) -> Result { + unimplemented!() + } +} + +pub struct CraneliftFunctionCodeGenerator {} + +impl FunctionCodeGenerator for CraneliftFunctionCodeGenerator { + fn feed_return(&mut self, _ty: WpType) -> Result<(), CodegenError> { + unimplemented!() + } + + fn feed_param(&mut self, _ty: WpType) -> Result<(), CodegenError> { + unimplemented!() + } + + fn feed_local(&mut self, _ty: WpType, _n: usize) -> Result<(), CodegenError> { + unimplemented!() + } + + fn begin_body(&mut self, _module_info: &ModuleInfo) -> Result<(), CodegenError> { + unimplemented!() + } + + fn feed_event(&mut self, _op: Event, _module_info: &ModuleInfo) -> Result<(), CodegenError> { + unimplemented!() + } + + fn finalize(&mut self) -> Result<(), CodegenError> { + unimplemented!() + } +} + +#[derive(Debug)] +pub struct CodegenError { + pub message: String, +} diff --git a/lib/clif-backend/src/lib.rs b/lib/clif-backend/src/lib.rs index 639249c34..a8cd0f448 100644 --- a/lib/clif-backend/src/lib.rs +++ b/lib/clif-backend/src/lib.rs @@ -1,6 +1,7 @@ #![deny(unused_imports, unused_variables)] mod cache; +mod code; mod func_env; mod libcalls; mod module; @@ -31,15 +32,15 @@ extern crate serde; use wasmparser::{self, WasmDecoder}; -pub struct CraneliftCompiler {} +pub struct OldCraneliftCompiler {} -impl CraneliftCompiler { +impl OldCraneliftCompiler { pub fn new() -> Self { Self {} } } -impl Compiler for CraneliftCompiler { +impl Compiler for OldCraneliftCompiler { /// Compiles wasm binary to a wasmer module. fn compile( &self, @@ -129,3 +130,12 @@ fn validate(bytes: &[u8]) -> CompileResult<()> { /// The current version of this crate pub const VERSION: &str = env!("CARGO_PKG_VERSION"); + +use wasmer_runtime_core::codegen::SimpleStreamingCompilerGen; + +pub type CraneliftCompiler = SimpleStreamingCompilerGen< + code::CraneliftModuleCodeGenerator, + code::CraneliftFunctionCodeGenerator, + signal::Caller, + code::CodegenError, +>; From 7315cd11007314b61ad5d08135a7a66b3f0ee070 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 12 May 2019 19:16:01 -0500 Subject: [PATCH 02/33] Add some basic partial implementation of Cranelift codegen --- lib/clif-backend/src/code.rs | 45 +++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs index 28257621e..2107559e5 100644 --- a/lib/clif-backend/src/code.rs +++ b/lib/clif-backend/src/code.rs @@ -1,4 +1,5 @@ use crate::signal::Caller; +use std::sync::Arc; use wasmer_runtime_core::{ backend::{Backend, CacheGen, Token}, cache::{Artifact, Error as CacheError}, @@ -9,25 +10,35 @@ use wasmer_runtime_core::{ }; use wasmparser::Type as WpType; -pub struct CraneliftModuleCodeGenerator {} +pub struct CraneliftModuleCodeGenerator { + signatures: Option>>, + function_signatures: Option>>, + functions: Vec, +} impl ModuleCodeGenerator for CraneliftModuleCodeGenerator { fn new() -> Self { - unimplemented!() + CraneliftModuleCodeGenerator { + functions: vec![], + function_signatures: None, + signatures: None, + } } fn backend_id() -> Backend { - unimplemented!() + Backend::Cranelift } fn check_precondition(&mut self, _module_info: &ModuleInfo) -> Result<(), CodegenError> { - unimplemented!() + Ok(()) } fn next_function(&mut self) -> Result<&mut CraneliftFunctionCodeGenerator, CodegenError> { - unimplemented!() + let code = CraneliftFunctionCodeGenerator {}; + self.functions.push(code); + Ok(self.functions.last_mut().unwrap()) } fn finalize( @@ -37,19 +48,21 @@ impl ModuleCodeGenerator unimplemented!() } - fn feed_signatures(&mut self, _signatures: Map) -> Result<(), CodegenError> { - unimplemented!() + fn feed_signatures(&mut self, signatures: Map) -> Result<(), CodegenError> { + self.signatures = Some(Arc::new(signatures)); + Ok(()) } fn feed_function_signatures( &mut self, - _assoc: Map, + assoc: Map, ) -> Result<(), CodegenError> { - unimplemented!() + self.function_signatures = Some(Arc::new(assoc)); + Ok(()) } fn feed_import_function(&mut self) -> Result<(), CodegenError> { - unimplemented!() + Ok(()) } unsafe fn from_cache(_cache: Artifact, _: Token) -> Result { @@ -61,27 +74,27 @@ pub struct CraneliftFunctionCodeGenerator {} impl FunctionCodeGenerator for CraneliftFunctionCodeGenerator { fn feed_return(&mut self, _ty: WpType) -> Result<(), CodegenError> { - unimplemented!() + Ok(()) } fn feed_param(&mut self, _ty: WpType) -> Result<(), CodegenError> { - unimplemented!() + Ok(()) } fn feed_local(&mut self, _ty: WpType, _n: usize) -> Result<(), CodegenError> { - unimplemented!() + Ok(()) } fn begin_body(&mut self, _module_info: &ModuleInfo) -> Result<(), CodegenError> { - unimplemented!() + Ok(()) } fn feed_event(&mut self, _op: Event, _module_info: &ModuleInfo) -> Result<(), CodegenError> { - unimplemented!() + Ok(()) } fn finalize(&mut self) -> Result<(), CodegenError> { - unimplemented!() + Ok(()) } } From 74a758d39e8c4d78efb82e4c9023038e7dcd732a Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sat, 18 May 2019 16:31:08 -0500 Subject: [PATCH 03/33] Add progress on next_event --- Cargo.lock | 69 ++++--- lib/clif-backend/Cargo.toml | 18 +- lib/clif-backend/src/code.rs | 344 ++++++++++++++++++++++++++++++- lib/clif-backend/src/func_env.rs | 35 ++-- lib/clif-backend/src/lib.rs | 2 +- lib/runtime-core/src/codegen.rs | 2 +- lib/runtime-core/src/parse.rs | 2 +- 7 files changed, 405 insertions(+), 67 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4a0e4d5d0..804c65f2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -309,67 +309,67 @@ dependencies = [ [[package]] name = "cranelift-bforest" version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#71581b822e51edab335368af1e0102ab0c811464" dependencies = [ - "cranelift-entity 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-entity 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", ] [[package]] name = "cranelift-codegen" version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#71581b822e51edab335368af1e0102ab0c811464" dependencies = [ - "cranelift-bforest 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen-meta 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-entity 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-bforest 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", + "cranelift-codegen-meta 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", + "cranelift-entity 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-codegen-meta" version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#71581b822e51edab335368af1e0102ab0c811464" dependencies = [ - "cranelift-entity 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-entity 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", ] [[package]] name = "cranelift-entity" version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#71581b822e51edab335368af1e0102ab0c811464" [[package]] name = "cranelift-frontend" version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#71581b822e51edab335368af1e0102ab0c811464" dependencies = [ - "cranelift-codegen 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-codegen 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-native" version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#71581b822e51edab335368af1e0102ab0c811464" dependencies = [ - "cranelift-codegen 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-codegen 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cranelift-wasm" version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#71581b822e51edab335368af1e0102ab0c811464" dependencies = [ "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-entity 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-frontend 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-codegen 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", + "cranelift-entity 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", + "cranelift-frontend 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1861,7 +1861,7 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2250,10 +2250,11 @@ name = "wasmer-clif-backend" version = "0.4.1" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-codegen 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-entity 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-native 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cranelift-wasm 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cranelift-codegen 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", + "cranelift-entity 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", + "cranelift-frontend 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", + "cranelift-native 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", + "cranelift-wasm 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2262,7 +2263,7 @@ dependencies = [ "serde-bench 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "serde_bytes 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", - "target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-runtime-core 0.4.1", "wasmer-win-exception-handler 0.4.1", "wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2609,13 +2610,13 @@ dependencies = [ "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" "checksum core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "286e0b41c3a20da26536c6000a280585d519fd07b3956b43aed8a79e9edce980" "checksum core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "716c271e8613ace48344f723b60b900a93150271e5be206212d052bbc0883efa" -"checksum cranelift-bforest 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e5a357d20666bf4a8c2d626a19f1b59dbca66cd844fb1e66c5612254fd0f7505" -"checksum cranelift-codegen 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab00cb149a5bb0f7e6dd391357356a5d71c335a431e8eece94f32da2d5a043f7" -"checksum cranelift-codegen-meta 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e3797a2f450ac71297e083dd440d0cdd0d3bceabe4a3ca6bcb9e4077e9c0327d" -"checksum cranelift-entity 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b66e28877b75b3d2b31250f780bb5db8f68ae3df681cd56add803b2567ac4fd" -"checksum cranelift-frontend 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b72d55fd732b1f7a99d043a36c54a5679b6ec8bc777c8d954fb97c4fa0fce7eb" -"checksum cranelift-native 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0239f34836621a127c2132980b2f5c32a1be1c40e2d1a9a1a9bd5af33c12aee" -"checksum cranelift-wasm 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740ebfba28c8433f06750f84819f1eb663ea9f5e4b9a81c01f4e52262d868b56" +"checksum cranelift-bforest 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)" = "" +"checksum cranelift-codegen 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)" = "" +"checksum cranelift-codegen-meta 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)" = "" +"checksum cranelift-entity 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)" = "" +"checksum cranelift-frontend 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)" = "" +"checksum cranelift-native 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)" = "" +"checksum cranelift-wasm 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)" = "" "checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" "checksum criterion 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "1c6e5ee5b9652d4f851418c448af105642e1f99e9a2741a8ff45c0d2c911b1e0" @@ -2783,7 +2784,7 @@ dependencies = [ "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" "checksum tar 0.4.22 (registry+https://github.com/rust-lang/crates.io-index)" = "c2167ff53da2a661702b3299f71a91b61b1dffef36b4b2884b1f9c67254c0133" -"checksum target-lexicon 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6923974ce4eb5bd28814756256d8ab71c28dd6e7483313fe7ab6614306bf633" +"checksum target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1b0ab4982b8945c35cc1c46a83a9094c414f6828a099ce5dcaa8ee2b04642dcb" "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" "checksum tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b86c784c88d98c801132806dadd3819ed29d8600836c4088e855cdf3e178ed8a" "checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" diff --git a/lib/clif-backend/Cargo.toml b/lib/clif-backend/Cargo.toml index cbfbfb44a..841004bf2 100644 --- a/lib/clif-backend/Cargo.toml +++ b/lib/clif-backend/Cargo.toml @@ -9,12 +9,20 @@ edition = "2018" [dependencies] wasmer-runtime-core = { path = "../runtime-core", version = "0.4.1" } -cranelift-native = "0.30.0" -cranelift-codegen = "0.30.0" -cranelift-entity = "0.30.0" -cranelift-wasm = "0.30.0" +# cranelift-native = { path = "../../../cranelift/cranelift-native" } +# cranelift-codegen = { path = "../../../cranelift/cranelift-codegen" } +# cranelift-entity = { path = "../../../cranelift/cranelift-entity" } +# cranelift-frontend = { path = "../../../cranelift/cranelift-frontend" } +# cranelift-wasm = { git = "https://github.com/wasmerio/cranelift.git", branch = "wasmer" } +cranelift-native = { git = "https://github.com/wasmerio/cranelift.git", branch = "wasmer" } +cranelift-codegen = { git = "https://github.com/wasmerio/cranelift.git", branch = "wasmer" } +cranelift-entity = { git = "https://github.com/wasmerio/cranelift.git", branch = "wasmer" } +cranelift-frontend = { git = "https://github.com/wasmerio/cranelift.git", branch = "wasmer" } +cranelift-wasm = { git = "https://github.com/wasmerio/cranelift.git", branch = "wasmer" } + + hashbrown = "0.1" -target-lexicon = "0.3.0" +target-lexicon = "0.4.0" wasmparser = "0.29.2" byteorder = "1" nix = "0.13.0" diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs index 2107559e5..8f5e7e2f1 100644 --- a/lib/clif-backend/src/code.rs +++ b/lib/clif-backend/src/code.rs @@ -1,29 +1,51 @@ -use crate::signal::Caller; +use crate::{func_env::FuncEnv, module::{Converter, Module}, signal::Caller, get_isa}; use std::sync::Arc; use wasmer_runtime_core::{ backend::{Backend, CacheGen, Token}, cache::{Artifact, Error as CacheError}, codegen::*, module::{ModuleInfo, ModuleInner}, - structures::Map, - types::{FuncIndex, FuncSig, SigIndex}, + structures::{TypedIndex, Map}, + types::{ + FuncSig, FuncIndex, + ElementType, GlobalDescriptor, GlobalIndex, GlobalInit, Initializer, LocalFuncIndex, + LocalOrImport, MemoryDescriptor, SigIndex, TableDescriptor, Value, + }, }; +use cranelift_codegen::isa; +use cranelift_codegen::entity::EntityRef; +use cranelift_codegen::ir::{self, Ebb, InstBuilder, ValueLabel}; +use cranelift_codegen::timing; use wasmparser::Type as WpType; +use cranelift_wasm::{translate_operator, TranslationState, get_vmctx_value_label}; +use cranelift_wasm::{self, translate_module, FuncTranslator, ModuleEnvironment}; +use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; pub struct CraneliftModuleCodeGenerator { + isa: Box, signatures: Option>>, + pub clif_signatures: Map, function_signatures: Option>>, functions: Vec, + func_bodies: Map, +} + +pub struct ClifFuncEnv { + } impl ModuleCodeGenerator for CraneliftModuleCodeGenerator { fn new() -> Self { + let isa = get_isa(); CraneliftModuleCodeGenerator { + isa, + clif_signatures: Map::new(), // TODO FIX functions: vec![], function_signatures: None, signatures: None, + func_bodies: Map::new(), } } @@ -35,9 +57,233 @@ impl ModuleCodeGenerator Ok(()) } - fn next_function(&mut self) -> Result<&mut CraneliftFunctionCodeGenerator, CodegenError> { - let code = CraneliftFunctionCodeGenerator {}; - self.functions.push(code); + fn next_function(&mut self, module_info: &ModuleInfo) -> Result<&mut CraneliftFunctionCodeGenerator, CodegenError> { + + // define_function_body( + + + + + let mut func_translator = FuncTranslator::new(); + +// let func_body = { + + +// let mut func_env = FuncEnv::new(self); + + let func_index = self.func_bodies.next_index(); + let name = ir::ExternalName::user(0, func_index.index() as u32); + + let sig = generate_signature(self, + self.get_func_type(&module_info, Converter(func_index.convert_up(&module_info)).into()), + ); + + let mut func = ir::Function::with_name_signature(name, sig); + + //func_translator.translate(body_bytes, body_offset, &mut func, &mut func_env)?; + // This clears the `FunctionBuilderContext`. + + let mut func_env = CraneliftFunctionCodeGenerator { + builder: None, + func_body: func, + func_translator, + // translator: + }; + let builder = FunctionBuilder::new(&mut func_env.func_body, &mut func_env.func_translator.func_ctx); + func_env.builder = Some(builder); + + let mut builder = func_env.builder.as_ref().unwrap(); + + // TODO srcloc + //builder.set_srcloc(cur_srcloc(&reader)); + + let entry_block = builder.create_ebb(); + builder.append_ebb_params_for_function_params(entry_block); + builder.switch_to_block(entry_block); // This also creates values for the arguments. + builder.seal_block(entry_block); + // Make sure the entry block is inserted in the layout before we make any callbacks to + // `environ`. The callback functions may need to insert things in the entry block. + builder.ensure_inserted_ebb(); + + let num_params = declare_wasm_parameters(&mut builder, entry_block); + + // Set up the translation state with a single pushed control block representing the whole + // function and its return values. + let exit_block = builder.create_ebb(); + builder.append_ebb_params_for_function_returns(exit_block); + func_translator.state.initialize(&builder.func.signature, exit_block); + + + #[cfg(feature = "debug")] + { + use cranelift_codegen::cursor::{Cursor, FuncCursor}; + use cranelift_codegen::ir::InstBuilder; + let entry_ebb = func.layout.entry_block().unwrap(); + let ebb = func.dfg.make_ebb(); + func.layout.insert_ebb(ebb, entry_ebb); + let mut pos = FuncCursor::new(&mut func).at_first_insertion_point(ebb); + let params = pos.func.dfg.ebb_params(entry_ebb).to_vec(); + + let new_ebb_params: Vec<_> = params + .iter() + .map(|¶m| { + pos.func + .dfg + .append_ebb_param(ebb, pos.func.dfg.value_type(param)) + }) + .collect(); + + let start_debug = { + let signature = pos.func.import_signature(ir::Signature { + call_conv: self.target_config().default_call_conv, + params: vec![ + ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), + ir::AbiParam::new(ir::types::I32), + ], + returns: vec![], + }); + + let name = ir::ExternalName::testcase("strtdbug"); + + pos.func.import_function(ir::ExtFuncData { + name, + signature, + colocated: false, + }) + }; + + let end_debug = { + let signature = pos.func.import_signature(ir::Signature { + call_conv: self.target_config().default_call_conv, + params: vec![ir::AbiParam::special( + ir::types::I64, + ir::ArgumentPurpose::VMContext, + )], + returns: vec![], + }); + + let name = ir::ExternalName::testcase("enddbug"); + + pos.func.import_function(ir::ExtFuncData { + name, + signature, + colocated: false, + }) + }; + + let i32_print = { + let signature = pos.func.import_signature(ir::Signature { + call_conv: self.target_config().default_call_conv, + params: vec![ + ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), + ir::AbiParam::new(ir::types::I32), + ], + returns: vec![], + }); + + let name = ir::ExternalName::testcase("i32print"); + + pos.func.import_function(ir::ExtFuncData { + name, + signature, + colocated: false, + }) + }; + + let i64_print = { + let signature = pos.func.import_signature(ir::Signature { + call_conv: self.target_config().default_call_conv, + params: vec![ + ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), + ir::AbiParam::new(ir::types::I64), + ], + returns: vec![], + }); + + let name = ir::ExternalName::testcase("i64print"); + + pos.func.import_function(ir::ExtFuncData { + name, + signature, + colocated: false, + }) + }; + + let f32_print = { + let signature = pos.func.import_signature(ir::Signature { + call_conv: self.target_config().default_call_conv, + params: vec![ + ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), + ir::AbiParam::new(ir::types::F32), + ], + returns: vec![], + }); + + let name = ir::ExternalName::testcase("f32print"); + + pos.func.import_function(ir::ExtFuncData { + name, + signature, + colocated: false, + }) + }; + + let f64_print = { + let signature = pos.func.import_signature(ir::Signature { + call_conv: self.target_config().default_call_conv, + params: vec![ + ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), + ir::AbiParam::new(ir::types::F64), + ], + returns: vec![], + }); + + let name = ir::ExternalName::testcase("f64print"); + + pos.func.import_function(ir::ExtFuncData { + name, + signature, + colocated: false, + }) + }; + + let vmctx = pos + .func + .special_param(ir::ArgumentPurpose::VMContext) + .expect("missing vmctx parameter"); + + let func_index = pos.ins().iconst( + ir::types::I32, + func_index.index() as i64 + self.module.info.imported_functions.len() as i64, + ); + + pos.ins().call(start_debug, &[vmctx, func_index]); + + for param in new_ebb_params.iter().cloned() { + match pos.func.dfg.value_type(param) { + ir::types::I32 => pos.ins().call(i32_print, &[vmctx, param]), + ir::types::I64 => pos.ins().call(i64_print, &[vmctx, param]), + ir::types::F32 => pos.ins().call(f32_print, &[vmctx, param]), + ir::types::F64 => pos.ins().call(f64_print, &[vmctx, param]), + _ => unimplemented!(), + }; + } + + pos.ins().call(end_debug, &[vmctx]); + + pos.ins().jump(entry_ebb, new_ebb_params.as_slice()); + } + +// func +// }; + + // Add function body to list of function bodies. +// self.func_bodies.push(func); + + + + + self.functions.push(func_env); Ok(self.functions.last_mut().unwrap()) } @@ -70,7 +316,11 @@ impl ModuleCodeGenerator } } -pub struct CraneliftFunctionCodeGenerator {} +pub struct CraneliftFunctionCodeGenerator { + func_body: ir::Function, + builder: Option>, + func_translator: FuncTranslator, +} impl FunctionCodeGenerator for CraneliftFunctionCodeGenerator { fn feed_return(&mut self, _ty: WpType) -> Result<(), CodegenError> { @@ -89,11 +339,22 @@ impl FunctionCodeGenerator for CraneliftFunctionCodeGenerator { Ok(()) } - fn feed_event(&mut self, _op: Event, _module_info: &ModuleInfo) -> Result<(), CodegenError> { + fn feed_event(&mut self, event: Event, _module_info: &ModuleInfo) -> Result<(), CodegenError> { + let op = match event { + Event::Wasm(x) => x, + Event::Internal(_x) => { + return Ok(()); + } + }; + let builder = &self.builder; + //let func_environment = FuncEnv::new(); + //let state = TranslationState::new(); + //translate_operator(*op, builder, state, func_environment); Ok(()) } fn finalize(&mut self) -> Result<(), CodegenError> { + self.builder.as_mut().unwrap().finalize(); Ok(()) } } @@ -102,3 +363,70 @@ impl FunctionCodeGenerator for CraneliftFunctionCodeGenerator { pub struct CodegenError { pub message: String, } + +impl CraneliftModuleCodeGenerator { + /// Return the signature index for the given function index. + pub fn get_func_type( + &self, + module_info: &ModuleInfo, + func_index: cranelift_wasm::FuncIndex, + ) -> cranelift_wasm::SignatureIndex { + let sig_index: SigIndex = module_info.func_assoc[Converter(func_index).into()]; + Converter(sig_index).into() + } + + + +} + +/// Creates a signature with VMContext as the last param +fn generate_signature( + env: &CraneliftModuleCodeGenerator, + clif_sig_index: cranelift_wasm::SignatureIndex, +) -> ir::Signature { + // Get signature + let mut signature = env.clif_signatures[Converter(clif_sig_index).into()].clone(); + + // Add the vmctx parameter type to it + signature.params.insert( + 0, + ir::AbiParam::special(pointer_type(env), ir::ArgumentPurpose::VMContext), + ); + + // Return signature + signature +} + +fn pointer_type(mcg: &CraneliftModuleCodeGenerator) -> ir::Type { + ir::Type::int(u16::from(mcg.isa.frontend_config().pointer_bits())).unwrap() +} + + +/// Declare local variables for the signature parameters that correspond to WebAssembly locals. +/// +/// Return the number of local variables declared. +fn declare_wasm_parameters(builder: &mut FunctionBuilder, entry_block: Ebb) -> usize { + let sig_len = builder.func.signature.params.len(); + let mut next_local = 0; + for i in 0..sig_len { + let param_type = builder.func.signature.params[i]; + // There may be additional special-purpose parameters following the normal WebAssembly + // signature parameters. For example, a `vmctx` pointer. + if param_type.purpose == ir::ArgumentPurpose::Normal { + // This is a normal WebAssembly signature parameter, so create a local for it. + let local = Variable::new(next_local); + builder.declare_var(local, param_type.value_type); + next_local += 1; + + let param_value = builder.ebb_params(entry_block)[i]; + builder.def_var(local, param_value); + } + if param_type.purpose == ir::ArgumentPurpose::VMContext { + let param_value = builder.ebb_params(entry_block)[i]; + builder.set_val_label(param_value, get_vmctx_value_label()); + } + } + + next_local +} + diff --git a/lib/clif-backend/src/func_env.rs b/lib/clif-backend/src/func_env.rs index 8a65444b7..10f968386 100644 --- a/lib/clif-backend/src/func_env.rs +++ b/lib/clif-backend/src/func_env.rs @@ -1,4 +1,5 @@ -use crate::{module::Converter, module_env::ModuleEnv, relocation::call_names}; +use crate::{module::Converter, + module_env::ModuleEnv, relocation::call_names}; use cranelift_codegen::{ cursor::FuncCursor, ir::{self, InstBuilder}, @@ -68,7 +69,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> { &mut self, func: &mut ir::Function, clif_global_index: cranelift_wasm::GlobalIndex, - ) -> cranelift_wasm::GlobalVariable { + ) -> cranelift_wasm::WasmResult { let global_index: GlobalIndex = Converter(clif_global_index).into(); // Create VMContext value. @@ -124,11 +125,11 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> { } }; - cranelift_wasm::GlobalVariable::Memory { + Ok(cranelift_wasm::GlobalVariable::Memory { gv: local_global_addr, offset: (vm::LocalGlobal::offset_data() as i32).into(), ty: self.env.get_global(clif_global_index).ty, - } + }) } /// Sets up the necessary preamble definitions in `func` to access the linear memory identified @@ -139,7 +140,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> { &mut self, func: &mut ir::Function, clif_mem_index: cranelift_wasm::MemoryIndex, - ) -> ir::Heap { + ) -> cranelift_wasm::WasmResult { let mem_index: MemoryIndex = Converter(clif_mem_index).into(); // Create VMContext value. let vmctx = func.create_global_value(ir::GlobalValueData::VMContext); @@ -217,7 +218,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> { readonly: false, }); - func.create_heap(ir::HeapData { + Ok(func.create_heap(ir::HeapData { base: local_memory_base, min_size: (description.minimum.bytes().0 as u64).into(), offset_guard_size: mem_type.guard_size().into(), @@ -225,9 +226,9 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> { bound_gv: local_memory_bound, }, index_type: ir::types::I32, - }) + })) } - mem_type @ MemoryType::Static | mem_type @ MemoryType::SharedStatic => func + mem_type @ MemoryType::Static | mem_type @ MemoryType::SharedStatic => Ok(func .create_heap(ir::HeapData { base: local_memory_base, min_size: (description.minimum.bytes().0 as u64).into(), @@ -236,7 +237,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> { bound: mem_type.bounds().unwrap().into(), }, index_type: ir::types::I32, - }), + })), } } @@ -248,7 +249,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> { &mut self, func: &mut ir::Function, clif_table_index: cranelift_wasm::TableIndex, - ) -> ir::Table { + ) -> cranelift_wasm::WasmResult { let table_index: TableIndex = Converter(clif_table_index).into(); // Create VMContext value. let vmctx = func.create_global_value(ir::GlobalValueData::VMContext); @@ -326,13 +327,13 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> { readonly: false, }); - func.create_table(ir::TableData { + Ok(func.create_table(ir::TableData { base_gv: table_base, min_size: (description.minimum as u64).into(), bound_gv: table_count, element_size: (vm::Anyfunc::size() as u64).into(), index_type: ir::types::I32, - }) + })) } /// Sets up a signature definition in `func`'s preamble. @@ -343,9 +344,9 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> { &mut self, func: &mut ir::Function, clif_sig_index: cranelift_wasm::SignatureIndex, - ) -> ir::SigRef { + ) -> cranelift_wasm::WasmResult { // Create a signature reference out of specified signature (with VMContext param added). - func.import_signature(self.generate_signature(clif_sig_index)) + Ok(func.import_signature(self.generate_signature(clif_sig_index))) } /// Sets up an external function definition in the preamble of `func` that can be used to @@ -356,7 +357,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> { &mut self, func: &mut ir::Function, func_index: cranelift_wasm::FuncIndex, - ) -> ir::FuncRef { + ) -> cranelift_wasm::WasmResult { // Get signature of function. let signature_index = self.env.get_func_type(func_index); @@ -367,12 +368,12 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> { let name = ir::ExternalName::user(0, func_index.as_u32()); // Create function reference from fuction data. - func.import_function(ir::ExtFuncData { + Ok(func.import_function(ir::ExtFuncData { name, signature, // Make this colocated so all calls between local functions are relative. colocated: true, - }) + })) } /// Generates an indirect call IR with `callee` and `call_args`. diff --git a/lib/clif-backend/src/lib.rs b/lib/clif-backend/src/lib.rs index 0ae4e9a59..82f67a39d 100644 --- a/lib/clif-backend/src/lib.rs +++ b/lib/clif-backend/src/lib.rs @@ -1,4 +1,4 @@ -#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)] +#![deny(unused_unsafe, unreachable_patterns)] mod cache; mod code; diff --git a/lib/runtime-core/src/codegen.rs b/lib/runtime-core/src/codegen.rs index b61ce58bb..f04fd0bb5 100644 --- a/lib/runtime-core/src/codegen.rs +++ b/lib/runtime-core/src/codegen.rs @@ -47,7 +47,7 @@ pub trait ModuleCodeGenerator, RM: RunnableModule, fn check_precondition(&mut self, module_info: &ModuleInfo) -> Result<(), E>; /// Creates a new function and returns the function-scope code generator for it. - fn next_function(&mut self) -> Result<&mut FCG, E>; + fn next_function(&mut self, module_info: &ModuleInfo) -> Result<&mut FCG, E>; fn finalize(self, module_info: &ModuleInfo) -> Result<(RM, Box), E>; fn feed_signatures(&mut self, signatures: Map) -> Result<(), E>; diff --git a/lib/runtime-core/src/parse.rs b/lib/runtime-core/src/parse.rs index e7e80fc29..c827d1fd8 100644 --- a/lib/runtime-core/src/parse.rs +++ b/lib/runtime-core/src/parse.rs @@ -201,7 +201,7 @@ pub fn read_module< } let fcg = mcg - .next_function() + .next_function(&info) .map_err(|x| LoadError::Codegen(format!("{:?}", x)))?; middlewares .run( From 2d10306c87ef447f4f83d6dd4520d506d675a497 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sat, 18 May 2019 16:32:22 -0500 Subject: [PATCH 04/33] Add copyright notice --- lib/clif-backend/src/code.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs index 8f5e7e2f1..cd66fcb3f 100644 --- a/lib/clif-backend/src/code.rs +++ b/lib/clif-backend/src/code.rs @@ -1,3 +1,6 @@ +// Parts of the following code are Copyright 2018 Cranelift Developers +// and subject to the license https://github.com/CraneStation/cranelift/blob/c47ca7bafc8fc48358f1baa72360e61fc1f7a0f2/cranelift-wasm/LICENSE + use crate::{func_env::FuncEnv, module::{Converter, Module}, signal::Caller, get_isa}; use std::sync::Arc; use wasmer_runtime_core::{ From 6d5dd5ff21954dc97722c949652f837b6d4d93be Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 19 May 2019 00:27:39 -0500 Subject: [PATCH 05/33] Implement more function codegen --- Cargo.lock | 14 +- lib/clif-backend/Cargo.toml | 2 +- lib/clif-backend/src/code.rs | 717 ++++++++++++++++++++++++++++++++++- 3 files changed, 710 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 804c65f2d..09bb0d4cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -309,7 +309,7 @@ dependencies = [ [[package]] name = "cranelift-bforest" version = "0.30.0" -source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#71581b822e51edab335368af1e0102ab0c811464" +source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#f291d01c3a23282e1432c955beb6ef0ab34db7ea" dependencies = [ "cranelift-entity 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", ] @@ -317,7 +317,7 @@ dependencies = [ [[package]] name = "cranelift-codegen" version = "0.30.0" -source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#71581b822e51edab335368af1e0102ab0c811464" +source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#f291d01c3a23282e1432c955beb6ef0ab34db7ea" dependencies = [ "cranelift-bforest 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", "cranelift-codegen-meta 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", @@ -331,7 +331,7 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" version = "0.30.0" -source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#71581b822e51edab335368af1e0102ab0c811464" +source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#f291d01c3a23282e1432c955beb6ef0ab34db7ea" dependencies = [ "cranelift-entity 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", ] @@ -339,12 +339,12 @@ dependencies = [ [[package]] name = "cranelift-entity" version = "0.30.0" -source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#71581b822e51edab335368af1e0102ab0c811464" +source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#f291d01c3a23282e1432c955beb6ef0ab34db7ea" [[package]] name = "cranelift-frontend" version = "0.30.0" -source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#71581b822e51edab335368af1e0102ab0c811464" +source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#f291d01c3a23282e1432c955beb6ef0ab34db7ea" dependencies = [ "cranelift-codegen 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -354,7 +354,7 @@ dependencies = [ [[package]] name = "cranelift-native" version = "0.30.0" -source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#71581b822e51edab335368af1e0102ab0c811464" +source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#f291d01c3a23282e1432c955beb6ef0ab34db7ea" dependencies = [ "cranelift-codegen 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -364,7 +364,7 @@ dependencies = [ [[package]] name = "cranelift-wasm" version = "0.30.0" -source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#71581b822e51edab335368af1e0102ab0c811464" +source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#f291d01c3a23282e1432c955beb6ef0ab34db7ea" dependencies = [ "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-codegen 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", diff --git a/lib/clif-backend/Cargo.toml b/lib/clif-backend/Cargo.toml index 841004bf2..3ee7895b1 100644 --- a/lib/clif-backend/Cargo.toml +++ b/lib/clif-backend/Cargo.toml @@ -13,7 +13,7 @@ wasmer-runtime-core = { path = "../runtime-core", version = "0.4.1" } # cranelift-codegen = { path = "../../../cranelift/cranelift-codegen" } # cranelift-entity = { path = "../../../cranelift/cranelift-entity" } # cranelift-frontend = { path = "../../../cranelift/cranelift-frontend" } -# cranelift-wasm = { git = "https://github.com/wasmerio/cranelift.git", branch = "wasmer" } +# cranelift-wasm = { path = "../../../cranelift/cranelift-wasm" } cranelift-native = { git = "https://github.com/wasmerio/cranelift.git", branch = "wasmer" } cranelift-codegen = { git = "https://github.com/wasmerio/cranelift.git", branch = "wasmer" } cranelift-entity = { git = "https://github.com/wasmerio/cranelift.git", branch = "wasmer" } diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs index cd66fcb3f..b5b56c30c 100644 --- a/lib/clif-backend/src/code.rs +++ b/lib/clif-backend/src/code.rs @@ -1,7 +1,7 @@ // Parts of the following code are Copyright 2018 Cranelift Developers // and subject to the license https://github.com/CraneStation/cranelift/blob/c47ca7bafc8fc48358f1baa72360e61fc1f7a0f2/cranelift-wasm/LICENSE -use crate::{func_env::FuncEnv, module::{Converter, Module}, signal::Caller, get_isa}; +use crate::{func_env::FuncEnv, module::{Converter, Module}, signal::Caller, get_isa, relocation::call_names}; use std::sync::Arc; use wasmer_runtime_core::{ backend::{Backend, CacheGen, Token}, @@ -9,17 +9,21 @@ use wasmer_runtime_core::{ codegen::*, module::{ModuleInfo, ModuleInner}, structures::{TypedIndex, Map}, + memory::MemoryType, types::{ FuncSig, FuncIndex, ElementType, GlobalDescriptor, GlobalIndex, GlobalInit, Initializer, LocalFuncIndex, - LocalOrImport, MemoryDescriptor, SigIndex, TableDescriptor, Value, + LocalOrImport, MemoryDescriptor, SigIndex, TableDescriptor, Value, MemoryIndex, TableIndex, }, + vm, }; -use cranelift_codegen::isa; +use std::mem; +use cranelift_codegen::{isa, cursor::FuncCursor}; use cranelift_codegen::entity::EntityRef; use cranelift_codegen::ir::{self, Ebb, InstBuilder, ValueLabel}; use cranelift_codegen::timing; use wasmparser::Type as WpType; +use cranelift_wasm::{FuncEnvironment, ReturnMode, WasmError, WasmResult}; use cranelift_wasm::{translate_operator, TranslationState, get_vmctx_value_label}; use cranelift_wasm::{self, translate_module, FuncTranslator, ModuleEnvironment}; use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; @@ -64,9 +68,6 @@ impl ModuleCodeGenerator // define_function_body( - - - let mut func_translator = FuncTranslator::new(); // let func_body = { @@ -74,6 +75,7 @@ impl ModuleCodeGenerator // let mut func_env = FuncEnv::new(self); + // TODO should func_index come from self.functions? let func_index = self.func_bodies.next_index(); let name = ir::ExternalName::user(0, func_index.index() as u32); @@ -90,12 +92,13 @@ impl ModuleCodeGenerator builder: None, func_body: func, func_translator, + next_local: 0, // translator: }; let builder = FunctionBuilder::new(&mut func_env.func_body, &mut func_env.func_translator.func_ctx); func_env.builder = Some(builder); - let mut builder = func_env.builder.as_ref().unwrap(); + let mut builder = func_env.builder.as_mut().unwrap(); // TODO srcloc //builder.set_srcloc(cur_srcloc(&reader)); @@ -281,10 +284,7 @@ impl ModuleCodeGenerator // }; // Add function body to list of function bodies. -// self.func_bodies.push(func); - - - + //self.func_bodies.push(func); self.functions.push(func_env); Ok(self.functions.last_mut().unwrap()) @@ -323,6 +323,664 @@ pub struct CraneliftFunctionCodeGenerator { func_body: ir::Function, builder: Option>, func_translator: FuncTranslator, + next_local: usize, +} + +impl FuncEnvironment for CraneliftFunctionCodeGenerator { + /// Gets configuration information needed for compiling functions + fn target_config(&self) -> isa::TargetFrontendConfig { + self.env.target_config() + } + + /// Gets native pointers types. + /// + /// `I64` on 64-bit arch; `I32` on 32-bit arch. + fn pointer_type(&self) -> ir::Type { + ir::Type::int(u16::from(self.target_config().pointer_bits())).unwrap() + } + + /// Gets the size of a native pointer in bytes. + fn pointer_bytes(&self) -> u8 { + self.target_config().pointer_bytes() + } + + /// Sets up the necessary preamble definitions in `func` to access the global identified + /// by `index`. + /// + /// The index space covers both imported and locally declared globals. + fn make_global( + &mut self, + func: &mut ir::Function, + clif_global_index: cranelift_wasm::GlobalIndex, + ) -> cranelift_wasm::WasmResult { + let global_index: GlobalIndex = Converter(clif_global_index).into(); + + // Create VMContext value. + let vmctx = func.create_global_value(ir::GlobalValueData::VMContext); + let ptr_type = self.pointer_type(); + + let local_global_addr = match global_index.local_or_import(&self.env.module.info) { + LocalOrImport::Local(local_global_index) => { + let globals_base_addr = func.create_global_value(ir::GlobalValueData::Load { + base: vmctx, + offset: (vm::Ctx::offset_globals() as i32).into(), + global_type: ptr_type, + readonly: true, + }); + + let offset = local_global_index.index() * mem::size_of::<*mut vm::LocalGlobal>(); + + let local_global_ptr_ptr = func.create_global_value(ir::GlobalValueData::IAddImm { + base: globals_base_addr, + offset: (offset as i64).into(), + global_type: ptr_type, + }); + + func.create_global_value(ir::GlobalValueData::Load { + base: local_global_ptr_ptr, + offset: 0.into(), + global_type: ptr_type, + readonly: true, + }) + } + LocalOrImport::Import(import_global_index) => { + let globals_base_addr = func.create_global_value(ir::GlobalValueData::Load { + base: vmctx, + offset: (vm::Ctx::offset_imported_globals() as i32).into(), + global_type: ptr_type, + readonly: true, + }); + + let offset = import_global_index.index() * mem::size_of::<*mut vm::LocalGlobal>(); + + let local_global_ptr_ptr = func.create_global_value(ir::GlobalValueData::IAddImm { + base: globals_base_addr, + offset: (offset as i64).into(), + global_type: ptr_type, + }); + + func.create_global_value(ir::GlobalValueData::Load { + base: local_global_ptr_ptr, + offset: 0.into(), + global_type: ptr_type, + readonly: true, + }) + } + }; + + Ok(cranelift_wasm::GlobalVariable::Memory { + gv: local_global_addr, + offset: (vm::LocalGlobal::offset_data() as i32).into(), + ty: self.env.get_global(clif_global_index).ty, + }) + } + + /// Sets up the necessary preamble definitions in `func` to access the linear memory identified + /// by `index`. + /// + /// The index space covers both imported and locally declared memories. + fn make_heap( + &mut self, + func: &mut ir::Function, + clif_mem_index: cranelift_wasm::MemoryIndex, + ) -> cranelift_wasm::WasmResult { + let mem_index: MemoryIndex = Converter(clif_mem_index).into(); + // Create VMContext value. + let vmctx = func.create_global_value(ir::GlobalValueData::VMContext); + let ptr_type = self.pointer_type(); + + let (local_memory_ptr_ptr, description) = + match mem_index.local_or_import(&self.env.module.info) { + LocalOrImport::Local(local_mem_index) => { + let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load { + base: vmctx, + offset: (vm::Ctx::offset_memories() as i32).into(), + global_type: ptr_type, + readonly: true, + }); + + let local_memory_ptr_offset = + local_mem_index.index() * mem::size_of::<*mut vm::LocalMemory>(); + + ( + func.create_global_value(ir::GlobalValueData::IAddImm { + base: memories_base_addr, + offset: (local_memory_ptr_offset as i64).into(), + global_type: ptr_type, + }), + self.env.module.info.memories[local_mem_index], + ) + } + LocalOrImport::Import(import_mem_index) => { + let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load { + base: vmctx, + offset: (vm::Ctx::offset_imported_memories() as i32).into(), + global_type: ptr_type, + readonly: true, + }); + + let local_memory_ptr_offset = + import_mem_index.index() * mem::size_of::<*mut vm::LocalMemory>(); + + ( + func.create_global_value(ir::GlobalValueData::IAddImm { + base: memories_base_addr, + offset: (local_memory_ptr_offset as i64).into(), + global_type: ptr_type, + }), + self.env.module.info.imported_memories[import_mem_index].1, + ) + } + }; + + let (local_memory_ptr, local_memory_base) = { + let local_memory_ptr = func.create_global_value(ir::GlobalValueData::Load { + base: local_memory_ptr_ptr, + offset: 0.into(), + global_type: ptr_type, + readonly: true, + }); + + ( + local_memory_ptr, + func.create_global_value(ir::GlobalValueData::Load { + base: local_memory_ptr, + offset: (vm::LocalMemory::offset_base() as i32).into(), + global_type: ptr_type, + readonly: false, + }), + ) + }; + + match description.memory_type() { + mem_type @ MemoryType::Dynamic => { + let local_memory_bound = func.create_global_value(ir::GlobalValueData::Load { + base: local_memory_ptr, + offset: (vm::LocalMemory::offset_bound() as i32).into(), + global_type: ptr_type, + readonly: false, + }); + + Ok(func.create_heap(ir::HeapData { + base: local_memory_base, + min_size: (description.minimum.bytes().0 as u64).into(), + offset_guard_size: mem_type.guard_size().into(), + style: ir::HeapStyle::Dynamic { + bound_gv: local_memory_bound, + }, + index_type: ir::types::I32, + })) + } + mem_type @ MemoryType::Static | mem_type @ MemoryType::SharedStatic => Ok(func + .create_heap(ir::HeapData { + base: local_memory_base, + min_size: (description.minimum.bytes().0 as u64).into(), + offset_guard_size: mem_type.guard_size().into(), + style: ir::HeapStyle::Static { + bound: mem_type.bounds().unwrap().into(), + }, + index_type: ir::types::I32, + })), + } + } + + /// Sets up the necessary preamble definitions in `func` to access the table identified + /// by `index`. + /// + /// The index space covers both imported and locally declared tables. + fn make_table( + &mut self, + func: &mut ir::Function, + clif_table_index: cranelift_wasm::TableIndex, + ) -> cranelift_wasm::WasmResult { + let table_index: TableIndex = Converter(clif_table_index).into(); + // Create VMContext value. + let vmctx = func.create_global_value(ir::GlobalValueData::VMContext); + let ptr_type = self.pointer_type(); + + let (table_struct_ptr_ptr, description) = match table_index + .local_or_import(&self.env.module.info) + { + LocalOrImport::Local(local_table_index) => { + let tables_base = func.create_global_value(ir::GlobalValueData::Load { + base: vmctx, + offset: (vm::Ctx::offset_tables() as i32).into(), + global_type: ptr_type, + readonly: true, + }); + + let table_struct_ptr_offset = + local_table_index.index() * vm::LocalTable::size() as usize; + + let table_struct_ptr_ptr = func.create_global_value(ir::GlobalValueData::IAddImm { + base: tables_base, + offset: (table_struct_ptr_offset as i64).into(), + global_type: ptr_type, + }); + + ( + table_struct_ptr_ptr, + self.env.module.info.tables[local_table_index], + ) + } + LocalOrImport::Import(import_table_index) => { + let tables_base = func.create_global_value(ir::GlobalValueData::Load { + base: vmctx, + offset: (vm::Ctx::offset_imported_tables() as i32).into(), + global_type: ptr_type, + readonly: true, + }); + + let table_struct_ptr_offset = + import_table_index.index() * vm::LocalTable::size() as usize; + + let table_struct_ptr_ptr = func.create_global_value(ir::GlobalValueData::IAddImm { + base: tables_base, + offset: (table_struct_ptr_offset as i64).into(), + global_type: ptr_type, + }); + + ( + table_struct_ptr_ptr, + self.env.module.info.imported_tables[import_table_index].1, + ) + } + }; + + let table_struct_ptr = func.create_global_value(ir::GlobalValueData::Load { + base: table_struct_ptr_ptr, + offset: 0.into(), + global_type: ptr_type, + readonly: true, + }); + + let table_base = func.create_global_value(ir::GlobalValueData::Load { + base: table_struct_ptr, + offset: (vm::LocalTable::offset_base() as i32).into(), + global_type: ptr_type, + // The table can reallocate, so the ptr can't be readonly. + readonly: false, + }); + + let table_count = func.create_global_value(ir::GlobalValueData::Load { + base: table_struct_ptr, + offset: (vm::LocalTable::offset_count() as i32).into(), + global_type: ptr_type, + // The table length can change, so it can't be readonly. + readonly: false, + }); + + Ok(func.create_table(ir::TableData { + base_gv: table_base, + min_size: (description.minimum as u64).into(), + bound_gv: table_count, + element_size: (vm::Anyfunc::size() as u64).into(), + index_type: ir::types::I32, + })) + } + + /// Sets up a signature definition in `func`'s preamble. + /// + /// Signature may contain additional argument, but arguments marked as ArgumentPurpose::Normal` + /// must correspond to the arguments in the wasm signature + fn make_indirect_sig( + &mut self, + func: &mut ir::Function, + clif_sig_index: cranelift_wasm::SignatureIndex, + ) -> cranelift_wasm::WasmResult { + // Create a signature reference out of specified signature (with VMContext param added). + Ok(func.import_signature(self.generate_signature(clif_sig_index))) + } + + /// Sets up an external function definition in the preamble of `func` that can be used to + /// directly call the function `index`. + /// + /// The index space covers both imported functions and functions defined in the current module. + fn make_direct_func( + &mut self, + func: &mut ir::Function, + func_index: cranelift_wasm::FuncIndex, + ) -> cranelift_wasm::WasmResult { + // Get signature of function. + let signature_index = self.env.get_func_type(func_index); + + // Create a signature reference from specified signature (with VMContext param added). + let signature = func.import_signature(self.generate_signature(signature_index)); + + // Get name of function. + let name = ir::ExternalName::user(0, func_index.as_u32()); + + // Create function reference from fuction data. + Ok(func.import_function(ir::ExtFuncData { + name, + signature, + // Make this colocated so all calls between local functions are relative. + colocated: true, + })) + } + + /// Generates an indirect call IR with `callee` and `call_args`. + /// + /// Inserts instructions at `pos` to the function `callee` in the table + /// `table_index` with WebAssembly signature `sig_index` + #[cfg_attr(feature = "cargo-clippy", allow(clippy::too_many_arguments))] + fn translate_call_indirect( + &mut self, + mut pos: FuncCursor, + _table_index: cranelift_wasm::TableIndex, + table: ir::Table, + clif_sig_index: cranelift_wasm::SignatureIndex, + sig_ref: ir::SigRef, + callee: ir::Value, + call_args: &[ir::Value], + ) -> cranelift_wasm::WasmResult { + // Get the pointer type based on machine's pointer size. + let ptr_type = self.pointer_type(); + + // The `callee` value is an index into a table of Anyfunc structures. + let entry_addr = pos.ins().table_addr(ptr_type, table, callee, 0); + + let mflags = ir::MemFlags::trusted(); + + let func_ptr = pos.ins().load( + ptr_type, + mflags, + entry_addr, + vm::Anyfunc::offset_func() as i32, + ); + + let vmctx_ptr = { + let loaded_vmctx_ptr = pos.ins().load( + ptr_type, + mflags, + entry_addr, + vm::Anyfunc::offset_vmctx() as i32, + ); + + let argument_vmctx_ptr = pos + .func + .special_param(ir::ArgumentPurpose::VMContext) + .expect("missing vmctx parameter"); + + // If the loaded vmctx ptr is zero, use the caller vmctx, else use the callee (loaded) vmctx. + pos.ins() + .select(loaded_vmctx_ptr, loaded_vmctx_ptr, argument_vmctx_ptr) + }; + + let found_sig = pos.ins().load( + ir::types::I32, + mflags, + entry_addr, + vm::Anyfunc::offset_sig_id() as i32, + ); + + pos.ins().trapz(func_ptr, ir::TrapCode::IndirectCallToNull); + + let expected_sig = { + let sig_index_global = pos.func.create_global_value(ir::GlobalValueData::Symbol { + // The index of the `ExternalName` is the undeduplicated, signature index. + name: ir::ExternalName::user( + call_names::SIG_NAMESPACE, + clif_sig_index.index() as u32, + ), + offset: 0.into(), + colocated: false, + }); + + pos.ins().symbol_value(ir::types::I64, sig_index_global) + + // let dynamic_sigindices_array_ptr = pos.ins().load( + // ptr_type, + // mflags, + + // ) + + // let expected_sig = pos.ins().iconst(ir::types::I32, sig_index.index() as i64); + + // self.env.deduplicated[clif_sig_index] + }; + + let not_equal_flags = pos.ins().ifcmp(found_sig, expected_sig); + + pos.ins().trapif( + ir::condcodes::IntCC::NotEqual, + not_equal_flags, + ir::TrapCode::BadSignature, + ); + + // Build a value list for the indirect call instruction containing the call_args + // and the vmctx parameter. + let mut args = Vec::with_capacity(call_args.len() + 1); + args.push(vmctx_ptr); + args.extend(call_args.iter().cloned()); + + Ok(pos.ins().call_indirect(sig_ref, func_ptr, &args)) + } + + /// Generates a call IR with `callee` and `call_args` and inserts it at `pos` + /// TODO: add support for imported functions + fn translate_call( + &mut self, + mut pos: FuncCursor, + clif_callee_index: cranelift_wasm::FuncIndex, + callee: ir::FuncRef, + call_args: &[ir::Value], + ) -> cranelift_wasm::WasmResult { + let callee_index: FuncIndex = Converter(clif_callee_index).into(); + let ptr_type = self.pointer_type(); + + match callee_index.local_or_import(&self.env.module.info) { + LocalOrImport::Local(local_function_index) => { + // this is an internal function + let vmctx = pos + .func + .special_param(ir::ArgumentPurpose::VMContext) + .expect("missing vmctx parameter"); + + let mut args = Vec::with_capacity(call_args.len() + 1); + args.push(vmctx); + args.extend(call_args.iter().cloned()); + + let sig_ref = pos.func.dfg.ext_funcs[callee].signature; + let function_ptr = { + let mflags = ir::MemFlags::trusted(); + + let function_array_ptr = pos.ins().load( + ptr_type, + mflags, + vmctx, + vm::Ctx::offset_local_functions() as i32, + ); + + pos.ins().load( + ptr_type, + mflags, + function_array_ptr, + (local_function_index.index() as i32) * 8, + ) + }; + + Ok(pos.ins().call_indirect(sig_ref, function_ptr, &args)) + } + LocalOrImport::Import(imported_func_index) => { + // this is an imported function + let vmctx = pos.func.create_global_value(ir::GlobalValueData::VMContext); + + let imported_funcs = pos.func.create_global_value(ir::GlobalValueData::Load { + base: vmctx, + offset: (vm::Ctx::offset_imported_funcs() as i32).into(), + global_type: ptr_type, + readonly: true, + }); + + let imported_func_offset = + imported_func_index.index() * vm::ImportedFunc::size() as usize; + + let imported_func_struct_addr = + pos.func.create_global_value(ir::GlobalValueData::IAddImm { + base: imported_funcs, + offset: (imported_func_offset as i64).into(), + global_type: ptr_type, + }); + + let imported_func_addr = pos.func.create_global_value(ir::GlobalValueData::Load { + base: imported_func_struct_addr, + offset: (vm::ImportedFunc::offset_func() as i32).into(), + global_type: ptr_type, + readonly: true, + }); + + let imported_vmctx_addr = pos.func.create_global_value(ir::GlobalValueData::Load { + base: imported_func_struct_addr, + offset: (vm::ImportedFunc::offset_vmctx() as i32).into(), + global_type: ptr_type, + readonly: true, + }); + + let imported_func_addr = pos.ins().global_value(ptr_type, imported_func_addr); + let imported_vmctx_addr = pos.ins().global_value(ptr_type, imported_vmctx_addr); + + let sig_ref = pos.func.dfg.ext_funcs[callee].signature; + + let mut args = Vec::with_capacity(call_args.len() + 1); + args.push(imported_vmctx_addr); + args.extend(call_args.iter().cloned()); + + Ok(pos + .ins() + .call_indirect(sig_ref, imported_func_addr, &args[..])) + } + } + } + + /// Generates code corresponding to wasm `memory.grow`. + /// + /// `index` refers to the linear memory to query. + /// + /// `heap` refers to the IR generated by `make_heap`. + /// + /// `val` refers the value to grow the memory by. + fn translate_memory_grow( + &mut self, + mut pos: FuncCursor, + clif_mem_index: cranelift_wasm::MemoryIndex, + _heap: ir::Heap, + by_value: ir::Value, + ) -> cranelift_wasm::WasmResult { + let signature = pos.func.import_signature(ir::Signature { + call_conv: self.target_config().default_call_conv, + params: vec![ + ir::AbiParam::special(self.pointer_type(), ir::ArgumentPurpose::VMContext), + ir::AbiParam::new(ir::types::I32), + ir::AbiParam::new(ir::types::I32), + ], + returns: vec![ir::AbiParam::new(ir::types::I32)], + }); + + let mem_index: MemoryIndex = Converter(clif_mem_index).into(); + + let (namespace, mem_index, description) = + match mem_index.local_or_import(&self.env.module.info) { + LocalOrImport::Local(local_mem_index) => ( + call_names::LOCAL_NAMESPACE, + local_mem_index.index(), + self.env.module.info.memories[local_mem_index], + ), + LocalOrImport::Import(import_mem_index) => ( + call_names::IMPORT_NAMESPACE, + import_mem_index.index(), + self.env.module.info.imported_memories[import_mem_index].1, + ), + }; + + let name_index = match description.memory_type() { + MemoryType::Dynamic => call_names::DYNAMIC_MEM_GROW, + MemoryType::Static => call_names::STATIC_MEM_GROW, + MemoryType::SharedStatic => call_names::SHARED_STATIC_MEM_GROW, + }; + + let name = ir::ExternalName::user(namespace, name_index); + + let mem_grow_func = pos.func.import_function(ir::ExtFuncData { + name, + signature, + colocated: false, + }); + + let const_mem_index = pos.ins().iconst(ir::types::I32, mem_index as i64); + + let vmctx = pos + .func + .special_param(ir::ArgumentPurpose::VMContext) + .expect("missing vmctx parameter"); + + let call_inst = pos + .ins() + .call(mem_grow_func, &[vmctx, const_mem_index, by_value]); + + Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap()) + } + + /// Generates code corresponding to wasm `memory.size`. + /// + /// `index` refers to the linear memory to query. + /// + /// `heap` refers to the IR generated by `make_heap`. + fn translate_memory_size( + &mut self, + mut pos: FuncCursor, + clif_mem_index: cranelift_wasm::MemoryIndex, + _heap: ir::Heap, + ) -> cranelift_wasm::WasmResult { + let signature = pos.func.import_signature(ir::Signature { + call_conv: self.target_config().default_call_conv, + params: vec![ + ir::AbiParam::special(self.pointer_type(), ir::ArgumentPurpose::VMContext), + ir::AbiParam::new(ir::types::I32), + ], + returns: vec![ir::AbiParam::new(ir::types::I32)], + }); + + let mem_index: MemoryIndex = Converter(clif_mem_index).into(); + + let (namespace, mem_index, description) = + match mem_index.local_or_import(&self.env.module.info) { + LocalOrImport::Local(local_mem_index) => ( + call_names::LOCAL_NAMESPACE, + local_mem_index.index(), + self.env.module.info.memories[local_mem_index], + ), + LocalOrImport::Import(import_mem_index) => ( + call_names::IMPORT_NAMESPACE, + import_mem_index.index(), + self.env.module.info.imported_memories[import_mem_index].1, + ), + }; + + let name_index = match description.memory_type() { + MemoryType::Dynamic => call_names::DYNAMIC_MEM_SIZE, + MemoryType::Static => call_names::STATIC_MEM_SIZE, + MemoryType::SharedStatic => call_names::SHARED_STATIC_MEM_SIZE, + }; + + let name = ir::ExternalName::user(namespace, name_index); + + let mem_grow_func = pos.func.import_function(ir::ExtFuncData { + name, + signature, + colocated: false, + }); + + let const_mem_index = pos.ins().iconst(ir::types::I32, mem_index as i64); + let vmctx = pos + .func + .special_param(ir::ArgumentPurpose::VMContext) + .expect("missing vmctx parameter"); + + let call_inst = pos.ins().call(mem_grow_func, &[vmctx, const_mem_index]); + + Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap()) + } } impl FunctionCodeGenerator for CraneliftFunctionCodeGenerator { @@ -331,10 +989,12 @@ impl FunctionCodeGenerator for CraneliftFunctionCodeGenerator { } fn feed_param(&mut self, _ty: WpType) -> Result<(), CodegenError> { + self.next_local += 1; Ok(()) } - fn feed_local(&mut self, _ty: WpType, _n: usize) -> Result<(), CodegenError> { + fn feed_local(&mut self, ty: WpType, n: usize) -> Result<(), CodegenError> { + cranelift_wasm::declare_locals(self.builder.as_mut().unwrap(), n as u32, ty, &mut self.next_local); Ok(()) } @@ -349,14 +1009,37 @@ impl FunctionCodeGenerator for CraneliftFunctionCodeGenerator { return Ok(()); } }; - let builder = &self.builder; + let builder = self.builder.as_mut().unwrap(); //let func_environment = FuncEnv::new(); //let state = TranslationState::new(); - //translate_operator(*op, builder, state, func_environment); + translate_operator(*op, builder, &mut self.func_translator.state, self); Ok(()) } fn finalize(&mut self) -> Result<(), CodegenError> { + let return_mode = self.return_mode(); + let state = &mut self.func_translator.state; + let builder = self.builder.as_mut().unwrap(); + + // The final `End` operator left us in the exit block where we need to manually add a return + // instruction. + // + // If the exit block is unreachable, it may not have the correct arguments, so we would + // generate a return instruction that doesn't match the signature. + if state.reachable { + debug_assert!(builder.is_pristine()); + if !builder.is_unreachable() { + match return_mode { + ReturnMode::NormalReturns => builder.ins().return_(&state.stack), + ReturnMode::FallthroughReturn => builder.ins().fallthrough_return(&state.stack), + }; + } + } + + // Discard any remaining values on the stack. Either we just returned them, + // or the end of the function is unreachable. + state.stack.clear(); + self.builder.as_mut().unwrap().finalize(); Ok(()) } @@ -378,8 +1061,12 @@ impl CraneliftModuleCodeGenerator { Converter(sig_index).into() } +} - +impl CraneliftFunctionCodeGenerator { + pub fn return_mode(&self) -> ReturnMode { + ReturnMode::NormalReturns + } } /// Creates a signature with VMContext as the last param From 47479b547f913228be73ef0f07e9e46182454a67 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 19 May 2019 10:53:33 -0500 Subject: [PATCH 06/33] Implement MCG.{finalize, from_cache} --- lib/clif-backend/src/code.rs | 604 +++++++++++++++++-------------- lib/clif-backend/src/func_env.rs | 3 +- 2 files changed, 336 insertions(+), 271 deletions(-) diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs index b5b56c30c..9654aecaf 100644 --- a/lib/clif-backend/src/code.rs +++ b/lib/clif-backend/src/code.rs @@ -1,32 +1,43 @@ // Parts of the following code are Copyright 2018 Cranelift Developers // and subject to the license https://github.com/CraneStation/cranelift/blob/c47ca7bafc8fc48358f1baa72360e61fc1f7a0f2/cranelift-wasm/LICENSE -use crate::{func_env::FuncEnv, module::{Converter, Module}, signal::Caller, get_isa, relocation::call_names}; +use crate::{ + cache::{BackendCache, CacheGenerator}, + func_env::FuncEnv, + get_isa, module, + module::{Converter, Module}, + relocation::call_names, + resolver::FuncResolverBuilder, + signal::Caller, + trampoline::Trampolines, +}; + +use cranelift_codegen::entity::EntityRef; +use cranelift_codegen::ir::{self, Ebb, InstBuilder, ValueLabel}; +use cranelift_codegen::timing; +use cranelift_codegen::{cursor::FuncCursor, isa}; +use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; +use cranelift_wasm::{self, translate_module, FuncTranslator, ModuleEnvironment}; +use cranelift_wasm::{get_vmctx_value_label, translate_operator, TranslationState}; +use cranelift_wasm::{FuncEnvironment, ReturnMode, WasmError, WasmResult}; +use std::mem; use std::sync::Arc; +use wasmer_runtime_core::error::CompileError; use wasmer_runtime_core::{ backend::{Backend, CacheGen, Token}, cache::{Artifact, Error as CacheError}, codegen::*, - module::{ModuleInfo, ModuleInner}, - structures::{TypedIndex, Map}, memory::MemoryType, + module::{ModuleInfo, ModuleInner}, + structures::{Map, TypedIndex}, types::{ - FuncSig, FuncIndex, - ElementType, GlobalDescriptor, GlobalIndex, GlobalInit, Initializer, LocalFuncIndex, - LocalOrImport, MemoryDescriptor, SigIndex, TableDescriptor, Value, MemoryIndex, TableIndex, + ElementType, FuncIndex, FuncSig, GlobalDescriptor, GlobalIndex, GlobalInit, Initializer, + LocalFuncIndex, LocalOrImport, MemoryDescriptor, MemoryIndex, SigIndex, TableDescriptor, + TableIndex, Value, }, vm, }; -use std::mem; -use cranelift_codegen::{isa, cursor::FuncCursor}; -use cranelift_codegen::entity::EntityRef; -use cranelift_codegen::ir::{self, Ebb, InstBuilder, ValueLabel}; -use cranelift_codegen::timing; use wasmparser::Type as WpType; -use cranelift_wasm::{FuncEnvironment, ReturnMode, WasmError, WasmResult}; -use cranelift_wasm::{translate_operator, TranslationState, get_vmctx_value_label}; -use cranelift_wasm::{self, translate_module, FuncTranslator, ModuleEnvironment}; -use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; pub struct CraneliftModuleCodeGenerator { isa: Box, @@ -37,9 +48,7 @@ pub struct CraneliftModuleCodeGenerator { func_bodies: Map, } -pub struct ClifFuncEnv { - -} +pub struct ClifFuncEnv {} impl ModuleCodeGenerator for CraneliftModuleCodeGenerator @@ -64,224 +73,232 @@ impl ModuleCodeGenerator Ok(()) } - fn next_function(&mut self, module_info: &ModuleInfo) -> Result<&mut CraneliftFunctionCodeGenerator, CodegenError> { - + fn next_function( + &mut self, + module_info: &ModuleInfo, + ) -> Result<&mut CraneliftFunctionCodeGenerator, CodegenError> { // define_function_body( let mut func_translator = FuncTranslator::new(); -// let func_body = { + // let func_body = { + // let mut func_env = FuncEnv::new(self); -// let mut func_env = FuncEnv::new(self); + // TODO should func_index come from self.functions? + let func_index = self.func_bodies.next_index(); + let name = ir::ExternalName::user(0, func_index.index() as u32); - // TODO should func_index come from self.functions? - let func_index = self.func_bodies.next_index(); - let name = ir::ExternalName::user(0, func_index.index() as u32); + let sig = generate_signature( + self, + self.get_func_type( + &module_info, + Converter(func_index.convert_up(&module_info)).into(), + ), + ); - let sig = generate_signature(self, - self.get_func_type(&module_info, Converter(func_index.convert_up(&module_info)).into()), + let mut func = ir::Function::with_name_signature(name, sig); + + //func_translator.translate(body_bytes, body_offset, &mut func, &mut func_env)?; + // This clears the `FunctionBuilderContext`. + + let mut func_env = CraneliftFunctionCodeGenerator { + builder: None, + func_body: func, + func_translator, + next_local: 0, + }; + let builder = FunctionBuilder::new( + &mut func_env.func_body, + &mut func_env.func_translator.func_ctx, + ); + func_env.builder = Some(builder); + + let mut builder = func_env.builder.as_mut().unwrap(); + + // TODO srcloc + //builder.set_srcloc(cur_srcloc(&reader)); + + let entry_block = builder.create_ebb(); + builder.append_ebb_params_for_function_params(entry_block); + builder.switch_to_block(entry_block); // This also creates values for the arguments. + builder.seal_block(entry_block); + // Make sure the entry block is inserted in the layout before we make any callbacks to + // `environ`. The callback functions may need to insert things in the entry block. + builder.ensure_inserted_ebb(); + + let num_params = declare_wasm_parameters(&mut builder, entry_block); + + // Set up the translation state with a single pushed control block representing the whole + // function and its return values. + let exit_block = builder.create_ebb(); + builder.append_ebb_params_for_function_returns(exit_block); + func_translator + .state + .initialize(&builder.func.signature, exit_block); + + #[cfg(feature = "debug")] + { + use cranelift_codegen::cursor::{Cursor, FuncCursor}; + use cranelift_codegen::ir::InstBuilder; + let entry_ebb = func.layout.entry_block().unwrap(); + let ebb = func.dfg.make_ebb(); + func.layout.insert_ebb(ebb, entry_ebb); + let mut pos = FuncCursor::new(&mut func).at_first_insertion_point(ebb); + let params = pos.func.dfg.ebb_params(entry_ebb).to_vec(); + + let new_ebb_params: Vec<_> = params + .iter() + .map(|¶m| { + pos.func + .dfg + .append_ebb_param(ebb, pos.func.dfg.value_type(param)) + }) + .collect(); + + let start_debug = { + let signature = pos.func.import_signature(ir::Signature { + call_conv: self.target_config().default_call_conv, + params: vec![ + ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), + ir::AbiParam::new(ir::types::I32), + ], + returns: vec![], + }); + + let name = ir::ExternalName::testcase("strtdbug"); + + pos.func.import_function(ir::ExtFuncData { + name, + signature, + colocated: false, + }) + }; + + let end_debug = { + let signature = pos.func.import_signature(ir::Signature { + call_conv: self.target_config().default_call_conv, + params: vec![ir::AbiParam::special( + ir::types::I64, + ir::ArgumentPurpose::VMContext, + )], + returns: vec![], + }); + + let name = ir::ExternalName::testcase("enddbug"); + + pos.func.import_function(ir::ExtFuncData { + name, + signature, + colocated: false, + }) + }; + + let i32_print = { + let signature = pos.func.import_signature(ir::Signature { + call_conv: self.target_config().default_call_conv, + params: vec![ + ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), + ir::AbiParam::new(ir::types::I32), + ], + returns: vec![], + }); + + let name = ir::ExternalName::testcase("i32print"); + + pos.func.import_function(ir::ExtFuncData { + name, + signature, + colocated: false, + }) + }; + + let i64_print = { + let signature = pos.func.import_signature(ir::Signature { + call_conv: self.target_config().default_call_conv, + params: vec![ + ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), + ir::AbiParam::new(ir::types::I64), + ], + returns: vec![], + }); + + let name = ir::ExternalName::testcase("i64print"); + + pos.func.import_function(ir::ExtFuncData { + name, + signature, + colocated: false, + }) + }; + + let f32_print = { + let signature = pos.func.import_signature(ir::Signature { + call_conv: self.target_config().default_call_conv, + params: vec![ + ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), + ir::AbiParam::new(ir::types::F32), + ], + returns: vec![], + }); + + let name = ir::ExternalName::testcase("f32print"); + + pos.func.import_function(ir::ExtFuncData { + name, + signature, + colocated: false, + }) + }; + + let f64_print = { + let signature = pos.func.import_signature(ir::Signature { + call_conv: self.target_config().default_call_conv, + params: vec![ + ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), + ir::AbiParam::new(ir::types::F64), + ], + returns: vec![], + }); + + let name = ir::ExternalName::testcase("f64print"); + + pos.func.import_function(ir::ExtFuncData { + name, + signature, + colocated: false, + }) + }; + + let vmctx = pos + .func + .special_param(ir::ArgumentPurpose::VMContext) + .expect("missing vmctx parameter"); + + let func_index = pos.ins().iconst( + ir::types::I32, + func_index.index() as i64 + self.module.info.imported_functions.len() as i64, ); - let mut func = ir::Function::with_name_signature(name, sig); + pos.ins().call(start_debug, &[vmctx, func_index]); - //func_translator.translate(body_bytes, body_offset, &mut func, &mut func_env)?; - // This clears the `FunctionBuilderContext`. + for param in new_ebb_params.iter().cloned() { + match pos.func.dfg.value_type(param) { + ir::types::I32 => pos.ins().call(i32_print, &[vmctx, param]), + ir::types::I64 => pos.ins().call(i64_print, &[vmctx, param]), + ir::types::F32 => pos.ins().call(f32_print, &[vmctx, param]), + ir::types::F64 => pos.ins().call(f64_print, &[vmctx, param]), + _ => unimplemented!(), + }; + } - let mut func_env = CraneliftFunctionCodeGenerator { - builder: None, - func_body: func, - func_translator, - next_local: 0, - // translator: - }; - let builder = FunctionBuilder::new(&mut func_env.func_body, &mut func_env.func_translator.func_ctx); - func_env.builder = Some(builder); + pos.ins().call(end_debug, &[vmctx]); - let mut builder = func_env.builder.as_mut().unwrap(); + pos.ins().jump(entry_ebb, new_ebb_params.as_slice()); + } - // TODO srcloc - //builder.set_srcloc(cur_srcloc(&reader)); - - let entry_block = builder.create_ebb(); - builder.append_ebb_params_for_function_params(entry_block); - builder.switch_to_block(entry_block); // This also creates values for the arguments. - builder.seal_block(entry_block); - // Make sure the entry block is inserted in the layout before we make any callbacks to - // `environ`. The callback functions may need to insert things in the entry block. - builder.ensure_inserted_ebb(); - - let num_params = declare_wasm_parameters(&mut builder, entry_block); - - // Set up the translation state with a single pushed control block representing the whole - // function and its return values. - let exit_block = builder.create_ebb(); - builder.append_ebb_params_for_function_returns(exit_block); - func_translator.state.initialize(&builder.func.signature, exit_block); - - - #[cfg(feature = "debug")] - { - use cranelift_codegen::cursor::{Cursor, FuncCursor}; - use cranelift_codegen::ir::InstBuilder; - let entry_ebb = func.layout.entry_block().unwrap(); - let ebb = func.dfg.make_ebb(); - func.layout.insert_ebb(ebb, entry_ebb); - let mut pos = FuncCursor::new(&mut func).at_first_insertion_point(ebb); - let params = pos.func.dfg.ebb_params(entry_ebb).to_vec(); - - let new_ebb_params: Vec<_> = params - .iter() - .map(|¶m| { - pos.func - .dfg - .append_ebb_param(ebb, pos.func.dfg.value_type(param)) - }) - .collect(); - - let start_debug = { - let signature = pos.func.import_signature(ir::Signature { - call_conv: self.target_config().default_call_conv, - params: vec![ - ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), - ir::AbiParam::new(ir::types::I32), - ], - returns: vec![], - }); - - let name = ir::ExternalName::testcase("strtdbug"); - - pos.func.import_function(ir::ExtFuncData { - name, - signature, - colocated: false, - }) - }; - - let end_debug = { - let signature = pos.func.import_signature(ir::Signature { - call_conv: self.target_config().default_call_conv, - params: vec![ir::AbiParam::special( - ir::types::I64, - ir::ArgumentPurpose::VMContext, - )], - returns: vec![], - }); - - let name = ir::ExternalName::testcase("enddbug"); - - pos.func.import_function(ir::ExtFuncData { - name, - signature, - colocated: false, - }) - }; - - let i32_print = { - let signature = pos.func.import_signature(ir::Signature { - call_conv: self.target_config().default_call_conv, - params: vec![ - ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), - ir::AbiParam::new(ir::types::I32), - ], - returns: vec![], - }); - - let name = ir::ExternalName::testcase("i32print"); - - pos.func.import_function(ir::ExtFuncData { - name, - signature, - colocated: false, - }) - }; - - let i64_print = { - let signature = pos.func.import_signature(ir::Signature { - call_conv: self.target_config().default_call_conv, - params: vec![ - ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), - ir::AbiParam::new(ir::types::I64), - ], - returns: vec![], - }); - - let name = ir::ExternalName::testcase("i64print"); - - pos.func.import_function(ir::ExtFuncData { - name, - signature, - colocated: false, - }) - }; - - let f32_print = { - let signature = pos.func.import_signature(ir::Signature { - call_conv: self.target_config().default_call_conv, - params: vec![ - ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), - ir::AbiParam::new(ir::types::F32), - ], - returns: vec![], - }); - - let name = ir::ExternalName::testcase("f32print"); - - pos.func.import_function(ir::ExtFuncData { - name, - signature, - colocated: false, - }) - }; - - let f64_print = { - let signature = pos.func.import_signature(ir::Signature { - call_conv: self.target_config().default_call_conv, - params: vec![ - ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), - ir::AbiParam::new(ir::types::F64), - ], - returns: vec![], - }); - - let name = ir::ExternalName::testcase("f64print"); - - pos.func.import_function(ir::ExtFuncData { - name, - signature, - colocated: false, - }) - }; - - let vmctx = pos - .func - .special_param(ir::ArgumentPurpose::VMContext) - .expect("missing vmctx parameter"); - - let func_index = pos.ins().iconst( - ir::types::I32, - func_index.index() as i64 + self.module.info.imported_functions.len() as i64, - ); - - pos.ins().call(start_debug, &[vmctx, func_index]); - - for param in new_ebb_params.iter().cloned() { - match pos.func.dfg.value_type(param) { - ir::types::I32 => pos.ins().call(i32_print, &[vmctx, param]), - ir::types::I64 => pos.ins().call(i64_print, &[vmctx, param]), - ir::types::F32 => pos.ins().call(f32_print, &[vmctx, param]), - ir::types::F64 => pos.ins().call(f64_print, &[vmctx, param]), - _ => unimplemented!(), - }; - } - - pos.ins().call(end_debug, &[vmctx]); - - pos.ins().jump(entry_ebb, new_ebb_params.as_slice()); - } - -// func -// }; + // func + // }; // Add function body to list of function bodies. //self.func_bodies.push(func); @@ -294,7 +311,26 @@ impl ModuleCodeGenerator self, _module_info: &ModuleInfo, ) -> Result<(Caller, Box), CodegenError> { - unimplemented!() + let (func_resolver_builder, handler_data) = + FuncResolverBuilder::new(self.isa, functions, &self.info)?; + + let trampolines = Arc::new(Trampolines::new(self.isa, &self.info)); + + let (func_resolver, backend_cache) = func_resolver_builder.finalize( + &self.info.signatures, + Arc::clone(&trampolines), + handler_data.clone(), + )?; + + let cache_gen = Box::new(CacheGenerator::new( + backend_cache, + Arc::clone(&func_resolver.memory), + )); + + Ok(( + Caller::new(handler_data, trampolines, func_resolver), + cache_gen, + )) } fn feed_signatures(&mut self, signatures: Map) -> Result<(), CodegenError> { @@ -314,8 +350,16 @@ impl ModuleCodeGenerator Ok(()) } - unsafe fn from_cache(_cache: Artifact, _: Token) -> Result { - unimplemented!() + unsafe fn from_cache(cache: Artifact, _: Token) -> Result { + module::Module::from_cache(cache) + } +} + +impl From for CodegenError { + fn from(other: CompileError) -> CodegenError { + CodegenError { + message: format!("{:?}", other), + } } } @@ -540,52 +584,52 @@ impl FuncEnvironment for CraneliftFunctionCodeGenerator { let (table_struct_ptr_ptr, description) = match table_index .local_or_import(&self.env.module.info) - { - LocalOrImport::Local(local_table_index) => { - let tables_base = func.create_global_value(ir::GlobalValueData::Load { - base: vmctx, - offset: (vm::Ctx::offset_tables() as i32).into(), - global_type: ptr_type, - readonly: true, - }); + { + LocalOrImport::Local(local_table_index) => { + let tables_base = func.create_global_value(ir::GlobalValueData::Load { + base: vmctx, + offset: (vm::Ctx::offset_tables() as i32).into(), + global_type: ptr_type, + readonly: true, + }); - let table_struct_ptr_offset = - local_table_index.index() * vm::LocalTable::size() as usize; + let table_struct_ptr_offset = + local_table_index.index() * vm::LocalTable::size() as usize; - let table_struct_ptr_ptr = func.create_global_value(ir::GlobalValueData::IAddImm { - base: tables_base, - offset: (table_struct_ptr_offset as i64).into(), - global_type: ptr_type, - }); + let table_struct_ptr_ptr = func.create_global_value(ir::GlobalValueData::IAddImm { + base: tables_base, + offset: (table_struct_ptr_offset as i64).into(), + global_type: ptr_type, + }); - ( - table_struct_ptr_ptr, - self.env.module.info.tables[local_table_index], - ) - } - LocalOrImport::Import(import_table_index) => { - let tables_base = func.create_global_value(ir::GlobalValueData::Load { - base: vmctx, - offset: (vm::Ctx::offset_imported_tables() as i32).into(), - global_type: ptr_type, - readonly: true, - }); + ( + table_struct_ptr_ptr, + self.env.module.info.tables[local_table_index], + ) + } + LocalOrImport::Import(import_table_index) => { + let tables_base = func.create_global_value(ir::GlobalValueData::Load { + base: vmctx, + offset: (vm::Ctx::offset_imported_tables() as i32).into(), + global_type: ptr_type, + readonly: true, + }); - let table_struct_ptr_offset = - import_table_index.index() * vm::LocalTable::size() as usize; + let table_struct_ptr_offset = + import_table_index.index() * vm::LocalTable::size() as usize; - let table_struct_ptr_ptr = func.create_global_value(ir::GlobalValueData::IAddImm { - base: tables_base, - offset: (table_struct_ptr_offset as i64).into(), - global_type: ptr_type, - }); + let table_struct_ptr_ptr = func.create_global_value(ir::GlobalValueData::IAddImm { + base: tables_base, + offset: (table_struct_ptr_offset as i64).into(), + global_type: ptr_type, + }); - ( - table_struct_ptr_ptr, - self.env.module.info.imported_tables[import_table_index].1, - ) - } - }; + ( + table_struct_ptr_ptr, + self.env.module.info.imported_tables[import_table_index].1, + ) + } + }; let table_struct_ptr = func.create_global_value(ir::GlobalValueData::Load { base: table_struct_ptr_ptr, @@ -983,6 +1027,26 @@ impl FuncEnvironment for CraneliftFunctionCodeGenerator { } } +impl CraneliftFunctionCodeGenerator { + /// Creates a signature with VMContext as the last param + pub fn generate_signature( + &self, + clif_sig_index: cranelift_wasm::SignatureIndex, + ) -> ir::Signature { + // Get signature + let mut signature = self.env.signatures[Converter(clif_sig_index).into()].clone(); + + // Add the vmctx parameter type to it + signature.params.insert( + 0, + ir::AbiParam::special(self.pointer_type(), ir::ArgumentPurpose::VMContext), + ); + + // Return signature + signature + } +} + impl FunctionCodeGenerator for CraneliftFunctionCodeGenerator { fn feed_return(&mut self, _ty: WpType) -> Result<(), CodegenError> { Ok(()) @@ -994,7 +1058,12 @@ impl FunctionCodeGenerator for CraneliftFunctionCodeGenerator { } fn feed_local(&mut self, ty: WpType, n: usize) -> Result<(), CodegenError> { - cranelift_wasm::declare_locals(self.builder.as_mut().unwrap(), n as u32, ty, &mut self.next_local); + cranelift_wasm::declare_locals( + self.builder.as_mut().unwrap(), + n as u32, + ty, + &mut self.next_local, + ); Ok(()) } @@ -1060,7 +1129,6 @@ impl CraneliftModuleCodeGenerator { let sig_index: SigIndex = module_info.func_assoc[Converter(func_index).into()]; Converter(sig_index).into() } - } impl CraneliftFunctionCodeGenerator { @@ -1091,7 +1159,6 @@ fn pointer_type(mcg: &CraneliftModuleCodeGenerator) -> ir::Type { ir::Type::int(u16::from(mcg.isa.frontend_config().pointer_bits())).unwrap() } - /// Declare local variables for the signature parameters that correspond to WebAssembly locals. /// /// Return the number of local variables declared. @@ -1119,4 +1186,3 @@ fn declare_wasm_parameters(builder: &mut FunctionBuilder, entry_block: Ebb) -> u next_local } - diff --git a/lib/clif-backend/src/func_env.rs b/lib/clif-backend/src/func_env.rs index 10f968386..e4112e0d7 100644 --- a/lib/clif-backend/src/func_env.rs +++ b/lib/clif-backend/src/func_env.rs @@ -1,5 +1,4 @@ -use crate::{module::Converter, - module_env::ModuleEnv, relocation::call_names}; +use crate::{module::Converter, module_env::ModuleEnv, relocation::call_names}; use cranelift_codegen::{ cursor::FuncCursor, ir::{self, InstBuilder}, From e34e625009e79e25883ab086b4e8fa0a41ca13ef Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 19 May 2019 11:45:16 -0500 Subject: [PATCH 07/33] Implement MCG.next_function in other backends --- lib/llvm-backend/src/code.rs | 5 ++++- lib/singlepass-backend/src/codegen_x64.rs | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 028207a8c..932ebfc1c 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -2473,7 +2473,10 @@ impl ModuleCodeGenerator Ok(()) } - fn next_function(&mut self) -> Result<&mut LLVMFunctionCodeGenerator, CodegenError> { + fn next_function( + &mut self, + _module_info: &ModuleInfo, + ) -> Result<&mut LLVMFunctionCodeGenerator, CodegenError> { // Creates a new function and returns the function-scope code generator for it. let (context, builder, intrinsics) = match self.functions.last_mut() { Some(x) => ( diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 9aa6c9151..9cb163372 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -300,7 +300,10 @@ impl ModuleCodeGenerator Ok(()) } - fn next_function(&mut self) -> Result<&mut X64FunctionCode, CodegenError> { + fn next_function( + &mut self, + _module_info: &ModuleInfo, + ) -> Result<&mut X64FunctionCode, CodegenError> { let (mut assembler, mut function_labels, br_table_data, breakpoints) = match self.functions.last_mut() { Some(x) => ( From d547beda72985e7577063b3ad77f3eaaa522dd69 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 19 May 2019 13:05:35 -0500 Subject: [PATCH 08/33] Fix self.info compilation error in MCG.finalize --- lib/clif-backend/src/code.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs index 9654aecaf..7b5636ecc 100644 --- a/lib/clif-backend/src/code.rs +++ b/lib/clif-backend/src/code.rs @@ -309,12 +309,12 @@ impl ModuleCodeGenerator fn finalize( self, - _module_info: &ModuleInfo, + module_info: &ModuleInfo, ) -> Result<(Caller, Box), CodegenError> { let (func_resolver_builder, handler_data) = - FuncResolverBuilder::new(self.isa, functions, &self.info)?; + FuncResolverBuilder::new(&self.isa, functions, module_info)?; - let trampolines = Arc::new(Trampolines::new(self.isa, &self.info)); + let trampolines = Arc::new(Trampolines::new(self.isa, module_info)); let (func_resolver, backend_cache) = func_resolver_builder.finalize( &self.info.signatures, From db669f7eb76c9e4ea191733dba2d02de0fba1c91 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 19 May 2019 15:01:25 -0500 Subject: [PATCH 09/33] Fix more codegen compilation issues --- lib/clif-backend/src/code.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs index 7b5636ecc..7d827d940 100644 --- a/lib/clif-backend/src/code.rs +++ b/lib/clif-backend/src/code.rs @@ -301,7 +301,7 @@ impl ModuleCodeGenerator // }; // Add function body to list of function bodies. - //self.func_bodies.push(func); + self.func_bodies.push(func); self.functions.push(func_env); Ok(self.functions.last_mut().unwrap()) @@ -312,12 +312,12 @@ impl ModuleCodeGenerator module_info: &ModuleInfo, ) -> Result<(Caller, Box), CodegenError> { let (func_resolver_builder, handler_data) = - FuncResolverBuilder::new(&self.isa, functions, module_info)?; + FuncResolverBuilder::new(&*self.isa, self.func_bodies, module_info)?; - let trampolines = Arc::new(Trampolines::new(self.isa, module_info)); + let trampolines = Arc::new(Trampolines::new(&*self.isa, module_info)); let (func_resolver, backend_cache) = func_resolver_builder.finalize( - &self.info.signatures, + &self.signatures.as_ref().unwrap(), Arc::clone(&trampolines), handler_data.clone(), )?; From 5db575e8efe9727d9811679b0c3485b8ec06c758 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 19 May 2019 15:22:02 -0500 Subject: [PATCH 10/33] Fix clif_signatures in function codegen --- lib/clif-backend/src/code.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs index 7d827d940..650d31c3b 100644 --- a/lib/clif-backend/src/code.rs +++ b/lib/clif-backend/src/code.rs @@ -107,6 +107,7 @@ impl ModuleCodeGenerator func_body: func, func_translator, next_local: 0, + clif_signatures: self.clif_signatures.clone(), }; let builder = FunctionBuilder::new( &mut func_env.func_body, @@ -368,6 +369,7 @@ pub struct CraneliftFunctionCodeGenerator { builder: Option>, func_translator: FuncTranslator, next_local: usize, + pub clif_signatures: Map, } impl FuncEnvironment for CraneliftFunctionCodeGenerator { @@ -1034,7 +1036,7 @@ impl CraneliftFunctionCodeGenerator { clif_sig_index: cranelift_wasm::SignatureIndex, ) -> ir::Signature { // Get signature - let mut signature = self.env.signatures[Converter(clif_sig_index).into()].clone(); + let mut signature = self.clif_signatures[Converter(clif_sig_index).into()].clone(); // Add the vmctx parameter type to it signature.params.insert( From 04d6ccc95c2c430340dbf2dbfbe46a63995896e6 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Tue, 21 May 2019 23:44:31 -0500 Subject: [PATCH 11/33] Pass module info to FCG as Arc --- lib/clif-backend/src/code.rs | 164 ++++++++++++---------- lib/llvm-backend/src/code.rs | 2 +- lib/runtime-core/src/codegen.rs | 3 +- lib/runtime-core/src/module.rs | 2 +- lib/runtime-core/src/parse.rs | 74 +++++++--- lib/singlepass-backend/src/codegen_x64.rs | 2 +- 6 files changed, 145 insertions(+), 102 deletions(-) diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs index 650d31c3b..dcfcb77dd 100644 --- a/lib/clif-backend/src/code.rs +++ b/lib/clif-backend/src/code.rs @@ -37,6 +37,7 @@ use wasmer_runtime_core::{ }, vm, }; +use wasmparser::Operator; use wasmparser::Type as WpType; pub struct CraneliftModuleCodeGenerator { @@ -75,7 +76,7 @@ impl ModuleCodeGenerator fn next_function( &mut self, - module_info: &ModuleInfo, + module_info: Arc, ) -> Result<&mut CraneliftFunctionCodeGenerator, CodegenError> { // define_function_body( @@ -108,6 +109,8 @@ impl ModuleCodeGenerator func_translator, next_local: 0, clif_signatures: self.clif_signatures.clone(), + module_info: Arc::clone(&module_info), + target_config: self.isa.frontend_config().clone(), }; let builder = FunctionBuilder::new( &mut func_env.func_body, @@ -370,12 +373,14 @@ pub struct CraneliftFunctionCodeGenerator { func_translator: FuncTranslator, next_local: usize, pub clif_signatures: Map, + module_info: Arc, + target_config: isa::TargetFrontendConfig, } impl FuncEnvironment for CraneliftFunctionCodeGenerator { /// Gets configuration information needed for compiling functions fn target_config(&self) -> isa::TargetFrontendConfig { - self.env.target_config() + self.target_config } /// Gets native pointers types. @@ -405,7 +410,7 @@ impl FuncEnvironment for CraneliftFunctionCodeGenerator { let vmctx = func.create_global_value(ir::GlobalValueData::VMContext); let ptr_type = self.pointer_type(); - let local_global_addr = match global_index.local_or_import(&self.env.module.info) { + let local_global_addr = match global_index.local_or_import(&self.module_info) { LocalOrImport::Local(local_global_index) => { let globals_base_addr = func.create_global_value(ir::GlobalValueData::Load { base: vmctx, @@ -457,7 +462,7 @@ impl FuncEnvironment for CraneliftFunctionCodeGenerator { Ok(cranelift_wasm::GlobalVariable::Memory { gv: local_global_addr, offset: (vm::LocalGlobal::offset_data() as i32).into(), - ty: self.env.get_global(clif_global_index).ty, + ty: ptr_type, }) } @@ -475,49 +480,49 @@ impl FuncEnvironment for CraneliftFunctionCodeGenerator { let vmctx = func.create_global_value(ir::GlobalValueData::VMContext); let ptr_type = self.pointer_type(); - let (local_memory_ptr_ptr, description) = - match mem_index.local_or_import(&self.env.module.info) { - LocalOrImport::Local(local_mem_index) => { - let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load { - base: vmctx, - offset: (vm::Ctx::offset_memories() as i32).into(), + let (local_memory_ptr_ptr, description) = match mem_index.local_or_import(&self.module_info) + { + LocalOrImport::Local(local_mem_index) => { + let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load { + base: vmctx, + offset: (vm::Ctx::offset_memories() as i32).into(), + global_type: ptr_type, + readonly: true, + }); + + let local_memory_ptr_offset = + local_mem_index.index() * mem::size_of::<*mut vm::LocalMemory>(); + + ( + func.create_global_value(ir::GlobalValueData::IAddImm { + base: memories_base_addr, + offset: (local_memory_ptr_offset as i64).into(), global_type: ptr_type, - readonly: true, - }); + }), + self.module_info.memories[local_mem_index], + ) + } + LocalOrImport::Import(import_mem_index) => { + let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load { + base: vmctx, + offset: (vm::Ctx::offset_imported_memories() as i32).into(), + global_type: ptr_type, + readonly: true, + }); - let local_memory_ptr_offset = - local_mem_index.index() * mem::size_of::<*mut vm::LocalMemory>(); + let local_memory_ptr_offset = + import_mem_index.index() * mem::size_of::<*mut vm::LocalMemory>(); - ( - func.create_global_value(ir::GlobalValueData::IAddImm { - base: memories_base_addr, - offset: (local_memory_ptr_offset as i64).into(), - global_type: ptr_type, - }), - self.env.module.info.memories[local_mem_index], - ) - } - LocalOrImport::Import(import_mem_index) => { - let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load { - base: vmctx, - offset: (vm::Ctx::offset_imported_memories() as i32).into(), + ( + func.create_global_value(ir::GlobalValueData::IAddImm { + base: memories_base_addr, + offset: (local_memory_ptr_offset as i64).into(), global_type: ptr_type, - readonly: true, - }); - - let local_memory_ptr_offset = - import_mem_index.index() * mem::size_of::<*mut vm::LocalMemory>(); - - ( - func.create_global_value(ir::GlobalValueData::IAddImm { - base: memories_base_addr, - offset: (local_memory_ptr_offset as i64).into(), - global_type: ptr_type, - }), - self.env.module.info.imported_memories[import_mem_index].1, - ) - } - }; + }), + self.module_info.imported_memories[import_mem_index].1, + ) + } + }; let (local_memory_ptr, local_memory_base) = { let local_memory_ptr = func.create_global_value(ir::GlobalValueData::Load { @@ -585,7 +590,7 @@ impl FuncEnvironment for CraneliftFunctionCodeGenerator { let ptr_type = self.pointer_type(); let (table_struct_ptr_ptr, description) = match table_index - .local_or_import(&self.env.module.info) + .local_or_import(&self.module_info) { LocalOrImport::Local(local_table_index) => { let tables_base = func.create_global_value(ir::GlobalValueData::Load { @@ -606,7 +611,7 @@ impl FuncEnvironment for CraneliftFunctionCodeGenerator { ( table_struct_ptr_ptr, - self.env.module.info.tables[local_table_index], + self.module_info.tables[local_table_index], ) } LocalOrImport::Import(import_table_index) => { @@ -628,7 +633,7 @@ impl FuncEnvironment for CraneliftFunctionCodeGenerator { ( table_struct_ptr_ptr, - self.env.module.info.imported_tables[import_table_index].1, + self.module_info.imported_tables[import_table_index].1, ) } }; @@ -688,7 +693,7 @@ impl FuncEnvironment for CraneliftFunctionCodeGenerator { func_index: cranelift_wasm::FuncIndex, ) -> cranelift_wasm::WasmResult { // Get signature of function. - let signature_index = self.env.get_func_type(func_index); + let signature_index = self.get_func_type(func_index); // Create a signature reference from specified signature (with VMContext param added). let signature = func.import_signature(self.generate_signature(signature_index)); @@ -815,7 +820,7 @@ impl FuncEnvironment for CraneliftFunctionCodeGenerator { let callee_index: FuncIndex = Converter(clif_callee_index).into(); let ptr_type = self.pointer_type(); - match callee_index.local_or_import(&self.env.module.info) { + match callee_index.local_or_import(&self.module_info) { LocalOrImport::Local(local_function_index) => { // this is an internal function let vmctx = pos @@ -925,19 +930,19 @@ impl FuncEnvironment for CraneliftFunctionCodeGenerator { let mem_index: MemoryIndex = Converter(clif_mem_index).into(); - let (namespace, mem_index, description) = - match mem_index.local_or_import(&self.env.module.info) { - LocalOrImport::Local(local_mem_index) => ( - call_names::LOCAL_NAMESPACE, - local_mem_index.index(), - self.env.module.info.memories[local_mem_index], - ), - LocalOrImport::Import(import_mem_index) => ( - call_names::IMPORT_NAMESPACE, - import_mem_index.index(), - self.env.module.info.imported_memories[import_mem_index].1, - ), - }; + let (namespace, mem_index, description) = match mem_index.local_or_import(&self.module_info) + { + LocalOrImport::Local(local_mem_index) => ( + call_names::LOCAL_NAMESPACE, + local_mem_index.index(), + self.module_info.memories[local_mem_index], + ), + LocalOrImport::Import(import_mem_index) => ( + call_names::IMPORT_NAMESPACE, + import_mem_index.index(), + self.module_info.imported_memories[import_mem_index].1, + ), + }; let name_index = match description.memory_type() { MemoryType::Dynamic => call_names::DYNAMIC_MEM_GROW, @@ -989,19 +994,19 @@ impl FuncEnvironment for CraneliftFunctionCodeGenerator { let mem_index: MemoryIndex = Converter(clif_mem_index).into(); - let (namespace, mem_index, description) = - match mem_index.local_or_import(&self.env.module.info) { - LocalOrImport::Local(local_mem_index) => ( - call_names::LOCAL_NAMESPACE, - local_mem_index.index(), - self.env.module.info.memories[local_mem_index], - ), - LocalOrImport::Import(import_mem_index) => ( - call_names::IMPORT_NAMESPACE, - import_mem_index.index(), - self.env.module.info.imported_memories[import_mem_index].1, - ), - }; + let (namespace, mem_index, description) = match mem_index.local_or_import(&self.module_info) + { + LocalOrImport::Local(local_mem_index) => ( + call_names::LOCAL_NAMESPACE, + local_mem_index.index(), + self.module_info.memories[local_mem_index], + ), + LocalOrImport::Import(import_mem_index) => ( + call_names::IMPORT_NAMESPACE, + import_mem_index.index(), + self.module_info.imported_memories[import_mem_index].1, + ), + }; let name_index = match description.memory_type() { MemoryType::Dynamic => call_names::DYNAMIC_MEM_SIZE, @@ -1083,7 +1088,8 @@ impl FunctionCodeGenerator for CraneliftFunctionCodeGenerator { let builder = self.builder.as_mut().unwrap(); //let func_environment = FuncEnv::new(); //let state = TranslationState::new(); - translate_operator(*op, builder, &mut self.func_translator.state, self); + let opp = Operator::Unreachable; // Placeholder + translate_operator(opp, builder, &mut self.func_translator.state, self); Ok(()) } @@ -1137,6 +1143,14 @@ impl CraneliftFunctionCodeGenerator { pub fn return_mode(&self) -> ReturnMode { ReturnMode::NormalReturns } + + pub fn get_func_type( + &self, + func_index: cranelift_wasm::FuncIndex, + ) -> cranelift_wasm::SignatureIndex { + let sig_index: SigIndex = self.module_info.func_assoc[Converter(func_index).into()]; + Converter(sig_index).into() + } } /// Creates a signature with VMContext as the last param diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 932ebfc1c..54674923e 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -2475,7 +2475,7 @@ impl ModuleCodeGenerator fn next_function( &mut self, - _module_info: &ModuleInfo, + _module_info: Arc, ) -> Result<&mut LLVMFunctionCodeGenerator, CodegenError> { // Creates a new function and returns the function-scope code generator for it. let (context, builder, intrinsics) = match self.functions.last_mut() { diff --git a/lib/runtime-core/src/codegen.rs b/lib/runtime-core/src/codegen.rs index f04fd0bb5..266811422 100644 --- a/lib/runtime-core/src/codegen.rs +++ b/lib/runtime-core/src/codegen.rs @@ -11,6 +11,7 @@ use smallvec::SmallVec; use std::fmt; use std::fmt::Debug; use std::marker::PhantomData; +use std::sync::Arc; use wasmparser::{Operator, Type as WpType}; #[derive(Debug)] @@ -47,7 +48,7 @@ pub trait ModuleCodeGenerator, RM: RunnableModule, fn check_precondition(&mut self, module_info: &ModuleInfo) -> Result<(), E>; /// Creates a new function and returns the function-scope code generator for it. - fn next_function(&mut self, module_info: &ModuleInfo) -> Result<&mut FCG, E>; + fn next_function(&mut self, module_info: Arc) -> Result<&mut FCG, E>; fn finalize(self, module_info: &ModuleInfo) -> Result<(RM, Box), E>; fn feed_signatures(&mut self, signatures: Map) -> Result<(), E>; diff --git a/lib/runtime-core/src/module.rs b/lib/runtime-core/src/module.rs index 1ffbc71fc..111bc8754 100644 --- a/lib/runtime-core/src/module.rs +++ b/lib/runtime-core/src/module.rs @@ -27,7 +27,7 @@ pub struct ModuleInner { pub info: ModuleInfo, } -#[derive(Clone, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct ModuleInfo { // This are strictly local and the typsystem ensures that. pub memories: Map, diff --git a/lib/runtime-core/src/parse.rs b/lib/runtime-core/src/parse.rs index c827d1fd8..04b38bfcf 100644 --- a/lib/runtime-core/src/parse.rs +++ b/lib/runtime-core/src/parse.rs @@ -16,6 +16,7 @@ use crate::{ }; use hashbrown::HashMap; use std::fmt::Debug; +use std::sync::Arc; use wasmparser::{ BinaryReaderError, ExternalKind, FuncType, ImportSectionEntryType, Operator, Type as WpType, WasmDecoder, @@ -53,7 +54,7 @@ pub fn read_module< middlewares: &mut MiddlewareChain, compiler_config: &CompilerConfig, ) -> Result { - let mut info = ModuleInfo { + let mut info = Arc::new(ModuleInfo { memories: Map::new(), globals: Map::new(), tables: Map::new(), @@ -80,7 +81,7 @@ pub fn read_module< em_symbol_map: compiler_config.symbol_map.clone(), custom_sections: HashMap::new(), - }; + }); let mut parser = wasmparser::ValidatingParser::new( wasm, @@ -103,10 +104,13 @@ pub fn read_module< use wasmparser::ParserState; let state = parser.read(); match *state { - ParserState::EndWasm => break Ok(info), + ParserState::EndWasm => break Ok(Arc::try_unwrap(info).unwrap()), ParserState::Error(err) => Err(LoadError::Parse(err))?, ParserState::TypeSectionEntry(ref ty) => { - info.signatures.push(func_type_to_func_sig(ty)?); + Arc::get_mut(&mut info) + .unwrap() + .signatures + .push(func_type_to_func_sig(ty)?); } ParserState::ImportSectionEntry { module, field, ty } => { let namespace_index = namespace_builder.as_mut().unwrap().register(module); @@ -119,8 +123,11 @@ pub fn read_module< match ty { ImportSectionEntryType::Function(sigindex) => { let sigindex = SigIndex::new(sigindex as usize); - info.imported_functions.push(import_name); - info.func_assoc.push(sigindex); + Arc::get_mut(&mut info) + .unwrap() + .imported_functions + .push(import_name); + Arc::get_mut(&mut info).unwrap().func_assoc.push(sigindex); mcg.feed_import_function() .map_err(|x| LoadError::Codegen(format!("{:?}", x)))?; } @@ -132,7 +139,10 @@ pub fn read_module< maximum: table_ty.limits.maximum, }; - info.imported_tables.push((import_name, table_desc)); + Arc::get_mut(&mut info) + .unwrap() + .imported_tables + .push((import_name, table_desc)); } ImportSectionEntryType::Memory(memory_ty) => { let mem_desc = MemoryDescriptor { @@ -140,20 +150,26 @@ pub fn read_module< maximum: memory_ty.limits.maximum.map(|max| Pages(max)), shared: memory_ty.shared, }; - info.imported_memories.push((import_name, mem_desc)); + Arc::get_mut(&mut info) + .unwrap() + .imported_memories + .push((import_name, mem_desc)); } ImportSectionEntryType::Global(global_ty) => { let global_desc = GlobalDescriptor { mutable: global_ty.mutable, ty: wp_type_to_type(global_ty.content_type)?, }; - info.imported_globals.push((import_name, global_desc)); + Arc::get_mut(&mut info) + .unwrap() + .imported_globals + .push((import_name, global_desc)); } } } ParserState::FunctionSectionEntry(sigindex) => { let sigindex = SigIndex::new(sigindex as usize); - info.func_assoc.push(sigindex); + Arc::get_mut(&mut info).unwrap().func_assoc.push(sigindex); } ParserState::TableSectionEntry(table_ty) => { let table_desc = TableDescriptor { @@ -162,7 +178,7 @@ pub fn read_module< maximum: table_ty.limits.maximum, }; - info.tables.push(table_desc); + Arc::get_mut(&mut info).unwrap().tables.push(table_desc); } ParserState::MemorySectionEntry(memory_ty) => { let mem_desc = MemoryDescriptor { @@ -171,7 +187,7 @@ pub fn read_module< shared: memory_ty.shared, }; - info.memories.push(mem_desc); + Arc::get_mut(&mut info).unwrap().memories.push(mem_desc); } ParserState::ExportSectionEntry { field, kind, index } => { let export_index = match kind { @@ -181,17 +197,23 @@ pub fn read_module< ExternalKind::Global => ExportIndex::Global(GlobalIndex::new(index as usize)), }; - info.exports.insert(field.to_string(), export_index); + Arc::get_mut(&mut info) + .unwrap() + .exports + .insert(field.to_string(), export_index); } ParserState::StartSectionEntry(start_index) => { - info.start_func = Some(FuncIndex::new(start_index as usize)); + Arc::get_mut(&mut info).unwrap().start_func = + Some(FuncIndex::new(start_index as usize)); } ParserState::BeginFunctionBody { .. } => { let id = func_count.wrapping_add(1); func_count = id; if func_count == 0 { - info.namespace_table = namespace_builder.take().unwrap().finish(); - info.name_table = name_builder.take().unwrap().finish(); + Arc::get_mut(&mut info).unwrap().namespace_table = + namespace_builder.take().unwrap().finish(); + Arc::get_mut(&mut info).unwrap().name_table = + name_builder.take().unwrap().finish(); mcg.feed_signatures(info.signatures.clone()) .map_err(|x| LoadError::Codegen(format!("{:?}", x)))?; mcg.feed_function_signatures(info.func_assoc.clone()) @@ -201,7 +223,7 @@ pub fn read_module< } let fcg = mcg - .next_function(&info) + .next_function(Arc::clone(&info)) .map_err(|x| LoadError::Codegen(format!("{:?}", x)))?; middlewares .run( @@ -233,15 +255,15 @@ pub fn read_module< loop { let state = parser.read(); - match *state { - ParserState::Error(err) => return Err(LoadError::Parse(err)), + match state { + ParserState::Error(err) => return Err(LoadError::Parse(*err)), ParserState::FunctionBodyLocals { ref locals } => { for &(count, ty) in locals.iter() { fcg.feed_local(ty, count as usize) .map_err(|x| LoadError::Codegen(format!("{:?}", x)))?; } } - ParserState::CodeOperator(ref op) => { + ParserState::CodeOperator(op) => { if !body_begun { body_begun = true; fcg.begin_body(&info) @@ -299,7 +321,10 @@ pub fn read_module< elements: elements.unwrap(), }; - info.elem_initializers.push(table_init); + Arc::get_mut(&mut info) + .unwrap() + .elem_initializers + .push(table_init); } ParserState::BeginActiveDataSectionEntry(memory_index) => { let memory_index = MemoryIndex::new(memory_index as usize); @@ -330,7 +355,10 @@ pub fn read_module< base: base.unwrap(), data, }; - info.data_initializers.push(data_init); + Arc::get_mut(&mut info) + .unwrap() + .data_initializers + .push(data_init); } ParserState::BeginGlobalSectionEntry(ty) => { let init = loop { @@ -351,7 +379,7 @@ pub fn read_module< let global_init = GlobalInit { desc, init }; - info.globals.push(global_init); + Arc::get_mut(&mut info).unwrap().globals.push(global_init); } _ => {} diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 9cb163372..69937f86e 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -302,7 +302,7 @@ impl ModuleCodeGenerator fn next_function( &mut self, - _module_info: &ModuleInfo, + _module_info: Arc, ) -> Result<&mut X64FunctionCode, CodegenError> { let (mut assembler, mut function_labels, br_table_data, breakpoints) = match self.functions.last_mut() { From 5d3f6ea16731ec56124aef8ce7ddf2aca2b462a7 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Wed, 22 May 2019 17:21:16 -0500 Subject: [PATCH 12/33] Fixing lifetime issues in clif codegen refactor --- lib/clif-backend/src/code.rs | 60 ++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs index dcfcb77dd..d18f53dc0 100644 --- a/lib/clif-backend/src/code.rs +++ b/lib/clif-backend/src/code.rs @@ -13,7 +13,7 @@ use crate::{ }; use cranelift_codegen::entity::EntityRef; -use cranelift_codegen::ir::{self, Ebb, InstBuilder, ValueLabel}; +use cranelift_codegen::ir::{self, Ebb, Function, InstBuilder, ValueLabel}; use cranelift_codegen::timing; use cranelift_codegen::{cursor::FuncCursor, isa}; use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; @@ -105,17 +105,23 @@ impl ModuleCodeGenerator let mut func_env = CraneliftFunctionCodeGenerator { builder: None, - func_body: func, func_translator, next_local: 0, clif_signatures: self.clif_signatures.clone(), module_info: Arc::clone(&module_info), target_config: self.isa.frontend_config().clone(), }; - let builder = FunctionBuilder::new( - &mut func_env.func_body, - &mut func_env.func_translator.func_ctx, - ); + + // Coercing lifetime to accommodate FunctionBuilder new + let func_ref = + unsafe { ::std::mem::transmute::<&mut Function, &'static mut Function>(&mut func) }; + let func_ctx = unsafe { + ::std::mem::transmute::<&mut FunctionBuilderContext, &'static mut FunctionBuilderContext>( + &mut func_env.func_translator.func_ctx, + ) + }; + + let builder = FunctionBuilder::new(func_ref, func_ctx); func_env.builder = Some(builder); let mut builder = func_env.builder.as_mut().unwrap(); @@ -137,7 +143,8 @@ impl ModuleCodeGenerator // function and its return values. let exit_block = builder.create_ebb(); builder.append_ebb_params_for_function_returns(exit_block); - func_translator + func_env + .func_translator .state .initialize(&builder.func.signature, exit_block); @@ -368,7 +375,6 @@ impl From for CodegenError { } pub struct CraneliftFunctionCodeGenerator { - func_body: ir::Function, builder: Option>, func_translator: FuncTranslator, next_local: usize, @@ -377,7 +383,13 @@ pub struct CraneliftFunctionCodeGenerator { target_config: isa::TargetFrontendConfig, } -impl FuncEnvironment for CraneliftFunctionCodeGenerator { +pub struct FunctionEnvironment { + module_info: Arc, + target_config: isa::TargetFrontendConfig, + clif_signatures: Map, +} + +impl FuncEnvironment for FunctionEnvironment { /// Gets configuration information needed for compiling functions fn target_config(&self) -> isa::TargetFrontendConfig { self.target_config @@ -1034,7 +1046,15 @@ impl FuncEnvironment for CraneliftFunctionCodeGenerator { } } -impl CraneliftFunctionCodeGenerator { +impl FunctionEnvironment { + pub fn get_func_type( + &self, + func_index: cranelift_wasm::FuncIndex, + ) -> cranelift_wasm::SignatureIndex { + let sig_index: SigIndex = self.module_info.func_assoc[Converter(func_index).into()]; + Converter(sig_index).into() + } + /// Creates a signature with VMContext as the last param pub fn generate_signature( &self, @@ -1088,8 +1108,18 @@ impl FunctionCodeGenerator for CraneliftFunctionCodeGenerator { let builder = self.builder.as_mut().unwrap(); //let func_environment = FuncEnv::new(); //let state = TranslationState::new(); + let mut function_environment = FunctionEnvironment { + module_info: Arc::clone(&self.module_info), + target_config: self.target_config.clone(), + clif_signatures: self.clif_signatures.clone(), + }; let opp = Operator::Unreachable; // Placeholder - translate_operator(opp, builder, &mut self.func_translator.state, self); + translate_operator( + opp, + builder, + &mut self.func_translator.state, + &mut function_environment, + ); Ok(()) } @@ -1143,14 +1173,6 @@ impl CraneliftFunctionCodeGenerator { pub fn return_mode(&self) -> ReturnMode { ReturnMode::NormalReturns } - - pub fn get_func_type( - &self, - func_index: cranelift_wasm::FuncIndex, - ) -> cranelift_wasm::SignatureIndex { - let sig_index: SigIndex = self.module_info.func_assoc[Converter(func_index).into()]; - Converter(sig_index).into() - } } /// Creates a signature with VMContext as the last param From a713043360551c53b903c37831999de14a9ae123 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Wed, 22 May 2019 23:46:38 -0500 Subject: [PATCH 13/33] Update translate_operator op argument --- Cargo.lock | 14 +++++++------- lib/clif-backend/src/code.rs | 3 +-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 09bb0d4cb..a69746302 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -309,7 +309,7 @@ dependencies = [ [[package]] name = "cranelift-bforest" version = "0.30.0" -source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#f291d01c3a23282e1432c955beb6ef0ab34db7ea" +source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#50eaeb72cfd02e508d9416b599f0882767ced69f" dependencies = [ "cranelift-entity 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", ] @@ -317,7 +317,7 @@ dependencies = [ [[package]] name = "cranelift-codegen" version = "0.30.0" -source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#f291d01c3a23282e1432c955beb6ef0ab34db7ea" +source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#50eaeb72cfd02e508d9416b599f0882767ced69f" dependencies = [ "cranelift-bforest 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", "cranelift-codegen-meta 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", @@ -331,7 +331,7 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" version = "0.30.0" -source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#f291d01c3a23282e1432c955beb6ef0ab34db7ea" +source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#50eaeb72cfd02e508d9416b599f0882767ced69f" dependencies = [ "cranelift-entity 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", ] @@ -339,12 +339,12 @@ dependencies = [ [[package]] name = "cranelift-entity" version = "0.30.0" -source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#f291d01c3a23282e1432c955beb6ef0ab34db7ea" +source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#50eaeb72cfd02e508d9416b599f0882767ced69f" [[package]] name = "cranelift-frontend" version = "0.30.0" -source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#f291d01c3a23282e1432c955beb6ef0ab34db7ea" +source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#50eaeb72cfd02e508d9416b599f0882767ced69f" dependencies = [ "cranelift-codegen 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -354,7 +354,7 @@ dependencies = [ [[package]] name = "cranelift-native" version = "0.30.0" -source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#f291d01c3a23282e1432c955beb6ef0ab34db7ea" +source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#50eaeb72cfd02e508d9416b599f0882767ced69f" dependencies = [ "cranelift-codegen 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -364,7 +364,7 @@ dependencies = [ [[package]] name = "cranelift-wasm" version = "0.30.0" -source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#f291d01c3a23282e1432c955beb6ef0ab34db7ea" +source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#50eaeb72cfd02e508d9416b599f0882767ced69f" dependencies = [ "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-codegen 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs index d18f53dc0..7f526d5a8 100644 --- a/lib/clif-backend/src/code.rs +++ b/lib/clif-backend/src/code.rs @@ -1113,9 +1113,8 @@ impl FunctionCodeGenerator for CraneliftFunctionCodeGenerator { target_config: self.target_config.clone(), clif_signatures: self.clif_signatures.clone(), }; - let opp = Operator::Unreachable; // Placeholder translate_operator( - opp, + op, builder, &mut self.func_translator.state, &mut function_environment, From 9f2e068ff41387cae9e721ee8ca63ff0f22512cd Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Thu, 23 May 2019 20:04:55 -0500 Subject: [PATCH 14/33] Implement conversion of signatures into clif signatures --- lib/clif-backend/src/code.rs | 5 +++- lib/clif-backend/src/module.rs | 43 ++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs index 7f526d5a8..d574da43e 100644 --- a/lib/clif-backend/src/code.rs +++ b/lib/clif-backend/src/code.rs @@ -58,7 +58,7 @@ impl ModuleCodeGenerator let isa = get_isa(); CraneliftModuleCodeGenerator { isa, - clif_signatures: Map::new(), // TODO FIX + clif_signatures: Map::new(), functions: vec![], function_signatures: None, signatures: None, @@ -346,6 +346,9 @@ impl ModuleCodeGenerator fn feed_signatures(&mut self, signatures: Map) -> Result<(), CodegenError> { self.signatures = Some(Arc::new(signatures)); + for (_sig_idx, func_sig) in self.signatures.as_ref().unwrap().iter() { + self.clif_signatures.push(Converter(func_sig).into()); + } Ok(()) } diff --git a/lib/clif-backend/src/module.rs b/lib/clif-backend/src/module.rs index ad0576e59..77660a55f 100644 --- a/lib/clif-backend/src/module.rs +++ b/lib/clif-backend/src/module.rs @@ -9,6 +9,7 @@ use std::sync::Arc; use wasmer_runtime_core::cache::{Artifact, Error as CacheError}; +use cranelift_codegen::isa::CallConv; use wasmer_runtime_core::{ backend::{Backend, CompilerConfig}, error::CompileResult, @@ -168,6 +169,26 @@ impl From> for FuncSig { } } +impl From> for ir::Signature { + fn from(sig: Converter<&FuncSig>) -> Self { + ir::Signature { + params: sig + .0 + .params() + .iter() + .map(|params| Converter(*params).into()) + .collect::>(), + returns: sig + .0 + .returns() + .iter() + .map(|returns| Converter(*returns).into()) + .collect::>(), + call_conv: CallConv::SystemV, // TODO should come from isa + } + } +} + impl From> for Type { fn from(ty: Converter) -> Self { match ty.0 { @@ -179,3 +200,25 @@ impl From> for Type { } } } + +impl From> for ir::Type { + fn from(ty: Converter) -> Self { + match ty.0 { + Type::I32 => ir::types::I32, + Type::I64 => ir::types::I64, + Type::F32 => ir::types::F32, + Type::F64 => ir::types::F64, + } + } +} + +impl From> for ir::AbiParam { + fn from(ty: Converter) -> Self { + match ty.0 { + Type::I32 => ir::AbiParam::new(ir::types::I32), + Type::I64 => ir::AbiParam::new(ir::types::I64), + Type::F32 => ir::AbiParam::new(ir::types::F32), + Type::F64 => ir::AbiParam::new(ir::types::F64), + } + } +} From fc15bc58f62148d9cf0af586da7dce11f5372845 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Fri, 24 May 2019 18:00:07 -0700 Subject: [PATCH 15/33] add mapdir for emscripten; implement getdents, etc. --- Cargo.lock | 1 + lib/emscripten/Cargo.toml | 7 +- lib/emscripten/src/lib.rs | 12 +++- lib/emscripten/src/syscalls/mod.rs | 53 ++++++++------ lib/emscripten/src/syscalls/unix.rs | 95 ++++++++++++++++++++++++-- lib/emscripten/src/syscalls/windows.rs | 6 ++ lib/emscripten/src/utils.rs | 32 +++++++++ src/bin/wasmer.rs | 1 + 8 files changed, 176 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f5504e8c1..72fda4277 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2336,6 +2336,7 @@ version = "0.4.2" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/lib/emscripten/Cargo.toml b/lib/emscripten/Cargo.toml index c9209eb8f..3d9e5df71 100644 --- a/lib/emscripten/Cargo.toml +++ b/lib/emscripten/Cargo.toml @@ -9,14 +9,15 @@ edition = "2018" build = "build/mod.rs" [dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.4.2" } +byteorder = "1" +hashbrown = "0.1" lazy_static = "1.2.0" libc = "0.2.49" -byteorder = "1" time = "0.1.41" wasmer-clif-backend = { path = "../clif-backend", version = "0.4.2" } -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.4.2", optional = true } wasmer-llvm-backend = { path = "../llvm-backend", version = "0.4.2", optional = true } +wasmer-runtime-core = { path = "../runtime-core", version = "0.4.2" } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.4.2", optional = true } [target.'cfg(windows)'.dependencies] rand = "0.6" diff --git a/lib/emscripten/src/lib.rs b/lib/emscripten/src/lib.rs index f60156bab..0e6005755 100644 --- a/lib/emscripten/src/lib.rs +++ b/lib/emscripten/src/lib.rs @@ -3,8 +3,10 @@ #[macro_use] extern crate wasmer_runtime_core; +use hashbrown::HashMap; use lazy_static::lazy_static; use std::cell::UnsafeCell; +use std::path::PathBuf; use std::{f64, ffi::c_void}; use wasmer_runtime_core::{ error::CallResult, @@ -141,10 +143,14 @@ pub struct EmscriptenData<'a> { pub stack_save: Option>, pub stack_restore: Option>, pub set_threw: Option>, + pub mapped_dirs: HashMap, } impl<'a> EmscriptenData<'a> { - pub fn new(instance: &'a mut Instance) -> EmscriptenData<'a> { + pub fn new( + instance: &'a mut Instance, + mapped_dirs: HashMap, + ) -> EmscriptenData<'a> { let malloc = instance.func("_malloc").unwrap(); let free = instance.func("_free").unwrap(); let memalign = instance.func("_memalign").ok(); @@ -272,6 +278,7 @@ impl<'a> EmscriptenData<'a> { stack_save, stack_restore, set_threw, + mapped_dirs, } } } @@ -282,8 +289,9 @@ pub fn run_emscripten_instance( path: &str, args: Vec<&str>, entrypoint: Option, + mapped_dirs: Vec<(String, PathBuf)>, ) -> CallResult<()> { - let mut data = EmscriptenData::new(instance); + let mut data = EmscriptenData::new(instance, mapped_dirs.into_iter().collect()); let data_ptr = &mut data as *mut _ as *mut c_void; instance.context_mut().data = data_ptr; diff --git a/lib/emscripten/src/syscalls/mod.rs b/lib/emscripten/src/syscalls/mod.rs index 5654a1299..18808f0ad 100644 --- a/lib/emscripten/src/syscalls/mod.rs +++ b/lib/emscripten/src/syscalls/mod.rs @@ -10,7 +10,8 @@ pub use self::unix::*; #[cfg(windows)] pub use self::windows::*; -use super::utils::copy_stat_into_wasm; +use crate::utils::{copy_stat_into_wasm, get_cstr_path, get_current_directory}; + use super::varargs::VarArgs; use byteorder::{ByteOrder, LittleEndian}; /// NOTE: TODO: These syscalls only support wasm_32 for now because they assume offsets are u32 @@ -94,13 +95,17 @@ pub fn ___syscall6(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int pub fn ___syscall12(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall12 (chdir) {}", _which); let path_addr: i32 = varargs.get(ctx); - unsafe { - let path_ptr = emscripten_memory_pointer!(ctx.memory(0), path_addr) as *const i8; - let _path = std::ffi::CStr::from_ptr(path_ptr); - let ret = chdir(path_ptr); - debug!("=> path: {:?}, ret: {}", _path, ret); + let path_ptr = emscripten_memory_pointer!(ctx.memory(0), path_addr) as *const i8; + let real_path = get_cstr_path(ctx, path_ptr) + .map(|cstr| cstr.as_c_str() as *const _ as *const i8) + .unwrap_or(path_ptr); + let ret = unsafe { chdir(real_path) }; + debug!( + "=> path: {:?}, ret: {}", + unsafe { std::ffi::CStr::from_ptr(real_path) }, ret - } + ); + ret } pub fn ___syscall10(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { @@ -126,11 +131,17 @@ pub fn ___syscall38(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 { let new_path_addr: u32 = varargs.get(ctx); let old_path = emscripten_memory_pointer!(ctx.memory(0), old_path_addr) as *const i8; let new_path = emscripten_memory_pointer!(ctx.memory(0), new_path_addr) as *const i8; - let result = unsafe { rename(old_path, new_path) }; + let real_old_path = get_cstr_path(ctx, old_path) + .map(|cstr| cstr.as_c_str() as *const _ as *const i8) + .unwrap_or(old_path); + let real_new_path = get_cstr_path(ctx, new_path) + .map(|cstr| cstr.as_c_str() as *const _ as *const i8) + .unwrap_or(new_path); + let result = unsafe { rename(real_old_path, real_new_path) }; debug!( "=> old_path: {}, new_path: {}, result: {}", - unsafe { std::ffi::CStr::from_ptr(old_path).to_str().unwrap() }, - unsafe { std::ffi::CStr::from_ptr(new_path).to_str().unwrap() }, + unsafe { std::ffi::CStr::from_ptr(real_old_path).to_str().unwrap() }, + unsafe { std::ffi::CStr::from_ptr(real_new_path).to_str().unwrap() }, result ); result @@ -141,7 +152,10 @@ pub fn ___syscall40(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int debug!("emscripten::___syscall40 (rmdir)"); let pathname: u32 = varargs.get(ctx); let pathname_addr = emscripten_memory_pointer!(ctx.memory(0), pathname) as *const i8; - unsafe { rmdir(pathname_addr) } + let real_path = get_cstr_path(ctx, pathname_addr) + .map(|cstr| cstr.as_c_str() as *const _ as *const i8) + .unwrap_or(pathname_addr); + unsafe { rmdir(real_path) } } // pipe @@ -224,10 +238,9 @@ pub fn ___syscall110(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { // getcwd pub fn ___syscall183(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 { debug!("emscripten::___syscall183"); - use std::env; let buf_offset: c_int = varargs.get(ctx); let _size: c_int = varargs.get(ctx); - let path = env::current_dir(); + let path = get_current_directory(ctx); let path_string = path.unwrap().display().to_string(); let len = path_string.len(); unsafe { @@ -401,15 +414,18 @@ pub fn ___syscall195(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in let buf: u32 = varargs.get(ctx); let pathname_addr = emscripten_memory_pointer!(ctx.memory(0), pathname) as *const i8; + let real_path = get_cstr_path(ctx, pathname_addr) + .map(|cstr| cstr.as_c_str() as *const _ as *const i8) + .unwrap_or(pathname_addr); unsafe { let mut _stat: stat = std::mem::zeroed(); - let ret = stat(pathname_addr, &mut _stat); + let ret = stat(real_path, &mut _stat); debug!( "=> pathname: {}, buf: {}, path: {} = {}\nlast os error: {}", pathname, buf, - std::ffi::CStr::from_ptr(pathname_addr).to_str().unwrap(), + std::ffi::CStr::from_ptr(real_path).to_str().unwrap(), ret, Error::last_os_error() ); @@ -440,11 +456,6 @@ pub fn ___syscall197(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in 0 } -pub fn ___syscall220(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { - debug!("emscripten::___syscall220"); - -1 -} - // fcntl64 pub fn ___syscall221(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall221 (fcntl64) {}", _which); @@ -457,7 +468,7 @@ pub fn ___syscall221(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in // |FNONBLOCK - 0x04 debug!("=> fd: {}, cmd: {}", _fd, cmd); match cmd { - 2 => 0, + 1 | 2 => 0, 13 | 14 => 0, // pretend file locking worked _ => -1, } diff --git a/lib/emscripten/src/syscalls/unix.rs b/lib/emscripten/src/syscalls/unix.rs index ec8b98f3f..0283a756d 100644 --- a/lib/emscripten/src/syscalls/unix.rs +++ b/lib/emscripten/src/syscalls/unix.rs @@ -43,6 +43,7 @@ use libc::{ pid_t, pread, pwrite, + readdir, // readv, recvfrom, recvmsg, @@ -108,8 +109,11 @@ pub fn ___syscall5(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int let flags: i32 = varargs.get(ctx); let mode: u32 = varargs.get(ctx); let pathname_addr = emscripten_memory_pointer!(ctx.memory(0), pathname) as *const i8; - let _path_str = unsafe { std::ffi::CStr::from_ptr(pathname_addr).to_str().unwrap() }; - let fd = unsafe { open(pathname_addr, flags, mode) }; + let real_path = utils::get_cstr_path(ctx, pathname_addr) + .map(|cstr| cstr.as_c_str() as *const _ as *const i8) + .unwrap_or(pathname_addr); + let _path_str = unsafe { std::ffi::CStr::from_ptr(real_path).to_str().unwrap() }; + let fd = unsafe { open(real_path, flags, mode) }; debug!( "=> pathname: {}, flags: {}, mode: {} = fd: {}\npath: {}\nlast os error: {}", pathname, @@ -160,11 +164,17 @@ pub fn ___syscall83(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int let path2_ptr: c_int = varargs.get(ctx); let path1 = emscripten_memory_pointer!(ctx.memory(0), path1_ptr) as *mut i8; let path2 = emscripten_memory_pointer!(ctx.memory(0), path2_ptr) as *mut i8; - let result = unsafe { symlink(path1, path2) }; + let real_path1 = utils::get_cstr_path(ctx, path1) + .map(|cstr| cstr.as_c_str() as *const _ as *const i8) + .unwrap_or(path1); + let real_path2 = utils::get_cstr_path(ctx, path2) + .map(|cstr| cstr.as_c_str() as *const _ as *const i8) + .unwrap_or(path2); + let result = unsafe { symlink(real_path1, real_path2) }; debug!( "=> path1: {}, path2: {}, result: {}", - unsafe { std::ffi::CStr::from_ptr(path1).to_str().unwrap() }, - unsafe { std::ffi::CStr::from_ptr(path2).to_str().unwrap() }, + unsafe { std::ffi::CStr::from_ptr(real_path1).to_str().unwrap() }, + unsafe { std::ffi::CStr::from_ptr(real_path2).to_str().unwrap() }, result, ); result @@ -796,6 +806,81 @@ pub fn ___syscall196(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 { 0 } +// getdents +// dirent structure is +// i64, i64, u16 (280), i8, [i8; 256] +pub fn ___syscall220(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 { + debug!("emscripten::___syscall220"); + let fd: i32 = varargs.get(ctx); + let dirp_addr: i32 = varargs.get(ctx); + let count: u32 = varargs.get(ctx); + + //let dir = dbg!(emscripten_memory_pointer!(ctx.memory(0), dbg!(fd)) as *mut libc::DIR); + let dirp = emscripten_memory_pointer!(ctx.memory(0), dirp_addr) as *mut u8; + + let mut pos = 0; + // need to persist stream across calls? + + let dir: *mut libc::DIR = unsafe { libc::fdopendir(fd) }; + + dbg!("Start loop"); + while pos + 280 <= dbg!(count) as usize { + dbg!("Pre readdir"); + let dirent = unsafe { readdir(dir) }; + dbg!("post readdir"); + if dirent.is_null() { + break; + } + dbg!("dirent is not null"); + unsafe { + *(dirp.add(pos) as *mut u64) = dbg!((*dirent).d_ino); + #[cfg(not(target_os = "macos"))] + { + *(dirp.add(pos + 8) as *mut u64) = 280 //dbg!((*dirent).d_off); + } + #[cfg(target_os = "macos")] + { + *(dirp.add(pos + 8) as *mut u64) = if pos + 280 > count as usize { + count.into() + } else { + dbg!((*dirent).d_seekoff); + pos as u64 + 56 //280 + }; //; + } + dbg!((*dirent).d_namlen); + *(dirp.add(pos + 16) as *mut u16) = 280; //dbg!((*dirent).d_reclen); + *(dirp.add(pos + 18) as *mut u8) = dbg!((*dirent).d_type); + let upper_bound = std::cmp::min((*dirent).d_reclen, 255) as usize; + let mut i = 0; + while i < upper_bound { + *(dirp.add(pos + 19 + i) as *mut i8) = (*dirent).d_name[i]; + //dbg!((*dirent).d_name[i] as u8 as char); + //dbg!((*dirent).d_name[i] as u8 as char); + i += 1; + } + *(dirp.add(pos + 19 + i) as *mut i8) = 0 as i8; + } + dbg!("dirent written to memory"); + pos += 280; + /*unsafe { + eprintln!( + "{}", + std::ffi::CStr::from_bytes_with_nul_unchecked({ + let arr = *(dirent as *const u8 as *const [u8; 256]); + &arr.to_vec() + .into_iter() + .map(|b| b as u8) + .collect::>()[..20] + }) + .to_str() + .unwrap() + ); + }*/ + } + + dbg!(pos as i32) +} + /// fallocate pub fn ___syscall324(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall324 (fallocate) {}", _which); diff --git a/lib/emscripten/src/syscalls/windows.rs b/lib/emscripten/src/syscalls/windows.rs index a7ac8c11c..a65fa733e 100644 --- a/lib/emscripten/src/syscalls/windows.rs +++ b/lib/emscripten/src/syscalls/windows.rs @@ -251,6 +251,12 @@ pub fn ___syscall196(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { -1 } +// getdents +pub fn ___syscall220(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { + debug!("emscripten::___syscall220"); + -1 +} + /// fchown pub fn ___syscall207(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall207 (fchown) {}", _which); diff --git a/lib/emscripten/src/utils.rs b/lib/emscripten/src/utils.rs index 2ad5b9a40..090ac25d7 100644 --- a/lib/emscripten/src/utils.rs +++ b/lib/emscripten/src/utils.rs @@ -5,6 +5,7 @@ use libc::stat; use std::ffi::CStr; use std::mem::size_of; use std::os::raw::c_char; +use std::path::PathBuf; use std::slice; use wasmer_runtime_core::memory::Memory; use wasmer_runtime_core::{ @@ -204,6 +205,37 @@ pub fn read_string_from_wasm(memory: &Memory, offset: u32) -> String { String::from_utf8_lossy(&v).to_owned().to_string() } +/// This function trys to find an entry in mapdir +/// translating paths into their correct value +pub fn get_cstr_path(ctx: &mut Ctx, path: *const i8) -> Option { + let path_str = unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() }.to_string(); + if let Some(val) = get_emscripten_data(ctx).mapped_dirs.get(&path_str) { + std::ffi::CString::new(val.to_string_lossy().as_bytes()).ok() + } else { + None + } +} + +/// gets the current directory +/// handles mapdir logic +pub fn get_current_directory(ctx: &mut Ctx) -> Option { + if let Some(val) = get_emscripten_data(ctx).mapped_dirs.get(".") { + return Some(val.clone()); + } + std::env::current_dir() + .map(|cwd| { + if let Some(val) = get_emscripten_data(ctx) + .mapped_dirs + .get(&cwd.to_string_lossy().to_string()) + { + val.clone() + } else { + cwd + } + }) + .ok() +} + #[cfg(test)] mod tests { use super::is_emscripten_module; diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 00249ebf9..cd43a5f07 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -458,6 +458,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { }, options.args.iter().map(|arg| arg.as_str()).collect(), options.em_entrypoint.clone(), + mapped_dirs, ) .map_err(|e| format!("{:?}", e))?; } else { From d440776bc080cd31086ef4779af84b1b0e0081e2 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sat, 25 May 2019 18:06:41 -0500 Subject: [PATCH 16/33] Update lifetime of function builder references --- lib/clif-backend/src/code.rs | 97 ++++++++++++++++++--------------- lib/runtime-core/src/codegen.rs | 22 +++++++- lib/runtime-core/src/parse.rs | 5 +- lib/spectests/examples/test.rs | 31 ++++++++++- 4 files changed, 106 insertions(+), 49 deletions(-) diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs index d574da43e..6425415bc 100644 --- a/lib/clif-backend/src/code.rs +++ b/lib/clif-backend/src/code.rs @@ -13,14 +13,18 @@ use crate::{ }; use cranelift_codegen::entity::EntityRef; +use cranelift_codegen::flowgraph::BasicBlock; use cranelift_codegen::ir::{self, Ebb, Function, InstBuilder, ValueLabel}; +use cranelift_codegen::packed_option::ReservedValue; use cranelift_codegen::timing; use cranelift_codegen::{cursor::FuncCursor, isa}; -use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; +use cranelift_entity::packed_option::PackedOption; +use cranelift_frontend::{Block, FunctionBuilder, FunctionBuilderContext, Position, Variable}; use cranelift_wasm::{self, translate_module, FuncTranslator, ModuleEnvironment}; use cranelift_wasm::{get_vmctx_value_label, translate_operator, TranslationState}; use cranelift_wasm::{FuncEnvironment, ReturnMode, WasmError, WasmResult}; use std::mem; +use std::rc::Rc; use std::sync::Arc; use wasmer_runtime_core::error::CompileError; use wasmer_runtime_core::{ @@ -82,12 +86,7 @@ impl ModuleCodeGenerator let mut func_translator = FuncTranslator::new(); - // let func_body = { - - // let mut func_env = FuncEnv::new(self); - - // TODO should func_index come from self.functions? - let func_index = self.func_bodies.next_index(); + let func_index = LocalFuncIndex::new(self.functions.len()); let name = ir::ExternalName::user(0, func_index.index() as u32); let sig = generate_signature( @@ -101,30 +100,25 @@ impl ModuleCodeGenerator let mut func = ir::Function::with_name_signature(name, sig); //func_translator.translate(body_bytes, body_offset, &mut func, &mut func_env)?; - // This clears the `FunctionBuilderContext`. let mut func_env = CraneliftFunctionCodeGenerator { - builder: None, + func, func_translator, next_local: 0, clif_signatures: self.clif_signatures.clone(), module_info: Arc::clone(&module_info), target_config: self.isa.frontend_config().clone(), + position: Position::default(), }; - // Coercing lifetime to accommodate FunctionBuilder new - let func_ref = - unsafe { ::std::mem::transmute::<&mut Function, &'static mut Function>(&mut func) }; - let func_ctx = unsafe { - ::std::mem::transmute::<&mut FunctionBuilderContext, &'static mut FunctionBuilderContext>( - &mut func_env.func_translator.func_ctx, - ) - }; + debug_assert_eq!(func_env.func.dfg.num_ebbs(), 0, "Function must be empty"); + debug_assert_eq!(func_env.func.dfg.num_insts(), 0, "Function must be empty"); - let builder = FunctionBuilder::new(func_ref, func_ctx); - func_env.builder = Some(builder); - - let mut builder = func_env.builder.as_mut().unwrap(); + let mut builder = FunctionBuilder::new( + &mut func_env.func, + &mut func_env.func_translator.func_ctx, + &mut func_env.position, + ); // TODO srcloc //builder.set_srcloc(cur_srcloc(&reader)); @@ -308,12 +302,6 @@ impl ModuleCodeGenerator pos.ins().jump(entry_ebb, new_ebb_params.as_slice()); } - // func - // }; - - // Add function body to list of function bodies. - self.func_bodies.push(func); - self.functions.push(func_env); Ok(self.functions.last_mut().unwrap()) } @@ -322,8 +310,13 @@ impl ModuleCodeGenerator self, module_info: &ModuleInfo, ) -> Result<(Caller, Box), CodegenError> { + let mut func_bodies: Map = Map::new(); + for f in self.functions.into_iter() { + func_bodies.push(f.func); + } + let (func_resolver_builder, handler_data) = - FuncResolverBuilder::new(&*self.isa, self.func_bodies, module_info)?; + FuncResolverBuilder::new(&*self.isa, func_bodies, module_info)?; let trampolines = Arc::new(Trampolines::new(&*self.isa, module_info)); @@ -378,12 +371,13 @@ impl From for CodegenError { } pub struct CraneliftFunctionCodeGenerator { - builder: Option>, + func: Function, func_translator: FuncTranslator, next_local: usize, pub clif_signatures: Map, module_info: Arc, target_config: isa::TargetFrontendConfig, + position: Position, } pub struct FunctionEnvironment { @@ -1088,12 +1082,9 @@ impl FunctionCodeGenerator for CraneliftFunctionCodeGenerator { } fn feed_local(&mut self, ty: WpType, n: usize) -> Result<(), CodegenError> { - cranelift_wasm::declare_locals( - self.builder.as_mut().unwrap(), - n as u32, - ty, - &mut self.next_local, - ); + let mut next_local = self.next_local; + cranelift_wasm::declare_locals(&mut self.builder(), n as u32, ty, &mut next_local); + self.next_local = next_local; Ok(()) } @@ -1108,7 +1099,8 @@ impl FunctionCodeGenerator for CraneliftFunctionCodeGenerator { return Ok(()); } }; - let builder = self.builder.as_mut().unwrap(); + + //let builder = self.builder.as_mut().unwrap(); //let func_environment = FuncEnv::new(); //let state = TranslationState::new(); let mut function_environment = FunctionEnvironment { @@ -1116,19 +1108,30 @@ impl FunctionCodeGenerator for CraneliftFunctionCodeGenerator { target_config: self.target_config.clone(), clif_signatures: self.clif_signatures.clone(), }; - translate_operator( - op, - builder, - &mut self.func_translator.state, - &mut function_environment, + + if (self.func_translator.state.control_stack.is_empty()) { + return Ok(()); + } + + let mut builder = FunctionBuilder::new( + &mut self.func, + &mut self.func_translator.func_ctx, + &mut self.position, ); + let state = &mut self.func_translator.state; + translate_operator(op, &mut builder, state, &mut function_environment); Ok(()) } fn finalize(&mut self) -> Result<(), CodegenError> { let return_mode = self.return_mode(); + + let mut builder = FunctionBuilder::new( + &mut self.func, + &mut self.func_translator.func_ctx, + &mut self.position, + ); let state = &mut self.func_translator.state; - let builder = self.builder.as_mut().unwrap(); // The final `End` operator left us in the exit block where we need to manually add a return // instruction. @@ -1149,7 +1152,7 @@ impl FunctionCodeGenerator for CraneliftFunctionCodeGenerator { // or the end of the function is unreachable. state.stack.clear(); - self.builder.as_mut().unwrap().finalize(); + self.builder().finalize(); Ok(()) } } @@ -1172,6 +1175,14 @@ impl CraneliftModuleCodeGenerator { } impl CraneliftFunctionCodeGenerator { + pub fn builder(&mut self) -> FunctionBuilder { + FunctionBuilder::new( + &mut self.func, + &mut self.func_translator.func_ctx, + &mut self.position, + ) + } + pub fn return_mode(&self) -> ReturnMode { ReturnMode::NormalReturns } diff --git a/lib/runtime-core/src/codegen.rs b/lib/runtime-core/src/codegen.rs index 266811422..5abfa70ca 100644 --- a/lib/runtime-core/src/codegen.rs +++ b/lib/runtime-core/src/codegen.rs @@ -12,6 +12,7 @@ use std::fmt; use std::fmt::Debug; use std::marker::PhantomData; use std::sync::Arc; +use wasmparser::{self, WasmDecoder}; use wasmparser::{Operator, Type as WpType}; #[derive(Debug)] @@ -118,6 +119,20 @@ impl< } } +fn validate(bytes: &[u8]) -> CompileResult<()> { + let mut parser = wasmparser::ValidatingParser::new(bytes, None); + loop { + let state = parser.read(); + match *state { + wasmparser::ParserState::EndWasm => break Ok(()), + wasmparser::ParserState::Error(err) => Err(CompileError::ValidationError { + msg: err.message.to_string(), + })?, + _ => {} + } + } +} + impl< MCG: ModuleCodeGenerator, FCG: FunctionCodeGenerator, @@ -132,6 +147,11 @@ impl< compiler_config: CompilerConfig, _: Token, ) -> CompileResult { + let res = validate(wasm); + if let Err(e) = res { + return Err(e); + } + let mut mcg = MCG::new(); let mut chain = (self.middleware_chain_generator)(); let info = crate::parse::read_module( @@ -149,7 +169,7 @@ impl< Ok(ModuleInner { cache_gen, runnable_module: Box::new(exec_context), - info, + info: Arc::try_unwrap(info).unwrap(), }) } diff --git a/lib/runtime-core/src/parse.rs b/lib/runtime-core/src/parse.rs index 04b38bfcf..2ab4f33ae 100644 --- a/lib/runtime-core/src/parse.rs +++ b/lib/runtime-core/src/parse.rs @@ -53,7 +53,7 @@ pub fn read_module< mcg: &mut MCG, middlewares: &mut MiddlewareChain, compiler_config: &CompilerConfig, -) -> Result { +) -> Result, LoadError> { let mut info = Arc::new(ModuleInfo { memories: Map::new(), globals: Map::new(), @@ -104,7 +104,7 @@ pub fn read_module< use wasmparser::ParserState; let state = parser.read(); match *state { - ParserState::EndWasm => break Ok(Arc::try_unwrap(info).unwrap()), + ParserState::EndWasm => break, ParserState::Error(err) => Err(LoadError::Parse(err))?, ParserState::TypeSectionEntry(ref ty) => { Arc::get_mut(&mut info) @@ -385,6 +385,7 @@ pub fn read_module< _ => {} } } + Ok(info) } pub fn wp_type_to_type(ty: WpType) -> Result { diff --git a/lib/spectests/examples/test.rs b/lib/spectests/examples/test.rs index 6f725e994..8ce199695 100644 --- a/lib/spectests/examples/test.rs +++ b/lib/spectests/examples/test.rs @@ -1,6 +1,6 @@ use wabt::wat2wasm; use wasmer_clif_backend::CraneliftCompiler; -use wasmer_runtime_core::{import::ImportObject, Instance}; +use wasmer_runtime_core::{backend::Compiler, import::ImportObject, Instance}; fn main() { let instance = create_module_1(); @@ -24,13 +24,38 @@ fn create_module_1() -> Instance { (elem (;1;) (i32.const 9) 1)) "#; let wasm_binary = wat2wasm(module_str.as_bytes()).expect("WAST not valid or malformed"); - let module = wasmer_runtime_core::compile_with(&wasm_binary[..], &CraneliftCompiler::new()) + let module = wasmer_runtime_core::compile_with(&wasm_binary[..], &get_compiler()) .expect("WASM can't be compiled"); module .instantiate(&generate_imports()) .expect("WASM can't be instantiated") } +#[cfg(feature = "clif")] +fn get_compiler() -> impl Compiler { + use wasmer_clif_backend::CraneliftCompiler; + CraneliftCompiler::new() +} + +#[cfg(feature = "llvm")] +fn get_compiler() -> impl Compiler { + use wasmer_llvm_backend::LLVMCompiler; + LLVMCompiler::new() +} + +#[cfg(feature = "singlepass")] +fn get_compiler() -> impl Compiler { + use wasmer_singlepass_backend::SinglePassCompiler; + SinglePassCompiler::new() +} + +#[cfg(not(any(feature = "llvm", feature = "clif", feature = "singlepass")))] +fn get_compiler() -> impl Compiler { + panic!("compiler not specified, activate a compiler via features"); + use wasmer_clif_backend::CraneliftCompiler; + CraneliftCompiler::new() +} + static IMPORT_MODULE: &str = r#" (module (type $t0 (func (param i32))) @@ -44,7 +69,7 @@ static IMPORT_MODULE: &str = r#" pub fn generate_imports() -> ImportObject { let wasm_binary = wat2wasm(IMPORT_MODULE.as_bytes()).expect("WAST not valid or malformed"); - let module = wasmer_runtime_core::compile_with(&wasm_binary[..], &CraneliftCompiler::new()) + let module = wasmer_runtime_core::compile_with(&wasm_binary[..], &get_compiler()) .expect("WASM can't be compiled"); let instance = module .instantiate(&ImportObject::new()) From 5da0c4766a61b6d225d6867d2ae4d83d5494616a Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sat, 25 May 2019 19:30:44 -0500 Subject: [PATCH 17/33] Update to Arc> for interior mutability --- lib/clif-backend/src/code.rs | 157 ++++++++++++++++---------------- lib/runtime-core/src/codegen.rs | 8 +- lib/runtime-core/src/parse.rs | 90 +++++++++--------- 3 files changed, 126 insertions(+), 129 deletions(-) diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs index 6425415bc..71412b7c2 100644 --- a/lib/clif-backend/src/code.rs +++ b/lib/clif-backend/src/code.rs @@ -25,7 +25,7 @@ use cranelift_wasm::{get_vmctx_value_label, translate_operator, TranslationState use cranelift_wasm::{FuncEnvironment, ReturnMode, WasmError, WasmResult}; use std::mem; use std::rc::Rc; -use std::sync::Arc; +use std::sync::{Arc, RwLock}; use wasmer_runtime_core::error::CompileError; use wasmer_runtime_core::{ backend::{Backend, CacheGen, Token}, @@ -80,7 +80,7 @@ impl ModuleCodeGenerator fn next_function( &mut self, - module_info: Arc, + module_info: Arc>, ) -> Result<&mut CraneliftFunctionCodeGenerator, CodegenError> { // define_function_body( @@ -92,8 +92,8 @@ impl ModuleCodeGenerator let sig = generate_signature( self, self.get_func_type( - &module_info, - Converter(func_index.convert_up(&module_info)).into(), + &module_info.read().unwrap(), + Converter(func_index.convert_up(&module_info.read().unwrap())).into(), ), ); @@ -375,13 +375,13 @@ pub struct CraneliftFunctionCodeGenerator { func_translator: FuncTranslator, next_local: usize, pub clif_signatures: Map, - module_info: Arc, + module_info: Arc>, target_config: isa::TargetFrontendConfig, position: Position, } pub struct FunctionEnvironment { - module_info: Arc, + module_info: Arc>, target_config: isa::TargetFrontendConfig, clif_signatures: Map, } @@ -419,7 +419,9 @@ impl FuncEnvironment for FunctionEnvironment { let vmctx = func.create_global_value(ir::GlobalValueData::VMContext); let ptr_type = self.pointer_type(); - let local_global_addr = match global_index.local_or_import(&self.module_info) { + let local_global_addr = match global_index + .local_or_import(&self.module_info.read().unwrap()) + { LocalOrImport::Local(local_global_index) => { let globals_base_addr = func.create_global_value(ir::GlobalValueData::Load { base: vmctx, @@ -489,49 +491,49 @@ impl FuncEnvironment for FunctionEnvironment { let vmctx = func.create_global_value(ir::GlobalValueData::VMContext); let ptr_type = self.pointer_type(); - let (local_memory_ptr_ptr, description) = match mem_index.local_or_import(&self.module_info) - { - LocalOrImport::Local(local_mem_index) => { - let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load { - base: vmctx, - offset: (vm::Ctx::offset_memories() as i32).into(), - global_type: ptr_type, - readonly: true, - }); - - let local_memory_ptr_offset = - local_mem_index.index() * mem::size_of::<*mut vm::LocalMemory>(); - - ( - func.create_global_value(ir::GlobalValueData::IAddImm { - base: memories_base_addr, - offset: (local_memory_ptr_offset as i64).into(), + let (local_memory_ptr_ptr, description) = + match mem_index.local_or_import(&self.module_info.read().unwrap()) { + LocalOrImport::Local(local_mem_index) => { + let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load { + base: vmctx, + offset: (vm::Ctx::offset_memories() as i32).into(), global_type: ptr_type, - }), - self.module_info.memories[local_mem_index], - ) - } - LocalOrImport::Import(import_mem_index) => { - let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load { - base: vmctx, - offset: (vm::Ctx::offset_imported_memories() as i32).into(), - global_type: ptr_type, - readonly: true, - }); + readonly: true, + }); - let local_memory_ptr_offset = - import_mem_index.index() * mem::size_of::<*mut vm::LocalMemory>(); + let local_memory_ptr_offset = + local_mem_index.index() * mem::size_of::<*mut vm::LocalMemory>(); - ( - func.create_global_value(ir::GlobalValueData::IAddImm { - base: memories_base_addr, - offset: (local_memory_ptr_offset as i64).into(), + ( + func.create_global_value(ir::GlobalValueData::IAddImm { + base: memories_base_addr, + offset: (local_memory_ptr_offset as i64).into(), + global_type: ptr_type, + }), + self.module_info.read().unwrap().memories[local_mem_index], + ) + } + LocalOrImport::Import(import_mem_index) => { + let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load { + base: vmctx, + offset: (vm::Ctx::offset_imported_memories() as i32).into(), global_type: ptr_type, - }), - self.module_info.imported_memories[import_mem_index].1, - ) - } - }; + readonly: true, + }); + + let local_memory_ptr_offset = + import_mem_index.index() * mem::size_of::<*mut vm::LocalMemory>(); + + ( + func.create_global_value(ir::GlobalValueData::IAddImm { + base: memories_base_addr, + offset: (local_memory_ptr_offset as i64).into(), + global_type: ptr_type, + }), + self.module_info.read().unwrap().imported_memories[import_mem_index].1, + ) + } + }; let (local_memory_ptr, local_memory_base) = { let local_memory_ptr = func.create_global_value(ir::GlobalValueData::Load { @@ -599,7 +601,7 @@ impl FuncEnvironment for FunctionEnvironment { let ptr_type = self.pointer_type(); let (table_struct_ptr_ptr, description) = match table_index - .local_or_import(&self.module_info) + .local_or_import(&self.module_info.read().unwrap()) { LocalOrImport::Local(local_table_index) => { let tables_base = func.create_global_value(ir::GlobalValueData::Load { @@ -620,7 +622,7 @@ impl FuncEnvironment for FunctionEnvironment { ( table_struct_ptr_ptr, - self.module_info.tables[local_table_index], + self.module_info.read().unwrap().tables[local_table_index], ) } LocalOrImport::Import(import_table_index) => { @@ -642,7 +644,7 @@ impl FuncEnvironment for FunctionEnvironment { ( table_struct_ptr_ptr, - self.module_info.imported_tables[import_table_index].1, + self.module_info.read().unwrap().imported_tables[import_table_index].1, ) } }; @@ -829,7 +831,7 @@ impl FuncEnvironment for FunctionEnvironment { let callee_index: FuncIndex = Converter(clif_callee_index).into(); let ptr_type = self.pointer_type(); - match callee_index.local_or_import(&self.module_info) { + match callee_index.local_or_import(&self.module_info.read().unwrap()) { LocalOrImport::Local(local_function_index) => { // this is an internal function let vmctx = pos @@ -939,19 +941,19 @@ impl FuncEnvironment for FunctionEnvironment { let mem_index: MemoryIndex = Converter(clif_mem_index).into(); - let (namespace, mem_index, description) = match mem_index.local_or_import(&self.module_info) - { - LocalOrImport::Local(local_mem_index) => ( - call_names::LOCAL_NAMESPACE, - local_mem_index.index(), - self.module_info.memories[local_mem_index], - ), - LocalOrImport::Import(import_mem_index) => ( - call_names::IMPORT_NAMESPACE, - import_mem_index.index(), - self.module_info.imported_memories[import_mem_index].1, - ), - }; + let (namespace, mem_index, description) = + match mem_index.local_or_import(&self.module_info.read().unwrap()) { + LocalOrImport::Local(local_mem_index) => ( + call_names::LOCAL_NAMESPACE, + local_mem_index.index(), + self.module_info.read().unwrap().memories[local_mem_index], + ), + LocalOrImport::Import(import_mem_index) => ( + call_names::IMPORT_NAMESPACE, + import_mem_index.index(), + self.module_info.read().unwrap().imported_memories[import_mem_index].1, + ), + }; let name_index = match description.memory_type() { MemoryType::Dynamic => call_names::DYNAMIC_MEM_GROW, @@ -1003,19 +1005,19 @@ impl FuncEnvironment for FunctionEnvironment { let mem_index: MemoryIndex = Converter(clif_mem_index).into(); - let (namespace, mem_index, description) = match mem_index.local_or_import(&self.module_info) - { - LocalOrImport::Local(local_mem_index) => ( - call_names::LOCAL_NAMESPACE, - local_mem_index.index(), - self.module_info.memories[local_mem_index], - ), - LocalOrImport::Import(import_mem_index) => ( - call_names::IMPORT_NAMESPACE, - import_mem_index.index(), - self.module_info.imported_memories[import_mem_index].1, - ), - }; + let (namespace, mem_index, description) = + match mem_index.local_or_import(&self.module_info.read().unwrap()) { + LocalOrImport::Local(local_mem_index) => ( + call_names::LOCAL_NAMESPACE, + local_mem_index.index(), + self.module_info.read().unwrap().memories[local_mem_index], + ), + LocalOrImport::Import(import_mem_index) => ( + call_names::IMPORT_NAMESPACE, + import_mem_index.index(), + self.module_info.read().unwrap().imported_memories[import_mem_index].1, + ), + }; let name_index = match description.memory_type() { MemoryType::Dynamic => call_names::DYNAMIC_MEM_SIZE, @@ -1048,7 +1050,8 @@ impl FunctionEnvironment { &self, func_index: cranelift_wasm::FuncIndex, ) -> cranelift_wasm::SignatureIndex { - let sig_index: SigIndex = self.module_info.func_assoc[Converter(func_index).into()]; + let sig_index: SigIndex = + self.module_info.read().unwrap().func_assoc[Converter(func_index).into()]; Converter(sig_index).into() } diff --git a/lib/runtime-core/src/codegen.rs b/lib/runtime-core/src/codegen.rs index 5abfa70ca..1cdd10c2f 100644 --- a/lib/runtime-core/src/codegen.rs +++ b/lib/runtime-core/src/codegen.rs @@ -11,7 +11,7 @@ use smallvec::SmallVec; use std::fmt; use std::fmt::Debug; use std::marker::PhantomData; -use std::sync::Arc; +use std::sync::{Arc, RwLock}; use wasmparser::{self, WasmDecoder}; use wasmparser::{Operator, Type as WpType}; @@ -49,7 +49,7 @@ pub trait ModuleCodeGenerator, RM: RunnableModule, fn check_precondition(&mut self, module_info: &ModuleInfo) -> Result<(), E>; /// Creates a new function and returns the function-scope code generator for it. - fn next_function(&mut self, module_info: Arc) -> Result<&mut FCG, E>; + fn next_function(&mut self, module_info: Arc>) -> Result<&mut FCG, E>; fn finalize(self, module_info: &ModuleInfo) -> Result<(RM, Box), E>; fn feed_signatures(&mut self, signatures: Map) -> Result<(), E>; @@ -162,14 +162,14 @@ impl< &compiler_config, )?; let (exec_context, cache_gen) = - mcg.finalize(&info) + mcg.finalize(&info.read().unwrap()) .map_err(|x| CompileError::InternalError { msg: format!("{:?}", x), })?; Ok(ModuleInner { cache_gen, runnable_module: Box::new(exec_context), - info: Arc::try_unwrap(info).unwrap(), + info: Arc::try_unwrap(info).unwrap().into_inner().unwrap(), }) } diff --git a/lib/runtime-core/src/parse.rs b/lib/runtime-core/src/parse.rs index 2ab4f33ae..dfa5c4eae 100644 --- a/lib/runtime-core/src/parse.rs +++ b/lib/runtime-core/src/parse.rs @@ -16,7 +16,7 @@ use crate::{ }; use hashbrown::HashMap; use std::fmt::Debug; -use std::sync::Arc; +use std::sync::{Arc, RwLock}; use wasmparser::{ BinaryReaderError, ExternalKind, FuncType, ImportSectionEntryType, Operator, Type as WpType, WasmDecoder, @@ -53,8 +53,8 @@ pub fn read_module< mcg: &mut MCG, middlewares: &mut MiddlewareChain, compiler_config: &CompilerConfig, -) -> Result, LoadError> { - let mut info = Arc::new(ModuleInfo { +) -> Result>, LoadError> { + let mut info = Arc::new(RwLock::new(ModuleInfo { memories: Map::new(), globals: Map::new(), tables: Map::new(), @@ -81,7 +81,7 @@ pub fn read_module< em_symbol_map: compiler_config.symbol_map.clone(), custom_sections: HashMap::new(), - }); + })); let mut parser = wasmparser::ValidatingParser::new( wasm, @@ -107,14 +107,14 @@ pub fn read_module< ParserState::EndWasm => break, ParserState::Error(err) => Err(LoadError::Parse(err))?, ParserState::TypeSectionEntry(ref ty) => { - Arc::get_mut(&mut info) + info.write() .unwrap() .signatures .push(func_type_to_func_sig(ty)?); } ParserState::ImportSectionEntry { module, field, ty } => { - let namespace_index = namespace_builder.as_mut().unwrap().register(module); - let name_index = name_builder.as_mut().unwrap().register(field); + let namespace_index = namespace_builder.as_mut().expect("116").register(module); + let name_index = name_builder.as_mut().expect("117").register(field); let import_name = ImportName { namespace_index, name_index, @@ -123,11 +123,8 @@ pub fn read_module< match ty { ImportSectionEntryType::Function(sigindex) => { let sigindex = SigIndex::new(sigindex as usize); - Arc::get_mut(&mut info) - .unwrap() - .imported_functions - .push(import_name); - Arc::get_mut(&mut info).unwrap().func_assoc.push(sigindex); + info.write().unwrap().imported_functions.push(import_name); + info.write().unwrap().func_assoc.push(sigindex); mcg.feed_import_function() .map_err(|x| LoadError::Codegen(format!("{:?}", x)))?; } @@ -139,7 +136,7 @@ pub fn read_module< maximum: table_ty.limits.maximum, }; - Arc::get_mut(&mut info) + info.write() .unwrap() .imported_tables .push((import_name, table_desc)); @@ -150,7 +147,7 @@ pub fn read_module< maximum: memory_ty.limits.maximum.map(|max| Pages(max)), shared: memory_ty.shared, }; - Arc::get_mut(&mut info) + info.write() .unwrap() .imported_memories .push((import_name, mem_desc)); @@ -160,7 +157,7 @@ pub fn read_module< mutable: global_ty.mutable, ty: wp_type_to_type(global_ty.content_type)?, }; - Arc::get_mut(&mut info) + info.write() .unwrap() .imported_globals .push((import_name, global_desc)); @@ -169,7 +166,7 @@ pub fn read_module< } ParserState::FunctionSectionEntry(sigindex) => { let sigindex = SigIndex::new(sigindex as usize); - Arc::get_mut(&mut info).unwrap().func_assoc.push(sigindex); + info.write().unwrap().func_assoc.push(sigindex); } ParserState::TableSectionEntry(table_ty) => { let table_desc = TableDescriptor { @@ -178,7 +175,7 @@ pub fn read_module< maximum: table_ty.limits.maximum, }; - Arc::get_mut(&mut info).unwrap().tables.push(table_desc); + info.write().unwrap().tables.push(table_desc); } ParserState::MemorySectionEntry(memory_ty) => { let mem_desc = MemoryDescriptor { @@ -187,7 +184,7 @@ pub fn read_module< shared: memory_ty.shared, }; - Arc::get_mut(&mut info).unwrap().memories.push(mem_desc); + info.write().unwrap().memories.push(mem_desc); } ParserState::ExportSectionEntry { field, kind, index } => { let export_index = match kind { @@ -197,28 +194,26 @@ pub fn read_module< ExternalKind::Global => ExportIndex::Global(GlobalIndex::new(index as usize)), }; - Arc::get_mut(&mut info) + info.write() .unwrap() .exports .insert(field.to_string(), export_index); } ParserState::StartSectionEntry(start_index) => { - Arc::get_mut(&mut info).unwrap().start_func = - Some(FuncIndex::new(start_index as usize)); + info.write().unwrap().start_func = Some(FuncIndex::new(start_index as usize)); } ParserState::BeginFunctionBody { .. } => { let id = func_count.wrapping_add(1); func_count = id; if func_count == 0 { - Arc::get_mut(&mut info).unwrap().namespace_table = - namespace_builder.take().unwrap().finish(); - Arc::get_mut(&mut info).unwrap().name_table = - name_builder.take().unwrap().finish(); - mcg.feed_signatures(info.signatures.clone()) + info.write().unwrap().namespace_table = + namespace_builder.take().expect("214").finish(); + info.write().unwrap().name_table = name_builder.take().expect("216").finish(); + mcg.feed_signatures(info.read().unwrap().signatures.clone()) .map_err(|x| LoadError::Codegen(format!("{:?}", x)))?; - mcg.feed_function_signatures(info.func_assoc.clone()) + mcg.feed_function_signatures(info.read().unwrap().func_assoc.clone()) .map_err(|x| LoadError::Codegen(format!("{:?}", x)))?; - mcg.check_precondition(&info) + mcg.check_precondition(&info.read().unwrap()) .map_err(|x| LoadError::Codegen(format!("{:?}", x)))?; } @@ -229,19 +224,24 @@ pub fn read_module< .run( Some(fcg), Event::Internal(InternalEvent::FunctionBegin(id as u32)), - &info, + &info.read().unwrap(), ) .map_err(|x| LoadError::Codegen(x))?; - let sig = info + let info_read = info.read().unwrap(); + let sig = info_read .signatures .get( *info + .read() + .unwrap() .func_assoc - .get(FuncIndex::new(id as usize + info.imported_functions.len())) - .unwrap(), + .get(FuncIndex::new( + id as usize + info.read().unwrap().imported_functions.len(), + )) + .expect("242"), ) - .unwrap(); + .expect("244"); for ret in sig.returns() { fcg.feed_return(type_to_wp_type(*ret)) .map_err(|x| LoadError::Codegen(format!("{:?}", x)))?; @@ -266,11 +266,11 @@ pub fn read_module< ParserState::CodeOperator(op) => { if !body_begun { body_begun = true; - fcg.begin_body(&info) + fcg.begin_body(&info.read().unwrap()) .map_err(|x| LoadError::Codegen(format!("{:?}", x)))?; } middlewares - .run(Some(fcg), Event::Wasm(op), &info) + .run(Some(fcg), Event::Wasm(op), &info.read().unwrap()) .map_err(|x| LoadError::Codegen(x))?; } ParserState::EndFunctionBody => break, @@ -281,7 +281,7 @@ pub fn read_module< .run( Some(fcg), Event::Internal(InternalEvent::FunctionEnd), - &info, + &info.read().unwrap(), ) .map_err(|x| LoadError::Codegen(x))?; fcg.finalize() @@ -317,14 +317,11 @@ pub fn read_module< let table_init = TableInitializer { table_index, - base: base.unwrap(), - elements: elements.unwrap(), + base: base.expect("320"), + elements: elements.expect("321"), }; - Arc::get_mut(&mut info) - .unwrap() - .elem_initializers - .push(table_init); + info.write().unwrap().elem_initializers.push(table_init); } ParserState::BeginActiveDataSectionEntry(memory_index) => { let memory_index = MemoryIndex::new(memory_index as usize); @@ -352,13 +349,10 @@ pub fn read_module< let data_init = DataInitializer { memory_index, - base: base.unwrap(), + base: base.expect("355"), data, }; - Arc::get_mut(&mut info) - .unwrap() - .data_initializers - .push(data_init); + info.write().unwrap().data_initializers.push(data_init); } ParserState::BeginGlobalSectionEntry(ty) => { let init = loop { @@ -379,7 +373,7 @@ pub fn read_module< let global_init = GlobalInit { desc, init }; - Arc::get_mut(&mut info).unwrap().globals.push(global_init); + info.write().unwrap().globals.push(global_init); } _ => {} From 6ca311f92df94a5c8d2f3df3466bbe30c5f648b1 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 26 May 2019 11:13:37 -0500 Subject: [PATCH 18/33] Fix compilation errors and warnings --- Cargo.lock | 14 +++--- lib/clif-backend/src/code.rs | 53 ++++++++++------------- lib/llvm-backend/src/code.rs | 4 +- lib/runtime-core/src/parse.rs | 2 +- lib/singlepass-backend/src/codegen_x64.rs | 8 +++- 5 files changed, 38 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a69746302..226c85da6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -309,7 +309,7 @@ dependencies = [ [[package]] name = "cranelift-bforest" version = "0.30.0" -source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#50eaeb72cfd02e508d9416b599f0882767ced69f" +source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#84ec31b0fdfc10db491ef950815ee2961db057cb" dependencies = [ "cranelift-entity 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", ] @@ -317,7 +317,7 @@ dependencies = [ [[package]] name = "cranelift-codegen" version = "0.30.0" -source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#50eaeb72cfd02e508d9416b599f0882767ced69f" +source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#84ec31b0fdfc10db491ef950815ee2961db057cb" dependencies = [ "cranelift-bforest 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", "cranelift-codegen-meta 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", @@ -331,7 +331,7 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" version = "0.30.0" -source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#50eaeb72cfd02e508d9416b599f0882767ced69f" +source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#84ec31b0fdfc10db491ef950815ee2961db057cb" dependencies = [ "cranelift-entity 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", ] @@ -339,12 +339,12 @@ dependencies = [ [[package]] name = "cranelift-entity" version = "0.30.0" -source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#50eaeb72cfd02e508d9416b599f0882767ced69f" +source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#84ec31b0fdfc10db491ef950815ee2961db057cb" [[package]] name = "cranelift-frontend" version = "0.30.0" -source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#50eaeb72cfd02e508d9416b599f0882767ced69f" +source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#84ec31b0fdfc10db491ef950815ee2961db057cb" dependencies = [ "cranelift-codegen 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -354,7 +354,7 @@ dependencies = [ [[package]] name = "cranelift-native" version = "0.30.0" -source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#50eaeb72cfd02e508d9416b599f0882767ced69f" +source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#84ec31b0fdfc10db491ef950815ee2961db057cb" dependencies = [ "cranelift-codegen 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -364,7 +364,7 @@ dependencies = [ [[package]] name = "cranelift-wasm" version = "0.30.0" -source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#50eaeb72cfd02e508d9416b599f0882767ced69f" +source = "git+https://github.com/wasmerio/cranelift.git?branch=wasmer#84ec31b0fdfc10db491ef950815ee2961db057cb" dependencies = [ "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-codegen 0.30.0 (git+https://github.com/wasmerio/cranelift.git?branch=wasmer)", diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs index 71412b7c2..1080fb8bd 100644 --- a/lib/clif-backend/src/code.rs +++ b/lib/clif-backend/src/code.rs @@ -2,29 +2,18 @@ // and subject to the license https://github.com/CraneStation/cranelift/blob/c47ca7bafc8fc48358f1baa72360e61fc1f7a0f2/cranelift-wasm/LICENSE use crate::{ - cache::{BackendCache, CacheGenerator}, - func_env::FuncEnv, - get_isa, module, - module::{Converter, Module}, - relocation::call_names, - resolver::FuncResolverBuilder, - signal::Caller, - trampoline::Trampolines, + cache::CacheGenerator, get_isa, module, module::Converter, relocation::call_names, + resolver::FuncResolverBuilder, signal::Caller, trampoline::Trampolines, }; use cranelift_codegen::entity::EntityRef; -use cranelift_codegen::flowgraph::BasicBlock; -use cranelift_codegen::ir::{self, Ebb, Function, InstBuilder, ValueLabel}; -use cranelift_codegen::packed_option::ReservedValue; -use cranelift_codegen::timing; +use cranelift_codegen::ir::{self, Ebb, Function, InstBuilder}; use cranelift_codegen::{cursor::FuncCursor, isa}; -use cranelift_entity::packed_option::PackedOption; -use cranelift_frontend::{Block, FunctionBuilder, FunctionBuilderContext, Position, Variable}; -use cranelift_wasm::{self, translate_module, FuncTranslator, ModuleEnvironment}; -use cranelift_wasm::{get_vmctx_value_label, translate_operator, TranslationState}; -use cranelift_wasm::{FuncEnvironment, ReturnMode, WasmError, WasmResult}; +use cranelift_frontend::{FunctionBuilder, Position, Variable}; +use cranelift_wasm::{self, FuncTranslator}; +use cranelift_wasm::{get_vmctx_value_label, translate_operator}; +use cranelift_wasm::{FuncEnvironment, ReturnMode, WasmError}; use std::mem; -use std::rc::Rc; use std::sync::{Arc, RwLock}; use wasmer_runtime_core::error::CompileError; use wasmer_runtime_core::{ @@ -35,13 +24,11 @@ use wasmer_runtime_core::{ module::{ModuleInfo, ModuleInner}, structures::{Map, TypedIndex}, types::{ - ElementType, FuncIndex, FuncSig, GlobalDescriptor, GlobalIndex, GlobalInit, Initializer, - LocalFuncIndex, LocalOrImport, MemoryDescriptor, MemoryIndex, SigIndex, TableDescriptor, - TableIndex, Value, + FuncIndex, FuncSig, GlobalIndex, LocalFuncIndex, LocalOrImport, MemoryIndex, SigIndex, + TableIndex, }, vm, }; -use wasmparser::Operator; use wasmparser::Type as WpType; pub struct CraneliftModuleCodeGenerator { @@ -50,11 +37,8 @@ pub struct CraneliftModuleCodeGenerator { pub clif_signatures: Map, function_signatures: Option>>, functions: Vec, - func_bodies: Map, } -pub struct ClifFuncEnv {} - impl ModuleCodeGenerator for CraneliftModuleCodeGenerator { @@ -66,7 +50,6 @@ impl ModuleCodeGenerator functions: vec![], function_signatures: None, signatures: None, - func_bodies: Map::new(), } } @@ -84,7 +67,7 @@ impl ModuleCodeGenerator ) -> Result<&mut CraneliftFunctionCodeGenerator, CodegenError> { // define_function_body( - let mut func_translator = FuncTranslator::new(); + let func_translator = FuncTranslator::new(); let func_index = LocalFuncIndex::new(self.functions.len()); let name = ir::ExternalName::user(0, func_index.index() as u32); @@ -97,7 +80,7 @@ impl ModuleCodeGenerator ), ); - let mut func = ir::Function::with_name_signature(name, sig); + let func = ir::Function::with_name_signature(name, sig); //func_translator.translate(body_bytes, body_offset, &mut func, &mut func_env)?; @@ -370,6 +353,14 @@ impl From for CodegenError { } } +impl From for CodegenError { + fn from(other: WasmError) -> CodegenError { + CodegenError { + message: format!("{:?}", other), + } + } +} + pub struct CraneliftFunctionCodeGenerator { func: Function, func_translator: FuncTranslator, @@ -1086,7 +1077,7 @@ impl FunctionCodeGenerator for CraneliftFunctionCodeGenerator { fn feed_local(&mut self, ty: WpType, n: usize) -> Result<(), CodegenError> { let mut next_local = self.next_local; - cranelift_wasm::declare_locals(&mut self.builder(), n as u32, ty, &mut next_local); + cranelift_wasm::declare_locals(&mut self.builder(), n as u32, ty, &mut next_local)?; self.next_local = next_local; Ok(()) } @@ -1112,7 +1103,7 @@ impl FunctionCodeGenerator for CraneliftFunctionCodeGenerator { clif_signatures: self.clif_signatures.clone(), }; - if (self.func_translator.state.control_stack.is_empty()) { + if self.func_translator.state.control_stack.is_empty() { return Ok(()); } @@ -1122,7 +1113,7 @@ impl FunctionCodeGenerator for CraneliftFunctionCodeGenerator { &mut self.position, ); let state = &mut self.func_translator.state; - translate_operator(op, &mut builder, state, &mut function_environment); + translate_operator(op, &mut builder, state, &mut function_environment)?; Ok(()) } diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 54674923e..bb9f95958 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -8,7 +8,7 @@ use inkwell::{ AddressSpace, FloatPredicate, IntPredicate, }; use smallvec::SmallVec; -use std::sync::Arc; +use std::sync::{Arc, RwLock}; use wasmer_runtime_core::{ backend::{Backend, CacheGen, Token}, cache::{Artifact, Error as CacheError}, @@ -2475,7 +2475,7 @@ impl ModuleCodeGenerator fn next_function( &mut self, - _module_info: Arc, + _module_info: Arc>, ) -> Result<&mut LLVMFunctionCodeGenerator, CodegenError> { // Creates a new function and returns the function-scope code generator for it. let (context, builder, intrinsics) = match self.functions.last_mut() { diff --git a/lib/runtime-core/src/parse.rs b/lib/runtime-core/src/parse.rs index dfa5c4eae..0724005c8 100644 --- a/lib/runtime-core/src/parse.rs +++ b/lib/runtime-core/src/parse.rs @@ -54,7 +54,7 @@ pub fn read_module< middlewares: &mut MiddlewareChain, compiler_config: &CompilerConfig, ) -> Result>, LoadError> { - let mut info = Arc::new(RwLock::new(ModuleInfo { + let info = Arc::new(RwLock::new(ModuleInfo { memories: Map::new(), globals: Map::new(), tables: Map::new(), diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 69937f86e..56e1854f5 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -8,7 +8,11 @@ use dynasmrt::{ }; use smallvec::SmallVec; use std::ptr::NonNull; -use std::{any::Any, collections::HashMap, sync::Arc}; +use std::{ + any::Any, + collections::HashMap, + sync::{Arc, RwLock}, +}; use wasmer_runtime_core::{ backend::{sys::Memory, Backend, CacheGen, RunnableModule, Token}, cache::{Artifact, Error as CacheError}, @@ -302,7 +306,7 @@ impl ModuleCodeGenerator fn next_function( &mut self, - _module_info: Arc, + _module_info: Arc>, ) -> Result<&mut X64FunctionCode, CodegenError> { let (mut assembler, mut function_labels, br_table_data, breakpoints) = match self.functions.last_mut() { From cc4b1871d0fef4a3992d27876991a15f119a21bd Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 26 May 2019 14:15:30 -0500 Subject: [PATCH 19/33] Fix get global type --- lib/clif-backend/src/code.rs | 42 ++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs index 1080fb8bd..034c64963 100644 --- a/lib/clif-backend/src/code.rs +++ b/lib/clif-backend/src/code.rs @@ -410,7 +410,7 @@ impl FuncEnvironment for FunctionEnvironment { let vmctx = func.create_global_value(ir::GlobalValueData::VMContext); let ptr_type = self.pointer_type(); - let local_global_addr = match global_index + let (local_global_addr, ty) = match global_index .local_or_import(&self.module_info.read().unwrap()) { LocalOrImport::Local(local_global_index) => { @@ -429,12 +429,19 @@ impl FuncEnvironment for FunctionEnvironment { global_type: ptr_type, }); - func.create_global_value(ir::GlobalValueData::Load { - base: local_global_ptr_ptr, - offset: 0.into(), - global_type: ptr_type, - readonly: true, - }) + let ty = self.module_info.read().unwrap().globals[local_global_index] + .desc + .ty; + + ( + func.create_global_value(ir::GlobalValueData::Load { + base: local_global_ptr_ptr, + offset: 0.into(), + global_type: ptr_type, + readonly: true, + }), + ty, + ) } LocalOrImport::Import(import_global_index) => { let globals_base_addr = func.create_global_value(ir::GlobalValueData::Load { @@ -452,19 +459,26 @@ impl FuncEnvironment for FunctionEnvironment { global_type: ptr_type, }); - func.create_global_value(ir::GlobalValueData::Load { - base: local_global_ptr_ptr, - offset: 0.into(), - global_type: ptr_type, - readonly: true, - }) + let ty = self.module_info.read().unwrap().imported_globals[import_global_index] + .1 + .ty; + + ( + func.create_global_value(ir::GlobalValueData::Load { + base: local_global_ptr_ptr, + offset: 0.into(), + global_type: ptr_type, + readonly: true, + }), + ty, + ) } }; Ok(cranelift_wasm::GlobalVariable::Memory { gv: local_global_addr, offset: (vm::LocalGlobal::offset_data() as i32).into(), - ty: ptr_type, + ty: Converter(ty).into(), }) } From f42ca84480ae2a6d792478b8fa9a3e36748a2ccf Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 26 May 2019 14:44:17 -0500 Subject: [PATCH 20/33] Add calling convention to function signatures --- lib/clif-backend/src/code.rs | 21 ++++++++++++++++++++- lib/clif-backend/src/module.rs | 21 --------------------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs index 034c64963..303070282 100644 --- a/lib/clif-backend/src/code.rs +++ b/lib/clif-backend/src/code.rs @@ -8,6 +8,7 @@ use crate::{ use cranelift_codegen::entity::EntityRef; use cranelift_codegen::ir::{self, Ebb, Function, InstBuilder}; +use cranelift_codegen::isa::CallConv; use cranelift_codegen::{cursor::FuncCursor, isa}; use cranelift_frontend::{FunctionBuilder, Position, Variable}; use cranelift_wasm::{self, FuncTranslator}; @@ -322,8 +323,10 @@ impl ModuleCodeGenerator fn feed_signatures(&mut self, signatures: Map) -> Result<(), CodegenError> { self.signatures = Some(Arc::new(signatures)); + let call_conv = self.isa.frontend_config().default_call_conv; for (_sig_idx, func_sig) in self.signatures.as_ref().unwrap().iter() { - self.clif_signatures.push(Converter(func_sig).into()); + self.clif_signatures + .push(convert_func_sig(func_sig, call_conv)); } Ok(()) } @@ -345,6 +348,22 @@ impl ModuleCodeGenerator } } +fn convert_func_sig(sig: &FuncSig, call_conv: CallConv) -> ir::Signature { + ir::Signature { + params: sig + .params() + .iter() + .map(|params| Converter(*params).into()) + .collect::>(), + returns: sig + .returns() + .iter() + .map(|returns| Converter(*returns).into()) + .collect::>(), + call_conv, + } +} + impl From for CodegenError { fn from(other: CompileError) -> CodegenError { CodegenError { diff --git a/lib/clif-backend/src/module.rs b/lib/clif-backend/src/module.rs index 77660a55f..94593f1c7 100644 --- a/lib/clif-backend/src/module.rs +++ b/lib/clif-backend/src/module.rs @@ -9,7 +9,6 @@ use std::sync::Arc; use wasmer_runtime_core::cache::{Artifact, Error as CacheError}; -use cranelift_codegen::isa::CallConv; use wasmer_runtime_core::{ backend::{Backend, CompilerConfig}, error::CompileResult, @@ -169,26 +168,6 @@ impl From> for FuncSig { } } -impl From> for ir::Signature { - fn from(sig: Converter<&FuncSig>) -> Self { - ir::Signature { - params: sig - .0 - .params() - .iter() - .map(|params| Converter(*params).into()) - .collect::>(), - returns: sig - .0 - .returns() - .iter() - .map(|returns| Converter(*returns).into()) - .collect::>(), - call_conv: CallConv::SystemV, // TODO should come from isa - } - } -} - impl From> for Type { fn from(ty: Converter) -> Self { match ty.0 { From bf1cfc257800cca8a05cc1d1b6485aab06422d08 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 26 May 2019 22:17:49 -0500 Subject: [PATCH 21/33] Re-enable deny warnings in clif backend --- lib/clif-backend/src/code.rs | 2 +- lib/clif-backend/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs index 303070282..3a4b48016 100644 --- a/lib/clif-backend/src/code.rs +++ b/lib/clif-backend/src/code.rs @@ -115,7 +115,7 @@ impl ModuleCodeGenerator // `environ`. The callback functions may need to insert things in the entry block. builder.ensure_inserted_ebb(); - let num_params = declare_wasm_parameters(&mut builder, entry_block); + declare_wasm_parameters(&mut builder, entry_block); // Set up the translation state with a single pushed control block representing the whole // function and its return values. diff --git a/lib/clif-backend/src/lib.rs b/lib/clif-backend/src/lib.rs index 82f67a39d..0ae4e9a59 100644 --- a/lib/clif-backend/src/lib.rs +++ b/lib/clif-backend/src/lib.rs @@ -1,4 +1,4 @@ -#![deny(unused_unsafe, unreachable_patterns)] +#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)] mod cache; mod code; From 3f0cafce5cd54381470c2495c26b9d8d9424e24a Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 26 May 2019 22:32:11 -0500 Subject: [PATCH 22/33] Remove old Cranelift compiler code --- lib/clif-backend/src/func_env.rs | 700 ----------------------------- lib/clif-backend/src/lib.rs | 91 ---- lib/clif-backend/src/module.rs | 78 +--- lib/clif-backend/src/module_env.rs | 557 ----------------------- 4 files changed, 5 insertions(+), 1421 deletions(-) delete mode 100644 lib/clif-backend/src/func_env.rs delete mode 100644 lib/clif-backend/src/module_env.rs diff --git a/lib/clif-backend/src/func_env.rs b/lib/clif-backend/src/func_env.rs deleted file mode 100644 index e4112e0d7..000000000 --- a/lib/clif-backend/src/func_env.rs +++ /dev/null @@ -1,700 +0,0 @@ -use crate::{module::Converter, module_env::ModuleEnv, relocation::call_names}; -use cranelift_codegen::{ - cursor::FuncCursor, - ir::{self, InstBuilder}, - isa, -}; -use cranelift_entity::EntityRef; -use cranelift_wasm::{self, FuncEnvironment, ModuleEnvironment}; -use std::mem; -use wasmer_runtime_core::{ - memory::MemoryType, - structures::TypedIndex, - types::{FuncIndex, GlobalIndex, LocalOrImport, MemoryIndex, TableIndex}, - vm, -}; - -pub struct FuncEnv<'env, 'module, 'isa> { - env: &'env ModuleEnv<'module, 'isa>, -} - -impl<'env, 'module, 'isa> FuncEnv<'env, 'module, 'isa> { - pub fn new(env: &'env ModuleEnv<'module, 'isa>) -> Self { - Self { env } - } - - /// Creates a signature with VMContext as the last param - pub fn generate_signature( - &self, - clif_sig_index: cranelift_wasm::SignatureIndex, - ) -> ir::Signature { - // Get signature - let mut signature = self.env.signatures[Converter(clif_sig_index).into()].clone(); - - // Add the vmctx parameter type to it - signature.params.insert( - 0, - ir::AbiParam::special(self.pointer_type(), ir::ArgumentPurpose::VMContext), - ); - - // Return signature - signature - } -} - -impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> { - /// Gets configuration information needed for compiling functions - fn target_config(&self) -> isa::TargetFrontendConfig { - self.env.target_config() - } - - /// Gets native pointers types. - /// - /// `I64` on 64-bit arch; `I32` on 32-bit arch. - fn pointer_type(&self) -> ir::Type { - ir::Type::int(u16::from(self.target_config().pointer_bits())).unwrap() - } - - /// Gets the size of a native pointer in bytes. - fn pointer_bytes(&self) -> u8 { - self.target_config().pointer_bytes() - } - - /// Sets up the necessary preamble definitions in `func` to access the global identified - /// by `index`. - /// - /// The index space covers both imported and locally declared globals. - fn make_global( - &mut self, - func: &mut ir::Function, - clif_global_index: cranelift_wasm::GlobalIndex, - ) -> cranelift_wasm::WasmResult { - let global_index: GlobalIndex = Converter(clif_global_index).into(); - - // Create VMContext value. - let vmctx = func.create_global_value(ir::GlobalValueData::VMContext); - let ptr_type = self.pointer_type(); - - let local_global_addr = match global_index.local_or_import(&self.env.module.info) { - LocalOrImport::Local(local_global_index) => { - let globals_base_addr = func.create_global_value(ir::GlobalValueData::Load { - base: vmctx, - offset: (vm::Ctx::offset_globals() as i32).into(), - global_type: ptr_type, - readonly: true, - }); - - let offset = local_global_index.index() * mem::size_of::<*mut vm::LocalGlobal>(); - - let local_global_ptr_ptr = func.create_global_value(ir::GlobalValueData::IAddImm { - base: globals_base_addr, - offset: (offset as i64).into(), - global_type: ptr_type, - }); - - func.create_global_value(ir::GlobalValueData::Load { - base: local_global_ptr_ptr, - offset: 0.into(), - global_type: ptr_type, - readonly: true, - }) - } - LocalOrImport::Import(import_global_index) => { - let globals_base_addr = func.create_global_value(ir::GlobalValueData::Load { - base: vmctx, - offset: (vm::Ctx::offset_imported_globals() as i32).into(), - global_type: ptr_type, - readonly: true, - }); - - let offset = import_global_index.index() * mem::size_of::<*mut vm::LocalGlobal>(); - - let local_global_ptr_ptr = func.create_global_value(ir::GlobalValueData::IAddImm { - base: globals_base_addr, - offset: (offset as i64).into(), - global_type: ptr_type, - }); - - func.create_global_value(ir::GlobalValueData::Load { - base: local_global_ptr_ptr, - offset: 0.into(), - global_type: ptr_type, - readonly: true, - }) - } - }; - - Ok(cranelift_wasm::GlobalVariable::Memory { - gv: local_global_addr, - offset: (vm::LocalGlobal::offset_data() as i32).into(), - ty: self.env.get_global(clif_global_index).ty, - }) - } - - /// Sets up the necessary preamble definitions in `func` to access the linear memory identified - /// by `index`. - /// - /// The index space covers both imported and locally declared memories. - fn make_heap( - &mut self, - func: &mut ir::Function, - clif_mem_index: cranelift_wasm::MemoryIndex, - ) -> cranelift_wasm::WasmResult { - let mem_index: MemoryIndex = Converter(clif_mem_index).into(); - // Create VMContext value. - let vmctx = func.create_global_value(ir::GlobalValueData::VMContext); - let ptr_type = self.pointer_type(); - - let (local_memory_ptr_ptr, description) = - match mem_index.local_or_import(&self.env.module.info) { - LocalOrImport::Local(local_mem_index) => { - let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load { - base: vmctx, - offset: (vm::Ctx::offset_memories() as i32).into(), - global_type: ptr_type, - readonly: true, - }); - - let local_memory_ptr_offset = - local_mem_index.index() * mem::size_of::<*mut vm::LocalMemory>(); - - ( - func.create_global_value(ir::GlobalValueData::IAddImm { - base: memories_base_addr, - offset: (local_memory_ptr_offset as i64).into(), - global_type: ptr_type, - }), - self.env.module.info.memories[local_mem_index], - ) - } - LocalOrImport::Import(import_mem_index) => { - let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load { - base: vmctx, - offset: (vm::Ctx::offset_imported_memories() as i32).into(), - global_type: ptr_type, - readonly: true, - }); - - let local_memory_ptr_offset = - import_mem_index.index() * mem::size_of::<*mut vm::LocalMemory>(); - - ( - func.create_global_value(ir::GlobalValueData::IAddImm { - base: memories_base_addr, - offset: (local_memory_ptr_offset as i64).into(), - global_type: ptr_type, - }), - self.env.module.info.imported_memories[import_mem_index].1, - ) - } - }; - - let (local_memory_ptr, local_memory_base) = { - let local_memory_ptr = func.create_global_value(ir::GlobalValueData::Load { - base: local_memory_ptr_ptr, - offset: 0.into(), - global_type: ptr_type, - readonly: true, - }); - - ( - local_memory_ptr, - func.create_global_value(ir::GlobalValueData::Load { - base: local_memory_ptr, - offset: (vm::LocalMemory::offset_base() as i32).into(), - global_type: ptr_type, - readonly: false, - }), - ) - }; - - match description.memory_type() { - mem_type @ MemoryType::Dynamic => { - let local_memory_bound = func.create_global_value(ir::GlobalValueData::Load { - base: local_memory_ptr, - offset: (vm::LocalMemory::offset_bound() as i32).into(), - global_type: ptr_type, - readonly: false, - }); - - Ok(func.create_heap(ir::HeapData { - base: local_memory_base, - min_size: (description.minimum.bytes().0 as u64).into(), - offset_guard_size: mem_type.guard_size().into(), - style: ir::HeapStyle::Dynamic { - bound_gv: local_memory_bound, - }, - index_type: ir::types::I32, - })) - } - mem_type @ MemoryType::Static | mem_type @ MemoryType::SharedStatic => Ok(func - .create_heap(ir::HeapData { - base: local_memory_base, - min_size: (description.minimum.bytes().0 as u64).into(), - offset_guard_size: mem_type.guard_size().into(), - style: ir::HeapStyle::Static { - bound: mem_type.bounds().unwrap().into(), - }, - index_type: ir::types::I32, - })), - } - } - - /// Sets up the necessary preamble definitions in `func` to access the table identified - /// by `index`. - /// - /// The index space covers both imported and locally declared tables. - fn make_table( - &mut self, - func: &mut ir::Function, - clif_table_index: cranelift_wasm::TableIndex, - ) -> cranelift_wasm::WasmResult { - let table_index: TableIndex = Converter(clif_table_index).into(); - // Create VMContext value. - let vmctx = func.create_global_value(ir::GlobalValueData::VMContext); - let ptr_type = self.pointer_type(); - - let (table_struct_ptr_ptr, description) = match table_index - .local_or_import(&self.env.module.info) - { - LocalOrImport::Local(local_table_index) => { - let tables_base = func.create_global_value(ir::GlobalValueData::Load { - base: vmctx, - offset: (vm::Ctx::offset_tables() as i32).into(), - global_type: ptr_type, - readonly: true, - }); - - let table_struct_ptr_offset = - local_table_index.index() * vm::LocalTable::size() as usize; - - let table_struct_ptr_ptr = func.create_global_value(ir::GlobalValueData::IAddImm { - base: tables_base, - offset: (table_struct_ptr_offset as i64).into(), - global_type: ptr_type, - }); - - ( - table_struct_ptr_ptr, - self.env.module.info.tables[local_table_index], - ) - } - LocalOrImport::Import(import_table_index) => { - let tables_base = func.create_global_value(ir::GlobalValueData::Load { - base: vmctx, - offset: (vm::Ctx::offset_imported_tables() as i32).into(), - global_type: ptr_type, - readonly: true, - }); - - let table_struct_ptr_offset = - import_table_index.index() * vm::LocalTable::size() as usize; - - let table_struct_ptr_ptr = func.create_global_value(ir::GlobalValueData::IAddImm { - base: tables_base, - offset: (table_struct_ptr_offset as i64).into(), - global_type: ptr_type, - }); - - ( - table_struct_ptr_ptr, - self.env.module.info.imported_tables[import_table_index].1, - ) - } - }; - - let table_struct_ptr = func.create_global_value(ir::GlobalValueData::Load { - base: table_struct_ptr_ptr, - offset: 0.into(), - global_type: ptr_type, - readonly: true, - }); - - let table_base = func.create_global_value(ir::GlobalValueData::Load { - base: table_struct_ptr, - offset: (vm::LocalTable::offset_base() as i32).into(), - global_type: ptr_type, - // The table can reallocate, so the ptr can't be readonly. - readonly: false, - }); - - let table_count = func.create_global_value(ir::GlobalValueData::Load { - base: table_struct_ptr, - offset: (vm::LocalTable::offset_count() as i32).into(), - global_type: ptr_type, - // The table length can change, so it can't be readonly. - readonly: false, - }); - - Ok(func.create_table(ir::TableData { - base_gv: table_base, - min_size: (description.minimum as u64).into(), - bound_gv: table_count, - element_size: (vm::Anyfunc::size() as u64).into(), - index_type: ir::types::I32, - })) - } - - /// Sets up a signature definition in `func`'s preamble. - /// - /// Signature may contain additional argument, but arguments marked as ArgumentPurpose::Normal` - /// must correspond to the arguments in the wasm signature - fn make_indirect_sig( - &mut self, - func: &mut ir::Function, - clif_sig_index: cranelift_wasm::SignatureIndex, - ) -> cranelift_wasm::WasmResult { - // Create a signature reference out of specified signature (with VMContext param added). - Ok(func.import_signature(self.generate_signature(clif_sig_index))) - } - - /// Sets up an external function definition in the preamble of `func` that can be used to - /// directly call the function `index`. - /// - /// The index space covers both imported functions and functions defined in the current module. - fn make_direct_func( - &mut self, - func: &mut ir::Function, - func_index: cranelift_wasm::FuncIndex, - ) -> cranelift_wasm::WasmResult { - // Get signature of function. - let signature_index = self.env.get_func_type(func_index); - - // Create a signature reference from specified signature (with VMContext param added). - let signature = func.import_signature(self.generate_signature(signature_index)); - - // Get name of function. - let name = ir::ExternalName::user(0, func_index.as_u32()); - - // Create function reference from fuction data. - Ok(func.import_function(ir::ExtFuncData { - name, - signature, - // Make this colocated so all calls between local functions are relative. - colocated: true, - })) - } - - /// Generates an indirect call IR with `callee` and `call_args`. - /// - /// Inserts instructions at `pos` to the function `callee` in the table - /// `table_index` with WebAssembly signature `sig_index` - #[cfg_attr(feature = "cargo-clippy", allow(clippy::too_many_arguments))] - fn translate_call_indirect( - &mut self, - mut pos: FuncCursor, - _table_index: cranelift_wasm::TableIndex, - table: ir::Table, - clif_sig_index: cranelift_wasm::SignatureIndex, - sig_ref: ir::SigRef, - callee: ir::Value, - call_args: &[ir::Value], - ) -> cranelift_wasm::WasmResult { - // Get the pointer type based on machine's pointer size. - let ptr_type = self.pointer_type(); - - // The `callee` value is an index into a table of Anyfunc structures. - let entry_addr = pos.ins().table_addr(ptr_type, table, callee, 0); - - let mflags = ir::MemFlags::trusted(); - - let func_ptr = pos.ins().load( - ptr_type, - mflags, - entry_addr, - vm::Anyfunc::offset_func() as i32, - ); - - let vmctx_ptr = { - let loaded_vmctx_ptr = pos.ins().load( - ptr_type, - mflags, - entry_addr, - vm::Anyfunc::offset_vmctx() as i32, - ); - - let argument_vmctx_ptr = pos - .func - .special_param(ir::ArgumentPurpose::VMContext) - .expect("missing vmctx parameter"); - - // If the loaded vmctx ptr is zero, use the caller vmctx, else use the callee (loaded) vmctx. - pos.ins() - .select(loaded_vmctx_ptr, loaded_vmctx_ptr, argument_vmctx_ptr) - }; - - let found_sig = pos.ins().load( - ir::types::I32, - mflags, - entry_addr, - vm::Anyfunc::offset_sig_id() as i32, - ); - - pos.ins().trapz(func_ptr, ir::TrapCode::IndirectCallToNull); - - let expected_sig = { - let sig_index_global = pos.func.create_global_value(ir::GlobalValueData::Symbol { - // The index of the `ExternalName` is the undeduplicated, signature index. - name: ir::ExternalName::user( - call_names::SIG_NAMESPACE, - clif_sig_index.index() as u32, - ), - offset: 0.into(), - colocated: false, - }); - - pos.ins().symbol_value(ir::types::I64, sig_index_global) - - // let dynamic_sigindices_array_ptr = pos.ins().load( - // ptr_type, - // mflags, - - // ) - - // let expected_sig = pos.ins().iconst(ir::types::I32, sig_index.index() as i64); - - // self.env.deduplicated[clif_sig_index] - }; - - let not_equal_flags = pos.ins().ifcmp(found_sig, expected_sig); - - pos.ins().trapif( - ir::condcodes::IntCC::NotEqual, - not_equal_flags, - ir::TrapCode::BadSignature, - ); - - // Build a value list for the indirect call instruction containing the call_args - // and the vmctx parameter. - let mut args = Vec::with_capacity(call_args.len() + 1); - args.push(vmctx_ptr); - args.extend(call_args.iter().cloned()); - - Ok(pos.ins().call_indirect(sig_ref, func_ptr, &args)) - } - - /// Generates a call IR with `callee` and `call_args` and inserts it at `pos` - /// TODO: add support for imported functions - fn translate_call( - &mut self, - mut pos: FuncCursor, - clif_callee_index: cranelift_wasm::FuncIndex, - callee: ir::FuncRef, - call_args: &[ir::Value], - ) -> cranelift_wasm::WasmResult { - let callee_index: FuncIndex = Converter(clif_callee_index).into(); - let ptr_type = self.pointer_type(); - - match callee_index.local_or_import(&self.env.module.info) { - LocalOrImport::Local(local_function_index) => { - // this is an internal function - let vmctx = pos - .func - .special_param(ir::ArgumentPurpose::VMContext) - .expect("missing vmctx parameter"); - - let mut args = Vec::with_capacity(call_args.len() + 1); - args.push(vmctx); - args.extend(call_args.iter().cloned()); - - let sig_ref = pos.func.dfg.ext_funcs[callee].signature; - let function_ptr = { - let mflags = ir::MemFlags::trusted(); - - let function_array_ptr = pos.ins().load( - ptr_type, - mflags, - vmctx, - vm::Ctx::offset_local_functions() as i32, - ); - - pos.ins().load( - ptr_type, - mflags, - function_array_ptr, - (local_function_index.index() as i32) * 8, - ) - }; - - Ok(pos.ins().call_indirect(sig_ref, function_ptr, &args)) - } - LocalOrImport::Import(imported_func_index) => { - // this is an imported function - let vmctx = pos.func.create_global_value(ir::GlobalValueData::VMContext); - - let imported_funcs = pos.func.create_global_value(ir::GlobalValueData::Load { - base: vmctx, - offset: (vm::Ctx::offset_imported_funcs() as i32).into(), - global_type: ptr_type, - readonly: true, - }); - - let imported_func_offset = - imported_func_index.index() * vm::ImportedFunc::size() as usize; - - let imported_func_struct_addr = - pos.func.create_global_value(ir::GlobalValueData::IAddImm { - base: imported_funcs, - offset: (imported_func_offset as i64).into(), - global_type: ptr_type, - }); - - let imported_func_addr = pos.func.create_global_value(ir::GlobalValueData::Load { - base: imported_func_struct_addr, - offset: (vm::ImportedFunc::offset_func() as i32).into(), - global_type: ptr_type, - readonly: true, - }); - - let imported_vmctx_addr = pos.func.create_global_value(ir::GlobalValueData::Load { - base: imported_func_struct_addr, - offset: (vm::ImportedFunc::offset_vmctx() as i32).into(), - global_type: ptr_type, - readonly: true, - }); - - let imported_func_addr = pos.ins().global_value(ptr_type, imported_func_addr); - let imported_vmctx_addr = pos.ins().global_value(ptr_type, imported_vmctx_addr); - - let sig_ref = pos.func.dfg.ext_funcs[callee].signature; - - let mut args = Vec::with_capacity(call_args.len() + 1); - args.push(imported_vmctx_addr); - args.extend(call_args.iter().cloned()); - - Ok(pos - .ins() - .call_indirect(sig_ref, imported_func_addr, &args[..])) - } - } - } - - /// Generates code corresponding to wasm `memory.grow`. - /// - /// `index` refers to the linear memory to query. - /// - /// `heap` refers to the IR generated by `make_heap`. - /// - /// `val` refers the value to grow the memory by. - fn translate_memory_grow( - &mut self, - mut pos: FuncCursor, - clif_mem_index: cranelift_wasm::MemoryIndex, - _heap: ir::Heap, - by_value: ir::Value, - ) -> cranelift_wasm::WasmResult { - let signature = pos.func.import_signature(ir::Signature { - call_conv: self.target_config().default_call_conv, - params: vec![ - ir::AbiParam::special(self.pointer_type(), ir::ArgumentPurpose::VMContext), - ir::AbiParam::new(ir::types::I32), - ir::AbiParam::new(ir::types::I32), - ], - returns: vec![ir::AbiParam::new(ir::types::I32)], - }); - - let mem_index: MemoryIndex = Converter(clif_mem_index).into(); - - let (namespace, mem_index, description) = - match mem_index.local_or_import(&self.env.module.info) { - LocalOrImport::Local(local_mem_index) => ( - call_names::LOCAL_NAMESPACE, - local_mem_index.index(), - self.env.module.info.memories[local_mem_index], - ), - LocalOrImport::Import(import_mem_index) => ( - call_names::IMPORT_NAMESPACE, - import_mem_index.index(), - self.env.module.info.imported_memories[import_mem_index].1, - ), - }; - - let name_index = match description.memory_type() { - MemoryType::Dynamic => call_names::DYNAMIC_MEM_GROW, - MemoryType::Static => call_names::STATIC_MEM_GROW, - MemoryType::SharedStatic => call_names::SHARED_STATIC_MEM_GROW, - }; - - let name = ir::ExternalName::user(namespace, name_index); - - let mem_grow_func = pos.func.import_function(ir::ExtFuncData { - name, - signature, - colocated: false, - }); - - let const_mem_index = pos.ins().iconst(ir::types::I32, mem_index as i64); - - let vmctx = pos - .func - .special_param(ir::ArgumentPurpose::VMContext) - .expect("missing vmctx parameter"); - - let call_inst = pos - .ins() - .call(mem_grow_func, &[vmctx, const_mem_index, by_value]); - - Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap()) - } - - /// Generates code corresponding to wasm `memory.size`. - /// - /// `index` refers to the linear memory to query. - /// - /// `heap` refers to the IR generated by `make_heap`. - fn translate_memory_size( - &mut self, - mut pos: FuncCursor, - clif_mem_index: cranelift_wasm::MemoryIndex, - _heap: ir::Heap, - ) -> cranelift_wasm::WasmResult { - let signature = pos.func.import_signature(ir::Signature { - call_conv: self.target_config().default_call_conv, - params: vec![ - ir::AbiParam::special(self.pointer_type(), ir::ArgumentPurpose::VMContext), - ir::AbiParam::new(ir::types::I32), - ], - returns: vec![ir::AbiParam::new(ir::types::I32)], - }); - - let mem_index: MemoryIndex = Converter(clif_mem_index).into(); - - let (namespace, mem_index, description) = - match mem_index.local_or_import(&self.env.module.info) { - LocalOrImport::Local(local_mem_index) => ( - call_names::LOCAL_NAMESPACE, - local_mem_index.index(), - self.env.module.info.memories[local_mem_index], - ), - LocalOrImport::Import(import_mem_index) => ( - call_names::IMPORT_NAMESPACE, - import_mem_index.index(), - self.env.module.info.imported_memories[import_mem_index].1, - ), - }; - - let name_index = match description.memory_type() { - MemoryType::Dynamic => call_names::DYNAMIC_MEM_SIZE, - MemoryType::Static => call_names::STATIC_MEM_SIZE, - MemoryType::SharedStatic => call_names::SHARED_STATIC_MEM_SIZE, - }; - - let name = ir::ExternalName::user(namespace, name_index); - - let mem_grow_func = pos.func.import_function(ir::ExtFuncData { - name, - signature, - colocated: false, - }); - - let const_mem_index = pos.ins().iconst(ir::types::I32, mem_index as i64); - let vmctx = pos - .func - .special_param(ir::ArgumentPurpose::VMContext) - .expect("missing vmctx parameter"); - - let call_inst = pos.ins().call(mem_grow_func, &[vmctx, const_mem_index]); - - Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap()) - } -} diff --git a/lib/clif-backend/src/lib.rs b/lib/clif-backend/src/lib.rs index 0ae4e9a59..074b0b670 100644 --- a/lib/clif-backend/src/lib.rs +++ b/lib/clif-backend/src/lib.rs @@ -2,10 +2,8 @@ mod cache; mod code; -mod func_env; mod libcalls; mod module; -mod module_env; mod relocation; mod resolver; mod signal; @@ -17,87 +15,12 @@ use cranelift_codegen::{ }; use target_lexicon::Triple; -use wasmer_runtime_core::cache::{Artifact, Error as CacheError}; -use wasmer_runtime_core::{ - backend::{Compiler, CompilerConfig, Token}, - error::{CompileError, CompileResult}, - module::ModuleInner, -}; - #[macro_use] extern crate serde_derive; extern crate rayon; extern crate serde; -use wasmparser::{self, WasmDecoder}; - -pub struct OldCraneliftCompiler {} - -impl OldCraneliftCompiler { - pub fn new() -> Self { - Self {} - } -} - -impl Compiler for OldCraneliftCompiler { - /// Compiles wasm binary to a wasmer module. - fn compile( - &self, - wasm: &[u8], - compiler_config: CompilerConfig, - _: Token, - ) -> CompileResult { - validate(wasm)?; - - let isa = get_isa(); - - let mut module = module::Module::new(&compiler_config); - let module_env = module_env::ModuleEnv::new(&mut module, &*isa); - - let func_bodies = module_env.translate(wasm)?; - - module.compile(&*isa, func_bodies) - } - - /// Create a wasmer Module from an already-compiled cache. - - unsafe fn from_cache(&self, cache: Artifact, _: Token) -> Result { - module::Module::from_cache(cache) - } - - // - // fn compile_to_backend_cache_data( - // &self, - // wasm: &[u8], - // _: Token, - // ) -> CompileResult<(Box, Vec, Memory)> { - // validate(wasm)?; - - // let isa = get_isa(); - - // let mut module = module::Module::new(wasm); - // let module_env = module_env::ModuleEnv::new(&mut module, &*isa); - - // let func_bodies = module_env.translate(wasm)?; - - // let (info, backend_cache, compiled_code) = module - // .compile_to_backend_cache(&*isa, func_bodies) - // .map_err(|e| CompileError::InternalError { - // msg: format!("{:?}", e), - // })?; - - // let buffer = - // backend_cache - // .into_backend_data() - // .map_err(|e| CompileError::InternalError { - // msg: format!("{:?}", e), - // })?; - - // Ok((Box::new(info), buffer, compiled_code)) - // } -} - fn get_isa() -> Box { let flags = { let mut builder = settings::builder(); @@ -114,20 +37,6 @@ fn get_isa() -> Box { isa::lookup(Triple::host()).unwrap().finish(flags) } -fn validate(bytes: &[u8]) -> CompileResult<()> { - let mut parser = wasmparser::ValidatingParser::new(bytes, None); - loop { - let state = parser.read(); - match *state { - wasmparser::ParserState::EndWasm => break Ok(()), - wasmparser::ParserState::Error(err) => Err(CompileError::ValidationError { - msg: err.message.to_string(), - })?, - _ => {} - } - } -} - /// The current version of this crate pub const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/lib/clif-backend/src/module.rs b/lib/clif-backend/src/module.rs index 94593f1c7..14adb1547 100644 --- a/lib/clif-backend/src/module.rs +++ b/lib/clif-backend/src/module.rs @@ -1,22 +1,17 @@ use crate::cache::{BackendCache, CacheGenerator}; -use crate::{resolver::FuncResolverBuilder, signal::Caller, trampoline::Trampolines}; +use crate::{resolver::FuncResolverBuilder, signal::Caller}; -use cranelift_codegen::{ir, isa}; +use cranelift_codegen::ir; use cranelift_entity::EntityRef; use cranelift_wasm; -use hashbrown::HashMap; use std::sync::Arc; use wasmer_runtime_core::cache::{Artifact, Error as CacheError}; use wasmer_runtime_core::{ - backend::{Backend, CompilerConfig}, - error::CompileResult, - module::{ModuleInfo, ModuleInner, StringTable}, - structures::{Map, TypedIndex}, - types::{ - FuncIndex, FuncSig, GlobalIndex, LocalFuncIndex, MemoryIndex, SigIndex, TableIndex, Type, - }, + module::{ModuleInfo, ModuleInner}, + structures::TypedIndex, + types::{FuncIndex, FuncSig, GlobalIndex, MemoryIndex, SigIndex, TableIndex, Type}, }; /// This contains all of the items in a `ModuleInner` except the `func_resolver`. @@ -25,69 +20,6 @@ pub struct Module { } impl Module { - pub fn new(compiler_config: &CompilerConfig) -> Self { - Self { - info: ModuleInfo { - memories: Map::new(), - globals: Map::new(), - tables: Map::new(), - - imported_functions: Map::new(), - imported_memories: Map::new(), - imported_tables: Map::new(), - imported_globals: Map::new(), - - exports: HashMap::new(), - - data_initializers: Vec::new(), - elem_initializers: Vec::new(), - - start_func: None, - - func_assoc: Map::new(), - signatures: Map::new(), - backend: Backend::Cranelift, - - namespace_table: StringTable::new(), - name_table: StringTable::new(), - em_symbol_map: compiler_config.symbol_map.clone(), - - custom_sections: HashMap::new(), - }, - } - } - - pub fn compile( - self, - isa: &isa::TargetIsa, - functions: Map, - ) -> CompileResult { - let (func_resolver_builder, handler_data) = - FuncResolverBuilder::new(isa, functions, &self.info)?; - - let trampolines = Arc::new(Trampolines::new(isa, &self.info)); - - let (func_resolver, backend_cache) = func_resolver_builder.finalize( - &self.info.signatures, - Arc::clone(&trampolines), - handler_data.clone(), - )?; - - let cache_gen = Box::new(CacheGenerator::new( - backend_cache, - Arc::clone(&func_resolver.memory), - )); - - let runnable_module = Caller::new(handler_data, trampolines, func_resolver); - - Ok(ModuleInner { - runnable_module: Box::new(runnable_module), - cache_gen, - - info: self.info, - }) - } - pub fn from_cache(cache: Artifact) -> Result { let (info, compiled_code, backend_cache) = BackendCache::from_cache(cache)?; diff --git a/lib/clif-backend/src/module_env.rs b/lib/clif-backend/src/module_env.rs deleted file mode 100644 index 7cf1dfaff..000000000 --- a/lib/clif-backend/src/module_env.rs +++ /dev/null @@ -1,557 +0,0 @@ -use crate::{ - func_env::FuncEnv, - module::{Converter, Module}, -}; -use cranelift_codegen::{ir, isa}; -use cranelift_wasm::{self, translate_module, FuncTranslator, ModuleEnvironment}; -use wasmer_runtime_core::{ - error::{CompileError, CompileResult}, - module::{ - DataInitializer, ExportIndex, ImportName, NameIndex, NamespaceIndex, StringTableBuilder, - TableInitializer, - }, - structures::{Map, TypedIndex}, - types::{ - ElementType, GlobalDescriptor, GlobalIndex, GlobalInit, Initializer, LocalFuncIndex, - LocalOrImport, MemoryDescriptor, SigIndex, TableDescriptor, Value, - }, - units::Pages, -}; - -pub struct ModuleEnv<'module, 'isa> { - pub module: &'module mut Module, - isa: &'isa isa::TargetIsa, - pub signatures: Map, - globals: Map, - func_bodies: Map, - namespace_table_builder: StringTableBuilder, - name_table_builder: StringTableBuilder, -} - -impl<'module, 'isa> ModuleEnv<'module, 'isa> { - pub fn new(module: &'module mut Module, isa: &'isa isa::TargetIsa) -> Self { - Self { - module, - isa, - signatures: Map::new(), - globals: Map::new(), - func_bodies: Map::new(), - namespace_table_builder: StringTableBuilder::new(), - name_table_builder: StringTableBuilder::new(), - } - } - - pub fn translate(mut self, wasm: &[u8]) -> CompileResult> { - translate_module(wasm, &mut self) - .map_err(|e| CompileError::InternalError { msg: e.to_string() })?; - - self.module.info.namespace_table = self.namespace_table_builder.finish(); - self.module.info.name_table = self.name_table_builder.finish(); - - Ok(self.func_bodies) - } - - /// Return the global for the given global index. - pub fn get_global(&self, global_index: cranelift_wasm::GlobalIndex) -> &cranelift_wasm::Global { - &self.globals[Converter(global_index).into()] - } - - /// Return the signature index for the given function index. - pub fn get_func_type( - &self, - func_index: cranelift_wasm::FuncIndex, - ) -> cranelift_wasm::SignatureIndex { - let sig_index: SigIndex = self.module.info.func_assoc[Converter(func_index).into()]; - Converter(sig_index).into() - } -} - -impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa> { - /// Get the information needed to produce Cranelift IR for the current target. - fn target_config(&self) -> isa::TargetFrontendConfig { - self.isa.frontend_config() - } - - /// Declares a function signature to the environment. - fn declare_signature(&mut self, sig: ir::Signature) { - self.signatures.push(sig.clone()); - self.module.info.signatures.push(Converter(sig).into()); - } - - /// Declares a function import to the environment. - fn declare_func_import( - &mut self, - clif_sig_index: cranelift_wasm::SignatureIndex, - namespace: &'data str, - name: &'data str, - ) { - // We convert the cranelift signature index to - // a wasmer signature index without deduplicating - // because we'll deduplicate later. - let sig_index = Converter(clif_sig_index).into(); - self.module.info.func_assoc.push(sig_index); - - let namespace_index = self.namespace_table_builder.register(namespace); - let name_index = self.name_table_builder.register(name); - - // Add import names to list of imported functions - self.module.info.imported_functions.push(ImportName { - namespace_index, - name_index, - }); - } - - /// Declares the type (signature) of a local function in the module. - fn declare_func_type(&mut self, clif_sig_index: cranelift_wasm::SignatureIndex) { - // We convert the cranelift signature index to - // a wasmer signature index without deduplicating - // because we'll deduplicate later. - let sig_index = Converter(clif_sig_index).into(); - self.module.info.func_assoc.push(sig_index); - } - - /// Declares a global to the environment. - fn declare_global(&mut self, global: cranelift_wasm::Global) { - let desc = GlobalDescriptor { - mutable: global.mutability, - ty: Converter(global.ty).into(), - }; - - let init = match global.initializer { - cranelift_wasm::GlobalInit::I32Const(x) => Initializer::Const(Value::I32(x)), - cranelift_wasm::GlobalInit::I64Const(x) => Initializer::Const(Value::I64(x)), - cranelift_wasm::GlobalInit::F32Const(x) => { - Initializer::Const(Value::F32(f32::from_bits(x))) - } - cranelift_wasm::GlobalInit::F64Const(x) => { - Initializer::Const(Value::F64(f64::from_bits(x))) - } - cranelift_wasm::GlobalInit::GetGlobal(global_index) => { - // assert!(!desc.mutable); - let global_index: GlobalIndex = Converter(global_index).into(); - let imported_global_index = global_index - .local_or_import(&self.module.info) - .import() - .expect("invalid global initializer when declaring an imported global"); - Initializer::GetGlobal(imported_global_index) - } - _ => panic!("invalid global initializer when declaring a local global"), - }; - - // Add global ir to the list of globals - self.module.info.globals.push(GlobalInit { desc, init }); - - self.globals.push(global); - } - - /// Declares a global import to the environment. - fn declare_global_import( - &mut self, - global: cranelift_wasm::Global, - namespace: &'data str, - name: &'data str, - ) { - assert!(match global.initializer { - cranelift_wasm::GlobalInit::Import => true, - _ => false, - }); - - let namespace_index = self.namespace_table_builder.register(namespace); - let name_index = self.name_table_builder.register(name); - - let import_name = ImportName { - namespace_index, - name_index, - }; - - let desc = GlobalDescriptor { - mutable: global.mutability, - ty: Converter(global.ty).into(), - }; - - // Add global ir to the list of globals - self.module.info.imported_globals.push((import_name, desc)); - - self.globals.push(global); - } - - /// Declares a table to the environment. - fn declare_table(&mut self, table: cranelift_wasm::Table) { - use cranelift_wasm::TableElementType; - // Add table ir to the list of tables - self.module.info.tables.push(TableDescriptor { - element: match table.ty { - TableElementType::Func => ElementType::Anyfunc, - _ => unimplemented!(), - }, - minimum: table.minimum, - maximum: table.maximum, - }); - } - - /// Declares a table import to the environment. - fn declare_table_import( - &mut self, - table: cranelift_wasm::Table, - namespace: &'data str, - name: &'data str, - ) { - use cranelift_wasm::TableElementType; - - let namespace_index = self.namespace_table_builder.register(namespace); - let name_index = self.name_table_builder.register(name); - - let import_name = ImportName { - namespace_index, - name_index, - }; - - let imported_table = TableDescriptor { - element: match table.ty { - TableElementType::Func => ElementType::Anyfunc, - _ => unimplemented!(), - }, - minimum: table.minimum, - maximum: table.maximum, - }; - - // Add import names to list of imported tables - self.module - .info - .imported_tables - .push((import_name, imported_table)); - } - - /// Fills a declared table with references to functions in the module. - fn declare_table_elements( - &mut self, - table_index: cranelift_wasm::TableIndex, - base: Option, - offset: usize, - elements: Box<[cranelift_wasm::FuncIndex]>, - ) { - // Convert Cranelift GlobalIndex to wamser GlobalIndex - // let base = base.map(|index| WasmerGlobalIndex::new(index.index())); - let base = match base { - Some(global_index) => { - let global_index: GlobalIndex = Converter(global_index).into(); - Initializer::GetGlobal(match global_index.local_or_import(&self.module.info) { - LocalOrImport::Import(imported_global_index) => imported_global_index, - LocalOrImport::Local(_) => { - panic!("invalid global initializer when declaring an imported global") - } - }) - } - None => Initializer::Const((offset as i32).into()), - }; - - // Add table initializer to list of table initializers - self.module.info.elem_initializers.push(TableInitializer { - table_index: Converter(table_index).into(), - base, - elements: elements - .iter() - .map(|&func_index| Converter(func_index).into()) - .collect(), - }); - } - - /// Declares a memory to the environment - fn declare_memory(&mut self, memory: cranelift_wasm::Memory) { - self.module.info.memories.push(MemoryDescriptor { - minimum: Pages(memory.minimum), - maximum: memory.maximum.map(|max| Pages(max)), - shared: memory.shared, - }); - } - - /// Declares a memory import to the environment. - fn declare_memory_import( - &mut self, - memory: cranelift_wasm::Memory, - namespace: &'data str, - name: &'data str, - ) { - let namespace_index = self.namespace_table_builder.register(namespace); - let name_index = self.name_table_builder.register(name); - - let import_name = ImportName { - namespace_index, - name_index, - }; - - let memory = MemoryDescriptor { - minimum: Pages(memory.minimum), - maximum: memory.maximum.map(|max| Pages(max)), - shared: memory.shared, - }; - - // Add import names to list of imported memories - self.module - .info - .imported_memories - .push((import_name, memory)); - } - - /// Fills a declared memory with bytes at module instantiation. - fn declare_data_initialization( - &mut self, - memory_index: cranelift_wasm::MemoryIndex, - base: Option, - offset: usize, - data: &'data [u8], - ) { - // Convert Cranelift GlobalIndex to wamser GlobalIndex - let base = match base { - Some(global_index) => { - let global_index: GlobalIndex = Converter(global_index).into(); - Initializer::GetGlobal(match global_index.local_or_import(&self.module.info) { - LocalOrImport::Import(imported_global_index) => imported_global_index, - LocalOrImport::Local(_) => { - panic!("invalid global initializer when declaring an imported global") - } - }) - } - None => Initializer::Const((offset as i32).into()), - }; - - // Add data initializer to list of data initializers - self.module.info.data_initializers.push(DataInitializer { - memory_index: Converter(memory_index).into(), - base, - data: data.to_vec(), - }); - } - - /// Declares a function export to the environment. - fn declare_func_export(&mut self, func_index: cranelift_wasm::FuncIndex, name: &'data str) { - self.module.info.exports.insert( - name.to_string(), - ExportIndex::Func(Converter(func_index).into()), - ); - } - /// Declares a table export to the environment. - fn declare_table_export(&mut self, table_index: cranelift_wasm::TableIndex, name: &'data str) { - self.module.info.exports.insert( - name.to_string(), - ExportIndex::Table(Converter(table_index).into()), - ); - } - /// Declares a memory export to the environment. - fn declare_memory_export( - &mut self, - memory_index: cranelift_wasm::MemoryIndex, - name: &'data str, - ) { - self.module.info.exports.insert( - name.to_string(), - ExportIndex::Memory(Converter(memory_index).into()), - ); - } - /// Declares a global export to the environment. - fn declare_global_export( - &mut self, - global_index: cranelift_wasm::GlobalIndex, - name: &'data str, - ) { - self.module.info.exports.insert( - name.to_string(), - ExportIndex::Global(Converter(global_index).into()), - ); - } - - /// Declares a start function. - fn declare_start_func(&mut self, func_index: cranelift_wasm::FuncIndex) { - self.module.info.start_func = Some(Converter(func_index).into()); - } - - /// Provides the contents of a function body. - fn define_function_body( - &mut self, - body_bytes: &'data [u8], - body_offset: usize, - ) -> cranelift_wasm::WasmResult<()> { - let mut func_translator = FuncTranslator::new(); - - let func_body = { - let mut func_env = FuncEnv::new(self); - let func_index = self.func_bodies.next_index(); - let name = ir::ExternalName::user(0, func_index.index() as u32); - - let sig = func_env.generate_signature( - self.get_func_type(Converter(func_index.convert_up(&self.module.info)).into()), - ); - - let mut func = ir::Function::with_name_signature(name, sig); - - func_translator.translate(body_bytes, body_offset, &mut func, &mut func_env)?; - - #[cfg(feature = "debug")] - { - use cranelift_codegen::cursor::{Cursor, FuncCursor}; - use cranelift_codegen::ir::InstBuilder; - let entry_ebb = func.layout.entry_block().unwrap(); - let ebb = func.dfg.make_ebb(); - func.layout.insert_ebb(ebb, entry_ebb); - let mut pos = FuncCursor::new(&mut func).at_first_insertion_point(ebb); - let params = pos.func.dfg.ebb_params(entry_ebb).to_vec(); - - let new_ebb_params: Vec<_> = params - .iter() - .map(|¶m| { - pos.func - .dfg - .append_ebb_param(ebb, pos.func.dfg.value_type(param)) - }) - .collect(); - - let start_debug = { - let signature = pos.func.import_signature(ir::Signature { - call_conv: self.target_config().default_call_conv, - params: vec![ - ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), - ir::AbiParam::new(ir::types::I32), - ], - returns: vec![], - }); - - let name = ir::ExternalName::testcase("strtdbug"); - - pos.func.import_function(ir::ExtFuncData { - name, - signature, - colocated: false, - }) - }; - - let end_debug = { - let signature = pos.func.import_signature(ir::Signature { - call_conv: self.target_config().default_call_conv, - params: vec![ir::AbiParam::special( - ir::types::I64, - ir::ArgumentPurpose::VMContext, - )], - returns: vec![], - }); - - let name = ir::ExternalName::testcase("enddbug"); - - pos.func.import_function(ir::ExtFuncData { - name, - signature, - colocated: false, - }) - }; - - let i32_print = { - let signature = pos.func.import_signature(ir::Signature { - call_conv: self.target_config().default_call_conv, - params: vec![ - ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), - ir::AbiParam::new(ir::types::I32), - ], - returns: vec![], - }); - - let name = ir::ExternalName::testcase("i32print"); - - pos.func.import_function(ir::ExtFuncData { - name, - signature, - colocated: false, - }) - }; - - let i64_print = { - let signature = pos.func.import_signature(ir::Signature { - call_conv: self.target_config().default_call_conv, - params: vec![ - ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), - ir::AbiParam::new(ir::types::I64), - ], - returns: vec![], - }); - - let name = ir::ExternalName::testcase("i64print"); - - pos.func.import_function(ir::ExtFuncData { - name, - signature, - colocated: false, - }) - }; - - let f32_print = { - let signature = pos.func.import_signature(ir::Signature { - call_conv: self.target_config().default_call_conv, - params: vec![ - ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), - ir::AbiParam::new(ir::types::F32), - ], - returns: vec![], - }); - - let name = ir::ExternalName::testcase("f32print"); - - pos.func.import_function(ir::ExtFuncData { - name, - signature, - colocated: false, - }) - }; - - let f64_print = { - let signature = pos.func.import_signature(ir::Signature { - call_conv: self.target_config().default_call_conv, - params: vec![ - ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), - ir::AbiParam::new(ir::types::F64), - ], - returns: vec![], - }); - - let name = ir::ExternalName::testcase("f64print"); - - pos.func.import_function(ir::ExtFuncData { - name, - signature, - colocated: false, - }) - }; - - let vmctx = pos - .func - .special_param(ir::ArgumentPurpose::VMContext) - .expect("missing vmctx parameter"); - - let func_index = pos.ins().iconst( - ir::types::I32, - func_index.index() as i64 + self.module.info.imported_functions.len() as i64, - ); - - pos.ins().call(start_debug, &[vmctx, func_index]); - - for param in new_ebb_params.iter().cloned() { - match pos.func.dfg.value_type(param) { - ir::types::I32 => pos.ins().call(i32_print, &[vmctx, param]), - ir::types::I64 => pos.ins().call(i64_print, &[vmctx, param]), - ir::types::F32 => pos.ins().call(f32_print, &[vmctx, param]), - ir::types::F64 => pos.ins().call(f64_print, &[vmctx, param]), - _ => unimplemented!(), - }; - } - - pos.ins().call(end_debug, &[vmctx]); - - pos.ins().jump(entry_ebb, new_ebb_params.as_slice()); - } - - func - }; - - // Add function body to list of function bodies. - self.func_bodies.push(func_body); - - Ok(()) - } -} From 00707ea849f18aaf875563e8b8228f445b7e1711 Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 26 May 2019 22:44:37 -0500 Subject: [PATCH 23/33] Cleanup cranelift validation --- lib/runtime-core/src/codegen.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/runtime-core/src/codegen.rs b/lib/runtime-core/src/codegen.rs index c687302f2..b89c060f5 100644 --- a/lib/runtime-core/src/codegen.rs +++ b/lib/runtime-core/src/codegen.rs @@ -156,9 +156,8 @@ impl< compiler_config: CompilerConfig, _: Token, ) -> CompileResult { - let res = validate(wasm); - if let Err(e) = res { - return Err(e); + if requires_pre_validation(MCG::backend_id()) { + validate(wasm)?; } let mut mcg = MCG::new(); @@ -191,6 +190,14 @@ impl< } } +fn requires_pre_validation(backend: Backend) -> bool { + match backend { + Backend::Cranelift => true, + Backend::LLVM => false, + Backend::Singlepass => false, + } +} + pub struct EventSink<'a, 'b> { buffer: SmallVec<[Event<'a, 'b>; 2]>, } From 921e95035f4ad2b2581ed3e531e3ac08928a2e9c Mon Sep 17 00:00:00 2001 From: Brandon Fish Date: Sun, 26 May 2019 22:50:23 -0500 Subject: [PATCH 24/33] Cleanup expect messages used for debugging --- lib/runtime-core/src/parse.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/runtime-core/src/parse.rs b/lib/runtime-core/src/parse.rs index deb326739..7a76a46ac 100644 --- a/lib/runtime-core/src/parse.rs +++ b/lib/runtime-core/src/parse.rs @@ -115,8 +115,8 @@ pub fn read_module< .push(func_type_to_func_sig(ty)?); } ParserState::ImportSectionEntry { module, field, ty } => { - let namespace_index = namespace_builder.as_mut().expect("116").register(module); - let name_index = name_builder.as_mut().expect("117").register(field); + let namespace_index = namespace_builder.as_mut().unwrap().register(module); + let name_index = name_builder.as_mut().unwrap().register(field); let import_name = ImportName { namespace_index, name_index, @@ -209,8 +209,8 @@ pub fn read_module< func_count = id; if func_count == 0 { info.write().unwrap().namespace_table = - namespace_builder.take().expect("214").finish(); - info.write().unwrap().name_table = name_builder.take().expect("216").finish(); + namespace_builder.take().unwrap().finish(); + info.write().unwrap().name_table = name_builder.take().unwrap().finish(); mcg.feed_signatures(info.read().unwrap().signatures.clone()) .map_err(|x| LoadError::Codegen(format!("{:?}", x)))?; mcg.feed_function_signatures(info.read().unwrap().func_assoc.clone()) @@ -241,9 +241,9 @@ pub fn read_module< .get(FuncIndex::new( id as usize + info.read().unwrap().imported_functions.len(), )) - .expect("242"), + .unwrap(), ) - .expect("244"); + .unwrap(); for ret in sig.returns() { fcg.feed_return(type_to_wp_type(*ret)) .map_err(|x| LoadError::Codegen(format!("{:?}", x)))?; @@ -319,8 +319,8 @@ pub fn read_module< let table_init = TableInitializer { table_index, - base: base.expect("320"), - elements: elements.expect("321"), + base: base.unwrap(), + elements: elements.unwrap(), }; info.write().unwrap().elem_initializers.push(table_init); @@ -351,7 +351,7 @@ pub fn read_module< let data_init = DataInitializer { memory_index, - base: base.expect("355"), + base: base.unwrap(), data, }; info.write().unwrap().data_initializers.push(data_init); From 3a4517d5d6e0517450426d8fdf85e3a8ab9563f5 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 28 May 2019 10:06:22 -0700 Subject: [PATCH 25/33] clean up code, verify it behaves the same as emscripten with js --- lib/emscripten/src/syscalls/unix.rs | 57 +++++------------------------ 1 file changed, 10 insertions(+), 47 deletions(-) diff --git a/lib/emscripten/src/syscalls/unix.rs b/lib/emscripten/src/syscalls/unix.rs index 0283a756d..81d3c667b 100644 --- a/lib/emscripten/src/syscalls/unix.rs +++ b/lib/emscripten/src/syscalls/unix.rs @@ -815,70 +815,33 @@ pub fn ___syscall220(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 { let dirp_addr: i32 = varargs.get(ctx); let count: u32 = varargs.get(ctx); - //let dir = dbg!(emscripten_memory_pointer!(ctx.memory(0), dbg!(fd)) as *mut libc::DIR); let dirp = emscripten_memory_pointer!(ctx.memory(0), dirp_addr) as *mut u8; - - let mut pos = 0; // need to persist stream across calls? - let dir: *mut libc::DIR = unsafe { libc::fdopendir(fd) }; - dbg!("Start loop"); - while pos + 280 <= dbg!(count) as usize { - dbg!("Pre readdir"); + let mut pos = 0; + let offset = 280; + while pos + offset <= count as usize { let dirent = unsafe { readdir(dir) }; - dbg!("post readdir"); if dirent.is_null() { break; } - dbg!("dirent is not null"); unsafe { - *(dirp.add(pos) as *mut u64) = dbg!((*dirent).d_ino); - #[cfg(not(target_os = "macos"))] - { - *(dirp.add(pos + 8) as *mut u64) = 280 //dbg!((*dirent).d_off); - } - #[cfg(target_os = "macos")] - { - *(dirp.add(pos + 8) as *mut u64) = if pos + 280 > count as usize { - count.into() - } else { - dbg!((*dirent).d_seekoff); - pos as u64 + 56 //280 - }; //; - } - dbg!((*dirent).d_namlen); - *(dirp.add(pos + 16) as *mut u16) = 280; //dbg!((*dirent).d_reclen); - *(dirp.add(pos + 18) as *mut u8) = dbg!((*dirent).d_type); - let upper_bound = std::cmp::min((*dirent).d_reclen, 255) as usize; + *(dirp.add(pos) as *mut u64) = (*dirent).d_ino; + *(dirp.add(pos + 8) as *mut u64) = pos as u64 + offset as u64; + *(dirp.add(pos + 16) as *mut u16) = offset as u16; + *(dirp.add(pos + 18) as *mut u8) = (*dirent).d_type; + let upper_bound = std::cmp::min((*dirent).d_reclen, 254) as usize; let mut i = 0; while i < upper_bound { *(dirp.add(pos + 19 + i) as *mut i8) = (*dirent).d_name[i]; - //dbg!((*dirent).d_name[i] as u8 as char); - //dbg!((*dirent).d_name[i] as u8 as char); i += 1; } *(dirp.add(pos + 19 + i) as *mut i8) = 0 as i8; } - dbg!("dirent written to memory"); - pos += 280; - /*unsafe { - eprintln!( - "{}", - std::ffi::CStr::from_bytes_with_nul_unchecked({ - let arr = *(dirent as *const u8 as *const [u8; 256]); - &arr.to_vec() - .into_iter() - .map(|b| b as u8) - .collect::>()[..20] - }) - .to_str() - .unwrap() - ); - }*/ + pos += offset; } - - dbg!(pos as i32) + pos as i32 } /// fallocate From 6606a7c7b0a73fe21054d487820448177bd81955 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 28 May 2019 14:06:24 -0700 Subject: [PATCH 26/33] silence clippy on pointer alignment --- lib/emscripten/src/syscalls/unix.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/emscripten/src/syscalls/unix.rs b/lib/emscripten/src/syscalls/unix.rs index 7907e7642..797878fa3 100644 --- a/lib/emscripten/src/syscalls/unix.rs +++ b/lib/emscripten/src/syscalls/unix.rs @@ -814,6 +814,7 @@ pub fn ___syscall220(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 { if dirent.is_null() { break; } + #[allow(clippy::cast_ptr_alignment)] unsafe { *(dirp.add(pos) as *mut u64) = (*dirent).d_ino; *(dirp.add(pos + 8) as *mut u64) = pos as u64 + offset as u64; From e0d4c9e1b79c3b49a06ceac77b30a1432819ec14 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 29 May 2019 01:03:51 -0700 Subject: [PATCH 27/33] Trying to make ghr always to pass in CircleCI --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 37b1de24e..11c4035aa 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -362,7 +362,7 @@ jobs: # VERSION_TAG=$(git describe --exact-match --tags) #if [ "$VERSION" == "$VERSION_TAG" ]; then # echo "Versions match, publishing to Github" - ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} ${VERSION} ./artifacts/ + ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} ${VERSION} ./artifacts/ || true #else # echo "Versions don't match. Wasmer output version (wasmer --version) is ${VERSION} while Git tag is ${VERSION_TAG}" # exit 1 From ff5d50b27375000840b13fb974f4d0841c2b2e27 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 29 May 2019 16:04:07 +0200 Subject: [PATCH 28/33] fix(runtime-c-api) Set the install name of the dylib to `@rpath`. ```sh $ objdump -macho -dylib-id libwasmer_runtime_c_api.dylib libwasmer_runtime_c_api.dylib: /Users/distiller/project/target/release/deps/libwasmer_runtime_c_api.dylib ``` we observe that the dylib ID (aka install name) is set to `/Users/distiller/project/target/release/deps/libwasmer_runtime_c_api.dylib`, which is valid only in the context of CircleCI. This patch changes the dylib ID to `@rpath/libwasmer_runtime_c_api.dylib`, which can be then changed by the linker option `-rpath` (use `-Wl,-rpath,$value` with the compiler to send the `-rpath` value to the linker). This is super useful when dynamically linking libraries against another language. --- .circleci/config.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 11c4035aa..eead29af0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -284,10 +284,11 @@ jobs: # VERSION=$(cargo pkgid | cut -d# -f2 | cut -d: -f2) # echo "${VERSION}" >> artifacts/version - run: - name: Dynamic library + name: Generate dynamic library for the runtime C API command: | export PATH="$HOME/.cargo/bin:$PATH" cargo build --release --manifest-path lib/runtime-c-api/Cargo.toml + install_name_tool -id "@rpath/libwasmer_runtime_c_api.dylib" target/release/libwasmer_runtime_c_api.dylib cp target/release/libwasmer_runtime_c_api.dylib ./artifacts - persist_to_workspace: root: . From 7a7aa4608aa25964b1a948aef2ea1b998c28c834 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Wed, 29 May 2019 11:41:29 -0700 Subject: [PATCH 29/33] fix emscripten regression tests --- lib/emscripten/tests/emtests/_common.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/emscripten/tests/emtests/_common.rs b/lib/emscripten/tests/emtests/_common.rs index 43c1aecbf..993842a18 100644 --- a/lib/emscripten/tests/emtests/_common.rs +++ b/lib/emscripten/tests/emtests/_common.rs @@ -56,6 +56,7 @@ macro_rules! assert_emscripten_output { $name, $args, None, + vec![], ).expect("run_emscripten_instance finishes"); let output = capturer.end().unwrap().0; From b627fbf8bbbacbb9231c3bff8e95f955f64ee34c Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 29 May 2019 12:36:09 -0700 Subject: [PATCH 30/33] Added support for Go --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b3a7a070d..27b04baab 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ Wasmer runtime can also be embedded in different languages, so you can use WebAs * [**🐘 PHP**](https://github.com/wasmerio/php-ext-wasm) * [**🐍 Python**](https://github.com/wasmerio/python-ext-wasm) * [**💎 Ruby**](https://github.com/wasmerio/ruby-ext-wasm) +* [**🐹 Go**](https://github.com/wasmerio/go-ext-wasm) ### Usage From 281c5ff45d5c066e2e0344347da31e00a4b9de2f Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Wed, 29 May 2019 14:20:52 -0700 Subject: [PATCH 31/33] fix bugs in em mapdir, improve it for relative paths, use it more --- lib/emscripten/src/syscalls/mod.rs | 47 +++++++++++------ lib/emscripten/src/syscalls/unix.rs | 73 ++++++++++++++++++++------ lib/emscripten/src/syscalls/windows.rs | 20 +++++-- lib/emscripten/src/utils.rs | 32 +++++++++-- src/bin/wasmer.rs | 3 -- 5 files changed, 131 insertions(+), 44 deletions(-) diff --git a/lib/emscripten/src/syscalls/mod.rs b/lib/emscripten/src/syscalls/mod.rs index 05766bf79..94f118947 100644 --- a/lib/emscripten/src/syscalls/mod.rs +++ b/lib/emscripten/src/syscalls/mod.rs @@ -96,9 +96,12 @@ pub fn ___syscall6(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int pub fn ___syscall12(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall12 (chdir) {}", _which); let path_ptr = varargs.get_str(ctx); - let real_path = get_cstr_path(ctx, path_ptr) - .map(|cstr| cstr.as_c_str() as *const _ as *const i8) - .unwrap_or(path_ptr); + let real_path_owned = get_cstr_path(ctx, path_ptr); + let real_path = if let Some(ref rp) = real_path_owned { + rp.as_c_str().as_ptr() + } else { + path_ptr + }; let ret = unsafe { chdir(real_path) }; debug!( "=> path: {:?}, ret: {}", @@ -129,12 +132,18 @@ pub fn ___syscall38(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 { debug!("emscripten::___syscall38 (rename)"); let old_path = varargs.get_str(ctx); let new_path = varargs.get_str(ctx); - let real_old_path = get_cstr_path(ctx, old_path) - .map(|cstr| cstr.as_c_str() as *const _ as *const i8) - .unwrap_or(old_path); - let real_new_path = get_cstr_path(ctx, new_path) - .map(|cstr| cstr.as_c_str() as *const _ as *const i8) - .unwrap_or(new_path); + let real_old_path_owned = get_cstr_path(ctx, old_path); + let real_old_path = if let Some(ref rp) = real_old_path_owned { + rp.as_c_str().as_ptr() + } else { + old_path + }; + let real_new_path_owned = get_cstr_path(ctx, new_path); + let real_new_path = if let Some(ref rp) = real_new_path_owned { + rp.as_c_str().as_ptr() + } else { + new_path + }; let result = unsafe { rename(real_old_path, real_new_path) }; debug!( "=> old_path: {}, new_path: {}, result: {}", @@ -149,9 +158,12 @@ pub fn ___syscall38(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 { pub fn ___syscall40(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall40 (rmdir)"); let pathname_addr = varargs.get_str(ctx); - let real_path = get_cstr_path(ctx, pathname_addr) - .map(|cstr| cstr.as_c_str() as *const _ as *const i8) - .unwrap_or(pathname_addr); + let real_path_owned = get_cstr_path(ctx, pathname_addr); + let real_path = if let Some(ref rp) = real_path_owned { + rp.as_c_str().as_ptr() + } else { + pathname_addr + }; unsafe { rmdir(real_path) } } @@ -433,16 +445,19 @@ pub fn ___syscall195(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in let pathname_addr = varargs.get_str(ctx); let buf: u32 = varargs.get(ctx); - let real_path = get_cstr_path(ctx, pathname_addr) - .map(|cstr| cstr.as_c_str() as *const _ as *const i8) - .unwrap_or(pathname_addr); + let real_path_owned = get_cstr_path(ctx, pathname_addr); + let real_path = if let Some(ref rp) = real_path_owned { + rp.as_c_str().as_ptr() + } else { + pathname_addr + }; unsafe { let mut _stat: stat = std::mem::zeroed(); let ret = stat(real_path, &mut _stat); debug!( "=> pathname: {}, buf: {} = {}, last os error: {}", - std::ffi::CStr::from_ptr(pathname_addr).to_str().unwrap(), + std::ffi::CStr::from_ptr(real_path).to_str().unwrap(), buf, ret, Error::last_os_error() diff --git a/lib/emscripten/src/syscalls/unix.rs b/lib/emscripten/src/syscalls/unix.rs index 797878fa3..1c4db071b 100644 --- a/lib/emscripten/src/syscalls/unix.rs +++ b/lib/emscripten/src/syscalls/unix.rs @@ -108,9 +108,12 @@ pub fn ___syscall5(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int let pathname_addr = varargs.get_str(ctx); let flags: i32 = varargs.get(ctx); let mode: u32 = varargs.get(ctx); - let real_path = utils::get_cstr_path(ctx, pathname_addr) - .map(|cstr| cstr.as_c_str() as *const _ as *const i8) - .unwrap_or(pathname_addr); + let real_path_owned = utils::get_cstr_path(ctx, pathname_addr); + let real_path = if let Some(ref rp) = real_path_owned { + rp.as_c_str().as_ptr() + } else { + pathname_addr + }; let _path_str = unsafe { std::ffi::CStr::from_ptr(real_path).to_str().unwrap() }; let fd = unsafe { open(real_path, flags, mode) }; debug!( @@ -158,12 +161,18 @@ pub fn ___syscall83(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int let path1 = varargs.get_str(ctx); let path2 = varargs.get_str(ctx); - let real_path1 = utils::get_cstr_path(ctx, path1) - .map(|cstr| cstr.as_c_str() as *const _ as *const i8) - .unwrap_or(path1); - let real_path2 = utils::get_cstr_path(ctx, path2) - .map(|cstr| cstr.as_c_str() as *const _ as *const i8) - .unwrap_or(path2); + let real_path1_owned = utils::get_cstr_path(ctx, path1); + let real_path1 = if let Some(ref rp) = real_path1_owned { + rp.as_c_str().as_ptr() + } else { + path1 + }; + let real_path2_owned = utils::get_cstr_path(ctx, path2); + let real_path2 = if let Some(ref rp) = real_path2_owned { + rp.as_c_str().as_ptr() + } else { + path2 + }; let result = unsafe { symlink(real_path1, real_path2) }; debug!( "=> path1: {}, path2: {}, result: {}", @@ -191,12 +200,18 @@ pub fn ___syscall194(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in pub fn ___syscall198(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall198 (lchown) {}", _which); let path_ptr = varargs.get_str(ctx); + let real_path_owned = utils::get_cstr_path(ctx, path_ptr); + let real_path = if let Some(ref rp) = real_path_owned { + rp.as_c_str().as_ptr() + } else { + path_ptr + }; let uid: uid_t = varargs.get(ctx); let gid: gid_t = varargs.get(ctx); - let result = unsafe { lchown(path_ptr, uid, gid) }; + let result = unsafe { lchown(real_path, uid, gid) }; debug!( "=> path: {}, uid: {}, gid: {}, result: {}", - unsafe { std::ffi::CStr::from_ptr(path_ptr).to_str().unwrap() }, + unsafe { std::ffi::CStr::from_ptr(real_path).to_str().unwrap() }, uid, gid, result, @@ -226,10 +241,16 @@ pub fn ___syscall212(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in debug!("emscripten::___syscall212 (chown) {}", _which); let pathname_addr = varargs.get_str(ctx); + let real_path_owned = utils::get_cstr_path(ctx, pathname_addr); + let real_path = if let Some(ref rp) = real_path_owned { + rp.as_c_str().as_ptr() + } else { + pathname_addr + }; let owner: u32 = varargs.get(ctx); let group: u32 = varargs.get(ctx); - unsafe { chown(pathname_addr, owner, group) } + unsafe { chown(real_path, owner, group) } } /// madvise @@ -249,11 +270,17 @@ pub fn ___syscall219(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in pub fn ___syscall33(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall33 (access) {}", _which); let path = varargs.get_str(ctx); + let real_path_owned = utils::get_cstr_path(ctx, path); + let real_path = if let Some(ref rp) = real_path_owned { + rp.as_c_str().as_ptr() + } else { + path + }; let amode: c_int = varargs.get(ctx); - let result = unsafe { access(path, amode) }; + let result = unsafe { access(real_path, amode) }; debug!( "=> path: {}, amode: {}, result: {}", - unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() }, + unsafe { std::ffi::CStr::from_ptr(real_path).to_str().unwrap() }, amode, result ); @@ -271,8 +298,14 @@ pub fn ___syscall34(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int pub fn ___syscall39(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall39 (mkdir) {}", _which); let pathname_addr = varargs.get_str(ctx); + let real_path_owned = utils::get_cstr_path(ctx, pathname_addr); + let real_path = if let Some(ref rp) = real_path_owned { + rp.as_c_str().as_ptr() + } else { + pathname_addr + }; let mode: u32 = varargs.get(ctx); - unsafe { mkdir(pathname_addr, mode as _) } + unsafe { mkdir(real_path, mode as _) } } /// dup @@ -771,6 +804,12 @@ pub fn ___syscall122(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in pub fn ___syscall196(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 { debug!("emscripten::___syscall196 (lstat64) {}", _which); let path = varargs.get_str(ctx); + let real_path_owned = utils::get_cstr_path(ctx, path); + let real_path = if let Some(ref rp) = real_path_owned { + rp.as_c_str().as_ptr() + } else { + path + }; let buf_ptr: u32 = varargs.get(ctx); unsafe { let mut stat: stat = std::mem::zeroed(); @@ -781,9 +820,9 @@ pub fn ___syscall196(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 { let stat_ptr = &mut stat as *mut stat; #[cfg(target_os = "macos")] - let ret = lstat64(path, stat_ptr); + let ret = lstat64(real_path, stat_ptr); #[cfg(not(target_os = "macos"))] - let ret = lstat(path, stat_ptr); + let ret = lstat(real_path, stat_ptr); debug!("ret: {}", ret); if ret != 0 { diff --git a/lib/emscripten/src/syscalls/windows.rs b/lib/emscripten/src/syscalls/windows.rs index 1355ebb1c..b3f7b748f 100644 --- a/lib/emscripten/src/syscalls/windows.rs +++ b/lib/emscripten/src/syscalls/windows.rs @@ -1,4 +1,4 @@ -use crate::utils::copy_cstr_into_wasm; +use crate::utils::{copy_cstr_into_wasm, get_cstr_path}; use crate::varargs::VarArgs; use libc::mkdir; use libc::open; @@ -19,9 +19,15 @@ pub fn ___syscall5(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { #[cfg(not(feature = "debug"))] let _ = which; let pathname_addr = varargs.get_str(ctx); + let real_path_owned = get_cstr_path(ctx, pathname_addr); + let real_path = if let Some(ref rp) = real_path_owned { + rp.as_c_str().as_ptr() + } else { + pathname_addr + }; let flags: i32 = varargs.get(ctx); let mode: u32 = varargs.get(ctx); - let path_str = unsafe { std::ffi::CStr::from_ptr(pathname_addr).to_str().unwrap() }; + let path_str = unsafe { std::ffi::CStr::from_ptr(real_path).to_str().unwrap() }; match path_str { "/dev/urandom" => { // create a fake urandom file for windows, super hacky @@ -47,7 +53,7 @@ pub fn ___syscall5(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { fd } _ => { - let fd = unsafe { open(pathname_addr, flags, mode) }; + let fd = unsafe { open(real_path, flags, mode) }; debug!( "=> pathname: {}, flags: {}, mode: {} = fd: {}\npath: {}", path_str, flags, mode, fd, path_str @@ -95,7 +101,13 @@ pub fn ___syscall39(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int #[cfg(not(feature = "debug"))] let _ = which; let pathname_addr = varargs.get_str(ctx); - unsafe { mkdir(pathname_addr) } + let real_path_owned = get_cstr_path(ctx, pathname_addr); + let real_path = if let Some(ref rp) = real_path_owned { + rp.as_c_str().as_ptr() + } else { + pathname_addr + }; + unsafe { mkdir(real_path) } } /// dup diff --git a/lib/emscripten/src/utils.rs b/lib/emscripten/src/utils.rs index 090ac25d7..112728130 100644 --- a/lib/emscripten/src/utils.rs +++ b/lib/emscripten/src/utils.rs @@ -208,12 +208,36 @@ pub fn read_string_from_wasm(memory: &Memory, offset: u32) -> String { /// This function trys to find an entry in mapdir /// translating paths into their correct value pub fn get_cstr_path(ctx: &mut Ctx, path: *const i8) -> Option { + use std::collections::VecDeque; + let path_str = unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() }.to_string(); - if let Some(val) = get_emscripten_data(ctx).mapped_dirs.get(&path_str) { - std::ffi::CString::new(val.to_string_lossy().as_bytes()).ok() - } else { - None + let data = get_emscripten_data(ctx); + let path = PathBuf::from(path_str); + let mut prefix_added = false; + let mut components = path.components().collect::>(); + // TODO(mark): handle absolute/non-canonical/non-relative paths too (this + // functionality should be shared among the abis) + if components.len() == 1 { + components.push_front(std::path::Component::CurDir); + prefix_added = true; } + let mut cumulative_path = PathBuf::new(); + for c in components.into_iter() { + cumulative_path.push(c); + if let Some(val) = data + .mapped_dirs + .get(&cumulative_path.to_string_lossy().to_string()) + { + let rest_of_path = if !prefix_added { + path.strip_prefix(cumulative_path).ok()? + } else { + &path + }; + let rebased_path = val.join(rest_of_path); + return std::ffi::CString::new(rebased_path.to_string_lossy().as_bytes()).ok(); + } + } + None } /// gets the current directory diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index cd43a5f07..6f835b4ec 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -445,9 +445,6 @@ fn execute_wasm(options: &Run) -> Result<(), String> { .instantiate(&import_object) .map_err(|e| format!("Can't instantiate module: {:?}", e))?; - if !mapped_dirs.is_empty() { - eprintln!("WARN: mapdir is not implemented for emscripten targets"); - } wasmer_emscripten::run_emscripten_instance( &module, &mut instance, From 4c8915efd842a3fb36345ad3af498e9517c36c1b Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Wed, 29 May 2019 14:35:58 -0700 Subject: [PATCH 32/33] add mapdir pr to changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93857f7d8..35838a19b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ Blocks of changes will separated by version increments. ## **[Unreleased]** +- [#470](https://github.com/wasmerio/wasmer/pull/470) Add mapdir support to Emscripten, implement getdents for Unix - [#467](https://github.com/wasmerio/wasmer/pull/467) `wasmer_instantiate` returns better error messages in the runtime C API - [#463](https://github.com/wasmerio/wasmer/pull/463) Fix bug in WASI path_open allowing one level above preopened dir to be accessed - [#461](https://github.com/wasmerio/wasmer/pull/461) Prevent passing negative lengths in various places in the runtime C API From 5d63c96d9609defdfcc1bd899563c6897caf0394 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 29 May 2019 15:12:45 -0700 Subject: [PATCH 33/33] Update ARCHITECTURE.md --- ARCHITECTURE.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index e3d87738d..e1d1c4ae3 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -2,7 +2,7 @@ Wasmer uses the following components: -- [Cranelift](https://github.com/cranestation/cranelift): for compiling Wasm binaries to machine code +- Compiler backends: for compiling Wasm binaries to machine code ([more info here](https://github.com/wasmerio/wasmer/tree/master/lib#backends)) - [wabt](https://github.com/pepyakin/wabt-rs): for transforming `.wast` files to `.wasm` and running WebAssembly spec tests - [wasmparser](https://github.com/yurydelendik/wasmparser.rs): for parsing the `.wasm` files and translating them into WebAssembly modules @@ -67,3 +67,8 @@ Once that's finished, we will have a `Instance` function that will be ready to e Wasmer's Emscripten integration tries to wrap (and emulate) all the different syscalls that Emscripten needs. We provide this integration by filling the `import_object` with the Emscripten functions, while instantiating the WebAssembly Instance. + +## WASI + +Wasmer's WASI integration implements all the different syscalls that WASI needs. +We provide this integration by filling the `import_object` with the WASI functions, while instantiating the WebAssembly Instance.