From 397c57442da609790070f63882818ae1e62983e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camil=20B=C4=83ncioiu?= Date: Thu, 9 Dec 2021 23:46:10 +0200 Subject: [PATCH 01/22] Begin adding derivations of Archive for Artifact (WIP) --- .ycm_extra_conf.py | 5 + Cargo.lock | 155 +++++++++++++++++++--- lib/runtime-core/Cargo.toml | 1 + lib/runtime-core/src/cache.rs | 6 +- lib/runtime-core/src/lib.rs | 2 + lib/runtime-core/src/module.rs | 15 ++- lib/runtime-core/src/structures/map.rs | 4 +- lib/runtime-core/src/sys/unix/memory.rs | 5 +- lib/runtime-core/src/types.rs | 3 +- lib/runtime-core/src/wrapped_index_map.rs | 116 ++++++++++++++++ 10 files changed, 282 insertions(+), 30 deletions(-) create mode 100644 .ycm_extra_conf.py create mode 100644 lib/runtime-core/src/wrapped_index_map.rs diff --git a/.ycm_extra_conf.py b/.ycm_extra_conf.py new file mode 100644 index 000000000000..57a3cb275edf --- /dev/null +++ b/.ycm_extra_conf.py @@ -0,0 +1,5 @@ +def Settings(**kwargs): + if kwargs['language'] == 'rust': + return { + 'diagnostics_disabled': ['unresolved-proc-macro', 'inactive-code'] + } diff --git a/Cargo.lock b/Cargo.lock index f6c7da54dc62..54076ce3aa81 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,17 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom 0.2.3", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" version = "0.7.13" @@ -86,7 +97,7 @@ dependencies = [ "arrayref", "arrayvec", "cc", - "cfg-if", + "cfg-if 0.1.10", "constant_time_eq", "crypto-mac", "digest", @@ -104,6 +115,27 @@ dependencies = [ "serde", ] +[[package]] +name = "bytecheck" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "314889ea31cda264cb7c3d6e6e5c9415a987ecb0e72c17c00d36fbb881d34abe" +dependencies = [ + "bytecheck_derive", + "ptr_meta", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a2b3b92c135dae665a6f760205b89187638e83bed17ef3e44e83c712cf30600" +dependencies = [ + "proc-macro2 1.0.20", + "quote 1.0.7", + "syn 1.0.40", +] + [[package]] name = "byteorder" version = "1.3.4" @@ -148,6 +180,12 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "chrono" version = "0.4.15" @@ -341,7 +379,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" dependencies = [ "autocfg 1.0.1", - "cfg-if", + "cfg-if 0.1.10", "crossbeam-utils", "lazy_static", "maybe-uninit", @@ -356,7 +394,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ "autocfg 1.0.1", - "cfg-if", + "cfg-if 0.1.10", "lazy_static", ] @@ -524,7 +562,7 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e1d3b771574f62d0548cee0ad9057857e9fc25d7a3335f140c84f6acd0bf601" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "serde", ] @@ -543,11 +581,22 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "wasi 0.9.0+wasi-snapshot-preview1", ] +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", +] + [[package]] name = "ghost" version = "0.1.2" @@ -613,6 +662,15 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00d63df3d41950fb462ed38308eea019113ad1508da725bbedcd0fa5a85ef5f7" +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash", +] + [[package]] name = "heck" version = "0.3.1" @@ -644,7 +702,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2" dependencies = [ "autocfg 1.0.1", - "hashbrown", + "hashbrown 0.9.0", "serde", ] @@ -733,7 +791,7 @@ checksum = "db65c6da02e61f55dae90a0ae427b2a5f6b3e8db09f58d10efab23af92592616" dependencies = [ "arrayvec", "bitflags", - "cfg-if", + "cfg-if 0.1.10", "ryu", "static_assertions", ] @@ -772,7 +830,7 @@ version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", ] [[package]] @@ -840,7 +898,7 @@ checksum = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229" dependencies = [ "bitflags", "cc", - "cfg-if", + "cfg-if 0.1.10", "libc", "void", ] @@ -909,9 +967,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.4.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "260e51e7efe62b592207e9e13a68e43692a7a279171d6ba57abd208bf23645ad" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" [[package]] name = "orbclient" @@ -967,7 +1025,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "cloudabi", "libc", "redox_syscall", @@ -1039,6 +1097,26 @@ dependencies = [ "unicode-xid 0.2.1", ] +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2 1.0.20", + "quote 1.0.7", + "syn 1.0.40", +] + [[package]] name = "quote" version = "0.6.13" @@ -1082,7 +1160,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom", + "getrandom 0.1.14", "libc", "rand_chacha 0.2.2", "rand_core 0.5.1", @@ -1130,7 +1208,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom", + "getrandom 0.1.14", ] [[package]] @@ -1307,6 +1385,40 @@ dependencies = [ "winapi", ] +[[package]] +name = "rend" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1033f6fe7ce48c8333e5412891b933e85d6a3a09728c4883240edf64e7a6f11a" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "rkyv" +version = "0.7.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66bf572c17c77322f4d858c214def56b13a3c32b8d833cd6d28a92de8325ac5f" +dependencies = [ + "bytecheck", + "hashbrown 0.11.2", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3eca50f172b8e59e2080810fb41b65f047960c197149564d4bd0680af1888e" +dependencies = [ + "proc-macro2 1.0.20", + "quote 1.0.7", + "syn 1.0.40", +] + [[package]] name = "rustc_version" version = "0.2.3" @@ -1398,10 +1510,16 @@ version = "0.32.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34e71125077d297d57e4c1acfe8981b5bdfbf5a20e7b589abfdcb33bf1127f86" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", ] +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + [[package]] name = "semver" version = "0.9.0" @@ -1579,7 +1697,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "rand 0.7.3", "redox_syscall", @@ -1883,7 +2001,7 @@ name = "wasmer-emscripten" version = "0.15.0" dependencies = [ "byteorder", - "getrandom", + "getrandom 0.1.14", "lazy_static", "libc", "log", @@ -2021,6 +2139,7 @@ dependencies = [ "nix", "page_size", "parking_lot", + "rkyv", "rustc_version", "serde", "serde-bench", @@ -2081,7 +2200,7 @@ dependencies = [ "bincode", "byteorder", "generational-arena", - "getrandom", + "getrandom 0.1.14", "libc", "log", "serde", diff --git a/lib/runtime-core/Cargo.toml b/lib/runtime-core/Cargo.toml index f7278a1cdadc..ff2a10530a74 100644 --- a/lib/runtime-core/Cargo.toml +++ b/lib/runtime-core/Cargo.toml @@ -22,6 +22,7 @@ smallvec = "0.6" bincode = "1.1" wasm-debug = { optional = true, version = "0.1.0" } target-lexicon = "0.9" +rkyv = "0.7.26" [dependencies.indexmap] version = "1.2" diff --git a/lib/runtime-core/src/cache.rs b/lib/runtime-core/src/cache.rs index 0e74ee4dc51d..e174ca6bd094 100644 --- a/lib/runtime-core/src/cache.rs +++ b/lib/runtime-core/src/cache.rs @@ -3,6 +3,7 @@ //! and loaded to allow skipping compilation and fast startup. use crate::{module::ModuleInfo, sys::Memory}; +use rkyv::{Archive, Serialize as RkyvSerialize, Deserialize as RkyvDeserialize}; use std::{io, mem, slice}; /// Indicates the invalid type of invalid cache file @@ -152,8 +153,8 @@ impl ArtifactHeader { } -#[derive(Serialize, Deserialize)] -struct ArtifactInner { +#[derive(Serialize, Deserialize, Archive, RkyvSerialize, RkyvDeserialize)] +pub struct ArtifactInner { info: Box, #[serde(with = "serde_bytes")] backend_metadata: Box<[u8]>, @@ -162,6 +163,7 @@ struct ArtifactInner { /// Artifact are produced by caching, are serialized/deserialized to binaries, and contain /// module info, backend metadata, and compiled code. +#[derive(Archive, RkyvSerialize, RkyvDeserialize)] pub struct Artifact { inner: ArtifactInner, } diff --git a/lib/runtime-core/src/lib.rs b/lib/runtime-core/src/lib.rs index daf63ef74193..68d29a099bf5 100644 --- a/lib/runtime-core/src/lib.rs +++ b/lib/runtime-core/src/lib.rs @@ -25,6 +25,7 @@ #![cfg_attr(nightly, feature(unwind_attributes))] #![doc(html_favicon_url = "https://wasmer.io/static/icons/favicon.ico")] #![doc(html_logo_url = "https://avatars3.githubusercontent.com/u/44205449?s=200&v=4")] +#![feature(trivial_bounds)] #[macro_use] extern crate serde_derive; @@ -60,6 +61,7 @@ pub mod typed_func; pub mod types; pub mod units; pub mod vm; +pub mod wrapped_index_map; #[doc(hidden)] pub mod vmcalls; #[cfg(all(unix, target_arch = "x86_64"))] diff --git a/lib/runtime-core/src/module.rs b/lib/runtime-core/src/module.rs index 47a38ae8babf..27b7e7b51268 100644 --- a/lib/runtime-core/src/module.rs +++ b/lib/runtime-core/src/module.rs @@ -18,10 +18,12 @@ use crate::{ use crate::backend::CacheGen; #[cfg(feature = "generate-debug-information")] use crate::jit_debug; -use indexmap::IndexMap; +use crate::wrapped_index_map::WrappedIndexMap; use std::collections::HashMap; use std::sync::Arc; +use rkyv::{Archive, Serialize as RkyvSerialize, Deserialize as RkyvDeserialize}; + /// This is used to instantiate a new WebAssembly module. #[doc(hidden)] pub struct ModuleInner { @@ -31,7 +33,7 @@ pub struct ModuleInner { } /// Container for module data including memories, globals, tables, imports, and exports. -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, Archive, RkyvSerialize, RkyvDeserialize)] pub struct ModuleInfo { /// Map of memory index to memory descriptors. // This are strictly local and the typesystem ensures that. @@ -52,7 +54,7 @@ pub struct ModuleInfo { pub imported_globals: Map, /// Map of string to export index. - pub exports: IndexMap, + pub exports: WrappedIndexMap, /// Vector of data initializers. pub data_initializers: Vec, @@ -217,7 +219,7 @@ pub struct DataInitializer { } /// A WebAssembly table initializer. -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, Archive, RkyvSerialize, RkyvDeserialize)] pub struct TableInitializer { /// The index of a table to initialize. pub table_index: TableIndex, @@ -228,8 +230,9 @@ pub struct TableInitializer { } /// String table builder. +#[derive(Archive, RkyvSerialize, RkyvDeserialize)] pub struct StringTableBuilder { - map: IndexMap, + map: WrappedIndexMap, buffer: String, count: u32, } @@ -238,7 +241,7 @@ impl StringTableBuilder { /// Creates a new [`StringTableBuilder`]. pub fn new() -> Self { Self { - map: IndexMap::new(), + map: WrappedIndexMap::new(), buffer: String::new(), count: 0, } diff --git a/lib/runtime-core/src/structures/map.rs b/lib/runtime-core/src/structures/map.rs index 0ea4beb4ff92..9e41fd75a4e0 100644 --- a/lib/runtime-core/src/structures/map.rs +++ b/lib/runtime-core/src/structures/map.rs @@ -7,8 +7,10 @@ use std::{ slice, vec, }; +use rkyv::{Archive, Serialize as RkyvSerialize, Deserialize as RkyvDeserialize}; + /// Dense item map -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, Archive, RkyvSerialize, RkyvDeserialize)] pub struct Map where K: TypedIndex, diff --git a/lib/runtime-core/src/sys/unix/memory.rs b/lib/runtime-core/src/sys/unix/memory.rs index 45a58a3e860e..40aebbc39e65 100644 --- a/lib/runtime-core/src/sys/unix/memory.rs +++ b/lib/runtime-core/src/sys/unix/memory.rs @@ -6,12 +6,13 @@ use nix::libc; use page_size; use std::ops::{Bound, RangeBounds}; use std::{fs::File, os::unix::io::IntoRawFd, path::Path, ptr, slice, sync::Arc}; +use rkyv::{Archive, Serialize as RkyvSerialize, Deserialize as RkyvDeserialize}; unsafe impl Send for Memory {} unsafe impl Sync for Memory {} /// Data for a sized and protected region of memory. -#[derive(Debug)] +#[derive(Debug, Archive, RkyvSerialize, RkyvDeserialize)] pub struct Memory { ptr: *mut u8, size: usize, @@ -295,7 +296,7 @@ impl Protect { } #[derive(Debug)] -struct RawFd(i32); +pub struct RawFd(i32); impl RawFd { fn from_file(f: File) -> Self { diff --git a/lib/runtime-core/src/types.rs b/lib/runtime-core/src/types.rs index 122aa544a8b8..2ea06f26f55a 100644 --- a/lib/runtime-core/src/types.rs +++ b/lib/runtime-core/src/types.rs @@ -3,6 +3,7 @@ use crate::{memory::MemoryType, module::ModuleInfo, structures::TypedIndex, units::Pages}; use std::{borrow::Cow, convert::TryFrom}; +use rkyv::{Archive, Serialize as RkyvSerialize, Deserialize as RkyvDeserialize}; /// Represents a WebAssembly type. #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -423,7 +424,7 @@ pub trait LocalImport { macro_rules! define_map_index { ($ty:ident) => { /// Typed Index - #[derive(Serialize, Deserialize)] + #[derive(Serialize, Deserialize, Archive, RkyvSerialize, RkyvDeserialize)] #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct $ty (u32); impl TypedIndex for $ty { diff --git a/lib/runtime-core/src/wrapped_index_map.rs b/lib/runtime-core/src/wrapped_index_map.rs new file mode 100644 index 000000000000..72238af584e3 --- /dev/null +++ b/lib/runtime-core/src/wrapped_index_map.rs @@ -0,0 +1,116 @@ +use ::core::hash::Hash; +use indexmap::{IndexMap, Equivalent}; +use indexmap::map::Iter; +use rkyv::{Archive, Serialize as RkyvSerialize, Deserialize as RkyvDeserialize}; +use ::core::fmt; +use serde::ser::{Serialize, Serializer}; +use serde::de::{ Deserialize, Deserializer}; +use ::core::ops::Index; + +#[derive(Archive, RkyvSerialize, RkyvDeserialize)] +pub struct WrappedIndexMap(IndexMap); + +impl WrappedIndexMap +where + K: Hash + Eq, +{ + pub fn new() -> Self { + WrappedIndexMap(IndexMap::new()) + } + + pub fn get(&self, key: &Q) -> Option<&V> + where + Q: Hash + Equivalent, + { + self.0.get(&key) + } + + pub fn iter(&self) -> Iter<'_, K, V> { + self.0.iter() + } + + pub fn contains_key(&self, key: &Q) -> bool + where + Q: Hash + Equivalent, + { + self.0.contains_key(&key) + } + + pub fn insert(&mut self, key: K, value: V) -> Option { + self.0.insert(key, value) + } + + pub fn values(&self) -> Values<'_, K, V> { + self.0.values() + } +} + +impl Clone for WrappedIndexMap +where + K: Clone, + V: Clone, +{ + fn clone(&self) -> Self { + self.0.clone() + } + + fn clone_from(&mut self, other: &Self) { + self.0.clone_from(&other); + } +} + +impl fmt::Debug for WrappedIndexMap +where + K: fmt::Debug, + V: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(&f) + } +} + +impl Serialize for WrappedIndexMap +where + K: Serialize + Hash + Eq, + V: Serialize, +{ + fn serialize(&self, serializer: T) -> Result + where + T: Serializer, + { + self.0.serialize(serializer) + } +} + +impl<'de, K, V> Deserialize<'de> for WrappedIndexMap +where + K: Deserialize<'de> + Eq + Hash, + V: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + IndexMap::deserialize(deserializer) + } +} + +impl Index<&Q> for WrappedIndexMap +where + Q: Hash + Equivalent, + K: Hash + Eq, +{ + type Output = V; + + fn index(&self, key: &Q) -> &V { + self.0.index(&key) + } +} + +impl Default for IndexMap +where + S: Default, +{ + /// Return an empty `IndexMap` + fn default() -> Self { + } From c44860cfb6156c557cfb04ee00d2026e53ee1ca1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camil=20B=C4=83ncioiu?= Date: Sun, 12 Dec 2021 19:56:08 +0200 Subject: [PATCH 02/22] More references to WrappedIndexMap --- lib/runtime-core/src/cache.rs | 1 + lib/runtime-core/src/memory/mod.rs | 4 ++- lib/runtime-core/src/module.rs | 16 ++++----- lib/runtime-core/src/sys/unix/memory.rs | 4 +-- lib/runtime-core/src/types.rs | 18 +++++----- lib/runtime-core/src/units.rs | 4 ++- lib/runtime-core/src/vm.rs | 4 +-- lib/runtime-core/src/wrapped_index_map.rs | 44 +++++++++++++++-------- 8 files changed, 58 insertions(+), 37 deletions(-) diff --git a/lib/runtime-core/src/cache.rs b/lib/runtime-core/src/cache.rs index e174ca6bd094..fbce632d2a79 100644 --- a/lib/runtime-core/src/cache.rs +++ b/lib/runtime-core/src/cache.rs @@ -153,6 +153,7 @@ impl ArtifactHeader { } +/// Inner information of an Artifact. #[derive(Serialize, Deserialize, Archive, RkyvSerialize, RkyvDeserialize)] pub struct ArtifactInner { info: Box, diff --git a/lib/runtime-core/src/memory/mod.rs b/lib/runtime-core/src/memory/mod.rs index 46818f7c3b35..83797d65266b 100644 --- a/lib/runtime-core/src/memory/mod.rs +++ b/lib/runtime-core/src/memory/mod.rs @@ -14,6 +14,8 @@ use std::{cell::Cell, fmt, mem, sync::Arc}; use std::sync::Mutex as StdMutex; +use rkyv::{Archive, Serialize as RkyvSerialize, Deserialize as RkyvDeserialize}; + pub use self::dynamic::DynamicMemory; pub use self::static_::StaticMemory; pub use self::view::{Atomically, MemoryView}; @@ -173,7 +175,7 @@ impl fmt::Debug for Memory { } /// A kind a memory. -#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, Archive, RkyvSerialize, RkyvDeserialize)] pub enum MemoryType { /// A dynamic memory. Dynamic, diff --git a/lib/runtime-core/src/module.rs b/lib/runtime-core/src/module.rs index 27b7e7b51268..11e6cbddedae 100644 --- a/lib/runtime-core/src/module.rs +++ b/lib/runtime-core/src/module.rs @@ -15,6 +15,8 @@ use crate::{ Instance, }; +use rkyv::{Archive, Serialize as RkyvSerialize, Deserialize as RkyvDeserialize}; + use crate::backend::CacheGen; #[cfg(feature = "generate-debug-information")] use crate::jit_debug; @@ -22,8 +24,6 @@ use crate::wrapped_index_map::WrappedIndexMap; use std::collections::HashMap; use std::sync::Arc; -use rkyv::{Archive, Serialize as RkyvSerialize, Deserialize as RkyvDeserialize}; - /// This is used to instantiate a new WebAssembly module. #[doc(hidden)] pub struct ModuleInner { @@ -178,7 +178,7 @@ impl Clone for Module { impl ModuleInner {} #[doc(hidden)] -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, Archive, RkyvSerialize, RkyvDeserialize)] pub struct ImportName { pub namespace_index: NamespaceIndex, pub name_index: NameIndex, @@ -190,7 +190,7 @@ pub struct ImportName { /// Used in [`ModuleInfo`] to access function signatures ([`SigIndex`]s, /// [`FuncSig`]), [`GlobalInit`]s, [`MemoryDescriptor`]s, and /// [`TableDescriptor`]s. -#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Archive, RkyvSerialize, RkyvDeserialize)] pub enum ExportIndex { /// Function export index. [`FuncIndex`] is a type-safe handle referring to /// a Wasm function. @@ -207,7 +207,7 @@ pub enum ExportIndex { } /// A data initializer for linear memory. -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, Archive, RkyvSerialize, RkyvDeserialize)] pub struct DataInitializer { /// The index of the memory to initialize. pub memory_index: MemoryIndex, @@ -286,7 +286,7 @@ impl StringTableBuilder { } /// A map of index to string. -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, Archive, RkyvSerialize, RkyvDeserialize)] pub struct StringTable { table: Map, buffer: String, @@ -321,7 +321,7 @@ impl StringTable { } /// A type-safe handle referring to a module namespace. -#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash, Archive, RkyvSerialize, RkyvDeserialize)] pub struct NamespaceIndex(u32); impl TypedIndex for NamespaceIndex { @@ -337,7 +337,7 @@ impl TypedIndex for NamespaceIndex { } /// A type-safe handle referring to a name in a module namespace. -#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash, Archive, RkyvSerialize, RkyvDeserialize)] pub struct NameIndex(u32); impl TypedIndex for NameIndex { diff --git a/lib/runtime-core/src/sys/unix/memory.rs b/lib/runtime-core/src/sys/unix/memory.rs index 40aebbc39e65..26cc4ff8228e 100644 --- a/lib/runtime-core/src/sys/unix/memory.rs +++ b/lib/runtime-core/src/sys/unix/memory.rs @@ -252,7 +252,7 @@ impl Clone for Memory { } /// Kinds of memory protection. -#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Archive, RkyvSerialize, RkyvDeserialize)] #[allow(dead_code)] pub enum Protect { /// Read/write/exec allowed. @@ -295,7 +295,7 @@ impl Protect { } } -#[derive(Debug)] +#[derive(Debug, Archive, RkyvSerialize, RkyvDeserialize)] pub struct RawFd(i32); impl RawFd { diff --git a/lib/runtime-core/src/types.rs b/lib/runtime-core/src/types.rs index 2ea06f26f55a..76cdb1ad3f4b 100644 --- a/lib/runtime-core/src/types.rs +++ b/lib/runtime-core/src/types.rs @@ -30,7 +30,7 @@ impl std::fmt::Display for Type { /// /// As the number of types in WebAssembly expand, /// this structure will expand as well. -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Archive, RkyvSerialize, RkyvDeserialize)] pub enum Value { /// The `i32` type. I32(i32), @@ -247,7 +247,7 @@ 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)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Archive, RkyvSerialize, RkyvDeserialize)] pub enum ElementType { /// Any wasm function. Anyfunc, @@ -255,7 +255,7 @@ pub enum ElementType { /// Describes the properties of a table including the element types, minimum and optional maximum, /// number of elements in the table. -#[derive(Serialize, Deserialize, Debug, Clone, Copy)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy, Archive, RkyvSerialize, RkyvDeserialize)] pub struct TableDescriptor { /// Type of data stored in this table. pub element: ElementType, @@ -279,7 +279,7 @@ impl TableDescriptor { /// A const value initializer. /// Over time, this will be able to represent more and more /// complex expressions. -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Archive, RkyvSerialize, RkyvDeserialize)] pub enum Initializer { /// Corresponds to a `const.*` instruction. Const(Value), @@ -288,7 +288,7 @@ pub enum Initializer { } /// Describes the mutability and type of a Global -#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Archive, RkyvSerialize, RkyvDeserialize)] pub struct GlobalDescriptor { /// Mutable flag. pub mutable: bool, @@ -297,7 +297,7 @@ pub struct GlobalDescriptor { } /// A wasm global. -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, Archive, RkyvSerialize, RkyvDeserialize)] pub struct GlobalInit { /// Global descriptor. pub desc: GlobalDescriptor, @@ -306,7 +306,7 @@ pub struct GlobalInit { } /// A wasm memory descriptor. -#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Archive, RkyvSerialize, RkyvDeserialize)] pub struct MemoryDescriptor { /// The minimum number of allowed pages. pub minimum: Pages, @@ -354,7 +354,7 @@ impl MemoryDescriptor { /// The signature of a function that is either implemented /// in a wasm module or exposed to wasm by the host. -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash, Archive, RkyvSerialize, RkyvDeserialize)] pub struct FuncSig { params: Cow<'static, [Type]>, returns: Cow<'static, [Type]>, @@ -504,7 +504,7 @@ define_local_or_import![ ]; /// Index for signature. -#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash, Archive, RkyvSerialize, RkyvDeserialize)] pub struct SigIndex(u32); impl TypedIndex for SigIndex { #[doc(hidden)] diff --git a/lib/runtime-core/src/units.rs b/lib/runtime-core/src/units.rs index 780ceb034dda..0df5bdec2c07 100644 --- a/lib/runtime-core/src/units.rs +++ b/lib/runtime-core/src/units.rs @@ -6,6 +6,8 @@ use std::{ ops::{Add, Sub}, }; +use rkyv::{Archive, Serialize as RkyvSerialize, Deserialize as RkyvDeserialize}; + /// The page size in bytes of a wasm page. pub const WASM_PAGE_SIZE: usize = 65_536; /// The max number of wasm pages allowed. @@ -15,7 +17,7 @@ pub const WASM_MAX_PAGES: usize = 65_536; pub const WASM_MIN_PAGES: usize = 256; /// Units of WebAssembly pages (as specified to be 65,536 bytes). -#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Archive, RkyvSerialize, RkyvDeserialize)] pub struct Pages(pub u32); impl Pages { diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index 73b9b2e61131..5a3a5c61490e 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -1072,7 +1072,7 @@ mod vm_ctx_tests { use crate::cache::Error as CacheError; use crate::typed_func::Wasm; use crate::types::{LocalFuncIndex, SigIndex}; - use indexmap::IndexMap; + use crate::WrappedIndexMap; use std::any::Any; use std::collections::HashMap; use std::ptr::NonNull; @@ -1113,7 +1113,7 @@ mod vm_ctx_tests { imported_tables: Map::new(), imported_globals: Map::new(), - exports: IndexMap::new(), + exports: WrappedIndexMap::new(), data_initializers: Vec::new(), elem_initializers: Vec::new(), diff --git a/lib/runtime-core/src/wrapped_index_map.rs b/lib/runtime-core/src/wrapped_index_map.rs index 72238af584e3..558ca945fa44 100644 --- a/lib/runtime-core/src/wrapped_index_map.rs +++ b/lib/runtime-core/src/wrapped_index_map.rs @@ -1,12 +1,16 @@ +//! Provides WrappedIndexMap, a newtype built on indexmap::IndexMap in order to implement +//! the rkyv::Archive trait. + use ::core::hash::Hash; use indexmap::{IndexMap, Equivalent}; -use indexmap::map::Iter; +use indexmap::map::{Iter, Values}; use rkyv::{Archive, Serialize as RkyvSerialize, Deserialize as RkyvDeserialize}; use ::core::fmt; use serde::ser::{Serialize, Serializer}; use serde::de::{ Deserialize, Deserializer}; use ::core::ops::Index; +/// A newtype that wraps indexmap::IndexMap. #[derive(Archive, RkyvSerialize, RkyvDeserialize)] pub struct WrappedIndexMap(IndexMap); @@ -14,32 +18,38 @@ impl WrappedIndexMap where K: Hash + Eq, { + /// Passthrough method. pub fn new() -> Self { WrappedIndexMap(IndexMap::new()) } + /// Passthrough method. pub fn get(&self, key: &Q) -> Option<&V> where - Q: Hash + Equivalent, + Q: Hash + Eq + Equivalent, { - self.0.get(&key) + self.0.get(key) } + /// Passthrough method. pub fn iter(&self) -> Iter<'_, K, V> { self.0.iter() } + /// Passthrough method. pub fn contains_key(&self, key: &Q) -> bool where - Q: Hash + Equivalent, + Q: Hash + Eq + Equivalent, { - self.0.contains_key(&key) + self.0.contains_key(key) } + /// Passthrough method. pub fn insert(&mut self, key: K, value: V) -> Option { self.0.insert(key, value) } + /// Passthrough method. pub fn values(&self) -> Values<'_, K, V> { self.0.values() } @@ -50,12 +60,14 @@ where K: Clone, V: Clone, { + /// Passthrough method. fn clone(&self) -> Self { - self.0.clone() + WrappedIndexMap(self.0.clone()) } + /// Passthrough method. fn clone_from(&mut self, other: &Self) { - self.0.clone_from(&other); + self.0.clone_from(&other.0); } } @@ -64,8 +76,9 @@ where K: fmt::Debug, V: fmt::Debug, { + /// Passthrough method. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(&f) + self.0.fmt(f) } } @@ -74,6 +87,7 @@ where K: Serialize + Hash + Eq, V: Serialize, { + /// Passthrough method. fn serialize(&self, serializer: T) -> Result where T: Serializer, @@ -87,11 +101,12 @@ where K: Deserialize<'de> + Eq + Hash, V: Deserialize<'de>, { + /// Passthrough method. fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { - IndexMap::deserialize(deserializer) + serde::Deserialize::deserialize(deserializer) } } @@ -102,15 +117,16 @@ where { type Output = V; + /// Passthrough method. fn index(&self, key: &Q) -> &V { - self.0.index(&key) + self.0.index(key) } } -impl Default for IndexMap -where - S: Default, +impl Default for WrappedIndexMap { - /// Return an empty `IndexMap` + /// Passthrough method. fn default() -> Self { + WrappedIndexMap(IndexMap::default()) } +} From 3b70e7d53b4b04aadfe5db337528789d5e943a1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camil=20B=C4=83ncioiu?= Date: Tue, 14 Dec 2021 15:43:43 +0200 Subject: [PATCH 03/22] Enable the indexmap feature of rkyv --- Cargo.lock | 15 +++++---------- lib/runtime-core/Cargo.toml | 7 +++++-- lib/runtime-core/src/module.rs | 9 +++++---- lib/runtime-core/src/types.rs | 2 +- lib/runtime-core/src/vm.rs | 4 ++-- 5 files changed, 18 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 54076ce3aa81..d3b5fe270036 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -656,12 +656,6 @@ dependencies = [ "scroll 0.10.1", ] -[[package]] -name = "hashbrown" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00d63df3d41950fb462ed38308eea019113ad1508da725bbedcd0fa5a85ef5f7" - [[package]] name = "hashbrown" version = "0.11.2" @@ -697,12 +691,12 @@ checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" [[package]] name = "indexmap" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" dependencies = [ "autocfg 1.0.1", - "hashbrown 0.9.0", + "hashbrown", "serde", ] @@ -1401,7 +1395,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66bf572c17c77322f4d858c214def56b13a3c32b8d833cd6d28a92de8325ac5f" dependencies = [ "bytecheck", - "hashbrown 0.11.2", + "hashbrown", + "indexmap", "ptr_meta", "rend", "rkyv_derive", diff --git a/lib/runtime-core/Cargo.toml b/lib/runtime-core/Cargo.toml index ff2a10530a74..6bb6477eb122 100644 --- a/lib/runtime-core/Cargo.toml +++ b/lib/runtime-core/Cargo.toml @@ -22,10 +22,13 @@ smallvec = "0.6" bincode = "1.1" wasm-debug = { optional = true, version = "0.1.0" } target-lexicon = "0.9" -rkyv = "0.7.26" + +[dependencies.rkyv] +version = "0.7.26" +features = ["indexmap"] [dependencies.indexmap] -version = "1.2" +version = "1.7" features = ["serde-1"] # Dependencies for caching. diff --git a/lib/runtime-core/src/module.rs b/lib/runtime-core/src/module.rs index 11e6cbddedae..41c280d99477 100644 --- a/lib/runtime-core/src/module.rs +++ b/lib/runtime-core/src/module.rs @@ -15,12 +15,13 @@ use crate::{ Instance, }; +use indexmap::IndexMap; + use rkyv::{Archive, Serialize as RkyvSerialize, Deserialize as RkyvDeserialize}; use crate::backend::CacheGen; #[cfg(feature = "generate-debug-information")] use crate::jit_debug; -use crate::wrapped_index_map::WrappedIndexMap; use std::collections::HashMap; use std::sync::Arc; @@ -54,7 +55,7 @@ pub struct ModuleInfo { pub imported_globals: Map, /// Map of string to export index. - pub exports: WrappedIndexMap, + pub exports: IndexMap, /// Vector of data initializers. pub data_initializers: Vec, @@ -232,7 +233,7 @@ pub struct TableInitializer { /// String table builder. #[derive(Archive, RkyvSerialize, RkyvDeserialize)] pub struct StringTableBuilder { - map: WrappedIndexMap, + map: IndexMap, buffer: String, count: u32, } @@ -241,7 +242,7 @@ impl StringTableBuilder { /// Creates a new [`StringTableBuilder`]. pub fn new() -> Self { Self { - map: WrappedIndexMap::new(), + map: IndexMap::new(), buffer: String::new(), count: 0, } diff --git a/lib/runtime-core/src/types.rs b/lib/runtime-core/src/types.rs index 76cdb1ad3f4b..e6e5f6c4c4db 100644 --- a/lib/runtime-core/src/types.rs +++ b/lib/runtime-core/src/types.rs @@ -6,7 +6,7 @@ use std::{borrow::Cow, convert::TryFrom}; use rkyv::{Archive, Serialize as RkyvSerialize, Deserialize as RkyvDeserialize}; /// Represents a WebAssembly type. -#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, Archive, RkyvSerialize, RkyvDeserialize)] pub enum Type { /// The `i32` type. I32, diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index 5a3a5c61490e..73b9b2e61131 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -1072,7 +1072,7 @@ mod vm_ctx_tests { use crate::cache::Error as CacheError; use crate::typed_func::Wasm; use crate::types::{LocalFuncIndex, SigIndex}; - use crate::WrappedIndexMap; + use indexmap::IndexMap; use std::any::Any; use std::collections::HashMap; use std::ptr::NonNull; @@ -1113,7 +1113,7 @@ mod vm_ctx_tests { imported_tables: Map::new(), imported_globals: Map::new(), - exports: WrappedIndexMap::new(), + exports: IndexMap::new(), data_initializers: Vec::new(), elem_initializers: Vec::new(), From 9a0986fa1b1d4c7caec3946f63b1d88e46a2c176 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camil=20B=C4=83ncioiu?= Date: Wed, 15 Dec 2021 18:42:57 +0200 Subject: [PATCH 04/22] Begin implementation of WrappedCow --- lib/runtime-core/src/lib.rs | 1 + lib/runtime-core/src/types.rs | 11 +++--- lib/runtime-core/src/wrapped_cow.rs | 58 +++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 5 deletions(-) create mode 100644 lib/runtime-core/src/wrapped_cow.rs diff --git a/lib/runtime-core/src/lib.rs b/lib/runtime-core/src/lib.rs index 68d29a099bf5..81e6eba6eb9f 100644 --- a/lib/runtime-core/src/lib.rs +++ b/lib/runtime-core/src/lib.rs @@ -61,6 +61,7 @@ pub mod typed_func; pub mod types; pub mod units; pub mod vm; +pub mod wrapped_cow; pub mod wrapped_index_map; #[doc(hidden)] pub mod vmcalls; diff --git a/lib/runtime-core/src/types.rs b/lib/runtime-core/src/types.rs index e6e5f6c4c4db..46df35aa9dc0 100644 --- a/lib/runtime-core/src/types.rs +++ b/lib/runtime-core/src/types.rs @@ -2,8 +2,9 @@ //! convert to other represenations. use crate::{memory::MemoryType, module::ModuleInfo, structures::TypedIndex, units::Pages}; -use std::{borrow::Cow, convert::TryFrom}; +use std::convert::TryFrom; use rkyv::{Archive, Serialize as RkyvSerialize, Deserialize as RkyvDeserialize}; +use crate::wrapped_cow::WrappedCow; /// Represents a WebAssembly type. #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, Archive, RkyvSerialize, RkyvDeserialize)] @@ -356,16 +357,16 @@ impl MemoryDescriptor { /// in a wasm module or exposed to wasm by the host. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash, Archive, RkyvSerialize, RkyvDeserialize)] pub struct FuncSig { - params: Cow<'static, [Type]>, - returns: Cow<'static, [Type]>, + params: WrappedCow<'static, [Type]>, + returns: WrappedCow<'static, [Type]>, } impl FuncSig { /// Creates a new function signatures with the given parameter and return types. pub fn new(params: Params, returns: Returns) -> Self where - Params: Into>, - Returns: Into>, + Params: Into>, + Returns: Into>, { Self { params: params.into(), diff --git a/lib/runtime-core/src/wrapped_cow.rs b/lib/runtime-core/src/wrapped_cow.rs new file mode 100644 index 000000000000..b2c5338bb47a --- /dev/null +++ b/lib/runtime-core/src/wrapped_cow.rs @@ -0,0 +1,58 @@ +//! Provides WrappedCow, a newtype built on std::borrow:Cow in order to implement +//! the rkyv::Archive trait. + +use std::borrow::Cow; +use core::ops::Deref; + +use rkyv::{Archive, Serialize as RkyvSerialize, Deserialize as RkyvDeserialize}; + +/// A newtype that wraps borrow::Cow. +#[derive(Archive, RkyvSerialize, RkyvDeserialize)] +pub struct WrappedCow<'a, B: ?Sized + ToOwned + 'a>(Cow<'a, B>); + +impl Clone for WrappedCow<'_, B> { + /// Passthrough method. + fn clone(&self) -> Self { + WrappedCow(self.0.clone()) + } + + /// Passthrough method. + fn clone_from(&mut self, source: &Self) { + self.0.clone_from(&source.0); + } +} + +impl WrappedCow<'_, B> { + /// Passthrough method. + pub fn to_mut(&mut self) -> &mut ::Owned { + self.0.to_mut() + } + + /// Passthrough method. + pub fn into_owned(self) -> ::Owned { + self.0.into_owned() + } +} + +impl Deref for WrappedCow<'_, B> { + type Target = B; + + /// Passthrough method. + fn deref(&self) -> &B { + self.0.deref() + } +} + +impl<'a, T: Clone> From> for Cow<'a, [T]> { + /// Newtype requirement. + fn from(v: Vec) -> Cow<'a, [T]> { + Cow::Owned(v) + } +} + +impl<'a, T: Clone> From<&'a Vec> for Cow<'a, [T]> { + /// Newtype requirement. + fn from(v: &'a Vec) -> Cow<'a, [T]> { + Cow::Borrowed(v.as_slice()) + } +} From d1ee9e7881fc8218c1f0b4baf3469e17e85220ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camil=20B=C4=83ncioiu?= Date: Wed, 15 Dec 2021 22:29:06 +0200 Subject: [PATCH 05/22] More type matching for WrappedCow --- Cargo.lock | 6 +-- lib/runtime-core/src/wrapped_cow.rs | 59 +++++++++++++++++++++++++---- 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d3b5fe270036..7e75a7e925f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2250,13 +2250,13 @@ checksum = "c702914acda5feeeffbc29e4d953e5b9ce79d8b98da4dbf18a77086e116c5470" [[package]] name = "wasmparser" version = "0.51.4" -source = "git+https://github.com/ElrondNetwork/wasmparser.rs#f776d0ae8c349463b25d023ab6c8b1a80a761fd7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aeb1956b19469d1c5e63e459d29e7b5aa0f558d9f16fcef09736f8a265e6c10a" [[package]] name = "wasmparser" version = "0.51.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aeb1956b19469d1c5e63e459d29e7b5aa0f558d9f16fcef09736f8a265e6c10a" +source = "git+https://github.com/ElrondNetwork/wasmparser.rs#f776d0ae8c349463b25d023ab6c8b1a80a761fd7" [[package]] name = "wast" diff --git a/lib/runtime-core/src/wrapped_cow.rs b/lib/runtime-core/src/wrapped_cow.rs index b2c5338bb47a..06341ff88bdf 100644 --- a/lib/runtime-core/src/wrapped_cow.rs +++ b/lib/runtime-core/src/wrapped_cow.rs @@ -2,13 +2,39 @@ //! the rkyv::Archive trait. use std::borrow::Cow; +use core::borrow::Borrow; use core::ops::Deref; +use std::hash::Hash; +use std::cmp::PartialEq; use rkyv::{Archive, Serialize as RkyvSerialize, Deserialize as RkyvDeserialize}; /// A newtype that wraps borrow::Cow. -#[derive(Archive, RkyvSerialize, RkyvDeserialize)] -pub struct WrappedCow<'a, B: ?Sized + ToOwned + 'a>(Cow<'a, B>); +#[derive(Hash, Archive, RkyvSerialize, RkyvDeserialize, Serialize, Deserialize)] +pub struct WrappedCow<'a, B: ?Sized + ToOwned + 'a>(Cow<'a, B>); + +impl<'a, B: ?Sized> Borrow for WrappedCow<'a, B> +where + B: ToOwned + Clone, + ::Owned: 'a, +{ + fn borrow(&self) -> &B { + self.0.borrow() + } +} + +impl Eq for WrappedCow<'_, B> where B: Eq + ToOwned {} + +impl<'a, 'b, B: ?Sized, C: ?Sized> PartialEq> for WrappedCow<'a, B> +where + B: PartialEq + ToOwned + Clone, + C: ToOwned + Clone, +{ + #[inline] + fn eq(&self, other: &WrappedCow<'b, C>) -> bool { + self.0.eq(&other.0) + } +} impl Clone for WrappedCow<'_, B> { /// Passthrough method. @@ -43,16 +69,33 @@ impl Deref for WrappedCow<'_, B> { } } -impl<'a, T: Clone> From> for Cow<'a, [T]> { +impl AsRef for WrappedCow<'_, B> { + /// Passthrough method. + fn as_ref(&self) -> &B { + self.0.as_ref() + } +} + +impl<'a, B: Clone> From> for WrappedCow<'a, [B]> { /// Newtype requirement. - fn from(v: Vec) -> Cow<'a, [T]> { - Cow::Owned(v) + fn from(v: Vec) -> WrappedCow<'a, [B]> { + WrappedCow(Cow::Owned(v)) } } -impl<'a, T: Clone> From<&'a Vec> for Cow<'a, [T]> { +impl<'a, B: Clone> From<&'a Vec> for WrappedCow<'a, [B]> { /// Newtype requirement. - fn from(v: &'a Vec) -> Cow<'a, [T]> { - Cow::Borrowed(v.as_slice()) + fn from(v: &'a Vec) -> WrappedCow<'a, [B]> { + WrappedCow(Cow::Borrowed(v.as_slice())) + } +} + +impl<'a, B> From<&'a [B]> for WrappedCow<'a, [B]> +where + [B]: ToOwned +{ + /// Newtype requirement + fn from(s: &'a [B]) -> WrappedCow<'a, [B]> { + WrappedCow(Cow::Borrowed(s)) } } From ddb436110467f650155fa5cd4fc26b334c6a1cde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camil=20B=C4=83ncioiu?= Date: Thu, 16 Dec 2021 15:44:26 +0200 Subject: [PATCH 06/22] More type alignment --- lib/runtime-core/src/types.rs | 4 +-- lib/runtime-core/src/wrapped_cow.rs | 43 +++++++++++++++-------------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/lib/runtime-core/src/types.rs b/lib/runtime-core/src/types.rs index 46df35aa9dc0..dcf3d4122a48 100644 --- a/lib/runtime-core/src/types.rs +++ b/lib/runtime-core/src/types.rs @@ -376,12 +376,12 @@ impl FuncSig { /// Parameter types. pub fn params(&self) -> &[Type] { - &self.params + &self.params.0 } /// Return types. pub fn returns(&self) -> &[Type] { - &self.returns + &self.returns.0 } /// Returns true if parameter types match the function signature. diff --git a/lib/runtime-core/src/wrapped_cow.rs b/lib/runtime-core/src/wrapped_cow.rs index 06341ff88bdf..cb93b32637c4 100644 --- a/lib/runtime-core/src/wrapped_cow.rs +++ b/lib/runtime-core/src/wrapped_cow.rs @@ -6,14 +6,15 @@ use core::borrow::Borrow; use core::ops::Deref; use std::hash::Hash; use std::cmp::PartialEq; +use serde; use rkyv::{Archive, Serialize as RkyvSerialize, Deserialize as RkyvDeserialize}; /// A newtype that wraps borrow::Cow. -#[derive(Hash, Archive, RkyvSerialize, RkyvDeserialize, Serialize, Deserialize)] -pub struct WrappedCow<'a, B: ?Sized + ToOwned + 'a>(Cow<'a, B>); +#[derive(PartialEq, Debug, Hash, Archive, RkyvSerialize, RkyvDeserialize, Serialize, Deserialize)] +pub struct WrappedCow<'a, B: ?Sized + ToOwned + serde::Serialize + serde::Deserialize<'a> + 'a>(pub Cow<'a, B>); -impl<'a, B: ?Sized> Borrow for WrappedCow<'a, B> +impl<'a, B: ?Sized + serde::Serialize + serde::Deserialize<'a>> Borrow for WrappedCow<'a, B> where B: ToOwned + Clone, ::Owned: 'a, @@ -23,20 +24,20 @@ where } } -impl Eq for WrappedCow<'_, B> where B: Eq + ToOwned {} +// impl Eq for WrappedCow<'_, B> where B: Eq + ToOwned {} -impl<'a, 'b, B: ?Sized, C: ?Sized> PartialEq> for WrappedCow<'a, B> -where - B: PartialEq + ToOwned + Clone, - C: ToOwned + Clone, -{ - #[inline] - fn eq(&self, other: &WrappedCow<'b, C>) -> bool { - self.0.eq(&other.0) - } -} +// impl<'a, 'b, B: ?Sized, C: ?Sized> PartialEq> for WrappedCow<'a, B> +// where +// B: PartialEq + ToOwned + Clone, +// C: ToOwned + Clone, +// { +// #[inline] +// fn eq(&self, other: &WrappedCow<'b, C>) -> bool { +// self.0.eq(&other.0) +// } +// } -impl Clone for WrappedCow<'_, B> { +impl<'a, B: ?Sized + ToOwned + Clone + serde::Serialize + serde::Deserialize<'a>> Clone for WrappedCow<'a, B> { /// Passthrough method. fn clone(&self) -> Self { WrappedCow(self.0.clone()) @@ -48,7 +49,7 @@ impl Clone for WrappedCow<'_, B> { } } -impl WrappedCow<'_, B> { +impl<'a, B: ?Sized + ToOwned + Clone + serde::Serialize + serde::Deserialize<'a>> WrappedCow<'a, B> { /// Passthrough method. pub fn to_mut(&mut self) -> &mut ::Owned { self.0.to_mut() @@ -60,7 +61,7 @@ impl WrappedCow<'_, B> { } } -impl Deref for WrappedCow<'_, B> { +impl<'a, B: ?Sized + ToOwned + Clone + serde::Serialize + serde::Deserialize<'a>> Deref for WrappedCow<'a, B> { type Target = B; /// Passthrough method. @@ -69,28 +70,28 @@ impl Deref for WrappedCow<'_, B> { } } -impl AsRef for WrappedCow<'_, B> { +impl<'a, B: ?Sized + ToOwned + Clone + serde::Serialize + serde::Deserialize<'a>> AsRef for WrappedCow<'a, B> { /// Passthrough method. fn as_ref(&self) -> &B { self.0.as_ref() } } -impl<'a, B: Clone> From> for WrappedCow<'a, [B]> { +impl<'a, B: Clone + serde::Serialize + serde::Deserialize<'a>> From> for WrappedCow<'a, [B]> { /// Newtype requirement. fn from(v: Vec) -> WrappedCow<'a, [B]> { WrappedCow(Cow::Owned(v)) } } -impl<'a, B: Clone> From<&'a Vec> for WrappedCow<'a, [B]> { +impl<'a, B: Clone + serde::Serialize + serde::Deserialize<'a>> From<&'a Vec> for WrappedCow<'a, [B]> { /// Newtype requirement. fn from(v: &'a Vec) -> WrappedCow<'a, [B]> { WrappedCow(Cow::Borrowed(v.as_slice())) } } -impl<'a, B> From<&'a [B]> for WrappedCow<'a, [B]> +impl<'a, B: serde::Serialize + serde::Deserialize<'a>> From<&'a [B]> for WrappedCow<'a, [B]> where [B]: ToOwned { From 27de7f36dd8105cd234a11d34597528c308e8344 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camil=20B=C4=83ncioiu?= Date: Fri, 17 Dec 2021 12:20:11 +0200 Subject: [PATCH 07/22] More attempts --- Cargo.lock | 6 +-- lib/runtime-core/src/wrapped_cow.rs | 72 ++++++++++++++++++++++++----- 2 files changed, 64 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7e75a7e925f2..d3b5fe270036 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2250,13 +2250,13 @@ checksum = "c702914acda5feeeffbc29e4d953e5b9ce79d8b98da4dbf18a77086e116c5470" [[package]] name = "wasmparser" version = "0.51.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aeb1956b19469d1c5e63e459d29e7b5aa0f558d9f16fcef09736f8a265e6c10a" +source = "git+https://github.com/ElrondNetwork/wasmparser.rs#f776d0ae8c349463b25d023ab6c8b1a80a761fd7" [[package]] name = "wasmparser" version = "0.51.4" -source = "git+https://github.com/ElrondNetwork/wasmparser.rs#f776d0ae8c349463b25d023ab6c8b1a80a761fd7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aeb1956b19469d1c5e63e459d29e7b5aa0f558d9f16fcef09736f8a265e6c10a" [[package]] name = "wast" diff --git a/lib/runtime-core/src/wrapped_cow.rs b/lib/runtime-core/src/wrapped_cow.rs index cb93b32637c4..5e037994d5be 100644 --- a/lib/runtime-core/src/wrapped_cow.rs +++ b/lib/runtime-core/src/wrapped_cow.rs @@ -6,15 +6,16 @@ use core::borrow::Borrow; use core::ops::Deref; use std::hash::Hash; use std::cmp::PartialEq; -use serde; +use serde::{Serialize, Deserialize}; +use crate::types; use rkyv::{Archive, Serialize as RkyvSerialize, Deserialize as RkyvDeserialize}; /// A newtype that wraps borrow::Cow. -#[derive(PartialEq, Debug, Hash, Archive, RkyvSerialize, RkyvDeserialize, Serialize, Deserialize)] -pub struct WrappedCow<'a, B: ?Sized + ToOwned + serde::Serialize + serde::Deserialize<'a> + 'a>(pub Cow<'a, B>); +#[derive(PartialEq, Debug, Hash, Archive, RkyvSerialize, RkyvDeserialize)] +pub struct WrappedCow<'a, B: ?Sized + ToOwned + 'a>(pub Cow<'a, B>); -impl<'a, B: ?Sized + serde::Serialize + serde::Deserialize<'a>> Borrow for WrappedCow<'a, B> +impl<'a, B: ?Sized> Borrow for WrappedCow<'a, B> where B: ToOwned + Clone, ::Owned: 'a, @@ -24,6 +25,49 @@ where } } +impl <'a, B: ?Sized + Clone> serde::Serialize for WrappedCow<'a, B> { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + (**self).serialize(serializer) + } +} + +// impl<'de, 'a, B: ?Sized + ToOwned + serde::Serialize + serde::Deserialize<'de>> serde::Deserialize<'de> for WrappedCow<'a, B> +// where +// B: ToOwned, +// B::Owned: serde::Deserialize<'de>, +// 'a: 'de, +// { +// #[inline] +// fn deserialize(deserializer: D) -> Result +// where +// D: serde::Deserializer<'de>, +// { +// match B::Owned::deserialize(deserializer) { +// Ok(b) => WrappedCow(Cow::Owned(b)), +// Err(e) => Err(e) +// } +// } +// } + +impl serde::Deserialize<'static> for WrappedCow<'static, [types::Type]> +where +{ + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'static>, + { + match Vec::<[types::Type]>::deserialize(deserializer) { + Ok(b) => WrappedCow(Cow::Owned(b)), + Err(e) => Err(e) + } + } +} + // impl Eq for WrappedCow<'_, B> where B: Eq + ToOwned {} // impl<'a, 'b, B: ?Sized, C: ?Sized> PartialEq> for WrappedCow<'a, B> @@ -37,7 +81,7 @@ where // } // } -impl<'a, B: ?Sized + ToOwned + Clone + serde::Serialize + serde::Deserialize<'a>> Clone for WrappedCow<'a, B> { +impl<'a, B: ?Sized + ToOwned + Clone> Clone for WrappedCow<'a, B> { /// Passthrough method. fn clone(&self) -> Self { WrappedCow(self.0.clone()) @@ -49,7 +93,7 @@ impl<'a, B: ?Sized + ToOwned + Clone + serde::Serialize + serde::Deserialize<'a> } } -impl<'a, B: ?Sized + ToOwned + Clone + serde::Serialize + serde::Deserialize<'a>> WrappedCow<'a, B> { +impl<'a, B: ?Sized + ToOwned + Clone> WrappedCow<'a, B> { /// Passthrough method. pub fn to_mut(&mut self) -> &mut ::Owned { self.0.to_mut() @@ -61,7 +105,7 @@ impl<'a, B: ?Sized + ToOwned + Clone + serde::Serialize + serde::Deserialize<'a> } } -impl<'a, B: ?Sized + ToOwned + Clone + serde::Serialize + serde::Deserialize<'a>> Deref for WrappedCow<'a, B> { +impl<'a, B: ?Sized + ToOwned + Clone> Deref for WrappedCow<'a, B> { type Target = B; /// Passthrough method. @@ -70,28 +114,34 @@ impl<'a, B: ?Sized + ToOwned + Clone + serde::Serialize + serde::Deserialize<'a> } } -impl<'a, B: ?Sized + ToOwned + Clone + serde::Serialize + serde::Deserialize<'a>> AsRef for WrappedCow<'a, B> { +impl<'a, B: ?Sized + ToOwned + Clone> AsRef for WrappedCow<'a, B> { /// Passthrough method. fn as_ref(&self) -> &B { self.0.as_ref() } } -impl<'a, B: Clone + serde::Serialize + serde::Deserialize<'a>> From> for WrappedCow<'a, [B]> { +impl<'a, B: Clone> From> for WrappedCow<'a, [B]> +where + [B]: ToOwned +{ /// Newtype requirement. fn from(v: Vec) -> WrappedCow<'a, [B]> { WrappedCow(Cow::Owned(v)) } } -impl<'a, B: Clone + serde::Serialize + serde::Deserialize<'a>> From<&'a Vec> for WrappedCow<'a, [B]> { +impl<'a, B: Clone> From<&'a Vec> for WrappedCow<'a, [B]> +where + [B]: ToOwned +{ /// Newtype requirement. fn from(v: &'a Vec) -> WrappedCow<'a, [B]> { WrappedCow(Cow::Borrowed(v.as_slice())) } } -impl<'a, B: serde::Serialize + serde::Deserialize<'a>> From<&'a [B]> for WrappedCow<'a, [B]> +impl<'a, B> From<&'a [B]> for WrappedCow<'a, [B]> where [B]: ToOwned { From c430a2ecf3b8e1053e9a58c9378e6f5fed95359d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camil=20B=C4=83ncioiu?= Date: Mon, 20 Dec 2021 16:06:21 +0200 Subject: [PATCH 08/22] Remove WrappedCow and WrappedIndexMap --- lib/runtime-core/src/lib.rs | 2 - lib/runtime-core/src/types.rs | 19 +-- lib/runtime-core/src/wrapped_cow.rs | 152 ---------------------- lib/runtime-core/src/wrapped_index_map.rs | 132 ------------------- 4 files changed, 10 insertions(+), 295 deletions(-) delete mode 100644 lib/runtime-core/src/wrapped_cow.rs delete mode 100644 lib/runtime-core/src/wrapped_index_map.rs diff --git a/lib/runtime-core/src/lib.rs b/lib/runtime-core/src/lib.rs index 81e6eba6eb9f..15e7e0ed27e8 100644 --- a/lib/runtime-core/src/lib.rs +++ b/lib/runtime-core/src/lib.rs @@ -61,8 +61,6 @@ pub mod typed_func; pub mod types; pub mod units; pub mod vm; -pub mod wrapped_cow; -pub mod wrapped_index_map; #[doc(hidden)] pub mod vmcalls; #[cfg(all(unix, target_arch = "x86_64"))] diff --git a/lib/runtime-core/src/types.rs b/lib/runtime-core/src/types.rs index dcf3d4122a48..712806112cec 100644 --- a/lib/runtime-core/src/types.rs +++ b/lib/runtime-core/src/types.rs @@ -2,9 +2,8 @@ //! convert to other represenations. use crate::{memory::MemoryType, module::ModuleInfo, structures::TypedIndex, units::Pages}; -use std::convert::TryFrom; -use rkyv::{Archive, Serialize as RkyvSerialize, Deserialize as RkyvDeserialize}; -use crate::wrapped_cow::WrappedCow; +use std::{borrow::Cow, convert::TryFrom}; +use rkyv::{Archive, Serialize as RkyvSerialize, Deserialize as RkyvDeserialize, with::AsOwned}; /// Represents a WebAssembly type. #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, Archive, RkyvSerialize, RkyvDeserialize)] @@ -357,16 +356,18 @@ impl MemoryDescriptor { /// in a wasm module or exposed to wasm by the host. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash, Archive, RkyvSerialize, RkyvDeserialize)] pub struct FuncSig { - params: WrappedCow<'static, [Type]>, - returns: WrappedCow<'static, [Type]>, + #[with(AsOwned)] + params: Cow<'static, [Type]>, + #[with(AsOwned)] + returns: Cow<'static, [Type]>, } impl FuncSig { /// Creates a new function signatures with the given parameter and return types. pub fn new(params: Params, returns: Returns) -> Self where - Params: Into>, - Returns: Into>, + Params: Into>, + Returns: Into>, { Self { params: params.into(), @@ -376,12 +377,12 @@ impl FuncSig { /// Parameter types. pub fn params(&self) -> &[Type] { - &self.params.0 + &self.params } /// Return types. pub fn returns(&self) -> &[Type] { - &self.returns.0 + &self.returns } /// Returns true if parameter types match the function signature. diff --git a/lib/runtime-core/src/wrapped_cow.rs b/lib/runtime-core/src/wrapped_cow.rs deleted file mode 100644 index 5e037994d5be..000000000000 --- a/lib/runtime-core/src/wrapped_cow.rs +++ /dev/null @@ -1,152 +0,0 @@ -//! Provides WrappedCow, a newtype built on std::borrow:Cow in order to implement -//! the rkyv::Archive trait. - -use std::borrow::Cow; -use core::borrow::Borrow; -use core::ops::Deref; -use std::hash::Hash; -use std::cmp::PartialEq; -use serde::{Serialize, Deserialize}; -use crate::types; - -use rkyv::{Archive, Serialize as RkyvSerialize, Deserialize as RkyvDeserialize}; - -/// A newtype that wraps borrow::Cow. -#[derive(PartialEq, Debug, Hash, Archive, RkyvSerialize, RkyvDeserialize)] -pub struct WrappedCow<'a, B: ?Sized + ToOwned + 'a>(pub Cow<'a, B>); - -impl<'a, B: ?Sized> Borrow for WrappedCow<'a, B> -where - B: ToOwned + Clone, - ::Owned: 'a, -{ - fn borrow(&self) -> &B { - self.0.borrow() - } -} - -impl <'a, B: ?Sized + Clone> serde::Serialize for WrappedCow<'a, B> { - #[inline] - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - (**self).serialize(serializer) - } -} - -// impl<'de, 'a, B: ?Sized + ToOwned + serde::Serialize + serde::Deserialize<'de>> serde::Deserialize<'de> for WrappedCow<'a, B> -// where -// B: ToOwned, -// B::Owned: serde::Deserialize<'de>, -// 'a: 'de, -// { -// #[inline] -// fn deserialize(deserializer: D) -> Result -// where -// D: serde::Deserializer<'de>, -// { -// match B::Owned::deserialize(deserializer) { -// Ok(b) => WrappedCow(Cow::Owned(b)), -// Err(e) => Err(e) -// } -// } -// } - -impl serde::Deserialize<'static> for WrappedCow<'static, [types::Type]> -where -{ - #[inline] - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'static>, - { - match Vec::<[types::Type]>::deserialize(deserializer) { - Ok(b) => WrappedCow(Cow::Owned(b)), - Err(e) => Err(e) - } - } -} - -// impl Eq for WrappedCow<'_, B> where B: Eq + ToOwned {} - -// impl<'a, 'b, B: ?Sized, C: ?Sized> PartialEq> for WrappedCow<'a, B> -// where -// B: PartialEq + ToOwned + Clone, -// C: ToOwned + Clone, -// { -// #[inline] -// fn eq(&self, other: &WrappedCow<'b, C>) -> bool { -// self.0.eq(&other.0) -// } -// } - -impl<'a, B: ?Sized + ToOwned + Clone> Clone for WrappedCow<'a, B> { - /// Passthrough method. - fn clone(&self) -> Self { - WrappedCow(self.0.clone()) - } - - /// Passthrough method. - fn clone_from(&mut self, source: &Self) { - self.0.clone_from(&source.0); - } -} - -impl<'a, B: ?Sized + ToOwned + Clone> WrappedCow<'a, B> { - /// Passthrough method. - pub fn to_mut(&mut self) -> &mut ::Owned { - self.0.to_mut() - } - - /// Passthrough method. - pub fn into_owned(self) -> ::Owned { - self.0.into_owned() - } -} - -impl<'a, B: ?Sized + ToOwned + Clone> Deref for WrappedCow<'a, B> { - type Target = B; - - /// Passthrough method. - fn deref(&self) -> &B { - self.0.deref() - } -} - -impl<'a, B: ?Sized + ToOwned + Clone> AsRef for WrappedCow<'a, B> { - /// Passthrough method. - fn as_ref(&self) -> &B { - self.0.as_ref() - } -} - -impl<'a, B: Clone> From> for WrappedCow<'a, [B]> -where - [B]: ToOwned -{ - /// Newtype requirement. - fn from(v: Vec) -> WrappedCow<'a, [B]> { - WrappedCow(Cow::Owned(v)) - } -} - -impl<'a, B: Clone> From<&'a Vec> for WrappedCow<'a, [B]> -where - [B]: ToOwned -{ - /// Newtype requirement. - fn from(v: &'a Vec) -> WrappedCow<'a, [B]> { - WrappedCow(Cow::Borrowed(v.as_slice())) - } -} - -impl<'a, B> From<&'a [B]> for WrappedCow<'a, [B]> -where - [B]: ToOwned -{ - /// Newtype requirement - fn from(s: &'a [B]) -> WrappedCow<'a, [B]> { - WrappedCow(Cow::Borrowed(s)) - } -} diff --git a/lib/runtime-core/src/wrapped_index_map.rs b/lib/runtime-core/src/wrapped_index_map.rs deleted file mode 100644 index 558ca945fa44..000000000000 --- a/lib/runtime-core/src/wrapped_index_map.rs +++ /dev/null @@ -1,132 +0,0 @@ -//! Provides WrappedIndexMap, a newtype built on indexmap::IndexMap in order to implement -//! the rkyv::Archive trait. - -use ::core::hash::Hash; -use indexmap::{IndexMap, Equivalent}; -use indexmap::map::{Iter, Values}; -use rkyv::{Archive, Serialize as RkyvSerialize, Deserialize as RkyvDeserialize}; -use ::core::fmt; -use serde::ser::{Serialize, Serializer}; -use serde::de::{ Deserialize, Deserializer}; -use ::core::ops::Index; - -/// A newtype that wraps indexmap::IndexMap. -#[derive(Archive, RkyvSerialize, RkyvDeserialize)] -pub struct WrappedIndexMap(IndexMap); - -impl WrappedIndexMap -where - K: Hash + Eq, -{ - /// Passthrough method. - pub fn new() -> Self { - WrappedIndexMap(IndexMap::new()) - } - - /// Passthrough method. - pub fn get(&self, key: &Q) -> Option<&V> - where - Q: Hash + Eq + Equivalent, - { - self.0.get(key) - } - - /// Passthrough method. - pub fn iter(&self) -> Iter<'_, K, V> { - self.0.iter() - } - - /// Passthrough method. - pub fn contains_key(&self, key: &Q) -> bool - where - Q: Hash + Eq + Equivalent, - { - self.0.contains_key(key) - } - - /// Passthrough method. - pub fn insert(&mut self, key: K, value: V) -> Option { - self.0.insert(key, value) - } - - /// Passthrough method. - pub fn values(&self) -> Values<'_, K, V> { - self.0.values() - } -} - -impl Clone for WrappedIndexMap -where - K: Clone, - V: Clone, -{ - /// Passthrough method. - fn clone(&self) -> Self { - WrappedIndexMap(self.0.clone()) - } - - /// Passthrough method. - fn clone_from(&mut self, other: &Self) { - self.0.clone_from(&other.0); - } -} - -impl fmt::Debug for WrappedIndexMap -where - K: fmt::Debug, - V: fmt::Debug, -{ - /// Passthrough method. - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -impl Serialize for WrappedIndexMap -where - K: Serialize + Hash + Eq, - V: Serialize, -{ - /// Passthrough method. - fn serialize(&self, serializer: T) -> Result - where - T: Serializer, - { - self.0.serialize(serializer) - } -} - -impl<'de, K, V> Deserialize<'de> for WrappedIndexMap -where - K: Deserialize<'de> + Eq + Hash, - V: Deserialize<'de>, -{ - /// Passthrough method. - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - serde::Deserialize::deserialize(deserializer) - } -} - -impl Index<&Q> for WrappedIndexMap -where - Q: Hash + Equivalent, - K: Hash + Eq, -{ - type Output = V; - - /// Passthrough method. - fn index(&self, key: &Q) -> &V { - self.0.index(key) - } -} - -impl Default for WrappedIndexMap -{ - /// Passthrough method. - fn default() -> Self { - WrappedIndexMap(IndexMap::default()) - } -} From c6e0e84484c522bfde95069c7b206123acff44c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camil=20B=C4=83ncioiu?= Date: Tue, 11 Jan 2022 20:50:29 +0200 Subject: [PATCH 09/22] Implement wrapper for serializing Memory --- .ycm_extra_conf.py | 10 ++- lib/runtime-core/src/cache.rs | 4 +- lib/runtime-core/src/sys/memory_rkyv.rs | 100 ++++++++++++++++++++++++ lib/runtime-core/src/sys/mod.rs | 4 + lib/runtime-core/src/sys/unix/memory.rs | 2 +- 5 files changed, 117 insertions(+), 3 deletions(-) create mode 100644 lib/runtime-core/src/sys/memory_rkyv.rs diff --git a/.ycm_extra_conf.py b/.ycm_extra_conf.py index 57a3cb275edf..60b5b509f975 100644 --- a/.ycm_extra_conf.py +++ b/.ycm_extra_conf.py @@ -1,5 +1,13 @@ def Settings(**kwargs): if kwargs['language'] == 'rust': return { - 'diagnostics_disabled': ['unresolved-proc-macro', 'inactive-code'] + 'ls': { + 'diagnostics': { + 'disabled': ['unresolved-proc-macro', 'inactive-code'] + }, + 'checkOnSave': { + 'enable': True, + 'extraArgs': ['--target-dir', 'target/check'] + }, + } } diff --git a/lib/runtime-core/src/cache.rs b/lib/runtime-core/src/cache.rs index fbce632d2a79..bf52d3d5bd9e 100644 --- a/lib/runtime-core/src/cache.rs +++ b/lib/runtime-core/src/cache.rs @@ -2,7 +2,7 @@ //! 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::{module::ModuleInfo, sys::Memory}; +use crate::{module::ModuleInfo, sys::Memory, sys::ArchivableMemory}; use rkyv::{Archive, Serialize as RkyvSerialize, Deserialize as RkyvDeserialize}; use std::{io, mem, slice}; @@ -159,6 +159,8 @@ pub struct ArtifactInner { info: Box, #[serde(with = "serde_bytes")] backend_metadata: Box<[u8]>, + + #[with(ArchivableMemory)] compiled_code: Memory, } diff --git a/lib/runtime-core/src/sys/memory_rkyv.rs b/lib/runtime-core/src/sys/memory_rkyv.rs new file mode 100644 index 000000000000..0343211ead6d --- /dev/null +++ b/lib/runtime-core/src/sys/memory_rkyv.rs @@ -0,0 +1,100 @@ +#[cfg(unix)] +use crate::sys::unix::{Memory, Protect}; + +#[cfg(windows)] +use crate::sys::windows::{Memory, Protect}; + +use rkyv::{ + Archive, + Fallible, + Serialize as RkyvSerialize, + Deserialize as RkyvDeserialize, + ser::{Serializer, ScratchSpace}, + with::{ArchiveWith, SerializeWith, DeserializeWith}, +}; + +/// A serializable wrapper for Memory. +pub struct ArchivableMemory; + +/// The archived contents of a wrapped Memory. +#[cfg(unix)] +#[derive(Debug, Archive, RkyvSerialize, RkyvDeserialize)] +pub struct ArchivedMemory { + contents: Vec, + protection: Protect, +} + +impl ArchivedMemory { + /// Construct an ArchivedMemory from a Memory. + pub unsafe fn from_memory(memory: &Memory) -> Self { + ArchivedMemory { + contents: memory.as_slice().to_vec(), + protection: memory.protection(), + } + } +} + +impl ArchiveWith for ArchivableMemory { + type Archived = ::Archived; + type Resolver = ::Resolver; + + unsafe fn resolve_with(memory: &Memory, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { + let archived_memory = ArchivedMemory::from_memory(memory); + archived_memory.resolve(pos, resolver, out); + } +} + +impl SerializeWith for ArchivableMemory +where + Memory: RkyvSerialize, + S: Serializer + ScratchSpace +{ + fn serialize_with(memory: &Memory, serializer: &mut S) -> Result { + unsafe { + let archived_memory = ArchivedMemory::from_memory(memory); + archived_memory.serialize(serializer) + } + } +} + +impl DeserializeWith for ArchivableMemory +where + ArchivedMemory: RkyvDeserialize, +{ + fn deserialize_with(archived_memory: &ArchivedMemory, _: &mut D) -> Result { + let original_protection = archived_memory.protection; + let bytes = archived_memory.contents.as_slice(); + + let mut memory = Memory::with_size_protect(bytes.len(), Protect::ReadWrite) + .expect("Could not create a memory"); + + unsafe { + memory.as_slice_mut().copy_from_slice(&*bytes); + + if memory.protection() != original_protection { + memory + .protect(.., original_protection) + .expect("Could not protect memory as its original protection"); + } + } + + Ok(memory) + } +} + +#[cfg(test)] +mod tests { + use crate::sys::unix::*; + + #[test] + fn test_new_memory() { + let bytes = b"abcdefghijkl"; + let mut memory = Memory::with_size_protect(1000, Protect::ReadWrite) + .expect("Could not create memory"); + + unsafe { + memory.as_slice_mut().copy_from_slice(&bytes[..]); + assert_eq!(memory.as_slice(), &bytes[..]); + } + } +} diff --git a/lib/runtime-core/src/sys/mod.rs b/lib/runtime-core/src/sys/mod.rs index 02b4fd25669b..19a041f5ee26 100644 --- a/lib/runtime-core/src/sys/mod.rs +++ b/lib/runtime-core/src/sys/mod.rs @@ -1,3 +1,5 @@ +mod memory_rkyv; + #[cfg(unix)] mod unix; @@ -10,6 +12,8 @@ pub use self::unix::*; #[cfg(windows)] pub use self::windows::*; +pub use self::memory_rkyv::*; + use serde::{ de::{self, SeqAccess, Visitor}, ser::SerializeStruct, diff --git a/lib/runtime-core/src/sys/unix/memory.rs b/lib/runtime-core/src/sys/unix/memory.rs index 26cc4ff8228e..c9c8a0d3f83c 100644 --- a/lib/runtime-core/src/sys/unix/memory.rs +++ b/lib/runtime-core/src/sys/unix/memory.rs @@ -12,7 +12,7 @@ unsafe impl Send for Memory {} unsafe impl Sync for Memory {} /// Data for a sized and protected region of memory. -#[derive(Debug, Archive, RkyvSerialize, RkyvDeserialize)] +#[derive(Debug)] pub struct Memory { ptr: *mut u8, size: usize, From 932622d316ff555895c7c80ec3c557d671ab7b4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camil=20B=C4=83ncioiu?= Date: Fri, 14 Jan 2022 13:09:19 +0200 Subject: [PATCH 10/22] Attempt rkyv test for Artifact --- Cargo.lock | 1 + lib/runtime-c-api/Cargo.toml | 4 ++ lib/runtime-c-api/src/instance_cache.rs | 93 ++++++++++++++++++++---- lib/runtime-c-api/wasmer.h | 4 ++ lib/runtime-c-api/wasmer.hh | 4 ++ lib/runtime-core/src/cache.rs | 94 +++++++++++++++++++++++++ lib/runtime-core/src/sys/memory_rkyv.rs | 94 ++++++++++++++++++++----- lib/runtime-core/src/sys/unix/memory.rs | 3 + src/webassembly.rs | 1 - 9 files changed, 264 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d3b5fe270036..6f501ea8fdea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2108,6 +2108,7 @@ version = "0.15.0" dependencies = [ "cbindgen", "libc", + "rkyv", "wasmer-clif-backend", "wasmer-emscripten", "wasmer-llvm-backend", diff --git a/lib/runtime-c-api/Cargo.toml b/lib/runtime-c-api/Cargo.toml index 4596912c69de..efce4f34e0aa 100644 --- a/lib/runtime-c-api/Cargo.toml +++ b/lib/runtime-c-api/Cargo.toml @@ -17,6 +17,10 @@ crate-type = ["cdylib", "rlib", "staticlib"] [dependencies] libc = "0.2.60" +[dependencies.rkyv] +version = "0.7.26" +features = ["indexmap"] + [dependencies.wasmer-runtime] default-features = false path = "../runtime" diff --git a/lib/runtime-c-api/src/instance_cache.rs b/lib/runtime-c-api/src/instance_cache.rs index 18952fc18174..0584fe731710 100644 --- a/lib/runtime-c-api/src/instance_cache.rs +++ b/lib/runtime-c-api/src/instance_cache.rs @@ -3,6 +3,13 @@ use crate::{ instance::{wasmer_instance_t, wasmer_compilation_options_t, CompilationOptions, prepare_middleware_chain_generator, get_compiler}, wasmer_result_t, }; + +use rkyv::{ + Deserialize as RkyvDeserialize, + ser::Serializer, + ser::serializers::AllocSerializer, +}; + use wasmer_runtime_core::{cache::Artifact, import::ImportObject}; use std::slice; use crate::import::GLOBAL_IMPORT_OBJECT; @@ -56,6 +63,43 @@ pub unsafe extern "C" fn wasmer_instance_cache( wasmer_result_t::WASMER_OK } +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub unsafe extern "C" fn wasmer_instance_cache_rkyv( + instance: *mut wasmer_instance_t, + cache_bytes: *mut *const u8, + cache_len: *mut u32, +) -> wasmer_result_t { + if instance.is_null() { + update_last_error(CApiError { + msg: "null instance".to_string(), + }); + return wasmer_result_t::WASMER_ERROR; + } + + let instance = &mut *(instance as *mut wasmer_runtime::Instance); + let module = instance.module(); + match module.cache() { + Err(error) => { + update_last_error(CApiError { + msg: format!("{:?}", error), + }); + return wasmer_result_t::WASMER_ERROR; + } + Ok(artifact) => { + let serialized = serialize_artifact_to_rkyv(artifact); + if !serialized.is_empty() { + let buf = serialized.into_boxed_slice(); + *cache_bytes = buf.as_ptr(); + *cache_len = buf.len() as u32; + std::mem::forget(buf); + } + } + }; + + wasmer_result_t::WASMER_OK +} + #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub unsafe extern "C" fn wasmer_instance_from_cache( @@ -75,22 +119,25 @@ pub unsafe extern "C" fn wasmer_instance_from_cache( let options: &CompilationOptions = &*(options as *const CompilationOptions); let compiler_chain_generator = prepare_middleware_chain_generator(&options); let compiler = get_compiler(compiler_chain_generator); - let new_module = match Artifact::deserialize(bytes) { - Ok(serialized_cache) => match wasmer_runtime_core::load_cache_with(serialized_cache, &compiler) { - Ok(deserialized_module) => { - deserialized_module - } - Err(_) => { - update_last_error(CApiError { - msg: "Failed to compile the serialized module".to_string(), - }); - return wasmer_result_t::WASMER_ERROR; - } - }, - Err(err) => { - println!("{:?}", err); + + let artifact = match Artifact::deserialize(bytes) { + Ok(deserialized_artifact) => deserialized_artifact, + Err(_) => { update_last_error(CApiError { - msg: "Failed to deserialize the module".to_string(), + msg: "Failed to compile the serialized module".to_string(), + }); + return wasmer_result_t::WASMER_ERROR; + } + }; + + + let new_module = match wasmer_runtime_core::load_cache_with(artifact, &compiler) { + Ok(deserialized_module) => { + deserialized_module + } + Err(_) => { + update_last_error(CApiError { + msg: "Failed to compile the serialized module".to_string(), }); return wasmer_result_t::WASMER_ERROR; } @@ -109,3 +156,19 @@ pub unsafe extern "C" fn wasmer_instance_from_cache( *instance = Box::into_raw(Box::new(new_instance)) as *mut wasmer_instance_t; wasmer_result_t::WASMER_OK } + +fn serialize_artifact_to_rkyv(artifact: Artifact) -> Vec { + let mut serializer = AllocSerializer::<4096>::default(); + serializer.serialize_value(&artifact).unwrap(); + let serialized = serializer.into_serializer().into_inner().to_vec(); + assert!(serialized.len() > 0); + + serialized +} + +fn deserialize_artifact_from_rkyv(bytes: &[u8]) -> Artifact { + let archived = unsafe { rkyv::archived_root::(&bytes[..]) }; + let artifact: Artifact = archived.deserialize(&mut rkyv::Infallible).unwrap().into_inner(); + artifact +} + diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 455dbaaa58aa..72fffc83c6cf 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -861,6 +861,10 @@ wasmer_result_t wasmer_instance_cache(wasmer_instance_t *instance, const uint8_t **cache_bytes, uint32_t *cache_len); +wasmer_result_t wasmer_instance_cache_rkyv(wasmer_instance_t *instance, + const uint8_t **cache_bytes, + uint32_t *cache_len); + /** * Calls an exported function of a WebAssembly instance by `name` * with the provided parameters. The exported function results are diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 888cb07b3a25..1f35663054f9 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -676,6 +676,10 @@ wasmer_result_t wasmer_instance_cache(wasmer_instance_t *instance, const uint8_t **cache_bytes, uint32_t *cache_len); +wasmer_result_t wasmer_instance_cache_rkyv(wasmer_instance_t *instance, + const uint8_t **cache_bytes, + uint32_t *cache_len); + /// Calls an exported function of a WebAssembly instance by `name` /// with the provided parameters. The exported function results are /// stored on the provided `results` pointer. diff --git a/lib/runtime-core/src/cache.rs b/lib/runtime-core/src/cache.rs index bf52d3d5bd9e..84791b216788 100644 --- a/lib/runtime-core/src/cache.rs +++ b/lib/runtime-core/src/cache.rs @@ -234,3 +234,97 @@ impl Artifact { /// A unique ID generated from the version of Wasmer for use with cache versioning pub const WASMER_VERSION_HASH: &'static str = include_str!(concat!(env!("OUT_DIR"), "/wasmer_version_hash.txt")); + +#[cfg(test)] +mod tests { + use super::*; + use std::collections::HashMap; + use crate::structures::Map; + use crate::module::StringTable; + use rkyv::ser::serializers::AllocSerializer; + use rkyv::ser::Serializer as RkyvSerializer; + use rkyv::with::With; + use crate::sys::{ArchivableMemory, CompactMemory}; + + #[test] + fn test_rkyv_artifact() { + let bytes = make_test_bytes(); + let memory = make_test_memory(&bytes); + + let module_info = make_empty_module_info(); + let artifact = Artifact::from_parts( + Box::new(module_info), + b"test_backend".to_vec().into_boxed_slice(), + memory, + ); + + let mut serializer = AllocSerializer::<4096>::default(); + serializer.serialize_value(&artifact).unwrap(); + let serialized = serializer.into_serializer().into_inner(); + assert!(serialized.len() > 0); + print!("{:?}", serialized); + + let archived: &::Archived + = unsafe { rkyv::archived_root::(&serialized[..]) }; + + let deser_result: Result + = archived.deserialize(&mut rkyv::Infallible); + + // let wrapped_artifact = deser_result.unwrap(); + // let deserialized_artifact: Artifact = wrapped_artifact.into_inner(); + // let deserialized_compiled_code = unsafe { deserialized_artifact.inner.compiled_code.as_slice() }; + // assert_eq!(deserialized_compiled_code, bytes); + } + + fn make_empty_module_info() -> ModuleInfo { + ModuleInfo { + memories: Map::new(), + globals: Map::new(), + tables: Map::new(), + + imported_functions: Map::new(), + imported_memories: Map::new(), + imported_tables: Map::new(), + imported_globals: Map::new(), + + exports: Default::default(), + + data_initializers: Vec::new(), + elem_initializers: Vec::new(), + + start_func: None, + + func_assoc: Map::new(), + signatures: Map::new(), + backend: "test".to_string(), + + namespace_table: StringTable::new(), + name_table: StringTable::new(), + + em_symbol_map: None, + + custom_sections: HashMap::new(), + + generate_debug_info: false, + #[cfg(feature = "generate-debug-information")] + debug_info_manager: crate::jit_debug::JitCodeDebugInfoManager::new(), + } + } + + fn make_test_memory(bytes: &Vec) -> Memory { + let mut memory = Memory::with_size_protect(1000, crate::sys::Protect::ReadWrite) + .expect("Could not create memory"); + unsafe { + memory.as_slice_mut().copy_from_slice(&bytes[..]); + } + memory + } + + fn make_test_bytes() -> Vec { + let page_size = page_size::get(); + let mut bytes = b"abcdefghijkl".to_vec(); + let padding_zeros = [0 as u8; 1].repeat(page_size - bytes.len()); + bytes.extend(padding_zeros); + bytes + } +} diff --git a/lib/runtime-core/src/sys/memory_rkyv.rs b/lib/runtime-core/src/sys/memory_rkyv.rs index 0343211ead6d..c23c0c568917 100644 --- a/lib/runtime-core/src/sys/memory_rkyv.rs +++ b/lib/runtime-core/src/sys/memory_rkyv.rs @@ -17,51 +17,68 @@ use rkyv::{ pub struct ArchivableMemory; /// The archived contents of a wrapped Memory. -#[cfg(unix)] -#[derive(Debug, Archive, RkyvSerialize, RkyvDeserialize)] -pub struct ArchivedMemory { +#[derive(Archive, RkyvSerialize, RkyvDeserialize, Debug, PartialEq)] +#[archive(compare(PartialEq))] +#[archive_attr(derive(Debug))] +#[archive_attr(derive(PartialEq))] +pub struct CompactMemory { contents: Vec, protection: Protect, } -impl ArchivedMemory { - /// Construct an ArchivedMemory from a Memory. +impl CompactMemory { + /// Construct a CompactMemory from a Memory. pub unsafe fn from_memory(memory: &Memory) -> Self { - ArchivedMemory { + CompactMemory { contents: memory.as_slice().to_vec(), protection: memory.protection(), } } + + /// Construct a Memory from a CompactMemory. + pub unsafe fn into_memory(&self) -> Memory { + let bytes = self.contents.as_slice(); + + let mut memory = Memory::with_size_protect(bytes.len(), Protect::ReadWrite) + .expect("Could not create a memory"); + + memory.as_slice_mut().copy_from_slice(&*bytes); + + if memory.protection() != self.protection { + memory + .protect(.., self.protection) + .expect("Could not protect memory as its original protection"); + } + + memory + } } impl ArchiveWith for ArchivableMemory { - type Archived = ::Archived; - type Resolver = ::Resolver; + type Archived = ::Archived; + type Resolver = ::Resolver; unsafe fn resolve_with(memory: &Memory, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { - let archived_memory = ArchivedMemory::from_memory(memory); + let archived_memory = CompactMemory::from_memory(memory); archived_memory.resolve(pos, resolver, out); } } impl SerializeWith for ArchivableMemory where - Memory: RkyvSerialize, S: Serializer + ScratchSpace { fn serialize_with(memory: &Memory, serializer: &mut S) -> Result { unsafe { - let archived_memory = ArchivedMemory::from_memory(memory); + let archived_memory = CompactMemory::from_memory(memory); archived_memory.serialize(serializer) } } } -impl DeserializeWith for ArchivableMemory -where - ArchivedMemory: RkyvDeserialize, +impl DeserializeWith for ArchivableMemory { - fn deserialize_with(archived_memory: &ArchivedMemory, _: &mut D) -> Result { + fn deserialize_with(archived_memory: &CompactMemory, _: &mut D) -> Result { let original_protection = archived_memory.protection; let bytes = archived_memory.contents.as_slice(); @@ -84,17 +101,58 @@ where #[cfg(test)] mod tests { + use super::*; + use rkyv::ser::serializers::AllocSerializer; use crate::sys::unix::*; #[test] fn test_new_memory() { - let bytes = b"abcdefghijkl"; + let bytes = make_test_bytes(); + let memory = make_test_memory(&bytes); + unsafe { + assert_eq!(memory.as_slice(), bytes); + } + } + + #[test] + fn test_rkyv_memory() { + let bytes = make_test_bytes(); + let memory = make_test_memory(&bytes); + + let compact_memory = unsafe { CompactMemory::from_memory(&memory) }; + + let mut serializer = AllocSerializer::<4096>::default(); + serializer.serialize_value(&compact_memory).unwrap(); + let serialized = serializer.into_serializer().into_inner(); + assert!(serialized.len() > 0); + + let archived = unsafe { rkyv::archived_root::(&serialized[..]) }; + assert_eq!(archived, &compact_memory); + + let deserialized: CompactMemory = archived.deserialize(&mut rkyv::Infallible).unwrap(); + assert_eq!(deserialized, compact_memory); + + let deserialized_memory = unsafe { deserialized.into_memory() }; + assert_eq!(deserialized_memory.protection(), memory.protection()); + unsafe { + assert_eq!(deserialized_memory.as_slice(), memory.as_slice()); + }; + } + + fn make_test_memory(bytes: &Vec) -> Memory { let mut memory = Memory::with_size_protect(1000, Protect::ReadWrite) .expect("Could not create memory"); - unsafe { memory.as_slice_mut().copy_from_slice(&bytes[..]); - assert_eq!(memory.as_slice(), &bytes[..]); } + memory + } + + fn make_test_bytes() -> Vec { + let page_size = page_size::get(); + let mut bytes = b"abcdefghijkl".to_vec(); + let padding_zeros = [0 as u8; 1].repeat(page_size - bytes.len()); + bytes.extend(padding_zeros); + bytes } } diff --git a/lib/runtime-core/src/sys/unix/memory.rs b/lib/runtime-core/src/sys/unix/memory.rs index c9c8a0d3f83c..c515636cd54c 100644 --- a/lib/runtime-core/src/sys/unix/memory.rs +++ b/lib/runtime-core/src/sys/unix/memory.rs @@ -254,6 +254,9 @@ impl Clone for Memory { /// Kinds of memory protection. #[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Archive, RkyvSerialize, RkyvDeserialize)] #[allow(dead_code)] +#[archive(compare(PartialEq))] +#[archive_attr(derive(Debug))] +#[archive_attr(derive(PartialEq))] pub enum Protect { /// Read/write/exec allowed. None, diff --git a/src/webassembly.rs b/src/webassembly.rs index 0df8b59e8b18..0fd75b20ab41 100644 --- a/src/webassembly.rs +++ b/src/webassembly.rs @@ -1,4 +1,3 @@ -use std::panic; pub use wasmer_runtime::compile_with_config_with; use wasmer_runtime::{self as runtime, error::Result, ImportObject, Instance, Module}; From 8d46a26ca6816c89669c9a8efd0fdc0e04f6a65d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camil=20B=C4=83ncioiu?= Date: Wed, 19 Jan 2022 13:48:01 +0200 Subject: [PATCH 11/22] Update Cargo.lock --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6f501ea8fdea..c96e7081d50b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2251,13 +2251,13 @@ checksum = "c702914acda5feeeffbc29e4d953e5b9ce79d8b98da4dbf18a77086e116c5470" [[package]] name = "wasmparser" version = "0.51.4" -source = "git+https://github.com/ElrondNetwork/wasmparser.rs#f776d0ae8c349463b25d023ab6c8b1a80a761fd7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aeb1956b19469d1c5e63e459d29e7b5aa0f558d9f16fcef09736f8a265e6c10a" [[package]] name = "wasmparser" version = "0.51.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aeb1956b19469d1c5e63e459d29e7b5aa0f558d9f16fcef09736f8a265e6c10a" +source = "git+https://github.com/ElrondNetwork/wasmparser.rs#f776d0ae8c349463b25d023ab6c8b1a80a761fd7" [[package]] name = "wast" From f3a57c64267c1b4a267972310b1f0294a6d7c664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camil=20B=C4=83ncioiu?= Date: Tue, 25 Jan 2022 17:48:15 +0200 Subject: [PATCH 12/22] Extra test --- lib/runtime-core/src/cache.rs | 33 ++++++++++++++++++++++--- lib/runtime-core/src/sys/memory_rkyv.rs | 2 +- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/lib/runtime-core/src/cache.rs b/lib/runtime-core/src/cache.rs index 84791b216788..da12d18b50aa 100644 --- a/lib/runtime-core/src/cache.rs +++ b/lib/runtime-core/src/cache.rs @@ -244,7 +244,8 @@ mod tests { use rkyv::ser::serializers::AllocSerializer; use rkyv::ser::Serializer as RkyvSerializer; use rkyv::with::With; - use crate::sys::{ArchivableMemory, CompactMemory}; + use rkyv::Archived; + // use crate::sys::{ArchivableMemory, CompactMemory}; #[test] fn test_rkyv_artifact() { @@ -264,11 +265,11 @@ mod tests { assert!(serialized.len() > 0); print!("{:?}", serialized); - let archived: &::Archived + let _: &::Archived = unsafe { rkyv::archived_root::(&serialized[..]) }; - let deser_result: Result - = archived.deserialize(&mut rkyv::Infallible); + // let deser_result: Result, std::convert::Infallible> + // = archived.deserialize(&mut rkyv::Infallible); // let wrapped_artifact = deser_result.unwrap(); // let deserialized_artifact: Artifact = wrapped_artifact.into_inner(); @@ -276,6 +277,30 @@ mod tests { // assert_eq!(deserialized_compiled_code, bytes); } + #[test] + fn test_rkyv_artifact_inner() { + let bytes = make_test_bytes(); + let memory = make_test_memory(&bytes); + + let module_info = make_empty_module_info(); + let artifact_inner = ArtifactInner { + info: Box::new(module_info), + backend_metadata: b"test_backend".to_vec().into_boxed_slice(), + compiled_code: memory, + }; + + let mut serializer = AllocSerializer::<4096>::default(); + serializer.serialize_value(&artifact_inner).unwrap(); + let serialized = serializer.into_serializer().into_inner(); + assert!(serialized.len() > 0); + print!("{:?}", serialized); + + let archived: &Archived + = unsafe { rkyv::archived_root::(&serialized[..]) }; + + let deser_result: ArtifactInner = archived.deserialize(&mut rkyv::Infallible).unwrap(); + } + fn make_empty_module_info() -> ModuleInfo { ModuleInfo { memories: Map::new(), diff --git a/lib/runtime-core/src/sys/memory_rkyv.rs b/lib/runtime-core/src/sys/memory_rkyv.rs index c23c0c568917..3b4f77f40505 100644 --- a/lib/runtime-core/src/sys/memory_rkyv.rs +++ b/lib/runtime-core/src/sys/memory_rkyv.rs @@ -115,7 +115,7 @@ mod tests { } #[test] - fn test_rkyv_memory() { + fn test_rkyv_compact_memory() { let bytes = make_test_bytes(); let memory = make_test_memory(&bytes); From 2beeb339b2ab7b7027a4e11caa6f2f307fcfcc7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camil=20B=C4=83ncioiu?= Date: Tue, 25 Jan 2022 18:49:31 +0200 Subject: [PATCH 13/22] Fix ArchivableMemory deserialization --- lib/runtime-core/src/cache.rs | 12 +++++++++--- lib/runtime-core/src/sys/memory_rkyv.rs | 6 +++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/runtime-core/src/cache.rs b/lib/runtime-core/src/cache.rs index da12d18b50aa..8d9ec928beab 100644 --- a/lib/runtime-core/src/cache.rs +++ b/lib/runtime-core/src/cache.rs @@ -237,13 +237,17 @@ pub const WASMER_VERSION_HASH: &'static str = #[cfg(test)] mod tests { - use super::*; + use super::Artifact; + use super::ArtifactInner; + use super::Memory; + use super::ModuleInfo; use std::collections::HashMap; use crate::structures::Map; use crate::module::StringTable; use rkyv::ser::serializers::AllocSerializer; use rkyv::ser::Serializer as RkyvSerializer; - use rkyv::with::With; + use rkyv::Archive; + use rkyv::Deserialize; use rkyv::Archived; // use crate::sys::{ArchivableMemory, CompactMemory}; @@ -298,7 +302,9 @@ mod tests { let archived: &Archived = unsafe { rkyv::archived_root::(&serialized[..]) }; - let deser_result: ArtifactInner = archived.deserialize(&mut rkyv::Infallible).unwrap(); + let deserialized_artifact = Deserialize::::deserialize(archived, &mut rkyv::Infallible).unwrap(); + unsafe { assert_eq!(deserialized_artifact.compiled_code.as_slice(), artifact_inner.compiled_code.as_slice()) }; + assert_eq!(deserialized_artifact.compiled_code.protection(), artifact_inner.compiled_code.protection()); } fn make_empty_module_info() -> ModuleInfo { diff --git a/lib/runtime-core/src/sys/memory_rkyv.rs b/lib/runtime-core/src/sys/memory_rkyv.rs index 3b4f77f40505..b058442fd11a 100644 --- a/lib/runtime-core/src/sys/memory_rkyv.rs +++ b/lib/runtime-core/src/sys/memory_rkyv.rs @@ -76,10 +76,10 @@ where } } -impl DeserializeWith for ArchivableMemory +impl DeserializeWith for ArchivableMemory { - fn deserialize_with(archived_memory: &CompactMemory, _: &mut D) -> Result { - let original_protection = archived_memory.protection; + fn deserialize_with(archived_memory: &ArchivedCompactMemory, deserializer: &mut D) -> Result { + let original_protection = archived_memory.protection.deserialize(deserializer)?; let bytes = archived_memory.contents.as_slice(); let mut memory = Memory::with_size_protect(bytes.len(), Protect::ReadWrite) From 5994d9cc47ef7fda602e2d21d8912e18c832f9a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camil=20B=C4=83ncioiu?= Date: Wed, 26 Jan 2022 12:48:53 +0200 Subject: [PATCH 14/22] Minor type rewrite for DeserializeWith; clean tests --- Cargo.lock | 6 +++--- lib/runtime-core/src/cache.rs | 17 +++++++---------- lib/runtime-core/src/sys/memory_rkyv.rs | 5 +++-- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c96e7081d50b..6f501ea8fdea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2251,13 +2251,13 @@ checksum = "c702914acda5feeeffbc29e4d953e5b9ce79d8b98da4dbf18a77086e116c5470" [[package]] name = "wasmparser" version = "0.51.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aeb1956b19469d1c5e63e459d29e7b5aa0f558d9f16fcef09736f8a265e6c10a" +source = "git+https://github.com/ElrondNetwork/wasmparser.rs#f776d0ae8c349463b25d023ab6c8b1a80a761fd7" [[package]] name = "wasmparser" version = "0.51.4" -source = "git+https://github.com/ElrondNetwork/wasmparser.rs#f776d0ae8c349463b25d023ab6c8b1a80a761fd7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aeb1956b19469d1c5e63e459d29e7b5aa0f558d9f16fcef09736f8a265e6c10a" [[package]] name = "wast" diff --git a/lib/runtime-core/src/cache.rs b/lib/runtime-core/src/cache.rs index 8d9ec928beab..e82d7ab6a343 100644 --- a/lib/runtime-core/src/cache.rs +++ b/lib/runtime-core/src/cache.rs @@ -246,10 +246,8 @@ mod tests { use crate::module::StringTable; use rkyv::ser::serializers::AllocSerializer; use rkyv::ser::Serializer as RkyvSerializer; - use rkyv::Archive; use rkyv::Deserialize; use rkyv::Archived; - // use crate::sys::{ArchivableMemory, CompactMemory}; #[test] fn test_rkyv_artifact() { @@ -269,14 +267,13 @@ mod tests { assert!(serialized.len() > 0); print!("{:?}", serialized); - let _: &::Archived + let archived: &Archived = unsafe { rkyv::archived_root::(&serialized[..]) }; - // let deser_result: Result, std::convert::Infallible> - // = archived.deserialize(&mut rkyv::Infallible); + let deserialized_artifact = Deserialize::::deserialize(archived, &mut rkyv::Infallible).unwrap(); + unsafe { assert_eq!(deserialized_artifact.inner.compiled_code.as_slice(), artifact.inner.compiled_code.as_slice()) }; + assert_eq!(deserialized_artifact.inner.compiled_code.protection(), artifact.inner.compiled_code.protection()); - // let wrapped_artifact = deser_result.unwrap(); - // let deserialized_artifact: Artifact = wrapped_artifact.into_inner(); // let deserialized_compiled_code = unsafe { deserialized_artifact.inner.compiled_code.as_slice() }; // assert_eq!(deserialized_compiled_code, bytes); } @@ -302,9 +299,9 @@ mod tests { let archived: &Archived = unsafe { rkyv::archived_root::(&serialized[..]) }; - let deserialized_artifact = Deserialize::::deserialize(archived, &mut rkyv::Infallible).unwrap(); - unsafe { assert_eq!(deserialized_artifact.compiled_code.as_slice(), artifact_inner.compiled_code.as_slice()) }; - assert_eq!(deserialized_artifact.compiled_code.protection(), artifact_inner.compiled_code.protection()); + let deserialized_artifact_inner = Deserialize::::deserialize(archived, &mut rkyv::Infallible).unwrap(); + unsafe { assert_eq!(deserialized_artifact_inner.compiled_code.as_slice(), artifact_inner.compiled_code.as_slice()) }; + assert_eq!(deserialized_artifact_inner.compiled_code.protection(), artifact_inner.compiled_code.protection()); } fn make_empty_module_info() -> ModuleInfo { diff --git a/lib/runtime-core/src/sys/memory_rkyv.rs b/lib/runtime-core/src/sys/memory_rkyv.rs index b058442fd11a..a10d5ee36abe 100644 --- a/lib/runtime-core/src/sys/memory_rkyv.rs +++ b/lib/runtime-core/src/sys/memory_rkyv.rs @@ -6,6 +6,7 @@ use crate::sys::windows::{Memory, Protect}; use rkyv::{ Archive, + Archived, Fallible, Serialize as RkyvSerialize, Deserialize as RkyvDeserialize, @@ -76,9 +77,9 @@ where } } -impl DeserializeWith for ArchivableMemory +impl DeserializeWith, Memory, D> for ArchivableMemory { - fn deserialize_with(archived_memory: &ArchivedCompactMemory, deserializer: &mut D) -> Result { + fn deserialize_with(archived_memory: &Archived, deserializer: &mut D) -> Result { let original_protection = archived_memory.protection.deserialize(deserializer)?; let bytes = archived_memory.contents.as_slice(); From c1a2aac9ab19ea653ac2147c4090b4296851bff2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camil=20B=C4=83ncioiu?= Date: Wed, 26 Jan 2022 13:01:38 +0200 Subject: [PATCH 15/22] Implement C API wasmer_instance_cache_rkyv() and wasmer_instance_from_cache_rkyv() --- lib/runtime-c-api/src/instance_cache.rs | 61 ++++++++++++++++++++++--- lib/runtime-c-api/wasmer.h | 5 ++ lib/runtime-c-api/wasmer.hh | 5 ++ lib/runtime-core/src/cache.rs | 3 -- 4 files changed, 64 insertions(+), 10 deletions(-) diff --git a/lib/runtime-c-api/src/instance_cache.rs b/lib/runtime-c-api/src/instance_cache.rs index 0584fe731710..a98a9a421814 100644 --- a/lib/runtime-c-api/src/instance_cache.rs +++ b/lib/runtime-c-api/src/instance_cache.rs @@ -89,10 +89,9 @@ pub unsafe extern "C" fn wasmer_instance_cache_rkyv( Ok(artifact) => { let serialized = serialize_artifact_to_rkyv(artifact); if !serialized.is_empty() { - let buf = serialized.into_boxed_slice(); - *cache_bytes = buf.as_ptr(); - *cache_len = buf.len() as u32; - std::mem::forget(buf); + *cache_bytes = serialized.as_ptr(); + *cache_len = serialized.len() as u32; + std::mem::forget(serialized); } } }; @@ -157,10 +156,58 @@ pub unsafe extern "C" fn wasmer_instance_from_cache( wasmer_result_t::WASMER_OK } -fn serialize_artifact_to_rkyv(artifact: Artifact) -> Vec { +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub unsafe extern "C" fn wasmer_instance_from_cache_rkyv( + instance: *mut *mut wasmer_instance_t, + cache_bytes: *mut u8, + cache_len: u32, + options: *const wasmer_compilation_options_t, +) -> wasmer_result_t { + if cache_bytes.is_null() { + update_last_error(CApiError { + msg: "cache bytes ptr is null".to_string(), + }); + return wasmer_result_t::WASMER_ERROR; + } + + let bytes: &[u8] = slice::from_raw_parts(cache_bytes, cache_len as usize); + let options: &CompilationOptions = &*(options as *const CompilationOptions); + let compiler_chain_generator = prepare_middleware_chain_generator(&options); + let compiler = get_compiler(compiler_chain_generator); + + let artifact = deserialize_artifact_from_rkyv(bytes); + + let new_module = match wasmer_runtime_core::load_cache_with(artifact, &compiler) { + Ok(deserialized_module) => { + deserialized_module + } + Err(_) => { + update_last_error(CApiError { + msg: "Failed to compile the serialized module".to_string(), + }); + return wasmer_result_t::WASMER_ERROR; + } + }; + + let import_object: &mut ImportObject = &mut *(GLOBAL_IMPORT_OBJECT as *mut ImportObject); + let result_instantiation = new_module.instantiate(&import_object); + let mut new_instance = match result_instantiation { + Ok(instance) => instance, + Err(error) => { + update_last_error(error); + return wasmer_result_t::WASMER_ERROR; + } + }; + metering::set_points_limit(&mut new_instance, options.gas_limit); + *instance = Box::into_raw(Box::new(new_instance)) as *mut wasmer_instance_t; + wasmer_result_t::WASMER_OK +} + +fn serialize_artifact_to_rkyv(artifact: Artifact) -> Box<[u8]> { let mut serializer = AllocSerializer::<4096>::default(); serializer.serialize_value(&artifact).unwrap(); - let serialized = serializer.into_serializer().into_inner().to_vec(); + let serialized = serializer.into_serializer().into_inner().into_boxed_slice(); assert!(serialized.len() > 0); serialized @@ -168,7 +215,7 @@ fn serialize_artifact_to_rkyv(artifact: Artifact) -> Vec { fn deserialize_artifact_from_rkyv(bytes: &[u8]) -> Artifact { let archived = unsafe { rkyv::archived_root::(&bytes[..]) }; - let artifact: Artifact = archived.deserialize(&mut rkyv::Infallible).unwrap().into_inner(); + let artifact: Artifact = RkyvDeserialize::::deserialize(archived, &mut rkyv::Infallible).unwrap(); artifact } diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 72fffc83c6cf..fad305dd91e3 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -1083,6 +1083,11 @@ wasmer_result_t wasmer_instance_from_cache(wasmer_instance_t **instance, uint32_t cache_len, const wasmer_compilation_options_t *options); +wasmer_result_t wasmer_instance_from_cache_rkyv(wasmer_instance_t **instance, + uint8_t *cache_bytes, + uint32_t cache_len, + const wasmer_compilation_options_t *options); + uint64_t wasmer_instance_get_points_used(wasmer_instance_t *instance); uint64_t wasmer_instance_get_runtime_breakpoint_value(wasmer_instance_t *instance); diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 1f35663054f9..adeb62ce209b 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -884,6 +884,11 @@ wasmer_result_t wasmer_instance_from_cache(wasmer_instance_t **instance, uint32_t cache_len, const wasmer_compilation_options_t *options); +wasmer_result_t wasmer_instance_from_cache_rkyv(wasmer_instance_t **instance, + uint8_t *cache_bytes, + uint32_t cache_len, + const wasmer_compilation_options_t *options); + uint64_t wasmer_instance_get_points_used(wasmer_instance_t *instance); uint64_t wasmer_instance_get_runtime_breakpoint_value(wasmer_instance_t *instance); diff --git a/lib/runtime-core/src/cache.rs b/lib/runtime-core/src/cache.rs index e82d7ab6a343..a651f8b0747b 100644 --- a/lib/runtime-core/src/cache.rs +++ b/lib/runtime-core/src/cache.rs @@ -273,9 +273,6 @@ mod tests { let deserialized_artifact = Deserialize::::deserialize(archived, &mut rkyv::Infallible).unwrap(); unsafe { assert_eq!(deserialized_artifact.inner.compiled_code.as_slice(), artifact.inner.compiled_code.as_slice()) }; assert_eq!(deserialized_artifact.inner.compiled_code.protection(), artifact.inner.compiled_code.protection()); - - // let deserialized_compiled_code = unsafe { deserialized_artifact.inner.compiled_code.as_slice() }; - // assert_eq!(deserialized_compiled_code, bytes); } #[test] From a9dfb5b7eb117628ec50c1c09533d6fb612dc264 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camil=20B=C4=83ncioiu?= Date: Fri, 28 Jan 2022 17:45:59 +0200 Subject: [PATCH 16/22] Add type MachineSubvalue to break recursivity of MachineValue --- Cargo.lock | 1 + lib/llvm-backend/src/stackmap.rs | 4 +- lib/runtime-core/src/state.rs | 81 +++++++++++++++-------- lib/singlepass-backend/Cargo.toml | 3 + lib/singlepass-backend/src/codegen_x64.rs | 11 ++- 5 files changed, 71 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6f501ea8fdea..95225f5d180e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2170,6 +2170,7 @@ dependencies = [ "lazy_static", "libc", "nix", + "rkyv", "serde", "serde_derive", "smallvec 0.6.13", diff --git a/lib/llvm-backend/src/stackmap.rs b/lib/llvm-backend/src/stackmap.rs index d2f1eef89111..50b7fbd07ba0 100644 --- a/lib/llvm-backend/src/stackmap.rs +++ b/lib/llvm-backend/src/stackmap.rs @@ -253,8 +253,8 @@ impl StackmapEntry { machine_stack_layout.push(major.clone()); } else { machine_stack_layout.push(MachineValue::TwoHalves(Box::new(( - major.clone(), - minor.clone(), + major.clone().into(), + minor.clone().into(), )))); } } diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index 1dfcae8135e3..a3d9d95b4e60 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -7,8 +7,14 @@ use std::collections::BTreeMap; use std::ops::Bound::{Included, Unbounded}; use std::sync::Arc; +use rkyv::{ + Archive, + Serialize as RkyvSerialize, + Deserialize as RkyvDeserialize, +}; + /// An index to a register -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize, Archive, RkyvSerialize, RkyvDeserialize)] pub struct RegisterIndex(pub usize); /// A kind of wasm or constant value @@ -21,7 +27,7 @@ pub enum WasmAbstractValue { } /// A container for the state of a running wasm instance. -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, Archive, RkyvSerialize, RkyvDeserialize)] pub struct MachineState { /// Stack values. pub stack_values: Vec, @@ -64,7 +70,7 @@ pub struct MachineStateDiff { } /// A kind of machine value. -#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize, Archive, RkyvSerialize, RkyvDeserialize)] pub enum MachineValue { /// Undefined. Undefined, @@ -83,11 +89,38 @@ pub enum MachineValue { /// 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? + TwoHalves(Box<(MachineSubvalue, MachineSubvalue)>), // 32-bit values. TODO: optimize: add another type for inner "half" value to avoid boxing? +} + +/// A kind of machine value used in MachineValue::TwoHalves. Created so that MachineValue does not +/// reference two more MachineValues as part of TwoHalves. +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize, Archive, RkyvSerialize, RkyvDeserialize)] +pub enum MachineSubvalue { + /// Undefined. + Undefined, + /// Vmctx Deref. + VmctxDeref(Vec), + /// Wasm Stack. + WasmStack(usize), + /// Wasm Local. + WasmLocal(usize), +} + +impl From for MachineSubvalue { + #[inline] + fn from(subvalue: MachineValue) -> MachineSubvalue { + match subvalue { + MachineValue::Undefined => MachineSubvalue::Undefined, + MachineValue::VmctxDeref(v) => MachineSubvalue::VmctxDeref(v), + MachineValue::WasmStack(i) => MachineSubvalue::WasmStack(i), + MachineValue::WasmLocal(i) => MachineSubvalue::WasmLocal(i), + _ => unimplemented!("invalid kind of MachineValue to convert to MachineSubvalue"), + } + } } /// A map of function states. -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, Archive, RkyvSerialize, RkyvDeserialize)] pub struct FunctionStateMap { /// Initial. pub initial: MachineState, @@ -134,7 +167,7 @@ pub struct OffsetInfo { } /// A map of module state. -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, Archive, RkyvSerialize, RkyvDeserialize)] pub struct ModuleStateMap { /// Local functions. pub local_functions: BTreeMap, @@ -753,7 +786,7 @@ pub mod x64 { stack_offset -= 1; // TODO: Cleanup match inner.0 { - MachineValue::WasmStack(x) => match state.wasm_stack[x] { + MachineSubvalue::WasmStack(x) => match state.wasm_stack[x] { WasmAbstractValue::Const(x) => { assert!(x <= std::u32::MAX as u64); stack[stack_offset] |= x; @@ -764,7 +797,7 @@ pub mod x64 { stack[stack_offset] |= v; } }, - MachineValue::WasmLocal(x) => match fsm.locals[x] { + MachineSubvalue::WasmLocal(x) => match fsm.locals[x] { WasmAbstractValue::Const(x) => { assert!(x <= std::u32::MAX as u64); stack[stack_offset] |= x; @@ -775,16 +808,15 @@ pub mod x64 { stack[stack_offset] |= v; } }, - MachineValue::VmctxDeref(ref seq) => { + MachineSubvalue::VmctxDeref(ref seq) => { stack[stack_offset] |= compute_vmctx_deref(vmctx as *const Ctx, seq) & (std::u32::MAX as u64); } - MachineValue::Undefined => {} - _ => unimplemented!("TwoHalves.0"), + MachineSubvalue::Undefined => {} } match inner.1 { - MachineValue::WasmStack(x) => match state.wasm_stack[x] { + MachineSubvalue::WasmStack(x) => match state.wasm_stack[x] { WasmAbstractValue::Const(x) => { assert!(x <= std::u32::MAX as u64); stack[stack_offset] |= x << 32; @@ -795,7 +827,7 @@ pub mod x64 { stack[stack_offset] |= v << 32; } }, - MachineValue::WasmLocal(x) => match fsm.locals[x] { + MachineSubvalue::WasmLocal(x) => match fsm.locals[x] { WasmAbstractValue::Const(x) => { assert!(x <= std::u32::MAX as u64); stack[stack_offset] |= x << 32; @@ -806,14 +838,13 @@ pub mod x64 { stack[stack_offset] |= v << 32; } }, - MachineValue::VmctxDeref(ref seq) => { + MachineSubvalue::VmctxDeref(ref seq) => { stack[stack_offset] |= (compute_vmctx_deref(vmctx as *const Ctx, seq) & (std::u32::MAX as u64)) << 32; } - MachineValue::Undefined => {} - _ => unimplemented!("TwoHalves.1"), + MachineSubvalue::Undefined => {} } } } @@ -1198,26 +1229,24 @@ pub mod x64 { let v = *stack; stack = stack.offset(1); match inner.0 { - MachineValue::WasmStack(idx) => { + MachineSubvalue::WasmStack(idx) => { wasm_stack[idx] = Some(v & 0xffffffffu64); } - MachineValue::WasmLocal(idx) => { + MachineSubvalue::WasmLocal(idx) => { wasm_locals[idx] = Some(v & 0xffffffffu64); } - MachineValue::VmctxDeref(_) => {} - MachineValue::Undefined => {} - _ => unimplemented!("TwoHalves.0 (read)"), + MachineSubvalue::VmctxDeref(_) => {} + MachineSubvalue::Undefined => {} } match inner.1 { - MachineValue::WasmStack(idx) => { + MachineSubvalue::WasmStack(idx) => { wasm_stack[idx] = Some(v >> 32); } - MachineValue::WasmLocal(idx) => { + MachineSubvalue::WasmLocal(idx) => { wasm_locals[idx] = Some(v >> 32); } - MachineValue::VmctxDeref(_) => {} - MachineValue::Undefined => {} - _ => unimplemented!("TwoHalves.1 (read)"), + MachineSubvalue::VmctxDeref(_) => {} + MachineSubvalue::Undefined => {} } } } diff --git a/lib/singlepass-backend/Cargo.toml b/lib/singlepass-backend/Cargo.toml index 0478b5ba7e53..dc5ee96aecb2 100644 --- a/lib/singlepass-backend/Cargo.toml +++ b/lib/singlepass-backend/Cargo.toml @@ -24,6 +24,9 @@ bincode = "1.2" serde = "1.0" serde_derive = "1.0" +[dependencies.rkyv] +version = "0.7.26" + [features] default = ["deterministic-execution"] deterministic-execution = ["wasmparser/deterministic", "wasmer-runtime-core/deterministic-execution"] diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index ec44ddb1efa3..6a58d3a12c64 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -20,6 +20,12 @@ use std::{ usize, }; +use rkyv::{ + Archive, + Serialize as RkyvSerialize, + Deserialize as RkyvDeserialize, +}; + use bincode; use wasmer_runtime_core::{ @@ -253,7 +259,10 @@ pub struct X64ExecutionContext { /// On-disk cache format. /// Offsets are relative to the start of the executable image. -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Archive, RkyvSerialize, RkyvDeserialize)] +#[archive(compare(PartialEq))] +#[archive_attr(derive(Debug))] +#[archive_attr(derive(PartialEq))] pub struct CacheImage { /// The executable image. code: Vec, From 42275645643adaba425f671f4b2efa30b5df0453 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camil=20B=C4=83ncioiu?= Date: Mon, 31 Jan 2022 20:02:57 +0200 Subject: [PATCH 17/22] Fixes for compilation --- lib/runtime-core/src/backend.rs | 10 ++++++++-- lib/runtime-core/src/state.rs | 10 +++++----- lib/singlepass-backend/src/codegen_x64.rs | 5 +---- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/lib/runtime-core/src/backend.rs b/lib/runtime-core/src/backend.rs index 4aca2d2a71c2..173c0ae36d01 100644 --- a/lib/runtime-core/src/backend.rs +++ b/lib/runtime-core/src/backend.rs @@ -18,6 +18,12 @@ use std::{any::Any, ptr::NonNull}; use std::collections::HashMap; +use rkyv::{ + Archive, + Serialize as RkyvSerialize, + Deserialize as RkyvDeserialize, +}; + pub mod sys { pub use crate::sys::*; } @@ -154,7 +160,7 @@ impl CompilerConfig { } /// An exception table for a `RunnableModule`. -#[derive(Clone, Debug, Default, Serialize, Deserialize)] +#[derive(Clone, Debug, Default, Serialize, Deserialize, Archive, RkyvSerialize, RkyvDeserialize)] pub struct ExceptionTable { /// Mappings from offsets in generated machine code to the corresponding exception code. pub offset_to_code: HashMap, @@ -167,7 +173,7 @@ impl ExceptionTable { } /// The code of an exception. -#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Archive, RkyvSerialize, RkyvDeserialize)] pub enum ExceptionCode { /// An `unreachable` opcode was executed. Unreachable = 0, diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index a3d9d95b4e60..0041eb91983f 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -18,7 +18,7 @@ use rkyv::{ pub struct RegisterIndex(pub usize); /// A kind of wasm or constant value -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize, Archive, RkyvSerialize, RkyvDeserialize)] pub enum WasmAbstractValue { /// A wasm runtime value Runtime, @@ -44,7 +44,7 @@ pub struct MachineState { } /// A diff of two `MachineState`s. -#[derive(Clone, Debug, Default, Serialize, Deserialize)] +#[derive(Clone, Debug, Default, Serialize, Deserialize, Archive, RkyvSerialize, RkyvDeserialize)] pub struct MachineStateDiff { /// Last. pub last: Option, @@ -114,7 +114,7 @@ impl From for MachineSubvalue { MachineValue::VmctxDeref(v) => MachineSubvalue::VmctxDeref(v), MachineValue::WasmStack(i) => MachineSubvalue::WasmStack(i), MachineValue::WasmLocal(i) => MachineSubvalue::WasmLocal(i), - _ => unimplemented!("invalid kind of MachineValue to convert to MachineSubvalue"), + _ => unreachable!("invalid kind of MachineValue to convert to MachineSubvalue"), } } } @@ -145,7 +145,7 @@ pub struct FunctionStateMap { } /// A kind of suspend offset. -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Serialize, Deserialize, Archive, RkyvSerialize, RkyvDeserialize)] pub enum SuspendOffset { /// A loop. Loop(usize), @@ -156,7 +156,7 @@ pub enum SuspendOffset { } /// Info for an offset. -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, Archive, RkyvSerialize, RkyvDeserialize)] pub struct OffsetInfo { /// End offset. pub end_offset: usize, // excluded bound diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 6a58d3a12c64..b404c0f0bf74 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -259,10 +259,7 @@ pub struct X64ExecutionContext { /// On-disk cache format. /// Offsets are relative to the start of the executable image. -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Archive, RkyvSerialize, RkyvDeserialize)] -#[archive(compare(PartialEq))] -#[archive_attr(derive(Debug))] -#[archive_attr(derive(PartialEq))] +#[derive(Clone, Debug, Serialize, Deserialize, Archive, RkyvSerialize, RkyvDeserialize)] pub struct CacheImage { /// The executable image. code: Vec, From 29addef588d80ca7630b6f8f89d55b0600c6d641 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camil=20B=C4=83ncioiu?= Date: Wed, 9 Feb 2022 20:17:52 +0200 Subject: [PATCH 18/22] Ensure correct size of the serialized data --- lib/runtime-c-api/src/instance_cache.rs | 217 ++++++++++++---------- lib/runtime-c-api/wasmer.h | 13 +- lib/runtime-c-api/wasmer.hh | 13 +- lib/runtime-core/src/sys/memory_rkyv.rs | 22 +-- lib/runtime-core/src/sys/unix/memory.rs | 31 ++++ lib/singlepass-backend/src/codegen_x64.rs | 33 +++- lib/singlepass-backend/src/lib.rs | 2 + 7 files changed, 192 insertions(+), 139 deletions(-) diff --git a/lib/runtime-c-api/src/instance_cache.rs b/lib/runtime-c-api/src/instance_cache.rs index a98a9a421814..8d836e6c5966 100644 --- a/lib/runtime-c-api/src/instance_cache.rs +++ b/lib/runtime-c-api/src/instance_cache.rs @@ -10,13 +10,41 @@ use rkyv::{ ser::serializers::AllocSerializer, }; -use wasmer_runtime_core::{cache::Artifact, import::ImportObject}; +use wasmer_runtime_core::{ + cache::{Artifact, Error as CacheError}, + import::ImportObject, +}; use std::slice; use crate::import::GLOBAL_IMPORT_OBJECT; #[cfg(not(feature = "cranelift-backend"))] use wasmer_middleware_common::metering; +#[cfg(feature = "singlepass-backend")] +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub unsafe extern "C" fn wasmer_instance_enable_rkyv() { + wasmer_singlepass_backend::USE_RKYV_SERIALIZATION = true; +} + +#[cfg(feature = "singlepass-backend")] +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +pub unsafe extern "C" fn wasmer_instance_disable_rkyv() { + wasmer_singlepass_backend::USE_RKYV_SERIALIZATION = false; +} + +#[cfg(feature = "singlepass-backend")] +pub unsafe fn is_rkyv_enabled() -> bool { + wasmer_singlepass_backend::USE_RKYV_SERIALIZATION +} + +#[cfg(not(feature = "singlepass-backend"))] +pub unsafe fn is_rkyv_enabled() -> bool { + false +} + + #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub unsafe extern "C" fn wasmer_instance_cache( @@ -33,28 +61,26 @@ pub unsafe extern "C" fn wasmer_instance_cache( let instance = &mut *(instance as *mut wasmer_runtime::Instance); let module = instance.module(); + match module.cache() { Err(error) => { update_last_error(CApiError { - msg: format!("{:?}", error), + msg: format!("wasmer_instance_cache: artifact creation failed: {:?}", error), }); return wasmer_result_t::WASMER_ERROR; } Ok(artifact) => { - match artifact.serialize() { + match serialize_artifact(artifact) { Err(error) => { update_last_error(CApiError { - msg: format!("{:?}", error), + msg: format!("wasmer_instance_cache: artifact serialization failed: {:?}", error), }); return wasmer_result_t::WASMER_ERROR; } - Ok(bytes_vec) => { - if !bytes_vec.is_empty() { - let buf = bytes_vec.into_boxed_slice(); - *cache_bytes = buf.as_ptr(); - *cache_len = buf.len() as u32; - std::mem::forget(buf); - } + Ok(bytes) => { + *cache_bytes = bytes.as_ptr(); + *cache_len = bytes.len() as u32; + std::mem::forget(bytes); } } } @@ -63,42 +89,6 @@ pub unsafe extern "C" fn wasmer_instance_cache( wasmer_result_t::WASMER_OK } -#[allow(clippy::cast_ptr_alignment)] -#[no_mangle] -pub unsafe extern "C" fn wasmer_instance_cache_rkyv( - instance: *mut wasmer_instance_t, - cache_bytes: *mut *const u8, - cache_len: *mut u32, -) -> wasmer_result_t { - if instance.is_null() { - update_last_error(CApiError { - msg: "null instance".to_string(), - }); - return wasmer_result_t::WASMER_ERROR; - } - - let instance = &mut *(instance as *mut wasmer_runtime::Instance); - let module = instance.module(); - match module.cache() { - Err(error) => { - update_last_error(CApiError { - msg: format!("{:?}", error), - }); - return wasmer_result_t::WASMER_ERROR; - } - Ok(artifact) => { - let serialized = serialize_artifact_to_rkyv(artifact); - if !serialized.is_empty() { - *cache_bytes = serialized.as_ptr(); - *cache_len = serialized.len() as u32; - std::mem::forget(serialized); - } - } - }; - - wasmer_result_t::WASMER_OK -} - #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub unsafe extern "C" fn wasmer_instance_from_cache( @@ -119,24 +109,23 @@ pub unsafe extern "C" fn wasmer_instance_from_cache( let compiler_chain_generator = prepare_middleware_chain_generator(&options); let compiler = get_compiler(compiler_chain_generator); - let artifact = match Artifact::deserialize(bytes) { + let artifact = match deserialize_artifact(bytes) { Ok(deserialized_artifact) => deserialized_artifact, Err(_) => { update_last_error(CApiError { - msg: "Failed to compile the serialized module".to_string(), + msg: "wasmer_instance_from_cache: artifact deserialization failed".to_string(), }); return wasmer_result_t::WASMER_ERROR; } }; - let new_module = match wasmer_runtime_core::load_cache_with(artifact, &compiler) { Ok(deserialized_module) => { deserialized_module } Err(_) => { update_last_error(CApiError { - msg: "Failed to compile the serialized module".to_string(), + msg: "wasmer_instance_from_cache: artifact instantiation into module failed".to_string(), }); return wasmer_result_t::WASMER_ERROR; } @@ -156,66 +145,94 @@ pub unsafe extern "C" fn wasmer_instance_from_cache( wasmer_result_t::WASMER_OK } -#[allow(clippy::cast_ptr_alignment)] -#[no_mangle] -pub unsafe extern "C" fn wasmer_instance_from_cache_rkyv( - instance: *mut *mut wasmer_instance_t, - cache_bytes: *mut u8, - cache_len: u32, - options: *const wasmer_compilation_options_t, -) -> wasmer_result_t { - if cache_bytes.is_null() { - update_last_error(CApiError { - msg: "cache bytes ptr is null".to_string(), - }); - return wasmer_result_t::WASMER_ERROR; - } - - let bytes: &[u8] = slice::from_raw_parts(cache_bytes, cache_len as usize); - let options: &CompilationOptions = &*(options as *const CompilationOptions); - let compiler_chain_generator = prepare_middleware_chain_generator(&options); - let compiler = get_compiler(compiler_chain_generator); - - let artifact = deserialize_artifact_from_rkyv(bytes); - - let new_module = match wasmer_runtime_core::load_cache_with(artifact, &compiler) { - Ok(deserialized_module) => { - deserialized_module - } - Err(_) => { - update_last_error(CApiError { - msg: "Failed to compile the serialized module".to_string(), - }); - return wasmer_result_t::WASMER_ERROR; - } +#[cfg(feature = "singlepass-backend")] +fn serialize_artifact(artifact: Artifact) -> Result, CacheError> { + let serializer = match unsafe { is_rkyv_enabled() } { + true => serialize_artifact_with_rkyv, + false => serialize_artifact_with_serde, }; - let import_object: &mut ImportObject = &mut *(GLOBAL_IMPORT_OBJECT as *mut ImportObject); - let result_instantiation = new_module.instantiate(&import_object); - let mut new_instance = match result_instantiation { - Ok(instance) => instance, - Err(error) => { - update_last_error(error); - return wasmer_result_t::WASMER_ERROR; - } - }; - metering::set_points_limit(&mut new_instance, options.gas_limit); - *instance = Box::into_raw(Box::new(new_instance)) as *mut wasmer_instance_t; - wasmer_result_t::WASMER_OK + serializer(artifact).into() +} + +#[cfg(not(feature = "singlepass-backend"))] +fn serialize_artifact(artifact: Artifact) -> Result, CacheError> { + serialize_artifact_with_serde(artifact).into() } -fn serialize_artifact_to_rkyv(artifact: Artifact) -> Box<[u8]> { +#[cfg(feature = "singlepass-backend")] +fn serialize_artifact_with_rkyv(artifact: Artifact) -> Result, CacheError> { let mut serializer = AllocSerializer::<4096>::default(); serializer.serialize_value(&artifact).unwrap(); let serialized = serializer.into_serializer().into_inner().into_boxed_slice(); - assert!(serialized.len() > 0); + if serialized.is_empty() { + return Err(CacheError::SerializeError("rkyv serialization failed".to_string())); + } + + Ok(serialized) +} - serialized +fn serialize_artifact_with_serde(artifact: Artifact) -> Result, CacheError> { + match artifact.serialize() { + Ok(serialized) => Ok(serialized.into_boxed_slice()), + Err(error) => Err(error), + } +} + +#[cfg(feature = "singlepass-backend")] +fn deserialize_artifact(bytes: &[u8]) -> Result { + let deserializer = match unsafe { is_rkyv_enabled() } { + true => deserialize_artifact_with_rkyv, + false => deserialize_artifact_with_serde, + }; + + deserializer(bytes) +} + +#[cfg(not(feature = "singlepass-backend"))] +fn deserialize_artifact(bytes: &[u8]) -> Result { + deserialize_artifact_with_serde(bytes) } -fn deserialize_artifact_from_rkyv(bytes: &[u8]) -> Artifact { +#[cfg(feature = "singlepass-backend")] +fn deserialize_artifact_with_rkyv(bytes: &[u8]) -> Result { let archived = unsafe { rkyv::archived_root::(&bytes[..]) }; let artifact: Artifact = RkyvDeserialize::::deserialize(archived, &mut rkyv::Infallible).unwrap(); - artifact + Ok(artifact) } +fn deserialize_artifact_with_serde(bytes: &[u8]) -> Result { + Artifact::deserialize(bytes) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_simple_instantiation() { + let bytecode = get_wasm(); + + let options = CompilationOptions { + gas_limit: 1000, + unmetered_locals: 100, + max_memory_grow: 10, + max_memory_grow_delta: 10, + opcode_trace: false, + metering: true, + runtime_breakpoints: true + }; + + let compiler_chain_generator = unsafe { prepare_middleware_chain_generator(&options) }; + let compiler = unsafe { get_compiler(compiler_chain_generator) }; + let module = wasmer_runtime_core::compile_with(bytecode.as_slice(), &compiler).unwrap(); + let import_object = &mut ImportObject::new(); + let mut instance = module.instantiate(&import_object).unwrap(); + metering::set_points_limit(&mut instance, options.gas_limit); + } + + fn get_wasm() -> Vec { + let filename = "../../examples/erc20.wasm"; + std::fs::read(filename).expect("could not read bytecode from file") + } +} diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index fad305dd91e3..cccdcb148516 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -861,10 +861,6 @@ wasmer_result_t wasmer_instance_cache(wasmer_instance_t *instance, const uint8_t **cache_bytes, uint32_t *cache_len); -wasmer_result_t wasmer_instance_cache_rkyv(wasmer_instance_t *instance, - const uint8_t **cache_bytes, - uint32_t *cache_len); - /** * Calls an exported function of a WebAssembly instance by `name` * with the provided parameters. The exported function results are @@ -1033,6 +1029,10 @@ const wasmer_memory_t *wasmer_instance_context_memory(const wasmer_instance_cont */ void wasmer_instance_destroy(wasmer_instance_t *instance); +void wasmer_instance_disable_rkyv(void); + +void wasmer_instance_enable_rkyv(void); + /** * Gets all the exports of the given WebAssembly instance. * @@ -1083,11 +1083,6 @@ wasmer_result_t wasmer_instance_from_cache(wasmer_instance_t **instance, uint32_t cache_len, const wasmer_compilation_options_t *options); -wasmer_result_t wasmer_instance_from_cache_rkyv(wasmer_instance_t **instance, - uint8_t *cache_bytes, - uint32_t cache_len, - const wasmer_compilation_options_t *options); - uint64_t wasmer_instance_get_points_used(wasmer_instance_t *instance); uint64_t wasmer_instance_get_runtime_breakpoint_value(wasmer_instance_t *instance); diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index adeb62ce209b..98426f852e71 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -676,10 +676,6 @@ wasmer_result_t wasmer_instance_cache(wasmer_instance_t *instance, const uint8_t **cache_bytes, uint32_t *cache_len); -wasmer_result_t wasmer_instance_cache_rkyv(wasmer_instance_t *instance, - const uint8_t **cache_bytes, - uint32_t *cache_len); - /// Calls an exported function of a WebAssembly instance by `name` /// with the provided parameters. The exported function results are /// stored on the provided `results` pointer. @@ -836,6 +832,10 @@ const wasmer_memory_t *wasmer_instance_context_memory(const wasmer_instance_cont /// ``` void wasmer_instance_destroy(wasmer_instance_t *instance); +void wasmer_instance_disable_rkyv(); + +void wasmer_instance_enable_rkyv(); + /// Gets all the exports of the given WebAssembly instance. /// /// This function stores a Rust vector of exports into `exports` as an @@ -884,11 +884,6 @@ wasmer_result_t wasmer_instance_from_cache(wasmer_instance_t **instance, uint32_t cache_len, const wasmer_compilation_options_t *options); -wasmer_result_t wasmer_instance_from_cache_rkyv(wasmer_instance_t **instance, - uint8_t *cache_bytes, - uint32_t cache_len, - const wasmer_compilation_options_t *options); - uint64_t wasmer_instance_get_points_used(wasmer_instance_t *instance); uint64_t wasmer_instance_get_runtime_breakpoint_value(wasmer_instance_t *instance); diff --git a/lib/runtime-core/src/sys/memory_rkyv.rs b/lib/runtime-core/src/sys/memory_rkyv.rs index a10d5ee36abe..b729447323bb 100644 --- a/lib/runtime-core/src/sys/memory_rkyv.rs +++ b/lib/runtime-core/src/sys/memory_rkyv.rs @@ -24,6 +24,7 @@ pub struct ArchivableMemory; #[archive_attr(derive(PartialEq))] pub struct CompactMemory { contents: Vec, + content_size: usize, protection: Protect, } @@ -32,6 +33,7 @@ impl CompactMemory { pub unsafe fn from_memory(memory: &Memory) -> Self { CompactMemory { contents: memory.as_slice().to_vec(), + content_size: memory.content_size(), protection: memory.protection(), } } @@ -51,6 +53,8 @@ impl CompactMemory { .expect("Could not protect memory as its original protection"); } + memory.set_content_size(self.content_size); + memory } } @@ -80,21 +84,8 @@ where impl DeserializeWith, Memory, D> for ArchivableMemory { fn deserialize_with(archived_memory: &Archived, deserializer: &mut D) -> Result { - let original_protection = archived_memory.protection.deserialize(deserializer)?; - let bytes = archived_memory.contents.as_slice(); - - let mut memory = Memory::with_size_protect(bytes.len(), Protect::ReadWrite) - .expect("Could not create a memory"); - - unsafe { - memory.as_slice_mut().copy_from_slice(&*bytes); - - if memory.protection() != original_protection { - memory - .protect(.., original_protection) - .expect("Could not protect memory as its original protection"); - } - } + let compact_memory: CompactMemory = archived_memory.deserialize(deserializer)?; + let memory = unsafe { compact_memory.into_memory() }; Ok(memory) } @@ -128,7 +119,6 @@ mod tests { assert!(serialized.len() > 0); let archived = unsafe { rkyv::archived_root::(&serialized[..]) }; - assert_eq!(archived, &compact_memory); let deserialized: CompactMemory = archived.deserialize(&mut rkyv::Infallible).unwrap(); assert_eq!(deserialized, compact_memory); diff --git a/lib/runtime-core/src/sys/unix/memory.rs b/lib/runtime-core/src/sys/unix/memory.rs index c515636cd54c..b3c121fadf79 100644 --- a/lib/runtime-core/src/sys/unix/memory.rs +++ b/lib/runtime-core/src/sys/unix/memory.rs @@ -18,6 +18,7 @@ pub struct Memory { size: usize, protection: Protect, fd: Option>, + content_size: usize, } impl Memory { @@ -54,6 +55,7 @@ impl Memory { size: file_len as usize, protection, fd: Some(Arc::new(raw_fd)), + content_size: 0, }) } } @@ -66,6 +68,7 @@ impl Memory { size: 0, protection, fd: None, + content_size: 0, }); } @@ -90,10 +93,19 @@ impl Memory { size, protection, fd: None, + content_size: 0, }) } } + /// Create a new memory with the given contents size and protection. + /// Used when the size of the contents must be tracked (e.g. for rkyv deserialization). + pub fn with_content_size_protect(content_size: usize, protection: Protect) -> Result { + let mut memory = Self::with_size_protect(content_size, protection)?; + memory.set_content_size(content_size); + Ok(memory) + } + /// Create a new memory with the given size. pub fn with_size(size: usize) -> Result { if size == 0 { @@ -102,6 +114,7 @@ impl Memory { size: 0, protection: Protect::None, fd: None, + content_size: 0, }); } @@ -129,6 +142,7 @@ impl Memory { size, protection: Protect::None, fd: None, + content_size: 0, }) } } @@ -173,6 +187,12 @@ impl Memory { } } + /// Set the content size of this memory. Must be set manually, as this is different in each + /// case. + pub fn set_content_size(&mut self, size: usize) { + self.content_size = size; + } + /// 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(); @@ -187,6 +207,7 @@ impl Memory { size: second_size, protection: self.protection, fd: self.fd.clone(), + content_size: 0, }; (self, second) @@ -200,11 +221,21 @@ impl Memory { self.size } + /// Gets the size of the actual contents of this memory. + pub fn content_size(&self) -> usize { + self.content_size + } + /// Gets a slice for this memory. pub unsafe fn as_slice(&self) -> &[u8] { slice::from_raw_parts(self.ptr, self.size) } + /// Gets a slice for this memory, bounded by content_size. + pub unsafe fn as_slice_contents(&self) -> &[u8] { + slice::from_raw_parts(self.ptr, self.content_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) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index b404c0f0bf74..196971d2206a 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -22,8 +22,11 @@ use std::{ use rkyv::{ Archive, + Archived, Serialize as RkyvSerialize, Deserialize as RkyvDeserialize, + ser::Serializer, + ser::serializers::AllocSerializer, }; use bincode; @@ -67,6 +70,8 @@ pub const INLINE_BREAKPOINT_SIZE_X86_SINGLEPASS: usize = 7; /// Inline breakpoint size for aarch64. pub const INLINE_BREAKPOINT_SIZE_AARCH64_SINGLEPASS: usize = 12; +pub static mut USE_RKYV_SERIALIZATION: bool = false; + static BACKEND_ID: &str = "singlepass"; #[cfg(target_arch = "x86_64")] @@ -306,7 +311,7 @@ pub struct SinglepassCache { impl CacheGen for SinglepassCache { fn generate_cache(&self) -> Result<(Box<[u8]>, Memory), CacheError> { - let mut memory = Memory::with_size_protect(self.buffer.len(), Protect::ReadWrite) + let mut memory = Memory::with_content_size_protect(self.buffer.len(), Protect::ReadWrite) .map_err(CacheError::SerializeError)?; let buffer = &*self.buffer; @@ -848,8 +853,19 @@ impl ModuleCodeGenerator exception_table: exception_table.clone(), }; - let cache = SinglepassCache { - buffer: Arc::from(bincode::serialize(&cache_image).unwrap().into_boxed_slice()), + let cache = if unsafe { USE_RKYV_SERIALIZATION } { + let mut serializer = AllocSerializer::<4096>::default(); + serializer.serialize_value(&cache_image).unwrap(); + let archived_cache_image = serializer.into_serializer().into_inner(); + + SinglepassCache { + buffer: Arc::from(archived_cache_image.as_slice()), + } + } else { + let serialized_cache_image = bincode::serialize(&cache_image).unwrap().into_boxed_slice(); + SinglepassCache { + buffer: Arc::from(serialized_cache_image), + } }; Ok(( @@ -940,8 +956,15 @@ impl ModuleCodeGenerator unsafe fn from_cache(artifact: Artifact, _: Token) -> Result { let (info, _, memory) = artifact.consume(); - let cache_image: CacheImage = bincode::deserialize(memory.as_slice()) - .map_err(|x| CacheError::DeserializeError(format!("{:?}", x)))?; + let cache_image: CacheImage = if USE_RKYV_SERIALIZATION { + let memory_contents = memory.as_slice_contents(); + let archived_cache_image: &Archived + = rkyv::archived_root::(memory_contents); + RkyvDeserialize::::deserialize(archived_cache_image, &mut rkyv::Infallible).unwrap() + } else { + bincode::deserialize(memory.as_slice()) + .map_err(|x| CacheError::DeserializeError(format!("{:?}", x)))? + }; let mut code_mem = CodeMemory::new(cache_image.code.len()); code_mem[0..cache_image.code.len()].copy_from_slice(&cache_image.code); diff --git a/lib/singlepass-backend/src/lib.rs b/lib/singlepass-backend/src/lib.rs index 0704cd8eba60..701c4c47e835 100644 --- a/lib/singlepass-backend/src/lib.rs +++ b/lib/singlepass-backend/src/lib.rs @@ -41,6 +41,8 @@ mod machine; #[cfg(target_arch = "aarch64")] mod translator_aarch64; +pub use codegen_x64::USE_RKYV_SERIALIZATION; + pub use codegen_x64::X64FunctionCode as FunctionCodeGenerator; pub use codegen_x64::X64ModuleCodeGenerator as ModuleCodeGenerator; From f8fb1df0e5289529fe0e47d4c43f90d92e7f931b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camil=20B=C4=83ncioiu?= Date: Wed, 9 Feb 2022 20:26:01 +0200 Subject: [PATCH 19/22] Update comment --- lib/runtime-core/src/sys/memory_rkyv.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/runtime-core/src/sys/memory_rkyv.rs b/lib/runtime-core/src/sys/memory_rkyv.rs index b729447323bb..b9c5066696cd 100644 --- a/lib/runtime-core/src/sys/memory_rkyv.rs +++ b/lib/runtime-core/src/sys/memory_rkyv.rs @@ -17,7 +17,7 @@ use rkyv::{ /// A serializable wrapper for Memory. pub struct ArchivableMemory; -/// The archived contents of a wrapped Memory. +/// The archived contents of a Memory. #[derive(Archive, RkyvSerialize, RkyvDeserialize, Debug, PartialEq)] #[archive(compare(PartialEq))] #[archive_attr(derive(Debug))] From 037321df7149d037461c101a7f19be619c64f1e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camil=20B=C4=83ncioiu?= Date: Wed, 9 Feb 2022 20:34:36 +0200 Subject: [PATCH 20/22] Remove unneeded config file --- .gitignore | 1 + .ycm_extra_conf.py | 13 ------------- 2 files changed, 1 insertion(+), 13 deletions(-) delete mode 100644 .ycm_extra_conf.py diff --git a/.gitignore b/.gitignore index 3768a739734f..8861fc3b5949 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ capi/ api-docs/ api-docs-repo/ tags +.ycm* diff --git a/.ycm_extra_conf.py b/.ycm_extra_conf.py deleted file mode 100644 index 60b5b509f975..000000000000 --- a/.ycm_extra_conf.py +++ /dev/null @@ -1,13 +0,0 @@ -def Settings(**kwargs): - if kwargs['language'] == 'rust': - return { - 'ls': { - 'diagnostics': { - 'disabled': ['unresolved-proc-macro', 'inactive-code'] - }, - 'checkOnSave': { - 'enable': True, - 'extraArgs': ['--target-dir', 'target/check'] - }, - } - } From e17fd73446b225647693826cf6b5e964a4e49ef0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camil=20B=C4=83ncioiu?= Date: Wed, 9 Feb 2022 20:36:12 +0200 Subject: [PATCH 21/22] Delete irrelevant test --- lib/runtime-c-api/src/instance_cache.rs | 32 ------------------------- 1 file changed, 32 deletions(-) diff --git a/lib/runtime-c-api/src/instance_cache.rs b/lib/runtime-c-api/src/instance_cache.rs index 8d836e6c5966..58f1e074dd59 100644 --- a/lib/runtime-c-api/src/instance_cache.rs +++ b/lib/runtime-c-api/src/instance_cache.rs @@ -204,35 +204,3 @@ fn deserialize_artifact_with_rkyv(bytes: &[u8]) -> Result fn deserialize_artifact_with_serde(bytes: &[u8]) -> Result { Artifact::deserialize(bytes) } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_simple_instantiation() { - let bytecode = get_wasm(); - - let options = CompilationOptions { - gas_limit: 1000, - unmetered_locals: 100, - max_memory_grow: 10, - max_memory_grow_delta: 10, - opcode_trace: false, - metering: true, - runtime_breakpoints: true - }; - - let compiler_chain_generator = unsafe { prepare_middleware_chain_generator(&options) }; - let compiler = unsafe { get_compiler(compiler_chain_generator) }; - let module = wasmer_runtime_core::compile_with(bytecode.as_slice(), &compiler).unwrap(); - let import_object = &mut ImportObject::new(); - let mut instance = module.instantiate(&import_object).unwrap(); - metering::set_points_limit(&mut instance, options.gas_limit); - } - - fn get_wasm() -> Vec { - let filename = "../../examples/erc20.wasm"; - std::fs::read(filename).expect("could not read bytecode from file") - } -} From 68f13582ba9185e6c8813ef134708991cbaff63a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camil=20B=C4=83ncioiu?= Date: Wed, 9 Feb 2022 21:03:05 +0200 Subject: [PATCH 22/22] Minor fixes --- lib/runtime-core/src/cache.rs | 9 --------- lib/runtime-core/src/lib.rs | 1 - lib/runtime-core/src/sys/memory_rkyv.rs | 2 +- lib/runtime-core/src/sys/unix/memory.rs | 12 ++++++------ lib/singlepass-backend/src/codegen_x64.rs | 4 +++- 5 files changed, 10 insertions(+), 18 deletions(-) diff --git a/lib/runtime-core/src/cache.rs b/lib/runtime-core/src/cache.rs index a651f8b0747b..3f8820788341 100644 --- a/lib/runtime-core/src/cache.rs +++ b/lib/runtime-core/src/cache.rs @@ -306,30 +306,21 @@ mod tests { memories: Map::new(), globals: Map::new(), tables: Map::new(), - imported_functions: Map::new(), imported_memories: Map::new(), imported_tables: Map::new(), imported_globals: Map::new(), - exports: Default::default(), - data_initializers: Vec::new(), elem_initializers: Vec::new(), - start_func: None, - func_assoc: Map::new(), signatures: Map::new(), backend: "test".to_string(), - namespace_table: StringTable::new(), name_table: StringTable::new(), - em_symbol_map: None, - custom_sections: HashMap::new(), - generate_debug_info: false, #[cfg(feature = "generate-debug-information")] debug_info_manager: crate::jit_debug::JitCodeDebugInfoManager::new(), diff --git a/lib/runtime-core/src/lib.rs b/lib/runtime-core/src/lib.rs index 15e7e0ed27e8..daf63ef74193 100644 --- a/lib/runtime-core/src/lib.rs +++ b/lib/runtime-core/src/lib.rs @@ -25,7 +25,6 @@ #![cfg_attr(nightly, feature(unwind_attributes))] #![doc(html_favicon_url = "https://wasmer.io/static/icons/favicon.ico")] #![doc(html_logo_url = "https://avatars3.githubusercontent.com/u/44205449?s=200&v=4")] -#![feature(trivial_bounds)] #[macro_use] extern crate serde_derive; diff --git a/lib/runtime-core/src/sys/memory_rkyv.rs b/lib/runtime-core/src/sys/memory_rkyv.rs index b9c5066696cd..c7954eb77358 100644 --- a/lib/runtime-core/src/sys/memory_rkyv.rs +++ b/lib/runtime-core/src/sys/memory_rkyv.rs @@ -24,7 +24,7 @@ pub struct ArchivableMemory; #[archive_attr(derive(PartialEq))] pub struct CompactMemory { contents: Vec, - content_size: usize, + content_size: u32, protection: Protect, } diff --git a/lib/runtime-core/src/sys/unix/memory.rs b/lib/runtime-core/src/sys/unix/memory.rs index b3c121fadf79..8b56ac6b78eb 100644 --- a/lib/runtime-core/src/sys/unix/memory.rs +++ b/lib/runtime-core/src/sys/unix/memory.rs @@ -18,7 +18,7 @@ pub struct Memory { size: usize, protection: Protect, fd: Option>, - content_size: usize, + content_size: u32, } impl Memory { @@ -100,8 +100,8 @@ impl Memory { /// Create a new memory with the given contents size and protection. /// Used when the size of the contents must be tracked (e.g. for rkyv deserialization). - pub fn with_content_size_protect(content_size: usize, protection: Protect) -> Result { - let mut memory = Self::with_size_protect(content_size, protection)?; + pub fn with_content_size_protect(content_size: u32, protection: Protect) -> Result { + let mut memory = Self::with_size_protect(content_size as usize, protection)?; memory.set_content_size(content_size); Ok(memory) } @@ -189,7 +189,7 @@ impl Memory { /// Set the content size of this memory. Must be set manually, as this is different in each /// case. - pub fn set_content_size(&mut self, size: usize) { + pub fn set_content_size(&mut self, size: u32) { self.content_size = size; } @@ -222,7 +222,7 @@ impl Memory { } /// Gets the size of the actual contents of this memory. - pub fn content_size(&self) -> usize { + pub fn content_size(&self) -> u32 { self.content_size } @@ -233,7 +233,7 @@ impl Memory { /// Gets a slice for this memory, bounded by content_size. pub unsafe fn as_slice_contents(&self) -> &[u8] { - slice::from_raw_parts(self.ptr, self.content_size) + slice::from_raw_parts(self.ptr, self.content_size as usize) } /// Gets a mutable slice for this memory. diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 196971d2206a..116e0deb0ee1 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -18,6 +18,7 @@ use std::{ slice, sync::{Arc, RwLock}, usize, + convert::TryInto, }; use rkyv::{ @@ -311,7 +312,8 @@ pub struct SinglepassCache { impl CacheGen for SinglepassCache { fn generate_cache(&self) -> Result<(Box<[u8]>, Memory), CacheError> { - let mut memory = Memory::with_content_size_protect(self.buffer.len(), Protect::ReadWrite) + let content_size: u32 = self.buffer.len().try_into().unwrap(); + let mut memory = Memory::with_content_size_protect(content_size, Protect::ReadWrite) .map_err(CacheError::SerializeError)?; let buffer = &*self.buffer;