diff --git a/base/Cargo.toml b/base/Cargo.toml index b709ffa14d..387421a41a 100644 --- a/base/Cargo.toml +++ b/base/Cargo.toml @@ -13,3 +13,4 @@ documentation = "https://marwes.github.io/gluon/gluon/index.html" [dependencies] log = "0.3.6" quick-error = "1.0.0" +fnv = "1.0.3" diff --git a/base/src/fixed.rs b/base/src/fixed.rs index dd379c955f..b5a414edb0 100644 --- a/base/src/fixed.rs +++ b/base/src/fixed.rs @@ -2,12 +2,12 @@ //! are alive. This is done by storing each value in a stable memory location and preventing an //! earlier inserted value to be overwritten. use std::cell::{RefCell, Ref}; -use std::collections::HashMap; use std::fmt; use std::hash::Hash; use std::iter::{FromIterator, IntoIterator}; use std::ops::{Index, IndexMut}; +use fnv::FnvMap; // NOTE: transmute is used to circumvent the borrow checker in this module // This is safe since the containers hold boxed values meaning allocating larger // storage does not invalidate the references that are handed out and because values @@ -26,7 +26,7 @@ unsafe fn forget_lifetime_mut<'a, 'b, T: ?Sized>(x: &'a mut T) -> &'b mut T { // Through this and the fact the all values are stored as pointers it is possible to safely // insert new values without invalidating pointers retrieved from it pub struct FixedMap { - map: RefCell>>, + map: RefCell>>, } impl Default for FixedMap { @@ -43,7 +43,7 @@ impl fmt::Debug for FixedMap { impl FixedMap { pub fn new() -> FixedMap { - FixedMap { map: RefCell::new(HashMap::new()) } + FixedMap { map: RefCell::new(FnvMap::default()) } } pub fn clear(&mut self) { diff --git a/base/src/fnv.rs b/base/src/fnv.rs new file mode 100644 index 0000000000..06c99ec256 --- /dev/null +++ b/base/src/fnv.rs @@ -0,0 +1,13 @@ +extern crate fnv; + +use std::collections::HashMap; +use std::hash::BuildHasherDefault; + +pub use self::fnv::FnvHasher; + +/// Non-crypto HashMap using Fnv Hasher +/// +/// The default hashing implementation in std::collections uses `SipHasher` +/// since gluon doesn't need the cryptographic quarantee provided by SipHasher, +/// we've opted for the faster fnv hash. +pub type FnvMap = HashMap>; diff --git a/base/src/instantiate.rs b/base/src/instantiate.rs index 3dae2eef0b..981b7e8f49 100644 --- a/base/src/instantiate.rs +++ b/base/src/instantiate.rs @@ -1,12 +1,12 @@ use std::borrow::Cow; use std::cell::RefCell; -use std::collections::HashMap; use std::collections::hash_map::Entry; use std::ops::Deref; use types; use types::{AliasData, Type, Generic, TcType, TypeEnv, merge}; use symbol::Symbol; +use fnv::FnvMap; quick_error! { #[derive(Debug)] @@ -166,12 +166,12 @@ pub fn type_of_alias(alias: &AliasData, arguments: &[TcType]) -> #[derive(Debug, Default)] pub struct Instantiator { - pub named_variables: RefCell>, + pub named_variables: RefCell>, } impl Instantiator { pub fn new() -> Instantiator { - Instantiator { named_variables: RefCell::new(HashMap::new()) } + Instantiator { named_variables: RefCell::new(FnvMap::default()) } } fn variable_for(&self, diff --git a/base/src/lib.rs b/base/src/lib.rs index 3cac08b247..978a001b2e 100644 --- a/base/src/lib.rs +++ b/base/src/lib.rs @@ -14,3 +14,4 @@ pub mod types; pub mod scoped_map; pub mod metadata; pub mod instantiate; +pub mod fnv; diff --git a/base/src/scoped_map.rs b/base/src/scoped_map.rs index e43f89dcd0..db175cc559 100644 --- a/base/src/scoped_map.rs +++ b/base/src/scoped_map.rs @@ -1,10 +1,11 @@ //! A map data type which allows the same key to exist at multiple scope levels use std::borrow::Borrow; -use std::collections::HashMap; use std::collections::hash_map; use std::collections::hash_map::{Entry, IterMut}; use std::hash::Hash; +use fnv::FnvMap; + /// A map struct which allows for the introduction of different scopes /// Introducing a new scope will make it possible to introduce additional /// variables with names already defined, shadowing the old name @@ -13,7 +14,7 @@ use std::hash::Hash; pub struct ScopedMap { /// A hashmap storing a key -> value mapping /// Stores a vector of values in which the value at the top is value returned from 'get' - map: HashMap>, + map: FnvMap>, /// A vector of scopes, when entering a scope, None is added as a marker /// when later exiting a scope, values are removed from the map until the marker is found scopes: Vec>, @@ -23,7 +24,7 @@ pub struct ScopedMap { impl ScopedMap { pub fn new() -> ScopedMap { ScopedMap { - map: HashMap::new(), + map: FnvMap::default(), scopes: Vec::new(), } } diff --git a/base/src/symbol.rs b/base/src/symbol.rs index 1227f4f30c..27f2d84cac 100644 --- a/base/src/symbol.rs +++ b/base/src/symbol.rs @@ -1,6 +1,5 @@ //! Module which contains types working with symbols use std::cmp::Ordering; -use std::collections::HashMap; use std::hash::{Hash, Hasher}; use std::fmt; use std::sync::Arc; @@ -8,6 +7,7 @@ use std::borrow::Borrow; use std::ops::Deref; use ast::{AstId, DisplayEnv, IdentEnv, AstType}; +use fnv::FnvMap; // FIXME Don't have a double indirection (Arc + String) #[derive(Clone, Eq)] @@ -262,15 +262,15 @@ impl<'a> From<&'a Name> for NameBuf { #[derive(Debug, Default)] pub struct Symbols { - strings: HashMap, - indexes: HashMap, + strings: FnvMap, + indexes: FnvMap, } impl Symbols { pub fn new() -> Symbols { Symbols { - strings: HashMap::new(), - indexes: HashMap::new(), + strings: FnvMap::default(), + indexes: FnvMap::default(), } } diff --git a/check/src/rename.rs b/check/src/rename.rs index a2e020aebe..18348c4841 100644 --- a/check/src/rename.rs +++ b/check/src/rename.rs @@ -320,16 +320,17 @@ pub fn rename(symbols: &mut SymbolModule, } -use std::collections::HashMap; use base::instantiate; use unify_type::{TypeError, State}; use unify::{Error as UnifyError, Unifier, Unifiable, UnifierState}; +use base::fnv::FnvMap; + pub fn equivalent(env: &TypeEnv, actual: &TcType, inferred: &TcType) -> bool { let mut unifier = UnifierState { state: State::new(env), unifier: Equivalent { - map: HashMap::new(), + map: FnvMap::default(), equiv: true, }, }; @@ -338,7 +339,7 @@ pub fn equivalent(env: &TypeEnv, actual: &TcType, inferred: &TcType) -> bool { } struct Equivalent { - map: HashMap, + map: FnvMap, equiv: bool, } diff --git a/check/src/unify.rs b/check/src/unify.rs index 59b14fac80..4014f4ef02 100644 --- a/check/src/unify.rs +++ b/check/src/unify.rs @@ -1,9 +1,8 @@ -use std::collections::HashMap; use std::fmt; use std::hash::Hash; use base::error::Errors; - +use base::fnv::FnvMap; use substitution::{Substitution, Substitutable, Variable}; #[derive(Debug, PartialEq)] @@ -174,7 +173,7 @@ pub fn intersection(subs: &Substitution, state: S, l: &T, r: &T) -> T let mut unifier = UnifierState { state: state, unifier: Intersect { - mismatch_map: HashMap::new(), + mismatch_map: FnvMap::default(), subs: subs, }, }; @@ -182,7 +181,7 @@ pub fn intersection(subs: &Substitution, state: S, l: &T, r: &T) -> T } struct Intersect<'m, T: 'm> { - mismatch_map: HashMap<(T, T), T>, + mismatch_map: FnvMap<(T, T), T>, subs: &'m Substitution, } diff --git a/src/import.rs b/src/import.rs index 20a5098371..6d52076b52 100644 --- a/src/import.rs +++ b/src/import.rs @@ -1,6 +1,5 @@ //! Implementation of the `import` macro. use std::any::Any; -use std::collections::HashMap; use std::sync::{Arc, RwLock, Mutex}; use std::fs::File; use std::io; @@ -15,7 +14,7 @@ use vm::thread::{Thread, ThreadInternal}; use vm::internal::Value; use super::{filename_to_module, Compiler}; use base::types::TcIdent; - +use base::fnv::FnvMap; quick_error! { /// Error type for the import macro @@ -70,10 +69,10 @@ impl Importer for DefaultImporter { } #[derive(Clone)] -pub struct CheckImporter(pub Arc>>>>); +pub struct CheckImporter(pub Arc>>>>); impl CheckImporter { pub fn new() -> CheckImporter { - CheckImporter(Arc::new(Mutex::new(HashMap::new()))) + CheckImporter(Arc::new(Mutex::new(FnvMap::default()))) } } impl Importer for CheckImporter { diff --git a/vm/src/gc.rs b/vm/src/gc.rs index f58dc4e6cc..85d1588196 100644 --- a/vm/src/gc.rs +++ b/vm/src/gc.rs @@ -2,7 +2,7 @@ use std::fmt; use std::mem; use std::ptr; use std::collections::hash_map::Entry; -use std::collections::{HashMap, VecDeque}; +use std::collections::VecDeque; use std::cmp::Ordering; use std::hash::{Hash, Hasher}; use std::ops::{Deref, DerefMut}; @@ -10,6 +10,8 @@ use std::cell::Cell; use std::any::{Any, TypeId}; use std::marker::PhantomData; +use base::fnv::FnvMap; + #[inline] unsafe fn allocate(size: usize) -> *mut u8 { // Allocate an extra element if it does not fit exactly @@ -99,7 +101,7 @@ pub struct Gc { values: Option, allocated_memory: usize, collect_limit: usize, - type_infos: HashMap>, + type_infos: FnvMap>, /// The generation of a gc determines what values it needs to copy and what values it can /// share. A gc can share values generated by itself (the same generation) and those in an /// earlier (lower) generation. It is important to note that two garbage collectors can have @@ -512,7 +514,7 @@ impl Gc { values: None, allocated_memory: 0, collect_limit: 100, - type_infos: HashMap::new(), + type_infos: FnvMap::default(), generation: generation, } } diff --git a/vm/src/interner.rs b/vm/src/interner.rs index 7779c93a80..981451823c 100644 --- a/vm/src/interner.rs +++ b/vm/src/interner.rs @@ -1,8 +1,8 @@ -use std::collections::HashMap; use std::fmt; use std::hash::{Hash, Hasher}; use std::ops::Deref; use base::ast::{AstId, DisplayEnv, IdentEnv, AstType}; +use base::fnv::FnvMap; use gc::{GcPtr, Gc, Traverseable}; use array::Str; @@ -56,7 +56,7 @@ pub struct Interner { // not be expected to be the same as ordinary strings, we use a transmute to &'static str to // have the keys as strings without any unsafety as the keys do not escape the interner and they // live as long as their values - indexes: HashMap<&'static str, InternedStr>, + indexes: FnvMap<&'static str, InternedStr>, } impl Traverseable for Interner { @@ -69,7 +69,7 @@ impl Traverseable for Interner { impl Interner { pub fn new() -> Interner { - Interner { indexes: HashMap::new() } + Interner { indexes: FnvMap::default() } } pub fn intern(&mut self, gc: &mut Gc, s: &str) -> InternedStr { diff --git a/vm/src/macros.rs b/vm/src/macros.rs index b363dd8030..77855fc97c 100644 --- a/vm/src/macros.rs +++ b/vm/src/macros.rs @@ -1,12 +1,12 @@ //! Module providing the building blocks to create macros and expand them. use std::sync::RwLock; -use std::collections::HashMap; use std::error::Error as StdError; use base::ast; use base::ast::MutVisitor; use base::types::TcIdent; use base::error::Errors; +use base::fnv::FnvMap; use thread::Thread; @@ -41,13 +41,13 @@ impl Macro for F /// Type containing macros bound to symbols which can be applied on an AST expression to transform /// it. pub struct MacroEnv { - macros: RwLock>>, + macros: RwLock>>, } impl MacroEnv { /// Creates a new `MacroEnv` pub fn new() -> MacroEnv { - MacroEnv { macros: RwLock::new(HashMap::new()) } + MacroEnv { macros: RwLock::new(FnvMap::default()) } } /// Inserts a `Macro` which acts on any occurance of `symbol` when applied to an expression. diff --git a/vm/src/thread.rs b/vm/src/thread.rs index d57218fb84..30b288ea9d 100644 --- a/vm/src/thread.rs +++ b/vm/src/thread.rs @@ -1,6 +1,5 @@ //! The thread/vm type use std::any::Any; -use std::collections::HashMap; use std::sync::{Mutex, RwLock, RwLockWriteGuard, RwLockReadGuard, MutexGuard}; use std::cmp::Ordering; use std::fmt; @@ -12,6 +11,7 @@ use base::metadata::Metadata; use base::symbol::Symbol; use base::types::TcType; use base::types; +use base::fnv::FnvMap; use {Variants, Error, Result}; use macros::MacroEnv; @@ -676,7 +676,7 @@ impl ThreadInternal for Thread { } fn deep_clone(&self, value: Value) -> Result { - let mut visited = HashMap::new(); + let mut visited = FnvMap::default(); ::value::deep_clone(value, &mut visited, &mut self.local_gc.lock().unwrap()) } } diff --git a/vm/src/types.rs b/vm/src/types.rs index 8dfe9ecbfc..0bc3ac0ac2 100644 --- a/vm/src/types.rs +++ b/vm/src/types.rs @@ -1,7 +1,7 @@ -use std::collections::HashMap; use base::symbol::{Symbol, SymbolRef}; use base::types; use base::types::{Alias, KindEnv, TypeEnv, TcType, Type}; +use base::fnv::FnvMap; pub use self::Instruction::*; @@ -139,8 +139,8 @@ impl Instruction { #[derive(Debug)] pub struct TypeInfos { - pub id_to_type: HashMap>, - pub type_to_id: HashMap, + pub id_to_type: FnvMap>, + pub type_to_id: FnvMap, } impl KindEnv for TypeInfos { @@ -209,8 +209,8 @@ impl TypeEnv for TypeInfos { impl TypeInfos { pub fn new() -> TypeInfos { TypeInfos { - id_to_type: HashMap::new(), - type_to_id: HashMap::new(), + id_to_type: FnvMap::default(), + type_to_id: FnvMap::default(), } } diff --git a/vm/src/value.rs b/vm/src/value.rs index 9820bf9e7c..b5712a7817 100644 --- a/vm/src/value.rs +++ b/vm/src/value.rs @@ -1,10 +1,12 @@ use std::fmt; -use std::collections::HashMap; +use std::any::Any; use std::collections::hash_map::Entry; use std::result::Result as StdResult; use base::symbol::Symbol; use types::*; +use base::fnv::FnvMap; + use interner::InternedStr; use gc::{Gc, GcPtr, Traverseable, DataDef, WriteOnly}; use array::{Array, Str}; @@ -702,7 +704,7 @@ unsafe impl<'b> DataDef for ArrayDef<'b> { } fn deep_clone_ptr(value: GcPtr, - visited: &mut HashMap<*const (), Value>, + visited: &mut FnvMap<*const (), Value>, alloc: A) -> StdResult> where A: FnOnce(&T) -> (Value, GcPtr) @@ -721,7 +723,7 @@ fn deep_clone_ptr(value: GcPtr, } fn deep_clone_str(data: GcPtr, - visited: &mut HashMap<*const (), Value>, + visited: &mut FnvMap<*const (), Value>, gc: &mut Gc) -> Result { Ok(deep_clone_ptr(data, visited, |data| { @@ -731,7 +733,7 @@ fn deep_clone_str(data: GcPtr, .unwrap_or_else(String)) } fn deep_clone_data(data: GcPtr, - visited: &mut HashMap<*const (), Value>, + visited: &mut FnvMap<*const (), Value>, gc: &mut Gc) -> Result> { let result = deep_clone_ptr(data, visited, |data| { @@ -757,13 +759,13 @@ fn deep_clone_data(data: GcPtr, } fn deep_clone_array(array: GcPtr, - visited: &mut HashMap<*const (), Value>, + visited: &mut FnvMap<*const (), Value>, gc: &mut Gc) -> Result> { - type CloneFn = fn(T, &mut HashMap<*const (), Value>, &mut Gc) -> Result; + type CloneFn = fn(T, &mut FnvMap<*const (), Value>, &mut Gc) -> Result; unsafe fn deep_clone_elems(deep_clone: CloneFn, mut new_array: GcPtr, - visited: &mut HashMap<*const (), Value>, + visited: &mut FnvMap<*const (), Value>, gc: &mut Gc) -> Result<()> { let new_array = new_array.as_mut().unsafe_array_mut::(); @@ -799,7 +801,7 @@ fn deep_clone_array(array: GcPtr, } fn deep_clone_closure(data: GcPtr, - visited: &mut HashMap<*const (), Value>, + visited: &mut FnvMap<*const (), Value>, gc: &mut Gc) -> Result> { let result = deep_clone_ptr(data, visited, |data| { @@ -821,7 +823,7 @@ fn deep_clone_closure(data: GcPtr, } } fn deep_clone_app(data: GcPtr, - visited: &mut HashMap<*const (), Value>, + visited: &mut FnvMap<*const (), Value>, gc: &mut Gc) -> Result> { let result = deep_clone_ptr(data, visited, |data| { @@ -844,7 +846,7 @@ fn deep_clone_app(data: GcPtr, } } pub fn deep_clone(value: Value, - visited: &mut HashMap<*const (), Value>, + visited: &mut FnvMap<*const (), Value>, gc: &mut Gc) -> Result { // Only need to clone values which belong to a younger generation than the gc that the new diff --git a/vm/src/vm.rs b/vm/src/vm.rs index d80a09cc12..04b3171cde 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -1,7 +1,6 @@ use std::borrow::Cow; use std::sync::{Mutex, RwLock, RwLockReadGuard}; use std::any::{Any, TypeId}; -use std::collections::HashMap; use std::result::Result as StdResult; use std::string::String as StdString; @@ -10,6 +9,7 @@ use base::metadata::{Metadata, MetadataEnv}; use base::symbol::{Name, Symbol, SymbolRef}; use base::types::{Alias, AliasData, Generic, Type, Kind, KindEnv, TypeEnv, PrimitiveEnv, TcType, RcKind}; +use base::fnv::FnvMap; use macros::MacroEnv; use {Error, Result}; @@ -74,8 +74,8 @@ impl Typed for Global { pub struct GlobalVmState { env: RwLock, - generics: RwLock>, - typeids: RwLock>, + generics: RwLock>, + typeids: RwLock>, interner: RwLock, macros: MacroEnv, // FIXME These fields should not be public @@ -102,7 +102,7 @@ impl Traverseable for GlobalVmState { #[derive(Debug)] pub struct VmEnv { pub type_infos: TypeInfos, - pub globals: HashMap, + pub globals: FnvMap, } impl CompilerEnv for VmEnv { @@ -315,11 +315,11 @@ impl GlobalVmState { pub fn new() -> GlobalVmState { let mut vm = GlobalVmState { env: RwLock::new(VmEnv { - globals: HashMap::new(), + globals: FnvMap::default(), type_infos: TypeInfos::new(), }), - generics: RwLock::new(HashMap::new()), - typeids: RwLock::new(HashMap::new()), + generics: RwLock::new(FnvMap::default()), + typeids: RwLock::new(FnvMap::default()), interner: RwLock::new(Interner::new()), gc: Mutex::new(Gc::new(0)), macros: MacroEnv::new(), @@ -333,7 +333,7 @@ impl GlobalVmState { fn add_types(&mut self) -> StdResult<(), (TypeId, TcType)> { use api::generic::A; use api::Generic; - fn add_type(ids: &mut HashMap, + fn add_type(ids: &mut FnvMap, env: &mut VmEnv, name: &str, typ: TcType) {