1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
use crate::store::{InstanceId, StoreOpaque};
use crate::trampoline::create_handle;
use crate::{GlobalType, Mutability, Val};
use anyhow::Result;
use wasmtime_environ::{
    AnyfuncIndex, EntityIndex, Global, GlobalInit, Module, ModuleType, SignatureIndex,
};
use wasmtime_runtime::VMFunctionImport;

pub fn create_global(store: &mut StoreOpaque, gt: &GlobalType, val: Val) -> Result<InstanceId> {
    let mut module = Module::new();
    let mut func_imports = Vec::new();
    let mut externref_init = None;
    let mut one_signature = None;

    let global = Global {
        wasm_ty: gt.content().to_wasm_type(),
        mutability: match gt.mutability() {
            Mutability::Const => false,
            Mutability::Var => true,
        },
        initializer: match val {
            Val::I32(i) => GlobalInit::I32Const(i),
            Val::I64(i) => GlobalInit::I64Const(i),
            Val::F32(f) => GlobalInit::F32Const(f),
            Val::F64(f) => GlobalInit::F64Const(f),
            Val::V128(i) => GlobalInit::V128Const(i.into()),
            Val::ExternRef(None) | Val::FuncRef(None) => GlobalInit::RefNullConst,
            Val::ExternRef(Some(x)) => {
                // There is no `GlobalInit` variant for using an existing
                // `externref` that isn't an import (because Wasm can't create
                // an `externref` by itself). Therefore, initialize the global
                // as null, and then monkey patch it after instantiation below.
                externref_init = Some(x);
                GlobalInit::RefNullConst
            }
            Val::FuncRef(Some(f)) => {
                // Add a function import to the stub module, and then initialize
                // our global with a `ref.func` to grab that imported function.
                let f = f.caller_checked_anyfunc(store);
                let f = unsafe { f.as_ref() };
                let sig_id = SignatureIndex::from_u32(0);
                one_signature = Some(f.type_index);
                module.types.push(ModuleType::Function(sig_id));
                let func_index = module.push_escaped_function(sig_id, AnyfuncIndex::from_u32(0));
                module.num_imported_funcs = 1;
                module.num_escaped_funcs = 1;
                module
                    .initializers
                    .push(wasmtime_environ::Initializer::Import {
                        name: "".into(),
                        field: "".into(),
                        index: EntityIndex::Function(func_index),
                    });

                func_imports.push(VMFunctionImport {
                    body: f.func_ptr,
                    vmctx: f.vmctx,
                });

                GlobalInit::RefFunc(func_index)
            }
        },
    };

    let global_id = module.globals.push(global);
    module
        .exports
        .insert(String::new(), EntityIndex::Global(global_id));
    let id = create_handle(module, store, Box::new(()), &func_imports, one_signature)?;

    if let Some(x) = externref_init {
        let instance = store.instance_mut(id);
        let g = instance.get_exported_global(global_id);
        unsafe {
            *(*g.definition).as_externref_mut() = Some(x.inner);
        }
    }

    Ok(id)
}