Skip to content
Merged
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ wasmtime-wasi-tls = { workspace = true, optional = true }
wasmtime-wasi-keyvalue = { workspace = true, optional = true }
wasmtime-wasi-threads = { workspace = true, optional = true }
wasmtime-wasi-http = { workspace = true, optional = true }
wasmtime-unwinder = { workspace = true }
clap = { workspace = true }
clap_complete = { workspace = true, optional = true }
anyhow = { workspace = true, features = ['std'] }
Expand Down
2 changes: 1 addition & 1 deletion cranelift/codegen/src/isa/aarch64/inst/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -976,7 +976,7 @@ impl MachInst for Inst {
//
// See the note in [crate::isa::aarch64::abi::is_caller_save_reg] for
// more information on this ABI-implementation hack.
let caller_clobbers = AArch64MachineDeps::get_regs_clobbered_by_call(caller, is_exception);
let caller_clobbers = AArch64MachineDeps::get_regs_clobbered_by_call(caller, false);
let callee_clobbers = AArch64MachineDeps::get_regs_clobbered_by_call(callee, is_exception);

let mut all_clobbers = caller_clobbers;
Expand Down
4 changes: 3 additions & 1 deletion cranelift/codegen/src/machinst/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2495,7 +2495,9 @@ impl TryCallInfo {
TryCallHandler::Default(label) => MachExceptionHandler::Default(*label),
TryCallHandler::Context(reg) => {
let loc = if let Some(spillslot) = reg.to_spillslot() {
let offset = layout.spillslot_offset(spillslot);
// The spillslot offset is relative to the "fixed
// storage area", which comes after outgoing args.
let offset = layout.spillslot_offset(spillslot) + i64::from(layout.outgoing_args_size);
ExceptionContextLoc::SPOffset(u32::try_from(offset).expect("SP offset cannot be negative or larger than 4GiB"))
} else if let Some(realreg) = reg.to_real_reg() {
ExceptionContextLoc::GPR(realreg.hw_enc())
Expand Down
21 changes: 16 additions & 5 deletions cranelift/filetests/src/function_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -648,21 +648,32 @@ extern "C-unwind" fn __cranelift_throw(
) -> ! {
let compiled_test_file = unsafe { &*COMPILED_TEST_FILE.get() };
let unwind_host = wasmtime_unwinder::UnwindHost;
let module_lookup = |pc| {
compiled_test_file
let frame_handler = |frame: &wasmtime_unwinder::Frame| -> Option<usize> {
let (base, table) = compiled_test_file
.module
.as_ref()
.unwrap()
.lookup_wasmtime_exception_data(pc)
.lookup_wasmtime_exception_data(frame.pc())?;
let relative_pc = u32::try_from(
frame
.pc()
.checked_sub(base)
.expect("module lookup did not return a module base below the PC"),
)
.expect("module larger than 4GiB");

table.lookup_pc_tag(relative_pc, tag).map(|handler| {
base.checked_add(usize::try_from(handler).unwrap())
.expect("Handler address computation overflowed")
})
};
unsafe {
match wasmtime_unwinder::compute_throw_action(
&unwind_host,
module_lookup,
frame_handler,
exit_pc,
exit_fp,
entry_fp,
tag,
) {
wasmtime_unwinder::ThrowAction::Handler { pc, sp, fp } => {
wasmtime_unwinder::resume_to_exception_handler(pc, sp, fp, payload1, payload2);
Expand Down
10 changes: 1 addition & 9 deletions crates/cli-flags/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -401,8 +401,6 @@ wasmtime_option_group! {
pub extended_const: Option<bool>,
/// Configure support for the exceptions proposal.
pub exceptions: Option<bool>,
/// DEPRECATED: Configure support for the legacy exceptions proposal.
pub legacy_exceptions: Option<bool>,
/// Whether or not any GC infrastructure in Wasmtime is enabled or not.
pub gc_support: Option<bool>,
}
Expand Down Expand Up @@ -1035,13 +1033,6 @@ impl CommonOptions {
if let Some(enable) = self.wasm.extended_const.or(all) {
config.wasm_extended_const(enable);
}
if let Some(enable) = self.wasm.exceptions.or(all) {
config.wasm_exceptions(enable);
}
if let Some(enable) = self.wasm.legacy_exceptions.or(all) {
#[expect(deprecated, reason = "forwarding CLI flag")]
config.wasm_legacy_exceptions(enable);
}

macro_rules! handle_conditionally_compiled {
($(($feature:tt, $field:tt, $method:tt))*) => ($(
Expand All @@ -1066,6 +1057,7 @@ impl CommonOptions {
("gc", gc, wasm_gc)
("gc", reference_types, wasm_reference_types)
("gc", function_references, wasm_function_references)
("gc", exceptions, wasm_exceptions)
("stack-switching", stack_switching, wasm_stack_switching)
}

Expand Down
1 change: 1 addition & 0 deletions crates/cranelift/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ wasmtime-versioned-export-macros = { workspace = true }
itertools = { workspace = true }
pulley-interpreter = { workspace = true, optional = true }
wasmtime-math = { workspace = true }
wasmtime-unwinder = { workspace = true, features = ["cranelift"] }

[features]
all-arch = ["cranelift-codegen/all-arch"]
Expand Down
54 changes: 39 additions & 15 deletions crates/cranelift/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use cranelift_codegen::isa::{
unwind::{UnwindInfo, UnwindInfoKind},
};
use cranelift_codegen::print_errors::pretty_error;
use cranelift_codegen::{CompiledCode, Context};
use cranelift_codegen::{CompiledCode, Context, FinalizedMachCallSite};
use cranelift_entity::PrimaryMap;
use cranelift_frontend::FunctionBuilder;
use object::write::{Object, StandardSegment, SymbolId};
Expand All @@ -28,13 +28,15 @@ use std::ops::Range;
use std::path;
use std::sync::{Arc, Mutex};
use wasmparser::{FuncValidatorAllocations, FunctionBody};
use wasmtime_environ::obj::ELF_WASMTIME_EXCEPTIONS;
use wasmtime_environ::{
AddressMapSection, BuiltinFunctionIndex, CacheStore, CompileError, CompiledFunctionBody,
DefinedFuncIndex, FlagValue, FuncKey, FunctionBodyData, FunctionLoc, HostCall,
InliningCompiler, ModuleTranslation, ModuleTypesBuilder, PtrSize, StackMapSection,
StaticModuleIndex, TrapEncodingBuilder, TrapSentinel, TripleExt, Tunables, VMOffsets,
WasmFuncType, WasmValType,
};
use wasmtime_unwinder::ExceptionTableBuilder;

#[cfg(feature = "component-model")]
mod component;
Expand Down Expand Up @@ -525,6 +527,7 @@ impl wasmtime_environ::Compiler for Compiler {
let mut addrs = AddressMapSection::default();
let mut traps = TrapEncodingBuilder::default();
let mut stack_maps = StackMapSection::default();
let mut exception_tables = ExceptionTableBuilder::default();

let mut ret = Vec::with_capacity(funcs.len());
for (i, (sym, func)) in funcs.iter().enumerate() {
Expand All @@ -547,6 +550,11 @@ impl wasmtime_environ::Compiler for Compiler {
);

traps.push(range.clone(), &func.traps().collect::<Vec<_>>());
clif_to_env_exception_tables(
&mut exception_tables,
range.clone(),
func.buffer.call_sites(),
)?;
builder.append_padding(self.linkopts.padding_between_functions);

let info = FunctionLoc {
Expand All @@ -564,6 +572,15 @@ impl wasmtime_environ::Compiler for Compiler {
stack_maps.append_to(obj);
traps.append_to(obj);

let exception_section = obj.add_section(
obj.segment_name(StandardSegment::Data).to_vec(),
ELF_WASMTIME_EXCEPTIONS.as_bytes().to_vec(),
SectionKind::ReadOnlyData,
);
exception_tables.serialize(|bytes| {
obj.append_section_data(exception_section, bytes, 1);
});

Ok(ret)
}

Expand Down Expand Up @@ -1328,6 +1345,21 @@ fn clif_to_env_stack_maps(
}
}

/// Convert from Cranelift's representation of exception handler
/// metadata to Wasmtime's compiler-agnostic representation.
///
/// Here `builder` is the wasmtime-unwinder exception section being
/// created and `range` is the range of the function being added. The
/// `call_sites` iterator is the raw iterator over callsite metadata
/// (including exception handlers) from Cranelift.
fn clif_to_env_exception_tables<'a>(
builder: &mut ExceptionTableBuilder,
range: Range<u64>,
call_sites: impl Iterator<Item = FinalizedMachCallSite<'a>>,
) -> anyhow::Result<()> {
builder.add_func(CodeOffset::try_from(range.start).unwrap(), call_sites)
}

fn declare_and_call(
builder: &mut FunctionBuilder,
signature: ir::Signature,
Expand Down Expand Up @@ -1417,25 +1449,17 @@ fn save_last_wasm_exit_fp_and_pc(
ptr: &impl PtrSize,
limits: Value,
) {
// Save the exit Wasm FP to the limits. We dereference the current FP to get
// the previous FP because the current FP is the trampoline's FP, and we
// want the Wasm function's FP, which is the caller of this trampoline.
// Save the trampoline FP to the limits. Exception unwind needs
// this so that it can know the SP (bottom of frame) for the very
// last Wasm frame.
let trampoline_fp = builder.ins().get_frame_pointer(pointer_type);
let wasm_fp = builder.ins().load(
pointer_type,
MemFlags::trusted(),
trampoline_fp,
// The FP always points to the next older FP for all supported
// targets. See assertion in
// `crates/wasmtime/src/runtime/vm/traphandlers/backtrace.rs`.
0,
);
builder.ins().store(
MemFlags::trusted(),
wasm_fp,
trampoline_fp,
limits,
ptr.vmstore_context_last_wasm_exit_fp(),
ptr.vmstore_context_last_wasm_exit_trampoline_fp(),
);

// Finally save the Wasm return address to the limits.
let wasm_pc = builder.ins().get_return_address(pointer_type);
builder.ins().store(
Expand Down
Loading
Loading