wasmtime/runtime/trampoline/
global.rs

1use crate::runtime::vm::{StoreBox, VMGlobalDefinition};
2use crate::store::{AutoAssertNoGc, StoreOpaque};
3use crate::type_registry::RegisteredType;
4use crate::{GlobalType, Mutability, Result, RootedGcRefImpl, Val};
5use core::ptr;
6use wasmtime_environ::Global;
7
8#[repr(C)]
9pub struct VMHostGlobalContext {
10    pub(crate) ty: Global,
11    pub(crate) global: VMGlobalDefinition,
12
13    _registered_type: Option<RegisteredType>,
14}
15
16pub 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(anyhow::anyhow!(
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}