Split Artifact to have ArtifactCreate that handles only the creation part, not the run part

This commit is contained in:
ptitSeb
2022-03-25 20:00:29 +01:00
parent 1783aa50f1
commit 1f3613c881
28 changed files with 728 additions and 569 deletions

19
Cargo.lock generated
View File

@@ -2765,6 +2765,7 @@ dependencies = [
"thiserror",
"wasm-bindgen",
"wasm-bindgen-test",
"wasmer-artifact",
"wasmer-compiler",
"wasmer-compiler-cranelift",
"wasmer-compiler-llvm",
@@ -2780,6 +2781,17 @@ dependencies = [
"winapi",
]
[[package]]
name = "wasmer-artifact"
version = "2.2.1"
dependencies = [
"enumset",
"loupe",
"thiserror",
"wasmer-compiler",
"wasmer-types",
]
[[package]]
name = "wasmer-bin-fuzz"
version = "0.0.0"
@@ -2858,6 +2870,7 @@ dependencies = [
"tempfile",
"unix_mode",
"wasmer",
"wasmer-artifact",
"wasmer-cache",
"wasmer-compiler",
"wasmer-compiler-cranelift",
@@ -2996,6 +3009,7 @@ dependencies = [
"serde_bytes",
"target-lexicon 0.12.3",
"thiserror",
"wasmer-artifact",
"wasmer-compiler",
"wasmer-types",
"wasmer-vm",
@@ -3010,6 +3024,7 @@ dependencies = [
"loupe",
"serde",
"serde_bytes",
"wasmer-artifact",
"wasmer-compiler",
"wasmer-engine",
"wasmer-types",
@@ -3031,6 +3046,7 @@ dependencies = [
"serde",
"tempfile",
"tracing",
"wasmer-artifact",
"wasmer-compiler",
"wasmer-engine",
"wasmer-object",
@@ -3052,6 +3068,7 @@ dependencies = [
"serde",
"tempfile",
"tracing",
"wasmer-artifact",
"wasmer-compiler",
"wasmer-engine",
"wasmer-object",
@@ -3070,6 +3087,7 @@ dependencies = [
"loupe",
"region",
"rkyv",
"wasmer-artifact",
"wasmer-compiler",
"wasmer-engine",
"wasmer-types",
@@ -3156,6 +3174,7 @@ dependencies = [
"scopeguard",
"serde",
"thiserror",
"wasmer-artifact",
"wasmer-types",
"winapi",
]

View File

@@ -22,6 +22,7 @@ edition = "2018"
# Shared dependencies.
[dependencies]
# - Mandatory shared dependencies.
wasmer-artifact = { path = "../artifact", version = "=2.2.1" }
indexmap = { version = "1.6", features = ["serde-1"] }
cfg-if = "1.0"
thiserror = "1.0"

22
lib/artifact/Cargo.toml Normal file
View File

@@ -0,0 +1,22 @@
[package]
name = "wasmer-artifact"
version = "2.2.1"
description = "Wasmer Artifact abstraction"
categories = ["wasm"]
keywords = ["wasm", "webassembly", "engine"]
authors = ["Wasmer Engineering Team <engineering@wasmer.io>"]
repository = "https://github.com/wasmerio/wasmer"
license = "MIT OR Apache-2.0 WITH LLVM-exception "
readme = "README.md"
edition = "2018"
[dependencies]
wasmer-types = { path = "../types", version = "=2.2.1" }
wasmer-compiler = { path = "../compiler", version = "=2.2.1" }
loupe = "0.1"
thiserror = "1.0"
enumset = "1.0"
[badges]
maintenance = { status = "actively-developed" }

20
lib/artifact/README.md Normal file
View File

@@ -0,0 +1,20 @@
# `wasmer-artifact` [![Build Status](https://github.com/wasmerio/wasmer/workflows/build/badge.svg?style=flat-square)](https://github.com/wasmerio/wasmer/actions?query=workflow%3Abuild) [![Join Wasmer Slack](https://img.shields.io/static/v1?label=Slack&message=join%20chat&color=brighgreen&style=flat-square)](https://slack.wasmer.io) [![MIT License](https://img.shields.io/github/license/wasmerio/wasmer.svg?style=flat-square)](https://github.com/wasmerio/wasmer/blob/master/LICENSE)
This crate is the general abstraction for creating Artifacts in Wasmer.
### Acknowledgments
This project borrowed some of the code of the trap implementation from
the [`wasmtime-api`], the code since then has evolved significantly.
Please check [Wasmer `ATTRIBUTIONS`] to further see licenses and other
attributions of the project.
[`wasmer-engine-universal`]: https://github.com/wasmerio/wasmer/tree/master/lib/engine-universal
[`wasmer-engine-dylib`]: https://github.com/wasmerio/wasmer/tree/master/lib/engine-dylib
[`wasmer-engine-staticlib`]: https://github.com/wasmerio/wasmer/tree/master/lib/engine-staticlib
[`wasmer-engine-dummy`]: https://github.com/wasmerio/wasmer/tree/master/tests/lib/engine-dummy
[`wasmtime-api`]: https://crates.io/crates/wasmtime
[Wasmer `ATTRIBUTIONS`]: https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md

View File

@@ -0,0 +1,166 @@
use crate::{DeserializeError, SerializeError};
use enumset::EnumSet;
use loupe::MemoryUsage;
use std::any::Any;
use std::convert::TryInto;
use std::path::Path;
use std::sync::Arc;
use std::{fs, mem};
use wasmer_compiler::{CpuFeature, Features};
use wasmer_types::entity::PrimaryMap;
use wasmer_types::{
MemoryIndex, MemoryStyle, ModuleInfo, OwnedDataInitializer, TableIndex, TableStyle,
};
/// An `Artifact` is the product that the `Engine`
/// implementation produce and use.
///
/// The `Artifact` contains the compiled data for a given
/// module as well as extra information needed to run the
/// module at runtime, such as [`ModuleInfo`] and [`Features`].
pub trait ArtifactCreate: Send + Sync + Upcastable + MemoryUsage {
/// Return a reference-counted pointer to the module
fn module(&self) -> Arc<ModuleInfo>;
/// Return a pointer to a module.
fn module_ref(&self) -> &ModuleInfo;
/// Gets a mutable reference to the info.
///
/// Note: this will return `None` if the module is already instantiated.
fn module_mut(&mut self) -> Option<&mut ModuleInfo>;
/// Register thie `Artifact` stack frame information into the global scope.
///
/// This is required to ensure that any traps can be properly symbolicated.
fn register_frame_info(&self);
/// Returns the features for this Artifact
fn features(&self) -> &Features;
/// Returns the CPU features for this Artifact
fn cpu_features(&self) -> EnumSet<CpuFeature>;
/// Returns the memory styles associated with this `Artifact`.
fn memory_styles(&self) -> &PrimaryMap<MemoryIndex, MemoryStyle>;
/// Returns the table plans associated with this `Artifact`.
fn table_styles(&self) -> &PrimaryMap<TableIndex, TableStyle>;
/// Returns data initializers to pass to `InstanceHandle::initialize`
fn data_initializers(&self) -> &[OwnedDataInitializer];
/// Serializes an artifact into bytes
fn serialize(&self) -> Result<Vec<u8>, SerializeError>;
/// Serializes an artifact into a file path
fn serialize_to_file(&self, path: &Path) -> Result<(), SerializeError> {
let serialized = self.serialize()?;
fs::write(&path, serialized)?;
Ok(())
}
}
// Implementation of `Upcastable` taken from https://users.rust-lang.org/t/why-does-downcasting-not-work-for-subtraits/33286/7 .
/// Trait needed to get downcasting of `Engine`s to work.
pub trait Upcastable {
/// upcast ref
fn upcast_any_ref(&'_ self) -> &'_ dyn Any;
/// upcast mut ref
fn upcast_any_mut(&'_ mut self) -> &'_ mut dyn Any;
/// upcast boxed dyn
fn upcast_any_box(self: Box<Self>) -> Box<dyn Any>;
}
impl<T: Any + Send + Sync + 'static> Upcastable for T {
#[inline]
fn upcast_any_ref(&'_ self) -> &'_ dyn Any {
self
}
#[inline]
fn upcast_any_mut(&'_ mut self) -> &'_ mut dyn Any {
self
}
#[inline]
fn upcast_any_box(self: Box<Self>) -> Box<dyn Any> {
self
}
}
impl dyn ArtifactCreate + 'static {
/// Try to downcast the artifact into a given type.
#[inline]
pub fn downcast_ref<T: 'static>(&'_ self) -> Option<&'_ T> {
self.upcast_any_ref().downcast_ref::<T>()
}
/// Try to downcast the artifact into a given type mutably.
#[inline]
pub fn downcast_mut<T: 'static>(&'_ mut self) -> Option<&'_ mut T> {
self.upcast_any_mut().downcast_mut::<T>()
}
}
/// Metadata header which holds an ABI version and the length of the remaining
/// metadata.
#[repr(C)]
#[derive(Clone, Copy)]
pub struct MetadataHeader {
magic: [u8; 8],
version: u32,
len: u32,
}
impl MetadataHeader {
/// Current ABI version. Increment this any time breaking changes are made
/// to the format of the serialized data.
const CURRENT_VERSION: u32 = 1;
/// Magic number to identify wasmer metadata.
const MAGIC: [u8; 8] = *b"WASMER\0\0";
/// Length of the metadata header.
pub const LEN: usize = 16;
/// Alignment of the metadata.
pub const ALIGN: usize = 16;
/// Creates a new header for metadata of the given length.
pub fn new(len: usize) -> [u8; 16] {
let header = MetadataHeader {
magic: Self::MAGIC,
version: Self::CURRENT_VERSION,
len: len.try_into().expect("metadata exceeds maximum length"),
};
unsafe { mem::transmute(header) }
}
/// Parses the header and returns the length of the metadata following it.
pub fn parse(bytes: &[u8]) -> Result<usize, DeserializeError> {
if bytes.as_ptr() as usize % 16 != 0 {
return Err(DeserializeError::CorruptedBinary(
"misaligned metadata".to_string(),
));
}
let bytes: [u8; 16] = bytes
.get(..16)
.ok_or_else(|| {
DeserializeError::CorruptedBinary("invalid metadata header".to_string())
})?
.try_into()
.unwrap();
let header: MetadataHeader = unsafe { mem::transmute(bytes) };
if header.magic != Self::MAGIC {
return Err(DeserializeError::Incompatible(
"The provided bytes were not serialized by Wasmer".to_string(),
));
}
if header.version != Self::CURRENT_VERSION {
return Err(DeserializeError::Incompatible(
"The provided bytes were serialized by an incompatible version of Wasmer"
.to_string(),
));
}
Ok(header.len as usize)
}
}

66
lib/artifact/src/error.rs Normal file
View File

@@ -0,0 +1,66 @@
//! The WebAssembly possible errors
use std::io;
use thiserror::Error;
use wasmer_compiler::CompileError;
use wasmer_types::ExternType;
/// The Serialize error can occur when serializing a
/// compiled Module into a binary.
#[derive(Error, Debug)]
pub enum SerializeError {
/// An IO error
#[error(transparent)]
Io(#[from] io::Error),
/// A generic serialization error
#[error("{0}")]
Generic(String),
}
/// The Deserialize error can occur when loading a
/// compiled Module from a binary.
#[derive(Error, Debug)]
pub enum DeserializeError {
/// An IO error
#[error(transparent)]
Io(#[from] io::Error),
/// A generic deserialization error
#[error("{0}")]
Generic(String),
/// Incompatible serialized binary
#[error("incompatible binary: {0}")]
Incompatible(String),
/// The provided binary is corrupted
#[error("corrupted binary: {0}")]
CorruptedBinary(String),
/// The binary was valid, but we got an error when
/// trying to allocate the required resources.
#[error(transparent)]
Compiler(CompileError),
}
/// An ImportError.
///
/// Note: this error is not standard to WebAssembly, but it's
/// useful to determine the import issue on the API side.
#[derive(Error, Debug)]
pub enum ImportError {
/// Incompatible Import Type.
/// This error occurs when the import types mismatch.
#[error("incompatible import type. Expected {0:?} but received {1:?}")]
IncompatibleType(ExternType, ExternType),
/// Unknown Import.
/// This error occurs when an import was expected but not provided.
#[error("unknown import. Expected {0:?}")]
UnknownImport(ExternType),
}
/// An error while preinstantiating a module.
///
#[derive(Error, Debug)]
pub enum PreInstantiationError {
/// The module was compiled with a CPU feature that is not available on
/// the current host.
#[error("module compiled with CPU feature that is missing from host")]
CpuFeature(String),
}

View File

@@ -0,0 +1,17 @@
/// A placeholder byte-sized type which is just used to provide some amount of type
/// safety when dealing with pointers to JIT-compiled function bodies. Note that it's
/// deliberately not Copy, as we shouldn't be carelessly copying function body bytes
/// around.
#[repr(C)]
pub struct VMFunctionBody(u8);
#[cfg(test)]
mod test_vmfunction_body {
use super::VMFunctionBody;
use std::mem::size_of;
#[test]
fn check_vmfunction_body_offsets() {
assert_eq!(size_of::<VMFunctionBody>(), 1);
}
}

55
lib/artifact/src/lib.rs Normal file
View File

@@ -0,0 +1,55 @@
//! Generic Artifact abstraction for Wasmer Engines.
#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)]
#![warn(unused_import_braces)]
#![cfg_attr(
feature = "cargo-clippy",
allow(clippy::new_without_default, clippy::new_without_default)
)]
#![cfg_attr(
feature = "cargo-clippy",
warn(
clippy::float_arithmetic,
clippy::mut_mut,
clippy::nonminimal_bool,
clippy::option_map_unwrap_or,
clippy::option_map_unwrap_or_else,
clippy::print_stdout,
clippy::unicode_not_nfc,
clippy::use_self
)
)]
mod artifact;
mod error;
mod funcbody;
pub use crate::artifact::{ArtifactCreate, MetadataHeader, Upcastable};
pub use crate::error::{DeserializeError, ImportError, PreInstantiationError, SerializeError};
pub use crate::funcbody::VMFunctionBody;
use loupe::MemoryUsage;
/// Version number of this crate.
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
/// A safe wrapper around `VMFunctionBody`.
#[derive(Clone, Copy, Debug, MemoryUsage)]
#[repr(transparent)]
pub struct FunctionBodyPtr(pub *const VMFunctionBody);
impl std::ops::Deref for FunctionBodyPtr {
type Target = *const VMFunctionBody;
fn deref(&self) -> &Self::Target {
&self.0
}
}
/// # Safety
/// The VMFunctionBody that this points to is opaque, so there's no data to
/// read or write through this pointer. This is essentially a usize.
unsafe impl Send for FunctionBodyPtr {}
/// # Safety
/// The VMFunctionBody that this points to is opaque, so there's no data to
/// read or write through this pointer. This is essentially a usize.
unsafe impl Sync for FunctionBodyPtr {}

View File

@@ -24,6 +24,7 @@ doc = false
required-features = ["headless"]
[dependencies]
wasmer-artifact = { version = "=2.2.1", path = "../artifact" }
wasmer-compiler = { version = "=2.2.1", path = "../compiler" }
wasmer-compiler-singlepass = { version = "=2.2.1", path = "../compiler-singlepass", optional = true }
wasmer-engine = { version = "=2.2.1", path = "../engine" }

View File

@@ -11,6 +11,7 @@ readme = "README.md"
edition = "2018"
[dependencies]
wasmer-artifact = { path = "../artifact", version = "=2.2.1" }
wasmer-types = { path = "../types", version = "=2.2.1" }
wasmer-compiler = { path = "../compiler", version = "=2.2.1" }
wasmer-vm = { path = "../vm", version = "=2.2.1", features = ["enable-rkyv"] }

View File

@@ -19,6 +19,7 @@ use tempfile::NamedTempFile;
use tracing::log::error;
#[cfg(feature = "compiler")]
use tracing::trace;
use wasmer_artifact::ArtifactCreate;
use wasmer_compiler::{
Architecture, CompileError, CompiledFunctionFrameInfo, CpuFeature, Features,
FunctionAddressMap, OperatingSystem, Symbol, SymbolRegistry, Triple,
@@ -678,7 +679,7 @@ impl DylibArtifact {
}
}
impl Artifact for DylibArtifact {
impl ArtifactCreate for DylibArtifact {
fn module(&self) -> Arc<ModuleInfo> {
self.metadata.compile_info.module.clone()
}
@@ -841,30 +842,6 @@ impl Artifact for DylibArtifact {
&self.metadata.compile_info.table_styles
}
fn finished_functions(&self) -> &BoxedSlice<LocalFunctionIndex, FunctionBodyPtr> {
&self.finished_functions
}
fn finished_function_call_trampolines(&self) -> &BoxedSlice<SignatureIndex, VMTrampoline> {
&self.finished_function_call_trampolines
}
fn finished_dynamic_function_trampolines(&self) -> &BoxedSlice<FunctionIndex, FunctionBodyPtr> {
&self.finished_dynamic_function_trampolines
}
fn signatures(&self) -> &BoxedSlice<SignatureIndex, VMSharedSignatureIndex> {
&self.signatures
}
fn func_data_registry(&self) -> &FuncDataRegistry {
&self.func_data_registry
}
fn preinstantiate(&self) -> Result<(), InstantiationError> {
Ok(())
}
/// Serialize a `DylibArtifact`.
fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
Ok(std::fs::read(&self.dylib_path)?)
@@ -908,3 +885,28 @@ impl Artifact for DylibArtifact {
Ok(())
}
}
impl Artifact for DylibArtifact {
fn finished_functions(&self) -> &BoxedSlice<LocalFunctionIndex, FunctionBodyPtr> {
&self.finished_functions
}
fn finished_function_call_trampolines(&self) -> &BoxedSlice<SignatureIndex, VMTrampoline> {
&self.finished_function_call_trampolines
}
fn finished_dynamic_function_trampolines(&self) -> &BoxedSlice<FunctionIndex, FunctionBodyPtr> {
&self.finished_dynamic_function_trampolines
}
fn signatures(&self) -> &BoxedSlice<SignatureIndex, VMSharedSignatureIndex> {
&self.signatures
}
fn func_data_registry(&self) -> &FuncDataRegistry {
&self.func_data_registry
}
fn preinstantiate(&self) -> Result<(), InstantiationError> {
Ok(())
}
}

View File

@@ -11,6 +11,7 @@ readme = "README.md"
edition = "2018"
[dependencies]
wasmer-artifact = { path = "../artifact", version = "=2.2.1" }
wasmer-types = { path = "../types", version = "=2.2.1" }
wasmer-compiler = { path = "../compiler", version = "=2.2.1" }
wasmer-vm = { path = "../vm", version = "=2.2.1" }

View File

@@ -9,6 +9,7 @@ use std::collections::BTreeMap;
use std::error::Error;
use std::mem;
use std::sync::Arc;
use wasmer_artifact::ArtifactCreate;
use wasmer_compiler::{
CompileError, CpuFeature, Features, OperatingSystem, SymbolRegistry, Triple,
};
@@ -436,7 +437,7 @@ impl StaticlibArtifact {
}
}
impl Artifact for StaticlibArtifact {
impl ArtifactCreate for StaticlibArtifact {
fn module(&self) -> Arc<ModuleInfo> {
self.metadata.compile_info.module.clone()
}
@@ -473,6 +474,12 @@ impl Artifact for StaticlibArtifact {
&self.metadata.compile_info.table_styles
}
/// Serialize a StaticlibArtifact
fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
Ok(self.module_bytes.clone())
}
}
impl Artifact for StaticlibArtifact {
fn finished_functions(&self) -> &BoxedSlice<LocalFunctionIndex, FunctionBodyPtr> {
&self.finished_functions
}
@@ -492,7 +499,6 @@ impl Artifact for StaticlibArtifact {
fn func_data_registry(&self) -> &FuncDataRegistry {
&self.func_data_registry
}
fn preinstantiate(&self) -> Result<(), InstantiationError> {
if self.is_compiled {
panic!(
@@ -502,9 +508,4 @@ impl Artifact for StaticlibArtifact {
}
Ok(())
}
/// Serialize a StaticlibArtifact
fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
Ok(self.module_bytes.clone())
}
}

View File

@@ -11,6 +11,7 @@ readme = "README.md"
edition = "2018"
[dependencies]
wasmer-artifact = { path = "../artifact", version = "=2.2.1" }
wasmer-types = { path = "../types", version = "=2.2.1", features = [
"enable-rkyv",
] }
@@ -21,7 +22,6 @@ wasmer-compiler = { path = "../compiler", version = "=2.2.1", features = [
wasmer-vm = { path = "../vm", version = "=2.2.1", features = ["enable-rkyv"] }
wasmer-engine = { path = "../engine", version = "=2.2.1" }
# flexbuffers = { path = "../../../flatbuffers/rust/flexbuffers", version = "0.1.0" }
region = { version = "3.0" }
cfg-if = "1.0"
leb128 = "0.2"
rkyv = "0.7.20"
@@ -29,6 +29,9 @@ loupe = "0.1"
enumset = "1.0"
enum-iterator = "0.7.0"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
region = { version = "3.0" }
[target.'cfg(target_os = "windows")'.dependencies]
winapi = { version = "0.3", features = ["winnt", "impl-default"] }

View File

@@ -11,6 +11,7 @@ use enumset::EnumSet;
use loupe::MemoryUsage;
use std::mem;
use std::sync::{Arc, Mutex};
use wasmer_artifact::ArtifactCreate;
use wasmer_compiler::{CompileError, CpuFeature, Features, Triple};
#[cfg(feature = "compiler")]
use wasmer_compiler::{CompileModuleInfo, ModuleEnvironment, ModuleMiddlewareChain};
@@ -267,7 +268,7 @@ impl UniversalArtifact {
}
}
impl Artifact for UniversalArtifact {
impl ArtifactCreate for UniversalArtifact {
fn module(&self) -> Arc<ModuleInfo> {
self.serializable.compile_info.module.clone()
}
@@ -324,6 +325,19 @@ impl Artifact for UniversalArtifact {
&self.serializable.compile_info.table_styles
}
fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
let serialized_data = self.serializable.serialize()?;
assert!(mem::align_of::<SerializableModule>() <= MetadataHeader::ALIGN);
let mut metadata_binary = vec![];
metadata_binary.extend(Self::MAGIC_HEADER);
metadata_binary.extend(MetadataHeader::new(serialized_data.len()));
metadata_binary.extend(serialized_data);
Ok(metadata_binary)
}
}
impl Artifact for UniversalArtifact {
fn finished_functions(&self) -> &BoxedSlice<LocalFunctionIndex, FunctionBodyPtr> {
&self.finished_functions
}
@@ -343,14 +357,4 @@ impl Artifact for UniversalArtifact {
fn func_data_registry(&self) -> &FuncDataRegistry {
&self.func_data_registry
}
fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
let serialized_data = self.serializable.serialize()?;
assert!(mem::align_of::<SerializableModule>() <= MetadataHeader::ALIGN);
let mut metadata_binary = vec![];
metadata_binary.extend(Self::MAGIC_HEADER);
metadata_binary.extend(MetadataHeader::new(serialized_data.len()));
metadata_binary.extend(serialized_data);
Ok(metadata_binary)
}
}

View File

@@ -13,6 +13,7 @@ edition = "2018"
[dependencies]
wasmer-types = { path = "../types", version = "=2.2.1" }
wasmer-compiler = { path = "../compiler", version = "=2.2.1" }
wasmer-artifact = { path = "../artifact", version = "=2.2.1" }
target-lexicon = { version = "0.12.2", default-features = false }
# flexbuffers = { path = "../../../flatbuffers/rust/flexbuffers", version = "0.1.0" }
backtrace = "0.3"

View File

@@ -1,63 +1,26 @@
use crate::{
resolve_imports, DeserializeError, InstantiationError, Resolver, RuntimeError, SerializeError,
Tunables,
};
use enumset::EnumSet;
use crate::{resolve_imports, InstantiationError, Resolver, RuntimeError, Tunables};
use loupe::MemoryUsage;
use std::any::Any;
use std::convert::TryInto;
use std::path::Path;
use std::sync::Arc;
use std::{fs, mem};
use wasmer_compiler::{CpuFeature, Features};
use wasmer_types::entity::{BoxedSlice, PrimaryMap};
use wasmer_types::{
DataInitializer, FunctionIndex, LocalFunctionIndex, MemoryIndex, ModuleInfo,
OwnedDataInitializer, SignatureIndex, TableIndex,
};
pub use wasmer_artifact::MetadataHeader;
use wasmer_artifact::{ArtifactCreate, Upcastable};
use wasmer_compiler::CpuFeature;
use wasmer_types::entity::BoxedSlice;
use wasmer_types::{DataInitializer, FunctionIndex, LocalFunctionIndex, SignatureIndex};
use wasmer_vm::{
FuncDataRegistry, FunctionBodyPtr, InstanceAllocator, InstanceHandle, MemoryStyle, TableStyle,
TrapHandler, VMSharedSignatureIndex, VMTrampoline,
FuncDataRegistry, FunctionBodyPtr, InstanceAllocator, InstanceHandle, TrapHandler,
VMSharedSignatureIndex, VMTrampoline,
};
/// An `Artifact` is the product that the `Engine`
/// implementation produce and use.
///
/// The `Artifact` contains the compiled data for a given
/// module as well as extra information needed to run the
/// An `Artifact` is the product that the `Engine`
/// implementation produce and use.
///
/// The `ArtifactRun` contains the extra information needed to run the
/// module at runtime, such as [`ModuleInfo`] and [`Features`].
pub trait Artifact: Send + Sync + Upcastable + MemoryUsage {
/// Return a reference-counted pointer to the module
fn module(&self) -> Arc<ModuleInfo>;
/// Return a pointer to a module.
fn module_ref(&self) -> &ModuleInfo;
/// Gets a mutable reference to the info.
///
/// Note: this will return `None` if the module is already instantiated.
fn module_mut(&mut self) -> Option<&mut ModuleInfo>;
/// Register thie `Artifact` stack frame information into the global scope.
///
/// This is required to ensure that any traps can be properly symbolicated.
fn register_frame_info(&self);
/// Returns the features for this Artifact
fn features(&self) -> &Features;
/// Returns the CPU features for this Artifact
fn cpu_features(&self) -> EnumSet<CpuFeature>;
/// Returns the memory styles associated with this `Artifact`.
fn memory_styles(&self) -> &PrimaryMap<MemoryIndex, MemoryStyle>;
/// Returns the table plans associated with this `Artifact`.
fn table_styles(&self) -> &PrimaryMap<TableIndex, TableStyle>;
/// Returns data initializers to pass to `InstanceHandle::initialize`
fn data_initializers(&self) -> &[OwnedDataInitializer];
pub trait Artifact: Send + Sync + Upcastable + MemoryUsage + ArtifactCreate {
/// Returns the functions allocated in memory or this `Artifact`
/// ready to be run.
fn finished_functions(&self) -> &BoxedSlice<LocalFunctionIndex, FunctionBodyPtr>;
@@ -76,21 +39,10 @@ pub trait Artifact: Send + Sync + Upcastable + MemoryUsage {
/// Get the func data registry
fn func_data_registry(&self) -> &FuncDataRegistry;
/// Serializes an artifact into bytes
fn serialize(&self) -> Result<Vec<u8>, SerializeError>;
/// Serializes an artifact into a file path
fn serialize_to_file(&self, path: &Path) -> Result<(), SerializeError> {
let serialized = self.serialize()?;
fs::write(&path, serialized)?;
Ok(())
}
/// Do preinstantiation logic that is executed before instantiating
fn preinstantiate(&self) -> Result<(), InstantiationError> {
Ok(())
}
/// Crate an `Instance` from this `Artifact`.
///
/// # Safety
@@ -168,7 +120,6 @@ pub trait Artifact: Send + Sync + Upcastable + MemoryUsage {
.map_err(|trap| InstantiationError::Start(RuntimeError::from_trap(trap)))?;
Ok(handle)
}
/// Finishes the instantiation of a just created `InstanceHandle`.
///
/// # Safety
@@ -193,29 +144,6 @@ pub trait Artifact: Send + Sync + Upcastable + MemoryUsage {
}
}
// Implementation of `Upcastable` taken from https://users.rust-lang.org/t/why-does-downcasting-not-work-for-subtraits/33286/7 .
/// Trait needed to get downcasting of `Engine`s to work.
pub trait Upcastable {
fn upcast_any_ref(&'_ self) -> &'_ dyn Any;
fn upcast_any_mut(&'_ mut self) -> &'_ mut dyn Any;
fn upcast_any_box(self: Box<Self>) -> Box<dyn Any>;
}
impl<T: Any + Send + Sync + 'static> Upcastable for T {
#[inline]
fn upcast_any_ref(&'_ self) -> &'_ dyn Any {
self
}
#[inline]
fn upcast_any_mut(&'_ mut self) -> &'_ mut dyn Any {
self
}
#[inline]
fn upcast_any_box(self: Box<Self>) -> Box<dyn Any> {
self
}
}
impl dyn Artifact + 'static {
/// Try to downcast the artifact into a given type.
#[inline]
@@ -229,67 +157,3 @@ impl dyn Artifact + 'static {
self.upcast_any_mut().downcast_mut::<T>()
}
}
/// Metadata header which holds an ABI version and the length of the remaining
/// metadata.
#[repr(C)]
#[derive(Clone, Copy)]
pub struct MetadataHeader {
magic: [u8; 8],
version: u32,
len: u32,
}
impl MetadataHeader {
/// Current ABI version. Increment this any time breaking changes are made
/// to the format of the serialized data.
const CURRENT_VERSION: u32 = 1;
/// Magic number to identify wasmer metadata.
const MAGIC: [u8; 8] = *b"WASMER\0\0";
/// Length of the metadata header.
pub const LEN: usize = 16;
/// Alignment of the metadata.
pub const ALIGN: usize = 16;
/// Creates a new header for metadata of the given length.
pub fn new(len: usize) -> [u8; 16] {
let header = MetadataHeader {
magic: Self::MAGIC,
version: Self::CURRENT_VERSION,
len: len.try_into().expect("metadata exceeds maximum length"),
};
unsafe { mem::transmute(header) }
}
/// Parses the header and returns the length of the metadata following it.
pub fn parse(bytes: &[u8]) -> Result<usize, DeserializeError> {
if bytes.as_ptr() as usize % 16 != 0 {
return Err(DeserializeError::CorruptedBinary(
"misaligned metadata".to_string(),
));
}
let bytes: [u8; 16] = bytes
.get(..16)
.ok_or_else(|| {
DeserializeError::CorruptedBinary("invalid metadata header".to_string())
})?
.try_into()
.unwrap();
let header: MetadataHeader = unsafe { mem::transmute(bytes) };
if header.magic != Self::MAGIC {
return Err(DeserializeError::Incompatible(
"The provided bytes were not serialized by Wasmer".to_string(),
));
}
if header.version != Self::CURRENT_VERSION {
return Err(DeserializeError::Incompatible(
"The provided bytes were serialized by an incompatible version of Wasmer"
.to_string(),
));
}
Ok(header.len as usize)
}
}

View File

@@ -1,60 +1,7 @@
//! The WebAssembly possible errors
use crate::trap::RuntimeError;
use std::io;
use thiserror::Error;
use wasmer_compiler::CompileError;
use wasmer_types::ExternType;
/// The Serialize error can occur when serializing a
/// compiled Module into a binary.
#[derive(Error, Debug)]
pub enum SerializeError {
/// An IO error
#[error(transparent)]
Io(#[from] io::Error),
/// A generic serialization error
#[error("{0}")]
Generic(String),
}
/// The Deserialize error can occur when loading a
/// compiled Module from a binary.
#[derive(Error, Debug)]
pub enum DeserializeError {
/// An IO error
#[error(transparent)]
Io(#[from] io::Error),
/// A generic deserialization error
#[error("{0}")]
Generic(String),
/// Incompatible serialized binary
#[error("incompatible binary: {0}")]
Incompatible(String),
/// The provided binary is corrupted
#[error("corrupted binary: {0}")]
CorruptedBinary(String),
/// The binary was valid, but we got an error when
/// trying to allocate the required resources.
#[error(transparent)]
Compiler(CompileError),
}
/// An ImportError.
///
/// Note: this error is not standard to WebAssembly, but it's
/// useful to determine the import issue on the API side.
#[derive(Error, Debug)]
pub enum ImportError {
/// Incompatible Import Type.
/// This error occurs when the import types mismatch.
#[error("incompatible import type. Expected {0:?} but received {1:?}")]
IncompatibleType(ExternType, ExternType),
/// Unknown Import.
/// This error occurs when an import was expected but not provided.
#[error("unknown import. Expected {0:?}")]
UnknownImport(ExternType),
}
pub use wasmer_artifact::{DeserializeError, ImportError, SerializeError};
/// The WebAssembly.LinkError object indicates an error during
/// module instantiation (besides traps from the start function).

View File

@@ -31,11 +31,9 @@ mod resolver;
mod trap;
mod tunables;
pub use crate::artifact::{Artifact, MetadataHeader};
pub use crate::artifact::Artifact;
pub use crate::engine::{Engine, EngineId};
pub use crate::error::{
DeserializeError, ImportError, InstantiationError, LinkError, SerializeError,
};
pub use crate::error::{InstantiationError, LinkError};
pub use crate::export::{Export, ExportFunction, ExportFunctionMetadata};
pub use crate::resolver::{
resolve_imports, ChainableNamedResolver, NamedResolver, NamedResolverChain, NullResolver,
@@ -43,6 +41,8 @@ pub use crate::resolver::{
};
pub use crate::trap::*;
pub use crate::tunables::Tunables;
pub use wasmer_artifact::{ArtifactCreate, MetadataHeader};
pub use wasmer_artifact::{DeserializeError, ImportError, SerializeError};
/// Version number of this crate.
pub const VERSION: &str = env!("CARGO_PKG_VERSION");

View File

@@ -2,6 +2,7 @@ use enum_iterator::IntoEnumIterator;
use loupe::MemoryUsage;
#[cfg(feature = "enable-rkyv")]
use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
#[cfg(feature = "enable-serde")]
use serde::{Deserialize, Serialize};
use std::fmt;
@@ -12,9 +13,8 @@ use std::fmt;
feature = "enable-rkyv",
derive(RkyvSerialize, RkyvDeserialize, Archive)
)]
#[derive(
Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, MemoryUsage, IntoEnumIterator,
)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, MemoryUsage, IntoEnumIterator)]
pub enum LibCall {
/// ceil.f32
CeilF32,

View File

@@ -2,6 +2,7 @@ use crate::Pages;
use loupe::MemoryUsage;
#[cfg(feature = "enable-rkyv")]
use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
#[cfg(feature = "enable-serde")]
use serde::{Deserialize, Serialize};
use thiserror::Error;
@@ -48,11 +49,12 @@ pub enum MemoryError {
}
/// Implementation styles for WebAssembly linear memory.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, MemoryUsage)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, MemoryUsage)]
#[cfg_attr(
feature = "enable-rkyv",
derive(RkyvSerialize, RkyvDeserialize, Archive)
)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub enum MemoryStyle {
/// The actual memory can be resized and moved.
Dynamic {

View File

@@ -1,14 +1,16 @@
use loupe::MemoryUsage;
#[cfg(feature = "enable-rkyv")]
use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
#[cfg(feature = "enable-serde")]
use serde::{Deserialize, Serialize};
/// Implementation styles for WebAssembly tables.
#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, MemoryUsage)]
#[derive(Debug, Clone, Hash, PartialEq, Eq, MemoryUsage)]
#[cfg_attr(
feature = "enable-rkyv",
derive(RkyvSerialize, RkyvDeserialize, Archive)
)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub enum TableStyle {
/// Signatures are stored in the table and checked in the caller.
CallerChecksSignature,

View File

@@ -9,6 +9,7 @@ use core::str::FromStr;
use loupe::MemoryUsage;
#[cfg(feature = "enable-rkyv")]
use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
#[cfg(feature = "enable-serde")]
use serde::{Deserialize, Serialize};
use std::error::Error;
use thiserror::Error;
@@ -16,11 +17,12 @@ use thiserror::Error;
/// A trap code describing the reason for a trap.
///
/// All trap instructions have an explicit trap code.
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize, Deserialize, Error, MemoryUsage)]
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Error, MemoryUsage)]
#[cfg_attr(
feature = "enable-rkyv",
derive(RkyvSerialize, RkyvDeserialize, Archive)
)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
#[repr(u32)]
pub enum TrapCode {
/// The current stack space was exhausted.

View File

@@ -12,6 +12,7 @@ edition = "2018"
[dependencies]
wasmer-types = { path = "../types", version = "=2.2.1" }
wasmer-artifact = { path = "../artifact", version = "=2.2.1" }
libc = { version = "^0.2", default-features = false }
memoffset = "0.6"
indexmap = { version = "1.6", features = ["serde-1"] }

View File

@@ -50,12 +50,11 @@ pub use crate::sig_registry::SignatureRegistry;
pub use crate::table::{LinearTable, Table, TableElement};
pub use crate::trap::*;
pub use crate::vmcontext::{
VMCallerCheckedAnyfunc, VMContext, VMDynamicFunctionContext, VMFunctionBody,
VMFunctionEnvironment, VMFunctionImport, VMFunctionKind, VMGlobalDefinition, VMGlobalImport,
VMMemoryDefinition, VMMemoryImport, VMSharedSignatureIndex, VMTableDefinition, VMTableImport,
VMTrampoline,
VMCallerCheckedAnyfunc, VMContext, VMDynamicFunctionContext, VMFunctionEnvironment,
VMFunctionImport, VMFunctionKind, VMGlobalDefinition, VMGlobalImport, VMMemoryDefinition,
VMMemoryImport, VMSharedSignatureIndex, VMTableDefinition, VMTableImport, VMTrampoline,
};
use loupe::MemoryUsage;
pub use wasmer_artifact::{FunctionBodyPtr, VMFunctionBody};
pub use wasmer_types::LibCall;
pub use wasmer_types::TableStyle;
#[deprecated(
@@ -71,28 +70,6 @@ pub use wasmer_types::{
/// Version number of this crate.
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
/// A safe wrapper around `VMFunctionBody`.
#[derive(Clone, Copy, Debug, MemoryUsage)]
#[repr(transparent)]
pub struct FunctionBodyPtr(pub *const VMFunctionBody);
impl std::ops::Deref for FunctionBodyPtr {
type Target = *const VMFunctionBody;
fn deref(&self) -> &Self::Target {
&self.0
}
}
/// # Safety
/// The VMFunctionBody that this points to is opaque, so there's no data to
/// read or write through this pointer. This is essentially a usize.
unsafe impl Send for FunctionBodyPtr {}
/// # Safety
/// The VMFunctionBody that this points to is opaque, so there's no data to
/// read or write through this pointer. This is essentially a usize.
unsafe impl Sync for FunctionBodyPtr {}
/// Pointers to section data.
#[derive(Clone, Copy, Debug)]
#[repr(transparent)]

View File

@@ -20,6 +20,7 @@ use std::mem;
use std::ptr::{self, NonNull};
use std::sync::Arc;
use std::u32;
pub use wasmer_artifact::VMFunctionBody;
/// Union representing the first parameter passed when calling a function.
///
@@ -169,24 +170,6 @@ mod test_vmdynamicfunction_import_context {
}
}
/// A placeholder byte-sized type which is just used to provide some amount of type
/// safety when dealing with pointers to JIT-compiled function bodies. Note that it's
/// deliberately not Copy, as we shouldn't be carelessly copying function body bytes
/// around.
#[repr(C)]
pub struct VMFunctionBody(u8);
#[cfg(test)]
mod test_vmfunction_body {
use super::VMFunctionBody;
use std::mem::size_of;
#[test]
fn check_vmfunction_body_offsets() {
assert_eq!(size_of::<VMFunctionBody>(), 1);
}
}
/// A function kind is a calling convention into and out of wasm code.
#[derive(Debug, Copy, Clone, PartialEq, MemoryUsage)]
#[repr(C)]
@@ -799,9 +782,8 @@ pub struct VMSharedSignatureIndex(u32);
#[cfg(test)]
mod test_vmshared_signature_index {
use super::VMSharedSignatureIndex;
use crate::vmoffsets::{TargetSharedSignatureIndex, VMOffsets};
use std::mem::size_of;
use wasmer_types::ModuleInfo;
use wasmer_types::{ModuleInfo, TargetSharedSignatureIndex, VMOffsets};
#[test]
fn check_vmshared_signature_index() {

View File

@@ -8,6 +8,7 @@ edition = "2018"
publish = false
[dependencies]
wasmer-artifact = { path = "../../../lib/artifact", version = "=2.2.1" }
wasmer-types = { path = "../../../lib/types", version = "=2.2.1" }
wasmer-compiler = { path = "../../../lib/compiler", version = "=2.2.1" }
wasmer-vm = { path = "../../../lib/vm", version = "=2.2.1" }

View File

@@ -7,6 +7,7 @@ use loupe::MemoryUsage;
#[cfg(feature = "serialize")]
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use wasmer_artifact::ArtifactCreate;
#[cfg(feature = "compiler")]
use wasmer_compiler::ModuleEnvironment;
use wasmer_compiler::{CompileError, CpuFeature};
@@ -193,7 +194,7 @@ impl DummyArtifact {
}
}
impl Artifact for DummyArtifact {
impl ArtifactCreate for DummyArtifact {
fn module(&self) -> Arc<ModuleInfo> {
self.metadata.module.clone()
}
@@ -229,7 +230,25 @@ impl Artifact for DummyArtifact {
fn table_styles(&self) -> &PrimaryMap<TableIndex, TableStyle> {
&self.metadata.table_styles
}
#[cfg(feature = "serialize")]
fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
let bytes = bincode::serialize(&self.metadata)
.map_err(|e| SerializeError::Generic(format!("{:?}", e)))?;
// Prepend the header.
let mut serialized = Self::MAGIC_HEADER.to_vec();
serialized.extend(bytes);
Ok(serialized)
}
#[cfg(not(feature = "serialize"))]
fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
Err(SerializeError::Generic(
"The serializer feature is not enabled in the DummyEngine",
))
}
}
impl Artifact for DummyArtifact {
fn finished_functions(&self) -> &BoxedSlice<LocalFunctionIndex, FunctionBodyPtr> {
&self.finished_functions
}
@@ -249,22 +268,4 @@ impl Artifact for DummyArtifact {
fn func_data_registry(&self) -> &FuncDataRegistry {
&self.func_data_registry
}
#[cfg(feature = "serialize")]
fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
let bytes = bincode::serialize(&self.metadata)
.map_err(|e| SerializeError::Generic(format!("{:?}", e)))?;
// Prepend the header.
let mut serialized = Self::MAGIC_HEADER.to_vec();
serialized.extend(bytes);
Ok(serialized)
}
#[cfg(not(feature = "serialize"))]
fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
Err(SerializeError::Generic(
"The serializer feature is not enabled in the DummyEngine",
))
}
}