From 5e69366b1d9b1cf36299b14fcc1cc9e62489fd39 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 18 Mar 2021 14:05:38 +0100 Subject: [PATCH 1/5] feat(types) Remove dependency to `cranelift-entity`. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't be afraid, everything is cool. `cranelift-entity` is nice, but we are limited by it. We want to go further for some features. Those features are very likely to be refused by Cranelift because it's out of their scope. This patch basically copies the code from `cranelift-entity` inside `wasmer-types`. The code has been modified to fit in our own “`no_std`” strategy. The code will be modified deeper in upcoming patches and most of the entities are likely to radically change. The goal of this patch is strictly to not break our code while porting the new code. --- Cargo.lock | 4 - lib/wasmer-types/Cargo.toml | 5 +- lib/wasmer-types/src/entity/boxed_slice.rs | 316 ++++++++++++++ lib/wasmer-types/src/entity/iter.rs | 124 ++++++ lib/wasmer-types/src/entity/keys.rs | 58 +++ lib/wasmer-types/src/entity/mod.rs | 92 ++++ lib/wasmer-types/src/entity/packed_option.rs | 171 ++++++++ lib/wasmer-types/src/entity/primary_map.rs | 425 +++++++++++++++++++ lib/wasmer-types/src/entity/secondary_map.rs | 320 ++++++++++++++ lib/wasmer-types/src/lib.rs | 19 +- 10 files changed, 1517 insertions(+), 17 deletions(-) create mode 100644 lib/wasmer-types/src/entity/boxed_slice.rs create mode 100644 lib/wasmer-types/src/entity/iter.rs create mode 100644 lib/wasmer-types/src/entity/keys.rs create mode 100644 lib/wasmer-types/src/entity/mod.rs create mode 100644 lib/wasmer-types/src/entity/packed_option.rs create mode 100644 lib/wasmer-types/src/entity/primary_map.rs create mode 100644 lib/wasmer-types/src/entity/secondary_map.rs diff --git a/Cargo.lock b/Cargo.lock index eb73620585a..8a9238eefe7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -426,9 +426,6 @@ name = "cranelift-entity" version = "0.70.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e55e9043403f0dec775f317280015150e78b2352fb947d2f37407fd4ce6311c7" -dependencies = [ - "serde", -] [[package]] name = "cranelift-frontend" @@ -2602,7 +2599,6 @@ dependencies = [ name = "wasmer-types" version = "1.0.2" dependencies = [ - "cranelift-entity", "serde", "thiserror", ] diff --git a/lib/wasmer-types/Cargo.toml b/lib/wasmer-types/Cargo.toml index 9f56e3361ff..892c13ad943 100644 --- a/lib/wasmer-types/Cargo.toml +++ b/lib/wasmer-types/Cargo.toml @@ -11,9 +11,6 @@ readme = "README.md" edition = "2018" [dependencies] -# We use `cranelift-entity` here because it's a lightweight dependency and it contains -# some useful data structures -cranelift-entity = "0.70" serde = { version = "1.0", features = ["derive"], optional = true, default-features = false } thiserror = "1.0" @@ -21,4 +18,4 @@ thiserror = "1.0" default = ["std", "enable-serde"] std = ["serde/std"] core = [] -enable-serde = ["serde", "cranelift-entity/enable-serde"] +enable-serde = ["serde"] diff --git a/lib/wasmer-types/src/entity/boxed_slice.rs b/lib/wasmer-types/src/entity/boxed_slice.rs new file mode 100644 index 00000000000..277d09a9d2d --- /dev/null +++ b/lib/wasmer-types/src/entity/boxed_slice.rs @@ -0,0 +1,316 @@ +//! Boxed slices for `PrimaryMap`. + +use crate::entity::iter::{Iter, IterMut}; +use crate::entity::keys::Keys; +use crate::entity::EntityRef; +use crate::lib::std::boxed::Box; +use crate::lib::std::marker::PhantomData; +use crate::lib::std::ops::{Index, IndexMut}; +use crate::lib::std::slice; + +/// A slice mapping `K -> V` allocating dense entity references. +/// +/// The `BoxedSlice` data structure uses the dense index space to implement a map with a boxed +/// slice. +#[derive(Debug, Clone)] +pub struct BoxedSlice +where + K: EntityRef, +{ + elems: Box<[V]>, + unused: PhantomData, +} + +impl BoxedSlice +where + K: EntityRef, +{ + /// Create a new slice from a raw pointer. A safer way to create slices is + /// to use `PrimaryMap::into_boxed_slice()`. + /// + /// # Safety + /// + /// This relies on `raw` pointing to a valid slice of `V`s. + pub unsafe fn from_raw(raw: *mut [V]) -> Self { + Self { + elems: Box::from_raw(raw), + unused: PhantomData, + } + } + + /// Check if `k` is a valid key in the map. + pub fn is_valid(&self, k: K) -> bool { + k.index() < self.elems.len() + } + + /// Get the element at `k` if it exists. + pub fn get(&self, k: K) -> Option<&V> { + self.elems.get(k.index()) + } + + /// Get the element at `k` if it exists, mutable version. + pub fn get_mut(&mut self, k: K) -> Option<&mut V> { + self.elems.get_mut(k.index()) + } + + /// Is this map completely empty? + pub fn is_empty(&self) -> bool { + self.elems.is_empty() + } + + /// Get the total number of entity references created. + pub fn len(&self) -> usize { + self.elems.len() + } + + /// Iterate over all the keys in this map. + pub fn keys(&self) -> Keys { + Keys::with_len(self.elems.len()) + } + + /// Iterate over all the values in this map. + pub fn values(&self) -> slice::Iter { + self.elems.iter() + } + + /// Iterate over all the values in this map, mutable edition. + pub fn values_mut(&mut self) -> slice::IterMut { + self.elems.iter_mut() + } + + /// Iterate over all the keys and values in this map. + pub fn iter(&self) -> Iter { + Iter::new(self.elems.iter()) + } + + /// Iterate over all the keys and values in this map, mutable edition. + pub fn iter_mut(&mut self) -> IterMut { + IterMut::new(self.elems.iter_mut()) + } + + /// Returns the last element that was inserted in the map. + pub fn last(&self) -> Option<&V> { + self.elems.last() + } +} + +/// Immutable indexing into a `BoxedSlice`. +/// The indexed value must be in the map. +impl Index for BoxedSlice +where + K: EntityRef, +{ + type Output = V; + + fn index(&self, k: K) -> &V { + &self.elems[k.index()] + } +} + +/// Mutable indexing into a `BoxedSlice`. +impl IndexMut for BoxedSlice +where + K: EntityRef, +{ + fn index_mut(&mut self, k: K) -> &mut V { + &mut self.elems[k.index()] + } +} + +impl<'a, K, V> IntoIterator for &'a BoxedSlice +where + K: EntityRef, +{ + type Item = (K, &'a V); + type IntoIter = Iter<'a, K, V>; + + fn into_iter(self) -> Self::IntoIter { + Iter::new(self.elems.iter()) + } +} + +impl<'a, K, V> IntoIterator for &'a mut BoxedSlice +where + K: EntityRef, +{ + type Item = (K, &'a mut V); + type IntoIter = IterMut<'a, K, V>; + + fn into_iter(self) -> Self::IntoIter { + IterMut::new(self.elems.iter_mut()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::lib::std::vec::Vec; + use crate::primary::PrimaryMap; + + // `EntityRef` impl for testing. + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + struct E(u32); + + impl EntityRef for E { + fn new(i: usize) -> Self { + E(i as u32) + } + fn index(self) -> usize { + self.0 as usize + } + } + + #[test] + fn basic() { + let r0 = E(0); + let r1 = E(1); + let p = PrimaryMap::::new(); + let m = p.into_boxed_slice(); + + let v: Vec = m.keys().collect(); + assert_eq!(v, []); + + assert!(!m.is_valid(r0)); + assert!(!m.is_valid(r1)); + } + + #[test] + fn iter() { + let mut p: PrimaryMap = PrimaryMap::new(); + p.push(12); + p.push(33); + let mut m = p.into_boxed_slice(); + + let mut i = 0; + for (key, value) in &m { + assert_eq!(key.index(), i); + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + i += 1; + } + i = 0; + for (key_mut, value_mut) in m.iter_mut() { + assert_eq!(key_mut.index(), i); + match i { + 0 => assert_eq!(*value_mut, 12), + 1 => assert_eq!(*value_mut, 33), + _ => panic!(), + } + i += 1; + } + } + + #[test] + fn iter_rev() { + let mut p: PrimaryMap = PrimaryMap::new(); + p.push(12); + p.push(33); + let mut m = p.into_boxed_slice(); + + let mut i = 2; + for (key, value) in m.iter().rev() { + i -= 1; + assert_eq!(key.index(), i); + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + } + + i = 2; + for (key, value) in m.iter_mut().rev() { + i -= 1; + assert_eq!(key.index(), i); + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + } + } + #[test] + fn keys() { + let mut p: PrimaryMap = PrimaryMap::new(); + p.push(12); + p.push(33); + let m = p.into_boxed_slice(); + + let mut i = 0; + for key in m.keys() { + assert_eq!(key.index(), i); + i += 1; + } + } + + #[test] + fn keys_rev() { + let mut p: PrimaryMap = PrimaryMap::new(); + p.push(12); + p.push(33); + let m = p.into_boxed_slice(); + + let mut i = 2; + for key in m.keys().rev() { + i -= 1; + assert_eq!(key.index(), i); + } + } + + #[test] + fn values() { + let mut p: PrimaryMap = PrimaryMap::new(); + p.push(12); + p.push(33); + let mut m = p.into_boxed_slice(); + + let mut i = 0; + for value in m.values() { + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + i += 1; + } + i = 0; + for value_mut in m.values_mut() { + match i { + 0 => assert_eq!(*value_mut, 12), + 1 => assert_eq!(*value_mut, 33), + _ => panic!(), + } + i += 1; + } + } + + #[test] + fn values_rev() { + let mut p: PrimaryMap = PrimaryMap::new(); + p.push(12); + p.push(33); + let mut m = p.into_boxed_slice(); + + let mut i = 2; + for value in m.values().rev() { + i -= 1; + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + } + i = 2; + for value_mut in m.values_mut().rev() { + i -= 1; + match i { + 0 => assert_eq!(*value_mut, 12), + 1 => assert_eq!(*value_mut, 33), + _ => panic!(), + } + } + } +} diff --git a/lib/wasmer-types/src/entity/iter.rs b/lib/wasmer-types/src/entity/iter.rs new file mode 100644 index 00000000000..26ee370f3f9 --- /dev/null +++ b/lib/wasmer-types/src/entity/iter.rs @@ -0,0 +1,124 @@ +//! A double-ended iterator over entity references and entities. + +use crate::entity::EntityRef; +use crate::lib::std::iter::Enumerate; +use crate::lib::std::marker::PhantomData; +use crate::lib::std::slice; +use crate::lib::std::vec; + +/// Iterate over all keys in order. +pub struct Iter<'a, K: EntityRef, V> +where + V: 'a, +{ + enumerate: Enumerate>, + unused: PhantomData, +} + +impl<'a, K: EntityRef, V> Iter<'a, K, V> { + /// Create an `Iter` iterator that visits the `PrimaryMap` keys and values + /// of `iter`. + pub fn new(iter: slice::Iter<'a, V>) -> Self { + Self { + enumerate: iter.enumerate(), + unused: PhantomData, + } + } +} + +impl<'a, K: EntityRef, V> Iterator for Iter<'a, K, V> { + type Item = (K, &'a V); + + fn next(&mut self) -> Option { + self.enumerate.next().map(|(i, v)| (K::new(i), v)) + } + + fn size_hint(&self) -> (usize, Option) { + self.enumerate.size_hint() + } +} + +impl<'a, K: EntityRef, V> DoubleEndedIterator for Iter<'a, K, V> { + fn next_back(&mut self) -> Option { + self.enumerate.next_back().map(|(i, v)| (K::new(i), v)) + } +} + +impl<'a, K: EntityRef, V> ExactSizeIterator for Iter<'a, K, V> {} + +/// Iterate over all keys in order. +pub struct IterMut<'a, K: EntityRef, V> +where + V: 'a, +{ + enumerate: Enumerate>, + unused: PhantomData, +} + +impl<'a, K: EntityRef, V> IterMut<'a, K, V> { + /// Create an `IterMut` iterator that visits the `PrimaryMap` keys and values + /// of `iter`. + pub fn new(iter: slice::IterMut<'a, V>) -> Self { + Self { + enumerate: iter.enumerate(), + unused: PhantomData, + } + } +} + +impl<'a, K: EntityRef, V> Iterator for IterMut<'a, K, V> { + type Item = (K, &'a mut V); + + fn next(&mut self) -> Option { + self.enumerate.next().map(|(i, v)| (K::new(i), v)) + } + + fn size_hint(&self) -> (usize, Option) { + self.enumerate.size_hint() + } +} + +impl<'a, K: EntityRef, V> DoubleEndedIterator for IterMut<'a, K, V> { + fn next_back(&mut self) -> Option { + self.enumerate.next_back().map(|(i, v)| (K::new(i), v)) + } +} + +impl<'a, K: EntityRef, V> ExactSizeIterator for IterMut<'a, K, V> {} + +/// Iterate over all keys in order. +pub struct IntoIter { + enumerate: Enumerate>, + unused: PhantomData, +} + +impl IntoIter { + /// Create an `IntoIter` iterator that visits the `PrimaryMap` keys and values + /// of `iter`. + pub fn new(iter: vec::IntoIter) -> Self { + Self { + enumerate: iter.enumerate(), + unused: PhantomData, + } + } +} + +impl Iterator for IntoIter { + type Item = (K, V); + + fn next(&mut self) -> Option { + self.enumerate.next().map(|(i, v)| (K::new(i), v)) + } + + fn size_hint(&self) -> (usize, Option) { + self.enumerate.size_hint() + } +} + +impl DoubleEndedIterator for IntoIter { + fn next_back(&mut self) -> Option { + self.enumerate.next_back().map(|(i, v)| (K::new(i), v)) + } +} + +impl ExactSizeIterator for IntoIter {} diff --git a/lib/wasmer-types/src/entity/keys.rs b/lib/wasmer-types/src/entity/keys.rs new file mode 100644 index 00000000000..b9892bf551f --- /dev/null +++ b/lib/wasmer-types/src/entity/keys.rs @@ -0,0 +1,58 @@ +//! A double-ended iterator over entity references. +//! +//! When `core::iter::Step` is stabilized, `Keys` could be implemented as a wrapper around +//! `core::ops::Range`, but for now, we implement it manually. + +use crate::entity::EntityRef; +use crate::lib::std::marker::PhantomData; + +/// Iterate over all keys in order. +pub struct Keys { + pos: usize, + rev_pos: usize, + unused: PhantomData, +} + +impl Keys { + /// Create a `Keys` iterator that visits `len` entities starting from 0. + pub fn with_len(len: usize) -> Self { + Self { + pos: 0, + rev_pos: len, + unused: PhantomData, + } + } +} + +impl Iterator for Keys { + type Item = K; + + fn next(&mut self) -> Option { + if self.pos < self.rev_pos { + let k = K::new(self.pos); + self.pos += 1; + Some(k) + } else { + None + } + } + + fn size_hint(&self) -> (usize, Option) { + let size = self.rev_pos - self.pos; + (size, Some(size)) + } +} + +impl DoubleEndedIterator for Keys { + fn next_back(&mut self) -> Option { + if self.rev_pos > self.pos { + let k = K::new(self.rev_pos - 1); + self.rev_pos -= 1; + Some(k) + } else { + None + } + } +} + +impl ExactSizeIterator for Keys {} diff --git a/lib/wasmer-types/src/entity/mod.rs b/lib/wasmer-types/src/entity/mod.rs new file mode 100644 index 00000000000..cc802ef85e5 --- /dev/null +++ b/lib/wasmer-types/src/entity/mod.rs @@ -0,0 +1,92 @@ +/// A type wrapping a small integer index should implement `EntityRef` so it can be used as the key +/// of an `SecondaryMap` or `SparseMap`. +pub trait EntityRef: Copy + Eq { + /// Create a new entity reference from a small integer. + /// This should crash if the requested index is not representable. + fn new(_: usize) -> Self; + + /// Get the index that was used to create this entity reference. + fn index(self) -> usize; +} + +/// Macro which provides the common implementation of a 32-bit entity reference. +#[macro_export] +macro_rules! entity_impl { + // Basic traits. + ($entity:ident) => { + impl $crate::entity::EntityRef for $entity { + fn new(index: usize) -> Self { + debug_assert!(index < ($crate::lib::std::u32::MAX as usize)); + $entity(index as u32) + } + + fn index(self) -> usize { + self.0 as usize + } + } + + impl $crate::entity::packed_option::ReservedValue for $entity { + fn reserved_value() -> $entity { + $entity($crate::lib::std::u32::MAX) + } + + fn is_reserved_value(&self) -> bool { + self.0 == $crate::lib::std::u32::MAX + } + } + + impl $entity { + /// Create a new instance from a `u32`. + #[allow(dead_code)] + pub fn from_u32(x: u32) -> Self { + debug_assert!(x < $crate::lib::std::u32::MAX); + $entity(x) + } + + /// Return the underlying index value as a `u32`. + #[allow(dead_code)] + pub fn as_u32(self) -> u32 { + self.0 + } + } + }; + + // Include basic `Display` impl using the given display prefix. + // Display a `Block` reference as "block12". + ($entity:ident, $display_prefix:expr) => { + entity_impl!($entity); + + impl $crate::lib::std::fmt::Display for $entity { + fn fmt( + &self, + f: &mut $crate::lib::std::fmt::Formatter, + ) -> $crate::lib::std::fmt::Result { + write!(f, concat!($display_prefix, "{}"), self.0) + } + } + + impl $crate::lib::std::fmt::Debug for $entity { + fn fmt( + &self, + f: &mut $crate::lib::std::fmt::Formatter, + ) -> $crate::lib::std::fmt::Result { + (self as &dyn $crate::lib::std::fmt::Display).fmt(f) + } + } + }; +} + +pub mod packed_option; + +mod boxed_slice; +mod iter; +mod keys; +mod primary_map; +mod secondary_map; + +pub use crate::entity_impl; +pub use boxed_slice::BoxedSlice; +pub use iter::{Iter, IterMut}; +pub use keys::Keys; +pub use primary_map::PrimaryMap; +pub use secondary_map::SecondaryMap; diff --git a/lib/wasmer-types/src/entity/packed_option.rs b/lib/wasmer-types/src/entity/packed_option.rs new file mode 100644 index 00000000000..6ba51cdf262 --- /dev/null +++ b/lib/wasmer-types/src/entity/packed_option.rs @@ -0,0 +1,171 @@ +//! Compact representation of `Option` for types with a reserved value. +//! +//! Small Cranelift types like the 32-bit entity references are often used in tables and linked +//! lists where an `Option` is needed. Unfortunately, that would double the size of the tables +//! because `Option` is twice as big as `T`. +//! +//! This module provides a `PackedOption` for types that have a reserved value that can be used +//! to represent `None`. + +use crate::lib::std::fmt; +use crate::lib::std::mem; + +#[cfg(feature = "enable-serde")] +use serde::{Deserialize, Serialize}; + +/// Types that have a reserved value which can't be created any other way. +pub trait ReservedValue { + /// Create an instance of the reserved value. + fn reserved_value() -> Self; + /// Checks whether value is the reserved one. + fn is_reserved_value(&self) -> bool; +} + +/// Packed representation of `Option`. +#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct PackedOption(T); + +impl PackedOption { + /// Returns `true` if the packed option is a `None` value. + pub fn is_none(&self) -> bool { + self.0.is_reserved_value() + } + + /// Returns `true` if the packed option is a `Some` value. + pub fn is_some(&self) -> bool { + !self.0.is_reserved_value() + } + + /// Expand the packed option into a normal `Option`. + pub fn expand(self) -> Option { + if self.is_none() { + None + } else { + Some(self.0) + } + } + + /// Maps a `PackedOption` to `Option` by applying a function to a contained value. + pub fn map(self, f: F) -> Option + where + F: FnOnce(T) -> U, + { + self.expand().map(f) + } + + /// Unwrap a packed `Some` value or panic. + pub fn unwrap(self) -> T { + self.expand().unwrap() + } + + /// Unwrap a packed `Some` value or panic. + pub fn expect(self, msg: &str) -> T { + self.expand().expect(msg) + } + + /// Takes the value out of the packed option, leaving a `None` in its place. + pub fn take(&mut self) -> Option { + mem::replace(self, None.into()).expand() + } +} + +impl Default for PackedOption { + /// Create a default packed option representing `None`. + fn default() -> Self { + Self(T::reserved_value()) + } +} + +impl From for PackedOption { + /// Convert `t` into a packed `Some(x)`. + fn from(t: T) -> Self { + debug_assert!( + !t.is_reserved_value(), + "Can't make a PackedOption from the reserved value." + ); + Self(t) + } +} + +impl From> for PackedOption { + /// Convert an option into its packed equivalent. + fn from(opt: Option) -> Self { + match opt { + None => Self::default(), + Some(t) => t.into(), + } + } +} + +impl Into> for PackedOption { + fn into(self) -> Option { + self.expand() + } +} + +impl fmt::Debug for PackedOption +where + T: ReservedValue + fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.is_none() { + write!(f, "None") + } else { + write!(f, "Some({:?})", self.0) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + // Dummy entity class, with no Copy or Clone. + #[derive(Debug, PartialEq, Eq)] + struct NoC(u32); + + impl ReservedValue for NoC { + fn reserved_value() -> Self { + NoC(13) + } + + fn is_reserved_value(&self) -> bool { + self.0 == 13 + } + } + + #[test] + fn moves() { + let x = NoC(3); + let somex: PackedOption = x.into(); + assert!(!somex.is_none()); + assert_eq!(somex.expand(), Some(NoC(3))); + + let none: PackedOption = None.into(); + assert!(none.is_none()); + assert_eq!(none.expand(), None); + } + + // Dummy entity class, with Copy. + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + struct Ent(u32); + + impl ReservedValue for Ent { + fn reserved_value() -> Self { + Ent(13) + } + + fn is_reserved_value(&self) -> bool { + self.0 == 13 + } + } + + #[test] + fn copies() { + let x = Ent(2); + let some: PackedOption = x.into(); + assert_eq!(some.expand(), x.into()); + assert_eq!(some, x.into()); + } +} diff --git a/lib/wasmer-types/src/entity/primary_map.rs b/lib/wasmer-types/src/entity/primary_map.rs new file mode 100644 index 00000000000..c709afef050 --- /dev/null +++ b/lib/wasmer-types/src/entity/primary_map.rs @@ -0,0 +1,425 @@ +//! Densely numbered entity references as mapping keys. +use crate::entity::boxed_slice::BoxedSlice; +use crate::entity::iter::{IntoIter, Iter, IterMut}; +use crate::entity::keys::Keys; +use crate::entity::EntityRef; +use crate::lib::std::boxed::Box; +use crate::lib::std::iter::FromIterator; +use crate::lib::std::marker::PhantomData; +use crate::lib::std::ops::{Index, IndexMut}; +use crate::lib::std::slice; +use crate::lib::std::vec::Vec; +#[cfg(feature = "enable-serde")] +use serde::{Deserialize, Serialize}; + +/// A primary mapping `K -> V` allocating dense entity references. +/// +/// The `PrimaryMap` data structure uses the dense index space to implement a map with a vector. +/// +/// A primary map contains the main definition of an entity, and it can be used to allocate new +/// entity references with the `push` method. +/// +/// There should only be a single `PrimaryMap` instance for a given `EntityRef` type, otherwise +/// conflicting references will be created. Using unknown keys for indexing will cause a panic. +/// +/// Note that `PrimaryMap` doesn't implement `Deref` or `DerefMut`, which would allow +/// `&PrimaryMap` to convert to `&[V]`. One of the main advantages of `PrimaryMap` is +/// that it only allows indexing with the distinct `EntityRef` key type, so converting to a +/// plain slice would make it easier to use incorrectly. To make a slice of a `PrimaryMap`, use +/// `into_boxed_slice`. +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct PrimaryMap +where + K: EntityRef, +{ + elems: Vec, + unused: PhantomData, +} + +impl PrimaryMap +where + K: EntityRef, +{ + /// Create a new empty map. + pub fn new() -> Self { + Self { + elems: Vec::new(), + unused: PhantomData, + } + } + + /// Create a new empty map with the given capacity. + pub fn with_capacity(capacity: usize) -> Self { + Self { + elems: Vec::with_capacity(capacity), + unused: PhantomData, + } + } + + /// Check if `k` is a valid key in the map. + pub fn is_valid(&self, k: K) -> bool { + k.index() < self.elems.len() + } + + /// Get the element at `k` if it exists. + pub fn get(&self, k: K) -> Option<&V> { + self.elems.get(k.index()) + } + + /// Get the element at `k` if it exists, mutable version. + pub fn get_mut(&mut self, k: K) -> Option<&mut V> { + self.elems.get_mut(k.index()) + } + + /// Is this map completely empty? + pub fn is_empty(&self) -> bool { + self.elems.is_empty() + } + + /// Get the total number of entity references created. + pub fn len(&self) -> usize { + self.elems.len() + } + + /// Iterate over all the keys in this map. + pub fn keys(&self) -> Keys { + Keys::with_len(self.elems.len()) + } + + /// Iterate over all the values in this map. + pub fn values(&self) -> slice::Iter { + self.elems.iter() + } + + /// Iterate over all the values in this map, mutable edition. + pub fn values_mut(&mut self) -> slice::IterMut { + self.elems.iter_mut() + } + + /// Iterate over all the keys and values in this map. + pub fn iter(&self) -> Iter { + Iter::new(self.elems.iter()) + } + + /// Iterate over all the keys and values in this map, mutable edition. + pub fn iter_mut(&mut self) -> IterMut { + IterMut::new(self.elems.iter_mut()) + } + + /// Remove all entries from this map. + pub fn clear(&mut self) { + self.elems.clear() + } + + /// Get the key that will be assigned to the next pushed value. + pub fn next_key(&self) -> K { + K::new(self.elems.len()) + } + + /// Append `v` to the mapping, assigning a new key which is returned. + pub fn push(&mut self, v: V) -> K { + let k = self.next_key(); + self.elems.push(v); + k + } + + /// Returns the last element that was inserted in the map. + pub fn last(&self) -> Option<&V> { + self.elems.last() + } + + /// Reserves capacity for at least `additional` more elements to be inserted. + pub fn reserve(&mut self, additional: usize) { + self.elems.reserve(additional) + } + + /// Reserves the minimum capacity for exactly `additional` more elements to be inserted. + pub fn reserve_exact(&mut self, additional: usize) { + self.elems.reserve_exact(additional) + } + + /// Shrinks the capacity of the `PrimaryMap` as much as possible. + pub fn shrink_to_fit(&mut self) { + self.elems.shrink_to_fit() + } + + /// Consumes this `PrimaryMap` and produces a `BoxedSlice`. + pub fn into_boxed_slice(self) -> BoxedSlice { + unsafe { BoxedSlice::::from_raw(Box::<[V]>::into_raw(self.elems.into_boxed_slice())) } + } +} + +impl Default for PrimaryMap +where + K: EntityRef, +{ + fn default() -> PrimaryMap { + PrimaryMap::new() + } +} + +/// Immutable indexing into an `PrimaryMap`. +/// The indexed value must be in the map. +impl Index for PrimaryMap +where + K: EntityRef, +{ + type Output = V; + + fn index(&self, k: K) -> &V { + &self.elems[k.index()] + } +} + +/// Mutable indexing into an `PrimaryMap`. +impl IndexMut for PrimaryMap +where + K: EntityRef, +{ + fn index_mut(&mut self, k: K) -> &mut V { + &mut self.elems[k.index()] + } +} + +impl IntoIterator for PrimaryMap +where + K: EntityRef, +{ + type Item = (K, V); + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + IntoIter::new(self.elems.into_iter()) + } +} + +impl<'a, K, V> IntoIterator for &'a PrimaryMap +where + K: EntityRef, +{ + type Item = (K, &'a V); + type IntoIter = Iter<'a, K, V>; + + fn into_iter(self) -> Self::IntoIter { + Iter::new(self.elems.iter()) + } +} + +impl<'a, K, V> IntoIterator for &'a mut PrimaryMap +where + K: EntityRef, +{ + type Item = (K, &'a mut V); + type IntoIter = IterMut<'a, K, V>; + + fn into_iter(self) -> Self::IntoIter { + IterMut::new(self.elems.iter_mut()) + } +} + +impl FromIterator for PrimaryMap +where + K: EntityRef, +{ + fn from_iter(iter: T) -> Self + where + T: IntoIterator, + { + Self { + elems: Vec::from_iter(iter), + unused: PhantomData, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + // `EntityRef` impl for testing. + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + struct E(u32); + + impl EntityRef for E { + fn new(i: usize) -> Self { + E(i as u32) + } + fn index(self) -> usize { + self.0 as usize + } + } + + #[test] + fn basic() { + let r0 = E(0); + let r1 = E(1); + let m = PrimaryMap::::new(); + + let v: Vec = m.keys().collect(); + assert_eq!(v, []); + + assert!(!m.is_valid(r0)); + assert!(!m.is_valid(r1)); + } + + #[test] + fn push() { + let mut m = PrimaryMap::new(); + let k0: E = m.push(12); + let k1 = m.push(33); + + assert_eq!(m[k0], 12); + assert_eq!(m[k1], 33); + + let v: Vec = m.keys().collect(); + assert_eq!(v, [k0, k1]); + } + + #[test] + fn iter() { + let mut m: PrimaryMap = PrimaryMap::new(); + m.push(12); + m.push(33); + + let mut i = 0; + for (key, value) in &m { + assert_eq!(key.index(), i); + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + i += 1; + } + i = 0; + for (key_mut, value_mut) in m.iter_mut() { + assert_eq!(key_mut.index(), i); + match i { + 0 => assert_eq!(*value_mut, 12), + 1 => assert_eq!(*value_mut, 33), + _ => panic!(), + } + i += 1; + } + } + + #[test] + fn iter_rev() { + let mut m: PrimaryMap = PrimaryMap::new(); + m.push(12); + m.push(33); + + let mut i = 2; + for (key, value) in m.iter().rev() { + i -= 1; + assert_eq!(key.index(), i); + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + } + + i = 2; + for (key, value) in m.iter_mut().rev() { + i -= 1; + assert_eq!(key.index(), i); + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + } + } + #[test] + fn keys() { + let mut m: PrimaryMap = PrimaryMap::new(); + m.push(12); + m.push(33); + + let mut i = 0; + for key in m.keys() { + assert_eq!(key.index(), i); + i += 1; + } + } + + #[test] + fn keys_rev() { + let mut m: PrimaryMap = PrimaryMap::new(); + m.push(12); + m.push(33); + + let mut i = 2; + for key in m.keys().rev() { + i -= 1; + assert_eq!(key.index(), i); + } + } + + #[test] + fn values() { + let mut m: PrimaryMap = PrimaryMap::new(); + m.push(12); + m.push(33); + + let mut i = 0; + for value in m.values() { + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + i += 1; + } + i = 0; + for value_mut in m.values_mut() { + match i { + 0 => assert_eq!(*value_mut, 12), + 1 => assert_eq!(*value_mut, 33), + _ => panic!(), + } + i += 1; + } + } + + #[test] + fn values_rev() { + let mut m: PrimaryMap = PrimaryMap::new(); + m.push(12); + m.push(33); + + let mut i = 2; + for value in m.values().rev() { + i -= 1; + match i { + 0 => assert_eq!(*value, 12), + 1 => assert_eq!(*value, 33), + _ => panic!(), + } + } + i = 2; + for value_mut in m.values_mut().rev() { + i -= 1; + match i { + 0 => assert_eq!(*value_mut, 12), + 1 => assert_eq!(*value_mut, 33), + _ => panic!(), + } + } + } + + #[test] + fn from_iter() { + let mut m: PrimaryMap = PrimaryMap::new(); + m.push(12); + m.push(33); + + let n = m.values().collect::>(); + assert!(m.len() == n.len()); + for (me, ne) in m.values().zip(n.values()) { + assert!(*me == **ne); + } + } +} diff --git a/lib/wasmer-types/src/entity/secondary_map.rs b/lib/wasmer-types/src/entity/secondary_map.rs new file mode 100644 index 00000000000..936caa24957 --- /dev/null +++ b/lib/wasmer-types/src/entity/secondary_map.rs @@ -0,0 +1,320 @@ +//! Densely numbered entity references as mapping keys. + +use crate::entity::iter::{Iter, IterMut}; +use crate::entity::keys::Keys; +use crate::entity::EntityRef; +use crate::lib::std::cmp::min; +use crate::lib::std::marker::PhantomData; +use crate::lib::std::ops::{Index, IndexMut}; +use crate::lib::std::slice; +use crate::lib::std::vec::Vec; +#[cfg(feature = "enable-serde")] +use serde::{ + de::{Deserializer, SeqAccess, Visitor}, + ser::{SerializeSeq, Serializer}, + Deserialize, Serialize, +}; + +/// A mapping `K -> V` for densely indexed entity references. +/// +/// The `SecondaryMap` data structure uses the dense index space to implement a map with a vector. +/// Unlike `PrimaryMap`, an `SecondaryMap` can't be used to allocate entity references. It is used +/// to associate secondary information with entities. +/// +/// The map does not track if an entry for a key has been inserted or not. Instead it behaves as if +/// all keys have a default entry from the beginning. +#[derive(Debug, Clone)] +pub struct SecondaryMap +where + K: EntityRef, + V: Clone, +{ + elems: Vec, + default: V, + unused: PhantomData, +} + +/// Shared `SecondaryMap` implementation for all value types. +impl SecondaryMap +where + K: EntityRef, + V: Clone, +{ + /// Create a new empty map. + pub fn new() -> Self + where + V: Default, + { + Self { + elems: Vec::new(), + default: Default::default(), + unused: PhantomData, + } + } + + /// Create a new, empty map with the specified capacity. + /// + /// The map will be able to hold exactly `capacity` elements without reallocating. + pub fn with_capacity(capacity: usize) -> Self + where + V: Default, + { + Self { + elems: Vec::with_capacity(capacity), + default: Default::default(), + unused: PhantomData, + } + } + + /// Create a new empty map with a specified default value. + /// + /// This constructor does not require V to implement Default. + pub fn with_default(default: V) -> Self { + Self { + elems: Vec::new(), + default, + unused: PhantomData, + } + } + + /// Returns the number of elements the map can hold without reallocating. + pub fn capacity(&self) -> usize { + self.elems.capacity() + } + + /// Get the element at `k` if it exists. + #[inline(always)] + pub fn get(&self, k: K) -> Option<&V> { + self.elems.get(k.index()) + } + + /// Is this map completely empty? + #[inline(always)] + pub fn is_empty(&self) -> bool { + self.elems.is_empty() + } + + /// Remove all entries from this map. + #[inline(always)] + pub fn clear(&mut self) { + self.elems.clear() + } + + /// Iterate over all the keys and values in this map. + pub fn iter(&self) -> Iter { + Iter::new(self.elems.iter()) + } + + /// Iterate over all the keys and values in this map, mutable edition. + pub fn iter_mut(&mut self) -> IterMut { + IterMut::new(self.elems.iter_mut()) + } + + /// Iterate over all the keys in this map. + pub fn keys(&self) -> Keys { + Keys::with_len(self.elems.len()) + } + + /// Iterate over all the values in this map. + pub fn values(&self) -> slice::Iter { + self.elems.iter() + } + + /// Iterate over all the values in this map, mutable edition. + pub fn values_mut(&mut self) -> slice::IterMut { + self.elems.iter_mut() + } + + /// Resize the map to have `n` entries by adding default entries as needed. + pub fn resize(&mut self, n: usize) { + self.elems.resize(n, self.default.clone()); + } +} + +impl Default for SecondaryMap +where + K: EntityRef, + V: Clone + Default, +{ + fn default() -> SecondaryMap { + SecondaryMap::new() + } +} + +/// Immutable indexing into an `SecondaryMap`. +/// +/// All keys are permitted. Untouched entries have the default value. +impl Index for SecondaryMap +where + K: EntityRef, + V: Clone, +{ + type Output = V; + + #[inline(always)] + fn index(&self, k: K) -> &V { + self.elems.get(k.index()).unwrap_or(&self.default) + } +} + +/// Mutable indexing into an `SecondaryMap`. +/// +/// The map grows as needed to accommodate new keys. +impl IndexMut for SecondaryMap +where + K: EntityRef, + V: Clone, +{ + #[inline(always)] + fn index_mut(&mut self, k: K) -> &mut V { + let i = k.index(); + if i >= self.elems.len() { + self.elems.resize(i + 1, self.default.clone()); + } + &mut self.elems[i] + } +} + +impl PartialEq for SecondaryMap +where + K: EntityRef, + V: Clone + PartialEq, +{ + fn eq(&self, other: &Self) -> bool { + let min_size = min(self.elems.len(), other.elems.len()); + self.default == other.default + && self.elems[..min_size] == other.elems[..min_size] + && self.elems[min_size..].iter().all(|e| *e == self.default) + && other.elems[min_size..].iter().all(|e| *e == other.default) + } +} + +impl Eq for SecondaryMap +where + K: EntityRef, + V: Clone + PartialEq + Eq, +{ +} + +#[cfg(feature = "enable-serde")] +impl Serialize for SecondaryMap +where + K: EntityRef, + V: Clone + PartialEq + Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + // TODO: bincode encodes option as "byte for Some/None" and then optionally the content + // TODO: we can actually optimize it by encoding manually bitmask, then elements + let mut elems_cnt = self.elems.len(); + while elems_cnt > 0 && self.elems[elems_cnt - 1] == self.default { + elems_cnt -= 1; + } + let mut seq = serializer.serialize_seq(Some(1 + elems_cnt))?; + seq.serialize_element(&Some(self.default.clone()))?; + for e in self.elems.iter().take(elems_cnt) { + let some_e = Some(e); + seq.serialize_element(if *e == self.default { &None } else { &some_e })?; + } + seq.end() + } +} + +#[cfg(feature = "enable-serde")] +impl<'de, K, V> Deserialize<'de> for SecondaryMap +where + K: EntityRef, + V: Clone + Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + use crate::lib::std::fmt; + + struct SecondaryMapVisitor { + unused: PhantomData V>, + } + + impl<'de, K, V> Visitor<'de> for SecondaryMapVisitor + where + K: EntityRef, + V: Clone + Deserialize<'de>, + { + type Value = SecondaryMap; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("struct SecondaryMap") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + match seq.next_element()? { + Some(Some(default_val)) => { + let default_val: V = default_val; // compiler can't infer the type + let mut m = SecondaryMap::with_default(default_val.clone()); + let mut idx = 0; + while let Some(val) = seq.next_element()? { + let val: Option<_> = val; // compiler can't infer the type + m[K::new(idx)] = val.unwrap_or_else(|| default_val.clone()); + idx += 1; + } + Ok(m) + } + _ => Err(serde::de::Error::custom("Default value required")), + } + } + } + + deserializer.deserialize_seq(SecondaryMapVisitor { + unused: PhantomData {}, + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + // `EntityRef` impl for testing. + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + struct E(u32); + + impl EntityRef for E { + fn new(i: usize) -> Self { + E(i as u32) + } + fn index(self) -> usize { + self.0 as usize + } + } + + #[test] + fn basic() { + let r0 = E(0); + let r1 = E(1); + let r2 = E(2); + let mut m = SecondaryMap::new(); + + let v: Vec = m.keys().collect(); + assert_eq!(v, []); + + m[r2] = 3; + m[r1] = 5; + + assert_eq!(m[r1], 5); + assert_eq!(m[r2], 3); + + let v: Vec = m.keys().collect(); + assert_eq!(v, [r0, r1, r2]); + + let shared = &m; + assert_eq!(shared[r0], 0); + assert_eq!(shared[r1], 5); + assert_eq!(shared[r2], 3); + } +} diff --git a/lib/wasmer-types/src/lib.rs b/lib/wasmer-types/src/lib.rs index c197486dc4c..d08c1a47e4e 100644 --- a/lib/wasmer-types/src/lib.rs +++ b/lib/wasmer-types/src/lib.rs @@ -34,18 +34,22 @@ compile_error!("Both the `std` and `core` features are disabled. Please enable o #[cfg(feature = "core")] extern crate alloc; -mod lib { +/// The `lib` module defines a `std` module that is identical whether +/// the `core` or the `std` feature is enabled. +pub mod lib { + /// Custom `std` module. #[cfg(feature = "core")] pub mod std { - pub use alloc::{borrow, boxed, format, rc, slice, string, vec}; - pub use core::{any, cell, convert, fmt, hash, marker, ops, ptr, sync}; + pub use alloc::{borrow, boxed, format, iter, rc, slice, string, vec}; + pub use core::{any, cell, cmp, convert, fmt, hash, marker, mem, ops, ptr, sync, u32}; } + /// Custom `std` module. #[cfg(feature = "std")] pub mod std { pub use std::{ - any, borrow, boxed, cell, convert, fmt, format, hash, marker, ops, ptr, rc, slice, - string, sync, vec, + any, borrow, boxed, cell, cmp, convert, fmt, format, hash, iter, marker, mem, ops, ptr, + rc, slice, string, sync, u32, vec, }; } } @@ -61,10 +65,7 @@ mod units; mod values; /// The entity module, with common helpers for Rust structures -pub mod entity { - pub use cranelift_entity::*; -} - +pub mod entity; pub use crate::features::Features; pub use crate::indexes::{ CustomSectionIndex, DataIndex, ElemIndex, ExportIndex, FunctionIndex, GlobalIndex, ImportIndex, From 9c1ec38a9aa540b73956450bd135f54f88978c0b Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 18 Mar 2021 14:41:37 +0100 Subject: [PATCH 2/5] feat(compiler-cranelift) Migrate to the recent changes in `wasmer-types`. --- lib/compiler-cranelift/Cargo.toml | 3 ++- lib/compiler-cranelift/src/sink.rs | 1 + lib/compiler-cranelift/src/translator/translation_utils.rs | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/compiler-cranelift/Cargo.toml b/lib/compiler-cranelift/Cargo.toml index 9a2c809f55c..017daca3731 100644 --- a/lib/compiler-cranelift/Cargo.toml +++ b/lib/compiler-cranelift/Cargo.toml @@ -15,6 +15,7 @@ edition = "2018" wasmer-compiler = { path = "../compiler", version = "1.0.2", features = ["translator"], default-features = false } wasmer-vm = { path = "../vm", version = "1.0.2" } wasmer-types = { path = "../wasmer-types", version = "1.0.2", default-features = false, features = ["std"] } +cranelift-entity = { version = "0.70", default-features = false } cranelift-codegen = { version = "0.70", default-features = false, features = ["x86", "arm64"] } cranelift-frontend = { version = "0.70", default-features = false } tracing = "0.1" @@ -36,7 +37,7 @@ maintenance = { status = "actively-developed" } [features] default = ["std", "enable-serde", "unwind"] unwind = ["cranelift-codegen/unwind", "gimli"] -enable-serde = ["wasmer-compiler/enable-serde", "wasmer-types/enable-serde"] +enable-serde = ["wasmer-compiler/enable-serde", "wasmer-types/enable-serde", "cranelift-entity/enable-serde"] std = ["cranelift-codegen/std", "cranelift-frontend/std", "wasmer-compiler/std", "wasmer-types/std"] core = ["hashbrown", "cranelift-codegen/core", "cranelift-frontend/core"] diff --git a/lib/compiler-cranelift/src/sink.rs b/lib/compiler-cranelift/src/sink.rs index 12f93adbce7..54f802912bc 100644 --- a/lib/compiler-cranelift/src/sink.rs +++ b/lib/compiler-cranelift/src/sink.rs @@ -3,6 +3,7 @@ use crate::translator::{irlibcall_to_libcall, irreloc_to_relocationkind}; use cranelift_codegen::binemit; use cranelift_codegen::ir::{self, ExternalName}; +use cranelift_entity::EntityRef as CraneliftEntityRef; use wasmer_compiler::{JumpTable, Relocation, RelocationTarget, TrapInformation}; use wasmer_types::entity::EntityRef; use wasmer_types::{FunctionIndex, LocalFunctionIndex}; diff --git a/lib/compiler-cranelift/src/translator/translation_utils.rs b/lib/compiler-cranelift/src/translator/translation_utils.rs index 4b4c77e2522..69d40937520 100644 --- a/lib/compiler-cranelift/src/translator/translation_utils.rs +++ b/lib/compiler-cranelift/src/translator/translation_utils.rs @@ -6,6 +6,7 @@ use core::u32; use cranelift_codegen::binemit::Reloc; use cranelift_codegen::ir::{self, AbiParam}; use cranelift_codegen::isa::TargetFrontendConfig; +use cranelift_entity::{EntityRef as CraneliftEntityRef, SecondaryMap as CraneliftSecondaryMap}; use cranelift_frontend::FunctionBuilder; use wasmer_compiler::wasm_unsupported; use wasmer_compiler::wasmparser; @@ -148,7 +149,7 @@ pub fn get_vmctx_value_label() -> ir::ValueLabel { /// Transforms Cranelift JumpTable's into runtime JumpTables pub fn transform_jump_table( - jt_offsets: SecondaryMap, + jt_offsets: CraneliftSecondaryMap, ) -> SecondaryMap { let mut func_jt_offsets = SecondaryMap::with_capacity(jt_offsets.capacity()); From ae4939c4cd75f222cdc349f3aeb74f97356c2248 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 18 Mar 2021 14:41:53 +0100 Subject: [PATCH 3/5] chore(cargo) Update `Cargo.lock`. --- Cargo.lock | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 8a9238eefe7..04786340550 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -426,6 +426,9 @@ name = "cranelift-entity" version = "0.70.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e55e9043403f0dec775f317280015150e78b2352fb947d2f37407fd4ce6311c7" +dependencies = [ + "serde", +] [[package]] name = "cranelift-frontend" @@ -2402,6 +2405,7 @@ name = "wasmer-compiler-cranelift" version = "1.0.2" dependencies = [ "cranelift-codegen", + "cranelift-entity", "cranelift-frontend", "gimli", "hashbrown", From 896f86540e7562b0b03f2fa62d7afe7d51d112fa Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 18 Mar 2021 15:00:24 +0100 Subject: [PATCH 4/5] test(types) Fix an import issue. --- lib/wasmer-types/src/entity/boxed_slice.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/wasmer-types/src/entity/boxed_slice.rs b/lib/wasmer-types/src/entity/boxed_slice.rs index 277d09a9d2d..6405126db2c 100644 --- a/lib/wasmer-types/src/entity/boxed_slice.rs +++ b/lib/wasmer-types/src/entity/boxed_slice.rs @@ -144,8 +144,8 @@ where #[cfg(test)] mod tests { use super::*; + use crate::entity::PrimaryMap; use crate::lib::std::vec::Vec; - use crate::primary::PrimaryMap; // `EntityRef` impl for testing. #[derive(Clone, Copy, Debug, PartialEq, Eq)] From 805a6370f943269038374cd90d8ef9d12beed18e Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 18 Mar 2021 17:15:15 +0100 Subject: [PATCH 5/5] chore(types) Add correct attributions. --- lib/wasmer-types/README.md | 7 +++++++ lib/wasmer-types/src/entity/boxed_slice.rs | 3 +++ lib/wasmer-types/src/entity/iter.rs | 3 +++ lib/wasmer-types/src/entity/keys.rs | 3 +++ lib/wasmer-types/src/entity/mod.rs | 3 +++ lib/wasmer-types/src/entity/packed_option.rs | 7 +++++-- lib/wasmer-types/src/entity/primary_map.rs | 3 +++ lib/wasmer-types/src/entity/secondary_map.rs | 3 +++ 8 files changed, 30 insertions(+), 2 deletions(-) diff --git a/lib/wasmer-types/README.md b/lib/wasmer-types/README.md index 26e66882008..3bcae53b9ce 100644 --- a/lib/wasmer-types/README.md +++ b/lib/wasmer-types/README.md @@ -1,3 +1,10 @@ # `wasmer-types` [![Build Status](https://github.com/wasmerio/wasmer/workflows/build/badge.svg?style=flat-square)](https://github.com/wasmerio/wasmer/actions?query=workflow%3Abuild) [![Join Wasmer Slack](https://img.shields.io/static/v1?label=Slack&message=join%20chat&color=brighgreen&style=flat-square)](https://slack.wasmer.io) [![MIT License](https://img.shields.io/github/license/wasmerio/wasmer.svg?style=flat-square)](https://github.com/wasmerio/wasmer/blob/master/LICENSE) This crate provides the basic structures to use WebAssembly easily anywhere. + +### Acknowledgments + +This project borrowed some of the code for the entity structure from [cranelift-entity](https://crates.io/crates/cranelift-entity). +We decided to move it here to help on serialization/deserialization and also to ease the integration with other tools like `loupe`. + +Please check [Wasmer ATTRIBUTIONS](https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md) to further see licenses and other attributions of the project. diff --git a/lib/wasmer-types/src/entity/boxed_slice.rs b/lib/wasmer-types/src/entity/boxed_slice.rs index 6405126db2c..4f9aa95eaf8 100644 --- a/lib/wasmer-types/src/entity/boxed_slice.rs +++ b/lib/wasmer-types/src/entity/boxed_slice.rs @@ -1,3 +1,6 @@ +// This file contains code from external sources. +// Attributions: https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md + //! Boxed slices for `PrimaryMap`. use crate::entity::iter::{Iter, IterMut}; diff --git a/lib/wasmer-types/src/entity/iter.rs b/lib/wasmer-types/src/entity/iter.rs index 26ee370f3f9..a157abef8f1 100644 --- a/lib/wasmer-types/src/entity/iter.rs +++ b/lib/wasmer-types/src/entity/iter.rs @@ -1,3 +1,6 @@ +// This file contains code from external sources. +// Attributions: https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md + //! A double-ended iterator over entity references and entities. use crate::entity::EntityRef; diff --git a/lib/wasmer-types/src/entity/keys.rs b/lib/wasmer-types/src/entity/keys.rs index b9892bf551f..08d5a225c18 100644 --- a/lib/wasmer-types/src/entity/keys.rs +++ b/lib/wasmer-types/src/entity/keys.rs @@ -1,3 +1,6 @@ +// This file contains code from external sources. +// Attributions: https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md + //! A double-ended iterator over entity references. //! //! When `core::iter::Step` is stabilized, `Keys` could be implemented as a wrapper around diff --git a/lib/wasmer-types/src/entity/mod.rs b/lib/wasmer-types/src/entity/mod.rs index cc802ef85e5..f654bdaff21 100644 --- a/lib/wasmer-types/src/entity/mod.rs +++ b/lib/wasmer-types/src/entity/mod.rs @@ -1,3 +1,6 @@ +// This file contains code from external sources. +// Attributions: https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md + /// A type wrapping a small integer index should implement `EntityRef` so it can be used as the key /// of an `SecondaryMap` or `SparseMap`. pub trait EntityRef: Copy + Eq { diff --git a/lib/wasmer-types/src/entity/packed_option.rs b/lib/wasmer-types/src/entity/packed_option.rs index 6ba51cdf262..ceadbf70008 100644 --- a/lib/wasmer-types/src/entity/packed_option.rs +++ b/lib/wasmer-types/src/entity/packed_option.rs @@ -1,7 +1,10 @@ +// This file contains code from external sources. +// Attributions: https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md + //! Compact representation of `Option` for types with a reserved value. //! -//! Small Cranelift types like the 32-bit entity references are often used in tables and linked -//! lists where an `Option` is needed. Unfortunately, that would double the size of the tables +//! Small types are often used in tables and linked lists where an +//! `Option` is needed. Unfortunately, that would double the size of the tables //! because `Option` is twice as big as `T`. //! //! This module provides a `PackedOption` for types that have a reserved value that can be used diff --git a/lib/wasmer-types/src/entity/primary_map.rs b/lib/wasmer-types/src/entity/primary_map.rs index c709afef050..c82bf4d5ad4 100644 --- a/lib/wasmer-types/src/entity/primary_map.rs +++ b/lib/wasmer-types/src/entity/primary_map.rs @@ -1,3 +1,6 @@ +// This file contains code from external sources. +// Attributions: https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md + //! Densely numbered entity references as mapping keys. use crate::entity::boxed_slice::BoxedSlice; use crate::entity::iter::{IntoIter, Iter, IterMut}; diff --git a/lib/wasmer-types/src/entity/secondary_map.rs b/lib/wasmer-types/src/entity/secondary_map.rs index 936caa24957..9fd474d4d1f 100644 --- a/lib/wasmer-types/src/entity/secondary_map.rs +++ b/lib/wasmer-types/src/entity/secondary_map.rs @@ -1,3 +1,6 @@ +// This file contains code from external sources. +// Attributions: https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md + //! Densely numbered entity references as mapping keys. use crate::entity::iter::{Iter, IterMut};