diff --git a/.git-third-party/.gitattributes b/.git-third-party/.gitattributes new file mode 100644 index 00000000..afbc4add --- /dev/null +++ b/.git-third-party/.gitattributes @@ -0,0 +1,6 @@ +# Managed by git-third-party. + +# Patch names are a digest of the patch bytes: normalizing them changes what +# gets applied, and breaks the name. +patches/** -text +manifest.json text eol=lf diff --git a/.git-third-party/.gitignore b/.git-third-party/.gitignore new file mode 100644 index 00000000..9b33cbe9 --- /dev/null +++ b/.git-third-party/.gitignore @@ -0,0 +1,5 @@ +# Managed by git-third-party. + +# Scratch left behind by an interrupted write. +*.tmp +patches/**/*.tmp diff --git a/.git-third-party/config.json b/.git-third-party/config.json deleted file mode 100644 index eb8cc9e9..00000000 --- a/.git-third-party/config.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "repos": { - "executor/third-party/wasmtime": { - "url": "https://github.com/bytecodealliance/wasmtime.git", - "commit": "6844a83b530f86ad13a65175282fe2dbcd33cad1", - "patches": 5, - "submodules": [] - }, - "executor/third-party/wasm-tools": { - "url": "https://github.com/bytecodealliance/wasm-tools.git", - "commit": "76927bf4bdbddf4b15f835c5eddfffbdfe3bdbd5", - "patches": 1 - } - } -} diff --git a/.git-third-party/manifest.json b/.git-third-party/manifest.json new file mode 100644 index 00000000..fee3a719 --- /dev/null +++ b/.git-third-party/manifest.json @@ -0,0 +1,23 @@ +{ + "repos": { + "executor/third-party/wasmtime": { + "url": "https://github.com/bytecodealliance/wasmtime.git", + "commit": "7bac2c2775808aaec5d4aa5627a5e447b51102cf", + "patches": [ + "gbm0xv16dc1fs2km", + "zsjxmza3dms0hr10", + "4rr93pqjtwm5m701", + "r6518c8dxghpkhsj", + "6xy06vg0d71czwmm" + ], + "submodules": [] + }, + "executor/third-party/wasm-tools": { + "url": "https://github.com/bytecodealliance/wasm-tools.git", + "commit": "bb58fdf919912e05c976a0b71aaa843f7d1938f9", + "patches": [ + "n359mz2sdabr2wsa" + ] + } + } +} diff --git a/.git-third-party/patches/executor/third-party/wasm-tools/1 b/.git-third-party/patches/executor/third-party/wasm-tools/n359mz2sdabr2wsa similarity index 93% rename from .git-third-party/patches/executor/third-party/wasm-tools/1 rename to .git-third-party/patches/executor/third-party/wasm-tools/n359mz2sdabr2wsa index e24efdf7..23855af3 100644 --- a/.git-third-party/patches/executor/third-party/wasm-tools/1 +++ b/.git-third-party/patches/executor/third-party/wasm-tools/n359mz2sdabr2wsa @@ -9,10 +9,10 @@ Subject: [PATCH] fix: expose method for fuzzing 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/wasm-smith/src/core.rs b/crates/wasm-smith/src/core.rs -index e37ab57..502262b 100644 +index b59fd588..ced65860 100644 --- a/crates/wasm-smith/src/core.rs +++ b/crates/wasm-smith/src/core.rs -@@ -2573,7 +2573,7 @@ impl Module { +@@ -2796,7 +2796,7 @@ impl Module { // allow encoding any other type in that form. let can_use_function_list = ty == RefType::FUNCREF; if !self.config.reference_types_enabled { @@ -22,7 +22,7 @@ index e37ab57..502262b 100644 // If a function list is possible then build up a list of diff --git a/crates/wasm-smith/src/core/encode.rs b/crates/wasm-smith/src/core/encode.rs -index d2ffd48..5b9b551 100644 +index d2ffd488..5b9b5514 100644 --- a/crates/wasm-smith/src/core/encode.rs +++ b/crates/wasm-smith/src/core/encode.rs @@ -6,7 +6,8 @@ impl Module { diff --git a/.git-third-party/patches/executor/third-party/wasmtime/4 b/.git-third-party/patches/executor/third-party/wasmtime/4 deleted file mode 100644 index 3ccf9edb..00000000 --- a/.git-third-party/patches/executor/third-party/wasmtime/4 +++ /dev/null @@ -1,92 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: kp2pml30 -Date: Thu, 2 Jul 2026 22:33:10 +0900 -Subject: [PATCH] =?UTF-8?q?chore(wasm):=20rename=20DeterministicMode=20tra?= - =?UTF-8?q?p=20to=20NondetInstruction=20=E2=99=BB=EF=B8=8F?= -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - ---- - crates/cranelift/src/func_environ.rs | 4 ++-- - crates/cranelift/src/lib.rs | 4 ++-- - crates/cranelift/src/translate/code_translator.rs | 2 +- - crates/environ/src/trap_encoding.rs | 8 ++++---- - 4 files changed, 9 insertions(+), 9 deletions(-) - -diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs -index 8f549ff5..0c5821fa 100644 ---- a/crates/cranelift/src/func_environ.rs -+++ b/crates/cranelift/src/func_environ.rs -@@ -3929,9 +3929,9 @@ impl FuncEnvironment<'_> { - self.fuel_save_from_var(builder); - } - -- pub fn trap_deterministic_mode(&mut self, builder: &mut FunctionBuilder) { -+ pub fn trap_nondet_instruction(&mut self, builder: &mut FunctionBuilder) { - self.fuel_before_unreachable(builder); -- self.trap(builder, crate::TRAP_DETERMINISTIC_MODE); -+ self.trap(builder, crate::TRAP_NONDET_INSTRUCTION); - self.stacks.reachable = false; - } - -diff --git a/crates/cranelift/src/lib.rs b/crates/cranelift/src/lib.rs -index 4db70f6a..8119e7da 100644 ---- a/crates/cranelift/src/lib.rs -+++ b/crates/cranelift/src/lib.rs -@@ -72,8 +72,8 @@ pub const TRAP_CONTINUATION_ALREADY_CONSUMED: TrapCode = - TrapCode::unwrap_user(Trap::ContinuationAlreadyConsumed as u8 + TRAP_OFFSET); - pub const TRAP_CAST_FAILURE: TrapCode = - TrapCode::unwrap_user(Trap::CastFailure as u8 + TRAP_OFFSET); --pub const TRAP_DETERMINISTIC_MODE: TrapCode = -- TrapCode::unwrap_user(Trap::DeterministicMode as u8 + TRAP_OFFSET); -+pub const TRAP_NONDET_INSTRUCTION: TrapCode = -+ TrapCode::unwrap_user(Trap::NondetInstruction as u8 + TRAP_OFFSET); - - /// Creates a new cranelift `Signature` with no wasm params/results for the - /// given calling convention. -diff --git a/crates/cranelift/src/translate/code_translator.rs b/crates/cranelift/src/translate/code_translator.rs -index 927df0f8..b5cf3d17 100644 ---- a/crates/cranelift/src/translate/code_translator.rs -+++ b/crates/cranelift/src/translate/code_translator.rs -@@ -4574,6 +4574,6 @@ fn float_op_unreachable_check(environ: &mut FuncEnvironment<'_>, builder: &mut F - if environ.are_floats_enabled() { - return false; - } -- environ.trap_deterministic_mode(builder); -+ environ.trap_nondet_instruction(builder); - return true; - } -diff --git a/crates/environ/src/trap_encoding.rs b/crates/environ/src/trap_encoding.rs -index 2d49707b..fe4f0dea 100644 ---- a/crates/environ/src/trap_encoding.rs -+++ b/crates/environ/src/trap_encoding.rs -@@ -142,8 +142,8 @@ pub enum Trap { - /// value. - UnalignedPointer, - -- /// Deterministic mode violation -- DeterministicMode, -+ /// Nondeterministic instruction executed in deterministic mode -+ NondetInstruction, - // if adding a variant here be sure to update the `check!` macro below, and - // remember to update `trap.rs` and `trap.h` as mentioned above - } -@@ -196,7 +196,7 @@ impl Trap { - ListOutOfBounds - InvalidDiscriminant - UnalignedPointer -- DeterministicMode -+ NondetInstruction - } - - None -@@ -242,7 +242,7 @@ impl fmt::Display for Trap { - ListOutOfBounds => "list content out-of-bounds", - InvalidDiscriminant => "invalid variant discriminant", - UnalignedPointer => "unaligned pointer", -- DeterministicMode => "deterministic mode violation (cpu)", -+ NondetInstruction => "nondeterministic instruction (cpu)", - }; - write!(f, "wasm trap: {desc}") - } diff --git a/.git-third-party/patches/executor/third-party/wasmtime/3 b/.git-third-party/patches/executor/third-party/wasmtime/4rr93pqjtwm5m701 similarity index 89% rename from .git-third-party/patches/executor/third-party/wasmtime/3 rename to .git-third-party/patches/executor/third-party/wasmtime/4rr93pqjtwm5m701 index 43aead07..c387d36a 100644 --- a/.git-third-party/patches/executor/third-party/wasmtime/3 +++ b/.git-third-party/patches/executor/third-party/wasmtime/4rr93pqjtwm5m701 @@ -11,17 +11,15 @@ f32x4/f64x2 splat, extract_lane and replace_lane are bit-exact copies (no rounding or NaN semantics), matching the existing exception for loads/bitcasts; genvm-floats-to-soft intentionally leaves them in place, so trapping on them broke real numpy code paths. - -Claude-Session: https://claude.ai/code/session_013QtkVNJFxWsNwCLhTp5idV --- crates/cranelift/src/translate/code_translator.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/cranelift/src/translate/code_translator.rs b/crates/cranelift/src/translate/code_translator.rs -index 9dde783c..927df0f8 100644 +index 5c33b47..0a02c4d 100644 --- a/crates/cranelift/src/translate/code_translator.rs +++ b/crates/cranelift/src/translate/code_translator.rs -@@ -1750,7 +1750,8 @@ pub fn translate_operator( +@@ -1804,7 +1804,8 @@ pub fn translate_operator( } Operator::F32x4Splat | Operator::F64x2Splat => { @@ -31,7 +29,7 @@ index 9dde783c..927df0f8 100644 let splatted = builder.ins().splat(type_of(op), environ.stacks.pop1()); environ.stacks.push1(splatted) } -@@ -1839,7 +1840,7 @@ pub fn translate_operator( +@@ -1893,7 +1894,7 @@ pub fn translate_operator( } Operator::F32x4ExtractLane { lane } | Operator::F64x2ExtractLane { lane } => { @@ -40,7 +38,7 @@ index 9dde783c..927df0f8 100644 let vector = pop1_with_bitcast(environ, type_of(op), builder); environ .stacks -@@ -1864,7 +1865,7 @@ pub fn translate_operator( +@@ -1918,7 +1919,7 @@ pub fn translate_operator( } Operator::F32x4ReplaceLane { lane } | Operator::F64x2ReplaceLane { lane } => { diff --git a/.git-third-party/patches/executor/third-party/wasmtime/5 b/.git-third-party/patches/executor/third-party/wasmtime/5 deleted file mode 100644 index 199319ca..00000000 --- a/.git-third-party/patches/executor/third-party/wasmtime/5 +++ /dev/null @@ -1,85 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: kp2pml30 -Date: Tue, 7 Jul 2026 14:03:52 +0900 -Subject: [PATCH] feat(genvm): configure wasm stack limits - ---- - crates/wasmtime/src/config.rs | 14 ++++++++++++++ - crates/wasmtime/src/runtime/store.rs | 5 ++++- - crates/wasmtime/src/runtime/vm/vmcontext.rs | 8 ++++++++ - 3 files changed, 26 insertions(+), 1 deletion(-) - -diff --git a/crates/wasmtime/src/config.rs b/crates/wasmtime/src/config.rs -index 1cbbd4b2..746ae852 100644 ---- a/crates/wasmtime/src/config.rs -+++ b/crates/wasmtime/src/config.rs -@@ -160,6 +160,8 @@ pub struct Config { - pub(crate) custom_code_memory: Option>, - pub(crate) allocation_strategy: InstanceAllocationStrategy, - pub(crate) max_wasm_stack: usize, -+ pub(crate) wasm_call_stack_limit: u32, -+ pub(crate) wasm_value_stack_limit: u32, - /// Explicitly enabled features via `Config::wasm_*` methods. This is a - /// signal that the embedder specifically wants something turned on - /// regardless of the defaults that Wasmtime might otherwise have enabled. -@@ -274,6 +276,8 @@ impl Config { - // 1` forces this), or at least it passed when this change was - // committed. - max_wasm_stack: 512 * 1024, -+ wasm_call_stack_limit: 1024, -+ wasm_value_stack_limit: 65535, - wasm_backtrace: true, - wasm_backtrace_details_env_used: false, - native_unwind_info: None, -@@ -741,6 +745,16 @@ impl Config { - self - } - -+ /// Configures semantic WebAssembly stack limits. -+ /// -+ /// `call_depth` is the maximum number of nested Wasm function calls and -+ /// `value_slots` is the maximum number of Wasm operand-stack slots. -+ pub fn wasm_stack_limits(&mut self, call_depth: u32, value_slots: u32) -> &mut Self { -+ self.wasm_call_stack_limit = call_depth; -+ self.wasm_value_stack_limit = value_slots; -+ self -+ } -+ - /// Configures the size of the stacks used for asynchronous execution. - /// - /// This setting configures the size of the stacks that are allocated for -diff --git a/crates/wasmtime/src/runtime/store.rs b/crates/wasmtime/src/runtime/store.rs -index 3656a449..ce31edb4 100644 ---- a/crates/wasmtime/src/runtime/store.rs -+++ b/crates/wasmtime/src/runtime/store.rs -@@ -753,7 +753,10 @@ impl Store { - let inner = StoreOpaque { - _marker: marker::PhantomPinned, - engine: engine.clone(), -- vm_store_context: Default::default(), -+ vm_store_context: VMStoreContext::new( -+ engine.config().wasm_call_stack_limit, -+ engine.config().wasm_value_stack_limit, -+ ), - #[cfg(feature = "stack-switching")] - continuations: Vec::new(), - instances: wasmtime_environ::collections::PrimaryMap::new(), -diff --git a/crates/wasmtime/src/runtime/vm/vmcontext.rs b/crates/wasmtime/src/runtime/vm/vmcontext.rs -index 01e3373a..cc0421c3 100644 ---- a/crates/wasmtime/src/runtime/vm/vmcontext.rs -+++ b/crates/wasmtime/src/runtime/vm/vmcontext.rs -@@ -1196,6 +1196,14 @@ pub struct VMStoreContext { - } - - impl VMStoreContext { -+ pub(crate) fn new(wasm_call_stack_limit: u32, wasm_value_stack_limit: u32) -> VMStoreContext { -+ VMStoreContext { -+ call_stack_limit_reverse: UnsafeCell::new(wasm_call_stack_limit), -+ value_stack_limit_reverse: UnsafeCell::new(wasm_value_stack_limit), -+ ..Default::default() -+ } -+ } -+ - /// From the current saved trampoline FP, get the FP of the last - /// Wasm frame. If the current saved trampoline FP is null, return - /// null. diff --git a/.git-third-party/patches/executor/third-party/wasmtime/6xy06vg0d71czwmm b/.git-third-party/patches/executor/third-party/wasmtime/6xy06vg0d71czwmm new file mode 100644 index 00000000..0160cdac --- /dev/null +++ b/.git-third-party/patches/executor/third-party/wasmtime/6xy06vg0d71czwmm @@ -0,0 +1,1391 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: kp2pml30 +Date: Tue, 7 Jul 2026 14:03:52 +0900 +Subject: [PATCH] feat(genvm): configure wasm stack limits + +--- + crates/cranelift/src/alias_region.rs | 86 +++++ + crates/cranelift/src/compiler.rs | 31 -- + crates/cranelift/src/func_environ.rs | 116 +++++-- + .../src/translate/code_translator.rs | 324 ++++++++++++------ + .../src/translate/func_translator.rs | 13 +- + crates/cranelift/src/translate/stack.rs | 34 +- + crates/wasmtime/src/config.rs | 15 + + crates/wasmtime/src/engine/serialization.rs | 6 +- + crates/wasmtime/src/runtime/func.rs | 13 +- + crates/wasmtime/src/runtime/store.rs | 5 +- + crates/wasmtime/src/runtime/vm/vmcontext.rs | 8 + + crates/wiggle/generate/src/wasmtime.rs | 11 +- + 12 files changed, 479 insertions(+), 183 deletions(-) + +diff --git a/crates/cranelift/src/alias_region.rs b/crates/cranelift/src/alias_region.rs +index 873f34b..b63e651 100644 +--- a/crates/cranelift/src/alias_region.rs ++++ b/crates/cranelift/src/alias_region.rs +@@ -1440,6 +1440,92 @@ where + ) + } + ++ /// Load the remaining semantic Wasm call depth. ++ pub fn vmstore_context_call_stack_limit_reverse( ++ &mut self, ++ cursor: &mut FuncCursor<'_>, ++ vmstore_ctx: ir::Value, ++ ) -> ir::Value { ++ let offset = self ++ .offsets ++ .get_ptr_size() ++ .vm_store_context() ++ .call_stack_limit_reverse() ++ .into(); ++ self.vmstore_context_load( ++ cursor, ++ ir::types::I32, ++ ir::MemFlagsData::trusted(), ++ vmstore_ctx, ++ offset, ++ ) ++ } ++ ++ /// Store the remaining semantic Wasm call depth. ++ pub fn store_vmstore_context_call_stack_limit_reverse( ++ &mut self, ++ cursor: &mut FuncCursor<'_>, ++ vmstore_ctx: ir::Value, ++ limit: ir::Value, ++ ) { ++ let offset = self ++ .offsets ++ .get_ptr_size() ++ .vm_store_context() ++ .call_stack_limit_reverse() ++ .into(); ++ self.vmstore_context_store( ++ cursor, ++ ir::MemFlagsData::trusted(), ++ vmstore_ctx, ++ offset, ++ limit, ++ ) ++ } ++ ++ /// Load the remaining semantic Wasm value slots. ++ pub fn vmstore_context_value_stack_limit_reverse( ++ &mut self, ++ cursor: &mut FuncCursor<'_>, ++ vmstore_ctx: ir::Value, ++ ) -> ir::Value { ++ let offset = self ++ .offsets ++ .get_ptr_size() ++ .vm_store_context() ++ .value_stack_limit_reverse() ++ .into(); ++ self.vmstore_context_load( ++ cursor, ++ ir::types::I32, ++ ir::MemFlagsData::trusted(), ++ vmstore_ctx, ++ offset, ++ ) ++ } ++ ++ /// Store the remaining semantic Wasm value slots. ++ pub fn store_vmstore_context_value_stack_limit_reverse( ++ &mut self, ++ cursor: &mut FuncCursor<'_>, ++ vmstore_ctx: ir::Value, ++ limit: ir::Value, ++ ) { ++ let offset = self ++ .offsets ++ .get_ptr_size() ++ .vm_store_context() ++ .value_stack_limit_reverse() ++ .into(); ++ self.vmstore_context_store( ++ cursor, ++ ir::MemFlagsData::trusted(), ++ vmstore_ctx, ++ offset, ++ limit, ++ ) ++ } ++ + /// Load the `VMStoreContext::epoch_deadline` field. + pub fn vmstore_context_epoch_deadline( + &mut self, +diff --git a/crates/cranelift/src/compiler.rs b/crates/cranelift/src/compiler.rs +index afa5ab6..5f3fdee 100644 +--- a/crates/cranelift/src/compiler.rs ++++ b/crates/cranelift/src/compiler.rs +@@ -561,37 +561,6 @@ impl wasmtime_environ::Compiler for Compiler { + } else { + func_env.stack_limit_at_function_entry = Some(stack_limit); + } +- +- let store_ctx = VmctxLoadChain::new([store_ctx].into()).emit_global(&mut context.func); +- func_env.call_stack_depth_reverse = Some(context.func.create_global_value( +- ir::GlobalValueData::IAddImm { +- base: store_ctx, +- offset: i64::from( +- func_env +- .offsets +- .ptr +- .vm_store_context() +- .call_stack_limit_reverse(), +- ) +- .into(), +- global_type: isa.pointer_type(), +- }, +- )); +- +- func_env.value_stack_depth_reverse = Some(context.func.create_global_value( +- ir::GlobalValueData::IAddImm { +- base: store_ctx, +- offset: i64::from( +- func_env +- .offsets +- .ptr +- .vm_store_context() +- .value_stack_limit_reverse(), +- ) +- .into(), +- global_type: isa.pointer_type(), +- }, +- )); + } + let mut validator = + validator.into_validator(mem::take(&mut compiler.cx.validator_allocations)); +diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs +index 7dea98f..ee471b7 100644 +--- a/crates/cranelift/src/func_environ.rs ++++ b/crates/cranelift/src/func_environ.rs +@@ -52,6 +52,14 @@ pub(crate) enum Extension { + Zero, + } + ++#[derive(Copy, Clone)] ++struct SemanticStackLimits { ++ caller_call_limit: ir::Value, ++ caller_value_limit: ir::Value, ++ current_call_limit: ir::Value, ++ current_value_limit: ir::Value, ++} ++ + /// A struct with an `Option` member for every builtin + /// function, to de-duplicate constructing/getting its function. + pub(crate) struct BuiltinFunctions { +@@ -211,8 +219,7 @@ pub struct FuncEnvironment<'module_environment> { + /// into the host to trap when signal handlers are disabled. + pub(crate) stack_limit_at_function_entry: Option, + +- pub call_stack_depth_reverse: Option, +- pub value_stack_depth_reverse: Option, ++ semantic_stack_limits: Option, + + /// Used by the stack switching feature. If set, we have a allocated a + /// slot on this function's stack to be used for the +@@ -301,9 +308,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> { + translation, + + stack_limit_at_function_entry: None, +- +- call_stack_depth_reverse: None, +- value_stack_depth_reverse: None, ++ semantic_stack_limits: None, + + stack_switching_handler_list_buffer: None, + stack_switching_values_buffer: None, +@@ -5144,25 +5149,42 @@ impl FuncEnvironment<'_> { + + self.update_state_slot_vmctx(builder); + +- if let Some(gv) = self.call_stack_depth_reverse { +- let limit_addr = builder.ins().global_value(self.pointer_type(), gv); ++ if let Some(value_slots) = builder.value_stack_size { ++ let vmstore_ctx = self.get_vmstore_context_ptr(builder); ++ let old_call_limit = self ++ .alias_regions ++ .vmstore_context_call_stack_limit_reverse(&mut builder.cursor(), vmstore_ctx); + let one = builder.ins().iconst(I32, 1); +- let old_val = builder.ins().load(ir::types::I32, ir::MemFlags::trusted(), limit_addr, 0); +- let (new_val, overflowed) = builder.ins().usub_overflow(old_val, one); +- self.trapnz(builder, overflowed, ir::TrapCode::STACK_OVERFLOW); +- builder.ins().store(ir::MemFlags::trusted(), new_val, limit_addr, 0); +- } ++ let (new_call_limit, call_limit_exhausted) = ++ builder.ins().usub_overflow(old_call_limit, one); ++ self.trapnz(builder, call_limit_exhausted, ir::TrapCode::STACK_OVERFLOW); ++ self.alias_regions ++ .store_vmstore_context_call_stack_limit_reverse( ++ &mut builder.cursor(), ++ vmstore_ctx, ++ new_call_limit, ++ ); + +- if let Some(gv) = self.value_stack_depth_reverse { +- if let Some(delta_val) = builder.value_stack_size { +- let limit_addr = builder.ins().global_value(self.pointer_type(), gv); +- let old_val = builder.ins().load(ir::types::I32, ir::MemFlags::trusted(), limit_addr, 0); +- let (new_val, overflowed) = builder.ins().usub_overflow(old_val, delta_val); +- self.trapnz(builder, overflowed, ir::TrapCode::STACK_OVERFLOW); +- builder.ins().store(ir::MemFlags::trusted(), new_val, limit_addr, 0); +- } +- } ++ let old_value_limit = self ++ .alias_regions ++ .vmstore_context_value_stack_limit_reverse(&mut builder.cursor(), vmstore_ctx); ++ let (new_value_limit, value_limit_exhausted) = ++ builder.ins().usub_overflow(old_value_limit, value_slots); ++ self.trapnz(builder, value_limit_exhausted, ir::TrapCode::STACK_OVERFLOW); ++ self.alias_regions ++ .store_vmstore_context_value_stack_limit_reverse( ++ &mut builder.cursor(), ++ vmstore_ctx, ++ new_value_limit, ++ ); + ++ self.semantic_stack_limits = Some(SemanticStackLimits { ++ caller_call_limit: old_call_limit, ++ caller_value_limit: old_value_limit, ++ current_call_limit: new_call_limit, ++ current_value_limit: new_value_limit, ++ }); ++ } + + // Additionally we initialize `fuel_var` if it will get used. + if self.tunables.consume_fuel { +@@ -5225,22 +5247,44 @@ impl FuncEnvironment<'_> { + } + + pub fn before_return(&mut self, builder: &mut FunctionBuilder) { +- if let Some(gv) = self.call_stack_depth_reverse { +- let limit_addr = builder.ins().global_value(self.pointer_type(), gv); +- let one = builder.ins().iconst(I32, 1); +- let old_val = builder.ins().load(ir::types::I32, ir::MemFlags::trusted(), limit_addr, 0); +- let (new_val, _) = builder.ins().uadd_overflow(old_val, one); +- builder.ins().store(ir::MemFlags::trusted(), new_val, limit_addr, 0); +- } ++ let Some(limits) = self.semantic_stack_limits else { ++ return; ++ }; ++ let vmstore_ctx = self.get_vmstore_context_ptr(builder); ++ self.alias_regions ++ .store_vmstore_context_call_stack_limit_reverse( ++ &mut builder.cursor(), ++ vmstore_ctx, ++ limits.caller_call_limit, ++ ); ++ self.alias_regions ++ .store_vmstore_context_value_stack_limit_reverse( ++ &mut builder.cursor(), ++ vmstore_ctx, ++ limits.caller_value_limit, ++ ); ++ } + +- if let Some(gv) = self.value_stack_depth_reverse { +- if let Some(delta_val) = builder.value_stack_size { +- let limit_addr = builder.ins().global_value(self.pointer_type(), gv); +- let old_val = builder.ins().load(ir::types::I32, ir::MemFlags::trusted(), limit_addr, 0); +- let (new_val, _) = builder.ins().uadd_overflow(old_val, delta_val); +- builder.ins().store(ir::MemFlags::trusted(), new_val, limit_addr, 0); +- } +- } ++ pub(crate) fn restore_semantic_stack_limits_after_exception( ++ &mut self, ++ builder: &mut FunctionBuilder, ++ ) { ++ let Some(limits) = self.semantic_stack_limits else { ++ return; ++ }; ++ let vmstore_ctx = self.get_vmstore_context_ptr(builder); ++ self.alias_regions ++ .store_vmstore_context_call_stack_limit_reverse( ++ &mut builder.cursor(), ++ vmstore_ctx, ++ limits.current_call_limit, ++ ); ++ self.alias_regions ++ .store_vmstore_context_value_stack_limit_reverse( ++ &mut builder.cursor(), ++ vmstore_ctx, ++ limits.current_value_limit, ++ ); + } + + pub fn translate_cont_bind( +diff --git a/crates/cranelift/src/translate/code_translator.rs b/crates/cranelift/src/translate/code_translator.rs +index 772f112..a7bf09c 100644 +--- a/crates/cranelift/src/translate/code_translator.rs ++++ b/crates/cranelift/src/translate/code_translator.rs +@@ -368,22 +368,17 @@ pub fn translate_operator( + Operator::Else => { + let i = environ.stacks.control_stack.len() - 1; + let reachable = environ.is_reachable(); ++ environ.stacks.finish_if_consequent(i, reachable); + match environ.stacks.control_stack[i] { + ControlStackFrame::If { + ref else_data, + head_is_reachable, +- ref mut consequent_ends_reachable, + num_return_values, + blocktype, + destination, + else_is_cold, + .. + } => { +- // We finished the consequent, so record its final +- // reachability state. +- debug_assert!(consequent_ends_reachable.is_none()); +- *consequent_ends_reachable = Some(reachable); +- + if head_is_reachable { + // We have a branch from the head of the `if` to the `else`. + environ.stacks.reachable = true; +@@ -453,7 +448,7 @@ pub fn translate_operator( + } + } + Operator::End => { +- let frame = environ.stacks.control_stack.pop().unwrap(); ++ let frame = environ.stacks.pop_control(); + let next_block = frame.following_code(); + let return_count = frame.num_return_values(); + +@@ -1071,145 +1066,195 @@ pub fn translate_operator( + environ.stacks.push1(builder.ins().ireduce(I32, val)); + } + Operator::F32Sqrt | Operator::F64Sqrt => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let arg = environ.stacks.pop1(); + environ.stacks.push1(builder.ins().sqrt(arg)); + } + Operator::F32Ceil => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let arg = environ.stacks.pop1(); + let result = environ.ceil_f32(builder, arg); + environ.stacks.push1(result); + } + Operator::F64Ceil => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let arg = environ.stacks.pop1(); + let result = environ.ceil_f64(builder, arg); + environ.stacks.push1(result); + } + Operator::F32Floor => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let arg = environ.stacks.pop1(); + let result = environ.floor_f32(builder, arg); + environ.stacks.push1(result); + } + Operator::F64Floor => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let arg = environ.stacks.pop1(); + let result = environ.floor_f64(builder, arg); + environ.stacks.push1(result); + } + Operator::F32Trunc => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let arg = environ.stacks.pop1(); + let result = environ.trunc_f32(builder, arg); + environ.stacks.push1(result); + } + Operator::F64Trunc => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let arg = environ.stacks.pop1(); + let result = environ.trunc_f64(builder, arg); + environ.stacks.push1(result); + } + Operator::F32Nearest => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let arg = environ.stacks.pop1(); + let result = environ.nearest_f32(builder, arg); + environ.stacks.push1(result); + } + Operator::F64Nearest => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let arg = environ.stacks.pop1(); + let result = environ.nearest_f64(builder, arg); + environ.stacks.push1(result); + } + Operator::F32Abs | Operator::F64Abs => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let val = environ.stacks.pop1(); + environ.stacks.push1(builder.ins().fabs(val)); + } + Operator::F32Neg | Operator::F64Neg => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let arg = environ.stacks.pop1(); + environ.stacks.push1(builder.ins().fneg(arg)); + } + Operator::F64ConvertI64U | Operator::F64ConvertI32U => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let val = environ.stacks.pop1(); + environ.stacks.push1(builder.ins().fcvt_from_uint(F64, val)); + } + Operator::F64ConvertI64S | Operator::F64ConvertI32S => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let val = environ.stacks.pop1(); + environ.stacks.push1(builder.ins().fcvt_from_sint(F64, val)); + } + Operator::F32ConvertI64S | Operator::F32ConvertI32S => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let val = environ.stacks.pop1(); + environ.stacks.push1(builder.ins().fcvt_from_sint(F32, val)); + } + Operator::F32ConvertI64U | Operator::F32ConvertI32U => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let val = environ.stacks.pop1(); + environ.stacks.push1(builder.ins().fcvt_from_uint(F32, val)); + } + Operator::F64PromoteF32 => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let val = environ.stacks.pop1(); + environ.stacks.push1(builder.ins().fpromote(F64, val)); + } + Operator::F32DemoteF64 => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let val = environ.stacks.pop1(); + environ.stacks.push1(builder.ins().fdemote(F32, val)); + } + Operator::I64TruncF64S | Operator::I64TruncF32S => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let val = environ.stacks.pop1(); + let result = environ.translate_fcvt_to_sint(builder, I64, val); + environ.stacks.push1(result); + } + Operator::I32TruncF64S | Operator::I32TruncF32S => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let val = environ.stacks.pop1(); + let result = environ.translate_fcvt_to_sint(builder, I32, val); + environ.stacks.push1(result); + } + Operator::I64TruncF64U | Operator::I64TruncF32U => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let val = environ.stacks.pop1(); + let result = environ.translate_fcvt_to_uint(builder, I64, val); + environ.stacks.push1(result); + } + Operator::I32TruncF64U | Operator::I32TruncF32U => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let val = environ.stacks.pop1(); + let result = environ.translate_fcvt_to_uint(builder, I32, val); + environ.stacks.push1(result); + } + Operator::I64TruncSatF64S | Operator::I64TruncSatF32S => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let val = environ.stacks.pop1(); + environ + .stacks + .push1(builder.ins().fcvt_to_sint_sat(I64, val)); + } + Operator::I32TruncSatF64S | Operator::I32TruncSatF32S => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let val = environ.stacks.pop1(); + environ + .stacks + .push1(builder.ins().fcvt_to_sint_sat(I32, val)); + } + Operator::I64TruncSatF64U | Operator::I64TruncSatF32U => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let val = environ.stacks.pop1(); + environ + .stacks + .push1(builder.ins().fcvt_to_uint_sat(I64, val)); + } + Operator::I32TruncSatF64U | Operator::I32TruncSatF32U => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let val = environ.stacks.pop1(); + environ + .stacks +@@ -1307,7 +1352,9 @@ pub fn translate_operator( + environ.stacks.push1(builder.ins().rotr(arg1, arg2)); + } + Operator::F32Add | Operator::F64Add => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let (arg1, arg2) = environ.stacks.pop2(); + environ.stacks.push1(builder.ins().fadd(arg1, arg2)); + } +@@ -1316,7 +1363,9 @@ pub fn translate_operator( + environ.stacks.push1(builder.ins().isub(arg1, arg2)); + } + Operator::F32Sub | Operator::F64Sub => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let (arg1, arg2) = environ.stacks.pop2(); + environ.stacks.push1(builder.ins().fsub(arg1, arg2)); + } +@@ -1325,12 +1374,16 @@ pub fn translate_operator( + environ.stacks.push1(builder.ins().imul(arg1, arg2)); + } + Operator::F32Mul | Operator::F64Mul => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let (arg1, arg2) = environ.stacks.pop2(); + environ.stacks.push1(builder.ins().fmul(arg1, arg2)); + } + Operator::F32Div | Operator::F64Div => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let (arg1, arg2) = environ.stacks.pop2(); + environ.stacks.push1(builder.ins().fdiv(arg1, arg2)); + } +@@ -1355,17 +1408,23 @@ pub fn translate_operator( + environ.stacks.push1(result); + } + Operator::F32Min | Operator::F64Min => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let (arg1, arg2) = environ.stacks.pop2(); + environ.stacks.push1(builder.ins().fmin(arg1, arg2)); + } + Operator::F32Max | Operator::F64Max => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let (arg1, arg2) = environ.stacks.pop2(); + environ.stacks.push1(builder.ins().fmax(arg1, arg2)); + } + Operator::F32Copysign | Operator::F64Copysign => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let (arg1, arg2) = environ.stacks.pop2(); + environ.stacks.push1(builder.ins().fcopysign(arg1, arg2)); + } +@@ -1797,13 +1856,11 @@ pub fn translate_operator( + let splatted = builder.ins().splat(type_of(op), reduced); + environ.stacks.push1(splatted) + } +- Operator::I32x4Splat +- | Operator::I64x2Splat => { ++ Operator::I32x4Splat | Operator::I64x2Splat => { + let splatted = builder.ins().splat(type_of(op), environ.stacks.pop1()); + environ.stacks.push1(splatted) + } +- Operator::F32x4Splat +- | Operator::F64x2Splat => { ++ Operator::F32x4Splat | Operator::F64x2Splat => { + // Lane duplication is a bit-exact copy (no rounding/NaN semantics), + // so it stays allowed in deterministic mode. + let splatted = builder.ins().splat(type_of(op), environ.stacks.pop1()); +@@ -1885,15 +1942,13 @@ pub fn translate_operator( + // uextend could be elided; for now, uextend is needed for Cranelift's type checks to + // work. + } +- Operator::I32x4ExtractLane { lane } +- | Operator::I64x2ExtractLane { lane } => { ++ Operator::I32x4ExtractLane { lane } | Operator::I64x2ExtractLane { lane } => { + let vector = pop1_with_bitcast(environ, type_of(op), builder); + environ + .stacks + .push1(builder.ins().extractlane(vector, *lane)) + } +- Operator::F32x4ExtractLane { lane } +- | Operator::F64x2ExtractLane { lane } => { ++ Operator::F32x4ExtractLane { lane } | Operator::F64x2ExtractLane { lane } => { + // Bit-exact lane copy; allowed in deterministic mode. + let vector = pop1_with_bitcast(environ, type_of(op), builder); + environ +@@ -1909,16 +1964,14 @@ pub fn translate_operator( + .stacks + .push1(builder.ins().insertlane(vector, reduced, *lane)) + } +- Operator::I32x4ReplaceLane { lane } +- | Operator::I64x2ReplaceLane { lane } => { ++ Operator::I32x4ReplaceLane { lane } | Operator::I64x2ReplaceLane { lane } => { + let (vector, replacement) = environ.stacks.pop2(); + let vector = optionally_bitcast_vector(vector, type_of(op), builder); + environ + .stacks + .push1(builder.ins().insertlane(vector, replacement, *lane)) + } +- Operator::F32x4ReplaceLane { lane } +- | Operator::F64x2ReplaceLane { lane } => { ++ Operator::F32x4ReplaceLane { lane } | Operator::F64x2ReplaceLane { lane } => { + // Bit-exact lane copy; allowed in deterministic mode. + let (vector, replacement) = environ.stacks.pop2(); + let vector = optionally_bitcast_vector(vector, type_of(op), builder); +@@ -2127,37 +2180,51 @@ pub fn translate_operator( + translate_vector_fcmp(FloatCC::GreaterThanOrEqual, type_of(op), builder, environ) + } + Operator::F32x4Add | Operator::F64x2Add => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let (a, b) = pop2_with_bitcast(environ, type_of(op), builder); + environ.stacks.push1(builder.ins().fadd(a, b)) + } + Operator::F32x4Sub | Operator::F64x2Sub => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let (a, b) = pop2_with_bitcast(environ, type_of(op), builder); + environ.stacks.push1(builder.ins().fsub(a, b)) + } + Operator::F32x4Mul | Operator::F64x2Mul => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let (a, b) = pop2_with_bitcast(environ, type_of(op), builder); + environ.stacks.push1(builder.ins().fmul(a, b)) + } + Operator::F32x4Div | Operator::F64x2Div => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let (a, b) = pop2_with_bitcast(environ, type_of(op), builder); + environ.stacks.push1(builder.ins().fdiv(a, b)) + } + Operator::F32x4Max | Operator::F64x2Max => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let (a, b) = pop2_with_bitcast(environ, type_of(op), builder); + environ.stacks.push1(builder.ins().fmax(a, b)) + } + Operator::F32x4Min | Operator::F64x2Min => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let (a, b) = pop2_with_bitcast(environ, type_of(op), builder); + environ.stacks.push1(builder.ins().fmin(a, b)) + } + Operator::F32x4PMax | Operator::F64x2PMax => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + // Note the careful ordering here with respect to `fcmp` and + // `bitselect`. This matches the spec definition of: + // +@@ -2171,7 +2238,9 @@ pub fn translate_operator( + environ.stacks.push1(builder.ins().bitselect(cmp, b, a)) + } + Operator::F32x4PMin | Operator::F64x2PMin => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + // Note the careful ordering here which is similar to `pmax` above: + // + // fpmin(z1, z2) = +@@ -2184,32 +2253,44 @@ pub fn translate_operator( + environ.stacks.push1(builder.ins().bitselect(cmp, b, a)) + } + Operator::F32x4Sqrt | Operator::F64x2Sqrt => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let a = pop1_with_bitcast(environ, type_of(op), builder); + environ.stacks.push1(builder.ins().sqrt(a)) + } + Operator::F32x4Neg | Operator::F64x2Neg => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let a = pop1_with_bitcast(environ, type_of(op), builder); + environ.stacks.push1(builder.ins().fneg(a)) + } + Operator::F32x4Abs | Operator::F64x2Abs => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let a = pop1_with_bitcast(environ, type_of(op), builder); + environ.stacks.push1(builder.ins().fabs(a)) + } + Operator::F32x4ConvertI32x4S => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let a = pop1_with_bitcast(environ, I32X4, builder); + environ.stacks.push1(builder.ins().fcvt_from_sint(F32X4, a)) + } + Operator::F32x4ConvertI32x4U => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let a = pop1_with_bitcast(environ, I32X4, builder); + environ.stacks.push1(builder.ins().fcvt_from_uint(F32X4, a)) + } + Operator::F64x2ConvertLowI32x4S => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let a = pop1_with_bitcast(environ, I32X4, builder); + let widened_a = builder.ins().swiden_low(a); + environ +@@ -2217,7 +2298,9 @@ pub fn translate_operator( + .push1(builder.ins().fcvt_from_sint(F64X2, widened_a)); + } + Operator::F64x2ConvertLowI32x4U => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let a = pop1_with_bitcast(environ, I32X4, builder); + let widened_a = builder.ins().uwiden_low(a); + environ +@@ -2225,24 +2308,32 @@ pub fn translate_operator( + .push1(builder.ins().fcvt_from_uint(F64X2, widened_a)); + } + Operator::F64x2PromoteLowF32x4 => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let a = pop1_with_bitcast(environ, F32X4, builder); + environ.stacks.push1(builder.ins().fvpromote_low(a)); + } + Operator::F32x4DemoteF64x2Zero => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let a = pop1_with_bitcast(environ, F64X2, builder); + environ.stacks.push1(builder.ins().fvdemote(a)); + } + Operator::I32x4TruncSatF32x4S => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let a = pop1_with_bitcast(environ, F32X4, builder); + environ + .stacks + .push1(builder.ins().fcvt_to_sint_sat(I32X4, a)) + } + Operator::I32x4TruncSatF64x2SZero => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let a = pop1_with_bitcast(environ, F64X2, builder); + let converted_a = builder.ins().fcvt_to_sint_sat(I64X2, a); + let handle = builder.func.dfg.constants.insert(vec![0u8; 16].into()); +@@ -2265,14 +2356,18 @@ pub fn translate_operator( + // perhaps for other backends too) should be added and the codegen for + // the relaxed instruction should conditionally be different. + Operator::I32x4RelaxedTruncF32x4U | Operator::I32x4TruncSatF32x4U => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let a = pop1_with_bitcast(environ, F32X4, builder); + environ + .stacks + .push1(builder.ins().fcvt_to_uint_sat(I32X4, a)) + } + Operator::I32x4RelaxedTruncF64x2UZero | Operator::I32x4TruncSatF64x2UZero => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let a = pop1_with_bitcast(environ, F64X2, builder); + let zero_constant = builder.func.dfg.constants.insert(vec![0u8; 16].into()); + let result = if environ.is_x86() && !environ.isa().has_round() { +@@ -2393,49 +2488,65 @@ pub fn translate_operator( + .push1(builder.ins().iadd_pairwise(widen_low, widen_high)); + } + Operator::F32x4Ceil => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let arg = pop1_with_bitcast(environ, F32X4, builder); + let result = environ.ceil_f32x4(builder, arg); + environ.stacks.push1(result); + } + Operator::F64x2Ceil => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let arg = pop1_with_bitcast(environ, F64X2, builder); + let result = environ.ceil_f64x2(builder, arg); + environ.stacks.push1(result); + } + Operator::F32x4Floor => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let arg = pop1_with_bitcast(environ, F32X4, builder); + let result = environ.floor_f32x4(builder, arg); + environ.stacks.push1(result); + } + Operator::F64x2Floor => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let arg = pop1_with_bitcast(environ, F64X2, builder); + let result = environ.floor_f64x2(builder, arg); + environ.stacks.push1(result); + } + Operator::F32x4Trunc => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let arg = pop1_with_bitcast(environ, F32X4, builder); + let result = environ.trunc_f32x4(builder, arg); + environ.stacks.push1(result); + } + Operator::F64x2Trunc => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let arg = pop1_with_bitcast(environ, F64X2, builder); + let result = environ.trunc_f64x2(builder, arg); + environ.stacks.push1(result); + } + Operator::F32x4Nearest => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let arg = pop1_with_bitcast(environ, F32X4, builder); + let result = environ.nearest_f32x4(builder, arg); + environ.stacks.push1(result); + } + Operator::F64x2Nearest => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let arg = pop1_with_bitcast(environ, F64X2, builder); + let result = environ.nearest_f64x2(builder, arg); + environ.stacks.push1(result); +@@ -2538,7 +2649,9 @@ pub fn translate_operator( + } + + Operator::F32x4RelaxedMax | Operator::F64x2RelaxedMax => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let ty = type_of(op); + let (a, b) = pop2_with_bitcast(environ, ty, builder); + environ.stacks.push1( +@@ -2558,7 +2671,9 @@ pub fn translate_operator( + } + + Operator::F32x4RelaxedMin | Operator::F64x2RelaxedMin => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let ty = type_of(op); + let (a, b) = pop2_with_bitcast(environ, ty, builder); + environ.stacks.push1( +@@ -2584,26 +2699,34 @@ pub fn translate_operator( + } + + Operator::F32x4RelaxedMadd => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let (a, b, c) = pop3_with_bitcast(environ, type_of(op), builder); + let result = environ.fma_f32x4(builder, a, b, c); + environ.stacks.push1(result); + } + Operator::F64x2RelaxedMadd => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let (a, b, c) = pop3_with_bitcast(environ, type_of(op), builder); + let result = environ.fma_f64x2(builder, a, b, c); + environ.stacks.push1(result); + } + Operator::F32x4RelaxedNmadd => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let (a, b, c) = pop3_with_bitcast(environ, type_of(op), builder); + let a = builder.ins().fneg(a); + let result = environ.fma_f32x4(builder, a, b, c); + environ.stacks.push1(result); + } + Operator::F64x2RelaxedNmadd => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let (a, b, c) = pop3_with_bitcast(environ, type_of(op), builder); + let a = builder.ins().fneg(a); + let result = environ.fma_f64x2(builder, a, b, c); +@@ -2633,7 +2756,9 @@ pub fn translate_operator( + } + + Operator::I32x4RelaxedTruncF32x4S => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let a = pop1_with_bitcast(environ, F32X4, builder); + environ.stacks.push1( + if environ.relaxed_simd_deterministic() || !environ.is_x86() { +@@ -2646,7 +2771,9 @@ pub fn translate_operator( + ) + } + Operator::I32x4RelaxedTruncF64x2SZero => { +- if float_op_unreachable_check(environ, builder) { return Ok(()) } ++ if float_op_unreachable_check(environ, builder) { ++ return Ok(()); ++ } + let a = pop1_with_bitcast(environ, F64X2, builder); + let converted_a = if environ.relaxed_simd_deterministic() || !environ.is_x86() { + // Deterministic semantics are to match the +@@ -3558,16 +3685,13 @@ fn translate_unreachable_operator( + Operator::Else => { + let i = environ.stacks.control_stack.len() - 1; + let reachable = environ.is_reachable(); ++ environ.stacks.finish_if_consequent(i, reachable); + match environ.stacks.control_stack[i] { + ControlStackFrame::If { + ref else_data, + head_is_reachable, +- ref mut consequent_ends_reachable, + .. + } => { +- debug_assert!(consequent_ends_reachable.is_none()); +- *consequent_ends_reachable = Some(reachable); +- + if head_is_reachable { + // We have a branch from the head of the `if` to the `else`. + environ.stacks.reachable = true; +@@ -3615,7 +3739,7 @@ fn translate_unreachable_operator( + } + } + Operator::End => { +- let frame = environ.stacks.control_stack.pop().unwrap(); ++ let frame = environ.stacks.pop_control(); + + frame.restore_catch_handlers(&mut environ.stacks.handlers, builder); + +@@ -4168,7 +4292,9 @@ fn translate_vector_icmp( + } + + fn translate_fcmp(cc: FloatCC, builder: &mut FunctionBuilder, env: &mut FuncEnvironment<'_>) { +- if float_op_unreachable_check(env, builder) { return } ++ if float_op_unreachable_check(env, builder) { ++ return; ++ } + let (arg0, arg1) = env.stacks.pop2(); + let val = builder.ins().fcmp(cc, arg0, arg1); + env.stacks.push1(builder.ins().uextend(I32, val)); +@@ -4180,7 +4306,9 @@ fn translate_vector_fcmp( + builder: &mut FunctionBuilder, + env: &mut FuncEnvironment<'_>, + ) { +- if float_op_unreachable_check(env, builder) { return } ++ if float_op_unreachable_check(env, builder) { ++ return; ++ } + let (a, b) = env.stacks.pop2(); + let bitcast_a = optionally_bitcast_vector(a, needed_type, builder); + let bitcast_b = optionally_bitcast_vector(b, needed_type, builder); +@@ -4720,6 +4848,7 @@ fn create_catch_block( + let block = builder.create_block(); + let exn_ref = builder.append_block_param(block, exn_payload_ty); + builder.switch_to_block(block); ++ environ.restore_semantic_stack_limits_after_exception(builder); + debug_assert!(exn_ref_ty.bits() <= exn_payload_ty.bits()); + let exn_ref = if exn_ref_ty.bits() < exn_payload_ty.bits() { + builder.ins().ireduce(exn_ref_ty, exn_ref) +@@ -4760,7 +4889,10 @@ fn create_catch_block( + Ok(block) + } + +-fn float_op_unreachable_check(environ: &mut FuncEnvironment<'_>, builder: &mut FunctionBuilder) -> bool { ++fn float_op_unreachable_check( ++ environ: &mut FuncEnvironment<'_>, ++ builder: &mut FunctionBuilder, ++) -> bool { + if environ.are_floats_enabled() { + return false; + } +diff --git a/crates/cranelift/src/translate/func_translator.rs b/crates/cranelift/src/translate/func_translator.rs +index 3177a6b..1b448fe 100644 +--- a/crates/cranelift/src/translate/func_translator.rs ++++ b/crates/cranelift/src/translate/func_translator.rs +@@ -121,18 +121,19 @@ impl FuncTranslator { + + parse_function_body(validator, reader, &mut builder, environ)?; + +- let total_slots = u64::from(total_locals) + environ.stacks.max_stack as u64; +- if total_slots > u64::from(u16::MAX) { ++ let total_slots = ++ num_params as u64 + u64::from(total_locals) + environ.stacks.max_stack as u64; ++ if total_slots > u64::from(u32::MAX) { + return Err(wasmtime_environ::WasmError::InvalidWebAssembly { + message: "too many locals and operand stack values".to_owned(), + offset: 0, + }); + } + let placeholder = builder.func.dfg.value_def(value_stack_size).unwrap_inst(); +- builder.func.dfg.replace(placeholder).iconst( +- cranelift_codegen::ir::types::I32, +- total_slots as i64, +- ); ++ builder ++ .func ++ .replace(placeholder) ++ .iconst(cranelift_codegen::ir::types::I32, total_slots as i64); + + builder.finalize(environ.target_config()); + crate::alias_region::debug_assert_all_mem_insts_have_alias_regions(func); +diff --git a/crates/cranelift/src/translate/stack.rs b/crates/cranelift/src/translate/stack.rs +index 8772f54..8fd876f 100644 +--- a/crates/cranelift/src/translate/stack.rs ++++ b/crates/cranelift/src/translate/stack.rs +@@ -261,6 +261,7 @@ pub struct FuncTranslationStacks { + /// point. + pub(crate) stack: Vec, + pub(crate) max_stack: usize, ++ hidden_if_params: usize, + /// "Shape" of stack at each index, if emitting debug instrumentation. + /// + /// When we pop `stack`, we automatically pop `stack_shape` as +@@ -311,6 +312,7 @@ impl FuncTranslationStacks { + Self { + stack: Vec::new(), + max_stack: 0, ++ hidden_if_params: 0, + stack_shape: Vec::new(), + control_stack: Vec::new(), + block_param_vars: SecondaryMap::new(), +@@ -321,7 +323,7 @@ impl FuncTranslationStacks { + + /// + pub fn recalc_stack(&mut self) { +- self.max_stack = self.max_stack.max(self.stack.len()); ++ self.max_stack = self.max_stack.max(self.stack.len() - self.hidden_if_params); + } + + fn clear(&mut self) { +@@ -329,8 +331,10 @@ impl FuncTranslationStacks { + debug_assert!(self.stack_shape.is_empty()); + debug_assert!(self.control_stack.is_empty()); + debug_assert!(self.handlers.is_empty()); ++ debug_assert_eq!(self.hidden_if_params, 0); + self.block_param_vars.clear(); + self.max_stack = 0; ++ self.hidden_if_params = 0; + self.reachable = true; + } + +@@ -560,6 +564,7 @@ impl FuncTranslationStacks { + self.stack_shape.push(shape); + } + } ++ self.hidden_if_params += num_param_types; + + self.control_stack.push(ControlStackFrame::If { + destination, +@@ -575,6 +580,33 @@ impl FuncTranslationStacks { + }); + } + ++ pub(crate) fn finish_if_consequent(&mut self, index: usize, reachable: bool) { ++ let ControlStackFrame::If { ++ num_param_values, ++ consequent_ends_reachable, ++ .. ++ } = &mut self.control_stack[index] ++ else { ++ unreachable!() ++ }; ++ debug_assert!(consequent_ends_reachable.is_none()); ++ *consequent_ends_reachable = Some(reachable); ++ self.hidden_if_params -= *num_param_values; ++ } ++ ++ pub(crate) fn pop_control(&mut self) -> ControlStackFrame { ++ let frame = self.control_stack.pop().unwrap(); ++ if let ControlStackFrame::If { ++ num_param_values, ++ consequent_ends_reachable: None, ++ .. ++ } = &frame ++ { ++ self.hidden_if_params -= *num_param_values; ++ } ++ frame ++ } ++ + pub(crate) fn assert_debug_stack_is_synced(&self) { + debug_assert!(self.stack_shape.is_empty() || self.stack_shape.len() == self.stack.len()); + } +diff --git a/crates/wasmtime/src/config.rs b/crates/wasmtime/src/config.rs +index cc5640b..b3bd0cd 100644 +--- a/crates/wasmtime/src/config.rs ++++ b/crates/wasmtime/src/config.rs +@@ -173,6 +173,8 @@ pub struct Config { + pub(crate) custom_code_memory: Option>, + pub(crate) allocation_strategy: InstanceAllocationStrategy, + pub(crate) max_wasm_stack: usize, ++ pub(crate) wasm_call_stack_limit: u32, ++ pub(crate) wasm_value_stack_limit: u32, + /// Explicitly enabled features via `Config::wasm_*` methods. This is a + /// signal that the embedder specifically wants something turned on + /// regardless of the defaults that Wasmtime might otherwise have enabled. +@@ -293,6 +295,8 @@ impl Config { + // 1` forces this), or at least it passed when this change was + // committed. + max_wasm_stack: 512 * 1024, ++ wasm_call_stack_limit: 1024, ++ wasm_value_stack_limit: 65535, + wasm_backtrace_details_env_used: false, + wasm_backtrace_max_frames: Some(DEFAULT_WASM_BACKTRACE_MAX_FRAMES), + native_unwind_info: None, +@@ -855,6 +859,17 @@ impl Config { + self + } + ++ /// Configures semantic WebAssembly stack limits. ++ /// ++ /// `call_depth` is the maximum number of nested Wasm function calls and ++ /// `value_slots` is the maximum combined number of local and operand-stack ++ /// slots across active Wasm calls. ++ pub fn wasm_stack_limits(&mut self, call_depth: u32, value_slots: u32) -> &mut Self { ++ self.wasm_call_stack_limit = call_depth; ++ self.wasm_value_stack_limit = value_slots; ++ self ++ } ++ + /// Configures the size of the stacks used for asynchronous execution. + /// + /// This setting configures the size of the stacks that are allocated for +diff --git a/crates/wasmtime/src/engine/serialization.rs b/crates/wasmtime/src/engine/serialization.rs +index bd8f42f..b90a75d 100644 +--- a/crates/wasmtime/src/engine/serialization.rs ++++ b/crates/wasmtime/src/engine/serialization.rs +@@ -403,11 +403,7 @@ impl Metadata<'_> { + other.signals_based_traps, + "Signals-based traps", + )?; +- Self::check_bool( +- floats_enabled, +- other.floats_enabled, +- "Floats enabled", +- )?; ++ Self::check_bool(floats_enabled, other.floats_enabled, "Floats enabled")?; + Self::check_bool( + memory_init_cow, + other.memory_init_cow, +diff --git a/crates/wasmtime/src/runtime/func.rs b/crates/wasmtime/src/runtime/func.rs +index c657833..b129bed 100644 +--- a/crates/wasmtime/src/runtime/func.rs ++++ b/crates/wasmtime/src/runtime/func.rs +@@ -1509,7 +1509,10 @@ impl<'a, T: 'static> StoreContextMut<'a, T> { + duplicate += 1; + } + +- for mem in inst.all_memories(store.0.store_opaque_mut()).collect::>() { ++ for mem in inst ++ .all_memories(store.0.store_opaque_mut()) ++ .collect::>() ++ { + let data = match &mem.1 { + crate::runtime::vm::ExportMemory::Unshared(m) => m.data(&store), + crate::runtime::vm::ExportMemory::Shared(_sm, _) => &[], +@@ -1581,6 +1584,8 @@ pub(crate) struct EntryStoreContext { + pub last_wasm_entry_sp: usize, + pub last_wasm_entry_trap_handler: usize, + pub stack_chain: VMStackChain, ++ pub call_stack_limit_reverse: u32, ++ pub value_stack_limit_reverse: u32, + + /// We need a pointer to the runtime limits, so we can update them from + /// `drop`/`exit_wasm`. +@@ -1686,6 +1691,8 @@ impl EntryStoreContext { + .last_wasm_entry_trap_handler + .get(), + stack_chain, ++ call_stack_limit_reverse: *(*vm_store_context).call_stack_limit_reverse.get(), ++ value_stack_limit_reverse: *(*vm_store_context).value_stack_limit_reverse.get(), + vm_store_context, + } + } +@@ -1710,6 +1717,10 @@ impl EntryStoreContext { + *(*self.vm_store_context).last_wasm_entry_trap_handler.get() = + self.last_wasm_entry_trap_handler; + *(*self.vm_store_context).stack_chain.get() = self.stack_chain.clone(); ++ *(*self.vm_store_context).call_stack_limit_reverse.get() = ++ self.call_stack_limit_reverse; ++ *(*self.vm_store_context).value_stack_limit_reverse.get() = ++ self.value_stack_limit_reverse; + } + } + } +diff --git a/crates/wasmtime/src/runtime/store.rs b/crates/wasmtime/src/runtime/store.rs +index f7ab83b..cad9d79 100644 +--- a/crates/wasmtime/src/runtime/store.rs ++++ b/crates/wasmtime/src/runtime/store.rs +@@ -737,7 +737,10 @@ impl Store { + let inner = StoreOpaque { + _marker: marker::PhantomPinned, + engine: engine.clone(), +- vm_store_context: Default::default(), ++ vm_store_context: VMStoreContext::new( ++ engine.config().wasm_call_stack_limit, ++ engine.config().wasm_value_stack_limit, ++ ), + #[cfg(feature = "stack-switching")] + continuations: Vec::new(), + instances: TryPrimaryMap::new(), +diff --git a/crates/wasmtime/src/runtime/vm/vmcontext.rs b/crates/wasmtime/src/runtime/vm/vmcontext.rs +index 4509bc4..a086355 100644 +--- a/crates/wasmtime/src/runtime/vm/vmcontext.rs ++++ b/crates/wasmtime/src/runtime/vm/vmcontext.rs +@@ -721,6 +721,14 @@ const _: () = { + }; + + impl VMStoreContext { ++ pub(crate) fn new(wasm_call_stack_limit: u32, wasm_value_stack_limit: u32) -> VMStoreContext { ++ VMStoreContext { ++ call_stack_limit_reverse: UnsafeCell::new(wasm_call_stack_limit), ++ value_stack_limit_reverse: UnsafeCell::new(wasm_value_stack_limit), ++ ..Default::default() ++ } ++ } ++ + /// From the current saved trampoline FP, get the FP of the last + /// Wasm frame. If the current saved trampoline FP is null, return + /// null. +diff --git a/crates/wiggle/generate/src/wasmtime.rs b/crates/wiggle/generate/src/wasmtime.rs +index ad86140..6147c72 100644 +--- a/crates/wiggle/generate/src/wasmtime.rs ++++ b/crates/wiggle/generate/src/wasmtime.rs +@@ -53,7 +53,10 @@ pub fn link_module( + let trait_name = if target_path.is_none() { + format_ident!("AddToLinkerFn") + } else { +- format_ident!("Add{}ToLinkerFn", module.name.as_str().to_upper_camel_case()) ++ format_ident!( ++ "Add{}ToLinkerFn", ++ module.name.as_str().to_upper_camel_case() ++ ) + }; + return quote! { + pub trait #trait_name { +@@ -149,11 +152,7 @@ fn generate_func( + quote!(get_cx) + }; + +- let cx_ref = if ctx_ref_type { +- quote!(&mut) +- } else { +- quote!() +- }; ++ let cx_ref = if ctx_ref_type { quote!(&mut) } else { quote!() }; + + let body = quote! { + let export = caller.get_export("memory"); diff --git a/.git-third-party/patches/executor/third-party/wasmtime/1 b/.git-third-party/patches/executor/third-party/wasmtime/gbm0xv16dc1fs2km similarity index 81% rename from .git-third-party/patches/executor/third-party/wasmtime/1 rename to .git-third-party/patches/executor/third-party/wasmtime/gbm0xv16dc1fs2km index 93c93761..c10b52b9 100644 --- a/.git-third-party/patches/executor/third-party/wasmtime/1 +++ b/.git-third-party/patches/executor/third-party/wasmtime/gbm0xv16dc1fs2km @@ -6,52 +6,54 @@ Subject: [PATCH] feat: rebase genvm --- Cargo.toml | 24 ++-- cranelift/frontend/src/frontend.rs | 4 + + crates/c-api/include/wasmtime/trap.h | 2 + + crates/c-api/src/trap.rs | 1 + crates/cache/src/config.rs | 8 +- - crates/cranelift/src/compiler.rs | 12 ++ - crates/cranelift/src/func_environ.rs | 74 ++++++++++++ + crates/cranelift/src/compiler.rs | 31 +++++ + crates/cranelift/src/func_environ.rs | 67 +++++++++++ crates/cranelift/src/lib.rs | 2 + .../src/translate/code_translator.rs | 109 +++++++++++++++++- - .../src/translate/func_translator.rs | 20 +++- - crates/cranelift/src/translate/stack.rs | 10 ++ + .../src/translate/func_translator.rs | 27 ++++- + crates/cranelift/src/translate/stack.rs | 11 ++ crates/environ/Cargo.toml | 2 +- - crates/environ/src/trap_encoding.rs | 5 + + crates/environ/src/trap_encoding.rs | 3 + crates/environ/src/tunables.rs | 4 + - crates/environ/src/vmoffsets.rs | 10 ++ + crates/environ/src/vmtypes.rs | 6 + crates/wasmtime/Cargo.toml | 2 + - crates/wasmtime/src/config.rs | 22 +++- + crates/wasmtime/src/config.rs | 20 ++++ crates/wasmtime/src/engine/serialization.rs | 6 + crates/wasmtime/src/lib.rs | 3 + crates/wasmtime/src/runtime/func.rs | 71 ++++++++++++ crates/wasmtime/src/runtime/instance.rs | 1 - crates/wasmtime/src/runtime/store.rs | 29 +++-- - crates/wasmtime/src/runtime/vm/vmcontext.rs | 7 +- + crates/wasmtime/src/runtime/vm/vmcontext.rs | 4 +- crates/wiggle/generate/src/config.rs | 7 +- crates/wiggle/generate/src/module_trait.rs | 7 -- crates/wiggle/generate/src/wasmtime.rs | 60 ++++++++-- crates/wiggle/src/guest_error.rs | 2 + crates/wiggle/src/lib.rs | 5 + - 26 files changed, 453 insertions(+), 53 deletions(-) + 28 files changed, 466 insertions(+), 52 deletions(-) diff --git a/Cargo.toml b/Cargo.toml -index dc159f65..1a0bcd80 100644 +index 83b09c9..4560d95 100644 --- a/Cargo.toml +++ b/Cargo.toml -@@ -343,18 +343,18 @@ wit-bindgen = { version = "0.51.0", default-features = false } - wit-bindgen-rust-macro = { version = "0.51.0", default-features = false } +@@ -375,18 +375,18 @@ wit-bindgen = { version = "0.60.0", default-features = false } + wit-bindgen-rust-macro = { version = "0.60.0", default-features = false } # wasm-tools family: --wasmparser = { version = "0.244.0", default-features = false, features = ['simd'] } --wat = "1.244.0" --wast = "244.0.0" --wasmprinter = "0.244.0" --wasm-encoder = "0.244.0" --wasm-smith = "0.244.0" --wasm-mutate = "0.244.0" --wit-parser = "0.244.0" --wit-component = "0.244.0" --wasm-wave = "0.244.0" --wasm-compose = "0.244.0" --json-from-wast = "0.244.0" +-wasmparser = { version = "0.254.0", default-features = false, features = ['simd'] } +-wat = "1.254.0" +-wast = "254.0.0" +-wasmprinter = "0.254.0" +-wasm-encoder = "0.254.0" +-wasm-smith = "0.254.0" +-wasm-mutate = "0.254.0" +-wit-parser = "0.254.0" +-wit-component = "0.254.0" +-wasm-wave = "0.254.0" +-wasm-compose = { version = "0.254.0", default-features = false } +-json-from-wast = "0.254.0" +wasmparser = { path = "../wasm-tools/crates/wasmparser", default-features = false, features = ['simd']} +wat = { path = "../wasm-tools/crates/wat" } +wast = { path = "../wasm-tools/crates/wast" } @@ -65,32 +67,57 @@ index dc159f65..1a0bcd80 100644 +wasm-compose = { path = "../wasm-tools/crates/wasm-compose" } +json-from-wast = { path = "../wasm-tools/crates/json-from-wast" } - # Non-Bytecode Alliance maintained dependencies: - # -------------------------- + wstd = "0.6.5" + wasip2 = "1.0" diff --git a/cranelift/frontend/src/frontend.rs b/cranelift/frontend/src/frontend.rs -index d51dbbbb..5ceb7b48 100644 +index 195de37..5559ac0 100644 --- a/cranelift/frontend/src/frontend.rs +++ b/cranelift/frontend/src/frontend.rs -@@ -47,6 +47,9 @@ pub struct FunctionBuilder<'a> { +@@ -45,6 +45,9 @@ pub struct FunctionBuilder<'a> { func_ctx: &'a mut FunctionBuilderContext, position: PackedOption, + -+ /// -+ pub value_stack_size_inst: Option, ++ /// Placeholder value for the function's semantic value-stack usage. ++ pub value_stack_size: Option, } #[derive(Clone, Default, Eq, PartialEq)] -@@ -325,6 +328,7 @@ impl<'a> FunctionBuilder<'a> { +@@ -327,6 +330,7 @@ impl<'a> FunctionBuilder<'a> { srcloc: Default::default(), func_ctx, position: Default::default(), -+ value_stack_size_inst: None, ++ value_stack_size: None, } } +diff --git a/crates/c-api/include/wasmtime/trap.h b/crates/c-api/include/wasmtime/trap.h +index 523c3c5..f5dfe91 100644 +--- a/crates/c-api/include/wasmtime/trap.h ++++ b/crates/c-api/include/wasmtime/trap.h +@@ -144,6 +144,8 @@ enum wasmtime_trap_code_enum { + WASMTIME_TRAP_CODE_WAITABLE_SYNC_AND_ASYNC = 48, + /// An exception propagated out of a component without being caught. + WASMTIME_TRAP_CODE_UNCAUGHT_EXCEPTION = 49, ++ /// A deterministic-mode restriction was violated. ++ WASMTIME_TRAP_CODE_DETERMINISTIC_MODE = 50, + }; + + /** +diff --git a/crates/c-api/src/trap.rs b/crates/c-api/src/trap.rs +index b1750c6..80dcb86 100644 +--- a/crates/c-api/src/trap.rs ++++ b/crates/c-api/src/trap.rs +@@ -56,6 +56,7 @@ const _: () = { + assert!(Trap::StreamOpTooBig as u8 == 47); + assert!(Trap::WaitableSyncAndAsync as u8 == 48); + assert!(Trap::UncaughtException as u8 == 49); ++ assert!(Trap::DeterministicMode as u8 == 50); + }; + + #[repr(C)] diff --git a/crates/cache/src/config.rs b/crates/cache/src/config.rs -index 90de0060..2451a73e 100644 +index bc39f87..5e4200d 100644 --- a/crates/cache/src/config.rs +++ b/crates/cache/src/config.rs @@ -339,10 +339,16 @@ impl CacheConfig { @@ -112,35 +139,54 @@ index 90de0060..2451a73e 100644 // get config file path let (config_file, user_custom_file) = match config_file { diff --git a/crates/cranelift/src/compiler.rs b/crates/cranelift/src/compiler.rs -index 3b75e282..0529e5fa 100644 +index 5f3fdee..afa5ab6 100644 --- a/crates/cranelift/src/compiler.rs +++ b/crates/cranelift/src/compiler.rs -@@ -314,6 +314,18 @@ impl wasmtime_environ::Compiler for Compiler { +@@ -561,6 +561,37 @@ impl wasmtime_environ::Compiler for Compiler { } else { func_env.stack_limit_at_function_entry = Some(stack_limit); } + -+ func_env.call_stack_depth_reverse = Some(context.func.create_global_value(ir::GlobalValueData::IAddImm { -+ base: interrupts_ptr, -+ offset: ir::immediates::Imm64::new(i32::from(func_env.offsets.ptr.vmstore_context_call_stack_left()).into()), -+ global_type: isa.pointer_type(), -+ })); ++ let store_ctx = VmctxLoadChain::new([store_ctx].into()).emit_global(&mut context.func); ++ func_env.call_stack_depth_reverse = Some(context.func.create_global_value( ++ ir::GlobalValueData::IAddImm { ++ base: store_ctx, ++ offset: i64::from( ++ func_env ++ .offsets ++ .ptr ++ .vm_store_context() ++ .call_stack_limit_reverse(), ++ ) ++ .into(), ++ global_type: isa.pointer_type(), ++ }, ++ )); + -+ func_env.value_stack_depth_reverse = Some(context.func.create_global_value(ir::GlobalValueData::IAddImm { -+ base: interrupts_ptr, -+ offset: ir::immediates::Imm64::new(i32::from(func_env.offsets.ptr.vmstore_context_value_stack_left()).into()), -+ global_type: isa.pointer_type(), -+ })); ++ func_env.value_stack_depth_reverse = Some(context.func.create_global_value( ++ ir::GlobalValueData::IAddImm { ++ base: store_ctx, ++ offset: i64::from( ++ func_env ++ .offsets ++ .ptr ++ .vm_store_context() ++ .value_stack_limit_reverse(), ++ ) ++ .into(), ++ global_type: isa.pointer_type(), ++ }, ++ )); } - let FunctionBodyData { validator, body } = input; let mut validator = + validator.into_validator(mem::take(&mut compiler.cx.validator_allocations)); diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs -index 5bb16980..8f549ff5 100644 +index 64e9642..fe1b8d8 100644 --- a/crates/cranelift/src/func_environ.rs +++ b/crates/cranelift/src/func_environ.rs -@@ -203,6 +203,9 @@ pub struct FuncEnvironment<'module_environment> { +@@ -211,6 +211,9 @@ pub struct FuncEnvironment<'module_environment> { /// into the host to trap when signal handlers are disabled. - pub(crate) stack_limit_at_function_entry: Option, + pub(crate) stack_limit_at_function_entry: Option, + pub call_stack_depth_reverse: Option, + pub value_stack_depth_reverse: Option, @@ -148,7 +194,7 @@ index 5bb16980..8f549ff5 100644 /// Used by the stack switching feature. If set, we have a allocated a /// slot on this function's stack to be used for the /// current stack's `handler_list` field. -@@ -273,6 +276,9 @@ impl<'module_environment> FuncEnvironment<'module_environment> { +@@ -299,6 +302,9 @@ impl<'module_environment> FuncEnvironment<'module_environment> { stack_limit_at_function_entry: None, @@ -158,7 +204,7 @@ index 5bb16980..8f549ff5 100644 stack_switching_handler_list_buffer: None, stack_switching_values_buffer: None, -@@ -3296,6 +3302,7 @@ impl FuncEnvironment<'_> { +@@ -3444,6 +3450,7 @@ impl FuncEnvironment<'_> { sig_ref: ir::SigRef, call_args: &[ir::Value], ) -> WasmResult<()> { @@ -166,15 +212,15 @@ index 5bb16980..8f549ff5 100644 Call::new_tail(builder, self, srcloc).direct_call(callee_index, sig_ref, call_args)?; Ok(()) } -@@ -3311,6 +3318,7 @@ impl FuncEnvironment<'_> { +@@ -3458,6 +3465,7 @@ impl FuncEnvironment<'_> { callee: ir::Value, call_args: &[ir::Value], ) -> WasmResult<()> { + self.before_return(builder); Call::new_tail(builder, self, srcloc).indirect_call( - features, table_index, -@@ -3330,6 +3338,7 @@ impl FuncEnvironment<'_> { + ty_index, +@@ -3476,6 +3484,7 @@ impl FuncEnvironment<'_> { callee: ir::Value, call_args: &[ir::Value], ) -> WasmResult<()> { @@ -182,9 +228,9 @@ index 5bb16980..8f549ff5 100644 Call::new_tail(builder, self, srcloc).call_ref(sig_ref, callee, call_args)?; Ok(()) } -@@ -3837,6 +3846,32 @@ impl FuncEnvironment<'_> { - self.conditionally_trap(builder, overflow, ir::TrapCode::STACK_OVERFLOW); - } +@@ -5135,6 +5144,26 @@ impl FuncEnvironment<'_> { + + self.update_state_slot_vmctx(builder); + if let Some(gv) = self.call_stack_depth_reverse { + let limit_addr = builder.ins().global_value(self.pointer_type(), gv); @@ -196,8 +242,7 @@ index 5bb16980..8f549ff5 100644 + } + + if let Some(gv) = self.value_stack_depth_reverse { -+ if let Some(delta) = builder.value_stack_size_inst { -+ let delta_val = builder.func.dfg.first_result(delta); ++ if let Some(delta_val) = builder.value_stack_size { + let limit_addr = builder.ins().global_value(self.pointer_type(), gv); + let old_val = builder.ins().load(ir::types::I32, ir::MemFlags::trusted(), limit_addr, 0); + let (new_val, overflowed) = builder.ins().usub_overflow(old_val, delta_val); @@ -206,16 +251,11 @@ index 5bb16980..8f549ff5 100644 + } + } + -+ // If the `vm_store_context` variable will get used then we initialize -+ // it here. -+ if true || self.tunables.consume_fuel || self.tunables.epoch_interruption { -+ self.get_vmstore_context_ptr(builder); -+ } + // Additionally we initialize `fuel_var` if it will get used. if self.tunables.consume_fuel { self.fuel_function_entry(builder); -@@ -3882,6 +3917,44 @@ impl FuncEnvironment<'_> { +@@ -5177,6 +5206,43 @@ impl FuncEnvironment<'_> { self.isa.triple().architecture == target_lexicon::Architecture::X86_64 } @@ -247,8 +287,7 @@ index 5bb16980..8f549ff5 100644 + } + + if let Some(gv) = self.value_stack_depth_reverse { -+ if let Some(delta) = builder.value_stack_size_inst { -+ let delta_val = builder.func.dfg.first_result(delta); ++ if let Some(delta_val) = builder.value_stack_size { + let limit_addr = builder.ins().global_value(self.pointer_type(), gv); + let old_val = builder.ins().load(ir::types::I32, ir::MemFlags::trusted(), limit_addr, 0); + let (new_val, _) = builder.ins().uadd_overflow(old_val, delta_val); @@ -260,40 +299,32 @@ index 5bb16980..8f549ff5 100644 pub fn translate_cont_bind( &mut self, builder: &mut FunctionBuilder<'_>, -@@ -4001,6 +4074,7 @@ impl FuncEnvironment<'_> { +@@ -5334,6 +5400,7 @@ impl FuncEnvironment<'_> { } pub fn handle_before_return(&mut self, retvals: &[ir::Value], builder: &mut FunctionBuilder) { + self.before_return(builder); - #[cfg(feature = "wmemcheck")] if self.compiler.wmemcheck { let func_name = self.current_func_name(builder); + if func_name == Some("malloc") { diff --git a/crates/cranelift/src/lib.rs b/crates/cranelift/src/lib.rs -index 1d1ac61c..4db70f6a 100644 +index 50c0b26..1511a65 100644 --- a/crates/cranelift/src/lib.rs +++ b/crates/cranelift/src/lib.rs -@@ -72,6 +72,8 @@ pub const TRAP_CONTINUATION_ALREADY_CONSUMED: TrapCode = - TrapCode::unwrap_user(Trap::ContinuationAlreadyConsumed as u8 + TRAP_OFFSET); - pub const TRAP_CAST_FAILURE: TrapCode = +@@ -77,6 +77,8 @@ pub const TRAP_CAST_FAILURE: TrapCode = TrapCode::unwrap_user(Trap::CastFailure as u8 + TRAP_OFFSET); + pub const TRAP_UNCAUGHT_EXCEPTION: TrapCode = + TrapCode::unwrap_user(Trap::UncaughtException as u8 + TRAP_OFFSET); +pub const TRAP_DETERMINISTIC_MODE: TrapCode = + TrapCode::unwrap_user(Trap::DeterministicMode as u8 + TRAP_OFFSET); /// Creates a new cranelift `Signature` with no wasm params/results for the /// given calling convention. diff --git a/crates/cranelift/src/translate/code_translator.rs b/crates/cranelift/src/translate/code_translator.rs -index b7565bd2..9dde783c 100644 +index 7de3ab3..5c33b47 100644 --- a/crates/cranelift/src/translate/code_translator.rs +++ b/crates/cranelift/src/translate/code_translator.rs -@@ -264,6 +264,7 @@ pub fn translate_operator( - .stacks - .stack - .extend_from_slice(builder.block_params(loop_body)); -+ environ.stacks.recalc_stack(); - - builder.switch_to_block(loop_body); - environ.translate_loop_header(builder)?; -@@ -1016,120 +1017,145 @@ pub fn translate_operator( +@@ -1071,120 +1071,145 @@ pub fn translate_operator( environ.stacks.push1(builder.ins().ireduce(I32, val)); } Operator::F32Sqrt | Operator::F64Sqrt => { @@ -439,7 +470,7 @@ index b7565bd2..9dde783c 100644 let val = environ.stacks.pop1(); environ .stacks -@@ -1227,6 +1253,7 @@ pub fn translate_operator( +@@ -1282,6 +1307,7 @@ pub fn translate_operator( environ.stacks.push1(builder.ins().rotr(arg1, arg2)); } Operator::F32Add | Operator::F64Add => { @@ -447,7 +478,7 @@ index b7565bd2..9dde783c 100644 let (arg1, arg2) = environ.stacks.pop2(); environ.stacks.push1(builder.ins().fadd(arg1, arg2)); } -@@ -1235,6 +1262,7 @@ pub fn translate_operator( +@@ -1290,6 +1316,7 @@ pub fn translate_operator( environ.stacks.push1(builder.ins().isub(arg1, arg2)); } Operator::F32Sub | Operator::F64Sub => { @@ -455,7 +486,7 @@ index b7565bd2..9dde783c 100644 let (arg1, arg2) = environ.stacks.pop2(); environ.stacks.push1(builder.ins().fsub(arg1, arg2)); } -@@ -1243,10 +1271,12 @@ pub fn translate_operator( +@@ -1298,10 +1325,12 @@ pub fn translate_operator( environ.stacks.push1(builder.ins().imul(arg1, arg2)); } Operator::F32Mul | Operator::F64Mul => { @@ -468,7 +499,7 @@ index b7565bd2..9dde783c 100644 let (arg1, arg2) = environ.stacks.pop2(); environ.stacks.push1(builder.ins().fdiv(arg1, arg2)); } -@@ -1271,14 +1301,17 @@ pub fn translate_operator( +@@ -1326,14 +1355,17 @@ pub fn translate_operator( environ.stacks.push1(result); } Operator::F32Min | Operator::F64Min => { @@ -486,7 +517,7 @@ index b7565bd2..9dde783c 100644 let (arg1, arg2) = environ.stacks.pop2(); environ.stacks.push1(builder.ins().fcopysign(arg1, arg2)); } -@@ -1711,9 +1744,13 @@ pub fn translate_operator( +@@ -1766,9 +1798,13 @@ pub fn translate_operator( environ.stacks.push1(splatted) } Operator::I32x4Splat @@ -502,7 +533,7 @@ index b7565bd2..9dde783c 100644 let splatted = builder.ins().splat(type_of(op), environ.stacks.pop1()); environ.stacks.push1(splatted) } -@@ -1794,9 +1831,15 @@ pub fn translate_operator( +@@ -1849,9 +1885,15 @@ pub fn translate_operator( // work. } Operator::I32x4ExtractLane { lane } @@ -520,7 +551,7 @@ index b7565bd2..9dde783c 100644 let vector = pop1_with_bitcast(environ, type_of(op), builder); environ .stacks -@@ -1812,9 +1855,16 @@ pub fn translate_operator( +@@ -1867,9 +1909,16 @@ pub fn translate_operator( .push1(builder.ins().insertlane(vector, reduced, *lane)) } Operator::I32x4ReplaceLane { lane } @@ -539,7 +570,7 @@ index b7565bd2..9dde783c 100644 let (vector, replacement) = environ.stacks.pop2(); let vector = optionally_bitcast_vector(vector, type_of(op), builder); environ -@@ -2022,30 +2072,37 @@ pub fn translate_operator( +@@ -2077,30 +2126,37 @@ pub fn translate_operator( translate_vector_fcmp(FloatCC::GreaterThanOrEqual, type_of(op), builder, environ) } Operator::F32x4Add | Operator::F64x2Add => { @@ -577,7 +608,7 @@ index b7565bd2..9dde783c 100644 // Note the careful ordering here with respect to `fcmp` and // `bitselect`. This matches the spec definition of: // -@@ -2059,6 +2116,7 @@ pub fn translate_operator( +@@ -2114,6 +2170,7 @@ pub fn translate_operator( environ.stacks.push1(builder.ins().bitselect(cmp, b, a)) } Operator::F32x4PMin | Operator::F64x2PMin => { @@ -585,7 +616,7 @@ index b7565bd2..9dde783c 100644 // Note the careful ordering here which is similar to `pmax` above: // // fpmin(z1, z2) = -@@ -2071,26 +2129,32 @@ pub fn translate_operator( +@@ -2126,26 +2183,32 @@ pub fn translate_operator( environ.stacks.push1(builder.ins().bitselect(cmp, b, a)) } Operator::F32x4Sqrt | Operator::F64x2Sqrt => { @@ -618,7 +649,7 @@ index b7565bd2..9dde783c 100644 let a = pop1_with_bitcast(environ, I32X4, builder); let widened_a = builder.ins().swiden_low(a); environ -@@ -2098,6 +2162,7 @@ pub fn translate_operator( +@@ -2153,6 +2216,7 @@ pub fn translate_operator( .push1(builder.ins().fcvt_from_sint(F64X2, widened_a)); } Operator::F64x2ConvertLowI32x4U => { @@ -626,7 +657,7 @@ index b7565bd2..9dde783c 100644 let a = pop1_with_bitcast(environ, I32X4, builder); let widened_a = builder.ins().uwiden_low(a); environ -@@ -2105,20 +2170,24 @@ pub fn translate_operator( +@@ -2160,20 +2224,24 @@ pub fn translate_operator( .push1(builder.ins().fcvt_from_uint(F64X2, widened_a)); } Operator::F64x2PromoteLowF32x4 => { @@ -651,7 +682,7 @@ index b7565bd2..9dde783c 100644 let a = pop1_with_bitcast(environ, F64X2, builder); let converted_a = builder.ins().fcvt_to_sint_sat(I64X2, a); let handle = builder.func.dfg.constants.insert(vec![0u8; 16].into()); -@@ -2141,12 +2210,14 @@ pub fn translate_operator( +@@ -2196,12 +2264,14 @@ pub fn translate_operator( // perhaps for other backends too) should be added and the codegen for // the relaxed instruction should conditionally be different. Operator::I32x4RelaxedTruncF32x4U | Operator::I32x4TruncSatF32x4U => { @@ -666,7 +697,7 @@ index b7565bd2..9dde783c 100644 let a = pop1_with_bitcast(environ, F64X2, builder); let zero_constant = builder.func.dfg.constants.insert(vec![0u8; 16].into()); let result = if environ.is_x86() && !environ.isa().has_round() { -@@ -2267,41 +2338,49 @@ pub fn translate_operator( +@@ -2322,41 +2392,49 @@ pub fn translate_operator( .push1(builder.ins().iadd_pairwise(widen_low, widen_high)); } Operator::F32x4Ceil => { @@ -716,7 +747,7 @@ index b7565bd2..9dde783c 100644 let arg = pop1_with_bitcast(environ, F64X2, builder); let result = environ.nearest_f64x2(builder, arg); environ.stacks.push1(result); -@@ -2404,6 +2483,7 @@ pub fn translate_operator( +@@ -2459,6 +2537,7 @@ pub fn translate_operator( } Operator::F32x4RelaxedMax | Operator::F64x2RelaxedMax => { @@ -724,7 +755,7 @@ index b7565bd2..9dde783c 100644 let ty = type_of(op); let (a, b) = pop2_with_bitcast(environ, ty, builder); environ.stacks.push1( -@@ -2423,6 +2503,7 @@ pub fn translate_operator( +@@ -2478,6 +2557,7 @@ pub fn translate_operator( } Operator::F32x4RelaxedMin | Operator::F64x2RelaxedMin => { @@ -732,7 +763,7 @@ index b7565bd2..9dde783c 100644 let ty = type_of(op); let (a, b) = pop2_with_bitcast(environ, ty, builder); environ.stacks.push1( -@@ -2448,22 +2529,26 @@ pub fn translate_operator( +@@ -2503,22 +2583,26 @@ pub fn translate_operator( } Operator::F32x4RelaxedMadd => { @@ -759,7 +790,7 @@ index b7565bd2..9dde783c 100644 let (a, b, c) = pop3_with_bitcast(environ, type_of(op), builder); let a = builder.ins().fneg(a); let result = environ.fma_f64x2(builder, a, b, c); -@@ -2493,6 +2578,7 @@ pub fn translate_operator( +@@ -2548,6 +2632,7 @@ pub fn translate_operator( } Operator::I32x4RelaxedTruncF32x4S => { @@ -767,7 +798,7 @@ index b7565bd2..9dde783c 100644 let a = pop1_with_bitcast(environ, F32X4, builder); environ.stacks.push1( if environ.relaxed_simd_deterministic() || !environ.is_x86() { -@@ -2505,6 +2591,7 @@ pub fn translate_operator( +@@ -2560,6 +2645,7 @@ pub fn translate_operator( ) } Operator::I32x4RelaxedTruncF64x2SZero => { @@ -775,7 +806,7 @@ index b7565bd2..9dde783c 100644 let a = pop1_with_bitcast(environ, F64X2, builder); let converted_a = if environ.relaxed_simd_deterministic() || !environ.is_x86() { // Deterministic semantics are to match the -@@ -3942,6 +4029,7 @@ fn translate_vector_icmp( +@@ -4081,6 +4167,7 @@ fn translate_vector_icmp( } fn translate_fcmp(cc: FloatCC, builder: &mut FunctionBuilder, env: &mut FuncEnvironment<'_>) { @@ -783,7 +814,7 @@ index b7565bd2..9dde783c 100644 let (arg0, arg1) = env.stacks.pop2(); let val = builder.ins().fcmp(cc, arg0, arg1); env.stacks.push1(builder.ins().uextend(I32, val)); -@@ -3953,6 +4041,7 @@ fn translate_vector_fcmp( +@@ -4092,6 +4179,7 @@ fn translate_vector_fcmp( builder: &mut FunctionBuilder, env: &mut FuncEnvironment<'_>, ) { @@ -791,7 +822,15 @@ index b7565bd2..9dde783c 100644 let (a, b) = env.stacks.pop2(); let bitcast_a = optionally_bitcast_vector(a, needed_type, builder); let bitcast_b = optionally_bitcast_vector(b, needed_type, builder); -@@ -4479,3 +4568,11 @@ fn create_catch_block( +@@ -4444,6 +4532,7 @@ fn push_block_params( + let val = builder.use_var(*var); + environ.stacks.stack.push(val); + } ++ environ.stacks.recalc_stack(); + } + + /// Generate a `jump` instruction, but first cast all 128-bit vector values to I8X16 if they +@@ -4669,3 +4758,11 @@ fn create_catch_block( Ok(block) } @@ -804,38 +843,50 @@ index b7565bd2..9dde783c 100644 + return true; +} diff --git a/crates/cranelift/src/translate/func_translator.rs b/crates/cranelift/src/translate/func_translator.rs -index bda7dd4d..08478285 100644 +index f26bb70..3177a6b 100644 --- a/crates/cranelift/src/translate/func_translator.rs +++ b/crates/cranelift/src/translate/func_translator.rs -@@ -73,6 +73,9 @@ impl FuncTranslator { +@@ -76,6 +76,9 @@ impl FuncTranslator { builder.switch_to_block(entry_block); builder.seal_block(entry_block); // Declare all predecessors known. -+ let (placeholder, _) = builder.ins().UnaryImm(cranelift_codegen::ir::Opcode::Iconst, cranelift_codegen::ir::types::I32, 0.into()); -+ builder.value_stack_size_inst = Some(placeholder); ++ let value_stack_size = builder.ins().iconst(ir::types::I32, 0); ++ builder.value_stack_size = Some(value_stack_size); + environ.create_state_slot(&mut builder); // Make sure the entry block is inserted in the layout before we make any callbacks to -@@ -89,9 +92,16 @@ impl FuncTranslator { +@@ -91,7 +94,8 @@ impl FuncTranslator { .stacks .initialize(&builder.func.signature, exit_block); - parse_local_decls(&mut reader, &mut builder, num_params, environ, validator)?; -+ let total_locals = parse_local_decls(&mut reader, &mut builder, num_params, environ, validator)?; ++ let total_locals = ++ parse_local_decls(&mut reader, &mut builder, num_params, environ, validator)?; + + // Represent the function's return values as `Variable`s, exactly like + // Wasm block parameters, rather than as real CLIF block parameters. +@@ -117,6 +121,19 @@ impl FuncTranslator { + parse_function_body(validator, reader, &mut builder, environ)?; -+ let max_stack = environ.stacks.max_stack; -+ let total_subtract = total_locals as u64 + max_stack as u64; -+ if total_subtract > 65535 { -+ return Err(wasmtime_environ::WasmError::InvalidWebAssembly { message: "too many locals".to_owned(), offset: 0 }); ++ let total_slots = u64::from(total_locals) + environ.stacks.max_stack as u64; ++ if total_slots > u64::from(u16::MAX) { ++ return Err(wasmtime_environ::WasmError::InvalidWebAssembly { ++ message: "too many locals and operand stack values".to_owned(), ++ offset: 0, ++ }); + } -+ builder.func.dfg.replace(placeholder).iconst(cranelift_codegen::ir::types::I32, total_subtract as i64); ++ let placeholder = builder.func.dfg.value_def(value_stack_size).unwrap_inst(); ++ builder.func.dfg.replace(placeholder).iconst( ++ cranelift_codegen::ir::types::I32, ++ total_slots as i64, ++ ); + - builder.finalize(); + builder.finalize(environ.target_config()); + crate::alias_region::debug_assert_all_mem_insts_have_alias_regions(func); log::trace!("translated Wasm to CLIF:\n{}", func.display()); - Ok(()) -@@ -145,10 +155,12 @@ fn parse_local_decls( +@@ -193,10 +210,12 @@ fn parse_local_decls( num_params: usize, environ: &mut FuncEnvironment<'_>, validator: &mut FuncValidator, @@ -849,7 +900,7 @@ index bda7dd4d..08478285 100644 for _ in 0..local_count { builder.set_srcloc(cur_srcloc(reader)); let pos = reader.original_position(); -@@ -156,9 +168,11 @@ fn parse_local_decls( +@@ -204,9 +223,11 @@ fn parse_local_decls( let ty = reader.read()?; validator.define_locals(pos, count, ty)?; declare_locals(builder, count, ty, &mut next_local, environ)?; @@ -863,10 +914,10 @@ index bda7dd4d..08478285 100644 /// Declare `count` local variables of the same type, starting from `next_local`. diff --git a/crates/cranelift/src/translate/stack.rs b/crates/cranelift/src/translate/stack.rs -index f338fe3f..8b4716a9 100644 +index 8fb6a67..8772f54 100644 --- a/crates/cranelift/src/translate/stack.rs +++ b/crates/cranelift/src/translate/stack.rs -@@ -255,6 +255,7 @@ pub struct FuncTranslationStacks { +@@ -260,6 +260,7 @@ pub struct FuncTranslationStacks { /// A stack of values corresponding to the active values in the input wasm function at this /// point. pub(crate) stack: Vec, @@ -874,15 +925,15 @@ index f338fe3f..8b4716a9 100644 /// "Shape" of stack at each index, if emitting debug instrumentation. /// /// When we pop `stack`, we automatically pop `stack_shape` as -@@ -286,6 +287,7 @@ impl FuncTranslationStacks { +@@ -309,6 +310,7 @@ impl FuncTranslationStacks { pub(crate) fn new() -> Self { Self { stack: Vec::new(), + max_stack: 0, stack_shape: Vec::new(), control_stack: Vec::new(), - handlers: HandlerState::default(), -@@ -293,6 +295,11 @@ impl FuncTranslationStacks { + block_param_vars: SecondaryMap::new(), +@@ -317,12 +319,18 @@ impl FuncTranslationStacks { } } @@ -894,7 +945,14 @@ index f338fe3f..8b4716a9 100644 fn clear(&mut self) { debug_assert!(self.stack.is_empty()); debug_assert!(self.stack_shape.is_empty()); -@@ -320,17 +327,20 @@ impl FuncTranslationStacks { + debug_assert!(self.control_stack.is_empty()); + debug_assert!(self.handlers.is_empty()); + self.block_param_vars.clear(); ++ self.max_stack = 0; + self.reachable = true; + } + +@@ -345,17 +353,20 @@ impl FuncTranslationStacks { /// Push a value. pub(crate) fn push1(&mut self, val: Value) { self.stack.push(val); @@ -916,12 +974,12 @@ index f338fe3f..8b4716a9 100644 /// Pop one value. diff --git a/crates/environ/Cargo.toml b/crates/environ/Cargo.toml -index 07d8ef57..83e95f6d 100644 +index aecdb45..b25c64b 100644 --- a/crates/environ/Cargo.toml +++ b/crates/environ/Cargo.toml -@@ -24,7 +24,7 @@ cpp_demangle = { version = "0.4.3", optional = true } - cranelift-entity = { workspace = true, features = ['enable-serde'] } +@@ -25,7 +25,7 @@ cranelift-entity = { workspace = true, features = ['enable-serde'] } cranelift-bitset = { workspace = true, features = ['enable-serde'] } + cranelift-bforest = { workspace = true } hashbrown = { workspace = true, features = ["default-hasher"] } -wasmparser = { workspace = true, features = ['validate', 'serde', 'features'] } +wasmparser = { workspace = true, features = ['validate', 'serde', 'features', "simd"] } @@ -929,80 +987,60 @@ index 07d8ef57..83e95f6d 100644 serde = { workspace = true } serde_derive = { workspace = true } diff --git a/crates/environ/src/trap_encoding.rs b/crates/environ/src/trap_encoding.rs -index f9d22368..2d49707b 100644 +index 692238a..68ed1e4 100644 --- a/crates/environ/src/trap_encoding.rs +++ b/crates/environ/src/trap_encoding.rs -@@ -141,6 +141,9 @@ pub enum Trap { - /// A component passed an unaligned pointer when lifting or lowering a - /// value. - UnalignedPointer, -+ -+ /// Deterministic mode violation -+ DeterministicMode, - // if adding a variant here be sure to update the `check!` macro below, and - // remember to update `trap.rs` and `trap.h` as mentioned above - } -@@ -193,6 +196,7 @@ impl Trap { - ListOutOfBounds - InvalidDiscriminant - UnalignedPointer -+ DeterministicMode - } +@@ -279,6 +279,9 @@ generate_trap_type! { + /// An exception propagated out of a component without being caught. + UncaughtException = "uncaught exception propagated out of component", - None -@@ -238,6 +242,7 @@ impl fmt::Display for Trap { - ListOutOfBounds => "list content out-of-bounds", - InvalidDiscriminant => "invalid variant discriminant", - UnalignedPointer => "unaligned pointer", -+ DeterministicMode => "deterministic mode violation (cpu)", - }; - write!(f, "wasm trap: {desc}") ++ /// A floating-point instruction was reached while floats were disabled. ++ DeterministicMode = "deterministic mode violation (CPU)", ++ + // if adding a variant here be sure to update `trap.rs` and `trap.h` as + // mentioned above } diff --git a/crates/environ/src/tunables.rs b/crates/environ/src/tunables.rs -index fc9b4c3c..7f0ebd5b 100644 +index 70ea869..5f9771b 100644 --- a/crates/environ/src/tunables.rs +++ b/crates/environ/src/tunables.rs -@@ -144,6 +144,9 @@ define_tunables! { - /// Whether any component model feature related to concurrency is - /// enabled. - pub concurrency_support: bool, +@@ -199,6 +199,9 @@ define_tunables! { + /// Whether `metadata.code.branch_hint` sections are parsed and used to + /// mark cold blocks during compilation. + pub branch_hinting: bool, + -+ /// Whether floats enabled ++ /// Whether floating-point instructions are enabled. + pub floats_enabled: bool, } pub struct ConfigTunables { -@@ -220,6 +223,7 @@ impl Tunables { - inlining_sum_size_threshold: 2000, - debug_guest: false, - concurrency_support: true, +@@ -287,6 +290,7 @@ impl Tunables { + metadata_for_gc_heap_corruption: true, + branch_hinting: false, + debug_symbols: true, + floats_enabled: true, } } -diff --git a/crates/environ/src/vmoffsets.rs b/crates/environ/src/vmoffsets.rs -index 60c88a2c..25ae8261 100644 ---- a/crates/environ/src/vmoffsets.rs -+++ b/crates/environ/src/vmoffsets.rs -@@ -243,6 +243,16 @@ pub trait PtrSize { - self.vmstore_context_stack_chain() + self.size_of_vmstack_chain() - } +diff --git a/crates/environ/src/vmtypes.rs b/crates/environ/src/vmtypes.rs +index 867c1b8..7830fa9 100644 +--- a/crates/environ/src/vmtypes.rs ++++ b/crates/environ/src/vmtypes.rs +@@ -383,6 +383,12 @@ macro_rules! for_each_vm_type { + /// `store-data-address` unsafe intrinsic. + pub store_data: VmPtr<()>, -+ /// -+ fn vmstore_context_call_stack_left(&self) -> u8 { -+ self.vmstore_context_store_data() + self.size() -+ } ++ /// Remaining nested Wasm calls before the semantic stack limit traps. ++ pub call_stack_limit_reverse: UnsafeCell, + -+ /// -+ fn vmstore_context_value_stack_left(&self) -> u8 { -+ self.vmstore_context_call_stack_left() + 4 -+ } ++ /// Remaining Wasm value slots before the semantic stack limit traps. ++ pub value_stack_limit_reverse: UnsafeCell, + - // Offsets within `VMMemoryDefinition` - - /// The offset of the `base` field. + /// The range, in addresses, of the guard page that is currently in use. + /// + /// This field is used when signal handlers are run to determine whether a diff --git a/crates/wasmtime/Cargo.toml b/crates/wasmtime/Cargo.toml -index 7ff85259..71e2e6ee 100644 +index 2ee8eb4..6969644 100644 --- a/crates/wasmtime/Cargo.toml +++ b/crates/wasmtime/Cargo.toml @@ -17,6 +17,8 @@ workspace = true @@ -1015,10 +1053,10 @@ index 7ff85259..71e2e6ee 100644 wasmtime-jit-debug = { workspace = true, optional = true } wasmtime-jit-icache-coherence = { workspace = true, optional = true } diff --git a/crates/wasmtime/src/config.rs b/crates/wasmtime/src/config.rs -index 6c611d54..1cbbd4b2 100644 +index c833bc1..cc5640b 100644 --- a/crates/wasmtime/src/config.rs +++ b/crates/wasmtime/src/config.rs -@@ -1037,6 +1037,17 @@ impl Config { +@@ -1159,6 +1159,17 @@ impl Config { self } @@ -1036,7 +1074,7 @@ index 6c611d54..1cbbd4b2 100644 /// Configures whether the [WebAssembly bulk memory operations /// proposal][proposal] will be enabled for compilation. /// -@@ -1521,6 +1532,15 @@ impl Config { +@@ -1689,6 +1700,15 @@ impl Config { self } @@ -1052,28 +1090,19 @@ index 6c611d54..1cbbd4b2 100644 /// Sets a custom memory creator. /// /// Custom memory creators are used when creating host `Memory` objects or when -@@ -2210,7 +2230,7 @@ impl Config { - | WasmFeatures::CM_THREADING - | WasmFeatures::CM_ERROR_CONTEXT - | WasmFeatures::CM_GC -- | WasmFeatures::CM_FIXED_SIZE_LIST; -+ | WasmFeatures::CM_FIXED_LENGTH_LISTS; - - #[allow(unused_mut, reason = "easier to avoid #[cfg]")] - let mut unsupported = !features_known_to_wasmtime; diff --git a/crates/wasmtime/src/engine/serialization.rs b/crates/wasmtime/src/engine/serialization.rs -index 9b17cbb8..a01c1e66 100644 +index cc91db3..bd8f42f 100644 --- a/crates/wasmtime/src/engine/serialization.rs +++ b/crates/wasmtime/src/engine/serialization.rs -@@ -270,6 +270,7 @@ impl Metadata<'_> { +@@ -309,6 +309,7 @@ impl Metadata<'_> { relaxed_simd_deterministic, winch_callable, signals_based_traps, + floats_enabled, memory_init_cow, inlining, - inlining_intra_module, -@@ -340,6 +341,11 @@ impl Metadata<'_> { + inlining_small_callee_size, +@@ -402,6 +403,11 @@ impl Metadata<'_> { other.signals_based_traps, "Signals-based traps", )?; @@ -1086,10 +1115,10 @@ index 9b17cbb8..a01c1e66 100644 memory_init_cow, other.memory_init_cow, diff --git a/crates/wasmtime/src/lib.rs b/crates/wasmtime/src/lib.rs -index 4915240b..e509feba 100644 +index f3f0a3f..698ffc6 100644 --- a/crates/wasmtime/src/lib.rs +++ b/crates/wasmtime/src/lib.rs -@@ -544,6 +544,9 @@ pub use self::error::{Error, Result, bail, ensure, format_err}; +@@ -540,6 +540,9 @@ pub use self::error::{Error, OutOfMemory, Result, bail, ensure, format_err}; #[cfg(feature = "reexport-wasmparser")] pub use wasmparser; @@ -1100,10 +1129,10 @@ index 4915240b..e509feba 100644 fn _assertions_lib() { diff --git a/crates/wasmtime/src/runtime/func.rs b/crates/wasmtime/src/runtime/func.rs -index d8ce5016..c19cf62f 100644 +index d847800..b0a53c5 100644 --- a/crates/wasmtime/src/runtime/func.rs +++ b/crates/wasmtime/src/runtime/func.rs -@@ -1392,6 +1392,32 @@ impl Func { +@@ -1446,6 +1446,32 @@ impl Func { } } @@ -1136,7 +1165,7 @@ index d8ce5016..c19cf62f 100644 /// Prepares for entrance into WebAssembly. /// /// This function will set up context such that `closure` is allowed to call a -@@ -1426,6 +1452,51 @@ pub(crate) fn invoke_wasm_and_catch_traps( +@@ -1480,6 +1506,51 @@ pub(crate) fn invoke_wasm_and_catch_traps( core::mem::drop(previous_runtime_state); store.0.call_hook(CallHook::ReturningFromWasm)?; result @@ -1189,7 +1218,7 @@ index d8ce5016..c19cf62f 100644 /// This type helps managing the state of the runtime when entering and exiting diff --git a/crates/wasmtime/src/runtime/instance.rs b/crates/wasmtime/src/runtime/instance.rs -index 2a55d962..0c882e74 100644 +index 53fd54f..c158007 100644 --- a/crates/wasmtime/src/runtime/instance.rs +++ b/crates/wasmtime/src/runtime/instance.rs @@ -630,7 +630,6 @@ impl Instance { @@ -1201,28 +1230,28 @@ index 2a55d962..0c882e74 100644 &'a self, store: &'a StoreOpaque, diff --git a/crates/wasmtime/src/runtime/store.rs b/crates/wasmtime/src/runtime/store.rs -index f214fff5..16e617d2 100644 +index a081654..9911f9d 100644 --- a/crates/wasmtime/src/runtime/store.rs +++ b/crates/wasmtime/src/runtime/store.rs -@@ -108,6 +108,7 @@ use crate::{Engine, Module, Val, ValRaw, module::ModuleRegistry}; - #[cfg(feature = "gc")] - use crate::{ExnRef, Rooted}; +@@ -95,6 +95,7 @@ use crate::trampoline::VMHostGlobalContext; + use crate::{BreakpointState, DebugHandler, FrameDataCache}; + use crate::{Engine, Module, Val, ValRaw, module::ModuleRegistry}; use crate::{Global, Instance, Table}; +use alloc::sync::Arc; use core::convert::Infallible; use core::fmt; - use core::marker; -@@ -571,6 +572,9 @@ pub struct StoreOpaque { - /// logic before returning to allow execution to resume. + #[cfg(any(feature = "async", feature = "gc"))] +@@ -549,6 +550,9 @@ pub struct StoreOpaque { + /// enabled, so the key-space is unique for each store.) #[cfg(feature = "debug")] - breakpoints: BreakpointState, + frame_data_cache: FrameDataCache, + + /// Context for the GenVM. + pub genvm_ctx: GenVMCtx, } /// Self-pointer to `StoreInner` from within a `StoreOpaque` which is chiefly -@@ -717,6 +721,14 @@ enum StoreInstanceKind { +@@ -695,6 +699,14 @@ enum StoreInstanceKind { Dummy, } @@ -1237,7 +1266,7 @@ index f214fff5..16e617d2 100644 impl Store { /// Creates a new [`Store`] to be associated with the given [`Engine`] and /// `data` provided. -@@ -727,14 +739,14 @@ impl Store { +@@ -705,8 +717,8 @@ impl Store { /// The store will limit the number of instances, linear memories, and /// tables created to 10,000. This can be overridden with the /// [`Store::limiter`] configuration method. @@ -1248,22 +1277,24 @@ index f214fff5..16e617d2 100644 "allocation failure during `Store::new` (use `Store::try_new` to handle such errors)", ) } - - /// Like `Store::new` but returns an error on allocation failure. +@@ -718,7 +730,7 @@ impl Store { + /// This function will return an [`OutOfMemory`][crate::OutOfMemory] error when + /// memory allocation fails. See the `OutOfMemory` type's documentation for + /// details on Wasmtime's out-of-memory handling. - pub fn try_new(engine: &Engine, data: T) -> Result { + pub fn try_new(engine: &Engine, data: T, genvm_ctx: GenVMCtx) -> Result { - let store_data = StoreData::new(); + let store_data = StoreData::new(engine); log::trace!("creating new store {:?}", store_data.id()); -@@ -799,6 +811,7 @@ impl Store { - }, - #[cfg(feature = "debug")] +@@ -759,6 +771,7 @@ impl Store { breakpoints: Default::default(), + #[cfg(feature = "debug")] + frame_data_cache: FrameDataCache::new(), + genvm_ctx, }; let mut inner = try_new::>(StoreInner { inner, -@@ -2948,11 +2961,11 @@ impl StoreInner { +@@ -2394,11 +2407,11 @@ impl StoreInner { } } @@ -1281,20 +1312,10 @@ index f214fff5..16e617d2 100644 impl fmt::Debug for Store { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/crates/wasmtime/src/runtime/vm/vmcontext.rs b/crates/wasmtime/src/runtime/vm/vmcontext.rs -index c3287979..01e3373a 100644 +index 9324674..4509bc4 100644 --- a/crates/wasmtime/src/runtime/vm/vmcontext.rs +++ b/crates/wasmtime/src/runtime/vm/vmcontext.rs -@@ -1179,6 +1179,9 @@ pub struct VMStoreContext { - /// `store-data-address` unsafe intrinsic. - pub store_data: VmPtr<()>, - -+ pub call_stack_limit_reverse: UnsafeCell, -+ pub value_stack_limit_reverse: UnsafeCell, -+ - /// The range, in addresses, of the guard page that is currently in use. - /// - /// This field is used when signal handlers are run to determine whether a -@@ -1271,8 +1274,10 @@ impl Default for VMStoreContext { +@@ -810,8 +810,10 @@ impl Default for VMStoreContext { last_wasm_entry_sp: UnsafeCell::new(0), last_wasm_entry_trap_handler: UnsafeCell::new(0), stack_chain: UnsafeCell::new(VMStackChain::Absent), @@ -1303,11 +1324,11 @@ index c3287979..01e3373a 100644 + call_stack_limit_reverse: UnsafeCell::new(1024), + value_stack_limit_reverse: UnsafeCell::new(65535), + async_guard_range: ptr::null_mut()..ptr::null_mut(), + component_context: UnsafeCell::new([0; NUM_COMPONENT_CONTEXT_SLOTS]), + current_thread: UnsafeCell::new(VMLazyThread::none()), } - } - } diff --git a/crates/wiggle/generate/src/config.rs b/crates/wiggle/generate/src/config.rs -index 43dd2bff..77a0528a 100644 +index 43dd2bf..77a0528 100644 --- a/crates/wiggle/generate/src/config.rs +++ b/crates/wiggle/generate/src/config.rs @@ -251,7 +251,12 @@ impl Parse for Paths { @@ -1325,7 +1346,7 @@ index 43dd2bff..77a0528a 100644 .collect::>(); diff --git a/crates/wiggle/generate/src/module_trait.rs b/crates/wiggle/generate/src/module_trait.rs -index 598e3ff4..73b18731 100644 +index 598e3ff..73b1873 100644 --- a/crates/wiggle/generate/src/module_trait.rs +++ b/crates/wiggle/generate/src/module_trait.rs @@ -81,13 +81,6 @@ pub fn define_module_trait(m: &Module, settings: &CodegenSettings) -> TokenStrea @@ -1343,7 +1364,7 @@ index 598e3ff4..73b18731 100644 } } diff --git a/crates/wiggle/generate/src/wasmtime.rs b/crates/wiggle/generate/src/wasmtime.rs -index bea34fb3..ad861408 100644 +index bea34fb..ad86140 100644 --- a/crates/wiggle/generate/src/wasmtime.rs +++ b/crates/wiggle/generate/src/wasmtime.rs @@ -2,6 +2,7 @@ use crate::CodegenSettings; @@ -1458,7 +1479,7 @@ index bea34fb3..ad861408 100644 #field_str, move |mut caller: wiggle::wasmtime_crate::Caller<'_, T> #(, #arg_decls)*| -> wiggle::error::Result<#ret_ty> { diff --git a/crates/wiggle/src/guest_error.rs b/crates/wiggle/src/guest_error.rs -index 590ee16e..03b79823 100644 +index 590ee16..03b7982 100644 --- a/crates/wiggle/src/guest_error.rs +++ b/crates/wiggle/src/guest_error.rs @@ -27,4 +27,6 @@ pub enum GuestError { @@ -1469,7 +1490,7 @@ index 590ee16e..03b79823 100644 + MemoryNotExported, } diff --git a/crates/wiggle/src/lib.rs b/crates/wiggle/src/lib.rs -index 1888a1ff..c8953ab9 100644 +index 1888a1f..c8953ab 100644 --- a/crates/wiggle/src/lib.rs +++ b/crates/wiggle/src/lib.rs @@ -271,6 +271,11 @@ impl<'a> GuestMemory<'a> { diff --git a/.git-third-party/patches/executor/third-party/wasmtime/r6518c8dxghpkhsj b/.git-third-party/patches/executor/third-party/wasmtime/r6518c8dxghpkhsj new file mode 100644 index 00000000..9de42312 --- /dev/null +++ b/.git-third-party/patches/executor/third-party/wasmtime/r6518c8dxghpkhsj @@ -0,0 +1,104 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: kp2pml30 +Date: Thu, 2 Jul 2026 22:33:10 +0900 +Subject: [PATCH] =?UTF-8?q?chore(wasm):=20rename=20DeterministicMode=20tra?= + =?UTF-8?q?p=20to=20NondetInstruction=20=E2=99=BB=EF=B8=8F?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--- + crates/c-api/include/wasmtime/trap.h | 4 ++-- + crates/c-api/src/trap.rs | 2 +- + crates/cranelift/src/func_environ.rs | 4 ++-- + crates/cranelift/src/lib.rs | 4 ++-- + crates/cranelift/src/translate/code_translator.rs | 2 +- + crates/environ/src/trap_encoding.rs | 4 ++-- + 6 files changed, 10 insertions(+), 10 deletions(-) + +diff --git a/crates/c-api/include/wasmtime/trap.h b/crates/c-api/include/wasmtime/trap.h +index f5dfe91..d58a268 100644 +--- a/crates/c-api/include/wasmtime/trap.h ++++ b/crates/c-api/include/wasmtime/trap.h +@@ -144,8 +144,8 @@ enum wasmtime_trap_code_enum { + WASMTIME_TRAP_CODE_WAITABLE_SYNC_AND_ASYNC = 48, + /// An exception propagated out of a component without being caught. + WASMTIME_TRAP_CODE_UNCAUGHT_EXCEPTION = 49, +- /// A deterministic-mode restriction was violated. +- WASMTIME_TRAP_CODE_DETERMINISTIC_MODE = 50, ++ /// A nondeterministic instruction was reached in deterministic mode. ++ WASMTIME_TRAP_CODE_NONDET_INSTRUCTION = 50, + }; + + /** +diff --git a/crates/c-api/src/trap.rs b/crates/c-api/src/trap.rs +index 80dcb86..342489f 100644 +--- a/crates/c-api/src/trap.rs ++++ b/crates/c-api/src/trap.rs +@@ -56,7 +56,7 @@ const _: () = { + assert!(Trap::StreamOpTooBig as u8 == 47); + assert!(Trap::WaitableSyncAndAsync as u8 == 48); + assert!(Trap::UncaughtException as u8 == 49); +- assert!(Trap::DeterministicMode as u8 == 50); ++ assert!(Trap::NondetInstruction as u8 == 50); + }; + + #[repr(C)] +diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs +index fe1b8d8..7dea98f 100644 +--- a/crates/cranelift/src/func_environ.rs ++++ b/crates/cranelift/src/func_environ.rs +@@ -5218,9 +5218,9 @@ impl FuncEnvironment<'_> { + self.fuel_save_from_var(builder); + } + +- pub fn trap_deterministic_mode(&mut self, builder: &mut FunctionBuilder) { ++ pub fn trap_nondet_instruction(&mut self, builder: &mut FunctionBuilder) { + self.fuel_before_unreachable(builder); +- self.trap(builder, crate::TRAP_DETERMINISTIC_MODE); ++ self.trap(builder, crate::TRAP_NONDET_INSTRUCTION); + self.stacks.reachable = false; + } + +diff --git a/crates/cranelift/src/lib.rs b/crates/cranelift/src/lib.rs +index 1511a65..5669ddb 100644 +--- a/crates/cranelift/src/lib.rs ++++ b/crates/cranelift/src/lib.rs +@@ -77,8 +77,8 @@ pub const TRAP_CAST_FAILURE: TrapCode = + TrapCode::unwrap_user(Trap::CastFailure as u8 + TRAP_OFFSET); + pub const TRAP_UNCAUGHT_EXCEPTION: TrapCode = + TrapCode::unwrap_user(Trap::UncaughtException as u8 + TRAP_OFFSET); +-pub const TRAP_DETERMINISTIC_MODE: TrapCode = +- TrapCode::unwrap_user(Trap::DeterministicMode as u8 + TRAP_OFFSET); ++pub const TRAP_NONDET_INSTRUCTION: TrapCode = ++ TrapCode::unwrap_user(Trap::NondetInstruction as u8 + TRAP_OFFSET); + + /// Creates a new cranelift `Signature` with no wasm params/results for the + /// given calling convention. +diff --git a/crates/cranelift/src/translate/code_translator.rs b/crates/cranelift/src/translate/code_translator.rs +index 0a02c4d..772f112 100644 +--- a/crates/cranelift/src/translate/code_translator.rs ++++ b/crates/cranelift/src/translate/code_translator.rs +@@ -4764,6 +4764,6 @@ fn float_op_unreachable_check(environ: &mut FuncEnvironment<'_>, builder: &mut F + if environ.are_floats_enabled() { + return false; + } +- environ.trap_deterministic_mode(builder); ++ environ.trap_nondet_instruction(builder); + return true; + } +diff --git a/crates/environ/src/trap_encoding.rs b/crates/environ/src/trap_encoding.rs +index 68ed1e4..b2fdf2c 100644 +--- a/crates/environ/src/trap_encoding.rs ++++ b/crates/environ/src/trap_encoding.rs +@@ -279,8 +279,8 @@ generate_trap_type! { + /// An exception propagated out of a component without being caught. + UncaughtException = "uncaught exception propagated out of component", + +- /// A floating-point instruction was reached while floats were disabled. +- DeterministicMode = "deterministic mode violation (CPU)", ++ /// A nondeterministic floating-point instruction was reached. ++ NondetInstruction = "nondeterministic instruction (CPU)", + + // if adding a variant here be sure to update `trap.rs` and `trap.h` as + // mentioned above diff --git a/.git-third-party/patches/executor/third-party/wasmtime/2 b/.git-third-party/patches/executor/third-party/wasmtime/zsjxmza3dms0hr10 similarity index 80% rename from .git-third-party/patches/executor/third-party/wasmtime/2 rename to .git-third-party/patches/executor/third-party/wasmtime/zsjxmza3dms0hr10 index 9f6f844c..b66b8435 100644 --- a/.git-third-party/patches/executor/third-party/wasmtime/2 +++ b/.git-third-party/patches/executor/third-party/wasmtime/zsjxmza3dms0hr10 @@ -11,18 +11,27 @@ Move memory fingerprinting off the error path: instead of hashing all linear memories on trap and attaching the result to the error, expose it as Store::fingerprint so callers take it on demand from the still-live store after execution finishes. - -Co-Authored-By: Claude Opus 4.8 (1M context) --- - crates/wasmtime/src/runtime/func.rs | 95 +++++++++++++++------------- - crates/wasmtime/src/runtime/store.rs | 2 - - 2 files changed, 50 insertions(+), 47 deletions(-) + crates/wasmtime/src/runtime/func.rs | 105 +++++++++++++++------------ + crates/wasmtime/src/runtime/store.rs | 2 - + 2 files changed, 59 insertions(+), 48 deletions(-) diff --git a/crates/wasmtime/src/runtime/func.rs b/crates/wasmtime/src/runtime/func.rs -index c19cf62f..c09f17b5 100644 +index b0a53c5..c657833 100644 --- a/crates/wasmtime/src/runtime/func.rs +++ b/crates/wasmtime/src/runtime/func.rs -@@ -1418,6 +1418,53 @@ impl std::fmt::Display for Fingerprint { +@@ -1462,7 +1462,9 @@ use std::collections::BTreeMap; + #[derive(Debug, Clone)] + /// A fingerprint of the current state of the Wasm store, except backtrace + pub struct Fingerprint { +- /// all modules by name ++ /// All module instances by unique name ++ /// ++ /// Duplicate module names are suffixed with `#2`, `#3`, and so on. + pub module_instances: BTreeMap, + } + +@@ -1472,6 +1474,59 @@ impl std::fmt::Display for Fingerprint { } } @@ -53,7 +62,13 @@ index c19cf62f..c09f17b5 100644 + memories: Vec::new(), + }; + -+ let inst_mod_name = inst.module(&mut store.0).name().unwrap_or("").to_owned(); ++ let module_name = inst.module(&mut store.0).name().unwrap_or("").to_owned(); ++ let mut inst_mod_name = module_name.clone(); ++ let mut duplicate = 2; ++ while fp.module_instances.contains_key(&inst_mod_name) { ++ inst_mod_name = format!("{module_name}#{duplicate}"); ++ duplicate += 1; ++ } + + for mem in inst.all_memories(store.0.store_opaque_mut()).collect::>() { + let data = match &mem.1 { @@ -76,7 +91,7 @@ index c19cf62f..c09f17b5 100644 /// Prepares for entrance into WebAssembly. /// /// This function will set up context such that `closure` is allowed to call a -@@ -1451,52 +1498,10 @@ pub(crate) fn invoke_wasm_and_catch_traps( +@@ -1505,52 +1560,10 @@ pub(crate) fn invoke_wasm_and_catch_traps( } core::mem::drop(previous_runtime_state); store.0.call_hook(CallHook::ReturningFromWasm)?; @@ -133,10 +148,10 @@ index c19cf62f..c09f17b5 100644 /// This type helps managing the state of the runtime when entering and exiting diff --git a/crates/wasmtime/src/runtime/store.rs b/crates/wasmtime/src/runtime/store.rs -index 16e617d2..3656a449 100644 +index 9911f9d..f7ab83b 100644 --- a/crates/wasmtime/src/runtime/store.rs +++ b/crates/wasmtime/src/runtime/store.rs -@@ -725,8 +725,6 @@ enum StoreInstanceKind { +@@ -703,8 +703,6 @@ enum StoreInstanceKind { pub struct GenVMCtx { /// non-zero if should quit pub should_quit: Arc, diff --git a/executor/Cargo.lock b/executor/Cargo.lock index 7876e27a..414f259d 100644 --- a/executor/Cargo.lock +++ b/executor/Cargo.lock @@ -125,9 +125,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.102" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] name = "arbitrary" @@ -251,9 +251,9 @@ checksum = "ece5ad97cde626d9fb807bf2dd4b4c4d13d7317a93a2ee0f8f9ef6389850a49e" [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" dependencies = [ "allocator-api2", ] @@ -438,9 +438,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpp_demangle" -version = "0.4.4" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96e58d342ad113c2b878f16d5d034c03be492ae460cdbc02b7f0f2284d310c7d" +checksum = "0667304c32ea56cb4cd6d2d7c0cfe9a2f8041229db8c033af7f8d69492429def" dependencies = [ "cfg-if", ] @@ -456,28 +456,29 @@ dependencies = [ [[package]] name = "cranelift-assembler-x64" -version = "0.129.1" +version = "0.135.1" dependencies = [ "cranelift-assembler-x64-meta", ] [[package]] name = "cranelift-assembler-x64-meta" -version = "0.129.1" +version = "0.135.1" dependencies = [ "cranelift-srcgen", ] [[package]] name = "cranelift-bforest" -version = "0.129.1" +version = "0.135.1" dependencies = [ "cranelift-entity", + "wasmtime-internal-core", ] [[package]] name = "cranelift-bitset" -version = "0.129.1" +version = "0.135.1" dependencies = [ "serde", "serde_derive", @@ -486,7 +487,7 @@ dependencies = [ [[package]] name = "cranelift-codegen" -version = "0.129.1" +version = "0.135.1" dependencies = [ "bumpalo", "cranelift-assembler-x64", @@ -498,13 +499,16 @@ dependencies = [ "cranelift-entity", "cranelift-isle", "gimli 0.33.0", - "hashbrown 0.15.2", + "hashbrown 0.17.1", "libm", "log", + "postcard", "pulley-interpreter", "regalloc2", "rustc-hash", "serde", + "serde_derive", + "sha2", "smallvec", "target-lexicon", "wasmtime-internal-core", @@ -512,7 +516,7 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.129.1" +version = "0.135.1" dependencies = [ "cranelift-assembler-x64-meta", "cranelift-codegen-shared", @@ -523,18 +527,18 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.129.1" +version = "0.135.1" [[package]] name = "cranelift-control" -version = "0.129.1" +version = "0.135.1" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.129.1" +version = "0.135.1" dependencies = [ "cranelift-bitset", "serde", @@ -544,9 +548,10 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.129.1" +version = "0.135.1" dependencies = [ "cranelift-codegen", + "hashbrown 0.17.1", "log", "smallvec", "target-lexicon", @@ -554,11 +559,11 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.129.1" +version = "0.135.1" [[package]] name = "cranelift-native" -version = "0.129.1" +version = "0.135.1" dependencies = [ "cranelift-codegen", "libc", @@ -567,7 +572,7 @@ dependencies = [ [[package]] name = "cranelift-srcgen" -version = "0.129.1" +version = "0.135.1" [[package]] name = "crc32fast" @@ -1146,7 +1151,7 @@ checksum = "0bf7f043f89559805f8c7cacc432749b2fa0d0a0a9ee46ce47164ed5ba7f126c" dependencies = [ "fnv", "hashbrown 0.16.1", - "indexmap 2.13.0", + "indexmap 2.14.2", "stable_deref_trait", ] @@ -1178,6 +1183,12 @@ name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" dependencies = [ "foldhash 0.2.0", "serde", @@ -1309,12 +1320,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.13.0" +version = "2.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.17.1", "serde", "serde_core", ] @@ -1398,9 +1409,9 @@ checksum = "775bf80d5878ab7c2b1080b5351a48b2f737d9f6f8b383574eebcc22be0dfccb" [[package]] name = "libc" -version = "0.2.183" +version = "0.2.189" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" [[package]] name = "liblzma" @@ -1483,12 +1494,9 @@ checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "mach2" -version = "0.4.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" -dependencies = [ - "libc", -] +checksum = "dae608c151f68243f2b000364e1f7b186d9c29845f7d2d85bd31b9ad77ad552b" [[package]] name = "memchr" @@ -1612,13 +1620,13 @@ dependencies = [ [[package]] name = "object" -version = "0.37.3" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +checksum = "2e5a6c098c7a3b6547378093f5cc30bc54fd361ce711e05293a5cc589562739b" dependencies = [ "crc32fast", - "hashbrown 0.15.2", - "indexmap 2.13.0", + "hashbrown 0.17.1", + "indexmap 2.14.2", "memchr", ] @@ -1772,7 +1780,7 @@ dependencies = [ [[package]] name = "pulley-interpreter" -version = "42.0.1" +version = "48.0.1" dependencies = [ "cranelift-bitset", "log", @@ -1782,7 +1790,7 @@ dependencies = [ [[package]] name = "pulley-macros" -version = "42.0.1" +version = "48.0.1" dependencies = [ "proc-macro2", "quote", @@ -1912,15 +1920,16 @@ dependencies = [ [[package]] name = "regalloc2" -version = "0.13.5" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08effbc1fa53aaebff69521a5c05640523fab037b34a4a2c109506bc938246fa" +checksum = "757712e8e61590d6d4f5d563483755538b5aa13467837a3b41cd9832509a7f85" dependencies = [ "allocator-api2", "bumpalo", - "hashbrown 0.15.2", + "hashbrown 0.17.1", "log", "rustc-hash", + "serde", "smallvec", ] @@ -2035,9 +2044,13 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" -version = "1.0.26" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +dependencies = [ + "serde", + "serde_core", +] [[package]] name = "serde" @@ -2110,7 +2123,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.13.0", + "indexmap 2.14.2", "serde", "serde_derive", "serde_json", @@ -2136,7 +2149,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.13.0", + "indexmap 2.14.2", "itoa", "ryu", "serde", @@ -2435,7 +2448,7 @@ version = "0.9.12+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" dependencies = [ - "indexmap 2.13.0", + "indexmap 2.14.2", "serde_core", "serde_spanned", "toml_datetime 0.7.5+spec-1.1.0", @@ -2465,7 +2478,7 @@ version = "0.22.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ - "indexmap 2.13.0", + "indexmap 2.14.2", "toml_datetime 0.6.8", "winnow", ] @@ -2559,9 +2572,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-xid" @@ -2668,26 +2681,36 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.245.1" +version = "0.254.0" dependencies = [ "leb128fmt", "wasmparser", ] +[[package]] +name = "wasm-metadata" +version = "0.254.0" +dependencies = [ + "anyhow", + "indexmap 2.14.2", + "wasm-encoder", + "wasmparser", +] + [[package]] name = "wasmparser" -version = "0.245.1" +version = "0.254.0" dependencies = [ "bitflags", - "hashbrown 0.16.1", - "indexmap 2.13.0", + "hashbrown 0.17.1", + "indexmap 2.14.2", "semver", "serde", ] [[package]] name = "wasmprinter" -version = "0.245.1" +version = "0.254.0" dependencies = [ "anyhow", "termcolor", @@ -2696,7 +2719,7 @@ dependencies = [ [[package]] name = "wasmtime" -version = "42.0.1" +version = "48.0.1" dependencies = [ "addr2line 0.26.0", "async-trait", @@ -2704,12 +2727,12 @@ dependencies = [ "blake3", "bumpalo", "cc", - "cfg-if", + "futures", "libc", "log", "mach2", "memfd", - "object 0.37.3", + "object 0.39.1", "once_cell", "postcard", "pulley-interpreter", @@ -2736,32 +2759,36 @@ dependencies = [ [[package]] name = "wasmtime-environ" -version = "42.0.1" +version = "48.0.1" dependencies = [ "anyhow", "cpp_demangle", + "cranelift-bforest", "cranelift-bitset", "cranelift-entity", "gimli 0.33.0", - "hashbrown 0.15.2", - "indexmap 2.13.0", + "hashbrown 0.17.1", + "indexmap 2.14.2", "log", - "object 0.37.3", + "object 0.39.1", "postcard", "rustc-demangle", + "semver", "serde", "serde_derive", + "sha2", "smallvec", "target-lexicon", "wasm-encoder", "wasmparser", "wasmprinter", + "wasmtime-internal-component-util", "wasmtime-internal-core", ] [[package]] name = "wasmtime-internal-cache" -version = "42.0.1" +version = "48.0.1" dependencies = [ "base64", "directories-next", @@ -2779,7 +2806,7 @@ dependencies = [ [[package]] name = "wasmtime-internal-component-macro" -version = "42.0.1" +version = "48.0.1" dependencies = [ "anyhow", "proc-macro2", @@ -2792,21 +2819,22 @@ dependencies = [ [[package]] name = "wasmtime-internal-component-util" -version = "42.0.1" +version = "48.0.1" [[package]] name = "wasmtime-internal-core" -version = "42.0.1" +version = "48.0.1" dependencies = [ "anyhow", + "hashbrown 0.17.1", "libm", + "serde", ] [[package]] name = "wasmtime-internal-cranelift" -version = "42.0.1" +version = "48.0.1" dependencies = [ - "cfg-if", "cranelift-codegen", "cranelift-control", "cranelift-entity", @@ -2815,7 +2843,7 @@ dependencies = [ "gimli 0.33.0", "itertools", "log", - "object 0.37.3", + "object 0.39.1", "pulley-interpreter", "smallvec", "target-lexicon", @@ -2829,10 +2857,9 @@ dependencies = [ [[package]] name = "wasmtime-internal-fiber" -version = "42.0.1" +version = "48.0.1" dependencies = [ "cc", - "cfg-if", "libc", "rustix 1.1.4", "wasmtime-environ", @@ -2842,7 +2869,7 @@ dependencies = [ [[package]] name = "wasmtime-internal-jit-debug" -version = "42.0.1" +version = "48.0.1" dependencies = [ "cc", "wasmtime-internal-versioned-export-macros", @@ -2850,9 +2877,8 @@ dependencies = [ [[package]] name = "wasmtime-internal-jit-icache-coherence" -version = "42.0.1" +version = "48.0.1" dependencies = [ - "cfg-if", "libc", "wasmtime-internal-core", "windows-sys 0.61.2", @@ -2860,18 +2886,17 @@ dependencies = [ [[package]] name = "wasmtime-internal-unwinder" -version = "42.0.1" +version = "48.0.1" dependencies = [ - "cfg-if", "cranelift-codegen", "log", - "object 0.37.3", + "object 0.39.1", "wasmtime-environ", ] [[package]] name = "wasmtime-internal-versioned-export-macros" -version = "42.0.1" +version = "48.0.1" dependencies = [ "proc-macro2", "quote", @@ -2880,12 +2905,13 @@ dependencies = [ [[package]] name = "wasmtime-internal-wit-bindgen" -version = "42.0.1" +version = "48.0.1" dependencies = [ "anyhow", "bitflags", "heck", - "indexmap 2.13.0", + "indexmap 2.14.2", + "wit-component", "wit-parser", ] @@ -2900,7 +2926,7 @@ dependencies = [ [[package]] name = "wiggle" -version = "42.0.1" +version = "48.0.1" dependencies = [ "bitflags", "thiserror 2.0.19", @@ -2912,7 +2938,7 @@ dependencies = [ [[package]] name = "wiggle-generate" -version = "42.0.1" +version = "48.0.1" dependencies = [ "heck", "proc-macro2", @@ -2924,7 +2950,7 @@ dependencies = [ [[package]] name = "wiggle-macro" -version = "42.0.1" +version = "48.0.1" dependencies = [ "proc-macro2", "quote", @@ -3137,20 +3163,37 @@ dependencies = [ "bitflags", ] +[[package]] +name = "wit-component" +version = "0.254.0" +dependencies = [ + "anyhow", + "bitflags", + "indexmap 2.14.2", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + [[package]] name = "wit-parser" -version = "0.245.1" +version = "0.254.0" dependencies = [ "anyhow", - "hashbrown 0.16.1", + "hashbrown 0.17.1", "id-arena", - "indexmap 2.13.0", + "indexmap 2.14.2", "log", "semver", "serde", "serde_derive", "serde_json", - "unicode-xid", + "unicode-ident", "wasmparser", ] @@ -3236,7 +3279,7 @@ dependencies = [ "flate2", "getrandom 0.3.2", "hmac", - "indexmap 2.13.0", + "indexmap 2.14.2", "liblzma", "memchr", "pbkdf2", diff --git a/executor/crates/common/src/expr/evaluator.rs b/executor/crates/common/src/expr/evaluator.rs index 72f6634d..6cfdb90b 100644 --- a/executor/crates/common/src/expr/evaluator.rs +++ b/executor/crates/common/src/expr/evaluator.rs @@ -204,6 +204,14 @@ static BUILTINS: std::sync::LazyLock>); +enum ThunkStateFailure { + Generic(String), + VMError(String), + InternalError(String), +} + enum ThunkState { Forced(Value), - Failed(String), + Failed(ThunkStateFailure), Deferred(Box Result + Send>), InProgress, } @@ -194,7 +202,13 @@ impl Thunk { return Ok(v); } ThunkState::Failed(msg) => { - let err = EvalError::AlreadyFailed(msg.clone()); + let err = match &msg { + ThunkStateFailure::Generic(m) => EvalError::AlreadyFailed(m.clone()), + ThunkStateFailure::InternalError(m) => { + EvalError::ScriptInternalError(m.clone()) + } + ThunkStateFailure::VMError(m) => EvalError::ScriptVMError(m.clone()), + }; *state = ThunkState::Failed(msg); return Err(err); } @@ -213,7 +227,13 @@ impl Thunk { // A failed computation is not retried either: later forces report that failure *state = match &result { Ok(v) => ThunkState::Forced(v.clone()), - Err(e) => ThunkState::Failed(e.to_string()), + Err(EvalError::ScriptVMError(msg)) => { + ThunkState::Failed(ThunkStateFailure::VMError(msg.clone())) + } + Err(EvalError::ScriptInternalError(msg)) => { + ThunkState::Failed(ThunkStateFailure::InternalError(msg.clone())) + } + Err(e) => ThunkState::Failed(ThunkStateFailure::Generic(e.to_string())), }; result diff --git a/executor/src/rt/errors.rs b/executor/src/rt/errors.rs index 569f77c0..5e5cabad 100644 --- a/executor/src/rt/errors.rs +++ b/executor/src/rt/errors.rs @@ -132,7 +132,7 @@ impl UnwrapDynError { /// independent of the wasm store and can be done even after it is consumed. pub fn extract_backtrace(err: &UnwrapDynError) -> Option { let Some(bt) = err.downcast_ref::() else { - log_warn!("no backtrace attached"); + log_debug!("no backtrace attached"); return None; }; diff --git a/executor/src/rt/supervisor/mod.rs b/executor/src/rt/supervisor/mod.rs index ee48cc81..b1ffe4bc 100644 --- a/executor/src/rt/supervisor/mod.rs +++ b/executor/src/rt/supervisor/mod.rs @@ -1,5 +1,6 @@ use std::{ collections::{BTreeMap, BTreeSet, HashSet}, + num::NonZeroUsize, sync::{atomic::AtomicU32, Arc}, }; @@ -182,7 +183,6 @@ pub fn create_engines( .wasm_features(WasmFeatures::SIGN_EXTENSION, true) .wasm_features(WasmFeatures::MUTABLE_GLOBAL, true) .wasm_features(WasmFeatures::MULTI_VALUE, true) - .wasm_features(WasmFeatures::SATURATING_FLOAT_TO_INT, false) //.wasm_features(WasmFeatures::REFERENCE_TYPES, false) .wasm_features(WasmFeatures::SATURATING_FLOAT_TO_INT, true); @@ -192,10 +192,12 @@ pub fn create_engines( det_conf .wasm_floats_enabled(false) .cranelift_nan_canonicalization(true) - .wasm_backtrace(true); + .wasm_backtrace_max_frames(NonZeroUsize::new(20)); let mut non_det_conf = base_conf.clone(); - non_det_conf.wasm_floats_enabled(true).wasm_backtrace(false); + non_det_conf + .wasm_floats_enabled(true) + .wasm_backtrace_max_frames(None); let det_engine = wasmtime::Engine::new(&det_conf) .map_err(crate::wasmtime_to_anyhow) diff --git a/executor/src/rt/vm/storage.rs b/executor/src/rt/vm/storage.rs index a96b4d02..1b013ff9 100644 --- a/executor/src/rt/vm/storage.rs +++ b/executor/src/rt/vm/storage.rs @@ -185,6 +185,9 @@ impl StoragePagesOverride { const STORAGE_CACHE_SIZE: usize = 128; +/// Octets a single slot holds; an access must end at or before it. +pub const SLOT_SIZE: u64 = 1 << 32; + pub struct Storage { pub address: calldata::Address, host: HS, diff --git a/executor/src/wasi/genlayer_sdk/mod.rs b/executor/src/wasi/genlayer_sdk/mod.rs index cf5fd34f..87180f16 100644 --- a/executor/src/wasi/genlayer_sdk/mod.rs +++ b/executor/src/wasi/genlayer_sdk/mod.rs @@ -519,6 +519,17 @@ fn checked_sum_le( a <= c_minus_b } +/// Returns `true` iff an access of `buf_len` octets at `index` ends inside the +/// slot. +/// +/// Both operands are widened before adding: a slot ends at `SLOT_SIZE`, which +/// is one past what a `u32` sum can represent, so the last octet would +/// otherwise be unreachable. +#[inline] +fn slot_access_fits(index: u32, buf_len: u32) -> bool { + u64::from(index) + u64::from(buf_len) <= rt::vm::storage::SLOT_SIZE +} + use message::EmitInternalDeployMessageArgs; #[allow(unused_variables)] @@ -690,7 +701,7 @@ impl generated::genlayer_sdk::GenlayerSdk for ContextVFS<'_> { ) -> Result<(), generated::types::Error> { let buf = buf.as_array(buf_len); - if index.checked_add(buf_len).is_none() { + if !slot_access_fits(index, buf_len) { return Err(generated::types::Errno::Inval.into()); } @@ -757,7 +768,7 @@ impl generated::genlayer_sdk::GenlayerSdk for ContextVFS<'_> { return Err(generated::types::Errno::Forbidden.into()); } - if index.checked_add(buf_len).is_none() { + if !slot_access_fits(index, buf_len) { return Err(generated::types::Errno::Inval.into()); } diff --git a/executor/src/wasi/genlayer_sdk/tests.rs b/executor/src/wasi/genlayer_sdk/tests.rs index 952d5eb4..ff18f3bd 100644 --- a/executor/src/wasi/genlayer_sdk/tests.rs +++ b/executor/src/wasi/genlayer_sdk/tests.rs @@ -816,6 +816,24 @@ fn validator_treats_a_post_cap_leader_mismatch_as_a_leader_fault() { ); } +#[test] +fn a_slot_access_may_end_at_the_slot_end() { + assert!(slot_access_fits(0, 0)); + assert!(slot_access_fits(1, u32::MAX)); + assert!(slot_access_fits(u32::MAX - 1, 2)); + assert!( + slot_access_fits(u32::MAX, 1), + "the last octet is addressable" + ); +} + +#[test] +fn a_slot_access_may_not_run_past_the_slot_end() { + assert!(!slot_access_fits(u32::MAX, 2)); + assert!(!slot_access_fits(2, u32::MAX)); + assert!(!slot_access_fits(u32::MAX, u32::MAX)); +} + #[test] fn balance_no_permission_is_forbidden() { let err = validate_balance_fee(false, true, Some(valid_params())).unwrap_err(); diff --git a/tests/integration/exploit/storage_rw_long/storage_r_long.py b/tests/integration/exploit/storage_rw_long/storage_r_long.py deleted file mode 100644 index ffe4dc7f..00000000 --- a/tests/integration/exploit/storage_rw_long/storage_r_long.py +++ /dev/null @@ -1,7 +0,0 @@ -# { "Depends": "py-genlayer:test" } - -import _genlayer_wasi as wasi - -buf = bytearray(3) -wasi.storage_read(b'\x00' * 32, 2**32 - 1, buf) -exit(0) diff --git a/tests/integration/exploit/storage_rw_long/storage_rw_long.0.stdout b/tests/integration/exploit/storage_rw_long/storage_rw_long.0.stdout deleted file mode 100644 index f74eb57e..00000000 --- a/tests/integration/exploit/storage_rw_long/storage_rw_long.0.stdout +++ /dev/null @@ -1 +0,0 @@ -executed with `VMError("exit_code 1")` diff --git a/tests/integration/exploit/storage_rw_long/storage_rw_long.0_0.stdout b/tests/integration/exploit/storage_rw_long/storage_rw_long.0_0.stdout deleted file mode 100644 index f74eb57e..00000000 --- a/tests/integration/exploit/storage_rw_long/storage_rw_long.0_0.stdout +++ /dev/null @@ -1 +0,0 @@ -executed with `VMError("exit_code 1")` diff --git a/tests/integration/exploit/storage_rw_long/storage_rw_long.jsonnet b/tests/integration/exploit/storage_rw_long/storage_rw_long.jsonnet deleted file mode 100644 index d2d7fef5..00000000 --- a/tests/integration/exploit/storage_rw_long/storage_rw_long.jsonnet +++ /dev/null @@ -1,12 +0,0 @@ -local simple = import 'templates/simple_deploy.jsonnet'; -local util = import 'templates/util.jsonnet'; -{tags: util.features([['exploit'], ['storage']], 'stable') + ['python'], - entry: util.addPaths([util.chain([ - simple.run('${jsonnetDir}/storage_r_long.py') { - "calldata": "{}", - }, - - simple.run('${jsonnetDir}/storage_w_long.py') { - "calldata": "{}", - } -])])} diff --git a/tests/integration/exploit/storage_rw_long/storage_w_long.py b/tests/integration/exploit/storage_rw_long/storage_w_long.py deleted file mode 100644 index d885c052..00000000 --- a/tests/integration/exploit/storage_rw_long/storage_w_long.py +++ /dev/null @@ -1,6 +0,0 @@ -# { "Depends": "py-genlayer:test" } - -import _genlayer_wasi as wasi - -wasi.storage_write(b'\x00' * 32, 2**32 - 1, b'\x00\x00') -exit(0) diff --git a/tests/integration/exploit/storage_slot_edge/storage_slot_edge.jsonnet b/tests/integration/exploit/storage_slot_edge/storage_slot_edge.jsonnet new file mode 100644 index 00000000..751b1153 --- /dev/null +++ b/tests/integration/exploit/storage_slot_edge/storage_slot_edge.jsonnet @@ -0,0 +1,16 @@ +local simple = import 'templates/simple_deploy.jsonnet'; +local util = import 'templates/util.jsonnet'; + +local deploy(case) = simple.run('${jsonnetDir}/storage_slot_edge.py') { + slug: case, + calldata: '{"args": ["%s"]}' % case, +}; + +{tags: util.features([['exploit'], ['storage']], 'stable') + ['python'], + entry: util.addPaths([ + deploy('read_last_byte'), + deploy('read_ends_at_end'), + deploy('read_over_end'), + deploy('write_last_byte'), + deploy('write_over_end'), + ])} diff --git a/tests/integration/exploit/storage_slot_edge/storage_slot_edge.py b/tests/integration/exploit/storage_slot_edge/storage_slot_edge.py new file mode 100644 index 00000000..1b70cfa0 --- /dev/null +++ b/tests/integration/exploit/storage_slot_edge/storage_slot_edge.py @@ -0,0 +1,74 @@ +# { "Depends": "py-genlayer:test" } + +import typing + +import _genlayer_wasi as wasi +import genlayer as gl + +SLOT = b'\x00' * 32 +SLOT_SIZE = 2**32 +""" +Octets a slot holds, so its last one sits at ``SLOT_SIZE - 1``. +""" + + +def _read(offset: int, le: int) -> None: + buf = bytearray(le) + wasi.storage_read(SLOT, offset, buf) + print(f'read {le} at {offset}: {bytes(buf)!r}') + + +def _write(offset: int, data: bytes) -> None: + wasi.storage_write(SLOT, offset, data) + print(f'wrote {data!r} at {offset}') + + +def _refused(what: typing.Callable[[], None]) -> None: + try: + what() + except SystemError as error: + print(f'refused: {error}') + else: + raise AssertionError('the slot boundary check did not fire') + + +def _read_last_byte() -> None: + _read(SLOT_SIZE - 1, 1) + + +def _read_over_end() -> None: + _refused(lambda: _read(SLOT_SIZE - 1, 2)) + + +def _write_last_byte() -> None: + _write(SLOT_SIZE - 1, b'\x01') + _read(SLOT_SIZE - 1, 1) + + +def _write_over_end() -> None: + _refused(lambda: _write(SLOT_SIZE - 1, b'\x01\x01')) + + +def _read_ends_at_end() -> None: + _read(SLOT_SIZE - 2, 2) + + +CASES = { + 'read_last_byte': _read_last_byte, + 'read_ends_at_end': _read_ends_at_end, + 'read_over_end': _read_over_end, + 'write_last_byte': _write_last_byte, + 'write_over_end': _write_over_end, +} + + +class Contract(gl.contract.Contract): + """ + Accesses a slot at its final octet through the raw guest ABI. + + A storage layout never reaches that far out, so the boundary -- and the + off-by-one past it -- is only observable from ``_genlayer_wasi``. + """ + + def __init__(self, case: str): + CASES[case]() diff --git a/tests/integration/exploit/storage_slot_edge/storage_slot_edge.read_ends_at_end.stdout b/tests/integration/exploit/storage_slot_edge/storage_slot_edge.read_ends_at_end.stdout new file mode 100644 index 00000000..4b19f424 --- /dev/null +++ b/tests/integration/exploit/storage_slot_edge/storage_slot_edge.read_ends_at_end.stdout @@ -0,0 +1,2 @@ +read 2 at 4294967294: b'\x00\x00' +executed with `Return(null)` diff --git a/tests/integration/exploit/storage_slot_edge/storage_slot_edge.read_last_byte.stdout b/tests/integration/exploit/storage_slot_edge/storage_slot_edge.read_last_byte.stdout new file mode 100644 index 00000000..feae8693 --- /dev/null +++ b/tests/integration/exploit/storage_slot_edge/storage_slot_edge.read_last_byte.stdout @@ -0,0 +1,2 @@ +read 1 at 4294967295: b'\x00' +executed with `Return(null)` diff --git a/tests/integration/exploit/storage_slot_edge/storage_slot_edge.read_over_end.stdout b/tests/integration/exploit/storage_slot_edge/storage_slot_edge.read_over_end.stdout new file mode 100644 index 00000000..1f34be1c --- /dev/null +++ b/tests/integration/exploit/storage_slot_edge/storage_slot_edge.read_over_end.stdout @@ -0,0 +1,2 @@ +refused: 2: inval +executed with `Return(null)` diff --git a/tests/integration/exploit/storage_slot_edge/storage_slot_edge.write_last_byte.stdout b/tests/integration/exploit/storage_slot_edge/storage_slot_edge.write_last_byte.stdout new file mode 100644 index 00000000..d0d24b7d --- /dev/null +++ b/tests/integration/exploit/storage_slot_edge/storage_slot_edge.write_last_byte.stdout @@ -0,0 +1,3 @@ +wrote b'\x01' at 4294967295 +read 1 at 4294967295: b'\x01' +executed with `Return(null)` diff --git a/tests/integration/exploit/storage_slot_edge/storage_slot_edge.write_over_end.stdout b/tests/integration/exploit/storage_slot_edge/storage_slot_edge.write_over_end.stdout new file mode 100644 index 00000000..1f34be1c --- /dev/null +++ b/tests/integration/exploit/storage_slot_edge/storage_slot_edge.write_over_end.stdout @@ -0,0 +1,2 @@ +refused: 2: inval +executed with `Return(null)`