Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/tests/all/component_model.rs
3067 views
1
use std::fmt::Write;
2
use std::iter;
3
use wasmtime::component::{
4
Component, ComponentNamedList, Instance, Lift, Linker, Lower, ResourceAny, TypedFunc,
5
};
6
use wasmtime::{Config, Result, Store};
7
use wasmtime_component_util::REALLOC_AND_FREE;
8
use wasmtime_test_util::component::{async_engine, config, engine};
9
10
mod aot;
11
mod r#async;
12
mod async_dynamic;
13
mod bindgen;
14
mod call_hook;
15
mod dynamic;
16
mod func;
17
mod import;
18
mod instance;
19
mod linker;
20
mod macros;
21
mod missing_async;
22
mod nested;
23
mod post_return;
24
mod resources;
25
mod strings;
26
27
#[derive(Copy, Clone)]
28
enum ApiStyle {
29
Sync,
30
Async,
31
AsyncNotConcurrent,
32
Concurrent,
33
}
34
35
impl ApiStyle {
36
fn config(self) -> Config {
37
let mut config = config();
38
match self {
39
ApiStyle::AsyncNotConcurrent => {
40
config.concurrency_support(false);
41
}
42
ApiStyle::Sync | ApiStyle::Async | ApiStyle::Concurrent => {
43
config.wasm_component_model_threading(true);
44
}
45
}
46
config
47
}
48
49
async fn instantiate<T: Send>(
50
self,
51
store: &mut Store<T>,
52
linker: &Linker<T>,
53
component: &Component,
54
) -> Result<Instance> {
55
match self {
56
ApiStyle::Sync => linker.instantiate(store, &component),
57
ApiStyle::Async | ApiStyle::AsyncNotConcurrent | ApiStyle::Concurrent => {
58
linker.instantiate_async(store, &component).await
59
}
60
}
61
}
62
63
async fn call<
64
P: ComponentNamedList + Lower + 'static,
65
R: ComponentNamedList + Lift + 'static,
66
T: Send,
67
>(
68
self,
69
store: &mut Store<T>,
70
func: TypedFunc<P, R>,
71
params: P,
72
) -> Result<R> {
73
match self {
74
ApiStyle::Sync => func.call(&mut *store, params),
75
ApiStyle::Async | ApiStyle::AsyncNotConcurrent => {
76
func.call_async(&mut *store, params).await
77
}
78
ApiStyle::Concurrent => Ok(store
79
.run_concurrent(async |access| func.call_concurrent(access, params).await)
80
.await??
81
.0),
82
}
83
}
84
85
async fn resource_drop<T: Send>(
86
self,
87
store: &mut Store<T>,
88
resource: ResourceAny,
89
) -> Result<()> {
90
match self {
91
ApiStyle::Sync => resource.resource_drop(store),
92
ApiStyle::Async | ApiStyle::AsyncNotConcurrent | ApiStyle::Concurrent => {
93
resource.resource_drop_async(store).await
94
}
95
}
96
}
97
}
98
99
#[test]
100
#[cfg_attr(miri, ignore)]
101
fn components_importing_modules() -> Result<()> {
102
let engine = engine();
103
104
// FIXME: these components should actually get instantiated in `*.wast`
105
// tests once supplying imports has actually been implemented.
106
107
Component::new(
108
&engine,
109
r#"
110
(component
111
(import "a" (core module))
112
)
113
"#,
114
)?;
115
116
Component::new(
117
&engine,
118
r#"
119
(component
120
(import "a" (core module $m1
121
(import "" "" (func))
122
(import "" "x" (global i32))
123
124
(export "a" (table 1 funcref))
125
(export "b" (memory 1))
126
(export "c" (func (result f32)))
127
(export "d" (global i64))
128
))
129
130
(core module $m2
131
(func (export ""))
132
(global (export "x") i32 i32.const 0)
133
)
134
(core instance $i2 (instantiate (module $m2)))
135
(core instance $i1 (instantiate (module $m1) (with "" (instance $i2))))
136
137
(core module $m3
138
(import "mod" "1" (memory 1))
139
(import "mod" "2" (table 1 funcref))
140
(import "mod" "3" (global i64))
141
(import "mod" "4" (func (result f32)))
142
)
143
144
(core instance $i3 (instantiate (module $m3)
145
(with "mod" (instance
146
(export "1" (memory $i1 "b"))
147
(export "2" (table $i1 "a"))
148
(export "3" (global $i1 "d"))
149
(export "4" (func $i1 "c"))
150
))
151
))
152
)
153
"#,
154
)?;
155
156
Ok(())
157
}
158
159
#[derive(Copy, Clone, PartialEq, Eq)]
160
enum Type {
161
S8,
162
U8,
163
S16,
164
U16,
165
I32,
166
I64,
167
F32,
168
F64,
169
}
170
171
impl Type {
172
fn store(&self) -> &'static str {
173
match self {
174
Self::S8 | Self::U8 => "store8",
175
Self::S16 | Self::U16 => "store16",
176
Self::I32 | Self::F32 | Self::I64 | Self::F64 => "store",
177
}
178
}
179
180
fn primitive(&self) -> &'static str {
181
match self {
182
Self::S8 | Self::U8 | Self::S16 | Self::U16 | Self::I32 => "i32",
183
Self::I64 => "i64",
184
Self::F32 => "f32",
185
Self::F64 => "f64",
186
}
187
}
188
}
189
190
#[derive(Copy, Clone, PartialEq, Eq)]
191
struct Param(Type, Option<usize>);
192
193
fn make_echo_component(type_definition: &str, type_size: u32) -> String {
194
let mut offset = 0;
195
make_echo_component_with_params(
196
type_definition,
197
&iter::repeat(Type::I32)
198
.map(|ty| {
199
let param = Param(ty, Some(offset));
200
offset += 4;
201
param
202
})
203
.take(usize::try_from(type_size).unwrap() / 4)
204
.collect::<Vec<_>>(),
205
)
206
}
207
208
fn make_echo_component_with_params(type_definition: &str, params: &[Param]) -> String {
209
let func = if params.len() == 0 {
210
format!("(func (export \"echo\"))")
211
} else if params.len() == 1 || params.len() > 16 {
212
let primitive = if params.len() == 1 {
213
params[0].0.primitive()
214
} else {
215
"i32"
216
};
217
218
format!(
219
r#"
220
(func (export "echo") (param {primitive}) (result {primitive})
221
local.get 0
222
)"#,
223
)
224
} else {
225
let mut param_string = String::new();
226
let mut store = String::new();
227
let mut size = 8;
228
229
for (index, Param(ty, offset)) in params.iter().enumerate() {
230
let primitive = ty.primitive();
231
232
write!(&mut param_string, " {primitive}").unwrap();
233
if let Some(offset) = offset {
234
write!(
235
&mut store,
236
"({primitive}.{} offset={offset} (local.get $base) (local.get {index}))",
237
ty.store(),
238
)
239
.unwrap();
240
241
size = size.max(offset + 8);
242
}
243
}
244
245
format!(
246
r#"
247
(func (export "echo") (param{param_string}) (result i32)
248
(local $base i32)
249
(local.set $base
250
(call $realloc
251
(i32.const 0)
252
(i32.const 0)
253
(i32.const 4)
254
(i32.const {size})))
255
{store}
256
local.get $base
257
)"#
258
)
259
};
260
261
let type_section = if type_definition.contains("(type ") {
262
type_definition.to_string()
263
} else {
264
format!("(type $Foo' {type_definition})")
265
};
266
267
format!(
268
r#"
269
(component
270
(core module $m
271
{func}
272
273
(memory (export "memory") 1)
274
{REALLOC_AND_FREE}
275
)
276
277
(core instance $i (instantiate $m))
278
279
{type_section}
280
(export $Foo "foo" (type $Foo'))
281
282
(func (export "echo") (param "a" $Foo) (result $Foo)
283
(canon lift
284
(core func $i "echo")
285
(memory $i "memory")
286
(realloc (func $i "realloc"))
287
)
288
)
289
)"#
290
)
291
}
292
293