diff --git a/client/executor/src/native_executor.rs b/client/executor/src/native_executor.rs index 64c51d6f72faa..79d7915acde01 100644 --- a/client/executor/src/native_executor.rs +++ b/client/executor/src/native_executor.rs @@ -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 _; @@ -288,16 +298,16 @@ impl RuntimeInfo for NativeExecutor { pub struct RuntimeInstanceSpawn { module: Arc, - forks: parking_lot::Mutex>>>, - counter: std::sync::atomic::AtomicU32, + forks: parking_lot::Mutex>>>, + counter: AtomicU64, scheduler: Box, } impl sp_io::RuntimeSpawn for RuntimeInstanceSpawn { - fn dyn_dispatch(&self, dispatcher_ref: u32, func: u32, data: Vec) -> 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) -> 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(); @@ -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"); @@ -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); } @@ -334,7 +344,7 @@ impl sp_io::RuntimeSpawn for RuntimeInstanceSpawn { new_handle } - fn join(&self, handle: u32) -> Vec { + fn join(&self, handle: u64) -> Vec { let receiver = self.forks.lock().remove(&handle).expect("No fork for such handle"); let output = receiver.recv().expect("No signal from forked execution"); output diff --git a/client/executor/wasmtime/src/instance_wrapper.rs b/client/executor/wasmtime/src/instance_wrapper.rs index 6e99aa67f3bfd..67c1ab9388081 100644 --- a/client/executor/wasmtime/src/instance_wrapper.rs +++ b/client/executor/wasmtime/src/instance_wrapper.rs @@ -88,6 +88,7 @@ pub struct EntryPoint { } impl EntryPoint { + /// Call this entry point. pub fn call(&self, data_ptr: Pointer, data_len: WordSize) -> anyhow::Result { let data_ptr = u32::from(data_ptr) as i32; let data_len = u32::from(data_len) as i32; @@ -108,6 +109,31 @@ impl EntryPoint { }, }).map(|results| results[0].unwrap_i64() as u64) } + + pub fn direct(func: wasmtime::Func) -> std::result::Result { + 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 { + 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. @@ -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)?; @@ -220,17 +243,14 @@ 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) @@ -238,21 +258,16 @@ impl InstanceWrapper { 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() } + )) + )? }, }) } diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index 8883c8b95097e..e276b3b512f86 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -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) -> u32; + /// + /// Returns handle of the spawned task. + fn dyn_dispatch(&self, dispatcher_ref: u32, func: u32, payload: Vec) -> u64; /// Join the result of previously created runtime instance invocation. - fn join(&self, handle: u32) -> Vec; + fn join(&self, handle: u64) -> Vec; } #[cfg(feature = "std")] @@ -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) -> u32 { + fn spawn(&mut self, dispatcher_ref: u32, entry: u32, payload: Vec) -> u64 { let runtime_spawn = self.extension::() .expect("Cannot spawn without dynamic runtime dispatcher (RuntimeSpawnExt)"); runtime_spawn.dyn_dispatch(dispatcher_ref, entry, payload) @@ -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 { + fn join(&mut self, handle: u64) -> Vec { let runtime_spawn = self.extension::() .expect("Cannot spawn without dynamic runtime dispatcher (RuntimeSpawnExt)"); runtime_spawn.join(handle) diff --git a/primitives/io/src/tasks.rs b/primitives/io/src/tasks.rs index ff9cdada0e5b6..e2d407dba5137 100644 --- a/primitives/io/src/tasks.rs +++ b/primitives/io/src/tasks.rs @@ -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 {