From 6d0ca05cb50c0b33fa0786824e07950d4db91819 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Donny/=EA=B0=95=EB=8F=99=EC=9C=A4?= Date: Sat, 15 Oct 2022 13:37:11 +0900 Subject: [PATCH] fix(es/minifier): Fix ordering issue of analyzer (#6150) **Description:** This is the groundwork for a parallel analyzer. This PR fixes the ordering issue of the analyzer so that the analyzer works identically regardless of the visit order. This patch contains some improvements because previously, we mixed `.and_modify()` and `.or_default()`. --- .../classDeclarationLoop.2.minified.js | 5 +-- crates/swc_ecma_minifier/src/analyzer/mod.rs | 42 ++++++++++++++++++- .../src/analyzer/storage/normal.rs | 41 ++++++++---------- .../tests/fixture/issues/2257/full/output.js | 3 +- .../fixture/next/react-pdf-renderer/output.js | 3 +- .../tests/projects/output/react-dom-17.0.2.js | 3 +- 6 files changed, 64 insertions(+), 33 deletions(-) diff --git a/crates/swc/tests/tsc-references/classDeclarationLoop.2.minified.js b/crates/swc/tests/tsc-references/classDeclarationLoop.2.minified.js index 3cdfa779b9a2..28f5173388ba 100644 --- a/crates/swc/tests/tsc-references/classDeclarationLoop.2.minified.js +++ b/crates/swc/tests/tsc-references/classDeclarationLoop.2.minified.js @@ -1,9 +1,8 @@ //// [classDeclarationLoop.ts] import _class_call_check from "@swc/helpers/src/_class_call_check.mjs"; for(var _loop = function(i) { - var C = function C() { + arr.push(function C() { "use strict"; _class_call_check(this, C), this.prop = i; - }; - arr.push(C); + }); }, arr = [], i = 0; i < 10; ++i)_loop(i); diff --git a/crates/swc_ecma_minifier/src/analyzer/mod.rs b/crates/swc_ecma_minifier/src/analyzer/mod.rs index e96d8c3af637..992af3f35a5b 100644 --- a/crates/swc_ecma_minifier/src/analyzer/mod.rs +++ b/crates/swc_ecma_minifier/src/analyzer/mod.rs @@ -68,7 +68,7 @@ where v.data } -#[derive(Debug, Default, Clone)] +#[derive(Debug, Clone)] pub(crate) struct VarUsageInfo { pub inline_prevented: bool, @@ -143,6 +143,46 @@ pub(crate) struct VarUsageInfo { pub used_recursively: bool, } +impl Default for VarUsageInfo { + fn default() -> Self { + Self { + inline_prevented: Default::default(), + ref_count: Default::default(), + cond_init: Default::default(), + declared: Default::default(), + declared_count: Default::default(), + declared_as_fn_param: Default::default(), + declared_as_fn_decl: Default::default(), + declared_as_fn_expr: Default::default(), + assign_count: Default::default(), + mutation_by_call_count: Default::default(), + usage_count: Default::default(), + reassigned_with_assignment: Default::default(), + reassigned_with_var_decl: Default::default(), + mutated: Default::default(), + has_property_access: Default::default(), + has_property_mutation: Default::default(), + exported: Default::default(), + used_above_decl: Default::default(), + is_fn_local: true, + executed_multiple_time: Default::default(), + used_in_cond: Default::default(), + var_kind: Default::default(), + var_initialized: Default::default(), + declared_as_catch_param: Default::default(), + no_side_effect_for_member_access: Default::default(), + used_as_callee: Default::default(), + used_as_arg: Default::default(), + indexed_with_dynamic_key: Default::default(), + pure_fn: Default::default(), + infects: Default::default(), + used_in_non_child_fn: Default::default(), + accessed_props: Default::default(), + used_recursively: Default::default(), + } + } +} + impl VarUsageInfo { pub fn is_mutated_only_by_one_call(&self) -> bool { self.assign_count == 0 && self.mutation_by_call_count == 1 diff --git a/crates/swc_ecma_minifier/src/analyzer/storage/normal.rs b/crates/swc_ecma_minifier/src/analyzer/storage/normal.rs index bc257328e36e..99e95bb07db5 100644 --- a/crates/swc_ecma_minifier/src/analyzer/storage/normal.rs +++ b/crates/swc_ecma_minifier/src/analyzer/storage/normal.rs @@ -153,32 +153,27 @@ impl Storage for ProgramData { // debug!(has_init = has_init, "declare_decl(`{}`)", i); // } - let v = self - .vars - .entry(i.to_id()) - .and_modify(|v| { - if has_init && (v.declared || v.var_initialized) { - trace_op!("declare_decl(`{}`): Already declared", i); - - v.mutated = true; - v.reassigned_with_var_decl = true; - v.assign_count += 1; - } + let v = self.vars.entry(i.to_id()).or_default(); - if v.used_in_non_child_fn { - v.is_fn_local = false; - } + if has_init && (v.declared || v.var_initialized) { + trace_op!("declare_decl(`{}`): Already declared", i); - v.var_initialized |= has_init; - }) - .or_insert_with(|| VarUsageInfo { - is_fn_local: true, - var_kind: kind, - var_initialized: has_init, - no_side_effect_for_member_access: ctx.in_decl_with_no_side_effect_for_member_access, + v.mutated = true; + v.reassigned_with_var_decl = true; + v.assign_count += 1; + } - ..Default::default() - }); + // This is not delcared yet, so this is the first declaration. + if !v.declared { + v.var_kind = kind; + v.no_side_effect_for_member_access = ctx.in_decl_with_no_side_effect_for_member_access; + } + + if v.used_in_non_child_fn { + v.is_fn_local = false; + } + + v.var_initialized |= has_init; v.declared_count += 1; v.declared = true; diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/2257/full/output.js b/crates/swc_ecma_minifier/tests/fixture/issues/2257/full/output.js index d1ee27c1ed7c..ad7117d85b87 100644 --- a/crates/swc_ecma_minifier/tests/fixture/issues/2257/full/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/issues/2257/full/output.js @@ -14843,8 +14843,7 @@ 0 === V && (V = 5); } function Uj(a) { - var b = eg(); - return gg(99, dk.bind(null, a, b)), null; + return gg(99, dk.bind(null, a, eg())), null; } function dk(a, b) { do Oj(); diff --git a/crates/swc_ecma_minifier/tests/fixture/next/react-pdf-renderer/output.js b/crates/swc_ecma_minifier/tests/fixture/next/react-pdf-renderer/output.js index 6bd8c485355f..1ce33377a949 100644 --- a/crates/swc_ecma_minifier/tests/fixture/next/react-pdf-renderer/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/next/react-pdf-renderer/output.js @@ -26501,8 +26501,7 @@ return t > (e = e.childExpirationTime) ? t : e; } function ie(e) { - var t = to(); - return tu(99, it.bind(null, e, t)), null; + return tu(99, it.bind(null, e, to())), null; } function it(e, t) { if (ir(), (48 & nx) != 0) throw Error(d(327)); diff --git a/crates/swc_ecma_minifier/tests/projects/output/react-dom-17.0.2.js b/crates/swc_ecma_minifier/tests/projects/output/react-dom-17.0.2.js index 5672b214d07e..ee8c7b943535 100644 --- a/crates/swc_ecma_minifier/tests/projects/output/react-dom-17.0.2.js +++ b/crates/swc_ecma_minifier/tests/projects/output/react-dom-17.0.2.js @@ -8072,8 +8072,7 @@ 0 === workInProgressRootExitStatus && (workInProgressRootExitStatus = 5); } function commitRoot(root) { - var renderPriorityLevel = getCurrentPriorityLevel(); - return runWithPriority$1(99, commitRootImpl.bind(null, root, renderPriorityLevel)), null; + return runWithPriority$1(99, commitRootImpl.bind(null, root, getCurrentPriorityLevel())), null; } function commitRootImpl(root, renderPriorityLevel) { do flushPassiveEffects();