Remove UserError and switch to error::Error (#2899)

* Remove `UserError` and switch to `error::Error`

* More cleanup

* Update core/executor/src/error.rs

Co-Authored-By: Sergei Pepyakin <s.pepyakin@gmail.com>

* Fix typo

* Update core/executor/src/allocator.rs

Co-Authored-By: Stanislav Tkach <stanislav.tkach@gmail.com>
This commit is contained in:
Bastian Köcher
2019-06-19 15:08:59 +02:00
committed by GitHub
parent 0d7cb00def
commit 37acb90847
5 changed files with 378 additions and 314 deletions
+37 -40
View File
@@ -17,9 +17,8 @@
//! This module implements a freeing-bump allocator.
//! See more details at https://github.com/paritytech/substrate/issues/1615.
use crate::wasm_utils::UserError;
use crate::error::{Error, Result};
use log::trace;
use wasmi::Error;
use wasmi::MemoryRef;
use wasmi::memory_units::Bytes;
@@ -34,9 +33,6 @@ const ALIGNMENT: u32 = 8;
const N: usize = 22;
const MAX_POSSIBLE_ALLOCATION: u32 = 16777216; // 2^24 bytes
pub const OUT_OF_SPACE: &str = "Requested allocation size does not fit into remaining heap space";
pub const REQUESTED_SIZE_TOO_LARGE: &str = "Requested size to allocate is too large";
pub struct FreeingBumpHeapAllocator {
bumper: u32,
heads: [u32; N],
@@ -46,8 +42,12 @@ pub struct FreeingBumpHeapAllocator {
total_size: u32,
}
impl FreeingBumpHeapAllocator {
/// Create an allocator error.
fn error(msg: &'static str) -> Error {
Error::Allocator(msg)
}
impl FreeingBumpHeapAllocator {
/// Creates a new allocation heap which follows a freeing-bump strategy.
/// The maximum size which can be allocated at once is 16 MiB.
///
@@ -87,23 +87,22 @@ impl FreeingBumpHeapAllocator {
/// Gets requested number of bytes to allocate and returns a pointer.
/// The maximum size which can be allocated at once is 16 MiB.
pub fn allocate(&mut self, size: u32) -> Result<u32, UserError> {
pub fn allocate(&mut self, size: u32) -> Result<u32> {
if size > MAX_POSSIBLE_ALLOCATION {
return Err(UserError(REQUESTED_SIZE_TOO_LARGE));
return Err(Error::RequestedAllocationTooLarge);
}
let size = size.max(8);
let item_size = size.next_power_of_two();
if item_size + 8 + self.total_size > self.max_heap_size {
return Err(UserError(OUT_OF_SPACE));
return Err(Error::AllocatorOutOfSpace);
}
let list_index = (item_size.trailing_zeros() - 3) as usize;
let ptr: u32 = if self.heads[list_index] != 0 {
// Something from the free list
let item = self.heads[list_index];
let four_bytes = self.get_heap_4bytes(item)
.map_err(|_| UserError("Unable to get bytes at pointer taken from list of free items"))?;
let four_bytes = self.get_heap_4bytes(item)?;
self.heads[list_index] = FreeingBumpHeapAllocator::le_bytes_to_u32(four_bytes);
item + 8
} else {
@@ -111,13 +110,9 @@ impl FreeingBumpHeapAllocator {
self.bump(item_size + 8) + 8
};
for i in 1..8 {
self.set_heap(ptr - i, 255)
.map_err(|_| UserError("Unable to successively write bytes into heap at pointer prefix"))?;
}
(1..8).try_for_each(|i| self.set_heap(ptr - i, 255))?;
self.set_heap(ptr - 8, list_index as u8)
.map_err(|_| UserError("Unable to write byte into heap at pointer prefix"))?;
self.set_heap(ptr - 8, list_index as u8)?;
self.total_size = self.total_size + item_size + 8;
trace!(target: "wasm-heap", "Heap size is {} bytes after allocation", self.total_size);
@@ -126,31 +121,24 @@ impl FreeingBumpHeapAllocator {
}
/// Deallocates the space which was allocated for a pointer.
pub fn deallocate(&mut self, ptr: u32) -> Result<(), UserError> {
pub fn deallocate(&mut self, ptr: u32) -> Result<()> {
let ptr = ptr - self.ptr_offset;
if ptr < 8 {
return Err(UserError("Invalid pointer for deallocation"));
return Err(error("Invalid pointer for deallocation"));
}
let list_index = self.get_heap_byte(ptr - 8)
.map_err(|_| UserError("Unable to access pointer prefix"))? as usize;
for i in 1..8 {
let heap_byte = self.get_heap_byte(ptr - i)
.map_err(|_| UserError("Unable to write single bytes into heap at pointer"))?;
debug_assert!(heap_byte == 255)
}
let list_index = usize::from(self.get_heap_byte(ptr - 8)?);
(1..8).try_for_each(|i| self.get_heap_byte(ptr - i).map(|byte| assert!(byte == 255)))?;
let tail = self.heads[list_index];
self.heads[list_index] = ptr - 8;
let mut slice = self.get_heap_4bytes(ptr - 8)
.map_err(|_| UserError("Unable to get 4 bytes from heap at pointer prefix"))?;
let mut slice = self.get_heap_4bytes(ptr - 8)?;
FreeingBumpHeapAllocator::write_u32_into_le_bytes(tail, &mut slice);
self.set_heap_4bytes(ptr - 8, slice)
.map_err(|_| UserError("Unable to write 4 bytes into heap at pointer prefix"))?;
self.set_heap_4bytes(ptr - 8, slice)?;
let item_size = FreeingBumpHeapAllocator::get_item_size_from_index(list_index);
self.total_size = self.total_size.checked_sub(item_size as u32 + 8)
.ok_or_else(|| UserError("Unable to subtract from total heap size without overflow"))?;
.ok_or_else(|| error("Unable to subtract from total heap size without overflow"))?;
trace!(target: "wasm-heap", "Heap size is {} bytes after deallocation", self.total_size);
Ok(())
@@ -176,24 +164,24 @@ impl FreeingBumpHeapAllocator {
1 << 3 << index
}
fn get_heap_4bytes(&mut self, ptr: u32) -> Result<[u8; 4], Error> {
fn get_heap_4bytes(&mut self, ptr: u32) -> Result<[u8; 4]> {
let mut arr = [0u8; 4];
self.heap.get_into(self.ptr_offset + ptr, &mut arr)?;
Ok(arr)
}
fn get_heap_byte(&mut self, ptr: u32) -> Result<u8, Error> {
fn get_heap_byte(&mut self, ptr: u32) -> Result<u8> {
let mut arr = [0u8; 1];
self.heap.get_into(self.ptr_offset + ptr, &mut arr)?;
Ok(arr[0])
}
fn set_heap(&mut self, ptr: u32, value: u8) -> Result<(), Error> {
self.heap.set(self.ptr_offset + ptr, &[value])
fn set_heap(&mut self, ptr: u32, value: u8) -> Result<()> {
self.heap.set(self.ptr_offset + ptr, &[value]).map_err(Into::into)
}
fn set_heap_4bytes(&mut self, ptr: u32, value: [u8; 4]) -> Result<(), Error> {
self.heap.set(self.ptr_offset + ptr, &value)
fn set_heap_4bytes(&mut self, ptr: u32, value: [u8; 4]) -> Result<()> {
self.heap.set(self.ptr_offset + ptr, &value).map_err(Into::into)
}
}
@@ -353,7 +341,10 @@ mod tests {
// then
assert_eq!(ptr.is_err(), true);
if let Err(err) = ptr {
assert_eq!(err, UserError(OUT_OF_SPACE));
match err {
Error::AllocatorOutOfSpace => {},
_ => panic!("Expected out of space error"),
}
}
}
@@ -372,7 +363,10 @@ mod tests {
// there is no room for another half page incl. its 8 byte prefix
assert_eq!(ptr2.is_err(), true);
if let Err(err) = ptr2 {
assert_eq!(err, UserError(OUT_OF_SPACE));
match err {
Error::AllocatorOutOfSpace => {},
_ => panic!("Expected out of space error"),
}
}
}
@@ -402,7 +396,10 @@ mod tests {
// then
assert_eq!(ptr.is_err(), true);
if let Err(err) = ptr {
assert_eq!(err, UserError(REQUESTED_SIZE_TOO_LARGE));
match err {
Error::RequestedAllocationTooLarge => {},
e => panic!("Expected out of space error, got: {:?}", e),
}
}
}
+20 -1
View File
@@ -55,9 +55,20 @@ pub enum Error {
/// Runtime failed.
#[display(fmt="Runtime error")]
Runtime,
/// Runtime failed.
/// Invalid memory reference.
#[display(fmt="Invalid memory reference")]
InvalidMemoryReference,
/// Some other error occurred
Other(&'static str),
/// Some error occurred in the allocator
#[display(fmt="Error in allocator: {}", _0)]
Allocator(&'static str),
/// The allocator run out of space.
#[display(fmt="Allocator run out of space")]
AllocatorOutOfSpace,
/// Someone tried to allocate more memory than the allowed maximum per allocation.
#[display(fmt="Requested allocation size is too large")]
RequestedAllocationTooLarge,
}
impl std::error::Error for Error {
@@ -72,3 +83,11 @@ impl std::error::Error for Error {
}
impl state_machine::Error for Error {}
impl wasmi::HostError for Error {}
impl From<&'static str> for Error {
fn from(err: &'static str) -> Error {
Error::Other(err)
}
}
+39 -44
View File
@@ -18,16 +18,13 @@
//! This module implements sandboxing support in the runtime.
use std::collections::HashMap;
use std::rc::Rc;
use crate::error::{Result, Error};
use std::{collections::HashMap, rc::Rc};
use parity_codec::{Decode, Encode};
use primitives::sandbox as sandbox_primitives;
use crate::wasm_utils::UserError;
use wasmi;
use wasmi::memory_units::Pages;
use wasmi::{
Externals, FuncRef, ImportResolver, MemoryInstance, MemoryRef, Module, ModuleInstance,
ModuleRef, RuntimeArgs, RuntimeValue, Trap, TrapKind
ModuleRef, RuntimeArgs, RuntimeValue, Trap, TrapKind, memory_units::Pages,
};
/// Index of a function inside the supervisor.
@@ -75,18 +72,18 @@ impl ImportResolver for Imports {
module_name: &str,
field_name: &str,
signature: &::wasmi::Signature,
) -> Result<FuncRef, ::wasmi::Error> {
) -> std::result::Result<FuncRef, wasmi::Error> {
let key = (
module_name.as_bytes().to_owned(),
field_name.as_bytes().to_owned(),
);
let idx = *self.func_map.get(&key).ok_or_else(|| {
::wasmi::Error::Instantiation(format!(
wasmi::Error::Instantiation(format!(
"Export {}:{} not found",
module_name, field_name
))
})?;
Ok(::wasmi::FuncInstance::alloc_host(signature.clone(), idx.0))
Ok(wasmi::FuncInstance::alloc_host(signature.clone(), idx.0))
}
fn resolve_memory(
@@ -94,7 +91,7 @@ impl ImportResolver for Imports {
module_name: &str,
field_name: &str,
_memory_type: &::wasmi::MemoryDescriptor,
) -> Result<MemoryRef, ::wasmi::Error> {
) -> std::result::Result<MemoryRef, wasmi::Error> {
let key = (
module_name.as_bytes().to_vec(),
field_name.as_bytes().to_vec(),
@@ -102,7 +99,7 @@ impl ImportResolver for Imports {
let mem = self.memories_map
.get(&key)
.ok_or_else(|| {
::wasmi::Error::Instantiation(format!(
wasmi::Error::Instantiation(format!(
"Export {}:{} not found",
module_name, field_name
))
@@ -116,8 +113,8 @@ impl ImportResolver for Imports {
module_name: &str,
field_name: &str,
_global_type: &::wasmi::GlobalDescriptor,
) -> Result<::wasmi::GlobalRef, ::wasmi::Error> {
Err(::wasmi::Error::Instantiation(format!(
) -> std::result::Result<wasmi::GlobalRef, wasmi::Error> {
Err(wasmi::Error::Instantiation(format!(
"Export {}:{} not found",
module_name, field_name
)))
@@ -128,8 +125,8 @@ impl ImportResolver for Imports {
module_name: &str,
field_name: &str,
_table_type: &::wasmi::TableDescriptor,
) -> Result<::wasmi::TableRef, ::wasmi::Error> {
Err(::wasmi::Error::Instantiation(format!(
) -> std::result::Result<wasmi::TableRef, wasmi::Error> {
Err(wasmi::Error::Instantiation(format!(
"Export {}:{} not found",
module_name, field_name
)))
@@ -153,7 +150,7 @@ pub trait SandboxCapabilities {
/// Returns `Err` if allocation not possible or errors during heap management.
///
/// Returns pointer to the allocated block.
fn allocate(&mut self, len: u32) -> Result<u32, UserError>;
fn allocate(&mut self, len: u32) -> Result<u32>;
/// Deallocate space specified by the pointer that was previously returned by [`allocate`].
///
@@ -162,21 +159,21 @@ pub trait SandboxCapabilities {
/// Returns `Err` if deallocation not possible or because of errors in heap management.
///
/// [`allocate`]: #tymethod.allocate
fn deallocate(&mut self, ptr: u32) -> Result<(), UserError>;
fn deallocate(&mut self, ptr: u32) -> Result<()>;
/// Write `data` into the supervisor memory at offset specified by `ptr`.
///
/// # Errors
///
/// Returns `Err` if `ptr + data.len()` is out of bounds.
fn write_memory(&mut self, ptr: u32, data: &[u8]) -> Result<(), UserError>;
fn write_memory(&mut self, ptr: u32, data: &[u8]) -> Result<()>;
/// Read `len` bytes from the supervisor memory.
///
/// # Errors
///
/// Returns `Err` if `ptr + len` is out of bounds.
fn read_memory(&self, ptr: u32, len: u32) -> Result<Vec<u8>, UserError>;
fn read_memory(&self, ptr: u32, len: u32) -> Result<Vec<u8>>;
}
/// Implementation of [`Externals`] that allows execution of guest module with
@@ -190,12 +187,12 @@ pub struct GuestExternals<'a, FE: SandboxCapabilities + Externals + 'a> {
}
fn trap(msg: &'static str) -> Trap {
TrapKind::Host(Box::new(UserError(msg))).into()
TrapKind::Host(Box::new(Error::Other(msg))).into()
}
fn deserialize_result(serialized_result: &[u8]) -> Result<Option<RuntimeValue>, Trap> {
fn deserialize_result(serialized_result: &[u8]) -> std::result::Result<Option<RuntimeValue>, Trap> {
use self::sandbox_primitives::{HostError, ReturnValue};
let result_val = Result::<ReturnValue, HostError>::decode(&mut &serialized_result[..])
let result_val = std::result::Result::<ReturnValue, HostError>::decode(&mut &serialized_result[..])
.ok_or_else(|| trap("Decoding Result<ReturnValue, HostError> failed!"))?;
match result_val {
@@ -212,7 +209,7 @@ impl<'a, FE: SandboxCapabilities + Externals + 'a> Externals for GuestExternals<
&mut self,
index: usize,
args: RuntimeArgs,
) -> Result<Option<RuntimeValue>, Trap> {
) -> std::result::Result<Option<RuntimeValue>, Trap> {
// Make `index` typesafe again.
let index = GuestFuncIndex(index);
@@ -331,7 +328,7 @@ impl SandboxInstance {
args: &[RuntimeValue],
supervisor_externals: &mut FE,
state: u32,
) -> Result<Option<wasmi::RuntimeValue>, wasmi::Error> {
) -> std::result::Result<Option<wasmi::RuntimeValue>, wasmi::Error> {
with_guest_externals(
supervisor_externals,
self,
@@ -362,7 +359,7 @@ pub enum InstantiationError {
fn decode_environment_definition(
raw_env_def: &[u8],
memories: &[Option<MemoryRef>],
) -> Result<(Imports, GuestToSupervisorFunctionMapping), InstantiationError> {
) -> std::result::Result<(Imports, GuestToSupervisorFunctionMapping), InstantiationError> {
let env_def = sandbox_primitives::EnvironmentDefinition::decode(&mut &raw_env_def[..])
.ok_or_else(|| InstantiationError::EnvironmentDefintionCorrupted)?;
@@ -420,7 +417,7 @@ pub fn instantiate<FE: SandboxCapabilities + Externals>(
wasm: &[u8],
raw_env_def: &[u8],
state: u32,
) -> Result<u32, InstantiationError> {
) -> std::result::Result<u32, InstantiationError> {
let (imports, guest_to_supervisor_mapping) =
decode_environment_definition(raw_env_def, &supervisor_externals.store().memories)?;
@@ -476,7 +473,7 @@ impl Store {
///
/// Returns `Err` if the memory couldn't be created.
/// Typically happens if `initial` is more than `maximum`.
pub fn new_memory(&mut self, initial: u32, maximum: u32) -> Result<u32, UserError> {
pub fn new_memory(&mut self, initial: u32, maximum: u32) -> Result<u32> {
let maximum = match maximum {
sandbox_primitives::MEM_UNLIMITED => None,
specified_limit => Some(Pages(specified_limit as usize)),
@@ -486,8 +483,7 @@ impl Store {
MemoryInstance::alloc(
Pages(initial as usize),
maximum,
)
.map_err(|_| UserError("Sandboxed memory allocation error"))?;
)?;
let mem_idx = self.memories.len();
self.memories.push(Some(mem));
@@ -500,12 +496,12 @@ impl Store {
///
/// Returns `Err` If `instance_idx` isn't a valid index of an instance or
/// instance is already torndown.
pub fn instance(&self, instance_idx: u32) -> Result<Rc<SandboxInstance>, UserError> {
pub fn instance(&self, instance_idx: u32) -> Result<Rc<SandboxInstance>> {
self.instances
.get(instance_idx as usize)
.cloned()
.ok_or_else(|| UserError("Trying to access a non-existent instance"))?
.ok_or_else(|| UserError("Trying to access a torndown instance"))
.ok_or_else(|| "Trying to access a non-existent instance")?
.ok_or_else(|| "Trying to access a torndown instance".into())
}
/// Returns reference to a memory instance by `memory_idx`.
@@ -514,12 +510,12 @@ impl Store {
///
/// Returns `Err` If `memory_idx` isn't a valid index of an memory or
/// if memory has been torn down.
pub fn memory(&self, memory_idx: u32) -> Result<MemoryRef, UserError> {
pub fn memory(&self, memory_idx: u32) -> Result<MemoryRef> {
self.memories
.get(memory_idx as usize)
.cloned()
.ok_or_else(|| UserError("Trying to access a non-existent sandboxed memory"))?
.ok_or_else(|| UserError("Trying to access a torndown sandboxed memory"))
.ok_or_else(|| "Trying to access a non-existent sandboxed memory")?
.ok_or_else(|| "Trying to access a torndown sandboxed memory".into())
}
/// Tear down the memory at the specified index.
@@ -528,10 +524,10 @@ impl Store {
///
/// Returns `Err` if `memory_idx` isn't a valid index of an memory or
/// if it has been torn down.
pub fn memory_teardown(&mut self, memory_idx: u32) -> Result<(), UserError> {
pub fn memory_teardown(&mut self, memory_idx: u32) -> Result<()> {
match self.memories.get_mut(memory_idx as usize) {
None => Err(UserError("Trying to teardown a non-existent sandboxed memory")),
Some(None) => Err(UserError("Double teardown of a sandboxed memory")),
None => Err("Trying to teardown a non-existent sandboxed memory".into()),
Some(None) => Err("Double teardown of a sandboxed memory".into()),
Some(memory) => {
*memory = None;
Ok(())
@@ -545,10 +541,10 @@ impl Store {
///
/// Returns `Err` if `instance_idx` isn't a valid index of an instance or
/// if it has been torn down.
pub fn instance_teardown(&mut self, instance_idx: u32) -> Result<(), UserError> {
pub fn instance_teardown(&mut self, instance_idx: u32) -> Result<()> {
match self.instances.get_mut(instance_idx as usize) {
None => Err(UserError("Trying to teardown a non-existent instance")),
Some(None) => Err(UserError("Double teardown of an instance")),
None => Err("Trying to teardown a non-existent instance".into()),
Some(None) => Err("Double teardown of an instance".into()),
Some(instance) => {
*instance = None;
Ok(())
@@ -565,9 +561,8 @@ impl Store {
#[cfg(test)]
mod tests {
use super::*;
use primitives::{Blake2Hasher};
use crate::allocator;
use crate::sandbox::trap;
use crate::wasm_executor::WasmExecutor;
use state_machine::TestExternalities as CoreTestExternalities;
use wabt;
@@ -647,7 +642,7 @@ mod tests {
if let Err(err) = res {
assert_eq!(
format!("{}", err),
format!("{}", wasmi::Error::Trap(trap(allocator::OUT_OF_SPACE)))
format!("{}", wasmi::Error::Trap(Error::AllocatorOutOfSpace.into()))
);
}
}
File diff suppressed because it is too large Load Diff
+79 -27
View File
@@ -16,31 +16,73 @@
//! Rust implementation of Substrate contracts.
use wasmi::{ValueType, RuntimeValue, HostError};
use wasmi::{ValueType, RuntimeValue};
use wasmi::nan_preserving_float::{F32, F64};
use std::fmt;
#[derive(Debug, PartialEq)]
pub struct UserError(pub &'static str);
impl fmt::Display for UserError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "UserError: {}", self.0)
}
}
impl HostError for UserError {
pub trait ConvertibleToWasm {
const VALUE_TYPE: ValueType;
type NativeType; fn to_runtime_value(self) -> RuntimeValue;
}
pub trait ConvertibleToWasm { const VALUE_TYPE: ValueType; type NativeType; fn to_runtime_value(self) -> RuntimeValue; }
impl ConvertibleToWasm for i32 { type NativeType = i32; const VALUE_TYPE: ValueType = ValueType::I32; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self) } }
impl ConvertibleToWasm for u32 { type NativeType = u32; const VALUE_TYPE: ValueType = ValueType::I32; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as i32) } }
impl ConvertibleToWasm for i64 { type NativeType = i64; const VALUE_TYPE: ValueType = ValueType::I64; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I64(self) } }
impl ConvertibleToWasm for u64 { type NativeType = u64; const VALUE_TYPE: ValueType = ValueType::I64; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I64(self as i64) } }
impl ConvertibleToWasm for F32 { type NativeType = F32; const VALUE_TYPE: ValueType = ValueType::F32; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::F32(self) } }
impl ConvertibleToWasm for F64 { type NativeType = F64; const VALUE_TYPE: ValueType = ValueType::F64; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::F64(self) } }
impl ConvertibleToWasm for isize { type NativeType = i32; const VALUE_TYPE: ValueType = ValueType::I32; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as i32) } }
impl ConvertibleToWasm for usize { type NativeType = u32; const VALUE_TYPE: ValueType = ValueType::I32; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as u32 as i32) } }
impl<T> ConvertibleToWasm for *const T { type NativeType = u32; const VALUE_TYPE: ValueType = ValueType::I32; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as isize as i32) } }
impl<T> ConvertibleToWasm for *mut T { type NativeType = u32; const VALUE_TYPE: ValueType = ValueType::I32; fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as isize as i32) } }
impl ConvertibleToWasm for i32 {
type NativeType = i32;
const VALUE_TYPE: ValueType = ValueType::I32;
fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self) }
}
impl ConvertibleToWasm for u32 {
type NativeType = u32;
const VALUE_TYPE: ValueType = ValueType::I32;
fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as i32) }
}
impl ConvertibleToWasm for i64 {
type NativeType = i64;
const VALUE_TYPE: ValueType = ValueType::I64;
fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I64(self) }
}
impl ConvertibleToWasm for u64 {
type NativeType = u64;
const VALUE_TYPE: ValueType = ValueType::I64;
fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I64(self as i64) }
}
impl ConvertibleToWasm for F32 {
type NativeType = F32;
const VALUE_TYPE: ValueType = ValueType::F32;
fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::F32(self) }
}
impl ConvertibleToWasm for F64 {
type NativeType = F64;
const VALUE_TYPE: ValueType = ValueType::F64;
fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::F64(self) }
}
impl ConvertibleToWasm for isize {
type NativeType = i32;
const VALUE_TYPE: ValueType = ValueType::I32;
fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as i32) }
}
impl ConvertibleToWasm for usize {
type NativeType = u32;
const VALUE_TYPE: ValueType = ValueType::I32;
fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as u32 as i32) }
}
impl<T> ConvertibleToWasm for *const T {
type NativeType = u32;
const VALUE_TYPE: ValueType = ValueType::I32;
fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as isize as i32) }
}
impl<T> ConvertibleToWasm for *mut T {
type NativeType = u32;
const VALUE_TYPE: ValueType = ValueType::I32;
fn to_runtime_value(self) -> RuntimeValue { RuntimeValue::I32(self as isize as i32) }
}
/// Converts arguments into respective WASM types.
#[macro_export]
@@ -118,7 +160,7 @@ macro_rules! unmarshall_args {
#[inline(always)]
pub fn constrain_closure<R, F>(f: F) -> F
where
F: FnOnce() -> Result<R, ::wasmi::Trap>
F: FnOnce() -> Result<R, crate::error::Error>
{
f
}
@@ -132,14 +174,14 @@ macro_rules! marshall {
>(|| {
unmarshall_args!($body, $objectname, $args_iter, $( $names : $params ),*)
});
let r = body()?;
let r = body().map_err(wasmi::Trap::from)?;
return Ok(Some({ use $crate::wasm_utils::ConvertibleToWasm; r.to_runtime_value() }))
});
( $args_iter:ident, $objectname:ident, ( $( $names:ident : $params:ty ),* ) => $body:tt ) => ({
let body = $crate::wasm_utils::constrain_closure::<(), _>(|| {
unmarshall_args!($body, $objectname, $args_iter, $( $names : $params ),*)
});
body()?;
body().map_err(wasmi::Trap::from)?;
return Ok(None)
})
}
@@ -154,7 +196,13 @@ macro_rules! dispatch_fn {
panic!("fn with index {} is undefined", $index);
};
( @iter $index:expr, $index_ident:ident, $objectname:ident, $args_iter:ident, $name:ident ( $( $names:ident : $params:ty ),* ) $( -> $returns:ty )* => $body:tt $($tail:tt)*) => (
(@iter
$index:expr,
$index_ident:ident,
$objectname:ident,
$args_iter:ident,
$name:ident ( $( $names:ident : $params:ty ),* ) $( -> $returns:ty )* => $body:tt $($tail:tt)*
) => (
if $index_ident == $index {
{ marshall!($args_iter, $objectname, ( $( $names : $params ),* ) $( -> $returns )* => $body) }
}
@@ -177,7 +225,11 @@ macro_rules! impl_function_executor {
fn resolver() -> &'static dyn $crate::wasmi::ModuleImportResolver {
struct Resolver;
impl $crate::wasmi::ModuleImportResolver for Resolver {
fn resolve_func(&self, name: &str, signature: &$crate::wasmi::Signature) -> ::std::result::Result<$crate::wasmi::FuncRef, $crate::wasmi::Error> {
fn resolve_func(
&self,
name: &str,
signature: &$crate::wasmi::Signature
) -> std::result::Result<$crate::wasmi::FuncRef, $crate::wasmi::Error> {
resolve_fn!(signature, name, $( $name( $( $params ),* ) $( -> $returns )* => )*);
Err($crate::wasmi::Error::Instantiation(
@@ -194,7 +246,7 @@ macro_rules! impl_function_executor {
&mut self,
index: usize,
args: $crate::wasmi::RuntimeArgs,
) -> ::std::result::Result<Option<$crate::wasmi::RuntimeValue>, $crate::wasmi::Trap> {
) -> std::result::Result<Option<$crate::wasmi::RuntimeValue>, $crate::wasmi::Trap> {
let $objectname = self;
let mut args = args.as_ref().iter();
dispatch_fn!(index, $objectname, args, $( $name( $( $names : $params ),* ) $( -> $returns )* => $body ),*);