Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/wast/src/spectest.rs
1691 views
1
use wasmtime::*;
2
3
/// Configuration of how spectest primitives work.
4
pub struct SpectestConfig {
5
/// Whether or not to have a `shared_memory` definition.
6
pub use_shared_memory: bool,
7
/// Whether or not spectest functions that print things actually print things.
8
pub suppress_prints: bool,
9
}
10
11
/// Return an instance implementing the "spectest" interface used in the
12
/// spec testsuite.
13
pub fn link_spectest<T>(
14
linker: &mut Linker<T>,
15
store: &mut Store<T>,
16
config: &SpectestConfig,
17
) -> Result<()> {
18
let suppress = config.suppress_prints;
19
linker.func_wrap("spectest", "print", || {})?;
20
linker.func_wrap("spectest", "print_i32", move |val: i32| {
21
if !suppress {
22
println!("{val}: i32")
23
}
24
})?;
25
linker.func_wrap("spectest", "print_i64", move |val: i64| {
26
if !suppress {
27
println!("{val}: i64")
28
}
29
})?;
30
linker.func_wrap("spectest", "print_f32", move |val: f32| {
31
if !suppress {
32
println!("{val}: f32")
33
}
34
})?;
35
linker.func_wrap("spectest", "print_f64", move |val: f64| {
36
if !suppress {
37
println!("{val}: f64")
38
}
39
})?;
40
linker.func_wrap("spectest", "print_i32_f32", move |i: i32, f: f32| {
41
if !suppress {
42
println!("{i}: i32");
43
println!("{f}: f32");
44
}
45
})?;
46
linker.func_wrap("spectest", "print_f64_f64", move |f1: f64, f2: f64| {
47
if !suppress {
48
println!("{f1}: f64");
49
println!("{f2}: f64");
50
}
51
})?;
52
53
let ty = GlobalType::new(ValType::I32, Mutability::Const);
54
let g = Global::new(&mut *store, ty, Val::I32(666))?;
55
linker.define(&mut *store, "spectest", "global_i32", g)?;
56
57
let ty = GlobalType::new(ValType::I64, Mutability::Const);
58
let g = Global::new(&mut *store, ty, Val::I64(666))?;
59
linker.define(&mut *store, "spectest", "global_i64", g)?;
60
61
let ty = GlobalType::new(ValType::F32, Mutability::Const);
62
let g = Global::new(&mut *store, ty, Val::F32(0x4426_a666))?;
63
linker.define(&mut *store, "spectest", "global_f32", g)?;
64
65
let ty = GlobalType::new(ValType::F64, Mutability::Const);
66
let g = Global::new(&mut *store, ty, Val::F64(0x4084_d4cc_cccc_cccd))?;
67
linker.define(&mut *store, "spectest", "global_f64", g)?;
68
69
let ty = TableType::new(RefType::FUNCREF, 10, Some(20));
70
let table = Table::new(&mut *store, ty, Ref::Func(None))?;
71
linker.define(&mut *store, "spectest", "table", table)?;
72
73
let ty = TableType::new64(RefType::FUNCREF, 10, Some(20));
74
let table = Table::new(&mut *store, ty, Ref::Func(None))?;
75
linker.define(&mut *store, "spectest", "table64", table)?;
76
77
let ty = MemoryType::new(1, Some(2));
78
let memory = Memory::new(&mut *store, ty)?;
79
linker.define(&mut *store, "spectest", "memory", memory)?;
80
81
if config.use_shared_memory {
82
let ty = MemoryType::shared(1, 1);
83
let memory = Memory::new(&mut *store, ty)?;
84
linker.define(&mut *store, "spectest", "shared_memory", memory)?;
85
}
86
87
Ok(())
88
}
89
90
#[cfg(feature = "component-model")]
91
pub fn link_component_spectest<T>(linker: &mut component::Linker<T>) -> Result<()> {
92
use std::sync::Arc;
93
use std::sync::atomic::{AtomicU32, Ordering::SeqCst};
94
use wasmtime::component::{Resource, ResourceType};
95
96
let engine = linker.engine().clone();
97
linker
98
.root()
99
.func_wrap("host-echo-u32", |_, v: (u32,)| Ok(v))?;
100
linker
101
.root()
102
.func_wrap("host-return-two", |_, _: ()| Ok((2u32,)))?;
103
let mut i = linker.instance("host")?;
104
i.func_wrap("return-three", |_, _: ()| Ok((3u32,)))?;
105
i.instance("nested")?
106
.func_wrap("return-four", |_, _: ()| Ok((4u32,)))?;
107
108
if !cfg!(miri) {
109
let module = Module::new(
110
&engine,
111
r#"
112
(module
113
(global (export "g") i32 i32.const 100)
114
(func (export "f") (result i32) i32.const 101)
115
)
116
"#,
117
)?;
118
i.module("simple-module", &module)?;
119
}
120
121
struct Resource1;
122
struct Resource2;
123
124
#[derive(Default)]
125
struct ResourceState {
126
drops: AtomicU32,
127
last_drop: AtomicU32,
128
}
129
130
let state = Arc::new(ResourceState::default());
131
132
i.resource("resource1", ResourceType::host::<Resource1>(), {
133
let state = state.clone();
134
move |_, rep| {
135
state.drops.fetch_add(1, SeqCst);
136
state.last_drop.store(rep, SeqCst);
137
138
Ok(())
139
}
140
})?;
141
i.resource(
142
"resource2",
143
ResourceType::host::<Resource2>(),
144
|_, _| Ok(()),
145
)?;
146
// Currently the embedder API requires redefining the resource destructor
147
// here despite this being the same type as before, and fixing that is left
148
// for a future refactoring.
149
i.resource(
150
"resource1-again",
151
ResourceType::host::<Resource1>(),
152
|_, _| {
153
panic!("shouldn't be destroyed");
154
},
155
)?;
156
157
i.func_wrap("[constructor]resource1", |_cx, (rep,): (u32,)| {
158
Ok((Resource::<Resource1>::new_own(rep),))
159
})?;
160
i.func_wrap(
161
"[static]resource1.assert",
162
|_cx, (resource, rep): (Resource<Resource1>, u32)| {
163
assert_eq!(resource.rep(), rep);
164
Ok(())
165
},
166
)?;
167
i.func_wrap("[static]resource1.last-drop", {
168
let state = state.clone();
169
move |_, (): ()| Ok((state.last_drop.load(SeqCst),))
170
})?;
171
i.func_wrap("[static]resource1.drops", {
172
let state = state.clone();
173
move |_, (): ()| Ok((state.drops.load(SeqCst),))
174
})?;
175
i.func_wrap(
176
"[method]resource1.simple",
177
|_cx, (resource, rep): (Resource<Resource1>, u32)| {
178
assert!(!resource.owned());
179
assert_eq!(resource.rep(), rep);
180
Ok(())
181
},
182
)?;
183
184
i.func_wrap(
185
"[method]resource1.take-borrow",
186
|_, (a, b): (Resource<Resource1>, Resource<Resource1>)| {
187
assert!(!a.owned());
188
assert!(!b.owned());
189
Ok(())
190
},
191
)?;
192
i.func_wrap(
193
"[method]resource1.take-own",
194
|_cx, (a, b): (Resource<Resource1>, Resource<Resource1>)| {
195
assert!(!a.owned());
196
assert!(b.owned());
197
Ok(())
198
},
199
)?;
200
Ok(())
201
}
202
203