Skip to content

Commit 06b2a50

Browse files
authored
[rust-compiler] Use rustc-hash FxHasher for all maps and sets (#36811)
Swaps the default hashers across the Rust compiler crates for rustc-hash's faster `FxHasher`. ## Why `FxHasher` is a simple, fast, non-cryptographic hasher. std's default (SipHash) is DoS-resistant but heavy — the compiler keys maps/sets almost entirely on small integer IDs (`IdentifierId`, `BlockId`, `ScopeId`, …) where that protection buys nothing. Switching gives: - **Performance** — faster hashing on the hot ID-keyed maps/sets used throughout the passes. - **Slight binary size reduction** — drops the heavy SipHash hasher pulled in by std's `HashMap`/`HashSet`. ## Changes - `std::collections::HashMap`/`HashSet` → `rustc_hash::FxHashMap`/`FxHashSet` - `indexmap` `IndexMap`/`IndexSet` now use `FxBuildHasher`, inlined as `IndexMap<K, V, FxBuildHasher>` (no `FxIndexMap` type aliases) - `rustc-hash = "2"` added to all 12 crate manifests - `rustc_hash`/`indexmap` imports consolidated into single brace imports at the top of each file The change is serde-neutral: `FxHashMap` and `IndexMap<_, _, FxBuildHasher>` serialize to byte-identical JSON, and `IndexMap` keeps insertion order. `cargo check`, `cargo fmt --check`, and `cargo test` all pass with no warnings.
1 parent 53b5c3c commit 06b2a50

89 files changed

Lines changed: 1036 additions & 961 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

compiler/Cargo.lock

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compiler/crates/react_compiler/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,6 @@ react_compiler_ssa = { path = "../react_compiler_ssa" }
1515
react_compiler_typeinference = { path = "../react_compiler_typeinference" }
1616
react_compiler_validation = { path = "../react_compiler_validation" }
1717
indexmap = "2"
18+
rustc-hash = "2"
1819
serde = { version = "1", features = ["derive"] }
1920
serde_json = { version = "1", features = ["raw_value"] }

compiler/crates/react_compiler/src/entrypoint/imports.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*/
7-
use std::collections::{HashMap, HashSet};
7+
use rustc_hash::{FxHashMap, FxHashSet};
88

99
use react_compiler_ast::common::BaseNode;
1010
use react_compiler_ast::declarations::{
@@ -72,9 +72,9 @@ pub struct ProgramContext {
7272
pub debug_enabled: bool,
7373

7474
// Internal state
75-
already_compiled: HashSet<u32>,
76-
known_referenced_names: HashSet<String>,
77-
imports: HashMap<String, HashMap<String, NonLocalImportSpecifier>>,
75+
already_compiled: FxHashSet<u32>,
76+
known_referenced_names: FxHashSet<String>,
77+
imports: FxHashMap<String, FxHashMap<String, NonLocalImportSpecifier>>,
7878
}
7979

8080
impl ProgramContext {
@@ -104,9 +104,9 @@ impl ProgramContext {
104104
renames: Vec::new(),
105105
timing: TimingData::new(profiling),
106106
debug_enabled,
107-
already_compiled: HashSet::new(),
108-
known_referenced_names: HashSet::new(),
109-
imports: HashMap::new(),
107+
already_compiled: FxHashSet::default(),
108+
known_referenced_names: FxHashSet::default(),
109+
imports: FxHashMap::default(),
110110
}
111111
}
112112

@@ -230,13 +230,13 @@ impl ProgramContext {
230230
}
231231

232232
/// Get the set of known referenced names for seeding per-function Environment UID generation.
233-
pub fn known_referenced_names(&self) -> &HashSet<String> {
233+
pub fn known_referenced_names(&self) -> &FxHashSet<String> {
234234
&self.known_referenced_names
235235
}
236236

237237
/// Merge UID names generated during a function compilation back into the program context,
238238
/// so subsequent function compilations avoid collisions.
239-
pub fn merge_uid_known_names(&mut self, names: &HashSet<String>) {
239+
pub fn merge_uid_known_names(&mut self, names: &FxHashSet<String>) {
240240
self.known_referenced_names.extend(names.iter().cloned());
241241
}
242242

@@ -259,7 +259,7 @@ impl ProgramContext {
259259
}
260260

261261
/// Get an immutable view of the generated imports.
262-
pub fn imports(&self) -> &HashMap<String, HashMap<String, NonLocalImportSpecifier>> {
262+
pub fn imports(&self) -> &FxHashMap<String, FxHashMap<String, NonLocalImportSpecifier>> {
263263
&self.imports
264264
}
265265
}
@@ -274,7 +274,7 @@ pub fn validate_restricted_imports(
274274
Some(b) if !b.is_empty() => b,
275275
_ => return None,
276276
};
277-
let restricted: HashSet<&str> = blocklisted.iter().map(|s| s.as_str()).collect();
277+
let restricted: FxHashSet<&str> = blocklisted.iter().map(|s| s.as_str()).collect();
278278
let mut error = CompilerError::new();
279279

280280
for stmt in &program.body {
@@ -326,7 +326,7 @@ pub fn add_imports_to_program(program: &mut Program, context: &ProgramContext) {
326326
}
327327

328328
// Collect existing non-namespaced imports by module name
329-
let existing_import_indices: HashMap<String, usize> = program
329+
let existing_import_indices: FxHashMap<String, usize> = program
330330
.body
331331
.iter()
332332
.enumerate()

compiler/crates/react_compiler/src/entrypoint/pipeline.rs

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@
88
//! Analogous to TS `Pipeline.ts` (`compileFn` → `run` → `runWithEnvironment`).
99
//! Currently runs BuildHIR (lowering) and PruneMaybeThrows.
1010
11+
use indexmap::IndexMap;
1112
use react_compiler_ast::scope::ScopeInfo;
1213
use react_compiler_diagnostics::CompilerError;
1314
use react_compiler_hir::ReactFunctionType;
1415
use react_compiler_hir::environment::Environment;
1516
use react_compiler_hir::environment::OutputMode;
1617
use react_compiler_hir::environment_config::EnvironmentConfig;
1718
use react_compiler_lowering::FunctionNode;
19+
use rustc_hash::{FxBuildHasher, FxHashMap};
1820

1921
use super::compile_result::CodegenFunction;
2022
use super::compile_result::CompilerErrorDetailInfo;
@@ -1229,25 +1231,23 @@ pub fn compile_outlined_fn(
12291231
fn build_outlined_scope_info(
12301232
func: &mut react_compiler_ast::statements::FunctionDeclaration,
12311233
) -> react_compiler_ast::scope::ScopeInfo {
1232-
use std::collections::HashMap;
1233-
12341234
use react_compiler_ast::scope::*;
12351235

12361236
let mut pos: u32 = 1; // reserve 0 for the function itself
12371237
func.base.start = Some(0);
12381238

1239-
let mut fn_bindings: HashMap<String, BindingId> = HashMap::new();
1239+
let mut fn_bindings: FxHashMap<String, BindingId> = FxHashMap::default();
12401240
let mut bindings_list: Vec<BindingData> = Vec::new();
1241-
let mut ref_to_binding: indexmap::IndexMap<u32, BindingId> = indexmap::IndexMap::new();
1241+
let mut ref_to_binding: IndexMap<u32, BindingId, FxBuildHasher> = IndexMap::default();
12421242

12431243
// Helper to add a binding
12441244
let _add_binding =
12451245
|name: &str,
12461246
kind: BindingKind,
12471247
p: u32,
1248-
fn_bindings: &mut HashMap<String, BindingId>,
1248+
fn_bindings: &mut FxHashMap<String, BindingId>,
12491249
bindings_list: &mut Vec<BindingData>,
1250-
ref_to_binding: &mut indexmap::IndexMap<u32, BindingId>| {
1250+
ref_to_binding: &mut IndexMap<u32, BindingId, FxBuildHasher>| {
12511251
if fn_bindings.contains_key(name) {
12521252
// Already exists, just add reference
12531253
let bid = fn_bindings[name];
@@ -1296,7 +1296,7 @@ fn build_outlined_scope_info(
12961296
id: ScopeId(0),
12971297
parent: None,
12981298
kind: ScopeKind::Program,
1299-
bindings: HashMap::new(),
1299+
bindings: FxHashMap::default(),
13001300
};
13011301
let fn_scope = ScopeData {
13021302
id: ScopeId(1),
@@ -1305,21 +1305,21 @@ fn build_outlined_scope_info(
13051305
bindings: fn_bindings,
13061306
};
13071307

1308-
let mut node_to_scope: HashMap<u32, ScopeId> = HashMap::new();
1308+
let mut node_to_scope: FxHashMap<u32, ScopeId> = FxHashMap::default();
13091309
node_to_scope.insert(0, ScopeId(1));
13101310

13111311
// Mirror position maps into node-ID maps for outlined functions
1312-
let mut node_id_to_scope: HashMap<u32, ScopeId> = HashMap::new();
1312+
let mut node_id_to_scope: FxHashMap<u32, ScopeId> = FxHashMap::default();
13131313
node_id_to_scope.insert(0, ScopeId(1));
1314-
let ref_node_id_to_binding: indexmap::IndexMap<u32, BindingId> =
1314+
let ref_node_id_to_binding: IndexMap<u32, BindingId, FxBuildHasher> =
13151315
ref_to_binding.iter().map(|(&k, &v)| (k, v)).collect();
13161316

13171317
ScopeInfo {
13181318
scopes: vec![program_scope, fn_scope],
13191319
bindings: bindings_list,
13201320
node_to_scope,
1321-
node_to_scope_end: HashMap::new(),
1322-
reference_to_binding: indexmap::IndexMap::new(),
1321+
node_to_scope_end: FxHashMap::default(),
1322+
reference_to_binding: IndexMap::default(),
13231323
ref_node_id_to_binding,
13241324
node_id_to_scope,
13251325
program_scope: ScopeId(0),
@@ -1331,9 +1331,9 @@ fn outlined_assign_pattern_positions(
13311331
pattern: &mut react_compiler_ast::patterns::PatternLike,
13321332
pos: &mut u32,
13331333
kind: react_compiler_ast::scope::BindingKind,
1334-
fn_bindings: &mut std::collections::HashMap<String, react_compiler_ast::scope::BindingId>,
1334+
fn_bindings: &mut rustc_hash::FxHashMap<String, react_compiler_ast::scope::BindingId>,
13351335
bindings_list: &mut Vec<react_compiler_ast::scope::BindingData>,
1336-
ref_to_binding: &mut indexmap::IndexMap<u32, react_compiler_ast::scope::BindingId>,
1336+
ref_to_binding: &mut IndexMap<u32, react_compiler_ast::scope::BindingId, FxBuildHasher>,
13371337
) {
13381338
use react_compiler_ast::patterns::PatternLike;
13391339
use react_compiler_ast::scope::*;
@@ -1432,9 +1432,9 @@ fn outlined_assign_pattern_positions(
14321432
fn outlined_assign_stmt_positions(
14331433
stmt: &mut react_compiler_ast::statements::Statement,
14341434
pos: &mut u32,
1435-
fn_bindings: &mut std::collections::HashMap<String, react_compiler_ast::scope::BindingId>,
1435+
fn_bindings: &mut rustc_hash::FxHashMap<String, react_compiler_ast::scope::BindingId>,
14361436
bindings_list: &mut Vec<react_compiler_ast::scope::BindingData>,
1437-
ref_to_binding: &mut indexmap::IndexMap<u32, react_compiler_ast::scope::BindingId>,
1437+
ref_to_binding: &mut IndexMap<u32, react_compiler_ast::scope::BindingId, FxBuildHasher>,
14381438
) {
14391439
use react_compiler_ast::statements::Statement;
14401440

@@ -1477,8 +1477,8 @@ fn outlined_assign_stmt_positions(
14771477
fn outlined_assign_expr_positions(
14781478
expr: &mut react_compiler_ast::expressions::Expression,
14791479
pos: &mut u32,
1480-
fn_bindings: &std::collections::HashMap<String, react_compiler_ast::scope::BindingId>,
1481-
ref_to_binding: &mut indexmap::IndexMap<u32, react_compiler_ast::scope::BindingId>,
1480+
fn_bindings: &rustc_hash::FxHashMap<String, react_compiler_ast::scope::BindingId>,
1481+
ref_to_binding: &mut IndexMap<u32, react_compiler_ast::scope::BindingId, FxBuildHasher>,
14821482
) {
14831483
use react_compiler_ast::expressions::*;
14841484

@@ -1538,8 +1538,8 @@ fn outlined_assign_expr_positions(
15381538
fn outlined_assign_jsx_name_positions(
15391539
name: &mut react_compiler_ast::jsx::JSXElementName,
15401540
pos: &mut u32,
1541-
fn_bindings: &std::collections::HashMap<String, react_compiler_ast::scope::BindingId>,
1542-
ref_to_binding: &mut indexmap::IndexMap<u32, react_compiler_ast::scope::BindingId>,
1541+
fn_bindings: &rustc_hash::FxHashMap<String, react_compiler_ast::scope::BindingId>,
1542+
ref_to_binding: &mut IndexMap<u32, react_compiler_ast::scope::BindingId, FxBuildHasher>,
15431543
) {
15441544
match name {
15451545
react_compiler_ast::jsx::JSXElementName::JSXIdentifier(id) => {
@@ -1561,8 +1561,8 @@ fn outlined_assign_jsx_name_positions(
15611561
fn outlined_assign_jsx_member_positions(
15621562
member: &mut react_compiler_ast::jsx::JSXMemberExpression,
15631563
pos: &mut u32,
1564-
fn_bindings: &std::collections::HashMap<String, react_compiler_ast::scope::BindingId>,
1565-
ref_to_binding: &mut indexmap::IndexMap<u32, react_compiler_ast::scope::BindingId>,
1564+
fn_bindings: &rustc_hash::FxHashMap<String, react_compiler_ast::scope::BindingId>,
1565+
ref_to_binding: &mut IndexMap<u32, react_compiler_ast::scope::BindingId, FxBuildHasher>,
15661566
) {
15671567
match &mut *member.object {
15681568
react_compiler_ast::jsx::JSXMemberExprObject::JSXIdentifier(id) => {
@@ -1583,8 +1583,8 @@ fn outlined_assign_jsx_member_positions(
15831583
fn outlined_assign_jsx_val_positions(
15841584
val: &mut react_compiler_ast::jsx::JSXAttributeValue,
15851585
pos: &mut u32,
1586-
fn_bindings: &std::collections::HashMap<String, react_compiler_ast::scope::BindingId>,
1587-
ref_to_binding: &mut indexmap::IndexMap<u32, react_compiler_ast::scope::BindingId>,
1586+
fn_bindings: &rustc_hash::FxHashMap<String, react_compiler_ast::scope::BindingId>,
1587+
ref_to_binding: &mut IndexMap<u32, react_compiler_ast::scope::BindingId, FxBuildHasher>,
15881588
) {
15891589
match val {
15901590
react_compiler_ast::jsx::JSXAttributeValue::JSXExpressionContainer(c) => {
@@ -1608,8 +1608,8 @@ fn outlined_assign_jsx_val_positions(
16081608
fn outlined_assign_jsx_child_positions(
16091609
child: &mut react_compiler_ast::jsx::JSXChild,
16101610
pos: &mut u32,
1611-
fn_bindings: &std::collections::HashMap<String, react_compiler_ast::scope::BindingId>,
1612-
ref_to_binding: &mut indexmap::IndexMap<u32, react_compiler_ast::scope::BindingId>,
1611+
fn_bindings: &rustc_hash::FxHashMap<String, react_compiler_ast::scope::BindingId>,
1612+
ref_to_binding: &mut IndexMap<u32, react_compiler_ast::scope::BindingId, FxBuildHasher>,
16131613
) {
16141614
match child {
16151615
react_compiler_ast::jsx::JSXChild::JSXExpressionContainer(c) => {

compiler/crates/react_compiler/src/entrypoint/program.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@
1414
//! 5. Processing each function through the compilation pipeline
1515
//! 6. Applying compiled functions back to the AST
1616
17-
use std::collections::HashMap;
18-
use std::collections::HashSet;
17+
use rustc_hash::{FxHashMap, FxHashSet};
1918

2019
use react_compiler_ast::File;
2120
use react_compiler_ast::Program;
@@ -2084,9 +2083,9 @@ struct CompiledFnForReplacement {
20842083
fn get_functions_referenced_before_declaration(
20852084
program: &Program,
20862085
compiled_fns: &[CompiledFnForReplacement],
2087-
) -> HashSet<u32> {
2086+
) -> FxHashSet<u32> {
20882087
// Collect function names and their node_ids for compiled FunctionDeclarations
2089-
let mut fn_names: HashMap<String, u32> = HashMap::new();
2088+
let mut fn_names: FxHashMap<String, u32> = FxHashMap::default();
20902089
for compiled in compiled_fns {
20912090
if compiled.original_kind == OriginalFnKind::FunctionDeclaration {
20922091
if let Some(ref name) = compiled.fn_name {
@@ -2098,10 +2097,10 @@ fn get_functions_referenced_before_declaration(
20982097
}
20992098

21002099
if fn_names.is_empty() {
2101-
return HashSet::new();
2100+
return FxHashSet::default();
21022101
}
21032102

2104-
let mut referenced_before_decl: HashSet<u32> = HashSet::new();
2103+
let mut referenced_before_decl: FxHashSet<u32> = FxHashSet::default();
21052104

21062105
// Walk through program body in order. For each statement, check if it references
21072106
// any of the function names before the function's declaration.
@@ -2597,7 +2596,7 @@ fn apply_compiled_functions(
25972596
let referenced_before_decl = if has_gating {
25982597
get_functions_referenced_before_declaration(program, compiled_fns)
25992598
} else {
2600-
HashSet::new()
2599+
FxHashSet::default()
26012600
};
26022601

26032602
// For gated functions, we need to clone the original function expressions

0 commit comments

Comments
 (0)