Skip to content

Commit 57cd5a9

Browse files
authored
Start plumbing the ability to run Pulley in Wasmtime (#9646)
* Start plumbing the ability to run Pulley in Wasmtime This commit starts setting up some infrastructure to run Pulley modules in Wasmtime, for example on the CLI. This doesn't actually work just yet due to other missing pieces of integration but this is enough to get to a fault and/or other compiler errors at this time. The changes here are: * An `Engine` allows mismatching targets in the case of Pulley, but the pointer widths must match. * All subcommands of Wasmtime now support `--target`, e.g. `wasmtime run`, as previously only the host was allowed. * Fix compile of bench-api * Fix miri tests * Switch from `NativeEndian` to `Endianness` This switches parsing ELF from always using the native endianness to instead using a runtime-defined value of endianness. This enables big-endian platforms such as s390x to load objects produced for pulley, a little-endian platform.
1 parent 8fd6208 commit 57cd5a9

File tree

15 files changed

+138
-31
lines changed

15 files changed

+138
-31
lines changed

crates/bench-api/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,6 @@ use clap::Parser;
141141
use std::os::raw::{c_int, c_void};
142142
use std::slice;
143143
use std::{env, path::PathBuf};
144-
use target_lexicon::Triple;
145144
use wasi_common::{sync::WasiCtxBuilder, I32Exit, WasiCtx};
146145
use wasmtime::{Engine, Instance, Linker, Module, Store};
147146
use wasmtime_cli_flags::CommonOptions;
@@ -435,7 +434,7 @@ impl BenchState {
435434
execution_end: extern "C" fn(*mut u8),
436435
make_wasi_cx: impl FnMut() -> Result<WasiCtx> + 'static,
437436
) -> Result<Self> {
438-
let mut config = options.config(Some(&Triple::host().to_string()), None)?;
437+
let mut config = options.config(None)?;
439438
// NB: always disable the compilation cache.
440439
config.disable_cache();
441440
let engine = Engine::new(&config)?;

crates/cli-flags/src/lib.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,10 @@ pub struct CommonOptions {
480480
pub wasm: WasmOptions,
481481
#[arg(skip)]
482482
pub wasi: WasiOptions,
483+
484+
/// The target triple; default is the host triple
485+
#[arg(long, value_name = "TARGET")]
486+
pub target: Option<String>,
483487
}
484488

485489
macro_rules! match_feature {
@@ -541,11 +545,7 @@ impl CommonOptions {
541545
Ok(())
542546
}
543547

544-
pub fn config(
545-
&mut self,
546-
target: Option<&str>,
547-
pooling_allocator_default: Option<bool>,
548-
) -> Result<Config> {
548+
pub fn config(&mut self, pooling_allocator_default: Option<bool>) -> Result<Config> {
549549
self.configure();
550550
let mut config = Config::new();
551551

@@ -560,7 +560,7 @@ impl CommonOptions {
560560
_ => err,
561561
}
562562
match_feature! {
563-
["cranelift" : target]
563+
["cranelift" : &self.target]
564564
target => config.target(target)?,
565565
_ => err,
566566
}

crates/wasmtime/src/engine.rs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,11 +257,32 @@ impl Engine {
257257
fn _check_compatible_with_native_host(&self) -> Result<(), String> {
258258
#[cfg(any(feature = "cranelift", feature = "winch"))]
259259
{
260+
use target_lexicon::{Architecture, PointerWidth, Triple};
261+
260262
let compiler = self.compiler();
261263

262-
// Check to see that the config's target matches the host
263264
let target = compiler.triple();
264-
if *target != target_lexicon::Triple::host() {
265+
let host = Triple::host();
266+
let target_matches_host = || {
267+
// If the host target and target triple match, then it's valid
268+
// to run results of compilation on this host.
269+
if host == *target {
270+
return true;
271+
}
272+
273+
// Otherwise if there's a mismatch the only allowed
274+
// configuration at this time is that any target can run Pulley,
275+
// Wasmtime's interpreter. This only works though if the
276+
// pointer-width of pulley matches the pointer-width of the
277+
// host, so check that here.
278+
match host.pointer_width() {
279+
Ok(PointerWidth::U32) => target.architecture == Architecture::Pulley32,
280+
Ok(PointerWidth::U64) => target.architecture == Architecture::Pulley64,
281+
_ => false,
282+
}
283+
};
284+
285+
if !target_matches_host() {
265286
return Err(format!(
266287
"target '{target}' specified in the configuration does not match the host"
267288
));
@@ -397,6 +418,22 @@ impl Engine {
397418
// available.
398419
FlagValue::Bool(true) => {}
399420

421+
// Pulley's pointer_width must match the host.
422+
FlagValue::Enum("pointer32") => {
423+
return if cfg!(target_pointer_width = "32") {
424+
Ok(())
425+
} else {
426+
Err("wrong host pointer width".to_string())
427+
}
428+
}
429+
FlagValue::Enum("pointer64") => {
430+
return if cfg!(target_pointer_width = "64") {
431+
Ok(())
432+
} else {
433+
Err("wrong host pointer width".to_string())
434+
}
435+
}
436+
400437
// Only `bool` values are supported right now, other settings would
401438
// need more support here.
402439
_ => {

crates/wasmtime/src/engine/serialization.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
use crate::prelude::*;
2525
use crate::{Engine, ModuleVersionStrategy, Precompiled};
2626
use core::str::FromStr;
27-
use object::endian::NativeEndian;
27+
use object::endian::Endianness;
2828
#[cfg(any(feature = "cranelift", feature = "winch"))]
2929
use object::write::{Object, StandardSegment};
3030
use object::{read::elf::ElfFile64, FileFlags, Object as _, ObjectSection, SectionKind};
@@ -56,7 +56,7 @@ pub fn check_compatible(engine: &Engine, mmap: &[u8], expected: ObjectKind) -> R
5656
// structured well enough to make this easy and additionally it's not really
5757
// a perf issue right now so doing that is left for another day's
5858
// refactoring.
59-
let obj = ElfFile64::<NativeEndian>::parse(mmap)
59+
let obj = ElfFile64::<Endianness>::parse(mmap)
6060
.err2anyhow()
6161
.context("failed to parse precompiled artifact as an ELF")?;
6262
let expected_e_flags = match expected {
@@ -145,7 +145,7 @@ pub fn append_compiler_info(engine: &Engine, obj: &mut Object<'_>, metadata: &Me
145145
}
146146

147147
fn detect_precompiled<'data, R: object::ReadRef<'data>>(
148-
obj: ElfFile64<'data, NativeEndian, R>,
148+
obj: ElfFile64<'data, Endianness, R>,
149149
) -> Option<Precompiled> {
150150
match obj.flags() {
151151
FileFlags::Elf {

crates/wasmtime/src/runtime/code_memory.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use crate::prelude::*;
44
use crate::runtime::vm::{libcalls, MmapVec, UnwindRegistration};
55
use core::ops::Range;
6-
use object::endian::NativeEndian;
6+
use object::endian::Endianness;
77
use object::read::{elf::ElfFile64, Object, ObjectSection};
88
use object::{ObjectSymbol, SectionFlags};
99
use wasmtime_environ::{lookup_trap_code, obj, Trap};
@@ -57,7 +57,7 @@ impl CodeMemory {
5757
/// The returned `CodeMemory` manages the internal `MmapVec` and the
5858
/// `publish` method is used to actually make the memory executable.
5959
pub fn new(mmap: MmapVec) -> Result<Self> {
60-
let obj = ElfFile64::<NativeEndian>::parse(&mmap[..])
60+
let obj = ElfFile64::<Endianness>::parse(&mmap[..])
6161
.err2anyhow()
6262
.with_context(|| "failed to parse internal compilation artifact")?;
6363

src/commands/compile.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,6 @@ pub struct CompileCommand {
3535
#[allow(missing_docs)]
3636
pub common: CommonOptions,
3737

38-
/// The target triple; default is the host triple
39-
#[arg(long, value_name = "TARGET")]
40-
pub target: Option<String>,
41-
4238
/// The path of the output compiled module; defaults to `<MODULE>.cwasm`
4339
#[arg(short = 'o', long, value_name = "OUTPUT")]
4440
pub output: Option<PathBuf>,
@@ -57,7 +53,7 @@ impl CompileCommand {
5753
pub fn execute(mut self) -> Result<()> {
5854
self.common.init_logging()?;
5955

60-
let mut config = self.common.config(self.target.as_deref(), None)?;
56+
let mut config = self.common.config(None)?;
6157

6258
if let Some(path) = self.emit_clif {
6359
if !path.exists() {

src/commands/explore.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,6 @@ pub struct ExploreCommand {
1313
#[command(flatten)]
1414
common: CommonOptions,
1515

16-
/// The target triple; default is the host triple
17-
#[arg(long, value_name = "TARGET")]
18-
target: Option<String>,
19-
2016
/// The path of the WebAssembly module to compile
2117
#[arg(required = true, value_name = "MODULE")]
2218
module: PathBuf,
@@ -32,7 +28,7 @@ impl ExploreCommand {
3228
pub fn execute(mut self) -> Result<()> {
3329
self.common.init_logging()?;
3430

35-
let mut config = self.common.config(self.target.as_deref(), None)?;
31+
let mut config = self.common.config(None)?;
3632

3733
let bytes =
3834
Cow::Owned(std::fs::read(&self.module).with_context(|| {
@@ -63,7 +59,7 @@ impl ExploreCommand {
6359

6460
wasmtime_explorer::generate(
6561
&config,
66-
self.target.as_deref(),
62+
self.common.target.as_deref(),
6763
clif_dir.as_ref().map(|tmp_dir| tmp_dir.path()),
6864
&bytes,
6965
&mut output_file,

src/commands/run.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ impl RunCommand {
8787
pub fn execute(mut self) -> Result<()> {
8888
self.run.common.init_logging()?;
8989

90-
let mut config = self.run.common.config(None, None)?;
90+
let mut config = self.run.common.config(None)?;
9191
config.async_support(true);
9292

9393
if self.run.common.wasm.timeout.is_some() {

src/commands/serve.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ impl ServeCommand {
318318
let mut config = self
319319
.run
320320
.common
321-
.config(None, use_pooling_allocator_by_default().unwrap_or(None))?;
321+
.config(use_pooling_allocator_by_default().unwrap_or(None))?;
322322
config.wasm_component_model(true);
323323
config.async_support(true);
324324

src/commands/wast.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ impl WastCommand {
2323
pub fn execute(mut self) -> Result<()> {
2424
self.common.init_logging()?;
2525

26-
let config = self.common.config(None, None)?;
26+
let config = self.common.config(None)?;
2727
let store = Store::new(&Engine::new(&config)?, ());
2828
let mut wast_context = WastContext::new(store);
2929

0 commit comments

Comments
 (0)