diff --git a/Cargo.lock b/Cargo.lock index f61028eb3e..015c7f8228 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4031,6 +4031,15 @@ dependencies = [ "wasmparser", ] +[[package]] +name = "winch-environ" +version = "0.6.0" +dependencies = [ + "wasmparser", + "wasmtime-environ", + "winch-codegen", +] + [[package]] name = "winch-filetests" version = "0.0.0" @@ -4045,6 +4054,7 @@ dependencies = [ "wasmtime-environ", "wat", "winch-codegen", + "winch-environ", "winch-test-macros", ] @@ -4075,6 +4085,7 @@ dependencies = [ "wasmtime-environ", "wat", "winch-codegen", + "winch-environ", "winch-filetests", "winch-test-macros", ] diff --git a/Cargo.toml b/Cargo.toml index f2634cffc9..6f081ca40a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -101,7 +101,8 @@ members = [ "examples/tokio/wasm", "fuzz", "winch", - "winch/codegen" + "winch/codegen", + "winch/environ" ] exclude = [ 'crates/wasi-common/WASI/tools/witx-cli', @@ -163,6 +164,7 @@ cranelift-bforest = { path = "cranelift/bforest", version = "0.95.0" } cranelift = { path = "cranelift/umbrella", version = "0.95.0" } winch-codegen = { path = "winch/codegen", version = "=0.6.0" } +winch-environ = { path = "winch/environ", version = "=0.6.0" } winch-filetests = { path = "winch/filetests" } winch-test-macros = { path = "winch/test-macros" } diff --git a/scripts/publish.rs b/scripts/publish.rs index 73a229a541..b64b178db8 100644 --- a/scripts/publish.rs +++ b/scripts/publish.rs @@ -57,6 +57,7 @@ const CRATES_TO_PUBLISH: &[&str] = &[ "wasmtime-jit", "wasmtime-cache", "wasmtime-winch", + "winch-environ", "wasmtime", // wasi-common/wiggle "wiggle", diff --git a/winch/Cargo.toml b/winch/Cargo.toml index d86a0b22a2..8259130178 100644 --- a/winch/Cargo.toml +++ b/winch/Cargo.toml @@ -13,6 +13,7 @@ path = "src/main.rs" [dependencies] winch-codegen = { workspace = true } +winch-environ = { workspace = true } winch-filetests = { workspace = true } winch-test-macros = { workspace = true } wasmtime-environ = { workspace = true } diff --git a/winch/codegen/src/codegen/env.rs b/winch/codegen/src/codegen/env.rs new file mode 100644 index 0000000000..f05ac47fc0 --- /dev/null +++ b/winch/codegen/src/codegen/env.rs @@ -0,0 +1,19 @@ +use wasmparser::FuncType; + +/// Function environment used the by the code generation to +/// resolve module and runtime-specific information. +pub trait FuncEnv { + /// Get the callee information from a given function index. + fn callee_from_index(&self, index: u32) -> Callee; +} + +/// Metadata about a function callee. Use by the code generation +/// to emit function calls. +pub struct Callee { + /// The function type. + pub ty: FuncType, + /// A flag to determine if the callee is imported. + pub import: bool, + /// The callee index in the WebAssembly function index space. + pub index: u32, +} diff --git a/winch/codegen/src/codegen/mod.rs b/winch/codegen/src/codegen/mod.rs index aa4ab537f3..8079122188 100644 --- a/winch/codegen/src/codegen/mod.rs +++ b/winch/codegen/src/codegen/mod.rs @@ -7,6 +7,8 @@ use wasmparser::{BinaryReader, FuncValidator, ValType, ValidatorResources, Visit mod context; pub(crate) use context::*; +mod env; +pub use env::*; /// The code generation abstraction. pub(crate) struct CodeGen<'a, M> diff --git a/winch/codegen/src/lib.rs b/winch/codegen/src/lib.rs index efee4a7114..3321998db7 100644 --- a/winch/codegen/src/lib.rs +++ b/winch/codegen/src/lib.rs @@ -8,6 +8,7 @@ mod abi; mod codegen; +pub use codegen::{Callee, FuncEnv}; mod frame; pub mod isa; pub use isa::*; diff --git a/winch/environ/Cargo.toml b/winch/environ/Cargo.toml new file mode 100644 index 0000000000..df49636dfb --- /dev/null +++ b/winch/environ/Cargo.toml @@ -0,0 +1,14 @@ +[package] +authors = ["The Winch Project Developers"] +name = "winch-environ" +description = "Implementation of Winch's function compilation environment" +license = "Apache-2.0 WITH LLVM-exception" +repository = "https://github.com/bytecodealliance/wasmtime" +version = "0.6.0" +edition.workspace = true + + +[dependencies] +winch-codegen = { workspace = true } +wasmtime-environ = { workspace = true } +wasmparser = { workspace = true } diff --git a/winch/environ/src/lib.rs b/winch/environ/src/lib.rs new file mode 100644 index 0000000000..1e46ea6ac8 --- /dev/null +++ b/winch/environ/src/lib.rs @@ -0,0 +1,41 @@ +//! This crate implements Winch's function compilation environment, +//! which allows Winch's code generation to resolve module and runtime +//! specific information. This crate mainly implements the +//! `winch_codegen::FuncEnv` trait. + +use wasmparser::types::Types; +use wasmtime_environ::{FuncIndex, Module}; +use winch_codegen::{self, Callee, TargetIsa}; + +/// Function environment containing module and runtime specific +/// information. +pub struct FuncEnv<'a> { + /// The translated WebAssembly module. + pub module: &'a Module, + /// Type information about a module, once it has been validated. + pub types: &'a Types, + /// The current ISA. + pub isa: &'a dyn TargetIsa, +} + +impl<'a> winch_codegen::FuncEnv for FuncEnv<'a> { + fn callee_from_index(&self, index: u32) -> Callee { + let func = self + .types + .function_at(index) + .unwrap_or_else(|| panic!("function type at index: {}", index)); + + Callee { + ty: func.clone(), + import: self.module.is_imported_function(FuncIndex::from_u32(index)), + index, + } + } +} + +impl<'a> FuncEnv<'a> { + /// Create a new function environment. + pub fn new(module: &'a Module, types: &'a Types, isa: &'a dyn TargetIsa) -> Self { + Self { module, types, isa } + } +} diff --git a/winch/filetests/Cargo.toml b/winch/filetests/Cargo.toml index 9250078b42..a629e3f681 100644 --- a/winch/filetests/Cargo.toml +++ b/winch/filetests/Cargo.toml @@ -12,6 +12,7 @@ edition.workspace = true winch-test-macros = {workspace = true} target-lexicon = { workspace = true } winch-codegen = { workspace = true, features = ['all-arch'] } +winch-environ = { workspace = true } wasmtime-environ = { workspace = true } anyhow = { workspace = true } wat = { workspace = true } diff --git a/winch/filetests/src/lib.rs b/winch/filetests/src/lib.rs index 3f49abddc7..0d4f8832db 100644 --- a/winch/filetests/src/lib.rs +++ b/winch/filetests/src/lib.rs @@ -10,11 +10,11 @@ mod test { use std::str::FromStr; use target_lexicon::Triple; use wasmtime_environ::{ - wasmparser::{types::Types, Parser as WasmParser, Validator}, - DefinedFuncIndex, FunctionBodyData, Module, ModuleEnvironment, Tunables, + wasmparser::{Parser as WasmParser, Validator}, + DefinedFuncIndex, FunctionBodyData, ModuleEnvironment, Tunables, }; - use winch_codegen::isa::TargetIsa; use winch_codegen::lookup; + use winch_environ::FuncEnv; use winch_test_macros::generate_file_tests; #[derive(Clone, Debug, Serialize, Deserialize)] @@ -109,10 +109,11 @@ mod test { let body_inputs = std::mem::take(&mut translation.function_body_inputs); let module = &translation.module; let types = translation.get_types(); + let env = FuncEnv::new(module, &types, &*isa); let binding = body_inputs .into_iter() - .map(|func| compile(&*isa, module, types, func).join("\n")) + .map(|func| compile(&env, func).join("\n")) .collect::>() .join("\n\n"); let actual = binding.as_str(); @@ -143,23 +144,20 @@ mod test { } } - fn compile( - isa: &dyn TargetIsa, - module: &Module, - types: &Types, - f: (DefinedFuncIndex, FunctionBodyData<'_>), - ) -> Vec { - let index = module.func_index(f.0); - let sig = types + fn compile(env: &FuncEnv, f: (DefinedFuncIndex, FunctionBodyData<'_>)) -> Vec { + let index = env.module.func_index(f.0); + let sig = env + .types .function_at(index.as_u32()) .expect(&format!("function type at index {:?}", index.as_u32())); let FunctionBodyData { body, validator } = f.1; let validator = validator.into_validator(Default::default()); - let buffer = isa + let buffer = env + .isa .compile_function(&sig, &body, validator) .expect("Couldn't compile function"); - disasm(buffer.data(), isa).unwrap() + disasm(buffer.data(), env.isa).unwrap() } } diff --git a/winch/src/compile.rs b/winch/src/compile.rs index 508fa56c78..1e05a6aaff 100644 --- a/winch/src/compile.rs +++ b/winch/src/compile.rs @@ -4,10 +4,11 @@ use cranelift_codegen::settings; use std::{fs, path::PathBuf, str::FromStr}; use target_lexicon::Triple; use wasmtime_environ::{ - wasmparser::{types::Types, Parser as WasmParser, Validator}, - DefinedFuncIndex, FunctionBodyData, Module, ModuleEnvironment, Tunables, + wasmparser::{Parser as WasmParser, Validator}, + DefinedFuncIndex, FunctionBodyData, ModuleEnvironment, Tunables, }; -use winch_codegen::{lookup, TargetIsa}; +use winch_codegen::lookup; +use winch_environ::FuncEnv; use winch_filetests::disasm::disasm; #[derive(Parser, Debug)] @@ -40,32 +41,30 @@ pub fn run(opt: &Options) -> Result<()> { let body_inputs = std::mem::take(&mut translation.function_body_inputs); let module = &translation.module; let types = translation.get_types(); + let env = FuncEnv::new(module, &types, &*isa); body_inputs .into_iter() - .try_for_each(|func| compile(&*isa, module, types, func))?; + .try_for_each(|func| compile(&env, func))?; Ok(()) } -fn compile( - isa: &dyn TargetIsa, - module: &Module, - types: &Types, - f: (DefinedFuncIndex, FunctionBodyData<'_>), -) -> Result<()> { - let index = module.func_index(f.0); - let sig = types +fn compile(env: &FuncEnv, f: (DefinedFuncIndex, FunctionBodyData<'_>)) -> Result<()> { + let index = env.module.func_index(f.0); + let sig = env + .types .function_at(index.as_u32()) .expect(&format!("function type at index {:?}", index.as_u32())); let FunctionBodyData { body, validator } = f.1; let validator = validator.into_validator(Default::default()); - let buffer = isa + let buffer = env + .isa .compile_function(&sig, &body, validator) .expect("Couldn't compile function"); println!("Disassembly for function: {}", index.as_u32()); - disasm(buffer.data(), isa)? + disasm(buffer.data(), env.isa)? .iter() .for_each(|s| println!("{}", s));