Repository: bytecodealliance/wasmtime
Pull request #1699 (2020-05-14 14:23:05)

Reduce arm64 Inst enum size
This reduces the size of the Inst enum from 112 bytes to 48 bytes.

Using DHAT on a regex-rs.wasm benchmark, `valgrind --tool=dhat clif-util compile --target aarch64`

The total number of allocated bytes, drops by around 170 MB.
At t-gmax drops by 3 MB.

Using `perf stat clif-util compile --target aarch64`, the instructions count dropped by 0.6%. Cache misses dropped by 6%. Cycles dropped by 2.3%.

Suggestions (or help!) for measuring this further are welcomed.

Inspired by nnethercote's changes / articles about reducing enum sizes in rustc.

github-actions[bot]: #### Subscribe to Label Action

cc @bnjbvr

<details>
This issue or pull request has been labeled: "cranelift", "cranelift:area:aarch64"

Thus the following users have been cc'd because of the following labels:

* bnjbvr: cranelift

To subscribe or unsubscribe from this label, edit the <code>.github/subscribe-to-label.json</code> configuration file.

[Learn more.](https://github.com/bytecodealliance/subscribe-to-label-action)
</details>

Patch:
diff --git a/.github/labeler.yml b/.github/labeler.yml
index 5ad56966e..c332a8a7c 100644
--- a/.github/labeler.yml
+++ b/.github/labeler.yml
@@ -53,7 +53,7 @@
   - "crates/wiggle/**"
 
 "wasmtime:api":
-  - "crates/wasmtime/**"
+  - "crates/api/**"
 
 "wasmtime:c-api":
   - "crates/c-api/**"
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index e99a2c6b3..428c3b910 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -75,10 +75,10 @@ jobs:
         toolchain: nightly
 
     # Check some feature combinations of the `wasmtime` crate
-    - run: cargo check --manifest-path crates/wasmtime/Cargo.toml --no-default-features
-    - run: cargo check --manifest-path crates/wasmtime/Cargo.toml --features wat
-    - run: cargo check --manifest-path crates/wasmtime/Cargo.toml --features lightbeam
-    - run: cargo check --manifest-path crates/wasmtime/Cargo.toml --features jitdump
+    - run: cargo check --manifest-path crates/api/Cargo.toml --no-default-features
+    - run: cargo check --manifest-path crates/api/Cargo.toml --features wat
+    - run: cargo check --manifest-path crates/api/Cargo.toml --features lightbeam
+    - run: cargo check --manifest-path crates/api/Cargo.toml --features jitdump
 
     # Check some feature combinations of the `wasmtime-c-api` crate
     - run: cargo check --manifest-path crates/c-api/Cargo.toml --no-default-features
diff --git a/Cargo.toml b/Cargo.toml
index 9439ed5c0..7184ecd47 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -22,7 +22,7 @@ doc = false
 
 [dependencies]
 # Enable all supported architectures by default.
-wasmtime = { path = "crates/wasmtime", version = "0.16.0", default-features = false }
+wasmtime = { path = "crates/api", version = "0.16.0", default-features = false }
 wasmtime-debug = { path = "crates/debug", version = "0.16.0" }
 wasmtime-environ = { path = "crates/environ", version = "0.16.0" }
 wasmtime-jit = { path = "crates/jit", version = "0.16.0" }
diff --git a/cranelift/codegen/src/ir/trapcode.rs b/cranelift/codegen/src/ir/trapcode.rs
index 0f1f62e3b..3f8ffe3fb 100644
--- a/cranelift/codegen/src/ir/trapcode.rs
+++ b/cranelift/codegen/src/ir/trapcode.rs
@@ -27,6 +27,9 @@ pub enum TrapCode {
     /// A `table_addr` instruction detected an out-of-bounds error.
     TableOutOfBounds,
 
+    /// Other bounds checking error.
+    OutOfBounds,
+
     /// Indirect call to a null table entry.
     IndirectCallToNull,
 
@@ -60,6 +63,7 @@ impl Display for TrapCode {
             StackOverflow => "stk_ovf",
             HeapOutOfBounds => "heap_oob",
             TableOutOfBounds => "table_oob",
+            OutOfBounds => "oob",
             IndirectCallToNull => "icall_null",
             BadSignature => "bad_sig",
             IntegerOverflow => "int_ovf",
@@ -82,6 +86,7 @@ impl FromStr for TrapCode {
             "stk_ovf" => Ok(StackOverflow),
             "heap_oob" => Ok(HeapOutOfBounds),
             "table_oob" => Ok(TableOutOfBounds),
+            "oob" => Ok(OutOfBounds),
             "icall_null" => Ok(IndirectCallToNull),
             "bad_sig" => Ok(BadSignature),
             "int_ovf" => Ok(IntegerOverflow),
@@ -101,10 +106,11 @@ mod tests {
     use alloc::string::ToString;
 
     // Everything but user-defined codes.
-    const CODES: [TrapCode; 10] = [
+    const CODES: [TrapCode; 11] = [
         TrapCode::StackOverflow,
         TrapCode::HeapOutOfBounds,
         TrapCode::TableOutOfBounds,
+        TrapCode::OutOfBounds,
         TrapCode::IndirectCallToNull,
         TrapCode::BadSignature,
         TrapCode::IntegerOverflow,
diff --git a/cranelift/codegen/src/isa/aarch64/abi.rs b/cranelift/codegen/src/isa/aarch64/abi.rs
index e58a7d989..d90c23421 100644
--- a/cranelift/codegen/src/isa/aarch64/abi.rs
+++ b/cranelift/codegen/src/isa/aarch64/abi.rs
@@ -68,6 +68,7 @@ use crate::isa::aarch64::{self, inst::*};
 use crate::machinst::*;
 use crate::settings;
 
+use alloc::boxed::Box;
 use alloc::vec::Vec;
 
 use regalloc::{RealReg, Reg, RegClass, Set, SpillSlot, Writable};
@@ -1275,9 +1276,9 @@ impl ABICall for AArch64ABICall {
         );
         match &self.dest {
             &CallDest::ExtName(ref name, RelocDistance::Near) => ctx.emit(Inst::Call {
-                dest: name.clone(),
-                uses,
-                defs,
+                dest: Box::new(name.clone()),
+                uses: Box::new(uses),
+                defs: Box::new(defs),
                 loc: self.loc,
                 opcode: self.opcode,
             }),
@@ -1290,16 +1291,16 @@ impl ABICall for AArch64ABICall {
                 });
                 ctx.emit(Inst::CallInd {
                     rn: spilltmp_reg(),
-                    uses,
-                    defs,
+                    uses: Box::new(uses),
+                    defs: Box::new(defs),
                     loc: self.loc,
                     opcode: self.opcode,
                 });
             }
             &CallDest::Reg(reg) => ctx.emit(Inst::CallInd {
                 rn: reg,
-                uses,
-                defs,
+                uses: Box::new(uses),
+                defs: Box::new(defs),
                 loc: self.loc,
                 opcode: self.opcode,
             }),
diff --git a/cranelift/codegen/src/isa/aarch64/inst/emit.rs b/cranelift/codegen/src/isa/aarch64/inst/emit.rs
index da7da9205..5a9f9fef5 100644
--- a/cranelift/codegen/src/isa/aarch64/inst/emit.rs
+++ b/cranelift/codegen/src/isa/aarch64/inst/emit.rs
@@ -1303,7 +1303,7 @@ impl<O: MachSectionOutput> MachInstEmit<O> for Inst {
                 };
                 inst.emit(sink, flags, state);
                 // Emit jump table (table of 32-bit offsets).
-                for target in targets {
+                for target in targets.iter() {
                     let off = target.as_offset_words() * 4;
                     let off = i32::try_from(off).unwrap();
                     // cast i32 to u32 (two's-complement)
diff --git a/cranelift/codegen/src/isa/aarch64/inst/mod.rs b/cranelift/codegen/src/isa/aarch64/inst/mod.rs
index d852d81f5..3e4247ac1 100644
--- a/cranelift/codegen/src/isa/aarch64/inst/mod.rs
+++ b/cranelift/codegen/src/isa/aarch64/inst/mod.rs
@@ -12,6 +12,7 @@ use crate::{settings, CodegenError, CodegenResult};
 use regalloc::{RealRegUniverse, Reg, RegClass, SpillSlot, VirtualReg, Writable};
 use regalloc::{RegUsageCollector, RegUsageMapper, Set};
 
+use alloc::boxed::Box;
 use alloc::vec::Vec;
 use smallvec::{smallvec, SmallVec};
 use std::string::{String, ToString};
@@ -616,17 +617,17 @@ pub enum Inst {
     /// code should use a `LoadExtName` / `CallInd` sequence instead, allowing an arbitrary 64-bit
     /// target.
     Call {
-        dest: ExternalName,
-        uses: Set<Reg>,
-        defs: Set<Writable<Reg>>,
+        dest: Box<ExternalName>,
+        uses: Box<Set<Reg>>,
+        defs: Box<Set<Writable<Reg>>>,
         loc: SourceLoc,
         opcode: Opcode,
     },
     /// A machine indirect-call instruction.
     CallInd {
         rn: Reg,
-        uses: Set<Reg>,
-        defs: Set<Writable<Reg>>,
+        uses: Box<Set<Reg>>,
+        defs: Box<Set<Writable<Reg>>>,
         loc: SourceLoc,
         opcode: Opcode,
     },
@@ -704,8 +705,8 @@ pub enum Inst {
     /// Jump-table sequence, as one compound instruction (see note in lower.rs
     /// for rationale).
     JTSequence {
-        targets: Vec<BranchTarget>,
-        targets_for_term: Vec<BlockIndex>, // needed for MachTerminator.
+        targets: Box<[BranchTarget]>,
+        targets_for_term: Box<[BlockIndex]>, // needed for MachTerminator.
         ridx: Reg,
         rtmp1: Writable<Reg>,
         rtmp2: Writable<Reg>,
@@ -760,6 +761,13 @@ fn count_zero_half_words(mut value: u64) -> usize {
     count
 }
 
+#[test]
+fn inst_size_test() {
+    // This test will help with unintentionally growing the size
+    // of the Inst enum.
+    assert_eq!(48, std::mem::size_of::<Inst>());
+}
+
 impl Inst {
     /// Create a move instruction.
     pub fn mov(to_reg: Writable<Reg>, from_reg: Reg) -> Inst {
@@ -1090,8 +1098,8 @@ fn aarch64_get_regs(inst: &Inst, collector: &mut RegUsageCollector) {
         &Inst::Call {
             ref uses, ref defs, ..
         } => {
-            collector.add_uses(uses);
-            collector.add_defs(defs);
+            collector.add_uses(&*uses);
+            collector.add_defs(&*defs);
         }
         &Inst::CallInd {
             ref uses,
@@ -1099,8 +1107,8 @@ fn aarch64_get_regs(inst: &Inst, collector: &mut RegUsageCollector) {
             rn,
             ..
         } => {
-            collector.add_uses(uses);
-            collector.add_defs(defs);
+            collector.add_uses(&*uses);
+            collector.add_defs(&*defs);
             collector.add_use(rn);
         }
         &Inst::CondBr { ref kind, .. }
@@ -1643,8 +1651,8 @@ fn aarch64_map_regs(inst: &mut Inst, mapper: &RegUsageMapper) {
                 map_def(mapper, &mut r);
                 r
             });
-            *uses = new_uses;
-            *defs = new_defs;
+            *uses = Box::new(new_uses);
+            *defs = Box::new(new_defs);
         }
         &mut Inst::Ret | &mut Inst::EpiloguePlaceholder => {}
         &mut Inst::CallInd {
@@ -1664,8 +1672,8 @@ fn aarch64_map_regs(inst: &mut Inst, mapper: &RegUsageMapper) {
                 map_def(mapper, &mut r);
                 r
             });
-            *uses = new_uses;
-            *defs = new_defs;
+            *uses = Box::new(new_uses);
+            *defs = Box::new(new_defs);
             map_use(mapper, rn);
         }
         &mut Inst::CondBr { ref mut kind, .. } => {
@@ -1895,7 +1903,7 @@ impl MachInst for Inst {
             &mut Inst::JTSequence {
                 targets: ref mut t, ..
             } => {
-                for target in t {
+                for target in t.iter_mut() {
                     // offset+20: jumptable is 20 bytes into compound sequence.
                     target.lower(targets, my_offset + 20);
                 }
diff --git a/cranelift/codegen/src/isa/aarch64/lower_inst.rs b/cranelift/codegen/src/isa/aarch64/lower_inst.rs
index d00a0b464..ffa9e1101 100644
--- a/cranelift/codegen/src/isa/aarch64/lower_inst.rs
+++ b/cranelift/codegen/src/isa/aarch64/lower_inst.rs
@@ -2132,8 +2132,8 @@ pub(crate) fn lower_branch<C: LowerCtx<I = Inst>>(
                     ridx,
                     rtmp1,
                     rtmp2,
-                    targets: jt_targets,
-                    targets_for_term,
+                    targets: jt_targets.into_boxed_slice(),
+                    targets_for_term: targets_for_term.into_boxed_slice(),
                 });
             }
 
diff --git a/cranelift/docs/compare-llvm.md b/cranelift/docs/compare-llvm.md
index 22df7ed64..190a29a3f 100644
--- a/cranelift/docs/compare-llvm.md
+++ b/cranelift/docs/compare-llvm.md
@@ -3,11 +3,10 @@
 [LLVM](https://llvm.org) is a collection of compiler components implemented as
 a set of C++ libraries. It can be used to build both JIT compilers and static
 compilers like [Clang](https://clang.llvm.org), and it is deservedly very
-popular.
-[Chris Lattner's chapter about LLVM](https://www.aosabook.org/en/llvm.html)
-in the 
-[Architecture of Open Source Applications](https://aosabook.org/en/index.html>)
-book gives an excellent overview of the architecture and design of LLVM.
+popular. [Chris Lattner's chapter about LLVM]
+(https://www.aosabook.org/en/llvm.html) in the [Architecture of Open Source
+Applications](https://aosabook.org/en/index.html>) book gives an excellent
+overview of the architecture and design of LLVM.
 
 Cranelift and LLVM are superficially similar projects, so it is worth
 highlighting some of the differences and similarities. Both projects:
@@ -133,9 +132,9 @@ only has a single target and falls through to the next instruction when its
 condition is false. The Cranelift representation is closer to how machine code
 works; LLVM's representation is more abstract.
 
-LLVM uses
-[phi instructions](https://llvm.org/docs/LangRef.html#phi-instruction)
-in its SSA representation. Cranelift passes arguments to EBBs instead. The two
+LLVM uses [phi instructions]
+(https://llvm.org/docs/LangRef.html#phi-instruction) in its SSA
+representation. Cranelift passes arguments to EBBs instead. The two
 representations are equivalent, but the EBB arguments are better suited to
 handle EBBs that may contain multiple branches to the same destination block
 with different arguments. Passing arguments to an EBB looks a lot like passing
diff --git a/cranelift/docs/index.md b/cranelift/docs/index.md
index 2ca568d37..955001ef0 100644
--- a/cranelift/docs/index.md
+++ b/cranelift/docs/index.md
@@ -16,7 +16,7 @@
 
 ## Cranelift crate documentation:
 
- - [cranelift](https://docs.rs/cranelift)
+ - [cranelift](https://docs.rs/cranelift-codegen)
     This is an umbrella crate that re-exports the codegen and frontend crates,
     to make them easier to use.
 
diff --git a/crates/wasmtime/Cargo.toml b/crates/api/Cargo.toml
similarity index 100%
rename from crates/wasmtime/Cargo.toml
rename to crates/api/Cargo.toml
diff --git a/crates/wasmtime/LICENSE b/crates/api/LICENSE
similarity index 100%
rename from crates/wasmtime/LICENSE
rename to crates/api/LICENSE
diff --git a/crates/wasmtime/README.md b/crates/api/README.md
similarity index 100%
rename from crates/wasmtime/README.md
rename to crates/api/README.md
diff --git a/crates/wasmtime/src/externals.rs b/crates/api/src/externals.rs
similarity index 99%
rename from crates/wasmtime/src/externals.rs
rename to crates/api/src/externals.rs
index d97ccb22f..6536f017f 100644
--- a/crates/wasmtime/src/externals.rs
+++ b/crates/api/src/externals.rs
@@ -420,7 +420,7 @@ impl Table {
         let src_table = src_table.instance.get_defined_table(src_table_index);
 
         runtime::Table::copy(dst_table, src_table, dst_index, src_index, len)
-            .map_err(Trap::from_runtime)?;
+            .map_err(Trap::from_jit)?;
         Ok(())
     }
 
diff --git a/crates/wasmtime/src/frame_info.rs b/crates/api/src/frame_info.rs
similarity index 100%
rename from crates/wasmtime/src/frame_info.rs
rename to crates/api/src/frame_info.rs
diff --git a/crates/wasmtime/src/func.rs b/crates/api/src/func.rs
similarity index 98%
rename from crates/wasmtime/src/func.rs
rename to crates/api/src/func.rs
index dda4fcee7..b1b18be7c 100644
--- a/crates/wasmtime/src/func.rs
+++ b/crates/api/src/func.rs
@@ -8,8 +8,8 @@ use std::mem;
 use std::panic::{self, AssertUnwindSafe};
 use std::ptr;
 use std::rc::Weak;
-use wasmtime_runtime::{raise_user_trap, ExportFunction, VMTrampoline};
 use wasmtime_runtime::{Export, InstanceHandle, VMContext, VMFunctionBody};
+use wasmtime_runtime::{ExportFunction, VMTrampoline};
 
 /// A WebAssembly function which can be called.
 ///
@@ -747,7 +747,7 @@ pub(crate) fn catch_traps(
             signalhandler.as_deref(),
             closure,
         )
-        .map_err(Trap::from_runtime)
+        .map_err(Trap::from_jit)
     }
 }
 
@@ -941,7 +941,7 @@ unsafe impl<T: WasmTy> WasmRet for Result<T, Trap> {
         }
 
         fn handle_trap(trap: Trap) -> ! {
-            unsafe { raise_user_trap(trap.into()) }
+            unsafe { wasmtime_runtime::raise_user_trap(Box::new(trap)) }
         }
     }
 
@@ -1133,9 +1133,9 @@ macro_rules! impl_into_func {
                 R::push(&mut ret);
                 let ty = FuncType::new(_args.into(), ret.into());
                 let store_weak = store.weak();
-                let trampoline = trampoline::<$($args,)* R>;
-                let (instance, export) = unsafe {
-                    crate::trampoline::generate_raw_func_export(
+                unsafe {
+					let trampoline = trampoline::<$($args,)* R>;
+                    let (instance, export) = crate::trampoline::generate_raw_func_export(
                         &ty,
                         std::slice::from_raw_parts_mut(
                             shim::<F, $($args,)* R> as *mut _,
@@ -1145,12 +1145,12 @@ macro_rules! impl_into_func {
                         store,
                         Box::new((self, store_weak)),
                     )
-                    .expect("failed to generate export")
-                };
-                Func {
-                    instance,
-                    export,
-                    trampoline,
+                    .expect("failed to generate export");
+                    Func {
+                        instance,
+                        export,
+                        trampoline,
+                    }
                 }
             }
         }
diff --git a/crates/wasmtime/src/instance.rs b/crates/api/src/instance.rs
similarity index 99%
rename from crates/wasmtime/src/instance.rs
rename to crates/api/src/instance.rs
index a048eecaf..808f5d397 100644
--- a/crates/wasmtime/src/instance.rs
+++ b/crates/api/src/instance.rs
@@ -52,7 +52,7 @@ fn instantiate(
             .map_err(|e| -> Error {
                 match e {
                     InstantiationError::StartTrap(trap) | InstantiationError::Trap(trap) => {
-                        Trap::from_runtime(trap).into()
+                        Trap::from_jit(trap).into()
                     }
                     other => other.into(),
                 }
diff --git a/crates/wasmtime/src/lib.rs b/crates/api/src/lib.rs
similarity index 100%
rename from crates/wasmtime/src/lib.rs
rename to crates/api/src/lib.rs
diff --git a/crates/wasmtime/src/linker.rs b/crates/api/src/linker.rs
similarity index 100%
rename from crates/wasmtime/src/linker.rs
rename to crates/api/src/linker.rs
diff --git a/crates/wasmtime/src/module.rs b/crates/api/src/module.rs
similarity index 100%
rename from crates/wasmtime/src/module.rs
rename to crates/api/src/module.rs
diff --git a/crates/wasmtime/src/ref.rs b/crates/api/src/ref.rs
similarity index 100%
rename from crates/wasmtime/src/ref.rs
rename to crates/api/src/ref.rs
diff --git a/crates/wasmtime/src/runtime.rs b/crates/api/src/runtime.rs
similarity index 100%
rename from crates/wasmtime/src/runtime.rs
rename to crates/api/src/runtime.rs
diff --git a/crates/wasmtime/src/trampoline/create_handle.rs b/crates/api/src/trampoline/create_handle.rs
similarity index 100%
rename from crates/wasmtime/src/trampoline/create_handle.rs
rename to crates/api/src/trampoline/create_handle.rs
diff --git a/crates/wasmtime/src/trampoline/func.rs b/crates/api/src/trampoline/func.rs
similarity index 99%
rename from crates/wasmtime/src/trampoline/func.rs
rename to crates/api/src/trampoline/func.rs
index 41d6ac61b..c54f5f0fc 100644
--- a/crates/wasmtime/src/trampoline/func.rs
+++ b/crates/api/src/trampoline/func.rs
@@ -54,7 +54,7 @@ unsafe extern "C" fn stub_fn(
 
         // If a trap was raised (an error returned from the imported function)
         // then we smuggle the trap through `Box<dyn Error>` through to the
-        // call-site, which gets unwrapped in `Trap::from_runtime` later on as we
+        // call-site, which gets unwrapped in `Trap::from_jit` later on as we
         // convert from the internal `Trap` type to our own `Trap` type in this
         // crate.
         Ok(Err(trap)) => wasmtime_runtime::raise_user_trap(Box::new(trap)),
diff --git a/crates/wasmtime/src/trampoline/global.rs b/crates/api/src/trampoline/global.rs
similarity index 100%
rename from crates/wasmtime/src/trampoline/global.rs
rename to crates/api/src/trampoline/global.rs
diff --git a/crates/wasmtime/src/trampoline/memory.rs b/crates/api/src/trampoline/memory.rs
similarity index 100%
rename from crates/wasmtime/src/trampoline/memory.rs
rename to crates/api/src/trampoline/memory.rs
diff --git a/crates/wasmtime/src/trampoline/mod.rs b/crates/api/src/trampoline/mod.rs
similarity index 100%
rename from crates/wasmtime/src/trampoline/mod.rs
rename to crates/api/src/trampoline/mod.rs
diff --git a/crates/wasmtime/src/trampoline/table.rs b/crates/api/src/trampoline/table.rs
similarity index 100%
rename from crates/wasmtime/src/trampoline/table.rs
rename to crates/api/src/trampoline/table.rs
diff --git a/crates/wasmtime/src/trap.rs b/crates/api/src/trap.rs
similarity index 77%
rename from crates/wasmtime/src/trap.rs
rename to crates/api/src/trap.rs
index 4c160b4cf..b1bdd6afd 100644
--- a/crates/wasmtime/src/trap.rs
+++ b/crates/api/src/trap.rs
@@ -12,27 +12,8 @@ pub struct Trap {
     inner: Arc<TrapInner>,
 }
 
-/// State describing the occasion which evoked a trap.
-#[derive(Debug)]
-enum TrapReason {
-    /// An error message describing a trap.
-    Message(String),
-
-    /// An `i32` exit status describing an explicit program exit.
-    I32Exit(i32),
-}
-
-impl fmt::Display for TrapReason {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            TrapReason::Message(s) => write!(f, "{}", s),
-            TrapReason::I32Exit(status) => write!(f, "Exited with i32 exit status {}", status),
-        }
-    }
-}
-
 struct TrapInner {
-    reason: TrapReason,
+    message: String,
     wasm_trace: Vec<FrameInfo>,
     native_trace: Backtrace,
 }
@@ -53,21 +34,9 @@ impl Trap {
         Trap::new_with_trace(&info, None, message.into(), Backtrace::new_unresolved())
     }
 
-    /// Creates a new `Trap` representing an explicit program exit with a classic `i32`
-    /// exit status value.
-    pub fn i32_exit(status: i32) -> Self {
-        Trap {
-            inner: Arc::new(TrapInner {
-                reason: TrapReason::I32Exit(status),
-                wasm_trace: Vec::new(),
-                native_trace: Backtrace::from(Vec::new()),
-            }),
-        }
-    }
-
-    pub(crate) fn from_runtime(runtime_trap: wasmtime_runtime::Trap) -> Self {
+    pub(crate) fn from_jit(jit: wasmtime_runtime::Trap) -> Self {
         let info = FRAME_INFO.read().unwrap();
-        match runtime_trap {
+        match jit {
             wasmtime_runtime::Trap::User(error) => {
                 // Since we're the only one using the wasmtime internals (in
                 // theory) we should only see user errors which were originally
@@ -116,6 +85,7 @@ impl Trap {
             StackOverflow => "call stack exhausted",
             HeapOutOfBounds => "out of bounds memory access",
             TableOutOfBounds => "undefined element: out of bounds table access",
+            OutOfBounds => "out of bounds",
             IndirectCallToNull => "uninitialized element",
             BadSignature => "indirect call type mismatch",
             IntegerOverflow => "integer overflow",
@@ -158,7 +128,7 @@ impl Trap {
         }
         Trap {
             inner: Arc::new(TrapInner {
-                reason: TrapReason::Message(message),
+                message,
                 wasm_trace,
                 native_trace,
             }),
@@ -166,23 +136,8 @@ impl Trap {
     }
 
     /// Returns a reference the `message` stored in `Trap`.
-    ///
-    /// In the case of an explicit exit, the exit status can be obtained by
-    /// calling `i32_exit_status`.
     pub fn message(&self) -> &str {
-        match &self.inner.reason {
-            TrapReason::Message(message) => message,
-            TrapReason::I32Exit(_) => "explicitly exited",
-        }
-    }
-
-    /// If the trap was the result of an explicit program exit with a classic
-    /// `i32` exit status value, return the value, otherwise return `None`.
-    pub fn i32_exit_status(&self) -> Option<i32> {
-        match self.inner.reason {
-            TrapReason::I32Exit(status) => Some(status),
-            _ => None,
-        }
+        &self.inner.message
     }
 
     /// Returns a list of function frames in WebAssembly code that led to this
@@ -195,7 +150,7 @@ impl Trap {
 impl fmt::Debug for Trap {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("Trap")
-            .field("reason", &self.inner.reason)
+            .field("message", &self.inner.message)
             .field("wasm_trace", &self.inner.wasm_trace)
             .field("native_trace", &self.inner.native_trace)
             .finish()
@@ -204,7 +159,7 @@ impl fmt::Debug for Trap {
 
 impl fmt::Display for Trap {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{}", self.inner.reason)?;
+        write!(f, "{}", self.inner.message)?;
         let trace = self.trace();
         if trace.is_empty() {
             return Ok(());
diff --git a/crates/wasmtime/src/types.rs b/crates/api/src/types.rs
similarity index 100%
rename from crates/wasmtime/src/types.rs
rename to crates/api/src/types.rs
diff --git a/crates/wasmtime/src/unix.rs b/crates/api/src/unix.rs
similarity index 100%
rename from crates/wasmtime/src/unix.rs
rename to crates/api/src/unix.rs
diff --git a/crates/wasmtime/src/values.rs b/crates/api/src/values.rs
similarity index 100%
rename from crates/wasmtime/src/values.rs
rename to crates/api/src/values.rs
diff --git a/crates/wasmtime/src/windows.rs b/crates/api/src/windows.rs
similarity index 100%
rename from crates/wasmtime/src/windows.rs
rename to crates/api/src/windows.rs
diff --git a/crates/c-api/Cargo.toml b/crates/c-api/Cargo.toml
index f81723285..f87c150b0 100644
--- a/crates/c-api/Cargo.toml
+++ b/crates/c-api/Cargo.toml
@@ -19,7 +19,7 @@ doctest = false
 [dependencies]
 anyhow = "1.0"
 once_cell = "1.3"
-wasmtime = { path = "../wasmtime", default-features = false }
+wasmtime = { path = "../api", default-features = false }
 wasmtime-c-api-macros = { path = "macros" }
 
 # Optional dependency for the `wat2wasm` API
diff --git a/crates/c-api/include/wasmtime.h b/crates/c-api/include/wasmtime.h
index ec8ba8897..b37fbf813 100644
--- a/crates/c-api/include/wasmtime.h
+++ b/crates/c-api/include/wasmtime.h
@@ -254,32 +254,6 @@ WASM_API_EXTERN own wasmtime_error_t *wasmtime_module_validate(
     const wasm_byte_vec_t *binary
 );
 
-
-// Similar to `wasm_table_*`, except these explicitly operate on funcref tables
-// and work with `wasm_func_t` values instead of `wasm_ref_t`.
-WASM_API_EXTERN own wasmtime_error_t *wasmtime_funcref_table_new(
-    wasm_store_t *store,
-    const wasm_tabletype_t *element_ty,
-    wasm_func_t *init,
-    own wasm_table_t **table
-);
-WASM_API_EXTERN bool wasmtime_funcref_table_get(
-    const wasm_table_t *table,
-    wasm_table_size_t index,
-    own wasm_func_t **func
-);
-WASM_API_EXTERN own wasmtime_error_t *wasmtime_funcref_table_set(
-    wasm_table_t *table,
-    wasm_table_size_t index,
-    const wasm_func_t *value
-);
-WASM_API_EXTERN wasmtime_error_t *wasmtime_funcref_table_grow(
-    wasm_table_t *table,
-    wasm_table_size_t delta,
-    const wasm_func_t *init,
-    wasm_table_size_t *prev_size
-);
-
 #undef own
 
 #ifdef __cplusplus
diff --git a/crates/c-api/src/func.rs b/crates/c-api/src/func.rs
index 879248b23..3c58d1ca4 100644
--- a/crates/c-api/src/func.rs
+++ b/crates/c-api/src/func.rs
@@ -63,7 +63,7 @@ impl wasm_func_t {
         }
     }
 
-    pub(crate) fn func(&self) -> &HostRef<Func> {
+    fn func(&self) -> &HostRef<Func> {
         match &self.ext.which {
             ExternHost::Func(f) => f,
             _ => unsafe { std::hint::unreachable_unchecked() },
@@ -75,16 +75,6 @@ impl wasm_func_t {
     }
 }
 
-impl From<HostRef<Func>> for wasm_func_t {
-    fn from(func: HostRef<Func>) -> wasm_func_t {
-        wasm_func_t {
-            ext: wasm_extern_t {
-                which: ExternHost::Func(func),
-            },
-        }
-    }
-}
-
 fn create_function(
     store: &wasm_store_t,
     ty: &wasm_functype_t,
@@ -107,7 +97,11 @@ fn create_function(
         }
         Ok(())
     });
-    Box::new(HostRef::new(func).into())
+    Box::new(wasm_func_t {
+        ext: wasm_extern_t {
+            which: ExternHost::Func(HostRef::new(func)),
+        },
+    })
 }
 
 #[no_mangle]
diff --git a/crates/c-api/src/table.rs b/crates/c-api/src/table.rs
index 21fe1a7ae..a52b79048 100644
--- a/crates/c-api/src/table.rs
+++ b/crates/c-api/src/table.rs
@@ -1,4 +1,4 @@
-use crate::{handle_result, wasm_func_t, wasm_ref_t, wasmtime_error_t};
+use crate::wasm_ref_t;
 use crate::{wasm_extern_t, wasm_store_t, wasm_tabletype_t, ExternHost};
 use std::ptr;
 use wasmtime::{AnyRef, HostRef, Table, Val};
@@ -34,14 +34,15 @@ impl wasm_table_t {
 }
 
 #[no_mangle]
-pub extern "C" fn wasm_table_new(
+pub unsafe extern "C" fn wasm_table_new(
     store: &wasm_store_t,
     tt: &wasm_tabletype_t,
-    init: Option<Box<wasm_ref_t>>,
+    init: *mut wasm_ref_t,
 ) -> Option<Box<wasm_table_t>> {
-    let init: Val = match init {
-        Some(init) => init.r.into(),
-        None => Val::AnyRef(AnyRef::Null),
+    let init: Val = if !init.is_null() {
+        Box::from_raw(init).r.into()
+    } else {
+        Val::AnyRef(AnyRef::Null)
     };
     let table = Table::new(&store.store.borrow(), tt.ty().ty.clone(), init).ok()?;
     Some(Box::new(wasm_table_t {
@@ -51,30 +52,6 @@ pub extern "C" fn wasm_table_new(
     }))
 }
 
-#[no_mangle]
-pub extern "C" fn wasmtime_funcref_table_new(
-    store: &wasm_store_t,
-    tt: &wasm_tabletype_t,
-    init: Option<&wasm_func_t>,
-    out: &mut *mut wasm_table_t,
-) -> Option<Box<wasmtime_error_t>> {
-    let init: Val = match init {
-        Some(val) => Val::FuncRef(val.func().borrow().clone()),
-        None => Val::AnyRef(AnyRef::Null),
-    };
-    handle_result(
-        Table::new(&store.store.borrow(), tt.ty().ty.clone(), init),
-        |table| {
-            *out = Box::into_raw(Box::new(wasm_table_t {
-                ext: wasm_extern_t {
-                    which: ExternHost::Table(HostRef::new(table)),
-                },
-            }));
-            println!("ret at {:?}", *out);
-        },
-    )
-}
-
 #[no_mangle]
 pub extern "C" fn wasm_table_type(t: &wasm_table_t) -> Box<wasm_tabletype_t> {
     let ty = t.table().borrow().ty();
@@ -82,33 +59,14 @@ pub extern "C" fn wasm_table_type(t: &wasm_table_t) -> Box<wasm_tabletype_t> {
 }
 
 #[no_mangle]
-pub extern "C" fn wasm_table_get(t: &wasm_table_t, index: wasm_table_size_t) -> *mut wasm_ref_t {
-    match t.table().borrow().get(index) {
-        Some(val) => into_funcref(val),
-        None => into_funcref(Val::AnyRef(AnyRef::Null)),
-    }
-}
-
-#[no_mangle]
-pub extern "C" fn wasmtime_funcref_table_get(
+pub unsafe extern "C" fn wasm_table_get(
     t: &wasm_table_t,
     index: wasm_table_size_t,
-    ptr: &mut *mut wasm_func_t,
-) -> bool {
-    println!("get {:p} at {}", t, index);
+) -> *mut wasm_ref_t {
     match t.table().borrow().get(index) {
-        Some(val) => {
-            *ptr = match val {
-                // TODO: what do do about creating new `HostRef` handles here?
-                Val::FuncRef(f) => Box::into_raw(Box::new(HostRef::new(f).into())),
-                Val::AnyRef(AnyRef::Null) => ptr::null_mut(),
-                _ => return false,
-            };
-        }
-
-        _ => return false,
+        Some(val) => into_funcref(val),
+        None => into_funcref(Val::AnyRef(AnyRef::Null)),
     }
-    true
 }
 
 #[no_mangle]
@@ -121,20 +79,7 @@ pub unsafe extern "C" fn wasm_table_set(
     t.table().borrow().set(index, val).is_ok()
 }
 
-#[no_mangle]
-pub extern "C" fn wasmtime_funcref_table_set(
-    t: &wasm_table_t,
-    index: wasm_table_size_t,
-    val: Option<&wasm_func_t>,
-) -> Option<Box<wasmtime_error_t>> {
-    let val = match val {
-        Some(val) => Val::FuncRef(val.func().borrow().clone()),
-        None => Val::AnyRef(AnyRef::Null),
-    };
-    handle_result(t.table().borrow().set(index, val), |()| {})
-}
-
-fn into_funcref(val: Val) -> *mut wasm_ref_t {
+unsafe fn into_funcref(val: Val) -> *mut wasm_ref_t {
     if let Val::AnyRef(AnyRef::Null) = val {
         return ptr::null_mut();
     }
@@ -169,24 +114,6 @@ pub unsafe extern "C" fn wasm_table_grow(
     t.table().borrow().grow(delta, init).is_ok()
 }
 
-#[no_mangle]
-pub extern "C" fn wasmtime_funcref_table_grow(
-    t: &wasm_table_t,
-    delta: wasm_table_size_t,
-    init: Option<&wasm_func_t>,
-    prev_size: Option<&mut wasm_table_size_t>,
-) -> Option<Box<wasmtime_error_t>> {
-    let val = match init {
-        Some(val) => Val::FuncRef(val.func().borrow().clone()),
-        None => Val::AnyRef(AnyRef::Null),
-    };
-    handle_result(t.table().borrow().grow(delta, val), |prev| {
-        if let Some(ptr) = prev_size {
-            *ptr = prev;
-        }
-    })
-}
-
 #[no_mangle]
 pub extern "C" fn wasm_table_as_extern(t: &wasm_table_t) -> &wasm_extern_t {
     &t.ext
diff --git a/crates/fuzzing/Cargo.toml b/crates/fuzzing/Cargo.toml
index 4b2778d6b..830bbc692 100644
--- a/crates/fuzzing/Cargo.toml
+++ b/crates/fuzzing/Cargo.toml
@@ -15,7 +15,7 @@ log = "0.4.8"
 rayon = "1.2.1"
 wasmparser = "0.52.0"
 wasmprinter = "0.2.1"
-wasmtime = { path = "../wasmtime" }
+wasmtime = { path = "../api" }
 wasmtime-wast = { path = "../wast" }
 
 [dev-dependencies]
diff --git a/crates/misc/rust/Cargo.toml b/crates/misc/rust/Cargo.toml
index 61f804a23..875ac99b2 100644
--- a/crates/misc/rust/Cargo.toml
+++ b/crates/misc/rust/Cargo.toml
@@ -17,7 +17,7 @@ doctest = false
 [dependencies]
 wasmtime-rust-macro = { path = "./macro", version = "0.16.0" }
 wasmtime-wasi = { path = "../../wasi", version = "0.16.0" }
-wasmtime = { path = "../../wasmtime", version = "0.16.0" }
+wasmtime = { path = "../../api", version = "0.16.0" }
 anyhow = "1.0.19"
 
 [badges]
diff --git a/crates/wasi-common/src/old/snapshot_0/hostcalls_impl/misc.rs b/crates/wasi-common/src/old/snapshot_0/hostcalls_impl/misc.rs
index d6f4d2468..922d8b304 100644
--- a/crates/wasi-common/src/old/snapshot_0/hostcalls_impl/misc.rs
+++ b/crates/wasi-common/src/old/snapshot_0/hostcalls_impl/misc.rs
@@ -342,6 +342,13 @@ pub(crate) struct FdEventData<'a> {
     pub(crate) userdata: wasi::__wasi_userdata_t,
 }
 
+pub(crate) fn proc_exit(_wasi_ctx: &WasiCtx, _memory: &mut [u8], rval: wasi::__wasi_exitcode_t) {
+    trace!("proc_exit(rval={:?})", rval);
+    // TODO: Rather than call std::process::exit here, we should trigger a
+    // stack unwind similar to a trap.
+    std::process::exit(rval as i32);
+}
+
 pub(crate) fn proc_raise(
     _wasi_ctx: &WasiCtx,
     _memory: &mut [u8],
diff --git a/crates/wasi-common/src/snapshots/wasi_snapshot_preview1.rs b/crates/wasi-common/src/snapshots/wasi_snapshot_preview1.rs
index 31117243a..4ab53f5d6 100644
--- a/crates/wasi-common/src/snapshots/wasi_snapshot_preview1.rs
+++ b/crates/wasi-common/src/snapshots/wasi_snapshot_preview1.rs
@@ -813,10 +813,13 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx {
         Ok(nevents)
     }
 
-    fn proc_exit(&self, _rval: types::Exitcode) -> std::result::Result<(), ()> {
-        // proc_exit is special in that it's expected to unwind the stack, which
-        // typically requires runtime-specific logic.
-        unimplemented!("runtimes are expected to override this implementation")
+    // This is just a temporary to ignore the warning which becomes a hard error
+    // in the CI. Once we figure out non-returns in `wiggle`, this should be gone.
+    #[allow(unreachable_code)]
+    fn proc_exit(&self, rval: types::Exitcode) -> std::result::Result<(), ()> {
+        // TODO: Rather than call std::process::exit here, we should trigger a
+        // stack unwind similar to a trap.
+        std::process::exit(rval as i32);
     }
 
     fn proc_raise(&self, _sig: types::Signal) -> Result<()> {
diff --git a/crates/wasi-common/wig/src/hostcalls.rs b/crates/wasi-common/wig/src/hostcalls.rs
index 2ea4e6e5e..0b73cae6d 100644
--- a/crates/wasi-common/wig/src/hostcalls.rs
+++ b/crates/wasi-common/wig/src/hostcalls.rs
@@ -17,13 +17,6 @@ pub fn define(args: TokenStream) -> TokenStream {
 
     for module in doc.modules() {
         for func in module.funcs() {
-            // `proc_exit` is special; it's essentially an unwinding primitive,
-            // so we implement it in the runtime rather than use the implementation
-            // in wasi-common.
-            if func.name.as_str() == "proc_exit" {
-                continue;
-            }
-
             ret.extend(generate_wrappers(&func, old));
         }
     }
diff --git a/crates/wasi-common/wig/src/wasi.rs b/crates/wasi-common/wig/src/wasi.rs
index 39e263c7a..b87484e53 100644
--- a/crates/wasi-common/wig/src/wasi.rs
+++ b/crates/wasi-common/wig/src/wasi.rs
@@ -46,15 +46,6 @@ pub fn define_struct(args: TokenStream) -> TokenStream {
             linker_add.push(quote! {
                 linker.define(#module_name, #name, self.#name_ident.clone())?;
             });
-            // `proc_exit` is special; it's essentially an unwinding primitive,
-            // so we implement it in the runtime rather than use the implementation
-            // in wasi-common.
-            if name == "proc_exit" {
-                ctor_externs.push(quote! {
-                    let #name_ident = wasmtime::Func::wrap(store, crate::wasi_proc_exit);
-                });
-                continue;
-            }
 
             let mut shim_arg_decls = Vec::new();
             let mut params = Vec::new();
@@ -300,15 +291,6 @@ pub fn define_struct_for_wiggle(args: TokenStream) -> TokenStream {
             linker_add.push(quote! {
                 linker.define(#module_name, #name, self.#name_ident.clone())?;
             });
-            // `proc_exit` is special; it's essentially an unwinding primitive,
-            // so we implement it in the runtime rather than use the implementation
-            // in wasi-common.
-            if name == "proc_exit" {
-                ctor_externs.push(quote! {
-                    let #name_ident = wasmtime::Func::wrap(store, crate::wasi_proc_exit);
-                });
-                continue;
-            }
 
             let mut shim_arg_decls = Vec::new();
             let mut params = Vec::new();
diff --git a/crates/wasi/Cargo.toml b/crates/wasi/Cargo.toml
index 8d0b67701..ab84856a4 100644
--- a/crates/wasi/Cargo.toml
+++ b/crates/wasi/Cargo.toml
@@ -15,7 +15,7 @@ edition = "2018"
 anyhow = "1.0"
 log = { version = "0.4.8", default-features = false }
 wasi-common = { path = "../wasi-common", version = "0.16.0" }
-wasmtime = { path = "../wasmtime", version = "0.16.0", default-features = false }
+wasmtime = { path = "../api", version = "0.16.0", default-features = false }
 wasmtime-runtime = { path = "../runtime", version = "0.16.0" }
 wig = { path = "../wasi-common/wig", version = "0.16.0" }
 wiggle = { path = "../wiggle", version = "0.16.0" }
diff --git a/crates/wasi/src/lib.rs b/crates/wasi/src/lib.rs
index e92b1d21d..d8e8be07f 100644
--- a/crates/wasi/src/lib.rs
+++ b/crates/wasi/src/lib.rs
@@ -1,5 +1,3 @@
-use wasmtime::Trap;
-
 pub mod old;
 
 pub use wasi_common::{WasiCtx, WasiCtxBuilder};
@@ -14,17 +12,3 @@ pub fn is_wasi_module(name: &str) -> bool {
     // trick.
     name.starts_with("wasi")
 }
-
-/// Implement the WASI `proc_exit` function. This function is implemented here
-/// instead of in wasi-common so that we can use the runtime to perform an
-/// unwind rather than exiting the host process.
-fn wasi_proc_exit(status: i32) -> Result<(), Trap> {
-    // Check that the status is within WASI's range.
-    if status >= 0 && status < 126 {
-        Err(Trap::i32_exit(status))
-    } else {
-        Err(Trap::new(
-            "exit with invalid exit status outside of [0..126)",
-        ))
-    }
-}
diff --git a/crates/wast/Cargo.toml b/crates/wast/Cargo.toml
index e0759cf54..b83b3fec5 100644
--- a/crates/wast/Cargo.toml
+++ b/crates/wast/Cargo.toml
@@ -12,7 +12,7 @@ edition = "2018"
 
 [dependencies]
 anyhow = "1.0.19"
-wasmtime = { path = "../wasmtime", version = "0.16.0", default-features = false }
+wasmtime = { path = "../api", version = "0.16.0", default-features = false }
 wast = "15.0.0"
 
 [badges]
diff --git a/crates/wast/src/wast.rs b/crates/wast/src/wast.rs
index 5c3c22531..83450bac9 100644
--- a/crates/wast/src/wast.rs
+++ b/crates/wast/src/wast.rs
@@ -123,7 +123,7 @@ impl WastContext {
     fn module(&mut self, instance_name: Option<&str>, module: &[u8]) -> Result<()> {
         let instance = match self.instantiate(module)? {
             Outcome::Ok(i) => i,
-            Outcome::Trap(e) => bail!("instantiation failed: {}", e.message()),
+            Outcome::Trap(e) => bail!("instantiation failed with: {}", e.message()),
         };
         if let Some(name) = instance_name {
             self.linker.instance(name, &instance)?;
diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml
index 38fa092d5..ace402161 100644
--- a/fuzz/Cargo.toml
+++ b/fuzz/Cargo.toml
@@ -14,7 +14,7 @@ cranelift-reader = { path = "../cranelift/reader" }
 cranelift-wasm = { path = "../cranelift/wasm" }
 libfuzzer-sys = "0.3.2"
 target-lexicon = "0.10"
-wasmtime = { path = "../crates/wasmtime" }
+wasmtime = { path = "../crates/api" }
 wasmtime-fuzzing = { path = "../crates/fuzzing" }
 
 [[bin]]
diff --git a/scripts/publish-wasmtime.sh b/scripts/publish-wasmtime.sh
index 67e1d0d65..7b7908b1c 100755
--- a/scripts/publish-wasmtime.sh
+++ b/scripts/publish-wasmtime.sh
@@ -32,7 +32,7 @@ for cargo_toml in \
     crates/profiling/Cargo.toml \
     crates/debug/Cargo.toml \
     crates/jit/Cargo.toml \
-    crates/wasmtime/Cargo.toml \
+    crates/api/Cargo.toml \
     crates/wasi/Cargo.toml \
     crates/wast/Cargo.toml \
     crates/misc/rust/macro/Cargo.toml \
diff --git a/src/commands/run.rs b/src/commands/run.rs
index d25340209..d30785eb6 100644
--- a/src/commands/run.rs
+++ b/src/commands/run.rs
@@ -142,24 +142,13 @@ impl RunCommand {
         {
             Ok(()) => (),
             Err(e) => {
-                // If the program exited because of a non-zero exit status, print
-                // a message and exit.
-                if let Some(trap) = e.downcast_ref::<Trap>() {
+                // If the program exited because of a trap, return an error code
+                // to the outside environment indicating a more severe problem
+                // than a simple failure.
+                if e.is::<Trap>() {
                     // Print the error message in the usual way.
                     eprintln!("Error: {:?}", e);
 
-                    if let Some(status) = trap.i32_exit_status() {
-                        // On Windows, exit status 3 indicates an abort (see below),
-                        // so return 1 indicating a non-zero status to avoid ambiguity.
-                        if cfg!(windows) && status >= 3 {
-                            process::exit(1);
-                        }
-                        process::exit(status);
-                    }
-
-                    // If the program exited because of a trap, return an error code
-                    // to the outside environment indicating a more severe problem
-                    // than a simple failure.
                     if cfg!(unix) {
                         // On Unix, return the error code of an abort.
                         process::exit(128 + libc::SIGABRT);


Test patch:
diff --git a/cranelift/codegen/src/isa/aarch64/inst/emit_tests.rs b/cranelift/codegen/src/isa/aarch64/inst/emit_tests.rs
index d9d2fe0fd..f98d3c6b0 100644
--- a/cranelift/codegen/src/isa/aarch64/inst/emit_tests.rs
+++ b/cranelift/codegen/src/isa/aarch64/inst/emit_tests.rs
@@ -3,6 +3,7 @@ use crate::isa::aarch64::inst::*;
 use crate::isa::test_utils;
 use crate::settings;
 
+use alloc::boxed::Box;
 use alloc::vec::Vec;
 
 #[test]
@@ -2112,9 +2113,9 @@ fn test_aarch64_binemit() {
 
     insns.push((
         Inst::Call {
-            dest: ExternalName::testcase("test0"),
-            uses: Set::empty(),
-            defs: Set::empty(),
+            dest: Box::new(ExternalName::testcase("test0")),
+            uses: Box::new(Set::empty()),
+            defs: Box::new(Set::empty()),
             loc: SourceLoc::default(),
             opcode: Opcode::Call,
         },
@@ -2125,8 +2126,8 @@ fn test_aarch64_binemit() {
     insns.push((
         Inst::CallInd {
             rn: xreg(10),
-            uses: Set::empty(),
-            defs: Set::empty(),
+            uses: Box::new(Set::empty()),
+            defs: Box::new(Set::empty()),
             loc: SourceLoc::default(),
             opcode: Opcode::CallIndirect,
         },
diff --git a/cranelift/filetests/filetests/parser/flags.clif b/cranelift/filetests/filetests/parser/flags.clif
index f8d9cd2b7..c8d6e7891 100644
--- a/cranelift/filetests/filetests/parser/flags.clif
+++ b/cranelift/filetests/filetests/parser/flags.clif
@@ -25,7 +25,7 @@ block201:
     return
 
 block202:
-    trap heap_oob
+    trap oob
 }
 ; check: v1 = ifcmp_imm v0, 17
 ; check: brif eq v1, block201
@@ -56,7 +56,7 @@ block201:
     return
 
 block202:
-    trap heap_oob
+    trap oob
 }
 ; check: v2 = ffcmp v0, v1
 ; check: brff eq v2, block201
diff --git a/cranelift/filetests/filetests/parser/tiny.clif b/cranelift/filetests/filetests/parser/tiny.clif
index 3f825e6ea..98f477f80 100644
--- a/cranelift/filetests/filetests/parser/tiny.clif
+++ b/cranelift/filetests/filetests/parser/tiny.clif
@@ -223,7 +223,7 @@ function %cond_traps(i32) {
 block0(v0: i32):
     trapz v0, stk_ovf
     v1 = ifcmp_imm v0, 5
-    trapif ugt v1, heap_oob
+    trapif ugt v1, oob
     v2 = bitcast.f32 v1
     v3 = ffcmp v2, v2
     trapff uno v3, int_ovf
@@ -233,7 +233,7 @@ block0(v0: i32):
 ; nextln: block0(v0: i32):
 ; nextln:     trapz v0, stk_ovf
 ; nextln:     v1 = ifcmp_imm v0, 5
-; nextln:     trapif ugt v1, heap_oob
+; nextln:     trapif ugt v1, oob
 ; nextln:     v2 = bitcast.f32 v1
 ; nextln:     v3 = ffcmp v2, v2
 ; nextln:     trapff uno v3, int_ovf
diff --git a/cranelift/filetests/filetests/regalloc/iterate.clif b/cranelift/filetests/filetests/regalloc/iterate.clif
index f3ed963d7..2c7d69176 100644
--- a/cranelift/filetests/filetests/regalloc/iterate.clif
+++ b/cranelift/filetests/filetests/regalloc/iterate.clif
@@ -139,7 +139,7 @@ block0(v0: i64):
     jump block4
 
 block4:
-    trap heap_oob
+    trap oob
 
 block2:
     v8 = load.i64 v5+8
diff --git a/cranelift/filetests/filetests/wasm/control.clif b/cranelift/filetests/filetests/wasm/control.clif
index 4f40ddffb..d00c5b316 100644
--- a/cranelift/filetests/filetests/wasm/control.clif
+++ b/cranelift/filetests/filetests/wasm/control.clif
@@ -54,7 +54,7 @@ block0(v0: i32):
     br_table v0, block4, jt0
 
 block4:
-    trap heap_oob
+    trap oob
 
 block1:
     return
diff --git a/crates/test-programs/Cargo.toml b/crates/test-programs/Cargo.toml
index d6657fe10..a42189620 100644
--- a/crates/test-programs/Cargo.toml
+++ b/crates/test-programs/Cargo.toml
@@ -12,7 +12,7 @@ cfg-if = "0.1.9"
 [dev-dependencies]
 wasi-common = { path = "../wasi-common", version = "0.16.0" }
 wasmtime-wasi = { path = "../wasi", version = "0.16.0" }
-wasmtime = { path = "../wasmtime", version = "0.16.0" }
+wasmtime = { path = "../api", version = "0.16.0" }
 target-lexicon = "0.10.0"
 pretty_env_logger = "0.4.0"
 tempfile = "3.1.0"
diff --git a/tests/all/cli_tests.rs b/tests/all/cli_tests.rs
index c8edbd1fb..04500f213 100644
--- a/tests/all/cli_tests.rs
+++ b/tests/all/cli_tests.rs
@@ -182,77 +182,3 @@ fn timeout_in_invoke() -> Result<()> {
     );
     Ok(())
 }
-
-// Exit with a valid non-zero exit code, snapshot0 edition.
-#[test]
-fn exit2_wasi_snapshot0() -> Result<()> {
-    let wasm = build_wasm("tests/wasm/exit2_wasi_snapshot0.wat")?;
-    let output = run_wasmtime_for_output(&[wasm.path().to_str().unwrap(), "--disable-cache"])?;
-    assert_eq!(output.status.code().unwrap(), 2);
-    Ok(())
-}
-
-// Exit with a valid non-zero exit code, snapshot1 edition.
-#[test]
-fn exit2_wasi_snapshot1() -> Result<()> {
-    let wasm = build_wasm("tests/wasm/exit2_wasi_snapshot1.wat")?;
-    let output = run_wasmtime_for_output(&[wasm.path().to_str().unwrap(), "--disable-cache"])?;
-    assert_eq!(output.status.code().unwrap(), 2);
-    Ok(())
-}
-
-// Exit with a valid non-zero exit code, snapshot0 edition.
-#[test]
-fn exit125_wasi_snapshot0() -> Result<()> {
-    let wasm = build_wasm("tests/wasm/exit125_wasi_snapshot0.wat")?;
-    let output = run_wasmtime_for_output(&[wasm.path().to_str().unwrap(), "--disable-cache"])?;
-    if cfg!(windows) {
-        assert_eq!(output.status.code().unwrap(), 1);
-    } else {
-        assert_eq!(output.status.code().unwrap(), 125);
-    }
-    Ok(())
-}
-
-// Exit with a valid non-zero exit code, snapshot1 edition.
-#[test]
-fn exit125_wasi_snapshot1() -> Result<()> {
-    let wasm = build_wasm("tests/wasm/exit125_wasi_snapshot1.wat")?;
-    let output = run_wasmtime_for_output(&[wasm.path().to_str().unwrap(), "--disable-cache"])?;
-    if cfg!(windows) {
-        assert_eq!(output.status.code().unwrap(), 1);
-    } else {
-        assert_eq!(output.status.code().unwrap(), 125);
-    }
-    Ok(())
-}
-
-// Exit with an invalid non-zero exit code, snapshot0 edition.
-#[test]
-fn exit126_wasi_snapshot0() -> Result<()> {
-    let wasm = build_wasm("tests/wasm/exit126_wasi_snapshot0.wat")?;
-    let output = run_wasmtime_for_output(&[wasm.path().to_str().unwrap(), "--disable-cache"])?;
-    if cfg!(windows) {
-        assert_eq!(output.status.code().unwrap(), 3);
-    } else {
-        assert_eq!(output.status.code().unwrap(), 128 + libc::SIGABRT);
-    }
-    assert!(output.stdout.is_empty());
-    assert!(String::from_utf8_lossy(&output.stderr).contains("invalid exit status"));
-    Ok(())
-}
-
-// Exit with an invalid non-zero exit code, snapshot1 edition.
-#[test]
-fn exit126_wasi_snapshot1() -> Result<()> {
-    let wasm = build_wasm("tests/wasm/exit126_wasi_snapshot1.wat")?;
-    let output = run_wasmtime_for_output(&[wasm.path().to_str().unwrap(), "--disable-cache"])?;
-    if cfg!(windows) {
-        assert_eq!(output.status.code().unwrap(), 3);
-    } else {
-        assert_eq!(output.status.code().unwrap(), 128 + libc::SIGABRT);
-    }
-    assert!(output.stdout.is_empty());
-    assert!(String::from_utf8_lossy(&output.stderr).contains("invalid exit status"));
-    Ok(())
-}
diff --git a/tests/all/func.rs b/tests/all/func.rs
index 16da165ba..ea5584056 100644
--- a/tests/all/func.rs
+++ b/tests/all/func.rs
@@ -182,7 +182,6 @@ fn trap_smoke() -> Result<()> {
     let f = Func::wrap(&store, || -> Result<(), Trap> { Err(Trap::new("test")) });
     let err = f.call(&[]).unwrap_err().downcast::<Trap>()?;
     assert_eq!(err.message(), "test");
-    assert!(err.i32_exit_status().is_none());
     Ok(())
 }
 
diff --git a/tests/all/iloop.rs b/tests/all/iloop.rs
index abfe5e4b3..9e0f5aa85 100644
--- a/tests/all/iloop.rs
+++ b/tests/all/iloop.rs
@@ -30,7 +30,7 @@ fn loops_interruptable() -> anyhow::Result<()> {
     let iloop = instance.get_func("loop").unwrap().get0::<()>()?;
     store.interrupt_handle()?.interrupt();
     let trap = iloop().unwrap_err();
-    assert!(trap.to_string().contains("wasm trap: interrupt"));
+    assert!(trap.message().contains("wasm trap: interrupt"));
     Ok(())
 }
 
@@ -44,9 +44,9 @@ fn functions_interruptable() -> anyhow::Result<()> {
     store.interrupt_handle()?.interrupt();
     let trap = iloop().unwrap_err();
     assert!(
-        trap.to_string().contains("wasm trap: interrupt"),
+        trap.message().contains("wasm trap: interrupt"),
         "{}",
-        trap.to_string()
+        trap.message()
     );
     Ok(())
 }
@@ -91,9 +91,9 @@ fn loop_interrupt_from_afar() -> anyhow::Result<()> {
     let trap = iloop().unwrap_err();
     thread.join().unwrap();
     assert!(
-        trap.to_string().contains("wasm trap: interrupt"),
+        trap.message().contains("wasm trap: interrupt"),
         "bad message: {}",
-        trap.to_string()
+        trap.message()
     );
     Ok(())
 }
@@ -127,9 +127,9 @@ fn function_interrupt_from_afar() -> anyhow::Result<()> {
     let trap = iloop().unwrap_err();
     thread.join().unwrap();
     assert!(
-        trap.to_string().contains("wasm trap: interrupt"),
+        trap.message().contains("wasm trap: interrupt"),
         "bad message: {}",
-        trap.to_string()
+        trap.message()
     );
     Ok(())
 }
diff --git a/tests/all/stack_overflow.rs b/tests/all/stack_overflow.rs
index 9d63dbdc4..283426130 100644
--- a/tests/all/stack_overflow.rs
+++ b/tests/all/stack_overflow.rs
@@ -30,9 +30,9 @@ fn host_always_has_some_stack() -> anyhow::Result<()> {
     // has been exhausted.
     let trap = foo().unwrap_err();
     assert!(
-        trap.to_string().contains("call stack exhausted"),
+        trap.message().contains("call stack exhausted"),
         "{}",
-        trap.to_string()
+        trap.message()
     );
 
     // Additionally, however, and this is the crucial test, make sure that the
diff --git a/tests/wasm/exit125_wasi_snapshot0.wat b/tests/wasm/exit125_wasi_snapshot0.wat
deleted file mode 100644
index 03e2ae900..000000000
--- a/tests/wasm/exit125_wasi_snapshot0.wat
+++ /dev/null
@@ -1,8 +0,0 @@
-(module
-  (import "wasi_unstable" "proc_exit"
-    (func $__wasi_proc_exit (param i32)))
-  (func $_start
-    (call $__wasi_proc_exit (i32.const 125))
-  )
-  (export "_start" (func $_start))
-)
diff --git a/tests/wasm/exit125_wasi_snapshot1.wat b/tests/wasm/exit125_wasi_snapshot1.wat
deleted file mode 100644
index 6d2dbbfd3..000000000
--- a/tests/wasm/exit125_wasi_snapshot1.wat
+++ /dev/null
@@ -1,8 +0,0 @@
-(module
-  (import "wasi_snapshot_preview1" "proc_exit"
-    (func $__wasi_proc_exit (param i32)))
-  (func $_start
-    (call $__wasi_proc_exit (i32.const 125))
-  )
-  (export "_start" (func $_start))
-)
diff --git a/tests/wasm/exit126_wasi_snapshot0.wat b/tests/wasm/exit126_wasi_snapshot0.wat
deleted file mode 100644
index 091e61001..000000000
--- a/tests/wasm/exit126_wasi_snapshot0.wat
+++ /dev/null
@@ -1,8 +0,0 @@
-(module
-  (import "wasi_unstable" "proc_exit"
-    (func $__wasi_proc_exit (param i32)))
-  (func $_start
-    (call $__wasi_proc_exit (i32.const 126))
-  )
-  (export "_start" (func $_start))
-)
diff --git a/tests/wasm/exit126_wasi_snapshot1.wat b/tests/wasm/exit126_wasi_snapshot1.wat
deleted file mode 100644
index e481533c5..000000000
--- a/tests/wasm/exit126_wasi_snapshot1.wat
+++ /dev/null
@@ -1,8 +0,0 @@
-(module
-  (import "wasi_snapshot_preview1" "proc_exit"
-    (func $__wasi_proc_exit (param i32)))
-  (func $_start
-    (call $__wasi_proc_exit (i32.const 126))
-  )
-  (export "_start" (func $_start))
-)
diff --git a/tests/wasm/exit2_wasi_snapshot0.wat b/tests/wasm/exit2_wasi_snapshot0.wat
deleted file mode 100644
index 244d7b604..000000000
--- a/tests/wasm/exit2_wasi_snapshot0.wat
+++ /dev/null
@@ -1,8 +0,0 @@
-(module
-  (import "wasi_unstable" "proc_exit"
-    (func $__wasi_proc_exit (param i32)))
-  (func $_start
-    (call $__wasi_proc_exit (i32.const 2))
-  )
-  (export "_start" (func $_start))
-)
diff --git a/tests/wasm/exit2_wasi_snapshot1.wat b/tests/wasm/exit2_wasi_snapshot1.wat
deleted file mode 100644
index 75f64407a..000000000
--- a/tests/wasm/exit2_wasi_snapshot1.wat
+++ /dev/null
@@ -1,8 +0,0 @@
-(module
-  (import "wasi_snapshot_preview1" "proc_exit"
-    (func $__wasi_proc_exit (param i32)))
-  (func $_start
-    (call $__wasi_proc_exit (i32.const 2))
-  )
-  (export "_start" (func $_start))
-)