1use crate::{ForeignData, wasm_engine_t, wasmtime_error_t, wasmtime_val_t};
2use std::cell::UnsafeCell;
3use std::ffi::c_void;
4use std::sync::Arc;
5use wasmtime::{
6 AsContext, AsContextMut, Caller, Store, StoreContext, StoreContextMut, StoreLimits,
7 StoreLimitsBuilder, UpdateDeadline, Val,
8};
9
10pub type WasmStoreData = ();
13pub type WasmStore = Store<WasmStoreData>;
14pub type WasmStoreContext<'a> = StoreContext<'a, WasmStoreData>;
15pub type WasmStoreContextMut<'a> = StoreContextMut<'a, WasmStoreData>;
16
17#[derive(Clone)]
29pub struct WasmStoreRef {
30 store: Arc<UnsafeCell<WasmStore>>,
31}
32
33impl 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)]
45pub struct wasm_store_t {
46 pub(crate) store: WasmStoreRef,
47}
48
49wasmtime_c_api_macros::declare_own!(wasm_store_t);
50
51#[unsafe(no_mangle)]
52pub 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
62pub type WasmtimeStore = Store<WasmtimeStoreData>;
65pub type WasmtimeStoreContext<'a> = StoreContext<'a, WasmtimeStoreData>;
66pub type WasmtimeStoreContextMut<'a> = StoreContextMut<'a, WasmtimeStoreData>;
67pub type WasmtimeCaller<'a> = Caller<'a, WasmtimeStoreData>;
68
69#[repr(C)]
77pub struct wasmtime_store_t {
78 pub(crate) store: WasmtimeStore,
79}
80
81wasmtime_c_api_macros::declare_own!(wasmtime_store_t);
82
83pub struct WasmtimeStoreData {
84 foreign: crate::ForeignData,
85 #[cfg(feature = "wasi")]
86 pub(crate) wasi: Option<wasmtime_wasi::p1::WasiP1Ctx>,
87
88 pub hostcall_val_storage: Vec<wasmtime_val_t>,
91
92 pub wasm_val_storage: Vec<Val>,
95
96 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"))]
107impl 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)]
117pub 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
141pub type wasmtime_update_deadline_kind_t = u8;
142pub const WASMTIME_UPDATE_DEADLINE_CONTINUE: wasmtime_update_deadline_kind_t = 0;
143pub const WASMTIME_UPDATE_DEADLINE_YIELD: wasmtime_update_deadline_kind_t = 1;
144
145#[unsafe(no_mangle)]
146pub 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; 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)]
181pub 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)]
188pub 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)]
217pub extern "C" fn wasmtime_context_get_data(store: WasmtimeStoreContext<'_>) -> *mut c_void {
218 store.data().foreign.data
219}
220
221#[unsafe(no_mangle)]
222pub 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)]
231pub 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)]
242pub 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)]
250pub extern "C" fn wasmtime_context_gc(mut context: WasmtimeStoreContextMut<'_>) {
251 context.gc(None);
252}
253
254#[unsafe(no_mangle)]
255pub 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)]
263pub 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)]
273pub 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}