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 {
context(&self) -> WasmStoreContext<'_>34 pub unsafe fn context(&self) -> WasmStoreContext<'_> {
35 (*self.store.get()).as_context()
36 }
37
context_mut(&mut self) -> WasmStoreContextMut<'_>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)]
wasm_store_new(engine: &wasm_engine_t) -> Box<wasm_store_t>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 #[cfg(feature = "wasi-http")]
88 pub(crate) wasi_http: Option<wasmtime_wasi_http::WasiHttpCtx>,
89
90 /// Temporary storage for usage during a wasm->host call to store values
91 /// in a slice we pass to the C API.
92 pub hostcall_val_storage: Vec<wasmtime_val_t>,
93
94 /// Temporary storage for usage during host->wasm calls, same as above but
95 /// for a different direction.
96 pub wasm_val_storage: Vec<Val>,
97
98 /// Limits for the store.
99 pub store_limits: StoreLimits,
100 }
101
102 #[cfg(all(feature = "component-model", feature = "wasi"))]
103 impl wasmtime_wasi::WasiView for WasmtimeStoreData {
ctx(&mut self) -> wasmtime_wasi::WasiCtxView<'_>104 fn ctx(&mut self) -> wasmtime_wasi::WasiCtxView<'_> {
105 self.wasi.as_mut().unwrap().ctx()
106 }
107 }
108
109 #[cfg(all(feature = "component-model", feature = "wasi-http"))]
110 impl wasmtime_wasi_http::p2::WasiHttpView for WasmtimeStoreData {
http(&mut self) -> wasmtime_wasi_http::p2::WasiHttpCtxView<'_>111 fn http(&mut self) -> wasmtime_wasi_http::p2::WasiHttpCtxView<'_> {
112 use wasmtime_wasi::WasiView;
113 let ctx = self.wasi_http.as_mut().unwrap();
114 let table = self.wasi.as_mut().unwrap().ctx().table;
115 wasmtime_wasi_http::p2::WasiHttpCtxView {
116 ctx,
117 table,
118 hooks: wasmtime_wasi_http::p2::default_hooks(),
119 }
120 }
121 }
122
123 #[unsafe(no_mangle)]
wasmtime_store_new( engine: &wasm_engine_t, data: *mut c_void, finalizer: Option<extern "C" fn(*mut c_void)>, ) -> Box<wasmtime_store_t>124 pub extern "C" fn wasmtime_store_new(
125 engine: &wasm_engine_t,
126 data: *mut c_void,
127 finalizer: Option<extern "C" fn(*mut c_void)>,
128 ) -> Box<wasmtime_store_t> {
129 Box::new(wasmtime_store_t {
130 store: Store::new(
131 &engine.engine,
132 WasmtimeStoreData {
133 foreign: ForeignData { data, finalizer },
134 #[cfg(feature = "wasi")]
135 wasi: None,
136 #[cfg(feature = "wasi-http")]
137 wasi_http: None,
138 hostcall_val_storage: Vec::new(),
139 wasm_val_storage: Vec::new(),
140 store_limits: StoreLimits::default(),
141 },
142 ),
143 })
144 }
145
146 pub type wasmtime_update_deadline_kind_t = u8;
147 pub const WASMTIME_UPDATE_DEADLINE_CONTINUE: wasmtime_update_deadline_kind_t = 0;
148 pub const WASMTIME_UPDATE_DEADLINE_YIELD: wasmtime_update_deadline_kind_t = 1;
149
150 #[unsafe(no_mangle)]
wasmtime_store_epoch_deadline_callback( store: &mut wasmtime_store_t, func: extern "C" fn( WasmtimeStoreContextMut<'_>, *mut c_void, *mut u64, *mut wasmtime_update_deadline_kind_t, ) -> Option<Box<wasmtime_error_t>>, data: *mut c_void, finalizer: Option<extern "C" fn(*mut c_void)>, )151 pub extern "C" fn wasmtime_store_epoch_deadline_callback(
152 store: &mut wasmtime_store_t,
153 func: extern "C" fn(
154 WasmtimeStoreContextMut<'_>,
155 *mut c_void,
156 *mut u64,
157 *mut wasmtime_update_deadline_kind_t,
158 ) -> Option<Box<wasmtime_error_t>>,
159 data: *mut c_void,
160 finalizer: Option<extern "C" fn(*mut c_void)>,
161 ) {
162 let foreign = crate::ForeignData { data, finalizer };
163 store.store.epoch_deadline_callback(move |mut store_ctx| {
164 let _ = &foreign; // Move foreign into this closure
165 let mut delta: u64 = 0;
166 let mut kind = WASMTIME_UPDATE_DEADLINE_CONTINUE;
167 let result = (func)(
168 store_ctx.as_context_mut(),
169 foreign.data,
170 &mut delta as *mut u64,
171 &mut kind as *mut wasmtime_update_deadline_kind_t,
172 );
173 match result {
174 Some(err) => Err((*err).into()),
175 None if kind == WASMTIME_UPDATE_DEADLINE_CONTINUE => {
176 Ok(UpdateDeadline::Continue(delta))
177 }
178 #[cfg(feature = "async")]
179 None if kind == WASMTIME_UPDATE_DEADLINE_YIELD => Ok(UpdateDeadline::Yield(delta)),
180 _ => panic!("unknown wasmtime_update_deadline_kind_t: {kind}"),
181 }
182 });
183 }
184
185 #[unsafe(no_mangle)]
wasmtime_store_context( store: &mut wasmtime_store_t, ) -> WasmtimeStoreContextMut<'_>186 pub extern "C" fn wasmtime_store_context(
187 store: &mut wasmtime_store_t,
188 ) -> WasmtimeStoreContextMut<'_> {
189 store.store.as_context_mut()
190 }
191
192 #[unsafe(no_mangle)]
wasmtime_store_limiter( store: &mut wasmtime_store_t, memory_size: i64, table_elements: i64, instances: i64, tables: i64, memories: i64, )193 pub extern "C" fn wasmtime_store_limiter(
194 store: &mut wasmtime_store_t,
195 memory_size: i64,
196 table_elements: i64,
197 instances: i64,
198 tables: i64,
199 memories: i64,
200 ) {
201 let mut limiter = StoreLimitsBuilder::new();
202 if memory_size >= 0 {
203 limiter = limiter.memory_size(memory_size as usize);
204 }
205 if table_elements >= 0 {
206 limiter = limiter.table_elements(table_elements as usize);
207 }
208 if instances >= 0 {
209 limiter = limiter.instances(instances as usize);
210 }
211 if tables >= 0 {
212 limiter = limiter.tables(tables as usize);
213 }
214 if memories >= 0 {
215 limiter = limiter.memories(memories as usize);
216 }
217 store.store.data_mut().store_limits = limiter.build();
218 store.store.limiter(|data| &mut data.store_limits);
219 }
220
221 #[unsafe(no_mangle)]
wasmtime_context_get_data(store: WasmtimeStoreContext<'_>) -> *mut c_void222 pub extern "C" fn wasmtime_context_get_data(store: WasmtimeStoreContext<'_>) -> *mut c_void {
223 store.data().foreign.data
224 }
225
226 #[unsafe(no_mangle)]
wasmtime_context_set_data( mut store: WasmtimeStoreContextMut<'_>, data: *mut c_void, )227 pub extern "C" fn wasmtime_context_set_data(
228 mut store: WasmtimeStoreContextMut<'_>,
229 data: *mut c_void,
230 ) {
231 store.data_mut().foreign.data = data;
232 }
233
234 #[cfg(feature = "wasi")]
235 #[unsafe(no_mangle)]
wasmtime_context_set_wasi( mut context: WasmtimeStoreContextMut<'_>, wasi: Box<crate::wasi_config_t>, ) -> Option<Box<wasmtime_error_t>>236 pub extern "C" fn wasmtime_context_set_wasi(
237 mut context: WasmtimeStoreContextMut<'_>,
238 wasi: Box<crate::wasi_config_t>,
239 ) -> Option<Box<wasmtime_error_t>> {
240 crate::handle_result(wasi.into_wasi_ctx(), |wasi| {
241 context.data_mut().wasi = Some(wasi);
242 })
243 }
244
245 #[cfg(feature = "wasi-http")]
246 #[unsafe(no_mangle)]
wasmtime_context_set_wasi_http(mut context: WasmtimeStoreContextMut<'_>)247 pub extern "C" fn wasmtime_context_set_wasi_http(mut context: WasmtimeStoreContextMut<'_>) {
248 context.data_mut().wasi_http = Some(wasmtime_wasi_http::WasiHttpCtx::new());
249 }
250
251 #[unsafe(no_mangle)]
wasmtime_context_gc( mut context: WasmtimeStoreContextMut<'_>, ) -> Option<Box<wasmtime_error_t>>252 pub extern "C" fn wasmtime_context_gc(
253 mut context: WasmtimeStoreContextMut<'_>,
254 ) -> Option<Box<wasmtime_error_t>> {
255 crate::handle_result(context.gc(None), |()| {})
256 }
257
258 #[unsafe(no_mangle)]
wasmtime_context_set_fuel( mut store: WasmtimeStoreContextMut<'_>, fuel: u64, ) -> Option<Box<wasmtime_error_t>>259 pub extern "C" fn wasmtime_context_set_fuel(
260 mut store: WasmtimeStoreContextMut<'_>,
261 fuel: u64,
262 ) -> Option<Box<wasmtime_error_t>> {
263 crate::handle_result(store.set_fuel(fuel), |()| {})
264 }
265
266 #[unsafe(no_mangle)]
wasmtime_context_get_fuel( store: WasmtimeStoreContext<'_>, fuel: &mut u64, ) -> Option<Box<wasmtime_error_t>>267 pub extern "C" fn wasmtime_context_get_fuel(
268 store: WasmtimeStoreContext<'_>,
269 fuel: &mut u64,
270 ) -> Option<Box<wasmtime_error_t>> {
271 crate::handle_result(store.get_fuel(), |amt| {
272 *fuel = amt;
273 })
274 }
275
276 #[unsafe(no_mangle)]
wasmtime_context_set_epoch_deadline( mut store: WasmtimeStoreContextMut<'_>, ticks_beyond_current: u64, )277 pub extern "C" fn wasmtime_context_set_epoch_deadline(
278 mut store: WasmtimeStoreContextMut<'_>,
279 ticks_beyond_current: u64,
280 ) {
281 store.set_epoch_deadline(ticks_beyond_current);
282 }
283