Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/wiggle/tests/wasmtime_sync.rs
3092 views
1
use wasmtime::{Engine, Linker, Module, Store, Val};
2
use wiggle::GuestMemory;
3
4
wiggle::from_witx!({
5
witx: ["tests/atoms.witx"],
6
block_on: {
7
atoms::double_int_return_float
8
}
9
});
10
11
pub struct Ctx;
12
impl wiggle::GuestErrorType for types::Errno {
13
fn success() -> Self {
14
types::Errno::Ok
15
}
16
}
17
18
const TRIGGER_PENDING: u32 = 0;
19
20
impl atoms::Atoms for Ctx {
21
fn int_float_args(
22
&mut self,
23
_: &mut GuestMemory<'_>,
24
an_int: u32,
25
an_float: f32,
26
) -> Result<(), types::Errno> {
27
println!("INT FLOAT ARGS: {an_int} {an_float}");
28
Ok(())
29
}
30
async fn double_int_return_float(
31
&mut self,
32
_: &mut GuestMemory<'_>,
33
an_int: u32,
34
) -> Result<types::AliasToFloat, types::Errno> {
35
if an_int == TRIGGER_PENDING {
36
// Define a Future that is pending forever. This is `futures::future::pending()`
37
// without incurring the dep.
38
use std::future::Future;
39
use std::pin::Pin;
40
use std::task::{Context, Poll};
41
struct Pending;
42
impl Future for Pending {
43
type Output = ();
44
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
45
Poll::Pending
46
}
47
}
48
// This await will pend, which should cause the dummy executor to Trap.
49
Pending.await;
50
}
51
Ok((an_int as f32) * 2.0)
52
}
53
}
54
55
#[test]
56
fn test_sync_host_func() {
57
let engine = Engine::default();
58
let mut linker = Linker::new(&engine);
59
atoms::add_to_linker(&mut linker, |cx| cx).unwrap();
60
let mut store = store(&engine);
61
let shim_mod = shim_module(&engine);
62
let shim_inst = linker.instantiate(&mut store, &shim_mod).unwrap();
63
64
let mut results = [Val::I32(0)];
65
shim_inst
66
.get_func(&mut store, "int_float_args_shim")
67
.unwrap()
68
.call(&mut store, &[0i32.into(), 123.45f32.into()], &mut results)
69
.unwrap();
70
71
assert_eq!(
72
results[0].unwrap_i32(),
73
types::Errno::Ok as i32,
74
"int_float_args errno"
75
);
76
}
77
78
#[test]
79
fn test_async_host_func() {
80
let engine = Engine::default();
81
let mut linker = Linker::new(&engine);
82
atoms::add_to_linker(&mut linker, |cx| cx).unwrap();
83
let mut store = store(&engine);
84
85
let shim_mod = shim_module(&engine);
86
let shim_inst = linker.instantiate(&mut store, &shim_mod).unwrap();
87
88
let input: i32 = 123;
89
let result_location: i32 = 0;
90
91
let mut results = [Val::I32(0)];
92
shim_inst
93
.get_func(&mut store, "double_int_return_float_shim")
94
.unwrap()
95
.call(
96
&mut store,
97
&[input.into(), result_location.into()],
98
&mut results,
99
)
100
.unwrap();
101
102
assert_eq!(
103
results[0].unwrap_i32(),
104
types::Errno::Ok as i32,
105
"double_int_return_float errno"
106
);
107
108
// The actual result is in memory:
109
let mem = shim_inst.get_memory(&mut store, "memory").unwrap();
110
let mut result_bytes: [u8; 4] = [0, 0, 0, 0];
111
mem.read(&store, result_location as usize, &mut result_bytes)
112
.unwrap();
113
let result = f32::from_le_bytes(result_bytes);
114
assert_eq!((input * 2) as f32, result);
115
}
116
117
#[test]
118
fn test_async_host_func_pending() {
119
let engine = Engine::default();
120
let mut linker = Linker::new(&engine);
121
atoms::add_to_linker(&mut linker, |cx| cx).unwrap();
122
let mut store = store(&engine);
123
124
let shim_mod = shim_module(&engine);
125
let shim_inst = linker.instantiate(&mut store, &shim_mod).unwrap();
126
127
let result_location: i32 = 0;
128
129
// This input triggers the host func pending forever
130
let input: i32 = TRIGGER_PENDING as i32;
131
let trap = shim_inst
132
.get_func(&mut store, "double_int_return_float_shim")
133
.unwrap()
134
.call(
135
&mut store,
136
&[input.into(), result_location.into()],
137
&mut [Val::I32(0)],
138
)
139
.unwrap_err();
140
assert!(
141
format!("{trap:?}").contains("Cannot wait on pending future"),
142
"expected get a pending future Trap from dummy executor, got: {trap}"
143
);
144
}
145
146
fn store(engine: &Engine) -> Store<Ctx> {
147
Store::new(engine, Ctx)
148
}
149
150
// Wiggle expects the caller to have an exported memory. Wasmtime can only
151
// provide this if the caller is a WebAssembly module, so we need to write
152
// a shim module:
153
fn shim_module(engine: &Engine) -> Module {
154
Module::new(
155
engine,
156
r#"
157
(module
158
(import "atoms" "int_float_args" (func $int_float_args (param i32 f32) (result i32)))
159
(import "atoms" "double_int_return_float" (func $double_int_return_float (param i32 i32) (result i32)))
160
161
(memory 1)
162
(export "memory" (memory 0))
163
164
(func $int_float_args_shim (param i32 f32) (result i32)
165
local.get 0
166
local.get 1
167
call $int_float_args
168
)
169
(func $double_int_return_float_shim (param i32 i32) (result i32)
170
local.get 0
171
local.get 1
172
call $double_int_return_float
173
)
174
(export "int_float_args_shim" (func $int_float_args_shim))
175
(export "double_int_return_float_shim" (func $double_int_return_float_shim))
176
)
177
"#,
178
)
179
.unwrap()
180
}
181
182