Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/c-api/src/store.rs
1692 views
1
use crate::{ForeignData, wasm_engine_t, wasmtime_error_t, wasmtime_val_t};
2
use std::cell::UnsafeCell;
3
use std::ffi::c_void;
4
use std::sync::Arc;
5
use wasmtime::{
6
AsContext, AsContextMut, Caller, Store, StoreContext, StoreContextMut, StoreLimits,
7
StoreLimitsBuilder, UpdateDeadline, Val,
8
};
9
10
// Store-related type aliases for `wasm.h` APIs. Not for use with `wasmtime.h`
11
// APIs!
12
pub type WasmStoreData = ();
13
pub type WasmStore = Store<WasmStoreData>;
14
pub type WasmStoreContext<'a> = StoreContext<'a, WasmStoreData>;
15
pub type WasmStoreContextMut<'a> = StoreContextMut<'a, WasmStoreData>;
16
17
/// This representation of a `Store` is used to implement the `wasm.h` API (and
18
/// *not* the `wasmtime.h` API!)
19
///
20
/// This is stored alongside `Func` and such for `wasm.h` so each object is
21
/// independently owned. The usage of `Arc` here is mostly to just get it to be
22
/// safe to drop across multiple threads, but otherwise acquiring the `context`
23
/// values from this struct is considered unsafe due to it being unknown how the
24
/// aliasing is working on the C side of things.
25
///
26
/// The aliasing requirements are documented in the C API `wasm.h` itself (at
27
/// least Wasmtime's implementation).
28
#[derive(Clone)]
29
pub struct WasmStoreRef {
30
store: Arc<UnsafeCell<WasmStore>>,
31
}
32
33
impl WasmStoreRef {
34
pub unsafe fn context(&self) -> WasmStoreContext<'_> {
35
(*self.store.get()).as_context()
36
}
37
38
pub unsafe fn context_mut(&mut self) -> WasmStoreContextMut<'_> {
39
(*self.store.get()).as_context_mut()
40
}
41
}
42
43
#[repr(C)]
44
#[derive(Clone)]
45
pub struct wasm_store_t {
46
pub(crate) store: WasmStoreRef,
47
}
48
49
wasmtime_c_api_macros::declare_own!(wasm_store_t);
50
51
#[unsafe(no_mangle)]
52
pub extern "C" fn wasm_store_new(engine: &wasm_engine_t) -> Box<wasm_store_t> {
53
let engine = &engine.engine;
54
let store = Store::new(engine, ());
55
Box::new(wasm_store_t {
56
store: WasmStoreRef {
57
store: Arc::new(UnsafeCell::new(store)),
58
},
59
})
60
}
61
62
// Store-related type aliases for `wasmtime.h` APIs. Not for use with `wasm.h`
63
// APIs!
64
pub type WasmtimeStore = Store<WasmtimeStoreData>;
65
pub type WasmtimeStoreContext<'a> = StoreContext<'a, WasmtimeStoreData>;
66
pub type WasmtimeStoreContextMut<'a> = StoreContextMut<'a, WasmtimeStoreData>;
67
pub type WasmtimeCaller<'a> = Caller<'a, WasmtimeStoreData>;
68
69
/// Representation of a `Store` for `wasmtime.h` This notably tries to move more
70
/// burden of aliasing on the caller rather than internally, allowing for a more
71
/// raw representation of contexts and such that requires less `unsafe` in the
72
/// implementation.
73
///
74
/// Note that this notably carries `WasmtimeStoreData` as a payload which allows
75
/// storing foreign data and configuring WASI as well.
76
#[repr(C)]
77
pub struct wasmtime_store_t {
78
pub(crate) store: WasmtimeStore,
79
}
80
81
wasmtime_c_api_macros::declare_own!(wasmtime_store_t);
82
83
pub struct WasmtimeStoreData {
84
foreign: crate::ForeignData,
85
#[cfg(feature = "wasi")]
86
pub(crate) wasi: Option<wasmtime_wasi::p1::WasiP1Ctx>,
87
88
/// Temporary storage for usage during a wasm->host call to store values
89
/// in a slice we pass to the C API.
90
pub hostcall_val_storage: Vec<wasmtime_val_t>,
91
92
/// Temporary storage for usage during host->wasm calls, same as above but
93
/// for a different direction.
94
pub wasm_val_storage: Vec<Val>,
95
96
/// Limits for the store.
97
pub store_limits: StoreLimits,
98
99
#[cfg(feature = "component-model")]
100
pub(crate) resource_table: wasmtime::component::ResourceTable,
101
102
#[cfg(all(feature = "component-model", feature = "wasi"))]
103
pub(crate) wasip2: Option<wasmtime_wasi::WasiCtx>,
104
}
105
106
#[cfg(all(feature = "component-model", feature = "wasi"))]
107
impl wasmtime_wasi::WasiView for WasmtimeStoreData {
108
fn ctx(&mut self) -> wasmtime_wasi::WasiCtxView<'_> {
109
wasmtime_wasi::WasiCtxView {
110
ctx: self.wasip2.as_mut().unwrap(),
111
table: &mut self.resource_table,
112
}
113
}
114
}
115
116
#[unsafe(no_mangle)]
117
pub extern "C" fn wasmtime_store_new(
118
engine: &wasm_engine_t,
119
data: *mut c_void,
120
finalizer: Option<extern "C" fn(*mut c_void)>,
121
) -> Box<wasmtime_store_t> {
122
Box::new(wasmtime_store_t {
123
store: Store::new(
124
&engine.engine,
125
WasmtimeStoreData {
126
foreign: ForeignData { data, finalizer },
127
#[cfg(feature = "wasi")]
128
wasi: None,
129
hostcall_val_storage: Vec::new(),
130
wasm_val_storage: Vec::new(),
131
store_limits: StoreLimits::default(),
132
#[cfg(feature = "component-model")]
133
resource_table: wasmtime::component::ResourceTable::default(),
134
#[cfg(all(feature = "component-model", feature = "wasi"))]
135
wasip2: None,
136
},
137
),
138
})
139
}
140
141
pub type wasmtime_update_deadline_kind_t = u8;
142
pub const WASMTIME_UPDATE_DEADLINE_CONTINUE: wasmtime_update_deadline_kind_t = 0;
143
pub const WASMTIME_UPDATE_DEADLINE_YIELD: wasmtime_update_deadline_kind_t = 1;
144
145
#[unsafe(no_mangle)]
146
pub extern "C" fn wasmtime_store_epoch_deadline_callback(
147
store: &mut wasmtime_store_t,
148
func: extern "C" fn(
149
WasmtimeStoreContextMut<'_>,
150
*mut c_void,
151
*mut u64,
152
*mut wasmtime_update_deadline_kind_t,
153
) -> Option<Box<wasmtime_error_t>>,
154
data: *mut c_void,
155
finalizer: Option<extern "C" fn(*mut c_void)>,
156
) {
157
let foreign = crate::ForeignData { data, finalizer };
158
store.store.epoch_deadline_callback(move |mut store_ctx| {
159
let _ = &foreign; // Move foreign into this closure
160
let mut delta: u64 = 0;
161
let mut kind = WASMTIME_UPDATE_DEADLINE_CONTINUE;
162
let result = (func)(
163
store_ctx.as_context_mut(),
164
foreign.data,
165
&mut delta as *mut u64,
166
&mut kind as *mut wasmtime_update_deadline_kind_t,
167
);
168
match result {
169
Some(err) => Err((*err).into()),
170
None if kind == WASMTIME_UPDATE_DEADLINE_CONTINUE => {
171
Ok(UpdateDeadline::Continue(delta))
172
}
173
#[cfg(feature = "async")]
174
None if kind == WASMTIME_UPDATE_DEADLINE_YIELD => Ok(UpdateDeadline::Yield(delta)),
175
_ => panic!("unknown wasmtime_update_deadline_kind_t: {kind}"),
176
}
177
});
178
}
179
180
#[unsafe(no_mangle)]
181
pub extern "C" fn wasmtime_store_context(
182
store: &mut wasmtime_store_t,
183
) -> WasmtimeStoreContextMut<'_> {
184
store.store.as_context_mut()
185
}
186
187
#[unsafe(no_mangle)]
188
pub extern "C" fn wasmtime_store_limiter(
189
store: &mut wasmtime_store_t,
190
memory_size: i64,
191
table_elements: i64,
192
instances: i64,
193
tables: i64,
194
memories: i64,
195
) {
196
let mut limiter = StoreLimitsBuilder::new();
197
if memory_size >= 0 {
198
limiter = limiter.memory_size(memory_size as usize);
199
}
200
if table_elements >= 0 {
201
limiter = limiter.table_elements(table_elements as usize);
202
}
203
if instances >= 0 {
204
limiter = limiter.instances(instances as usize);
205
}
206
if tables >= 0 {
207
limiter = limiter.tables(tables as usize);
208
}
209
if memories >= 0 {
210
limiter = limiter.memories(memories as usize);
211
}
212
store.store.data_mut().store_limits = limiter.build();
213
store.store.limiter(|data| &mut data.store_limits);
214
}
215
216
#[unsafe(no_mangle)]
217
pub extern "C" fn wasmtime_context_get_data(store: WasmtimeStoreContext<'_>) -> *mut c_void {
218
store.data().foreign.data
219
}
220
221
#[unsafe(no_mangle)]
222
pub extern "C" fn wasmtime_context_set_data(
223
mut store: WasmtimeStoreContextMut<'_>,
224
data: *mut c_void,
225
) {
226
store.data_mut().foreign.data = data;
227
}
228
229
#[cfg(feature = "wasi")]
230
#[unsafe(no_mangle)]
231
pub extern "C" fn wasmtime_context_set_wasi(
232
mut context: WasmtimeStoreContextMut<'_>,
233
wasi: Box<crate::wasi_config_t>,
234
) -> Option<Box<wasmtime_error_t>> {
235
crate::handle_result(wasi.into_wasi_ctx(), |wasi| {
236
context.data_mut().wasi = Some(wasi);
237
})
238
}
239
240
#[cfg(all(feature = "component-model", feature = "wasi"))]
241
#[unsafe(no_mangle)]
242
pub unsafe extern "C" fn wasmtime_context_set_wasip2(
243
mut context: WasmtimeStoreContextMut<'_>,
244
mut config: Box<crate::wasmtime_wasip2_config_t>,
245
) {
246
context.data_mut().wasip2 = Some(config.builder.build());
247
}
248
249
#[unsafe(no_mangle)]
250
pub extern "C" fn wasmtime_context_gc(mut context: WasmtimeStoreContextMut<'_>) {
251
context.gc(None);
252
}
253
254
#[unsafe(no_mangle)]
255
pub extern "C" fn wasmtime_context_set_fuel(
256
mut store: WasmtimeStoreContextMut<'_>,
257
fuel: u64,
258
) -> Option<Box<wasmtime_error_t>> {
259
crate::handle_result(store.set_fuel(fuel), |()| {})
260
}
261
262
#[unsafe(no_mangle)]
263
pub extern "C" fn wasmtime_context_get_fuel(
264
store: WasmtimeStoreContext<'_>,
265
fuel: &mut u64,
266
) -> Option<Box<wasmtime_error_t>> {
267
crate::handle_result(store.get_fuel(), |amt| {
268
*fuel = amt;
269
})
270
}
271
272
#[unsafe(no_mangle)]
273
pub extern "C" fn wasmtime_context_set_epoch_deadline(
274
mut store: WasmtimeStoreContextMut<'_>,
275
ticks_beyond_current: u64,
276
) {
277
store.set_epoch_deadline(ticks_beyond_current);
278
}
279
280