diff --git a/core/ast/src/scope.rs b/core/ast/src/scope.rs index 08481649955..f453299712a 100644 --- a/core/ast/src/scope.rs +++ b/core/ast/src/scope.rs @@ -18,6 +18,7 @@ struct Binding { lex: bool, strict: bool, escapes: bool, + accessed: bool, } /// A scope maps bound identifiers to their binding positions. @@ -259,6 +260,7 @@ impl Scope { .iter_mut() .find(|b| &b.name == name) { + binding.accessed = true; if crossed_function_border || eval_or_with { binding.escapes = true; } @@ -296,6 +298,7 @@ impl Scope { lex: !function_scope, strict: false, escapes: self.is_global(), + accessed: false, }); BindingLocator::declarative( name, @@ -320,6 +323,7 @@ impl Scope { lex: true, strict, escapes: self.is_global(), + accessed: false, }); } @@ -583,6 +587,37 @@ impl FunctionScopes { &self.function_scope } + /// Returns if the arguments object is accessed in this function. + #[must_use] + pub fn arguments_object_accessed(&self) -> bool { + if self + .function_scope + .inner + .bindings + .borrow() + .first() + .filter(|b| b.name == "arguments" && b.accessed) + .is_some() + { + return true; + } + + if let Some(scope) = &self.parameters_eval_scope { + if scope + .inner + .bindings + .borrow() + .first() + .filter(|b| b.name == "arguments" && b.accessed) + .is_some() + { + return true; + } + } + + false + } + /// Returns the parameters eval scope for this function. #[must_use] pub fn parameters_eval_scope(&self) -> Option<&Scope> { diff --git a/core/engine/src/bytecompiler/declarations.rs b/core/engine/src/bytecompiler/declarations.rs index 06b91d9293c..73b9d430722 100644 --- a/core/engine/src/bytecompiler/declarations.rs +++ b/core/engine/src/bytecompiler/declarations.rs @@ -974,6 +974,10 @@ impl ByteCompiler<'_> { } } + if arguments_object_needed { + arguments_object_needed = scopes.arguments_object_accessed(); + } + // 19-20 drop(self.push_declarative_scope(scopes.parameters_eval_scope()));