Files
wasmtime/src/obj.rs
Alex Crichton ddfadaeb38 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
2021-08-18 16:47:47 -05:00

66 lines
2.0 KiB
Rust

use anyhow::{bail, Context as _, Result};
use std::mem;
use target_lexicon::Triple;
use wasmparser::WasmFeatures;
use wasmtime::Strategy;
use wasmtime_environ::{ModuleEnvironment, PrimaryMap, Tunables};
/// Creates object file from binary wasm data.
pub fn compile_to_obj(
wasm: &[u8],
target: Option<&Triple>,
strategy: Strategy,
enable_simd: bool,
opt_level: wasmtime::OptLevel,
debug_info: bool,
) -> Result<Vec<u8>> {
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())?;
}
let mut features = WasmFeatures::default();
if enable_simd {
builder.enable("enable_simd").unwrap();
features.simd = true;
}
match opt_level {
wasmtime::OptLevel::None => {}
wasmtime::OptLevel::Speed => {
builder.set("opt_level", "speed").unwrap();
}
wasmtime::OptLevel::SpeedAndSize => {
builder.set("opt_level", "speed_and_size").unwrap();
}
other => bail!("unknown optimization level {:?}", other),
}
// TODO: Expose the tunables as command-line flags.
let mut tunables = Tunables::default();
tunables.generate_native_debuginfo = debug_info;
tunables.parse_wasm_debuginfo = debug_info;
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 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)
}