winch: Initial integration with wasmtime (#6119)

* Adding in trampoline compiling method for ISA

* Adding support for indirect call to memory address

* Refactoring frame to externalize defined locals, so it removes WASM depedencies in trampoline case

* Adding initial version of trampoline for testing

* Refactoring trampoline to be re-used by other architectures

* Initial wiring for winch with wasmtime

* Add a Wasmtime CLI option to select `winch`

This is effectively an option to select the `Strategy` enumeration.

* Implement `Compiler::compile_function` for Winch

Hook this into the `TargetIsa::compile_function` hook as well. Currently
this doesn't take into account `Tunables`, but that's left as a TODO for
later.

* Filling out Winch append_code method

* Adding back in changes from previous branch

Most of these are a WIP. It's missing trampolines for x64, but a basic
one exists for aarch64. It's missing the handling of arguments that
exist on the stack.

It currently imports `cranelift_wasm::WasmFuncType` since it's what's
passed to the `Compiler` trait. It's a bit awkward to use in the
`winch_codegen` crate since it mostly operates on `wasmparser` types.
I've had to hack in a conversion to get things working. Long term, I'm
not sure it's wise to rely on this type but it seems like it's easier on
the Cranelift side when creating the stub IR.

* Small API changes to make integration easier

* Adding in new FuncEnv, only a stub for now

* Removing unneeded parts of the old PoC, and refactoring trampoline code

* Moving FuncEnv into a separate file

* More comments for trampolines

* Adding in winch integration tests for first pass

* Using new addressing method to fix stack pointer error

* Adding test for stack arguments

* Only run tests on x86 for now, it's more complete for winch

* Add in missing documentation after rebase

* Updating based on feedback in draft PR

* Fixing formatting on doc comment for argv register

* Running formatting

* Lock updates, and turning on winch feature flags during tests

* Updating configuration with comments to no longer gate Strategy enum

* Using the winch-environ FuncEnv, but it required changing the sig

* Proper comment formatting

* Removing wasmtime-winch from dev-dependencies, adding the winch feature makes this not necessary

* Update doc attr to include winch check

* Adding winch feature to doc generation, which seems to fix the feature error in CI

* Add the `component-model` feature to the cargo doc invocation in CI

To match the metadata used by the docs.rs invocation when building docs.

* Add a comment clarifying the usage of `component-model` for docs.rs

* Correctly order wasmtime-winch and winch-environ in the publish script

* Ensure x86 test dependencies are included in cfg(target_arch)

* Further constrain Winch tests to x86_64 _and_ unix

---------

Co-authored-by: Alex Crichton <alex@alexcrichton.com>
Co-authored-by: Saúl Cabrera <saulecabrera@gmail.com>
This commit is contained in:
Kevin Rizzo
2023-04-04 20:32:40 -04:00
committed by GitHub
parent 81545c3a86
commit 3a92aa3d0a
36 changed files with 663 additions and 143 deletions

View File

@@ -20,7 +20,7 @@ use anyhow::{bail, Result};
use clap::Parser;
use std::collections::HashMap;
use std::path::PathBuf;
use wasmtime::{Config, ProfilingStrategy};
use wasmtime::{Config, ProfilingStrategy, Strategy};
pub const SUPPORTED_WASM_FEATURES: &[(&str, &str)] = &[
("all", "enables all supported WebAssembly features"),
@@ -240,6 +240,12 @@ pub struct CommonOptions {
/// performance cost.
#[clap(long)]
pub relaxed_simd_deterministic: bool,
/// Explicitly specify the name of the compiler to use for WebAssembly.
///
/// Currently only `cranelift` and `winch` are supported, but not all builds
/// of Wasmtime have both built in.
#[clap(long)]
pub compiler: Option<String>,
}
impl CommonOptions {
@@ -258,6 +264,13 @@ impl CommonOptions {
pub fn config(&self, target: Option<&str>) -> Result<Config> {
let mut config = Config::new();
config.strategy(match self.compiler.as_deref() {
None => Strategy::Auto,
Some("cranelift") => Strategy::Cranelift,
Some("winch") => Strategy::Winch,
Some(s) => bail!("unknown compiler: {s}"),
});
// Set the target before setting any cranelift options, since the
// target will reset any target-specific options.
if let Some(target) = target {

View File

@@ -12,6 +12,9 @@ rust-version.workspace = true
[package.metadata.docs.rs]
rustdoc-args = ["--cfg", "nightlydoc"]
# Docs.rs will use the `component-model` feature for documentation;
# so this feature also passed in to the `cargo doc` invocation in CI.
# See .github/workflows/main.yml
features = ["component-model"]
[dependencies]
@@ -21,6 +24,7 @@ wasmtime-jit = { workspace = true }
wasmtime-cache = { workspace = true, optional = true }
wasmtime-fiber = { workspace = true, optional = true }
wasmtime-cranelift = { workspace = true, optional = true }
wasmtime-winch = { workspace = true, optional = true }
wasmtime-component-macro = { workspace = true, optional = true }
wasmtime-component-util = { workspace = true, optional = true }
target-lexicon = { workspace = true }
@@ -73,6 +77,11 @@ default = [
# precompiled WebAssembly modules.
cranelift = ["dep:wasmtime-cranelift"]
# Enables support for winch, the WebAssembly baseline compiler. The Winch compiler
# strategy in `Config` will be available. It is currently in active development
# and shouldn't be used in production applications.
winch = ["dep:wasmtime-winch"]
# Enables support for incremental compilation cache to be enabled in `Config`.
incremental-cache = ["wasmtime-cranelift?/incremental-cache"]
@@ -103,7 +112,10 @@ pooling-allocator = ["wasmtime-runtime/pooling-allocator"]
# Enables support for all architectures in Cranelift, allowing
# cross-compilation using the `wasmtime` crate's API, notably the
# `Engine::precompile_module` function.
all-arch = ["wasmtime-cranelift?/all-arch"]
all-arch = [
"wasmtime-cranelift?/all-arch",
"wasmtime-winch?/all-arch",
]
# Enables trap handling using POSIX signals instead of Mach exceptions on MacOS.
# It is useful for applications that do not bind their own exception ports and
@@ -116,8 +128,10 @@ posix-signals-on-macos = ["wasmtime-runtime/posix-signals-on-macos"]
component-model = [
"wasmtime-environ/component-model",
"wasmtime-cranelift?/component-model",
"wasmtime-winch?/component-model",
"wasmtime-runtime/component-model",
"dep:wasmtime-component-macro",
"dep:wasmtime-component-util",
"dep:encoding_rs",
]

View File

@@ -12,7 +12,7 @@ fn main() {
// frequently then all rustdoc attributes also need to be updated with the
// new condition to ensure the documentation accurately reflects when an API
// is available.
if cfg!(feature = "cranelift") {
if cfg!(feature = "cranelift") || cfg!(feature = "winch") {
println!("cargo:rustc-cfg=compiler");
}

View File

@@ -85,7 +85,7 @@ impl Component {
//
// FIXME: need to write more docs here.
#[cfg(compiler)]
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
#[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))] // see build.rs
pub fn new(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result<Component> {
let bytes = bytes.as_ref();
#[cfg(feature = "wat")]
@@ -98,7 +98,7 @@ impl Component {
//
// FIXME: need to write more docs here.
#[cfg(compiler)]
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
#[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))] // see build.rs
pub fn from_file(engine: &Engine, file: impl AsRef<Path>) -> Result<Component> {
match Self::new(
engine,
@@ -124,7 +124,7 @@ impl Component {
//
// FIXME: need to write more docs here.
#[cfg(compiler)]
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
#[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))] // see build.rs
pub fn from_binary(engine: &Engine, binary: &[u8]) -> Result<Component> {
engine
.check_compatible_with_native_host()

View File

@@ -220,7 +220,7 @@ impl Config {
///
/// This method will error if the given target triple is not supported.
#[cfg(compiler)]
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
#[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))] // see build.rs
pub fn target(&mut self, target: &str) -> Result<&mut Self> {
self.compiler_config.target =
Some(target_lexicon::Triple::from_str(target).map_err(|e| anyhow::anyhow!(e))?);
@@ -820,7 +820,7 @@ impl Config {
///
/// The default value for this is `Strategy::Auto`.
#[cfg(compiler)]
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
#[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))] // see build.rs
pub fn strategy(&mut self, strategy: Strategy) -> &mut Self {
self.compiler_config.strategy = strategy;
self
@@ -854,7 +854,7 @@ impl Config {
///
/// The default value for this is `false`
#[cfg(compiler)]
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
#[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))] // see build.rs
pub fn cranelift_debug_verifier(&mut self, enable: bool) -> &mut Self {
let val = if enable { "true" } else { "false" };
self.compiler_config
@@ -871,7 +871,7 @@ impl Config {
///
/// The default value for this is `OptLevel::None`.
#[cfg(compiler)]
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
#[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))] // see build.rs
pub fn cranelift_opt_level(&mut self, level: OptLevel) -> &mut Self {
let val = match level {
OptLevel::None => "none",
@@ -895,7 +895,7 @@ impl Config {
///
/// The default value for this is `true`.
#[cfg(compiler)]
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
#[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))] // see build.rs
#[deprecated(
since = "5.0.0",
note = "egraphs will be the default and this method will be removed in a future version."
@@ -917,7 +917,7 @@ impl Config {
///
/// The default value for this is `false`
#[cfg(compiler)]
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
#[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))] // see build.rs
pub fn cranelift_nan_canonicalization(&mut self, enable: bool) -> &mut Self {
let val = if enable { "true" } else { "false" };
self.compiler_config
@@ -943,7 +943,7 @@ impl Config {
/// cause `Engine::new` fail if the flag's name does not exist, or the value is not appropriate
/// for the flag type.
#[cfg(compiler)]
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
#[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))] // see build.rs
pub unsafe fn cranelift_flag_enable(&mut self, flag: &str) -> &mut Self {
self.compiler_config.flags.insert(flag.to_string());
self
@@ -969,7 +969,7 @@ impl Config {
/// For example, feature `wasm_backtrace` will set `unwind_info` to `true`, but if it's
/// manually set to false then it will fail.
#[cfg(compiler)]
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
#[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))] // see build.rs
pub unsafe fn cranelift_flag_set(&mut self, name: &str, value: &str) -> &mut Self {
self.compiler_config
.settings
@@ -1546,7 +1546,18 @@ impl Config {
#[cfg(compiler)]
pub(crate) fn build_compiler(&mut self) -> Result<Box<dyn wasmtime_environ::Compiler>> {
let mut compiler = match self.compiler_config.strategy {
Strategy::Auto | Strategy::Cranelift => wasmtime_cranelift::builder(),
#[cfg(feature = "cranelift")]
Strategy::Auto => wasmtime_cranelift::builder(),
#[cfg(all(feature = "winch", not(feature = "cranelift")))]
Strategy::Auto => wasmtime_winch::builder(),
#[cfg(feature = "cranelift")]
Strategy::Cranelift => wasmtime_cranelift::builder(),
#[cfg(not(feature = "cranelift"))]
Strategy::Cranelift => bail!("cranelift support not compiled in"),
#[cfg(feature = "winch")]
Strategy::Winch => wasmtime_winch::builder(),
#[cfg(not(feature = "winch"))]
Strategy::Winch => bail!("winch support not compiled in"),
};
if let Some(target) = &self.compiler_config.target {
@@ -1711,6 +1722,10 @@ pub enum Strategy {
/// Currently the default backend, Cranelift aims to be a reasonably fast
/// code generator which generates high quality machine code.
Cranelift,
/// A baseline compiler for WebAssembly, currently under active development and not ready for
/// production applications.
Winch,
}
/// Possible optimization levels for the Cranelift codegen backend.

View File

@@ -218,7 +218,7 @@ impl Engine {
/// [binary]: https://webassembly.github.io/spec/core/binary/index.html
/// [text]: https://webassembly.github.io/spec/core/text/index.html
#[cfg(compiler)]
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
#[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))] // see build.rs
pub fn precompile_module(&self, bytes: &[u8]) -> Result<Vec<u8>> {
#[cfg(feature = "wat")]
let bytes = wat::parse_bytes(&bytes)?;
@@ -229,7 +229,7 @@ impl Engine {
/// Same as [`Engine::precompile_module`] except for a
/// [`Component`](crate::component::Component)
#[cfg(compiler)]
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
#[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))] // see build.rs
#[cfg(feature = "component-model")]
#[cfg_attr(nightlydoc, doc(cfg(feature = "component-model")))]
pub fn precompile_component(&self, bytes: &[u8]) -> Result<Vec<u8>> {

View File

@@ -346,7 +346,7 @@ impl Func {
///
/// [`Trap`]: crate::Trap
#[cfg(compiler)]
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
#[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))] // see build.rs
pub fn new<T>(
store: impl AsContextMut<Data = T>,
ty: FuncType,
@@ -384,7 +384,7 @@ impl Func {
/// the `func` provided correctly interprets the argument types provided to
/// it, or that the results it produces will be of the correct type.
#[cfg(compiler)]
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
#[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))] // see build.rs
pub unsafe fn new_unchecked<T>(
mut store: impl AsContextMut<Data = T>,
ty: FuncType,

View File

@@ -275,7 +275,7 @@ impl<T> Linker<T> {
/// # }
/// ```
#[cfg(compiler)]
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
#[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))] // see build.rs
pub fn define_unknown_imports_as_traps(&mut self, module: &Module) -> anyhow::Result<()> {
for import in module.imports() {
if let Err(import_err) = self._get_by_import(&import) {
@@ -311,7 +311,7 @@ impl<T> Linker<T> {
/// # }
/// ```
#[cfg(compiler)]
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
#[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))] // see build.rs
pub fn define_unknown_imports_as_default_values(
&mut self,
module: &Module,
@@ -416,7 +416,7 @@ impl<T> Linker<T> {
///
/// For more information see [`Linker::func_wrap`].
#[cfg(compiler)]
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
#[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))] // see build.rs
pub fn func_new(
&mut self,
module: &str,
@@ -434,7 +434,7 @@ impl<T> Linker<T> {
///
/// For more information see [`Linker::func_wrap`].
#[cfg(compiler)]
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
#[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))] // see build.rs
pub unsafe fn func_new_unchecked(
&mut self,
module: &str,
@@ -754,7 +754,7 @@ impl<T> Linker<T> {
/// # }
/// ```
#[cfg(compiler)]
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
#[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))] // see build.rs
pub fn module(
&mut self,
mut store: impl AsContextMut<Data = T>,

View File

@@ -196,7 +196,7 @@ impl Module {
/// # }
/// ```
#[cfg(compiler)]
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
#[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))] // see build.rs
pub fn new(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result<Module> {
let bytes = bytes.as_ref();
#[cfg(feature = "wat")]
@@ -233,7 +233,7 @@ impl Module {
/// # }
/// ```
#[cfg(compiler)]
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
#[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))] // see build.rs
pub fn from_file(engine: &Engine, file: impl AsRef<Path>) -> Result<Module> {
match Self::new(
engine,
@@ -286,7 +286,7 @@ impl Module {
/// # }
/// ```
#[cfg(compiler)]
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
#[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))] // see build.rs
pub fn from_binary(engine: &Engine, binary: &[u8]) -> Result<Module> {
engine
.check_compatible_with_native_host()
@@ -358,7 +358,7 @@ impl Module {
/// reflect the current state of the file, not necessarily the origianl
/// state of the file.
#[cfg(compiler)]
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
#[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))] // see build.rs
pub unsafe fn from_trusted_file(engine: &Engine, file: impl AsRef<Path>) -> Result<Module> {
let mmap = MmapVec::from_file(file.as_ref())?;
if &mmap[0..4] == b"\x7fELF" {
@@ -738,7 +738,7 @@ impl Module {
/// this method can be useful to get the serialized version without
/// compiling twice.
#[cfg(compiler)]
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
#[cfg_attr(nightlydoc, doc(cfg(any(feature = "cranelift", feature = "winch"))))] // see build.rs
pub fn serialize(&self) -> Result<Vec<u8>> {
// The current representation of compiled modules within a compiled
// component means that it cannot be serialized. The mmap returned here

View File

@@ -9,6 +9,7 @@ repository = "https://github.com/bytecodealliance/wasmtime"
[dependencies]
winch-codegen = { workspace = true }
winch-environ = { workspace = true }
target-lexicon = { workspace = true }
wasmtime-environ = { workspace = true }
anyhow = { workspace = true }
@@ -19,6 +20,5 @@ wasmparser = { workspace = true }
gimli = { workspace = true }
[features]
default = ["component-model"]
component-model = ["wasmtime-environ/component-model"]
all-arch = ["winch-codegen/all-arch"]

View File

@@ -1,50 +1,136 @@
use anyhow::Result;
use cranelift_codegen::{Final, MachBufferFinalized};
use object::write::{Object, SymbolId};
use std::any::Any;
use std::sync::Mutex;
use wasmparser::FuncValidatorAllocations;
use wasmtime_cranelift_shared::obj::ModuleTextBuilder;
use wasmtime_environ::{
CompileError, DefinedFuncIndex, FuncIndex, FunctionBodyData, FunctionLoc, ModuleTranslation,
ModuleTypes, PrimaryMap, Tunables, WasmFunctionInfo,
CompileError, DefinedFuncIndex, FilePos, FuncIndex, FunctionBodyData, FunctionLoc,
ModuleTranslation, ModuleTypes, PrimaryMap, Tunables, WasmFunctionInfo,
};
use winch_codegen::TargetIsa;
use winch_environ::FuncEnv;
pub(crate) struct Compiler {
isa: Box<dyn TargetIsa>,
allocations: Mutex<Vec<FuncValidatorAllocations>>,
}
struct CompiledFunction(MachBufferFinalized<Final>);
impl Compiler {
pub fn new(isa: Box<dyn TargetIsa>) -> Self {
Self { isa }
Self {
isa,
allocations: Mutex::new(Vec::new()),
}
}
fn take_allocations(&self) -> FuncValidatorAllocations {
self.allocations
.lock()
.unwrap()
.pop()
.unwrap_or_else(Default::default)
}
fn save_allocations(&self, allocs: FuncValidatorAllocations) {
self.allocations.lock().unwrap().push(allocs)
}
}
impl wasmtime_environ::Compiler for Compiler {
fn compile_function(
&self,
_translation: &ModuleTranslation<'_>,
_index: DefinedFuncIndex,
_data: FunctionBodyData<'_>,
translation: &ModuleTranslation<'_>,
index: DefinedFuncIndex,
data: FunctionBodyData<'_>,
_tunables: &Tunables,
_types: &ModuleTypes,
) -> Result<(WasmFunctionInfo, Box<dyn Any + Send>), CompileError> {
todo!()
let index = translation.module.func_index(index);
let sig = translation.get_types().function_at(index.as_u32()).unwrap();
let FunctionBodyData { body, validator } = data;
let start_srcloc = FilePos::new(
body.get_binary_reader()
.original_position()
.try_into()
.unwrap(),
);
let mut validator = validator.into_validator(self.take_allocations());
let env = FuncEnv::new(&translation.module, translation.get_types(), &self.isa);
let buffer = self
.isa
.compile_function(&sig, &body, &env, &mut validator)
.map_err(|e| CompileError::Codegen(format!("{e:?}")));
self.save_allocations(validator.into_allocations());
let buffer = buffer?;
Ok((
WasmFunctionInfo {
start_srcloc,
stack_maps: Box::new([]),
},
Box::new(CompiledFunction(buffer)),
))
}
fn compile_host_to_wasm_trampoline(
&self,
_ty: &wasmtime_environ::WasmFuncType,
ty: &wasmtime_environ::WasmFuncType,
) -> Result<Box<dyn Any + Send>, CompileError> {
todo!()
let wasm_ty = wasmparser::FuncType::new(
ty.params().iter().copied().map(Into::into),
ty.returns().iter().copied().map(Into::into),
);
let buffer = self
.isa
.host_to_wasm_trampoline(&wasm_ty)
.map_err(|e| CompileError::Codegen(format!("{:?}", e)))?;
Ok(Box::new(CompiledFunction(buffer)))
}
fn append_code(
&self,
_obj: &mut Object<'static>,
_funcs: &[(String, Box<dyn Any + Send>)],
obj: &mut Object<'static>,
funcs: &[(String, Box<dyn Any + Send>)],
_tunables: &Tunables,
_resolve_reloc: &dyn Fn(usize, FuncIndex) -> usize,
resolve_reloc: &dyn Fn(usize, FuncIndex) -> usize,
) -> Result<Vec<(SymbolId, FunctionLoc)>> {
assert!(_funcs.is_empty());
Ok(Vec::new())
let mut builder =
ModuleTextBuilder::new(obj, self, self.isa.text_section_builder(funcs.len()));
let mut ret = Vec::with_capacity(funcs.len());
for (i, (sym, func)) in funcs.iter().enumerate() {
let func = &func.downcast_ref::<CompiledFunction>().unwrap().0;
// TODO: Implement copying over this data into the
// `ModuleTextBuilder` type. Note that this should probably be
// deduplicated with the cranelift implementation in the long run.
assert!(func.relocs().is_empty());
assert!(func.traps().is_empty());
assert!(func.stack_maps().is_empty());
let (sym, range) = builder.append_func(
&sym,
func.data(),
self.function_alignment(),
None,
&[],
|idx| resolve_reloc(i, idx),
);
let info = FunctionLoc {
start: u32::try_from(range.start).unwrap(),
length: u32::try_from(range.end - range.start).unwrap(),
};
ret.push((sym, info));
}
builder.finish();
Ok(ret)
}
fn emit_trampoline_obj(