Simplified serialization

This commit is contained in:
Syrus
2020-05-20 21:06:12 -07:00
parent 2c66e2ac3c
commit 3d6ff89da0
10 changed files with 80 additions and 106 deletions

7
Cargo.lock generated
View File

@@ -444,12 +444,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d9d8664cf849d7d0f3114a3a387d2f5e4303176d746d5a951aaddc66dfe9240"
[[package]]
name = "downcast-rs"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52ba6eb47c2131e784a38b726eb54c1e1484904f013e576a25354d0124161af6"
[[package]]
name = "dynasm"
version = "0.5.2"
@@ -1925,7 +1919,6 @@ version = "0.16.2"
dependencies = [
"backtrace",
"bincode",
"downcast-rs",
"lazy_static",
"more-asserts",
"region",

View File

@@ -159,7 +159,7 @@ impl Module {
/// let serialized = module.serialize()?;
/// ```
pub fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
self.store.engine().serialize(self.artifact.borrow())
self.artifact.serialize()
}
/// Deserializes a a serialized Module binary into a `Module`.

View File

@@ -33,6 +33,13 @@ pub struct JITArtifact {
}
impl JITArtifact {
const MAGIC_HEADER: &'static [u8] = b"\0wasmer-jit";
/// Check if the provided bytes look like a serialized `JITArtifact`.
pub fn is_deserializable(bytes: &[u8]) -> bool {
bytes.starts_with(Self::MAGIC_HEADER)
}
/// Compile a data buffer into a `JITArtifact`, which may then be instantiated.
#[cfg(feature = "compiler")]
pub fn new(jit: &JITEngine, data: &[u8]) -> Result<Self, CompileError> {
@@ -123,21 +130,20 @@ impl JITArtifact {
))
}
/// Serialize a JITArtifact
pub fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
// let mut s = flexbuffers::FlexbufferSerializer::new();
// self.serializable.serialize(&mut s).map_err(|e| SerializeError::Generic(format!("{:?}", e)));
// Ok(s.take_buffer())
bincode::serialize(&self.serializable)
.map_err(|e| SerializeError::Generic(format!("{:?}", e)))
}
/// Deserialize a JITArtifact
pub fn deserialize(jit: &JITEngine, bytes: &[u8]) -> Result<Self, DeserializeError> {
if !Self::is_deserializable(bytes) {
return Err(DeserializeError::Incompatible(
"The provided bytes are not wasmer-jit".to_string(),
));
}
let inner_bytes = &bytes[Self::MAGIC_HEADER.len()..];
// let r = flexbuffers::Reader::get_root(bytes).map_err(|e| DeserializeError::CorruptedBinary(format!("{:?}", e)))?;
// let serializable = SerializableModule::deserialize(r).map_err(|e| DeserializeError::CorruptedBinary(format!("{:?}", e)))?;
let serializable: SerializableModule = bincode::deserialize(bytes)
let serializable: SerializableModule = bincode::deserialize(inner_bytes)
.map_err(|e| DeserializeError::CorruptedBinary(format!("{:?}", e)))?;
Self::from_parts(&mut jit.inner_mut(), serializable).map_err(DeserializeError::Compiler)
@@ -242,4 +248,17 @@ impl Artifact for JITArtifact {
fn signatures(&self) -> &BoxedSlice<SignatureIndex, VMSharedSignatureIndex> {
&self.signatures
}
fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
// let mut s = flexbuffers::FlexbufferSerializer::new();
// self.serializable.serialize(&mut s).map_err(|e| SerializeError::Generic(format!("{:?}", e)));
// Ok(s.take_buffer())
let bytes = bincode::serialize(&self.serializable)
.map_err(|e| SerializeError::Generic(format!("{:?}", e)))?;
// We append the header
let mut serialized = Self::MAGIC_HEADER.to_vec();
serialized.extend(bytes);
Ok(serialized)
}
}

View File

@@ -23,8 +23,6 @@ pub struct JITEngine {
}
impl JITEngine {
const MAGIC_HEADER: &'static [u8] = b"\0wasmer-jit";
/// Create a new `JITEngine` with the given config
#[cfg(feature = "compiler")]
pub fn new(
@@ -76,12 +74,6 @@ impl JITEngine {
pub(crate) fn inner_mut(&self) -> std::sync::MutexGuard<'_, JITEngineInner> {
self.inner.lock().unwrap()
}
/// Check if the provided bytes look like a serialized
/// module by the `JITEngine` implementation.
pub fn is_deserializable(bytes: &[u8]) -> bool {
bytes.starts_with(Self::MAGIC_HEADER)
}
}
impl Engine for JITEngine {
@@ -117,28 +109,9 @@ impl Engine for JITEngine {
Ok(Arc::new(JITArtifact::new(&self, binary)?))
}
/// Serializes a WebAssembly module
fn serialize(&self, compiled_module: &dyn Artifact) -> Result<Vec<u8>, SerializeError> {
let compiled_module = compiled_module
.downcast_ref::<JITArtifact>()
.expect("The provided module is not a JIT compiled module");
// We append the header
let mut serialized = Self::MAGIC_HEADER.to_vec();
serialized.extend(compiled_module.serialize()?);
Ok(serialized)
}
/// Deserializes a WebAssembly module
fn deserialize(&self, bytes: &[u8]) -> Result<Arc<dyn Artifact>, DeserializeError> {
if !Self::is_deserializable(bytes) {
return Err(DeserializeError::Incompatible(
"The provided bytes are not wasmer-jit".to_string(),
));
}
Ok(Arc::new(JITArtifact::deserialize(
&self,
&bytes[Self::MAGIC_HEADER.len()..],
)?))
Ok(Arc::new(JITArtifact::deserialize(&self, &bytes)?))
}
}

View File

@@ -38,6 +38,39 @@ fn to_compile_error(err: impl Error) -> CompileError {
}
impl NativeArtifact {
// Mach-O header in Mac
#[allow(dead_code)]
const MAGIC_HEADER_MH_CIGAM_64: &'static [u8] = &[207, 250, 237, 254];
// ELF Magic header for Linux (32 bit)
#[allow(dead_code)]
const MAGIC_HEADER_ELF_32: &'static [u8] = &[0x7f, b'E', b'L', b'F', 1];
// ELF Magic header for Linux (64 bit)
#[allow(dead_code)]
const MAGIC_HEADER_ELF_64: &'static [u8] = &[0x7f, b'E', b'L', b'F', 2];
/// Check if the provided bytes look like `NativeArtifact`.
///
/// This means, if the bytes look like a shared object file in the target
/// system.
pub fn is_deserializable(bytes: &[u8]) -> bool {
cfg_if::cfg_if! {
if #[cfg(all(target_pointer_width = "64", target_os="macos"))] {
return bytes.starts_with(Self::MAGIC_HEADER_MH_CIGAM_64);
}
else if #[cfg(all(target_pointer_width = "64", target_os="linux"))] {
return bytes.starts_with(Self::MAGIC_HEADER_ELF_64);
}
else if #[cfg(all(target_pointer_width = "32", target_os="linux"))] {
return bytes.starts_with(Self::MAGIC_HEADER_ELF_32);
}
else {
false
}
}
}
/// Compile a data buffer into a `NativeArtifact`, which may then be instantiated.
#[cfg(feature = "compiler")]
pub fn new(engine: &NativeEngine, data: &[u8]) -> Result<Self, CompileError> {
@@ -384,11 +417,6 @@ impl NativeArtifact {
))
}
/// Serialize a NativeArtifact
pub fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
Ok(std::fs::read(&self.sharedobject_path)?)
}
/// Deserialize a NativeArtifact
pub unsafe fn deserialize_from_file(
engine: &NativeEngine,
@@ -466,4 +494,9 @@ impl Artifact for NativeArtifact {
fn signatures(&self) -> &BoxedSlice<SignatureIndex, VMSharedSignatureIndex> {
&self.signatures
}
/// Serialize a NativeArtifact
fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
Ok(std::fs::read(&self.sharedobject_path)?)
}
}

View File

@@ -23,18 +23,6 @@ pub struct NativeEngine {
}
impl NativeEngine {
// Mach-O header in Mac
#[allow(dead_code)]
const MAGIC_HEADER_MH_CIGAM_64: &'static [u8] = &[207, 250, 237, 254];
// ELF Magic header for Linux (32 bit)
#[allow(dead_code)]
const MAGIC_HEADER_ELF_32: &'static [u8] = &[0x7f, b'E', b'L', b'F', 1];
// ELF Magic header for Linux (64 bit)
#[allow(dead_code)]
const MAGIC_HEADER_ELF_64: &'static [u8] = &[0x7f, b'E', b'L', b'F', 2];
/// Create a new `NativeEngine` with the given config
#[cfg(feature = "compiler")]
pub fn new(
@@ -105,25 +93,6 @@ impl NativeEngine {
pub(crate) fn inner_mut(&self) -> std::sync::MutexGuard<'_, NativeEngineInner> {
self.inner.lock().unwrap()
}
/// Check if the provided bytes look like a serialized
/// module by the `Native` implementation.
pub fn is_deserializable(bytes: &[u8]) -> bool {
cfg_if::cfg_if! {
if #[cfg(all(target_pointer_width = "64", target_os="macos"))] {
return &bytes[..Self::MAGIC_HEADER_MH_CIGAM_64.len()] == Self::MAGIC_HEADER_MH_CIGAM_64;
}
else if #[cfg(all(target_pointer_width = "64", target_os="linux"))] {
return &bytes[..Self::MAGIC_HEADER_ELF_64.len()] == Self::MAGIC_HEADER_ELF_64;
}
else if #[cfg(all(target_pointer_width = "32", target_os="linux"))] {
return &bytes[..Self::MAGIC_HEADER_ELF_32.len()] == Self::MAGIC_HEADER_ELF_32;
}
else {
false
}
}
}
}
impl Engine for NativeEngine {
@@ -159,18 +128,9 @@ impl Engine for NativeEngine {
Ok(Arc::new(NativeArtifact::new(&self, binary)?))
}
/// Serializes a WebAssembly module
fn serialize(&self, compiled_module: &dyn Artifact) -> Result<Vec<u8>, SerializeError> {
let compiled_module = compiled_module
.downcast_ref::<NativeArtifact>()
.expect("The provided module is not a Native compiled module");
let serialized = compiled_module.serialize()?;
Ok(serialized)
}
/// Deserializes a WebAssembly module (binary content of a Shared Object file)
fn deserialize(&self, bytes: &[u8]) -> Result<Arc<dyn Artifact>, DeserializeError> {
if !Self::is_deserializable(&bytes) {
if !NativeArtifact::is_deserializable(&bytes) {
return Err(DeserializeError::Incompatible(
"The provided bytes are not in any native format Wasmer can understand".to_string(),
));
@@ -192,7 +152,7 @@ impl Engine for NativeEngine {
let mut buffer = [0; 5];
// read up to 5 bytes
file.read_exact(&mut buffer)?;
if !Self::is_deserializable(&buffer) {
if !NativeArtifact::is_deserializable(&buffer) {
return Err(DeserializeError::Incompatible(
"The provided bytes are not in any native format Wasmer can understand".to_string(),
));

View File

@@ -25,7 +25,6 @@ serde = { version = "1.0", features = ["derive", "rc"] }
serde_bytes = { version = "0.11" }
bincode = "1.2"
lazy_static = "1.4"
downcast-rs = "1.1"
[target.'cfg(target_os = "windows")'.dependencies]
winapi = { version = "0.3", features = ["winnt", "impl-default"] }

View File

@@ -1,4 +1,4 @@
use crate::{resolve_imports, Engine, InstantiationError, Resolver, RuntimeError};
use crate::{resolve_imports, Engine, InstantiationError, Resolver, RuntimeError, SerializeError};
use std::any::Any;
use std::sync::Arc;
use wasm_common::entity::{BoxedSlice, PrimaryMap};
@@ -11,15 +11,13 @@ use wasmer_runtime::{
InstanceHandle, MemoryPlan, ModuleInfo, TablePlan, VMFunctionBody, VMSharedSignatureIndex,
};
use downcast_rs::{impl_downcast, Downcast};
/// An `Artifact` is the product that the `Engine` implementation
/// produce and use.
///
/// This means, the artifact that contains the compiled information
/// for a given modue, as well as extra information needed to run the
/// module at runtime.
pub trait Artifact: Downcast {
pub trait Artifact {
/// Return a pointer to the Arc module
fn module(&self) -> &Arc<ModuleInfo>;
@@ -124,6 +122,7 @@ pub trait Artifact: Downcast {
/// Returns the associated VM signatures for this `Artifact`.
fn signatures(&self) -> &BoxedSlice<SignatureIndex, VMSharedSignatureIndex>;
}
impl_downcast!(Artifact);
/// Serializes an artifact into bytes
fn serialize(&self) -> Result<Vec<u8>, SerializeError>;
}

View File

@@ -32,9 +32,6 @@ pub trait Engine {
/// Compile a WebAssembly binary
fn compile(&self, binary: &[u8]) -> Result<Arc<dyn Artifact>, CompileError>;
/// Serializes a WebAssembly module
fn serialize(&self, compiled_module: &dyn Artifact) -> Result<Vec<u8>, SerializeError>;
/// Deserializes a WebAssembly module
fn deserialize(&self, bytes: &[u8]) -> Result<Arc<dyn Artifact>, DeserializeError>;

View File

@@ -135,8 +135,8 @@ impl Run {
let contents = std::fs::read(self.path.clone())?;
#[cfg(feature = "native")]
{
use wasmer_engine_native::NativeEngine;
if NativeEngine::is_deserializable(&contents) {
use wasmer_engine_native::{NativeArtifact, NativeEngine};
if NativeArtifact::is_deserializable(&contents) {
let tunables = Tunables::default();
let engine = NativeEngine::headless(tunables);
let store = Store::new(Arc::new(engine));
@@ -146,7 +146,8 @@ impl Run {
}
#[cfg(feature = "jit")]
{
if wasmer_engine_jit::JITEngine::is_deserializable(&contents) {
use wasmer_engine_jit::{JITArtifact, JITEngine};
if JITArtifact::is_deserializable(&contents) {
let tunables = Tunables::default();
let engine = JITEngine::headless(tunables);
let store = Store::new(Arc::new(engine));