Skip to content

Commit

Permalink
perf(es/utils): Restrict recursion of get_type (#9933)
Browse files Browse the repository at this point in the history
  • Loading branch information
kdy1 authored Jan 23, 2025
1 parent d24f785 commit 1781b85
Show file tree
Hide file tree
Showing 16 changed files with 89 additions and 61 deletions.
6 changes: 6 additions & 0 deletions .changeset/empty-steaks-dream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
swc_ecma_ast: minor
swc_ecma_utils: major
---

perf(es/utils): Restrict recursion of `get_type`
8 changes: 4 additions & 4 deletions crates/swc_ecma_minifier/src/compress/optimize/bools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,13 @@ impl Optimizer<'_> {
}

if !is_ret_val_ignored {
if let Known(Type::Bool) = e.left.get_type() {
if let Known(Type::Bool) = e.left.get_type(self.ctx.expr_ctx) {
} else {
// Don't change type.
return false;
}

if let Known(Type::Bool) = e.right.get_type() {
if let Known(Type::Bool) = e.right.get_type(self.ctx.expr_ctx) {
} else {
// Don't change type.
return false;
Expand Down Expand Up @@ -277,8 +277,8 @@ impl Optimizer<'_> {
_ => return None,
};

let lt = left.get_type();
let rt = right.get_type();
let lt = left.get_type(self.ctx.expr_ctx);
let rt = right.get_type(self.ctx.expr_ctx);
if let Value::Known(lt) = lt {
if let Value::Known(rt) = rt {
match (lt, rt) {
Expand Down
4 changes: 2 additions & 2 deletions crates/swc_ecma_minifier/src/compress/optimize/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1630,11 +1630,11 @@ impl VisitMut for Optimizer<'_> {
self.optimize_bin_and_or(n);

if n.op == op!(bin, "+") {
if let Known(Type::Str) = n.left.get_type() {
if let Known(Type::Str) = n.left.get_type(self.ctx.expr_ctx) {
self.optimize_expr_in_str_ctx(&mut n.right);
}

if let Known(Type::Str) = n.right.get_type() {
if let Known(Type::Str) = n.right.get_type(self.ctx.expr_ctx) {
self.optimize_expr_in_str_ctx(&mut n.left);
}
}
Expand Down
15 changes: 9 additions & 6 deletions crates/swc_ecma_minifier/src/compress/optimize/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ impl Optimizer<'_> {
}
}

let lt = e.left.get_type();
let rt = e.right.get_type();
let lt = e.left.get_type(self.ctx.expr_ctx);
let rt = e.right.get_type(self.ctx.expr_ctx);

if e.op == op!("===") {
if let Known(lt) = lt {
Expand Down Expand Up @@ -127,7 +127,10 @@ impl Optimizer<'_> {
.into(),
)
};
match (n.left.get_type().opt()?, n.right.get_type().opt()?) {
match (
n.left.get_type(self.ctx.expr_ctx).opt()?,
n.right.get_type(self.ctx.expr_ctx).opt()?,
) {
// Abort if types differ, or one of them is unknown.
(lt, rt) if lt != rt => {}
(Type::Obj, Type::Obj) => {}
Expand Down Expand Up @@ -181,7 +184,7 @@ impl Optimizer<'_> {
| Expr::Bin(BinExpr { op: op!("<"), .. })
| Expr::Bin(BinExpr { op: op!(">="), .. })
| Expr::Bin(BinExpr { op: op!(">"), .. }) => {
if let Known(Type::Bool) = arg.get_type() {
if let Known(Type::Bool) = arg.get_type(self.ctx.expr_ctx) {
self.changed = true;
report_change!("Optimizing: `!!expr` => `expr`");
*e = *arg.take();
Expand Down Expand Up @@ -299,14 +302,14 @@ impl Optimizer<'_> {
_ => {}
}

let lt = bin.left.get_type();
let lt = bin.left.get_type(self.ctx.expr_ctx);
match lt {
// Don't change type
Known(Type::Bool) => {}
_ => return,
}

let rt = bin.right.get_type();
let rt = bin.right.get_type(self.ctx.expr_ctx);
match rt {
Known(Type::Bool) => {}
_ => return,
Expand Down
4 changes: 2 additions & 2 deletions crates/swc_ecma_minifier/src/compress/optimize/sequences.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2371,7 +2371,7 @@ impl Optimizer<'_> {
Mergable::Drop => return Ok(false),
};

let a_type = a_right.as_deref().map(|a| a.get_type());
let a_type = a_right.as_deref().map(|a| a.get_type(self.ctx.expr_ctx));

if let Some(a_right) = a_right {
if a_right.is_this() || a_right.is_ident_ref_to("arguments") {
Expand Down Expand Up @@ -2484,7 +2484,7 @@ impl Optimizer<'_> {
let Some(a_type) = a_type else {
return Ok(false);
};
let b_type = b.right.get_type();
let b_type = b.right.get_type(self.ctx.expr_ctx);

if let Some(a_op) = a_op {
if can_drop_op_for(a_op, b.op, var_type, a_type, b_type) {
Expand Down
20 changes: 10 additions & 10 deletions crates/swc_ecma_minifier/src/compress/pure/bools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,19 +85,19 @@ impl Pure<'_> {
matches!(op, op!("==") | op!("===") | op!("!=") | op!("!=="))
}

fn can_absorb_negate(e: &Expr) -> bool {
fn can_absorb_negate(e: &Expr, ctx: ExprCtx) -> bool {
match e {
Expr::Lit(_) => true,
Expr::Bin(BinExpr {
op: op!("&&") | op!("||"),
left,
right,
..
}) => can_absorb_negate(left) && can_absorb_negate(right),
}) => can_absorb_negate(left, ctx) && can_absorb_negate(right, ctx),
Expr::Bin(BinExpr { op, .. }) if is_eq(*op) => true,
Expr::Unary(UnaryExpr {
op: op!("!"), arg, ..
}) => arg.get_type() == Value::Known(Type::Bool),
}) => arg.get_type(ctx) == Value::Known(Type::Bool),
_ => false,
}
}
Expand All @@ -123,7 +123,7 @@ impl Pure<'_> {
return;
};

let arg_can_negate = can_absorb_negate(arg);
let arg_can_negate = can_absorb_negate(arg, self.expr_ctx);

match &mut **arg {
Expr::Bin(BinExpr { op, .. }) if is_eq(*op) => {
Expand Down Expand Up @@ -158,7 +158,7 @@ impl Pure<'_> {
}

pub(super) fn compress_cmp_with_long_op(&mut self, e: &mut BinExpr) {
fn should_optimize(l: &Expr, r: &Expr, opts: &CompressOptions) -> bool {
fn should_optimize(l: &Expr, r: &Expr, ctx: ExprCtx, opts: &CompressOptions) -> bool {
match (l, r) {
(
Expr::Unary(UnaryExpr {
Expand All @@ -168,7 +168,7 @@ impl Pure<'_> {
) => true,
_ => {
if opts.comparisons {
match (l.get_type(), r.get_type()) {
match (l.get_type(ctx), r.get_type(ctx)) {
(Value::Known(lt), Value::Known(rt)) => lt == rt,

_ => false,
Expand All @@ -185,8 +185,8 @@ impl Pure<'_> {
_ => return,
}

if should_optimize(&e.left, &e.right, self.options)
|| should_optimize(&e.right, &e.left, self.options)
if should_optimize(&e.left, &e.right, self.expr_ctx, self.options)
|| should_optimize(&e.right, &e.left, self.expr_ctx, self.options)
{
report_change!("bools: Compressing comparison of `typeof` with literal");
self.changed = true;
Expand Down Expand Up @@ -226,8 +226,8 @@ impl Pure<'_> {
right,
..
}) => {
let lt = left.get_type();
let rt = right.get_type();
let lt = left.get_type(self.expr_ctx);
let rt = right.get_type(self.expr_ctx);

if let (Value::Known(Type::Bool), Value::Known(Type::Bool)) = (lt, rt) {
let rb = right.as_pure_bool(self.expr_ctx);
Expand Down
8 changes: 4 additions & 4 deletions crates/swc_ecma_minifier/src/compress/pure/conds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ impl Pure<'_> {

let Expr::Cond(cond) = e else { return };

let lt = cond.cons.get_type();
let lt = cond.cons.get_type(self.expr_ctx);
if let Value::Known(Type::Bool) = lt {
let lb = cond.cons.as_pure_bool(self.expr_ctx);
if let Value::Known(true) = lb {
Expand Down Expand Up @@ -59,7 +59,7 @@ impl Pure<'_> {
}
}

let rt = cond.alt.get_type();
let rt = cond.alt.get_type(self.expr_ctx);
if let Value::Known(Type::Bool) = rt {
let rb = cond.alt.as_pure_bool(self.expr_ctx);
if let Value::Known(false) = rb {
Expand Down Expand Up @@ -220,8 +220,8 @@ impl Pure<'_> {
return;
}

let lt = bin.left.get_type();
let rt = bin.right.get_type();
let lt = bin.left.get_type(self.expr_ctx);
let rt = bin.right.get_type(self.expr_ctx);

let _lb = bin.left.as_pure_bool(self.expr_ctx);
let rb = bin.right.as_pure_bool(self.expr_ctx);
Expand Down
4 changes: 2 additions & 2 deletions crates/swc_ecma_minifier/src/compress/pure/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1675,8 +1675,8 @@ impl Pure<'_> {
_ => return,
};

let lt = cond.cons.get_type();
let rt = cond.alt.get_type();
let lt = cond.cons.get_type(self.expr_ctx);
let rt = cond.alt.get_type(self.expr_ctx);
match (lt, rt) {
(Known(Type::Bool), Known(Type::Bool)) => {}
_ => return,
Expand Down
12 changes: 6 additions & 6 deletions crates/swc_ecma_minifier/src/compress/pure/strings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ impl Pure<'_> {
_ => return,
};

match l_l.get_type() {
match l_l.get_type(self.expr_ctx) {
Known(Type::Str) => {}
_ => return,
}
match r_l.get_type() {
match r_l.get_type(self.expr_ctx) {
Known(Type::Str) => {}
_ => return,
}
Expand Down Expand Up @@ -487,8 +487,8 @@ impl Pure<'_> {
},
) = &mut *bin.left
{
let type_of_second = left.right.get_type();
let type_of_third = bin.right.get_type();
let type_of_second = left.right.get_type(self.expr_ctx);
let type_of_third = bin.right.get_type(self.expr_ctx);

if let Value::Known(Type::Str) = type_of_second {
if let Value::Known(Type::Str) = type_of_third {
Expand Down Expand Up @@ -534,8 +534,8 @@ impl Pure<'_> {
..
}) = e
{
let lt = left.get_type();
let rt = right.get_type();
let lt = left.get_type(self.expr_ctx);
let rt = right.get_type(self.expr_ctx);
if let Value::Known(Type::Str) = lt {
if let Value::Known(Type::Str) = rt {
match &**left {
Expand Down
3 changes: 2 additions & 1 deletion crates/swc_ecma_minifier/tests/benches-full/react.js
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,8 @@
throw payload._result;
}
function isValidElementType(type) {
return 'string' == typeof type || 'function' == typeof type || type === exports.Fragment || type === exports.Profiler || type === REACT_DEBUG_TRACING_MODE_TYPE || type === exports.StrictMode || type === exports.Suspense || type === REACT_SUSPENSE_LIST_TYPE || type === REACT_LEGACY_HIDDEN_TYPE || 'object' == typeof type && null !== type && (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_PROVIDER_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || type.$$typeof === REACT_FUNDAMENTAL_TYPE || type.$$typeof === REACT_BLOCK_TYPE || type[0] === REACT_SERVER_BLOCK_TYPE);
return 'string' == typeof type || 'function' == typeof type || type === exports.Fragment || type === exports.Profiler || type === REACT_DEBUG_TRACING_MODE_TYPE || type === exports.StrictMode || type === exports.Suspense || type === REACT_SUSPENSE_LIST_TYPE || type === REACT_LEGACY_HIDDEN_TYPE || 'object' == typeof type && null !== type && (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_PROVIDER_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || type.$$typeof === REACT_FUNDAMENTAL_TYPE || type.$$typeof === REACT_BLOCK_TYPE || type[0] === REACT_SERVER_BLOCK_TYPE) || !1 // Note: typeof might be other than 'symbol' or 'number' (e.g. if it's a polyfill).
;
}
function resolveDispatcher() {
var dispatcher = ReactCurrentDispatcher.current;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6701,7 +6701,7 @@
* LICENSE file in the root directory of this source tree.
*/ var u, b = Symbol.for("react.element"), c = Symbol.for("react.portal"), d = Symbol.for("react.fragment"), e = Symbol.for("react.strict_mode"), f = Symbol.for("react.profiler"), g = Symbol.for("react.provider"), h = Symbol.for("react.context"), k = Symbol.for("react.server_context"), l = Symbol.for("react.forward_ref"), m = Symbol.for("react.suspense"), n = Symbol.for("react.suspense_list"), p = Symbol.for("react.memo"), q = Symbol.for("react.lazy"), t = Symbol.for("react.offscreen");
u = Symbol.for("react.module.reference"), exports.isValidElementType = function(a) {
return "string" == typeof a || "function" == typeof a || a === d || a === f || a === e || a === m || a === n || a === t || "object" == typeof a && null !== a && (a.$$typeof === q || a.$$typeof === p || a.$$typeof === g || a.$$typeof === h || a.$$typeof === l || a.$$typeof === u || void 0 !== a.getModuleId);
return "string" == typeof a || "function" == typeof a || a === d || a === f || a === e || a === m || a === n || a === t || "object" == typeof a && null !== a && (a.$$typeof === q || a.$$typeof === p || a.$$typeof === g || a.$$typeof === h || a.$$typeof === l || a.$$typeof === u || void 0 !== a.getModuleId) || !1;
}, exports.typeOf = function(a) {
if ("object" == typeof a && null !== a) {
var r = a.$$typeof;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27994,7 +27994,7 @@

*/ ToolbarRenderer.prototype.renderColorPickerDropDown = function(args, item, colorPicker, defaultColor) {
var range, _this = this, proxy = this, css = classes /* CLS_RTE_ELEMENTS */ .i7 + ' ' + classes /* CLS_TB_BTN */ .Fs + (this.parent.inlineMode ? ' ' + classes /* CLS_INLINE_DROPDOWN */ .ZV : '');
css += ' ' + ('backgroundcolor' === item ? classes /* CLS_BACKGROUND_COLOR_DROPDOWN */ .Z8 : classes /* CLS_FONT_COLOR_DROPDOWN */ .UQ) + ' ' + this.parent.cssClass;
css += ' ' + ('backgroundcolor' === item ? classes /* CLS_BACKGROUND_COLOR_DROPDOWN */ .Z8 : classes /* CLS_FONT_COLOR_DROPDOWN */ .UQ), css += ' ' + this.parent.cssClass;
var content = proxy.parent.createElement('span', {
className: classes /* CLS_COLOR_CONTENT */ .uN
}), inlineEle = proxy.parent.createElement('span', {
Expand Down Expand Up @@ -30011,7 +30011,7 @@
* @returns {boolean} - returns the boolean value
* @hidden
*/ function isEditableValueEmpty(value) {
return '<p><br></p>' === value || '&lt;p&gt;&lt;br&gt;&lt;/p&gt;' === value || '<div><br></div>' === value || '&lt;div&gt;&lt;br&gt;&lt;/div&gt;' === value || '<br>' === value || '&lt;br&gt;' === value || '' === value;
return '<p><br></p>' === value || '&lt;p&gt;&lt;br&gt;&lt;/p&gt;' === value || '<div><br></div>' === value || '&lt;div&gt;&lt;br&gt;&lt;/div&gt;' === value || '<br>' === value || '&lt;br&gt;' === value || '' === value || !1;
}
/**
* @param {string} value - specifies the string value
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,8 @@
throw payload._result;
}
function isValidElementType(type) {
return "string" == typeof type || "function" == typeof type || type === exports.Fragment || type === exports.Profiler || type === REACT_DEBUG_TRACING_MODE_TYPE || type === exports.StrictMode || type === exports.Suspense || type === REACT_SUSPENSE_LIST_TYPE || type === REACT_LEGACY_HIDDEN_TYPE || "object" == typeof type && null !== type && (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_PROVIDER_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || type.$$typeof === REACT_FUNDAMENTAL_TYPE || type.$$typeof === REACT_BLOCK_TYPE || type[0] === REACT_SERVER_BLOCK_TYPE);
return "string" == typeof type || "function" == typeof type || type === exports.Fragment || type === exports.Profiler || type === REACT_DEBUG_TRACING_MODE_TYPE || type === exports.StrictMode || type === exports.Suspense || type === REACT_SUSPENSE_LIST_TYPE || type === REACT_LEGACY_HIDDEN_TYPE || "object" == typeof type && null !== type && (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_PROVIDER_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || type.$$typeof === REACT_FUNDAMENTAL_TYPE || type.$$typeof === REACT_BLOCK_TYPE || type[0] === REACT_SERVER_BLOCK_TYPE) || !1 // Note: typeof might be other than 'symbol' or 'number' (e.g. if it's a polyfill).
;
}
function resolveDispatcher() {
var dispatcher = ReactCurrentDispatcher.current;
Expand Down
18 changes: 12 additions & 6 deletions crates/swc_ecma_transforms_optimization/src/simplify/expr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ impl SimplifyExpr {
}
}

match expr.get_type() {
match expr.get_type(self.expr_ctx) {
// String concatenation
Known(StringType) => match expr {
Expr::Bin(BinExpr {
Expand Down Expand Up @@ -911,8 +911,8 @@ impl SimplifyExpr {

if (lv.is_unknown() && rv.is_unknown())
|| op == op!(bin, "+")
&& (!left.get_type().casted_to_number_on_add()
|| !right.get_type().casted_to_number_on_add())
&& (!left.get_type(self.expr_ctx).casted_to_number_on_add()
|| !right.get_type(self.expr_ctx).casted_to_number_on_add())
{
return Unknown;
}
Expand Down Expand Up @@ -1067,7 +1067,7 @@ impl SimplifyExpr {
}

// Try to evaluate based on the general type.
let (lt, rt) = (left.get_type(), right.get_type());
let (lt, rt) = (left.get_type(self.expr_ctx), right.get_type(self.expr_ctx));

if let (Known(StringType), Known(StringType)) = (lt, rt) {
if let (Known(lv), Known(rv)) = (
Expand Down Expand Up @@ -1099,7 +1099,10 @@ impl SimplifyExpr {

/// https://tc39.github.io/ecma262/#sec-abstract-equality-comparison
fn perform_abstract_eq_cmp(&mut self, span: Span, left: &Expr, right: &Expr) -> Value<bool> {
let (lt, rt) = (try_val!(left.get_type()), try_val!(right.get_type()));
let (lt, rt) = (
try_val!(left.get_type(self.expr_ctx)),
try_val!(right.get_type(self.expr_ctx)),
);

if lt == rt {
return self.perform_strict_eq_cmp(left, right);
Expand Down Expand Up @@ -1171,7 +1174,10 @@ impl SimplifyExpr {
_ => {}
}

let (lt, rt) = (try_val!(left.get_type()), try_val!(right.get_type()));
let (lt, rt) = (
try_val!(left.get_type(self.expr_ctx)),
try_val!(right.get_type(self.expr_ctx)),
);
// Strict equality can only be true for values of the same type.
if lt != rt {
return Known(false);
Expand Down
15 changes: 11 additions & 4 deletions crates/swc_ecma_usage_analyzer/src/analyzer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,15 +276,19 @@ where
match &n.left {
AssignTarget::Pat(p) => {
for id in find_pat_ids(p) {
self.data
.report_assign(self.ctx, id, is_op_assign, n.right.get_type())
self.data.report_assign(
self.ctx,
id,
is_op_assign,
n.right.get_type(self.expr_ctx),
)
}
}
AssignTarget::Simple(e) => {
self.report_assign_expr_if_ident(
e.as_ident().map(Ident::from).as_ref(),
is_op_assign,
n.right.get_type(),
n.right.get_type(self.expr_ctx),
);
self.mark_mutation_if_member(e.as_member())
}
Expand Down Expand Up @@ -1304,7 +1308,10 @@ where
let ctx = Ctx {
inline_prevented: self.ctx.inline_prevented || prevent_inline,
in_pat_of_var_decl: true,
in_pat_of_var_decl_with_init: e.init.as_ref().map(|init| init.get_type()),
in_pat_of_var_decl_with_init: e
.init
.as_ref()
.map(|init| init.get_type(self.expr_ctx)),
in_decl_with_no_side_effect_for_member_access: e
.init
.as_deref()
Expand Down
Loading

0 comments on commit 1781b85

Please sign in to comment.