winch: Introduce winch-environ (#6017)
This commit introduces the `winch-environ` crate. This crate's responsibility is to provide a shared implementatation of the `winch_codegen::FuncEnv` trait, which is Winch's function compilation environment, used to resolve module and runtime specific information needed by the code generation, such as resolving all the details about a callee in a WebAssembly module, or resolving specific information from the `VMContext`. As of this change, the implementation only includes the necessary pieces to resolve a function callee in a WebAssembly module. The idea is to evolve the `winch_codegen::FuncEnv` trait as we evolve Winch's code generation.
This commit is contained in:
11
Cargo.lock
generated
11
Cargo.lock
generated
@@ -4031,6 +4031,15 @@ dependencies = [
|
|||||||
"wasmparser",
|
"wasmparser",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winch-environ"
|
||||||
|
version = "0.6.0"
|
||||||
|
dependencies = [
|
||||||
|
"wasmparser",
|
||||||
|
"wasmtime-environ",
|
||||||
|
"winch-codegen",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winch-filetests"
|
name = "winch-filetests"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
@@ -4045,6 +4054,7 @@ dependencies = [
|
|||||||
"wasmtime-environ",
|
"wasmtime-environ",
|
||||||
"wat",
|
"wat",
|
||||||
"winch-codegen",
|
"winch-codegen",
|
||||||
|
"winch-environ",
|
||||||
"winch-test-macros",
|
"winch-test-macros",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -4075,6 +4085,7 @@ dependencies = [
|
|||||||
"wasmtime-environ",
|
"wasmtime-environ",
|
||||||
"wat",
|
"wat",
|
||||||
"winch-codegen",
|
"winch-codegen",
|
||||||
|
"winch-environ",
|
||||||
"winch-filetests",
|
"winch-filetests",
|
||||||
"winch-test-macros",
|
"winch-test-macros",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -101,7 +101,8 @@ members = [
|
|||||||
"examples/tokio/wasm",
|
"examples/tokio/wasm",
|
||||||
"fuzz",
|
"fuzz",
|
||||||
"winch",
|
"winch",
|
||||||
"winch/codegen"
|
"winch/codegen",
|
||||||
|
"winch/environ"
|
||||||
]
|
]
|
||||||
exclude = [
|
exclude = [
|
||||||
'crates/wasi-common/WASI/tools/witx-cli',
|
'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" }
|
cranelift = { path = "cranelift/umbrella", version = "0.95.0" }
|
||||||
|
|
||||||
winch-codegen = { path = "winch/codegen", version = "=0.6.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-filetests = { path = "winch/filetests" }
|
||||||
winch-test-macros = { path = "winch/test-macros" }
|
winch-test-macros = { path = "winch/test-macros" }
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ const CRATES_TO_PUBLISH: &[&str] = &[
|
|||||||
"wasmtime-jit",
|
"wasmtime-jit",
|
||||||
"wasmtime-cache",
|
"wasmtime-cache",
|
||||||
"wasmtime-winch",
|
"wasmtime-winch",
|
||||||
|
"winch-environ",
|
||||||
"wasmtime",
|
"wasmtime",
|
||||||
// wasi-common/wiggle
|
// wasi-common/wiggle
|
||||||
"wiggle",
|
"wiggle",
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ path = "src/main.rs"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
winch-codegen = { workspace = true }
|
winch-codegen = { workspace = true }
|
||||||
|
winch-environ = { workspace = true }
|
||||||
winch-filetests = { workspace = true }
|
winch-filetests = { workspace = true }
|
||||||
winch-test-macros = { workspace = true }
|
winch-test-macros = { workspace = true }
|
||||||
wasmtime-environ = { workspace = true }
|
wasmtime-environ = { workspace = true }
|
||||||
|
|||||||
19
winch/codegen/src/codegen/env.rs
Normal file
19
winch/codegen/src/codegen/env.rs
Normal file
@@ -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,
|
||||||
|
}
|
||||||
@@ -7,6 +7,8 @@ use wasmparser::{BinaryReader, FuncValidator, ValType, ValidatorResources, Visit
|
|||||||
|
|
||||||
mod context;
|
mod context;
|
||||||
pub(crate) use context::*;
|
pub(crate) use context::*;
|
||||||
|
mod env;
|
||||||
|
pub use env::*;
|
||||||
|
|
||||||
/// The code generation abstraction.
|
/// The code generation abstraction.
|
||||||
pub(crate) struct CodeGen<'a, M>
|
pub(crate) struct CodeGen<'a, M>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
mod abi;
|
mod abi;
|
||||||
mod codegen;
|
mod codegen;
|
||||||
|
pub use codegen::{Callee, FuncEnv};
|
||||||
mod frame;
|
mod frame;
|
||||||
pub mod isa;
|
pub mod isa;
|
||||||
pub use isa::*;
|
pub use isa::*;
|
||||||
|
|||||||
14
winch/environ/Cargo.toml
Normal file
14
winch/environ/Cargo.toml
Normal file
@@ -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 }
|
||||||
41
winch/environ/src/lib.rs
Normal file
41
winch/environ/src/lib.rs
Normal file
@@ -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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@ edition.workspace = true
|
|||||||
winch-test-macros = {workspace = true}
|
winch-test-macros = {workspace = true}
|
||||||
target-lexicon = { workspace = true }
|
target-lexicon = { workspace = true }
|
||||||
winch-codegen = { workspace = true, features = ['all-arch'] }
|
winch-codegen = { workspace = true, features = ['all-arch'] }
|
||||||
|
winch-environ = { workspace = true }
|
||||||
wasmtime-environ = { workspace = true }
|
wasmtime-environ = { workspace = true }
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
wat = { workspace = true }
|
wat = { workspace = true }
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ mod test {
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use target_lexicon::Triple;
|
use target_lexicon::Triple;
|
||||||
use wasmtime_environ::{
|
use wasmtime_environ::{
|
||||||
wasmparser::{types::Types, Parser as WasmParser, Validator},
|
wasmparser::{Parser as WasmParser, Validator},
|
||||||
DefinedFuncIndex, FunctionBodyData, Module, ModuleEnvironment, Tunables,
|
DefinedFuncIndex, FunctionBodyData, ModuleEnvironment, Tunables,
|
||||||
};
|
};
|
||||||
use winch_codegen::isa::TargetIsa;
|
|
||||||
use winch_codegen::lookup;
|
use winch_codegen::lookup;
|
||||||
|
use winch_environ::FuncEnv;
|
||||||
use winch_test_macros::generate_file_tests;
|
use winch_test_macros::generate_file_tests;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
@@ -109,10 +109,11 @@ mod test {
|
|||||||
let body_inputs = std::mem::take(&mut translation.function_body_inputs);
|
let body_inputs = std::mem::take(&mut translation.function_body_inputs);
|
||||||
let module = &translation.module;
|
let module = &translation.module;
|
||||||
let types = translation.get_types();
|
let types = translation.get_types();
|
||||||
|
let env = FuncEnv::new(module, &types, &*isa);
|
||||||
|
|
||||||
let binding = body_inputs
|
let binding = body_inputs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|func| compile(&*isa, module, types, func).join("\n"))
|
.map(|func| compile(&env, func).join("\n"))
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
.join("\n\n");
|
.join("\n\n");
|
||||||
let actual = binding.as_str();
|
let actual = binding.as_str();
|
||||||
@@ -143,23 +144,20 @@ mod test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile(
|
fn compile(env: &FuncEnv, f: (DefinedFuncIndex, FunctionBodyData<'_>)) -> Vec<String> {
|
||||||
isa: &dyn TargetIsa,
|
let index = env.module.func_index(f.0);
|
||||||
module: &Module,
|
let sig = env
|
||||||
types: &Types,
|
.types
|
||||||
f: (DefinedFuncIndex, FunctionBodyData<'_>),
|
|
||||||
) -> Vec<String> {
|
|
||||||
let index = module.func_index(f.0);
|
|
||||||
let sig = types
|
|
||||||
.function_at(index.as_u32())
|
.function_at(index.as_u32())
|
||||||
.expect(&format!("function type at index {:?}", index.as_u32()));
|
.expect(&format!("function type at index {:?}", index.as_u32()));
|
||||||
let FunctionBodyData { body, validator } = f.1;
|
let FunctionBodyData { body, validator } = f.1;
|
||||||
let validator = validator.into_validator(Default::default());
|
let validator = validator.into_validator(Default::default());
|
||||||
|
|
||||||
let buffer = isa
|
let buffer = env
|
||||||
|
.isa
|
||||||
.compile_function(&sig, &body, validator)
|
.compile_function(&sig, &body, validator)
|
||||||
.expect("Couldn't compile function");
|
.expect("Couldn't compile function");
|
||||||
|
|
||||||
disasm(buffer.data(), isa).unwrap()
|
disasm(buffer.data(), env.isa).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,11 @@ use cranelift_codegen::settings;
|
|||||||
use std::{fs, path::PathBuf, str::FromStr};
|
use std::{fs, path::PathBuf, str::FromStr};
|
||||||
use target_lexicon::Triple;
|
use target_lexicon::Triple;
|
||||||
use wasmtime_environ::{
|
use wasmtime_environ::{
|
||||||
wasmparser::{types::Types, Parser as WasmParser, Validator},
|
wasmparser::{Parser as WasmParser, Validator},
|
||||||
DefinedFuncIndex, FunctionBodyData, Module, ModuleEnvironment, Tunables,
|
DefinedFuncIndex, FunctionBodyData, ModuleEnvironment, Tunables,
|
||||||
};
|
};
|
||||||
use winch_codegen::{lookup, TargetIsa};
|
use winch_codegen::lookup;
|
||||||
|
use winch_environ::FuncEnv;
|
||||||
use winch_filetests::disasm::disasm;
|
use winch_filetests::disasm::disasm;
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[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 body_inputs = std::mem::take(&mut translation.function_body_inputs);
|
||||||
let module = &translation.module;
|
let module = &translation.module;
|
||||||
let types = translation.get_types();
|
let types = translation.get_types();
|
||||||
|
let env = FuncEnv::new(module, &types, &*isa);
|
||||||
|
|
||||||
body_inputs
|
body_inputs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.try_for_each(|func| compile(&*isa, module, types, func))?;
|
.try_for_each(|func| compile(&env, func))?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile(
|
fn compile(env: &FuncEnv, f: (DefinedFuncIndex, FunctionBodyData<'_>)) -> Result<()> {
|
||||||
isa: &dyn TargetIsa,
|
let index = env.module.func_index(f.0);
|
||||||
module: &Module,
|
let sig = env
|
||||||
types: &Types,
|
.types
|
||||||
f: (DefinedFuncIndex, FunctionBodyData<'_>),
|
|
||||||
) -> Result<()> {
|
|
||||||
let index = module.func_index(f.0);
|
|
||||||
let sig = types
|
|
||||||
.function_at(index.as_u32())
|
.function_at(index.as_u32())
|
||||||
.expect(&format!("function type at index {:?}", index.as_u32()));
|
.expect(&format!("function type at index {:?}", index.as_u32()));
|
||||||
let FunctionBodyData { body, validator } = f.1;
|
let FunctionBodyData { body, validator } = f.1;
|
||||||
let validator = validator.into_validator(Default::default());
|
let validator = validator.into_validator(Default::default());
|
||||||
let buffer = isa
|
let buffer = env
|
||||||
|
.isa
|
||||||
.compile_function(&sig, &body, validator)
|
.compile_function(&sig, &body, validator)
|
||||||
.expect("Couldn't compile function");
|
.expect("Couldn't compile function");
|
||||||
|
|
||||||
println!("Disassembly for function: {}", index.as_u32());
|
println!("Disassembly for function: {}", index.as_u32());
|
||||||
disasm(buffer.data(), isa)?
|
disasm(buffer.data(), env.isa)?
|
||||||
.iter()
|
.iter()
|
||||||
.for_each(|s| println!("{}", s));
|
.for_each(|s| println!("{}", s));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user