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

Commit

Permalink
update wasmtime
Browse files Browse the repository at this point in the history
  • Loading branch information
NikVolf committed Sep 15, 2020
1 parent 19ead82 commit cf40171
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 33 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 12 additions & 1 deletion client/executor/common/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,22 @@ pub enum Error {
/// No table is present.
///
/// Call was requested that requires table but none was present in the instance.
#[display(fmt="No table exported by wasm blob")]
NoTable,
/// No table is present.
/// No table entry is present.
///
/// Call was requested that requires specific entry in the table to be present.
#[display(fmt="No table entry with index {} in wasm blob exported table", _0)]
#[from(ignore)]
NoTableEntryWithIndex(u32),
/// Table entry is not a function.
#[display(fmt="Table element with index {} is not a function in wasm blob exported table", _0)]
#[from(ignore)]
TableElementIsNotAFunction(u32),
/// Function in table is null and thus cannot be called.
#[display(fmt="Table entry with index {} in wasm blob is null", _0)]
#[from(ignore)]
FunctionRefIsNull(u32),
}

impl std::error::Error for Error {
Expand Down
1 change: 1 addition & 0 deletions client/executor/wasmtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ description = "Defines a `WasmRuntime` that uses the Wasmtime JIT to execute."
targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
anyhow = "1.0"
log = "0.4.8"
scoped-tls = "1.0"
parity-wasm = "0.41.0"
Expand Down
120 changes: 102 additions & 18 deletions client/executor/wasmtime/src/instance_wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use std::{slice, marker};
use sc_executor_common::{
error::{Error, Result},
util::{WasmModuleInfo, DataSegmentsSnapshot},
wasm_runtime::CallSite,
};
use sp_wasm_interface::{Pointer, WordSize, Value};
use wasmtime::{Engine, Instance, Module, Memory, Table, Val, Func, Extern, Global, Store};
Expand Down Expand Up @@ -72,6 +73,40 @@ impl ModuleWrapper {
}
}

/// Format of the entrypoint.
pub enum EntryPointType {
/// Direct call.
Direct,
/// Indirect call.
Wrapped(u32),
}

/// Wasm blob entry point.
pub struct EntryPoint {
call_type: EntryPointType,
func: wasmtime::Func,
}

impl EntryPoint {
pub fn call(&self, data_ptr: i32, data_len: i32) -> anyhow::Result<u64> {
(match self.call_type {
EntryPointType::Direct => {
self.func.call(&[
wasmtime::Val::I32(data_ptr),
wasmtime::Val::I32(data_len),
])
},
EntryPointType::Wrapped(func) => {
self.func.call(&[
wasmtime::Val::I32(func as _),
wasmtime::Val::I32(data_ptr),
wasmtime::Val::I32(data_len),
])
},
}).map(|results| results[0].unwrap_i64() as u64)
}
}

/// Wrap the given WebAssembly Instance of a wasm module with Substrate-runtime.
///
/// This struct is a handy wrapper around a wasmtime `Instance` that provides substrate specific
Expand Down Expand Up @@ -150,24 +185,73 @@ impl InstanceWrapper {
///
/// An entrypoint must have a signature `(i32, i32) -> i64`, otherwise this function will return
/// an error.
pub fn resolve_entrypoint(&self, name: &str) -> Result<wasmtime::Func> {
// Resolve the requested method and verify that it has a proper signature.
let export = self
.instance
.get_export(name)
.ok_or_else(|| Error::from(format!("Exported method {} is not found", name)))?;
let entrypoint = extern_func(&export)
.ok_or_else(|| Error::from(format!("Export {} is not a function", name)))?;
match (entrypoint.ty().params(), entrypoint.ty().results()) {
(&[wasmtime::ValType::I32, wasmtime::ValType::I32], &[wasmtime::ValType::I64]) => {}
_ => {
return Err(Error::from(format!(
"method {} have an unsupported signature",
name
)))
}
}
Ok(entrypoint.clone())
pub fn resolve_entrypoint(&self, site: CallSite) -> Result<EntryPoint> {
Ok(match site {
CallSite::Export(method) => {
// Resolve the requested method and verify that it has a proper signature.
let export = self
.instance
.get_export(method)
.ok_or_else(|| Error::from(format!("Exported method {} is not found", method)))?;
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",
method,
)))
}
}
EntryPoint { call_type: EntryPointType::Direct, func }
},
CallSite::Table(func_ref) => {
let table = self.instance.get_table("__indirect_function_table").ok_or(Error::NoTable)?;
let val = table.get(func_ref)
.ok_or(Error::NoTableEntryWithIndex(func_ref))?;
let func = val
.funcref()
.ok_or(Error::TableElementIsNotAFunction(func_ref))?
.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",
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",
dispatcher_ref,
)))
}
}
EntryPoint { call_type: EntryPointType::Wrapped(func), func: dispatcher.clone() }
},
})
}

/// Returns an indirect function table of this instance.
Expand Down
22 changes: 8 additions & 14 deletions client/executor/wasmtime/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@

use crate::host::HostState;
use crate::imports::{Imports, resolve_imports};
use crate::instance_wrapper::{ModuleWrapper, InstanceWrapper, GlobalsSnapshot};
use crate::instance_wrapper::{ModuleWrapper, InstanceWrapper, GlobalsSnapshot, EntryPoint};
use crate::state_holder;

use std::rc::Rc;
use std::sync::Arc;
use sc_executor_common::{
error::{Error, Result, WasmError},
wasm_runtime::{WasmModule, WasmInstance},
wasm_runtime::{WasmModule, WasmInstance, CallSite},
};
use sp_allocator::FreeingBumpHeapAllocator;
use sp_runtime_interface::unpack_ptr_and_len;
Expand Down Expand Up @@ -90,8 +90,8 @@ pub struct WasmtimeInstance {
unsafe impl Send for WasmtimeInstance {}

impl WasmInstance for WasmtimeInstance {
fn call(&self, method: &str, data: &[u8]) -> Result<Vec<u8>> {
let entrypoint = self.instance_wrapper.resolve_entrypoint(method)?;
fn call(&self, call_site: CallSite, data: &[u8]) -> Result<Vec<u8>> {
let entrypoint = self.instance_wrapper.resolve_entrypoint(call_site)?;
let allocator = FreeingBumpHeapAllocator::new(self.heap_base);

self.module_wrapper
Expand Down Expand Up @@ -146,27 +146,21 @@ pub fn create_runtime(
fn perform_call(
data: &[u8],
instance_wrapper: Rc<InstanceWrapper>,
entrypoint: wasmtime::Func,
entrypoint: EntryPoint,
mut allocator: FreeingBumpHeapAllocator,
) -> Result<Vec<u8>> {
let (data_ptr, data_len) = inject_input_data(&instance_wrapper, &mut allocator, data)?;

let host_state = HostState::new(allocator, instance_wrapper.clone());
let ret = state_holder::with_initialized_state(&host_state, || {
match entrypoint.call(&[
wasmtime::Val::I32(u32::from(data_ptr) as i32),
wasmtime::Val::I32(u32::from(data_len) as i32),
]) {
Ok(results) => {
let retval = results[0].unwrap_i64() as u64;
Ok(unpack_ptr_and_len(retval))
}
match entrypoint.call(u32::from(data_ptr) as i32, u32::from(data_len) as i32) {
Ok(retval) => Ok(unpack_ptr_and_len(retval)),
Err(trap) => {
return Err(Error::from(format!(
"Wasm execution trapped: {}",
trap
)));
}
},
}
});
let (output_ptr, output_len) = ret?;
Expand Down

0 comments on commit cf40171

Please sign in to comment.