From fa76365dff650e2a610daebf110472908f87cff4 Mon Sep 17 00:00:00 2001 From: sapphi-red <49056869+sapphi-red@users.noreply.github.com> Date: Sat, 20 Sep 2025 13:02:22 +0000 Subject: [PATCH] feat(minifier): only apply `arguments` copy loop transformation in strict mode (#13951) Made the arguments copy loop transformation to only apply in strict mode to reduce the assumptions held. --- crates/oxc_minifier/docs/ASSUMPTIONS.md | 10 +++------- .../src/peephole/substitute_alternate_syntax.rs | 17 ++++++++++++++++- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/crates/oxc_minifier/docs/ASSUMPTIONS.md b/crates/oxc_minifier/docs/ASSUMPTIONS.md index 054c8bcbede72..88bfdc3298321 100644 --- a/crates/oxc_minifier/docs/ASSUMPTIONS.md +++ b/crates/oxc_minifier/docs/ASSUMPTIONS.md @@ -98,17 +98,13 @@ eval('var x = 1'); new Function('return x'); ``` -### `arguments` is always [the arguments object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments) +### No access to a variable named `arguments` outside functions -`arguments` variables are only accessed inside functions and not assigned with a different value. We intend to change this assumption to optional in the future. +`arguments` variables are only accessed inside functions. We intend to change this assumption to optional in the future. ```javascript // The minifier assumes this never happens: -console.log(arguments); // This is not the arguments object -function f(a) { - arguments = 2; // This makes the arguments variable point not to point to the arguments object - return a; -} +console.log(arguments); ``` ## Optional Assumptions diff --git a/crates/oxc_minifier/src/peephole/substitute_alternate_syntax.rs b/crates/oxc_minifier/src/peephole/substitute_alternate_syntax.rs index 5d1726418aa1c..0c9c976ffb48c 100644 --- a/crates/oxc_minifier/src/peephole/substitute_alternate_syntax.rs +++ b/crates/oxc_minifier/src/peephole/substitute_alternate_syntax.rs @@ -530,6 +530,11 @@ impl<'a> PeepholeOptimizations { } } + // In non-strict mode, a different value may be reassigned to the `arguments` variable + if !ctx.current_scope_flags().is_strict_mode() { + return; + } + // FIXME: this function treats `arguments` not inside a function scope as if they are inside it // we should check in a different way than `ctx.is_global_reference` @@ -1517,12 +1522,16 @@ where /// Port from #[cfg(test)] mod test { + use oxc_span::SourceType; use oxc_syntax::es_target::ESTarget; use crate::{ CompressOptions, CompressOptionsUnused, options::CompressOptionsKeepNames, - tester::{default_options, test, test_options, test_same, test_same_options}, + tester::{ + default_options, test, test_options, test_same, test_same_options, + test_same_options_source_type, + }, }; #[test] @@ -2346,6 +2355,12 @@ mod test { test_same( "for (var e = arguments.length, r = Array(e > 1 ? e - 2 : 0), a = 2; a < e; a++) r[a - 2] = arguments[a];", ); + + test_same_options_source_type( + "for (var e = arguments.length, r = Array(e), a = 0; a < e; a++) r[a] = arguments[a]; console.log(r)", + SourceType::cjs(), + &default_options(), + ); } #[test]