use super::create_handle::create_handle;
use crate::trampoline::StoreInstanceHandle;
use crate::{GlobalType, Mutability, Store, Val};
use anyhow::Result;
use wasmtime_environ::entity::PrimaryMap;
use wasmtime_environ::{wasm, EntityIndex, Module};
use wasmtime_runtime::VMFunctionImport;
pub fn create_global(store: &Store, gt: &GlobalType, val: Val) -> Result<StoreInstanceHandle> {
let mut module = Module::new();
let mut func_imports = Vec::new();
let mut externref_init = None;
let global = wasm::Global {
wasm_ty: gt.content().to_wasm_type(),
ty: gt.content().get_wasmtime_type(),
mutability: match gt.mutability() {
Mutability::Const => false,
Mutability::Var => true,
},
initializer: match val {
Val::I32(i) => wasm::GlobalInit::I32Const(i),
Val::I64(i) => wasm::GlobalInit::I64Const(i),
Val::F32(f) => wasm::GlobalInit::F32Const(f),
Val::F64(f) => wasm::GlobalInit::F64Const(f),
Val::ExternRef(None) | Val::FuncRef(None) => wasm::GlobalInit::RefNullConst,
Val::ExternRef(Some(x)) => {
externref_init = Some(x);
wasm::GlobalInit::RefNullConst
}
Val::FuncRef(Some(f)) => {
let shared_sig_index = f.sig_index();
let local_sig_index = module
.signatures
.push(store.lookup_wasm_and_native_signatures(shared_sig_index));
let func_index = module.functions.push(local_sig_index);
module.num_imported_funcs = 1;
module
.imports
.push(("".into(), "".into(), EntityIndex::Function(func_index)));
let f = f.caller_checked_anyfunc();
let f = unsafe { f.as_ref() };
func_imports.push(VMFunctionImport {
body: f.func_ptr,
vmctx: f.vmctx,
});
wasm::GlobalInit::RefFunc(func_index)
}
_ => unimplemented!("create_global for {:?}", gt),
},
};
let global_id = module.globals.push(global);
module
.exports
.insert("global".to_string(), EntityIndex::Global(global_id));
let handle = create_handle(
module,
store,
PrimaryMap::new(),
Default::default(),
Box::new(()),
&func_imports,
)?;
if let Some(x) = externref_init {
match handle.lookup("global").unwrap() {
wasmtime_runtime::Export::Global(g) => unsafe {
*(*g.definition).as_externref_mut() = Some(x.inner);
},
_ => unreachable!(),
}
}
Ok(handle)
}