Skip to content

Commit 805363e

Browse files
authored
perf: parallel mangle exports (#10877)
* perf: parallelize mangle exports info * perf: parallelize mangle exports info
1 parent 63bfefb commit 805363e

File tree

3 files changed

+76
-41
lines changed

3 files changed

+76
-41
lines changed

crates/rspack_core/src/exports/export_info.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ pub enum ExportName {
2121

2222
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
2323
pub struct ExportInfo {
24-
exports_info: ExportsInfo,
25-
export_name: ExportName,
24+
pub exports_info: ExportsInfo,
25+
pub export_name: ExportName,
2626
}
2727

2828
impl ExportInfo {

crates/rspack_core/src/module_graph/mod.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ use swc_core::ecma::atoms::Atom;
99

1010
use crate::{
1111
AsyncDependenciesBlock, AsyncDependenciesBlockIdentifier, Compilation, DependenciesBlock,
12-
Dependency, ExportProvided, ExportsInfoGetter, ModuleGraphCacheArtifact, PrefetchExportsInfoMode,
13-
PrefetchedExportsInfoWrapper, RuntimeSpec,
12+
Dependency, ExportInfo, ExportName, ExportProvided, ExportsInfoGetter, ModuleGraphCacheArtifact,
13+
PrefetchExportsInfoMode, PrefetchedExportsInfoWrapper, RuntimeSpec,
1414
};
1515
mod module;
1616
pub use module::*;
@@ -1256,4 +1256,37 @@ impl<'a> ModuleGraph<'a> {
12561256
active_partial.module_graph_modules.insert(mid, Some(mgm));
12571257
}
12581258
}
1259+
1260+
pub fn batch_set_export_info_used_name(&mut self, tasks: Vec<(ExportInfo, Atom)>) {
1261+
if self.active.is_none() {
1262+
panic!("should have active partial");
1263+
}
1264+
1265+
let active_partial = self.active.as_mut().expect("should have active partial");
1266+
for (export_info, used_name) in tasks {
1267+
let ExportInfo {
1268+
exports_info,
1269+
export_name,
1270+
} = export_info;
1271+
1272+
let data = active_partial
1273+
.exports_info_map
1274+
.get_mut(&exports_info)
1275+
.expect("should have exports info");
1276+
match export_name {
1277+
ExportName::Named(name) => {
1278+
data
1279+
.named_exports_mut(&name)
1280+
.expect("should have named export")
1281+
.set_used_name(used_name);
1282+
}
1283+
ExportName::Other => {
1284+
data.other_exports_info_mut().set_used_name(used_name);
1285+
}
1286+
ExportName::SideEffects => {
1287+
data.side_effects_only_info_mut().set_used_name(used_name);
1288+
}
1289+
}
1290+
}
1291+
}
12591292
}

crates/rspack_plugin_javascript/src/plugin/mangle_exports_plugin.rs

Lines changed: 39 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ enum Manglable {
5454
#[derive(Debug)]
5555
struct ExportInfoCache {
5656
id: ExportInfo,
57-
deterministic: bool,
5857
exports_info: Option<ExportsInfo>,
5958
can_mangle: Manglable,
6059
}
@@ -75,19 +74,14 @@ async fn optimize_code_generation(&self, compilation: &mut Compilation) -> Resul
7574
// TODO: should bailout if compilation.moduleMemCache is enable, https://github.com/webpack/webpack/blob/1f99ad6367f2b8a6ef17cce0e058f7a67fb7db18/lib/optimize/MangleExportsPlugin.js#L160-L164
7675
// We don't do that cause we don't have this option
7776
let mut mg = compilation.get_module_graph_mut();
78-
let module_id_list = mg.modules().keys().cloned().collect::<Vec<_>>();
77+
let modules = mg.modules();
7978

8079
let mut exports_info_cache = FxHashMap::default();
8180

82-
let mut q = module_id_list
81+
let mut q = modules
8382
.iter()
84-
.filter_map(|id| {
85-
let (Some(mgm), Some(module)) = (
86-
mg.module_graph_module_by_identifier(id),
87-
mg.module_by_identifier(id),
88-
) else {
89-
return None;
90-
};
83+
.filter_map(|(mid, module)| {
84+
let mgm = mg.module_graph_module_by_identifier(mid)?;
9185
let is_namespace = matches!(
9286
module.build_meta().exports_type,
9387
BuildMetaExportsType::Namespace
@@ -163,7 +157,6 @@ async fn optimize_code_generation(&self, compilation: &mut Compilation) -> Resul
163157

164158
ExportInfoCache {
165159
id: export_info_data.id(),
166-
deterministic,
167160
exports_info: nested_exports_info,
168161
can_mangle,
169162
}
@@ -184,21 +177,32 @@ async fn optimize_code_generation(&self, compilation: &mut Compilation) -> Resul
184177
}
185178
}
186179

187-
for identifier in module_id_list {
188-
let (Some(mgm), Some(_)) = (
189-
mg.module_graph_module_by_identifier(&identifier),
190-
mg.module_by_identifier(&identifier),
191-
) else {
192-
continue;
193-
};
194-
let exports_info = mgm.exports;
195-
mangle_exports_info(
196-
&mut mg,
197-
self.deterministic,
198-
exports_info,
199-
&exports_info_cache,
200-
);
180+
let mut queue = modules
181+
.into_iter()
182+
.filter_map(|(mid, _)| {
183+
let mgm = mg.module_graph_module_by_identifier(&mid)?;
184+
Some(mgm.exports)
185+
})
186+
.collect_vec();
187+
188+
while !queue.is_empty() {
189+
let tasks = std::mem::take(&mut queue);
190+
let batch = tasks
191+
.into_par_iter()
192+
.map(|exports_info| {
193+
mangle_exports_info(&mg, self.deterministic, exports_info, &exports_info_cache)
194+
})
195+
.collect::<Vec<_>>();
196+
197+
let mut used_name_tasks = vec![];
198+
for (changes, nested_exports) in batch {
199+
used_name_tasks.extend(changes);
200+
queue.extend(nested_exports);
201+
}
202+
203+
mg.batch_set_export_info_used_name(used_name_tasks);
201204
}
205+
202206
Ok(())
203207
}
204208

@@ -224,23 +228,25 @@ static MANGLE_NAME_DETERMINISTIC_REG: LazyLock<Regex> = LazyLock::new(|| {
224228

225229
/// Function to mangle exports information.
226230
fn mangle_exports_info(
227-
mg: &mut ModuleGraph,
231+
mg: &ModuleGraph,
228232
deterministic: bool,
229233
exports_info: ExportsInfo,
230234
exports_info_cache: &FxHashMap<ExportsInfo, Vec<ExportInfoCache>>,
231-
) {
235+
) -> (Vec<(ExportInfo, Atom)>, Vec<ExportsInfo>) {
236+
let mut changes = vec![];
237+
let mut nested_exports = vec![];
232238
let mut used_names = FxHashSet::default();
233239
let mut mangleable_exports = Vec::new();
234240
let Some(export_list) = exports_info_cache.get(&exports_info) else {
235-
return;
241+
return (changes, nested_exports);
236242
};
237243

238244
let mut mangleable_export_names = FxHashMap::default();
239245

240246
for export_info in export_list {
241247
match &export_info.can_mangle {
242248
Manglable::CanNotMangle(name) => {
243-
export_info.id.as_data_mut(mg).set_used_name(name.clone());
249+
changes.push((export_info.id.clone(), name.clone()));
244250
used_names.insert(name.to_string());
245251
}
246252
Manglable::CanMangle(name) => {
@@ -251,12 +257,7 @@ fn mangle_exports_info(
251257
}
252258

253259
if let Some(nested_exports_info) = export_info.exports_info {
254-
mangle_exports_info(
255-
mg,
256-
export_info.deterministic,
257-
nested_exports_info,
258-
exports_info_cache,
259-
);
260+
nested_exports.push(nested_exports_info);
260261
}
261262
}
262263

@@ -297,7 +298,7 @@ fn mangle_exports_info(
297298
0,
298299
);
299300
for (export_info, name) in export_info_used_name {
300-
export_info.as_data_mut(mg).set_used_name(name.into());
301+
changes.push((export_info, name.into()));
301302
}
302303
} else {
303304
let mut used_exports = Vec::new();
@@ -336,8 +337,9 @@ fn mangle_exports_info(
336337
}
337338
i += 1;
338339
}
339-
export_info.as_data_mut(mg).set_used_name(name.into());
340+
changes.push((export_info, name.into()));
340341
}
341342
}
342343
}
344+
(changes, nested_exports)
343345
}

0 commit comments

Comments
 (0)