Implement RFC 11: Redesigning Wasmtime's APIs (#2897)
Implement Wasmtime's new API as designed by RFC 11. This is quite a large commit which has had lots of discussion externally, so for more information it's best to read the RFC thread and the PR thread.
This commit is contained in:
@@ -5,7 +5,7 @@ use wasmtime::*;
|
||||
|
||||
#[test]
|
||||
fn test_trap_return() -> Result<()> {
|
||||
let store = Store::default();
|
||||
let mut store = Store::<()>::default();
|
||||
let wat = r#"
|
||||
(module
|
||||
(func $hello (import "" "hello"))
|
||||
@@ -15,12 +15,15 @@ fn test_trap_return() -> Result<()> {
|
||||
|
||||
let module = Module::new(store.engine(), wat)?;
|
||||
let hello_type = FuncType::new(None, None);
|
||||
let hello_func = Func::new(&store, hello_type, |_, _, _| Err(Trap::new("test 123")));
|
||||
let hello_func = Func::new(&mut store, hello_type, |_, _, _| Err(Trap::new("test 123")));
|
||||
|
||||
let instance = Instance::new(&store, &module, &[hello_func.into()])?;
|
||||
let run_func = instance.get_typed_func::<(), ()>("run")?;
|
||||
let instance = Instance::new(&mut store, &module, &[hello_func.into()])?;
|
||||
let run_func = instance.get_typed_func::<(), (), _>(&mut store, "run")?;
|
||||
|
||||
let e = run_func.call(()).err().expect("error calling function");
|
||||
let e = run_func
|
||||
.call(&mut store, ())
|
||||
.err()
|
||||
.expect("error calling function");
|
||||
assert!(e.to_string().contains("test 123"));
|
||||
|
||||
Ok(())
|
||||
@@ -29,7 +32,7 @@ fn test_trap_return() -> Result<()> {
|
||||
#[test]
|
||||
#[cfg_attr(all(target_os = "macos", target_arch = "aarch64"), ignore)] // TODO #2808 system libunwind is broken on aarch64
|
||||
fn test_trap_trace() -> Result<()> {
|
||||
let store = Store::default();
|
||||
let mut store = Store::<()>::default();
|
||||
let wat = r#"
|
||||
(module $hello_mod
|
||||
(func (export "run") (call $hello))
|
||||
@@ -38,10 +41,13 @@ fn test_trap_trace() -> Result<()> {
|
||||
"#;
|
||||
|
||||
let module = Module::new(store.engine(), wat)?;
|
||||
let instance = Instance::new(&store, &module, &[])?;
|
||||
let run_func = instance.get_typed_func::<(), ()>("run")?;
|
||||
let instance = Instance::new(&mut store, &module, &[])?;
|
||||
let run_func = instance.get_typed_func::<(), (), _>(&mut store, "run")?;
|
||||
|
||||
let e = run_func.call(()).err().expect("error calling function");
|
||||
let e = run_func
|
||||
.call(&mut store, ())
|
||||
.err()
|
||||
.expect("error calling function");
|
||||
|
||||
let trace = e.trace();
|
||||
assert_eq!(trace.len(), 2);
|
||||
@@ -67,7 +73,7 @@ fn test_trap_trace() -> Result<()> {
|
||||
#[test]
|
||||
#[cfg_attr(all(target_os = "macos", target_arch = "aarch64"), ignore)] // TODO #2808 system libunwind is broken on aarch64
|
||||
fn test_trap_trace_cb() -> Result<()> {
|
||||
let store = Store::default();
|
||||
let mut store = Store::<()>::default();
|
||||
let wat = r#"
|
||||
(module $hello_mod
|
||||
(import "" "throw" (func $throw))
|
||||
@@ -77,13 +83,16 @@ fn test_trap_trace_cb() -> Result<()> {
|
||||
"#;
|
||||
|
||||
let fn_type = FuncType::new(None, None);
|
||||
let fn_func = Func::new(&store, fn_type, |_, _, _| Err(Trap::new("cb throw")));
|
||||
let fn_func = Func::new(&mut store, fn_type, |_, _, _| Err(Trap::new("cb throw")));
|
||||
|
||||
let module = Module::new(store.engine(), wat)?;
|
||||
let instance = Instance::new(&store, &module, &[fn_func.into()])?;
|
||||
let run_func = instance.get_typed_func::<(), ()>("run")?;
|
||||
let instance = Instance::new(&mut store, &module, &[fn_func.into()])?;
|
||||
let run_func = instance.get_typed_func::<(), (), _>(&mut store, "run")?;
|
||||
|
||||
let e = run_func.call(()).err().expect("error calling function");
|
||||
let e = run_func
|
||||
.call(&mut store, ())
|
||||
.err()
|
||||
.expect("error calling function");
|
||||
|
||||
let trace = e.trace();
|
||||
assert_eq!(trace.len(), 2);
|
||||
@@ -99,7 +108,7 @@ fn test_trap_trace_cb() -> Result<()> {
|
||||
#[test]
|
||||
#[cfg_attr(all(target_os = "macos", target_arch = "aarch64"), ignore)] // TODO #2808 system libunwind is broken on aarch64
|
||||
fn test_trap_stack_overflow() -> Result<()> {
|
||||
let store = Store::default();
|
||||
let mut store = Store::<()>::default();
|
||||
let wat = r#"
|
||||
(module $rec_mod
|
||||
(func $run (export "run") (call $run))
|
||||
@@ -107,10 +116,13 @@ fn test_trap_stack_overflow() -> Result<()> {
|
||||
"#;
|
||||
|
||||
let module = Module::new(store.engine(), wat)?;
|
||||
let instance = Instance::new(&store, &module, &[])?;
|
||||
let run_func = instance.get_typed_func::<(), ()>("run")?;
|
||||
let instance = Instance::new(&mut store, &module, &[])?;
|
||||
let run_func = instance.get_typed_func::<(), (), _>(&mut store, "run")?;
|
||||
|
||||
let e = run_func.call(()).err().expect("error calling function");
|
||||
let e = run_func
|
||||
.call(&mut store, ())
|
||||
.err()
|
||||
.expect("error calling function");
|
||||
|
||||
let trace = e.trace();
|
||||
assert!(trace.len() >= 32);
|
||||
@@ -127,7 +139,7 @@ fn test_trap_stack_overflow() -> Result<()> {
|
||||
#[test]
|
||||
#[cfg_attr(all(target_os = "macos", target_arch = "aarch64"), ignore)] // TODO #2808 system libunwind is broken on aarch64
|
||||
fn trap_display_pretty() -> Result<()> {
|
||||
let store = Store::default();
|
||||
let mut store = Store::<()>::default();
|
||||
let wat = r#"
|
||||
(module $m
|
||||
(func $die unreachable)
|
||||
@@ -138,10 +150,13 @@ fn trap_display_pretty() -> Result<()> {
|
||||
"#;
|
||||
|
||||
let module = Module::new(store.engine(), wat)?;
|
||||
let instance = Instance::new(&store, &module, &[])?;
|
||||
let run_func = instance.get_typed_func::<(), ()>("bar")?;
|
||||
let instance = Instance::new(&mut store, &module, &[])?;
|
||||
let run_func = instance.get_typed_func::<(), (), _>(&mut store, "bar")?;
|
||||
|
||||
let e = run_func.call(()).err().expect("error calling function");
|
||||
let e = run_func
|
||||
.call(&mut store, ())
|
||||
.err()
|
||||
.expect("error calling function");
|
||||
assert_eq!(
|
||||
e.to_string(),
|
||||
"\
|
||||
@@ -159,7 +174,7 @@ wasm backtrace:
|
||||
#[test]
|
||||
#[cfg_attr(all(target_os = "macos", target_arch = "aarch64"), ignore)] // TODO #2808 system libunwind is broken on aarch64
|
||||
fn trap_display_multi_module() -> Result<()> {
|
||||
let store = Store::default();
|
||||
let mut store = Store::<()>::default();
|
||||
let wat = r#"
|
||||
(module $a
|
||||
(func $die unreachable)
|
||||
@@ -170,8 +185,8 @@ fn trap_display_multi_module() -> Result<()> {
|
||||
"#;
|
||||
|
||||
let module = Module::new(store.engine(), wat)?;
|
||||
let instance = Instance::new(&store, &module, &[])?;
|
||||
let bar = instance.get_export("bar").unwrap();
|
||||
let instance = Instance::new(&mut store, &module, &[])?;
|
||||
let bar = instance.get_export(&mut store, "bar").unwrap();
|
||||
|
||||
let wat = r#"
|
||||
(module $b
|
||||
@@ -181,10 +196,13 @@ fn trap_display_multi_module() -> Result<()> {
|
||||
)
|
||||
"#;
|
||||
let module = Module::new(store.engine(), wat)?;
|
||||
let instance = Instance::new(&store, &module, &[bar])?;
|
||||
let bar2 = instance.get_typed_func::<(), ()>("bar2")?;
|
||||
let instance = Instance::new(&mut store, &module, &[bar])?;
|
||||
let bar2 = instance.get_typed_func::<(), (), _>(&mut store, "bar2")?;
|
||||
|
||||
let e = bar2.call(()).err().expect("error calling function");
|
||||
let e = bar2
|
||||
.call(&mut store, ())
|
||||
.err()
|
||||
.expect("error calling function");
|
||||
assert_eq!(
|
||||
e.to_string(),
|
||||
"\
|
||||
@@ -203,7 +221,7 @@ wasm backtrace:
|
||||
|
||||
#[test]
|
||||
fn trap_start_function_import() -> Result<()> {
|
||||
let store = Store::default();
|
||||
let mut store = Store::<()>::default();
|
||||
let binary = wat::parse_str(
|
||||
r#"
|
||||
(module $a
|
||||
@@ -215,8 +233,8 @@ fn trap_start_function_import() -> Result<()> {
|
||||
|
||||
let module = Module::new(store.engine(), &binary)?;
|
||||
let sig = FuncType::new(None, None);
|
||||
let func = Func::new(&store, sig, |_, _, _| Err(Trap::new("user trap")));
|
||||
let err = Instance::new(&store, &module, &[func.into()])
|
||||
let func = Func::new(&mut store, sig, |_, _, _| Err(Trap::new("user trap")));
|
||||
let err = Instance::new(&mut store, &module, &[func.into()])
|
||||
.err()
|
||||
.unwrap();
|
||||
assert!(err
|
||||
@@ -229,7 +247,7 @@ fn trap_start_function_import() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
fn rust_panic_import() -> Result<()> {
|
||||
let store = Store::default();
|
||||
let mut store = Store::<()>::default();
|
||||
let binary = wat::parse_str(
|
||||
r#"
|
||||
(module $a
|
||||
@@ -243,22 +261,17 @@ fn rust_panic_import() -> Result<()> {
|
||||
|
||||
let module = Module::new(store.engine(), &binary)?;
|
||||
let sig = FuncType::new(None, None);
|
||||
let func = Func::new(&store, sig, |_, _, _| panic!("this is a panic"));
|
||||
let instance = Instance::new(
|
||||
&store,
|
||||
&module,
|
||||
&[
|
||||
func.into(),
|
||||
Func::wrap(&store, || panic!("this is another panic")).into(),
|
||||
],
|
||||
)?;
|
||||
let func = instance.get_typed_func::<(), ()>("foo")?;
|
||||
let err = panic::catch_unwind(AssertUnwindSafe(|| drop(func.call(())))).unwrap_err();
|
||||
let func = Func::new(&mut store, sig, |_, _, _| panic!("this is a panic"));
|
||||
let func2 = Func::wrap(&mut store, || panic!("this is another panic"));
|
||||
let instance = Instance::new(&mut store, &module, &[func.into(), func2.into()])?;
|
||||
let func = instance.get_typed_func::<(), (), _>(&mut store, "foo")?;
|
||||
let err =
|
||||
panic::catch_unwind(AssertUnwindSafe(|| drop(func.call(&mut store, ())))).unwrap_err();
|
||||
assert_eq!(err.downcast_ref::<&'static str>(), Some(&"this is a panic"));
|
||||
|
||||
let func = instance.get_typed_func::<(), ()>("bar")?;
|
||||
let func = instance.get_typed_func::<(), (), _>(&mut store, "bar")?;
|
||||
let err = panic::catch_unwind(AssertUnwindSafe(|| {
|
||||
drop(func.call(()));
|
||||
drop(func.call(&mut store, ()));
|
||||
}))
|
||||
.unwrap_err();
|
||||
assert_eq!(
|
||||
@@ -270,7 +283,7 @@ fn rust_panic_import() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
fn rust_panic_start_function() -> Result<()> {
|
||||
let store = Store::default();
|
||||
let mut store = Store::<()>::default();
|
||||
let binary = wat::parse_str(
|
||||
r#"
|
||||
(module $a
|
||||
@@ -282,16 +295,16 @@ fn rust_panic_start_function() -> Result<()> {
|
||||
|
||||
let module = Module::new(store.engine(), &binary)?;
|
||||
let sig = FuncType::new(None, None);
|
||||
let func = Func::new(&store, sig, |_, _, _| panic!("this is a panic"));
|
||||
let func = Func::new(&mut store, sig, |_, _, _| panic!("this is a panic"));
|
||||
let err = panic::catch_unwind(AssertUnwindSafe(|| {
|
||||
drop(Instance::new(&store, &module, &[func.into()]));
|
||||
drop(Instance::new(&mut store, &module, &[func.into()]));
|
||||
}))
|
||||
.unwrap_err();
|
||||
assert_eq!(err.downcast_ref::<&'static str>(), Some(&"this is a panic"));
|
||||
|
||||
let func = Func::wrap(&store, || panic!("this is another panic"));
|
||||
let func = Func::wrap(&mut store, || panic!("this is another panic"));
|
||||
let err = panic::catch_unwind(AssertUnwindSafe(|| {
|
||||
drop(Instance::new(&store, &module, &[func.into()]));
|
||||
drop(Instance::new(&mut store, &module, &[func.into()]));
|
||||
}))
|
||||
.unwrap_err();
|
||||
assert_eq!(
|
||||
@@ -303,7 +316,7 @@ fn rust_panic_start_function() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
fn mismatched_arguments() -> Result<()> {
|
||||
let store = Store::default();
|
||||
let mut store = Store::<()>::default();
|
||||
let binary = wat::parse_str(
|
||||
r#"
|
||||
(module $a
|
||||
@@ -313,18 +326,20 @@ fn mismatched_arguments() -> Result<()> {
|
||||
)?;
|
||||
|
||||
let module = Module::new(store.engine(), &binary)?;
|
||||
let instance = Instance::new(&store, &module, &[])?;
|
||||
let func = instance.get_func("foo").unwrap();
|
||||
let instance = Instance::new(&mut store, &module, &[])?;
|
||||
let func = instance.get_func(&mut store, "foo").unwrap();
|
||||
assert_eq!(
|
||||
func.call(&[]).unwrap_err().to_string(),
|
||||
func.call(&mut store, &[]).unwrap_err().to_string(),
|
||||
"expected 1 arguments, got 0"
|
||||
);
|
||||
assert_eq!(
|
||||
func.call(&[Val::F32(0)]).unwrap_err().to_string(),
|
||||
func.call(&mut store, &[Val::F32(0)])
|
||||
.unwrap_err()
|
||||
.to_string(),
|
||||
"argument type mismatch: found f32 but expected i32",
|
||||
);
|
||||
assert_eq!(
|
||||
func.call(&[Val::I32(0), Val::I32(1)])
|
||||
func.call(&mut store, &[Val::I32(0), Val::I32(1)])
|
||||
.unwrap_err()
|
||||
.to_string(),
|
||||
"expected 1 arguments, got 2"
|
||||
@@ -334,7 +349,7 @@ fn mismatched_arguments() -> Result<()> {
|
||||
|
||||
#[test]
|
||||
fn call_signature_mismatch() -> Result<()> {
|
||||
let store = Store::default();
|
||||
let mut store = Store::<()>::default();
|
||||
let binary = wat::parse_str(
|
||||
r#"
|
||||
(module $a
|
||||
@@ -351,7 +366,7 @@ fn call_signature_mismatch() -> Result<()> {
|
||||
)?;
|
||||
|
||||
let module = Module::new(store.engine(), &binary)?;
|
||||
let err = Instance::new(&store, &module, &[])
|
||||
let err = Instance::new(&mut store, &module, &[])
|
||||
.err()
|
||||
.unwrap()
|
||||
.downcast::<Trap>()
|
||||
@@ -365,7 +380,7 @@ fn call_signature_mismatch() -> Result<()> {
|
||||
#[test]
|
||||
#[cfg_attr(all(target_os = "macos", target_arch = "aarch64"), ignore)] // TODO #2808 system libunwind is broken on aarch64
|
||||
fn start_trap_pretty() -> Result<()> {
|
||||
let store = Store::default();
|
||||
let mut store = Store::<()>::default();
|
||||
let wat = r#"
|
||||
(module $m
|
||||
(func $die unreachable)
|
||||
@@ -377,7 +392,7 @@ fn start_trap_pretty() -> Result<()> {
|
||||
"#;
|
||||
|
||||
let module = Module::new(store.engine(), wat)?;
|
||||
let e = match Instance::new(&store, &module, &[]) {
|
||||
let e = match Instance::new(&mut store, &module, &[]) {
|
||||
Ok(_) => panic!("expected failure"),
|
||||
Err(e) => e.downcast::<Trap>()?,
|
||||
};
|
||||
@@ -399,17 +414,17 @@ wasm backtrace:
|
||||
#[test]
|
||||
#[cfg_attr(all(target_os = "macos", target_arch = "aarch64"), ignore)] // TODO #2808 system libunwind is broken on aarch64
|
||||
fn present_after_module_drop() -> Result<()> {
|
||||
let store = Store::default();
|
||||
let mut store = Store::<()>::default();
|
||||
let module = Module::new(store.engine(), r#"(func (export "foo") unreachable)"#)?;
|
||||
let instance = Instance::new(&store, &module, &[])?;
|
||||
let func = instance.get_typed_func::<(), ()>("foo")?;
|
||||
let instance = Instance::new(&mut store, &module, &[])?;
|
||||
let func = instance.get_typed_func::<(), (), _>(&mut store, "foo")?;
|
||||
|
||||
println!("asserting before we drop modules");
|
||||
assert_trap(func.call(()).unwrap_err());
|
||||
assert_trap(func.call(&mut store, ()).unwrap_err());
|
||||
drop((instance, module));
|
||||
|
||||
println!("asserting after drop");
|
||||
assert_trap(func.call(()).unwrap_err());
|
||||
assert_trap(func.call(&mut store, ()).unwrap_err());
|
||||
return Ok(());
|
||||
|
||||
fn assert_trap(t: Trap) {
|
||||
@@ -420,10 +435,10 @@ fn present_after_module_drop() -> Result<()> {
|
||||
}
|
||||
|
||||
fn assert_trap_code(wat: &str, code: wasmtime::TrapCode) {
|
||||
let store = Store::default();
|
||||
let mut store = Store::<()>::default();
|
||||
let module = Module::new(store.engine(), wat).unwrap();
|
||||
|
||||
let err = match Instance::new(&store, &module, &[]) {
|
||||
let err = match Instance::new(&mut store, &module, &[]) {
|
||||
Ok(_) => unreachable!(),
|
||||
Err(e) => e,
|
||||
};
|
||||
@@ -493,19 +508,18 @@ fn parse_dwarf_info() -> Result<()> {
|
||||
let mut config = Config::new();
|
||||
config.wasm_backtrace_details(WasmBacktraceDetails::Enable);
|
||||
let engine = Engine::new(&config)?;
|
||||
let store = Store::new(&engine);
|
||||
let module = Module::new(&engine, &wasm)?;
|
||||
let mut linker = Linker::new(&store);
|
||||
wasmtime_wasi::Wasi::new(
|
||||
&store,
|
||||
let mut linker = Linker::new(&engine);
|
||||
wasmtime_wasi::add_to_linker(&mut linker, |s| s)?;
|
||||
let mut store = Store::new(
|
||||
&engine,
|
||||
wasmtime_wasi::sync::WasiCtxBuilder::new()
|
||||
.inherit_stdio()
|
||||
.build(),
|
||||
)
|
||||
.add_to_linker(&mut linker)?;
|
||||
linker.module("", &module)?;
|
||||
let run = linker.get_default("")?;
|
||||
let trap = run.call(&[]).unwrap_err().downcast::<Trap>()?;
|
||||
);
|
||||
linker.module(&mut store, "", &module)?;
|
||||
let run = linker.get_default(&mut store, "")?;
|
||||
let trap = run.call(&mut store, &[]).unwrap_err().downcast::<Trap>()?;
|
||||
|
||||
let mut found = false;
|
||||
for frame in trap.trace() {
|
||||
@@ -529,7 +543,7 @@ fn no_hint_even_with_dwarf_info() -> Result<()> {
|
||||
let mut config = Config::new();
|
||||
config.wasm_backtrace_details(WasmBacktraceDetails::Disable);
|
||||
let engine = Engine::new(&config)?;
|
||||
let store = Store::new(&engine);
|
||||
let mut store = Store::new(&engine, ());
|
||||
let module = Module::new(
|
||||
&engine,
|
||||
r#"
|
||||
@@ -541,7 +555,7 @@ fn no_hint_even_with_dwarf_info() -> Result<()> {
|
||||
)
|
||||
"#,
|
||||
)?;
|
||||
let trap = Instance::new(&store, &module, &[])
|
||||
let trap = Instance::new(&mut store, &module, &[])
|
||||
.err()
|
||||
.unwrap()
|
||||
.downcast::<Trap>()?;
|
||||
@@ -564,7 +578,7 @@ fn hint_with_dwarf_info() -> Result<()> {
|
||||
if std::env::var("WASMTIME_BACKTRACE_DETAILS").is_ok() {
|
||||
return Ok(());
|
||||
}
|
||||
let store = Store::default();
|
||||
let mut store = Store::<()>::default();
|
||||
let module = Module::new(
|
||||
store.engine(),
|
||||
r#"
|
||||
@@ -576,7 +590,7 @@ fn hint_with_dwarf_info() -> Result<()> {
|
||||
)
|
||||
"#,
|
||||
)?;
|
||||
let trap = Instance::new(&store, &module, &[])
|
||||
let trap = Instance::new(&mut store, &module, &[])
|
||||
.err()
|
||||
.unwrap()
|
||||
.downcast::<Trap>()?;
|
||||
@@ -596,30 +610,23 @@ note: run with `WASMTIME_BACKTRACE_DETAILS=1` environment variable to display mo
|
||||
fn multithreaded_traps() -> Result<()> {
|
||||
// Compile and run unreachable on a thread, then moves over the whole store to another thread,
|
||||
// and make sure traps are still correctly caught after notifying the store of the move.
|
||||
let instance = {
|
||||
let store = Store::default();
|
||||
let module = Module::new(
|
||||
store.engine(),
|
||||
r#"(module (func (export "run") unreachable))"#,
|
||||
)?;
|
||||
Instance::new(&store, &module, &[])?
|
||||
};
|
||||
let mut store = Store::<()>::default();
|
||||
let module = Module::new(
|
||||
store.engine(),
|
||||
r#"(module (func (export "run") unreachable))"#,
|
||||
)?;
|
||||
let instance = Instance::new(&mut store, &module, &[])?;
|
||||
|
||||
assert!(instance.get_typed_func::<(), ()>("run")?.call(()).is_err());
|
||||
|
||||
struct SendInstance {
|
||||
inner: Instance,
|
||||
}
|
||||
unsafe impl Send for SendInstance {}
|
||||
|
||||
let instance = SendInstance { inner: instance };
|
||||
assert!(instance
|
||||
.get_typed_func::<(), (), _>(&mut store, "run")?
|
||||
.call(&mut store, ())
|
||||
.is_err());
|
||||
|
||||
let handle = std::thread::spawn(move || {
|
||||
let instance = instance.inner;
|
||||
assert!(instance
|
||||
.get_typed_func::<(), ()>("run")
|
||||
.get_typed_func::<(), (), _>(&mut store, "run")
|
||||
.unwrap()
|
||||
.call(())
|
||||
.call(&mut store, ())
|
||||
.is_err());
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user