Skip to content

Commit

Permalink
Use the wasmtime-cranelift for winch component trampolines (#8082)
Browse files Browse the repository at this point in the history
* Use wasmtime-cranelift compiler for winch trampolines

* Plumb the winch calling convention through Tunables

* Guard setting the winch_callable tunable

* Allow the trampolines field to be unused when component-model is disabled
  • Loading branch information
elliottt committed Mar 12, 2024
1 parent d29b863 commit ed0b537
Show file tree
Hide file tree
Showing 11 changed files with 84 additions and 36 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 10 additions & 8 deletions crates/cranelift-shared/src/compiled_function.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::any::Any;

use crate::{mach_reloc_to_reloc, mach_trap_to_trap, Relocation};
use cranelift_codegen::{
ir, ir::UserExternalNameRef, isa::unwind::CfaUnwindInfo, isa::unwind::UnwindInfo, Final,
Expand Down Expand Up @@ -59,29 +61,29 @@ pub struct CompiledFunctionMetadata {
}

/// Compiled function: machine code body, jump table offsets, and unwind information.
pub struct CompiledFunction<E: CompiledFuncEnv> {
pub struct CompiledFunction {
/// The machine code buffer for this function.
pub buffer: MachBufferFinalized<Final>,
/// The environment for the compiled function.
env: E,
env: Box<dyn CompiledFuncEnv + Send + 'static>,
/// The alignment for the compiled function.
pub alignment: u32,
/// The metadata for the compiled function, including unwind information
/// the function address map.
metadata: CompiledFunctionMetadata,
}

impl<E: CompiledFuncEnv> CompiledFunction<E>
where
E: CompiledFuncEnv,
{
impl CompiledFunction {
/// Creates a [CompiledFunction] from a [cranelift_codegen::MachBufferFinalized<Final>]
/// This function uses the information in the machine buffer to derive the traps and relocations
/// fields. The compiled function metadata is loaded with the default values.
pub fn new(buffer: MachBufferFinalized<Final>, env: E, alignment: u32) -> Self {
pub fn new<E>(buffer: MachBufferFinalized<Final>, env: E, alignment: u32) -> Self
where
E: Any + CompiledFuncEnv + Send + 'static,
{
Self {
buffer,
env,
env: Box::new(env),
alignment,
metadata: Default::default(),
}
Expand Down
4 changes: 2 additions & 2 deletions crates/cranelift-shared/src/obj.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
//! function body, the imported wasm function do not. The trampolines symbol
//! names have format "_trampoline_N", where N is `SignatureIndex`.

use crate::{CompiledFuncEnv, CompiledFunction, RelocationTarget};
use crate::{CompiledFunction, RelocationTarget};
use anyhow::Result;
use cranelift_codegen::binemit::Reloc;
use cranelift_codegen::ir::LibCall;
Expand Down Expand Up @@ -107,7 +107,7 @@ impl<'a> ModuleTextBuilder<'a> {
pub fn append_func(
&mut self,
name: &str,
compiled_func: &'a CompiledFunction<impl CompiledFuncEnv>,
compiled_func: &'a CompiledFunction,
resolve_reloc_target: impl Fn(FuncIndex) -> usize,
) -> (SymbolId, Range<u64>) {
let body = compiled_func.buffer.data();
Expand Down
18 changes: 8 additions & 10 deletions crates/cranelift/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ impl Default for CompilerContext {

/// A compiler that compiles a WebAssembly module with Compiler, translating
/// the Wasm to Compiler IR, optimizing it and then translating to assembly.
pub(crate) struct Compiler {
pub struct Compiler {
tunables: Tunables,
contexts: Mutex<Vec<CompilerContext>>,
isa: OwnedTargetIsa,
Expand Down Expand Up @@ -104,7 +104,7 @@ impl Drop for Compiler {
}

impl Compiler {
pub(crate) fn new(
pub fn new(
tunables: Tunables,
isa: OwnedTargetIsa,
cache_store: Option<Arc<dyn CacheStore>>,
Expand Down Expand Up @@ -460,9 +460,7 @@ impl wasmtime_environ::Compiler for Compiler {

let mut ret = Vec::with_capacity(funcs.len());
for (i, (sym, func)) in funcs.iter().enumerate() {
let func = func
.downcast_ref::<CompiledFunction<CompiledFuncEnv>>()
.unwrap();
let func = func.downcast_ref::<CompiledFunction>().unwrap();
let (sym, range) = builder.append_func(&sym, func, |idx| resolve_reloc(i, idx));
if self.tunables.generate_address_map {
let addr = func.address_map();
Expand Down Expand Up @@ -575,7 +573,7 @@ impl wasmtime_environ::Compiler for Compiler {
let functions_info = funcs
.iter()
.map(|(_, (_, func))| {
let f: &CompiledFunction<CompiledFuncEnv> = func.downcast_ref().unwrap();
let f = func.downcast_ref::<CompiledFunction>().unwrap();
f.metadata()
})
.collect();
Expand Down Expand Up @@ -725,7 +723,7 @@ impl Compiler {
&self,
ty: &WasmFuncType,
host_fn: usize,
) -> Result<CompiledFunction<CompiledFuncEnv>, CompileError> {
) -> Result<CompiledFunction, CompileError> {
let isa = &*self.isa;
let pointer_type = isa.pointer_type();
let native_call_sig = native_call_signature(isa, ty);
Expand Down Expand Up @@ -788,7 +786,7 @@ impl Compiler {
&self,
ty: &WasmFuncType,
host_fn: usize,
) -> Result<CompiledFunction<CompiledFuncEnv>, CompileError> {
) -> Result<CompiledFunction, CompileError> {
let isa = &*self.isa;
let pointer_type = isa.pointer_type();
let wasm_call_sig = wasm_call_signature(isa, ty, &self.tunables);
Expand Down Expand Up @@ -1012,7 +1010,7 @@ impl FunctionCompiler<'_> {
(builder, block0)
}

fn finish(self) -> Result<CompiledFunction<CompiledFuncEnv>, CompileError> {
fn finish(self) -> Result<CompiledFunction, CompileError> {
let (info, func) = self.finish_with_info(None)?;
assert!(info.stack_maps.is_empty());
Ok(func)
Expand All @@ -1021,7 +1019,7 @@ impl FunctionCompiler<'_> {
fn finish_with_info(
mut self,
body_and_tunables: Option<(&FunctionBody<'_>, &Tunables)>,
) -> Result<(WasmFunctionInfo, CompiledFunction<CompiledFuncEnv>), CompileError> {
) -> Result<(WasmFunctionInfo, CompiledFunction), CompileError> {
let context = &mut self.cx.codegen_context;
let isa = &*self.compiler.isa;
let (_, _code_buf) =
Expand Down
9 changes: 9 additions & 0 deletions crates/cranelift/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,15 @@ fn wasm_call_signature(
CallConv::Tail
}

// The winch calling convention is only implemented for x64 and aarch64
arch if tunables.tail_callable => {
assert!(
matches!(arch, Architecture::X86_64 | Architecture::Aarch64(_)),
"https://github.com/bytecodealliance/wasmtime/issues/6530"
);
CallConv::Winch
}

// On s390x the "wasmtime" calling convention is used to give vectors
// little-endian lane order at the ABI layer which should reduce the
// need for conversion when operating on vector function arguments. By
Expand Down
4 changes: 4 additions & 0 deletions crates/environ/src/tunables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ pub struct Tunables {

/// Whether or not Wasm functions can be tail-called or not.
pub tail_callable: bool,

/// Whether or not Wasm functions target the winch abi.
pub winch_callable: bool,
}

impl Tunables {
Expand Down Expand Up @@ -106,6 +109,7 @@ impl Tunables {
debug_adapter_modules: false,
relaxed_simd_deterministic: false,
tail_callable: false,
winch_callable: false,
}
}

Expand Down
10 changes: 10 additions & 0 deletions crates/wasmtime/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1719,6 +1719,16 @@ impl Config {
tail_callable
}

// If we're going to compile with winch, we must use the winch calling convention.
#[cfg(any(feature = "cranelift", feature = "winch"))]
{
tunables.winch_callable = match self.compiler_config.strategy {
Strategy::Auto => !cfg!(feature = "cranelift") && cfg!(feature = "winch"),
Strategy::Cranelift => false,
Strategy::Winch => true,
};
}

if tunables.static_memory_offset_guard_size < tunables.dynamic_memory_offset_guard_size {
bail!("static memory guard size cannot be smaller than dynamic memory guard size");
}
Expand Down
6 changes: 6 additions & 0 deletions crates/wasmtime/src/engine/serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ impl Metadata<'_> {
guard_before_linear_memory,
relaxed_simd_deterministic,
tail_callable,
winch_callable,

// This doesn't affect compilation, it's just a runtime setting.
dynamic_memory_growth_reserve: _,
Expand Down Expand Up @@ -402,6 +403,11 @@ impl Metadata<'_> {
"relaxed simd deterministic semantics",
)?;
Self::check_bool(tail_callable, other.tail_callable, "WebAssembly tail calls")?;
Self::check_bool(
winch_callable,
other.winch_callable,
"Winch calling convention",
)?;

Ok(())
}
Expand Down
6 changes: 5 additions & 1 deletion crates/winch/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@ wasmtime-environ = { workspace = true }
anyhow = { workspace = true }
object = { workspace = true }
cranelift-codegen = { workspace = true }
wasmtime-cranelift = { workspace = true }
wasmtime-cranelift-shared = { workspace = true }
wasmparser = { workspace = true }
gimli = { workspace = true }

[features]
component-model = ["wasmtime-environ/component-model"]
component-model = [
"wasmtime-environ/component-model",
"wasmtime-cranelift/component-model",
]
all-arch = ["winch-codegen/all-arch"]
27 changes: 18 additions & 9 deletions crates/winch/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ use winch_codegen::{isa, TargetIsa};
/// Compiler builder.
struct Builder {
inner: IsaBuilder<Result<Box<dyn TargetIsa>>>,
cranelift: Box<dyn CompilerBuilder>,
}

pub fn builder(triple: Option<Triple>) -> Result<Box<dyn CompilerBuilder>> {
Ok(Box::new(Builder {
inner: IsaBuilder::new(triple, |triple| isa::lookup(triple).map_err(|e| e.into()))?,
}))
let inner = IsaBuilder::new(triple.clone(), |triple| {
isa::lookup(triple).map_err(|e| e.into())
})?;
let cranelift = wasmtime_cranelift::builder(triple)?;
Ok(Box::new(Builder { inner, cranelift }))
}

impl CompilerBuilder for Builder {
Expand All @@ -23,31 +26,37 @@ impl CompilerBuilder for Builder {
}

fn target(&mut self, target: target_lexicon::Triple) -> Result<()> {
self.inner.target(target)?;
self.inner.target(target.clone())?;
self.cranelift.target(target)?;
Ok(())
}

fn set(&mut self, name: &str, value: &str) -> Result<()> {
self.inner.set(name, value)
self.inner.set(name, value)?;
self.cranelift.set(name, value)?;
Ok(())
}

fn enable(&mut self, name: &str) -> Result<()> {
self.inner.enable(name)
self.inner.enable(name)?;
self.cranelift.enable(name)?;
Ok(())
}

fn settings(&self) -> Vec<Setting> {
self.inner.settings()
}

fn set_tunables(&mut self, tunables: wasmtime_environ::Tunables) -> Result<()> {
let _ = tunables;
assert!(tunables.winch_callable);
self.cranelift.set_tunables(tunables)?;
Ok(())
}

fn build(&self) -> Result<Box<dyn wasmtime_environ::Compiler>> {
let isa = self.inner.build()?;

Ok(Box::new(Compiler::new(isa)))
let cranelift = self.cranelift.build()?;
Ok(Box::new(Compiler::new(isa, cranelift)))
}

fn enable_incremental_compilation(
Expand Down
17 changes: 11 additions & 6 deletions crates/winch/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ struct CompilationContext {

pub(crate) struct Compiler {
isa: Box<dyn TargetIsa>,

/// The trampoline compiler is only used for the component model currently, but will soon be
/// used for all winch trampolines. For now, mark it as unused to handle the situation where
/// the component-model feature is disabled.
#[allow(unused)]
trampolines: Box<dyn wasmtime_environ::Compiler>,
contexts: Mutex<Vec<CompilationContext>>,
}

Expand All @@ -40,9 +46,10 @@ impl wasmtime_cranelift_shared::CompiledFuncEnv for CompiledFuncEnv {
}

impl Compiler {
pub fn new(isa: Box<dyn TargetIsa>) -> Self {
pub fn new(isa: Box<dyn TargetIsa>, trampolines: Box<dyn wasmtime_environ::Compiler>) -> Self {
Self {
isa,
trampolines,
contexts: Mutex::new(Vec::new()),
}
}
Expand All @@ -68,7 +75,7 @@ impl Compiler {
/// Emit unwind info into the [`CompiledFunction`].
fn emit_unwind_info(
&self,
compiled_function: &mut CompiledFunction<CompiledFuncEnv>,
compiled_function: &mut CompiledFunction,
) -> Result<(), CompileError> {
let kind = match self.isa.triple().operating_system {
target_lexicon::OperatingSystem::Windows => UnwindInfoKind::Windows,
Expand Down Expand Up @@ -217,9 +224,7 @@ impl wasmtime_environ::Compiler for Compiler {

let mut ret = Vec::with_capacity(funcs.len());
for (i, (sym, func)) in funcs.iter().enumerate() {
let func = func
.downcast_ref::<CompiledFunction<CompiledFuncEnv>>()
.unwrap();
let func = func.downcast_ref::<CompiledFunction>().unwrap();

let (sym, range) = builder.append_func(&sym, func, |idx| resolve_reloc(i, idx));
traps.push(range.clone(), &func.traps().collect::<Vec<_>>());
Expand Down Expand Up @@ -265,7 +270,7 @@ impl wasmtime_environ::Compiler for Compiler {

#[cfg(feature = "component-model")]
fn component_compiler(&self) -> &dyn wasmtime_environ::component::ComponentCompiler {
todo!()
self.trampolines.component_compiler()
}

fn append_dwarf(
Expand Down

0 comments on commit ed0b537

Please sign in to comment.