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