Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move HashMap to liballoc #51846

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,14 @@ use self::Entry::*;
use self::VacantEntryState::*;

use collections::CollectionAllocErr;
use cell::Cell;
use borrow::Borrow;
use cmp::max;
use fmt::{self, Debug};
use core::borrow::Borrow;
use core::cmp::max;
use core::fmt::{self, Debug};
#[allow(deprecated)]
use hash::{Hash, Hasher, BuildHasher, SipHasher13};
use iter::{FromIterator, FusedIterator};
use mem::{self, replace};
use ops::{Deref, Index};
use sys;
use core::hash::{Hash, Hasher, BuildHasher, SipHasher13};
use core::iter::{FromIterator, FusedIterator};
use core::mem::{self, replace};
use core::ops::{Deref, Index};

use super::table::{self, Bucket, EmptyBucket, Fallibility, FullBucket, FullBucketMut, RawTable,
SafeHash};
Expand Down Expand Up @@ -2561,7 +2559,7 @@ impl<'a, K, V, S> Extend<(&'a K, &'a V)> for HashMap<K, V, S>
/// instances are unlikely to produce the same result for the same values.
///
/// [`HashMap`]: struct.HashMap.html
/// [`Hasher`]: ../../hash/trait.Hasher.html
/// [`Hasher`]: ../../../std/hash/trait.Hasher.html
///
/// # Examples
///
Expand Down Expand Up @@ -2592,29 +2590,22 @@ impl RandomState {
/// ```
#[inline]
#[allow(deprecated)]
// rand
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
pub fn new() -> RandomState {
// Historically this function did not cache keys from the OS and instead
// simply always called `rand::thread_rng().gen()` twice. In #31356 it
// was discovered, however, that because we re-seed the thread-local RNG
// from the OS periodically that this can cause excessive slowdown when
// many hash maps are created on a thread. To solve this performance
// trap we cache the first set of randomly generated keys per-thread.
//
// Later in #36481 it was discovered that exposing a deterministic
// iteration order allows a form of DOS attack. To counter that we
// increment one of the seeds on every RandomState creation, giving
// every corresponding HashMap a different iteration order.
thread_local!(static KEYS: Cell<(u64, u64)> = {
Cell::new(sys::hashmap_random_keys())
});
// Use a weak lang item to get random keys without a hard dependency
// on libstd.
#[cfg(not(stage0))]
#[allow(improper_ctypes)]
extern {
#[lang = "hashmap_random_keys"]
#[unwind(allowed)]
fn hashmap_random_keys() -> (u64, u64);
}
#[cfg(stage0)]
unsafe fn hashmap_random_keys() -> (u64, u64) { (0, 0) }

KEYS.with(|keys| {
let (k0, k1) = keys.get();
keys.set((k0.wrapping_add(1), k1));
RandomState { k0: k0, k1: k1 }
})
let (k0, k1) = unsafe { hashmap_random_keys() };
RandomState { k0: k0, k1: k1 }
}
}

Expand All @@ -2634,7 +2625,7 @@ impl BuildHasher for RandomState {
/// not be relied upon over releases.
///
/// [`RandomState`]: struct.RandomState.html
/// [`Hasher`]: ../../hash/trait.Hasher.html
/// [`Hasher`]: ../../../std/hash/trait.Hasher.html
#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
#[allow(deprecated)]
#[derive(Clone, Debug)]
Expand Down Expand Up @@ -2768,11 +2759,12 @@ mod test_map {
use super::HashMap;
use super::Entry::{Occupied, Vacant};
use super::RandomState;
use cell::RefCell;
use core::cell::RefCell;
use rand::{thread_rng, Rng};
use realstd::collections::CollectionAllocErr::*;
use realstd::mem::size_of;
use realstd::usize;
use collections::CollectionAllocErr::*;
use std::mem::size_of;
use std::usize;
use vec::Vec;

#[test]
fn test_zero_capacities() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use borrow::Borrow;
use fmt;
use hash::{Hash, BuildHasher};
use iter::{Chain, FromIterator, FusedIterator};
use ops::{BitOr, BitAnd, BitXor, Sub};
use core::borrow::Borrow;
use core::fmt;
use core::hash::{Hash, BuildHasher};
use core::iter::{Chain, FromIterator, FusedIterator};
use core::ops::{BitOr, BitAnd, BitXor, Sub};

use super::Recover;
use super::map::{self, HashMap, Keys, RandomState};
Expand Down Expand Up @@ -1403,6 +1403,7 @@ fn assert_covariance() {
mod test_set {
use super::HashSet;
use super::super::map::RandomState;
use vec::Vec;

#[test]
fn test_zero_capacities() {
Expand Down Expand Up @@ -1712,7 +1713,7 @@ mod test_set {

#[test]
fn test_replace() {
use hash;
use core::hash;

#[derive(Debug)]
struct Foo(&'static str, i32);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@

use alloc::{Global, Alloc, Layout, LayoutErr, handle_alloc_error};
use collections::CollectionAllocErr;
use hash::{BuildHasher, Hash, Hasher};
use marker;
use mem::{size_of, needs_drop};
use mem;
use ops::{Deref, DerefMut};
use ptr::{self, Unique, NonNull};
use hint;
use core::hash::{BuildHasher, Hash, Hasher};
use core::marker;
use core::mem::{size_of, needs_drop};
use core::mem;
use core::ops::{Deref, DerefMut};
use core::ptr::{self, Unique, NonNull};
use core::hint;

use self::BucketState::*;

Expand Down
23 changes: 23 additions & 0 deletions src/liballoc/collections/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

pub mod binary_heap;
mod btree;
mod hash;
pub mod linked_list;
pub mod vec_deque;

Expand All @@ -31,6 +32,20 @@ pub mod btree_set {
pub use super::btree::set::*;
}

#[unstable(feature = "alloc_hashmap", reason = "HashMap in liballoc is unstable", issue="0")]
pub mod hash_map {
//! A hash map implemented with linear probing and Robin Hood bucket stealing.
#[stable(feature = "rust1", since = "1.0.0")]
pub use super::hash::map::*;
}

#[unstable(feature = "alloc_hashmap", reason = "HashMap in liballoc is unstable", issue="0")]
pub mod hash_set {
//! A hash set implemented as a `HashMap` where the value is `()`.
#[stable(feature = "rust1", since = "1.0.0")]
pub use super::hash::set::*;
}

#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
pub use self::binary_heap::BinaryHeap;
Expand All @@ -43,6 +58,14 @@ pub use self::btree_map::BTreeMap;
#[doc(no_inline)]
pub use self::btree_set::BTreeSet;

#[unstable(feature = "alloc_hashmap", reason = "HashMap in liballoc is unstable", issue="0")]
#[doc(no_inline)]
pub use self::hash_map::HashMap;

#[unstable(feature = "alloc_hashmap", reason = "HashMap in liballoc is unstable", issue="0")]
#[doc(no_inline)]
pub use self::hash_set::HashSet;

#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
pub use self::linked_list::LinkedList;
Expand Down
4 changes: 3 additions & 1 deletion src/liballoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/",
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))]
test(no_crate_inject, attr(allow(unused_variables, unused_mut), deny(warnings))))]
#![no_std]
#![needs_allocator]
#![deny(missing_debug_implementations)]
Expand Down Expand Up @@ -122,6 +122,8 @@
#![feature(inclusive_range_methods)]
#![feature(rustc_const_unstable)]
#![feature(const_vec_new)]
#![feature(unwind_attributes)]
#![feature(hashmap_internals)]

#![cfg_attr(not(test), feature(fn_traits, i128))]
#![cfg_attr(test, feature(test))]
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/middle/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,8 @@ language_item_table! {
AlignOffsetLangItem, "align_offset", align_offset_fn;

TerminationTraitLangItem, "termination", termination;

HashMapRandomKeysLangItem, "hashmap_random_keys", hashmap_random_keys;
}

impl<'a, 'tcx, 'gcx> TyCtxt<'a, 'tcx, 'gcx> {
Expand Down
1 change: 1 addition & 0 deletions src/librustc/middle/weak_lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,4 +166,5 @@ weak_lang_items! {
eh_personality, EhPersonalityLangItem, rust_eh_personality;
eh_unwind_resume, EhUnwindResumeLangItem, rust_eh_unwind_resume;
oom, OomLangItem, rust_oom;
hashmap_random_keys,HashMapRandomKeysLangItem, rust_hashmap_random_keys;
}
48 changes: 36 additions & 12 deletions src/libstd/collections/mod.rs → src/libstd/collections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,27 +431,51 @@ pub use alloc_crate::collections::{LinkedList, VecDeque};
pub use alloc_crate::collections::{binary_heap, btree_map, btree_set};
#[stable(feature = "rust1", since = "1.0.0")]
pub use alloc_crate::collections::{linked_list, vec_deque};

#[stable(feature = "rust1", since = "1.0.0")]
pub use self::hash_map::HashMap;
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::hash_set::HashSet;

#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
pub use alloc_crate::collections::CollectionAllocErr;

mod hash;
pub use alloc_crate::collections::{HashMap, HashSet};

// We can't just re-export the modules directly since they are unstable in liballoc
#[stable(feature = "rust1", since = "1.0.0")]
pub mod hash_map {
//! A hash map implemented with linear probing and Robin Hood bucket stealing.
#[stable(feature = "rust1", since = "1.0.0")]
pub use super::hash::map::*;
pub use alloc_crate::collections::hash_map::*;
}

#[stable(feature = "rust1", since = "1.0.0")]
pub mod hash_set {
//! A hash set implemented as a `HashMap` where the value is `()`.
#[stable(feature = "rust1", since = "1.0.0")]
pub use super::hash::set::*;
pub use alloc_crate::collections::hash_set::*;
}

#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
pub use alloc_crate::collections::CollectionAllocErr;

#[cfg(not(stage0))]
#[cfg_attr(not(test), lang = "hashmap_random_keys")]
#[cfg_attr(test, allow(dead_code))]
fn hashmap_random_keys() -> (u64, u64) {
use sys;
use cell::Cell;

// Historically this function did not cache keys from the OS and instead
// simply always called `rand::thread_rng().gen()` twice. In #31356 it
// was discovered, however, that because we re-seed the thread-local RNG
// from the OS periodically that this can cause excessive slowdown when
// many hash maps are created on a thread. To solve this performance
// trap we cache the first set of randomly generated keys per-thread.
//
// Later in #36481 it was discovered that exposing a deterministic
// iteration order allows a form of DOS attack. To counter that we
// increment one of the seeds on every RandomState creation, giving
// every corresponding HashMap a different iteration order.
thread_local!(static KEYS: Cell<(u64, u64)> = {
Cell::new(sys::hashmap_random_keys())
});

KEYS.with(|keys| {
let (k0, k1) = keys.get();
keys.set((k0.wrapping_add(1), k1));
(k0, k1)
})
}
2 changes: 1 addition & 1 deletion src/libstd/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,6 @@
#![feature(fnbox)]
#![feature(futures_api)]
#![feature(generator_trait)]
#![feature(hashmap_internals)]
#![feature(int_error_internals)]
#![feature(integer_atomics)]
#![feature(into_cow)]
Expand Down Expand Up @@ -323,6 +322,7 @@
#![feature(float_internals)]
#![feature(panic_info_message)]
#![feature(panic_implementation)]
#![feature(alloc_hashmap)]

#![default_lib_allocator]

Expand Down
3 changes: 3 additions & 0 deletions src/test/ui/missing-allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,7 @@ fn panic(_: &core::panic::PanicInfo) -> ! {
#[lang = "oom"]
fn oom() {}

#[lang = "hashmap_random_keys"]
fn hashmap_random_keys() {}

extern crate alloc;