Add a cranelift compile-time feature to wasmtime (#3206)
* Remove unnecessary into_iter/map Forgotten from a previous refactoring, this variable was already of the right type! * Move `wasmtime_jit::Compiler` into `wasmtime` This `Compiler` struct is mostly a historical artifact at this point and wasn't necessarily pulling much weight any more. This organization also doesn't lend itself super well to compiling out `cranelift` when the `Compiler` here is used for both parallel iteration configuration settings as well as compilation. The movement into `wasmtime` is relatively small, with `Module::build_artifacts` being the main function added here which is a merging of the previous functions removed from the `wasmtime-jit` crate. * Add a `cranelift` compile-time feature to `wasmtime` This commit concludes the saga of refactoring Wasmtime and making Cranelift an optional dependency by adding a new Cargo feature to the `wasmtime` crate called `cranelift`, which is enabled by default. This feature is implemented by having a new cfg for `wasmtime` itself, `cfg(compiler)`, which is used wherever compilation is necessary. This bubbles up to disable APIs such as `Module::new`, `Func::new`, `Engine::precompile_module`, and a number of `Config` methods affecting compiler configuration. Checks are added to CI that when built in this mode Wasmtime continues to successfully build. It's hoped that although this is effectively "sprinkle `#[cfg]` until things compile" this won't be too too bad to maintain over time since it's also an use case we're interested in supporting. With `cranelift` disabled the only way to create a `Module` is with the `Module::deserialize` method, which requires some form of precompiled artifact. Two consequences of this change are: * `Module::serialize` is also disabled in this mode. The reason for this is that serialized modules contain ISA/shared flags encoded in them which were used to produce the compiled code. There's no storage for this if compilation is disabled. This could probably be re-enabled in the future if necessary, but it may not end up being all that necessary. * Deserialized modules are not checked to ensure that their ISA/shared flags are compatible with the host CPU. This is actually already the case, though, with normal modules. We'll likely want to fix this in the future using a shared implementation for both these locations. Documentation should be updated to indicate that `cranelift` can be disabled, although it's not really the most prominent documentation because this is expected to be a somewhat niche use case (albeit important, just not too common). * Always enable cranelift for the C API * Fix doc example builds * Fix check tests on GitHub Actions
This commit is contained in:
24
.github/workflows/main.yml
vendored
24
.github/workflows/main.yml
vendored
@@ -75,7 +75,7 @@ jobs:
|
||||
echo "${{ runner.tool_cache }}/mdbook/bin" >> $GITHUB_PATH
|
||||
cargo install --root ${{ runner.tool_cache }}/mdbook --version ${{ env.CARGO_MDBOOK_VERSION }} mdbook
|
||||
- run: (cd docs && mdbook build)
|
||||
- run: cargo build -p wasmtime-wasi --features wasmtime/wat
|
||||
- run: cargo build -p wasmtime-wasi --features wasmtime/wat,wasmtime/cranelift
|
||||
- run: (cd docs && mdbook test -L ../target/debug/deps)
|
||||
|
||||
# Build Rust API documentation
|
||||
@@ -124,18 +124,20 @@ jobs:
|
||||
- uses: ./.github/actions/install-rust
|
||||
|
||||
# Check some feature combinations of the `wasmtime` crate
|
||||
- run: cargo check --manifest-path crates/wasmtime/Cargo.toml --no-default-features
|
||||
- run: cargo check --manifest-path crates/wasmtime/Cargo.toml --features wat
|
||||
- run: cargo check --manifest-path crates/wasmtime/Cargo.toml --features lightbeam
|
||||
- run: cargo check --manifest-path crates/wasmtime/Cargo.toml --features jitdump
|
||||
- run: cargo check --manifest-path crates/wasmtime/Cargo.toml --features cache
|
||||
- run: cargo check --manifest-path crates/wasmtime/Cargo.toml --features async
|
||||
- run: cargo check --manifest-path crates/wasmtime/Cargo.toml --features uffd
|
||||
- run: cargo check -p wasmtime --no-default-features
|
||||
- run: cargo check -p wasmtime --no-default-features --features wat
|
||||
- run: cargo check -p wasmtime --no-default-features --features lightbeam
|
||||
- run: cargo check -p wasmtime --no-default-features --features jitdump
|
||||
- run: cargo check -p wasmtime --no-default-features --features cache
|
||||
- run: cargo check -p wasmtime --no-default-features --features async
|
||||
- run: cargo check -p wasmtime --no-default-features --features uffd
|
||||
- run: cargo check -p wasmtime --no-default-features --features cranelift
|
||||
- run: cargo check -p wasmtime --no-default-features --features cranelift,wat,async,cache
|
||||
|
||||
# Check some feature combinations of the `wasmtime-c-api` crate
|
||||
- run: cargo check --manifest-path crates/c-api/Cargo.toml --no-default-features
|
||||
- run: cargo check --manifest-path crates/c-api/Cargo.toml --features wat
|
||||
- run: cargo check --manifest-path crates/c-api/Cargo.toml --features wasi
|
||||
- run: cargo check -p wasmtime-c-api --no-default-features
|
||||
- run: cargo check -p wasmtime-c-api --no-default-features --features wat
|
||||
- run: cargo check -p wasmtime-c-api --no-default-features --features wasi
|
||||
|
||||
# Check a few builds of the cranelift backend
|
||||
# - only x86 backend support,
|
||||
|
||||
6
Cargo.lock
generated
6
Cargo.lock
generated
@@ -3558,6 +3558,7 @@ dependencies = [
|
||||
"log",
|
||||
"paste",
|
||||
"psm",
|
||||
"rayon",
|
||||
"region",
|
||||
"rustc-demangle",
|
||||
"serde",
|
||||
@@ -3567,6 +3568,7 @@ dependencies = [
|
||||
"wasi-cap-std-sync",
|
||||
"wasmparser",
|
||||
"wasmtime-cache",
|
||||
"wasmtime-cranelift",
|
||||
"wasmtime-environ",
|
||||
"wasmtime-fiber",
|
||||
"wasmtime-jit",
|
||||
@@ -3667,6 +3669,7 @@ dependencies = [
|
||||
"wasmparser",
|
||||
"wasmtime",
|
||||
"wasmtime-cache",
|
||||
"wasmtime-cranelift",
|
||||
"wasmtime-environ",
|
||||
"wasmtime-fuzzing",
|
||||
"wasmtime-jit",
|
||||
@@ -3776,15 +3779,12 @@ dependencies = [
|
||||
"log",
|
||||
"more-asserts",
|
||||
"object",
|
||||
"rayon",
|
||||
"region",
|
||||
"serde",
|
||||
"target-lexicon",
|
||||
"thiserror",
|
||||
"wasmparser",
|
||||
"wasmtime-cranelift",
|
||||
"wasmtime-environ",
|
||||
"wasmtime-lightbeam",
|
||||
"wasmtime-profiling",
|
||||
"wasmtime-runtime",
|
||||
"winapi",
|
||||
|
||||
@@ -21,8 +21,9 @@ path = "src/bin/wasmtime.rs"
|
||||
doc = false
|
||||
|
||||
[dependencies]
|
||||
wasmtime = { path = "crates/wasmtime", version = "0.29.0", default-features = false, features = ['cache'] }
|
||||
wasmtime = { path = "crates/wasmtime", version = "0.29.0", default-features = false, features = ['cache', 'cranelift'] }
|
||||
wasmtime-cache = { path = "crates/cache", version = "0.29.0" }
|
||||
wasmtime-cranelift = { path = "crates/cranelift", version = "0.29.0" }
|
||||
wasmtime-environ = { path = "crates/environ", version = "0.29.0" }
|
||||
wasmtime-jit = { path = "crates/jit", version = "0.29.0" }
|
||||
wasmtime-wast = { path = "crates/wast", version = "0.29.0" }
|
||||
@@ -70,6 +71,7 @@ members = [
|
||||
"cranelift",
|
||||
"crates/bench-api",
|
||||
"crates/c-api",
|
||||
"crates/lightbeam/wasmtime",
|
||||
"crates/misc/run-examples",
|
||||
"examples/fib-debug/wasm",
|
||||
"examples/wasi/wasm",
|
||||
|
||||
@@ -20,7 +20,7 @@ doctest = false
|
||||
env_logger = "0.8"
|
||||
anyhow = "1.0"
|
||||
once_cell = "1.3"
|
||||
wasmtime = { path = "../wasmtime", default-features = false }
|
||||
wasmtime = { path = "../wasmtime", default-features = false, features = ['cranelift'] }
|
||||
wasmtime-c-api-macros = { path = "macros" }
|
||||
|
||||
# Optional dependency for the `wat2wasm` API
|
||||
|
||||
@@ -13,10 +13,7 @@ edition = "2018"
|
||||
[dependencies]
|
||||
wasmtime-environ = { path = "../environ", version = "0.29.0" }
|
||||
wasmtime-runtime = { path = "../runtime", version = "0.29.0" }
|
||||
wasmtime-cranelift = { path = "../cranelift", version = "0.29.0" }
|
||||
wasmtime-lightbeam = { path = "../lightbeam/wasmtime", version = "0.29.0", optional = true }
|
||||
wasmtime-profiling = { path = "../profiling", version = "0.29.0" }
|
||||
rayon = { version = "1.0", optional = true }
|
||||
region = "2.2.0"
|
||||
thiserror = "1.0.4"
|
||||
target-lexicon = { version = "0.12.0", default-features = false }
|
||||
@@ -34,14 +31,8 @@ addr2line = { version = "0.16.0", default-features = false }
|
||||
winapi = { version = "0.3.8", features = ["winnt", "impl-default"] }
|
||||
|
||||
[features]
|
||||
lightbeam = ["wasmtime-lightbeam"]
|
||||
jitdump = ["wasmtime-profiling/jitdump"]
|
||||
vtune = ["wasmtime-profiling/vtune"]
|
||||
parallel-compilation = ["rayon"]
|
||||
all-arch = ["wasmtime-cranelift/all-arch"]
|
||||
|
||||
# Use the old x86 backend.
|
||||
old-x86-backend = ["wasmtime-cranelift/old-x86-backend"]
|
||||
|
||||
[badges]
|
||||
maintenance = { status = "actively-developed" }
|
||||
|
||||
@@ -1,180 +0,0 @@
|
||||
//! JIT compilation.
|
||||
|
||||
use crate::instantiate::SetupError;
|
||||
#[cfg(feature = "parallel-compilation")]
|
||||
use rayon::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::BTreeMap;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::mem;
|
||||
use wasmparser::WasmFeatures;
|
||||
use wasmtime_environ::{
|
||||
Compiler as EnvCompiler, CompilerBuilder, DefinedFuncIndex, FunctionInfo, ModuleTranslation,
|
||||
PrimaryMap, Tunables, TypeTables,
|
||||
};
|
||||
|
||||
/// Select which kind of compilation to use.
|
||||
#[derive(Copy, Clone, Debug, Hash, Serialize, Deserialize, Eq, PartialEq)]
|
||||
pub enum CompilationStrategy {
|
||||
/// Let Wasmtime pick the strategy.
|
||||
Auto,
|
||||
|
||||
/// Compile all functions with Cranelift.
|
||||
Cranelift,
|
||||
|
||||
/// Compile all functions with Lightbeam.
|
||||
#[cfg(feature = "lightbeam")]
|
||||
Lightbeam,
|
||||
}
|
||||
|
||||
/// A WebAssembly code JIT compiler.
|
||||
pub struct Compiler {
|
||||
compiler: Box<dyn EnvCompiler>,
|
||||
tunables: Tunables,
|
||||
features: WasmFeatures,
|
||||
parallel_compilation: bool,
|
||||
}
|
||||
|
||||
impl Compiler {
|
||||
/// Creates a new compiler builder for the provided compilation strategy.
|
||||
pub fn builder(strategy: CompilationStrategy) -> Box<dyn CompilerBuilder> {
|
||||
match strategy {
|
||||
CompilationStrategy::Auto | CompilationStrategy::Cranelift => {
|
||||
wasmtime_cranelift::builder()
|
||||
}
|
||||
#[cfg(feature = "lightbeam")]
|
||||
CompilationStrategy::Lightbeam => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new instance of a `Compiler` from the provided compiler
|
||||
/// builder.
|
||||
pub fn new(
|
||||
builder: &dyn CompilerBuilder,
|
||||
tunables: Tunables,
|
||||
features: WasmFeatures,
|
||||
parallel_compilation: bool,
|
||||
) -> Compiler {
|
||||
Compiler {
|
||||
compiler: builder.build(),
|
||||
tunables,
|
||||
features,
|
||||
parallel_compilation,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn _assert_compiler_send_sync() {
|
||||
fn _assert<T: Send + Sync>() {}
|
||||
_assert::<Compiler>();
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub struct Compilation {
|
||||
pub obj: Vec<u8>,
|
||||
pub funcs: PrimaryMap<DefinedFuncIndex, FunctionInfo>,
|
||||
}
|
||||
|
||||
impl Compiler {
|
||||
/// Return the tunables in use by this engine.
|
||||
pub fn tunables(&self) -> &Tunables {
|
||||
&self.tunables
|
||||
}
|
||||
|
||||
/// Return the enabled wasm features.
|
||||
pub fn features(&self) -> &WasmFeatures {
|
||||
&self.features
|
||||
}
|
||||
|
||||
/// Return the underlying compiler in use
|
||||
pub fn compiler(&self) -> &dyn EnvCompiler {
|
||||
&*self.compiler
|
||||
}
|
||||
|
||||
/// Returns the target this compiler is compiling for.
|
||||
pub fn triple(&self) -> &target_lexicon::Triple {
|
||||
self.compiler.triple()
|
||||
}
|
||||
|
||||
/// Compile the given function bodies.
|
||||
pub fn compile<'data>(
|
||||
&self,
|
||||
translation: &mut ModuleTranslation,
|
||||
types: &TypeTables,
|
||||
) -> Result<Compilation, SetupError> {
|
||||
let functions = mem::take(&mut translation.function_body_inputs);
|
||||
let functions = functions.into_iter().collect::<Vec<_>>();
|
||||
|
||||
let funcs = self
|
||||
.run_maybe_parallel(functions, |(index, func)| {
|
||||
self.compiler
|
||||
.compile_function(translation, index, func, &self.tunables, types)
|
||||
})?
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
let (obj, funcs) = self.compiler.emit_obj(
|
||||
&translation,
|
||||
types,
|
||||
funcs,
|
||||
self.tunables.generate_native_debuginfo,
|
||||
)?;
|
||||
|
||||
Ok(Compilation { obj, funcs })
|
||||
}
|
||||
|
||||
/// Run the given closure in parallel if the compiler is configured to do so.
|
||||
pub(crate) fn run_maybe_parallel<
|
||||
A: Send,
|
||||
B: Send,
|
||||
E: Send,
|
||||
F: Fn(A) -> Result<B, E> + Send + Sync,
|
||||
>(
|
||||
&self,
|
||||
input: Vec<A>,
|
||||
f: F,
|
||||
) -> Result<Vec<B>, E> {
|
||||
if self.parallel_compilation {
|
||||
#[cfg(feature = "parallel-compilation")]
|
||||
return input
|
||||
.into_par_iter()
|
||||
.map(|a| f(a))
|
||||
.collect::<Result<Vec<B>, E>>();
|
||||
}
|
||||
|
||||
// In case the parallel-compilation feature is disabled or the parallel_compilation config
|
||||
// was turned off dynamically fallback to the non-parallel version.
|
||||
input
|
||||
.into_iter()
|
||||
.map(|a| f(a))
|
||||
.collect::<Result<Vec<B>, E>>()
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Compiler {
|
||||
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
||||
let Compiler {
|
||||
compiler,
|
||||
tunables,
|
||||
features,
|
||||
parallel_compilation: _,
|
||||
} = self;
|
||||
|
||||
compiler.triple().hash(hasher);
|
||||
compiler
|
||||
.flags()
|
||||
.into_iter()
|
||||
.collect::<BTreeMap<_, _>>()
|
||||
.hash(hasher);
|
||||
compiler
|
||||
.isa_flags()
|
||||
.into_iter()
|
||||
.collect::<BTreeMap<_, _>>()
|
||||
.hash(hasher);
|
||||
tunables.hash(hasher);
|
||||
features.hash(hasher);
|
||||
|
||||
// Catch accidental bugs of reusing across crate versions.
|
||||
env!("CARGO_PKG_VERSION").hash(hasher);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
//! steps.
|
||||
|
||||
use crate::code_memory::CodeMemory;
|
||||
use crate::compiler::{Compilation, Compiler};
|
||||
use crate::debug::create_gdbjit_image;
|
||||
use crate::link::link_module;
|
||||
use anyhow::Result;
|
||||
@@ -14,8 +13,8 @@ use std::sync::Arc;
|
||||
use thiserror::Error;
|
||||
use wasmtime_environ::{
|
||||
CompileError, DebugInfoData, DefinedFuncIndex, FunctionInfo, InstanceSignature,
|
||||
InstanceTypeIndex, Module, ModuleEnvironment, ModuleSignature, ModuleTranslation,
|
||||
ModuleTypeIndex, PrimaryMap, SignatureIndex, StackMapInformation, WasmFuncType,
|
||||
InstanceTypeIndex, Module, ModuleSignature, ModuleTranslation, ModuleTypeIndex, PrimaryMap,
|
||||
SignatureIndex, StackMapInformation, Tunables, WasmFuncType,
|
||||
};
|
||||
use wasmtime_profiling::ProfilingAgent;
|
||||
use wasmtime_runtime::{GdbJitImageRegistration, InstantiationError, VMFunctionBody, VMTrampoline};
|
||||
@@ -84,70 +83,32 @@ struct DebugInfo {
|
||||
}
|
||||
|
||||
impl CompilationArtifacts {
|
||||
/// Creates a `CompilationArtifacts` for a singular translated wasm module.
|
||||
///
|
||||
/// The `use_paged_init` argument controls whether or not an attempt is made to
|
||||
/// organize linear memory initialization data as entire pages or to leave
|
||||
/// the memory initialization data as individual segments.
|
||||
pub fn build(
|
||||
compiler: &Compiler,
|
||||
data: &[u8],
|
||||
use_paged_mem_init: bool,
|
||||
) -> Result<(usize, Vec<CompilationArtifacts>, TypeTables), SetupError> {
|
||||
let (main_module, translations, types) =
|
||||
ModuleEnvironment::new(compiler.tunables(), compiler.features())
|
||||
.translate(data)
|
||||
.map_err(|error| SetupError::Compile(CompileError::Wasm(error)))?;
|
||||
|
||||
let list = compiler.run_maybe_parallel::<_, _, SetupError, _>(
|
||||
translations,
|
||||
|mut translation| {
|
||||
let Compilation { obj, funcs } = compiler.compile(&mut translation, &types)?;
|
||||
|
||||
let ModuleTranslation {
|
||||
mut module,
|
||||
debuginfo,
|
||||
has_unparsed_debuginfo,
|
||||
..
|
||||
} = translation;
|
||||
|
||||
if use_paged_mem_init {
|
||||
if let Some(init) = module.memory_initialization.to_paged(&module) {
|
||||
module.memory_initialization = init;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(CompilationArtifacts {
|
||||
module: Arc::new(module),
|
||||
obj: obj.into_boxed_slice(),
|
||||
funcs: funcs
|
||||
.into_iter()
|
||||
.map(|(_, func)| FunctionInfo {
|
||||
stack_maps: func.stack_maps,
|
||||
traps: func.traps,
|
||||
address_map: func.address_map,
|
||||
})
|
||||
.collect(),
|
||||
native_debug_info_present: compiler.tunables().generate_native_debuginfo,
|
||||
debug_info: if compiler.tunables().parse_wasm_debuginfo {
|
||||
Some(debuginfo.into())
|
||||
} else {
|
||||
None
|
||||
},
|
||||
has_unparsed_debuginfo,
|
||||
})
|
||||
/// Creates a new `CompilationArtifacts` from the final results of
|
||||
/// compilation.
|
||||
pub fn new(
|
||||
translation: ModuleTranslation<'_>,
|
||||
obj: Vec<u8>,
|
||||
funcs: PrimaryMap<DefinedFuncIndex, FunctionInfo>,
|
||||
tunables: &Tunables,
|
||||
) -> CompilationArtifacts {
|
||||
let ModuleTranslation {
|
||||
module,
|
||||
debuginfo,
|
||||
has_unparsed_debuginfo,
|
||||
..
|
||||
} = translation;
|
||||
CompilationArtifacts {
|
||||
module: Arc::new(module),
|
||||
obj: obj.into_boxed_slice(),
|
||||
funcs,
|
||||
native_debug_info_present: tunables.generate_native_debuginfo,
|
||||
debug_info: if tunables.parse_wasm_debuginfo {
|
||||
Some(debuginfo.into())
|
||||
} else {
|
||||
None
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok((
|
||||
main_module,
|
||||
list,
|
||||
TypeTables {
|
||||
wasm_signatures: types.wasm_signatures,
|
||||
module_signatures: types.module_signatures,
|
||||
instance_signatures: types.instance_signatures,
|
||||
},
|
||||
))
|
||||
has_unparsed_debuginfo,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,16 +150,6 @@ pub struct CompiledModule {
|
||||
}
|
||||
|
||||
impl CompiledModule {
|
||||
/// Creates a list of compiled modules from the given list of compilation
|
||||
/// artifacts.
|
||||
pub fn from_artifacts_list(
|
||||
artifacts: Vec<CompilationArtifacts>,
|
||||
profiler: &dyn ProfilingAgent,
|
||||
compiler: &Compiler,
|
||||
) -> Result<Vec<Arc<Self>>, SetupError> {
|
||||
compiler.run_maybe_parallel(artifacts, |a| CompiledModule::from_artifacts(a, profiler))
|
||||
}
|
||||
|
||||
/// Creates `CompiledModule` directly from `CompilationArtifacts`.
|
||||
pub fn from_artifacts(
|
||||
artifacts: CompilationArtifacts,
|
||||
|
||||
@@ -21,14 +21,12 @@
|
||||
)]
|
||||
|
||||
mod code_memory;
|
||||
mod compiler;
|
||||
mod debug;
|
||||
mod instantiate;
|
||||
mod link;
|
||||
mod unwind;
|
||||
|
||||
pub use crate::code_memory::CodeMemory;
|
||||
pub use crate::compiler::{Compilation, CompilationStrategy, Compiler};
|
||||
pub use crate::instantiate::{
|
||||
CompilationArtifacts, CompiledModule, ModuleCode, SetupError, SymbolizeContext, TypeTables,
|
||||
};
|
||||
|
||||
@@ -19,6 +19,7 @@ wasmtime-jit = { path = "../jit", version = "0.29.0" }
|
||||
wasmtime-cache = { path = "../cache", version = "0.29.0", optional = true }
|
||||
wasmtime-profiling = { path = "../profiling", version = "0.29.0" }
|
||||
wasmtime-fiber = { path = "../fiber", version = "0.29.0", optional = true }
|
||||
wasmtime-cranelift = { path = "../cranelift", version = "0.29.0", optional = true }
|
||||
target-lexicon = { version = "0.12.0", default-features = false }
|
||||
wasmparser = "0.80"
|
||||
anyhow = "1.0.19"
|
||||
@@ -37,6 +38,7 @@ indexmap = "1.6"
|
||||
paste = "1.0.3"
|
||||
psm = "0.1.11"
|
||||
lazy_static = "1.4"
|
||||
rayon = { version = "1.0", optional = true }
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
winapi = "0.3.7"
|
||||
@@ -50,12 +52,16 @@ wasi-cap-std-sync = { path = "../wasi-common/cap-std-sync" }
|
||||
maintenance = { status = "actively-developed" }
|
||||
|
||||
[features]
|
||||
default = ['async', 'cache', 'wat', 'jitdump', 'parallel-compilation']
|
||||
default = ['async', 'cache', 'wat', 'jitdump', 'parallel-compilation', 'cranelift']
|
||||
|
||||
# Enables experimental support for the lightbeam codegen backend, an alternative
|
||||
# to cranelift. Requires Nightly Rust currently, and this is not enabled by
|
||||
# default.
|
||||
lightbeam = ["wasmtime-jit/lightbeam"]
|
||||
# An on-by-default feature enabling runtime compilation of WebAssembly modules
|
||||
# with the Cranelift compiler. Cranelift is the default compilation backend of
|
||||
# Wasmtime. If disabled then WebAssembly modules can only be created from
|
||||
# precompiled WebAssembly modules.
|
||||
cranelift = ["wasmtime-cranelift"]
|
||||
|
||||
# Deprecated, does not actually do anything any more.
|
||||
lightbeam = []
|
||||
|
||||
# Enables support for the `perf` jitdump profiler
|
||||
jitdump = ["wasmtime-jit/jitdump"]
|
||||
@@ -63,14 +69,14 @@ jitdump = ["wasmtime-jit/jitdump"]
|
||||
# Enables support for the `VTune` profiler
|
||||
vtune = ["wasmtime-jit/vtune"]
|
||||
|
||||
# Enables parallel compilation of WebAssembly code
|
||||
parallel-compilation = ["wasmtime-jit/parallel-compilation"]
|
||||
# Enables parallel compilation of WebAssembly code.
|
||||
parallel-compilation = ["rayon"]
|
||||
|
||||
# Enables support for automatic cache configuration to be enabled in `Config`.
|
||||
cache = ["wasmtime-cache"]
|
||||
|
||||
# Use the old x86 backend.
|
||||
old-x86-backend = ["wasmtime-jit/old-x86-backend"]
|
||||
# Use Cranelift's old x86 backend.
|
||||
old-x86-backend = ["wasmtime-cranelift/old-x86-backend"]
|
||||
|
||||
# Enables support for "async stores" as well as defining host functions as
|
||||
# `async fn` and calling functions asynchronously.
|
||||
@@ -79,8 +85,10 @@ async = ["wasmtime-fiber", "wasmtime-runtime/async"]
|
||||
# Enables userfaultfd support in the runtime's pooling allocator when building on Linux
|
||||
uffd = ["wasmtime-runtime/uffd"]
|
||||
|
||||
# Enables support for all architectures in JIT and the `wasmtime compile` CLI command.
|
||||
all-arch = ["wasmtime-jit/all-arch"]
|
||||
# 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"]
|
||||
|
||||
# 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
|
||||
|
||||
20
crates/wasmtime/build.rs
Normal file
20
crates/wasmtime/build.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
fn main() {
|
||||
// Code in the `wasmtime` crate will use #[cfg(compiler)] conditional
|
||||
// compilation when runtime compilation is supported or not. This #[cfg] is
|
||||
// defined by this build script here, and is guarded with a conditional.
|
||||
// Currently this conditional is #[cfg(feature = "cranelift")] since that's
|
||||
// the only supported compiler.
|
||||
//
|
||||
// Note that #[doc(cfg)] throughout the `wasmtime` crate points here. We
|
||||
// want the rustdoc documentation to accurately reflect the requirements for
|
||||
// APIs, so the condition here is duplicated into all #[doc(cfg)]
|
||||
// attributes. If this condition is updated to emit #[cfg(compiler)] more
|
||||
// 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") {
|
||||
println!("cargo:rustc-cfg=compiler");
|
||||
}
|
||||
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
}
|
||||
@@ -11,7 +11,6 @@ use wasmparser::WasmFeatures;
|
||||
#[cfg(feature = "cache")]
|
||||
use wasmtime_cache::CacheConfig;
|
||||
use wasmtime_environ::{CompilerBuilder, Tunables};
|
||||
use wasmtime_jit::{CompilationStrategy, Compiler};
|
||||
use wasmtime_profiling::{JitDumpAgent, NullProfilerAgent, ProfilingAgent, VTuneAgent};
|
||||
use wasmtime_runtime::{
|
||||
InstanceAllocator, OnDemandInstanceAllocator, PoolingInstanceAllocator, RuntimeMemoryCreator,
|
||||
@@ -337,6 +336,7 @@ impl Default for InstanceAllocationStrategy {
|
||||
/// This structure exposed a builder-like interface and is primarily consumed by
|
||||
/// [`Engine::new()`](crate::Engine::new)
|
||||
pub struct Config {
|
||||
#[cfg(compiler)]
|
||||
pub(crate) compiler: Box<dyn CompilerBuilder>,
|
||||
pub(crate) tunables: Tunables,
|
||||
#[cfg(feature = "cache")]
|
||||
@@ -360,7 +360,8 @@ impl Config {
|
||||
pub fn new() -> Self {
|
||||
let mut ret = Self {
|
||||
tunables: Tunables::default(),
|
||||
compiler: Compiler::builder(CompilationStrategy::Auto),
|
||||
#[cfg(compiler)]
|
||||
compiler: compiler_builder(Strategy::Auto).unwrap(),
|
||||
#[cfg(feature = "cache")]
|
||||
cache_config: CacheConfig::new_cache_disabled(),
|
||||
profiler: Arc::new(NullProfilerAgent),
|
||||
@@ -375,8 +376,11 @@ impl Config {
|
||||
deserialize_check_wasmtime_version: true,
|
||||
parallel_compilation: true,
|
||||
};
|
||||
ret.cranelift_debug_verifier(false);
|
||||
ret.cranelift_opt_level(OptLevel::Speed);
|
||||
#[cfg(compiler)]
|
||||
{
|
||||
ret.cranelift_debug_verifier(false);
|
||||
ret.cranelift_opt_level(OptLevel::Speed);
|
||||
}
|
||||
ret.wasm_reference_types(true);
|
||||
ret.wasm_multi_value(true);
|
||||
ret.wasm_bulk_memory(true);
|
||||
@@ -396,6 +400,8 @@ impl Config {
|
||||
/// # Errors
|
||||
///
|
||||
/// This method will error if the given target triple is not supported.
|
||||
#[cfg(compiler)]
|
||||
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
|
||||
pub fn target(&mut self, target: &str) -> Result<&mut Self> {
|
||||
use std::str::FromStr;
|
||||
self.compiler
|
||||
@@ -655,9 +661,12 @@ impl Config {
|
||||
pub fn wasm_reference_types(&mut self, enable: bool) -> &mut Self {
|
||||
self.features.reference_types = enable;
|
||||
|
||||
self.compiler
|
||||
.set("enable_safepoints", if enable { "true" } else { "false" })
|
||||
.unwrap();
|
||||
#[cfg(compiler)]
|
||||
{
|
||||
self.compiler
|
||||
.set("enable_safepoints", if enable { "true" } else { "false" })
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// The reference types proposal depends on the bulk memory proposal.
|
||||
if enable {
|
||||
@@ -689,10 +698,13 @@ impl Config {
|
||||
/// [proposal]: https://github.com/webassembly/simd
|
||||
pub fn wasm_simd(&mut self, enable: bool) -> &mut Self {
|
||||
self.features.simd = enable;
|
||||
let val = if enable { "true" } else { "false" };
|
||||
self.compiler
|
||||
.set("enable_simd", val)
|
||||
.expect("should be valid flag");
|
||||
#[cfg(compiler)]
|
||||
{
|
||||
let val = if enable { "true" } else { "false" };
|
||||
self.compiler
|
||||
.set("enable_simd", val)
|
||||
.expect("should be valid flag");
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
@@ -780,18 +792,10 @@ impl Config {
|
||||
/// Some compilation strategies require compile-time options of `wasmtime`
|
||||
/// itself to be set, but if they're not set and the strategy is specified
|
||||
/// here then an error will be returned.
|
||||
#[cfg(compiler)]
|
||||
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
|
||||
pub fn strategy(&mut self, strategy: Strategy) -> Result<&mut Self> {
|
||||
let strategy = match strategy {
|
||||
Strategy::Auto => CompilationStrategy::Auto,
|
||||
Strategy::Cranelift => CompilationStrategy::Cranelift,
|
||||
#[cfg(feature = "lightbeam")]
|
||||
Strategy::Lightbeam => CompilationStrategy::Lightbeam,
|
||||
#[cfg(not(feature = "lightbeam"))]
|
||||
Strategy::Lightbeam => {
|
||||
anyhow::bail!("lightbeam compilation strategy wasn't enabled at compile time");
|
||||
}
|
||||
};
|
||||
self.compiler = Compiler::builder(strategy);
|
||||
self.compiler = compiler_builder(strategy)?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
@@ -816,6 +820,8 @@ impl Config {
|
||||
/// developers of wasmtime itself.
|
||||
///
|
||||
/// The default value for this is `false`
|
||||
#[cfg(compiler)]
|
||||
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
|
||||
pub fn cranelift_debug_verifier(&mut self, enable: bool) -> &mut Self {
|
||||
let val = if enable { "true" } else { "false" };
|
||||
self.compiler
|
||||
@@ -831,6 +837,8 @@ impl Config {
|
||||
/// more information see the documentation of [`OptLevel`].
|
||||
///
|
||||
/// The default value for this is `OptLevel::None`.
|
||||
#[cfg(compiler)]
|
||||
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
|
||||
pub fn cranelift_opt_level(&mut self, level: OptLevel) -> &mut Self {
|
||||
let val = match level {
|
||||
OptLevel::None => "none",
|
||||
@@ -851,6 +859,8 @@ impl Config {
|
||||
/// This is not required by the WebAssembly spec, so it is not enabled by default.
|
||||
///
|
||||
/// The default value for this is `false`
|
||||
#[cfg(compiler)]
|
||||
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
|
||||
pub fn cranelift_nan_canonicalization(&mut self, enable: bool) -> &mut Self {
|
||||
let val = if enable { "true" } else { "false" };
|
||||
self.compiler
|
||||
@@ -873,6 +883,8 @@ impl Config {
|
||||
/// # Errors
|
||||
///
|
||||
/// This method can fail if the flag's name does not exist.
|
||||
#[cfg(compiler)]
|
||||
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
|
||||
pub unsafe fn cranelift_flag_enable(&mut self, flag: &str) -> Result<&mut Self> {
|
||||
self.compiler.enable(flag)?;
|
||||
Ok(self)
|
||||
@@ -891,6 +903,8 @@ impl Config {
|
||||
///
|
||||
/// This method can 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
|
||||
pub unsafe fn cranelift_flag_set(&mut self, name: &str, value: &str) -> Result<&mut Self> {
|
||||
self.compiler.set(name, value)?;
|
||||
Ok(self)
|
||||
@@ -1203,17 +1217,6 @@ impl Config {
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn build_compiler(&self, allocator: &dyn InstanceAllocator) -> Compiler {
|
||||
let mut tunables = self.tunables.clone();
|
||||
allocator.adjust_tunables(&mut tunables);
|
||||
Compiler::new(
|
||||
&*self.compiler,
|
||||
tunables,
|
||||
self.features,
|
||||
self.parallel_compilation,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn build_allocator(&self) -> Result<Box<dyn InstanceAllocator>> {
|
||||
#[cfg(feature = "async")]
|
||||
let stack_size = self.async_stack_size;
|
||||
@@ -1241,6 +1244,19 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(compiler)]
|
||||
fn compiler_builder(strategy: Strategy) -> Result<Box<dyn CompilerBuilder>> {
|
||||
match strategy {
|
||||
Strategy::Auto | Strategy::Cranelift => Ok(wasmtime_cranelift::builder()),
|
||||
#[cfg(feature = "lightbeam")]
|
||||
Strategy::Lightbeam => unimplemented!(),
|
||||
#[cfg(not(feature = "lightbeam"))]
|
||||
Strategy::Lightbeam => {
|
||||
anyhow::bail!("lightbeam compilation strategy wasn't enabled at compile time");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn round_up_to_pages(val: u64) -> u64 {
|
||||
let page_size = region::page::size() as u64;
|
||||
debug_assert!(page_size.is_power_of_two());
|
||||
@@ -1258,6 +1274,7 @@ impl Default for Config {
|
||||
impl Clone for Config {
|
||||
fn clone(&self) -> Config {
|
||||
Config {
|
||||
#[cfg(compiler)]
|
||||
compiler: self.compiler.clone(),
|
||||
tunables: self.tunables.clone(),
|
||||
#[cfg(feature = "cache")]
|
||||
@@ -1279,8 +1296,8 @@ impl Clone for Config {
|
||||
|
||||
impl fmt::Debug for Config {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("Config")
|
||||
.field("debug_info", &self.tunables.generate_native_debuginfo)
|
||||
let mut f = f.debug_struct("Config");
|
||||
f.field("debug_info", &self.tunables.generate_native_debuginfo)
|
||||
.field("parse_wasm_debuginfo", &self.tunables.parse_wasm_debuginfo)
|
||||
.field("wasm_threads", &self.features.threads)
|
||||
.field("wasm_reference_types", &self.features.reference_types)
|
||||
@@ -1305,9 +1322,12 @@ impl fmt::Debug for Config {
|
||||
"guard_before_linear_memory",
|
||||
&self.tunables.guard_before_linear_memory,
|
||||
)
|
||||
.field("parallel_compilation", &self.parallel_compilation)
|
||||
.field("compiler", &self.compiler)
|
||||
.finish()
|
||||
.field("parallel_compilation", &self.parallel_compilation);
|
||||
#[cfg(compiler)]
|
||||
{
|
||||
f.field("compiler", &self.compiler);
|
||||
}
|
||||
f.finish()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use crate::signatures::SignatureRegistry;
|
||||
use crate::{Config, Trap};
|
||||
use anyhow::Result;
|
||||
#[cfg(feature = "parallel-compilation")]
|
||||
use rayon::prelude::*;
|
||||
use std::sync::Arc;
|
||||
#[cfg(feature = "cache")]
|
||||
use wasmtime_cache::CacheConfig;
|
||||
use wasmtime_jit::Compiler;
|
||||
use wasmtime_runtime::{debug_builtins, InstanceAllocator};
|
||||
|
||||
/// An `Engine` which is a global context for compilation and management of wasm
|
||||
@@ -36,7 +37,8 @@ pub struct Engine {
|
||||
|
||||
struct EngineInner {
|
||||
config: Config,
|
||||
compiler: Compiler,
|
||||
#[cfg(compiler)]
|
||||
compiler: Box<dyn wasmtime_environ::Compiler>,
|
||||
allocator: Box<dyn InstanceAllocator>,
|
||||
signatures: SignatureRegistry,
|
||||
}
|
||||
@@ -50,13 +52,17 @@ impl Engine {
|
||||
// as configuring signals, vectored exception handlers, etc.
|
||||
wasmtime_runtime::init_traps(crate::module::GlobalModuleRegistry::is_wasm_pc);
|
||||
debug_builtins::ensure_exported();
|
||||
let allocator = config.build_allocator()?;
|
||||
|
||||
let registry = SignatureRegistry::new();
|
||||
let mut config = config.clone();
|
||||
let allocator = config.build_allocator()?;
|
||||
allocator.adjust_tunables(&mut config.tunables);
|
||||
|
||||
Ok(Engine {
|
||||
inner: Arc::new(EngineInner {
|
||||
config: config.clone(),
|
||||
compiler: config.build_compiler(allocator.as_ref()),
|
||||
#[cfg(compiler)]
|
||||
compiler: config.compiler.build(),
|
||||
config,
|
||||
allocator,
|
||||
signatures: registry,
|
||||
}),
|
||||
@@ -90,8 +96,9 @@ impl Engine {
|
||||
&self.inner.config
|
||||
}
|
||||
|
||||
pub(crate) fn compiler(&self) -> &Compiler {
|
||||
&self.inner.compiler
|
||||
#[cfg(compiler)]
|
||||
pub(crate) fn compiler(&self) -> &dyn wasmtime_environ::Compiler {
|
||||
&*self.inner.compiler
|
||||
}
|
||||
|
||||
pub(crate) fn allocator(&self) -> &dyn InstanceAllocator {
|
||||
@@ -134,20 +141,39 @@ 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
|
||||
pub fn precompile_module(&self, bytes: &[u8]) -> Result<Vec<u8>> {
|
||||
const USE_PAGED_MEM_INIT: bool = cfg!(all(feature = "uffd", target_os = "linux"));
|
||||
|
||||
#[cfg(feature = "wat")]
|
||||
let bytes = wat::parse_bytes(&bytes)?;
|
||||
let (_, artifacts, types) = crate::Module::build_artifacts(self, &bytes)?;
|
||||
crate::module::SerializedModule::from_artifacts(self, &artifacts, &types).to_bytes()
|
||||
}
|
||||
|
||||
let (_, artifacts, types) = wasmtime_jit::CompilationArtifacts::build(
|
||||
&self.inner.compiler,
|
||||
&bytes,
|
||||
USE_PAGED_MEM_INIT,
|
||||
)?;
|
||||
pub(crate) fn run_maybe_parallel<
|
||||
A: Send,
|
||||
B: Send,
|
||||
E: Send,
|
||||
F: Fn(A) -> Result<B, E> + Send + Sync,
|
||||
>(
|
||||
&self,
|
||||
input: Vec<A>,
|
||||
f: F,
|
||||
) -> Result<Vec<B>, E> {
|
||||
if self.config().parallel_compilation {
|
||||
#[cfg(feature = "parallel-compilation")]
|
||||
return input
|
||||
.into_par_iter()
|
||||
.map(|a| f(a))
|
||||
.collect::<Result<Vec<B>, E>>();
|
||||
}
|
||||
|
||||
crate::module::SerializedModule::from_artifacts(&self.inner.compiler, &artifacts, &types)
|
||||
.to_bytes()
|
||||
// In case the parallel-compilation feature is disabled or the parallel_compilation config
|
||||
// was turned off dynamically fallback to the non-parallel version.
|
||||
input
|
||||
.into_iter()
|
||||
.map(|a| f(a))
|
||||
.collect::<Result<Vec<B>, E>>()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -300,6 +300,8 @@ impl Func {
|
||||
///
|
||||
/// For more information about `Send + Sync + 'static` requirements on the
|
||||
/// `func`, see [`Func::wrap`](#why-send--sync--static).
|
||||
#[cfg(compiler)]
|
||||
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
|
||||
pub fn new<T>(
|
||||
mut store: impl AsContextMut<Data = T>,
|
||||
ty: FuncType,
|
||||
@@ -378,8 +380,8 @@ impl Func {
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[cfg(feature = "async")]
|
||||
#[cfg_attr(nightlydoc, doc(cfg(feature = "async")))]
|
||||
#[cfg(all(feature = "async", feature = "cranelift"))]
|
||||
#[cfg_attr(nightlydoc, doc(cfg(all(feature = "async", feature = "cranelift"))))]
|
||||
pub fn new_async<T, F>(store: impl AsContextMut<Data = T>, ty: FuncType, func: F) -> Func
|
||||
where
|
||||
F: for<'a> Fn(
|
||||
@@ -1883,6 +1885,7 @@ pub(crate) struct HostFunc {
|
||||
|
||||
impl HostFunc {
|
||||
/// Analog of [`Func::new`]
|
||||
#[cfg(compiler)]
|
||||
pub fn new<T>(
|
||||
engine: &Engine,
|
||||
ty: FuncType,
|
||||
|
||||
@@ -234,6 +234,13 @@
|
||||
//! crate. Be sure to check the API you're using to see if any crate features
|
||||
//! are enabled.
|
||||
//!
|
||||
//! * `cranelift` - Enabled by default, this features enables using Cranelift at
|
||||
//! runtime to compile a WebAssembly module to native code. This feature is
|
||||
//! required to process and compile new WebAssembly modules. If this feature
|
||||
//! is disabled then the only way to create a [`Module`] is to use the
|
||||
//! [`Module::deserialize`] function with a precompiled artifact (typically
|
||||
//! compiled with the same version of Wasmtime, just somewhere else).
|
||||
//!
|
||||
//! * `cache` - Enabled by default, this feature adds support for wasmtime to
|
||||
//! perform internal caching of modules in a global location. This must still
|
||||
//! be enabled explicitly through [`Config::cache_config_load`] or
|
||||
@@ -358,7 +365,7 @@
|
||||
//! ```
|
||||
|
||||
#![allow(unknown_lints)]
|
||||
#![deny(missing_docs, broken_intra_doc_links)]
|
||||
#![deny(missing_docs, rustdoc::broken_intra_doc_links)]
|
||||
#![doc(test(attr(deny(warnings))))]
|
||||
#![doc(test(attr(allow(dead_code, unused_variables, unused_mut))))]
|
||||
#![cfg_attr(nightlydoc, feature(doc_cfg))]
|
||||
|
||||
@@ -289,6 +289,8 @@ impl<T> Linker<T> {
|
||||
/// Creates a [`Func::new`]-style function named in this linker.
|
||||
///
|
||||
/// For more information see [`Linker::func_wrap`].
|
||||
#[cfg(compiler)]
|
||||
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
|
||||
pub fn func_new(
|
||||
&mut self,
|
||||
module: &str,
|
||||
@@ -305,8 +307,8 @@ impl<T> Linker<T> {
|
||||
/// Creates a [`Func::new_async`]-style function named in this linker.
|
||||
///
|
||||
/// For more information see [`Linker::func_wrap`].
|
||||
#[cfg(feature = "async")]
|
||||
#[cfg_attr(nightlydoc, doc(cfg(feature = "async")))]
|
||||
#[cfg(all(feature = "async", feature = "cranelift"))]
|
||||
#[cfg_attr(nightlydoc, doc(cfg(all(feature = "async", feature = "cranelift"))))]
|
||||
pub fn func_new_async<F>(
|
||||
&mut self,
|
||||
module: &str,
|
||||
@@ -587,6 +589,8 @@ impl<T> Linker<T> {
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[cfg(compiler)]
|
||||
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
|
||||
pub fn module(
|
||||
&mut self,
|
||||
mut store: impl AsContextMut<Data = T>,
|
||||
@@ -655,8 +659,8 @@ impl<T> Linker<T> {
|
||||
/// Define automatic instantiations of a [`Module`] in this linker.
|
||||
///
|
||||
/// This is the same as [`Linker::module`], except for async `Store`s.
|
||||
#[cfg(feature = "async")]
|
||||
#[cfg_attr(nightlydoc, doc(cfg(feature = "async")))]
|
||||
#[cfg(all(feature = "async", feature = "cranelift"))]
|
||||
#[cfg_attr(nightlydoc, doc(cfg(all(feature = "async", feature = "cranelift"))))]
|
||||
pub async fn module_async(
|
||||
&mut self,
|
||||
mut store: impl AsContextMut<Data = T>,
|
||||
|
||||
@@ -5,12 +5,11 @@ use crate::{
|
||||
use crate::{Engine, ModuleType};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use std::fs;
|
||||
use std::mem;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use wasmparser::Validator;
|
||||
#[cfg(feature = "cache")]
|
||||
use wasmtime_cache::ModuleCacheEntry;
|
||||
use wasmtime_environ::{ModuleIndex, PrimaryMap};
|
||||
use wasmtime_environ::{ModuleEnvironment, ModuleIndex, PrimaryMap};
|
||||
use wasmtime_jit::{CompilationArtifacts, CompiledModule, TypeTables};
|
||||
|
||||
mod registry;
|
||||
@@ -176,6 +175,8 @@ impl Module {
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[cfg(compiler)]
|
||||
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
|
||||
pub fn new(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result<Module> {
|
||||
let bytes = bytes.as_ref();
|
||||
#[cfg(feature = "wat")]
|
||||
@@ -187,6 +188,8 @@ impl Module {
|
||||
/// data. The provided `name` will be used in traps/backtrace details.
|
||||
///
|
||||
/// See [`Module::new`] for other details.
|
||||
#[cfg(compiler)]
|
||||
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
|
||||
pub fn new_with_name(engine: &Engine, bytes: impl AsRef<[u8]>, name: &str) -> Result<Module> {
|
||||
let mut module = Self::new(engine, bytes.as_ref())?;
|
||||
Arc::get_mut(&mut Arc::get_mut(&mut module.inner).unwrap().module)
|
||||
@@ -225,6 +228,8 @@ impl Module {
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[cfg(compiler)]
|
||||
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
|
||||
pub fn from_file(engine: &Engine, file: impl AsRef<Path>) -> Result<Module> {
|
||||
match Self::new(
|
||||
engine,
|
||||
@@ -276,9 +281,11 @@ impl Module {
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[cfg(compiler)]
|
||||
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
|
||||
pub fn from_binary(engine: &Engine, binary: &[u8]) -> Result<Module> {
|
||||
// Check to see that the config's target matches the host
|
||||
let target = engine.compiler().compiler().triple();
|
||||
let target = engine.compiler().triple();
|
||||
if *target != target_lexicon::Triple::host() {
|
||||
bail!(
|
||||
"target '{}' specified in the configuration does not match the host",
|
||||
@@ -290,40 +297,111 @@ impl Module {
|
||||
// would be inferred for the host, otherwise the JIT might produce unrunnable code
|
||||
// for the features the host's CPU actually has.
|
||||
|
||||
const USE_PAGED_MEM_INIT: bool = cfg!(all(feature = "uffd", target_os = "linux"));
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "cache")] {
|
||||
let (main_module, artifacts, types) = ModuleCacheEntry::new(
|
||||
let (main_module, artifacts, types) = wasmtime_cache::ModuleCacheEntry::new(
|
||||
"wasmtime",
|
||||
engine.cache_config(),
|
||||
)
|
||||
.get_data((engine.compiler(), binary), |(compiler, binary)| {
|
||||
CompilationArtifacts::build(
|
||||
compiler,
|
||||
binary,
|
||||
USE_PAGED_MEM_INIT,
|
||||
)
|
||||
.get_data((HashedEngineCompileEnv(engine), binary), |(engine, binary)| {
|
||||
Module::build_artifacts(engine.0, binary)
|
||||
})?;
|
||||
} else {
|
||||
let (main_module, artifacts, types) =
|
||||
CompilationArtifacts::build(
|
||||
engine.compiler(),
|
||||
binary,
|
||||
USE_PAGED_MEM_INIT,
|
||||
)?;
|
||||
Module::build_artifacts(engine, binary)?;
|
||||
}
|
||||
};
|
||||
|
||||
let modules = CompiledModule::from_artifacts_list(
|
||||
artifacts,
|
||||
&*engine.config().profiler,
|
||||
engine.compiler(),
|
||||
)?;
|
||||
let modules = engine.run_maybe_parallel(artifacts, |a| {
|
||||
CompiledModule::from_artifacts(a, &*engine.config().profiler)
|
||||
})?;
|
||||
|
||||
Self::from_parts(engine, modules, main_module, Arc::new(types), &[])
|
||||
}
|
||||
|
||||
/// Converts an input binary-encoded WebAssembly module to compilation
|
||||
/// artifacts and type information.
|
||||
///
|
||||
/// This is where compilation actually happens of WebAssembly modules and
|
||||
/// translation/parsing/validation of the binary input occurs. The actual
|
||||
/// result here is a triple of:
|
||||
///
|
||||
/// * The index into the second field of the "main module". The "main
|
||||
/// module" in this case is the outermost module described by the `wasm`
|
||||
/// input, and is here for the module linking proposal.
|
||||
/// * A list of `CompilationArtifacts` for each module found within `wasm`.
|
||||
/// Note that if module linking is disabled then this list will always
|
||||
/// have a size of exactly 1.
|
||||
/// * Type information about all the modules returned. All returned modules
|
||||
/// have local type information with indices that refer to these returned
|
||||
/// tables.
|
||||
#[cfg(compiler)]
|
||||
pub(crate) fn build_artifacts(
|
||||
engine: &Engine,
|
||||
wasm: &[u8],
|
||||
) -> Result<(usize, Vec<CompilationArtifacts>, TypeTables)> {
|
||||
let tunables = &engine.config().tunables;
|
||||
|
||||
// First a `ModuleEnvironment` is created which records type information
|
||||
// about the wasm module. This is where the WebAssembly is parsed and
|
||||
// validated. Afterwards `types` will have all the type information for
|
||||
// this module.
|
||||
let (main_module, translations, types) =
|
||||
ModuleEnvironment::new(tunables, &engine.config().features)
|
||||
.translate(wasm)
|
||||
.context("failed to parse WebAssembly module")?;
|
||||
|
||||
// Perform a two-level map/reduce here to get the final list of
|
||||
// compilation artifacts. The first level of map/reduce maps over all
|
||||
// modules found and reduces to collection into a vector. The second
|
||||
// level of map/reduce here maps over all functions within each wasm
|
||||
// module found and collects into an ELF image via `emit_obj`.
|
||||
let list = engine.run_maybe_parallel(translations, |mut translation| -> Result<_> {
|
||||
let functions = mem::take(&mut translation.function_body_inputs);
|
||||
let functions = functions.into_iter().collect::<Vec<_>>();
|
||||
|
||||
let funcs = engine
|
||||
.run_maybe_parallel(functions, |(index, func)| {
|
||||
engine
|
||||
.compiler()
|
||||
.compile_function(&translation, index, func, tunables, &types)
|
||||
})?
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
let (obj, funcs) = engine.compiler().emit_obj(
|
||||
&translation,
|
||||
&types,
|
||||
funcs,
|
||||
tunables.generate_native_debuginfo,
|
||||
)?;
|
||||
|
||||
// If configured, attempt to use paged memory initialization
|
||||
// instead of the default mode of memory initialization
|
||||
if cfg!(all(feature = "uffd", target_os = "linux")) {
|
||||
if let Some(init) = translation
|
||||
.module
|
||||
.memory_initialization
|
||||
.to_paged(&translation.module)
|
||||
{
|
||||
translation.module.memory_initialization = init;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(CompilationArtifacts::new(translation, obj, funcs, tunables))
|
||||
})?;
|
||||
|
||||
Ok((
|
||||
main_module,
|
||||
list,
|
||||
TypeTables {
|
||||
wasm_signatures: types.wasm_signatures,
|
||||
module_signatures: types.module_signatures,
|
||||
instance_signatures: types.instance_signatures,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
/// Deserializes an in-memory compiled module previously created with
|
||||
/// [`Module::serialize`] or [`Engine::precompile_module`].
|
||||
///
|
||||
@@ -499,6 +577,8 @@ impl Module {
|
||||
///
|
||||
/// Use `Module::new` or `Module::from_binary` to create the module
|
||||
/// from the bytes.
|
||||
#[cfg(compiler)]
|
||||
#[cfg_attr(nightlydoc, doc(cfg(feature = "cranelift")))] // see build.rs
|
||||
pub fn serialize(&self) -> Result<Vec<u8>> {
|
||||
SerializedModule::new(self).to_bytes()
|
||||
}
|
||||
@@ -794,3 +874,41 @@ fn _assert_send_sync() {
|
||||
fn _assert<T: Send + Sync>() {}
|
||||
_assert::<Module>();
|
||||
}
|
||||
|
||||
/// This is a helper struct used when caching to hash the state of an `Engine`
|
||||
/// used for module compilation.
|
||||
///
|
||||
/// The hash computed for this structure is used to key the global wasmtime
|
||||
/// cache and dictates whether artifacts are reused. Consequently the contents
|
||||
/// of this hash dictate when artifacts are or aren't re-used.
|
||||
#[cfg(all(feature = "cache", compiler))]
|
||||
struct HashedEngineCompileEnv<'a>(&'a Engine);
|
||||
|
||||
#[cfg(all(feature = "cache", compiler))]
|
||||
impl std::hash::Hash for HashedEngineCompileEnv<'_> {
|
||||
fn hash<H: std::hash::Hasher>(&self, hasher: &mut H) {
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
// Hash the compiler's state based on its target and configuration.
|
||||
let compiler = self.0.compiler();
|
||||
compiler.triple().hash(hasher);
|
||||
compiler
|
||||
.flags()
|
||||
.into_iter()
|
||||
.collect::<BTreeMap<_, _>>()
|
||||
.hash(hasher);
|
||||
compiler
|
||||
.isa_flags()
|
||||
.into_iter()
|
||||
.collect::<BTreeMap<_, _>>()
|
||||
.hash(hasher);
|
||||
|
||||
// Hash configuration state read for compilation
|
||||
let config = self.0.config();
|
||||
config.tunables.hash(hasher);
|
||||
config.features.hash(hasher);
|
||||
|
||||
// Catch accidental bugs of reusing across crate versions.
|
||||
env!("CARGO_PKG_VERSION").hash(hasher);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use wasmtime_environ::{FlagValue, Tunables};
|
||||
use wasmtime_jit::{CompilationArtifacts, CompiledModule, Compiler, TypeTables};
|
||||
use wasmtime_environ::{Compiler, FlagValue, Tunables};
|
||||
use wasmtime_jit::{CompilationArtifacts, CompiledModule, TypeTables};
|
||||
|
||||
const HEADER: &[u8] = b"\0wasmtime-aot";
|
||||
|
||||
@@ -162,8 +162,8 @@ pub struct SerializedModule<'a> {
|
||||
}
|
||||
|
||||
impl<'a> SerializedModule<'a> {
|
||||
#[cfg(compiler)]
|
||||
pub fn new(module: &'a Module) -> Self {
|
||||
let compiler = module.engine().compiler();
|
||||
let artifacts = module
|
||||
.inner
|
||||
.artifact_upvars
|
||||
@@ -181,38 +181,40 @@ impl<'a> SerializedModule<'a> {
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Self::with_data(
|
||||
compiler,
|
||||
module.engine(),
|
||||
artifacts,
|
||||
module_upvars,
|
||||
MyCow::Borrowed(module.types()),
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(compiler)]
|
||||
pub fn from_artifacts(
|
||||
compiler: &Compiler,
|
||||
engine: &Engine,
|
||||
artifacts: &'a Vec<CompilationArtifacts>,
|
||||
types: &'a TypeTables,
|
||||
) -> Self {
|
||||
Self::with_data(
|
||||
compiler,
|
||||
engine,
|
||||
artifacts.iter().map(MyCow::Borrowed).collect(),
|
||||
Vec::new(),
|
||||
MyCow::Borrowed(types),
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(compiler)]
|
||||
fn with_data(
|
||||
compiler: &Compiler,
|
||||
engine: &Engine,
|
||||
artifacts: Vec<MyCow<'a, CompilationArtifacts>>,
|
||||
module_upvars: Vec<SerializedModuleUpvar>,
|
||||
types: MyCow<'a, TypeTables>,
|
||||
) -> Self {
|
||||
Self {
|
||||
target: compiler.triple().to_string(),
|
||||
shared_flags: compiler.compiler().flags(),
|
||||
isa_flags: compiler.compiler().isa_flags(),
|
||||
tunables: compiler.tunables().clone(),
|
||||
features: compiler.features().into(),
|
||||
target: engine.compiler().triple().to_string(),
|
||||
shared_flags: engine.compiler().flags(),
|
||||
isa_flags: engine.compiler().isa_flags(),
|
||||
tunables: engine.config().tunables.clone(),
|
||||
features: (&engine.config().features).into(),
|
||||
artifacts,
|
||||
module_upvars,
|
||||
types,
|
||||
@@ -220,22 +222,32 @@ impl<'a> SerializedModule<'a> {
|
||||
}
|
||||
|
||||
pub fn into_module(mut self, engine: &Engine) -> Result<Module> {
|
||||
let compiler = engine.compiler();
|
||||
// Verify that the module we're loading matches the triple that `engine`
|
||||
// is configured for. If compilation is disabled within engine then the
|
||||
// assumed triple is the host itself.
|
||||
#[cfg(compiler)]
|
||||
let engine_triple = engine.compiler().triple();
|
||||
#[cfg(not(compiler))]
|
||||
let engine_triple = &target_lexicon::Triple::host();
|
||||
self.check_triple(engine_triple)?;
|
||||
|
||||
self.check_triple(compiler)?;
|
||||
self.check_shared_flags(compiler)?;
|
||||
self.check_isa_flags(compiler)?;
|
||||
self.check_tunables(compiler)?;
|
||||
self.check_features(compiler)?;
|
||||
// FIXME: Similar to `Module::from_binary` it should likely be validated
|
||||
// here that when `cfg(not(compiler))` is true the isa/shared flags
|
||||
// enabled for this precompiled module are compatible with the host
|
||||
// itself, which `engine` is assumed to be running code for.
|
||||
#[cfg(compiler)]
|
||||
{
|
||||
let compiler = engine.compiler();
|
||||
self.check_shared_flags(compiler)?;
|
||||
self.check_isa_flags(compiler)?;
|
||||
}
|
||||
|
||||
let modules = CompiledModule::from_artifacts_list(
|
||||
self.artifacts
|
||||
.into_iter()
|
||||
.map(|i| i.unwrap_owned())
|
||||
.collect(),
|
||||
&*engine.config().profiler,
|
||||
engine.compiler(),
|
||||
)?;
|
||||
self.check_tunables(&engine.config().tunables)?;
|
||||
self.check_features(&engine.config().features)?;
|
||||
|
||||
let modules = engine.run_maybe_parallel(self.artifacts, |i| {
|
||||
CompiledModule::from_artifacts(i.unwrap_owned(), &*engine.config().profiler)
|
||||
})?;
|
||||
|
||||
assert!(!modules.is_empty());
|
||||
|
||||
@@ -304,17 +316,17 @@ impl<'a> SerializedModule<'a> {
|
||||
.context("deserialize compilation artifacts")?)
|
||||
}
|
||||
|
||||
fn check_triple(&self, compiler: &Compiler) -> Result<()> {
|
||||
fn check_triple(&self, other: &target_lexicon::Triple) -> Result<()> {
|
||||
let triple = target_lexicon::Triple::from_str(&self.target).map_err(|e| anyhow!(e))?;
|
||||
|
||||
if triple.architecture != compiler.triple().architecture {
|
||||
if triple.architecture != other.architecture {
|
||||
bail!(
|
||||
"Module was compiled for architecture '{}'",
|
||||
triple.architecture
|
||||
);
|
||||
}
|
||||
|
||||
if triple.operating_system != compiler.triple().operating_system {
|
||||
if triple.operating_system != other.operating_system {
|
||||
bail!(
|
||||
"Module was compiled for operating system '{}'",
|
||||
triple.operating_system
|
||||
@@ -324,9 +336,9 @@ impl<'a> SerializedModule<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_shared_flags(&mut self, compiler: &Compiler) -> Result<()> {
|
||||
fn check_shared_flags(&mut self, compiler: &dyn Compiler) -> Result<()> {
|
||||
let mut shared_flags = std::mem::take(&mut self.shared_flags);
|
||||
for (name, host) in compiler.compiler().flags() {
|
||||
for (name, host) in compiler.flags() {
|
||||
match shared_flags.remove(&name) {
|
||||
Some(v) => {
|
||||
if v != host {
|
||||
@@ -347,9 +359,9 @@ impl<'a> SerializedModule<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_isa_flags(&mut self, compiler: &Compiler) -> Result<()> {
|
||||
fn check_isa_flags(&mut self, compiler: &dyn Compiler) -> Result<()> {
|
||||
let mut isa_flags = std::mem::take(&mut self.isa_flags);
|
||||
for (name, host) in compiler.compiler().isa_flags() {
|
||||
for (name, host) in compiler.isa_flags() {
|
||||
match isa_flags.remove(&name) {
|
||||
Some(v) => match (&v, &host) {
|
||||
(FlagValue::Bool(v), FlagValue::Bool(host)) => {
|
||||
@@ -406,7 +418,7 @@ impl<'a> SerializedModule<'a> {
|
||||
);
|
||||
}
|
||||
|
||||
fn check_tunables(&self, compiler: &Compiler) -> Result<()> {
|
||||
fn check_tunables(&mut self, other: &Tunables) -> Result<()> {
|
||||
let Tunables {
|
||||
static_memory_bound,
|
||||
static_memory_offset_guard_size,
|
||||
@@ -419,8 +431,6 @@ impl<'a> SerializedModule<'a> {
|
||||
guard_before_linear_memory,
|
||||
} = self.tunables;
|
||||
|
||||
let other = compiler.tunables();
|
||||
|
||||
Self::check_int(
|
||||
static_memory_bound,
|
||||
other.static_memory_bound,
|
||||
@@ -462,7 +472,7 @@ impl<'a> SerializedModule<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_features(&self, compiler: &Compiler) -> Result<()> {
|
||||
fn check_features(&mut self, other: &wasmparser::WasmFeatures) -> Result<()> {
|
||||
let WasmFeatures {
|
||||
reference_types,
|
||||
multi_value,
|
||||
@@ -477,7 +487,6 @@ impl<'a> SerializedModule<'a> {
|
||||
memory64,
|
||||
} = self.features;
|
||||
|
||||
let other = compiler.features();
|
||||
Self::check_bool(
|
||||
reference_types,
|
||||
other.reference_types,
|
||||
|
||||
@@ -7,7 +7,7 @@ mod table;
|
||||
|
||||
pub(crate) use memory::MemoryCreatorProxy;
|
||||
|
||||
pub use self::func::{create_function, create_raw_function};
|
||||
pub use self::func::*;
|
||||
use self::global::create_global;
|
||||
use self::memory::create_memory;
|
||||
use self::table::create_table;
|
||||
|
||||
@@ -70,13 +70,13 @@ unsafe extern "C" fn stub_fn(
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(compiler)]
|
||||
pub fn create_function(
|
||||
ft: &FuncType,
|
||||
func: Box<dyn Fn(*mut VMContext, *mut u128) -> Result<(), Trap> + Send + Sync>,
|
||||
engine: &Engine,
|
||||
) -> Result<(InstanceHandle, VMTrampoline)> {
|
||||
let obj = engine
|
||||
.compiler()
|
||||
.compiler()
|
||||
.emit_trampoline_obj(ft.as_wasm_func_type(), stub_fn as usize)?;
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.19"
|
||||
wasmtime = { path = "../wasmtime", version = "0.29.0", default-features = false }
|
||||
wasmtime = { path = "../wasmtime", version = "0.29.0", default-features = false, features = ['cranelift'] }
|
||||
wast = "37.0.0"
|
||||
|
||||
[badges]
|
||||
|
||||
@@ -5,7 +5,6 @@ use std::collections::BTreeMap;
|
||||
use std::str::FromStr;
|
||||
use structopt::StructOpt;
|
||||
use wasmtime_environ::{FlagValue, Setting, SettingKind};
|
||||
use wasmtime_jit::Compiler;
|
||||
|
||||
/// Displays available Cranelift settings for a target.
|
||||
#[derive(StructOpt)]
|
||||
@@ -19,7 +18,7 @@ pub struct SettingsCommand {
|
||||
impl SettingsCommand {
|
||||
/// Executes the command.
|
||||
pub fn execute(self) -> Result<()> {
|
||||
let mut builder = Compiler::builder(wasmtime_jit::CompilationStrategy::Auto);
|
||||
let mut builder = wasmtime_cranelift::builder();
|
||||
if let Some(target) = &self.target {
|
||||
let target = target_lexicon::Triple::from_str(target).map_err(|e| anyhow!(e))?;
|
||||
builder.target(target)?;
|
||||
|
||||
34
src/obj.rs
34
src/obj.rs
@@ -1,9 +1,9 @@
|
||||
use anyhow::{bail, Context as _, Result};
|
||||
use std::mem;
|
||||
use target_lexicon::Triple;
|
||||
use wasmparser::WasmFeatures;
|
||||
use wasmtime::Strategy;
|
||||
use wasmtime_environ::{ModuleEnvironment, Tunables};
|
||||
use wasmtime_jit::Compiler;
|
||||
use wasmtime_environ::{ModuleEnvironment, PrimaryMap, Tunables};
|
||||
|
||||
/// Creates object file from binary wasm data.
|
||||
pub fn compile_to_obj(
|
||||
@@ -14,16 +14,11 @@ pub fn compile_to_obj(
|
||||
opt_level: wasmtime::OptLevel,
|
||||
debug_info: bool,
|
||||
) -> Result<Vec<u8>> {
|
||||
let strategy = match strategy {
|
||||
Strategy::Auto => wasmtime_jit::CompilationStrategy::Auto,
|
||||
Strategy::Cranelift => wasmtime_jit::CompilationStrategy::Cranelift,
|
||||
#[cfg(feature = "lightbeam")]
|
||||
Strategy::Lightbeam => wasmtime_jit::CompilationStrategy::Lightbeam,
|
||||
#[cfg(not(feature = "lightbeam"))]
|
||||
Strategy::Lightbeam => bail!("lightbeam support not enabled"),
|
||||
s => bail!("unknown compilation strategy {:?}", s),
|
||||
};
|
||||
let mut builder = Compiler::builder(strategy);
|
||||
match strategy {
|
||||
Strategy::Cranelift | Strategy::Auto => {}
|
||||
other => panic!("unsupported strategy {:?}", other),
|
||||
}
|
||||
let mut builder = wasmtime_cranelift::builder();
|
||||
if let Some(target) = target {
|
||||
builder.target(target.clone())?;
|
||||
}
|
||||
@@ -50,12 +45,21 @@ pub fn compile_to_obj(
|
||||
tunables.generate_native_debuginfo = debug_info;
|
||||
tunables.parse_wasm_debuginfo = debug_info;
|
||||
|
||||
let compiler = Compiler::new(&*builder, tunables.clone(), features.clone(), true);
|
||||
let compiler = builder.build();
|
||||
let environ = ModuleEnvironment::new(&tunables, &features);
|
||||
let (_main_module, mut translation, types) = environ
|
||||
.translate(wasm)
|
||||
.context("failed to translate module")?;
|
||||
assert_eq!(translation.len(), 1);
|
||||
let compilation = compiler.compile(&mut translation[0], &types)?;
|
||||
Ok(compilation.obj)
|
||||
let mut funcs = PrimaryMap::default();
|
||||
for (index, func) in mem::take(&mut translation[0].function_body_inputs) {
|
||||
funcs.push(compiler.compile_function(&translation[0], index, func, &tunables, &types)?);
|
||||
}
|
||||
let (obj, _) = compiler.emit_obj(
|
||||
&translation[0],
|
||||
&types,
|
||||
funcs,
|
||||
tunables.generate_native_debuginfo,
|
||||
)?;
|
||||
Ok(obj)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user