Repository: bytecodealliance/wasmtime
Pull request #9394 (2024-10-08 13:06:41)

docs(readme): mention wasmtime_home
This PR is very minor update to README:

- Mention `wasmtime_home` environment variable.

Reference: https://github.com/bytecodealliance/wasmtime.dev/blob/481a3aee5b86617b499274452dda34fe928fd7b0/install.sh#L548

Future PRs can elaborate further if needed but this PR is narrow scope.


Patch:
diff --git a/README.md b/README.md
index add5f9622..6cd36d83e 100644
--- a/README.md
+++ b/README.md
@@ -34,6 +34,7 @@ script:
 ```sh
 curl https://wasmtime.dev/install.sh -sSf | bash
 ```
+This script installs into `$WASMTIME_HOME` (defaults to `$HOME/.wasmtime`), and executable is placed in `$WASMTIME_HOME/bin`.
 
 Windows or otherwise interested users can download installers and
 binaries directly from the [GitHub
diff --git a/ci/vendor-wit.sh b/ci/vendor-wit.sh
index 55ffdf2a4..1e83d720b 100755
--- a/ci/vendor-wit.sh
+++ b/ci/vendor-wit.sh
@@ -37,22 +37,22 @@ make_vendor() {
 cache_dir=$(mktemp -d)
 
 make_vendor "wasi" "
-  cli@v0.2.1
-  clocks@v0.2.1
-  filesystem@v0.2.1
-  io@v0.2.1
-  random@v0.2.1
-  sockets@v0.2.1
+  cli@v0.2.2
+  clocks@v0.2.2
+  filesystem@v0.2.2
+  io@v0.2.2
+  random@v0.2.2
+  sockets@v0.2.2
 "
 
 make_vendor "wasi-http" "
-  cli@v0.2.1
-  clocks@v0.2.1
-  filesystem@v0.2.1
-  io@v0.2.1
-  random@v0.2.1
-  sockets@v0.2.1
-  http@v0.2.1
+  cli@v0.2.2
+  clocks@v0.2.2
+  filesystem@v0.2.2
+  io@v0.2.2
+  random@v0.2.2
+  sockets@v0.2.2
+  http@v0.2.2
 "
 
 make_vendor "wasi-runtime-config" "runtime-config@c667fe6"
diff --git a/cranelift/codegen/src/isa/s390x/inst.isle b/cranelift/codegen/src/isa/s390x/inst.isle
index 74022b0e5..451dda7a5 100644
--- a/cranelift/codegen/src/isa/s390x/inst.isle
+++ b/cranelift/codegen/src/isa/s390x/inst.isle
@@ -372,12 +372,6 @@
       (rd Reg)
       (mem MemArg))
 
-    ;; A memory copy of 1-256 bytes.
-    (Mvc
-      (dst MemArgPair)
-      (src MemArgPair)
-      (len_minus_one u8))
-
     ;; A load-multiple instruction.
     (LoadMultiple64
       (rt WritableReg)
@@ -1860,25 +1854,6 @@
       inst)
 
 
-;; Accessors for `MemArgPair`.
-
-(type MemArgPair extern (enum))
-
-;; Convert a MemArg to a MemArgPair, reloading the address if necessary.
-(decl memarg_pair (MemArg) MemArgPair)
-(rule 1 (memarg_pair (memarg_pair_from_memarg mem)) mem)
-(rule (memarg_pair mem) (memarg_pair_from_reg
-                          (load_addr mem) (memarg_flags mem)))
-
-;; Convert a MemArg to a MemArgPair if no reloading is necessary.
-(decl memarg_pair_from_memarg (MemArgPair) MemArg)
-(extern extractor memarg_pair_from_memarg memarg_pair_from_memarg)
-
-;; Create a MemArgPair from a single base register.
-(decl memarg_pair_from_reg (Reg MemFlags) MemArgPair)
-(extern constructor memarg_pair_from_reg memarg_pair_from_reg)
-
-
 ;; Helpers for stack-slot addresses ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (decl stack_addr_impl (Type StackSlot Offset32) Reg)
@@ -2320,11 +2295,6 @@
 (rule (storerev64 src addr)
       (SideEffectNoResult.Inst (MInst.StoreRev64 src addr)))
 
-;; Helper for emitting `MInst.Mvc` instructions.
-(decl mvc (MemArgPair MemArgPair u8) SideEffectNoResult)
-(rule (mvc dst src len_minus_one)
-      (SideEffectNoResult.Inst (MInst.Mvc dst src len_minus_one)))
-
 ;; Helper for emitting `MInst.LoadAR` instructions.
 (decl load_ar (u8) Reg)
 (rule (load_ar ar)
@@ -2916,14 +2886,6 @@
       (if-let $false (lane_order_equal callee_lane_order (lane_order)))
       (vec_elt_rev ty reg))
 
-;; Helpers to emit a memory copy (MVC or memcpy libcall).
-(decl memcpy (MemArg MemArg u64) SideEffectNoResult)
-(rule 1 (memcpy dst src (len_minus_one len))
-      (mvc (memarg_pair dst) (memarg_pair src) len))
-(rule (memcpy dst src len)
-      (lib_call
-        (lib_call_info_memcpy (load_addr dst) (load_addr src) (imm $I64 len))))
-
 ;; Prepare a stack copy of a single (oversized) argument.
 (decl copy_to_buffer (MemArg ABIArg Value) InstOutput)
 (rule 2 (copy_to_buffer base (abi_arg_only_slot slot) _) (output_none))
@@ -3604,18 +3566,6 @@
 (extern constructor abi_lane_order abi_lane_order)
 
 
-;; Helpers for generating calls to library routines ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-(type LibCallInfo extern (enum))
-
-(decl lib_call_info_memcpy (Reg Reg Reg) BoxCallInfo)
-(extern constructor lib_call_info_memcpy lib_call_info_memcpy)
-
-(decl lib_call (BoxCallInfo) SideEffectNoResult)
-(rule (lib_call info)
-      (call_impl (writable_link_reg) info))
-
-
 ;; Helpers for generating vector pack and unpack instructions ;;;;;;;;;;;;;;;;;;
 
 (decl vec_widen_type (Type) Type)
diff --git a/cranelift/codegen/src/isa/s390x/inst/args.rs b/cranelift/codegen/src/isa/s390x/inst/args.rs
index 0aa96bf58..5134f9bd3 100644
--- a/cranelift/codegen/src/isa/s390x/inst/args.rs
+++ b/cranelift/codegen/src/isa/s390x/inst/args.rs
@@ -124,53 +124,6 @@ impl MemArg {
     }
 }
 
-/// A memory argument for an instruction with two memory operands.
-/// We cannot use two instances of MemArg, because we do not have
-/// two free temp registers that would be needed to reload two
-/// addresses in the general case.  Also, two copies of MemArg would
-/// increase the size of Inst beyond its current limit.  Use this
-/// simplified form instead that never needs any reloads, and suffices
-/// for all current users.
-#[derive(Clone, Debug)]
-pub struct MemArgPair {
-    pub base: Reg,
-    pub disp: UImm12,
-    pub flags: MemFlags,
-}
-
-impl MemArgPair {
-    /// Convert a MemArg to a MemArgPair if possible.
-    pub fn maybe_from_memarg(mem: &MemArg) -> Option<MemArgPair> {
-        match mem {
-            &MemArg::BXD12 {
-                base,
-                index,
-                disp,
-                flags,
-            } => {
-                if index != zero_reg() {
-                    None
-                } else {
-                    Some(MemArgPair { base, disp, flags })
-                }
-            }
-            &MemArg::RegOffset { reg, off, flags } => {
-                if off < 0 {
-                    None
-                } else {
-                    let disp = UImm12::maybe_from_u64(off as u64)?;
-                    Some(MemArgPair {
-                        base: reg,
-                        disp,
-                        flags,
-                    })
-                }
-            }
-            _ => None,
-        }
-    }
-}
-
 //=============================================================================
 // Instruction sub-components (conditions, branches and branch targets):
 // definitions
diff --git a/cranelift/codegen/src/isa/s390x/inst/emit.rs b/cranelift/codegen/src/isa/s390x/inst/emit.rs
index acc63cad6..3947d1b09 100644
--- a/cranelift/codegen/src/isa/s390x/inst/emit.rs
+++ b/cranelift/codegen/src/isa/s390x/inst/emit.rs
@@ -368,34 +368,6 @@ pub fn mem_imm16_emit(
     }
 }
 
-pub fn mem_mem_emit(
-    dst: &MemArgPair,
-    src: &MemArgPair,
-    len_minus_one: u8,
-    opcode_ss: u8,
-    add_trap: bool,
-    sink: &mut MachBuffer<Inst>,
-    _state: &mut EmitState,
-) {
-    if add_trap {
-        if let Some(trap_code) = dst.flags.trap_code().or(src.flags.trap_code()) {
-            sink.add_trap(trap_code);
-        }
-    }
-
-    put(
-        sink,
-        &enc_ss_a(
-            opcode_ss,
-            dst.base,
-            dst.disp.bits(),
-            src.base,
-            src.disp.bits(),
-            len_minus_one,
-        ),
-    );
-}
-
 pub fn mem_vrx_emit(
     rd: Reg,
     mem: &MemArg,
@@ -963,31 +935,6 @@ fn enc_siy(opcode: u16, b1: Reg, d1: u32, i2: u8) -> [u8; 6] {
     enc
 }
 
-/// SSa-type instructions.
-///
-///   47     39 31 27 15 11
-///   opcode  l b1 d1 b2 d2
-///       40 32 28 16 12  0
-///
-///
-fn enc_ss_a(opcode: u8, b1: Reg, d1: u32, b2: Reg, d2: u32, l: u8) -> [u8; 6] {
-    let b1 = machreg_to_gpr(b1) & 0x0f;
-    let d1_lo = (d1 & 0xff) as u8;
-    let d1_hi = ((d1 >> 8) & 0x0f) as u8;
-    let b2 = machreg_to_gpr(b2) & 0x0f;
-    let d2_lo = (d2 & 0xff) as u8;
-    let d2_hi = ((d2 >> 8) & 0x0f) as u8;
-
-    let mut enc: [u8; 6] = [0; 6];
-    enc[0] = opcode;
-    enc[1] = l;
-    enc[2] = b1 << 4 | d1_hi;
-    enc[3] = d1_lo;
-    enc[4] = b2 << 4 | d2_hi;
-    enc[5] = d2_lo;
-    enc
-}
-
 /// VRIa-type instructions.
 ///
 ///   47      39 35 31 15 11  7
@@ -2185,16 +2132,6 @@ impl Inst {
                 };
                 mem_imm16_emit(imm, &mem, opcode, true, sink, emit_info, state);
             }
-            &Inst::Mvc {
-                ref dst,
-                ref src,
-                len_minus_one,
-            } => {
-                let dst = dst.clone();
-                let src = src.clone();
-                let opcode = 0xd2; // MVC
-                mem_mem_emit(&dst, &src, len_minus_one, opcode, true, sink, state);
-            }
 
             &Inst::LoadMultiple64 { rt, rt2, ref mem } => {
                 let mem = mem.clone();
@@ -2248,9 +2185,7 @@ impl Inst {
                 put(sink, &enc_rre(opcode, rd.to_reg(), rm));
             }
             &Inst::MovPReg { rd, rm } => {
-                let rm: Reg = rm.into();
-                debug_assert!([regs::gpr(0), regs::gpr(14), regs::gpr(15)].contains(&rm));
-                Inst::Mov64 { rd, rm }.emit(sink, emit_info, state);
+                Inst::Mov64 { rd, rm: rm.into() }.emit(sink, emit_info, state);
             }
             &Inst::Mov32 { rd, rm } => {
                 let opcode = 0x18; // LR
@@ -3258,8 +3193,6 @@ impl Inst {
                 state.nominal_sp_offset += size;
             }
             &Inst::Call { link, ref info } => {
-                debug_assert_eq!(link.to_reg(), gpr(14));
-
                 let opcode = 0xc05; // BRASL
 
                 // Add relocation for target function.  This has to be done *before*
@@ -3278,8 +3211,6 @@ impl Inst {
                 state.nominal_sp_offset -= info.callee_pop_size;
             }
             &Inst::CallInd { link, ref info } => {
-                debug_assert_eq!(link.to_reg(), gpr(14));
-
                 if let Some(s) = state.take_stack_map() {
                     let offset = sink.cur_offset() + 2;
                     sink.push_user_stack_map(state, offset, s);
@@ -3322,8 +3253,6 @@ impl Inst {
             &Inst::ElfTlsGetOffset {
                 ref symbol, link, ..
             } => {
-                debug_assert_eq!(link.to_reg(), gpr(14));
-
                 let opcode = 0xc05; // BRASL
 
                 // Add relocation for target function. This has to be done
@@ -3336,13 +3265,12 @@ impl Inst {
                     _ => unreachable!(),
                 }
 
-                put(sink, &enc_ril_b(opcode, gpr(14), 0));
+                put(sink, &enc_ril_b(opcode, link.to_reg(), 0));
                 sink.add_call_site();
             }
             &Inst::Args { .. } => {}
             &Inst::Rets { .. } => {}
             &Inst::Ret { link } => {
-                debug_assert_eq!(link, gpr(14));
                 let opcode = 0x07; // BCR
                 put(sink, &enc_rr(opcode, gpr(15), link));
             }
diff --git a/cranelift/codegen/src/isa/s390x/inst/mod.rs b/cranelift/codegen/src/isa/s390x/inst/mod.rs
index bccd0057b..9c3322143 100644
--- a/cranelift/codegen/src/isa/s390x/inst/mod.rs
+++ b/cranelift/codegen/src/isa/s390x/inst/mod.rs
@@ -148,7 +148,6 @@ impl Inst {
             | Inst::StoreRev16 { .. }
             | Inst::StoreRev32 { .. }
             | Inst::StoreRev64 { .. }
-            | Inst::Mvc { .. }
             | Inst::LoadMultiple64 { .. }
             | Inst::StoreMultiple64 { .. }
             | Inst::Mov32 { .. }
@@ -564,10 +563,6 @@ fn s390x_get_operands(inst: &mut Inst, collector: &mut DenyReuseVisitor<impl Ope
         | Inst::StoreImm64SExt16 { mem, .. } => {
             memarg_operands(mem, collector);
         }
-        Inst::Mvc { dst, src, .. } => {
-            collector.reg_use(&mut dst.base);
-            collector.reg_use(&mut src.base);
-        }
         Inst::LoadMultiple64 { rt, rt2, mem, .. } => {
             memarg_operands(mem, collector);
             let first_regnum = rt.to_reg().to_real_reg().unwrap().hw_enc();
@@ -589,9 +584,8 @@ fn s390x_get_operands(inst: &mut Inst, collector: &mut DenyReuseVisitor<impl Ope
             collector.reg_use(rm);
         }
         Inst::MovPReg { rd, rm } => {
-            debug_assert!([gpr_preg(0), gpr_preg(14), gpr_preg(15)].contains(rm));
-            debug_assert!(rd.to_reg().is_virtual());
             collector.reg_def(rd);
+            collector.reg_fixed_nonallocatable(*rm);
         }
         Inst::Mov32 { rd, rm } => {
             collector.reg_def(rd);
@@ -1937,22 +1931,6 @@ impl Inst {
 
                 format!("{mem_str}{op} {mem}, {imm}")
             }
-            &Inst::Mvc {
-                ref dst,
-                ref src,
-                len_minus_one,
-            } => {
-                let dst = dst.clone();
-                let src = src.clone();
-                format!(
-                    "mvc {}({},{}), {}({})",
-                    dst.disp.pretty_print_default(),
-                    len_minus_one,
-                    show_reg(dst.base),
-                    src.disp.pretty_print_default(),
-                    show_reg(src.base)
-                )
-            }
             &Inst::LoadMultiple64 { rt, rt2, ref mem } => {
                 let mem = mem.clone();
                 let (mem_str, mem) = mem_finalize_for_show(
@@ -3148,7 +3126,6 @@ impl Inst {
                 } else {
                     "".to_string()
                 };
-                debug_assert_eq!(link, gpr(14));
                 format!(
                     "brasl {}, {}{}",
                     show_reg(link),
@@ -3164,7 +3141,6 @@ impl Inst {
                 } else {
                     "".to_string()
                 };
-                debug_assert_eq!(link, gpr(14));
                 format!("basr {}, {}{}", show_reg(link), rn, callee_pop_size)
             }
             &Inst::ReturnCall { ref info } => {
@@ -3196,7 +3172,6 @@ impl Inst {
                     }
                     _ => unreachable!(),
                 };
-                debug_assert_eq!(link, gpr(14));
                 format!("brasl {}, {}", show_reg(link), dest)
             }
             &Inst::Args { ref args } => {
@@ -3218,7 +3193,6 @@ impl Inst {
                 s
             }
             &Inst::Ret { link } => {
-                debug_assert_eq!(link, gpr(14));
                 let link = show_reg(link);
                 format!("br {link}")
             }
diff --git a/cranelift/codegen/src/isa/s390x/lower/isle.rs b/cranelift/codegen/src/isa/s390x/lower/isle.rs
index 6fdb72aa9..c65aa9c21 100644
--- a/cranelift/codegen/src/isa/s390x/lower/isle.rs
+++ b/cranelift/codegen/src/isa/s390x/lower/isle.rs
@@ -7,8 +7,8 @@ use crate::ir::ExternalName;
 // Types that the generated ISLE code uses via `use super::*`.
 use crate::isa::s390x::abi::{S390xMachineDeps, REG_SAVE_AREA_SIZE};
 use crate::isa::s390x::inst::{
-    gpr, stack_reg, writable_gpr, zero_reg, Cond, Inst as MInst, LaneOrder, MemArg, MemArgPair,
-    RegPair, ReturnCallInfo, SymbolReloc, UImm12, UImm16Shifted, UImm32Shifted, WritableRegPair,
+    gpr, stack_reg, writable_gpr, zero_reg, Cond, Inst as MInst, LaneOrder, MemArg, RegPair,
+    ReturnCallInfo, SymbolReloc, UImm12, UImm16Shifted, UImm32Shifted, WritableRegPair,
 };
 use crate::isa::s390x::S390xBackend;
 use crate::machinst::isle::*;
@@ -16,8 +16,8 @@ use crate::machinst::{CallInfo, MachLabel, Reg};
 use crate::{
     ir::{
         condcodes::*, immediates::*, types::*, ArgumentExtension, ArgumentPurpose, AtomicRmwOp,
-        BlockCall, Endianness, Inst, InstructionData, KnownSymbol, LibCall, MemFlags, Opcode,
-        TrapCode, Value, ValueList,
+        BlockCall, Endianness, Inst, InstructionData, KnownSymbol, MemFlags, Opcode, TrapCode,
+        Value, ValueList,
     },
     isa::CallConv,
     machinst::abi::ABIMachineSpec,
@@ -309,47 +309,6 @@ impl generated_code::Context for IsleContext<'_, '_, MInst, S390xBackend> {
         })
     }
 
-    fn lib_call_info_memcpy(
-        &mut self,
-        dst: Reg,
-        src: Reg,
-        len: Reg,
-    ) -> Box<CallInfo<ExternalName>> {
-        let caller_conv = self.lower_ctx.abi().call_conv(self.lower_ctx.sigs());
-        let callee_conv = CallConv::for_libcall(&self.backend.flags, caller_conv);
-
-        // Clobbers are defined by the calling convention. We will remove return value regs later.
-        let clobbers = S390xMachineDeps::get_regs_clobbered_by_call(callee_conv);
-
-        // Libcalls only require the register save area.
-        self.lower_ctx
-            .abi_mut()
-            .accumulate_outgoing_args_size(REG_SAVE_AREA_SIZE);
-
-        Box::new(CallInfo {
-            dest: ExternalName::LibCall(LibCall::Memcpy),
-            uses: smallvec![
-                CallArgPair {
-                    vreg: dst,
-                    preg: gpr(2),
-                },
-                CallArgPair {
-                    vreg: src,
-                    preg: gpr(3),
-                },
-                CallArgPair {
-                    vreg: len,
-                    preg: gpr(4),
-                },
-            ],
-            defs: smallvec![],
-            clobbers,
-            caller_conv,
-            callee_conv,
-            callee_pop_size: 0,
-        })
-    }
-
     fn abi_for_elf_tls_get_offset(&mut self) {
         self.lower_ctx
             .abi_mut()
@@ -916,20 +875,6 @@ impl generated_code::Context for IsleContext<'_, '_, MInst, S390xBackend> {
         }
     }
 
-    #[inline]
-    fn memarg_pair_from_memarg(&mut self, mem: &MemArg) -> Option<MemArgPair> {
-        MemArgPair::maybe_from_memarg(mem)
-    }
-
-    #[inline]
-    fn memarg_pair_from_reg(&mut self, reg: Reg, flags: MemFlags) -> MemArgPair {
-        MemArgPair {
-            base: reg,
-            disp: UImm12::zero(),
-            flags,
-        }
-    }
-
     #[inline]
     fn memarg_frame_pointer_offset(&mut self) -> MemArg {
         // The frame pointer (back chain) is stored directly at SP.
diff --git a/crates/wasi-http/wit/deps/cli/command.wit b/crates/wasi-http/wit/deps/cli/command.wit
index dc064a3cd..cc7a352c2 100644
--- a/crates/wasi-http/wit/deps/cli/command.wit
+++ b/crates/wasi-http/wit/deps/cli/command.wit
@@ -1,4 +1,4 @@
-package wasi:cli@0.2.1;
+package wasi:cli@0.2.2;
 
 @since(version = 0.2.0)
 world command {
diff --git a/crates/wasi-http/wit/deps/cli/imports.wit b/crates/wasi-http/wit/deps/cli/imports.wit
index b8339d3b2..ebd7ba173 100644
--- a/crates/wasi-http/wit/deps/cli/imports.wit
+++ b/crates/wasi-http/wit/deps/cli/imports.wit
@@ -1,17 +1,17 @@
-package wasi:cli@0.2.1;
+package wasi:cli@0.2.2;
 
 @since(version = 0.2.0)
 world imports {
   @since(version = 0.2.0)
-  include wasi:clocks/imports@0.2.1;
+  include wasi:clocks/imports@0.2.2;
   @since(version = 0.2.0)
-  include wasi:filesystem/imports@0.2.1;
+  include wasi:filesystem/imports@0.2.2;
   @since(version = 0.2.0)
-  include wasi:sockets/imports@0.2.1;
+  include wasi:sockets/imports@0.2.2;
   @since(version = 0.2.0)
-  include wasi:random/imports@0.2.1;
+  include wasi:random/imports@0.2.2;
   @since(version = 0.2.0)
-  include wasi:io/imports@0.2.1;
+  include wasi:io/imports@0.2.2;
 
   @since(version = 0.2.0)
   import environment;
diff --git a/crates/wasi-http/wit/deps/cli/stdio.wit b/crates/wasi-http/wit/deps/cli/stdio.wit
index d1d26eb61..860313eea 100644
--- a/crates/wasi-http/wit/deps/cli/stdio.wit
+++ b/crates/wasi-http/wit/deps/cli/stdio.wit
@@ -1,7 +1,7 @@
 @since(version = 0.2.0)
 interface stdin {
   @since(version = 0.2.0)
-  use wasi:io/streams@0.2.1.{input-stream};
+  use wasi:io/streams@0.2.2.{input-stream};
 
   @since(version = 0.2.0)
   get-stdin: func() -> input-stream;
@@ -10,7 +10,7 @@ interface stdin {
 @since(version = 0.2.0)
 interface stdout {
   @since(version = 0.2.0)
-  use wasi:io/streams@0.2.1.{output-stream};
+  use wasi:io/streams@0.2.2.{output-stream};
 
   @since(version = 0.2.0)
   get-stdout: func() -> output-stream;
@@ -19,7 +19,7 @@ interface stdout {
 @since(version = 0.2.0)
 interface stderr {
   @since(version = 0.2.0)
-  use wasi:io/streams@0.2.1.{output-stream};
+  use wasi:io/streams@0.2.2.{output-stream};
 
   @since(version = 0.2.0)
   get-stderr: func() -> output-stream;
diff --git a/crates/wasi-http/wit/deps/clocks/monotonic-clock.wit b/crates/wasi-http/wit/deps/clocks/monotonic-clock.wit
index 3c24840c9..233cace4c 100644
--- a/crates/wasi-http/wit/deps/clocks/monotonic-clock.wit
+++ b/crates/wasi-http/wit/deps/clocks/monotonic-clock.wit
@@ -1,4 +1,4 @@
-package wasi:clocks@0.2.1;
+package wasi:clocks@0.2.2;
 /// WASI Monotonic Clock is a clock API intended to let users measure elapsed
 /// time.
 ///
@@ -10,7 +10,7 @@ package wasi:clocks@0.2.1;
 @since(version = 0.2.0)
 interface monotonic-clock {
     @since(version = 0.2.0)
-    use wasi:io/poll@0.2.1.{pollable};
+    use wasi:io/poll@0.2.2.{pollable};
 
     /// An instant in time, in nanoseconds. An instant is relative to an
     /// unspecified initial value, and can only be compared to instances from
diff --git a/crates/wasi-http/wit/deps/clocks/timezone.wit b/crates/wasi-http/wit/deps/clocks/timezone.wit
index 212da6682..349fb5703 100644
--- a/crates/wasi-http/wit/deps/clocks/timezone.wit
+++ b/crates/wasi-http/wit/deps/clocks/timezone.wit
@@ -1,4 +1,4 @@
-package wasi:clocks@0.2.1;
+package wasi:clocks@0.2.2;
 
 @unstable(feature = clocks-timezone)
 interface timezone {
diff --git a/crates/wasi-http/wit/deps/clocks/wall-clock.wit b/crates/wasi-http/wit/deps/clocks/wall-clock.wit
index 6be069a32..ec05a1f1a 100644
--- a/crates/wasi-http/wit/deps/clocks/wall-clock.wit
+++ b/crates/wasi-http/wit/deps/clocks/wall-clock.wit
@@ -1,4 +1,4 @@
-package wasi:clocks@0.2.1;
+package wasi:clocks@0.2.2;
 /// WASI Wall Clock is a clock API intended to let users query the current
 /// time. The name "wall" makes an analogy to a "clock on the wall", which
 /// is not necessarily monotonic as it may be reset.
diff --git a/crates/wasi-http/wit/deps/clocks/world.wit b/crates/wasi-http/wit/deps/clocks/world.wit
index 9251ac645..e36802cc8 100644
--- a/crates/wasi-http/wit/deps/clocks/world.wit
+++ b/crates/wasi-http/wit/deps/clocks/world.wit
@@ -1,4 +1,4 @@
-package wasi:clocks@0.2.1;
+package wasi:clocks@0.2.2;
 
 @since(version = 0.2.0)
 world imports {
diff --git a/crates/wasi-http/wit/deps/filesystem/preopens.wit b/crates/wasi-http/wit/deps/filesystem/preopens.wit
index ca2f726af..410bec1dc 100644
--- a/crates/wasi-http/wit/deps/filesystem/preopens.wit
+++ b/crates/wasi-http/wit/deps/filesystem/preopens.wit
@@ -1,4 +1,4 @@
-package wasi:filesystem@0.2.1;
+package wasi:filesystem@0.2.2;
 
 @since(version = 0.2.0)
 interface preopens {
diff --git a/crates/wasi-http/wit/deps/filesystem/types.wit b/crates/wasi-http/wit/deps/filesystem/types.wit
index db3d96867..49e0a30bb 100644
--- a/crates/wasi-http/wit/deps/filesystem/types.wit
+++ b/crates/wasi-http/wit/deps/filesystem/types.wit
@@ -1,4 +1,4 @@
-package wasi:filesystem@0.2.1;
+package wasi:filesystem@0.2.2;
 /// WASI filesystem is a filesystem API primarily intended to let users run WASI
 /// programs that access their files on their existing filesystems, without
 /// significant overhead.
@@ -26,9 +26,9 @@ package wasi:filesystem@0.2.1;
 @since(version = 0.2.0)
 interface types {
     @since(version = 0.2.0)
-    use wasi:io/streams@0.2.1.{input-stream, output-stream, error};
+    use wasi:io/streams@0.2.2.{input-stream, output-stream, error};
     @since(version = 0.2.0)
-    use wasi:clocks/wall-clock@0.2.1.{datetime};
+    use wasi:clocks/wall-clock@0.2.2.{datetime};
 
     /// File size or length of a region within a file.
     @since(version = 0.2.0)
@@ -523,12 +523,6 @@ interface types {
 
         /// Open a file or directory.
         ///
-        /// The returned descriptor is not guaranteed to be the lowest-numbered
-        /// descriptor not currently open/ it is randomized to prevent applications
-        /// from depending on making assumptions about indexes, since this is
-        /// error-prone in multi-threaded contexts. The returned descriptor is
-        /// guaranteed to be less than 2**31.
-        ///
         /// If `flags` contains `descriptor-flags::mutate-directory`, and the base
         /// descriptor doesn't have `descriptor-flags::mutate-directory` set,
         /// `open-at` fails with `error-code::read-only`.
diff --git a/crates/wasi-http/wit/deps/filesystem/world.wit b/crates/wasi-http/wit/deps/filesystem/world.wit
index af0146cbc..8064bd64b 100644
--- a/crates/wasi-http/wit/deps/filesystem/world.wit
+++ b/crates/wasi-http/wit/deps/filesystem/world.wit
@@ -1,4 +1,4 @@
-package wasi:filesystem@0.2.1;
+package wasi:filesystem@0.2.2;
 
 @since(version = 0.2.0)
 world imports {
diff --git a/crates/wasi-http/wit/deps/http/proxy.wit b/crates/wasi-http/wit/deps/http/proxy.wit
index 415d2ee1c..fadb89a3e 100644
--- a/crates/wasi-http/wit/deps/http/proxy.wit
+++ b/crates/wasi-http/wit/deps/http/proxy.wit
@@ -1,4 +1,4 @@
-package wasi:http@0.2.1;
+package wasi:http@0.2.2;
 
 /// The `wasi:http/imports` world imports all the APIs for HTTP proxies.
 /// It is intended to be `include`d in other worlds.
@@ -6,25 +6,25 @@ package wasi:http@0.2.1;
 world imports {
   /// HTTP proxies have access to time and randomness.
   @since(version = 0.2.0)
-  import wasi:clocks/monotonic-clock@0.2.1;
+  import wasi:clocks/monotonic-clock@0.2.2;
   @since(version = 0.2.0)
-  import wasi:clocks/wall-clock@0.2.1;
+  import wasi:clocks/wall-clock@0.2.2;
   @since(version = 0.2.0)
-  import wasi:random/random@0.2.1;
+  import wasi:random/random@0.2.2;
 
   /// Proxies have standard output and error streams which are expected to
   /// terminate in a developer-facing console provided by the host.
   @since(version = 0.2.0)
-  import wasi:cli/stdout@0.2.1;
+  import wasi:cli/stdout@0.2.2;
   @since(version = 0.2.0)
-  import wasi:cli/stderr@0.2.1;
+  import wasi:cli/stderr@0.2.2;
 
   /// TODO: this is a temporary workaround until component tooling is able to
   /// gracefully handle the absence of stdin. Hosts must return an eof stream
   /// for this import, which is what wasi-libc + tooling will do automatically
   /// when this import is properly removed.
   @since(version = 0.2.0)
-  import wasi:cli/stdin@0.2.1;
+  import wasi:cli/stdin@0.2.2;
 
   /// This is the default handler to use when user code simply wants to make an
   /// HTTP request (e.g., via `fetch()`).
diff --git a/crates/wasi-http/wit/deps/http/types.wit b/crates/wasi-http/wit/deps/http/types.wit
index 3c45cd08b..40ee77068 100644
--- a/crates/wasi-http/wit/deps/http/types.wit
+++ b/crates/wasi-http/wit/deps/http/types.wit
@@ -4,13 +4,13 @@
 @since(version = 0.2.0)
 interface types {
   @since(version = 0.2.0)
-  use wasi:clocks/monotonic-clock@0.2.1.{duration};
+  use wasi:clocks/monotonic-clock@0.2.2.{duration};
   @since(version = 0.2.0)
-  use wasi:io/streams@0.2.1.{input-stream, output-stream};
+  use wasi:io/streams@0.2.2.{input-stream, output-stream};
   @since(version = 0.2.0)
-  use wasi:io/error@0.2.1.{error as io-error};
+  use wasi:io/error@0.2.2.{error as io-error};
   @since(version = 0.2.0)
-  use wasi:io/poll@0.2.1.{pollable};
+  use wasi:io/poll@0.2.2.{pollable};
 
   /// This type corresponds to HTTP standard Methods.
   @since(version = 0.2.0)
@@ -124,12 +124,12 @@ interface types {
   /// setting or appending to a `fields` resource.
   @since(version = 0.2.0)
   variant header-error {
-    /// This error indicates that a `field-key` or `field-value` was
+    /// This error indicates that a `field-name` or `field-value` was
     /// syntactically invalid when used with an operation that sets headers in a
     /// `fields`.
     invalid-syntax,
 
-    /// This error indicates that a forbidden `field-key` was used when trying
+    /// This error indicates that a forbidden `field-name` was used when trying
     /// to set a header in a `fields`.
     forbidden,
 
@@ -138,8 +138,23 @@ interface types {
     immutable,
   }
 
+  /// Field names are always strings.
+  ///
+  /// Field names should always be treated as case insensitive by the `fields`
+  /// resource for the purposes of equality checking.
+  @since(version = 0.2.1)
+  type field-name = field-key;
+
   /// Field keys are always strings.
+  ///
+  /// Field keys should always be treated as case insensitive by the `fields`
+  /// resource for the purposes of equality checking.
+  /// 
+  /// # Deprecation
+  /// 
+  /// This type has been deprecated in favor of the `field-name` type.
   @since(version = 0.2.0)
+  @deprecated(version = 0.2.2)
   type field-key = string;
 
   /// Field values should always be ASCII strings. However, in
@@ -171,70 +186,73 @@ interface types {
     ///
     /// The resulting `fields` is mutable.
     ///
-    /// The list represents each key-value pair in the Fields. Keys
+    /// The list represents each name-value pair in the Fields. Names
     /// which have multiple values are represented by multiple entries in this
-    /// list with the same key.
+    /// list with the same name.
     ///
-    /// The tuple is a pair of the field key, represented as a string, and
+    /// The tuple is a pair of the field name, represented as a string, and
     /// Value, represented as a list of bytes.
     ///
-    /// An error result will be returned if any `field-key` or `field-value` is
+    /// An error result will be returned if any `field-name` or `field-value` is
     /// syntactically invalid, or if a field is forbidden.
     @since(version = 0.2.0)
     from-list: static func(
-      entries: list<tuple<field-key,field-value>>
+      entries: list<tuple<field-name,field-value>>
     ) -> result<fields, header-error>;
 
-    /// Get all of the values corresponding to a key. If the key is not present
+    /// Get all of the values corresponding to a name. If the name is not present
     /// in this `fields` or is syntactically invalid, an empty list is returned.
-    /// However, if the key is present but empty, this is represented by a list
+    /// However, if the name is present but empty, this is represented by a list
     /// with one or more empty field-values present.
     @since(version = 0.2.0)
-    get: func(name: field-key) -> list<field-value>;
+    get: func(name: field-name) -> list<field-value>;
 
-    /// Returns `true` when the key is present in this `fields`. If the key is
+    /// Returns `true` when the name is present in this `fields`. If the name is
     /// syntactically invalid, `false` is returned.
     @since(version = 0.2.0)
-    has: func(name: field-key) -> bool;
+    has: func(name: field-name) -> bool;
 
-    /// Set all of the values for a key. Clears any existing values for that
-    /// key, if they have been set.
+    /// Set all of the values for a name. Clears any existing values for that
+    /// name, if they have been set.
     ///
     /// Fails with `header-error.immutable` if the `fields` are immutable.
     ///
-    /// Fails with `header-error.invalid-syntax` if the `field-key` or any of
+    /// Fails with `header-error.invalid-syntax` if the `field-name` or any of
     /// the `field-value`s are syntactically invalid.
     @since(version = 0.2.0)
-    set: func(name: field-key, value: list<field-value>) -> result<_, header-error>;
+    set: func(name: field-name, value: list<field-value>) -> result<_, header-error>;
 
-    /// Delete all values for a key. Does nothing if no values for the key
+    /// Delete all values for a name. Does nothing if no values for the name
     /// exist.
     ///
     /// Fails with `header-error.immutable` if the `fields` are immutable.
     ///
-    /// Fails with `header-error.invalid-syntax` if the `field-key` is
+    /// Fails with `header-error.invalid-syntax` if the `field-name` is
     /// syntactically invalid.
     @since(version = 0.2.0)
-    delete: func(name: field-key) -> result<_, header-error>;
+    delete: func(name: field-name) -> result<_, header-error>;
 
-    /// Append a value for a key. Does not change or delete any existing
-    /// values for that key.
+    /// Append a value for a name. Does not change or delete any existing
+    /// values for that name.
     ///
     /// Fails with `header-error.immutable` if the `fields` are immutable.
     ///
-    /// Fails with `header-error.invalid-syntax` if the `field-key` or
+    /// Fails with `header-error.invalid-syntax` if the `field-name` or
     /// `field-value` are syntactically invalid.
     @since(version = 0.2.0)
-    append: func(name: field-key, value: field-value) -> result<_, header-error>;
+    append: func(name: field-name, value: field-value) -> result<_, header-error>;
 
-    /// Retrieve the full set of keys and values in the Fields. Like the
-    /// constructor, the list represents each key-value pair.
+    /// Retrieve the full set of names and values in the Fields. Like the
+    /// constructor, the list represents each name-value pair.
     ///
-    /// The outer list represents each key-value pair in the Fields. Keys
+    /// The outer list represents each name-value pair in the Fields. Names
     /// which have multiple values are represented by multiple entries in this
-    /// list with the same key.
+    /// list with the same name.
+    ///
+    /// The names and values are always returned in the original casing and in
+    /// the order in which they will be serialized for transport.
     @since(version = 0.2.0)
-    entries: func() -> list<tuple<field-key,field-value>>;
+    entries: func() -> list<tuple<field-name,field-value>>;
 
     /// Make a deep copy of the Fields. Equivalent in behavior to calling the
     /// `fields` constructor on the return value of `entries`. The resulting
diff --git a/crates/wasi-http/wit/deps/io/error.wit b/crates/wasi-http/wit/deps/io/error.wit
index 4ea29c469..717135f8c 100644
--- a/crates/wasi-http/wit/deps/io/error.wit
+++ b/crates/wasi-http/wit/deps/io/error.wit
@@ -1,4 +1,4 @@
-package wasi:io@0.2.1;
+package wasi:io@0.2.2;
 
 @since(version = 0.2.0)
 interface error {
diff --git a/crates/wasi-http/wit/deps/io/poll.wit b/crates/wasi-http/wit/deps/io/poll.wit
index b25ac729f..49c1c5ede 100644
--- a/crates/wasi-http/wit/deps/io/poll.wit
+++ b/crates/wasi-http/wit/deps/io/poll.wit
@@ -1,4 +1,4 @@
-package wasi:io@0.2.1;
+package wasi:io@0.2.2;
 
 /// A poll API intended to let users wait for I/O events on multiple handles
 /// at once.
diff --git a/crates/wasi-http/wit/deps/io/streams.wit b/crates/wasi-http/wit/deps/io/streams.wit
index b697e24d6..330f7095c 100644
--- a/crates/wasi-http/wit/deps/io/streams.wit
+++ b/crates/wasi-http/wit/deps/io/streams.wit
@@ -1,4 +1,4 @@
-package wasi:io@0.2.1;
+package wasi:io@0.2.2;
 
 /// WASI I/O is an I/O abstraction API which is currently focused on providing
 /// stream types.
@@ -18,6 +18,9 @@ interface streams {
         /// The last operation (a write or flush) failed before completion.
         ///
         /// More information is available in the `error` payload.
+        ///
+        /// After this, the stream will be closed. All future operations return
+        /// `stream-error::closed`.
         last-operation-failed(error),
         /// The stream is closed: no more input will be accepted by the
         /// stream. A closed output-stream will return this error on all
@@ -205,6 +208,7 @@ interface streams {
         /// The created `pollable` is a child resource of the `output-stream`.
         /// Implementations may trap if the `output-stream` is dropped before
         /// all derived `pollable`s created with this function are dropped.
+        @since(version = 0.2.0)
         subscribe: func() -> pollable;
 
         /// Write zeroes to a stream.
diff --git a/crates/wasi-http/wit/deps/io/world.wit b/crates/wasi-http/wit/deps/io/world.wit
index 6405a4e48..f7001ccff 100644
--- a/crates/wasi-http/wit/deps/io/world.wit
+++ b/crates/wasi-http/wit/deps/io/world.wit
@@ -1,4 +1,4 @@
-package wasi:io@0.2.1;
+package wasi:io@0.2.2;
 
 @since(version = 0.2.0)
 world imports {
diff --git a/crates/wasi-http/wit/deps/random/insecure-seed.wit b/crates/wasi-http/wit/deps/random/insecure-seed.wit
index 7e708dc52..cdea716cf 100644
--- a/crates/wasi-http/wit/deps/random/insecure-seed.wit
+++ b/crates/wasi-http/wit/deps/random/insecure-seed.wit
@@ -1,4 +1,4 @@
-package wasi:random@0.2.1;
+package wasi:random@0.2.2;
 /// The insecure-seed interface for seeding hash-map DoS resistance.
 ///
 /// It is intended to be portable at least between Unix-family platforms and
diff --git a/crates/wasi-http/wit/deps/random/insecure.wit b/crates/wasi-http/wit/deps/random/insecure.wit
index 3cdb53dfb..b71e85879 100644
--- a/crates/wasi-http/wit/deps/random/insecure.wit
+++ b/crates/wasi-http/wit/deps/random/insecure.wit
@@ -1,4 +1,4 @@
-package wasi:random@0.2.1;
+package wasi:random@0.2.2;
 /// The insecure interface for insecure pseudo-random numbers.
 ///
 /// It is intended to be portable at least between Unix-family platforms and
diff --git a/crates/wasi-http/wit/deps/random/random.wit b/crates/wasi-http/wit/deps/random/random.wit
index 2b5035d1c..0c57e8c80 100644
--- a/crates/wasi-http/wit/deps/random/random.wit
+++ b/crates/wasi-http/wit/deps/random/random.wit
@@ -1,4 +1,4 @@
-package wasi:random@0.2.1;
+package wasi:random@0.2.2;
 /// WASI Random is a random data API.
 ///
 /// It is intended to be portable at least between Unix-family platforms and
diff --git a/crates/wasi-http/wit/deps/random/world.wit b/crates/wasi-http/wit/deps/random/world.wit
index c615e96dc..16d68acfa 100644
--- a/crates/wasi-http/wit/deps/random/world.wit
+++ b/crates/wasi-http/wit/deps/random/world.wit
@@ -1,4 +1,4 @@
-package wasi:random@0.2.1;
+package wasi:random@0.2.2;
 
 @since(version = 0.2.0)
 world imports {
diff --git a/crates/wasi-http/wit/deps/sockets/ip-name-lookup.wit b/crates/wasi-http/wit/deps/sockets/ip-name-lookup.wit
index dc56f3000..d3ab88aed 100644
--- a/crates/wasi-http/wit/deps/sockets/ip-name-lookup.wit
+++ b/crates/wasi-http/wit/deps/sockets/ip-name-lookup.wit
@@ -1,7 +1,7 @@
 @since(version = 0.2.0)
 interface ip-name-lookup {
     @since(version = 0.2.0)
-    use wasi:io/poll@0.2.1.{pollable};
+    use wasi:io/poll@0.2.2.{pollable};
     @since(version = 0.2.0)
     use network.{network, error-code, ip-address};
 
@@ -48,7 +48,7 @@ interface ip-name-lookup {
 
         /// Create a `pollable` which will resolve once the stream is ready for I/O.
         ///
-        /// Note: this function is here for WASI Preview2 only.
+        /// Note: this function is here for WASI 0.2 only.
         /// It's planned to be removed when `future` is natively supported in Preview3.
         @since(version = 0.2.0)
         subscribe: func() -> pollable;
diff --git a/crates/wasi-http/wit/deps/sockets/network.wit b/crates/wasi-http/wit/deps/sockets/network.wit
index 8c13b348e..7f2d86a4c 100644
--- a/crates/wasi-http/wit/deps/sockets/network.wit
+++ b/crates/wasi-http/wit/deps/sockets/network.wit
@@ -1,5 +1,8 @@
 @since(version = 0.2.0)
 interface network {
+    @unstable(feature = network-error-code)
+    use wasi:io/error@0.2.2.{error};
+
     /// An opaque resource that represents access to (a subset of) the network.
     /// This enables context-based security for networking.
     /// There is no need for this to map 1:1 to a physical network interface.
@@ -105,6 +108,19 @@ interface network {
         permanent-resolver-failure,
     }
 
+    /// Attempts to extract a network-related `error-code` from the stream
+    /// `error` provided.
+    ///
+    /// Stream operations which return `stream-error::last-operation-failed`
+    /// have a payload with more information about the operation that failed.
+    /// This payload can be passed through to this function to see if there's
+    /// network-related information about the error to return.
+    ///
+    /// Note that this function is fallible because not all stream-related
+    /// errors are network-related errors.
+    @unstable(feature = network-error-code)
+    network-error-code: func(err: borrow<error>) -> option<error-code>;
+
     @since(version = 0.2.0)
     enum ip-address-family {
         /// Similar to `AF_INET` in POSIX.
diff --git a/crates/wasi-http/wit/deps/sockets/tcp.wit b/crates/wasi-http/wit/deps/sockets/tcp.wit
index bae5a29ec..728822dfa 100644
--- a/crates/wasi-http/wit/deps/sockets/tcp.wit
+++ b/crates/wasi-http/wit/deps/sockets/tcp.wit
@@ -1,11 +1,11 @@
 @since(version = 0.2.0)
 interface tcp {
     @since(version = 0.2.0)
-    use wasi:io/streams@0.2.1.{input-stream, output-stream};
+    use wasi:io/streams@0.2.2.{input-stream, output-stream};
     @since(version = 0.2.0)
-    use wasi:io/poll@0.2.1.{pollable};
+    use wasi:io/poll@0.2.2.{pollable};
     @since(version = 0.2.0)
-    use wasi:clocks/monotonic-clock@0.2.1.{duration};
+    use wasi:clocks/monotonic-clock@0.2.2.{duration};
     @since(version = 0.2.0)
     use network.{network, error-code, ip-socket-address, ip-address-family};
 
@@ -353,7 +353,7 @@ interface tcp {
         /// See <https://github.com/WebAssembly/wasi-sockets/blob/main/TcpSocketOperationalSemantics.md#pollable-readiness>
         /// for more information.
         ///
-        /// Note: this function is here for WASI Preview2 only.
+        /// Note: this function is here for WASI 0.2 only.
         /// It's planned to be removed when `future` is natively supported in Preview3.
         @since(version = 0.2.0)
         subscribe: func() -> pollable;
diff --git a/crates/wasi-http/wit/deps/sockets/udp.wit b/crates/wasi-http/wit/deps/sockets/udp.wit
index b289e4943..d8acb2d29 100644
--- a/crates/wasi-http/wit/deps/sockets/udp.wit
+++ b/crates/wasi-http/wit/deps/sockets/udp.wit
@@ -1,7 +1,7 @@
 @since(version = 0.2.0)
 interface udp {
     @since(version = 0.2.0)
-    use wasi:io/poll@0.2.1.{pollable};
+    use wasi:io/poll@0.2.2.{pollable};
     @since(version = 0.2.0)
     use network.{network, error-code, ip-socket-address, ip-address-family};
 
@@ -184,7 +184,7 @@ interface udp {
 
         /// Create a `pollable` which will resolve once the socket is ready for I/O.
         ///
-        /// Note: this function is here for WASI Preview2 only.
+        /// Note: this function is here for WASI 0.2 only.
         /// It's planned to be removed when `future` is natively supported in Preview3.
         @since(version = 0.2.0)
         subscribe: func() -> pollable;
@@ -220,7 +220,7 @@ interface udp {
 
         /// Create a `pollable` which will resolve once the stream is ready to receive again.
         ///
-        /// Note: this function is here for WASI Preview2 only.
+        /// Note: this function is here for WASI 0.2 only.
         /// It's planned to be removed when `future` is natively supported in Preview3.
         @since(version = 0.2.0)
         subscribe: func() -> pollable;
@@ -280,7 +280,7 @@ interface udp {
         
         /// Create a `pollable` which will resolve once the stream is ready to send again.
         ///
-        /// Note: this function is here for WASI Preview2 only.
+        /// Note: this function is here for WASI 0.2 only.
         /// It's planned to be removed when `future` is natively supported in Preview3.
         @since(version = 0.2.0)
         subscribe: func() -> pollable;
diff --git a/crates/wasi-http/wit/deps/sockets/world.wit b/crates/wasi-http/wit/deps/sockets/world.wit
index a1d42670e..6e349c756 100644
--- a/crates/wasi-http/wit/deps/sockets/world.wit
+++ b/crates/wasi-http/wit/deps/sockets/world.wit
@@ -1,4 +1,4 @@
-package wasi:sockets@0.2.1;
+package wasi:sockets@0.2.2;
 
 @since(version = 0.2.0)
 world imports {
diff --git a/crates/wasi-http/wit/world.wit b/crates/wasi-http/wit/world.wit
index 0875bb306..75aa81ff0 100644
--- a/crates/wasi-http/wit/world.wit
+++ b/crates/wasi-http/wit/world.wit
@@ -2,5 +2,5 @@
 package wasmtime:wasi-http;
 
 world bindings {
-  include wasi:http/proxy@0.2.1;
+  include wasi:http/proxy@0.2.2;
 }
diff --git a/crates/wasi-preview1-component-adapter/src/descriptors.rs b/crates/wasi-preview1-component-adapter/src/descriptors.rs
index d534bb6b5..80a1ede00 100644
--- a/crates/wasi-preview1-component-adapter/src/descriptors.rs
+++ b/crates/wasi-preview1-component-adapter/src/descriptors.rs
@@ -149,7 +149,7 @@ pub struct Descriptors {
 }
 
 #[cfg(not(feature = "proxy"))]
-#[link(wasm_import_module = "wasi:filesystem/preopens@0.2.1")]
+#[link(wasm_import_module = "wasi:filesystem/preopens@0.2.2")]
 extern "C" {
     #[link_name = "get-directories"]
     fn wasi_filesystem_get_directories(rval: *mut PreopenList);
diff --git a/crates/wasi-preview1-component-adapter/src/lib.rs b/crates/wasi-preview1-component-adapter/src/lib.rs
index 1806df36f..f3d9b9710 100644
--- a/crates/wasi-preview1-component-adapter/src/lib.rs
+++ b/crates/wasi-preview1-component-adapter/src/lib.rs
@@ -91,12 +91,12 @@ pub mod bindings {
             package wasmtime:adapter;
 
             world adapter {
-                import wasi:clocks/wall-clock@0.2.1;
-                import wasi:clocks/monotonic-clock@0.2.1;
-                import wasi:random/random@0.2.1;
-                import wasi:cli/stdout@0.2.1;
-                import wasi:cli/stderr@0.2.1;
-                import wasi:cli/stdin@0.2.1;
+                import wasi:clocks/wall-clock@0.2.2;
+                import wasi:clocks/monotonic-clock@0.2.2;
+                import wasi:random/random@0.2.2;
+                import wasi:cli/stdout@0.2.2;
+                import wasi:cli/stderr@0.2.2;
+                import wasi:cli/stdin@0.2.2;
             }
         "#,
         world: "wasmtime:adapter/adapter",
@@ -115,7 +115,7 @@ pub mod bindings {
     }
 }
 
-#[export_name = "wasi:cli/run@0.2.1#run"]
+#[export_name = "wasi:cli/run@0.2.2#run"]
 #[cfg(feature = "command")]
 pub unsafe extern "C" fn run() -> u32 {
     #[link(wasm_import_module = "__main_module__")]
@@ -457,7 +457,7 @@ impl BumpAlloc {
 }
 
 #[cfg(not(feature = "proxy"))]
-#[link(wasm_import_module = "wasi:cli/environment@0.2.1")]
+#[link(wasm_import_module = "wasi:cli/environment@0.2.2")]
 extern "C" {
     #[link_name = "get-arguments"]
     fn wasi_cli_get_arguments(rval: *mut WasmStrList);
@@ -2156,7 +2156,7 @@ pub unsafe extern "C" fn poll_oneoff(
             });
         }
 
-        #[link(wasm_import_module = "wasi:io/poll@0.2.1")]
+        #[link(wasm_import_module = "wasi:io/poll@0.2.2")]
         #[allow(improper_ctypes)] // FIXME(bytecodealliance/wit-bindgen#684)
         extern "C" {
             #[link_name = "poll"]
diff --git a/crates/wasi/src/bindings.rs b/crates/wasi/src/bindings.rs
index c236bc3f0..72c2c3ff9 100644
--- a/crates/wasi/src/bindings.rs
+++ b/crates/wasi/src/bindings.rs
@@ -26,7 +26,7 @@
 //!         // An example of extending the `wasi:cli/command` world with a
 //!         // custom host interface.
 //!         world my-world {
-//!             include wasi:cli/command@0.2.1;
+//!             include wasi:cli/command@0.2.2;
 //!
 //!             import custom-host;
 //!         }
@@ -96,7 +96,7 @@
 ///         // An example of extending the `wasi:cli/command` world with a
 ///         // custom host interface.
 ///         world my-world {
-///             include wasi:cli/command@0.2.1;
+///             include wasi:cli/command@0.2.2;
 ///
 ///             import custom-host;
 ///         }
diff --git a/crates/wasi/src/host/network.rs b/crates/wasi/src/host/network.rs
index 6772db788..3f7f4b827 100644
--- a/crates/wasi/src/host/network.rs
+++ b/crates/wasi/src/host/network.rs
@@ -4,6 +4,7 @@ use crate::bindings::sockets::network::{
 };
 use crate::network::{from_ipv4_addr, from_ipv6_addr, to_ipv4_addr, to_ipv6_addr};
 use crate::{SocketError, WasiImpl, WasiView};
+use anyhow::Error;
 use rustix::io::Errno;
 use std::io;
 use wasmtime::component::Resource;
@@ -15,6 +16,12 @@ where
     fn convert_error_code(&mut self, error: SocketError) -> anyhow::Result<ErrorCode> {
         error.downcast()
     }
+
+    fn network_error_code(&mut self, err: Resource<Error>) -> anyhow::Result<Option<ErrorCode>> {
+        let err = self.table().get(&err)?;
+        let _ = err; // TODO: should fill in this implementation
+        Ok(None)
+    }
 }
 
 impl<T> crate::bindings::sockets::network::HostNetwork for WasiImpl<T>
diff --git a/crates/wasi/src/lib.rs b/crates/wasi/src/lib.rs
index 8fb740cda..ddb389964 100644
--- a/crates/wasi/src/lib.rs
+++ b/crates/wasi/src/lib.rs
@@ -323,7 +323,7 @@ pub fn add_to_linker_with_options_async<T: WasiView>(
     crate::bindings::sockets::udp::add_to_linker_get_host(l, closure)?;
     crate::bindings::sockets::udp_create_socket::add_to_linker_get_host(l, closure)?;
     crate::bindings::sockets::instance_network::add_to_linker_get_host(l, closure)?;
-    crate::bindings::sockets::network::add_to_linker_get_host(l, closure)?;
+    crate::bindings::sockets::network::add_to_linker_get_host(l, &options.into(), closure)?;
     crate::bindings::sockets::ip_name_lookup::add_to_linker_get_host(l, closure)?;
     Ok(())
 }
@@ -422,7 +422,7 @@ pub fn add_to_linker_with_options_sync<T: WasiView>(
     crate::bindings::sync::sockets::udp::add_to_linker_get_host(l, closure)?;
     crate::bindings::sockets::udp_create_socket::add_to_linker_get_host(l, closure)?;
     crate::bindings::sockets::instance_network::add_to_linker_get_host(l, closure)?;
-    crate::bindings::sockets::network::add_to_linker_get_host(l, closure)?;
+    crate::bindings::sockets::network::add_to_linker_get_host(l, &options.into(), closure)?;
     crate::bindings::sockets::ip_name_lookup::add_to_linker_get_host(l, closure)?;
     Ok(())
 }
diff --git a/crates/wasi/wit/deps/cli/command.wit b/crates/wasi/wit/deps/cli/command.wit
index dc064a3cd..cc7a352c2 100644
--- a/crates/wasi/wit/deps/cli/command.wit
+++ b/crates/wasi/wit/deps/cli/command.wit
@@ -1,4 +1,4 @@
-package wasi:cli@0.2.1;
+package wasi:cli@0.2.2;
 
 @since(version = 0.2.0)
 world command {
diff --git a/crates/wasi/wit/deps/cli/imports.wit b/crates/wasi/wit/deps/cli/imports.wit
index b8339d3b2..ebd7ba173 100644
--- a/crates/wasi/wit/deps/cli/imports.wit
+++ b/crates/wasi/wit/deps/cli/imports.wit
@@ -1,17 +1,17 @@
-package wasi:cli@0.2.1;
+package wasi:cli@0.2.2;
 
 @since(version = 0.2.0)
 world imports {
   @since(version = 0.2.0)
-  include wasi:clocks/imports@0.2.1;
+  include wasi:clocks/imports@0.2.2;
   @since(version = 0.2.0)
-  include wasi:filesystem/imports@0.2.1;
+  include wasi:filesystem/imports@0.2.2;
   @since(version = 0.2.0)
-  include wasi:sockets/imports@0.2.1;
+  include wasi:sockets/imports@0.2.2;
   @since(version = 0.2.0)
-  include wasi:random/imports@0.2.1;
+  include wasi:random/imports@0.2.2;
   @since(version = 0.2.0)
-  include wasi:io/imports@0.2.1;
+  include wasi:io/imports@0.2.2;
 
   @since(version = 0.2.0)
   import environment;
diff --git a/crates/wasi/wit/deps/cli/stdio.wit b/crates/wasi/wit/deps/cli/stdio.wit
index d1d26eb61..860313eea 100644
--- a/crates/wasi/wit/deps/cli/stdio.wit
+++ b/crates/wasi/wit/deps/cli/stdio.wit
@@ -1,7 +1,7 @@
 @since(version = 0.2.0)
 interface stdin {
   @since(version = 0.2.0)
-  use wasi:io/streams@0.2.1.{input-stream};
+  use wasi:io/streams@0.2.2.{input-stream};
 
   @since(version = 0.2.0)
   get-stdin: func() -> input-stream;
@@ -10,7 +10,7 @@ interface stdin {
 @since(version = 0.2.0)
 interface stdout {
   @since(version = 0.2.0)
-  use wasi:io/streams@0.2.1.{output-stream};
+  use wasi:io/streams@0.2.2.{output-stream};
 
   @since(version = 0.2.0)
   get-stdout: func() -> output-stream;
@@ -19,7 +19,7 @@ interface stdout {
 @since(version = 0.2.0)
 interface stderr {
   @since(version = 0.2.0)
-  use wasi:io/streams@0.2.1.{output-stream};
+  use wasi:io/streams@0.2.2.{output-stream};
 
   @since(version = 0.2.0)
   get-stderr: func() -> output-stream;
diff --git a/crates/wasi/wit/deps/clocks/monotonic-clock.wit b/crates/wasi/wit/deps/clocks/monotonic-clock.wit
index 3c24840c9..233cace4c 100644
--- a/crates/wasi/wit/deps/clocks/monotonic-clock.wit
+++ b/crates/wasi/wit/deps/clocks/monotonic-clock.wit
@@ -1,4 +1,4 @@
-package wasi:clocks@0.2.1;
+package wasi:clocks@0.2.2;
 /// WASI Monotonic Clock is a clock API intended to let users measure elapsed
 /// time.
 ///
@@ -10,7 +10,7 @@ package wasi:clocks@0.2.1;
 @since(version = 0.2.0)
 interface monotonic-clock {
     @since(version = 0.2.0)
-    use wasi:io/poll@0.2.1.{pollable};
+    use wasi:io/poll@0.2.2.{pollable};
 
     /// An instant in time, in nanoseconds. An instant is relative to an
     /// unspecified initial value, and can only be compared to instances from
diff --git a/crates/wasi/wit/deps/clocks/timezone.wit b/crates/wasi/wit/deps/clocks/timezone.wit
index 212da6682..349fb5703 100644
--- a/crates/wasi/wit/deps/clocks/timezone.wit
+++ b/crates/wasi/wit/deps/clocks/timezone.wit
@@ -1,4 +1,4 @@
-package wasi:clocks@0.2.1;
+package wasi:clocks@0.2.2;
 
 @unstable(feature = clocks-timezone)
 interface timezone {
diff --git a/crates/wasi/wit/deps/clocks/wall-clock.wit b/crates/wasi/wit/deps/clocks/wall-clock.wit
index 6be069a32..ec05a1f1a 100644
--- a/crates/wasi/wit/deps/clocks/wall-clock.wit
+++ b/crates/wasi/wit/deps/clocks/wall-clock.wit
@@ -1,4 +1,4 @@
-package wasi:clocks@0.2.1;
+package wasi:clocks@0.2.2;
 /// WASI Wall Clock is a clock API intended to let users query the current
 /// time. The name "wall" makes an analogy to a "clock on the wall", which
 /// is not necessarily monotonic as it may be reset.
diff --git a/crates/wasi/wit/deps/clocks/world.wit b/crates/wasi/wit/deps/clocks/world.wit
index 9251ac645..e36802cc8 100644
--- a/crates/wasi/wit/deps/clocks/world.wit
+++ b/crates/wasi/wit/deps/clocks/world.wit
@@ -1,4 +1,4 @@
-package wasi:clocks@0.2.1;
+package wasi:clocks@0.2.2;
 
 @since(version = 0.2.0)
 world imports {
diff --git a/crates/wasi/wit/deps/filesystem/preopens.wit b/crates/wasi/wit/deps/filesystem/preopens.wit
index ca2f726af..410bec1dc 100644
--- a/crates/wasi/wit/deps/filesystem/preopens.wit
+++ b/crates/wasi/wit/deps/filesystem/preopens.wit
@@ -1,4 +1,4 @@
-package wasi:filesystem@0.2.1;
+package wasi:filesystem@0.2.2;
 
 @since(version = 0.2.0)
 interface preopens {
diff --git a/crates/wasi/wit/deps/filesystem/types.wit b/crates/wasi/wit/deps/filesystem/types.wit
index db3d96867..49e0a30bb 100644
--- a/crates/wasi/wit/deps/filesystem/types.wit
+++ b/crates/wasi/wit/deps/filesystem/types.wit
@@ -1,4 +1,4 @@
-package wasi:filesystem@0.2.1;
+package wasi:filesystem@0.2.2;
 /// WASI filesystem is a filesystem API primarily intended to let users run WASI
 /// programs that access their files on their existing filesystems, without
 /// significant overhead.
@@ -26,9 +26,9 @@ package wasi:filesystem@0.2.1;
 @since(version = 0.2.0)
 interface types {
     @since(version = 0.2.0)
-    use wasi:io/streams@0.2.1.{input-stream, output-stream, error};
+    use wasi:io/streams@0.2.2.{input-stream, output-stream, error};
     @since(version = 0.2.0)
-    use wasi:clocks/wall-clock@0.2.1.{datetime};
+    use wasi:clocks/wall-clock@0.2.2.{datetime};
 
     /// File size or length of a region within a file.
     @since(version = 0.2.0)
@@ -523,12 +523,6 @@ interface types {
 
         /// Open a file or directory.
         ///
-        /// The returned descriptor is not guaranteed to be the lowest-numbered
-        /// descriptor not currently open/ it is randomized to prevent applications
-        /// from depending on making assumptions about indexes, since this is
-        /// error-prone in multi-threaded contexts. The returned descriptor is
-        /// guaranteed to be less than 2**31.
-        ///
         /// If `flags` contains `descriptor-flags::mutate-directory`, and the base
         /// descriptor doesn't have `descriptor-flags::mutate-directory` set,
         /// `open-at` fails with `error-code::read-only`.
diff --git a/crates/wasi/wit/deps/filesystem/world.wit b/crates/wasi/wit/deps/filesystem/world.wit
index af0146cbc..8064bd64b 100644
--- a/crates/wasi/wit/deps/filesystem/world.wit
+++ b/crates/wasi/wit/deps/filesystem/world.wit
@@ -1,4 +1,4 @@
-package wasi:filesystem@0.2.1;
+package wasi:filesystem@0.2.2;
 
 @since(version = 0.2.0)
 world imports {
diff --git a/crates/wasi/wit/deps/io/error.wit b/crates/wasi/wit/deps/io/error.wit
index 4ea29c469..717135f8c 100644
--- a/crates/wasi/wit/deps/io/error.wit
+++ b/crates/wasi/wit/deps/io/error.wit
@@ -1,4 +1,4 @@
-package wasi:io@0.2.1;
+package wasi:io@0.2.2;
 
 @since(version = 0.2.0)
 interface error {
diff --git a/crates/wasi/wit/deps/io/poll.wit b/crates/wasi/wit/deps/io/poll.wit
index b25ac729f..49c1c5ede 100644
--- a/crates/wasi/wit/deps/io/poll.wit
+++ b/crates/wasi/wit/deps/io/poll.wit
@@ -1,4 +1,4 @@
-package wasi:io@0.2.1;
+package wasi:io@0.2.2;
 
 /// A poll API intended to let users wait for I/O events on multiple handles
 /// at once.
diff --git a/crates/wasi/wit/deps/io/streams.wit b/crates/wasi/wit/deps/io/streams.wit
index b697e24d6..330f7095c 100644
--- a/crates/wasi/wit/deps/io/streams.wit
+++ b/crates/wasi/wit/deps/io/streams.wit
@@ -1,4 +1,4 @@
-package wasi:io@0.2.1;
+package wasi:io@0.2.2;
 
 /// WASI I/O is an I/O abstraction API which is currently focused on providing
 /// stream types.
@@ -18,6 +18,9 @@ interface streams {
         /// The last operation (a write or flush) failed before completion.
         ///
         /// More information is available in the `error` payload.
+        ///
+        /// After this, the stream will be closed. All future operations return
+        /// `stream-error::closed`.
         last-operation-failed(error),
         /// The stream is closed: no more input will be accepted by the
         /// stream. A closed output-stream will return this error on all
@@ -205,6 +208,7 @@ interface streams {
         /// The created `pollable` is a child resource of the `output-stream`.
         /// Implementations may trap if the `output-stream` is dropped before
         /// all derived `pollable`s created with this function are dropped.
+        @since(version = 0.2.0)
         subscribe: func() -> pollable;
 
         /// Write zeroes to a stream.
diff --git a/crates/wasi/wit/deps/io/world.wit b/crates/wasi/wit/deps/io/world.wit
index 6405a4e48..f7001ccff 100644
--- a/crates/wasi/wit/deps/io/world.wit
+++ b/crates/wasi/wit/deps/io/world.wit
@@ -1,4 +1,4 @@
-package wasi:io@0.2.1;
+package wasi:io@0.2.2;
 
 @since(version = 0.2.0)
 world imports {
diff --git a/crates/wasi/wit/deps/random/insecure-seed.wit b/crates/wasi/wit/deps/random/insecure-seed.wit
index 7e708dc52..cdea716cf 100644
--- a/crates/wasi/wit/deps/random/insecure-seed.wit
+++ b/crates/wasi/wit/deps/random/insecure-seed.wit
@@ -1,4 +1,4 @@
-package wasi:random@0.2.1;
+package wasi:random@0.2.2;
 /// The insecure-seed interface for seeding hash-map DoS resistance.
 ///
 /// It is intended to be portable at least between Unix-family platforms and
diff --git a/crates/wasi/wit/deps/random/insecure.wit b/crates/wasi/wit/deps/random/insecure.wit
index 3cdb53dfb..b71e85879 100644
--- a/crates/wasi/wit/deps/random/insecure.wit
+++ b/crates/wasi/wit/deps/random/insecure.wit
@@ -1,4 +1,4 @@
-package wasi:random@0.2.1;
+package wasi:random@0.2.2;
 /// The insecure interface for insecure pseudo-random numbers.
 ///
 /// It is intended to be portable at least between Unix-family platforms and
diff --git a/crates/wasi/wit/deps/random/random.wit b/crates/wasi/wit/deps/random/random.wit
index 2b5035d1c..0c57e8c80 100644
--- a/crates/wasi/wit/deps/random/random.wit
+++ b/crates/wasi/wit/deps/random/random.wit
@@ -1,4 +1,4 @@
-package wasi:random@0.2.1;
+package wasi:random@0.2.2;
 /// WASI Random is a random data API.
 ///
 /// It is intended to be portable at least between Unix-family platforms and
diff --git a/crates/wasi/wit/deps/random/world.wit b/crates/wasi/wit/deps/random/world.wit
index c615e96dc..16d68acfa 100644
--- a/crates/wasi/wit/deps/random/world.wit
+++ b/crates/wasi/wit/deps/random/world.wit
@@ -1,4 +1,4 @@
-package wasi:random@0.2.1;
+package wasi:random@0.2.2;
 
 @since(version = 0.2.0)
 world imports {
diff --git a/crates/wasi/wit/deps/sockets/ip-name-lookup.wit b/crates/wasi/wit/deps/sockets/ip-name-lookup.wit
index dc56f3000..d3ab88aed 100644
--- a/crates/wasi/wit/deps/sockets/ip-name-lookup.wit
+++ b/crates/wasi/wit/deps/sockets/ip-name-lookup.wit
@@ -1,7 +1,7 @@
 @since(version = 0.2.0)
 interface ip-name-lookup {
     @since(version = 0.2.0)
-    use wasi:io/poll@0.2.1.{pollable};
+    use wasi:io/poll@0.2.2.{pollable};
     @since(version = 0.2.0)
     use network.{network, error-code, ip-address};
 
@@ -48,7 +48,7 @@ interface ip-name-lookup {
 
         /// Create a `pollable` which will resolve once the stream is ready for I/O.
         ///
-        /// Note: this function is here for WASI Preview2 only.
+        /// Note: this function is here for WASI 0.2 only.
         /// It's planned to be removed when `future` is natively supported in Preview3.
         @since(version = 0.2.0)
         subscribe: func() -> pollable;
diff --git a/crates/wasi/wit/deps/sockets/network.wit b/crates/wasi/wit/deps/sockets/network.wit
index 8c13b348e..7f2d86a4c 100644
--- a/crates/wasi/wit/deps/sockets/network.wit
+++ b/crates/wasi/wit/deps/sockets/network.wit
@@ -1,5 +1,8 @@
 @since(version = 0.2.0)
 interface network {
+    @unstable(feature = network-error-code)
+    use wasi:io/error@0.2.2.{error};
+
     /// An opaque resource that represents access to (a subset of) the network.
     /// This enables context-based security for networking.
     /// There is no need for this to map 1:1 to a physical network interface.
@@ -105,6 +108,19 @@ interface network {
         permanent-resolver-failure,
     }
 
+    /// Attempts to extract a network-related `error-code` from the stream
+    /// `error` provided.
+    ///
+    /// Stream operations which return `stream-error::last-operation-failed`
+    /// have a payload with more information about the operation that failed.
+    /// This payload can be passed through to this function to see if there's
+    /// network-related information about the error to return.
+    ///
+    /// Note that this function is fallible because not all stream-related
+    /// errors are network-related errors.
+    @unstable(feature = network-error-code)
+    network-error-code: func(err: borrow<error>) -> option<error-code>;
+
     @since(version = 0.2.0)
     enum ip-address-family {
         /// Similar to `AF_INET` in POSIX.
diff --git a/crates/wasi/wit/deps/sockets/tcp.wit b/crates/wasi/wit/deps/sockets/tcp.wit
index bae5a29ec..728822dfa 100644
--- a/crates/wasi/wit/deps/sockets/tcp.wit
+++ b/crates/wasi/wit/deps/sockets/tcp.wit
@@ -1,11 +1,11 @@
 @since(version = 0.2.0)
 interface tcp {
     @since(version = 0.2.0)
-    use wasi:io/streams@0.2.1.{input-stream, output-stream};
+    use wasi:io/streams@0.2.2.{input-stream, output-stream};
     @since(version = 0.2.0)
-    use wasi:io/poll@0.2.1.{pollable};
+    use wasi:io/poll@0.2.2.{pollable};
     @since(version = 0.2.0)
-    use wasi:clocks/monotonic-clock@0.2.1.{duration};
+    use wasi:clocks/monotonic-clock@0.2.2.{duration};
     @since(version = 0.2.0)
     use network.{network, error-code, ip-socket-address, ip-address-family};
 
@@ -353,7 +353,7 @@ interface tcp {
         /// See <https://github.com/WebAssembly/wasi-sockets/blob/main/TcpSocketOperationalSemantics.md#pollable-readiness>
         /// for more information.
         ///
-        /// Note: this function is here for WASI Preview2 only.
+        /// Note: this function is here for WASI 0.2 only.
         /// It's planned to be removed when `future` is natively supported in Preview3.
         @since(version = 0.2.0)
         subscribe: func() -> pollable;
diff --git a/crates/wasi/wit/deps/sockets/udp.wit b/crates/wasi/wit/deps/sockets/udp.wit
index b289e4943..d8acb2d29 100644
--- a/crates/wasi/wit/deps/sockets/udp.wit
+++ b/crates/wasi/wit/deps/sockets/udp.wit
@@ -1,7 +1,7 @@
 @since(version = 0.2.0)
 interface udp {
     @since(version = 0.2.0)
-    use wasi:io/poll@0.2.1.{pollable};
+    use wasi:io/poll@0.2.2.{pollable};
     @since(version = 0.2.0)
     use network.{network, error-code, ip-socket-address, ip-address-family};
 
@@ -184,7 +184,7 @@ interface udp {
 
         /// Create a `pollable` which will resolve once the socket is ready for I/O.
         ///
-        /// Note: this function is here for WASI Preview2 only.
+        /// Note: this function is here for WASI 0.2 only.
         /// It's planned to be removed when `future` is natively supported in Preview3.
         @since(version = 0.2.0)
         subscribe: func() -> pollable;
@@ -220,7 +220,7 @@ interface udp {
 
         /// Create a `pollable` which will resolve once the stream is ready to receive again.
         ///
-        /// Note: this function is here for WASI Preview2 only.
+        /// Note: this function is here for WASI 0.2 only.
         /// It's planned to be removed when `future` is natively supported in Preview3.
         @since(version = 0.2.0)
         subscribe: func() -> pollable;
@@ -280,7 +280,7 @@ interface udp {
         
         /// Create a `pollable` which will resolve once the stream is ready to send again.
         ///
-        /// Note: this function is here for WASI Preview2 only.
+        /// Note: this function is here for WASI 0.2 only.
         /// It's planned to be removed when `future` is natively supported in Preview3.
         @since(version = 0.2.0)
         subscribe: func() -> pollable;
diff --git a/crates/wasi/wit/deps/sockets/world.wit b/crates/wasi/wit/deps/sockets/world.wit
index a1d42670e..6e349c756 100644
--- a/crates/wasi/wit/deps/sockets/world.wit
+++ b/crates/wasi/wit/deps/sockets/world.wit
@@ -1,4 +1,4 @@
-package wasi:sockets@0.2.1;
+package wasi:sockets@0.2.2;
 
 @since(version = 0.2.0)
 world imports {
diff --git a/crates/wasi/wit/world.wit b/crates/wasi/wit/world.wit
index e540b1f6d..0b3c62819 100644
--- a/crates/wasi/wit/world.wit
+++ b/crates/wasi/wit/world.wit
@@ -2,5 +2,5 @@
 package wasmtime:wasi;
 
 world bindings {
-  include wasi:cli/imports@0.2.1;
+  include wasi:cli/imports@0.2.2;
 }
diff --git a/crates/wasmtime/src/runtime/vm/sys/custom/mmap.rs b/crates/wasmtime/src/runtime/vm/sys/custom/mmap.rs
index 171cf010a..f3a9def96 100644
--- a/crates/wasmtime/src/runtime/vm/sys/custom/mmap.rs
+++ b/crates/wasmtime/src/runtime/vm/sys/custom/mmap.rs
@@ -15,7 +15,7 @@ pub struct Mmap {
 impl Mmap {
     pub fn new_empty() -> Mmap {
         Mmap {
-            memory: SendSyncPtr::from(&mut [][..]),
+            memory: crate::vm::sys::empty_mmap(),
         }
     }
 
diff --git a/crates/wasmtime/src/runtime/vm/sys/miri/mmap.rs b/crates/wasmtime/src/runtime/vm/sys/miri/mmap.rs
index de2a6aa3f..625b56bd4 100644
--- a/crates/wasmtime/src/runtime/vm/sys/miri/mmap.rs
+++ b/crates/wasmtime/src/runtime/vm/sys/miri/mmap.rs
@@ -21,7 +21,7 @@ pub struct Mmap {
 impl Mmap {
     pub fn new_empty() -> Mmap {
         Mmap {
-            memory: SendSyncPtr::from(&mut [][..]),
+            memory: crate::vm::sys::empty_mmap(),
         }
     }
 
diff --git a/crates/wasmtime/src/runtime/vm/sys/mod.rs b/crates/wasmtime/src/runtime/vm/sys/mod.rs
index e25ebe305..f67bc312c 100644
--- a/crates/wasmtime/src/runtime/vm/sys/mod.rs
+++ b/crates/wasmtime/src/runtime/vm/sys/mod.rs
@@ -8,6 +8,9 @@
 
 #![allow(clippy::cast_sign_loss)] // platforms too fiddly to worry about this
 
+use crate::runtime::vm::SendSyncPtr;
+use core::ptr::{self, NonNull};
+
 /// What happens to a mapping after it is decommitted?
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub enum DecommitBehavior {
@@ -19,6 +22,30 @@ pub enum DecommitBehavior {
     RestoreOriginalMapping,
 }
 
+fn empty_mmap() -> SendSyncPtr<[u8]> {
+    // Callers of this API assume that `.as_ptr()` below returns something
+    // page-aligned and non-null. This is because the pointer returned from
+    // that location is casted to other types which reside at a higher
+    // alignment than a byte for example. Despite the length being zero we
+    // still need to ensure that the pointer is suitably aligned.
+    //
+    // To handle that do a bit of trickery here to get the compiler to
+    // generate an empty array to a high-alignment type (here 4k which is
+    // the min page size we work with today). Then use this empty array as
+    // the source pointer for an empty byte slice. It's a bit wonky but this
+    // makes it such that the returned length is always zero (so this is
+    // safe) but the pointer is always 4096 or suitably aligned.
+    #[repr(C, align(4096))]
+    struct PageAligned;
+    let empty_page_alloc: &mut [PageAligned] = &mut [];
+    let empty = NonNull::new(ptr::slice_from_raw_parts_mut(
+        empty_page_alloc.as_mut_ptr().cast(),
+        0,
+    ))
+    .unwrap();
+    SendSyncPtr::from(empty)
+}
+
 cfg_if::cfg_if! {
     if #[cfg(miri)] {
         mod miri;
diff --git a/crates/wasmtime/src/runtime/vm/sys/unix/mmap.rs b/crates/wasmtime/src/runtime/vm/sys/unix/mmap.rs
index 4c29a9ae1..c176de499 100644
--- a/crates/wasmtime/src/runtime/vm/sys/unix/mmap.rs
+++ b/crates/wasmtime/src/runtime/vm/sys/unix/mmap.rs
@@ -14,7 +14,7 @@ pub struct Mmap {
 impl Mmap {
     pub fn new_empty() -> Mmap {
         Mmap {
-            memory: SendSyncPtr::from(&mut [][..]),
+            memory: crate::vm::sys::empty_mmap(),
         }
     }
 
diff --git a/crates/wasmtime/src/runtime/vm/sys/windows/mmap.rs b/crates/wasmtime/src/runtime/vm/sys/windows/mmap.rs
index 13850e26d..f4a986d91 100644
--- a/crates/wasmtime/src/runtime/vm/sys/windows/mmap.rs
+++ b/crates/wasmtime/src/runtime/vm/sys/windows/mmap.rs
@@ -19,7 +19,7 @@ pub struct Mmap {
 impl Mmap {
     pub fn new_empty() -> Mmap {
         Mmap {
-            memory: SendSyncPtr::from(&mut [][..]),
+            memory: crate::vm::sys::empty_mmap(),
             is_file: false,
         }
     }
diff --git a/winch/codegen/src/isa/aarch64/asm.rs b/winch/codegen/src/isa/aarch64/asm.rs
index 2c6a668da..e5bb5ee17 100644
--- a/winch/codegen/src/isa/aarch64/asm.rs
+++ b/winch/codegen/src/isa/aarch64/asm.rs
@@ -315,9 +315,9 @@ impl Assembler {
         });
     }
 
-    pub fn mov_from_vec(&mut self, rn: Reg, rd: Reg, idx: u8, size: OperandSize) {
+    pub fn mov_from_vec(&mut self, rn: Reg, rd: WritableReg, idx: u8, size: OperandSize) {
         self.emit(Inst::MovFromVec {
-            rd: Writable::from_reg(rd.into()),
+            rd: rd.map(Into::into),
             rn: rn.into(),
             idx,
             size: size.into(),
@@ -342,10 +342,10 @@ impl Assembler {
     }
 
     /// Add across Vector.
-    pub fn addv(&mut self, rn: Reg, rd: Reg, size: VectorSize) {
+    pub fn addv(&mut self, rn: Reg, rd: WritableReg, size: VectorSize) {
         self.emit(Inst::VecLanes {
             op: VecLanesOp::Addv,
-            rd: Writable::from_reg(rd.into()),
+            rd: rd.map(Into::into),
             rn: rn.into(),
             size,
         });
@@ -540,7 +540,7 @@ impl Assembler {
     }
 
     /// Float round (ceil, trunc, floor) with two registers.
-    pub fn fround_rr(&mut self, rn: Reg, rd: Reg, mode: RoundingMode, size: OperandSize) {
+    pub fn fround_rr(&mut self, rn: Reg, rd: WritableReg, mode: RoundingMode, size: OperandSize) {
         let fpu_mode = match (mode, size) {
             (RoundingMode::Nearest, OperandSize::S32) => FpuRoundMode::Nearest32,
             (RoundingMode::Up, OperandSize::S32) => FpuRoundMode::Plus32,
@@ -687,11 +687,11 @@ impl Assembler {
     }
 
     // Population Count per byte.
-    pub fn cnt(&mut self, rd: Reg) {
+    pub fn cnt(&mut self, rd: WritableReg) {
         self.emit(Inst::VecMisc {
             op: VecMisc2::Cnt,
-            rd: Writable::from_reg(rd.into()),
-            rn: rd.into(),
+            rd: rd.map(Into::into),
+            rn: rd.to_reg().into(),
             size: VectorSize::Size8x8,
         });
     }
@@ -853,10 +853,10 @@ impl Assembler {
         });
     }
 
-    fn emit_fpu_round(&mut self, op: FpuRoundMode, rn: Reg, rd: Reg) {
+    fn emit_fpu_round(&mut self, op: FpuRoundMode, rn: Reg, rd: WritableReg) {
         self.emit(Inst::FpuRound {
             op: op,
-            rd: Writable::from_reg(rd.into()),
+            rd: rd.map(Into::into),
             rn: rn.into(),
         });
     }
diff --git a/winch/codegen/src/isa/aarch64/masm.rs b/winch/codegen/src/isa/aarch64/masm.rs
index dbc17b037..fa089b134 100644
--- a/winch/codegen/src/isa/aarch64/masm.rs
+++ b/winch/codegen/src/isa/aarch64/masm.rs
@@ -359,7 +359,8 @@ impl Masm for MacroAssembler {
         _fallback: F,
     ) {
         let src = context.pop_to_reg(self, None);
-        self.asm.fround_rr(src.into(), src.into(), mode, size);
+        self.asm
+            .fround_rr(src.into(), writable!(src.into()), mode, size);
         context.stack.push(src.into());
     }
 
@@ -459,9 +460,10 @@ impl Masm for MacroAssembler {
         let src = context.pop_to_reg(self, None);
         let tmp = regs::float_scratch();
         self.asm.mov_to_fpu(src.into(), writable!(tmp), size);
-        self.asm.cnt(tmp);
-        self.asm.addv(tmp, tmp, VectorSize::Size8x8);
-        self.asm.mov_from_vec(tmp, src.into(), 0, OperandSize::S8);
+        self.asm.cnt(writable!(tmp));
+        self.asm.addv(tmp, writable!(tmp), VectorSize::Size8x8);
+        self.asm
+            .mov_from_vec(tmp, writable!(src.into()), 0, OperandSize::S8);
         context.stack.push(src.into());
     }
 
diff --git a/winch/codegen/src/isa/x64/asm.rs b/winch/codegen/src/isa/x64/asm.rs
index ebec91d01..bcb0e7187 100644
--- a/winch/codegen/src/isa/x64/asm.rs
+++ b/winch/codegen/src/isa/x64/asm.rs
@@ -1224,7 +1224,13 @@ impl Assembler {
 
     /// Perform rounding operation on float register src and place results in
     /// float register dst.
-    pub fn xmm_rounds_rr(&mut self, src: Reg, dst: Reg, mode: RoundingMode, size: OperandSize) {
+    pub fn xmm_rounds_rr(
+        &mut self,
+        src: Reg,
+        dst: WritableReg,
+        mode: RoundingMode,
+        size: OperandSize,
+    ) {
         let op = match size {
             OperandSize::S32 => SseOpcode::Roundss,
             OperandSize::S64 => SseOpcode::Roundsd,
@@ -1242,7 +1248,7 @@ impl Assembler {
             op,
             src: XmmMemAligned::from(Xmm::from(src)),
             imm,
-            dst: dst.into(),
+            dst: dst.map(Into::into),
         })
     }
 
diff --git a/winch/codegen/src/isa/x64/masm.rs b/winch/codegen/src/isa/x64/masm.rs
index e42f39e62..f333f84ee 100644
--- a/winch/codegen/src/isa/x64/masm.rs
+++ b/winch/codegen/src/isa/x64/masm.rs
@@ -483,7 +483,8 @@ impl Masm for MacroAssembler {
     ) {
         if self.flags.has_sse41() {
             let src = context.pop_to_reg(self, None);
-            self.asm.xmm_rounds_rr(src.into(), src.into(), mode, size);
+            self.asm
+                .xmm_rounds_rr(src.into(), writable!(src.into()), mode, size);
             context.stack.push(src.into());
         } else {
             fallback(env, context, self);


Test patch:
diff --git a/cranelift/codegen/src/isa/s390x/inst/emit_tests.rs b/cranelift/codegen/src/isa/s390x/inst/emit_tests.rs
index ca59b0535..6c03b210b 100644
--- a/cranelift/codegen/src/isa/s390x/inst/emit_tests.rs
+++ b/cranelift/codegen/src/isa/s390x/inst/emit_tests.rs
@@ -6037,24 +6037,6 @@ fn test_s390x_binemit() {
         "stgrl %r1, label1",
     ));
 
-    insns.push((
-        Inst::Mvc {
-            dst: MemArgPair {
-                base: gpr(2),
-                disp: UImm12::maybe_from_u64(0x345).unwrap(),
-                flags: MemFlags::trusted(),
-            },
-            src: MemArgPair {
-                base: gpr(8),
-                disp: UImm12::maybe_from_u64(0x9ab).unwrap(),
-                flags: MemFlags::trusted(),
-            },
-            len_minus_one: 255,
-        },
-        "D2FF234589AB",
-        "mvc 837(255,%r2), 2475(%r8)",
-    ));
-
     insns.push((
         Inst::LoadMultiple64 {
             rt: writable_gpr(8),
diff --git a/crates/test-programs/src/lib.rs b/crates/test-programs/src/lib.rs
index bcb00225a..57e81dda1 100644
--- a/crates/test-programs/src/lib.rs
+++ b/crates/test-programs/src/lib.rs
@@ -8,8 +8,8 @@ wit_bindgen::generate!({
         package wasmtime:test;
 
         world test {
-            include wasi:cli/imports@0.2.1;
-            include wasi:http/imports@0.2.1;
+            include wasi:cli/imports@0.2.2;
+            include wasi:http/imports@0.2.2;
             include wasi:config/imports@0.2.0-draft;
             include wasi:keyvalue/imports@0.2.0-draft;
         }
@@ -31,17 +31,17 @@ pub mod proxy {
         default_bindings_module: "test_programs::proxy",
         pub_export_macro: true,
         with: {
-            "wasi:http/types@0.2.1": crate::wasi::http::types,
-            "wasi:http/outgoing-handler@0.2.1": crate::wasi::http::outgoing_handler,
-            "wasi:random/random@0.2.1": crate::wasi::random::random,
-            "wasi:io/error@0.2.1": crate::wasi::io::error,
-            "wasi:io/poll@0.2.1": crate::wasi::io::poll,
-            "wasi:io/streams@0.2.1": crate::wasi::io::streams,
-            "wasi:cli/stdout@0.2.1": crate::wasi::cli::stdout,
-            "wasi:cli/stderr@0.2.1": crate::wasi::cli::stderr,
-            "wasi:cli/stdin@0.2.1": crate::wasi::cli::stdin,
-            "wasi:clocks/monotonic-clock@0.2.1": crate::wasi::clocks::monotonic_clock,
-            "wasi:clocks/wall-clock@0.2.1": crate::wasi::clocks::wall_clock,
+            "wasi:http/types@0.2.2": crate::wasi::http::types,
+            "wasi:http/outgoing-handler@0.2.2": crate::wasi::http::outgoing_handler,
+            "wasi:random/random@0.2.2": crate::wasi::random::random,
+            "wasi:io/error@0.2.2": crate::wasi::io::error,
+            "wasi:io/poll@0.2.2": crate::wasi::io::poll,
+            "wasi:io/streams@0.2.2": crate::wasi::io::streams,
+            "wasi:cli/stdout@0.2.2": crate::wasi::cli::stdout,
+            "wasi:cli/stderr@0.2.2": crate::wasi::cli::stderr,
+            "wasi:cli/stdin@0.2.2": crate::wasi::cli::stdin,
+            "wasi:clocks/monotonic-clock@0.2.2": crate::wasi::clocks::monotonic_clock,
+            "wasi:clocks/wall-clock@0.2.2": crate::wasi::clocks::wall_clock,
         },
     });
 }
diff --git a/crates/wasi/wit/test.wit b/crates/wasi/wit/test.wit
index 14e531d08..4013722cd 100644
--- a/crates/wasi/wit/test.wit
+++ b/crates/wasi/wit/test.wit
@@ -1,13 +1,13 @@
 world test-reactor {
-  include wasi:cli/imports@0.2.1;
+  include wasi:cli/imports@0.2.2;
 
   export add-strings: func(s: list<string>) -> u32;
   export get-strings: func() -> list<string>;
 
-  use wasi:io/streams@0.2.1.{output-stream};
+  use wasi:io/streams@0.2.2.{output-stream};
 
   export write-strings-to: func(o: output-stream) -> result;
 
-  use wasi:filesystem/types@0.2.1.{descriptor-stat};
+  use wasi:filesystem/types@0.2.2.{descriptor-stat};
   export pass-an-imported-record: func(d: descriptor-stat) -> string;
 }
diff --git a/tests/all/pooling_allocator.rs b/tests/all/pooling_allocator.rs
index 4bf8e0d4c..fc6e98da7 100644
--- a/tests/all/pooling_allocator.rs
+++ b/tests/all/pooling_allocator.rs
@@ -1215,3 +1215,45 @@ fn decommit_batching() -> Result<()> {
 
     Ok(())
 }
+
+#[test]
+fn tricky_empty_table_with_empty_virtual_memory_alloc() -> Result<()> {
+    // Configure the pooling allocator to have no access to virtual memory, e.g.
+    // no table elements but a single table. This should technically support a
+    // single empty table being allocated into it but virtual memory isn't
+    // actually allocated here.
+    let mut cfg = PoolingAllocationConfig::default();
+    cfg.table_elements(0);
+    cfg.total_memories(0);
+    cfg.total_tables(1);
+    cfg.total_stacks(0);
+    cfg.total_core_instances(1);
+    cfg.max_memory_size(0);
+
+    let mut c = Config::new();
+    c.allocation_strategy(InstanceAllocationStrategy::Pooling(cfg));
+
+    // Disable lazy init to actually try to get this to do something interesting
+    // at runtime.
+    c.table_lazy_init(false);
+
+    let engine = Engine::new(&c)?;
+
+    // This module has a single empty table, with a single empty element
+    // segment. Nothing actually goes wrong here, it should instantiate
+    // successfully. Along the way though the empty mmap above will get viewed
+    // as an array-of-pointers, so everything internally should all line up to
+    // work ok.
+    let module = Module::new(
+        &engine,
+        r#"
+(module
+    (table 0 funcref)
+    (elem (i32.const 0) func)
+)
+"#,
+    )?;
+    let mut store = Store::new(&engine, ());
+    Instance::new(&mut store, &module, &[])?;
+    Ok(())
+}