Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

perf: parallelize side effects optimization #8781

Merged
merged 4 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,9 @@ impl ModuleDeps {
dep.dependency_type(),
crate::DependencyType::EsmImportSpecifier
) {
let dep_ids = dep.get_ids(module_graph);
ids.extend(dep_ids.into_iter());
// TODO: remove Dependency::get_ids once incremental build chunk graph is stable.
let dep_ids = dep._get_ids(module_graph);
ids.extend(dep_ids.iter().cloned());
}
}

Expand Down Expand Up @@ -142,13 +143,12 @@ impl HasModuleGraphChange {
mod t {
use std::borrow::Cow;

use itertools::Itertools;
use rspack_cacheable::{cacheable, cacheable_dyn, with::Skip};
use rspack_collections::Identifiable;
use rspack_error::{impl_empty_diagnosable_trait, Diagnostic, Result};
use rspack_macros::impl_source_map_config;
use rspack_sources::Source;
use rspack_util::source_map::SourceMapKind;
use rspack_util::{atom::Atom, source_map::SourceMapKind};

use crate::{
compiler::make::cutout::has_module_graph_change::ModuleDeps, AffectType, AsContextDependency,
Expand All @@ -162,12 +162,12 @@ mod t {
#[derive(Debug, Clone)]
struct TestDep {
#[cacheable(with=Skip)]
ids: Vec<&'static str>,
ids: Vec<Atom>,
id: DependencyId,
}

impl TestDep {
fn new(ids: Vec<&'static str>) -> Self {
fn new(ids: Vec<Atom>) -> Self {
Self {
ids,
id: DependencyId::new(),
Expand All @@ -187,12 +187,8 @@ mod t {
&self.id
}

fn get_ids(&self, _mg: &ModuleGraph) -> Vec<swc_core::atoms::Atom> {
self
.ids
.iter()
.map(|id| (*id).to_string().into())
.collect_vec()
fn _get_ids<'a>(&'a self, _mg: &'a ModuleGraph) -> &'a [Atom] {
&self.ids
}

fn could_affect_referencing_module(&self) -> AffectType {
Expand Down Expand Up @@ -354,7 +350,7 @@ mod t {
let mut partial = ModuleGraphPartial::default();
let mut mg = ModuleGraph::new(vec![], Some(&mut partial));

let dep1 = Box::new(TestDep::new(vec!["foo"]));
let dep1 = Box::new(TestDep::new(vec!["foo".into()]));
let dep1_id = *dep1.id();
let module_orig = Box::new(TestModule::new("app", vec![dep1_id]));
let module_orig_id = module_orig.identifier();
Expand All @@ -374,7 +370,7 @@ mod t {

assert_eq!(module_deps_1, module_deps_2);

let dep2 = Box::new(TestDep::new(vec!["bar"]));
let dep2 = Box::new(TestDep::new(vec!["bar".into()]));
let dep2_id = *dep2.id();
let module_orig: &mut TestModule = mg
.module_by_identifier_mut(&module_orig_id)
Expand Down
16 changes: 0 additions & 16 deletions crates/rspack_core/src/dependency/dependency_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ use std::sync::atomic::Ordering::Relaxed;

use rspack_cacheable::cacheable;
use serde::Serialize;
use swc_core::ecma::atoms::Atom;

use crate::ModuleGraph;

#[cacheable(hashable)]
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize)]
Expand All @@ -17,19 +14,6 @@ impl DependencyId {
pub fn new() -> Self {
Self(DEPENDENCY_ID.fetch_add(1, Relaxed))
}

pub fn set_ids(&self, ids: Vec<Atom>, mg: &mut ModuleGraph) {
mg.set_dep_meta(*self, ids);
}

/// # Panic
/// This method will panic if one of following condition is true:
/// * current dependency id is not belongs to `ESMImportSpecifierDependency` or `ESMExportImportedSpecifierDependency`
/// * current id is not in `ModuleGraph`
pub fn get_ids(&self, mg: &ModuleGraph) -> Vec<Atom> {
let dep = mg.dependency_by_id(self).expect("should have dep");
dep.get_ids(mg)
}
}

impl Default for DependencyId {
Expand Down
5 changes: 3 additions & 2 deletions crates/rspack_core/src/dependency/dependency_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use dyn_clone::{clone_trait_object, DynClone};
use rspack_cacheable::cacheable_dyn;
use rspack_collections::IdentifierSet;
use rspack_error::Diagnostic;
use rspack_util::atom::Atom;
use rspack_util::ext::AsAny;
use swc_core::ecma::atoms::Atom;

use super::dependency_template::AsDependencyTemplate;
use super::module_dependency::*;
Expand Down Expand Up @@ -89,9 +89,10 @@ pub trait Dependency:
None
}

// TODO: remove this once incremental build chunk graph is stable.
// For now only `ESMImportSpecifierDependency` and
// `ESMExportImportedSpecifierDependency` can use this method
fn get_ids(&self, _mg: &ModuleGraph) -> Vec<Atom> {
fn _get_ids<'a>(&'a self, _mg: &'a ModuleGraph) -> &'a [Atom] {
unreachable!()
}

Expand Down
14 changes: 9 additions & 5 deletions crates/rspack_core/src/dependency/runtime_template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ pub fn export_from_import(
default_interop: bool,
request: &str,
import_var: &str,
mut export_name: Vec<Atom>,
export_name: &[Atom],
id: &DependencyId,
is_call: bool,
call_context: bool,
Expand All @@ -124,6 +124,7 @@ pub fn export_from_import(

let exports_type = get_exports_type(&compilation.get_module_graph(), id, &module.identifier());

let mut exclude_default_export_name = None;
if default_interop {
if !export_name.is_empty()
&& let Some(first_export_name) = export_name.first()
Expand Down Expand Up @@ -151,7 +152,7 @@ pub fn export_from_import(
}
}
ExportsType::DefaultOnly | ExportsType::DefaultWithNamed => {
export_name = export_name[1..].to_vec();
exclude_default_export_name = Some(export_name[1..].to_vec());
}
_ => {}
}
Expand Down Expand Up @@ -204,6 +205,9 @@ pub fn export_from_import(
}
}

let export_name = exclude_default_export_name
.as_deref()
.unwrap_or(export_name);
if !export_name.is_empty() {
let used_name: Cow<Vec<Atom>> = {
let exports_info = compilation
Expand All @@ -212,7 +216,7 @@ pub fn export_from_import(
let used = exports_info.get_used_name(
&compilation.get_module_graph(),
*runtime,
crate::UsedName::Vec(export_name.clone()),
crate::UsedName::Vec(export_name.to_vec()),
);
if let Some(used) = used {
let used = match used {
Expand All @@ -223,12 +227,12 @@ pub fn export_from_import(
} else {
return format!(
"{} undefined",
to_normal_comment(&property_access(&export_name, 0))
to_normal_comment(&property_access(export_name, 0))
);
}
};
let comment = if *used_name != export_name {
to_normal_comment(&property_access(&export_name, 0))
to_normal_comment(&property_access(export_name, 0))
} else {
String::new()
};
Expand Down
105 changes: 66 additions & 39 deletions crates/rspack_core/src/exports_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,14 +342,14 @@ impl ExportsInfo {
pub fn get_nested_exports_info(
&self,
mg: &ModuleGraph,
name: Option<Vec<Atom>>,
name: Option<&[Atom]>,
) -> Option<ExportsInfo> {
if let Some(name) = name
&& !name.is_empty()
{
let info = self.get_read_only_export_info(mg, &name[0]);
if let Some(exports_info) = info.exports_info(mg) {
return exports_info.get_nested_exports_info(mg, Some(name[1..].to_vec()));
return exports_info.get_nested_exports_info(mg, Some(&name[1..]));
} else {
return None;
}
Expand Down Expand Up @@ -1307,43 +1307,6 @@ impl ExportInfo {
false
}

pub fn move_target(
&self,
mg: &mut ModuleGraph,
resolve_filter: ResolveFilterFnTy,
update_original_connection: UpdateOriginalFunctionTy,
) -> Option<ResolvedExportInfoTarget> {
let target = self.get_target_with_filter(mg, resolve_filter)?;
let max_target = self.get_max_target(mg);
let original_target = max_target
.values()
.next()
.expect("should have export info target"); // refer https://github.com/webpack/webpack/blob/ac7e531436b0d47cd88451f497cdfd0dad41535d/lib/ExportsInfo.js#L1388-L1394
if original_target.dependency.as_ref() == Some(&target.dependency)
&& original_target.export == target.export
{
return None;
}
let export_info_mut = self.as_export_info_mut(mg);
export_info_mut.target.clear();
let updated_dependency_id = update_original_connection(&target, mg);

// shadowning `export_info_mut` to reduce `&mut ModuleGraph` borrow life time, since
// `update_original_connection` also needs `&mut ModuleGraph`
let export_info_mut = self.as_export_info_mut(mg);
export_info_mut.target.insert(
None,
ExportInfoTargetValue {
dependency: updated_dependency_id,
export: target.export.clone(),
priority: 0,
},
);

export_info_mut.target_is_set = true;
Some(target)
}

pub fn set_used_conditionally(
&self,
mg: &mut ModuleGraph,
Expand Down Expand Up @@ -1871,6 +1834,18 @@ impl MaybeDynamicTargetExportInfo {
}
}

pub fn get_target_with_filter(
&self,
mg: &ModuleGraph,
resolve_filter: ResolveFilterFnTy,
) -> Option<ResolvedExportInfoTarget> {
match self.get_target_impl(mg, resolve_filter, &mut Default::default()) {
Some(ResolvedExportInfoTargetWithCircular::Circular) => None,
Some(ResolvedExportInfoTargetWithCircular::Target(target)) => Some(target),
None => None,
}
}

fn get_target_impl(
&self,
mg: &ModuleGraph,
Expand All @@ -1894,6 +1869,58 @@ impl MaybeDynamicTargetExportInfo {
}
}
}

fn get_max_target<'a>(
&'a self,
mg: &'a ModuleGraph,
) -> Cow<'a, HashMap<Option<DependencyId>, ExportInfoTargetValue>> {
match self {
MaybeDynamicTargetExportInfo::Static(export_info) => export_info.get_max_target(mg),
MaybeDynamicTargetExportInfo::Dynamic { data, .. } => data.get_max_target(),
}
}
}

impl MaybeDynamicTargetExportInfo {
pub fn can_move_target(
&self,
mg: &ModuleGraph,
resolve_filter: ResolveFilterFnTy,
) -> Option<ResolvedExportInfoTarget> {
let target = self.get_target_with_filter(mg, resolve_filter)?;
let max_target = self.get_max_target(mg);
let original_target = max_target
.values()
.next()
.expect("should have export info target"); // refer https://github.com/webpack/webpack/blob/ac7e531436b0d47cd88451f497cdfd0dad41535d/lib/ExportsInfo.js#L1388-L1394
if original_target.dependency.as_ref() == Some(&target.dependency)
&& original_target.export == target.export
{
return None;
}
Some(target)
}
}

impl ExportInfo {
pub fn do_move_target(
&self,
mg: &mut ModuleGraph,
dependency: DependencyId,
target_export: Option<Vec<Atom>>,
) {
let export_info_mut = self.as_export_info_mut(mg);
export_info_mut.target.clear();
export_info_mut.target.insert(
None,
ExportInfoTargetValue {
dependency: Some(dependency),
export: target_export,
priority: 0,
},
);
export_info_mut.target_is_set = true;
}
}

pub type ResolveFilterFnTy<'a> = Rc<dyn Fn(&ResolvedExportInfoTarget, &ModuleGraph) -> bool + 'a>;
Expand Down
21 changes: 11 additions & 10 deletions crates/rspack_core/src/module_graph/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -928,25 +928,27 @@ impl<'a> ModuleGraph<'a> {
self.loop_partials(|p| p.dep_meta_map.get(id))
}

pub fn set_dep_meta(&mut self, dep_id: DependencyId, ids: Vec<Atom>) {
pub fn set_dependency_extra_meta(&mut self, dep_id: DependencyId, extra: DependencyExtraMeta) {
let Some(active_partial) = &mut self.active else {
panic!("should have active partial");
};
active_partial
.dep_meta_map
.insert(dep_id, DependencyExtraMeta { ids });
active_partial.dep_meta_map.insert(dep_id, extra);
}

pub fn can_update_module(&self, dep_id: &DependencyId, module_id: &ModuleIdentifier) -> bool {
let connection = self
.connection_by_dependency_id(dep_id)
.expect("should have connection");
connection.module_identifier() != module_id
}

pub fn update_module(&mut self, dep_id: &DependencyId, module_id: &ModuleIdentifier) -> bool {
pub fn do_update_module(&mut self, dep_id: &DependencyId, module_id: &ModuleIdentifier) {
let connection = self
.connection_by_dependency_id_mut(dep_id)
.expect("should have connection");
let old_module_identifier = *connection.module_identifier();
if &old_module_identifier == module_id {
return false;
}

connection.set_module_identifier(*module_id);

// remove dep_id from old module mgm incoming connection
let old_mgm = self
.module_graph_module_by_identifier_mut(&old_module_identifier)
Expand All @@ -958,7 +960,6 @@ impl<'a> ModuleGraph<'a> {
.module_graph_module_by_identifier_mut(module_id)
.expect("should exist mgm");
new_mgm.add_incoming_connection(*dep_id);
true
}

pub fn get_exports_info(&self, module_identifier: &ModuleIdentifier) -> ExportsInfo {
Expand Down
Loading
Loading