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:
Alex Crichton
2021-08-18 16:47:47 -05:00
committed by GitHub
parent 7a19b8fe2c
commit ddfadaeb38
22 changed files with 418 additions and 436 deletions

View File

@@ -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)
}