Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
WIP state holder via *mut
Browse files Browse the repository at this point in the history
  • Loading branch information
0x7CFE committed Jul 13, 2020
1 parent 1be139b commit 4e770b4
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 68 deletions.
154 changes: 90 additions & 64 deletions client/executor/common/src/sandbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,9 @@ impl<FR> SandboxInstance<FR> {
///
/// The `state` parameter can be used to provide custom data for
/// these syscall implementations.
pub fn invoke<FE: SandboxCapabilities<SupervisorFuncRef=FR>>(
pub fn invoke
//<FE: SandboxCapabilities<SupervisorFuncRef=FR>>
(
&self,

// function to call that is exported from the module
Expand All @@ -372,55 +374,58 @@ impl<FR> SandboxInstance<FR> {
args: &[RuntimeValue],

// supervisor environment provided to the module
supervisor_externals: &mut FE,
// supervisor_externals: &mut FE,

// arbitraty context data of the call
state: u32,
) -> std::result::Result<Option<wasmi::RuntimeValue>, wasmi::Error> {
with_guest_externals(
supervisor_externals,
self,
state,
|guest_externals| {

let wasmi_result = self.wasmi_instance
.invoke_export(export_name, args, guest_externals)?;

let wasmtime_function = self
.wasmtime_instance
.get_func(export_name)
.ok_or(wasmi::Error::Function("wasmtime function failed".to_string()))?;

let args: Vec<Val> = args
.iter()
.map(|v| match *v {
RuntimeValue::I32(val) => Val::I32(val),
RuntimeValue::I64(val) => Val::I64(val),
RuntimeValue::F32(val) => Val::F32(val.into()),
RuntimeValue::F64(val) => Val::F64(val.into()),
})
.collect();

let wasmtime_result = wasmtime_function
.call(&args)
.map_err(|e| wasmi::Error::Function(e.to_string()))?;

assert_eq!(wasmtime_result.len(), 1, "multiple return types are not supported yet");
if let Some(wasmi_value) = wasmi_result {
let wasmtime_value = match *wasmtime_result.first().unwrap() {
Val::I32(val) => RuntimeValue::I32(val),
Val::I64(val) => RuntimeValue::I64(val),
Val::F32(val) => RuntimeValue::F32(val.into()),
Val::F64(val) => RuntimeValue::F64(val.into()),
_ => unreachable!(),
};

assert_eq!(wasmi_value, wasmtime_value, "return values do not match");
}

Ok(wasmi_result)
},
)
SCH::with_sandbox_capabilities( |supervisor_externals| {
with_guest_externals(
supervisor_externals,
self,
state,
|guest_externals| {

let wasmi_result = self.wasmi_instance
.invoke_export(export_name, args, guest_externals)?;

let wasmtime_function = self
.wasmtime_instance
.get_func(export_name)
.ok_or(wasmi::Error::Function("wasmtime function failed".to_string()))?;

let args: Vec<Val> = args
.iter()
.map(|v| match *v {
RuntimeValue::I32(val) => Val::I32(val),
RuntimeValue::I64(val) => Val::I64(val),
RuntimeValue::F32(val) => Val::F32(val.into()),
RuntimeValue::F64(val) => Val::F64(val.into()),
})
.collect();

let wasmtime_result = wasmtime_function
.call(&args)
.map_err(|e| wasmi::Error::Function(e.to_string()))?;

assert_eq!(wasmtime_result.len(), 1, "multiple return types are not supported yet");
if let Some(wasmi_value) = wasmi_result {
let wasmtime_value = match *wasmtime_result.first().unwrap() {
Val::I32(val) => RuntimeValue::I32(val),
Val::I64(val) => RuntimeValue::I64(val),
Val::F32(val) => RuntimeValue::F32(val.into()),
Val::F64(val) => RuntimeValue::F64(val.into()),
_ => unreachable!(),
};

assert_eq!(wasmi_value, wasmtime_value, "return values do not match");
}

Ok(wasmi_result)
},
)
})
}

/// Get the value from a global with the given `name`.
Expand Down Expand Up @@ -547,6 +552,13 @@ impl<FR> UnregisteredInstance<FR> {
}
}

pub trait SandboxCapabiliesHolder<'a> {
type SupervisorFuncRef;
type SC: SandboxCapabilities<SupervisorFuncRef = Self::SupervisorFuncRef> + 'a;

fn with_sandbox_capabilities<R, F: FnOnce(&mut Self::SC) -> R>(f: F) -> R;
}

/// Instantiate a guest module and return it's index in the store.
///
/// The guest module's code is specified in `wasm`. Environment that will be available to
Expand All @@ -555,13 +567,17 @@ impl<FR> UnregisteredInstance<FR> {
/// normally created by `sp_sandbox::Instance` primitive.
///
/// Returns uninitialized sandboxed module instance or an instantiation error.
pub fn instantiate<'a, FE: SandboxCapabilities>(
supervisor_externals: &mut FE,
pub fn instantiate<'a, FE, SCH>(
// supervisor_externals: &mut FE,
dispatch_thunk: FE::SupervisorFuncRef,
wasm: &[u8],
guest_env: GuestEnvironment,
state: u32,
) -> std::result::Result<UnregisteredInstance<FE::SupervisorFuncRef>, InstantiationError> {
) -> std::result::Result<UnregisteredInstance<FE::SupervisorFuncRef>, InstantiationError>
where
FE: SandboxCapabilities + 'a,
SCH: SandboxCapabiliesHolder<'a, SupervisorFuncRef = FE::SupervisorFuncRef, SC = FE>,
{
let wasmi_module = Module::from_buffer(wasm).map_err(|_| InstantiationError::ModuleDecoding)?;
let wasmi_instance = ModuleInstance::new(&wasmi_module, &guest_env.imports)
.map_err(|_| InstantiationError::Instantiation)?;
Expand All @@ -580,11 +596,19 @@ pub fn instantiate<'a, FE: SandboxCapabilities>(
.filter_map(|import| {
if let wasmtime::ExternType::Func(func_ty) = import.ty() {
Some(wasmtime::Extern::Func(wasmtime::Func::new(&wasmtime_store, func_ty,
move |_, _, _| Err(wasmtime::Trap::new(format!(
"Sandbox function stub",
// func_ty.to_string(),
// func_ty.name().to_string()
)))
move |_, _, _| {
SCH::with_sandbox_capabilities(|sc| {
// sc.invoke();
});

Ok(())
}

// Err(wasmtime::Trap::new(format!(
// "Sandbox function stub",
// // func_ty.to_string(),
// // func_ty.name().to_string()
// )))
)))
} else {
None
Expand All @@ -604,18 +628,20 @@ pub fn instantiate<'a, FE: SandboxCapabilities>(
guest_to_supervisor_mapping: guest_env.guest_to_supervisor_mapping,
});

with_guest_externals(
supervisor_externals,
&sandbox_instance,
state,
|guest_externals| {
wasmi_instance
.run_start(guest_externals)
.map_err(|_| InstantiationError::StartTrapped)
SCH::with_sandbox_capabilities( |supervisor_externals| {
with_guest_externals(
supervisor_externals,
&sandbox_instance,
state,
|guest_externals| {
wasmi_instance
.run_start(guest_externals)
.map_err(|_| InstantiationError::StartTrapped)

// Note: no need to run start on wasmtime instance, since it's done automatically
},
)?;
// Note: no need to run start on wasmtime instance, since it's done automatically
},
)
})?;

Ok(UnregisteredInstance { sandbox_instance })
}
Expand Down
20 changes: 18 additions & 2 deletions client/executor/wasmi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ impl<'a> Sandbox for FunctionExecutor<'a> {
.collect::<Vec<_>>();

let instance = self.sandbox_store.instance(instance_id).map_err(|e| e.to_string())?;
let result = instance.invoke(export_name, &args, self, state);
let result = instance.invoke(export_name, &args, state);

match result {
Ok(None) => Ok(sandbox_primitives::ERR_OK),
Expand Down Expand Up @@ -242,8 +242,24 @@ impl<'a> Sandbox for FunctionExecutor<'a> {
Err(_) => return Ok(sandbox_primitives::ERR_MODULE as u32),
};

struct Adapter;

impl<'a> sandbox::SandboxCapabiliesHolder<'a> for Adapter {
type SupervisorFuncRef = wasmi::FuncRef;
type SC = FunctionExecutor<'static>;

fn with_sandbox_capabilities<R, F: FnOnce(&mut Self::SC) -> R>(f: F) -> R {
todo!();

// FOO.with(|fe| {
// let mut fe = fe.borrow_mut();
// f(fe.deref_mut())
// });
}
}

let instance_idx_or_err_code =
match sandbox::instantiate(self, dispatch_thunk, wasm, guest_env, state)
match sandbox::instantiate::<_, Adapter>(dispatch_thunk, wasm, guest_env, state)
.map(|i| i.register(&mut self.sandbox_store))
{
Ok(instance_idx) => instance_idx,
Expand Down
48 changes: 46 additions & 2 deletions client/executor/wasmtime/src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use sc_executor_common::sandbox::{self, SandboxCapabilities, SupervisorFuncIndex
use sp_core::sandbox as sandbox_primitives;
use sp_wasm_interface::{FunctionContext, MemoryId, Pointer, Sandbox, WordSize};
use wasmtime::{Func, Val};
use sandbox::SandboxCapabiliesHolder;

/// Wrapper type for pointer to a Wasm table entry.
///
Expand Down Expand Up @@ -75,6 +76,36 @@ impl HostState {
/// a longer-living `HostState`.
pub struct HostContext<'a>(&'a HostState);

scoped_tls::scoped_thread_local!(static HOST_CONTEXT: *mut HostContext<'_>);

impl<'a> SandboxCapabiliesHolder<'a> for HostContext<'a> {
type SupervisorFuncRef = SupervisorFuncRef;
type SC = HostContext<'static>;

fn with_sandbox_capabilities<R, F: FnOnce(&mut Self::SC) -> R>(f: F) -> R {
use std::ops::DerefMut;

HOST_CONTEXT.with(|fe| {
// Safe because of a limited scope in which the value exists
let fe = unsafe { &mut **fe };

f(fe)
})
}
}

impl<'a> HostContext<'a> {
fn set_sandbox_capabilities<R, F: FnOnce() -> R>(&mut self, f: F) -> R {
unsafe {
// Erasing lifetime of `HostContext` to put it into scoped TLS. This is safe because
// the pointer will never leave this scope and is semantically equivalent to `&'a mut`.
let self_ptr: *mut HostContext<'static> = std::mem::transmute(self as *mut HostContext<'a>);

HOST_CONTEXT.set(&self_ptr, f)
}
}
}

impl<'a> std::ops::Deref for HostContext<'a> {
type Target = HostState;
fn deref(&self) -> &HostState {
Expand Down Expand Up @@ -262,7 +293,20 @@ impl<'a> Sandbox for HostContext<'a> {
.borrow()
.instance(instance_id)
.map_err(|e| e.to_string())?;
let result = instance.invoke(export_name, &args, self, state);

let result = self.set_sandbox_capabilities(|| {
instance.invoke(export_name, &args, state)
});

// let result = unsafe {
// // Erasing lifetime of `HostContext` to put it into scoped TLS. This is safe because
// // the pointer will never leave this scope and is semantically equivalent to `&'a mut`.
// let self_ptr: *mut HostContext<'static> = std::mem::transmute(self as *mut HostContext<'a>);

// HOST_CONTEXT.set(&self_ptr, || {
// instance.invoke(export_name, &args, self, state)
// })
// };

match result {
Ok(None) => Ok(sandbox_primitives::ERR_OK),
Expand Down Expand Up @@ -319,7 +363,7 @@ impl<'a> Sandbox for HostContext<'a> {
};

let instance_idx_or_err_code =
match sandbox::instantiate(self, dispatch_thunk, wasm, guest_env, state)
match sandbox::instantiate::<_, Self>(dispatch_thunk, wasm, guest_env, state)
.map(|i| i.register(&mut *self.sandbox_store.borrow_mut()))
{
Ok(instance_idx) => instance_idx,
Expand Down

0 comments on commit 4e770b4

Please sign in to comment.