From ebe3496bdc9d8b205af86c74bba270e32617ac5f Mon Sep 17 00:00:00 2001 From: Dunqing Date: Wed, 16 Apr 2025 21:26:53 +0800 Subject: [PATCH] perf(transformer/class-properties): return early if no private fields are found (#10418) If a class or its parent classes don't have a private field, we don't need to transform the expression. Because we only transform expressions that include a private field. Co-authored-by: Dunqing <29533304+Dunqing@users.noreply.github.com> --- .../oxc_transformer/src/es2022/class_properties/class.rs | 5 ++++- crates/oxc_transformer/src/es2022/class_properties/mod.rs | 8 ++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/crates/oxc_transformer/src/es2022/class_properties/class.rs b/crates/oxc_transformer/src/es2022/class_properties/class.rs index 373dae9c9c..4054d8c681 100644 --- a/crates/oxc_transformer/src/es2022/class_properties/class.rs +++ b/crates/oxc_transformer/src/es2022/class_properties/class.rs @@ -164,6 +164,8 @@ impl<'a> ClassProperties<'a, '_> { } } + self.private_field_count += private_props.len(); + // Exit if nothing to transform if instance_prop_count == 0 && !has_static_prop @@ -385,7 +387,6 @@ impl<'a> ClassProperties<'a, '_> { } else { debug_assert!(class_details.bindings.temp.is_none()); } - // Pop off stack. We're done! self.classes_stack.pop(); } @@ -444,6 +445,7 @@ impl<'a> ClassProperties<'a, '_> { } if let Some(private_props) = &class_details.private_props { + self.private_field_count -= private_props.len(); if self.private_fields_as_properties { let mut private_props = private_props .iter() @@ -588,6 +590,7 @@ impl<'a> ClassProperties<'a, '_> { // Babel has these always go first, regardless of order of class elements. // Also insert `var _prop;` temp var declarations for private static props. if let Some(private_props) = &class_details.private_props { + self.private_field_count -= private_props.len(); // Insert `var _prop;` declarations here rather than when binding was created to maintain // same order of `var` declarations as Babel. // `c = class C { #x = 1; static y = 2; }` -> `var _C, _x;` diff --git a/crates/oxc_transformer/src/es2022/class_properties/mod.rs b/crates/oxc_transformer/src/es2022/class_properties/mod.rs index 141fb7d7e4..fbf026a812 100644 --- a/crates/oxc_transformer/src/es2022/class_properties/mod.rs +++ b/crates/oxc_transformer/src/es2022/class_properties/mod.rs @@ -277,6 +277,8 @@ pub struct ClassProperties<'a, 'ctx> { /// Keys are symbols' IDs. /// Values are initially the original name of binding, later on the name of new UID name. clashing_constructor_symbols: FxHashMap>, + /// Count of private fields in class and also included parent classes. + private_field_count: usize, // ----- State used only during exit phase ----- // @@ -312,6 +314,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { instance_inits_constructor_scope_id: None, // `Vec`s and `FxHashMap`s which are reused for every class being transformed clashing_constructor_symbols: FxHashMap::default(), + private_field_count: 0, insert_before: vec![], insert_after_exprs: vec![], insert_after_stmts: vec![], @@ -339,6 +342,11 @@ impl<'a> Traverse<'a> for ClassProperties<'a, '_> { // `#[inline]` for fast exit for expressions which are not any of the transformed types #[inline] fn enter_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) { + // Return early if no private fields are found. + if self.private_field_count == 0 { + return; + } + match expr { // `object.#prop` Expression::PrivateFieldExpression(_) => {