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