1use crate::{wasm_engine_t, wasmtime_error_t, wasmtime_val_t, ForeignData};
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::preview1::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
100#[unsafe(no_mangle)]
101pub extern "C" fn wasmtime_store_new(
102 engine: &wasm_engine_t,
103 data: *mut c_void,
104 finalizer: Option<extern "C" fn(*mut c_void)>,
105) -> Box<wasmtime_store_t> {
106 Box::new(wasmtime_store_t {
107 store: Store::new(
108 &engine.engine,
109 WasmtimeStoreData {
110 foreign: ForeignData { data, finalizer },
111 #[cfg(feature = "wasi")]
112 wasi: None,
113 hostcall_val_storage: Vec::new(),
114 wasm_val_storage: Vec::new(),
115 store_limits: StoreLimits::default(),
116 },
117 ),
118 })
119}
120
121pub type wasmtime_update_deadline_kind_t = u8;
122pub const WASMTIME_UPDATE_DEADLINE_CONTINUE: wasmtime_update_deadline_kind_t = 0;
123pub const WASMTIME_UPDATE_DEADLINE_YIELD: wasmtime_update_deadline_kind_t = 1;
124
125#[unsafe(no_mangle)]
126pub extern "C" fn wasmtime_store_epoch_deadline_callback(
127 store: &mut wasmtime_store_t,
128 func: extern "C" fn(
129 WasmtimeStoreContextMut<'_>,
130 *mut c_void,
131 *mut u64,
132 *mut wasmtime_update_deadline_kind_t,
133 ) -> Option<Box<wasmtime_error_t>>,
134 data: *mut c_void,
135 finalizer: Option<extern "C" fn(*mut c_void)>,
136) {
137 let foreign = crate::ForeignData { data, finalizer };
138 store.store.epoch_deadline_callback(move |mut store_ctx| {
139 let _ = &foreign; let mut delta: u64 = 0;
141 let mut kind = WASMTIME_UPDATE_DEADLINE_CONTINUE;
142 let result = (func)(
143 store_ctx.as_context_mut(),
144 foreign.data,
145 &mut delta as *mut u64,
146 &mut kind as *mut wasmtime_update_deadline_kind_t,
147 );
148 match result {
149 Some(err) => Err(wasmtime::Error::from(<wasmtime_error_t as Into<
150 anyhow::Error,
151 >>::into(*err))),
152 None if kind == WASMTIME_UPDATE_DEADLINE_CONTINUE => {
153 Ok(UpdateDeadline::Continue(delta))
154 }
155 #[cfg(feature = "async")]
156 None if kind == WASMTIME_UPDATE_DEADLINE_YIELD => Ok(UpdateDeadline::Yield(delta)),
157 _ => panic!("unknown wasmtime_update_deadline_kind_t: {kind}"),
158 }
159 });
160}
161
162#[unsafe(no_mangle)]
163pub extern "C" fn wasmtime_store_context(
164 store: &mut wasmtime_store_t,
165) -> WasmtimeStoreContextMut<'_> {
166 store.store.as_context_mut()
167}
168
169#[unsafe(no_mangle)]
170pub extern "C" fn wasmtime_store_limiter(
171 store: &mut wasmtime_store_t,
172 memory_size: i64,
173 table_elements: i64,
174 instances: i64,
175 tables: i64,
176 memories: i64,
177) {
178 let mut limiter = StoreLimitsBuilder::new();
179 if memory_size >= 0 {
180 limiter = limiter.memory_size(memory_size as usize);
181 }
182 if table_elements >= 0 {
183 limiter = limiter.table_elements(table_elements as usize);
184 }
185 if instances >= 0 {
186 limiter = limiter.instances(instances as usize);
187 }
188 if tables >= 0 {
189 limiter = limiter.tables(tables as usize);
190 }
191 if memories >= 0 {
192 limiter = limiter.memories(memories as usize);
193 }
194 store.store.data_mut().store_limits = limiter.build();
195 store.store.limiter(|data| &mut data.store_limits);
196}
197
198#[unsafe(no_mangle)]
199pub extern "C" fn wasmtime_context_get_data(store: WasmtimeStoreContext<'_>) -> *mut c_void {
200 store.data().foreign.data
201}
202
203#[unsafe(no_mangle)]
204pub extern "C" fn wasmtime_context_set_data(
205 mut store: WasmtimeStoreContextMut<'_>,
206 data: *mut c_void,
207) {
208 store.data_mut().foreign.data = data;
209}
210
211#[cfg(feature = "wasi")]
212#[unsafe(no_mangle)]
213pub extern "C" fn wasmtime_context_set_wasi(
214 mut context: WasmtimeStoreContextMut<'_>,
215 wasi: Box<crate::wasi_config_t>,
216) -> Option<Box<wasmtime_error_t>> {
217 crate::handle_result(wasi.into_wasi_ctx(), |wasi| {
218 context.data_mut().wasi = Some(wasi);
219 })
220}
221
222#[unsafe(no_mangle)]
223pub extern "C" fn wasmtime_context_gc(mut context: WasmtimeStoreContextMut<'_>) {
224 context.gc();
225}
226
227#[unsafe(no_mangle)]
228pub extern "C" fn wasmtime_context_set_fuel(
229 mut store: WasmtimeStoreContextMut<'_>,
230 fuel: u64,
231) -> Option<Box<wasmtime_error_t>> {
232 crate::handle_result(store.set_fuel(fuel), |()| {})
233}
234
235#[unsafe(no_mangle)]
236pub extern "C" fn wasmtime_context_get_fuel(
237 store: WasmtimeStoreContext<'_>,
238 fuel: &mut u64,
239) -> Option<Box<wasmtime_error_t>> {
240 crate::handle_result(store.get_fuel(), |amt| {
241 *fuel = amt;
242 })
243}
244
245#[unsafe(no_mangle)]
246pub extern "C" fn wasmtime_context_set_epoch_deadline(
247 mut store: WasmtimeStoreContextMut<'_>,
248 ticks_beyond_current: u64,
249) {
250 store.set_epoch_deadline(ticks_beyond_current);
251}