Repository: bytecodealliance/wasmtime
Pull request #9314 (2024-09-25 19:14:12)

Remove module field from wasmtime::runtime::vm::const_expr::ConstEval…
Remove module field from wasmtime::runtime::vm::const_expr::ConstEvalContext
issue #9311 
<!--
Please make sure you include the following information:

- If this work has been discussed elsewhere, please include a link to that
  conversation. If it was discussed in an issue, just mention "issue #...".

- Explain why this change is needed. If the details are in an issue already,
  this can be brief.

Our development process is documented in the Wasmtime book:
https://docs.wasmtime.dev/contributing-development-process.html

Please ensure all communication follows the code of conduct:
https://github.com/bytecodealliance/wasmtime/blob/main/CODE_OF_CONDUCT.md
-->



Patch:
diff --git a/Cargo.lock b/Cargo.lock
index a03a226b4..8f1cd97f5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -449,6 +449,15 @@ dependencies = [
  "terminal_size",
 ]
 
+[[package]]
+name = "clap_complete"
+version = "4.5.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b378c786d3bde9442d2c6dd7e6080b2a818db2b96e30d6e7f1b6d224eb617d3"
+dependencies = [
+ "clap",
+]
+
 [[package]]
 name = "clap_derive"
 version = "4.5.13"
@@ -3547,6 +3556,7 @@ dependencies = [
  "capstone",
  "cfg-if",
  "clap",
+ "clap_complete",
  "component-macro-test",
  "component-test-util",
  "cranelift-codegen",
diff --git a/Cargo.toml b/Cargo.toml
index 74ee00055..0bf32b204 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -58,6 +58,7 @@ wasmtime-wasi-keyvalue = { workspace = true, optional = true }
 wasmtime-wasi-threads = { workspace = true, optional = true }
 wasmtime-wasi-http = { workspace = true, optional = true }
 clap = { workspace = true }
+clap_complete = { workspace = true, optional = true }
 anyhow = { workspace = true, features = ['std'] }
 target-lexicon = { workspace = true }
 once_cell = { workspace = true }
@@ -288,6 +289,7 @@ windows-sys = "0.59.0"
 env_logger = "0.11.5"
 log = { version = "0.4.8", default-features = false }
 clap = { version = "4.5.17", default-features = false, features = ["std", "derive"] }
+clap_complete = "4.4.7"
 hashbrown = { version = "0.14", default-features = false }
 capstone = "0.12.0"
 once_cell = { version = "1.12.0", default-features = false }
@@ -360,6 +362,7 @@ default = [
   "serve",
   "wast",
   "config",
+  "completion",
 
   # On-by-default WASI features
   "wasi-nn",
@@ -456,6 +459,7 @@ run = [
   "dep:tokio",
   "wasmtime-cli-flags/async",
 ]
+completion = ["dep:clap_complete"]
 
 [[test]]
 name = "host_segfault"
diff --git a/crates/c-api/src/async.rs b/crates/c-api/src/async.rs
index ef577d87c..c6066cf54 100644
--- a/crates/c-api/src/async.rs
+++ b/crates/c-api/src/async.rs
@@ -389,6 +389,9 @@ unsafe impl StackMemory for CHostStackMemory {
         let base = unsafe { top.sub(len) as usize };
         base..base + len
     }
+    fn guard_range(&self) -> Range<*mut u8> {
+        std::ptr::null_mut()..std::ptr::null_mut()
+    }
 }
 
 pub type wasmtime_new_stack_memory_callback_t = extern "C" fn(
diff --git a/crates/cranelift/src/gc/enabled.rs b/crates/cranelift/src/gc/enabled.rs
index 95fa1881b..0a217a5e3 100644
--- a/crates/cranelift/src/gc/enabled.rs
+++ b/crates/cranelift/src/gc/enabled.rs
@@ -25,10 +25,6 @@ fn unbarriered_load_gc_ref(
     flags: ir::MemFlags,
 ) -> WasmResult<ir::Value> {
     debug_assert!(ty.is_vmgcref_type());
-    assert!(
-        flags.explicit_endianness().is_none(),
-        "GC references are always native-endian"
-    );
     let gc_ref = builder.ins().load(ir::types::I32, flags, ptr_to_gc_ref, 0);
     if ty != WasmHeapType::I31 {
         builder.declare_value_needs_stack_map(gc_ref);
@@ -44,10 +40,6 @@ fn unbarriered_store_gc_ref(
     flags: ir::MemFlags,
 ) -> WasmResult<()> {
     debug_assert!(ty.is_vmgcref_type());
-    assert!(
-        flags.explicit_endianness().is_none(),
-        "GC references are always native-endian"
-    );
     builder.ins().store(flags, gc_ref, dst, 0);
     Ok(())
 }
@@ -156,42 +148,19 @@ pub fn translate_struct_get(
     // and relative to `gc_ref[0]`.
     let field_addr = func_env.prepare_gc_ref_access(builder, struct_ref, field_offset, field_size);
 
+    // Data inside GC objects is always little endian.
+    let flags = ir::MemFlags::trusted().with_endianness(ir::Endianness::Little);
+
     let field_val = match field_ty.element_type {
         WasmStorageType::Val(v) => match v {
-            WasmValType::I32 => {
-                builder
-                    .ins()
-                    .load(ir::types::I32, ir::MemFlags::trusted(), field_addr, 0)
-            }
-            WasmValType::I64 => {
-                builder
-                    .ins()
-                    .load(ir::types::I64, ir::MemFlags::trusted(), field_addr, 0)
-            }
-            WasmValType::F32 => {
-                builder
-                    .ins()
-                    .load(ir::types::F32, ir::MemFlags::trusted(), field_addr, 0)
-            }
-            WasmValType::F64 => {
-                builder
-                    .ins()
-                    .load(ir::types::F64, ir::MemFlags::trusted(), field_addr, 0)
-            }
-            WasmValType::V128 => {
-                builder
-                    .ins()
-                    .load(ir::types::I128, ir::MemFlags::trusted(), field_addr, 0)
-            }
+            WasmValType::I32 => builder.ins().load(ir::types::I32, flags, field_addr, 0),
+            WasmValType::I64 => builder.ins().load(ir::types::I64, flags, field_addr, 0),
+            WasmValType::F32 => builder.ins().load(ir::types::F32, flags, field_addr, 0),
+            WasmValType::F64 => builder.ins().load(ir::types::F64, flags, field_addr, 0),
+            WasmValType::V128 => builder.ins().load(ir::types::I128, flags, field_addr, 0),
             WasmValType::Ref(r) => match r.heap_type.top() {
                 WasmHeapTopType::Any | WasmHeapTopType::Extern => gc_compiler(func_env)?
-                    .translate_read_gc_reference(
-                        func_env,
-                        builder,
-                        r,
-                        field_addr,
-                        ir::MemFlags::trusted(),
-                    )?,
+                    .translate_read_gc_reference(func_env, builder, r, field_addr, flags)?,
                 WasmHeapTopType::Func => {
                     unimplemented!("funcrefs inside the GC heap")
                 }
@@ -237,17 +206,12 @@ fn translate_struct_get_and_extend(
     // TODO: See comment in `translate_struct_get` about the `prepare_gc_ref_access`.
     let field_addr = func_env.prepare_gc_ref_access(builder, struct_ref, field_offset, field_size);
 
+    // Data inside GC objects is always little endian.
+    let flags = ir::MemFlags::trusted().with_endianness(ir::Endianness::Little);
+
     let field_val = match field_ty.element_type {
-        WasmStorageType::I8 => {
-            builder
-                .ins()
-                .load(ir::types::I8, ir::MemFlags::trusted(), field_addr, 0)
-        }
-        WasmStorageType::I16 => {
-            builder
-                .ins()
-                .load(ir::types::I16, ir::MemFlags::trusted(), field_addr, 0)
-        }
+        WasmStorageType::I8 => builder.ins().load(ir::types::I8, flags, field_addr, 0),
+        WasmStorageType::I16 => builder.ins().load(ir::types::I16, flags, field_addr, 0),
         WasmStorageType::Val(_) => unreachable!(),
     };
 
@@ -320,35 +284,26 @@ pub fn translate_struct_set(
     // TODO: See comment in `translate_struct_get` about the `prepare_gc_ref_access`.
     let field_addr = func_env.prepare_gc_ref_access(builder, struct_ref, field_offset, field_size);
 
+    // Data inside GC objects is always little endian.
+    let flags = ir::MemFlags::trusted().with_endianness(ir::Endianness::Little);
+
     match &field_ty.element_type {
         WasmStorageType::I8 => {
-            builder
-                .ins()
-                .istore8(ir::MemFlags::trusted(), new_val, field_addr, 0);
+            builder.ins().istore8(flags, new_val, field_addr, 0);
         }
         WasmStorageType::I16 => {
-            builder
-                .ins()
-                .istore16(ir::MemFlags::trusted(), new_val, field_addr, 0);
+            builder.ins().istore16(flags, new_val, field_addr, 0);
         }
         WasmStorageType::Val(WasmValType::Ref(r)) if r.heap_type.top() == WasmHeapTopType::Func => {
             unimplemented!("funcrefs inside the GC heap")
         }
         WasmStorageType::Val(WasmValType::Ref(r)) => {
-            gc_compiler(func_env)?.translate_write_gc_reference(
-                func_env,
-                builder,
-                *r,
-                field_addr,
-                new_val,
-                ir::MemFlags::trusted(),
-            )?;
+            gc_compiler(func_env)?
+                .translate_write_gc_reference(func_env, builder, *r, field_addr, new_val, flags)?;
         }
         WasmStorageType::Val(_) => {
             assert_eq!(builder.func.dfg.value_type(new_val).bytes(), field_size);
-            builder
-                .ins()
-                .store(ir::MemFlags::trusted(), new_val, field_addr, 0);
+            builder.ins().store(flags, new_val, field_addr, 0);
         }
     }
 
diff --git a/crates/cranelift/src/gc/enabled/drc.rs b/crates/cranelift/src/gc/enabled/drc.rs
index cd351772e..8fe6eb43d 100644
--- a/crates/cranelift/src/gc/enabled/drc.rs
+++ b/crates/cranelift/src/gc/enabled/drc.rs
@@ -260,6 +260,9 @@ impl GcCompiler for DrcCompiler {
 
         // Second, initialize each of the newly-allocated struct's fields.
 
+        // Data inside GC objects is always little endian.
+        let flags = ir::MemFlags::trusted().with_endianness(ir::Endianness::Little);
+
         for ((ty, val), offset) in field_types.into_iter().zip(field_vals).zip(field_offsets) {
             let size_of_access =
                 wasmtime_environ::byte_size_of_wasm_ty_in_gc_heap(&ty.element_type);
@@ -276,29 +279,18 @@ impl GcCompiler for DrcCompiler {
                 }
                 WasmStorageType::Val(WasmValType::Ref(r)) => {
                     self.translate_init_gc_reference(
-                        func_env,
-                        builder,
-                        *r,
-                        field_addr,
-                        *val,
-                        ir::MemFlags::trusted(),
+                        func_env, builder, *r, field_addr, *val, flags,
                     )?;
                 }
                 WasmStorageType::I8 => {
-                    builder
-                        .ins()
-                        .istore8(ir::MemFlags::trusted(), *val, field_addr, 0);
+                    builder.ins().istore8(flags, *val, field_addr, 0);
                 }
                 WasmStorageType::I16 => {
-                    builder
-                        .ins()
-                        .istore16(ir::MemFlags::trusted(), *val, field_addr, 0);
+                    builder.ins().istore16(flags, *val, field_addr, 0);
                 }
                 WasmStorageType::Val(_) => {
                     assert_eq!(builder.func.dfg.value_type(*val).bytes(), size_of_access);
-                    builder
-                        .ins()
-                        .store(ir::MemFlags::trusted(), *val, field_addr, 0);
+                    builder.ins().store(flags, *val, field_addr, 0);
                 }
             }
         }
@@ -315,10 +307,6 @@ impl GcCompiler for DrcCompiler {
         flags: ir::MemFlags,
     ) -> WasmResult<ir::Value> {
         assert!(ty.is_vmgcref_type());
-        assert!(
-            flags.explicit_endianness().is_none(),
-            "GC references are always native-endian"
-        );
 
         let (reference_type, needs_stack_map) = func_env.reference_type(ty.heap_type);
         debug_assert!(needs_stack_map);
@@ -467,10 +455,6 @@ impl GcCompiler for DrcCompiler {
         flags: ir::MemFlags,
     ) -> WasmResult<()> {
         assert!(ty.is_vmgcref_type());
-        assert!(
-            flags.explicit_endianness().is_none(),
-            "GC references are always native-endian"
-        );
 
         let (ref_ty, needs_stack_map) = func_env.reference_type(ty.heap_type);
         debug_assert!(needs_stack_map);
diff --git a/crates/fiber/src/lib.rs b/crates/fiber/src/lib.rs
index 16fb10bd2..d17f92d6b 100644
--- a/crates/fiber/src/lib.rs
+++ b/crates/fiber/src/lib.rs
@@ -33,10 +33,11 @@ impl FiberStack {
     }
 
     /// Creates a new fiber stack with the given pointer to the bottom of the
-    /// stack plus the byte length of the stack.
+    /// stack plus how large the guard size and stack size are.
     ///
-    /// The `bottom` pointer should be addressable for `len` bytes. The page
-    /// beneath `bottom` should be unmapped as a guard page.
+    /// The bytes from `bottom` to `bottom.add(guard_size)` should all be
+    /// guaranteed to be unmapped. The bytes from `bottom.add(guard_size)` to
+    /// `bottom.add(guard_size + len)` should be addressable.
     ///
     /// # Safety
     ///
@@ -44,8 +45,14 @@ impl FiberStack {
     ///
     /// The caller must properly allocate the stack space with a guard page and
     /// make the pages accessible for correct behavior.
-    pub unsafe fn from_raw_parts(bottom: *mut u8, len: usize) -> io::Result<Self> {
-        Ok(Self(imp::FiberStack::from_raw_parts(bottom, len)?))
+    pub unsafe fn from_raw_parts(
+        bottom: *mut u8,
+        guard_size: usize,
+        len: usize,
+    ) -> io::Result<Self> {
+        Ok(Self(imp::FiberStack::from_raw_parts(
+            bottom, guard_size, len,
+        )?))
     }
 
     /// Gets the top of the stack.
@@ -67,6 +74,11 @@ impl FiberStack {
     pub fn is_from_raw_parts(&self) -> bool {
         self.0.is_from_raw_parts()
     }
+
+    /// Returns the range of memory that the guard page(s) reside in.
+    pub fn guard_range(&self) -> Option<Range<*mut u8>> {
+        self.0.guard_range()
+    }
 }
 
 /// A creator of RuntimeFiberStacks.
@@ -85,6 +97,8 @@ pub unsafe trait RuntimeFiberStack: Send + Sync {
     fn top(&self) -> *mut u8;
     /// The valid range of the stack without guard pages.
     fn range(&self) -> Range<usize>;
+    /// The range of the guard page(s)
+    fn guard_range(&self) -> Range<*mut u8>;
 }
 
 pub struct Fiber<'a, Resume, Yield, Return> {
diff --git a/crates/fiber/src/unix.rs b/crates/fiber/src/unix.rs
index b16006543..632188351 100644
--- a/crates/fiber/src/unix.rs
+++ b/crates/fiber/src/unix.rs
@@ -46,7 +46,7 @@ pub struct FiberStack {
 
 enum FiberStackStorage {
     Mmap(#[allow(dead_code)] MmapFiberStack),
-    Unmanaged,
+    Unmanaged(usize),
     Custom(#[allow(dead_code)] Box<dyn RuntimeFiberStack>),
 }
 
@@ -70,21 +70,21 @@ impl FiberStack {
         })
     }
 
-    pub unsafe fn from_raw_parts(base: *mut u8, len: usize) -> io::Result<Self> {
+    pub unsafe fn from_raw_parts(base: *mut u8, guard_size: usize, len: usize) -> io::Result<Self> {
         // See comments in `mod asan` below for why asan has a different stack
         // allocation strategy.
         if cfg!(asan) {
             return Self::from_custom(asan::new_fiber_stack(len)?);
         }
         Ok(FiberStack {
-            base,
+            base: base.add(guard_size),
             len,
-            storage: FiberStackStorage::Unmanaged,
+            storage: FiberStackStorage::Unmanaged(guard_size),
         })
     }
 
     pub fn is_from_raw_parts(&self) -> bool {
-        matches!(self.storage, FiberStackStorage::Unmanaged)
+        matches!(self.storage, FiberStackStorage::Unmanaged(_))
     }
 
     pub fn from_custom(custom: Box<dyn RuntimeFiberStack>) -> io::Result<Self> {
@@ -115,6 +115,17 @@ impl FiberStack {
         let base = self.base as usize;
         Some(base..base + self.len)
     }
+
+    pub fn guard_range(&self) -> Option<Range<*mut u8>> {
+        match &self.storage {
+            FiberStackStorage::Unmanaged(guard_size) => unsafe {
+                let start = self.base.sub(*guard_size);
+                Some(start..self.base)
+            },
+            FiberStackStorage::Mmap(mmap) => Some(mmap.mapping_base..self.base),
+            FiberStackStorage::Custom(custom) => Some(custom.guard_range()),
+        }
+    }
 }
 
 struct MmapFiberStack {
diff --git a/crates/fiber/src/windows.rs b/crates/fiber/src/windows.rs
index e15d1bb2b..16203bd5c 100644
--- a/crates/fiber/src/windows.rs
+++ b/crates/fiber/src/windows.rs
@@ -15,7 +15,11 @@ impl FiberStack {
         Ok(Self(size))
     }
 
-    pub unsafe fn from_raw_parts(_base: *mut u8, _len: usize) -> io::Result<Self> {
+    pub unsafe fn from_raw_parts(
+        _base: *mut u8,
+        _guard_size: usize,
+        _len: usize,
+    ) -> io::Result<Self> {
         Err(io::Error::from_raw_os_error(ERROR_NOT_SUPPORTED as i32))
     }
 
@@ -34,6 +38,10 @@ impl FiberStack {
     pub fn range(&self) -> Option<Range<usize>> {
         None
     }
+
+    pub fn guard_range(&self) -> Option<Range<*mut u8>> {
+        None
+    }
 }
 
 pub struct Fiber {
diff --git a/crates/wasmtime/src/runtime/func.rs b/crates/wasmtime/src/runtime/func.rs
index 753799e43..fd45ba84d 100644
--- a/crates/wasmtime/src/runtime/func.rs
+++ b/crates/wasmtime/src/runtime/func.rs
@@ -1610,6 +1610,7 @@ pub(crate) fn invoke_wasm_and_catch_traps<T>(
             store.0.signal_handler(),
             store.0.engine().config().wasm_backtrace,
             store.0.engine().config().coredump_on_trap,
+            store.0.async_guard_range(),
             store.0.default_caller(),
             closure,
         );
diff --git a/crates/wasmtime/src/runtime/stack.rs b/crates/wasmtime/src/runtime/stack.rs
index 703c03691..94f5732ec 100644
--- a/crates/wasmtime/src/runtime/stack.rs
+++ b/crates/wasmtime/src/runtime/stack.rs
@@ -57,6 +57,8 @@ pub unsafe trait StackMemory: Send + Sync {
     fn top(&self) -> *mut u8;
     /// The range of where this stack resides in memory, excluding guard pages.
     fn range(&self) -> Range<usize>;
+    /// The range of memory where the guard region of this stack resides.
+    fn guard_range(&self) -> Range<*mut u8>;
 }
 
 pub(crate) struct FiberStackProxy(pub Box<dyn StackMemory>);
@@ -69,4 +71,8 @@ unsafe impl RuntimeFiberStack for FiberStackProxy {
     fn range(&self) -> Range<usize> {
         self.0.range()
     }
+
+    fn guard_range(&self) -> Range<*mut u8> {
+        self.0.guard_range()
+    }
 }
diff --git a/crates/wasmtime/src/runtime/store.rs b/crates/wasmtime/src/runtime/store.rs
index 10ba85308..bf21c4a65 100644
--- a/crates/wasmtime/src/runtime/store.rs
+++ b/crates/wasmtime/src/runtime/store.rs
@@ -99,7 +99,7 @@ use core::future::Future;
 use core::marker;
 use core::mem::{self, ManuallyDrop};
 use core::num::NonZeroU64;
-use core::ops::{Deref, DerefMut};
+use core::ops::{Deref, DerefMut, Range};
 use core::pin::Pin;
 use core::ptr;
 use core::task::{Context, Poll};
@@ -391,7 +391,26 @@ pub struct StoreOpaque {
 #[cfg(feature = "async")]
 struct AsyncState {
     current_suspend: UnsafeCell<*mut wasmtime_fiber::Suspend<Result<()>, (), Result<()>>>,
-    current_poll_cx: UnsafeCell<*mut Context<'static>>,
+    current_poll_cx: UnsafeCell<PollContext>,
+}
+
+#[cfg(feature = "async")]
+#[derive(Clone, Copy)]
+struct PollContext {
+    future_context: *mut Context<'static>,
+    guard_range_start: *mut u8,
+    guard_range_end: *mut u8,
+}
+
+#[cfg(feature = "async")]
+impl Default for PollContext {
+    fn default() -> PollContext {
+        PollContext {
+            future_context: core::ptr::null_mut(),
+            guard_range_start: core::ptr::null_mut(),
+            guard_range_end: core::ptr::null_mut(),
+        }
+    }
 }
 
 // Lots of pesky unsafe cells and pointers in this structure. This means we need
@@ -536,7 +555,7 @@ impl<T> Store<T> {
                 #[cfg(feature = "async")]
                 async_state: AsyncState {
                     current_suspend: UnsafeCell::new(ptr::null_mut()),
-                    current_poll_cx: UnsafeCell::new(ptr::null_mut()),
+                    current_poll_cx: UnsafeCell::new(PollContext::default()),
                 },
                 fuel_reserve: 0,
                 fuel_yield_interval: None,
@@ -1779,13 +1798,13 @@ impl StoreOpaque {
         }
 
         let poll_cx_inner_ptr = unsafe { *poll_cx_box_ptr };
-        if poll_cx_inner_ptr.is_null() {
+        if poll_cx_inner_ptr.future_context.is_null() {
             return None;
         }
 
         Some(AsyncCx {
             current_suspend: self.async_state.current_suspend.get(),
-            current_poll_cx: poll_cx_box_ptr,
+            current_poll_cx: unsafe { core::ptr::addr_of_mut!((*poll_cx_box_ptr).future_context) },
             track_pkey_context_switch: self.pkey.is_some(),
         })
     }
@@ -2053,6 +2072,18 @@ at https://bytecodealliance.org/security.
 
         self.num_component_instances += 1;
     }
+
+    pub(crate) fn async_guard_range(&self) -> Range<*mut u8> {
+        #[cfg(feature = "async")]
+        unsafe {
+            let ptr = self.async_state.current_poll_cx.get();
+            (*ptr).guard_range_start..(*ptr).guard_range_end
+        }
+        #[cfg(not(feature = "async"))]
+        {
+            core::ptr::null_mut()..core::ptr::null_mut()
+        }
+    }
 }
 
 impl<T> StoreContextMut<'_, T> {
@@ -2123,7 +2154,7 @@ impl<T> StoreContextMut<'_, T> {
 
         struct FiberFuture<'a> {
             fiber: Option<wasmtime_fiber::Fiber<'a, Result<()>, (), Result<()>>>,
-            current_poll_cx: *mut *mut Context<'static>,
+            current_poll_cx: *mut PollContext,
             engine: Engine,
             // See comments in `FiberFuture::resume` for this
             state: Option<crate::runtime::vm::AsyncWasmCallState>,
@@ -2259,10 +2290,21 @@ impl<T> StoreContextMut<'_, T> {
                 // On exit from this function, though, we reset the polling
                 // context back to what it was to signify that `Store` no longer
                 // has access to this pointer.
+                let guard = self
+                    .fiber()
+                    .stack()
+                    .guard_range()
+                    .unwrap_or(core::ptr::null_mut()..core::ptr::null_mut());
                 unsafe {
                     let _reset = Reset(self.current_poll_cx, *self.current_poll_cx);
-                    *self.current_poll_cx =
-                        core::mem::transmute::<&mut Context<'_>, *mut Context<'static>>(cx);
+                    *self.current_poll_cx = PollContext {
+                        future_context: core::mem::transmute::<
+                            &mut Context<'_>,
+                            *mut Context<'static>,
+                        >(cx),
+                        guard_range_start: guard.start,
+                        guard_range_end: guard.end,
+                    };
 
                     // After that's set up we resume execution of the fiber, which
                     // may also start the fiber for the first time. This either
diff --git a/crates/wasmtime/src/runtime/vm/const_expr.rs b/crates/wasmtime/src/runtime/vm/const_expr.rs
index 6eca60a7b..da99f9e55 100644
--- a/crates/wasmtime/src/runtime/vm/const_expr.rs
+++ b/crates/wasmtime/src/runtime/vm/const_expr.rs
@@ -5,7 +5,7 @@ use crate::store::AutoAssertNoGc;
 use crate::{prelude::*, StructRef, StructRefPre, StructType, Val};
 use smallvec::SmallVec;
 use wasmtime_environ::{
-    ConstExpr, ConstOp, FuncIndex, GlobalIndex, Module, ModuleInternedTypeIndex, WasmCompositeType,
+    ConstExpr, ConstOp, FuncIndex, GlobalIndex, ModuleInternedTypeIndex, WasmCompositeType,
     WasmSubType,
 };
 
@@ -19,15 +19,14 @@ pub struct ConstExprEvaluator {
 }
 
 /// The context within which a particular const expression is evaluated.
-pub struct ConstEvalContext<'a, 'b> {
+pub struct ConstEvalContext<'a> {
     instance: &'a mut Instance,
-    module: &'b Module,
 }
 
-impl<'a, 'b> ConstEvalContext<'a, 'b> {
+impl<'a> ConstEvalContext<'a> {
     /// Create a new context.
-    pub fn new(instance: &'a mut Instance, module: &'b Module) -> Self {
-        Self { instance, module }
+    pub fn new(instance: &'a mut Instance) -> Self {
+        Self { instance }
     }
 
     fn global_get(&mut self, store: &mut AutoAssertNoGc<'_>, index: GlobalIndex) -> Result<ValRaw> {
@@ -38,7 +37,10 @@ impl<'a, 'b> ConstEvalContext<'a, 'b> {
                 .as_ref()
                 .unwrap();
             let mut gc_store = store.unwrap_gc_store_mut();
-            Ok(global.to_val_raw(&mut gc_store, self.module.globals[index].wasm_ty))
+            Ok(global.to_val_raw(
+                &mut gc_store,
+                self.instance.env_module().globals[index].wasm_ty,
+            ))
         }
     }
 
@@ -163,7 +165,7 @@ impl ConstExprEvaluator {
     /// the correct type.
     pub unsafe fn eval(
         &mut self,
-        context: &mut ConstEvalContext<'_, '_>,
+        context: &mut ConstEvalContext<'_>,
         expr: &ConstExpr,
     ) -> Result<ValRaw> {
         self.stack.clear();
@@ -240,7 +242,8 @@ impl ConstExprEvaluator {
 
                 #[cfg(feature = "gc")]
                 ConstOp::StructNew { struct_type_index } => {
-                    let interned_type_index = context.module.types[*struct_type_index];
+                    let interned_type_index =
+                        context.instance.env_module().types[*struct_type_index];
                     let len = context.struct_fields_len(interned_type_index);
 
                     if self.stack.len() < len {
@@ -262,7 +265,8 @@ impl ConstExprEvaluator {
 
                 #[cfg(feature = "gc")]
                 ConstOp::StructNewDefault { struct_type_index } => {
-                    let interned_type_index = context.module.types[*struct_type_index];
+                    let interned_type_index =
+                        context.instance.env_module().types[*struct_type_index];
                     self.stack
                         .push(context.struct_new_default(&mut store, interned_type_index)?);
                 }
diff --git a/crates/wasmtime/src/runtime/vm/gc/enabled/data.rs b/crates/wasmtime/src/runtime/vm/gc/enabled/data.rs
index 6a7cdc35c..ef117c636 100644
--- a/crates/wasmtime/src/runtime/vm/gc/enabled/data.rs
+++ b/crates/wasmtime/src/runtime/vm/gc/enabled/data.rs
@@ -6,21 +6,21 @@ use core::mem;
 /// A plain-old-data type that can be stored in a `ValType` or a `StorageType`.
 pub trait PodValType<const SIZE: usize>: Copy {
     /// Read an instance of `Self` from the given native-endian bytes.
-    fn read_ne(ne_bytes: &[u8; SIZE]) -> Self;
+    fn read_le(le_bytes: &[u8; SIZE]) -> Self;
 
     /// Write `self` into the given memory location, as native-endian bytes.
-    fn write_ne(&self, into: &mut [u8; SIZE]);
+    fn write_le(&self, into: &mut [u8; SIZE]);
 }
 
 macro_rules! impl_pod_val_type {
     ( $( $t:ty , )* ) => {
         $(
             impl PodValType<{mem::size_of::<$t>()}> for $t {
-                fn read_ne(ne_bytes: &[u8; mem::size_of::<$t>()]) -> Self {
-                    <$t>::from_ne_bytes(*ne_bytes)
+                fn read_le(le_bytes: &[u8; mem::size_of::<$t>()]) -> Self {
+                    <$t>::from_le_bytes(*le_bytes)
                 }
-                fn write_ne(&self, into: &mut [u8; mem::size_of::<$t>()]) {
-                    *into = self.to_ne_bytes();
+                fn write_le(&self, into: &mut [u8; mem::size_of::<$t>()]) {
+                    *into = self.to_le_bytes();
                 }
             }
         )*
@@ -39,11 +39,11 @@ impl_pod_val_type! {
 }
 
 impl PodValType<{ mem::size_of::<V128>() }> for V128 {
-    fn read_ne(ne_bytes: &[u8; mem::size_of::<V128>()]) -> Self {
-        u128::from_ne_bytes(*ne_bytes).into()
+    fn read_le(le_bytes: &[u8; mem::size_of::<V128>()]) -> Self {
+        u128::from_le_bytes(*le_bytes).into()
     }
-    fn write_ne(&self, into: &mut [u8; mem::size_of::<V128>()]) {
-        *into = self.as_u128().to_ne_bytes();
+    fn write_le(&self, into: &mut [u8; mem::size_of::<V128>()]) {
+        *into = self.as_u128().to_le_bytes();
     }
 }
 
@@ -112,7 +112,7 @@ impl<'a> VMGcObjectDataMut<'a> {
         let offset = usize::try_from(offset).unwrap();
         let end = offset.checked_add(N).unwrap();
         let bytes = self.data.get(offset..end).expect("out of bounds field");
-        T::read_ne(bytes.try_into().unwrap())
+        T::read_le(bytes.try_into().unwrap())
     }
 
     /// Read a POD field out of this object.
@@ -130,7 +130,7 @@ impl<'a> VMGcObjectDataMut<'a> {
         let offset = usize::try_from(offset).unwrap();
         let end = offset.checked_add(N).unwrap();
         let into = self.data.get_mut(offset..end).expect("out of bounds field");
-        val.write_ne(into.try_into().unwrap());
+        val.write_le(into.try_into().unwrap());
     }
 
     impl_pod_methods! {
diff --git a/crates/wasmtime/src/runtime/vm/instance.rs b/crates/wasmtime/src/runtime/vm/instance.rs
index ac9c525bc..6cbf83a94 100644
--- a/crates/wasmtime/src/runtime/vm/instance.rs
+++ b/crates/wasmtime/src/runtime/vm/instance.rs
@@ -874,7 +874,7 @@ impl Instance {
                     .get(src..)
                     .and_then(|s| s.get(..len))
                     .ok_or(Trap::TableOutOfBounds)?;
-                let mut context = ConstEvalContext::new(self, &module);
+                let mut context = ConstEvalContext::new(self);
                 match module.table_plans[table_index]
                     .table
                     .ref_type
@@ -1277,7 +1277,7 @@ impl Instance {
         module: &Module,
     ) {
         for (index, init) in module.global_initializers.iter() {
-            let mut context = ConstEvalContext::new(self, module);
+            let mut context = ConstEvalContext::new(self);
             let raw = const_evaluator
                 .eval(&mut context, init)
                 .expect("should be a valid const expr");
diff --git a/crates/wasmtime/src/runtime/vm/instance/allocator.rs b/crates/wasmtime/src/runtime/vm/instance/allocator.rs
index 28a4ca843..f93592378 100644
--- a/crates/wasmtime/src/runtime/vm/instance/allocator.rs
+++ b/crates/wasmtime/src/runtime/vm/instance/allocator.rs
@@ -533,7 +533,7 @@ fn check_table_init_bounds(instance: &mut Instance, module: &Module) -> Result<(
 
     for segment in module.table_initialization.segments.iter() {
         let table = unsafe { &*instance.get_table(segment.table_index) };
-        let mut context = ConstEvalContext::new(instance, module);
+        let mut context = ConstEvalContext::new(instance);
         let start = unsafe {
             const_evaluator
                 .eval(&mut context, &segment.offset)
@@ -564,7 +564,7 @@ fn initialize_tables(instance: &mut Instance, module: &Module) -> Result<()> {
             TableInitialValue::Null { precomputed: _ } => {}
 
             TableInitialValue::Expr(expr) => {
-                let mut context = ConstEvalContext::new(instance, module);
+                let mut context = ConstEvalContext::new(instance);
                 let raw = unsafe {
                     const_evaluator
                         .eval(&mut context, expr)
@@ -607,7 +607,7 @@ fn initialize_tables(instance: &mut Instance, module: &Module) -> Result<()> {
     // iterates over all segments (Segments mode) or leftover
     // segments (FuncTable mode) to initialize.
     for segment in module.table_initialization.segments.iter() {
-        let mut context = ConstEvalContext::new(instance, module);
+        let mut context = ConstEvalContext::new(instance);
         let start = unsafe {
             const_evaluator
                 .eval(&mut context, &segment.offset)
@@ -628,12 +628,8 @@ fn initialize_tables(instance: &mut Instance, module: &Module) -> Result<()> {
     Ok(())
 }
 
-fn get_memory_init_start(
-    init: &MemoryInitializer,
-    instance: &mut Instance,
-    module: &Module,
-) -> Result<u64> {
-    let mut context = ConstEvalContext::new(instance, module);
+fn get_memory_init_start(init: &MemoryInitializer, instance: &mut Instance) -> Result<u64> {
+    let mut context = ConstEvalContext::new(instance);
     let mut const_evaluator = ConstExprEvaluator::default();
     unsafe { const_evaluator.eval(&mut context, &init.offset) }.map(|v| {
         match instance.env_module().memory_plans[init.memory_index]
@@ -648,12 +644,11 @@ fn get_memory_init_start(
 
 fn check_memory_init_bounds(
     instance: &mut Instance,
-    module: &Module,
     initializers: &[MemoryInitializer],
 ) -> Result<()> {
     for init in initializers {
         let memory = instance.get_memory(init.memory_index);
-        let start = get_memory_init_start(init, instance, module)?;
+        let start = get_memory_init_start(init, instance)?;
         let end = usize::try_from(start)
             .ok()
             .and_then(|start| start.checked_add(init.data.len()));
@@ -702,7 +697,7 @@ fn initialize_memories(instance: &mut Instance, module: &Module) -> Result<()> {
             memory: wasmtime_environ::MemoryIndex,
             expr: &wasmtime_environ::ConstExpr,
         ) -> Option<u64> {
-            let mut context = ConstEvalContext::new(self.instance, self.module);
+            let mut context = ConstEvalContext::new(self.instance);
             let val = unsafe { self.const_evaluator.eval(&mut context, expr) }
                 .expect("const expression should be valid");
             Some(
@@ -767,7 +762,7 @@ fn check_init_bounds(instance: &mut Instance, module: &Module) -> Result<()> {
 
     match &module.memory_initialization {
         MemoryInitialization::Segmented(initializers) => {
-            check_memory_init_bounds(instance, module, initializers)?;
+            check_memory_init_bounds(instance, initializers)?;
         }
         // Statically validated already to have everything in-bounds.
         MemoryInitialization::Static { .. } => {}
diff --git a/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/unix_stack_pool.rs b/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/unix_stack_pool.rs
index 76dcdd999..f274e51df 100644
--- a/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/unix_stack_pool.rs
+++ b/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/unix_stack_pool.rs
@@ -105,13 +105,16 @@ impl StackPool {
             let bottom_of_stack = self
                 .mapping
                 .as_ptr()
-                .add((index * self.stack_size) + self.page_size)
+                .add(index * self.stack_size)
                 .cast_mut();
 
             commit_pages(bottom_of_stack, size_without_guard)?;
 
-            let stack =
-                wasmtime_fiber::FiberStack::from_raw_parts(bottom_of_stack, size_without_guard)?;
+            let stack = wasmtime_fiber::FiberStack::from_raw_parts(
+                bottom_of_stack,
+                self.page_size,
+                size_without_guard,
+            )?;
             Ok(stack)
         }
     }
diff --git a/crates/wasmtime/src/runtime/vm/sys/unix/machports.rs b/crates/wasmtime/src/runtime/vm/sys/unix/machports.rs
index 63872692b..3d65b25d2 100644
--- a/crates/wasmtime/src/runtime/vm/sys/unix/machports.rs
+++ b/crates/wasmtime/src/runtime/vm/sys/unix/machports.rs
@@ -47,7 +47,8 @@ use mach2::port::*;
 use mach2::thread_act::*;
 use mach2::thread_status::*;
 use mach2::traps::*;
-use std::mem;
+use std::io;
+use std::mem::{self, MaybeUninit};
 use std::ptr::addr_of_mut;
 use std::thread;
 use wasmtime_environ::Trap;
@@ -61,6 +62,8 @@ pub struct TrapHandler {
     thread: Option<thread::JoinHandle<()>>,
 }
 
+static mut PREV_SIGBUS: MaybeUninit<libc::sigaction> = MaybeUninit::uninit();
+
 impl TrapHandler {
     pub unsafe fn new() -> TrapHandler {
         // Mach ports do not currently work across forks, so configure Wasmtime to
@@ -86,6 +89,21 @@ impl TrapHandler {
         // we're not very interested in so it's detached here.
         let thread = thread::spawn(|| handler_thread());
 
+        // Setup a SIGBUS handler which is used for printing that the stack was
+        // overflowed when a host overflows its fiber stack.
+        unsafe {
+            let mut handler: libc::sigaction = mem::zeroed();
+            handler.sa_flags = libc::SA_SIGINFO | libc::SA_ONSTACK;
+            handler.sa_sigaction = sigbus_handler as usize;
+            libc::sigemptyset(&mut handler.sa_mask);
+            if libc::sigaction(libc::SIGBUS, &handler, PREV_SIGBUS.as_mut_ptr()) != 0 {
+                panic!(
+                    "unable to install signal handler: {}",
+                    io::Error::last_os_error(),
+                );
+            }
+        }
+
         TrapHandler {
             thread: Some(thread),
         }
@@ -102,6 +120,35 @@ impl Drop for TrapHandler {
     }
 }
 
+unsafe extern "C" fn sigbus_handler(
+    signum: libc::c_int,
+    siginfo: *mut libc::siginfo_t,
+    context: *mut libc::c_void,
+) {
+    // If this is a faulting address within the async guard range listed within
+    // our tls storage then print a helpful message about it and abort.
+    // Otherwise forward to the previous SIGBUS handler, if any.
+    tls::with(|info| {
+        let info = match info {
+            Some(info) => info,
+            None => return,
+        };
+        let faulting_addr = (*siginfo).si_addr() as usize;
+        let start = info.async_guard_range.start;
+        let end = info.async_guard_range.end;
+        if start as usize <= faulting_addr && faulting_addr < end as usize {
+            super::signals::abort_stack_overflow();
+        }
+    });
+
+    super::signals::delegate_signal_to_previous_handler(
+        PREV_SIGBUS.as_ptr(),
+        signum,
+        siginfo,
+        context,
+    )
+}
+
 // Note that this is copied from Gecko at
 //
 // https://searchfox.org/mozilla-central/rev/ed93119be4818da1509bbcb7b28e245853eeedd5/js/src/wasm/WasmSignalHandlers.cpp#583-601
diff --git a/crates/wasmtime/src/runtime/vm/sys/unix/signals.rs b/crates/wasmtime/src/runtime/vm/sys/unix/signals.rs
index 0736c52e0..5198d6b05 100644
--- a/crates/wasmtime/src/runtime/vm/sys/unix/signals.rs
+++ b/crates/wasmtime/src/runtime/vm/sys/unix/signals.rs
@@ -180,7 +180,16 @@ unsafe extern "C" fn trap_handler(
         // exception was handled by a custom exception handler, so we
         // keep executing.
         let jmp_buf = match test {
-            TrapTest::NotWasm => return false,
+            TrapTest::NotWasm => {
+                if let Some(faulting_addr) = faulting_addr {
+                    let start = info.async_guard_range.start;
+                    let end = info.async_guard_range.end;
+                    if start as usize <= faulting_addr && faulting_addr < end as usize {
+                        abort_stack_overflow();
+                    }
+                }
+                return false;
+            }
             TrapTest::HandledByEmbedder => return true,
             TrapTest::Trap { jmp_buf } => jmp_buf,
         };
@@ -227,6 +236,15 @@ unsafe extern "C" fn trap_handler(
         return;
     }
 
+    delegate_signal_to_previous_handler(previous, signum, siginfo, context)
+}
+
+pub unsafe fn delegate_signal_to_previous_handler(
+    previous: *const libc::sigaction,
+    signum: libc::c_int,
+    siginfo: *mut libc::siginfo_t,
+    context: *mut libc::c_void,
+) {
     // This signal is not for any compiled wasm code we expect, so we
     // need to forward the signal to the next handler. If there is no
     // next handler (SIG_IGN or SIG_DFL), then it's time to crash. To do
@@ -248,6 +266,14 @@ unsafe extern "C" fn trap_handler(
     }
 }
 
+pub fn abort_stack_overflow() -> ! {
+    unsafe {
+        let msg = "execution on async fiber has overflowed its stack";
+        libc::write(libc::STDERR_FILENO, msg.as_ptr().cast(), msg.len());
+        libc::abort();
+    }
+}
+
 #[allow(clippy::cast_possible_truncation)] // too fiddly to handle and wouldn't
                                            // help much anyway
 unsafe fn get_trap_registers(cx: *mut libc::c_void, _signum: libc::c_int) -> TrapRegisters {
diff --git a/crates/wasmtime/src/runtime/vm/traphandlers.rs b/crates/wasmtime/src/runtime/vm/traphandlers.rs
index 087039bfe..0f405c03e 100644
--- a/crates/wasmtime/src/runtime/vm/traphandlers.rs
+++ b/crates/wasmtime/src/runtime/vm/traphandlers.rs
@@ -17,6 +17,7 @@ use crate::runtime::vm::{Instance, VMContext, VMRuntimeLimits};
 use crate::sync::RwLock;
 use core::cell::{Cell, UnsafeCell};
 use core::mem::MaybeUninit;
+use core::ops::Range;
 use core::ptr;
 
 pub use self::backtrace::Backtrace;
@@ -246,6 +247,7 @@ pub unsafe fn catch_traps<F>(
     signal_handler: Option<*const SignalHandler<'static>>,
     capture_backtrace: bool,
     capture_coredump: bool,
+    async_guard_range: Range<*mut u8>,
     caller: *mut VMContext,
     mut closure: F,
 ) -> Result<(), Box<Trap>>
@@ -254,15 +256,21 @@ where
 {
     let limits = Instance::from_vmctx(caller, |i| i.runtime_limits());
 
-    let result = CallThreadState::new(signal_handler, capture_backtrace, capture_coredump, *limits)
-        .with(|cx| {
-            traphandlers::wasmtime_setjmp(
-                cx.jmp_buf.as_ptr(),
-                call_closure::<F>,
-                &mut closure as *mut F as *mut u8,
-                caller,
-            )
-        });
+    let result = CallThreadState::new(
+        signal_handler,
+        capture_backtrace,
+        capture_coredump,
+        *limits,
+        async_guard_range,
+    )
+    .with(|cx| {
+        traphandlers::wasmtime_setjmp(
+            cx.jmp_buf.as_ptr(),
+            call_closure::<F>,
+            &mut closure as *mut F as *mut u8,
+            caller,
+        )
+    });
 
     return match result {
         Ok(x) => Ok(x),
@@ -302,6 +310,8 @@ mod call_thread_state {
         pub(crate) limits: *const VMRuntimeLimits,
 
         pub(super) prev: Cell<tls::Ptr>,
+        #[cfg_attr(any(windows, miri), allow(dead_code))]
+        pub(crate) async_guard_range: Range<*mut u8>,
 
         // The values of `VMRuntimeLimits::last_wasm_{exit_{pc,fp},entry_sp}`
         // for the *previous* `CallThreadState` for this same store/limits. Our
@@ -333,6 +343,7 @@ mod call_thread_state {
             capture_backtrace: bool,
             capture_coredump: bool,
             limits: *const VMRuntimeLimits,
+            async_guard_range: Range<*mut u8>,
         ) -> CallThreadState {
             let _ = capture_coredump;
 
@@ -344,6 +355,7 @@ mod call_thread_state {
                 #[cfg(feature = "coredump")]
                 capture_coredump,
                 limits,
+                async_guard_range,
                 prev: Cell::new(ptr::null()),
                 old_last_wasm_exit_fp: Cell::new(unsafe { *(*limits).last_wasm_exit_fp.get() }),
                 old_last_wasm_exit_pc: Cell::new(unsafe { *(*limits).last_wasm_exit_pc.get() }),
diff --git a/crates/wit-bindgen/src/lib.rs b/crates/wit-bindgen/src/lib.rs
index 8cd6d5143..31b450875 100644
--- a/crates/wit-bindgen/src/lib.rs
+++ b/crates/wit-bindgen/src/lib.rs
@@ -2606,7 +2606,7 @@ impl<'a> InterfaceGenerator<'a> {
             FunctionKind::Freestanding => match owner {
                 TypeOwner::World(id) => format!(
                     "{}Imports",
-                    self.resolve.worlds[id].name.to_upper_camel_case()
+                    rust::to_rust_upper_camel_case(&self.resolve.worlds[id].name)
                 ),
                 _ => "Host".to_string(),
             },
diff --git a/src/bin/wasmtime.rs b/src/bin/wasmtime.rs
index fb64c0d76..ba3c1fb77 100644
--- a/src/bin/wasmtime.rs
+++ b/src/bin/wasmtime.rs
@@ -7,7 +7,7 @@ use anyhow::Result;
 use clap::Parser;
 
 /// Wasmtime WebAssembly Runtime
-#[derive(Parser, PartialEq)]
+#[derive(Parser)]
 #[command(
     name = "wasmtime",
     version = version(),
@@ -52,7 +52,7 @@ fn version() -> &'static str {
     option_env!("WASMTIME_VERSION_INFO").unwrap_or(env!("CARGO_PKG_VERSION"))
 }
 
-#[derive(Parser, PartialEq)]
+#[derive(Parser)]
 enum Subcommand {
     /// Runs a WebAssembly module
     #[cfg(feature = "run")]
@@ -81,6 +81,10 @@ enum Subcommand {
     /// Runs a WebAssembly test script file
     #[cfg(feature = "wast")]
     Wast(wasmtime_cli::commands::WastCommand),
+
+    /// Generate shell completions for the `wasmtime` CLI
+    #[cfg(feature = "completion")]
+    Completion(CompletionCommand),
 }
 
 impl Wasmtime {
@@ -112,10 +116,44 @@ impl Wasmtime {
 
             #[cfg(feature = "wast")]
             Subcommand::Wast(c) => c.execute(),
+
+            #[cfg(feature = "completion")]
+            Subcommand::Completion(c) => c.execute(),
         }
     }
 }
 
+/// Generate shell completion scripts for this CLI.
+///
+/// Shells have different paths for their completion scripts. Please refer to
+/// their documentation. For example, to generate completions for the fish
+/// shell, run the following command below:
+///
+///     wasmtime completion fish > ~/.config/fish/completions/wasmtime.fish
+///
+/// For a shell like zsh you can add this to your .zshrc or startup scripts:
+///
+///     eval "$(wasmtime completion zsh)"
+#[derive(Parser)]
+#[cfg(feature = "completion")]
+pub struct CompletionCommand {
+    /// The shell to generate completions for.
+    shell: clap_complete::Shell,
+}
+
+#[cfg(feature = "completion")]
+impl CompletionCommand {
+    pub fn execute(&self) -> Result<()> {
+        use clap::CommandFactory;
+
+        let mut cmd = Wasmtime::command();
+        let cli_name = cmd.get_name().to_owned();
+
+        clap_complete::generate(self.shell, &mut cmd, cli_name, &mut std::io::stdout());
+        Ok(())
+    }
+}
+
 fn main() -> Result<()> {
     return Wasmtime::parse().execute();
 }
diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml
index a44748957..b2cab043e 100644
--- a/supply-chain/audits.toml
+++ b/supply-chain/audits.toml
@@ -3814,6 +3814,12 @@ user-id = 6743 # Ed Page (epage)
 start = "2023-03-28"
 end = "2025-09-20"
 
+[[trusted.clap_complete]]
+criteria = "safe-to-deploy"
+user-id = 6743 # Ed Page (epage)
+start = "2021-12-31"
+end = "2025-09-25"
+
 [[trusted.clap_derive]]
 criteria = "safe-to-deploy"
 user-id = 6743 # Ed Page (epage)
diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock
index 8dc363bad..11d30ed2c 100644
--- a/supply-chain/imports.lock
+++ b/supply-chain/imports.lock
@@ -815,6 +815,13 @@ user-id = 6743
 user-login = "epage"
 user-name = "Ed Page"
 
+[[publisher.clap_complete]]
+version = "4.5.28"
+when = "2024-09-17"
+user-id = 6743
+user-login = "epage"
+user-name = "Ed Page"
+
 [[publisher.clap_derive]]
 version = "4.3.12"
 when = "2023-07-14"


Test patch:
diff --git a/crates/component-macro/tests/codegen/host-world.wit b/crates/component-macro/tests/codegen/host-world.wit
new file mode 100644
index 000000000..f2a7ca0ac
--- /dev/null
+++ b/crates/component-macro/tests/codegen/host-world.wit
@@ -0,0 +1,5 @@
+package foo:foo;
+
+world host {
+  import foo: func();
+}
\ No newline at end of file
diff --git a/crates/component-macro/tests/expanded/host-world.rs b/crates/component-macro/tests/expanded/host-world.rs
new file mode 100644
index 000000000..b5b514902
--- /dev/null
+++ b/crates/component-macro/tests/expanded/host-world.rs
@@ -0,0 +1,205 @@
+/// Auto-generated bindings for a pre-instantiated version of a
+/// component which implements the world `host`.
+///
+/// This structure is created through [`Host_Pre::new`] which
+/// takes a [`InstancePre`](wasmtime::component::InstancePre) that
+/// has been created through a [`Linker`](wasmtime::component::Linker).
+///
+/// For more information see [`Host_`] as well.
+pub struct Host_Pre<T> {
+    instance_pre: wasmtime::component::InstancePre<T>,
+    indices: Host_Indices,
+}
+impl<T> Clone for Host_Pre<T> {
+    fn clone(&self) -> Self {
+        Self {
+            instance_pre: self.instance_pre.clone(),
+            indices: self.indices.clone(),
+        }
+    }
+}
+impl<_T> Host_Pre<_T> {
+    /// Creates a new copy of `Host_Pre` bindings which can then
+    /// be used to instantiate into a particular store.
+    ///
+    /// This method may fail if the component behind `instance_pre`
+    /// does not have the required exports.
+    pub fn new(
+        instance_pre: wasmtime::component::InstancePre<_T>,
+    ) -> wasmtime::Result<Self> {
+        let indices = Host_Indices::new(instance_pre.component())?;
+        Ok(Self { instance_pre, indices })
+    }
+    pub fn engine(&self) -> &wasmtime::Engine {
+        self.instance_pre.engine()
+    }
+    pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> {
+        &self.instance_pre
+    }
+    /// Instantiates a new instance of [`Host_`] within the
+    /// `store` provided.
+    ///
+    /// This function will use `self` as the pre-instantiated
+    /// instance to perform instantiation. Afterwards the preloaded
+    /// indices in `self` are used to lookup all exports on the
+    /// resulting instance.
+    pub fn instantiate(
+        &self,
+        mut store: impl wasmtime::AsContextMut<Data = _T>,
+    ) -> wasmtime::Result<Host_> {
+        let mut store = store.as_context_mut();
+        let instance = self.instance_pre.instantiate(&mut store)?;
+        self.indices.load(&mut store, &instance)
+    }
+}
+/// Auto-generated bindings for index of the exports of
+/// `host`.
+///
+/// This is an implementation detail of [`Host_Pre`] and can
+/// be constructed if needed as well.
+///
+/// For more information see [`Host_`] as well.
+#[derive(Clone)]
+pub struct Host_Indices {}
+/// Auto-generated bindings for an instance a component which
+/// implements the world `host`.
+///
+/// This structure can be created through a number of means
+/// depending on your requirements and what you have on hand:
+///
+/// * The most convenient way is to use
+///   [`Host_::instantiate`] which only needs a
+///   [`Store`], [`Component`], and [`Linker`].
+///
+/// * Alternatively you can create a [`Host_Pre`] ahead of
+///   time with a [`Component`] to front-load string lookups
+///   of exports once instead of per-instantiation. This
+///   method then uses [`Host_Pre::instantiate`] to
+///   create a [`Host_`].
+///
+/// * If you've instantiated the instance yourself already
+///   then you can use [`Host_::new`].
+///
+/// * You can also access the guts of instantiation through
+///   [`Host_Indices::new_instance`] followed
+///   by [`Host_Indices::load`] to crate an instance of this
+///   type.
+///
+/// These methods are all equivalent to one another and move
+/// around the tradeoff of what work is performed when.
+///
+/// [`Store`]: wasmtime::Store
+/// [`Component`]: wasmtime::component::Component
+/// [`Linker`]: wasmtime::component::Linker
+pub struct Host_ {}
+pub trait Host_Imports {
+    fn foo(&mut self) -> ();
+}
+pub trait Host_ImportsGetHost<
+    T,
+>: Fn(T) -> <Self as Host_ImportsGetHost<T>>::Host + Send + Sync + Copy + 'static {
+    type Host: Host_Imports;
+}
+impl<F, T, O> Host_ImportsGetHost<T> for F
+where
+    F: Fn(T) -> O + Send + Sync + Copy + 'static,
+    O: Host_Imports,
+{
+    type Host = O;
+}
+impl<_T: Host_Imports + ?Sized> Host_Imports for &mut _T {
+    fn foo(&mut self) -> () {
+        Host_Imports::foo(*self)
+    }
+}
+const _: () = {
+    #[allow(unused_imports)]
+    use wasmtime::component::__internal::anyhow;
+    impl Host_Indices {
+        /// Creates a new copy of `Host_Indices` bindings which can then
+        /// be used to instantiate into a particular store.
+        ///
+        /// This method may fail if the component does not have the
+        /// required exports.
+        pub fn new(
+            component: &wasmtime::component::Component,
+        ) -> wasmtime::Result<Self> {
+            let _component = component;
+            Ok(Host_Indices {})
+        }
+        /// Creates a new instance of [`Host_Indices`] from an
+        /// instantiated component.
+        ///
+        /// This method of creating a [`Host_`] will perform string
+        /// lookups for all exports when this method is called. This
+        /// will only succeed if the provided instance matches the
+        /// requirements of [`Host_`].
+        pub fn new_instance(
+            mut store: impl wasmtime::AsContextMut,
+            instance: &wasmtime::component::Instance,
+        ) -> wasmtime::Result<Self> {
+            let _instance = instance;
+            Ok(Host_Indices {})
+        }
+        /// Uses the indices stored in `self` to load an instance
+        /// of [`Host_`] from the instance provided.
+        ///
+        /// Note that at this time this method will additionally
+        /// perform type-checks of all exports.
+        pub fn load(
+            &self,
+            mut store: impl wasmtime::AsContextMut,
+            instance: &wasmtime::component::Instance,
+        ) -> wasmtime::Result<Host_> {
+            let _instance = instance;
+            Ok(Host_ {})
+        }
+    }
+    impl Host_ {
+        /// Convenience wrapper around [`Host_Pre::new`] and
+        /// [`Host_Pre::instantiate`].
+        pub fn instantiate<_T>(
+            mut store: impl wasmtime::AsContextMut<Data = _T>,
+            component: &wasmtime::component::Component,
+            linker: &wasmtime::component::Linker<_T>,
+        ) -> wasmtime::Result<Host_> {
+            let pre = linker.instantiate_pre(component)?;
+            Host_Pre::new(pre)?.instantiate(store)
+        }
+        /// Convenience wrapper around [`Host_Indices::new_instance`] and
+        /// [`Host_Indices::load`].
+        pub fn new(
+            mut store: impl wasmtime::AsContextMut,
+            instance: &wasmtime::component::Instance,
+        ) -> wasmtime::Result<Host_> {
+            let indices = Host_Indices::new_instance(&mut store, instance)?;
+            indices.load(store, instance)
+        }
+        pub fn add_to_linker_imports_get_host<T>(
+            linker: &mut wasmtime::component::Linker<T>,
+            host_getter: impl for<'a> Host_ImportsGetHost<&'a mut T>,
+        ) -> wasmtime::Result<()> {
+            let mut linker = linker.root();
+            linker
+                .func_wrap(
+                    "foo",
+                    move |mut caller: wasmtime::StoreContextMut<'_, T>, (): ()| {
+                        let host = &mut host_getter(caller.data_mut());
+                        let r = Host_Imports::foo(host);
+                        Ok(r)
+                    },
+                )?;
+            Ok(())
+        }
+        pub fn add_to_linker<T, U>(
+            linker: &mut wasmtime::component::Linker<T>,
+            get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static,
+        ) -> wasmtime::Result<()>
+        where
+            U: Host_Imports,
+        {
+            Self::add_to_linker_imports_get_host(linker, get)?;
+            Ok(())
+        }
+    }
+};
diff --git a/crates/component-macro/tests/expanded/host-world_async.rs b/crates/component-macro/tests/expanded/host-world_async.rs
new file mode 100644
index 000000000..79226375a
--- /dev/null
+++ b/crates/component-macro/tests/expanded/host-world_async.rs
@@ -0,0 +1,219 @@
+/// Auto-generated bindings for a pre-instantiated version of a
+/// component which implements the world `host`.
+///
+/// This structure is created through [`Host_Pre::new`] which
+/// takes a [`InstancePre`](wasmtime::component::InstancePre) that
+/// has been created through a [`Linker`](wasmtime::component::Linker).
+///
+/// For more information see [`Host_`] as well.
+pub struct Host_Pre<T> {
+    instance_pre: wasmtime::component::InstancePre<T>,
+    indices: Host_Indices,
+}
+impl<T> Clone for Host_Pre<T> {
+    fn clone(&self) -> Self {
+        Self {
+            instance_pre: self.instance_pre.clone(),
+            indices: self.indices.clone(),
+        }
+    }
+}
+impl<_T> Host_Pre<_T> {
+    /// Creates a new copy of `Host_Pre` bindings which can then
+    /// be used to instantiate into a particular store.
+    ///
+    /// This method may fail if the component behind `instance_pre`
+    /// does not have the required exports.
+    pub fn new(
+        instance_pre: wasmtime::component::InstancePre<_T>,
+    ) -> wasmtime::Result<Self> {
+        let indices = Host_Indices::new(instance_pre.component())?;
+        Ok(Self { instance_pre, indices })
+    }
+    pub fn engine(&self) -> &wasmtime::Engine {
+        self.instance_pre.engine()
+    }
+    pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> {
+        &self.instance_pre
+    }
+    /// Instantiates a new instance of [`Host_`] within the
+    /// `store` provided.
+    ///
+    /// This function will use `self` as the pre-instantiated
+    /// instance to perform instantiation. Afterwards the preloaded
+    /// indices in `self` are used to lookup all exports on the
+    /// resulting instance.
+    pub async fn instantiate_async(
+        &self,
+        mut store: impl wasmtime::AsContextMut<Data = _T>,
+    ) -> wasmtime::Result<Host_>
+    where
+        _T: Send,
+    {
+        let mut store = store.as_context_mut();
+        let instance = self.instance_pre.instantiate_async(&mut store).await?;
+        self.indices.load(&mut store, &instance)
+    }
+}
+/// Auto-generated bindings for index of the exports of
+/// `host`.
+///
+/// This is an implementation detail of [`Host_Pre`] and can
+/// be constructed if needed as well.
+///
+/// For more information see [`Host_`] as well.
+#[derive(Clone)]
+pub struct Host_Indices {}
+/// Auto-generated bindings for an instance a component which
+/// implements the world `host`.
+///
+/// This structure can be created through a number of means
+/// depending on your requirements and what you have on hand:
+///
+/// * The most convenient way is to use
+///   [`Host_::instantiate_async`] which only needs a
+///   [`Store`], [`Component`], and [`Linker`].
+///
+/// * Alternatively you can create a [`Host_Pre`] ahead of
+///   time with a [`Component`] to front-load string lookups
+///   of exports once instead of per-instantiation. This
+///   method then uses [`Host_Pre::instantiate_async`] to
+///   create a [`Host_`].
+///
+/// * If you've instantiated the instance yourself already
+///   then you can use [`Host_::new`].
+///
+/// * You can also access the guts of instantiation through
+///   [`Host_Indices::new_instance`] followed
+///   by [`Host_Indices::load`] to crate an instance of this
+///   type.
+///
+/// These methods are all equivalent to one another and move
+/// around the tradeoff of what work is performed when.
+///
+/// [`Store`]: wasmtime::Store
+/// [`Component`]: wasmtime::component::Component
+/// [`Linker`]: wasmtime::component::Linker
+pub struct Host_ {}
+#[wasmtime::component::__internal::async_trait]
+pub trait Host_Imports: Send {
+    async fn foo(&mut self) -> ();
+}
+pub trait Host_ImportsGetHost<
+    T,
+>: Fn(T) -> <Self as Host_ImportsGetHost<T>>::Host + Send + Sync + Copy + 'static {
+    type Host: Host_Imports;
+}
+impl<F, T, O> Host_ImportsGetHost<T> for F
+where
+    F: Fn(T) -> O + Send + Sync + Copy + 'static,
+    O: Host_Imports,
+{
+    type Host = O;
+}
+#[wasmtime::component::__internal::async_trait]
+impl<_T: Host_Imports + ?Sized + Send> Host_Imports for &mut _T {
+    async fn foo(&mut self) -> () {
+        Host_Imports::foo(*self).await
+    }
+}
+const _: () = {
+    #[allow(unused_imports)]
+    use wasmtime::component::__internal::anyhow;
+    impl Host_Indices {
+        /// Creates a new copy of `Host_Indices` bindings which can then
+        /// be used to instantiate into a particular store.
+        ///
+        /// This method may fail if the component does not have the
+        /// required exports.
+        pub fn new(
+            component: &wasmtime::component::Component,
+        ) -> wasmtime::Result<Self> {
+            let _component = component;
+            Ok(Host_Indices {})
+        }
+        /// Creates a new instance of [`Host_Indices`] from an
+        /// instantiated component.
+        ///
+        /// This method of creating a [`Host_`] will perform string
+        /// lookups for all exports when this method is called. This
+        /// will only succeed if the provided instance matches the
+        /// requirements of [`Host_`].
+        pub fn new_instance(
+            mut store: impl wasmtime::AsContextMut,
+            instance: &wasmtime::component::Instance,
+        ) -> wasmtime::Result<Self> {
+            let _instance = instance;
+            Ok(Host_Indices {})
+        }
+        /// Uses the indices stored in `self` to load an instance
+        /// of [`Host_`] from the instance provided.
+        ///
+        /// Note that at this time this method will additionally
+        /// perform type-checks of all exports.
+        pub fn load(
+            &self,
+            mut store: impl wasmtime::AsContextMut,
+            instance: &wasmtime::component::Instance,
+        ) -> wasmtime::Result<Host_> {
+            let _instance = instance;
+            Ok(Host_ {})
+        }
+    }
+    impl Host_ {
+        /// Convenience wrapper around [`Host_Pre::new`] and
+        /// [`Host_Pre::instantiate_async`].
+        pub async fn instantiate_async<_T>(
+            mut store: impl wasmtime::AsContextMut<Data = _T>,
+            component: &wasmtime::component::Component,
+            linker: &wasmtime::component::Linker<_T>,
+        ) -> wasmtime::Result<Host_>
+        where
+            _T: Send,
+        {
+            let pre = linker.instantiate_pre(component)?;
+            Host_Pre::new(pre)?.instantiate_async(store).await
+        }
+        /// Convenience wrapper around [`Host_Indices::new_instance`] and
+        /// [`Host_Indices::load`].
+        pub fn new(
+            mut store: impl wasmtime::AsContextMut,
+            instance: &wasmtime::component::Instance,
+        ) -> wasmtime::Result<Host_> {
+            let indices = Host_Indices::new_instance(&mut store, instance)?;
+            indices.load(store, instance)
+        }
+        pub fn add_to_linker_imports_get_host<T>(
+            linker: &mut wasmtime::component::Linker<T>,
+            host_getter: impl for<'a> Host_ImportsGetHost<&'a mut T>,
+        ) -> wasmtime::Result<()>
+        where
+            T: Send,
+        {
+            let mut linker = linker.root();
+            linker
+                .func_wrap_async(
+                    "foo",
+                    move |mut caller: wasmtime::StoreContextMut<'_, T>, (): ()| {
+                        wasmtime::component::__internal::Box::new(async move {
+                            let host = &mut host_getter(caller.data_mut());
+                            let r = Host_Imports::foo(host).await;
+                            Ok(r)
+                        })
+                    },
+                )?;
+            Ok(())
+        }
+        pub fn add_to_linker<T, U>(
+            linker: &mut wasmtime::component::Linker<T>,
+            get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static,
+        ) -> wasmtime::Result<()>
+        where
+            T: Send,
+            U: Host_Imports + Send,
+        {
+            Self::add_to_linker_imports_get_host(linker, get)?;
+            Ok(())
+        }
+    }
+};
diff --git a/crates/component-macro/tests/expanded/host-world_tracing_async.rs b/crates/component-macro/tests/expanded/host-world_tracing_async.rs
new file mode 100644
index 000000000..9ded0ccb6
--- /dev/null
+++ b/crates/component-macro/tests/expanded/host-world_tracing_async.rs
@@ -0,0 +1,232 @@
+/// Auto-generated bindings for a pre-instantiated version of a
+/// component which implements the world `host`.
+///
+/// This structure is created through [`Host_Pre::new`] which
+/// takes a [`InstancePre`](wasmtime::component::InstancePre) that
+/// has been created through a [`Linker`](wasmtime::component::Linker).
+///
+/// For more information see [`Host_`] as well.
+pub struct Host_Pre<T> {
+    instance_pre: wasmtime::component::InstancePre<T>,
+    indices: Host_Indices,
+}
+impl<T> Clone for Host_Pre<T> {
+    fn clone(&self) -> Self {
+        Self {
+            instance_pre: self.instance_pre.clone(),
+            indices: self.indices.clone(),
+        }
+    }
+}
+impl<_T> Host_Pre<_T> {
+    /// Creates a new copy of `Host_Pre` bindings which can then
+    /// be used to instantiate into a particular store.
+    ///
+    /// This method may fail if the component behind `instance_pre`
+    /// does not have the required exports.
+    pub fn new(
+        instance_pre: wasmtime::component::InstancePre<_T>,
+    ) -> wasmtime::Result<Self> {
+        let indices = Host_Indices::new(instance_pre.component())?;
+        Ok(Self { instance_pre, indices })
+    }
+    pub fn engine(&self) -> &wasmtime::Engine {
+        self.instance_pre.engine()
+    }
+    pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> {
+        &self.instance_pre
+    }
+    /// Instantiates a new instance of [`Host_`] within the
+    /// `store` provided.
+    ///
+    /// This function will use `self` as the pre-instantiated
+    /// instance to perform instantiation. Afterwards the preloaded
+    /// indices in `self` are used to lookup all exports on the
+    /// resulting instance.
+    pub async fn instantiate_async(
+        &self,
+        mut store: impl wasmtime::AsContextMut<Data = _T>,
+    ) -> wasmtime::Result<Host_>
+    where
+        _T: Send,
+    {
+        let mut store = store.as_context_mut();
+        let instance = self.instance_pre.instantiate_async(&mut store).await?;
+        self.indices.load(&mut store, &instance)
+    }
+}
+/// Auto-generated bindings for index of the exports of
+/// `host`.
+///
+/// This is an implementation detail of [`Host_Pre`] and can
+/// be constructed if needed as well.
+///
+/// For more information see [`Host_`] as well.
+#[derive(Clone)]
+pub struct Host_Indices {}
+/// Auto-generated bindings for an instance a component which
+/// implements the world `host`.
+///
+/// This structure can be created through a number of means
+/// depending on your requirements and what you have on hand:
+///
+/// * The most convenient way is to use
+///   [`Host_::instantiate_async`] which only needs a
+///   [`Store`], [`Component`], and [`Linker`].
+///
+/// * Alternatively you can create a [`Host_Pre`] ahead of
+///   time with a [`Component`] to front-load string lookups
+///   of exports once instead of per-instantiation. This
+///   method then uses [`Host_Pre::instantiate_async`] to
+///   create a [`Host_`].
+///
+/// * If you've instantiated the instance yourself already
+///   then you can use [`Host_::new`].
+///
+/// * You can also access the guts of instantiation through
+///   [`Host_Indices::new_instance`] followed
+///   by [`Host_Indices::load`] to crate an instance of this
+///   type.
+///
+/// These methods are all equivalent to one another and move
+/// around the tradeoff of what work is performed when.
+///
+/// [`Store`]: wasmtime::Store
+/// [`Component`]: wasmtime::component::Component
+/// [`Linker`]: wasmtime::component::Linker
+pub struct Host_ {}
+#[wasmtime::component::__internal::async_trait]
+pub trait Host_Imports: Send {
+    async fn foo(&mut self) -> ();
+}
+pub trait Host_ImportsGetHost<
+    T,
+>: Fn(T) -> <Self as Host_ImportsGetHost<T>>::Host + Send + Sync + Copy + 'static {
+    type Host: Host_Imports;
+}
+impl<F, T, O> Host_ImportsGetHost<T> for F
+where
+    F: Fn(T) -> O + Send + Sync + Copy + 'static,
+    O: Host_Imports,
+{
+    type Host = O;
+}
+#[wasmtime::component::__internal::async_trait]
+impl<_T: Host_Imports + ?Sized + Send> Host_Imports for &mut _T {
+    async fn foo(&mut self) -> () {
+        Host_Imports::foo(*self).await
+    }
+}
+const _: () = {
+    #[allow(unused_imports)]
+    use wasmtime::component::__internal::anyhow;
+    impl Host_Indices {
+        /// Creates a new copy of `Host_Indices` bindings which can then
+        /// be used to instantiate into a particular store.
+        ///
+        /// This method may fail if the component does not have the
+        /// required exports.
+        pub fn new(
+            component: &wasmtime::component::Component,
+        ) -> wasmtime::Result<Self> {
+            let _component = component;
+            Ok(Host_Indices {})
+        }
+        /// Creates a new instance of [`Host_Indices`] from an
+        /// instantiated component.
+        ///
+        /// This method of creating a [`Host_`] will perform string
+        /// lookups for all exports when this method is called. This
+        /// will only succeed if the provided instance matches the
+        /// requirements of [`Host_`].
+        pub fn new_instance(
+            mut store: impl wasmtime::AsContextMut,
+            instance: &wasmtime::component::Instance,
+        ) -> wasmtime::Result<Self> {
+            let _instance = instance;
+            Ok(Host_Indices {})
+        }
+        /// Uses the indices stored in `self` to load an instance
+        /// of [`Host_`] from the instance provided.
+        ///
+        /// Note that at this time this method will additionally
+        /// perform type-checks of all exports.
+        pub fn load(
+            &self,
+            mut store: impl wasmtime::AsContextMut,
+            instance: &wasmtime::component::Instance,
+        ) -> wasmtime::Result<Host_> {
+            let _instance = instance;
+            Ok(Host_ {})
+        }
+    }
+    impl Host_ {
+        /// Convenience wrapper around [`Host_Pre::new`] and
+        /// [`Host_Pre::instantiate_async`].
+        pub async fn instantiate_async<_T>(
+            mut store: impl wasmtime::AsContextMut<Data = _T>,
+            component: &wasmtime::component::Component,
+            linker: &wasmtime::component::Linker<_T>,
+        ) -> wasmtime::Result<Host_>
+        where
+            _T: Send,
+        {
+            let pre = linker.instantiate_pre(component)?;
+            Host_Pre::new(pre)?.instantiate_async(store).await
+        }
+        /// Convenience wrapper around [`Host_Indices::new_instance`] and
+        /// [`Host_Indices::load`].
+        pub fn new(
+            mut store: impl wasmtime::AsContextMut,
+            instance: &wasmtime::component::Instance,
+        ) -> wasmtime::Result<Host_> {
+            let indices = Host_Indices::new_instance(&mut store, instance)?;
+            indices.load(store, instance)
+        }
+        pub fn add_to_linker_imports_get_host<T>(
+            linker: &mut wasmtime::component::Linker<T>,
+            host_getter: impl for<'a> Host_ImportsGetHost<&'a mut T>,
+        ) -> wasmtime::Result<()>
+        where
+            T: Send,
+        {
+            let mut linker = linker.root();
+            linker
+                .func_wrap_async(
+                    "foo",
+                    move |mut caller: wasmtime::StoreContextMut<'_, T>, (): ()| {
+                        use tracing::Instrument;
+                        let span = tracing::span!(
+                            tracing::Level::TRACE, "wit-bindgen import", module = "host",
+                            function = "foo",
+                        );
+                        wasmtime::component::__internal::Box::new(
+                            async move {
+                                tracing::event!(tracing::Level::TRACE, "call");
+                                let host = &mut host_getter(caller.data_mut());
+                                let r = Host_Imports::foo(host).await;
+                                tracing::event!(
+                                    tracing::Level::TRACE, result = tracing::field::debug(& r),
+                                    "return"
+                                );
+                                Ok(r)
+                            }
+                                .instrument(span),
+                        )
+                    },
+                )?;
+            Ok(())
+        }
+        pub fn add_to_linker<T, U>(
+            linker: &mut wasmtime::component::Linker<T>,
+            get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static,
+        ) -> wasmtime::Result<()>
+        where
+            T: Send,
+            U: Host_Imports + Send,
+        {
+            Self::add_to_linker_imports_get_host(linker, get)?;
+            Ok(())
+        }
+    }
+};
diff --git a/tests/all/stack_creator.rs b/tests/all/stack_creator.rs
index 9545908d1..e05629aee 100644
--- a/tests/all/stack_creator.rs
+++ b/tests/all/stack_creator.rs
@@ -31,6 +31,9 @@ unsafe impl StackMemory for CustomStack {
         let base = self.base.as_ptr() as usize;
         base..base + self.len
     }
+    fn guard_range(&self) -> Range<*mut u8> {
+        std::ptr::null_mut()..std::ptr::null_mut()
+    }
 }
 
 // A creator that allocates stacks on the heap instead of mmap'ing.
diff --git a/tests/disas/gc/struct-get.wat b/tests/disas/gc/struct-get.wat
index 8d6b914af..b3cec94bb 100644
--- a/tests/disas/gc/struct-get.wat
+++ b/tests/disas/gc/struct-get.wat
@@ -42,7 +42,7 @@
 ;; @0033                               trapz v12, user65535
 ;; @0033                               v5 = load.i64 notrap aligned readonly v0+40
 ;; @0033                               v13 = iadd v5, v9
-;; @0033                               v14 = load.f32 notrap aligned v13
+;; @0033                               v14 = load.f32 notrap aligned little v13
 ;; @0037                               jump block1
 ;;
 ;;                                 block1:
@@ -68,7 +68,7 @@
 ;; @003c                               trapz v12, user65535
 ;; @003c                               v5 = load.i64 notrap aligned readonly v0+40
 ;; @003c                               v13 = iadd v5, v9
-;; @003c                               v14 = load.i8 notrap aligned v13
+;; @003c                               v14 = load.i8 notrap aligned little v13
 ;; @0040                               jump block1
 ;;
 ;;                                 block1:
@@ -95,7 +95,7 @@
 ;; @0045                               trapz v12, user65535
 ;; @0045                               v5 = load.i64 notrap aligned readonly v0+40
 ;; @0045                               v13 = iadd v5, v9
-;; @0045                               v14 = load.i8 notrap aligned v13
+;; @0045                               v14 = load.i8 notrap aligned little v13
 ;; @0049                               jump block1
 ;;
 ;;                                 block1:
@@ -125,7 +125,7 @@
 ;; @004e                               trapz v12, user65535
 ;; @004e                               v5 = load.i64 notrap aligned readonly v0+40
 ;; @004e                               v13 = iadd v5, v9
-;; @004e                               v14 = load.i32 notrap aligned v13
+;; @004e                               v14 = load.i32 notrap aligned little v13
 ;;                                     v54 = stack_addr.i64 ss0
 ;;                                     store notrap v14, v54
 ;; @004e                               v15 = iconst.i32 -2
diff --git a/tests/disas/gc/struct-new-default.wat b/tests/disas/gc/struct-new-default.wat
index 55b72eb12..5cc41c1a0 100644
--- a/tests/disas/gc/struct-new-default.wat
+++ b/tests/disas/gc/struct-new-default.wat
@@ -37,7 +37,7 @@
 ;; @0021                               v3 = f32const 0.0
 ;; @0021                               v13 = load.i64 notrap aligned readonly v0+40
 ;; @0021                               v21 = iadd v13, v17
-;; @0021                               store notrap aligned v3, v21  ; v3 = 0.0
+;; @0021                               store notrap aligned little v3, v21  ; v3 = 0.0
 ;; @0021                               v26 = iconst.i64 20
 ;; @0021                               v27 = uadd_overflow_trap v15, v26, user65535  ; v26 = 20
 ;; @0021                               v28 = iconst.i64 1
@@ -45,7 +45,7 @@
 ;; @0021                               v30 = icmp ult v29, v14
 ;; @0021                               trapz v30, user65535
 ;; @0021                               v31 = iadd v13, v27
-;; @0021                               istore8 notrap aligned v4, v31  ; v4 = 0
+;; @0021                               istore8 notrap aligned little v4, v31  ; v4 = 0
 ;; @0021                               v36 = iconst.i64 24
 ;; @0021                               v37 = uadd_overflow_trap v15, v36, user65535  ; v36 = 24
 ;; @0021                               v39 = uadd_overflow_trap v37, v18, user65535  ; v18 = 4
@@ -72,7 +72,7 @@
 ;;                                 block3:
 ;;                                     v85 = iconst.i32 0
 ;; @0021                               v41 = iadd.i64 v13, v37
-;; @0021                               store notrap aligned v85, v41  ; v85 = 0
+;; @0021                               store notrap aligned little v85, v41  ; v85 = 0
 ;; @0024                               jump block1
 ;;
 ;;                                 block1:
diff --git a/tests/disas/gc/struct-new.wat b/tests/disas/gc/struct-new.wat
index f592504fb..42ed90e78 100644
--- a/tests/disas/gc/struct-new.wat
+++ b/tests/disas/gc/struct-new.wat
@@ -39,7 +39,7 @@
 ;; @002a                               trapz v20, user65535
 ;; @002a                               v13 = load.i64 notrap aligned readonly v0+40
 ;; @002a                               v21 = iadd v13, v17
-;; @002a                               store notrap aligned v2, v21
+;; @002a                               store notrap aligned little v2, v21
 ;; @002a                               v26 = iconst.i64 20
 ;; @002a                               v27 = uadd_overflow_trap v15, v26, user65535  ; v26 = 20
 ;; @002a                               v28 = iconst.i64 1
@@ -47,7 +47,7 @@
 ;; @002a                               v30 = icmp ult v29, v14
 ;; @002a                               trapz v30, user65535
 ;; @002a                               v31 = iadd v13, v27
-;; @002a                               istore8 notrap aligned v3, v31
+;; @002a                               istore8 notrap aligned little v3, v31
 ;; @002a                               v36 = iconst.i64 24
 ;; @002a                               v37 = uadd_overflow_trap v15, v36, user65535  ; v36 = 24
 ;; @002a                               v39 = uadd_overflow_trap v37, v18, user65535  ; v18 = 4
@@ -83,7 +83,7 @@
 ;;                                 block3:
 ;;                                     v67 = load.i32 notrap v71
 ;; @002a                               v41 = iadd.i64 v13, v37
-;; @002a                               store notrap aligned v67, v41
+;; @002a                               store notrap aligned little v67, v41
 ;; @002d                               jump block1
 ;;
 ;;                                 block1:
diff --git a/tests/disas/gc/struct-set.wat b/tests/disas/gc/struct-set.wat
index d31f014ec..9252db68b 100644
--- a/tests/disas/gc/struct-set.wat
+++ b/tests/disas/gc/struct-set.wat
@@ -38,7 +38,7 @@
 ;; @0034                               trapz v12, user65535
 ;; @0034                               v5 = load.i64 notrap aligned readonly v0+40
 ;; @0034                               v13 = iadd v5, v9
-;; @0034                               store notrap aligned v3, v13
+;; @0034                               store notrap aligned little v3, v13
 ;; @0038                               jump block1
 ;;
 ;;                                 block1:
@@ -64,7 +64,7 @@
 ;; @003f                               trapz v12, user65535
 ;; @003f                               v5 = load.i64 notrap aligned readonly v0+40
 ;; @003f                               v13 = iadd v5, v9
-;; @003f                               istore8 notrap aligned v3, v13
+;; @003f                               istore8 notrap aligned little v3, v13
 ;; @0043                               jump block1
 ;;
 ;;                                 block1:
@@ -92,7 +92,7 @@
 ;; @004a                               trapz v12, user65535
 ;; @004a                               v5 = load.i64 notrap aligned readonly v0+40
 ;; @004a                               v13 = iadd v5, v9
-;; @004a                               v14 = load.i32 notrap aligned v13
+;; @004a                               v14 = load.i32 notrap aligned little v13
 ;; @004a                               v15 = iconst.i32 -2
 ;; @004a                               v16 = band v3, v15  ; v15 = -2
 ;;                                     v67 = iconst.i32 0
@@ -115,7 +115,7 @@
 ;; @004a                               jump block3
 ;;
 ;;                                 block3:
-;; @004a                               store.i32 notrap aligned v3, v13
+;; @004a                               store.i32 notrap aligned little v3, v13
 ;;                                     v72 = iconst.i32 -2
 ;;                                     v73 = band.i32 v14, v72  ; v72 = -2
 ;;                                     v74 = iconst.i32 0
diff --git a/tests/host_segfault.rs b/tests/host_segfault.rs
index 1880e1039..9ea913083 100644
--- a/tests/host_segfault.rs
+++ b/tests/host_segfault.rs
@@ -95,6 +95,23 @@ fn main() {
         return;
     }
 
+    // Disable core dumps on Unix to avoid spamming the system core dump utility
+    // and having this test take longer.
+    #[cfg(unix)]
+    unsafe {
+        let zero = libc::rlimit {
+            rlim_cur: 0,
+            rlim_max: 0,
+        };
+        let rc = libc::setrlimit(libc::RLIMIT_CORE, &zero);
+        assert_eq!(
+            rc,
+            0,
+            "failed to disable core dumps: {}",
+            std::io::Error::last_os_error()
+        );
+    }
+
     let tests: &[(&str, fn(), bool)] = &[
         ("normal segfault", || segfault(), false),
         (
@@ -263,12 +280,16 @@ fn is_segfault(status: &ExitStatus) -> bool {
 fn is_stack_overflow(status: &ExitStatus, stderr: &str) -> bool {
     use std::os::unix::prelude::*;
 
-    // The main thread might overflow or it might be from a fiber stack (SIGSEGV/SIGBUS)
+    // The exit status should always be SIGABRT, not SIGSEGV. Something, be it
+    // the standard library or Wasmtime, should catch the original SIGSEGV or
+    // SIGBUS and abort instead.
+    match status.signal() {
+        Some(libc::SIGABRT) => {}
+        _ => return false,
+    }
+
+    // A helpful message should additionally be printed at all times.
     stderr.contains("has overflowed its stack")
-        || match status.signal() {
-            Some(libc::SIGSEGV) | Some(libc::SIGBUS) => true,
-            _ => false,
-        }
 }
 
 #[cfg(windows)]