Skip to content

Commit

Permalink
Split Artifact to have ArtifactCreate that handles only the creation …
Browse files Browse the repository at this point in the history
…part, not the run part
  • Loading branch information
ptitSeb committed May 3, 2022
1 parent 1783aa5 commit 1f3613c
Show file tree
Hide file tree
Showing 28 changed files with 728 additions and 569 deletions.
19 changes: 19 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions lib/api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
22 changes: 22 additions & 0 deletions lib/artifact/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>"]
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 changes: 20 additions & 0 deletions lib/artifact/README.md
Original file line number Diff line number Diff line change
@@ -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
166 changes: 166 additions & 0 deletions lib/artifact/src/artifact.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 66 additions & 0 deletions lib/artifact/src/error.rs
Original file line number Diff line number Diff line change
@@ -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),
}
17 changes: 17 additions & 0 deletions lib/artifact/src/funcbody.rs
Original file line number Diff line number Diff line change
@@ -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);
}
}
Loading

0 comments on commit 1f3613c

Please sign in to comment.