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:
Dan Gohman
2020-01-21 14:50:59 -08:00
committed by GitHub
parent de72435576
commit 9a88d3d894
33 changed files with 362 additions and 330 deletions

View File

@@ -3,7 +3,12 @@
#include "SignalHandlers.hpp"
extern "C"
int WasmtimeCallTrampoline(void *vmctx, void (*body)(void*, void*), void *args) {
int WasmtimeCallTrampoline(
void *vmctx,
void *caller_vmctx,
void (*body)(void*, void*, void*),
void *args)
{
jmp_buf buf;
void *volatile prev;
if (setjmp(buf) != 0) {
@@ -11,13 +16,13 @@ int WasmtimeCallTrampoline(void *vmctx, void (*body)(void*, void*), void *args)
return 0;
}
prev = EnterScope(&buf);
body(vmctx, args);
body(vmctx, caller_vmctx, args);
LeaveScope(prev);
return 1;
}
extern "C"
int WasmtimeCall(void *vmctx, void (*body)(void*)) {
int WasmtimeCall(void *vmctx, void *caller_vmctx, void (*body)(void*, void*)) {
jmp_buf buf;
void *volatile prev;
if (setjmp(buf) != 0) {
@@ -25,7 +30,7 @@ int WasmtimeCall(void *vmctx, void (*body)(void*)) {
return 0;
}
prev = EnterScope(&buf);
body(vmctx);
body(vmctx, caller_vmctx);
LeaveScope(prev);
return 1;
}

View File

@@ -18,9 +18,8 @@ use crate::vmcontext::{
use memoffset::offset_of;
use more_asserts::assert_lt;
use std::any::Any;
use std::borrow::Borrow;
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::collections::HashSet;
use std::convert::TryFrom;
use std::ptr::NonNull;
use std::rc::Rc;
@@ -294,11 +293,6 @@ pub(crate) struct Instance {
/// Offsets in the `vmctx` region.
offsets: VMOffsets,
/// A global namespace of exports. This is a temporary mechanism to avoid
/// cyclic dependencies when one module wants to import from another and
/// make its memory available too, that will be obviated by host-bindings.
global_exports: Rc<RefCell<HashMap<String, Option<Export>>>>,
/// WebAssembly linear memory data.
memories: BoxedSlice<DefinedMemoryIndex, LinearMemory>,
@@ -567,7 +561,7 @@ impl Instance {
};
// Make the call.
unsafe { wasmtime_call(callee_vmctx, callee_address) }
unsafe { wasmtime_call(callee_vmctx, self.vmctx_mut_ptr(), callee_address) }
.map_err(InstantiationError::StartTrap)
}
@@ -689,15 +683,6 @@ impl Instance {
foreign_instance.memory_size(foreign_index)
}
pub(crate) fn lookup_global_export(&self, field: &str) -> Option<Export> {
let cell: &RefCell<HashMap<String, Option<Export>>> = self.global_exports.borrow();
let map: &mut HashMap<String, Option<Export>> = &mut cell.borrow_mut();
if let Some(Some(export)) = map.get(field) {
return Some(export.clone());
}
None
}
/// Grow table by the specified amount of elements.
///
/// Returns `None` if table can't be grown by the specified amount
@@ -772,7 +757,6 @@ impl InstanceHandle {
/// Create a new `InstanceHandle` pointing at a new `Instance`.
pub fn new(
module: Rc<Module>,
global_exports: Rc<RefCell<HashMap<String, Option<Export>>>>,
finished_functions: BoxedSlice<DefinedFuncIndex, *const VMFunctionBody>,
imports: Imports,
data_initializers: &[DataInitializer<'_>],
@@ -814,7 +798,6 @@ impl InstanceHandle {
dependencies: imports.dependencies,
mmap: instance_mmap,
module,
global_exports,
offsets,
memories,
tables,
@@ -886,25 +869,6 @@ impl InstanceHandle {
initialize_memories(instance, data_initializers)?;
initialize_globals(instance);
// Collect the exports for the global export map.
for (field, decl) in &instance.module.exports {
use std::collections::hash_map::Entry::*;
let cell: &RefCell<HashMap<String, Option<Export>>> = instance.global_exports.borrow();
let map: &mut HashMap<String, Option<Export>> = &mut cell.borrow_mut();
match map.entry(field.to_string()) {
Vacant(entry) => {
entry.insert(Some(lookup_by_declaration(
&instance.module,
&mut instance.vmctx,
&instance.offsets,
&instance.finished_functions,
&decl,
)));
}
Occupied(ref mut entry) => *entry.get_mut() = None,
}
}
// Ensure that our signal handlers are ready for action.
// TODO: Move these calls out of `InstanceHandle`.
wasmtime_init_eager();

View File

@@ -13,10 +13,11 @@ use wasmtime_environ::ir;
extern "C" {
fn WasmtimeCallTrampoline(
vmctx: *mut u8,
caller_vmctx: *mut u8,
callee: *const VMFunctionBody,
values_vec: *mut u8,
) -> i32;
fn WasmtimeCall(vmctx: *mut u8, callee: *const VMFunctionBody) -> i32;
fn WasmtimeCall(vmctx: *mut u8, caller_vmctx: *mut u8, callee: *const VMFunctionBody) -> i32;
}
thread_local! {
@@ -165,10 +166,17 @@ fn trap_code_to_expected_string(trap_code: ir::TrapCode) -> String {
#[no_mangle]
pub unsafe extern "C" fn wasmtime_call_trampoline(
vmctx: *mut VMContext,
caller_vmctx: *mut VMContext,
callee: *const VMFunctionBody,
values_vec: *mut u8,
) -> Result<(), Trap> {
if WasmtimeCallTrampoline(vmctx as *mut u8, callee, values_vec) == 0 {
if WasmtimeCallTrampoline(
vmctx as *mut u8,
caller_vmctx as *mut u8,
callee,
values_vec,
) == 0
{
Err(last_trap())
} else {
Ok(())
@@ -180,9 +188,10 @@ pub unsafe extern "C" fn wasmtime_call_trampoline(
#[no_mangle]
pub unsafe extern "C" fn wasmtime_call(
vmctx: *mut VMContext,
caller_vmctx: *mut VMContext,
callee: *const VMFunctionBody,
) -> Result<(), Trap> {
if WasmtimeCall(vmctx as *mut u8, callee) == 0 {
if WasmtimeCall(vmctx as *mut u8, caller_vmctx as *mut u8, callee) == 0 {
Err(last_trap())
} else {
Ok(())

View File

@@ -595,7 +595,7 @@ impl VMInvokeArgument {
///
/// TODO: We could move the globals into the `vmctx` allocation too.
#[derive(Debug)]
#[repr(C)]
#[repr(C, align(16))] // align 16 since globals are aligned to that and contained inside
pub struct VMContext {}
impl VMContext {
@@ -617,12 +617,4 @@ impl VMContext {
pub unsafe fn host_state(&mut self) -> &mut dyn Any {
self.instance().host_state()
}
/// Lookup an export in the global exports namespace.
/// # Safety
/// This is unsafe because it doesn't work on just any `VMContext`, it must
/// be a `VMContext` allocated as part of an `Instance`.
pub unsafe fn lookup_global_export(&mut self, field: &str) -> Option<crate::export::Export> {
self.instance().lookup_global_export(field)
}
}