about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-03-06 18:16:39 -0800
committerbors <bors@rust-lang.org>2014-03-06 18:16:39 -0800
commit5862c0c28b7d25f1a1f8fd9165eff1f6f3d191d8 (patch)
tree6c4877cab523a54019eb8e15820c8531913139cc
parent0e95b086db515386faf41549b490515a540165b1 (diff)
parent0a8413292845f527b8cf6bb2d02c9923f782ff37 (diff)
downloadrust-5862c0c28b7d25f1a1f8fd9165eff1f6f3d191d8.tar.gz
rust-5862c0c28b7d25f1a1f8fd9165eff1f6f3d191d8.zip
auto merge of #12635 : alexcrichton/rust/speedy-hash, r=brson
This leverages the new hashing framework and hashmap implementation to provide a
much speedier hashing algorithm for node ids and def ids. The hash algorithm
used is currentl FNV hashing, but it's quite easy to swap out.

I originally implemented hashing as the identity function, but this actually
ended up in slowing down rustc compiling libstd from 8s to 13s. I would suspect
that this is a result of a large number of collisions.

With FNV hashing, we get these timings (compiling with --no-trans, in seconds):

|           |  before  |  after  |
|-----------|---------:|--------:|
| libstd    |   8.324  |  6.703  |
| stdtest   |  47.674  | 46.857  |
| libsyntax |   9.918  |  8.400  |
-rw-r--r--src/librustc/driver/driver.rs11
-rw-r--r--src/librustc/front/test.rs7
-rw-r--r--src/librustc/lib.rs3
-rw-r--r--src/librustc/metadata/encoder.rs11
-rw-r--r--src/librustc/middle/cfg/construct.rs6
-rw-r--r--src/librustc/middle/cfg/mod.rs4
-rw-r--r--src/librustc/middle/const_eval.rs17
-rw-r--r--src/librustc/middle/dataflow.rs6
-rw-r--r--src/librustc/middle/dead.rs7
-rw-r--r--src/librustc/middle/freevars.rs14
-rw-r--r--src/librustc/middle/liveness.rs20
-rw-r--r--src/librustc/middle/moves.rs14
-rw-r--r--src/librustc/middle/privacy.rs20
-rw-r--r--src/librustc/middle/reachable.rs9
-rw-r--r--src/librustc/middle/region.rs13
-rw-r--r--src/librustc/middle/resolve.rs25
-rw-r--r--src/librustc/middle/resolve_lifetime.rs6
-rw-r--r--src/librustc/middle/trans/base.rs7
-rw-r--r--src/librustc/middle/trans/common.rs7
-rw-r--r--src/librustc/middle/trans/context.rs37
-rw-r--r--src/librustc/middle/trans/expr.rs5
-rw-r--r--src/librustc/middle/ty.rs140
-rw-r--r--src/librustc/middle/typeck/check/mod.rs21
-rw-r--r--src/librustc/middle/typeck/mod.rs12
-rw-r--r--src/librustc/util/nodemap.rs127
-rw-r--r--src/librustdoc/html/render.rs5
-rw-r--r--src/librustdoc/passes.rs3
-rw-r--r--src/libsyntax/ext/base.rs6
-rw-r--r--src/libsyntax/ext/deriving/hash.rs20
-rw-r--r--src/libsyntax/ext/expand.rs39
-rw-r--r--src/libsyntax/lib.rs2
31 files changed, 412 insertions, 212 deletions
diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs
index c4f3bb21059..5b335d163d8 100644
--- a/src/librustc/driver/driver.rs
+++ b/src/librustc/driver/driver.rs
@@ -27,6 +27,7 @@ use middle::{trans, freevars, kind, ty, typeck, lint, astencode, reachable};
 use middle;
 use util::common::time;
 use util::ppaux;
+use util::nodemap::NodeSet;
 
 use serialize::{json, Encodable};
 
@@ -38,7 +39,7 @@ use std::os;
 use std::vec;
 use std::vec_ng::Vec;
 use std::vec_ng;
-use collections::{HashMap, HashSet};
+use collections::HashMap;
 use getopts::{optopt, optmulti, optflag, optflagopt, opt};
 use MaybeHasArg = getopts::Maybe;
 use OccurOptional = getopts::Optional;
@@ -223,8 +224,12 @@ pub fn phase_2_configure_and_expand(sess: Session,
                  front::config::strip_unconfigured_items(krate));
 
     krate = time(time_passes, "expansion", krate, |krate| {
+        let cfg = syntax::ext::expand::ExpansionConfig {
+            loader: loader,
+            deriving_hash_type_parameter: sess.features.default_type_params.get()
+        };
         syntax::ext::expand::expand_crate(sess.parse_sess,
-                                          loader,
+                                          cfg,
                                           krate)
     });
     // dump the syntax-time crates
@@ -258,7 +263,7 @@ pub struct CrateAnalysis {
     public_items: middle::privacy::PublicItems,
     ty_cx: ty::ctxt,
     maps: astencode::Maps,
-    reachable: @RefCell<HashSet<ast::NodeId>>
+    reachable: @RefCell<NodeSet>,
 }
 
 /// Run the resolution, typechecking, region checking and other
diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs
index 493fd3522d5..ecbb704684b 100644
--- a/src/librustc/front/test.rs
+++ b/src/librustc/front/test.rs
@@ -28,6 +28,7 @@ use syntax::attr;
 use syntax::codemap::{DUMMY_SP, Span, ExpnInfo, NameAndSpan, MacroAttribute};
 use syntax::codemap;
 use syntax::ext::base::ExtCtxt;
+use syntax::ext::expand::ExpansionConfig;
 use syntax::fold::Folder;
 use syntax::fold;
 use syntax::opt_vec;
@@ -165,7 +166,11 @@ fn generate_test_harness(sess: session::Session, krate: ast::Crate)
     let loader = &mut Loader::new(sess);
     let mut cx: TestCtxt = TestCtxt {
         sess: sess,
-        ext_cx: ExtCtxt::new(sess.parse_sess, sess.opts.cfg.clone(), loader),
+        ext_cx: ExtCtxt::new(sess.parse_sess, sess.opts.cfg.clone(),
+                             ExpansionConfig {
+                                 loader: loader,
+                                 deriving_hash_type_parameter: false,
+                             }),
         path: RefCell::new(~[]),
         testfns: RefCell::new(~[]),
         is_test_crate: is_test_crate(&krate),
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 2e68fdd1423..d1560abf773 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -29,7 +29,7 @@ This API is completely unstable and subject to change.
 
 #[allow(deprecated)];
 #[feature(macro_rules, globs, struct_variant, managed_boxes)];
-#[feature(quote)];
+#[feature(quote, default_type_params)];
 
 extern crate extra;
 extern crate flate;
@@ -125,6 +125,7 @@ pub mod util {
     pub mod common;
     pub mod ppaux;
     pub mod sha2;
+    pub mod nodemap;
 }
 
 pub mod lib {
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index 80bb5d23aa4..7d5688ba19b 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -23,6 +23,7 @@ use middle::astencode;
 use middle::ty;
 use middle::typeck;
 use middle;
+use util::nodemap::{NodeMap, NodeSet};
 
 use serialize::Encodable;
 use std::cast;
@@ -31,7 +32,7 @@ use std::hash;
 use std::hash::Hash;
 use std::io::MemWriter;
 use std::str;
-use collections::{HashMap, HashSet};
+use collections::HashMap;
 use syntax::abi::AbiSet;
 use syntax::ast::*;
 use syntax::ast;
@@ -69,8 +70,8 @@ pub struct EncodeParams<'a> {
     diag: @SpanHandler,
     tcx: ty::ctxt,
     reexports2: middle::resolve::ExportMap2,
-    item_symbols: &'a RefCell<HashMap<ast::NodeId, ~str>>,
-    non_inlineable_statics: &'a RefCell<HashSet<ast::NodeId>>,
+    item_symbols: &'a RefCell<NodeMap<~str>>,
+    non_inlineable_statics: &'a RefCell<NodeSet>,
     link_meta: &'a LinkMeta,
     cstore: @cstore::CStore,
     encode_inlined_item: EncodeInlinedItem<'a>,
@@ -97,8 +98,8 @@ pub struct EncodeContext<'a> {
     tcx: ty::ctxt,
     stats: @Stats,
     reexports2: middle::resolve::ExportMap2,
-    item_symbols: &'a RefCell<HashMap<ast::NodeId, ~str>>,
-    non_inlineable_statics: &'a RefCell<HashSet<ast::NodeId>>,
+    item_symbols: &'a RefCell<NodeMap<~str>>,
+    non_inlineable_statics: &'a RefCell<NodeSet>,
     link_meta: &'a LinkMeta,
     cstore: &'a cstore::CStore,
     encode_inlined_item: EncodeInlinedItem<'a>,
diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs
index 8a83147face..099ef284d95 100644
--- a/src/librustc/middle/cfg/construct.rs
+++ b/src/librustc/middle/cfg/construct.rs
@@ -12,15 +12,15 @@ use middle::cfg::*;
 use middle::graph;
 use middle::typeck;
 use middle::ty;
-use collections::HashMap;
 use syntax::ast;
 use syntax::ast_util;
 use syntax::opt_vec;
+use util::nodemap::NodeMap;
 
 struct CFGBuilder {
     tcx: ty::ctxt,
     method_map: typeck::MethodMap,
-    exit_map: HashMap<ast::NodeId, CFGIndex>,
+    exit_map: NodeMap<CFGIndex>,
     graph: CFGGraph,
     loop_scopes: ~[LoopScope],
 }
@@ -35,7 +35,7 @@ pub fn construct(tcx: ty::ctxt,
                  method_map: typeck::MethodMap,
                  blk: &ast::Block) -> CFG {
     let mut cfg_builder = CFGBuilder {
-        exit_map: HashMap::new(),
+        exit_map: NodeMap::new(),
         graph: graph::Graph::new(),
         tcx: tcx,
         method_map: method_map,
diff --git a/src/librustc/middle/cfg/mod.rs b/src/librustc/middle/cfg/mod.rs
index d6d54b604c8..bdf39e3e8ec 100644
--- a/src/librustc/middle/cfg/mod.rs
+++ b/src/librustc/middle/cfg/mod.rs
@@ -18,14 +18,14 @@ Uses `Graph` as the underlying representation.
 use middle::graph;
 use middle::ty;
 use middle::typeck;
-use collections::HashMap;
 use syntax::ast;
 use syntax::opt_vec::OptVec;
+use util::nodemap::NodeMap;
 
 mod construct;
 
 pub struct CFG {
-    exit_map: HashMap<ast::NodeId, CFGIndex>,
+    exit_map: NodeMap<CFGIndex>,
     graph: CFGGraph,
     entry: CFGIndex,
     exit: CFGIndex,
diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs
index cd52f24b8ea..effdbd8e451 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -16,6 +16,7 @@ use middle::astencode;
 use middle::ty;
 use middle::typeck::astconv;
 use middle;
+use util::nodemap::{DefIdMap, NodeMap};
 
 use syntax::ast::*;
 use syntax::parse::token::InternedString;
@@ -66,7 +67,7 @@ pub enum constness {
     non_const
 }
 
-type constness_cache = HashMap<ast::DefId, constness>;
+type constness_cache = DefIdMap<constness>;
 
 pub fn join(a: constness, b: constness) -> constness {
     match (a, b) {
@@ -134,9 +135,9 @@ pub fn lookup_variant_by_id(tcx: ty::ctxt,
         }
         let maps = astencode::Maps {
             root_map: @RefCell::new(HashMap::new()),
-            method_map: @RefCell::new(HashMap::new()),
-            vtable_map: @RefCell::new(HashMap::new()),
-            capture_map: @RefCell::new(HashMap::new())
+            method_map: @RefCell::new(NodeMap::new()),
+            vtable_map: @RefCell::new(NodeMap::new()),
+            capture_map: @RefCell::new(NodeMap::new())
         };
         let e = match csearch::maybe_get_item_ast(tcx, enum_def,
             |a, b, c, d| astencode::decode_inlined_item(a, b,
@@ -184,9 +185,9 @@ pub fn lookup_const_by_id(tcx: ty::ctxt, def_id: ast::DefId)
         }
         let maps = astencode::Maps {
             root_map: @RefCell::new(HashMap::new()),
-            method_map: @RefCell::new(HashMap::new()),
-            vtable_map: @RefCell::new(HashMap::new()),
-            capture_map: @RefCell::new(HashMap::new())
+            method_map: @RefCell::new(NodeMap::new()),
+            vtable_map: @RefCell::new(NodeMap::new()),
+            capture_map: @RefCell::new(NodeMap::new())
         };
         let e = match csearch::maybe_get_item_ast(tcx, def_id,
             |a, b, c, d| astencode::decode_inlined_item(a, b, maps, c, d)) {
@@ -305,7 +306,7 @@ pub fn process_crate(krate: &ast::Crate,
                      tcx: ty::ctxt) {
     let mut v = ConstEvalVisitor {
         tcx: tcx,
-        ccache: HashMap::new(),
+        ccache: DefIdMap::new(),
     };
     visit::walk_crate(&mut v, krate, ());
     tcx.sess.abort_if_errors();
diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs
index 74acc10abc0..700a3d5a4a4 100644
--- a/src/librustc/middle/dataflow.rs
+++ b/src/librustc/middle/dataflow.rs
@@ -20,7 +20,6 @@
 use std::io;
 use std::uint;
 use std::vec;
-use collections::HashMap;
 use syntax::ast;
 use syntax::ast_util;
 use syntax::ast_util::IdRange;
@@ -28,6 +27,7 @@ use syntax::print::{pp, pprust};
 use middle::ty;
 use middle::typeck;
 use util::ppaux::Repr;
+use util::nodemap::NodeMap;
 
 #[deriving(Clone)]
 pub struct DataFlowContext<O> {
@@ -45,7 +45,7 @@ pub struct DataFlowContext<O> {
     priv words_per_id: uint,
 
     // mapping from node to bitset index.
-    priv nodeid_to_bitset: HashMap<ast::NodeId,uint>,
+    priv nodeid_to_bitset: NodeMap<uint>,
 
     // Bit sets per id.  The following three fields (`gens`, `kills`,
     // and `on_entry`) all have the same structure. For each id in
@@ -139,7 +139,7 @@ impl<O:DataFlowOperator> DataFlowContext<O> {
             tcx: tcx,
             method_map: method_map,
             words_per_id: words_per_id,
-            nodeid_to_bitset: HashMap::new(),
+            nodeid_to_bitset: NodeMap::new(),
             bits_per_id: bits_per_id,
             oper: oper,
             gens: gens,
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index a0a34ff4f32..eaf665119d3 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -16,6 +16,7 @@ use middle::lint::{allow, contains_lint, DeadCode};
 use middle::privacy;
 use middle::ty;
 use middle::typeck;
+use util::nodemap::NodeSet;
 
 use collections::HashSet;
 use syntax::ast;
@@ -252,7 +253,7 @@ impl Visitor<()> for LifeSeeder {
 
 fn create_and_seed_worklist(tcx: ty::ctxt,
                             exported_items: &privacy::ExportedItems,
-                            reachable_symbols: &HashSet<ast::NodeId>,
+                            reachable_symbols: &NodeSet,
                             krate: &ast::Crate) -> ~[ast::NodeId] {
     let mut worklist = ~[];
 
@@ -286,7 +287,7 @@ fn create_and_seed_worklist(tcx: ty::ctxt,
 fn find_live(tcx: ty::ctxt,
              method_map: typeck::MethodMap,
              exported_items: &privacy::ExportedItems,
-             reachable_symbols: &HashSet<ast::NodeId>,
+             reachable_symbols: &NodeSet,
              krate: &ast::Crate)
              -> ~HashSet<ast::NodeId> {
     let worklist = create_and_seed_worklist(tcx, exported_items,
@@ -409,7 +410,7 @@ impl Visitor<()> for DeadVisitor {
 pub fn check_crate(tcx: ty::ctxt,
                    method_map: typeck::MethodMap,
                    exported_items: &privacy::ExportedItems,
-                   reachable_symbols: &HashSet<ast::NodeId>,
+                   reachable_symbols: &NodeSet,
                    krate: &ast::Crate) {
     let live_symbols = find_live(tcx, method_map, exported_items,
                                  reachable_symbols, krate);
diff --git a/src/librustc/middle/freevars.rs b/src/librustc/middle/freevars.rs
index 9ff67377c59..b41398b4401 100644
--- a/src/librustc/middle/freevars.rs
+++ b/src/librustc/middle/freevars.rs
@@ -15,8 +15,8 @@
 
 use middle::resolve;
 use middle::ty;
+use util::nodemap::{NodeMap, NodeSet};
 
-use collections::HashMap;
 use syntax::codemap::Span;
 use syntax::{ast, ast_util};
 use syntax::visit;
@@ -30,10 +30,10 @@ pub struct freevar_entry {
     span: Span     //< First span where it is accessed (there can be multiple)
 }
 pub type freevar_info = @~[@freevar_entry];
-pub type freevar_map = HashMap<ast::NodeId, freevar_info>;
+pub type freevar_map = NodeMap<freevar_info>;
 
 struct CollectFreevarsVisitor {
-    seen: HashMap<ast::NodeId, ()>,
+    seen: NodeSet,
     refs: ~[@freevar_entry],
     def_map: resolve::DefMap,
 }
@@ -65,12 +65,12 @@ impl Visitor<int> for CollectFreevarsVisitor {
                         }
                         if i == depth { // Made it to end of loop
                             let dnum = ast_util::def_id_of_def(def).node;
-                            if !self.seen.contains_key(&dnum) {
+                            if !self.seen.contains(&dnum) {
                                 self.refs.push(@freevar_entry {
                                     def: def,
                                     span: expr.span,
                                 });
-                                self.seen.insert(dnum, ());
+                                self.seen.insert(dnum);
                             }
                         }
                     }
@@ -89,7 +89,7 @@ impl Visitor<int> for CollectFreevarsVisitor {
 // of the AST, we take a walker function that we invoke with a visitor
 // in order to start the search.
 fn collect_freevars(def_map: resolve::DefMap, blk: &ast::Block) -> freevar_info {
-    let seen = HashMap::new();
+    let seen = NodeSet::new();
     let refs = ~[];
 
     let mut v = CollectFreevarsVisitor {
@@ -129,7 +129,7 @@ pub fn annotate_freevars(def_map: resolve::DefMap, krate: &ast::Crate) ->
    freevar_map {
     let mut visitor = AnnotateFreevarsVisitor {
         def_map: def_map,
-        freevars: HashMap::new(),
+        freevars: NodeMap::new(),
     };
     visit::walk_crate(&mut visitor, krate, ());
 
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index f12c8ad0c82..3ae85bbd6c7 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -108,6 +108,7 @@ use middle::pat_util;
 use middle::ty;
 use middle::typeck;
 use middle::moves;
+use util::nodemap::NodeMap;
 
 use std::cast::transmute;
 use std::cell::{Cell, RefCell};
@@ -116,7 +117,6 @@ use std::io;
 use std::str;
 use std::uint;
 use std::vec;
-use collections::HashMap;
 use syntax::ast::*;
 use syntax::codemap::Span;
 use syntax::parse::token::special_idents;
@@ -258,9 +258,9 @@ pub struct IrMaps {
 
     num_live_nodes: Cell<uint>,
     num_vars: Cell<uint>,
-    live_node_map: RefCell<HashMap<NodeId, LiveNode>>,
-    variable_map: RefCell<HashMap<NodeId, Variable>>,
-    capture_info_map: RefCell<HashMap<NodeId, @~[CaptureInfo]>>,
+    live_node_map: RefCell<NodeMap<LiveNode>>,
+    variable_map: RefCell<NodeMap<Variable>>,
+    capture_info_map: RefCell<NodeMap<@~[CaptureInfo]>>,
     var_kinds: RefCell<~[VarKind]>,
     lnks: RefCell<~[LiveNodeKind]>,
 }
@@ -275,9 +275,9 @@ fn IrMaps(tcx: ty::ctxt,
         capture_map: capture_map,
         num_live_nodes: Cell::new(0),
         num_vars: Cell::new(0),
-        live_node_map: RefCell::new(HashMap::new()),
-        variable_map: RefCell::new(HashMap::new()),
-        capture_info_map: RefCell::new(HashMap::new()),
+        live_node_map: RefCell::new(NodeMap::new()),
+        variable_map: RefCell::new(NodeMap::new()),
+        capture_info_map: RefCell::new(NodeMap::new()),
         var_kinds: RefCell::new(~[]),
         lnks: RefCell::new(~[]),
     }
@@ -584,7 +584,7 @@ static ACC_READ: uint = 1u;
 static ACC_WRITE: uint = 2u;
 static ACC_USE: uint = 4u;
 
-pub type LiveNodeMap = @RefCell<HashMap<NodeId, LiveNode>>;
+pub type LiveNodeMap = @RefCell<NodeMap<LiveNode>>;
 
 pub struct Liveness {
     tcx: ty::ctxt,
@@ -613,8 +613,8 @@ fn Liveness(ir: @IrMaps, specials: Specials) -> Liveness {
                                             ir.num_vars.get(),
                                             invalid_users())),
         loop_scope: @RefCell::new(~[]),
-        break_ln: @RefCell::new(HashMap::new()),
-        cont_ln: @RefCell::new(HashMap::new()),
+        break_ln: @RefCell::new(NodeMap::new()),
+        cont_ln: @RefCell::new(NodeMap::new()),
     }
 }
 
diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs
index dc4325fdd72..41ea80cff28 100644
--- a/src/librustc/middle/moves.rs
+++ b/src/librustc/middle/moves.rs
@@ -135,10 +135,10 @@ use util::ppaux;
 use util::ppaux::Repr;
 use util::common::indenter;
 use util::ppaux::UserString;
+use util::nodemap::{NodeMap, NodeSet};
 
 use std::cell::RefCell;
 use std::rc::Rc;
-use collections::{HashSet, HashMap};
 use syntax::ast::*;
 use syntax::ast_util;
 use syntax::visit;
@@ -159,9 +159,9 @@ pub struct CaptureVar {
     mode: CaptureMode // How variable is being accessed
 }
 
-pub type CaptureMap = @RefCell<HashMap<NodeId, Rc<~[CaptureVar]>>>;
+pub type CaptureMap = @RefCell<NodeMap<Rc<~[CaptureVar]>>>;
 
-pub type MovesMap = @RefCell<HashSet<NodeId>>;
+pub type MovesMap = @RefCell<NodeSet>;
 
 /**
  * Set of variable node-ids that are moved.
@@ -169,7 +169,7 @@ pub type MovesMap = @RefCell<HashSet<NodeId>>;
  * Note: The `VariableMovesMap` stores expression ids that
  * are moves, whereas this set stores the ids of the variables
  * that are moved at some point */
-pub type MovedVariablesSet = @RefCell<HashSet<NodeId>>;
+pub type MovedVariablesSet = @RefCell<NodeSet>;
 
 /** See the section Output on the module comment for explanation. */
 #[deriving(Clone)]
@@ -215,9 +215,9 @@ pub fn compute_moves(tcx: ty::ctxt,
         tcx: tcx,
         method_map: method_map,
         move_maps: MoveMaps {
-            moves_map: @RefCell::new(HashSet::new()),
-            capture_map: @RefCell::new(HashMap::new()),
-            moved_variables_set: @RefCell::new(HashSet::new())
+            moves_map: @RefCell::new(NodeSet::new()),
+            capture_map: @RefCell::new(NodeMap::new()),
+            moved_variables_set: @RefCell::new(NodeSet::new())
         }
     };
     let visit_cx = &mut visit_cx;
diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs
index 3d90566ee79..182a52817b2 100644
--- a/src/librustc/middle/privacy.rs
+++ b/src/librustc/middle/privacy.rs
@@ -13,7 +13,6 @@
 //! which are available for use externally when compiled as a library.
 
 use std::mem::replace;
-use collections::{HashSet, HashMap};
 
 use metadata::csearch;
 use middle::lint;
@@ -21,6 +20,7 @@ use middle::resolve;
 use middle::ty;
 use middle::typeck::{MethodMap, MethodOrigin, MethodParam};
 use middle::typeck::{MethodStatic, MethodObject};
+use util::nodemap::{NodeMap, NodeSet};
 
 use syntax::ast;
 use syntax::ast_map;
@@ -35,12 +35,12 @@ use syntax::visit::Visitor;
 type Context<'a> = (&'a MethodMap, &'a resolve::ExportMap2);
 
 /// A set of AST nodes exported by the crate.
-pub type ExportedItems = HashSet<ast::NodeId>;
+pub type ExportedItems = NodeSet;
 
 /// A set of AST nodes that are fully public in the crate. This map is used for
 /// documentation purposes (reexporting a private struct inlines the doc,
 /// reexporting a public struct doesn't inline the doc).
-pub type PublicItems = HashSet<ast::NodeId>;
+pub type PublicItems = NodeSet;
 
 /// Result of a checking operation - None => no errors were found. Some => an
 /// error and contains the span and message for reporting that error and
@@ -52,7 +52,7 @@ type CheckResult = Option<(Span, ~str, Option<(Span, ~str)>)>;
 ////////////////////////////////////////////////////////////////////////////////
 
 struct ParentVisitor {
-    parents: HashMap<ast::NodeId, ast::NodeId>,
+    parents: NodeMap<ast::NodeId>,
     curparent: ast::NodeId,
 }
 
@@ -161,7 +161,7 @@ struct EmbargoVisitor<'a> {
     // all nodes which are reexported *and* reachable from external crates. This
     // means that the destination of the reexport is exported, and hence the
     // destination must also be exported.
-    reexports: HashSet<ast::NodeId>,
+    reexports: NodeSet,
 
     // These two fields are closely related to one another in that they are only
     // used for generation of the 'PublicItems' set, not for privacy checking at
@@ -349,7 +349,7 @@ struct PrivacyVisitor<'a> {
     in_fn: bool,
     in_foreign: bool,
     method_map: &'a MethodMap,
-    parents: HashMap<ast::NodeId, ast::NodeId>,
+    parents: NodeMap<ast::NodeId>,
     external_exports: resolve::ExternalExports,
     last_private_map: resolve::LastPrivateMap,
 }
@@ -1424,7 +1424,7 @@ pub fn check_crate(tcx: ty::ctxt,
                    krate: &ast::Crate) -> (ExportedItems, PublicItems) {
     // Figure out who everyone's parent is
     let mut visitor = ParentVisitor {
-        parents: HashMap::new(),
+        parents: NodeMap::new(),
         curparent: ast::DUMMY_NODE_ID,
     };
     visit::walk_crate(&mut visitor, krate, ());
@@ -1456,9 +1456,9 @@ pub fn check_crate(tcx: ty::ctxt,
     // items which are reachable from external crates based on visibility.
     let mut visitor = EmbargoVisitor {
         tcx: tcx,
-        exported_items: HashSet::new(),
-        public_items: HashSet::new(),
-        reexports: HashSet::new(),
+        exported_items: NodeSet::new(),
+        public_items: NodeSet::new(),
+        reexports: NodeSet::new(),
         exp_map2: exp_map2,
         prev_exported: true,
         prev_public: true,
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index 305c60d8215..4ade65294d9 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -18,6 +18,7 @@
 use middle::ty;
 use middle::typeck;
 use middle::privacy;
+use util::nodemap::NodeSet;
 
 use std::cell::RefCell;
 use collections::HashSet;
@@ -88,7 +89,7 @@ struct ReachableContext {
     // methods they've been resolved to.
     method_map: typeck::MethodMap,
     // The set of items which must be exported in the linkage sense.
-    reachable_symbols: @RefCell<HashSet<ast::NodeId>>,
+    reachable_symbols: @RefCell<NodeSet>,
     // A worklist of item IDs. Each item ID in this worklist will be inlined
     // and will be scanned for further references.
     worklist: @RefCell<~[ast::NodeId]>,
@@ -98,7 +99,7 @@ struct MarkSymbolVisitor {
     worklist: @RefCell<~[ast::NodeId]>,
     method_map: typeck::MethodMap,
     tcx: ty::ctxt,
-    reachable_symbols: @RefCell<HashSet<ast::NodeId>>,
+    reachable_symbols: @RefCell<NodeSet>,
 }
 
 impl Visitor<()> for MarkSymbolVisitor {
@@ -188,7 +189,7 @@ impl ReachableContext {
         ReachableContext {
             tcx: tcx,
             method_map: method_map,
-            reachable_symbols: @RefCell::new(HashSet::new()),
+            reachable_symbols: @RefCell::new(NodeSet::new()),
             worklist: @RefCell::new(~[]),
         }
     }
@@ -395,7 +396,7 @@ impl ReachableContext {
 pub fn find_reachable(tcx: ty::ctxt,
                       method_map: typeck::MethodMap,
                       exported_items: &privacy::ExportedItems)
-                      -> @RefCell<HashSet<ast::NodeId>> {
+                      -> @RefCell<NodeSet> {
     let reachable_context = ReachableContext::new(tcx, method_map);
 
     // Step 1: Seed the worklist with all nodes which were found to be public as
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 9e1552ae35e..07b68900ba5 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -24,6 +24,7 @@ Most of the documentation on regions can be found in
 use driver::session::Session;
 use middle::ty::{FreeRegion};
 use middle::ty;
+use util::nodemap::NodeMap;
 
 use std::cell::RefCell;
 use collections::{HashMap, HashSet};
@@ -74,10 +75,10 @@ The region maps encode information about region relationships.
   for dynamic checks and/or arbitrary amounts of stack space.
 */
 pub struct RegionMaps {
-    priv scope_map: RefCell<HashMap<ast::NodeId, ast::NodeId>>,
-    priv var_map: RefCell<HashMap<ast::NodeId, ast::NodeId>>,
+    priv scope_map: RefCell<NodeMap<ast::NodeId>>,
+    priv var_map: RefCell<NodeMap<ast::NodeId>>,
     priv free_region_map: RefCell<HashMap<FreeRegion, ~[FreeRegion]>>,
-    priv rvalue_scopes: RefCell<HashMap<ast::NodeId, ast::NodeId>>,
+    priv rvalue_scopes: RefCell<NodeMap<ast::NodeId>>,
     priv terminating_scopes: RefCell<HashSet<ast::NodeId>>,
 }
 
@@ -910,10 +911,10 @@ impl<'a> Visitor<Context> for RegionResolutionVisitor<'a> {
 
 pub fn resolve_crate(sess: Session, krate: &ast::Crate) -> RegionMaps {
     let maps = RegionMaps {
-        scope_map: RefCell::new(HashMap::new()),
-        var_map: RefCell::new(HashMap::new()),
+        scope_map: RefCell::new(NodeMap::new()),
+        var_map: RefCell::new(NodeMap::new()),
         free_region_map: RefCell::new(HashMap::new()),
-        rvalue_scopes: RefCell::new(HashMap::new()),
+        rvalue_scopes: RefCell::new(NodeMap::new()),
         terminating_scopes: RefCell::new(HashSet::new()),
     };
     {
diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index 0e61629f178..46faf5b040f 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -16,6 +16,7 @@ use metadata::decoder::{DefLike, DlDef, DlField, DlImpl};
 use middle::lang_items::LanguageItems;
 use middle::lint::{UnnecessaryQualification, UnusedImports};
 use middle::pat_util::pat_bindings;
+use util::nodemap::{NodeMap, DefIdSet};
 
 use syntax::ast::*;
 use syntax::ast;
@@ -36,7 +37,7 @@ use std::mem::replace;
 use collections::{HashMap, HashSet};
 
 // Definition mapping
-pub type DefMap = @RefCell<HashMap<NodeId,Def>>;
+pub type DefMap = @RefCell<NodeMap<Def>>;
 
 struct binding_info {
     span: Span,
@@ -47,11 +48,11 @@ struct binding_info {
 type BindingMap = HashMap<Name,binding_info>;
 
 // Trait method resolution
-pub type TraitMap = HashMap<NodeId, ~[DefId]>;
+pub type TraitMap = NodeMap<~[DefId]>;
 
 // This is the replacement export map. It maps a module to all of the exports
 // within.
-pub type ExportMap2 = @RefCell<HashMap<NodeId, ~[Export2]>>;
+pub type ExportMap2 = @RefCell<NodeMap<~[Export2]>>;
 
 pub struct Export2 {
     name: ~str,        // The name of the target.
@@ -60,10 +61,10 @@ pub struct Export2 {
 
 // This set contains all exported definitions from external crates. The set does
 // not contain any entries from local crates.
-pub type ExternalExports = HashSet<DefId>;
+pub type ExternalExports = DefIdSet;
 
 // FIXME: dox
-pub type LastPrivateMap = HashMap<NodeId, LastPrivate>;
+pub type LastPrivateMap = NodeMap<LastPrivate>;
 
 pub enum LastPrivate {
     LastMod(PrivateDep),
@@ -457,7 +458,7 @@ struct Module {
     //
     // There will be an anonymous module created around `g` with the ID of the
     // entry block for `f`.
-    anonymous_children: RefCell<HashMap<NodeId,@Module>>,
+    anonymous_children: RefCell<NodeMap<@Module>>,
 
     // The status of resolving each import in this module.
     import_resolutions: RefCell<HashMap<Name, @ImportResolution>>,
@@ -489,7 +490,7 @@ impl Module {
             children: RefCell::new(HashMap::new()),
             imports: RefCell::new(~[]),
             external_module_children: RefCell::new(HashMap::new()),
-            anonymous_children: RefCell::new(HashMap::new()),
+            anonymous_children: RefCell::new(NodeMap::new()),
             import_resolutions: RefCell::new(HashMap::new()),
             glob_count: Cell::new(0),
             resolved_import_count: Cell::new(0),
@@ -827,12 +828,12 @@ fn Resolver(session: Session,
 
         namespaces: ~[ TypeNS, ValueNS ],
 
-        def_map: @RefCell::new(HashMap::new()),
-        export_map2: @RefCell::new(HashMap::new()),
-        trait_map: HashMap::new(),
+        def_map: @RefCell::new(NodeMap::new()),
+        export_map2: @RefCell::new(NodeMap::new()),
+        trait_map: NodeMap::new(),
         used_imports: HashSet::new(),
-        external_exports: HashSet::new(),
-        last_private: HashMap::new(),
+        external_exports: DefIdSet::new(),
+        last_private: NodeMap::new(),
 
         emit_errors: true,
     };
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 4e780f45111..c8e28d45e3c 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -19,7 +19,7 @@
 
 use driver::session;
 use std::cell::RefCell;
-use collections::HashMap;
+use util::nodemap::NodeMap;
 use syntax::ast;
 use syntax::codemap::Span;
 use syntax::opt_vec::OptVec;
@@ -31,7 +31,7 @@ use syntax::visit::Visitor;
 
 // maps the id of each lifetime reference to the lifetime decl
 // that it corresponds to
-pub type NamedRegionMap = HashMap<ast::NodeId, ast::DefRegion>;
+pub type NamedRegionMap = NodeMap<ast::DefRegion>;
 
 struct LifetimeContext {
     sess: session::Session,
@@ -49,7 +49,7 @@ pub fn krate(sess: session::Session, krate: &ast::Crate)
              -> @RefCell<NamedRegionMap> {
     let mut ctxt = LifetimeContext {
         sess: sess,
-        named_region_map: @RefCell::new(HashMap::new())
+        named_region_map: @RefCell::new(NodeMap::new())
     };
     visit::walk_crate(&mut ctxt, krate, &RootScope);
     sess.abort_if_errors();
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 6a1fe8611e5..625b130d47a 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -70,6 +70,7 @@ use middle::typeck;
 use util::common::indenter;
 use util::ppaux::{Repr, ty_to_str};
 use util::sha2::Sha256;
+use util::nodemap::NodeMap;
 
 use arena::TypedArena;
 use std::c_str::ToCStr;
@@ -1245,9 +1246,9 @@ pub fn new_fn_ctxt<'a>(ccx: @CrateContext,
           llreturn: Cell::new(None),
           personality: Cell::new(None),
           caller_expects_out_pointer: uses_outptr,
-          llargs: RefCell::new(HashMap::new()),
-          lllocals: RefCell::new(HashMap::new()),
-          llupvars: RefCell::new(HashMap::new()),
+          llargs: RefCell::new(NodeMap::new()),
+          lllocals: RefCell::new(NodeMap::new()),
+          llupvars: RefCell::new(NodeMap::new()),
           id: id,
           param_substs: param_substs,
           span: sp,
diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs
index de36074d2e6..90f37651833 100644
--- a/src/librustc/middle/trans/common.rs
+++ b/src/librustc/middle/trans/common.rs
@@ -29,6 +29,7 @@ use middle::ty::substs;
 use middle::ty;
 use middle::typeck;
 use util::ppaux::Repr;
+use util::nodemap::NodeMap;
 
 use arena::TypedArena;
 use std::c_str::ToCStr;
@@ -253,14 +254,14 @@ pub struct FunctionContext<'a> {
     caller_expects_out_pointer: bool,
 
     // Maps arguments to allocas created for them in llallocas.
-    llargs: RefCell<HashMap<ast::NodeId, LvalueDatum>>,
+    llargs: RefCell<NodeMap<LvalueDatum>>,
 
     // Maps the def_ids for local variables to the allocas created for
     // them in llallocas.
-    lllocals: RefCell<HashMap<ast::NodeId, LvalueDatum>>,
+    lllocals: RefCell<NodeMap<LvalueDatum>>,
 
     // Same as above, but for closure upvars
-    llupvars: RefCell<HashMap<ast::NodeId, ValueRef>>,
+    llupvars: RefCell<NodeMap<ValueRef>>,
 
     // The NodeId of the function, or -1 if it doesn't correspond to
     // a user-defined function.
diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs
index 5011ee8be6e..652336ecc00 100644
--- a/src/librustc/middle/trans/context.rs
+++ b/src/librustc/middle/trans/context.rs
@@ -27,6 +27,7 @@ use middle::trans::debuginfo;
 use middle::trans::type_::Type;
 use middle::ty;
 use util::sha2::Sha256;
+use util::nodemap::{NodeMap, NodeSet, DefIdMap};
 
 use std::cell::{Cell, RefCell};
 use std::c_str::ToCStr;
@@ -45,10 +46,10 @@ pub struct CrateContext {
     tn: TypeNames,
     externs: RefCell<ExternMap>,
     intrinsics: HashMap<&'static str, ValueRef>,
-    item_vals: RefCell<HashMap<ast::NodeId, ValueRef>>,
+    item_vals: RefCell<NodeMap<ValueRef>>,
     exp_map2: resolve::ExportMap2,
-    reachable: @RefCell<HashSet<ast::NodeId>>,
-    item_symbols: RefCell<HashMap<ast::NodeId, ~str>>,
+    reachable: @RefCell<NodeSet>,
+    item_symbols: RefCell<NodeMap<~str>>,
     link_meta: LinkMeta,
     drop_glues: RefCell<HashMap<ty::t, ValueRef>>,
     tydescs: RefCell<HashMap<ty::t, @tydesc_info>>,
@@ -56,17 +57,17 @@ pub struct CrateContext {
     // created.
     finished_tydescs: Cell<bool>,
     // Track mapping of external ids to local items imported for inlining
-    external: RefCell<HashMap<ast::DefId, Option<ast::NodeId>>>,
+    external: RefCell<DefIdMap<Option<ast::NodeId>>>,
     // Backwards version of the `external` map (inlined items to where they
     // came from)
-    external_srcs: RefCell<HashMap<ast::NodeId, ast::DefId>>,
+    external_srcs: RefCell<NodeMap<ast::DefId>>,
     // A set of static items which cannot be inlined into other crates. This
     // will pevent in IIItem() structures from being encoded into the metadata
     // that is generated
-    non_inlineable_statics: RefCell<HashSet<ast::NodeId>>,
+    non_inlineable_statics: RefCell<NodeSet>,
     // Cache instances of monomorphized functions
     monomorphized: RefCell<HashMap<mono_id, ValueRef>>,
-    monomorphizing: RefCell<HashMap<ast::DefId, uint>>,
+    monomorphizing: RefCell<DefIdMap<uint>>,
     // Cache generated vtables
     vtables: RefCell<HashMap<(ty::t, mono_id), ValueRef>>,
     // Cache of constant strings,
@@ -83,10 +84,10 @@ pub struct CrateContext {
     const_globals: RefCell<HashMap<int, ValueRef>>,
 
     // Cache of emitted const values
-    const_values: RefCell<HashMap<ast::NodeId, ValueRef>>,
+    const_values: RefCell<NodeMap<ValueRef>>,
 
     // Cache of external const values
-    extern_const_values: RefCell<HashMap<ast::DefId, ValueRef>>,
+    extern_const_values: RefCell<DefIdMap<ValueRef>>,
 
     impl_method_cache: RefCell<HashMap<(ast::DefId, ast::Name), ast::DefId>>,
 
@@ -125,7 +126,7 @@ impl CrateContext {
                maps: astencode::Maps,
                symbol_hasher: Sha256,
                link_meta: LinkMeta,
-               reachable: @RefCell<HashSet<ast::NodeId>>)
+               reachable: @RefCell<NodeSet>)
                -> CrateContext {
         unsafe {
             let llcx = llvm::LLVMContextCreate();
@@ -185,24 +186,24 @@ impl CrateContext {
                  tn: tn,
                  externs: RefCell::new(HashMap::new()),
                  intrinsics: intrinsics,
-                 item_vals: RefCell::new(HashMap::new()),
+                 item_vals: RefCell::new(NodeMap::new()),
                  exp_map2: emap2,
                  reachable: reachable,
-                 item_symbols: RefCell::new(HashMap::new()),
+                 item_symbols: RefCell::new(NodeMap::new()),
                  link_meta: link_meta,
                  drop_glues: RefCell::new(HashMap::new()),
                  tydescs: RefCell::new(HashMap::new()),
                  finished_tydescs: Cell::new(false),
-                 external: RefCell::new(HashMap::new()),
-                 external_srcs: RefCell::new(HashMap::new()),
-                 non_inlineable_statics: RefCell::new(HashSet::new()),
+                 external: RefCell::new(DefIdMap::new()),
+                 external_srcs: RefCell::new(NodeMap::new()),
+                 non_inlineable_statics: RefCell::new(NodeSet::new()),
                  monomorphized: RefCell::new(HashMap::new()),
-                 monomorphizing: RefCell::new(HashMap::new()),
+                 monomorphizing: RefCell::new(DefIdMap::new()),
                  vtables: RefCell::new(HashMap::new()),
                  const_cstr_cache: RefCell::new(HashMap::new()),
                  const_globals: RefCell::new(HashMap::new()),
-                 const_values: RefCell::new(HashMap::new()),
-                 extern_const_values: RefCell::new(HashMap::new()),
+                 const_values: RefCell::new(NodeMap::new()),
+                 extern_const_values: RefCell::new(DefIdMap::new()),
                  impl_method_cache: RefCell::new(HashMap::new()),
                  closure_bare_wrapper_cache: RefCell::new(HashMap::new()),
                  module_data: RefCell::new(HashMap::new()),
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index fbb7decb302..db9f3ed5a81 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -66,11 +66,10 @@ use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn};
 use middle::ty;
 use util::common::indenter;
 use util::ppaux::Repr;
+use util::nodemap::NodeMap;
 use middle::trans::machine::llsize_of;
-
 use middle::trans::type_::Type;
 
-use collections::HashMap;
 use std::vec;
 use syntax::ast;
 use syntax::ast_map;
@@ -944,7 +943,7 @@ pub fn trans_local_var<'a>(bcx: &'a Block<'a>,
     };
 
     fn take_local<'a>(bcx: &'a Block<'a>,
-                      table: &HashMap<ast::NodeId, Datum<Lvalue>>,
+                      table: &NodeMap<Datum<Lvalue>>,
                       nid: ast::NodeId)
                       -> Datum<Lvalue> {
         let datum = match table.find(&nid) {
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index ecbf9342ec0..9442a2144bd 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -30,6 +30,7 @@ use util::ppaux::{note_and_explain_region, bound_region_ptr_to_str};
 use util::ppaux::{trait_store_to_str, ty_to_str, vstore_to_str};
 use util::ppaux::{Repr, UserString};
 use util::common::{indenter};
+use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
 
 use std::cast;
 use std::cell::{Cell, RefCell};
@@ -178,11 +179,16 @@ impl cmp::Eq for intern_key {
     }
 }
 
+#[cfg(stage0)]
 impl Hash for intern_key {
     fn hash(&self, s: &mut sip::SipState) {
-        unsafe {
-            (*self.sty).hash(s)
-        }
+        unsafe { (*self.sty).hash(s) }
+    }
+}
+#[cfg(not(stage0))]
+impl<W:Writer> Hash<W> for intern_key {
+    fn hash(&self, s: &mut W) {
+        unsafe { (*self.sty).hash(s) }
     }
 }
 
@@ -250,7 +256,12 @@ pub type ctxt = @ctxt_;
 /// later on.
 pub struct ctxt_ {
     diag: @syntax::diagnostic::SpanHandler,
+    // Specifically use a speedy hash algorithm for this hash map, it's used
+    // quite often.
+    #[cfg(stage0)]
     interner: RefCell<HashMap<intern_key, ~t_box_>>,
+    #[cfg(not(stage0))]
+    interner: RefCell<HashMap<intern_key, ~t_box_, ::util::nodemap::FnvHasher>>,
     next_id: Cell<uint>,
     cstore: @metadata::cstore::CStore,
     sess: session::Session,
@@ -269,94 +280,94 @@ pub struct ctxt_ {
     // of this node.  This only applies to nodes that refer to entities
     // parameterized by type parameters, such as generic fns, types, or
     // other items.
-    node_type_substs: RefCell<HashMap<NodeId, ~[t]>>,
+    node_type_substs: RefCell<NodeMap<~[t]>>,
 
     // Maps from a method to the method "descriptor"
-    methods: RefCell<HashMap<DefId, @Method>>,
+    methods: RefCell<DefIdMap<@Method>>,
 
     // Maps from a trait def-id to a list of the def-ids of its methods
-    trait_method_def_ids: RefCell<HashMap<DefId, @~[DefId]>>,
+    trait_method_def_ids: RefCell<DefIdMap<@~[DefId]>>,
 
     // A cache for the trait_methods() routine
-    trait_methods_cache: RefCell<HashMap<DefId, @~[@Method]>>,
+    trait_methods_cache: RefCell<DefIdMap<@~[@Method]>>,
 
-    impl_trait_cache: RefCell<HashMap<ast::DefId, Option<@ty::TraitRef>>>,
+    impl_trait_cache: RefCell<DefIdMap<Option<@ty::TraitRef>>>,
 
-    trait_refs: RefCell<HashMap<NodeId, @TraitRef>>,
-    trait_defs: RefCell<HashMap<DefId, @TraitDef>>,
+    trait_refs: RefCell<NodeMap<@TraitRef>>,
+    trait_defs: RefCell<DefIdMap<@TraitDef>>,
 
     map: ast_map::Map,
-    intrinsic_defs: RefCell<HashMap<ast::DefId, t>>,
+    intrinsic_defs: RefCell<DefIdMap<t>>,
     freevars: RefCell<freevars::freevar_map>,
     tcache: type_cache,
     rcache: creader_cache,
     short_names_cache: RefCell<HashMap<t, ~str>>,
     needs_unwind_cleanup_cache: RefCell<HashMap<t, bool>>,
     tc_cache: RefCell<HashMap<uint, TypeContents>>,
-    ast_ty_to_ty_cache: RefCell<HashMap<NodeId, ast_ty_to_ty_cache_entry>>,
-    enum_var_cache: RefCell<HashMap<DefId, @~[@VariantInfo]>>,
-    ty_param_defs: RefCell<HashMap<ast::NodeId, TypeParameterDef>>,
-    adjustments: RefCell<HashMap<ast::NodeId, @AutoAdjustment>>,
+    ast_ty_to_ty_cache: RefCell<NodeMap<ast_ty_to_ty_cache_entry>>,
+    enum_var_cache: RefCell<DefIdMap<@~[@VariantInfo]>>,
+    ty_param_defs: RefCell<NodeMap<TypeParameterDef>>,
+    adjustments: RefCell<NodeMap<@AutoAdjustment>>,
     normalized_cache: RefCell<HashMap<t, t>>,
     lang_items: @middle::lang_items::LanguageItems,
     // A mapping of fake provided method def_ids to the default implementation
-    provided_method_sources: RefCell<HashMap<ast::DefId, ast::DefId>>,
-    supertraits: RefCell<HashMap<ast::DefId, @~[@TraitRef]>>,
+    provided_method_sources: RefCell<DefIdMap<ast::DefId>>,
+    supertraits: RefCell<DefIdMap<@~[@TraitRef]>>,
 
     // Maps from def-id of a type or region parameter to its
     // (inferred) variance.
-    item_variance_map: RefCell<HashMap<ast::DefId, @ItemVariances>>,
+    item_variance_map: RefCell<DefIdMap<@ItemVariances>>,
 
     // A mapping from the def ID of an enum or struct type to the def ID
     // of the method that implements its destructor. If the type is not
     // present in this map, it does not have a destructor. This map is
     // populated during the coherence phase of typechecking.
-    destructor_for_type: RefCell<HashMap<ast::DefId, ast::DefId>>,
+    destructor_for_type: RefCell<DefIdMap<ast::DefId>>,
 
     // A method will be in this list if and only if it is a destructor.
-    destructors: RefCell<HashSet<ast::DefId>>,
+    destructors: RefCell<DefIdSet>,
 
     // Maps a trait onto a list of impls of that trait.
-    trait_impls: RefCell<HashMap<ast::DefId, @RefCell<~[@Impl]>>>,
+    trait_impls: RefCell<DefIdMap<@RefCell<~[@Impl]>>>,
 
     // Maps a def_id of a type to a list of its inherent impls.
     // Contains implementations of methods that are inherent to a type.
     // Methods in these implementations don't need to be exported.
-    inherent_impls: RefCell<HashMap<ast::DefId, @RefCell<~[@Impl]>>>,
+    inherent_impls: RefCell<DefIdMap<@RefCell<~[@Impl]>>>,
 
     // Maps a def_id of an impl to an Impl structure.
     // Note that this contains all of the impls that we know about,
     // including ones in other crates. It's not clear that this is the best
     // way to do it.
-    impls: RefCell<HashMap<ast::DefId, @Impl>>,
+    impls: RefCell<DefIdMap<@Impl>>,
 
     // Set of used unsafe nodes (functions or blocks). Unsafe nodes not
     // present in this set can be warned about.
-    used_unsafe: RefCell<HashSet<ast::NodeId>>,
+    used_unsafe: RefCell<NodeSet>,
 
     // Set of nodes which mark locals as mutable which end up getting used at
     // some point. Local variable definitions not in this set can be warned
     // about.
-    used_mut_nodes: RefCell<HashSet<ast::NodeId>>,
+    used_mut_nodes: RefCell<NodeSet>,
 
     // vtable resolution information for impl declarations
     impl_vtables: typeck::impl_vtable_map,
 
     // The set of external nominal types whose implementations have been read.
     // This is used for lazy resolution of methods.
-    populated_external_types: RefCell<HashSet<ast::DefId>>,
+    populated_external_types: RefCell<DefIdSet>,
 
     // The set of external traits whose implementations have been read. This
     // is used for lazy resolution of traits.
-    populated_external_traits: RefCell<HashSet<ast::DefId>>,
+    populated_external_traits: RefCell<DefIdSet>,
 
     // Borrows
     upvar_borrow_map: RefCell<UpvarBorrowMap>,
 
     // These two caches are used by const_eval when decoding external statics
     // and variants that are found.
-    extern_const_statics: RefCell<HashMap<ast::DefId, Option<@ast::Expr>>>,
-    extern_const_variants: RefCell<HashMap<ast::DefId, Option<@ast::Expr>>>,
+    extern_const_statics: RefCell<DefIdMap<Option<@ast::Expr>>>,
+    extern_const_variants: RefCell<DefIdMap<Option<@ast::Expr>>>,
 }
 
 pub enum tbox_flag {
@@ -1068,7 +1079,7 @@ pub struct ty_param_substs_and_ty {
     ty: ty::t
 }
 
-pub type type_cache = RefCell<HashMap<ast::DefId, ty_param_bounds_and_ty>>;
+pub type type_cache = RefCell<DefIdMap<ty_param_bounds_and_ty>>;
 
 pub type node_type_table = RefCell<HashMap<uint,t>>;
 
@@ -1080,54 +1091,61 @@ pub fn mk_ctxt(s: session::Session,
                region_maps: middle::region::RegionMaps,
                lang_items: @middle::lang_items::LanguageItems)
             -> ctxt {
-
+    #[cfg(stage0)]
+    fn hasher() -> HashMap<intern_key, ~t_box_> {
+        HashMap::new()
+    }
+    #[cfg(not(stage0))]
+    fn hasher() -> HashMap<intern_key, ~t_box_, ::util::nodemap::FnvHasher> {
+        HashMap::with_hasher(::util::nodemap::FnvHasher)
+    }
     @ctxt_ {
         named_region_map: named_region_map,
-        item_variance_map: RefCell::new(HashMap::new()),
+        item_variance_map: RefCell::new(DefIdMap::new()),
         diag: s.diagnostic(),
-        interner: RefCell::new(HashMap::new()),
+        interner: RefCell::new(hasher()),
         next_id: Cell::new(primitives::LAST_PRIMITIVE_ID),
         cstore: s.cstore,
         sess: s,
         def_map: dm,
         region_maps: region_maps,
         node_types: RefCell::new(HashMap::new()),
-        node_type_substs: RefCell::new(HashMap::new()),
-        trait_refs: RefCell::new(HashMap::new()),
-        trait_defs: RefCell::new(HashMap::new()),
+        node_type_substs: RefCell::new(NodeMap::new()),
+        trait_refs: RefCell::new(NodeMap::new()),
+        trait_defs: RefCell::new(DefIdMap::new()),
         map: map,
-        intrinsic_defs: RefCell::new(HashMap::new()),
+        intrinsic_defs: RefCell::new(DefIdMap::new()),
         freevars: RefCell::new(freevars),
-        tcache: RefCell::new(HashMap::new()),
+        tcache: RefCell::new(DefIdMap::new()),
         rcache: RefCell::new(HashMap::new()),
         short_names_cache: RefCell::new(HashMap::new()),
         needs_unwind_cleanup_cache: RefCell::new(HashMap::new()),
         tc_cache: RefCell::new(HashMap::new()),
-        ast_ty_to_ty_cache: RefCell::new(HashMap::new()),
-        enum_var_cache: RefCell::new(HashMap::new()),
-        methods: RefCell::new(HashMap::new()),
-        trait_method_def_ids: RefCell::new(HashMap::new()),
-        trait_methods_cache: RefCell::new(HashMap::new()),
-        impl_trait_cache: RefCell::new(HashMap::new()),
-        ty_param_defs: RefCell::new(HashMap::new()),
-        adjustments: RefCell::new(HashMap::new()),
+        ast_ty_to_ty_cache: RefCell::new(NodeMap::new()),
+        enum_var_cache: RefCell::new(DefIdMap::new()),
+        methods: RefCell::new(DefIdMap::new()),
+        trait_method_def_ids: RefCell::new(DefIdMap::new()),
+        trait_methods_cache: RefCell::new(DefIdMap::new()),
+        impl_trait_cache: RefCell::new(DefIdMap::new()),
+        ty_param_defs: RefCell::new(NodeMap::new()),
+        adjustments: RefCell::new(NodeMap::new()),
         normalized_cache: RefCell::new(HashMap::new()),
         lang_items: lang_items,
-        provided_method_sources: RefCell::new(HashMap::new()),
-        supertraits: RefCell::new(HashMap::new()),
-        destructor_for_type: RefCell::new(HashMap::new()),
-        destructors: RefCell::new(HashSet::new()),
-        trait_impls: RefCell::new(HashMap::new()),
-        inherent_impls: RefCell::new(HashMap::new()),
-        impls: RefCell::new(HashMap::new()),
-        used_unsafe: RefCell::new(HashSet::new()),
-        used_mut_nodes: RefCell::new(HashSet::new()),
-        impl_vtables: RefCell::new(HashMap::new()),
-        populated_external_types: RefCell::new(HashSet::new()),
-        populated_external_traits: RefCell::new(HashSet::new()),
+        provided_method_sources: RefCell::new(DefIdMap::new()),
+        supertraits: RefCell::new(DefIdMap::new()),
+        destructor_for_type: RefCell::new(DefIdMap::new()),
+        destructors: RefCell::new(DefIdSet::new()),
+        trait_impls: RefCell::new(DefIdMap::new()),
+        inherent_impls: RefCell::new(DefIdMap::new()),
+        impls: RefCell::new(DefIdMap::new()),
+        used_unsafe: RefCell::new(NodeSet::new()),
+        used_mut_nodes: RefCell::new(NodeSet::new()),
+        impl_vtables: RefCell::new(DefIdMap::new()),
+        populated_external_types: RefCell::new(DefIdSet::new()),
+        populated_external_traits: RefCell::new(DefIdSet::new()),
         upvar_borrow_map: RefCell::new(HashMap::new()),
-        extern_const_statics: RefCell::new(HashMap::new()),
-        extern_const_variants: RefCell::new(HashMap::new()),
+        extern_const_statics: RefCell::new(DefIdMap::new()),
+        extern_const_variants: RefCell::new(DefIdMap::new()),
     }
 }
 
@@ -3787,7 +3805,7 @@ pub fn trait_ref_supertraits(cx: ctxt, trait_ref: &ty::TraitRef) -> ~[@TraitRef]
 fn lookup_locally_or_in_crate_store<V:Clone>(
                                     descr: &str,
                                     def_id: ast::DefId,
-                                    map: &mut HashMap<ast::DefId, V>,
+                                    map: &mut DefIdMap<V>,
                                     load_external: || -> V) -> V {
     /*!
      * Helper for looking things up in the various maps
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index fe8d4caf905..6a41f63a779 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -111,6 +111,7 @@ use middle::lang_items::TypeIdLangItem;
 use util::common::{block_query, indenter, loop_query};
 use util::ppaux;
 use util::ppaux::{UserString, Repr};
+use util::nodemap::NodeMap;
 
 use std::cell::{Cell, RefCell};
 use collections::HashMap;
@@ -153,13 +154,13 @@ pub mod method;
 /// share the inherited fields.
 pub struct Inherited {
     infcx: infer::InferCtxt,
-    locals: @RefCell<HashMap<ast::NodeId, ty::t>>,
+    locals: @RefCell<NodeMap<ty::t>>,
     param_env: ty::ParameterEnvironment,
 
     // Temporary tables:
-    node_types: RefCell<HashMap<ast::NodeId, ty::t>>,
-    node_type_substs: RefCell<HashMap<ast::NodeId, ty::substs>>,
-    adjustments: RefCell<HashMap<ast::NodeId, @ty::AutoAdjustment>>,
+    node_types: RefCell<NodeMap<ty::t>>,
+    node_type_substs: RefCell<NodeMap<ty::substs>>,
+    adjustments: RefCell<NodeMap<@ty::AutoAdjustment>>,
     method_map: MethodMap,
     vtable_map: vtable_map,
     upvar_borrow_map: RefCell<ty::UpvarBorrowMap>,
@@ -258,13 +259,13 @@ impl Inherited {
            -> Inherited {
         Inherited {
             infcx: infer::new_infer_ctxt(tcx),
-            locals: @RefCell::new(HashMap::new()),
+            locals: @RefCell::new(NodeMap::new()),
             param_env: param_env,
-            node_types: RefCell::new(HashMap::new()),
-            node_type_substs: RefCell::new(HashMap::new()),
-            adjustments: RefCell::new(HashMap::new()),
-            method_map: @RefCell::new(HashMap::new()),
-            vtable_map: @RefCell::new(HashMap::new()),
+            node_types: RefCell::new(NodeMap::new()),
+            node_type_substs: RefCell::new(NodeMap::new()),
+            adjustments: RefCell::new(NodeMap::new()),
+            method_map: @RefCell::new(NodeMap::new()),
+            vtable_map: @RefCell::new(NodeMap::new()),
             upvar_borrow_map: RefCell::new(HashMap::new()),
         }
     }
diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs
index 4030ca5a87f..aee2b24e60f 100644
--- a/src/librustc/middle/typeck/mod.rs
+++ b/src/librustc/middle/typeck/mod.rs
@@ -68,9 +68,9 @@ use middle::ty;
 use util::common::time;
 use util::ppaux::Repr;
 use util::ppaux;
+use util::nodemap::{DefIdMap, NodeMap};
 
 use std::cell::RefCell;
-use collections::HashMap;
 use std::rc::Rc;
 use collections::List;
 use syntax::codemap::Span;
@@ -150,7 +150,7 @@ pub struct MethodCallee {
 
 // maps from an expression id that corresponds to a method call to the details
 // of the method to be invoked
-pub type MethodMap = @RefCell<HashMap<ast::NodeId, MethodCallee>>;
+pub type MethodMap = @RefCell<NodeMap<MethodCallee>>;
 
 pub type vtable_param_res = @~[vtable_origin];
 // Resolutions for bounds of all parameters, left to right, for a given path.
@@ -194,7 +194,7 @@ impl Repr for vtable_origin {
     }
 }
 
-pub type vtable_map = @RefCell<HashMap<ast::NodeId, vtable_res>>;
+pub type vtable_map = @RefCell<NodeMap<vtable_res>>;
 
 
 // Information about the vtable resolutions for a trait impl.
@@ -216,7 +216,7 @@ impl Repr for impl_res {
     }
 }
 
-pub type impl_vtable_map = RefCell<HashMap<ast::DefId, impl_res>>;
+pub type impl_vtable_map = RefCell<DefIdMap<impl_res>>;
 
 pub struct CrateCtxt {
     // A mapping from method call sites to traits that have that method.
@@ -441,8 +441,8 @@ pub fn check_crate(tcx: ty::ctxt,
     let time_passes = tcx.sess.time_passes();
     let ccx = @CrateCtxt {
         trait_map: trait_map,
-        method_map: @RefCell::new(HashMap::new()),
-        vtable_map: @RefCell::new(HashMap::new()),
+        method_map: @RefCell::new(NodeMap::new()),
+        vtable_map: @RefCell::new(NodeMap::new()),
         tcx: tcx
     };
 
diff --git a/src/librustc/util/nodemap.rs b/src/librustc/util/nodemap.rs
new file mode 100644
index 00000000000..fe24733aba2
--- /dev/null
+++ b/src/librustc/util/nodemap.rs
@@ -0,0 +1,127 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! An efficient hash map for node IDs
+
+use collections::{HashMap, HashSet};
+use std::hash::{Hasher, Hash};
+use std::io;
+use syntax::ast;
+
+#[cfg(not(stage0))]
+pub type NodeMap<T> = HashMap<ast::NodeId, T, FnvHasher>;
+#[cfg(not(stage0))]
+pub type DefIdMap<T> = HashMap<ast::DefId, T, FnvHasher>;
+#[cfg(not(stage0))]
+pub type NodeSet = HashSet<ast::NodeId, FnvHasher>;
+#[cfg(not(stage0))]
+pub type DefIdSet = HashSet<ast::DefId, FnvHasher>;
+
+// Hacks to get good names
+#[cfg(not(stage0))]
+pub mod NodeMap {
+    use collections::HashMap;
+    pub fn new<T>() -> super::NodeMap<T> {
+        HashMap::with_hasher(super::FnvHasher)
+    }
+}
+#[cfg(not(stage0))]
+pub mod NodeSet {
+    use collections::HashSet;
+    pub fn new() -> super::NodeSet {
+        HashSet::with_hasher(super::FnvHasher)
+    }
+}
+#[cfg(not(stage0))]
+pub mod DefIdMap {
+    use collections::HashMap;
+    pub fn new<T>() -> super::DefIdMap<T> {
+        HashMap::with_hasher(super::FnvHasher)
+    }
+}
+#[cfg(not(stage0))]
+pub mod DefIdSet {
+    use collections::HashSet;
+    pub fn new() -> super::DefIdSet {
+        HashSet::with_hasher(super::FnvHasher)
+    }
+}
+
+#[cfg(stage0)]
+pub type NodeMap<T> = HashMap<ast::NodeId, T>;
+#[cfg(stage0)]
+pub type DefIdMap<T> = HashMap<ast::DefId, T>;
+#[cfg(stage0)]
+pub type NodeSet = HashSet<ast::NodeId>;
+#[cfg(stage0)]
+pub type DefIdSet = HashSet<ast::DefId>;
+
+// Hacks to get good names
+#[cfg(stage0)]
+pub mod NodeMap {
+    use collections::HashMap;
+    pub fn new<T>() -> super::NodeMap<T> {
+        HashMap::new()
+    }
+}
+#[cfg(stage0)]
+pub mod NodeSet {
+    use collections::HashSet;
+    pub fn new() -> super::NodeSet {
+        HashSet::new()
+    }
+}
+#[cfg(stage0)]
+pub mod DefIdMap {
+    use collections::HashMap;
+    pub fn new<T>() -> super::DefIdMap<T> {
+        HashMap::new()
+    }
+}
+#[cfg(stage0)]
+pub mod DefIdSet {
+    use collections::HashSet;
+    pub fn new() -> super::DefIdSet {
+        HashSet::new()
+    }
+}
+
+/// A speedy hash algorithm for node ids and def ids. The hashmap in
+/// libcollections by default uses SipHash which isn't quite as speedy as we
+/// want. In the compiler we're not really worried about DOS attempts, so we
+/// just default to a non-cryptographic hash.
+///
+/// This uses FNV hashing, as described here:
+/// http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
+#[deriving(Clone)]
+pub struct FnvHasher;
+
+pub struct FnvState(u64);
+
+impl Hasher<FnvState> for FnvHasher {
+    fn hash<T: Hash<FnvState>>(&self, t: &T) -> u64 {
+        let mut state = FnvState(0xcbf29ce484222325);
+        t.hash(&mut state);
+        let FnvState(ret) = state;
+        return ret;
+    }
+}
+
+impl Writer for FnvState {
+    fn write(&mut self, bytes: &[u8]) -> io::IoResult<()> {
+        let FnvState(mut hash) = *self;
+        for byte in bytes.iter() {
+            hash = hash * 0x100000001b3;
+            hash = hash ^ (*byte as u64);
+        }
+        *self = FnvState(hash);
+        Ok(())
+    }
+}
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 0c3e8354021..1029cc7444d 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -46,6 +46,7 @@ use serialize::json::ToJson;
 use syntax::ast;
 use syntax::attr;
 use syntax::parse::token::InternedString;
+use rustc::util::nodemap::NodeSet;
 
 use clean;
 use doctree;
@@ -158,7 +159,7 @@ pub struct Cache {
     priv parent_stack: ~[ast::NodeId],
     priv search_index: ~[IndexItem],
     priv privmod: bool,
-    priv public_items: HashSet<ast::NodeId>,
+    priv public_items: NodeSet,
 }
 
 /// Helper struct to render all source code to HTML pages
@@ -235,7 +236,7 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
     // Crawl the crate to build various caches used for the output
     let mut cache = local_data::get(::analysiskey, |analysis| {
         let public_items = analysis.map(|a| a.public_items.clone());
-        let public_items = public_items.unwrap_or(HashSet::new());
+        let public_items = public_items.unwrap_or(NodeSet::new());
         Cache {
             impls: HashMap::new(),
             typarams: HashMap::new(),
diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs
index b8cc271ca9c..fdd637b1d0f 100644
--- a/src/librustdoc/passes.rs
+++ b/src/librustdoc/passes.rs
@@ -13,6 +13,7 @@ use collections::HashSet;
 use std::local_data;
 use std::uint;
 use syntax::ast;
+use rustc::util::nodemap::NodeSet;
 
 use clean;
 use clean::Item;
@@ -110,7 +111,7 @@ pub fn strip_private(krate: clean::Crate) -> plugins::PluginResult {
 
 struct Stripper<'a> {
     retained: &'a mut HashSet<ast::NodeId>,
-    exported_items: &'a HashSet<ast::NodeId>,
+    exported_items: &'a NodeSet,
 }
 
 impl<'a> fold::DocFolder for Stripper<'a> {
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 79068d40469..459c0d1d0e3 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -283,7 +283,7 @@ pub struct ExtCtxt<'a> {
     parse_sess: @parse::ParseSess,
     cfg: ast::CrateConfig,
     backtrace: Option<@ExpnInfo>,
-    loader: &'a mut CrateLoader,
+    ecfg: expand::ExpansionConfig<'a>,
 
     mod_path: Vec<ast::Ident> ,
     trace_mac: bool
@@ -291,13 +291,13 @@ pub struct ExtCtxt<'a> {
 
 impl<'a> ExtCtxt<'a> {
     pub fn new<'a>(parse_sess: @parse::ParseSess, cfg: ast::CrateConfig,
-               loader: &'a mut CrateLoader) -> ExtCtxt<'a> {
+                   ecfg: expand::ExpansionConfig<'a>) -> ExtCtxt<'a> {
         ExtCtxt {
             parse_sess: parse_sess,
             cfg: cfg,
             backtrace: None,
-            loader: loader,
             mod_path: Vec::new(),
+            ecfg: ecfg,
             trace_mac: false
         }
     }
diff --git a/src/libsyntax/ext/deriving/hash.rs b/src/libsyntax/ext/deriving/hash.rs
index 1d6cfab120d..299989d5fe6 100644
--- a/src/libsyntax/ext/deriving/hash.rs
+++ b/src/libsyntax/ext/deriving/hash.rs
@@ -22,19 +22,31 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt,
                             item: @Item,
                             push: |@Item|) {
 
+    let (path, generics, args) = if cx.ecfg.deriving_hash_type_parameter {
+        (Path::new_(vec!("std", "hash", "Hash"), None,
+                    vec!(~Literal(Path::new_local("__H"))), true),
+         LifetimeBounds {
+             lifetimes: Vec::new(),
+             bounds: vec!(("__H", vec!(Path::new(vec!("std", "io", "Writer"))))),
+         },
+         Path::new_local("__H"))
+    } else {
+        (Path::new(vec!("std", "hash", "Hash")),
+         LifetimeBounds::empty(),
+         Path::new(vec!("std", "hash", "sip", "SipState")))
+    };
     let hash_trait_def = TraitDef {
         span: span,
         attributes: Vec::new(),
-        path: Path::new(vec!("std", "hash", "Hash")),
+        path: path,
         additional_bounds: Vec::new(),
-        generics: LifetimeBounds::empty(),
+        generics: generics,
         methods: vec!(
             MethodDef {
                 name: "hash",
                 generics: LifetimeBounds::empty(),
                 explicit_self: borrowed_explicit_self(),
-                args: vec!(Ptr(~Literal(Path::new(vec!("std", "hash", "sip", "SipState"))),
-                            Borrowed(None, MutMutable))),
+                args: vec!(Ptr(~Literal(args), Borrowed(None, MutMutable))),
                 ret_ty: nil_ty(),
                 inline: true,
                 const_nonmatching: false,
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 8b23de235b8..12eaa759ede 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -443,7 +443,7 @@ pub fn expand_view_item(vi: &ast::ViewItem,
 }
 
 fn load_extern_macros(krate: &ast::ViewItem, fld: &mut MacroExpander) {
-    let MacroCrate { lib, cnum } = fld.cx.loader.load_crate(krate);
+    let MacroCrate { lib, cnum } = fld.cx.ecfg.loader.load_crate(krate);
 
     let crate_name = match krate.node {
         ast::ViewItemExternMod(name, _, _) => name,
@@ -451,7 +451,7 @@ fn load_extern_macros(krate: &ast::ViewItem, fld: &mut MacroExpander) {
     };
     let name = format!("<{} macros>", token::get_ident(crate_name));
 
-    let exported_macros = fld.cx.loader.get_exported_macros(cnum);
+    let exported_macros = fld.cx.ecfg.loader.get_exported_macros(cnum);
     for source in exported_macros.iter() {
         let item = parse::parse_item_from_source_str(name.clone(),
                                                      (*source).clone(),
@@ -468,7 +468,7 @@ fn load_extern_macros(krate: &ast::ViewItem, fld: &mut MacroExpander) {
     // Make sure the path contains a / or the linker will search for it.
     let path = os::make_absolute(&path);
 
-    let registrar = match fld.cx.loader.get_registrar_symbol(cnum) {
+    let registrar = match fld.cx.ecfg.loader.get_registrar_symbol(cnum) {
         Some(registrar) => registrar,
         None => return
     };
@@ -823,10 +823,15 @@ impl<'a> Folder for MacroExpander<'a> {
     }
 }
 
+pub struct ExpansionConfig<'a> {
+    loader: &'a mut CrateLoader,
+    deriving_hash_type_parameter: bool,
+}
+
 pub fn expand_crate(parse_sess: @parse::ParseSess,
-                    loader: &mut CrateLoader,
+                    cfg: ExpansionConfig,
                     c: Crate) -> Crate {
-    let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), loader);
+    let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg);
     let mut expander = MacroExpander {
         extsbox: syntax_expander_table(),
         cx: &mut cx,
@@ -995,7 +1000,11 @@ mod test {
             Vec::new(),sess);
         // should fail:
         let mut loader = ErrLoader;
-        expand_crate(sess,&mut loader,crate_ast);
+        let cfg = ::syntax::ext::expand::ExpansionConfig {
+            loader: &mut loader,
+            deriving_hash_type_parameter: false,
+        };
+        expand_crate(sess,cfg,crate_ast);
     }
 
     // make sure that macros can leave scope for modules
@@ -1010,7 +1019,11 @@ mod test {
             Vec::new(),sess);
         // should fail:
         let mut loader = ErrLoader;
-        expand_crate(sess,&mut loader,crate_ast);
+        let cfg = ::syntax::ext::expand::ExpansionConfig {
+            loader: &mut loader,
+            deriving_hash_type_parameter: false,
+        };
+        expand_crate(sess,cfg,crate_ast);
     }
 
     // macro_escape modules shouldn't cause macros to leave scope
@@ -1024,7 +1037,11 @@ mod test {
             Vec::new(), sess);
         // should fail:
         let mut loader = ErrLoader;
-        expand_crate(sess, &mut loader, crate_ast);
+        let cfg = ::syntax::ext::expand::ExpansionConfig {
+            loader: &mut loader,
+            deriving_hash_type_parameter: false,
+        };
+        expand_crate(sess, cfg, crate_ast);
     }
 
     #[test] fn test_contains_flatten (){
@@ -1062,7 +1079,11 @@ mod test {
         let (crate_ast,ps) = string_to_crate_and_sess(crate_str);
         // the cfg argument actually does matter, here...
         let mut loader = ErrLoader;
-        expand_crate(ps,&mut loader,crate_ast)
+        let cfg = ::syntax::ext::expand::ExpansionConfig {
+            loader: &mut loader,
+            deriving_hash_type_parameter: false,
+        };
+        expand_crate(ps,cfg,crate_ast)
     }
 
     //fn expand_and_resolve(crate_str: @str) -> ast::crate {
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index 0d7e54bb69d..0d465e8475c 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -26,7 +26,7 @@ This API is completely unstable and subject to change.
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://static.rust-lang.org/doc/master")];
 
-#[feature(macro_rules, globs, managed_boxes)];
+#[feature(macro_rules, globs, managed_boxes, default_type_params)];
 #[allow(unknown_features)];// Note: remove it after a snapshot.
 #[feature(quote)];