1 use crate::runtime::vm::{StoreBox, VMGlobalDefinition};
2 use crate::store::{AutoAssertNoGc, StoreOpaque};
3 use crate::type_registry::RegisteredType;
4 use crate::{GlobalType, Mutability, Result, RootedGcRefImpl, Val};
5 use core::ptr;
6 use wasmtime_environ::Global;
7 
8 #[repr(C)]
9 pub struct VMHostGlobalContext {
10     pub(crate) ty: Global,
11     pub(crate) global: VMGlobalDefinition,
12 
13     _registered_type: Option<RegisteredType>,
14 }
15 
generate_global_export( store: &mut StoreOpaque, ty: GlobalType, val: Val, ) -> Result<crate::Global>16 pub fn generate_global_export(
17     store: &mut StoreOpaque,
18     ty: GlobalType,
19     val: Val,
20 ) -> Result<crate::Global> {
21     let global = wasmtime_environ::Global {
22         wasm_ty: ty.content().to_wasm_type(),
23         mutability: match ty.mutability() {
24             Mutability::Const => false,
25             Mutability::Var => true,
26         },
27     };
28     let ctx = StoreBox::new(VMHostGlobalContext {
29         ty: global,
30         global: VMGlobalDefinition::new(),
31         _registered_type: ty.into_registered_type(),
32     })?;
33 
34     let mut store = AutoAssertNoGc::new(store);
35     // SAFETY: the global that this is pointing to is rooted in `ctx` above and
36     // is safe to initialize.
37     unsafe {
38         let global = &mut ctx.get().as_mut().global;
39         match val {
40             Val::I32(x) => *global.as_i32_mut() = x,
41             Val::I64(x) => *global.as_i64_mut() = x,
42             Val::F32(x) => *global.as_f32_bits_mut() = x,
43             Val::F64(x) => *global.as_f64_bits_mut() = x,
44             Val::V128(x) => global.set_u128(x.into()),
45             Val::FuncRef(f) => {
46                 *global.as_func_ref_mut() =
47                     f.map_or(ptr::null_mut(), |f| f.vm_func_ref(&store).as_ptr());
48             }
49             Val::ExternRef(x) => {
50                 let new = match x {
51                     None => None,
52                     Some(x) => Some(x.try_gc_ref(&store)?.unchecked_copy()),
53                 };
54                 let new = new.as_ref();
55                 global.write_gc_ref(&mut store, new);
56             }
57             Val::AnyRef(a) => {
58                 let new = match a {
59                     None => None,
60                     Some(a) => Some(a.try_gc_ref(&store)?.unchecked_copy()),
61                 };
62                 let new = new.as_ref();
63                 global.write_gc_ref(&mut store, new);
64             }
65             Val::ExnRef(e) => {
66                 let new = match e {
67                     None => None,
68                     Some(e) => Some(e.try_gc_ref(&store)?.unchecked_copy()),
69                 };
70                 let new = new.as_ref();
71                 global.write_gc_ref(&mut store, new);
72             }
73             Val::ContRef(None) => {
74                 // Allow null continuation references for trampoline globals - these are just placeholders
75                 global.write_gc_ref(&mut store, None);
76             }
77             Val::ContRef(Some(_)) => {
78                 // TODO(#10248): Implement non-null trampoline continuation reference handling
79                 return Err(crate::format_err!(
80                     "non-null continuation references in trampoline globals not yet supported"
81                 ));
82             }
83         }
84     }
85 
86     let index = store.host_globals_mut().push(ctx)?;
87     Ok(crate::Global::from_host(store.id(), index))
88 }
89