Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support executing Pulley in Wasmtime #9744

Merged
merged 12 commits into from
Dec 6, 2024
4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1086,9 +1086,9 @@ jobs:
strategy:
matrix:
crate:
- "wasmtime"
- "wasmtime --features pulley"
- "wasmtime-cli"
- "wasmtime-environ"
- "wasmtime-environ --all-features"
- "pulley-interpreter --all-features"
needs: determine
if: needs.determine.outputs.test-miri && github.repository == 'bytecodealliance/wasmtime'
Expand Down
4 changes: 3 additions & 1 deletion cranelift/codegen/src/isa/pulley_shared/inst/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,9 @@ impl Amode {
+ frame_layout.outgoing_args_size;
i64::from(sp_offset) - offset
}
StackAMode::Slot(offset) => *offset,
StackAMode::Slot(offset) => {
offset + i64::from(state.frame_layout().outgoing_args_size)
}
StackAMode::OutgoingArg(offset) => *offset,
},
}
Expand Down
10 changes: 8 additions & 2 deletions cranelift/codegen/src/isa/pulley_shared/inst/emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -549,9 +549,15 @@ fn pulley_emit<P>(
*start_offset = sink.cur_offset();
}

Inst::PushFrame => enc::push_frame(sink),
Inst::PushFrame => {
sink.add_trap(ir::TrapCode::STACK_OVERFLOW);
enc::push_frame(sink);
}
Inst::PopFrame => enc::pop_frame(sink),
Inst::StackAlloc32 { amt } => enc::stack_alloc32(sink, *amt),
Inst::StackAlloc32 { amt } => {
sink.add_trap(ir::TrapCode::STACK_OVERFLOW);
enc::stack_alloc32(sink, *amt);
}
Inst::StackFree32 { amt } => enc::stack_free32(sink, *amt),

Inst::Zext8 { dst, src } => enc::zext8(sink, dst, src),
Expand Down
8 changes: 4 additions & 4 deletions cranelift/codegen/src/isa/pulley_shared/lower.isle
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,15 @@

;;;; Rules for `trapz` and `trapnz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(rule (lower (trapz a @ (value_type (fits_in_64 ty)) code))
(rule (lower (trapz a @ (value_type (ty_32_or_64 ty)) code))
(let ((zero Reg (pulley_xconst8 0)))
(side_effect (pulley_trap_if (IntCC.Equal)
(ty_to_operand_size ty)
a
zero
code))))

(rule (lower (trapnz a @ (value_type (fits_in_64 ty)) code))
(rule (lower (trapnz a @ (value_type (ty_32_or_64 ty)) code))
(let ((zero Reg (pulley_xconst8 0)))
(side_effect (pulley_trap_if (IntCC.NotEqual)
(ty_to_operand_size ty)
Expand All @@ -77,14 +77,14 @@

;; Fold `(trap[n]z (icmp ...))` together.

(rule 1 (lower (trapz (icmp cc a b @ (value_type (fits_in_64 ty))) code))
(rule 1 (lower (trapz (icmp cc a b @ (value_type (ty_32_or_64 ty))) code))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious: why was this change needed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah this is due to some other rule only accepting 32 or 64-bit inputs which causes ISLE to panic as something not a partial constructor. Basically tests panic unless this is here, so a future refactoring will need to flesh out more lowering rules for 8/16-bit types.

(side_effect (pulley_trap_if (intcc_complement cc)
(ty_to_operand_size ty)
a
b
code)))

(rule 1 (lower (trapnz (icmp cc a b @ (value_type (fits_in_64 ty))) code))
(rule 1 (lower (trapnz (icmp cc a b @ (value_type (ty_32_or_64 ty))) code))
(side_effect (pulley_trap_if cc
(ty_to_operand_size ty)
a
Expand Down
11 changes: 3 additions & 8 deletions crates/cranelift/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use wasmtime_environ::{
AddressMapSection, BuiltinFunctionIndex, CacheStore, CompileError, DefinedFuncIndex, FlagValue,
FunctionBodyData, FunctionLoc, HostCall, ModuleTranslation, ModuleTypesBuilder, PtrSize,
RelocationTarget, StackMapInformation, StaticModuleIndex, TrapEncodingBuilder, TrapSentinel,
Tunables, VMOffsets, WasmFuncType, WasmFunctionInfo, WasmValType,
TripleExt, Tunables, VMOffsets, WasmFuncType, WasmFunctionInfo, WasmValType,
};

#[cfg(feature = "component-model")]
Expand Down Expand Up @@ -152,12 +152,7 @@ impl Compiler {
// `call` instruction where the name is `colocated: false`. This will
// force a pulley-specific relocation to get emitted in addition to
// using the `call_indirect_host` instruction.
let is_pulley = match self.isa.triple().architecture {
target_lexicon::Architecture::Pulley32 => true,
target_lexicon::Architecture::Pulley64 => true,
_ => false,
};
if is_pulley {
if self.isa.triple().is_pulley() {
let mut new_signature = signature.clone();
new_signature
.params
Expand Down Expand Up @@ -246,7 +241,7 @@ impl wasmtime_environ::Compiler for Compiler {
// abort for the whole program since the runtime limits configured by
// the embedder should cause wasm to trap before it reaches that
// (ensuring the host has enough space as well for its functionality).
if !func_env.is_pulley() {
if !isa.triple().is_pulley() {
let vmctx = context
.func
.create_global_value(ir::GlobalValueData::VMContext);
Expand Down
20 changes: 5 additions & 15 deletions crates/cranelift/src/func_environ.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ use wasmparser::{Operator, WasmFeatures};
use wasmtime_environ::{
BuiltinFunctionIndex, DataIndex, ElemIndex, EngineOrModuleTypeIndex, FuncIndex, GlobalIndex,
IndexType, Memory, MemoryIndex, Module, ModuleInternedTypeIndex, ModuleTranslation,
ModuleTypesBuilder, PtrSize, Table, TableIndex, Tunables, TypeConvert, TypeIndex, VMOffsets,
WasmCompositeInnerType, WasmFuncType, WasmHeapTopType, WasmHeapType, WasmRefType, WasmResult,
WasmValType,
ModuleTypesBuilder, PtrSize, Table, TableIndex, TripleExt, Tunables, TypeConvert, TypeIndex,
VMOffsets, WasmCompositeInnerType, WasmFuncType, WasmHeapTopType, WasmHeapType, WasmRefType,
WasmResult, WasmValType,
};
use wasmtime_environ::{FUNCREF_INIT_BIT, FUNCREF_MASK};

Expand Down Expand Up @@ -1187,16 +1187,6 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
i32::from(self.offsets.ptr.vm_func_ref_type_index()),
)
}

/// Returns whether the current compilation target is for the Pulley
/// interpreter.
pub fn is_pulley(&self) -> bool {
match self.isa.triple().architecture {
target_lexicon::Architecture::Pulley32 => true,
target_lexicon::Architecture::Pulley64 => true,
_ => false,
}
}
}

struct Call<'a, 'func, 'module_env> {
Expand Down Expand Up @@ -3419,7 +3409,7 @@ impl FuncEnvironment<'_> {
/// being targetted since the Pulley runtime doesn't catch segfaults for
/// itself.
pub fn clif_memory_traps_enabled(&self) -> bool {
self.tunables.signals_based_traps && !self.is_pulley()
self.tunables.signals_based_traps && !self.isa.triple().is_pulley()
}

/// Returns whether it's acceptable to have CLIF instructions natively trap,
Expand All @@ -3429,7 +3419,7 @@ impl FuncEnvironment<'_> {
/// unconditionally since Pulley doesn't use hardware-based traps in its
/// runtime.
pub fn clif_instruction_traps_enabled(&self) -> bool {
self.tunables.signals_based_traps || self.is_pulley()
self.tunables.signals_based_traps || self.isa.triple().is_pulley()
}
}

Expand Down
18 changes: 15 additions & 3 deletions crates/cranelift/src/obj.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ use cranelift_control::ControlPlane;
use gimli::write::{Address, EhFrame, EndianVec, FrameTable, Writer};
use gimli::RunTimeEndian;
use object::write::{Object, SectionId, StandardSegment, Symbol, SymbolId, SymbolSection};
use object::{Architecture, SectionKind, SymbolFlags, SymbolKind, SymbolScope};
use object::{Architecture, SectionFlags, SectionKind, SymbolFlags, SymbolKind, SymbolScope};
use std::collections::HashMap;
use std::ops::Range;
use wasmtime_environ::obj::LibCall;
use wasmtime_environ::{Compiler, Unsigned};
use wasmtime_environ::obj::{self, LibCall};
use wasmtime_environ::{Compiler, TripleExt, Unsigned};

const TEXT_SECTION_NAME: &[u8] = b".text";

Expand Down Expand Up @@ -83,6 +83,18 @@ impl<'a> ModuleTextBuilder<'a> {
SectionKind::Text,
);

// If this target is Pulley then flag th text section as not needing the
alexcrichton marked this conversation as resolved.
Show resolved Hide resolved
// executable bit in virtual memory which means that the runtime won't
// try to call `Mmap::make_exectuable`, which makes Pulley more
// portable.
if compiler.triple().is_pulley() {
let section = obj.section_mut(text_section);
assert!(matches!(section.flags, SectionFlags::None));
section.flags = SectionFlags::Elf {
sh_flags: obj::SH_WASMTIME_NOT_EXECUTED,
};
}

Self {
compiler,
obj,
Expand Down
3 changes: 3 additions & 0 deletions crates/environ/src/compile/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,9 @@ pub trait Compiler: Send + Sync {
// 64 KB is the maximal page size (i.e. memory translation granule size)
// supported by the architecture and is used on some platforms.
(_, Architecture::Aarch64(..)) => 0x10000,
// Conservatively assume the max-of-all-supported-hosts for pulley
// and round up to 64k.
(_, Architecture::Pulley32 | Architecture::Pulley64) => 0x10000,
_ => 0x1000,
}
}
Expand Down
17 changes: 1 addition & 16 deletions crates/environ/src/compile/module_artifacts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@ pub struct ObjectBuilder<'a> {
/// will go.
data: SectionId,

/// The target triple for this compilation.
triple: target_lexicon::Triple,

/// The section identifier for function name information, or otherwise where
/// the `name` custom section of wasm is copied into.
///
Expand All @@ -46,11 +43,7 @@ pub struct ObjectBuilder<'a> {

impl<'a> ObjectBuilder<'a> {
/// Creates a new builder for the `obj` specified.
pub fn new(
mut obj: Object<'a>,
tunables: &'a Tunables,
triple: target_lexicon::Triple,
) -> ObjectBuilder<'a> {
pub fn new(mut obj: Object<'a>, tunables: &'a Tunables) -> ObjectBuilder<'a> {
let data = obj.add_section(
obj.segment_name(StandardSegment::Data).to_vec(),
obj::ELF_WASM_DATA.as_bytes().to_vec(),
Expand All @@ -60,7 +53,6 @@ impl<'a> ObjectBuilder<'a> {
obj,
tunables,
data,
triple,
names: None,
dwarf: None,
}
Expand Down Expand Up @@ -225,12 +217,6 @@ impl<'a> ObjectBuilder<'a> {
self.push_debuginfo(&mut dwarf, &debuginfo);
}

let is_pulley = matches!(
self.triple.architecture,
target_lexicon::Architecture::Pulley32 | target_lexicon::Architecture::Pulley64
);
assert!(!is_pulley || wasm_to_array_trampolines.is_empty());

Ok(CompiledModuleInfo {
module,
funcs,
Expand All @@ -240,7 +226,6 @@ impl<'a> ObjectBuilder<'a> {
has_unparsed_debuginfo,
code_section_offset: debuginfo.wasm_file.code_section_offset,
has_wasm_debuginfo: self.tunables.parse_wasm_debuginfo,
is_pulley,
dwarf,
},
})
Expand Down
21 changes: 16 additions & 5 deletions crates/environ/src/component/info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -452,19 +452,30 @@ pub struct CanonicalOptions {
}

/// Possible encodings of strings within the component model.
//
// Note that the `repr(u8)` is load-bearing here since this is used in an
// `extern "C" fn()` function argument which is called from cranelift-compiled
// code so we must know the representation of this.
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[allow(missing_docs, reason = "self-describing variants")]
#[repr(u8)]
pub enum StringEncoding {
Utf8,
Utf16,
CompactUtf16,
}

impl StringEncoding {
/// Decodes the `u8` provided back into a `StringEncoding`, if it's valid.
pub fn from_u8(val: u8) -> Option<StringEncoding> {
if val == StringEncoding::Utf8 as u8 {
return Some(StringEncoding::Utf8);
}
if val == StringEncoding::Utf16 as u8 {
return Some(StringEncoding::Utf16);
}
if val == StringEncoding::CompactUtf16 as u8 {
return Some(StringEncoding::CompactUtf16);
}
None
}
}

/// Possible transcoding operations that must be provided by the host.
///
/// Note that each transcoding operation may have a unique signature depending
Expand Down
18 changes: 18 additions & 0 deletions crates/environ/src/ext.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use target_lexicon::{Architecture, Triple};

/// Extension methods for `target_lexicon::Triple`.
pub trait TripleExt {
/// Helper for returning whether this target is for pulley, wasmtime's
/// interpreter.
fn is_pulley(&self) -> bool;
}

impl TripleExt for Triple {
fn is_pulley(&self) -> bool {
match self.architecture {
Architecture::Pulley32 => true,
Architecture::Pulley64 => true,
_ => false,
}
}
}
2 changes: 2 additions & 0 deletions crates/environ/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ mod address_map;
mod builtin;
mod demangling;
mod error;
mod ext;
mod gc;
mod hostcall;
mod module;
Expand All @@ -33,6 +34,7 @@ mod tunables;
mod types;
mod vmoffsets;

pub use self::ext::*;
pub use crate::address_map::*;
pub use crate::builtin::*;
pub use crate::demangling::*;
Expand Down
4 changes: 0 additions & 4 deletions crates/environ/src/module_artifacts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,6 @@ pub struct Metadata {
/// weren't found in the original wasm module itself.
pub has_wasm_debuginfo: bool,

/// Whether this artifact contains Pulley bytecode (instead of machine code)
/// or not.
pub is_pulley: bool,

/// Dwarf sections and the offsets at which they're stored in the
/// ELF_WASMTIME_DWARF
pub dwarf: Vec<(u8, Range<u64>)>,
Expand Down
21 changes: 14 additions & 7 deletions crates/misc/component-test-util/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,16 +132,23 @@ forward_impls! {

/// Helper method to apply `wast_config` to `config`.
pub fn apply_wast_config(config: &mut Config, wast_config: &wasmtime_wast_util::WastConfig) {
use wasmtime_wast_util::{Collector, Compiler};

config.strategy(match wast_config.compiler {
wasmtime_wast_util::Compiler::Cranelift => wasmtime::Strategy::Cranelift,
wasmtime_wast_util::Compiler::Winch => wasmtime::Strategy::Winch,
Compiler::Cranelift | Compiler::Pulley => wasmtime::Strategy::Cranelift,
Compiler::Winch => wasmtime::Strategy::Winch,
});
config.collector(match wast_config.collector {
wasmtime_wast_util::Collector::Auto => wasmtime::Collector::Auto,
wasmtime_wast_util::Collector::Null => wasmtime::Collector::Null,
wasmtime_wast_util::Collector::DeferredReferenceCounting => {
wasmtime::Collector::DeferredReferenceCounting
if let Compiler::Pulley = wast_config.compiler {
if cfg!(target_pointer_width = "32") {
config.target("pulley32").unwrap();
} else {
config.target("pulley64").unwrap();
}
}
config.collector(match wast_config.collector {
Collector::Auto => wasmtime::Collector::Auto,
Collector::Null => wasmtime::Collector::Null,
Collector::DeferredReferenceCounting => wasmtime::Collector::DeferredReferenceCounting,
});
}

Expand Down
Loading
Loading