wasmtime/runtime/externals/
global.rs1use crate::prelude::*;
2use crate::{
3 store::{AutoAssertNoGc, StoreData, StoreOpaque, Stored},
4 trampoline::generate_global_export,
5 AnyRef, AsContext, AsContextMut, ExternRef, Func, GlobalType, HeapType, Mutability, Ref,
6 RootedGcRefImpl, Val, ValType,
7};
8use core::ptr;
9use wasmtime_environ::TypeTrace;
10
11#[derive(Copy, Clone, Debug)]
24#[repr(transparent)] pub struct Global(pub(super) Stored<crate::runtime::vm::ExportGlobal>);
26
27impl Global {
28 pub fn new(mut store: impl AsContextMut, ty: GlobalType, val: Val) -> Result<Global> {
73 Global::_new(store.as_context_mut().0, ty, val)
74 }
75
76 fn _new(store: &mut StoreOpaque, ty: GlobalType, val: Val) -> Result<Global> {
77 val.ensure_matches_ty(store, ty.content()).context(
78 "type mismatch: initial value provided does not match the type of this global",
79 )?;
80 unsafe {
81 let wasmtime_export = generate_global_export(store, ty, val)?;
82 Ok(Global::from_wasmtime_global(wasmtime_export, store))
83 }
84 }
85
86 pub fn ty(&self, store: impl AsContext) -> GlobalType {
92 self._ty(store.as_context().0)
93 }
94
95 pub(crate) fn _ty(&self, store: &StoreOpaque) -> GlobalType {
96 let ty = &store[self.0].global;
97 GlobalType::from_wasmtime_global(store.engine(), &ty)
98 }
99
100 pub fn get(&self, mut store: impl AsContextMut) -> Val {
106 unsafe {
107 let store = store.as_context_mut();
108 let mut store = AutoAssertNoGc::new(store.0);
109 let definition = store[self.0].definition.as_ref();
110 match self._ty(&store).content() {
111 ValType::I32 => Val::from(*definition.as_i32()),
112 ValType::I64 => Val::from(*definition.as_i64()),
113 ValType::F32 => Val::F32(*definition.as_u32()),
114 ValType::F64 => Val::F64(*definition.as_u64()),
115 ValType::V128 => Val::V128(definition.get_u128().into()),
116 ValType::Ref(ref_ty) => {
117 let reference: Ref = match ref_ty.heap_type() {
118 HeapType::Func | HeapType::ConcreteFunc(_) => {
119 Func::_from_raw(&mut store, definition.as_func_ref().cast()).into()
120 }
121
122 HeapType::NoFunc => Ref::Func(None),
123
124 HeapType::Extern => Ref::Extern(
125 definition
126 .as_gc_ref()
127 .map(|r| {
128 let r = store.unwrap_gc_store_mut().clone_gc_ref(r);
129 ExternRef::from_cloned_gc_ref(&mut store, r)
130 })
131 .into(),
132 ),
133
134 HeapType::NoExtern => Ref::Extern(None),
135
136 HeapType::Any
137 | HeapType::Eq
138 | HeapType::I31
139 | HeapType::Struct
140 | HeapType::ConcreteStruct(_)
141 | HeapType::Array
142 | HeapType::ConcreteArray(_) => definition
143 .as_gc_ref()
144 .map(|r| {
145 let r = store.unwrap_gc_store_mut().clone_gc_ref(r);
146 AnyRef::from_cloned_gc_ref(&mut store, r)
147 })
148 .into(),
149
150 HeapType::None => Ref::Any(None),
151 };
152 debug_assert!(
153 ref_ty.is_nullable() || !reference.is_null(),
154 "if the type is non-nullable, we better have a non-null reference"
155 );
156 reference.into()
157 }
158 }
159 }
160 }
161
162 pub fn set(&self, mut store: impl AsContextMut, val: Val) -> Result<()> {
174 let mut store = AutoAssertNoGc::new(store.as_context_mut().0);
175 let global_ty = self._ty(&store);
176 if global_ty.mutability() != Mutability::Var {
177 bail!("immutable global cannot be set");
178 }
179 val.ensure_matches_ty(&store, global_ty.content())
180 .context("type mismatch: attempt to set global to value of wrong type")?;
181 unsafe {
182 let definition = store[self.0].definition.as_mut();
183 match val {
184 Val::I32(i) => *definition.as_i32_mut() = i,
185 Val::I64(i) => *definition.as_i64_mut() = i,
186 Val::F32(f) => *definition.as_u32_mut() = f,
187 Val::F64(f) => *definition.as_u64_mut() = f,
188 Val::V128(i) => definition.set_u128(i.into()),
189 Val::FuncRef(f) => {
190 *definition.as_func_ref_mut() = f.map_or(ptr::null_mut(), |f| {
191 f.vm_func_ref(&mut store).as_ptr().cast()
192 });
193 }
194 Val::ExternRef(e) => {
195 let new = match e {
196 None => None,
197 #[cfg_attr(not(feature = "gc"), allow(unreachable_patterns))]
198 Some(e) => Some(e.try_gc_ref(&store)?.unchecked_copy()),
199 };
200 let new = new.as_ref();
201 definition.write_gc_ref(store.unwrap_gc_store_mut(), new);
202 }
203 Val::AnyRef(a) => {
204 let new = match a {
205 None => None,
206 #[cfg_attr(not(feature = "gc"), allow(unreachable_patterns))]
207 Some(a) => Some(a.try_gc_ref(&store)?.unchecked_copy()),
208 };
209 let new = new.as_ref();
210 definition.write_gc_ref(store.unwrap_gc_store_mut(), new);
211 }
212 }
213 }
214 Ok(())
215 }
216
217 #[cfg(feature = "gc")]
218 pub(crate) fn trace_root(
219 &self,
220 store: &mut StoreOpaque,
221 gc_roots_list: &mut crate::runtime::vm::GcRootsList,
222 ) {
223 if let Some(ref_ty) = self._ty(store).content().as_ref() {
224 if !ref_ty.is_vmgcref_type_and_points_to_object() {
225 return;
226 }
227
228 if let Some(gc_ref) = unsafe { store[self.0].definition.as_ref().as_gc_ref() } {
229 unsafe {
230 gc_roots_list.add_root(gc_ref.into(), "Wasm global");
231 }
232 }
233 }
234 }
235
236 pub(crate) unsafe fn from_wasmtime_global(
237 wasmtime_export: crate::runtime::vm::ExportGlobal,
238 store: &mut StoreOpaque,
239 ) -> Global {
240 debug_assert!(wasmtime_export
241 .global
242 .wasm_ty
243 .is_canonicalized_for_runtime_usage());
244 Global(store.store_data_mut().insert(wasmtime_export))
245 }
246
247 pub(crate) fn wasmtime_ty<'a>(&self, data: &'a StoreData) -> &'a wasmtime_environ::Global {
248 &data[self.0].global
249 }
250
251 pub(crate) fn vmimport(&self, store: &StoreOpaque) -> crate::runtime::vm::VMGlobalImport {
252 crate::runtime::vm::VMGlobalImport {
253 from: store[self.0].definition.into(),
254 }
255 }
256
257 #[cfg(feature = "coredump")]
263 pub(crate) fn hash_key(&self, store: &StoreOpaque) -> impl core::hash::Hash + Eq + use<> {
264 store[self.0].definition.as_ptr() as usize
265 }
266}
267
268#[cfg(test)]
269mod tests {
270 use super::*;
271 use crate::{Instance, Module, Store};
272
273 #[test]
274 fn hash_key_is_stable_across_duplicate_store_data_entries() -> Result<()> {
275 let mut store = Store::<()>::default();
276 let module = Module::new(
277 store.engine(),
278 r#"
279 (module
280 (global (export "g") (mut i32) (i32.const 0))
281 )
282 "#,
283 )?;
284 let instance = Instance::new(&mut store, &module, &[])?;
285
286 let g1 = instance.get_global(&mut store, "g").unwrap();
290 let g2 = instance.get_global(&mut store, "g").unwrap();
291
292 assert_eq!(g1.get(&mut store).unwrap_i32(), 0);
294 assert_eq!(g2.get(&mut store).unwrap_i32(), 0);
295 g1.set(&mut store, Val::I32(42))?;
296 assert_eq!(g1.get(&mut store).unwrap_i32(), 42);
297 assert_eq!(g2.get(&mut store).unwrap_i32(), 42);
298
299 assert!(g1.hash_key(&store.as_context().0) == g2.hash_key(&store.as_context().0));
301
302 let instance2 = Instance::new(&mut store, &module, &[])?;
304 let g3 = instance2.get_global(&mut store, "g").unwrap();
305 assert!(g1.hash_key(&store.as_context().0) != g3.hash_key(&store.as_context().0));
306
307 Ok(())
308 }
309}