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