mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-20 04:06:30 +00:00
Deny missing docs in runtime core and add missing docs
This commit is contained in:
@ -17,6 +17,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use std::{fmt::Debug, slice};
|
use std::{fmt::Debug, slice};
|
||||||
|
|
||||||
|
/// Size of the array for internal instance usage
|
||||||
pub const INTERNALS_SIZE: usize = 256;
|
pub const INTERNALS_SIZE: usize = 256;
|
||||||
|
|
||||||
pub(crate) struct Internals(pub(crate) [u64; INTERNALS_SIZE]);
|
pub(crate) struct Internals(pub(crate) [u64; INTERNALS_SIZE]);
|
||||||
@ -472,6 +473,8 @@ impl LocalBacking {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The `ImportBacking` stores references to the imported resources of an Instance. This includes
|
||||||
|
/// imported memories, tables, globals and functions.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ImportBacking {
|
pub struct ImportBacking {
|
||||||
pub(crate) memories: BoxedMap<ImportedMemoryIndex, Memory>,
|
pub(crate) memories: BoxedMap<ImportedMemoryIndex, Memory>,
|
||||||
@ -488,6 +491,7 @@ pub struct ImportBacking {
|
|||||||
unsafe impl Send for ImportBacking {}
|
unsafe impl Send for ImportBacking {}
|
||||||
|
|
||||||
impl ImportBacking {
|
impl ImportBacking {
|
||||||
|
/// Creates a new `ImportBacking` from the given `ModuleInner`, `ImportObject`, and `Ctx`.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
module: &ModuleInner,
|
module: &ModuleInner,
|
||||||
imports: &ImportObject,
|
imports: &ImportObject,
|
||||||
@ -536,6 +540,7 @@ impl ImportBacking {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a `ImportedFunc` from the given `ImportedFuncIndex`.
|
||||||
pub fn imported_func(&self, index: ImportedFuncIndex) -> vm::ImportedFunc {
|
pub fn imported_func(&self, index: ImportedFuncIndex) -> vm::ImportedFunc {
|
||||||
self.vm_functions[index].clone()
|
self.vm_functions[index].clone()
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
//! The cache module provides the common data structures used by compiler backends to allow
|
||||||
|
//! serializing compiled wasm code to a binary format. The binary format can be persisted,
|
||||||
|
//! and loaded to allow skipping compilation and fast startup.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::Backend,
|
backend::Backend,
|
||||||
module::{Module, ModuleInfo},
|
module::{Module, ModuleInfo},
|
||||||
@ -6,20 +10,31 @@ use crate::{
|
|||||||
use blake2b_simd::blake2bp;
|
use blake2b_simd::blake2bp;
|
||||||
use std::{fmt, io, mem, slice};
|
use std::{fmt, io, mem, slice};
|
||||||
|
|
||||||
|
/// Indicates the invalid type of invalid cache file
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum InvalidFileType {
|
pub enum InvalidFileType {
|
||||||
|
/// Given cache header slice does not match the expected size of an `ArtifactHeader`
|
||||||
InvalidSize,
|
InvalidSize,
|
||||||
|
/// Given cache header slice does not contain the expected magic bytes
|
||||||
InvalidMagic,
|
InvalidMagic,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Kinds of caching errors
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
/// An IO error while reading/writing a cache binary.
|
||||||
IoError(io::Error),
|
IoError(io::Error),
|
||||||
|
/// An error deserializing bytes into a cache data structure.
|
||||||
DeserializeError(String),
|
DeserializeError(String),
|
||||||
|
/// An error serializing bytes from a cache data structure.
|
||||||
SerializeError(String),
|
SerializeError(String),
|
||||||
|
/// An undefined caching error with a message.
|
||||||
Unknown(String),
|
Unknown(String),
|
||||||
|
/// An invalid cache binary given.
|
||||||
InvalidFile(InvalidFileType),
|
InvalidFile(InvalidFileType),
|
||||||
|
/// The cached binary has been invalidated.
|
||||||
InvalidatedCache,
|
InvalidatedCache,
|
||||||
|
/// The current backend does not support caching.
|
||||||
UnsupportedBackend(Backend),
|
UnsupportedBackend(Backend),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,6 +179,8 @@ struct ArtifactInner {
|
|||||||
compiled_code: Memory,
|
compiled_code: Memory,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Artifact are produced by caching, are serialized/deserialized to binaries, and contain
|
||||||
|
/// module info, backend metadata, and compiled code.
|
||||||
pub struct Artifact {
|
pub struct Artifact {
|
||||||
inner: ArtifactInner,
|
inner: ArtifactInner,
|
||||||
}
|
}
|
||||||
@ -183,6 +200,7 @@ impl Artifact {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deserializes an `Artifact` from the given byte slice.
|
||||||
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
||||||
let (_, body_slice) = ArtifactHeader::read_from_slice(bytes)?;
|
let (_, body_slice) = ArtifactHeader::read_from_slice(bytes)?;
|
||||||
|
|
||||||
@ -192,6 +210,7 @@ impl Artifact {
|
|||||||
Ok(Artifact { inner })
|
Ok(Artifact { inner })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A reference to the `Artifact`'s stored `ModuleInfo`
|
||||||
pub fn info(&self) -> &ModuleInfo {
|
pub fn info(&self) -> &ModuleInfo {
|
||||||
&self.inner.info
|
&self.inner.info
|
||||||
}
|
}
|
||||||
@ -205,6 +224,7 @@ impl Artifact {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serializes the `Artifact` into a vector of bytes
|
||||||
pub fn serialize(&self) -> Result<Vec<u8>, Error> {
|
pub fn serialize(&self) -> Result<Vec<u8>, Error> {
|
||||||
let cache_header = ArtifactHeader {
|
let cache_header = ArtifactHeader {
|
||||||
magic: WASMER_CACHE_MAGIC,
|
magic: WASMER_CACHE_MAGIC,
|
||||||
@ -230,7 +250,9 @@ impl Artifact {
|
|||||||
///
|
///
|
||||||
/// The `wasmer-runtime` supplies a naive `FileSystemCache` api.
|
/// The `wasmer-runtime` supplies a naive `FileSystemCache` api.
|
||||||
pub trait Cache {
|
pub trait Cache {
|
||||||
|
/// Error type to return when load error occurs
|
||||||
type LoadError: fmt::Debug;
|
type LoadError: fmt::Debug;
|
||||||
|
/// Error type to return when store error occurs
|
||||||
type StoreError: fmt::Debug;
|
type StoreError: fmt::Debug;
|
||||||
|
|
||||||
/// loads a module using the default `Backend`
|
/// loads a module using the default `Backend`
|
||||||
@ -238,6 +260,7 @@ pub trait Cache {
|
|||||||
/// loads a cached module using a specific `Backend`
|
/// loads a cached module using a specific `Backend`
|
||||||
fn load_with_backend(&self, key: WasmHash, backend: Backend)
|
fn load_with_backend(&self, key: WasmHash, backend: Backend)
|
||||||
-> Result<Module, Self::LoadError>;
|
-> Result<Module, Self::LoadError>;
|
||||||
|
/// Store a module into the cache with the given key
|
||||||
fn store(&mut self, key: WasmHash, module: Module) -> Result<(), Self::StoreError>;
|
fn store(&mut self, key: WasmHash, module: Module) -> Result<(), Self::StoreError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//! The codegen module provides common functions and data structures used by multiple backends
|
||||||
|
//! during the code generation process.
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::RunnableModule,
|
backend::RunnableModule,
|
||||||
backend::{Backend, CacheGen, Compiler, CompilerConfig, Features, Token},
|
backend::{Backend, CacheGen, Compiler, CompilerConfig, Features, Token},
|
||||||
@ -17,22 +19,35 @@ use std::sync::{Arc, RwLock};
|
|||||||
use wasmparser::{self, WasmDecoder};
|
use wasmparser::{self, WasmDecoder};
|
||||||
use wasmparser::{Operator, Type as WpType};
|
use wasmparser::{Operator, Type as WpType};
|
||||||
|
|
||||||
|
/// A type that defines a function pointer, which is called when breakpoints occur.
|
||||||
pub type BreakpointHandler =
|
pub type BreakpointHandler =
|
||||||
Box<dyn Fn(BreakpointInfo) -> Result<(), Box<dyn Any>> + Send + Sync + 'static>;
|
Box<dyn Fn(BreakpointInfo) -> Result<(), Box<dyn Any>> + Send + Sync + 'static>;
|
||||||
|
|
||||||
|
/// Maps instruction pointers to their breakpoint handlers.
|
||||||
pub type BreakpointMap = Arc<HashMap<usize, BreakpointHandler>>;
|
pub type BreakpointMap = Arc<HashMap<usize, BreakpointHandler>>;
|
||||||
|
|
||||||
|
/// An event generated during parsing of a wasm binary
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Event<'a, 'b> {
|
pub enum Event<'a, 'b> {
|
||||||
|
/// An internal event created by the parser used to provide hooks during code generation.
|
||||||
Internal(InternalEvent),
|
Internal(InternalEvent),
|
||||||
|
/// An event generated by parsing a wasm operator
|
||||||
Wasm(&'b Operator<'a>),
|
Wasm(&'b Operator<'a>),
|
||||||
|
/// An event generated by parsing a wasm operator that contains an owned `Operator`
|
||||||
WasmOwned(Operator<'a>),
|
WasmOwned(Operator<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Kinds of `InternalEvent`s created during parsing.
|
||||||
pub enum InternalEvent {
|
pub enum InternalEvent {
|
||||||
|
/// A function parse is about to begin.
|
||||||
FunctionBegin(u32),
|
FunctionBegin(u32),
|
||||||
|
/// A function parsing has just completed.
|
||||||
FunctionEnd,
|
FunctionEnd,
|
||||||
|
/// A breakpoint emitted during parsing.
|
||||||
Breakpoint(BreakpointHandler),
|
Breakpoint(BreakpointHandler),
|
||||||
|
/// Indicates setting an internal field.
|
||||||
SetInternal(u32),
|
SetInternal(u32),
|
||||||
|
/// Indicates getting an internal field.
|
||||||
GetInternal(u32),
|
GetInternal(u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,10 +63,13 @@ impl fmt::Debug for InternalEvent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Information for a breakpoint
|
||||||
pub struct BreakpointInfo<'a> {
|
pub struct BreakpointInfo<'a> {
|
||||||
|
/// Fault.
|
||||||
pub fault: Option<&'a dyn Any>,
|
pub fault: Option<&'a dyn Any>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A trait that represents the functions needed to be implemented to generate code for a module.
|
||||||
pub trait ModuleCodeGenerator<FCG: FunctionCodeGenerator<E>, RM: RunnableModule, E: Debug> {
|
pub trait ModuleCodeGenerator<FCG: FunctionCodeGenerator<E>, RM: RunnableModule, E: Debug> {
|
||||||
/// Creates a new module code generator.
|
/// Creates a new module code generator.
|
||||||
fn new() -> Self;
|
fn new() -> Self;
|
||||||
@ -65,7 +83,7 @@ pub trait ModuleCodeGenerator<FCG: FunctionCodeGenerator<E>, RM: RunnableModule,
|
|||||||
}
|
}
|
||||||
/// Adds an import function.
|
/// Adds an import function.
|
||||||
fn feed_import_function(&mut self) -> Result<(), E>;
|
fn feed_import_function(&mut self) -> Result<(), E>;
|
||||||
|
/// Sets the signatures.
|
||||||
fn feed_signatures(&mut self, signatures: Map<SigIndex, FuncSig>) -> Result<(), E>;
|
fn feed_signatures(&mut self, signatures: Map<SigIndex, FuncSig>) -> Result<(), E>;
|
||||||
/// Sets function signatures.
|
/// Sets function signatures.
|
||||||
fn feed_function_signatures(&mut self, assoc: Map<FuncIndex, SigIndex>) -> Result<(), E>;
|
fn feed_function_signatures(&mut self, assoc: Map<FuncIndex, SigIndex>) -> Result<(), E>;
|
||||||
@ -80,6 +98,8 @@ pub trait ModuleCodeGenerator<FCG: FunctionCodeGenerator<E>, RM: RunnableModule,
|
|||||||
unsafe fn from_cache(cache: Artifact, _: Token) -> Result<ModuleInner, CacheError>;
|
unsafe fn from_cache(cache: Artifact, _: Token) -> Result<ModuleInner, CacheError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A streaming compiler which is designed to generated code for a module based on a stream
|
||||||
|
/// of wasm parser events.
|
||||||
pub struct StreamingCompiler<
|
pub struct StreamingCompiler<
|
||||||
MCG: ModuleCodeGenerator<FCG, RM, E>,
|
MCG: ModuleCodeGenerator<FCG, RM, E>,
|
||||||
FCG: FunctionCodeGenerator<E>,
|
FCG: FunctionCodeGenerator<E>,
|
||||||
@ -94,6 +114,7 @@ pub struct StreamingCompiler<
|
|||||||
_phantom_e: PhantomData<E>,
|
_phantom_e: PhantomData<E>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A simple generator for a `StreamingCompiler`.
|
||||||
pub struct SimpleStreamingCompilerGen<
|
pub struct SimpleStreamingCompilerGen<
|
||||||
MCG: ModuleCodeGenerator<FCG, RM, E>,
|
MCG: ModuleCodeGenerator<FCG, RM, E>,
|
||||||
FCG: FunctionCodeGenerator<E>,
|
FCG: FunctionCodeGenerator<E>,
|
||||||
@ -113,6 +134,7 @@ impl<
|
|||||||
E: Debug,
|
E: Debug,
|
||||||
> SimpleStreamingCompilerGen<MCG, FCG, RM, E>
|
> SimpleStreamingCompilerGen<MCG, FCG, RM, E>
|
||||||
{
|
{
|
||||||
|
/// Create a new `StreamingCompiler`.
|
||||||
pub fn new() -> StreamingCompiler<MCG, FCG, RM, E, impl Fn() -> MiddlewareChain> {
|
pub fn new() -> StreamingCompiler<MCG, FCG, RM, E, impl Fn() -> MiddlewareChain> {
|
||||||
StreamingCompiler::new(|| MiddlewareChain::new())
|
StreamingCompiler::new(|| MiddlewareChain::new())
|
||||||
}
|
}
|
||||||
@ -126,6 +148,7 @@ impl<
|
|||||||
CGEN: Fn() -> MiddlewareChain,
|
CGEN: Fn() -> MiddlewareChain,
|
||||||
> StreamingCompiler<MCG, FCG, RM, E, CGEN>
|
> StreamingCompiler<MCG, FCG, RM, E, CGEN>
|
||||||
{
|
{
|
||||||
|
/// Create a new `StreamingCompiler` with the given `MiddlewareChain`.
|
||||||
pub fn new(chain_gen: CGEN) -> Self {
|
pub fn new(chain_gen: CGEN) -> Self {
|
||||||
Self {
|
Self {
|
||||||
middleware_chain_generator: chain_gen,
|
middleware_chain_generator: chain_gen,
|
||||||
@ -137,6 +160,7 @@ impl<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new `ValidatingParserConfig` with the given features.
|
||||||
pub fn validating_parser_config(features: &Features) -> wasmparser::ValidatingParserConfig {
|
pub fn validating_parser_config(features: &Features) -> wasmparser::ValidatingParserConfig {
|
||||||
wasmparser::ValidatingParserConfig {
|
wasmparser::ValidatingParserConfig {
|
||||||
operator_config: wasmparser::OperatorValidatorConfig {
|
operator_config: wasmparser::OperatorValidatorConfig {
|
||||||
@ -220,29 +244,35 @@ fn requires_pre_validation(backend: Backend) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A sink for parse events.
|
||||||
pub struct EventSink<'a, 'b> {
|
pub struct EventSink<'a, 'b> {
|
||||||
buffer: SmallVec<[Event<'a, 'b>; 2]>,
|
buffer: SmallVec<[Event<'a, 'b>; 2]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> EventSink<'a, 'b> {
|
impl<'a, 'b> EventSink<'a, 'b> {
|
||||||
|
/// Push a new `Event` to this sink.
|
||||||
pub fn push(&mut self, ev: Event<'a, 'b>) {
|
pub fn push(&mut self, ev: Event<'a, 'b>) {
|
||||||
self.buffer.push(ev);
|
self.buffer.push(ev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A container for a chain of middlewares.
|
||||||
pub struct MiddlewareChain {
|
pub struct MiddlewareChain {
|
||||||
chain: Vec<Box<dyn GenericFunctionMiddleware>>,
|
chain: Vec<Box<dyn GenericFunctionMiddleware>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MiddlewareChain {
|
impl MiddlewareChain {
|
||||||
|
/// Create a new empty `MiddlewareChain`.
|
||||||
pub fn new() -> MiddlewareChain {
|
pub fn new() -> MiddlewareChain {
|
||||||
MiddlewareChain { chain: vec![] }
|
MiddlewareChain { chain: vec![] }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Push a new `FunctionMiddleware` to this `MiddlewareChain`.
|
||||||
pub fn push<M: FunctionMiddleware + 'static>(&mut self, m: M) {
|
pub fn push<M: FunctionMiddleware + 'static>(&mut self, m: M) {
|
||||||
self.chain.push(Box::new(m));
|
self.chain.push(Box::new(m));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Run this chain with the provided function code generator, event and module info.
|
||||||
pub(crate) fn run<E: Debug, FCG: FunctionCodeGenerator<E>>(
|
pub(crate) fn run<E: Debug, FCG: FunctionCodeGenerator<E>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
fcg: Option<&mut FCG>,
|
fcg: Option<&mut FCG>,
|
||||||
@ -270,8 +300,11 @@ impl MiddlewareChain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A trait that represents the signature required to implement middleware for a function.
|
||||||
pub trait FunctionMiddleware {
|
pub trait FunctionMiddleware {
|
||||||
|
/// The error type for this middleware's functions.
|
||||||
type Error: Debug;
|
type Error: Debug;
|
||||||
|
/// Processes the given event, module info and sink.
|
||||||
fn feed_event<'a, 'b: 'a>(
|
fn feed_event<'a, 'b: 'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
op: Event<'a, 'b>,
|
op: Event<'a, 'b>,
|
||||||
|
@ -1,13 +1,22 @@
|
|||||||
|
//! The error module contains the data structures and helper functions used to implement errors that
|
||||||
|
//! are produced and returned from the wasmer runtime core.
|
||||||
use crate::types::{FuncSig, GlobalDescriptor, MemoryDescriptor, TableDescriptor, Type};
|
use crate::types::{FuncSig, GlobalDescriptor, MemoryDescriptor, TableDescriptor, Type};
|
||||||
use core::borrow::Borrow;
|
use core::borrow::Borrow;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
|
||||||
|
/// Aliases the standard `Result` type as `Result` within this module.
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
/// Aliases the standard `Result` with `CompileError` as the default error type.
|
||||||
pub type CompileResult<T> = std::result::Result<T, CompileError>;
|
pub type CompileResult<T> = std::result::Result<T, CompileError>;
|
||||||
|
/// Aliases the standard `Result` with `Vec<LinkError>` as the default error type.
|
||||||
pub type LinkResult<T> = std::result::Result<T, Vec<LinkError>>;
|
pub type LinkResult<T> = std::result::Result<T, Vec<LinkError>>;
|
||||||
|
/// Aliases the standard `Result` with `RuntimeError` as the default error type.
|
||||||
pub type RuntimeResult<T> = std::result::Result<T, RuntimeError>;
|
pub type RuntimeResult<T> = std::result::Result<T, RuntimeError>;
|
||||||
|
/// Aliases the standard `Result` with `CallError` as the default error type.
|
||||||
pub type CallResult<T> = std::result::Result<T, CallError>;
|
pub type CallResult<T> = std::result::Result<T, CallError>;
|
||||||
|
/// Aliases the standard `Result` with `ResolveError` as the default error type.
|
||||||
pub type ResolveResult<T> = std::result::Result<T, ResolveError>;
|
pub type ResolveResult<T> = std::result::Result<T, ResolveError>;
|
||||||
|
/// Aliases the standard `Result` with `ParseError` as the default error type.
|
||||||
pub type ParseResult<T> = std::result::Result<T, ParseError>;
|
pub type ParseResult<T> = std::result::Result<T, ParseError>;
|
||||||
|
|
||||||
/// This is returned when the chosen compiler is unable to
|
/// This is returned when the chosen compiler is unable to
|
||||||
@ -17,8 +26,16 @@ pub type ParseResult<T> = std::result::Result<T, ParseError>;
|
|||||||
/// Comparing two `CompileError`s always evaluates to false.
|
/// Comparing two `CompileError`s always evaluates to false.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum CompileError {
|
pub enum CompileError {
|
||||||
ValidationError { msg: String },
|
/// A validation error containing an error message.
|
||||||
InternalError { msg: String },
|
ValidationError {
|
||||||
|
/// An error message.
|
||||||
|
msg: String,
|
||||||
|
},
|
||||||
|
/// A internal error containing an error message.
|
||||||
|
InternalError {
|
||||||
|
/// An error message.
|
||||||
|
msg: String,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for CompileError {
|
impl PartialEq for CompileError {
|
||||||
@ -46,41 +63,71 @@ impl std::error::Error for CompileError {}
|
|||||||
/// Comparing two `LinkError`s always evaluates to false.
|
/// Comparing two `LinkError`s always evaluates to false.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum LinkError {
|
pub enum LinkError {
|
||||||
|
/// The type of the provided import does not match the expected type.
|
||||||
IncorrectImportType {
|
IncorrectImportType {
|
||||||
|
/// Namespace.
|
||||||
namespace: String,
|
namespace: String,
|
||||||
|
/// Name.
|
||||||
name: String,
|
name: String,
|
||||||
|
/// Expected.
|
||||||
expected: String,
|
expected: String,
|
||||||
|
/// Found.
|
||||||
found: String,
|
found: String,
|
||||||
},
|
},
|
||||||
|
/// The signature of the provided import does not match the expected signature.
|
||||||
IncorrectImportSignature {
|
IncorrectImportSignature {
|
||||||
|
/// Namespace.
|
||||||
namespace: String,
|
namespace: String,
|
||||||
|
/// Name.
|
||||||
name: String,
|
name: String,
|
||||||
|
/// Expected.
|
||||||
expected: FuncSig,
|
expected: FuncSig,
|
||||||
|
/// Found.
|
||||||
found: FuncSig,
|
found: FuncSig,
|
||||||
},
|
},
|
||||||
|
/// An expected import was not provided.
|
||||||
ImportNotFound {
|
ImportNotFound {
|
||||||
|
/// Namespace.
|
||||||
namespace: String,
|
namespace: String,
|
||||||
|
/// Name.
|
||||||
name: String,
|
name: String,
|
||||||
},
|
},
|
||||||
|
/// The memory descriptor provided does not match the expected descriptor.
|
||||||
IncorrectMemoryDescriptor {
|
IncorrectMemoryDescriptor {
|
||||||
|
/// Namespace.
|
||||||
namespace: String,
|
namespace: String,
|
||||||
|
/// Name.
|
||||||
name: String,
|
name: String,
|
||||||
|
/// Expected.
|
||||||
expected: MemoryDescriptor,
|
expected: MemoryDescriptor,
|
||||||
|
/// Found.
|
||||||
found: MemoryDescriptor,
|
found: MemoryDescriptor,
|
||||||
},
|
},
|
||||||
|
/// The table descriptor provided does not match the expected descriptor.
|
||||||
IncorrectTableDescriptor {
|
IncorrectTableDescriptor {
|
||||||
|
/// Namespace.
|
||||||
namespace: String,
|
namespace: String,
|
||||||
|
/// Name.
|
||||||
name: String,
|
name: String,
|
||||||
|
/// Expected.
|
||||||
expected: TableDescriptor,
|
expected: TableDescriptor,
|
||||||
|
/// Found.
|
||||||
found: TableDescriptor,
|
found: TableDescriptor,
|
||||||
},
|
},
|
||||||
|
/// The global descriptor provided does not match the expected descriptor.
|
||||||
IncorrectGlobalDescriptor {
|
IncorrectGlobalDescriptor {
|
||||||
|
/// Namespace.
|
||||||
namespace: String,
|
namespace: String,
|
||||||
|
/// Name.
|
||||||
name: String,
|
name: String,
|
||||||
|
/// Expected.
|
||||||
expected: GlobalDescriptor,
|
expected: GlobalDescriptor,
|
||||||
|
/// Found.
|
||||||
found: GlobalDescriptor,
|
found: GlobalDescriptor,
|
||||||
},
|
},
|
||||||
|
/// A generic error with a message.
|
||||||
Generic {
|
Generic {
|
||||||
|
/// Error message.
|
||||||
message: String,
|
message: String,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -126,8 +173,16 @@ impl std::error::Error for LinkError {}
|
|||||||
///
|
///
|
||||||
/// Comparing two `RuntimeError`s always evaluates to false.
|
/// Comparing two `RuntimeError`s always evaluates to false.
|
||||||
pub enum RuntimeError {
|
pub enum RuntimeError {
|
||||||
Trap { msg: Box<str> },
|
/// Trap.
|
||||||
Error { data: Box<dyn Any> },
|
Trap {
|
||||||
|
/// Trap message.
|
||||||
|
msg: Box<str>,
|
||||||
|
},
|
||||||
|
/// Error.
|
||||||
|
Error {
|
||||||
|
/// Error data.
|
||||||
|
data: Box<dyn Any>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for RuntimeError {
|
impl PartialEq for RuntimeError {
|
||||||
@ -169,9 +224,23 @@ impl std::error::Error for RuntimeError {}
|
|||||||
/// Comparing two `ResolveError`s always evaluates to false.
|
/// Comparing two `ResolveError`s always evaluates to false.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ResolveError {
|
pub enum ResolveError {
|
||||||
Signature { expected: FuncSig, found: Vec<Type> },
|
/// Found signature did not match expected signature.
|
||||||
ExportNotFound { name: String },
|
Signature {
|
||||||
ExportWrongType { name: String },
|
/// Expected `FuncSig`.
|
||||||
|
expected: FuncSig,
|
||||||
|
/// Found type.
|
||||||
|
found: Vec<Type>,
|
||||||
|
},
|
||||||
|
/// Export not found.
|
||||||
|
ExportNotFound {
|
||||||
|
/// Name.
|
||||||
|
name: String,
|
||||||
|
},
|
||||||
|
/// Export found with the wrong type.
|
||||||
|
ExportWrongType {
|
||||||
|
/// Name.
|
||||||
|
name: String,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for ResolveError {
|
impl PartialEq for ResolveError {
|
||||||
@ -213,7 +282,9 @@ impl std::error::Error for ResolveError {}
|
|||||||
///
|
///
|
||||||
/// Comparing two `CallError`s always evaluates to false.
|
/// Comparing two `CallError`s always evaluates to false.
|
||||||
pub enum CallError {
|
pub enum CallError {
|
||||||
|
/// An error occured resolving the functions name or types.
|
||||||
Resolve(ResolveError),
|
Resolve(ResolveError),
|
||||||
|
/// A runtime error occurred during the function call.
|
||||||
Runtime(RuntimeError),
|
Runtime(RuntimeError),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,8 +318,11 @@ impl std::error::Error for CallError {}
|
|||||||
/// like a `Memory` or a `Table`.
|
/// like a `Memory` or a `Table`.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum CreationError {
|
pub enum CreationError {
|
||||||
|
/// Unable to create memory error.
|
||||||
UnableToCreateMemory,
|
UnableToCreateMemory,
|
||||||
|
/// Unable to create table error.
|
||||||
UnableToCreateTable,
|
UnableToCreateTable,
|
||||||
|
/// Invalid descriptor error with message.
|
||||||
InvalidDescriptor(String),
|
InvalidDescriptor(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,11 +355,17 @@ impl std::error::Error for CreationError {}
|
|||||||
/// Comparing two `Error`s always evaluates to false.
|
/// Comparing two `Error`s always evaluates to false.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
/// Compile error.
|
||||||
CompileError(CompileError),
|
CompileError(CompileError),
|
||||||
|
/// Link errors.
|
||||||
LinkError(Vec<LinkError>),
|
LinkError(Vec<LinkError>),
|
||||||
|
/// Runtime error.
|
||||||
RuntimeError(RuntimeError),
|
RuntimeError(RuntimeError),
|
||||||
|
/// Resolve error.
|
||||||
ResolveError(ResolveError),
|
ResolveError(ResolveError),
|
||||||
|
/// Call error.
|
||||||
CallError(CallError),
|
CallError(CallError),
|
||||||
|
/// Creation error.
|
||||||
CreationError(CreationError),
|
CreationError(CreationError),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,13 +448,20 @@ impl std::fmt::Display for Error {
|
|||||||
|
|
||||||
impl std::error::Error for Error {}
|
impl std::error::Error for Error {}
|
||||||
|
|
||||||
|
/// An error occurred while growing a memory or table.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum GrowError {
|
pub enum GrowError {
|
||||||
|
/// Error growing memory.
|
||||||
MemoryGrowError,
|
MemoryGrowError,
|
||||||
|
/// Error growing table.
|
||||||
TableGrowError,
|
TableGrowError,
|
||||||
|
/// Max pages were exceeded.
|
||||||
ExceededMaxPages(PageError),
|
ExceededMaxPages(PageError),
|
||||||
|
/// Max pages for memory were exceeded.
|
||||||
ExceededMaxPagesForMemory(usize, usize),
|
ExceededMaxPagesForMemory(usize, usize),
|
||||||
|
/// Error protecting memory.
|
||||||
CouldNotProtectMemory(MemoryProtectionError),
|
CouldNotProtectMemory(MemoryProtectionError),
|
||||||
|
/// Error creating memory.
|
||||||
CouldNotCreateMemory(MemoryCreationError),
|
CouldNotCreateMemory(MemoryCreationError),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,9 +480,11 @@ impl std::fmt::Display for GrowError {
|
|||||||
|
|
||||||
impl std::error::Error for GrowError {}
|
impl std::error::Error for GrowError {}
|
||||||
|
|
||||||
|
/// A kind of page error.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum PageError {
|
pub enum PageError {
|
||||||
// left, right, added
|
// left, right, added
|
||||||
|
/// Max pages were exceeded error.
|
||||||
ExceededMaxPages(usize, usize, usize),
|
ExceededMaxPages(usize, usize, usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -414,9 +503,12 @@ impl Into<GrowError> for PageError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Error occured while creating memory.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum MemoryCreationError {
|
pub enum MemoryCreationError {
|
||||||
|
/// Allocation of virtual memory failed error.
|
||||||
VirtualMemoryAllocationFailed(usize, String),
|
VirtualMemoryAllocationFailed(usize, String),
|
||||||
|
/// Error creating memory from file.
|
||||||
CouldNotCreateMemoryFromFile(std::io::Error),
|
CouldNotCreateMemoryFromFile(std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -446,8 +538,10 @@ impl From<std::io::Error> for MemoryCreationError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Error protecting memory.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum MemoryProtectionError {
|
pub enum MemoryProtectionError {
|
||||||
|
/// Protection failed error.
|
||||||
ProtectionFailed(usize, usize, String),
|
ProtectionFailed(usize, usize, String),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -470,8 +564,10 @@ impl Into<GrowError> for MemoryProtectionError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse Error.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ParseError {
|
pub enum ParseError {
|
||||||
|
/// Error reading binary.
|
||||||
BinaryReadError,
|
BinaryReadError,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
//! The export module contains the implementation data structures and helper functions used to
|
||||||
|
//! manipulate and access a wasm module's exports including memories, tables, globals, and
|
||||||
|
//! functions.
|
||||||
use crate::{
|
use crate::{
|
||||||
global::Global, instance::InstanceInner, memory::Memory, module::ExportIndex,
|
global::Global, instance::InstanceInner, memory::Memory, module::ExportIndex,
|
||||||
module::ModuleInner, table::Table, types::FuncSig, vm,
|
module::ModuleInner, table::Table, types::FuncSig, vm,
|
||||||
@ -5,27 +8,39 @@ use crate::{
|
|||||||
use indexmap::map::Iter as IndexMapIter;
|
use indexmap::map::Iter as IndexMapIter;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
/// A kind of Context.
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub enum Context {
|
pub enum Context {
|
||||||
|
/// External context include a mutable pointer to `Ctx`.
|
||||||
External(*mut vm::Ctx),
|
External(*mut vm::Ctx),
|
||||||
|
/// Internal context.
|
||||||
Internal,
|
Internal,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manually implemented because context contains a raw pointer to Ctx
|
// Manually implemented because context contains a raw pointer to Ctx
|
||||||
unsafe impl Send for Context {}
|
unsafe impl Send for Context {}
|
||||||
|
|
||||||
|
/// Kind of WebAssembly export.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Export {
|
pub enum Export {
|
||||||
|
/// Function export.
|
||||||
Function {
|
Function {
|
||||||
|
/// A pointer to a function.
|
||||||
func: FuncPointer,
|
func: FuncPointer,
|
||||||
|
/// A kind of context.
|
||||||
ctx: Context,
|
ctx: Context,
|
||||||
|
/// The signature of the function.
|
||||||
signature: Arc<FuncSig>,
|
signature: Arc<FuncSig>,
|
||||||
},
|
},
|
||||||
|
/// Memory export.
|
||||||
Memory(Memory),
|
Memory(Memory),
|
||||||
|
/// Table export.
|
||||||
Table(Table),
|
Table(Table),
|
||||||
|
/// Global export.
|
||||||
Global(Global),
|
Global(Global),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Const pointer to a `Func`.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct FuncPointer(*const vm::Func);
|
pub struct FuncPointer(*const vm::Func);
|
||||||
|
|
||||||
@ -45,6 +60,7 @@ impl FuncPointer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An iterator to an instance's exports.
|
||||||
pub struct ExportIter<'a> {
|
pub struct ExportIter<'a> {
|
||||||
inner: &'a InstanceInner,
|
inner: &'a InstanceInner,
|
||||||
iter: IndexMapIter<'a, String, ExportIndex>,
|
iter: IndexMapIter<'a, String, ExportIndex>,
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
|
//! The fault module contains the implementation for handling breakpoints, traps, and signals
|
||||||
|
//! for wasm code.
|
||||||
|
|
||||||
pub mod raw {
|
pub mod raw {
|
||||||
|
//! The raw module contains required externed function interfaces for the fault module.
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -40,13 +44,19 @@ struct UnwindInfo {
|
|||||||
payload: Option<Box<dyn Any>>, // out
|
payload: Option<Box<dyn Any>>, // out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A store for boundary register preservation.
|
||||||
#[repr(packed)]
|
#[repr(packed)]
|
||||||
#[derive(Default, Copy, Clone)]
|
#[derive(Default, Copy, Clone)]
|
||||||
pub struct BoundaryRegisterPreservation {
|
pub struct BoundaryRegisterPreservation {
|
||||||
|
/// R15.
|
||||||
pub r15: u64,
|
pub r15: u64,
|
||||||
|
/// R14.
|
||||||
pub r14: u64,
|
pub r14: u64,
|
||||||
|
/// R13.
|
||||||
pub r13: u64,
|
pub r13: u64,
|
||||||
|
/// R12.
|
||||||
pub r12: u64,
|
pub r12: u64,
|
||||||
|
/// RBX.
|
||||||
pub rbx: u64,
|
pub rbx: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,6 +68,7 @@ thread_local! {
|
|||||||
static BOUNDARY_REGISTER_PRESERVATION: UnsafeCell<BoundaryRegisterPreservation> = UnsafeCell::new(BoundaryRegisterPreservation::default());
|
static BOUNDARY_REGISTER_PRESERVATION: UnsafeCell<BoundaryRegisterPreservation> = UnsafeCell::new(BoundaryRegisterPreservation::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a mutable pointer to the `BoundaryRegisterPreservation`.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn get_boundary_register_preservation() -> *mut BoundaryRegisterPreservation {
|
pub unsafe extern "C" fn get_boundary_register_preservation() -> *mut BoundaryRegisterPreservation {
|
||||||
BOUNDARY_REGISTER_PRESERVATION.with(|x| x.get())
|
BOUNDARY_REGISTER_PRESERVATION.with(|x| x.get())
|
||||||
@ -89,10 +100,12 @@ lazy_static! {
|
|||||||
}
|
}
|
||||||
static INTERRUPT_SIGNAL_DELIVERED: AtomicBool = AtomicBool::new(false);
|
static INTERRUPT_SIGNAL_DELIVERED: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
|
/// Returns a boolean indicating if SIGINT triggered the fault.
|
||||||
pub fn was_sigint_triggered_fault() -> bool {
|
pub fn was_sigint_triggered_fault() -> bool {
|
||||||
WAS_SIGINT_TRIGGERED.with(|x| x.get())
|
WAS_SIGINT_TRIGGERED.with(|x| x.get())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Runs a callback function with the given `Ctx`.
|
||||||
pub unsafe fn with_ctx<R, F: FnOnce() -> R>(ctx: *mut vm::Ctx, cb: F) -> R {
|
pub unsafe fn with_ctx<R, F: FnOnce() -> R>(ctx: *mut vm::Ctx, cb: F) -> R {
|
||||||
let addr = CURRENT_CTX.with(|x| x.get());
|
let addr = CURRENT_CTX.with(|x| x.get());
|
||||||
let old = *addr;
|
let old = *addr;
|
||||||
@ -102,18 +115,22 @@ pub unsafe fn with_ctx<R, F: FnOnce() -> R>(ctx: *mut vm::Ctx, cb: F) -> R {
|
|||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Pushes a new `CodeVersion` to the current code versions.
|
||||||
pub fn push_code_version(version: CodeVersion) {
|
pub fn push_code_version(version: CodeVersion) {
|
||||||
CURRENT_CODE_VERSIONS.with(|x| x.borrow_mut().push(version));
|
CURRENT_CODE_VERSIONS.with(|x| x.borrow_mut().push(version));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Pops a `CodeVersion` from the current code versions.
|
||||||
pub fn pop_code_version() -> Option<CodeVersion> {
|
pub fn pop_code_version() -> Option<CodeVersion> {
|
||||||
CURRENT_CODE_VERSIONS.with(|x| x.borrow_mut().pop())
|
CURRENT_CODE_VERSIONS.with(|x| x.borrow_mut().pop())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the wasm interrupt signal mem.
|
||||||
pub unsafe fn get_wasm_interrupt_signal_mem() -> *mut u8 {
|
pub unsafe fn get_wasm_interrupt_signal_mem() -> *mut u8 {
|
||||||
INTERRUPT_SIGNAL_MEM.0
|
INTERRUPT_SIGNAL_MEM.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the wasm interrupt on the given `Ctx`.
|
||||||
pub unsafe fn set_wasm_interrupt_on_ctx(ctx: *mut vm::Ctx) {
|
pub unsafe fn set_wasm_interrupt_on_ctx(ctx: *mut vm::Ctx) {
|
||||||
if mprotect(
|
if mprotect(
|
||||||
(&*ctx).internal.interrupt_signal_mem as _,
|
(&*ctx).internal.interrupt_signal_mem as _,
|
||||||
@ -125,6 +142,7 @@ pub unsafe fn set_wasm_interrupt_on_ctx(ctx: *mut vm::Ctx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets a wasm interrupt.
|
||||||
pub unsafe fn set_wasm_interrupt() {
|
pub unsafe fn set_wasm_interrupt() {
|
||||||
let mem: *mut u8 = INTERRUPT_SIGNAL_MEM.0;
|
let mem: *mut u8 = INTERRUPT_SIGNAL_MEM.0;
|
||||||
if mprotect(mem as _, INTERRUPT_SIGNAL_MEM_SIZE, PROT_NONE) < 0 {
|
if mprotect(mem as _, INTERRUPT_SIGNAL_MEM_SIZE, PROT_NONE) < 0 {
|
||||||
@ -132,6 +150,7 @@ pub unsafe fn set_wasm_interrupt() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clears the wasm interrupt.
|
||||||
pub unsafe fn clear_wasm_interrupt() {
|
pub unsafe fn clear_wasm_interrupt() {
|
||||||
let mem: *mut u8 = INTERRUPT_SIGNAL_MEM.0;
|
let mem: *mut u8 = INTERRUPT_SIGNAL_MEM.0;
|
||||||
if mprotect(mem as _, INTERRUPT_SIGNAL_MEM_SIZE, PROT_READ | PROT_WRITE) < 0 {
|
if mprotect(mem as _, INTERRUPT_SIGNAL_MEM_SIZE, PROT_READ | PROT_WRITE) < 0 {
|
||||||
@ -139,6 +158,7 @@ pub unsafe fn clear_wasm_interrupt() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Catches an unsafe unwind with the given functions and breakpoints.
|
||||||
pub unsafe fn catch_unsafe_unwind<R, F: FnOnce() -> R>(
|
pub unsafe fn catch_unsafe_unwind<R, F: FnOnce() -> R>(
|
||||||
f: F,
|
f: F,
|
||||||
breakpoints: Option<BreakpointMap>,
|
breakpoints: Option<BreakpointMap>,
|
||||||
@ -164,6 +184,7 @@ pub unsafe fn catch_unsafe_unwind<R, F: FnOnce() -> R>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Begins an unsafe unwind.
|
||||||
pub unsafe fn begin_unsafe_unwind(e: Box<dyn Any>) -> ! {
|
pub unsafe fn begin_unsafe_unwind(e: Box<dyn Any>) -> ! {
|
||||||
let unwind = UNWIND.with(|x| x.get());
|
let unwind = UNWIND.with(|x| x.get());
|
||||||
let inner = (*unwind)
|
let inner = (*unwind)
|
||||||
@ -181,6 +202,7 @@ unsafe fn with_breakpoint_map<R, F: FnOnce(Option<&BreakpointMap>) -> R>(f: F) -
|
|||||||
f(inner.breakpoints.as_ref())
|
f(inner.breakpoints.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Allocates and runs with the given stack size and closure.
|
||||||
pub fn allocate_and_run<R, F: FnOnce() -> R>(size: usize, f: F) -> R {
|
pub fn allocate_and_run<R, F: FnOnce() -> R>(size: usize, f: F) -> R {
|
||||||
struct Context<F: FnOnce() -> R, R> {
|
struct Context<F: FnOnce() -> R, R> {
|
||||||
f: Option<F>,
|
f: Option<F>,
|
||||||
@ -316,6 +338,7 @@ extern "C" fn sigint_handler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Ensure the signal handler is installed.
|
||||||
pub fn ensure_sighandler() {
|
pub fn ensure_sighandler() {
|
||||||
INSTALL_SIGHANDLER.call_once(|| unsafe {
|
INSTALL_SIGHANDLER.call_once(|| unsafe {
|
||||||
install_sighandler();
|
install_sighandler();
|
||||||
@ -344,9 +367,13 @@ unsafe fn install_sighandler() {
|
|||||||
sigaction(SIGINT, &sa_interrupt).unwrap();
|
sigaction(SIGINT, &sa_interrupt).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Info about the fault
|
||||||
pub struct FaultInfo {
|
pub struct FaultInfo {
|
||||||
|
/// Faulting address.
|
||||||
pub faulting_addr: *const c_void,
|
pub faulting_addr: *const c_void,
|
||||||
|
/// Instruction pointer.
|
||||||
pub ip: *const c_void,
|
pub ip: *const c_void,
|
||||||
|
/// Known registers.
|
||||||
pub known_registers: [Option<u64>; 32],
|
pub known_registers: [Option<u64>; 32],
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -421,6 +448,7 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) ->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get fault info from siginfo and ucontext.
|
||||||
#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
|
#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
|
||||||
pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> FaultInfo {
|
pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> FaultInfo {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//! The global module contains the implementation data structures and helper functions used to
|
||||||
|
//! manipulate and access a wasm globals.
|
||||||
use crate::{
|
use crate::{
|
||||||
export::Export,
|
export::Export,
|
||||||
import::IsExport,
|
import::IsExport,
|
||||||
@ -9,6 +11,7 @@ use std::{
|
|||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Container with a descriptor and a reference to a global value.
|
||||||
pub struct Global {
|
pub struct Global {
|
||||||
desc: GlobalDescriptor,
|
desc: GlobalDescriptor,
|
||||||
storage: Arc<Mutex<vm::LocalGlobal>>,
|
storage: Arc<Mutex<vm::LocalGlobal>>,
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
//! The import module contains the implementation data structures and helper functions used to
|
||||||
|
//! manipulate and access a wasm module's imports including memories, tables, globals, and
|
||||||
|
//! functions.
|
||||||
use crate::export::Export;
|
use crate::export::Export;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::collections::{hash_map::Entry, HashMap};
|
use std::collections::{hash_map::Entry, HashMap};
|
||||||
@ -7,13 +10,20 @@ use std::{
|
|||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// This trait represents objects that act as a namespace for imports. For example, an `Instance`
|
||||||
|
/// or `ImportObject` could be considered namespaces that could provide imports to an instance.
|
||||||
pub trait LikeNamespace {
|
pub trait LikeNamespace {
|
||||||
|
/// Gets an export by name.
|
||||||
fn get_export(&self, name: &str) -> Option<Export>;
|
fn get_export(&self, name: &str) -> Option<Export>;
|
||||||
|
/// Gets all exports in the namespace.
|
||||||
fn get_exports(&self) -> Vec<(String, Export)>;
|
fn get_exports(&self) -> Vec<(String, Export)>;
|
||||||
|
/// Maybe insert an `Export` by name into the namespace.
|
||||||
fn maybe_insert(&mut self, name: &str, export: Export) -> Option<()>;
|
fn maybe_insert(&mut self, name: &str, export: Export) -> Option<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A trait that represents `Export` values.
|
||||||
pub trait IsExport {
|
pub trait IsExport {
|
||||||
|
/// Gets self as `Export`.
|
||||||
fn to_export(&self) -> Export;
|
fn to_export(&self) -> Export;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,6 +58,8 @@ pub struct ImportObject {
|
|||||||
map: Arc<Mutex<HashMap<String, Box<dyn LikeNamespace + Send>>>>,
|
map: Arc<Mutex<HashMap<String, Box<dyn LikeNamespace + Send>>>>,
|
||||||
pub(crate) state_creator:
|
pub(crate) state_creator:
|
||||||
Option<Arc<dyn Fn() -> (*mut c_void, fn(*mut c_void)) + Send + Sync + 'static>>,
|
Option<Arc<dyn Fn() -> (*mut c_void, fn(*mut c_void)) + Send + Sync + 'static>>,
|
||||||
|
/// Allow missing functions to be generated and instantiation to continue when required
|
||||||
|
/// functions are not provided.
|
||||||
pub allow_missing_functions: bool,
|
pub allow_missing_functions: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,6 +73,7 @@ impl ImportObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new `ImportObject` which generates data from the provided state creator.
|
||||||
pub fn new_with_data<F>(state_creator: F) -> Self
|
pub fn new_with_data<F>(state_creator: F) -> Self
|
||||||
where
|
where
|
||||||
F: Fn() -> (*mut c_void, fn(*mut c_void)) + 'static + Send + Sync,
|
F: Fn() -> (*mut c_void, fn(*mut c_void)) + 'static + Send + Sync,
|
||||||
@ -145,6 +158,7 @@ impl ImportObject {
|
|||||||
.and_then(|ns| f(ns))
|
.and_then(|ns| f(ns))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a clone ref of this namespace.
|
||||||
pub fn clone_ref(&self) -> Self {
|
pub fn clone_ref(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
map: Arc::clone(&self.map),
|
map: Arc::clone(&self.map),
|
||||||
@ -166,6 +180,7 @@ impl ImportObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Iterator for an `ImportObject`'s exports.
|
||||||
pub struct ImportObjectIterator {
|
pub struct ImportObjectIterator {
|
||||||
elements: VecDeque<(String, String, Export)>,
|
elements: VecDeque<(String, String, Export)>,
|
||||||
}
|
}
|
||||||
@ -204,17 +219,20 @@ impl Extend<(String, String, Export)> for ImportObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The top-level container for the two-level wasm imports
|
||||||
pub struct Namespace {
|
pub struct Namespace {
|
||||||
map: HashMap<String, Box<dyn IsExport + Send>>,
|
map: HashMap<String, Box<dyn IsExport + Send>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Namespace {
|
impl Namespace {
|
||||||
|
/// Create a new empty `Namespace`.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
map: HashMap::new(),
|
map: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Insert a new `Export` into the namespace with the given name.
|
||||||
pub fn insert<S, E>(&mut self, name: S, export: E) -> Option<Box<dyn IsExport + Send>>
|
pub fn insert<S, E>(&mut self, name: S, export: E) -> Option<Box<dyn IsExport + Send>>
|
||||||
where
|
where
|
||||||
S: Into<String>,
|
S: Into<String>,
|
||||||
@ -223,6 +241,7 @@ impl Namespace {
|
|||||||
self.map.insert(name.into(), Box::new(export))
|
self.map.insert(name.into(), Box::new(export))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the `Namespace` contains the given name.
|
||||||
pub fn contains_key<S>(&mut self, key: S) -> bool
|
pub fn contains_key<S>(&mut self, key: S) -> bool
|
||||||
where
|
where
|
||||||
S: Into<String>,
|
S: Into<String>,
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//! The instance module contains the implementation data structures and helper functions used to
|
||||||
|
//! manipulate and access wasm instances.
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::RunnableModule,
|
backend::RunnableModule,
|
||||||
backing::{ImportBacking, LocalBacking},
|
backing::{ImportBacking, LocalBacking},
|
||||||
@ -48,6 +50,7 @@ impl Drop for InstanceInner {
|
|||||||
///
|
///
|
||||||
/// [`ImportObject`]: struct.ImportObject.html
|
/// [`ImportObject`]: struct.ImportObject.html
|
||||||
pub struct Instance {
|
pub struct Instance {
|
||||||
|
/// Reference to the module used to instantiate this instance.
|
||||||
pub module: Arc<ModuleInner>,
|
pub module: Arc<ModuleInner>,
|
||||||
inner: Pin<Box<InstanceInner>>,
|
inner: Pin<Box<InstanceInner>>,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -137,6 +140,7 @@ impl Instance {
|
|||||||
Ok(instance)
|
Ok(instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Load an `Instance` using the given loader.
|
||||||
pub fn load<T: Loader>(&self, loader: T) -> ::std::result::Result<T::Instance, T::Error> {
|
pub fn load<T: Loader>(&self, loader: T) -> ::std::result::Result<T::Instance, T::Error> {
|
||||||
loader.load(&*self.module.runnable_module, &self.module.info, unsafe {
|
loader.load(&*self.module.runnable_module, &self.module.info, unsafe {
|
||||||
&*self.inner.vmctx
|
&*self.inner.vmctx
|
||||||
@ -230,6 +234,7 @@ impl Instance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resolve a function by name.
|
||||||
pub fn resolve_func(&self, name: &str) -> ResolveResult<usize> {
|
pub fn resolve_func(&self, name: &str) -> ResolveResult<usize> {
|
||||||
let export_index =
|
let export_index =
|
||||||
self.module
|
self.module
|
||||||
@ -381,10 +386,12 @@ impl Instance {
|
|||||||
Module::new(Arc::clone(&self.module))
|
Module::new(Arc::clone(&self.module))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the value of an internal field
|
||||||
pub fn get_internal(&self, field: &InternalField) -> u64 {
|
pub fn get_internal(&self, field: &InternalField) -> u64 {
|
||||||
self.inner.backing.internals.0[field.index()]
|
self.inner.backing.internals.0[field.index()]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the value of an internal field.
|
||||||
pub fn set_internal(&mut self, field: &InternalField, value: u64) {
|
pub fn set_internal(&mut self, field: &InternalField, value: u64) {
|
||||||
self.inner.backing.internals.0[field.index()] = value;
|
self.inner.backing.internals.0[field.index()] = value;
|
||||||
}
|
}
|
||||||
@ -774,10 +781,12 @@ impl<'a> DynFunc<'a> {
|
|||||||
Ok(results)
|
Ok(results)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the signature of this `Dynfunc`.
|
||||||
pub fn signature(&self) -> &FuncSig {
|
pub fn signature(&self) -> &FuncSig {
|
||||||
&*self.signature
|
&*self.signature
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a const pointer to the function represent by this `DynFunc`.
|
||||||
pub fn raw(&self) -> *const vm::Func {
|
pub fn raw(&self) -> *const vm::Func {
|
||||||
match self.func_index.local_or_import(&self.module.info) {
|
match self.func_index.local_or_import(&self.module.info) {
|
||||||
LocalOrImport::Local(local_func_index) => self
|
LocalOrImport::Local(local_func_index) => self
|
||||||
|
@ -1,5 +1,20 @@
|
|||||||
|
//! Wasmer Runtime Core Library
|
||||||
|
//!
|
||||||
|
//! The runtime core library provides common data structures which are shared by compiler backends
|
||||||
|
//! to implement a Web Assembly runtime.
|
||||||
|
//!
|
||||||
|
//! The runtime core also provides an API for users who use wasmer as an embedded wasm runtime which
|
||||||
|
//! allows operations like compiling, instantiating, providing imports, access exports, memories,
|
||||||
|
//! and tables for example.
|
||||||
|
//!
|
||||||
|
//! The runtime core library is recommended to be used by only power users who wish to customize the
|
||||||
|
//! wasmer runtime. Most wasmer users should prefer the API which is re-exported by the wasmer
|
||||||
|
//! runtime library which provides common defaults and a friendly API.
|
||||||
|
//!
|
||||||
|
|
||||||
#![deny(
|
#![deny(
|
||||||
dead_code,
|
dead_code,
|
||||||
|
missing_docs,
|
||||||
nonstandard_style,
|
nonstandard_style,
|
||||||
unused_imports,
|
unused_imports,
|
||||||
unused_mut,
|
unused_mut,
|
||||||
@ -77,6 +92,9 @@ pub use wasmparser;
|
|||||||
use self::cache::{Artifact, Error as CacheError};
|
use self::cache::{Artifact, Error as CacheError};
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
|
//! The prelude module is a helper module used to bring commonly used runtime core imports into
|
||||||
|
//! scope.
|
||||||
|
|
||||||
pub use crate::import::{ImportObject, Namespace};
|
pub use crate::import::{ImportObject, Namespace};
|
||||||
pub use crate::types::{
|
pub use crate::types::{
|
||||||
FuncIndex, GlobalIndex, ImportedFuncIndex, ImportedGlobalIndex, ImportedMemoryIndex,
|
FuncIndex, GlobalIndex, ImportedFuncIndex, ImportedGlobalIndex, ImportedMemoryIndex,
|
||||||
@ -158,6 +176,7 @@ pub fn validate_and_report_errors_with_features(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new module from the given cache `Artifact` for the specified compiler backend
|
||||||
pub unsafe fn load_cache_with(
|
pub unsafe fn load_cache_with(
|
||||||
cache: Artifact,
|
cache: Artifact,
|
||||||
compiler: &dyn backend::Compiler,
|
compiler: &dyn backend::Compiler,
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
//! The loader module functions are used to load an instance.
|
||||||
use crate::{backend::RunnableModule, module::ModuleInfo, types::Type, types::Value, vm::Ctx};
|
use crate::{backend::RunnableModule, module::ModuleInfo, types::Type, types::Value, vm::Ctx};
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use libc::{mmap, mprotect, munmap, MAP_ANON, MAP_PRIVATE, PROT_EXEC, PROT_READ, PROT_WRITE};
|
use libc::{mmap, mprotect, munmap, MAP_ANON, MAP_PRIVATE, PROT_EXEC, PROT_READ, PROT_WRITE};
|
||||||
@ -6,10 +7,14 @@ use std::{
|
|||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// The loader trait represents the functions used to load an instance.
|
||||||
pub trait Loader {
|
pub trait Loader {
|
||||||
|
/// The type of `Instance` for the loader.
|
||||||
type Instance: Instance;
|
type Instance: Instance;
|
||||||
|
/// The error type returned by the loader.
|
||||||
type Error: Debug;
|
type Error: Debug;
|
||||||
|
|
||||||
|
/// Loads the given module and context into an instance.
|
||||||
fn load(
|
fn load(
|
||||||
&self,
|
&self,
|
||||||
rm: &dyn RunnableModule,
|
rm: &dyn RunnableModule,
|
||||||
@ -18,18 +23,23 @@ pub trait Loader {
|
|||||||
) -> Result<Self::Instance, Self::Error>;
|
) -> Result<Self::Instance, Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This trait represents an instance used by the loader.
|
||||||
pub trait Instance {
|
pub trait Instance {
|
||||||
|
/// The error type returned by this instance.
|
||||||
type Error: Debug;
|
type Error: Debug;
|
||||||
|
/// Call a function by id with the given args.
|
||||||
fn call(&mut self, id: usize, args: &[Value]) -> Result<u128, Self::Error>;
|
fn call(&mut self, id: usize, args: &[Value]) -> Result<u128, Self::Error>;
|
||||||
|
/// Read memory at the given offset and length.
|
||||||
fn read_memory(&mut self, _offset: u32, _len: u32) -> Result<Vec<u8>, Self::Error> {
|
fn read_memory(&mut self, _offset: u32, _len: u32) -> Result<Vec<u8>, Self::Error> {
|
||||||
unimplemented!("Instance::read_memory")
|
unimplemented!("Instance::read_memory")
|
||||||
}
|
}
|
||||||
|
/// Write memory at the given offset and length.
|
||||||
fn write_memory(&mut self, _offset: u32, _len: u32, _buf: &[u8]) -> Result<(), Self::Error> {
|
fn write_memory(&mut self, _offset: u32, _len: u32, _buf: &[u8]) -> Result<(), Self::Error> {
|
||||||
unimplemented!("Instance::write_memory")
|
unimplemented!("Instance::write_memory")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A local implementation for `Loader`.
|
||||||
pub struct LocalLoader;
|
pub struct LocalLoader;
|
||||||
|
|
||||||
impl Loader for LocalLoader {
|
impl Loader for LocalLoader {
|
||||||
@ -54,6 +64,7 @@ impl Loader for LocalLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A local instance.
|
||||||
pub struct LocalInstance {
|
pub struct LocalInstance {
|
||||||
code: CodeMemory,
|
code: CodeMemory,
|
||||||
offsets: Vec<usize>,
|
offsets: Vec<usize>,
|
||||||
@ -111,6 +122,7 @@ impl Instance for LocalInstance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A pointer to code in memory.
|
||||||
pub struct CodeMemory {
|
pub struct CodeMemory {
|
||||||
ptr: *mut u8,
|
ptr: *mut u8,
|
||||||
size: usize,
|
size: usize,
|
||||||
@ -136,6 +148,7 @@ impl CodeMemory {
|
|||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
impl CodeMemory {
|
impl CodeMemory {
|
||||||
|
/// Creates a new code memory with the given size.
|
||||||
pub fn new(size: usize) -> CodeMemory {
|
pub fn new(size: usize) -> CodeMemory {
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
return CodeMemory {
|
return CodeMemory {
|
||||||
@ -167,12 +180,14 @@ impl CodeMemory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Makes this code memory executable.
|
||||||
pub fn make_executable(&self) {
|
pub fn make_executable(&self) {
|
||||||
if unsafe { mprotect(self.ptr as _, self.size, PROT_READ | PROT_EXEC) } != 0 {
|
if unsafe { mprotect(self.ptr as _, self.size, PROT_READ | PROT_EXEC) } != 0 {
|
||||||
panic!("cannot set code memory to executable");
|
panic!("cannot set code memory to executable");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Makes this code memory writable.
|
||||||
pub fn make_writable(&self) {
|
pub fn make_writable(&self) {
|
||||||
if unsafe { mprotect(self.ptr as _, self.size, PROT_READ | PROT_WRITE) } != 0 {
|
if unsafe { mprotect(self.ptr as _, self.size, PROT_READ | PROT_WRITE) } != 0 {
|
||||||
panic!("cannot set code memory to writable");
|
panic!("cannot set code memory to writable");
|
||||||
|
@ -11,6 +11,8 @@ macro_rules! debug {
|
|||||||
}, line!(), $($arg)*));
|
}, line!(), $($arg)*));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Prints a log message with args, similar to println, when the debug feature is enabled.
|
||||||
|
/// If the debug feature is disabled, arguments are not evaluated or printed.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
#[cfg(not(feature = "debug"))]
|
#[cfg(not(feature = "debug"))]
|
||||||
macro_rules! debug {
|
macro_rules! debug {
|
||||||
@ -18,6 +20,8 @@ macro_rules! debug {
|
|||||||
($fmt:expr, $($arg:tt)*) => {};
|
($fmt:expr, $($arg:tt)*) => {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Prints a log message with args, similar to println, when the trace feature is enabled.
|
||||||
|
/// If the trace feature is disabled, arguments are not evaluated or printed.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
macro_rules! trace {
|
macro_rules! trace {
|
||||||
@ -29,6 +33,8 @@ macro_rules! trace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Prints a log message with args, similar to println, when the trace feature is enabled.
|
||||||
|
/// If the trace feature is disabled, arguments are not evaluated or printed.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
#[cfg(not(feature = "trace"))]
|
#[cfg(not(feature = "trace"))]
|
||||||
macro_rules! trace {
|
macro_rules! trace {
|
||||||
@ -36,6 +42,7 @@ macro_rules! trace {
|
|||||||
($fmt:expr, $($arg:tt)*) => {};
|
($fmt:expr, $($arg:tt)*) => {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper macro to create a new `Func` object using the provided function pointer.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! func {
|
macro_rules! func {
|
||||||
($func:path) => {{
|
($func:path) => {{
|
||||||
|
@ -62,10 +62,12 @@ impl DynamicMemory {
|
|||||||
Ok(storage)
|
Ok(storage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The size of this memory in `Pages`.
|
||||||
pub fn size(&self) -> Pages {
|
pub fn size(&self) -> Pages {
|
||||||
self.current
|
self.current
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Try to grow self by the given number of delta pages.
|
||||||
pub fn grow(&mut self, delta: Pages, local: &mut vm::LocalMemory) -> Result<Pages, GrowError> {
|
pub fn grow(&mut self, delta: Pages, local: &mut vm::LocalMemory) -> Result<Pages, GrowError> {
|
||||||
if delta == Pages(0) {
|
if delta == Pages(0) {
|
||||||
return Ok(self.current);
|
return Ok(self.current);
|
||||||
@ -104,10 +106,12 @@ impl DynamicMemory {
|
|||||||
Ok(old_pages)
|
Ok(old_pages)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get this memory represented as a slice of bytes.
|
||||||
pub fn as_slice(&self) -> &[u8] {
|
pub fn as_slice(&self) -> &[u8] {
|
||||||
unsafe { &self.memory.as_slice()[0..self.current.bytes().0] }
|
unsafe { &self.memory.as_slice()[0..self.current.bytes().0] }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get this memory represented as a mutable slice of bytes
|
||||||
pub fn as_slice_mut(&mut self) -> &mut [u8] {
|
pub fn as_slice_mut(&mut self) -> &mut [u8] {
|
||||||
unsafe { &mut self.memory.as_slice_mut()[0..self.current.bytes().0] }
|
unsafe { &mut self.memory.as_slice_mut()[0..self.current.bytes().0] }
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//! The memory module contains the implementation data structures and helper functions used to
|
||||||
|
//! manipulate and access wasm memory.
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{CreationError, GrowError},
|
error::{CreationError, GrowError},
|
||||||
export::Export,
|
export::Export,
|
||||||
@ -170,10 +172,14 @@ impl fmt::Debug for Memory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A kind a memory.
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub enum MemoryType {
|
pub enum MemoryType {
|
||||||
|
/// A dynamic memory.
|
||||||
Dynamic,
|
Dynamic,
|
||||||
|
/// A static memory.
|
||||||
Static,
|
Static,
|
||||||
|
/// A shared static memory.
|
||||||
SharedStatic,
|
SharedStatic,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,6 +206,7 @@ enum UnsharedMemoryStorage {
|
|||||||
Static(Box<StaticMemory>),
|
Static(Box<StaticMemory>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A reference to an unshared memory.
|
||||||
pub struct UnsharedMemory {
|
pub struct UnsharedMemory {
|
||||||
internal: Arc<UnsharedMemoryInternal>,
|
internal: Arc<UnsharedMemoryInternal>,
|
||||||
}
|
}
|
||||||
@ -214,6 +221,7 @@ struct UnsharedMemoryInternal {
|
|||||||
unsafe impl Sync for UnsharedMemoryInternal {}
|
unsafe impl Sync for UnsharedMemoryInternal {}
|
||||||
|
|
||||||
impl UnsharedMemory {
|
impl UnsharedMemory {
|
||||||
|
/// Create a new `UnsharedMemory` from the given memory descriptor.
|
||||||
pub fn new(desc: MemoryDescriptor) -> Result<Self, CreationError> {
|
pub fn new(desc: MemoryDescriptor) -> Result<Self, CreationError> {
|
||||||
let mut local = vm::LocalMemory {
|
let mut local = vm::LocalMemory {
|
||||||
base: std::ptr::null_mut(),
|
base: std::ptr::null_mut(),
|
||||||
@ -243,6 +251,7 @@ impl UnsharedMemory {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Try to grow this memory by the given number of delta pages.
|
||||||
pub fn grow(&self, delta: Pages) -> Result<Pages, GrowError> {
|
pub fn grow(&self, delta: Pages) -> Result<Pages, GrowError> {
|
||||||
let mut storage = self.internal.storage.lock().unwrap();
|
let mut storage = self.internal.storage.lock().unwrap();
|
||||||
|
|
||||||
@ -260,6 +269,7 @@ impl UnsharedMemory {
|
|||||||
pages
|
pages
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Size of this memory in pages.
|
||||||
pub fn size(&self) -> Pages {
|
pub fn size(&self) -> Pages {
|
||||||
let storage = self.internal.storage.lock().unwrap();
|
let storage = self.internal.storage.lock().unwrap();
|
||||||
|
|
||||||
@ -282,10 +292,12 @@ impl Clone for UnsharedMemory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A reference to a shared memory.
|
||||||
pub struct SharedMemory {
|
pub struct SharedMemory {
|
||||||
internal: Arc<SharedMemoryInternal>,
|
internal: Arc<SharedMemoryInternal>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Data structure for a shared internal memory.
|
||||||
pub struct SharedMemoryInternal {
|
pub struct SharedMemoryInternal {
|
||||||
memory: StdMutex<Box<StaticMemory>>,
|
memory: StdMutex<Box<StaticMemory>>,
|
||||||
local: Cell<vm::LocalMemory>,
|
local: Cell<vm::LocalMemory>,
|
||||||
@ -315,6 +327,7 @@ impl SharedMemory {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Try to grow this memory by the given number of delta pages.
|
||||||
pub fn grow(&self, delta: Pages) -> Result<Pages, GrowError> {
|
pub fn grow(&self, delta: Pages) -> Result<Pages, GrowError> {
|
||||||
let _guard = self.internal.lock.lock();
|
let _guard = self.internal.lock.lock();
|
||||||
let mut local = self.internal.local.get();
|
let mut local = self.internal.local.get();
|
||||||
@ -323,12 +336,14 @@ impl SharedMemory {
|
|||||||
pages
|
pages
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Size of this memory in pages.
|
||||||
pub fn size(&self) -> Pages {
|
pub fn size(&self) -> Pages {
|
||||||
let _guard = self.internal.lock.lock();
|
let _guard = self.internal.lock.lock();
|
||||||
let memory = self.internal.memory.lock().unwrap();
|
let memory = self.internal.memory.lock().unwrap();
|
||||||
memory.size()
|
memory.size()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a mutable pointer to the `LocalMemory`.
|
||||||
// This function is scary, because the mutex is not locked here
|
// This function is scary, because the mutex is not locked here
|
||||||
pub(crate) fn vm_local_memory(&self) -> *mut vm::LocalMemory {
|
pub(crate) fn vm_local_memory(&self) -> *mut vm::LocalMemory {
|
||||||
self.internal.local.as_ptr()
|
self.internal.local.as_ptr()
|
||||||
|
@ -12,9 +12,12 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use std::{cell::Cell, fmt, marker::PhantomData, mem};
|
use std::{cell::Cell, fmt, marker::PhantomData, mem};
|
||||||
|
|
||||||
|
/// Array.
|
||||||
pub struct Array;
|
pub struct Array;
|
||||||
|
/// Item.
|
||||||
pub struct Item;
|
pub struct Item;
|
||||||
|
|
||||||
|
/// A pointer to a Wasm item.
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct WasmPtr<T: Copy, Ty = Item> {
|
pub struct WasmPtr<T: Copy, Ty = Item> {
|
||||||
offset: u32,
|
offset: u32,
|
||||||
@ -22,6 +25,7 @@ pub struct WasmPtr<T: Copy, Ty = Item> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Copy, Ty> WasmPtr<T, Ty> {
|
impl<T: Copy, Ty> WasmPtr<T, Ty> {
|
||||||
|
/// Create a new `WasmPtr` at the given offset.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(offset: u32) -> Self {
|
pub fn new(offset: u32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -30,6 +34,7 @@ impl<T: Copy, Ty> WasmPtr<T, Ty> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the offset for this `WasmPtr`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn offset(self) -> u32 {
|
pub fn offset(self) -> u32 {
|
||||||
self.offset
|
self.offset
|
||||||
@ -44,6 +49,7 @@ fn align_pointer(ptr: usize, align: usize) -> usize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Copy + ValueType> WasmPtr<T, Item> {
|
impl<T: Copy + ValueType> WasmPtr<T, Item> {
|
||||||
|
/// Dereference this `WasmPtr`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn deref<'a>(self, memory: &'a Memory) -> Option<&'a Cell<T>> {
|
pub fn deref<'a>(self, memory: &'a Memory) -> Option<&'a Cell<T>> {
|
||||||
if (self.offset as usize) + mem::size_of::<T>() >= memory.size().bytes().0 {
|
if (self.offset as usize) + mem::size_of::<T>() >= memory.size().bytes().0 {
|
||||||
@ -58,6 +64,7 @@ impl<T: Copy + ValueType> WasmPtr<T, Item> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Mutable dereference this `WasmPtr`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn deref_mut<'a>(self, memory: &'a Memory) -> Option<&'a mut Cell<T>> {
|
pub unsafe fn deref_mut<'a>(self, memory: &'a Memory) -> Option<&'a mut Cell<T>> {
|
||||||
if (self.offset as usize) + mem::size_of::<T>() >= memory.size().bytes().0 {
|
if (self.offset as usize) + mem::size_of::<T>() >= memory.size().bytes().0 {
|
||||||
@ -72,6 +79,7 @@ impl<T: Copy + ValueType> WasmPtr<T, Item> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Copy + ValueType> WasmPtr<T, Array> {
|
impl<T: Copy + ValueType> WasmPtr<T, Array> {
|
||||||
|
/// Dereference this `WasmPtr`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn deref<'a>(self, memory: &'a Memory, index: u32, length: u32) -> Option<&'a [Cell<T>]> {
|
pub fn deref<'a>(self, memory: &'a Memory, index: u32, length: u32) -> Option<&'a [Cell<T>]> {
|
||||||
// gets the size of the item in the array with padding added such that
|
// gets the size of the item in the array with padding added such that
|
||||||
@ -94,6 +102,7 @@ impl<T: Copy + ValueType> WasmPtr<T, Array> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Mutable dereference this `WasmPtr`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn deref_mut<'a>(
|
pub unsafe fn deref_mut<'a>(
|
||||||
self,
|
self,
|
||||||
@ -119,6 +128,7 @@ impl<T: Copy + ValueType> WasmPtr<T, Array> {
|
|||||||
Some(cell_ptrs)
|
Some(cell_ptrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a UTF-8 string representation of this `WasmPtr` with the given length.
|
||||||
pub fn get_utf8_string<'a>(self, memory: &'a Memory, str_len: u32) -> Option<&'a str> {
|
pub fn get_utf8_string<'a>(self, memory: &'a Memory, str_len: u32) -> Option<&'a str> {
|
||||||
if self.offset as usize + str_len as usize > memory.size().bytes().0 {
|
if self.offset as usize + str_len as usize > memory.size().bytes().0 {
|
||||||
return None;
|
return None;
|
||||||
|
@ -56,10 +56,12 @@ impl StaticMemory {
|
|||||||
Ok(storage)
|
Ok(storage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The size of this memory in `Pages`.
|
||||||
pub fn size(&self) -> Pages {
|
pub fn size(&self) -> Pages {
|
||||||
self.current
|
self.current
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Try to grow this memory by the given number of delta pages.
|
||||||
pub fn grow(&mut self, delta: Pages, local: &mut vm::LocalMemory) -> Result<Pages, GrowError> {
|
pub fn grow(&mut self, delta: Pages, local: &mut vm::LocalMemory) -> Result<Pages, GrowError> {
|
||||||
if delta == Pages(0) {
|
if delta == Pages(0) {
|
||||||
return Ok(self.current);
|
return Ok(self.current);
|
||||||
@ -94,10 +96,12 @@ impl StaticMemory {
|
|||||||
Ok(old_pages)
|
Ok(old_pages)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get this memory represented as a slice of bytes.
|
||||||
pub fn as_slice(&self) -> &[u8] {
|
pub fn as_slice(&self) -> &[u8] {
|
||||||
unsafe { &self.memory.as_slice()[0..self.current.bytes().0] }
|
unsafe { &self.memory.as_slice()[0..self.current.bytes().0] }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get this memory represented as a mutable slice of bytes.
|
||||||
pub fn as_slice_mut(&mut self) -> &mut [u8] {
|
pub fn as_slice_mut(&mut self) -> &mut [u8] {
|
||||||
unsafe { &mut self.memory.as_slice_mut()[0..self.current.bytes().0] }
|
unsafe { &mut self.memory.as_slice_mut()[0..self.current.bytes().0] }
|
||||||
}
|
}
|
||||||
|
@ -39,12 +39,16 @@ impl Atomic for f64 {
|
|||||||
type Output = AtomicU64;
|
type Output = AtomicU64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A trait that represants an atomic type.
|
||||||
pub trait Atomicity {}
|
pub trait Atomicity {}
|
||||||
|
/// Atomically.
|
||||||
pub struct Atomically;
|
pub struct Atomically;
|
||||||
impl Atomicity for Atomically {}
|
impl Atomicity for Atomically {}
|
||||||
|
/// Non-atomically.
|
||||||
pub struct NonAtomically;
|
pub struct NonAtomically;
|
||||||
impl Atomicity for NonAtomically {}
|
impl Atomicity for NonAtomically {}
|
||||||
|
|
||||||
|
/// A view into a memory.
|
||||||
pub struct MemoryView<'a, T: 'a, A = NonAtomically> {
|
pub struct MemoryView<'a, T: 'a, A = NonAtomically> {
|
||||||
ptr: *mut T,
|
ptr: *mut T,
|
||||||
length: usize,
|
length: usize,
|
||||||
@ -65,6 +69,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: Atomic> MemoryView<'a, T> {
|
impl<'a, T: Atomic> MemoryView<'a, T> {
|
||||||
|
/// Get atomic access to a memory view.
|
||||||
pub fn atomically(&self) -> MemoryView<'a, T::Output, Atomically> {
|
pub fn atomically(&self) -> MemoryView<'a, T::Output, Atomically> {
|
||||||
MemoryView {
|
MemoryView {
|
||||||
ptr: self.ptr as *mut T::Output,
|
ptr: self.ptr as *mut T::Output,
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//! The module module contains the implementation data structures and helper functions used to
|
||||||
|
//! manipulate and access wasm modules.
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{Backend, RunnableModule},
|
backend::{Backend, RunnableModule},
|
||||||
cache::{Artifact, Error as CacheError},
|
cache::{Artifact, Error as CacheError},
|
||||||
@ -27,40 +29,59 @@ pub struct ModuleInner {
|
|||||||
pub info: ModuleInfo,
|
pub info: ModuleInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Container for module data including memories, globals, tables, imports, and exports.
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct ModuleInfo {
|
pub struct ModuleInfo {
|
||||||
|
/// Map of memory index to memory descriptors.
|
||||||
// This are strictly local and the typesystem ensures that.
|
// This are strictly local and the typesystem ensures that.
|
||||||
pub memories: Map<LocalMemoryIndex, MemoryDescriptor>,
|
pub memories: Map<LocalMemoryIndex, MemoryDescriptor>,
|
||||||
|
/// Map of global index to global descriptors.
|
||||||
pub globals: Map<LocalGlobalIndex, GlobalInit>,
|
pub globals: Map<LocalGlobalIndex, GlobalInit>,
|
||||||
|
/// Map of table index to table descriptors.
|
||||||
pub tables: Map<LocalTableIndex, TableDescriptor>,
|
pub tables: Map<LocalTableIndex, TableDescriptor>,
|
||||||
|
|
||||||
|
/// Map of imported function index to import name.
|
||||||
// These are strictly imported and the typesystem ensures that.
|
// These are strictly imported and the typesystem ensures that.
|
||||||
pub imported_functions: Map<ImportedFuncIndex, ImportName>,
|
pub imported_functions: Map<ImportedFuncIndex, ImportName>,
|
||||||
|
/// Map of imported memory index to import name and memory descriptor.
|
||||||
pub imported_memories: Map<ImportedMemoryIndex, (ImportName, MemoryDescriptor)>,
|
pub imported_memories: Map<ImportedMemoryIndex, (ImportName, MemoryDescriptor)>,
|
||||||
|
/// Map of imported table index to import name and table descriptor.
|
||||||
pub imported_tables: Map<ImportedTableIndex, (ImportName, TableDescriptor)>,
|
pub imported_tables: Map<ImportedTableIndex, (ImportName, TableDescriptor)>,
|
||||||
|
/// Map of imported global index to import name and global descriptor.
|
||||||
pub imported_globals: Map<ImportedGlobalIndex, (ImportName, GlobalDescriptor)>,
|
pub imported_globals: Map<ImportedGlobalIndex, (ImportName, GlobalDescriptor)>,
|
||||||
|
|
||||||
|
/// Map of string to export index.
|
||||||
pub exports: IndexMap<String, ExportIndex>,
|
pub exports: IndexMap<String, ExportIndex>,
|
||||||
|
|
||||||
|
/// Vector of data initializers.
|
||||||
pub data_initializers: Vec<DataInitializer>,
|
pub data_initializers: Vec<DataInitializer>,
|
||||||
|
/// Vector of table initializers.
|
||||||
pub elem_initializers: Vec<TableInitializer>,
|
pub elem_initializers: Vec<TableInitializer>,
|
||||||
|
|
||||||
|
/// Index of optional start function.
|
||||||
pub start_func: Option<FuncIndex>,
|
pub start_func: Option<FuncIndex>,
|
||||||
|
|
||||||
|
/// Map function index to signature index.
|
||||||
pub func_assoc: Map<FuncIndex, SigIndex>,
|
pub func_assoc: Map<FuncIndex, SigIndex>,
|
||||||
|
/// Map signature index to function signature.
|
||||||
pub signatures: Map<SigIndex, FuncSig>,
|
pub signatures: Map<SigIndex, FuncSig>,
|
||||||
|
/// Backend.
|
||||||
pub backend: Backend,
|
pub backend: Backend,
|
||||||
|
|
||||||
|
/// Table of namespace indexes.
|
||||||
pub namespace_table: StringTable<NamespaceIndex>,
|
pub namespace_table: StringTable<NamespaceIndex>,
|
||||||
|
/// Table of name indexes.
|
||||||
pub name_table: StringTable<NameIndex>,
|
pub name_table: StringTable<NameIndex>,
|
||||||
|
|
||||||
/// Symbol information from emscripten
|
/// Symbol information from emscripten.
|
||||||
pub em_symbol_map: Option<HashMap<u32, String>>,
|
pub em_symbol_map: Option<HashMap<u32, String>>,
|
||||||
|
|
||||||
|
/// Custom sections.
|
||||||
pub custom_sections: HashMap<String, Vec<u8>>,
|
pub custom_sections: HashMap<String, Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleInfo {
|
impl ModuleInfo {
|
||||||
|
/// Creates custom section info from the given wasm file.
|
||||||
pub fn import_custom_sections(&mut self, wasm: &[u8]) -> crate::error::ParseResult<()> {
|
pub fn import_custom_sections(&mut self, wasm: &[u8]) -> crate::error::ParseResult<()> {
|
||||||
let mut parser = wasmparser::ModuleReader::new(wasm)?;
|
let mut parser = wasmparser::ModuleReader::new(wasm)?;
|
||||||
while !parser.eof() {
|
while !parser.eof() {
|
||||||
@ -120,6 +141,7 @@ impl Module {
|
|||||||
Instance::new(Arc::clone(&self.inner), import_object)
|
Instance::new(Arc::clone(&self.inner), import_object)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a cache artifact from this module.
|
||||||
pub fn cache(&self) -> Result<Artifact, CacheError> {
|
pub fn cache(&self) -> Result<Artifact, CacheError> {
|
||||||
let (backend_metadata, code) = self.inner.cache_gen.generate_cache()?;
|
let (backend_metadata, code) = self.inner.cache_gen.generate_cache()?;
|
||||||
Ok(Artifact::from_parts(
|
Ok(Artifact::from_parts(
|
||||||
@ -129,6 +151,7 @@ impl Module {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the module data for this module.
|
||||||
pub fn info(&self) -> &ModuleInfo {
|
pub fn info(&self) -> &ModuleInfo {
|
||||||
&self.inner.info
|
&self.inner.info
|
||||||
}
|
}
|
||||||
@ -151,11 +174,16 @@ pub struct ImportName {
|
|||||||
pub name_index: NameIndex,
|
pub name_index: NameIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Kinds of export indexes.
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum ExportIndex {
|
pub enum ExportIndex {
|
||||||
|
/// Function export index.
|
||||||
Func(FuncIndex),
|
Func(FuncIndex),
|
||||||
|
/// Memory export index.
|
||||||
Memory(MemoryIndex),
|
Memory(MemoryIndex),
|
||||||
|
/// Global export index.
|
||||||
Global(GlobalIndex),
|
Global(GlobalIndex),
|
||||||
|
/// Table export index.
|
||||||
Table(TableIndex),
|
Table(TableIndex),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,6 +210,7 @@ pub struct TableInitializer {
|
|||||||
pub elements: Vec<FuncIndex>,
|
pub elements: Vec<FuncIndex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// String table builder.
|
||||||
pub struct StringTableBuilder<K: TypedIndex> {
|
pub struct StringTableBuilder<K: TypedIndex> {
|
||||||
map: IndexMap<String, (K, u32, u32)>,
|
map: IndexMap<String, (K, u32, u32)>,
|
||||||
buffer: String,
|
buffer: String,
|
||||||
@ -189,6 +218,7 @@ pub struct StringTableBuilder<K: TypedIndex> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<K: TypedIndex> StringTableBuilder<K> {
|
impl<K: TypedIndex> StringTableBuilder<K> {
|
||||||
|
/// Creates a new `StringTableBuilder`.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
map: IndexMap::new(),
|
map: IndexMap::new(),
|
||||||
@ -197,6 +227,7 @@ impl<K: TypedIndex> StringTableBuilder<K> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Register a new string into table.
|
||||||
pub fn register<S>(&mut self, s: S) -> K
|
pub fn register<S>(&mut self, s: S) -> K
|
||||||
where
|
where
|
||||||
S: Into<String> + AsRef<str>,
|
S: Into<String> + AsRef<str>,
|
||||||
@ -219,6 +250,7 @@ impl<K: TypedIndex> StringTableBuilder<K> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Finish building the `StringTable`.
|
||||||
pub fn finish(self) -> StringTable<K> {
|
pub fn finish(self) -> StringTable<K> {
|
||||||
let table = self
|
let table = self
|
||||||
.map
|
.map
|
||||||
@ -233,6 +265,7 @@ impl<K: TypedIndex> StringTableBuilder<K> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A map of index to string.
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct StringTable<K: TypedIndex> {
|
pub struct StringTable<K: TypedIndex> {
|
||||||
table: Map<K, (u32, u32)>,
|
table: Map<K, (u32, u32)>,
|
||||||
@ -240,6 +273,7 @@ pub struct StringTable<K: TypedIndex> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<K: TypedIndex> StringTable<K> {
|
impl<K: TypedIndex> StringTable<K> {
|
||||||
|
/// Creates a `StringTable`.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
table: Map::new(),
|
table: Map::new(),
|
||||||
@ -247,6 +281,7 @@ impl<K: TypedIndex> StringTable<K> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a reference to a string at the given index.
|
||||||
pub fn get(&self, index: K) -> &str {
|
pub fn get(&self, index: K) -> &str {
|
||||||
let (offset, length) = self.table[index];
|
let (offset, length) = self.table[index];
|
||||||
let offset = offset as usize;
|
let offset = offset as usize;
|
||||||
@ -256,6 +291,7 @@ impl<K: TypedIndex> StringTable<K> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Namespace index.
|
||||||
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct NamespaceIndex(u32);
|
pub struct NamespaceIndex(u32);
|
||||||
|
|
||||||
@ -271,6 +307,7 @@ impl TypedIndex for NamespaceIndex {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Name index.
|
||||||
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct NameIndex(u32);
|
pub struct NameIndex(u32);
|
||||||
|
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
//! The parse module contains common data structures and functions using to parse wasm files into
|
||||||
|
//! runtime data structures.
|
||||||
|
|
||||||
use crate::codegen::*;
|
use crate::codegen::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{Backend, CompilerConfig, RunnableModule},
|
backend::{Backend, CompilerConfig, RunnableModule},
|
||||||
@ -22,9 +25,12 @@ use wasmparser::{
|
|||||||
WasmDecoder,
|
WasmDecoder,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Kind of load error.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum LoadError {
|
pub enum LoadError {
|
||||||
|
/// Parse error.
|
||||||
Parse(BinaryReaderError),
|
Parse(BinaryReaderError),
|
||||||
|
/// Code generation error.
|
||||||
Codegen(String),
|
Codegen(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,6 +48,8 @@ impl From<BinaryReaderError> for LoadError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Read wasm binary into module data using the given backend, module code generator, middlewares,
|
||||||
|
/// and compiler configuration.
|
||||||
pub fn read_module<
|
pub fn read_module<
|
||||||
MCG: ModuleCodeGenerator<FCG, RM, E>,
|
MCG: ModuleCodeGenerator<FCG, RM, E>,
|
||||||
FCG: FunctionCodeGenerator<E>,
|
FCG: FunctionCodeGenerator<E>,
|
||||||
@ -394,6 +402,7 @@ pub fn read_module<
|
|||||||
Ok(info)
|
Ok(info)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert given `WpType` to `Type`.
|
||||||
pub fn wp_type_to_type(ty: WpType) -> Result<Type, BinaryReaderError> {
|
pub fn wp_type_to_type(ty: WpType) -> Result<Type, BinaryReaderError> {
|
||||||
match ty {
|
match ty {
|
||||||
WpType::I32 => Ok(Type::I32),
|
WpType::I32 => Ok(Type::I32),
|
||||||
@ -410,6 +419,7 @@ pub fn wp_type_to_type(ty: WpType) -> Result<Type, BinaryReaderError> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert given `Type` to `WpType`.
|
||||||
pub fn type_to_wp_type(ty: Type) -> WpType {
|
pub fn type_to_wp_type(ty: Type) -> WpType {
|
||||||
match ty {
|
match ty {
|
||||||
Type::I32 => WpType::I32,
|
Type::I32 => WpType::I32,
|
||||||
|
@ -1,119 +1,191 @@
|
|||||||
|
//! The state module is used to track state of a running web assembly instances so that
|
||||||
|
//! state could read or updated at runtime. Use cases include generating stack traces, switching
|
||||||
|
//! generated code from one tier to another, or serializing state of a running instace.
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::ops::Bound::{Included, Unbounded};
|
use std::ops::Bound::{Included, Unbounded};
|
||||||
|
|
||||||
|
/// An index to a register
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
pub struct RegisterIndex(pub usize);
|
pub struct RegisterIndex(pub usize);
|
||||||
|
|
||||||
|
/// A kind of wasm or constant value
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
pub enum WasmAbstractValue {
|
pub enum WasmAbstractValue {
|
||||||
|
/// A wasm runtime value
|
||||||
Runtime,
|
Runtime,
|
||||||
|
/// A wasm constant value
|
||||||
Const(u64),
|
Const(u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A container for the state of a running wasm instance.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct MachineState {
|
pub struct MachineState {
|
||||||
|
/// Stack values.
|
||||||
pub stack_values: Vec<MachineValue>,
|
pub stack_values: Vec<MachineValue>,
|
||||||
|
/// Register values.
|
||||||
pub register_values: Vec<MachineValue>,
|
pub register_values: Vec<MachineValue>,
|
||||||
|
/// Previous frame.
|
||||||
pub prev_frame: BTreeMap<usize, MachineValue>,
|
pub prev_frame: BTreeMap<usize, MachineValue>,
|
||||||
|
/// Wasm stack.
|
||||||
pub wasm_stack: Vec<WasmAbstractValue>,
|
pub wasm_stack: Vec<WasmAbstractValue>,
|
||||||
|
/// Private depth of the wasm stack.
|
||||||
pub wasm_stack_private_depth: usize,
|
pub wasm_stack_private_depth: usize,
|
||||||
|
/// Wasm instruction offset.
|
||||||
pub wasm_inst_offset: usize,
|
pub wasm_inst_offset: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A diff of two `MachineState`s.
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct MachineStateDiff {
|
pub struct MachineStateDiff {
|
||||||
|
/// Last.
|
||||||
pub last: Option<usize>,
|
pub last: Option<usize>,
|
||||||
|
/// Stack push.
|
||||||
pub stack_push: Vec<MachineValue>,
|
pub stack_push: Vec<MachineValue>,
|
||||||
|
/// Stack pop.
|
||||||
pub stack_pop: usize,
|
pub stack_pop: usize,
|
||||||
|
|
||||||
|
/// Register diff.
|
||||||
pub reg_diff: Vec<(RegisterIndex, MachineValue)>,
|
pub reg_diff: Vec<(RegisterIndex, MachineValue)>,
|
||||||
|
|
||||||
|
/// Previous frame diff.
|
||||||
pub prev_frame_diff: BTreeMap<usize, Option<MachineValue>>, // None for removal
|
pub prev_frame_diff: BTreeMap<usize, Option<MachineValue>>, // None for removal
|
||||||
|
|
||||||
|
/// Wasm stack push.
|
||||||
pub wasm_stack_push: Vec<WasmAbstractValue>,
|
pub wasm_stack_push: Vec<WasmAbstractValue>,
|
||||||
|
/// Wasm stack pop.
|
||||||
pub wasm_stack_pop: usize,
|
pub wasm_stack_pop: usize,
|
||||||
|
/// Private depth of the wasm stack.
|
||||||
pub wasm_stack_private_depth: usize, // absolute value; not a diff.
|
pub wasm_stack_private_depth: usize, // absolute value; not a diff.
|
||||||
|
/// Wasm instruction offset.
|
||||||
pub wasm_inst_offset: usize, // absolute value; not a diff.
|
pub wasm_inst_offset: usize, // absolute value; not a diff.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A kind of machine value.
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
pub enum MachineValue {
|
pub enum MachineValue {
|
||||||
|
/// Undefined.
|
||||||
Undefined,
|
Undefined,
|
||||||
|
/// Vmctx.
|
||||||
Vmctx,
|
Vmctx,
|
||||||
|
/// Vmctx Deref.
|
||||||
VmctxDeref(Vec<usize>),
|
VmctxDeref(Vec<usize>),
|
||||||
|
/// Preserve Register.
|
||||||
PreserveRegister(RegisterIndex),
|
PreserveRegister(RegisterIndex),
|
||||||
|
/// Copy Stack BP Relative.
|
||||||
CopyStackBPRelative(i32), // relative to Base Pointer, in byte offset
|
CopyStackBPRelative(i32), // relative to Base Pointer, in byte offset
|
||||||
ExplicitShadow, // indicates that all values above this are above the shadow region
|
/// Explicit Shadow.
|
||||||
|
ExplicitShadow, // indicates that all values above this are above the shadow region
|
||||||
|
/// Wasm Stack.
|
||||||
WasmStack(usize),
|
WasmStack(usize),
|
||||||
|
/// Wasm Local.
|
||||||
WasmLocal(usize),
|
WasmLocal(usize),
|
||||||
|
/// Two Halves.
|
||||||
TwoHalves(Box<(MachineValue, MachineValue)>), // 32-bit values. TODO: optimize: add another type for inner "half" value to avoid boxing?
|
TwoHalves(Box<(MachineValue, MachineValue)>), // 32-bit values. TODO: optimize: add another type for inner "half" value to avoid boxing?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A map of function states.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct FunctionStateMap {
|
pub struct FunctionStateMap {
|
||||||
|
/// Initial.
|
||||||
pub initial: MachineState,
|
pub initial: MachineState,
|
||||||
|
/// Local Function Id.
|
||||||
pub local_function_id: usize,
|
pub local_function_id: usize,
|
||||||
|
/// Locals.
|
||||||
pub locals: Vec<WasmAbstractValue>,
|
pub locals: Vec<WasmAbstractValue>,
|
||||||
|
/// Shadow size.
|
||||||
pub shadow_size: usize, // for single-pass backend, 32 bytes on x86-64
|
pub shadow_size: usize, // for single-pass backend, 32 bytes on x86-64
|
||||||
|
/// Diffs.
|
||||||
pub diffs: Vec<MachineStateDiff>,
|
pub diffs: Vec<MachineStateDiff>,
|
||||||
|
/// Wasm Function Header target offset.
|
||||||
pub wasm_function_header_target_offset: Option<SuspendOffset>,
|
pub wasm_function_header_target_offset: Option<SuspendOffset>,
|
||||||
|
/// Wasm offset to target offset
|
||||||
pub wasm_offset_to_target_offset: BTreeMap<usize, SuspendOffset>,
|
pub wasm_offset_to_target_offset: BTreeMap<usize, SuspendOffset>,
|
||||||
|
/// Loop offsets.
|
||||||
pub loop_offsets: BTreeMap<usize, OffsetInfo>, /* suspend_offset -> info */
|
pub loop_offsets: BTreeMap<usize, OffsetInfo>, /* suspend_offset -> info */
|
||||||
|
/// Call offsets.
|
||||||
pub call_offsets: BTreeMap<usize, OffsetInfo>, /* suspend_offset -> info */
|
pub call_offsets: BTreeMap<usize, OffsetInfo>, /* suspend_offset -> info */
|
||||||
|
/// Trappable offsets.
|
||||||
pub trappable_offsets: BTreeMap<usize, OffsetInfo>, /* suspend_offset -> info */
|
pub trappable_offsets: BTreeMap<usize, OffsetInfo>, /* suspend_offset -> info */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A kind of suspend offset.
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum SuspendOffset {
|
pub enum SuspendOffset {
|
||||||
|
/// A loop.
|
||||||
Loop(usize),
|
Loop(usize),
|
||||||
|
/// A call.
|
||||||
Call(usize),
|
Call(usize),
|
||||||
|
/// A trappable.
|
||||||
Trappable(usize),
|
Trappable(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Info for an offset.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct OffsetInfo {
|
pub struct OffsetInfo {
|
||||||
|
/// End offset.
|
||||||
pub end_offset: usize, // excluded bound
|
pub end_offset: usize, // excluded bound
|
||||||
|
/// Diff Id.
|
||||||
pub diff_id: usize,
|
pub diff_id: usize,
|
||||||
|
/// Activate offset.
|
||||||
pub activate_offset: usize,
|
pub activate_offset: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A map of module state.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ModuleStateMap {
|
pub struct ModuleStateMap {
|
||||||
|
/// Local functions.
|
||||||
pub local_functions: BTreeMap<usize, FunctionStateMap>,
|
pub local_functions: BTreeMap<usize, FunctionStateMap>,
|
||||||
|
/// Total size.
|
||||||
pub total_size: usize,
|
pub total_size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// State dump of a wasm function.
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct WasmFunctionStateDump {
|
pub struct WasmFunctionStateDump {
|
||||||
|
/// Local function id.
|
||||||
pub local_function_id: usize,
|
pub local_function_id: usize,
|
||||||
|
/// Wasm instruction offset.
|
||||||
pub wasm_inst_offset: usize,
|
pub wasm_inst_offset: usize,
|
||||||
|
/// Stack.
|
||||||
pub stack: Vec<Option<u64>>,
|
pub stack: Vec<Option<u64>>,
|
||||||
|
/// Locals.
|
||||||
pub locals: Vec<Option<u64>>,
|
pub locals: Vec<Option<u64>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An image of the execution state.
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct ExecutionStateImage {
|
pub struct ExecutionStateImage {
|
||||||
|
/// Frames.
|
||||||
pub frames: Vec<WasmFunctionStateDump>,
|
pub frames: Vec<WasmFunctionStateDump>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents an image of an `Instance` including its memory, globals, and execution state.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct InstanceImage {
|
pub struct InstanceImage {
|
||||||
|
/// Memory for this `InstanceImage`
|
||||||
pub memory: Option<Vec<u8>>,
|
pub memory: Option<Vec<u8>>,
|
||||||
|
/// Stored globals for this `InstanceImage`
|
||||||
pub globals: Vec<u128>,
|
pub globals: Vec<u128>,
|
||||||
|
/// `ExecutionStateImage` for this `InstanceImage`
|
||||||
pub execution_state: ExecutionStateImage,
|
pub execution_state: ExecutionStateImage,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A `CodeVersion` is a container for a unit of generated code for a module.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CodeVersion {
|
pub struct CodeVersion {
|
||||||
|
/// Indicates if this code version is the baseline version.
|
||||||
pub baseline: bool,
|
pub baseline: bool,
|
||||||
|
|
||||||
|
/// `ModuleStateMap` for this code version.
|
||||||
pub msm: ModuleStateMap,
|
pub msm: ModuleStateMap,
|
||||||
|
|
||||||
|
/// A pointer to the machine code for this module.
|
||||||
pub base: usize,
|
pub base: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleStateMap {
|
impl ModuleStateMap {
|
||||||
|
/// Looks up an ip from self using the given ip, base, and offset table provider.
|
||||||
pub fn lookup_ip<F: FnOnce(&FunctionStateMap) -> &BTreeMap<usize, OffsetInfo>>(
|
pub fn lookup_ip<F: FnOnce(&FunctionStateMap) -> &BTreeMap<usize, OffsetInfo>>(
|
||||||
&self,
|
&self,
|
||||||
ip: usize,
|
ip: usize,
|
||||||
@ -146,6 +218,7 @@ impl ModuleStateMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Looks up a call ip from self using the given ip and base values.
|
||||||
pub fn lookup_call_ip(
|
pub fn lookup_call_ip(
|
||||||
&self,
|
&self,
|
||||||
ip: usize,
|
ip: usize,
|
||||||
@ -154,6 +227,7 @@ impl ModuleStateMap {
|
|||||||
self.lookup_ip(ip, base, |fsm| &fsm.call_offsets)
|
self.lookup_ip(ip, base, |fsm| &fsm.call_offsets)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Looks up a trappable ip from self using the given ip and base values.
|
||||||
pub fn lookup_trappable_ip(
|
pub fn lookup_trappable_ip(
|
||||||
&self,
|
&self,
|
||||||
ip: usize,
|
ip: usize,
|
||||||
@ -162,6 +236,7 @@ impl ModuleStateMap {
|
|||||||
self.lookup_ip(ip, base, |fsm| &fsm.trappable_offsets)
|
self.lookup_ip(ip, base, |fsm| &fsm.trappable_offsets)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Looks up a loop ip from self using the given ip and base values.
|
||||||
pub fn lookup_loop_ip(
|
pub fn lookup_loop_ip(
|
||||||
&self,
|
&self,
|
||||||
ip: usize,
|
ip: usize,
|
||||||
@ -172,6 +247,7 @@ impl ModuleStateMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FunctionStateMap {
|
impl FunctionStateMap {
|
||||||
|
/// Creates a new `FunctionStateMap` with the given parameters.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
initial: MachineState,
|
initial: MachineState,
|
||||||
local_function_id: usize,
|
local_function_id: usize,
|
||||||
@ -194,6 +270,7 @@ impl FunctionStateMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MachineState {
|
impl MachineState {
|
||||||
|
/// Creates a `MachineStateDiff` from self and the given `&MachineState`.
|
||||||
pub fn diff(&self, old: &MachineState) -> MachineStateDiff {
|
pub fn diff(&self, old: &MachineState) -> MachineStateDiff {
|
||||||
let first_diff_stack_depth: usize = self
|
let first_diff_stack_depth: usize = self
|
||||||
.stack_values
|
.stack_values
|
||||||
@ -256,6 +333,7 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MachineStateDiff {
|
impl MachineStateDiff {
|
||||||
|
/// Creates a `MachineState` from the given `&FunctionStateMap`.
|
||||||
pub fn build_state(&self, m: &FunctionStateMap) -> MachineState {
|
pub fn build_state(&self, m: &FunctionStateMap) -> MachineState {
|
||||||
let mut chain: Vec<&MachineStateDiff> = vec![];
|
let mut chain: Vec<&MachineStateDiff> = vec![];
|
||||||
chain.push(self);
|
chain.push(self);
|
||||||
@ -298,6 +376,7 @@ impl MachineStateDiff {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ExecutionStateImage {
|
impl ExecutionStateImage {
|
||||||
|
/// Prints a backtrace if the `WASMER_BACKTRACE` environment variable is 1.
|
||||||
pub fn print_backtrace_if_needed(&self) {
|
pub fn print_backtrace_if_needed(&self) {
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
@ -311,6 +390,7 @@ impl ExecutionStateImage {
|
|||||||
eprintln!("Run with `WASMER_BACKTRACE=1` environment variable to display a backtrace.");
|
eprintln!("Run with `WASMER_BACKTRACE=1` environment variable to display a backtrace.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts self into a `String`, used for display purposes.
|
||||||
pub fn output(&self) -> String {
|
pub fn output(&self) -> String {
|
||||||
fn join_strings(x: impl Iterator<Item = String>, sep: &str) -> String {
|
fn join_strings(x: impl Iterator<Item = String>, sep: &str) -> String {
|
||||||
let mut ret = String::new();
|
let mut ret = String::new();
|
||||||
@ -376,6 +456,7 @@ impl ExecutionStateImage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl InstanceImage {
|
impl InstanceImage {
|
||||||
|
/// Converts a slice of bytes into an `Option<InstanceImage>`
|
||||||
pub fn from_bytes(input: &[u8]) -> Option<InstanceImage> {
|
pub fn from_bytes(input: &[u8]) -> Option<InstanceImage> {
|
||||||
use bincode::deserialize;
|
use bincode::deserialize;
|
||||||
match deserialize(input) {
|
match deserialize(input) {
|
||||||
@ -384,6 +465,7 @@ impl InstanceImage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts self into a vector of bytes.
|
||||||
pub fn to_bytes(&self) -> Vec<u8> {
|
pub fn to_bytes(&self) -> Vec<u8> {
|
||||||
use bincode::serialize;
|
use bincode::serialize;
|
||||||
serialize(self).unwrap()
|
serialize(self).unwrap()
|
||||||
@ -392,6 +474,7 @@ impl InstanceImage {
|
|||||||
|
|
||||||
#[cfg(all(unix, target_arch = "x86_64"))]
|
#[cfg(all(unix, target_arch = "x86_64"))]
|
||||||
pub mod x64 {
|
pub mod x64 {
|
||||||
|
//! The x64 state module contains functions to generate state and code for x64 targets.
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::codegen::BreakpointMap;
|
use crate::codegen::BreakpointMap;
|
||||||
use crate::fault::{
|
use crate::fault::{
|
||||||
@ -410,6 +493,7 @@ pub mod x64 {
|
|||||||
ptr as usize as u64
|
ptr as usize as u64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new `MachineState` with default values.
|
||||||
pub fn new_machine_state() -> MachineState {
|
pub fn new_machine_state() -> MachineState {
|
||||||
MachineState {
|
MachineState {
|
||||||
stack_values: vec![],
|
stack_values: vec![],
|
||||||
@ -421,6 +505,8 @@ pub mod x64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Invokes a call return on the stack for the given module state map, code base, instance
|
||||||
|
/// image and context.
|
||||||
#[warn(unused_variables)]
|
#[warn(unused_variables)]
|
||||||
pub unsafe fn invoke_call_return_on_stack(
|
pub unsafe fn invoke_call_return_on_stack(
|
||||||
msm: &ModuleStateMap,
|
msm: &ModuleStateMap,
|
||||||
@ -772,6 +858,7 @@ pub mod x64 {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds an `InstanceImage` for the given `Ctx` and `ExecutionStateImage`.
|
||||||
pub fn build_instance_image(
|
pub fn build_instance_image(
|
||||||
vmctx: &mut Ctx,
|
vmctx: &mut Ctx,
|
||||||
execution_state: ExecutionStateImage,
|
execution_state: ExecutionStateImage,
|
||||||
@ -807,6 +894,8 @@ pub mod x64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a `ExecutionStateImage` for the given versions, stack, initial registers and
|
||||||
|
/// initial address.
|
||||||
#[warn(unused_variables)]
|
#[warn(unused_variables)]
|
||||||
pub unsafe fn read_stack<'a, I: Iterator<Item = &'a CodeVersion>, F: Fn() -> I + 'a>(
|
pub unsafe fn read_stack<'a, I: Iterator<Item = &'a CodeVersion>, F: Fn() -> I + 'a>(
|
||||||
versions: F,
|
versions: F,
|
||||||
@ -1022,55 +1111,93 @@ pub mod x64 {
|
|||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A kind of GPR register
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub enum GPR {
|
pub enum GPR {
|
||||||
|
/// RAX Register
|
||||||
RAX,
|
RAX,
|
||||||
|
/// RCX Register
|
||||||
RCX,
|
RCX,
|
||||||
|
/// RDX Register
|
||||||
RDX,
|
RDX,
|
||||||
|
/// RBX Register
|
||||||
RBX,
|
RBX,
|
||||||
|
/// RSP Register
|
||||||
RSP,
|
RSP,
|
||||||
|
/// RBP Register
|
||||||
RBP,
|
RBP,
|
||||||
|
/// RSI Register
|
||||||
RSI,
|
RSI,
|
||||||
|
/// RDI Register
|
||||||
RDI,
|
RDI,
|
||||||
|
/// R8 Register
|
||||||
R8,
|
R8,
|
||||||
|
/// R9 Register
|
||||||
R9,
|
R9,
|
||||||
|
/// R10 Register
|
||||||
R10,
|
R10,
|
||||||
|
/// R11 Register
|
||||||
R11,
|
R11,
|
||||||
|
/// R12 Register
|
||||||
R12,
|
R12,
|
||||||
|
/// R13 Register
|
||||||
R13,
|
R13,
|
||||||
|
/// R14 Register
|
||||||
R14,
|
R14,
|
||||||
|
/// R15 Register
|
||||||
R15,
|
R15,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A kind of XMM register
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub enum XMM {
|
pub enum XMM {
|
||||||
|
/// XMM0 Register
|
||||||
XMM0,
|
XMM0,
|
||||||
|
/// XMM1 Register
|
||||||
XMM1,
|
XMM1,
|
||||||
|
/// XMM2 Register
|
||||||
XMM2,
|
XMM2,
|
||||||
|
/// XMM3 Register
|
||||||
XMM3,
|
XMM3,
|
||||||
|
/// XMM4 Register
|
||||||
XMM4,
|
XMM4,
|
||||||
|
/// XMM5 Register
|
||||||
XMM5,
|
XMM5,
|
||||||
|
/// XMM6 Register
|
||||||
XMM6,
|
XMM6,
|
||||||
|
/// XMM7 Register
|
||||||
XMM7,
|
XMM7,
|
||||||
|
/// XMM8 Register
|
||||||
XMM8,
|
XMM8,
|
||||||
|
/// XMM9 Register
|
||||||
XMM9,
|
XMM9,
|
||||||
|
/// XMM10 Register
|
||||||
XMM10,
|
XMM10,
|
||||||
|
/// XMM11 Register
|
||||||
XMM11,
|
XMM11,
|
||||||
|
/// XMM12 Register
|
||||||
XMM12,
|
XMM12,
|
||||||
|
/// XMM13 Register
|
||||||
XMM13,
|
XMM13,
|
||||||
|
/// XMM14 Register
|
||||||
XMM14,
|
XMM14,
|
||||||
|
/// XMM15 Register
|
||||||
XMM15,
|
XMM15,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A kind of register belonging to the x64 register set
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum X64Register {
|
pub enum X64Register {
|
||||||
|
/// A register belonging to the GPR register set
|
||||||
GPR(GPR),
|
GPR(GPR),
|
||||||
|
/// A register belonging to the XMM register set
|
||||||
XMM(XMM),
|
XMM(XMM),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl X64Register {
|
impl X64Register {
|
||||||
|
/// Returns a `RegisterIndex` for the current `X64Register`.
|
||||||
pub fn to_index(&self) -> RegisterIndex {
|
pub fn to_index(&self) -> RegisterIndex {
|
||||||
match *self {
|
match *self {
|
||||||
X64Register::GPR(x) => RegisterIndex(x as usize),
|
X64Register::GPR(x) => RegisterIndex(x as usize),
|
||||||
@ -1078,6 +1205,7 @@ pub mod x64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns an `Option<X6Register>` for the given DWARF register integer number.
|
||||||
pub fn from_dwarf_regnum(x: u16) -> Option<X64Register> {
|
pub fn from_dwarf_regnum(x: u16) -> Option<X64Register> {
|
||||||
Some(match x {
|
Some(match x {
|
||||||
0 => X64Register::GPR(GPR::RAX),
|
0 => X64Register::GPR(GPR::RAX),
|
||||||
|
@ -5,6 +5,7 @@ use std::{
|
|||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Boxed map.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct BoxedMap<K, V>
|
pub struct BoxedMap<K, V>
|
||||||
where
|
where
|
||||||
|
@ -21,6 +21,7 @@ impl<K, V> Map<K, V>
|
|||||||
where
|
where
|
||||||
K: TypedIndex,
|
K: TypedIndex,
|
||||||
{
|
{
|
||||||
|
/// Creates a new `Map`.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
elems: Vec::new(),
|
elems: Vec::new(),
|
||||||
@ -28,6 +29,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new empty `Map` with the given capacity.
|
||||||
pub fn with_capacity(capacity: usize) -> Self {
|
pub fn with_capacity(capacity: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
elems: Vec::with_capacity(capacity),
|
elems: Vec::with_capacity(capacity),
|
||||||
@ -35,32 +37,39 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the size of this map.
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.elems.len()
|
self.elems.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if this map is empty.
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.elems.is_empty()
|
self.elems.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds a new value to this map.
|
||||||
pub fn push(&mut self, value: V) -> K {
|
pub fn push(&mut self, value: V) -> K {
|
||||||
let len = self.len();
|
let len = self.len();
|
||||||
self.elems.push(value);
|
self.elems.push(value);
|
||||||
K::new(len)
|
K::new(len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the next index into the map.
|
||||||
pub fn next_index(&self) -> K {
|
pub fn next_index(&self) -> K {
|
||||||
K::new(self.len())
|
K::new(self.len())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reserves the given size.
|
||||||
pub fn reserve_exact(&mut self, size: usize) {
|
pub fn reserve_exact(&mut self, size: usize) {
|
||||||
self.elems.reserve_exact(size);
|
self.elems.reserve_exact(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert this into a `BoxedMap`.
|
||||||
pub fn into_boxed_map(self) -> BoxedMap<K, V> {
|
pub fn into_boxed_map(self) -> BoxedMap<K, V> {
|
||||||
BoxedMap::new(self.elems.into_boxed_slice())
|
BoxedMap::new(self.elems.into_boxed_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert this into a `Vec`.
|
||||||
pub fn into_vec(self) -> Vec<V> {
|
pub fn into_vec(self) -> Vec<V> {
|
||||||
self.elems
|
self.elems
|
||||||
}
|
}
|
||||||
@ -71,6 +80,7 @@ where
|
|||||||
K: TypedIndex,
|
K: TypedIndex,
|
||||||
V: Clone,
|
V: Clone,
|
||||||
{
|
{
|
||||||
|
/// Resize this map to the given new length and value.
|
||||||
pub fn resize(&mut self, new_len: usize, value: V) {
|
pub fn resize(&mut self, new_len: usize, value: V) {
|
||||||
self.elems.resize(new_len, value);
|
self.elems.resize(new_len, value);
|
||||||
}
|
}
|
||||||
@ -184,6 +194,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Iterator for a `Map`.
|
||||||
pub struct Iter<'a, K: TypedIndex, V: 'a> {
|
pub struct Iter<'a, K: TypedIndex, V: 'a> {
|
||||||
enumerated: iter::Enumerate<slice::Iter<'a, V>>,
|
enumerated: iter::Enumerate<slice::Iter<'a, V>>,
|
||||||
_marker: PhantomData<K>,
|
_marker: PhantomData<K>,
|
||||||
@ -206,6 +217,7 @@ impl<'a, K: TypedIndex, V: 'a> Iterator for Iter<'a, K, V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Mutable iterator for a `Map`.
|
||||||
pub struct IterMut<'a, K: TypedIndex, V: 'a> {
|
pub struct IterMut<'a, K: TypedIndex, V: 'a> {
|
||||||
enumerated: iter::Enumerate<slice::IterMut<'a, V>>,
|
enumerated: iter::Enumerate<slice::IterMut<'a, V>>,
|
||||||
_marker: PhantomData<K>,
|
_marker: PhantomData<K>,
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
//! The structures module contains commonly used data structures.
|
||||||
mod boxed;
|
mod boxed;
|
||||||
mod map;
|
mod map;
|
||||||
mod slice;
|
mod slice;
|
||||||
@ -6,6 +7,7 @@ pub use self::boxed::BoxedMap;
|
|||||||
pub use self::map::{Iter, IterMut, Map};
|
pub use self::map::{Iter, IterMut, Map};
|
||||||
pub use self::slice::SliceMap;
|
pub use self::slice::SliceMap;
|
||||||
|
|
||||||
|
/// Represents a typed index.
|
||||||
pub trait TypedIndex: Copy + Clone {
|
pub trait TypedIndex: Copy + Clone {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
fn new(index: usize) -> Self;
|
fn new(index: usize) -> Self;
|
||||||
|
@ -20,30 +20,37 @@ impl<K, V> SliceMap<K, V>
|
|||||||
where
|
where
|
||||||
K: TypedIndex,
|
K: TypedIndex,
|
||||||
{
|
{
|
||||||
|
/// Gets a reference to the value at the given index.
|
||||||
pub fn get(&self, index: K) -> Option<&V> {
|
pub fn get(&self, index: K) -> Option<&V> {
|
||||||
self.slice.get(index.index())
|
self.slice.get(index.index())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a mutable reference to the value at the given index.
|
||||||
pub fn get_mut(&mut self, index: K) -> Option<&mut V> {
|
pub fn get_mut(&mut self, index: K) -> Option<&mut V> {
|
||||||
self.slice.get_mut(index.index())
|
self.slice.get_mut(index.index())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the length of this slice map.
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.slice.len()
|
self.slice.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator for this slice map.
|
||||||
pub fn iter(&self) -> Iter<K, V> {
|
pub fn iter(&self) -> Iter<K, V> {
|
||||||
Iter::new(self.slice.iter())
|
Iter::new(self.slice.iter())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a mutable iterator for this slice map.
|
||||||
pub fn iter_mut(&mut self) -> IterMut<K, V> {
|
pub fn iter_mut(&mut self) -> IterMut<K, V> {
|
||||||
IterMut::new(self.slice.iter_mut())
|
IterMut::new(self.slice.iter_mut())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a pointer to the `SliceMap`.
|
||||||
pub fn as_ptr(&self) -> *const V {
|
pub fn as_ptr(&self) -> *const V {
|
||||||
self as *const SliceMap<K, V> as *const V
|
self as *const SliceMap<K, V> as *const V
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a mutable pointer to the `SliceMap`.
|
||||||
pub fn as_mut_ptr(&mut self) -> *mut V {
|
pub fn as_mut_ptr(&mut self) -> *mut V {
|
||||||
self as *mut SliceMap<K, V> as *mut V
|
self as *mut SliceMap<K, V> as *mut V
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ use std::{fs::File, os::unix::io::IntoRawFd, path::Path, ptr, slice, sync::Arc};
|
|||||||
unsafe impl Send for Memory {}
|
unsafe impl Send for Memory {}
|
||||||
unsafe impl Sync for Memory {}
|
unsafe impl Sync for Memory {}
|
||||||
|
|
||||||
|
/// Data for a sized and protected region of memory.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Memory {
|
pub struct Memory {
|
||||||
ptr: *mut u8,
|
ptr: *mut u8,
|
||||||
@ -18,6 +19,7 @@ pub struct Memory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Memory {
|
impl Memory {
|
||||||
|
/// Create a new memory from the given path value and protection.
|
||||||
pub fn from_file_path<P>(path: P, protection: Protect) -> Result<Self, MemoryCreationError>
|
pub fn from_file_path<P>(path: P, protection: Protect) -> Result<Self, MemoryCreationError>
|
||||||
where
|
where
|
||||||
P: AsRef<Path>,
|
P: AsRef<Path>,
|
||||||
@ -54,6 +56,7 @@ impl Memory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new memory with the given size and protection.
|
||||||
pub fn with_size_protect(size: usize, protection: Protect) -> Result<Self, String> {
|
pub fn with_size_protect(size: usize, protection: Protect) -> Result<Self, String> {
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
return Ok(Self {
|
return Ok(Self {
|
||||||
@ -89,6 +92,7 @@ impl Memory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new memory with the given size.
|
||||||
pub fn with_size(size: usize) -> Result<Self, MemoryCreationError> {
|
pub fn with_size(size: usize) -> Result<Self, MemoryCreationError> {
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
return Ok(Self {
|
return Ok(Self {
|
||||||
@ -127,6 +131,7 @@ impl Memory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Protect this memory with the given range bounds and protection.
|
||||||
pub unsafe fn protect(
|
pub unsafe fn protect(
|
||||||
&mut self,
|
&mut self,
|
||||||
range: impl RangeBounds<usize>,
|
range: impl RangeBounds<usize>,
|
||||||
@ -166,6 +171,7 @@ impl Memory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Split this memory into multiple memories by the given offset.
|
||||||
pub fn split_at(mut self, offset: usize) -> (Memory, Memory) {
|
pub fn split_at(mut self, offset: usize) -> (Memory, Memory) {
|
||||||
let page_size = page_size::get();
|
let page_size = page_size::get();
|
||||||
if offset % page_size == 0 {
|
if offset % page_size == 0 {
|
||||||
@ -187,22 +193,27 @@ impl Memory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the size of this memory.
|
||||||
pub fn size(&self) -> usize {
|
pub fn size(&self) -> usize {
|
||||||
self.size
|
self.size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a slice for this memory.
|
||||||
pub unsafe fn as_slice(&self) -> &[u8] {
|
pub unsafe fn as_slice(&self) -> &[u8] {
|
||||||
slice::from_raw_parts(self.ptr, self.size)
|
slice::from_raw_parts(self.ptr, self.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a mutable slice for this memory.
|
||||||
pub unsafe fn as_slice_mut(&mut self) -> &mut [u8] {
|
pub unsafe fn as_slice_mut(&mut self) -> &mut [u8] {
|
||||||
slice::from_raw_parts_mut(self.ptr, self.size)
|
slice::from_raw_parts_mut(self.ptr, self.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the protect kind of this memory.
|
||||||
pub fn protection(&self) -> Protect {
|
pub fn protection(&self) -> Protect {
|
||||||
self.protection
|
self.protection
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets mutable pointer to the memory.
|
||||||
pub fn as_ptr(&self) -> *mut u8 {
|
pub fn as_ptr(&self) -> *mut u8 {
|
||||||
self.ptr
|
self.ptr
|
||||||
}
|
}
|
||||||
@ -238,13 +249,19 @@ impl Clone for Memory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Kinds of memory protection.
|
||||||
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub enum Protect {
|
pub enum Protect {
|
||||||
|
/// No protection.
|
||||||
None,
|
None,
|
||||||
|
/// Read protection.
|
||||||
Read,
|
Read,
|
||||||
|
/// Read/write protection.
|
||||||
ReadWrite,
|
ReadWrite,
|
||||||
|
/// Read/exec protection.
|
||||||
ReadExec,
|
ReadExec,
|
||||||
|
/// Read/write/exec protection.
|
||||||
ReadWriteExec,
|
ReadWriteExec,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,6 +276,7 @@ impl Protect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if this memory is readable.
|
||||||
pub fn is_readable(self) -> bool {
|
pub fn is_readable(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Protect::Read | Protect::ReadWrite | Protect::ReadExec | Protect::ReadWriteExec => true,
|
Protect::Read | Protect::ReadWrite | Protect::ReadExec | Protect::ReadWriteExec => true,
|
||||||
@ -266,6 +284,7 @@ impl Protect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if this memory is writable.
|
||||||
pub fn is_writable(self) -> bool {
|
pub fn is_writable(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Protect::ReadWrite | Protect::ReadWriteExec => true,
|
Protect::ReadWrite | Protect::ReadWriteExec => true,
|
||||||
|
@ -17,11 +17,13 @@ enum AnyfuncInner<'a> {
|
|||||||
Managed(DynFunc<'a>),
|
Managed(DynFunc<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Anyfunc data type.
|
||||||
pub struct Anyfunc<'a> {
|
pub struct Anyfunc<'a> {
|
||||||
inner: AnyfuncInner<'a>,
|
inner: AnyfuncInner<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Anyfunc<'a> {
|
impl<'a> Anyfunc<'a> {
|
||||||
|
/// Create a new `Anyfunc`.
|
||||||
pub unsafe fn new<Sig>(func: *const vm::Func, signature: Sig) -> Self
|
pub unsafe fn new<Sig>(func: *const vm::Func, signature: Sig) -> Self
|
||||||
where
|
where
|
||||||
Sig: Into<Arc<FuncSig>>,
|
Sig: Into<Arc<FuncSig>>,
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//! The runtime table module contains data structures and functions used to create and update wasm
|
||||||
|
//! tables.
|
||||||
use crate::{
|
use crate::{
|
||||||
error::CreationError,
|
error::CreationError,
|
||||||
export::Export,
|
export::Export,
|
||||||
@ -16,16 +18,20 @@ pub use self::anyfunc::Anyfunc;
|
|||||||
pub(crate) use self::anyfunc::AnyfuncTable;
|
pub(crate) use self::anyfunc::AnyfuncTable;
|
||||||
use crate::error::GrowError;
|
use crate::error::GrowError;
|
||||||
|
|
||||||
|
/// Kind of table element.
|
||||||
pub enum Element<'a> {
|
pub enum Element<'a> {
|
||||||
|
/// Anyfunc.
|
||||||
Anyfunc(Anyfunc<'a>),
|
Anyfunc(Anyfunc<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Kind of table storage.
|
||||||
// #[derive(Debug)]
|
// #[derive(Debug)]
|
||||||
pub enum TableStorage {
|
pub enum TableStorage {
|
||||||
/// This is intended to be a caller-checked Anyfunc.
|
/// This is intended to be a caller-checked Anyfunc.
|
||||||
Anyfunc(Box<AnyfuncTable>),
|
Anyfunc(Box<AnyfuncTable>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Container with a descriptor and a reference to a table storage.
|
||||||
pub struct Table {
|
pub struct Table {
|
||||||
desc: TableDescriptor,
|
desc: TableDescriptor,
|
||||||
storage: Arc<Mutex<(TableStorage, vm::LocalTable)>>,
|
storage: Arc<Mutex<(TableStorage, vm::LocalTable)>>,
|
||||||
@ -128,6 +134,7 @@ impl Table {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a mutable pointer to underlying table storage.
|
||||||
pub fn vm_local_table(&mut self) -> *mut vm::LocalTable {
|
pub fn vm_local_table(&mut self) -> *mut vm::LocalTable {
|
||||||
let mut storage = self.storage.lock().unwrap();
|
let mut storage = self.storage.lock().unwrap();
|
||||||
&mut storage.1
|
&mut storage.1
|
||||||
|
@ -62,6 +62,7 @@ pub fn get_context() -> *const CallContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TrampolineBufferBuilder {
|
impl TrampolineBufferBuilder {
|
||||||
|
/// Creates a new empty `TrampolineBufferBuilder`.
|
||||||
pub fn new() -> TrampolineBufferBuilder {
|
pub fn new() -> TrampolineBufferBuilder {
|
||||||
TrampolineBufferBuilder {
|
TrampolineBufferBuilder {
|
||||||
code: vec![],
|
code: vec![],
|
||||||
@ -100,6 +101,7 @@ impl TrampolineBufferBuilder {
|
|||||||
idx
|
idx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds context RSP state preserving trampoline to the buffer.
|
||||||
pub fn add_context_rsp_state_preserving_trampoline(
|
pub fn add_context_rsp_state_preserving_trampoline(
|
||||||
&mut self,
|
&mut self,
|
||||||
target: unsafe extern "C" fn(&mut Ctx, *const CallContext, *const u64),
|
target: unsafe extern "C" fn(&mut Ctx, *const CallContext, *const u64),
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//! The typed func module implements a way of representing a wasm function
|
||||||
|
//! with the correct types from rust. Function calls using a typed func have a low overhead.
|
||||||
use crate::{
|
use crate::{
|
||||||
error::RuntimeError,
|
error::RuntimeError,
|
||||||
export::{Context, Export, FuncPointer},
|
export::{Context, Export, FuncPointer},
|
||||||
@ -16,14 +18,22 @@ use std::{
|
|||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Wasm trap info.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub enum WasmTrapInfo {
|
pub enum WasmTrapInfo {
|
||||||
|
/// Unreachable trap.
|
||||||
Unreachable = 0,
|
Unreachable = 0,
|
||||||
|
/// Call indirect incorrect signature trap.
|
||||||
IncorrectCallIndirectSignature = 1,
|
IncorrectCallIndirectSignature = 1,
|
||||||
|
/// Memory out of bounds trap.
|
||||||
MemoryOutOfBounds = 2,
|
MemoryOutOfBounds = 2,
|
||||||
|
/// Call indirect out of bounds trap.
|
||||||
CallIndirectOOB = 3,
|
CallIndirectOOB = 3,
|
||||||
|
/// Illegal arithmetic trap.
|
||||||
IllegalArithmetic = 4,
|
IllegalArithmetic = 4,
|
||||||
|
/// Misaligned atomic access trap.
|
||||||
MisalignedAtomicAccess = 5,
|
MisalignedAtomicAccess = 5,
|
||||||
|
/// Unknown trap.
|
||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,12 +62,15 @@ impl fmt::Display for WasmTrapInfo {
|
|||||||
/// of the `Func` struct.
|
/// of the `Func` struct.
|
||||||
pub trait Kind {}
|
pub trait Kind {}
|
||||||
|
|
||||||
|
/// Aliases to an extern "C" type used as a trampoline to a function.
|
||||||
pub type Trampoline = unsafe extern "C" fn(
|
pub type Trampoline = unsafe extern "C" fn(
|
||||||
vmctx: *mut vm::Ctx,
|
vmctx: *mut vm::Ctx,
|
||||||
func: NonNull<vm::Func>,
|
func: NonNull<vm::Func>,
|
||||||
args: *const u64,
|
args: *const u64,
|
||||||
rets: *mut u64,
|
rets: *mut u64,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// Aliases to an extern "C" type used to invoke a function.
|
||||||
pub type Invoke = unsafe extern "C" fn(
|
pub type Invoke = unsafe extern "C" fn(
|
||||||
trampoline: Trampoline,
|
trampoline: Trampoline,
|
||||||
vmctx: *mut vm::Ctx,
|
vmctx: *mut vm::Ctx,
|
||||||
@ -80,6 +93,7 @@ pub struct Wasm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Wasm {
|
impl Wasm {
|
||||||
|
/// Create new `Wasm` from given parts.
|
||||||
pub unsafe fn from_raw_parts(
|
pub unsafe fn from_raw_parts(
|
||||||
trampoline: Trampoline,
|
trampoline: Trampoline,
|
||||||
invoke: Invoke,
|
invoke: Invoke,
|
||||||
@ -102,8 +116,10 @@ impl Kind for Host {}
|
|||||||
|
|
||||||
/// Represents a list of WebAssembly values.
|
/// Represents a list of WebAssembly values.
|
||||||
pub trait WasmTypeList {
|
pub trait WasmTypeList {
|
||||||
|
/// CStruct type.
|
||||||
type CStruct;
|
type CStruct;
|
||||||
|
|
||||||
|
/// Array of return values.
|
||||||
type RetArray: AsMut<[u64]>;
|
type RetArray: AsMut<[u64]>;
|
||||||
|
|
||||||
/// Construct `Self` based on an array of returned values.
|
/// Construct `Self` based on an array of returned values.
|
||||||
@ -175,14 +191,18 @@ where
|
|||||||
Args: WasmTypeList,
|
Args: WasmTypeList,
|
||||||
Rets: WasmTypeList,
|
Rets: WasmTypeList,
|
||||||
{
|
{
|
||||||
|
/// Conver to function pointer.
|
||||||
fn to_raw(&self) -> NonNull<vm::Func>;
|
fn to_raw(&self) -> NonNull<vm::Func>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents a TrapEarly type.
|
||||||
pub trait TrapEarly<Rets>
|
pub trait TrapEarly<Rets>
|
||||||
where
|
where
|
||||||
Rets: WasmTypeList,
|
Rets: WasmTypeList,
|
||||||
{
|
{
|
||||||
|
/// The error type for this trait.
|
||||||
type Error: 'static;
|
type Error: 'static;
|
||||||
|
/// Get returns or error result.
|
||||||
fn report(self) -> Result<Rets, Self::Error>;
|
fn report(self) -> Result<Rets, Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,6 +256,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the underlying func pointer.
|
||||||
pub fn get_vm_func(&self) -> NonNull<vm::Func> {
|
pub fn get_vm_func(&self) -> NonNull<vm::Func> {
|
||||||
self.f
|
self.f
|
||||||
}
|
}
|
||||||
@ -246,6 +267,7 @@ where
|
|||||||
Args: WasmTypeList,
|
Args: WasmTypeList,
|
||||||
Rets: WasmTypeList,
|
Rets: WasmTypeList,
|
||||||
{
|
{
|
||||||
|
/// Creates a new `Func`.
|
||||||
pub fn new<F, Kind>(f: F) -> Func<'a, Args, Rets, Host>
|
pub fn new<F, Kind>(f: F) -> Func<'a, Args, Rets, Host>
|
||||||
where
|
where
|
||||||
Kind: ExternalFunctionKind,
|
Kind: ExternalFunctionKind,
|
||||||
@ -390,6 +412,7 @@ impl<'a, A: WasmExternType, Rets> Func<'a, (A,), Rets, Wasm>
|
|||||||
where
|
where
|
||||||
Rets: WasmTypeList,
|
Rets: WasmTypeList,
|
||||||
{
|
{
|
||||||
|
/// Call wasm function and return results.
|
||||||
pub fn call(&self, a: A) -> Result<Rets, RuntimeError> {
|
pub fn call(&self, a: A) -> Result<Rets, RuntimeError> {
|
||||||
unsafe { <A as WasmTypeList>::call(a, self.f, self.inner, self.ctx) }
|
unsafe { <A as WasmTypeList>::call(a, self.f, self.inner, self.ctx) }
|
||||||
}
|
}
|
||||||
@ -397,6 +420,7 @@ where
|
|||||||
|
|
||||||
macro_rules! impl_traits {
|
macro_rules! impl_traits {
|
||||||
( [$repr:ident] $struct_name:ident, $( $x:ident ),* ) => {
|
( [$repr:ident] $struct_name:ident, $( $x:ident ),* ) => {
|
||||||
|
/// $struct_name for typed funcs.
|
||||||
#[repr($repr)]
|
#[repr($repr)]
|
||||||
pub struct $struct_name< $( $x ),* > ( $( <$x as WasmExternType>::Native ),* )
|
pub struct $struct_name< $( $x ),* > ( $( <$x as WasmExternType>::Native ),* )
|
||||||
where
|
where
|
||||||
@ -598,6 +622,7 @@ macro_rules! impl_traits {
|
|||||||
$( $x: WasmExternType, )*
|
$( $x: WasmExternType, )*
|
||||||
Rets: WasmTypeList,
|
Rets: WasmTypeList,
|
||||||
{
|
{
|
||||||
|
/// Call the typed func and return results.
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn call(&self, $( $x: $x, )* ) -> Result<Rets, RuntimeError> {
|
pub fn call(&self, $( $x: $x, )* ) -> Result<Rets, RuntimeError> {
|
||||||
#[allow(unused_parens)]
|
#[allow(unused_parens)]
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
//! The runtime types modules represent type used within the wasm runtime and helper functions to
|
||||||
|
//! convert to other represenations.
|
||||||
|
|
||||||
use crate::{memory::MemoryType, module::ModuleInfo, structures::TypedIndex, units::Pages};
|
use crate::{memory::MemoryType, module::ModuleInfo, structures::TypedIndex, units::Pages};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
@ -41,6 +44,7 @@ pub enum Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Value {
|
impl Value {
|
||||||
|
/// The `Type` of this `Value`.
|
||||||
pub fn ty(&self) -> Type {
|
pub fn ty(&self) -> Type {
|
||||||
match self {
|
match self {
|
||||||
Value::I32(_) => Type::I32,
|
Value::I32(_) => Type::I32,
|
||||||
@ -51,6 +55,7 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert this `Value` to a u128 binary representation.
|
||||||
pub fn to_u128(&self) -> u128 {
|
pub fn to_u128(&self) -> u128 {
|
||||||
match *self {
|
match *self {
|
||||||
Value::I32(x) => x as u128,
|
Value::I32(x) => x as u128,
|
||||||
@ -92,12 +97,16 @@ impl From<u128> for Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents a native wasm type.
|
||||||
pub unsafe trait NativeWasmType: Copy + Into<Value>
|
pub unsafe trait NativeWasmType: Copy + Into<Value>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
|
/// Type for this `NativeWasmType`.
|
||||||
const TYPE: Type;
|
const TYPE: Type;
|
||||||
|
/// Convert from u64 bites to self.
|
||||||
fn from_binary(bits: u64) -> Self;
|
fn from_binary(bits: u64) -> Self;
|
||||||
|
/// Convert self to u64 binary representation.
|
||||||
fn to_binary(self) -> u64;
|
fn to_binary(self) -> u64;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,12 +147,16 @@ unsafe impl NativeWasmType for f64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A trait to represent a wasm extern type.
|
||||||
pub unsafe trait WasmExternType: Copy
|
pub unsafe trait WasmExternType: Copy
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
|
/// Native wasm type for this `WasmExternType`.
|
||||||
type Native: NativeWasmType;
|
type Native: NativeWasmType;
|
||||||
|
/// Convert from given `Native` type to self.
|
||||||
fn from_native(native: Self::Native) -> Self;
|
fn from_native(native: Self::Native) -> Self;
|
||||||
|
/// Convert self to `Native` type.
|
||||||
fn to_native(self) -> Self::Native;
|
fn to_native(self) -> Self::Native;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,6 +268,7 @@ unsafe impl WasmExternType for f64 {
|
|||||||
// fn swap(&self, other: Self::Primitive) -> Self::Primitive;
|
// fn swap(&self, other: Self::Primitive) -> Self::Primitive;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
/// Trait for a Value type.
|
||||||
pub unsafe trait ValueType: Copy
|
pub unsafe trait ValueType: Copy
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
@ -274,12 +288,15 @@ macro_rules! convert_value_impl {
|
|||||||
|
|
||||||
convert_value_impl!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64);
|
convert_value_impl!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64);
|
||||||
|
|
||||||
|
/// Kinds of element types.
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum ElementType {
|
pub enum ElementType {
|
||||||
/// Any wasm function.
|
/// Any wasm function.
|
||||||
Anyfunc,
|
Anyfunc,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Describes the properties of a table including the element types, minimum and optional maximum,
|
||||||
|
/// number of elements in the table.
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
|
||||||
pub struct TableDescriptor {
|
pub struct TableDescriptor {
|
||||||
/// Type of data stored in this table.
|
/// Type of data stored in this table.
|
||||||
@ -315,14 +332,18 @@ pub enum Initializer {
|
|||||||
/// Describes the mutability and type of a Global
|
/// Describes the mutability and type of a Global
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct GlobalDescriptor {
|
pub struct GlobalDescriptor {
|
||||||
|
/// Mutable flag.
|
||||||
pub mutable: bool,
|
pub mutable: bool,
|
||||||
|
/// Wasm type.
|
||||||
pub ty: Type,
|
pub ty: Type,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A wasm global.
|
/// A wasm global.
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct GlobalInit {
|
pub struct GlobalInit {
|
||||||
|
/// Global descriptor.
|
||||||
pub desc: GlobalDescriptor,
|
pub desc: GlobalDescriptor,
|
||||||
|
/// Global initializer.
|
||||||
pub init: Initializer,
|
pub init: Initializer,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,6 +361,7 @@ pub struct MemoryDescriptor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MemoryDescriptor {
|
impl MemoryDescriptor {
|
||||||
|
/// Create a new memory descriptor with the given min/max pages and shared flag.
|
||||||
pub fn new(minimum: Pages, maximum: Option<Pages>, shared: bool) -> Result<Self, String> {
|
pub fn new(minimum: Pages, maximum: Option<Pages>, shared: bool) -> Result<Self, String> {
|
||||||
let memory_type = match (maximum.is_some(), shared) {
|
let memory_type = match (maximum.is_some(), shared) {
|
||||||
(true, true) => MemoryType::SharedStatic,
|
(true, true) => MemoryType::SharedStatic,
|
||||||
@ -357,6 +379,7 @@ impl MemoryDescriptor {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the `MemoryType` for this descriptor.
|
||||||
pub fn memory_type(&self) -> MemoryType {
|
pub fn memory_type(&self) -> MemoryType {
|
||||||
self.memory_type
|
self.memory_type
|
||||||
}
|
}
|
||||||
@ -380,6 +403,7 @@ pub struct FuncSig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FuncSig {
|
impl FuncSig {
|
||||||
|
/// Creates a new function signatures with the given parameter and return types.
|
||||||
pub fn new<Params, Returns>(params: Params, returns: Returns) -> Self
|
pub fn new<Params, Returns>(params: Params, returns: Returns) -> Self
|
||||||
where
|
where
|
||||||
Params: Into<Cow<'static, [Type]>>,
|
Params: Into<Cow<'static, [Type]>>,
|
||||||
@ -391,14 +415,17 @@ impl FuncSig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parameter types.
|
||||||
pub fn params(&self) -> &[Type] {
|
pub fn params(&self) -> &[Type] {
|
||||||
&self.params
|
&self.params
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return types.
|
||||||
pub fn returns(&self) -> &[Type] {
|
pub fn returns(&self) -> &[Type] {
|
||||||
&self.returns
|
&self.returns
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if parameter types match the function signature.
|
||||||
pub fn check_param_value_types(&self, params: &[Value]) -> bool {
|
pub fn check_param_value_types(&self, params: &[Value]) -> bool {
|
||||||
self.params.len() == params.len()
|
self.params.len() == params.len()
|
||||||
&& self
|
&& self
|
||||||
@ -427,14 +454,18 @@ impl std::fmt::Display for FuncSig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Trait that represents Local or Import.
|
||||||
pub trait LocalImport {
|
pub trait LocalImport {
|
||||||
|
/// Local type.
|
||||||
type Local: TypedIndex;
|
type Local: TypedIndex;
|
||||||
|
/// Import type.
|
||||||
type Import: TypedIndex;
|
type Import: TypedIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
macro_rules! define_map_index {
|
macro_rules! define_map_index {
|
||||||
($ty:ident) => {
|
($ty:ident) => {
|
||||||
|
/// Typed Index for $ty
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct $ty (u32);
|
pub struct $ty (u32);
|
||||||
@ -475,6 +506,7 @@ define_map_index![
|
|||||||
macro_rules! define_local_or_import {
|
macro_rules! define_local_or_import {
|
||||||
($ty:ident, $local_ty:ident, $imported_ty:ident, $imports:ident) => {
|
($ty:ident, $local_ty:ident, $imported_ty:ident, $imports:ident) => {
|
||||||
impl $ty {
|
impl $ty {
|
||||||
|
/// Converts self into `LocalOrImport`.
|
||||||
pub fn local_or_import(self, info: &ModuleInfo) -> LocalOrImport<$ty> {
|
pub fn local_or_import(self, info: &ModuleInfo) -> LocalOrImport<$ty> {
|
||||||
if self.index() < info.$imports.len() {
|
if self.index() < info.$imports.len() {
|
||||||
LocalOrImport::Import(<Self as LocalImport>::Import::new(self.index()))
|
LocalOrImport::Import(<Self as LocalImport>::Import::new(self.index()))
|
||||||
@ -485,12 +517,14 @@ macro_rules! define_local_or_import {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl $local_ty {
|
impl $local_ty {
|
||||||
|
/// Convert up.
|
||||||
pub fn convert_up(self, info: &ModuleInfo) -> $ty {
|
pub fn convert_up(self, info: &ModuleInfo) -> $ty {
|
||||||
$ty ((self.index() + info.$imports.len()) as u32)
|
$ty ((self.index() + info.$imports.len()) as u32)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $imported_ty {
|
impl $imported_ty {
|
||||||
|
/// Convert up.
|
||||||
pub fn convert_up(self, _info: &ModuleInfo) -> $ty {
|
pub fn convert_up(self, _info: &ModuleInfo) -> $ty {
|
||||||
$ty (self.index() as u32)
|
$ty (self.index() as u32)
|
||||||
}
|
}
|
||||||
@ -511,6 +545,7 @@ define_local_or_import![
|
|||||||
(GlobalIndex | (LocalGlobalIndex, ImportedGlobalIndex): imported_globals),
|
(GlobalIndex | (LocalGlobalIndex, ImportedGlobalIndex): imported_globals),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/// Index for signature.
|
||||||
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct SigIndex(u32);
|
pub struct SigIndex(u32);
|
||||||
impl TypedIndex for SigIndex {
|
impl TypedIndex for SigIndex {
|
||||||
@ -525,11 +560,14 @@ impl TypedIndex for SigIndex {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Kind of local or import type.
|
||||||
pub enum LocalOrImport<T>
|
pub enum LocalOrImport<T>
|
||||||
where
|
where
|
||||||
T: LocalImport,
|
T: LocalImport,
|
||||||
{
|
{
|
||||||
|
/// Local.
|
||||||
Local(T::Local),
|
Local(T::Local),
|
||||||
|
/// Import.
|
||||||
Import(T::Import),
|
Import(T::Import),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -537,6 +575,7 @@ impl<T> LocalOrImport<T>
|
|||||||
where
|
where
|
||||||
T: LocalImport,
|
T: LocalImport,
|
||||||
{
|
{
|
||||||
|
/// Returns `Some` if self is local, `None` if self is an import.
|
||||||
pub fn local(self) -> Option<T::Local> {
|
pub fn local(self) -> Option<T::Local> {
|
||||||
match self {
|
match self {
|
||||||
LocalOrImport::Local(local) => Some(local),
|
LocalOrImport::Local(local) => Some(local),
|
||||||
@ -544,6 +583,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `Some` if self is an import, `None` if self is local.
|
||||||
pub fn import(self) -> Option<T::Import> {
|
pub fn import(self) -> Option<T::Import> {
|
||||||
match self {
|
match self {
|
||||||
LocalOrImport::Import(import) => Some(import),
|
LocalOrImport::Import(import) => Some(import),
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
|
//! The units module provides common WebAssembly units like `Pages` and conversion functions into
|
||||||
|
//! other units.
|
||||||
use crate::error::PageError;
|
use crate::error::PageError;
|
||||||
use std::{
|
use std::{
|
||||||
fmt,
|
fmt,
|
||||||
ops::{Add, Sub},
|
ops::{Add, Sub},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// The page size in bytes of a wasm page.
|
||||||
pub const WASM_PAGE_SIZE: usize = 65_536;
|
pub const WASM_PAGE_SIZE: usize = 65_536;
|
||||||
|
/// Tbe max number of wasm pages allowed.
|
||||||
pub const WASM_MAX_PAGES: usize = 65_536;
|
pub const WASM_MAX_PAGES: usize = 65_536;
|
||||||
// From emscripten resize_heap implementation
|
// From emscripten resize_heap implementation
|
||||||
|
/// The minimum number of wasm pages allowed.
|
||||||
pub const WASM_MIN_PAGES: usize = 256;
|
pub const WASM_MIN_PAGES: usize = 256;
|
||||||
|
|
||||||
/// Units of WebAssembly pages (as specified to be 65,536 bytes).
|
/// Units of WebAssembly pages (as specified to be 65,536 bytes).
|
||||||
@ -14,6 +19,7 @@ pub const WASM_MIN_PAGES: usize = 256;
|
|||||||
pub struct Pages(pub u32);
|
pub struct Pages(pub u32);
|
||||||
|
|
||||||
impl Pages {
|
impl Pages {
|
||||||
|
/// Checked add of Pages to Pages.
|
||||||
pub fn checked_add(self, rhs: Pages) -> Result<Pages, PageError> {
|
pub fn checked_add(self, rhs: Pages) -> Result<Pages, PageError> {
|
||||||
let added = (self.0 as usize) + (rhs.0 as usize);
|
let added = (self.0 as usize) + (rhs.0 as usize);
|
||||||
if added <= WASM_MAX_PAGES {
|
if added <= WASM_MAX_PAGES {
|
||||||
@ -27,6 +33,7 @@ impl Pages {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Calculate number of bytes from pages.
|
||||||
pub fn bytes(self) -> Bytes {
|
pub fn bytes(self) -> Bytes {
|
||||||
self.into()
|
self.into()
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//! The runtime vm module contains data structures and helper functions used during runtime to
|
||||||
|
//! execute wasm instance functions.
|
||||||
pub use crate::backing::{ImportBacking, LocalBacking, INTERNALS_SIZE};
|
pub use crate::backing::{ImportBacking, LocalBacking, INTERNALS_SIZE};
|
||||||
use crate::{
|
use crate::{
|
||||||
error::CallResult,
|
error::CallResult,
|
||||||
@ -36,6 +38,7 @@ use std::collections::HashMap;
|
|||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Ctx {
|
pub struct Ctx {
|
||||||
// `internal` must be the first field of `Ctx`.
|
// `internal` must be the first field of `Ctx`.
|
||||||
|
/// InternalCtx data field
|
||||||
pub internal: InternalCtx,
|
pub internal: InternalCtx,
|
||||||
|
|
||||||
pub(crate) local_functions: *const *const Func,
|
pub(crate) local_functions: *const *const Func,
|
||||||
@ -43,7 +46,9 @@ pub struct Ctx {
|
|||||||
/// These are pointers to things that are known to be owned
|
/// These are pointers to things that are known to be owned
|
||||||
/// by the owning `Instance`.
|
/// by the owning `Instance`.
|
||||||
pub local_backing: *mut LocalBacking,
|
pub local_backing: *mut LocalBacking,
|
||||||
|
/// Mutable pointer to import data
|
||||||
pub import_backing: *mut ImportBacking,
|
pub import_backing: *mut ImportBacking,
|
||||||
|
/// Const pointer to module inner data
|
||||||
pub module: *const ModuleInner,
|
pub module: *const ModuleInner,
|
||||||
|
|
||||||
/// This is intended to be user-supplied, per-instance
|
/// This is intended to be user-supplied, per-instance
|
||||||
@ -110,22 +115,31 @@ pub struct InternalCtx {
|
|||||||
/// modules safely.
|
/// modules safely.
|
||||||
pub dynamic_sigindices: *const SigId,
|
pub dynamic_sigindices: *const SigId,
|
||||||
|
|
||||||
|
/// Const pointer to Intrinsics.
|
||||||
pub intrinsics: *const Intrinsics,
|
pub intrinsics: *const Intrinsics,
|
||||||
|
|
||||||
|
/// Stack lower bound.
|
||||||
pub stack_lower_bound: *mut u8,
|
pub stack_lower_bound: *mut u8,
|
||||||
|
|
||||||
|
/// Mutable pointer to memory base.
|
||||||
pub memory_base: *mut u8,
|
pub memory_base: *mut u8,
|
||||||
|
/// Memory bound.
|
||||||
pub memory_bound: usize,
|
pub memory_bound: usize,
|
||||||
|
|
||||||
|
/// Mutable pointer to internal fields.
|
||||||
pub internals: *mut [u64; INTERNALS_SIZE], // TODO: Make this dynamic?
|
pub internals: *mut [u64; INTERNALS_SIZE], // TODO: Make this dynamic?
|
||||||
|
|
||||||
|
/// Interrupt signal mem.
|
||||||
pub interrupt_signal_mem: *mut u8,
|
pub interrupt_signal_mem: *mut u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
static INTERNAL_FIELDS: AtomicUsize = AtomicUsize::new(0);
|
static INTERNAL_FIELDS: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
|
/// An internal field.
|
||||||
pub struct InternalField {
|
pub struct InternalField {
|
||||||
|
/// Init once field.
|
||||||
init: Once,
|
init: Once,
|
||||||
|
/// Inner field.
|
||||||
inner: UnsafeCell<usize>,
|
inner: UnsafeCell<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,6 +147,7 @@ unsafe impl Send for InternalField {}
|
|||||||
unsafe impl Sync for InternalField {}
|
unsafe impl Sync for InternalField {}
|
||||||
|
|
||||||
impl InternalField {
|
impl InternalField {
|
||||||
|
/// Allocate and return an `InternalField`.
|
||||||
pub const fn allocate() -> InternalField {
|
pub const fn allocate() -> InternalField {
|
||||||
InternalField {
|
InternalField {
|
||||||
init: Once::new(),
|
init: Once::new(),
|
||||||
@ -140,6 +155,7 @@ impl InternalField {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the index of this `InternalField`.
|
||||||
pub fn index(&self) -> usize {
|
pub fn index(&self) -> usize {
|
||||||
let inner: *mut usize = self.inner.get();
|
let inner: *mut usize = self.inner.get();
|
||||||
self.init.call_once(|| {
|
self.init.call_once(|| {
|
||||||
@ -157,9 +173,12 @@ impl InternalField {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A container for VM instrinsic functions
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Intrinsics {
|
pub struct Intrinsics {
|
||||||
|
/// Const pointer to memory grow `Func`.
|
||||||
pub memory_grow: *const Func,
|
pub memory_grow: *const Func,
|
||||||
|
/// Const pointer to memory size `Func`.
|
||||||
pub memory_size: *const Func,
|
pub memory_size: *const Func,
|
||||||
/*pub memory_grow: unsafe extern "C" fn(
|
/*pub memory_grow: unsafe extern "C" fn(
|
||||||
ctx: &mut Ctx,
|
ctx: &mut Ctx,
|
||||||
@ -176,27 +195,33 @@ unsafe impl Send for Intrinsics {}
|
|||||||
unsafe impl Sync for Intrinsics {}
|
unsafe impl Sync for Intrinsics {}
|
||||||
|
|
||||||
impl Intrinsics {
|
impl Intrinsics {
|
||||||
|
/// Memory grow offset
|
||||||
#[allow(clippy::erasing_op)]
|
#[allow(clippy::erasing_op)]
|
||||||
pub fn offset_memory_grow() -> u8 {
|
pub fn offset_memory_grow() -> u8 {
|
||||||
(0 * ::std::mem::size_of::<usize>()) as u8
|
(0 * ::std::mem::size_of::<usize>()) as u8
|
||||||
}
|
}
|
||||||
|
/// Memory size offset
|
||||||
pub fn offset_memory_size() -> u8 {
|
pub fn offset_memory_size() -> u8 {
|
||||||
(1 * ::std::mem::size_of::<usize>()) as u8
|
(1 * ::std::mem::size_of::<usize>()) as u8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Local static memory intrinsics
|
||||||
pub static INTRINSICS_LOCAL_STATIC_MEMORY: Intrinsics = Intrinsics {
|
pub static INTRINSICS_LOCAL_STATIC_MEMORY: Intrinsics = Intrinsics {
|
||||||
memory_grow: vmcalls::local_static_memory_grow as _,
|
memory_grow: vmcalls::local_static_memory_grow as _,
|
||||||
memory_size: vmcalls::local_static_memory_size as _,
|
memory_size: vmcalls::local_static_memory_size as _,
|
||||||
};
|
};
|
||||||
|
/// Local dynamic memory intrinsics
|
||||||
pub static INTRINSICS_LOCAL_DYNAMIC_MEMORY: Intrinsics = Intrinsics {
|
pub static INTRINSICS_LOCAL_DYNAMIC_MEMORY: Intrinsics = Intrinsics {
|
||||||
memory_grow: vmcalls::local_dynamic_memory_grow as _,
|
memory_grow: vmcalls::local_dynamic_memory_grow as _,
|
||||||
memory_size: vmcalls::local_dynamic_memory_size as _,
|
memory_size: vmcalls::local_dynamic_memory_size as _,
|
||||||
};
|
};
|
||||||
|
/// Imported static memory intrinsics
|
||||||
pub static INTRINSICS_IMPORTED_STATIC_MEMORY: Intrinsics = Intrinsics {
|
pub static INTRINSICS_IMPORTED_STATIC_MEMORY: Intrinsics = Intrinsics {
|
||||||
memory_grow: vmcalls::imported_static_memory_grow as _,
|
memory_grow: vmcalls::imported_static_memory_grow as _,
|
||||||
memory_size: vmcalls::imported_static_memory_size as _,
|
memory_size: vmcalls::imported_static_memory_size as _,
|
||||||
};
|
};
|
||||||
|
/// Imported dynamic memory intrinsics
|
||||||
pub static INTRINSICS_IMPORTED_DYNAMIC_MEMORY: Intrinsics = Intrinsics {
|
pub static INTRINSICS_IMPORTED_DYNAMIC_MEMORY: Intrinsics = Intrinsics {
|
||||||
memory_grow: vmcalls::imported_dynamic_memory_grow as _,
|
memory_grow: vmcalls::imported_dynamic_memory_grow as _,
|
||||||
memory_size: vmcalls::imported_dynamic_memory_size as _,
|
memory_size: vmcalls::imported_dynamic_memory_size as _,
|
||||||
@ -509,7 +534,9 @@ pub struct Func(InnerFunc);
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct ImportedFunc {
|
pub struct ImportedFunc {
|
||||||
|
/// Const pointer to `Func`.
|
||||||
pub func: *const Func,
|
pub func: *const Func,
|
||||||
|
/// Mutable pointer to `Ctx`.
|
||||||
pub vmctx: *mut Ctx,
|
pub vmctx: *mut Ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -517,15 +544,18 @@ pub struct ImportedFunc {
|
|||||||
unsafe impl Send for ImportedFunc {}
|
unsafe impl Send for ImportedFunc {}
|
||||||
|
|
||||||
impl ImportedFunc {
|
impl ImportedFunc {
|
||||||
|
/// Offset to func.
|
||||||
#[allow(clippy::erasing_op)] // TODO
|
#[allow(clippy::erasing_op)] // TODO
|
||||||
pub fn offset_func() -> u8 {
|
pub fn offset_func() -> u8 {
|
||||||
0 * (mem::size_of::<usize>() as u8)
|
0 * (mem::size_of::<usize>() as u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Offset to vmctx.
|
||||||
pub fn offset_vmctx() -> u8 {
|
pub fn offset_vmctx() -> u8 {
|
||||||
1 * (mem::size_of::<usize>() as u8)
|
1 * (mem::size_of::<usize>() as u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Size of an `ImportedFunc`.
|
||||||
pub fn size() -> u8 {
|
pub fn size() -> u8 {
|
||||||
mem::size_of::<Self>() as u8
|
mem::size_of::<Self>() as u8
|
||||||
}
|
}
|
||||||
@ -547,15 +577,18 @@ pub struct LocalTable {
|
|||||||
unsafe impl Send for LocalTable {}
|
unsafe impl Send for LocalTable {}
|
||||||
|
|
||||||
impl LocalTable {
|
impl LocalTable {
|
||||||
|
/// Offset base.
|
||||||
#[allow(clippy::erasing_op)] // TODO
|
#[allow(clippy::erasing_op)] // TODO
|
||||||
pub fn offset_base() -> u8 {
|
pub fn offset_base() -> u8 {
|
||||||
0 * (mem::size_of::<usize>() as u8)
|
0 * (mem::size_of::<usize>() as u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Offset count.
|
||||||
pub fn offset_count() -> u8 {
|
pub fn offset_count() -> u8 {
|
||||||
1 * (mem::size_of::<usize>() as u8)
|
1 * (mem::size_of::<usize>() as u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Size of a `LocalTable`.
|
||||||
pub fn size() -> u8 {
|
pub fn size() -> u8 {
|
||||||
mem::size_of::<Self>() as u8
|
mem::size_of::<Self>() as u8
|
||||||
}
|
}
|
||||||
@ -579,15 +612,18 @@ pub struct LocalMemory {
|
|||||||
unsafe impl Send for LocalMemory {}
|
unsafe impl Send for LocalMemory {}
|
||||||
|
|
||||||
impl LocalMemory {
|
impl LocalMemory {
|
||||||
|
/// Offset base.
|
||||||
#[allow(clippy::erasing_op)] // TODO
|
#[allow(clippy::erasing_op)] // TODO
|
||||||
pub fn offset_base() -> u8 {
|
pub fn offset_base() -> u8 {
|
||||||
0 * (mem::size_of::<usize>() as u8)
|
0 * (mem::size_of::<usize>() as u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Offset bound.
|
||||||
pub fn offset_bound() -> u8 {
|
pub fn offset_bound() -> u8 {
|
||||||
1 * (mem::size_of::<usize>() as u8)
|
1 * (mem::size_of::<usize>() as u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Size of a `LocalMemory`.
|
||||||
pub fn size() -> u8 {
|
pub fn size() -> u8 {
|
||||||
mem::size_of::<Self>() as u8
|
mem::size_of::<Self>() as u8
|
||||||
}
|
}
|
||||||
@ -597,24 +633,29 @@ impl LocalMemory {
|
|||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct LocalGlobal {
|
pub struct LocalGlobal {
|
||||||
|
/// Data.
|
||||||
pub data: u128,
|
pub data: u128,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LocalGlobal {
|
impl LocalGlobal {
|
||||||
|
/// Offset data.
|
||||||
#[allow(clippy::erasing_op)] // TODO
|
#[allow(clippy::erasing_op)] // TODO
|
||||||
pub fn offset_data() -> u8 {
|
pub fn offset_data() -> u8 {
|
||||||
0 * (mem::size_of::<usize>() as u8)
|
0 * (mem::size_of::<usize>() as u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A null `LocalGlobal`.
|
||||||
pub fn null() -> Self {
|
pub fn null() -> Self {
|
||||||
Self { data: 0 }
|
Self { data: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Size of a `LocalGlobal`.
|
||||||
pub fn size() -> u8 {
|
pub fn size() -> u8 {
|
||||||
mem::size_of::<Self>() as u8
|
mem::size_of::<Self>() as u8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Identifier for a function signature.
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct SigId(pub u32);
|
pub struct SigId(pub u32);
|
||||||
@ -623,8 +664,11 @@ pub struct SigId(pub u32);
|
|||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Anyfunc {
|
pub struct Anyfunc {
|
||||||
|
/// Const pointer to `Func`.
|
||||||
pub func: *const Func,
|
pub func: *const Func,
|
||||||
|
/// Mutable pointer to `Ctx`.
|
||||||
pub ctx: *mut Ctx,
|
pub ctx: *mut Ctx,
|
||||||
|
/// Sig id of this function
|
||||||
pub sig_id: SigId,
|
pub sig_id: SigId,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -632,6 +676,7 @@ pub struct Anyfunc {
|
|||||||
unsafe impl Send for Anyfunc {}
|
unsafe impl Send for Anyfunc {}
|
||||||
|
|
||||||
impl Anyfunc {
|
impl Anyfunc {
|
||||||
|
/// A null `Anyfunc` value.
|
||||||
pub fn null() -> Self {
|
pub fn null() -> Self {
|
||||||
Self {
|
Self {
|
||||||
func: ptr::null(),
|
func: ptr::null(),
|
||||||
@ -640,19 +685,23 @@ impl Anyfunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The offset for this func.
|
||||||
#[allow(clippy::erasing_op)] // TODO
|
#[allow(clippy::erasing_op)] // TODO
|
||||||
pub fn offset_func() -> u8 {
|
pub fn offset_func() -> u8 {
|
||||||
0 * (mem::size_of::<usize>() as u8)
|
0 * (mem::size_of::<usize>() as u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The offset of the vmctx.
|
||||||
pub fn offset_vmctx() -> u8 {
|
pub fn offset_vmctx() -> u8 {
|
||||||
1 * (mem::size_of::<usize>() as u8)
|
1 * (mem::size_of::<usize>() as u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The offset of the sig id.
|
||||||
pub fn offset_sig_id() -> u8 {
|
pub fn offset_sig_id() -> u8 {
|
||||||
2 * (mem::size_of::<usize>() as u8)
|
2 * (mem::size_of::<usize>() as u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The size of `Anyfunc`.
|
||||||
pub fn size() -> u8 {
|
pub fn size() -> u8 {
|
||||||
mem::size_of::<Self>() as u8
|
mem::size_of::<Self>() as u8
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user