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

Commit

Permalink
more refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
NikVolf committed Sep 15, 2020
1 parent b001b81 commit f7a02fc
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 48 deletions.
30 changes: 20 additions & 10 deletions client/executor/src/native_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,23 @@ use crate::{
RuntimeInfo, error::{Error, Result},
wasm_runtime::{RuntimeCache, WasmExecutionMethod},
};

use std::{
collections::HashMap,
panic::{UnwindSafe, AssertUnwindSafe},
result,
sync::{Arc, atomic::{AtomicU64, Ordering}, mpsc},
};

use sp_version::{NativeVersion, RuntimeVersion};
use codec::{Decode, Encode};
use sp_core::{
NativeOrEncoded, traits::{CodeExecutor, Externalities, RuntimeCode, MissingHostFunctions},
NativeOrEncoded,
traits::{
CodeExecutor, Externalities, RuntimeCode, MissingHostFunctions,
},
};
use log::trace;
use std::{result, panic::{UnwindSafe, AssertUnwindSafe}, sync::Arc, collections::HashMap};
use sp_wasm_interface::{HostFunctions, Function};
use sc_executor_common::wasm_runtime::{WasmInstance, WasmModule, CallSite};
use sp_externalities::ExternalitiesExt as _;
Expand Down Expand Up @@ -288,16 +298,16 @@ impl<D: NativeExecutionDispatch> RuntimeInfo for NativeExecutor<D> {

pub struct RuntimeInstanceSpawn {
module: Arc<dyn WasmModule>,
forks: parking_lot::Mutex<HashMap<u32, std::sync::mpsc::Receiver<Vec<u8>>>>,
counter: std::sync::atomic::AtomicU32,
forks: parking_lot::Mutex<HashMap<u64, mpsc::Receiver<Vec<u8>>>>,
counter: AtomicU64,
scheduler: Box<dyn sp_core::traits::SpawnNamed>,
}

impl sp_io::RuntimeSpawn for RuntimeInstanceSpawn {
fn dyn_dispatch(&self, dispatcher_ref: u32, func: u32, data: Vec<u8>) -> u32 {
let new_handle = self.counter.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
fn dyn_dispatch(&self, dispatcher_ref: u32, func: u32, data: Vec<u8>) -> u64 {
let new_handle = self.counter.fetch_add(1, Ordering::Relaxed);

let (sender, receiver) = std::sync::mpsc::channel();
let (sender, receiver) = mpsc::channel();
self.forks.lock().insert(new_handle, receiver);

let module = self.module.clone();
Expand All @@ -312,7 +322,7 @@ impl sp_io::RuntimeSpawn for RuntimeInstanceSpawn {
move || {

// FIXME: Should be refactored to shared "instance factory".
// Instatiating wasm here every time is suboptimal at the moment, shared
// Instantiating wasm here every time is suboptimal at the moment, shared
// pool of istances should be used.
let instance = module.new_instance().expect("Failed to create new instance for fork");

Expand All @@ -324,7 +334,7 @@ impl sp_io::RuntimeSpawn for RuntimeInstanceSpawn {
);

// If execution is panicked, the `join` in the original runtime code will panic as well,
// since the snder is dropped without seding anything.
// since the sender is dropped without seding anything.
if let Ok(output) = result {
let _ = sender.send(output);
}
Expand All @@ -334,7 +344,7 @@ impl sp_io::RuntimeSpawn for RuntimeInstanceSpawn {
new_handle
}

fn join(&self, handle: u32) -> Vec<u8> {
fn join(&self, handle: u64) -> Vec<u8> {
let receiver = self.forks.lock().remove(&handle).expect("No fork for such handle");
let output = receiver.recv().expect("No signal from forked execution");
output
Expand Down
81 changes: 48 additions & 33 deletions client/executor/wasmtime/src/instance_wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ pub struct EntryPoint {
}

impl EntryPoint {
/// Call this entry point.
pub fn call(&self, data_ptr: Pointer<u8>, data_len: WordSize) -> anyhow::Result<u64> {
let data_ptr = u32::from(data_ptr) as i32;
let data_len = u32::from(data_len) as i32;
Expand All @@ -108,6 +109,31 @@ impl EntryPoint {
},
}).map(|results| results[0].unwrap_i64() as u64)
}

pub fn direct(func: wasmtime::Func) -> std::result::Result<Self, &'static str> {
match (func.ty().params(), func.ty().results()) {
(&[wasmtime::ValType::I32, wasmtime::ValType::I32], &[wasmtime::ValType::I64]) => {
Ok(Self { func, call_type: EntryPointType::Direct })
}
_ => {
Err("Invalid signature")
}
}
}

pub fn wrapped(dispatcher: wasmtime::Func, func: u32) -> std::result::Result<Self, &'static str> {
match (dispatcher.ty().params(), dispatcher.ty().results()) {
(
&[wasmtime::ValType::I32, wasmtime::ValType::I32, wasmtime::ValType::I32],
&[wasmtime::ValType::I64],
) => {
Ok(Self { func: dispatcher, call_type: EntryPointType::Wrapped(func) })
},
_ => {
Err("Invalid signature")
}
}
}
}

/// Wrap the given WebAssembly Instance of a wasm module with Substrate-runtime.
Expand Down Expand Up @@ -199,16 +225,13 @@ impl InstanceWrapper {
let func = extern_func(&export)
.ok_or_else(|| Error::from(format!("Export {} is not a function", method)))?
.clone();
match (func.ty().params(), func.ty().results()) {
(&[wasmtime::ValType::I32, wasmtime::ValType::I32], &[wasmtime::ValType::I64]) => {}
_ => {
return Err(Error::from(format!(
"method {} have an unsupported signature",
EntryPoint::direct(func)
.map_err(|_|
Error::from(format!(
"Function '{}' has invalid signature.",
method,
)))
}
}
EntryPoint { call_type: EntryPointType::Direct, func }
))
)?
},
CallSite::Table(func_ref) => {
let table = self.instance.get_table("__indirect_function_table").ok_or(Error::NoTable)?;
Expand All @@ -220,39 +243,31 @@ impl InstanceWrapper {
.ok_or(Error::FunctionRefIsNull(func_ref))?
.clone();

match (func.ty().params(), func.ty().results()) {
(&[wasmtime::ValType::I32, wasmtime::ValType::I32], &[wasmtime::ValType::I64]) => {}
_ => {
return Err(Error::from(format!(
"Function @{} have an unsupported signature",
EntryPoint::direct(func)
.map_err(|_|
Error::from(format!(
"Function @{} has invalid signature.",
func_ref,
)))
}
}
EntryPoint { call_type: EntryPointType::Direct, func }
},
))
)?
},
CallSite::TableWithWrapper { dispatcher_ref, func } => {
let table = self.instance.get_table("__indirect_function_table").ok_or(Error::NoTable)?;
let val = table.get(dispatcher_ref)
.ok_or(Error::NoTableEntryWithIndex(dispatcher_ref))?;
let dispatcher = val
.funcref()
.ok_or(Error::TableElementIsNotAFunction(dispatcher_ref))?
.ok_or(Error::FunctionRefIsNull(dispatcher_ref))?;

match (dispatcher.ty().params(), dispatcher.ty().results()) {
(
&[wasmtime::ValType::I32, wasmtime::ValType::I32, wasmtime::ValType::I32],
&[wasmtime::ValType::I64],
) => {},
_ => {
return Err(Error::from(format!(
"Function @{} have an unsupported signature",
.ok_or(Error::FunctionRefIsNull(dispatcher_ref))?
.clone();

EntryPoint::wrapped(dispatcher, func)
.map_err(|_|
Error::from(format!(
"Function @{} has invalid signature.",
dispatcher_ref,
)))
}
}
EntryPoint { call_type: EntryPointType::Wrapped(func), func: dispatcher.clone() }
))
)?
},
})
}
Expand Down
10 changes: 6 additions & 4 deletions primitives/io/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1151,10 +1151,12 @@ pub trait Sandbox {
/// Runtime spawn extension.
pub trait RuntimeSpawn : Send {
/// Create new runtime instance and use dynamic dispatch to invoke with specified payload.
fn dyn_dispatch(&self, dispatcher_ref: u32, func: u32, payload: Vec<u8>) -> u32;
///
/// Returns handle of the spawned task.
fn dyn_dispatch(&self, dispatcher_ref: u32, func: u32, payload: Vec<u8>) -> u64;

/// Join the result of previously created runtime instance invocation.
fn join(&self, handle: u32) -> Vec<u8>;
fn join(&self, handle: u64) -> Vec<u8>;
}

#[cfg(feature = "std")]
Expand All @@ -1171,7 +1173,7 @@ pub trait RuntimeTasks {
/// Wasm host function for spawning task.
///
/// This should not be used directly. Use `sp_io::tasks::spawn` instead.
fn spawn(&mut self, dispatcher_ref: u32, entry: u32, payload: Vec<u8>) -> u32 {
fn spawn(&mut self, dispatcher_ref: u32, entry: u32, payload: Vec<u8>) -> u64 {
let runtime_spawn = self.extension::<RuntimeSpawnExt>()
.expect("Cannot spawn without dynamic runtime dispatcher (RuntimeSpawnExt)");
runtime_spawn.dyn_dispatch(dispatcher_ref, entry, payload)
Expand All @@ -1180,7 +1182,7 @@ pub trait RuntimeTasks {
/// Wasm host function for joining a task.
///
/// This should not be used directly. Use `join` of `sp_io::tasks::spawn` result instead.
fn join(&mut self, handle: u32) -> Vec<u8> {
fn join(&mut self, handle: u64) -> Vec<u8> {
let runtime_spawn = self.extension::<RuntimeSpawnExt>()
.expect("Cannot spawn without dynamic runtime dispatcher (RuntimeSpawnExt)");
runtime_spawn.join(handle)
Expand Down
2 changes: 1 addition & 1 deletion primitives/io/src/tasks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ mod inner {
/// This can be `join`-ed to get (blocking) the result of
/// the spawned task execution.
pub struct DataJoinHandle {
handle: u32,
handle: u64,
}

impl DataJoinHandle {
Expand Down

0 comments on commit f7a02fc

Please sign in to comment.