Replace the global-exports mechanism with a caller-vmctx mechanism. (#789)
* Replace the global-exports mechanism with a caller-vmctx mechanism. This eliminates the global exports mechanism, and instead adds a caller-vmctx argument to wasm functions so that WASI can obtain the memory and other things from the caller rather than looking them up in a global registry. This replaces #390. * Fixup some merge conflicts * Rustfmt * Ensure VMContext is aligned to 16 bytes With the removal of `global_exports` it "just so happens" that this isn't happening naturally any more. * Fixup some bugs with double vmctx in wasmtime crate * Trampoline stub needed adjusting * Use pointer type instead of always using I64 for caller vmctx * Don't store `ir::Signature` in `Func` since we don't know the pointer size at creation time. * Skip the first 2 arguments in IR signatures since that's the two vmctx parameters. * Update cranelift to 0.56.0 * Handle more merge conflicts * Rustfmt Co-authored-by: Alex Crichton <alex@alexcrichton.com>
This commit is contained in:
@@ -3,6 +3,7 @@ use crate::trampoline::{generate_func_export, take_api_trap};
|
||||
use crate::trap::Trap;
|
||||
use crate::types::FuncType;
|
||||
use crate::values::Val;
|
||||
use std::ptr;
|
||||
use std::rc::Rc;
|
||||
use wasmtime_environ::ir;
|
||||
use wasmtime_jit::InstanceHandle;
|
||||
@@ -150,6 +151,7 @@ impl WrappedCallable for WasmtimeFn {
|
||||
self.instance.with_signals_on(|| {
|
||||
wasmtime_runtime::wasmtime_call_trampoline(
|
||||
vmctx,
|
||||
ptr::null_mut(),
|
||||
exec_code_buf,
|
||||
values_vec.as_mut_ptr() as *mut u8,
|
||||
)
|
||||
|
||||
@@ -395,12 +395,10 @@ impl Module {
|
||||
}
|
||||
|
||||
fn compile(store: &Store, binary: &[u8], module_name: Option<&str>) -> Result<CompiledModule> {
|
||||
let exports = store.global_exports().clone();
|
||||
let compiled_module = CompiledModule::new(
|
||||
&mut store.compiler_mut(),
|
||||
binary,
|
||||
module_name,
|
||||
exports,
|
||||
store.engine().config().debug_info,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -342,7 +342,6 @@ pub struct Store {
|
||||
struct StoreInner {
|
||||
engine: Engine,
|
||||
compiler: RefCell<Compiler>,
|
||||
global_exports: Rc<RefCell<HashMap<String, Option<wasmtime_runtime::Export>>>>,
|
||||
signature_cache: RefCell<HashMap<wasmtime_runtime::VMSharedSignatureIndex, ir::Signature>>,
|
||||
}
|
||||
|
||||
@@ -355,7 +354,6 @@ impl Store {
|
||||
inner: Rc::new(StoreInner {
|
||||
engine: engine.clone(),
|
||||
compiler: RefCell::new(compiler),
|
||||
global_exports: Rc::new(RefCell::new(HashMap::new())),
|
||||
signature_cache: RefCell::new(HashMap::new()),
|
||||
}),
|
||||
}
|
||||
@@ -370,14 +368,6 @@ impl Store {
|
||||
self.inner.compiler.borrow_mut()
|
||||
}
|
||||
|
||||
// Specific to wasmtime: hack to pass memory around to wasi
|
||||
#[doc(hidden)]
|
||||
pub fn global_exports(
|
||||
&self,
|
||||
) -> &Rc<RefCell<HashMap<String, Option<wasmtime_runtime::Export>>>> {
|
||||
&self.inner.global_exports
|
||||
}
|
||||
|
||||
pub(crate) fn register_wasmtime_signature(
|
||||
&self,
|
||||
signature: &ir::Signature,
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
use crate::runtime::Store;
|
||||
use anyhow::Result;
|
||||
use std::any::Any;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::collections::HashSet;
|
||||
use std::rc::Rc;
|
||||
use wasmtime_environ::entity::PrimaryMap;
|
||||
use wasmtime_environ::wasm::DefinedFuncIndex;
|
||||
@@ -17,9 +16,6 @@ pub(crate) fn create_handle(
|
||||
finished_functions: PrimaryMap<DefinedFuncIndex, *const VMFunctionBody>,
|
||||
state: Box<dyn Any>,
|
||||
) -> Result<InstanceHandle> {
|
||||
let global_exports: Rc<RefCell<HashMap<String, Option<wasmtime_runtime::Export>>>> =
|
||||
Rc::new(RefCell::new(HashMap::new()));
|
||||
|
||||
let imports = Imports::new(
|
||||
HashSet::new(),
|
||||
PrimaryMap::new(),
|
||||
@@ -42,7 +38,6 @@ pub(crate) fn create_handle(
|
||||
|
||||
Ok(InstanceHandle::new(
|
||||
Rc::new(module),
|
||||
global_exports,
|
||||
finished_functions.into_boxed_slice(),
|
||||
imports,
|
||||
&data_initializers,
|
||||
|
||||
@@ -64,7 +64,12 @@ impl Drop for TrampolineState {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn stub_fn(vmctx: *mut VMContext, call_id: u32, values_vec: *mut i128) -> u32 {
|
||||
unsafe extern "C" fn stub_fn(
|
||||
vmctx: *mut VMContext,
|
||||
_caller_vmctx: *mut VMContext,
|
||||
call_id: u32,
|
||||
values_vec: *mut i128,
|
||||
) -> u32 {
|
||||
let mut instance = InstanceHandle::from_vmctx(vmctx);
|
||||
|
||||
let (args, returns_len) = {
|
||||
@@ -72,9 +77,9 @@ unsafe extern "C" fn stub_fn(vmctx: *mut VMContext, call_id: u32, values_vec: *m
|
||||
let signature = &module.signatures[module.functions[FuncIndex::new(call_id as usize)]];
|
||||
|
||||
let mut args = Vec::new();
|
||||
for i in 1..signature.params.len() {
|
||||
for i in 2..signature.params.len() {
|
||||
args.push(Val::read_value_from(
|
||||
values_vec.offset(i as isize - 1),
|
||||
values_vec.offset(i as isize - 2),
|
||||
signature.params[i].value_type,
|
||||
))
|
||||
}
|
||||
@@ -116,12 +121,15 @@ fn make_trampoline(
|
||||
let pointer_type = isa.pointer_type();
|
||||
let mut stub_sig = ir::Signature::new(isa.frontend_config().default_call_conv);
|
||||
|
||||
// Add the `vmctx` parameter.
|
||||
// Add the caller/callee `vmctx` parameters.
|
||||
stub_sig.params.push(ir::AbiParam::special(
|
||||
pointer_type,
|
||||
ir::ArgumentPurpose::VMContext,
|
||||
));
|
||||
|
||||
// Add the caller `vmctx` parameter.
|
||||
stub_sig.params.push(ir::AbiParam::new(pointer_type));
|
||||
|
||||
// Add the `call_id` parameter.
|
||||
stub_sig.params.push(ir::AbiParam::new(types::I32));
|
||||
|
||||
@@ -131,9 +139,10 @@ fn make_trampoline(
|
||||
// Add error/trap return.
|
||||
stub_sig.returns.push(ir::AbiParam::new(types::I32));
|
||||
|
||||
// Compute the size of the values vector. The vmctx and caller vmctx are passed separately.
|
||||
let value_size = 16;
|
||||
let values_vec_len = ((value_size as usize)
|
||||
* cmp::max(signature.params.len() - 1, signature.returns.len()))
|
||||
* cmp::max(signature.params.len() - 2, signature.returns.len()))
|
||||
as u32;
|
||||
|
||||
let mut context = Context::new();
|
||||
@@ -155,7 +164,7 @@ fn make_trampoline(
|
||||
|
||||
let values_vec_ptr_val = builder.ins().stack_addr(pointer_type, ss, 0);
|
||||
let mflags = MemFlags::trusted();
|
||||
for i in 1..signature.params.len() {
|
||||
for i in 2..signature.params.len() {
|
||||
if i == 0 {
|
||||
continue;
|
||||
}
|
||||
@@ -165,14 +174,21 @@ fn make_trampoline(
|
||||
mflags,
|
||||
val,
|
||||
values_vec_ptr_val,
|
||||
((i - 1) * value_size) as i32,
|
||||
((i - 2) * value_size) as i32,
|
||||
);
|
||||
}
|
||||
|
||||
let vmctx_ptr_val = builder.func.dfg.ebb_params(block0)[0];
|
||||
let ebb_params = builder.func.dfg.ebb_params(block0);
|
||||
let vmctx_ptr_val = ebb_params[0];
|
||||
let caller_vmctx_ptr_val = ebb_params[1];
|
||||
let call_id_val = builder.ins().iconst(types::I32, call_id as i64);
|
||||
|
||||
let callee_args = vec![vmctx_ptr_val, call_id_val, values_vec_ptr_val];
|
||||
let callee_args = vec![
|
||||
vmctx_ptr_val,
|
||||
caller_vmctx_ptr_val,
|
||||
call_id_val,
|
||||
values_vec_ptr_val,
|
||||
];
|
||||
|
||||
let new_sig = builder.import_signature(stub_sig);
|
||||
|
||||
@@ -236,17 +252,18 @@ pub fn create_handle_with_function(
|
||||
func: &Rc<dyn Callable + 'static>,
|
||||
store: &Store,
|
||||
) -> Result<InstanceHandle> {
|
||||
let sig = match ft.get_wasmtime_signature() {
|
||||
Some(sig) => sig.clone(),
|
||||
None => bail!("not a supported core wasm signature {:?}", ft),
|
||||
};
|
||||
|
||||
let isa = {
|
||||
let isa_builder = native::builder();
|
||||
let flag_builder = settings::builder();
|
||||
isa_builder.finish(settings::Flags::new(flag_builder))
|
||||
};
|
||||
|
||||
let pointer_type = isa.pointer_type();
|
||||
let sig = match ft.get_wasmtime_signature(pointer_type) {
|
||||
Some(sig) => sig.clone(),
|
||||
None => bail!("not a supported core wasm signature {:?}", ft),
|
||||
};
|
||||
|
||||
let mut fn_builder_ctx = FunctionBuilderContext::new();
|
||||
let mut module = Module::new();
|
||||
let mut finished_functions: PrimaryMap<DefinedFuncIndex, *const VMFunctionBody> =
|
||||
|
||||
@@ -191,12 +191,6 @@ fn from_wasmtime_abiparam(param: &ir::AbiParam) -> Option<ValType> {
|
||||
pub struct FuncType {
|
||||
params: Box<[ValType]>,
|
||||
results: Box<[ValType]>,
|
||||
// `None` if params/results aren't wasm-compatible (e.g. use wasm interface
|
||||
// types), or if they're not implemented (like anyref at the time of this
|
||||
// writing)
|
||||
//
|
||||
// `Some` if they're all wasm-compatible.
|
||||
signature: Option<ir::Signature>,
|
||||
}
|
||||
|
||||
impl FuncType {
|
||||
@@ -205,34 +199,7 @@ impl FuncType {
|
||||
/// The function descriptor returned will represent a function which takes
|
||||
/// `params` as arguments and returns `results` when it is finished.
|
||||
pub fn new(params: Box<[ValType]>, results: Box<[ValType]>) -> FuncType {
|
||||
use wasmtime_environ::ir::{types, AbiParam, ArgumentPurpose, Signature};
|
||||
use wasmtime_jit::native;
|
||||
let call_conv = native::call_conv();
|
||||
let signature = params
|
||||
.iter()
|
||||
.map(|p| p.get_wasmtime_type().map(AbiParam::new))
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.and_then(|params| {
|
||||
results
|
||||
.iter()
|
||||
.map(|p| p.get_wasmtime_type().map(AbiParam::new))
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.map(|results| (params, results))
|
||||
})
|
||||
.map(|(mut params, returns)| {
|
||||
params.insert(0, AbiParam::special(types::I64, ArgumentPurpose::VMContext));
|
||||
|
||||
Signature {
|
||||
params,
|
||||
returns,
|
||||
call_conv,
|
||||
}
|
||||
});
|
||||
FuncType {
|
||||
params,
|
||||
results,
|
||||
signature,
|
||||
}
|
||||
FuncType { params, results }
|
||||
}
|
||||
|
||||
/// Returns the list of parameter types for this function.
|
||||
@@ -248,8 +215,28 @@ 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) -> Option<&ir::Signature> {
|
||||
self.signature.as_ref()
|
||||
pub(crate) fn get_wasmtime_signature(&self, pointer_type: ir::Type) -> Option<ir::Signature> {
|
||||
use wasmtime_environ::ir::{types, 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<_>>>()?;
|
||||
let returns = self
|
||||
.results
|
||||
.iter()
|
||||
.map(|p| p.get_wasmtime_type().map(AbiParam::new))
|
||||
.collect::<Option<Vec<_>>>()?;
|
||||
params.insert(0, AbiParam::special(types::I64, ArgumentPurpose::VMContext));
|
||||
params.insert(1, AbiParam::new(pointer_type));
|
||||
|
||||
Some(Signature {
|
||||
params,
|
||||
returns,
|
||||
call_conv,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns `None` if any types in the signature can't be converted to the
|
||||
@@ -259,7 +246,7 @@ impl FuncType {
|
||||
let params = signature
|
||||
.params
|
||||
.iter()
|
||||
.filter(|p| p.purpose == ir::ArgumentPurpose::Normal)
|
||||
.skip(2) // skip the caller/callee vmctx
|
||||
.map(|p| from_wasmtime_abiparam(p))
|
||||
.collect::<Option<Vec<_>>>()?;
|
||||
let results = signature
|
||||
@@ -270,7 +257,6 @@ impl FuncType {
|
||||
Some(FuncType {
|
||||
params: params.into_boxed_slice(),
|
||||
results: results.into_boxed_slice(),
|
||||
signature: Some(signature),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user