Skip to content

Commit

Permalink
wasmtime: Enable {extern,func}ref globals in the API
Browse files Browse the repository at this point in the history
  • Loading branch information
fitzgen committed Jul 2, 2020
1 parent fb6913c commit b04bd00
Show file tree
Hide file tree
Showing 11 changed files with 199 additions and 43 deletions.
11 changes: 11 additions & 0 deletions crates/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,14 @@ pub fn ref_type() -> wasmtime_environ::ir::Type {
unreachable!()
}
}

/// The Cranelift IR type used for pointer types for this target architecture.
pub fn pointer_type() -> wasmtime_environ::ir::Type {
if cfg!(target_pointer_width = "32") {
wasmtime_environ::ir::types::I32
} else if cfg!(target_pointer_width = "64") {
wasmtime_environ::ir::types::I64
} else {
unreachable!()
}
}
14 changes: 14 additions & 0 deletions crates/runtime/src/sig_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,18 @@ impl SignatureRegistry {
pub fn lookup_wasm(&self, idx: VMSharedSignatureIndex) -> Option<WasmFuncType> {
self.index2wasm.get(&idx).cloned()
}

/// Looks up both a shared Wasm function signature and its associated native
/// `ir::Signature` within this registry.
///
/// Note that for this operation to be semantically correct the `idx` must
/// have previously come from a call to `register` of this same object.
pub fn lookup_wasm_and_native_signatures(
&self,
idx: VMSharedSignatureIndex,
) -> Option<(WasmFuncType, ir::Signature)> {
let wasm = self.lookup_wasm(idx)?;
let native = self.lookup_native(idx)?;
Some((wasm, native))
}
}
14 changes: 8 additions & 6 deletions crates/wasmtime/src/func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ use std::panic::{self, AssertUnwindSafe};
use std::ptr::{self, NonNull};
use std::rc::Weak;
use wasmtime_runtime::{
raise_user_trap, Export, InstanceHandle, VMContext, VMFunctionBody, VMTrampoline,
raise_user_trap, Export, InstanceHandle, VMContext, VMFunctionBody, VMSharedSignatureIndex,
VMTrampoline,
};

/// A WebAssembly function which can be called.
Expand Down Expand Up @@ -486,19 +487,20 @@ impl Func {
func.into_func(store)
}

pub(crate) fn sig_index(&self) -> VMSharedSignatureIndex {
unsafe { self.export.anyfunc.as_ref().type_index }
}

/// Returns the underlying wasm type that this `Func` has.
pub fn ty(&self) -> FuncType {
// Signatures should always be registered in the store's registry of
// shared signatures, so we should be able to unwrap safely here.
let sig = self
.instance
.store
.lookup_signature(unsafe { self.export.anyfunc.as_ref().type_index });
let wft = self.instance.store.lookup_signature(self.sig_index());

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

/// Returns the number of parameters that this function takes.
Expand Down
11 changes: 11 additions & 0 deletions crates/wasmtime/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -900,6 +900,17 @@ impl Store {
.expect("failed to lookup signature")
}

pub(crate) fn lookup_wasm_and_native_signatures(
&self,
sig_index: VMSharedSignatureIndex,
) -> (wasm::WasmFuncType, ir::Signature) {
self.inner
.signatures
.borrow()
.lookup_wasm_and_native_signatures(sig_index)
.expect("failed to lookup signature")
}

pub(crate) fn register_signature(
&self,
wasm_sig: wasm::WasmFuncType,
Expand Down
7 changes: 4 additions & 3 deletions crates/wasmtime/src/trampoline/create_handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ use std::any::Any;
use std::collections::HashMap;
use std::sync::Arc;
use wasmtime_environ::entity::PrimaryMap;
use wasmtime_environ::wasm::DefinedFuncIndex;
use wasmtime_environ::wasm::{DefinedFuncIndex, FuncIndex};
use wasmtime_environ::Module;
use wasmtime_runtime::{
Imports, InstanceHandle, StackMapRegistry, VMExternRefActivationsTable, VMFunctionBody,
VMSharedSignatureIndex, VMTrampoline,
VMFunctionImport, VMSharedSignatureIndex, VMTrampoline,
};

pub(crate) fn create_handle(
Expand All @@ -20,9 +20,10 @@ pub(crate) fn create_handle(
finished_functions: PrimaryMap<DefinedFuncIndex, *mut [VMFunctionBody]>,
trampolines: HashMap<VMSharedSignatureIndex, VMTrampoline>,
state: Box<dyn Any>,
func_imports: PrimaryMap<FuncIndex, VMFunctionImport>,
) -> Result<StoreInstanceHandle> {
let imports = Imports::new(
PrimaryMap::new(),
func_imports,
PrimaryMap::new(),
PrimaryMap::new(),
PrimaryMap::new(),
Expand Down
22 changes: 12 additions & 10 deletions crates/wasmtime/src/trampoline/func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use super::create_handle::create_handle;
use crate::trampoline::StoreInstanceHandle;
use crate::{FuncType, Store, Trap};
use anyhow::{bail, Result};
use anyhow::Result;
use std::any::Any;
use std::cmp;
use std::collections::HashMap;
Expand Down Expand Up @@ -211,10 +211,7 @@ pub fn create_handle_with_function(
let isa = store.engine().config().target_isa();

let pointer_type = isa.pointer_type();
let sig = match ft.get_wasmtime_signature(pointer_type) {
Some(sig) => sig,
None => bail!("not a supported core wasm signature {:?}", ft),
};
let sig = ft.get_wasmtime_signature(pointer_type);

let mut fn_builder_ctx = FunctionBuilderContext::new();
let mut module = Module::new();
Expand Down Expand Up @@ -259,6 +256,7 @@ pub fn create_handle_with_function(
finished_functions,
trampolines,
Box::new(trampoline_state),
PrimaryMap::new(),
)
.map(|instance| (instance, trampoline))
}
Expand All @@ -277,10 +275,7 @@ pub unsafe fn create_handle_with_raw_function(
};

let pointer_type = isa.pointer_type();
let sig = match ft.get_wasmtime_signature(pointer_type) {
Some(sig) => sig,
None => bail!("not a supported core wasm signature {:?}", ft),
};
let sig = ft.get_wasmtime_signature(pointer_type);

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

create_handle(module, store, finished_functions, trampolines, state)
create_handle(
module,
store,
finished_functions,
trampolines,
state,
PrimaryMap::new(),
)
}
57 changes: 51 additions & 6 deletions crates/wasmtime/src/trampoline/global.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
use super::create_handle::create_handle;
use crate::trampoline::StoreInstanceHandle;
use crate::{GlobalType, Mutability, Store, Val};
use anyhow::{bail, Result};
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 = PrimaryMap::new();
let mut externref_init = None;

let global = wasm::Global {
wasm_ty: gt.content().to_wasm_type(),
ty: match gt.content().get_wasmtime_type() {
Some(t) => t,
None => bail!("cannot support {:?} as a wasm global type", gt.content()),
},
ty: gt.content().get_wasmtime_type(),
mutability: match gt.mutability() {
Mutability::Const => false,
Mutability::Var => true,
Expand All @@ -21,10 +23,42 @@ pub fn create_global(store: &Store, gt: &GlobalType, val: Val) -> Result<StoreIn
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)) => {
// 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);
wasm::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 shared_sig_index = f.sig_index();
let local_sig_index = module
.local
.signatures
.push(store.lookup_wasm_and_native_signatures(shared_sig_index));
let func_index = module.local.functions.push(local_sig_index);
module.local.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 mut module = Module::new();

let global_id = module.local.globals.push(global);
module
.exports
Expand All @@ -35,6 +69,17 @@ pub fn create_global(store: &Store, gt: &GlobalType, val: Val) -> Result<StoreIn
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)
}
1 change: 1 addition & 0 deletions crates/wasmtime/src/trampoline/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub fn create_handle_with_memory(
PrimaryMap::new(),
Default::default(),
Box::new(()),
PrimaryMap::new(),
)
}

Expand Down
1 change: 1 addition & 0 deletions crates/wasmtime/src/trampoline/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,6 @@ pub fn create_handle_with_table(store: &Store, table: &TableType) -> Result<Stor
PrimaryMap::new(),
Default::default(),
Box::new(()),
PrimaryMap::new(),
)
}
34 changes: 16 additions & 18 deletions crates/wasmtime/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,15 +99,15 @@ impl ValType {
}
}

pub(crate) fn get_wasmtime_type(&self) -> Option<ir::Type> {
pub(crate) fn get_wasmtime_type(&self) -> ir::Type {
match self {
ValType::I32 => Some(ir::types::I32),
ValType::I64 => Some(ir::types::I64),
ValType::F32 => Some(ir::types::F32),
ValType::F64 => Some(ir::types::F64),
ValType::V128 => Some(ir::types::I8X16),
ValType::ExternRef => Some(wasmtime_runtime::ref_type()),
_ => None,
ValType::I32 => ir::types::I32,
ValType::I64 => ir::types::I64,
ValType::F32 => ir::types::F32,
ValType::F64 => ir::types::F64,
ValType::V128 => ir::types::I8X16,
ValType::ExternRef => wasmtime_runtime::ref_type(),
ValType::FuncRef => wasmtime_runtime::pointer_type(),
}
}

Expand Down Expand Up @@ -248,34 +248,32 @@ impl FuncType {
}
}

/// Returns `Some` if this function signature was compatible with cranelift,
/// or `None` if one of the types/results wasn't supported or compatible
/// with cranelift.
pub(crate) fn get_wasmtime_signature(&self, pointer_type: ir::Type) -> Option<ir::Signature> {
/// Get the Cranelift-compatible function signature.
pub(crate) fn get_wasmtime_signature(&self, pointer_type: ir::Type) -> ir::Signature {
use wasmtime_environ::ir::{AbiParam, ArgumentPurpose, Signature};
use wasmtime_jit::native;
let call_conv = native::call_conv();
let mut params = self
.params
.iter()
.map(|p| p.get_wasmtime_type().map(AbiParam::new))
.collect::<Option<Vec<_>>>()?;
.map(|p| AbiParam::new(p.get_wasmtime_type()))
.collect::<Vec<_>>();
let returns = self
.results
.iter()
.map(|p| p.get_wasmtime_type().map(AbiParam::new))
.collect::<Option<Vec<_>>>()?;
.map(|p| AbiParam::new(p.get_wasmtime_type()))
.collect::<Vec<_>>();
params.insert(
0,
AbiParam::special(pointer_type, ArgumentPurpose::VMContext),
);
params.insert(1, AbiParam::new(pointer_type));

Some(Signature {
Signature {
params,
returns,
call_conv,
})
}
}

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

0 comments on commit b04bd00

Please sign in to comment.