Skip to content

Commit

Permalink
Start plumbing pulley in wasmtime
Browse files Browse the repository at this point in the history
  • Loading branch information
alexcrichton committed Nov 20, 2024
1 parent a3461a7 commit 3691d9c
Show file tree
Hide file tree
Showing 10 changed files with 190 additions and 63 deletions.
8 changes: 8 additions & 0 deletions crates/wasmtime/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,14 @@ impl Engine {
#[cfg(not(miri))]
crate::runtime::vm::deinit_traps();
}

pub(crate) fn is_pulley(&self) -> bool {
match self.target().architecture {
target_lexicon::Architecture::Pulley32 => true,
target_lexicon::Architecture::Pulley64 => true,
_ => false,
}
}
}

/// A weak reference to an [`Engine`].
Expand Down
25 changes: 10 additions & 15 deletions crates/wasmtime/src/runtime/func.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::prelude::*;
use crate::runtime::vm::{
ExportFunction, SendSyncPtr, StoreBox, VMArrayCallHostFuncContext, VMContext, VMFuncRef,
VMFunctionImport, VMOpaqueContext,
ExportFunction, InterpreterRef, SendSyncPtr, StoreBox, VMArrayCallHostFuncContext, VMContext,
VMFuncRef, VMFunctionImport, VMOpaqueContext,
};
use crate::runtime::Uninhabited;
use crate::store::{AutoAssertNoGc, StoreData, StoreOpaque, Stored};
Expand Down Expand Up @@ -1069,10 +1069,12 @@ impl Func {
func_ref: NonNull<VMFuncRef>,
params_and_returns: *mut [ValRaw],
) -> Result<()> {
invoke_wasm_and_catch_traps(store, |caller| {
func_ref
.as_ref()
.array_call(caller.cast::<VMOpaqueContext>(), params_and_returns)
invoke_wasm_and_catch_traps(store, |caller, vm| {
func_ref.as_ref().array_call(
vm,
VMOpaqueContext::from_vmcontext(caller),
params_and_returns,
)
})
}

Expand Down Expand Up @@ -1593,7 +1595,7 @@ impl Func {
/// can pass to the called wasm function, if desired.
pub(crate) fn invoke_wasm_and_catch_traps<T>(
store: &mut StoreContextMut<'_, T>,
closure: impl FnMut(*mut VMContext),
closure: impl FnMut(*mut VMContext, Option<InterpreterRef<'_>>),
) -> Result<()> {
unsafe {
let exit = enter_wasm(store);
Expand All @@ -1602,14 +1604,7 @@ pub(crate) fn invoke_wasm_and_catch_traps<T>(
exit_wasm(store, exit);
return Err(trap);
}
let result = crate::runtime::vm::catch_traps(
store.0.signal_handler(),
store.0.engine().config().wasm_backtrace,
store.0.engine().config().coredump_on_trap,
store.0.async_guard_range(),
store.0.default_caller(),
closure,
);
let result = crate::runtime::vm::catch_traps(store.as_context_mut(), closure);
exit_wasm(store, exit);
store.0.call_hook(CallHook::ReturningFromWasm)?;
result.map_err(|t| crate::trap::from_runtime_box(store.0, t))
Expand Down
4 changes: 2 additions & 2 deletions crates/wasmtime/src/runtime/func/typed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,15 +211,15 @@ where
// the memory go away, so the size matters here for performance.
let mut captures = (func, storage);

let result = invoke_wasm_and_catch_traps(store, |caller| {
let result = invoke_wasm_and_catch_traps(store, |caller, vm| {
let (func_ref, storage) = &mut captures;
let storage_len = mem::size_of_val::<Storage<_, _>>(storage) / mem::size_of::<ValRaw>();
let storage: *mut Storage<_, _> = storage;
let storage = storage.cast::<ValRaw>();
let storage = core::ptr::slice_from_raw_parts_mut(storage, storage_len);
func_ref
.as_ref()
.array_call(VMOpaqueContext::from_vmcontext(caller), storage);
.array_call(vm, VMOpaqueContext::from_vmcontext(caller), storage);
});

let (_, storage) = captures;
Expand Down
10 changes: 6 additions & 4 deletions crates/wasmtime/src/runtime/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -361,10 +361,12 @@ impl Instance {
let f = instance.get_exported_func(start);
let caller_vmctx = instance.vmctx();
unsafe {
super::func::invoke_wasm_and_catch_traps(store, |_default_caller| {
f.func_ref
.as_ref()
.array_call(VMOpaqueContext::from_vmcontext(caller_vmctx), &mut [])
super::func::invoke_wasm_and_catch_traps(store, |_default_caller, vm| {
f.func_ref.as_ref().array_call(
vm,
VMOpaqueContext::from_vmcontext(caller_vmctx),
&mut [],
)
})?;
}
Ok(())
Expand Down
15 changes: 13 additions & 2 deletions crates/wasmtime/src/runtime/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ use crate::prelude::*;
use crate::runtime::vm::mpk::{self, ProtectionKey, ProtectionMask};
use crate::runtime::vm::{
Backtrace, ExportGlobal, GcRootsList, GcStore, InstanceAllocationRequest, InstanceAllocator,
InstanceHandle, ModuleRuntimeInfo, OnDemandInstanceAllocator, SignalHandler, StoreBox,
StorePtr, VMContext, VMFuncRef, VMGcRef, VMRuntimeLimits,
InstanceHandle, Interpreter, InterpreterRef, ModuleRuntimeInfo, OnDemandInstanceAllocator,
SignalHandler, StoreBox, StorePtr, VMContext, VMFuncRef, VMGcRef, VMRuntimeLimits, WasmFault,
};
use crate::trampoline::VMHostGlobalContext;
use crate::type_registry::RegisteredType;
Expand Down Expand Up @@ -387,6 +387,8 @@ pub struct StoreOpaque {
component_calls: crate::runtime::vm::component::CallContexts,
#[cfg(feature = "component-model")]
host_resource_data: crate::component::HostResourceData,

interpreter: Option<Interpreter>,
}

#[cfg(feature = "async")]
Expand Down Expand Up @@ -575,6 +577,11 @@ impl<T> Store<T> {
component_calls: Default::default(),
#[cfg(feature = "component-model")]
host_resource_data: Default::default(),
interpreter: if engine.is_pulley() {
Some(Interpreter::new())
} else {
None
},
},
limiter: None,
call_hook: None,
Expand Down Expand Up @@ -2133,6 +2140,10 @@ at https://bytecodealliance.org/security.
}
}
}

pub(crate) fn interpreter(&mut self) -> Option<InterpreterRef<'_>> {
self.interpreter.as_mut().map(|i| i.as_interpreter_ref())
}
}

impl<T> StoreContextMut<'_, T> {
Expand Down
12 changes: 9 additions & 3 deletions crates/wasmtime/src/runtime/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ pub mod debug_builtins;
pub mod libcalls;
pub mod mpk;

#[cfg(feature = "pulley")]
pub(crate) mod interpreter;
#[cfg(not(feature = "pulley"))]
pub(crate) mod interpreter_disabled;
#[cfg(not(feature = "pulley"))]
pub(crate) use interpreter_disabled as interpreter;

#[cfg(feature = "debug-builtins")]
pub use wasmtime_jit_debug::gdb_jit_int::GdbJitImageRegistration;

Expand All @@ -64,9 +71,8 @@ pub use crate::runtime::vm::instance::{
InstanceLimits, PoolConcurrencyLimitError, PoolingInstanceAllocator,
PoolingInstanceAllocatorConfig,
};
pub use crate::runtime::vm::memory::{
Memory, RuntimeLinearMemory, RuntimeMemoryCreator, SharedMemory,
};
pub use crate::runtime::vm::memory::{Memory, RuntimeLinearMemory, RuntimeMemoryCreator};
pub use crate::runtime::vm::mmap::Mmap;
pub use crate::runtime::vm::mmap_vec::MmapVec;
pub use crate::runtime::vm::mpk::MpkEnabled;
pub use crate::runtime::vm::store_box::*;
Expand Down
46 changes: 46 additions & 0 deletions crates/wasmtime/src/runtime/vm/interpreter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use crate::prelude::*;
use crate::runtime::vm::VMOpaqueContext;
use crate::ValRaw;
use core::marker;
use core::mem;
use core::ptr::NonNull;
use pulley_interpreter::interp::{Vm, XRegVal};

#[repr(transparent)]
pub struct Interpreter {
pulley: Box<Vm>,
}

impl Interpreter {
pub fn new() -> Interpreter {
Interpreter {
pulley: Box::new(Vm::new()),
}
}

pub fn as_interpreter_ref(&mut self) -> InterpreterRef<'_> {
InterpreterRef(&mut self.pulley)
}
}

#[repr(transparent)]
pub struct InterpreterRef<'a>(&'a mut Vm);

impl InterpreterRef<'_> {
pub unsafe fn call(
&mut self,
bytecode: NonNull<u8>,
callee: *mut VMOpaqueContext,
caller: *mut VMOpaqueContext,
args_and_results: *mut [ValRaw],
) {
let args = [
XRegVal::new_ptr(callee).into(),
XRegVal::new_ptr(caller).into(),
XRegVal::new_ptr(args_and_results.cast::<u8>()).into(),
XRegVal::new_u64(args_and_results.len() as u64).into(),
];
// TODO: handle result
let _ = self.0.call(bytecode, &args, []);
}
}
44 changes: 44 additions & 0 deletions crates/wasmtime/src/runtime/vm/interpreter_disabled.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use crate::runtime::vm::VMOpaqueContext;
use crate::ValRaw;
use core::marker;
use core::mem;
use core::ptr::NonNull;

pub struct Interpreter {
empty: Void,
}

const _: () = assert!(mem::size_of::<Interpreter>() == 0);
const _: () = assert!(mem::size_of::<Option<Interpreter>>() == 0);

enum Void {}

impl Interpreter {
pub fn new() -> Interpreter {
unreachable!()
}

pub fn as_interpreter_ref(&mut self) -> InterpreterRef<'_> {
match self.empty {}
}
}

pub struct InterpreterRef<'a> {
empty: Void,
_marker: marker::PhantomData<&'a mut Interpreter>,
}

const _: () = assert!(mem::size_of::<InterpreterRef<'_>>() == 0);
const _: () = assert!(mem::size_of::<Option<InterpreterRef<'_>>>() == 0);

impl InterpreterRef<'_> {
pub unsafe fn call(
&mut self,
_bytecode: NonNull<u8>,
_callee: *mut VMOpaqueContext,
_caller: *mut VMOpaqueContext,
_args_and_results: *mut [ValRaw],
) {
match self.empty {}
}
}
60 changes: 25 additions & 35 deletions crates/wasmtime/src/runtime/vm/traphandlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,14 @@ mod signals;
pub use self::signals::*;

use crate::prelude::*;
use crate::runtime::module::lookup_code;
use crate::runtime::store::StoreOpaque;
use crate::runtime::vm::sys::traphandlers;
use crate::runtime::vm::{Instance, InterpreterRef, VMContext, VMRuntimeLimits};
use crate::runtime::vm::{Instance, VMContext, VMRuntimeLimits};
use crate::sync::RwLock;
use crate::sync::RwLock;
use crate::StoreContextMut;
use core::cell::{Cell, UnsafeCell};
use core::mem::MaybeUninit;
use core::ops::Range;
Expand Down Expand Up @@ -174,33 +180,25 @@ impl From<wasmtime_environ::Trap> for TrapReason {
/// returning them as a `Result`.
///
/// Highly unsafe since `closure` won't have any dtors run.
pub unsafe fn catch_traps<F>(
signal_handler: Option<*const SignalHandler>,
capture_backtrace: bool,
capture_coredump: bool,
async_guard_range: Range<*mut u8>,
caller: *mut VMContext,
pub unsafe fn catch_traps<T, F>(
store: StoreContextMut<'_, T>,
mut closure: F,
) -> Result<(), Box<Trap>>
where
F: FnMut(*mut VMContext),
F: FnMut(*mut VMContext, Option<InterpreterRef<'_>>),
{
let limits = Instance::from_vmctx(caller, |i| i.runtime_limits());

let result = CallThreadState::new(
signal_handler,
capture_backtrace,
capture_coredump,
*limits,
async_guard_range,
)
.with(|cx| {
traphandlers::wasmtime_setjmp(
let caller = store.0.default_caller();
let result = CallThreadState::new(store.0, caller).with(|cx| match store.0.interpreter() {
Some(r) => {
closure(caller, Some(r));
1
}
None => traphandlers::wasmtime_setjmp(
cx.jmp_buf.as_ptr(),
call_closure::<F>,
&mut closure as *mut F as *mut u8,
caller,
)
),
});

return match result {
Expand All @@ -216,9 +214,9 @@ where

extern "C" fn call_closure<F>(payload: *mut u8, caller: *mut VMContext)
where
F: FnMut(*mut VMContext),
F: FnMut(*mut VMContext, Option<InterpreterRef<'_>>),
{
unsafe { (*(payload as *mut F))(caller) }
unsafe { (*(payload as *mut F))(caller, None) }
}
}

Expand Down Expand Up @@ -270,26 +268,18 @@ mod call_thread_state {

impl CallThreadState {
#[inline]
pub(super) fn new(
signal_handler: Option<*const SignalHandler>,
capture_backtrace: bool,
capture_coredump: bool,
limits: *const VMRuntimeLimits,
async_guard_range: Range<*mut u8>,
) -> CallThreadState {
let _ = (capture_coredump, signal_handler, &async_guard_range);
pub(super) fn new(store: &mut StoreOpaque, caller: *mut VMContext) -> CallThreadState {
let limits = unsafe { *Instance::from_vmctx(caller, |i| i.runtime_limits()) };

CallThreadState {
unwind: UnsafeCell::new(MaybeUninit::uninit()),
jmp_buf: Cell::new(ptr::null()),
#[cfg(all(feature = "signals-based-traps", not(miri)))]
signal_handler,
capture_backtrace,
signal_handler: store.signal_handler(),
capture_backtrace: store.engine().config().wasm_backtrace,
#[cfg(feature = "coredump")]
capture_coredump,
capture_coredump: store.engine().config().coredump_on_trap,
limits,
#[cfg(all(feature = "signals-based-traps", unix, not(miri)))]
async_guard_range,
async_guard_range: store.async_guard_range(),
prev: Cell::new(ptr::null()),
old_last_wasm_exit_fp: Cell::new(unsafe { *(*limits).last_wasm_exit_fp.get() }),
old_last_wasm_exit_pc: Cell::new(unsafe { *(*limits).last_wasm_exit_pc.get() }),
Expand Down
Loading

0 comments on commit 3691d9c

Please sign in to comment.