Deny missing docs in runtime core and add missing docs

This commit is contained in:
Brandon Fish
2019-11-10 13:13:18 -06:00
parent 0d644a53db
commit aad390d09d
32 changed files with 674 additions and 15 deletions

View File

@ -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()
} }

View File

@ -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>;
} }

View File

@ -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>,

View File

@ -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,
} }

View File

@ -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>,

View File

@ -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)]

View File

@ -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>>,

View File

@ -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>,

View File

@ -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

View File

@ -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,

View File

@ -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");

View File

@ -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) => {{

View File

@ -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] }
} }

View File

@ -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()

View File

@ -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;

View File

@ -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] }
} }

View File

@ -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,

View File

@ -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);

View File

@ -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,

View File

@ -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
/// Explicit Shadow.
ExplicitShadow, // indicates that all values above this are above the shadow region 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),

View File

@ -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

View File

@ -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>,

View File

@ -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;

View File

@ -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
} }

View File

@ -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,

View File

@ -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>>,

View File

@ -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

View File

@ -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),

View File

@ -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)]

View File

@ -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),

View File

@ -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()
} }

View File

@ -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
} }