Skip to content

Commit b04bd00

Browse files
committed
wasmtime: Enable {extern,func}ref globals in the API
1 parent fb6913c commit b04bd00

11 files changed

Lines changed: 199 additions & 43 deletions

File tree

crates/runtime/src/lib.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,14 @@ pub fn ref_type() -> wasmtime_environ::ir::Type {
6767
unreachable!()
6868
}
6969
}
70+
71+
/// The Cranelift IR type used for pointer types for this target architecture.
72+
pub fn pointer_type() -> wasmtime_environ::ir::Type {
73+
if cfg!(target_pointer_width = "32") {
74+
wasmtime_environ::ir::types::I32
75+
} else if cfg!(target_pointer_width = "64") {
76+
wasmtime_environ::ir::types::I64
77+
} else {
78+
unreachable!()
79+
}
80+
}

crates/runtime/src/sig_registry.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,18 @@ impl SignatureRegistry {
6565
pub fn lookup_wasm(&self, idx: VMSharedSignatureIndex) -> Option<WasmFuncType> {
6666
self.index2wasm.get(&idx).cloned()
6767
}
68+
69+
/// Looks up both a shared Wasm function signature and its associated native
70+
/// `ir::Signature` within this registry.
71+
///
72+
/// Note that for this operation to be semantically correct the `idx` must
73+
/// have previously come from a call to `register` of this same object.
74+
pub fn lookup_wasm_and_native_signatures(
75+
&self,
76+
idx: VMSharedSignatureIndex,
77+
) -> Option<(WasmFuncType, ir::Signature)> {
78+
let wasm = self.lookup_wasm(idx)?;
79+
let native = self.lookup_native(idx)?;
80+
Some((wasm, native))
81+
}
6882
}

crates/wasmtime/src/func.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ use std::panic::{self, AssertUnwindSafe};
99
use std::ptr::{self, NonNull};
1010
use std::rc::Weak;
1111
use wasmtime_runtime::{
12-
raise_user_trap, Export, InstanceHandle, VMContext, VMFunctionBody, VMTrampoline,
12+
raise_user_trap, Export, InstanceHandle, VMContext, VMFunctionBody, VMSharedSignatureIndex,
13+
VMTrampoline,
1314
};
1415

1516
/// A WebAssembly function which can be called.
@@ -486,19 +487,20 @@ impl Func {
486487
func.into_func(store)
487488
}
488489

490+
pub(crate) fn sig_index(&self) -> VMSharedSignatureIndex {
491+
unsafe { self.export.anyfunc.as_ref().type_index }
492+
}
493+
489494
/// Returns the underlying wasm type that this `Func` has.
490495
pub fn ty(&self) -> FuncType {
491496
// Signatures should always be registered in the store's registry of
492497
// shared signatures, so we should be able to unwrap safely here.
493-
let sig = self
494-
.instance
495-
.store
496-
.lookup_signature(unsafe { self.export.anyfunc.as_ref().type_index });
498+
let wft = self.instance.store.lookup_signature(self.sig_index());
497499

498500
// This is only called with `Export::Function`, and since it's coming
499501
// from wasmtime_runtime itself we should support all the types coming
500502
// out of it, so assert such here.
501-
FuncType::from_wasm_func_type(&sig).expect("core wasm signature should be supported")
503+
FuncType::from_wasm_func_type(&wft).expect("core wasm signature should be supported")
502504
}
503505

504506
/// Returns the number of parameters that this function takes.

crates/wasmtime/src/runtime.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -900,6 +900,17 @@ impl Store {
900900
.expect("failed to lookup signature")
901901
}
902902

903+
pub(crate) fn lookup_wasm_and_native_signatures(
904+
&self,
905+
sig_index: VMSharedSignatureIndex,
906+
) -> (wasm::WasmFuncType, ir::Signature) {
907+
self.inner
908+
.signatures
909+
.borrow()
910+
.lookup_wasm_and_native_signatures(sig_index)
911+
.expect("failed to lookup signature")
912+
}
913+
903914
pub(crate) fn register_signature(
904915
&self,
905916
wasm_sig: wasm::WasmFuncType,

crates/wasmtime/src/trampoline/create_handle.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ use std::any::Any;
77
use std::collections::HashMap;
88
use std::sync::Arc;
99
use wasmtime_environ::entity::PrimaryMap;
10-
use wasmtime_environ::wasm::DefinedFuncIndex;
10+
use wasmtime_environ::wasm::{DefinedFuncIndex, FuncIndex};
1111
use wasmtime_environ::Module;
1212
use wasmtime_runtime::{
1313
Imports, InstanceHandle, StackMapRegistry, VMExternRefActivationsTable, VMFunctionBody,
14-
VMSharedSignatureIndex, VMTrampoline,
14+
VMFunctionImport, VMSharedSignatureIndex, VMTrampoline,
1515
};
1616

1717
pub(crate) fn create_handle(
@@ -20,9 +20,10 @@ pub(crate) fn create_handle(
2020
finished_functions: PrimaryMap<DefinedFuncIndex, *mut [VMFunctionBody]>,
2121
trampolines: HashMap<VMSharedSignatureIndex, VMTrampoline>,
2222
state: Box<dyn Any>,
23+
func_imports: PrimaryMap<FuncIndex, VMFunctionImport>,
2324
) -> Result<StoreInstanceHandle> {
2425
let imports = Imports::new(
25-
PrimaryMap::new(),
26+
func_imports,
2627
PrimaryMap::new(),
2728
PrimaryMap::new(),
2829
PrimaryMap::new(),

crates/wasmtime/src/trampoline/func.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use super::create_handle::create_handle;
44
use crate::trampoline::StoreInstanceHandle;
55
use crate::{FuncType, Store, Trap};
6-
use anyhow::{bail, Result};
6+
use anyhow::Result;
77
use std::any::Any;
88
use std::cmp;
99
use std::collections::HashMap;
@@ -211,10 +211,7 @@ pub fn create_handle_with_function(
211211
let isa = store.engine().config().target_isa();
212212

213213
let pointer_type = isa.pointer_type();
214-
let sig = match ft.get_wasmtime_signature(pointer_type) {
215-
Some(sig) => sig,
216-
None => bail!("not a supported core wasm signature {:?}", ft),
217-
};
214+
let sig = ft.get_wasmtime_signature(pointer_type);
218215

219216
let mut fn_builder_ctx = FunctionBuilderContext::new();
220217
let mut module = Module::new();
@@ -259,6 +256,7 @@ pub fn create_handle_with_function(
259256
finished_functions,
260257
trampolines,
261258
Box::new(trampoline_state),
259+
PrimaryMap::new(),
262260
)
263261
.map(|instance| (instance, trampoline))
264262
}
@@ -277,10 +275,7 @@ pub unsafe fn create_handle_with_raw_function(
277275
};
278276

279277
let pointer_type = isa.pointer_type();
280-
let sig = match ft.get_wasmtime_signature(pointer_type) {
281-
Some(sig) => sig,
282-
None => bail!("not a supported core wasm signature {:?}", ft),
283-
};
278+
let sig = ft.get_wasmtime_signature(pointer_type);
284279

285280
let mut module = Module::new();
286281
let mut finished_functions = PrimaryMap::new();
@@ -298,5 +293,12 @@ pub unsafe fn create_handle_with_raw_function(
298293
let sig_id = store.register_signature(ft.to_wasm_func_type(), sig);
299294
trampolines.insert(sig_id, trampoline);
300295

301-
create_handle(module, store, finished_functions, trampolines, state)
296+
create_handle(
297+
module,
298+
store,
299+
finished_functions,
300+
trampolines,
301+
state,
302+
PrimaryMap::new(),
303+
)
302304
}
Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
use super::create_handle::create_handle;
22
use crate::trampoline::StoreInstanceHandle;
33
use crate::{GlobalType, Mutability, Store, Val};
4-
use anyhow::{bail, Result};
4+
use anyhow::Result;
55
use wasmtime_environ::entity::PrimaryMap;
66
use wasmtime_environ::{wasm, EntityIndex, Module};
7+
use wasmtime_runtime::VMFunctionImport;
78

89
pub fn create_global(store: &Store, gt: &GlobalType, val: Val) -> Result<StoreInstanceHandle> {
10+
let mut module = Module::new();
11+
let mut func_imports = PrimaryMap::new();
12+
let mut externref_init = None;
13+
914
let global = wasm::Global {
1015
wasm_ty: gt.content().to_wasm_type(),
11-
ty: match gt.content().get_wasmtime_type() {
12-
Some(t) => t,
13-
None => bail!("cannot support {:?} as a wasm global type", gt.content()),
14-
},
16+
ty: gt.content().get_wasmtime_type(),
1517
mutability: match gt.mutability() {
1618
Mutability::Const => false,
1719
Mutability::Var => true,
@@ -21,10 +23,42 @@ pub fn create_global(store: &Store, gt: &GlobalType, val: Val) -> Result<StoreIn
2123
Val::I64(i) => wasm::GlobalInit::I64Const(i),
2224
Val::F32(f) => wasm::GlobalInit::F32Const(f),
2325
Val::F64(f) => wasm::GlobalInit::F64Const(f),
26+
Val::ExternRef(None) | Val::FuncRef(None) => wasm::GlobalInit::RefNullConst,
27+
Val::ExternRef(Some(x)) => {
28+
// There is no `GlobalInit` variant for using an existing
29+
// `externref` that isn't an import (because Wasm can't create
30+
// an `externref` by itself). Therefore, initialize the global
31+
// as null, and then monkey patch it after instantiation below.
32+
externref_init = Some(x);
33+
wasm::GlobalInit::RefNullConst
34+
}
35+
Val::FuncRef(Some(f)) => {
36+
// Add a function import to the stub module, and then initialize
37+
// our global with a `ref.func` to grab that imported function.
38+
let shared_sig_index = f.sig_index();
39+
let local_sig_index = module
40+
.local
41+
.signatures
42+
.push(store.lookup_wasm_and_native_signatures(shared_sig_index));
43+
let func_index = module.local.functions.push(local_sig_index);
44+
module.local.num_imported_funcs = 1;
45+
module
46+
.imports
47+
.push(("".into(), "".into(), EntityIndex::Function(func_index)));
48+
49+
let f = f.caller_checked_anyfunc();
50+
let f = unsafe { f.as_ref() };
51+
func_imports.push(VMFunctionImport {
52+
body: f.func_ptr,
53+
vmctx: f.vmctx,
54+
});
55+
56+
wasm::GlobalInit::RefFunc(func_index)
57+
}
2458
_ => unimplemented!("create_global for {:?}", gt),
2559
},
2660
};
27-
let mut module = Module::new();
61+
2862
let global_id = module.local.globals.push(global);
2963
module
3064
.exports
@@ -35,6 +69,17 @@ pub fn create_global(store: &Store, gt: &GlobalType, val: Val) -> Result<StoreIn
3569
PrimaryMap::new(),
3670
Default::default(),
3771
Box::new(()),
72+
func_imports,
3873
)?;
74+
75+
if let Some(x) = externref_init {
76+
match handle.lookup("global").unwrap() {
77+
wasmtime_runtime::Export::Global(g) => unsafe {
78+
*(*g.definition).as_externref_mut() = Some(x.inner);
79+
},
80+
_ => unreachable!(),
81+
}
82+
}
83+
3984
Ok(handle)
4085
}

crates/wasmtime/src/trampoline/memory.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ pub fn create_handle_with_memory(
3535
PrimaryMap::new(),
3636
Default::default(),
3737
Box::new(()),
38+
PrimaryMap::new(),
3839
)
3940
}
4041

crates/wasmtime/src/trampoline/table.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,6 @@ pub fn create_handle_with_table(store: &Store, table: &TableType) -> Result<Stor
3232
PrimaryMap::new(),
3333
Default::default(),
3434
Box::new(()),
35+
PrimaryMap::new(),
3536
)
3637
}

crates/wasmtime/src/types.rs

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -99,15 +99,15 @@ impl ValType {
9999
}
100100
}
101101

102-
pub(crate) fn get_wasmtime_type(&self) -> Option<ir::Type> {
102+
pub(crate) fn get_wasmtime_type(&self) -> ir::Type {
103103
match self {
104-
ValType::I32 => Some(ir::types::I32),
105-
ValType::I64 => Some(ir::types::I64),
106-
ValType::F32 => Some(ir::types::F32),
107-
ValType::F64 => Some(ir::types::F64),
108-
ValType::V128 => Some(ir::types::I8X16),
109-
ValType::ExternRef => Some(wasmtime_runtime::ref_type()),
110-
_ => None,
104+
ValType::I32 => ir::types::I32,
105+
ValType::I64 => ir::types::I64,
106+
ValType::F32 => ir::types::F32,
107+
ValType::F64 => ir::types::F64,
108+
ValType::V128 => ir::types::I8X16,
109+
ValType::ExternRef => wasmtime_runtime::ref_type(),
110+
ValType::FuncRef => wasmtime_runtime::pointer_type(),
111111
}
112112
}
113113

@@ -248,34 +248,32 @@ impl FuncType {
248248
}
249249
}
250250

251-
/// Returns `Some` if this function signature was compatible with cranelift,
252-
/// or `None` if one of the types/results wasn't supported or compatible
253-
/// with cranelift.
254-
pub(crate) fn get_wasmtime_signature(&self, pointer_type: ir::Type) -> Option<ir::Signature> {
251+
/// Get the Cranelift-compatible function signature.
252+
pub(crate) fn get_wasmtime_signature(&self, pointer_type: ir::Type) -> ir::Signature {
255253
use wasmtime_environ::ir::{AbiParam, ArgumentPurpose, Signature};
256254
use wasmtime_jit::native;
257255
let call_conv = native::call_conv();
258256
let mut params = self
259257
.params
260258
.iter()
261-
.map(|p| p.get_wasmtime_type().map(AbiParam::new))
262-
.collect::<Option<Vec<_>>>()?;
259+
.map(|p| AbiParam::new(p.get_wasmtime_type()))
260+
.collect::<Vec<_>>();
263261
let returns = self
264262
.results
265263
.iter()
266-
.map(|p| p.get_wasmtime_type().map(AbiParam::new))
267-
.collect::<Option<Vec<_>>>()?;
264+
.map(|p| AbiParam::new(p.get_wasmtime_type()))
265+
.collect::<Vec<_>>();
268266
params.insert(
269267
0,
270268
AbiParam::special(pointer_type, ArgumentPurpose::VMContext),
271269
);
272270
params.insert(1, AbiParam::new(pointer_type));
273271

274-
Some(Signature {
272+
Signature {
275273
params,
276274
returns,
277275
call_conv,
278-
})
276+
}
279277
}
280278

281279
/// Returns `None` if any types in the signature can't be converted to the

0 commit comments

Comments
 (0)