From 5886a2e7e5b216588db59a15458d160556d4b140 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Sat, 11 Jan 2025 12:59:09 +0900 Subject: [PATCH 01/21] Dep on thread_local --- Cargo.toml | 1 + .../swc_ecma_transforms_optimization/Cargo.toml | 17 +++++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9953d5c4ba9a..7602e7b74da0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -122,6 +122,7 @@ resolver = "2" wasm-bindgen-futures = "0.4.41" wasmer = { version = "=5.0.5-rc1", default-features = false } wasmer-wasix = { version = "0.35.0", default-features = false } +thread_local = "1.1.8" [profile.release] lto = true diff --git a/crates/swc_ecma_transforms_optimization/Cargo.toml b/crates/swc_ecma_transforms_optimization/Cargo.toml index 18c65ac5dbc3..84c33d6c7e72 100644 --- a/crates/swc_ecma_transforms_optimization/Cargo.toml +++ b/crates/swc_ecma_transforms_optimization/Cargo.toml @@ -22,14 +22,15 @@ concurrent = [ debug = [] [dependencies] -dashmap = { workspace = true } -indexmap = { workspace = true } -once_cell = { workspace = true } -petgraph = { workspace = true } -rayon = { workspace = true, optional = true } -rustc-hash = { workspace = true } -serde_json = { workspace = true } -tracing = { workspace = true } +dashmap = { workspace = true } +indexmap = { workspace = true } +once_cell = { workspace = true } +petgraph = { workspace = true } +rayon = { workspace = true, optional = true } +rustc-hash = { workspace = true } +serde_json = { workspace = true } +thread_local = { workspace = true } +tracing = { workspace = true } swc_atoms = { version = "3.0.3", path = "../swc_atoms" } swc_common = { version = "5.0.0", path = "../swc_common" } From 8af69587b4aa75774b1c24d581ff62a4e86811a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Sat, 11 Jan 2025 12:59:13 +0900 Subject: [PATCH 02/21] cargo lockfile --- Cargo.lock | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5ac7b3b27972..8dee3ab4925e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5542,6 +5542,7 @@ dependencies = [ "swc_ecma_visit", "swc_fast_graph", "testing", + "thread_local", "tracing", ] @@ -6413,9 +6414,9 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.7" +version = "1.1.8" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if", "once_cell", From 0a29dd8b7163148c77e4b979f070301d478dc474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Sun, 12 Jan 2025 12:10:18 +0900 Subject: [PATCH 03/21] par --- .../src/simplify/dce/mod.rs | 92 ++++++++++++++----- 1 file changed, 69 insertions(+), 23 deletions(-) diff --git a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs index 985027e61fd4..49c966373166 100644 --- a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs +++ b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs @@ -1,4 +1,4 @@ -use std::{borrow::Cow, sync::Arc}; +use std::{borrow::Cow, cell::RefCell, sync::Arc}; use indexmap::IndexSet; use petgraph::{algo::tarjan_scc, Direction::Incoming}; @@ -22,6 +22,7 @@ use swc_ecma_visit::{ noop_visit_mut_type, noop_visit_type, visit_mut_pass, Visit, VisitMut, VisitMutWith, VisitWith, }; use swc_fast_graph::digraph::FastDiGraphMap; +use thread_local::ThreadLocal; use tracing::{debug, span, Level}; use crate::debug_assert_valid; @@ -113,6 +114,7 @@ struct Data { graph: FastDiGraphMap, /// Entrypoints. entries: FxHashSet, + entry_ids: FxHashSet, graph_ix: IndexSet, } @@ -213,7 +215,7 @@ struct Analyzer<'a> { config: &'a Config, in_var_decl: bool, scope: Scope<'a>, - data: &'a mut Data, + data: Arc>>, cur_class_id: Option, cur_fn_id: Option, } @@ -273,7 +275,7 @@ impl Analyzer<'_> { let mut v = Analyzer { scope: child, - data: self.data, + data: self.data.clone(), cur_fn_id: self.cur_fn_id.clone(), cur_class_id: self.cur_class_id.clone(), ..*self @@ -290,7 +292,13 @@ impl Analyzer<'_> { // If we found eval, mark all declarations in scope and upper as used if child_scope.found_direct_eval { for id in child_scope.bindings_affected_by_eval { - self.data.used_names.entry(id).or_default().usage += 1; + self.data + .get_or_default() + .borrow_mut() + .used_names + .entry(id) + .or_default() + .usage += 1; } self.scope.found_direct_eval = true; @@ -300,7 +308,13 @@ impl Analyzer<'_> { // Parameters for id in child_scope.bindings_affected_by_arguements { - self.data.used_names.entry(id).or_default().usage += 1; + self.data + .get_or_default() + .borrow_mut() + .used_names + .entry(id) + .or_default() + .usage += 1; } if !matches!(kind, ScopeKind::Fn) { @@ -326,16 +340,19 @@ impl Analyzer<'_> { } } + let mut data = self.data.get_or_default().borrow_mut(); + if self.scope.is_ast_path_empty() { // Add references from top level items into graph - let idx = self.data.node(&id); - self.data.entries.insert(idx); + let idx = data.node(&id); + data.entries.insert(idx); + data.entry_ids.insert(id.clone()); } else { let mut scope = Some(&self.scope); while let Some(s) = scope { for component in &s.ast_path { - self.data.add_dep_edge(component, &id, assign); + data.add_dep_edge(component, &id, assign); } if s.kind == ScopeKind::Fn && !s.ast_path.is_empty() { @@ -347,9 +364,9 @@ impl Analyzer<'_> { } if assign { - self.data.used_names.entry(id).or_default().assign += 1; + data.used_names.entry(id).or_default().assign += 1; } else { - self.data.used_names.entry(id).or_default().usage += 1; + data.used_names.entry(id).or_default().usage += 1; } } } @@ -635,11 +652,8 @@ impl TreeShaker { } // Abort if the variable is declared on top level scope. - let ix = self.data.graph_ix.get_index_of(&name); - if let Some(ix) = ix { - if self.data.entries.contains(&(ix as u32)) { - return false; - } + if self.data.entry_ids.contains(&name) { + return false; } } @@ -902,21 +916,37 @@ impl VisitMut for TreeShaker { self.bindings = Arc::new(collect_decls(&*m)) } - let mut data = Default::default(); + let data: Arc>> = Default::default(); { let mut analyzer = Analyzer { config: &self.config, in_var_decl: false, scope: Default::default(), - data: &mut data, + data: data.clone(), cur_class_id: Default::default(), cur_fn_id: Default::default(), }; m.visit_with(&mut analyzer); } - data.subtract_cycles(); - self.data = Arc::new(data); + let data = Arc::try_unwrap(data) + .map_err(|_| {}) + .unwrap() + .into_iter() + .map(|d| d.into_inner()) + .map(|mut data| { + data.subtract_cycles(); + data + }) + .collect::>(); + let mut merged = Data::default(); + + for data in data { + merged.used_names.extend(data.used_names); + merged.entry_ids.extend(data.entry_ids); + } + + self.data = Arc::new(merged); HELPERS.set(&Helpers::new(true), || { m.visit_mut_children_with(self); @@ -965,21 +995,37 @@ impl VisitMut for TreeShaker { self.bindings = Arc::new(collect_decls(&*m)) } - let mut data = Default::default(); + let data: Arc>> = Default::default(); { let mut analyzer = Analyzer { config: &self.config, in_var_decl: false, scope: Default::default(), - data: &mut data, + data: data.clone(), cur_class_id: Default::default(), cur_fn_id: Default::default(), }; m.visit_with(&mut analyzer); } - data.subtract_cycles(); - self.data = Arc::new(data); + let data = Arc::try_unwrap(data) + .map_err(|_| {}) + .unwrap() + .into_iter() + .map(|d| d.into_inner()) + .map(|mut data| { + data.subtract_cycles(); + data + }) + .collect::>(); + let mut merged = Data::default(); + + for data in data { + merged.used_names.extend(data.used_names); + merged.entry_ids.extend(data.entry_ids); + } + + self.data = Arc::new(merged); HELPERS.set(&Helpers::new(true), || { m.visit_mut_children_with(self); From 36f6076169304187843eab2f08f9fc1adb55f65c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Sun, 12 Jan 2025 12:21:39 +0900 Subject: [PATCH 04/21] HELPERS.set(&Helpers::new(true), || { --- .../src/simplify/dce/mod.rs | 185 +++++++++++------- 1 file changed, 115 insertions(+), 70 deletions(-) diff --git a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs index 49c966373166..9659e4a7a7fb 100644 --- a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs +++ b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs @@ -13,7 +13,7 @@ use swc_common::{ use swc_ecma_ast::*; use swc_ecma_transforms_base::{ helpers::{Helpers, HELPERS}, - perf::{cpu_count, ParVisitMut, Parallel}, + perf::{cpu_count, ParVisit, ParVisitMut, Parallel}, }; use swc_ecma_utils::{ collect_decls, find_pat_ids, ExprCtx, ExprExt, IsEmpty, ModuleItemLike, StmtLike, Value::Known, @@ -220,6 +220,23 @@ struct Analyzer<'a> { cur_fn_id: Option, } +impl Parallel for Analyzer<'_> { + fn create(&self) -> Self { + Self { + data: self.data.clone(), + scope: Scope { + parent: self.scope.parent, + ..Default::default() + }, + cur_class_id: self.cur_class_id.clone(), + cur_fn_id: self.cur_fn_id.clone(), + ..*self + } + } + + fn merge(&mut self, _: Self) {} +} + #[derive(Debug, Default)] struct Scope<'a> { parent: Option<&'a Scope<'a>>, @@ -564,6 +581,34 @@ impl Visit for Analyzer<'_> { self.in_var_decl = old; } + + fn visit_opt_vec_expr_or_spreads(&mut self, n: &[Option]) { + self.visit_par(cpu_count(), n); + } + + fn visit_prop_or_spreads(&mut self, n: &[PropOrSpread]) { + self.visit_par(cpu_count(), n); + } + + fn visit_expr_or_spreads(&mut self, n: &[ExprOrSpread]) { + self.visit_par(cpu_count(), n); + } + + fn visit_exprs(&mut self, n: &[Box]) { + self.visit_par(cpu_count(), n); + } + + fn visit_stmts(&mut self, n: &[Stmt]) { + self.visit_par(cpu_count(), n); + } + + fn visit_module_items(&mut self, n: &[ModuleItem]) { + self.visit_par(cpu_count(), n); + } + + fn visit_var_declarators(&mut self, n: &[VarDeclarator]) { + self.visit_par(cpu_count(), n); + } } impl Repeated for TreeShaker { @@ -908,47 +953,47 @@ impl VisitMut for TreeShaker { } fn visit_mut_module(&mut self, m: &mut Module) { - debug_assert_valid(m); + HELPERS.set(&Helpers::new(true), || { + debug_assert_valid(m); - let _tracing = span!(Level::ERROR, "tree-shaker", pass = self.pass).entered(); + let _tracing = span!(Level::ERROR, "tree-shaker", pass = self.pass).entered(); - if self.bindings.is_empty() { - self.bindings = Arc::new(collect_decls(&*m)) - } + if self.bindings.is_empty() { + self.bindings = Arc::new(collect_decls(&*m)) + } - let data: Arc>> = Default::default(); + let data: Arc>> = Default::default(); - { - let mut analyzer = Analyzer { - config: &self.config, - in_var_decl: false, - scope: Default::default(), - data: data.clone(), - cur_class_id: Default::default(), - cur_fn_id: Default::default(), - }; - m.visit_with(&mut analyzer); - } - let data = Arc::try_unwrap(data) - .map_err(|_| {}) - .unwrap() - .into_iter() - .map(|d| d.into_inner()) - .map(|mut data| { - data.subtract_cycles(); - data - }) - .collect::>(); - let mut merged = Data::default(); - - for data in data { - merged.used_names.extend(data.used_names); - merged.entry_ids.extend(data.entry_ids); - } + { + let mut analyzer = Analyzer { + config: &self.config, + in_var_decl: false, + scope: Default::default(), + data: data.clone(), + cur_class_id: Default::default(), + cur_fn_id: Default::default(), + }; + m.visit_with(&mut analyzer); + } + let data = Arc::try_unwrap(data) + .map_err(|_| {}) + .unwrap() + .into_iter() + .map(|d| d.into_inner()) + .map(|mut data| { + data.subtract_cycles(); + data + }) + .collect::>(); + let mut merged = Data::default(); + + for data in data { + merged.used_names.extend(data.used_names); + merged.entry_ids.extend(data.entry_ids); + } - self.data = Arc::new(merged); + self.data = Arc::new(merged); - HELPERS.set(&Helpers::new(true), || { m.visit_mut_children_with(self); }) } @@ -989,45 +1034,45 @@ impl VisitMut for TreeShaker { } fn visit_mut_script(&mut self, m: &mut Script) { - let _tracing = span!(Level::ERROR, "tree-shaker", pass = self.pass).entered(); + HELPERS.set(&Helpers::new(true), || { + let _tracing = span!(Level::ERROR, "tree-shaker", pass = self.pass).entered(); - if self.bindings.is_empty() { - self.bindings = Arc::new(collect_decls(&*m)) - } + if self.bindings.is_empty() { + self.bindings = Arc::new(collect_decls(&*m)) + } - let data: Arc>> = Default::default(); + let data: Arc>> = Default::default(); - { - let mut analyzer = Analyzer { - config: &self.config, - in_var_decl: false, - scope: Default::default(), - data: data.clone(), - cur_class_id: Default::default(), - cur_fn_id: Default::default(), - }; - m.visit_with(&mut analyzer); - } - let data = Arc::try_unwrap(data) - .map_err(|_| {}) - .unwrap() - .into_iter() - .map(|d| d.into_inner()) - .map(|mut data| { - data.subtract_cycles(); - data - }) - .collect::>(); - let mut merged = Data::default(); - - for data in data { - merged.used_names.extend(data.used_names); - merged.entry_ids.extend(data.entry_ids); - } + { + let mut analyzer = Analyzer { + config: &self.config, + in_var_decl: false, + scope: Default::default(), + data: data.clone(), + cur_class_id: Default::default(), + cur_fn_id: Default::default(), + }; + m.visit_with(&mut analyzer); + } + let data = Arc::try_unwrap(data) + .map_err(|_| {}) + .unwrap() + .into_iter() + .map(|d| d.into_inner()) + .map(|mut data| { + data.subtract_cycles(); + data + }) + .collect::>(); + let mut merged = Data::default(); - self.data = Arc::new(merged); + for data in data { + merged.used_names.extend(data.used_names); + merged.entry_ids.extend(data.entry_ids); + } + + self.data = Arc::new(merged); - HELPERS.set(&Helpers::new(true), || { m.visit_mut_children_with(self); }) } From 8ad456b72faca1c9e0be8dab4e53f61c1c41f427 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Sun, 12 Jan 2025 14:16:23 +0900 Subject: [PATCH 05/21] FxHashSet --- .../src/simplify/dce/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs index 9659e4a7a7fb..2c2eba38a996 100644 --- a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs +++ b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs @@ -1,11 +1,11 @@ -use std::{borrow::Cow, cell::RefCell, sync::Arc}; +use std::{borrow::Cow, cell::RefCell, hash::BuildHasherDefault, sync::Arc}; use indexmap::IndexSet; use petgraph::{algo::tarjan_scc, Direction::Incoming}; -use rustc_hash::FxHashSet; +use rustc_hash::{FxHashMap, FxHashSet, FxHasher}; use swc_atoms::{atom, JsWord}; use swc_common::{ - collections::{AHashMap, AHashSet, ARandomState}, + collections::AHashSet, pass::{CompilerPass, Repeated}, util::take::Take, Mark, SyntaxContext, DUMMY_SP, @@ -105,7 +105,7 @@ impl CompilerPass for TreeShaker { #[derive(Default)] struct Data { - used_names: AHashMap, + used_names: FxHashMap, /// Variable usage graph /// @@ -116,7 +116,7 @@ struct Data { entries: FxHashSet, entry_ids: FxHashSet, - graph_ix: IndexSet, + graph_ix: IndexSet>, } impl Data { From 7cdd78907ab5427ad1b9d1f2909f3789e32bcc18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Sun, 12 Jan 2025 16:56:09 +0900 Subject: [PATCH 06/21] merge_data --- .../src/simplify/dce/mod.rs | 57 ++++++++----------- 1 file changed, 23 insertions(+), 34 deletions(-) diff --git a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs index 2c2eba38a996..07ae66479818 100644 --- a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs +++ b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs @@ -975,24 +975,8 @@ impl VisitMut for TreeShaker { }; m.visit_with(&mut analyzer); } - let data = Arc::try_unwrap(data) - .map_err(|_| {}) - .unwrap() - .into_iter() - .map(|d| d.into_inner()) - .map(|mut data| { - data.subtract_cycles(); - data - }) - .collect::>(); - let mut merged = Data::default(); - - for data in data { - merged.used_names.extend(data.used_names); - merged.entry_ids.extend(data.entry_ids); - } - self.data = Arc::new(merged); + self.data = Arc::new(merge_data(data)); m.visit_mut_children_with(self); }) @@ -1054,24 +1038,8 @@ impl VisitMut for TreeShaker { }; m.visit_with(&mut analyzer); } - let data = Arc::try_unwrap(data) - .map_err(|_| {}) - .unwrap() - .into_iter() - .map(|d| d.into_inner()) - .map(|mut data| { - data.subtract_cycles(); - data - }) - .collect::>(); - let mut merged = Data::default(); - - for data in data { - merged.used_names.extend(data.used_names); - merged.entry_ids.extend(data.entry_ids); - } - self.data = Arc::new(merged); + self.data = Arc::new(merge_data(data)); m.visit_mut_children_with(self); }) @@ -1206,6 +1174,27 @@ impl VisitMut for TreeShaker { } } +fn merge_data(data: Arc>>) -> Data { + let data = Arc::try_unwrap(data) + .map_err(|_| {}) + .unwrap() + .into_iter() + .map(|d| d.into_inner()) + .map(|mut data| { + data.subtract_cycles(); + data + }) + .collect::>(); + let mut merged = Data::default(); + + for data in data { + merged.used_names.extend(data.used_names); + merged.entry_ids.extend(data.entry_ids); + } + + merged +} + impl Scope<'_> { /// Returns true if it's not in a function or class. fn is_ast_path_empty(&self) -> bool { From 875ad9bef2df6b1a18975e37aba4fb5c34bc86de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Mon, 13 Jan 2025 07:10:27 +0900 Subject: [PATCH 07/21] Parallel for Analyzer --- .../src/simplify/dce/mod.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs index 07ae66479818..413b23858133 100644 --- a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs +++ b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs @@ -226,7 +226,10 @@ impl Parallel for Analyzer<'_> { data: self.data.clone(), scope: Scope { parent: self.scope.parent, - ..Default::default() + ast_path: self.scope.ast_path.clone(), + bindings_affected_by_arguements: Default::default(), + bindings_affected_by_eval: Default::default(), + ..self.scope }, cur_class_id: self.cur_class_id.clone(), cur_fn_id: self.cur_fn_id.clone(), @@ -234,7 +237,16 @@ impl Parallel for Analyzer<'_> { } } - fn merge(&mut self, _: Self) {} + fn merge(&mut self, other: Self) { + self.scope.ast_path = other.scope.ast_path; + + self.scope + .bindings_affected_by_eval + .extend(other.scope.bindings_affected_by_eval); + self.scope + .bindings_affected_by_arguements + .extend(other.scope.bindings_affected_by_arguements); + } } #[derive(Debug, Default)] @@ -254,7 +266,7 @@ struct Scope<'a> { ast_path: Vec, } -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] enum ScopeKind { Fn, ArrowFn, From 73499829a0c4d2ed5a328583108305a41573f365 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Mon, 13 Jan 2025 08:14:31 +0900 Subject: [PATCH 08/21] Dep on ahash --- crates/swc_ecma_transforms_optimization/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/swc_ecma_transforms_optimization/Cargo.toml b/crates/swc_ecma_transforms_optimization/Cargo.toml index 84c33d6c7e72..a472cab84bd5 100644 --- a/crates/swc_ecma_transforms_optimization/Cargo.toml +++ b/crates/swc_ecma_transforms_optimization/Cargo.toml @@ -22,6 +22,7 @@ concurrent = [ debug = [] [dependencies] +ahash = { workspace = true } dashmap = { workspace = true } indexmap = { workspace = true } once_cell = { workspace = true } From 67d6455266da5591d637725dbbfe6e878a0bc2a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Mon, 13 Jan 2025 08:14:36 +0900 Subject: [PATCH 09/21] cargo lockfile --- Cargo.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.lock b/Cargo.lock index 8dee3ab4925e..691322496e72 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5519,6 +5519,7 @@ dependencies = [ name = "swc_ecma_transforms_optimization" version = "7.1.1" dependencies = [ + "ahash", "dashmap 5.5.3", "indexmap 2.5.0", "once_cell", From 55ade6587ae19d3414cf15dcbd81b82361df0a67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Mon, 13 Jan 2025 08:27:37 +0900 Subject: [PATCH 10/21] fix --- .../src/simplify/dce/mod.rs | 162 ++++++++++++------ 1 file changed, 111 insertions(+), 51 deletions(-) diff --git a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs index 413b23858133..ef060329fb79 100644 --- a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs +++ b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs @@ -1,8 +1,16 @@ -use std::{borrow::Cow, cell::RefCell, hash::BuildHasherDefault, sync::Arc}; +use std::{ + borrow::Cow, + cell::RefCell, + collections::HashMap, + hash::{BuildHasher, Hash}, + mem::take, + sync::Arc, +}; -use indexmap::IndexSet; +use ahash::RandomState; +use indexmap::{IndexMap, IndexSet}; use petgraph::{algo::tarjan_scc, Direction::Incoming}; -use rustc_hash::{FxHashMap, FxHashSet, FxHasher}; +use rustc_hash::{FxHashMap, FxHashSet}; use swc_atoms::{atom, JsWord}; use swc_common::{ collections::AHashSet, @@ -107,56 +115,60 @@ impl CompilerPass for TreeShaker { struct Data { used_names: FxHashMap, - /// Variable usage graph - /// - /// We use `u32` because [FastDiGraphMap] stores types as `(N, 1 bit)` so if - /// we use u32 it fits into the cache line of cpu. - graph: FastDiGraphMap, + edges: IndexMap<(Id, Id), VarInfo, RandomState>, /// Entrypoints. - entries: FxHashSet, entry_ids: FxHashSet, - - graph_ix: IndexSet>, } impl Data { - fn node(&mut self, id: &Id) -> u32 { - self.graph_ix.get_index_of(id).unwrap_or_else(|| { - let ix = self.graph_ix.len(); - self.graph_ix.insert_full(id.clone()); - ix - }) as _ - } - /// Add an edge to dependency graph - fn add_dep_edge(&mut self, from: &Id, to: &Id, assign: bool) { - let from = self.node(from); - let to = self.node(to); - - match self.graph.edge_weight_mut(from, to) { - Some(info) => { + fn add_dep_edge(&mut self, from: Id, to: Id, assign: bool) { + match self.edges.entry((from, to)) { + indexmap::map::Entry::Occupied(mut info) => { if assign { - info.assign += 1; + info.get_mut().assign += 1; } else { - info.usage += 1; + info.get_mut().usage += 1; } } - None => { - self.graph.add_edge( - from, - to, - VarInfo { - usage: u32::from(!assign), - assign: u32::from(assign), - }, - ); + indexmap::map::Entry::Vacant(info) => { + info.insert(VarInfo { + usage: u32::from(!assign), + assign: u32::from(assign), + }); } - }; + } } /// Traverse the graph and subtract usages from `used_names`. fn subtract_cycles(&mut self) { - let cycles = tarjan_scc(&self.graph); + let edges = take(&mut self.edges); + + let mut graph = FastDiGraphMap::default(); + let mut graph_ix = IndexMap::::default(); + + let mut get_node = |id: Id| -> u32 { + let len = graph_ix.len(); + + let id = *graph_ix.entry(id).or_insert(len as u32); + + id as _ + }; + + let entries = self + .entry_ids + .iter() + .map(|id| get_node(id.clone())) + .collect::>(); + + for ((src, dst), info) in edges { + let src = get_node(src); + let dst = get_node(dst); + + graph.add_edge(src, dst, info); + } + + let cycles = tarjan_scc(&graph); 'c: for cycle in cycles { if cycle.len() == 1 { @@ -167,11 +179,11 @@ impl Data { // of cycle. for &node in &cycle { // It's referenced by an outer node. - if self.entries.contains(&node) { + if entries.contains(&node) { continue 'c; } - if self.graph.neighbors_directed(node, Incoming).any(|node| { + if graph.neighbors_directed(node, Incoming).any(|node| { // Node in cycle does not matter !cycle.contains(&node) }) { @@ -185,13 +197,13 @@ impl Data { continue; } - let id = self.graph_ix.get_index(j as _); + let id = graph_ix.get_index(j as _); let id = match id { - Some(id) => id, + Some(id) => id.0, None => continue, }; - if let Some(w) = self.graph.edge_weight(i, j) { + if let Some(w) = graph.edge_weight(i, j) { let e = self.used_names.entry(id.clone()).or_default(); e.usage -= w.usage; e.assign -= w.assign; @@ -373,15 +385,13 @@ impl Analyzer<'_> { if self.scope.is_ast_path_empty() { // Add references from top level items into graph - let idx = data.node(&id); - data.entries.insert(idx); data.entry_ids.insert(id.clone()); } else { let mut scope = Some(&self.scope); while let Some(s) = scope { for component in &s.ast_path { - data.add_dep_edge(component, &id, assign); + data.add_dep_edge(component.clone(), id.clone(), assign); } if s.kind == ScopeKind::Fn && !s.ast_path.is_empty() { @@ -1192,21 +1202,71 @@ fn merge_data(data: Arc>>) -> Data { .unwrap() .into_iter() .map(|d| d.into_inner()) - .map(|mut data| { - data.subtract_cycles(); - data - }) .collect::>(); let mut merged = Data::default(); for data in data { - merged.used_names.extend(data.used_names); + merged.used_names.merge(data.used_names); merged.entry_ids.extend(data.entry_ids); + merged.edges.merge(data.edges); } + merged.subtract_cycles(); + merged } +trait Merge { + fn merge(&mut self, other: Self); +} + +impl Merge for HashMap +where + K: Eq + Hash, + V: Merge, + S: BuildHasher, +{ + fn merge(&mut self, other: Self) { + for (k, v) in other { + match self.entry(k) { + std::collections::hash_map::Entry::Occupied(mut e) => { + e.get_mut().merge(v); + } + std::collections::hash_map::Entry::Vacant(e) => { + e.insert(v); + } + } + } + } +} + +impl Merge for IndexMap +where + K: Eq + Hash, + V: Merge, + S: BuildHasher, +{ + fn merge(&mut self, other: Self) { + for (k, v) in other { + match self.entry(k) { + indexmap::map::Entry::Occupied(mut e) => { + e.get_mut().merge(v); + } + indexmap::map::Entry::Vacant(e) => { + e.insert(v); + } + } + } + } +} + +impl Merge for VarInfo { + fn merge(&mut self, other: Self) { + self.usage += other.usage; + self.assign += other.assign; + } +} + impl Scope<'_> { /// Returns true if it's not in a function or class. fn is_ast_path_empty(&self) -> bool { From df795951a4f89f76ba1a6248359fd59b5748046f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Mon, 13 Jan 2025 08:41:17 +0900 Subject: [PATCH 11/21] impl Merge for Data --- .../src/simplify/dce/mod.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs index ef060329fb79..9477a63f739f 100644 --- a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs +++ b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs @@ -1206,9 +1206,7 @@ fn merge_data(data: Arc>>) -> Data { let mut merged = Data::default(); for data in data { - merged.used_names.merge(data.used_names); - merged.entry_ids.extend(data.entry_ids); - merged.edges.merge(data.edges); + merged.merge(data); } merged.subtract_cycles(); @@ -1267,6 +1265,14 @@ impl Merge for VarInfo { } } +impl Merge for Data { + fn merge(&mut self, other: Self) { + self.used_names.merge(other.used_names); + self.entry_ids.extend(other.entry_ids); + self.edges.merge(other.edges); + } +} + impl Scope<'_> { /// Returns true if it's not in a function or class. fn is_ast_path_empty(&self) -> bool { From f085836aa2aa20414e20b45fc008679aae37ea6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Mon, 13 Jan 2025 12:40:53 +0900 Subject: [PATCH 12/21] reserve --- .../src/simplify/dce/mod.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs index 9477a63f739f..4ce2eb077354 100644 --- a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs +++ b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs @@ -252,9 +252,16 @@ impl Parallel for Analyzer<'_> { fn merge(&mut self, other: Self) { self.scope.ast_path = other.scope.ast_path; + self.scope + .bindings_affected_by_eval + .reserve(other.scope.bindings_affected_by_eval.len()); self.scope .bindings_affected_by_eval .extend(other.scope.bindings_affected_by_eval); + + self.scope + .bindings_affected_by_arguements + .reserve(other.scope.bindings_affected_by_arguements.len()); self.scope .bindings_affected_by_arguements .extend(other.scope.bindings_affected_by_arguements); @@ -1225,6 +1232,8 @@ where S: BuildHasher, { fn merge(&mut self, other: Self) { + self.reserve(other.len()); + for (k, v) in other { match self.entry(k) { std::collections::hash_map::Entry::Occupied(mut e) => { @@ -1245,6 +1254,8 @@ where S: BuildHasher, { fn merge(&mut self, other: Self) { + self.reserve(other.len()); + for (k, v) in other { match self.entry(k) { indexmap::map::Entry::Occupied(mut e) => { From c46747e42e4687b85d9f28fd1cab1a15a90619c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Mon, 13 Jan 2025 14:51:18 +0900 Subject: [PATCH 13/21] `Edges` --- .../src/simplify/dce/mod.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs index 4ce2eb077354..a7912186de91 100644 --- a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs +++ b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs @@ -115,15 +115,18 @@ impl CompilerPass for TreeShaker { struct Data { used_names: FxHashMap, - edges: IndexMap<(Id, Id), VarInfo, RandomState>, + edges: Edges, /// Entrypoints. entry_ids: FxHashSet, } +#[derive(Default)] +struct Edges(IndexMap<(Id, Id), VarInfo, RandomState>); + impl Data { /// Add an edge to dependency graph fn add_dep_edge(&mut self, from: Id, to: Id, assign: bool) { - match self.edges.entry((from, to)) { + match self.edges.0.entry((from, to)) { indexmap::map::Entry::Occupied(mut info) => { if assign { info.get_mut().assign += 1; @@ -161,7 +164,7 @@ impl Data { .map(|id| get_node(id.clone())) .collect::>(); - for ((src, dst), info) in edges { + for ((src, dst), info) in edges.0 { let src = get_node(src); let dst = get_node(dst); @@ -1280,7 +1283,7 @@ impl Merge for Data { fn merge(&mut self, other: Self) { self.used_names.merge(other.used_names); self.entry_ids.extend(other.entry_ids); - self.edges.merge(other.edges); + self.edges.0.merge(other.edges.0); } } From b093bd194e48bc68a7002f95c3bd4448bbb2bd10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Mon, 13 Jan 2025 15:29:19 +0900 Subject: [PATCH 14/21] with_capacity --- crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs index a7912186de91..8468438e80d0 100644 --- a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs +++ b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs @@ -147,7 +147,7 @@ impl Data { fn subtract_cycles(&mut self) { let edges = take(&mut self.edges); - let mut graph = FastDiGraphMap::default(); + let mut graph = FastDiGraphMap::with_capacity(self.used_names.len(), self.edges.0.len()); let mut graph_ix = IndexMap::::default(); let mut get_node = |id: Id| -> u32 { From de78722b40f8b5bb4f940d769b82796539634dc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Mon, 13 Jan 2025 15:34:09 +0900 Subject: [PATCH 15/21] with_capacity --- .../swc_ecma_transforms_optimization/src/simplify/dce/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs index 8468438e80d0..da84baa6b99d 100644 --- a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs +++ b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs @@ -148,7 +148,8 @@ impl Data { let edges = take(&mut self.edges); let mut graph = FastDiGraphMap::with_capacity(self.used_names.len(), self.edges.0.len()); - let mut graph_ix = IndexMap::::default(); + let mut graph_ix: IndexMap<(JsWord, SyntaxContext), u32, RandomState> = + IndexMap::with_capacity_and_hasher(self.used_names.len(), Default::default()); let mut get_node = |id: Id| -> u32 { let len = graph_ix.len(); From 873967098a1d190b646b3b06a46b961b5c8e3ae1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Mon, 13 Jan 2025 15:38:05 +0900 Subject: [PATCH 16/21] oh --- crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs index da84baa6b99d..23789eb11b7a 100644 --- a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs +++ b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs @@ -147,7 +147,7 @@ impl Data { fn subtract_cycles(&mut self) { let edges = take(&mut self.edges); - let mut graph = FastDiGraphMap::with_capacity(self.used_names.len(), self.edges.0.len()); + let mut graph = FastDiGraphMap::with_capacity(self.used_names.len(), edges.0.len()); let mut graph_ix: IndexMap<(JsWord, SyntaxContext), u32, RandomState> = IndexMap::with_capacity_and_hasher(self.used_names.len(), Default::default()); From bc31485760d24963e4f02cb5946090370bdc2219 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Mon, 13 Jan 2025 15:52:19 +0900 Subject: [PATCH 17/21] parallel --- .../src/simplify/dce/mod.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs index 23789eb11b7a..f843640801ab 100644 --- a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs +++ b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs @@ -616,31 +616,31 @@ impl Visit for Analyzer<'_> { } fn visit_opt_vec_expr_or_spreads(&mut self, n: &[Option]) { - self.visit_par(cpu_count(), n); + self.visit_par(cpu_count() * 8, n); } fn visit_prop_or_spreads(&mut self, n: &[PropOrSpread]) { - self.visit_par(cpu_count(), n); + self.visit_par(cpu_count() * 8, n); } fn visit_expr_or_spreads(&mut self, n: &[ExprOrSpread]) { - self.visit_par(cpu_count(), n); + self.visit_par(cpu_count() * 8, n); } fn visit_exprs(&mut self, n: &[Box]) { - self.visit_par(cpu_count(), n); + self.visit_par(cpu_count() * 8, n); } fn visit_stmts(&mut self, n: &[Stmt]) { - self.visit_par(cpu_count(), n); + self.visit_par(cpu_count() * 8, n); } fn visit_module_items(&mut self, n: &[ModuleItem]) { - self.visit_par(cpu_count(), n); + self.visit_par(cpu_count() * 8, n); } fn visit_var_declarators(&mut self, n: &[VarDeclarator]) { - self.visit_par(cpu_count(), n); + self.visit_par(cpu_count() * 8, n); } } From 87bef97e52046dc52720eb16202d3c5e6640a2be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Mon, 13 Jan 2025 16:48:59 +0900 Subject: [PATCH 18/21] cargo.toml --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 7602e7b74da0..f3862d1255a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -103,6 +103,7 @@ resolver = "2" tempfile = "3.6.0" termcolor = "1.0" thiserror = "1.0.30" + thread_local = "1.1.8" tokio = { version = "1", default-features = false } toml = "0.8.2" tracing = "0.1.40" @@ -122,7 +123,6 @@ resolver = "2" wasm-bindgen-futures = "0.4.41" wasmer = { version = "=5.0.5-rc1", default-features = false } wasmer-wasix = { version = "0.35.0", default-features = false } -thread_local = "1.1.8" [profile.release] lto = true From 4af92b6544f37e86b75eee5290f9155e4ca06f5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Sun, 19 Jan 2025 16:38:57 +0900 Subject: [PATCH 19/21] Disable cycle --- .../swc_ecma_transforms_optimization/src/simplify/dce/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs index f843640801ab..9107b9b7ac6b 100644 --- a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs +++ b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs @@ -144,6 +144,7 @@ impl Data { } /// Traverse the graph and subtract usages from `used_names`. + #[allow(unused)] fn subtract_cycles(&mut self) { let edges = take(&mut self.edges); @@ -1220,7 +1221,7 @@ fn merge_data(data: Arc>>) -> Data { merged.merge(data); } - merged.subtract_cycles(); + // merged.subtract_cycles(); merged } @@ -1284,7 +1285,7 @@ impl Merge for Data { fn merge(&mut self, other: Self) { self.used_names.merge(other.used_names); self.entry_ids.extend(other.entry_ids); - self.edges.0.merge(other.edges.0); + // self.edges.0.merge(other.edges.0); } } From f3c6d4ffb71cd986174dc1d58cdf2919f661759c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Mon, 20 Jan 2025 01:23:58 +0900 Subject: [PATCH 20/21] parallel merge --- .../src/simplify/dce/mod.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs index 9107b9b7ac6b..6accf1f02654 100644 --- a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs +++ b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs @@ -10,6 +10,8 @@ use std::{ use ahash::RandomState; use indexmap::{IndexMap, IndexSet}; use petgraph::{algo::tarjan_scc, Direction::Incoming}; +#[cfg(feature = "concurrent")] +use rayon::prelude::*; use rustc_hash::{FxHashMap, FxHashSet}; use swc_atoms::{atom, JsWord}; use swc_common::{ @@ -144,7 +146,6 @@ impl Data { } /// Traverse the graph and subtract usages from `used_names`. - #[allow(unused)] fn subtract_cycles(&mut self) { let edges = take(&mut self.edges); @@ -1215,13 +1216,19 @@ fn merge_data(data: Arc>>) -> Data { .into_iter() .map(|d| d.into_inner()) .collect::>(); - let mut merged = Data::default(); - for data in data { + #[cfg(feature = "concurrent")] + let iter = data.into_par_iter(); + + #[cfg(not(feature = "concurrent"))] + let iter = data.into_iter(); + + let mut merged = iter.reduce(Data::default, |mut merged, data| { merged.merge(data); - } + merged + }); - // merged.subtract_cycles(); + merged.subtract_cycles(); merged } From 2ea1a72173d506f2262f5c2afe935e9c36b497f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Mon, 20 Jan 2025 02:27:33 +0900 Subject: [PATCH 21/21] Optional parallel merge --- .../src/simplify/dce/mod.rs | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs index 6accf1f02654..7281a05ff83e 100644 --- a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs +++ b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs @@ -1210,6 +1210,7 @@ impl VisitMut for TreeShaker { } fn merge_data(data: Arc>>) -> Data { + #[cfg(feature = "concurrent")] let data = Arc::try_unwrap(data) .map_err(|_| {}) .unwrap() @@ -1218,15 +1219,23 @@ fn merge_data(data: Arc>>) -> Data { .collect::>(); #[cfg(feature = "concurrent")] - let iter = data.into_par_iter(); + let mut merged = data + .into_par_iter() + .reduce(Data::default, |mut merged, data| { + merged.merge(data); + merged + }); #[cfg(not(feature = "concurrent"))] - let iter = data.into_iter(); - - let mut merged = iter.reduce(Data::default, |mut merged, data| { - merged.merge(data); - merged - }); + let mut merged = Arc::try_unwrap(data) + .map_err(|_| {}) + .unwrap() + .into_iter() + .map(|d| d.into_inner()) + .fold(Data::default(), |mut merged, data| { + merged.merge(data); + merged + }); merged.subtract_cycles(); @@ -1292,7 +1301,7 @@ impl Merge for Data { fn merge(&mut self, other: Self) { self.used_names.merge(other.used_names); self.entry_ids.extend(other.entry_ids); - // self.edges.0.merge(other.edges.0); + self.edges.0.merge(other.edges.0); } }