Prechádzať zdrojové kódy

Reduce memory allocations in function calls (#1282)

Marko Lahma 2 rokov pred
rodič
commit
704a016ce4

+ 4 - 3
Jint/Engine.cs

@@ -805,7 +805,8 @@ namespace Jint
             Script script,
             GlobalEnvironmentRecord env)
         {
-            var hoistingScope = HoistingScope.GetProgramLevelDeclarations(script);
+            var strict = _isStrict || StrictModeScope.IsStrictModeCode;
+            var hoistingScope = HoistingScope.GetProgramLevelDeclarations(strict, script);
             var functionDeclarations = hoistingScope._functionDeclarations;
             var varDeclarations = hoistingScope._variablesDeclarations;
             var lexDeclarations = hoistingScope._lexicalDeclarations;
@@ -928,7 +929,7 @@ namespace Jint
             var func = functionInstance._functionDefinition;
 
             var env = (FunctionEnvironmentRecord) ExecutionContext.LexicalEnvironment;
-            var strict = StrictModeScope.IsStrictModeCode;
+            var strict = _isStrict || StrictModeScope.IsStrictModeCode;
 
             var configuration = func.Initialize(functionInstance);
             var parameterNames = configuration.ParameterNames;
@@ -1085,7 +1086,7 @@ namespace Jint
             PrivateEnvironmentRecord? privateEnv,
             bool strict)
         {
-            var hoistingScope = HoistingScope.GetProgramLevelDeclarations(script);
+            var hoistingScope = HoistingScope.GetProgramLevelDeclarations(strict, script);
 
             var lexEnvRec = (DeclarativeEnvironmentRecord) lexEnv;
             var varEnvRec = varEnv;

+ 34 - 20
Jint/HoistingScope.cs

@@ -12,50 +12,66 @@ namespace Jint
 
         internal readonly List<Declaration>? _lexicalDeclarations;
         internal readonly List<string>? _lexicalNames;
+        internal readonly bool _hasArgumentsReference;
 
-        private HoistingScope(
-            List<FunctionDeclaration>? functionDeclarations,
+        private HoistingScope(List<FunctionDeclaration>? functionDeclarations,
             List<Key>? varNames,
             List<VariableDeclaration>? variableDeclarations,
             List<Declaration>? lexicalDeclarations,
-            List<string>? lexicalNames)
+            List<string>? lexicalNames,
+            bool hasArgumentsReference)
         {
             _functionDeclarations = functionDeclarations;
             _varNames = varNames;
             _variablesDeclarations = variableDeclarations;
             _lexicalDeclarations = lexicalDeclarations;
             _lexicalNames = lexicalNames;
+            _hasArgumentsReference = hasArgumentsReference;
         }
 
         public static HoistingScope GetProgramLevelDeclarations(
+            bool strict,
             Program script,
             bool collectVarNames = false,
             bool collectLexicalNames = false)
         {
-            var treeWalker = new ScriptWalker(StrictModeScope.IsStrictModeCode, collectVarNames, collectLexicalNames);
+            var treeWalker = new ScriptWalker(strict, collectVarNames, collectLexicalNames, checkArgumentsReference: false);
             treeWalker.Visit(script, null);
             return new HoistingScope(
                 treeWalker._functions,
                 treeWalker._varNames,
                 treeWalker._variableDeclarations,
                 treeWalker._lexicalDeclarations,
-                treeWalker._lexicalNames);
+                treeWalker._lexicalNames,
+                false);
         }
 
         public static HoistingScope GetFunctionLevelDeclarations(
+            bool strict,
             IFunction node,
             bool collectVarNames = false,
-            bool collectLexicalNames = false)
+            bool collectLexicalNames = false,
+            bool checkArgumentsReference = false)
         {
-            var treeWalker = new ScriptWalker(StrictModeScope.IsStrictModeCode, collectVarNames, collectLexicalNames);
+            var treeWalker = new ScriptWalker(strict, collectVarNames, collectLexicalNames, checkArgumentsReference);
             treeWalker.Visit(node.Body, null);
 
+            if (checkArgumentsReference && !treeWalker._hasArgumentsReference)
+            {
+                ref readonly var parameters = ref node.Params;
+                for (var i = 0; i < parameters.Count; ++i)
+                {
+                    treeWalker.Visit(parameters[i], null);
+                }
+            }
+
             return new HoistingScope(
                 treeWalker._functions,
                 treeWalker._varNames,
                 treeWalker._variableDeclarations,
                 treeWalker._lexicalDeclarations,
-                treeWalker._lexicalNames);
+                treeWalker._lexicalNames,
+                treeWalker._hasArgumentsReference);
         }
 
         public static HoistingScope GetModuleLevelDeclarations(
@@ -64,14 +80,15 @@ namespace Jint
             bool collectLexicalNames = false)
         {
             //Modules area always strict
-            var treeWalker = new ScriptWalker(true, collectVarNames, collectLexicalNames);
+            var treeWalker = new ScriptWalker(strict: true, collectVarNames, collectLexicalNames, checkArgumentsReference: false);
             treeWalker.Visit(module, null);
             return new HoistingScope(
                 treeWalker._functions,
                 treeWalker._varNames,
                 treeWalker._variableDeclarations,
                 treeWalker._lexicalDeclarations,
-                treeWalker._lexicalNames);
+                treeWalker._lexicalNames,
+                false);
         }
 
         public static List<Declaration>? GetLexicalDeclarations(BlockStatement statement)
@@ -211,24 +228,26 @@ namespace Jint
             internal List<Key>? _varNames;
 
             private readonly bool _collectLexicalNames;
+            private readonly bool _checkArgumentsReference;
             internal List<Declaration>? _lexicalDeclarations;
             internal List<string>? _lexicalNames;
+            internal bool _hasArgumentsReference;
 
-            public ScriptWalker(bool strict, bool collectVarNames, bool collectLexicalNames)
+            public ScriptWalker(bool strict, bool collectVarNames, bool collectLexicalNames, bool checkArgumentsReference)
             {
                 _strict = strict;
                 _collectVarNames = collectVarNames;
                 _collectLexicalNames = collectLexicalNames;
+                _checkArgumentsReference = checkArgumentsReference;
             }
 
             public void Visit(Node node, Node? parent)
             {
                 foreach (var childNode in node.ChildNodes)
                 {
-                    if (childNode is null)
+                    if (_checkArgumentsReference && childNode.Type == Nodes.Identifier)
                     {
-                        // array expression can push null nodes in Esprima
-                        continue;
+                        _hasArgumentsReference |= ((Identifier) childNode).Name == "arguments";
                     }
 
                     if (childNode.Type == Nodes.VariableDeclaration)
@@ -252,7 +271,7 @@ namespace Jint
                             }
                         }
 
-                        if ((parent is null or Module) && variableDeclaration.Kind != VariableDeclarationKind.Var)
+                        if (parent is null or Module && variableDeclaration.Kind != VariableDeclarationKind.Var)
                         {
                             _lexicalDeclarations ??= new List<Declaration>();
                             _lexicalDeclarations.Add(variableDeclaration);
@@ -305,11 +324,6 @@ namespace Jint
             {
                 foreach (var childNode in node.ChildNodes)
                 {
-                    if (childNode is null)
-                    {
-                        continue;
-                    }
-
                     if (childNode.Type == Nodes.ImportDeclaration)
                     {
                         _importEntries ??= new();

+ 13 - 10
Jint/Runtime/Environments/DeclarativeEnvironmentRecord.cs

@@ -11,7 +11,7 @@ namespace Jint.Runtime.Environments
     /// </summary>
     internal class DeclarativeEnvironmentRecord : EnvironmentRecord
     {
-        internal readonly HybridDictionary<Binding> _dictionary = new();
+        internal HybridDictionary<Binding>? _dictionary;
         internal readonly bool _catchEnvironment;
 
         public DeclarativeEnvironmentRecord(Engine engine, bool catchEnvironment = false) : base(engine)
@@ -21,12 +21,12 @@ namespace Jint.Runtime.Environments
 
         public sealed override bool HasBinding(string name)
         {
-            return _dictionary.ContainsKey(name);
+            return _dictionary is not null && _dictionary.ContainsKey(name);
         }
 
         internal sealed override bool HasBinding(in BindingName name)
         {
-            return _dictionary.ContainsKey(name.Key);
+            return _dictionary is not null &&_dictionary.ContainsKey(name.Key);
         }
 
         internal override bool TryGetBinding(
@@ -36,33 +36,38 @@ namespace Jint.Runtime.Environments
             [NotNullWhen(true)] out JsValue? value)
         {
             binding = default;
-            var success = _dictionary.TryGetValue(name.Key, out binding);
+            var success = _dictionary is not null &&_dictionary.TryGetValue(name.Key, out binding);
             value = success && binding.IsInitialized() ? binding.Value : default;
             return success;
         }
 
         internal void CreateMutableBindingAndInitialize(Key name, bool canBeDeleted, JsValue value)
         {
+            _dictionary ??= new HybridDictionary<Binding>();
             _dictionary[name] = new Binding(value, canBeDeleted, mutable: true, strict: false);
         }
 
         internal void CreateImmutableBindingAndInitialize(Key name, bool strict, JsValue value)
         {
+            _dictionary ??= new HybridDictionary<Binding>();
             _dictionary[name] = new Binding(value, canBeDeleted: false, mutable: false, strict);
         }
 
         public sealed override void CreateMutableBinding(string name, bool canBeDeleted = false)
         {
+            _dictionary ??= new HybridDictionary<Binding>();
             _dictionary[name] = new Binding(null!, canBeDeleted, mutable: true, strict: false);
         }
 
         public sealed override void CreateImmutableBinding(string name, bool strict = true)
         {
+            _dictionary ??= new HybridDictionary<Binding>();
             _dictionary[name] = new Binding(null!, canBeDeleted: false, mutable: false, strict);
         }
 
         public sealed override void InitializeBinding(string name, JsValue value)
         {
+            _dictionary ??= new HybridDictionary<Binding>();
             _dictionary.SetOrUpdateValue(name, static (current, value) => current.ChangeValue(value), value);
         }
 
@@ -74,7 +79,7 @@ namespace Jint.Runtime.Environments
         public sealed override void SetMutableBinding(string name, JsValue value, bool strict)
         {
             var key = (Key) name;
-            if (!_dictionary.TryGetValue(key, out var binding))
+            if (_dictionary is null || !_dictionary.TryGetValue(key, out var binding))
             {
                 if (strict)
                 {
@@ -110,8 +115,7 @@ namespace Jint.Runtime.Environments
 
         public override JsValue GetBindingValue(string name, bool strict)
         {
-            _dictionary.TryGetValue(name, out var binding);
-            if (binding.IsInitialized())
+            if (_dictionary is not null && _dictionary.TryGetValue(name, out var binding) && binding.IsInitialized())
             {
                 return binding.Value;
             }
@@ -122,8 +126,7 @@ namespace Jint.Runtime.Environments
 
         internal sealed override bool TryGetBindingValue(string name, bool strict, [NotNullWhen(true)] out JsValue? value)
         {
-            _dictionary.TryGetValue(name, out var binding);
-            if (binding.IsInitialized())
+            if (_dictionary is not null && _dictionary.TryGetValue(name, out var binding) && binding.IsInitialized())
             {
                 value = binding.Value;
                 return true;
@@ -140,7 +143,7 @@ namespace Jint.Runtime.Environments
 
         public sealed override bool DeleteBinding(string name)
         {
-            if (!_dictionary.TryGetValue(name, out var binding))
+            if (_dictionary is null || !_dictionary.TryGetValue(name, out var binding))
             {
                 return true;
             }

+ 28 - 11
Jint/Runtime/Environments/FunctionEnvironmentRecord.cs

@@ -1,5 +1,6 @@
 using System.Runtime.CompilerServices;
 using Esprima.Ast;
+using Jint.Collections;
 using Jint.Native;
 using Jint.Native.Array;
 using Jint.Native.Function;
@@ -51,13 +52,15 @@ namespace Jint.Runtime.Environments
 
         public JsValue BindThisValue(JsValue value)
         {
-            if (_thisBindingStatus == ThisBindingStatus.Initialized)
+            if (_thisBindingStatus != ThisBindingStatus.Initialized)
             {
-                ExceptionHelper.ThrowReferenceError(_functionObject._realm, "'this' has already been bound");
+                _thisValue = value;
+                _thisBindingStatus = ThisBindingStatus.Initialized;
+                return value;
             }
-            _thisValue = value;
-            _thisBindingStatus = ThisBindingStatus.Initialized;
-            return value;
+
+            ExceptionHelper.ThrowReferenceError(_functionObject._realm, "'this' has already been bound");
+            return null!;
         }
 
         public override JsValue GetThisBinding()
@@ -67,6 +70,13 @@ namespace Jint.Runtime.Environments
                 return _thisValue!;
             }
 
+            ThrowUninitializedThis();
+            return null!;
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        private void ThrowUninitializedThis()
+        {
             var message = "Cannot access uninitialized 'this'";
             if (NewTarget is ScriptFunctionInstance { _isClassConstructor: true, _constructorKind: ConstructorKind.Derived })
             {
@@ -75,7 +85,6 @@ namespace Jint.Runtime.Environments
             }
 
             ExceptionHelper.ThrowReferenceError(_engine.ExecutionContext.Realm, message);
-            return null;
         }
 
         public JsValue GetSuperBase()
@@ -93,19 +102,25 @@ namespace Jint.Runtime.Environments
             bool hasDuplicates,
             JsValue[]? arguments)
         {
+            if (parameterNames.Length == 0)
+            {
+                return;
+            }
+
             var value = hasDuplicates ? Undefined : null;
-            var directSet = !hasDuplicates && _dictionary.Count == 0;
-            for (var i = 0; (uint) i < (uint) parameterNames.Length; i++)
+            var directSet = !hasDuplicates && (_dictionary is null || _dictionary.Count == 0);
+            for (uint i = 0; i < (uint) parameterNames.Length; i++)
             {
                 var paramName = parameterNames[i];
-                if (directSet || !_dictionary.ContainsKey(paramName))
+                if (directSet || _dictionary is null || !_dictionary.ContainsKey(paramName))
                 {
                     var parameterValue = value;
                     if (arguments != null)
                     {
-                        parameterValue = (uint) i < (uint) arguments.Length ? arguments[i] : Undefined;
+                        parameterValue = i < (uint) arguments.Length ? arguments[i] : Undefined;
                     }
 
+                    _dictionary ??= new HybridDictionary<Binding>();
                     _dictionary[paramName] = new Binding(parameterValue!, canBeDeleted: false, mutable: true, strict: false);
                 }
             }
@@ -113,7 +128,7 @@ namespace Jint.Runtime.Environments
 
         internal void AddFunctionParameters(EvaluationContext context, IFunction functionDeclaration, JsValue[] arguments)
         {
-            bool empty = _dictionary.Count == 0;
+            var empty = _dictionary is null || _dictionary.Count == 0;
             ref readonly var parameters = ref functionDeclaration.Params;
             var count = parameters.Count;
             for (var i = 0; i < count; i++)
@@ -377,6 +392,7 @@ namespace Jint.Runtime.Environments
         {
             if (initiallyEmpty)
             {
+                _dictionary ??= new HybridDictionary<Binding>();
                 _dictionary[name] = new Binding(argument, canBeDeleted: false, mutable: true, strict: false);
             }
             else
@@ -387,6 +403,7 @@ namespace Jint.Runtime.Environments
 
         private void SetItemCheckExisting(Key name, JsValue argument)
         {
+            _dictionary ??= new HybridDictionary<Binding>();
             if (!_dictionary.TryGetValue(name, out var existing))
             {
                 _dictionary[name] = new Binding(argument, canBeDeleted: false, mutable: true, strict: false);

+ 1 - 1
Jint/Runtime/Interpreter/Expressions/JintCallExpression.cs

@@ -60,7 +60,7 @@ namespace Jint.Runtime.Interpreter.Expressions
             if (cacheable)
             {
                 _cached = true;
-                var arguments = System.Array.Empty<JsValue>();
+                var arguments = Array.Empty<JsValue>();
                 if (cachedArgumentsHolder.JintArguments.Length > 0)
                 {
                     arguments = new JsValue[cachedArgumentsHolder.JintArguments.Length];

+ 0 - 1
Jint/Runtime/Interpreter/Expressions/JintFunctionExpression.cs

@@ -1,5 +1,4 @@
 using Esprima.Ast;
-using Jint.Native;
 using Jint.Native.Function;
 using Jint.Runtime.Environments;
 

+ 282 - 271
Jint/Runtime/Interpreter/JintFunctionDefinition.cs

@@ -4,275 +4,306 @@ using Jint.Native;
 using Jint.Native.Function;
 using Jint.Runtime.Interpreter.Expressions;
 
-namespace Jint.Runtime.Interpreter
+namespace Jint.Runtime.Interpreter;
+
+/// <summary>
+/// Works as memento for function execution. Optimization to cache things that don't change.
+/// </summary>
+internal sealed class JintFunctionDefinition
 {
-    /// <summary>
-    /// Works as memento for function execution. Optimization to cache things that don't change.
-    /// </summary>
-    internal sealed class JintFunctionDefinition
-    {
-        private readonly Engine _engine;
+    private readonly Engine _engine;
 
-        private JintExpression? _bodyExpression;
-        private JintStatementList? _bodyStatementList;
+    private JintExpression? _bodyExpression;
+    private JintStatementList? _bodyStatementList;
 
-        public readonly string? Name;
-        public readonly bool Strict;
-        public readonly IFunction Function;
+    public readonly string? Name;
+    public readonly bool Strict;
+    public readonly IFunction Function;
 
-        private State? _state;
+    private State? _state;
 
-        public JintFunctionDefinition(
-            Engine engine,
-            IFunction function)
-        {
-            _engine = engine;
-            Function = function;
-            Name = !string.IsNullOrEmpty(function.Id?.Name) ? function.Id!.Name : null;
-            Strict = function.Strict;
-        }
+    public JintFunctionDefinition(
+        Engine engine,
+        IFunction function)
+    {
+        _engine = engine;
+        Function = function;
+        Name = !string.IsNullOrEmpty(function.Id?.Name) ? function.Id!.Name : null;
+        Strict = function.Strict;
+    }
 
-        public FunctionThisMode ThisMode => Strict ? FunctionThisMode.Strict : FunctionThisMode.Global;
+    public FunctionThisMode ThisMode => Strict ? FunctionThisMode.Strict : FunctionThisMode.Global;
 
-        /// <summary>
-        /// https://tc39.es/ecma262/#sec-ordinarycallevaluatebody
-        /// </summary>
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        internal Completion EvaluateBody(EvaluationContext context, FunctionInstance functionObject, JsValue[] argumentsList)
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-ordinarycallevaluatebody
+    /// </summary>
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    internal Completion EvaluateBody(EvaluationContext context, FunctionInstance functionObject, JsValue[] argumentsList)
+    {
+        Completion result;
+        var argumentsInstance = _engine.FunctionDeclarationInstantiation(functionObject, argumentsList);
+        if (Function.Expression)
         {
-            Completion result;
-            var argumentsInstance = _engine.FunctionDeclarationInstantiation(functionObject, argumentsList);
-            if (Function.Expression)
-            {
-                // https://tc39.es/ecma262/#sec-runtime-semantics-evaluateconcisebody
-                _bodyExpression ??= JintExpression.Build(_engine, (Expression) Function.Body);
-                var jsValue = _bodyExpression.GetValue(context).GetValueOrDefault().Clone();
-                result = new Completion(CompletionType.Return, jsValue, null, Function.Body);
-            }
-            else if (Function.Generator)
-            {
-                // TODO generators
-                // result = EvaluateGeneratorBody(functionObject, argumentsList);
-                _bodyStatementList ??= new JintStatementList(Function);
-                result = _bodyStatementList.Execute(context);
-            }
-            else
-            {
-                // https://tc39.es/ecma262/#sec-runtime-semantics-evaluatefunctionbody
-                _bodyStatementList ??= new JintStatementList(Function);
-                result = _bodyStatementList.Execute(context);
-            }
-
-            argumentsInstance?.FunctionWasCalled();
-            return result;
+            // https://tc39.es/ecma262/#sec-runtime-semantics-evaluateconcisebody
+            _bodyExpression ??= JintExpression.Build(_engine, (Expression) Function.Body);
+            var jsValue = _bodyExpression.GetValue(context).GetValueOrDefault().Clone();
+            result = new Completion(CompletionType.Return, jsValue, null, Function.Body);
         }
-
-        /// <summary>
-        /// https://tc39.es/ecma262/#sec-runtime-semantics-evaluategeneratorbody
-        /// </summary>
-        private Completion EvaluateGeneratorBody(FunctionInstance functionObject, JsValue[] argumentsList)
+        else if (Function.Generator)
         {
-            ExceptionHelper.ThrowNotImplementedException("generators not implemented");
-            return default;
+            // TODO generators
+            // result = EvaluateGeneratorBody(functionObject, argumentsList);
+            _bodyStatementList ??= new JintStatementList(Function);
+            result = _bodyStatementList.Execute(context);
         }
-
-        internal State Initialize(FunctionInstance functionInstance)
+        else
         {
-            return _state ??= DoInitialize(functionInstance);
+            // https://tc39.es/ecma262/#sec-runtime-semantics-evaluatefunctionbody
+            _bodyStatementList ??= new JintStatementList(Function);
+            result = _bodyStatementList.Execute(context);
         }
 
-        internal sealed class State
-        {
-            public bool HasRestParameter;
-            public int Length;
-            public Key[] ParameterNames = null!;
-            public bool HasDuplicates;
-            public bool IsSimpleParameterList;
-            public bool HasParameterExpressions;
-            public bool ArgumentsObjectNeeded;
-            public List<Key>? VarNames;
-            public LinkedList<JintFunctionDefinition>? FunctionsToInitialize;
-            public readonly HashSet<Key> FunctionNames = new();
-            public LexicalVariableDeclaration[] LexicalDeclarations = Array.Empty<LexicalVariableDeclaration>();
-            public HashSet<Key>? ParameterBindings;
-            public List<VariableValuePair>? VarsToInitialize;
-
-            internal struct VariableValuePair
-            {
-                public Key Name;
-                public JsValue? InitialValue;
-            }
+        argumentsInstance?.FunctionWasCalled();
+        return result;
+    }
 
-            internal struct LexicalVariableDeclaration
-            {
-                public bool IsConstantDeclaration;
-                public List<string> BoundNames;
-            }
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-runtime-semantics-evaluategeneratorbody
+    /// </summary>
+    private Completion EvaluateGeneratorBody(FunctionInstance functionObject, JsValue[] argumentsList)
+    {
+        ExceptionHelper.ThrowNotImplementedException("generators not implemented");
+        return default;
+    }
+
+    internal State Initialize(FunctionInstance functionInstance)
+    {
+        return _state ??= DoInitialize(functionInstance);
+    }
+
+    internal sealed class State
+    {
+        public bool HasRestParameter;
+        public int Length;
+        public Key[] ParameterNames = null!;
+        public bool HasDuplicates;
+        public bool IsSimpleParameterList;
+        public bool HasParameterExpressions;
+        public bool ArgumentsObjectNeeded;
+        public List<Key>? VarNames;
+        public LinkedList<JintFunctionDefinition>? FunctionsToInitialize;
+        public readonly HashSet<Key> FunctionNames = new();
+        public LexicalVariableDeclaration[] LexicalDeclarations = Array.Empty<LexicalVariableDeclaration>();
+        public HashSet<Key>? ParameterBindings;
+        public List<VariableValuePair>? VarsToInitialize;
+
+        internal struct VariableValuePair
+        {
+            public Key Name;
+            public JsValue? InitialValue;
         }
 
-        private State DoInitialize(FunctionInstance functionInstance)
+        internal struct LexicalVariableDeclaration
         {
-            var state = new State();
+            public bool IsConstantDeclaration;
+            public List<string> BoundNames;
+        }
+    }
 
-            ProcessParameters(Function, state, out var hasArguments);
+    private State DoInitialize(FunctionInstance functionInstance)
+    {
+        var state = new State();
 
-            var hoistingScope = HoistingScope.GetFunctionLevelDeclarations(Function, collectVarNames: true, collectLexicalNames: true);
-            var functionDeclarations = hoistingScope._functionDeclarations;
-            var lexicalNames = hoistingScope._lexicalNames;
-            state.VarNames = hoistingScope._varNames;
+        ProcessParameters(Function, state, out var hasArguments);
 
-            LinkedList<JintFunctionDefinition>? functionsToInitialize = null;
+        var hoistingScope = HoistingScope.GetFunctionLevelDeclarations(
+            Strict,
+            Function,
+            collectVarNames: true,
+            collectLexicalNames: true,
+            checkArgumentsReference: true);
 
-            if (functionDeclarations != null)
+        var functionDeclarations = hoistingScope._functionDeclarations;
+        var lexicalNames = hoistingScope._lexicalNames;
+        state.VarNames = hoistingScope._varNames;
+
+        LinkedList<JintFunctionDefinition>? functionsToInitialize = null;
+
+        if (functionDeclarations != null)
+        {
+            functionsToInitialize = new LinkedList<JintFunctionDefinition>();
+            for (var i = functionDeclarations.Count - 1; i >= 0; i--)
             {
-                functionsToInitialize = new LinkedList<JintFunctionDefinition>();
-                for (var i = functionDeclarations.Count - 1; i >= 0; i--)
+                var d = functionDeclarations[i];
+                var fn = d.Id!.Name;
+                if (state.FunctionNames.Add(fn))
                 {
-                    var d = functionDeclarations[i];
-                    var fn = d.Id!.Name;
-                    if (state.FunctionNames.Add(fn))
-                    {
-                        functionsToInitialize.AddFirst(new JintFunctionDefinition(_engine, d));
-                    }
+                    functionsToInitialize.AddFirst(new JintFunctionDefinition(_engine, d));
                 }
             }
+        }
 
-            state.FunctionsToInitialize = functionsToInitialize;
+        state.FunctionsToInitialize = functionsToInitialize;
 
-            const string ParameterNameArguments = "arguments";
+        const string ParameterNameArguments = "arguments";
 
-            state.ArgumentsObjectNeeded = true;
-            if (functionInstance._thisMode == FunctionThisMode.Lexical)
-            {
-                state.ArgumentsObjectNeeded = false;
-            }
-            else if (hasArguments)
+        state.ArgumentsObjectNeeded = true;
+        if (functionInstance._thisMode == FunctionThisMode.Lexical)
+        {
+            state.ArgumentsObjectNeeded = false;
+        }
+        else if (hasArguments)
+        {
+            state.ArgumentsObjectNeeded = false;
+        }
+        else if (!state.HasParameterExpressions)
+        {
+            if (state.FunctionNames.Contains(ParameterNameArguments)
+                || lexicalNames?.Contains(ParameterNameArguments) == true)
             {
                 state.ArgumentsObjectNeeded = false;
             }
-            else if (!state.HasParameterExpressions)
-            {
-                if (state.FunctionNames.Contains(ParameterNameArguments)
-                    || lexicalNames?.Contains(ParameterNameArguments) == true)
-                {
-                    state.ArgumentsObjectNeeded = false;
-                }
-            }
+        }
 
-            var parameterBindings = new HashSet<Key>(state.ParameterNames);
-            if (state.ArgumentsObjectNeeded)
-            {
-                parameterBindings.Add(KnownKeys.Arguments);
-            }
+        if (state.ArgumentsObjectNeeded && !_engine._isDebugMode)
+        {
+            // just one extra check...
+            state.ArgumentsObjectNeeded = hoistingScope._hasArgumentsReference;
+        }
+
+        var parameterBindings = new HashSet<Key>(state.ParameterNames);
+        if (state.ArgumentsObjectNeeded)
+        {
+            parameterBindings.Add(KnownKeys.Arguments);
+        }
 
-            state.ParameterBindings = parameterBindings;
+        state.ParameterBindings = parameterBindings;
 
 
-            var varsToInitialize = new List<State.VariableValuePair>();
-            if (!state.HasParameterExpressions)
-            {
-                var instantiatedVarNames = state.VarNames != null
-                    ? new HashSet<Key>(state.ParameterBindings)
-                    : new HashSet<Key>();
+        var varsToInitialize = new List<State.VariableValuePair>();
+        if (!state.HasParameterExpressions)
+        {
+            var instantiatedVarNames = state.VarNames != null
+                ? new HashSet<Key>(state.ParameterBindings)
+                : new HashSet<Key>();
 
-                for (var i = 0; i < state.VarNames?.Count; i++)
+            for (var i = 0; i < state.VarNames?.Count; i++)
+            {
+                var n = state.VarNames[i];
+                if (instantiatedVarNames.Add(n))
                 {
-                    var n = state.VarNames[i];
-                    if (instantiatedVarNames.Add(n))
+                    varsToInitialize.Add(new State.VariableValuePair
                     {
-                        varsToInitialize.Add(new State.VariableValuePair
-                        {
-                            Name = n
-                        });
-                    }
+                        Name = n
+                    });
                 }
             }
-            else
-            {
-                var instantiatedVarNames = state.VarNames != null
-                    ? new HashSet<Key>(state.ParameterBindings)
-                    : null;
+        }
+        else
+        {
+            var instantiatedVarNames = state.VarNames != null
+                ? new HashSet<Key>(state.ParameterBindings)
+                : null;
 
-                for (var i = 0; i < state.VarNames?.Count; i++)
+            for (var i = 0; i < state.VarNames?.Count; i++)
+            {
+                var n = state.VarNames[i];
+                if (instantiatedVarNames!.Add(n))
                 {
-                    var n = state.VarNames[i];
-                    if (instantiatedVarNames!.Add(n))
+                    JsValue? initialValue = null;
+                    if (!state.ParameterBindings.Contains(n) || state.FunctionNames.Contains(n))
                     {
-                        JsValue? initialValue = null;
-                        if (!state.ParameterBindings.Contains(n) || state.FunctionNames.Contains(n))
-                        {
-                            initialValue = JsValue.Undefined;
-                        }
-
-                        varsToInitialize.Add(new State.VariableValuePair
-                        {
-                            Name = n,
-                            InitialValue = initialValue
-                        });
+                        initialValue = JsValue.Undefined;
                     }
+
+                    varsToInitialize.Add(new State.VariableValuePair
+                    {
+                        Name = n,
+                        InitialValue = initialValue
+                    });
                 }
             }
+        }
 
-            state.VarsToInitialize = varsToInitialize;
+        state.VarsToInitialize = varsToInitialize;
 
-            if (hoistingScope._lexicalDeclarations != null)
+        if (hoistingScope._lexicalDeclarations != null)
+        {
+            var _lexicalDeclarations = hoistingScope._lexicalDeclarations;
+            var lexicalDeclarationsCount = _lexicalDeclarations.Count;
+            var declarations = new State.LexicalVariableDeclaration[lexicalDeclarationsCount];
+            for (var i = 0; i < lexicalDeclarationsCount; i++)
             {
-                var _lexicalDeclarations = hoistingScope._lexicalDeclarations;
-                var lexicalDeclarationsCount = _lexicalDeclarations.Count;
-                var declarations = new State.LexicalVariableDeclaration[lexicalDeclarationsCount];
-                for (var i = 0; i < lexicalDeclarationsCount; i++)
+                var d = _lexicalDeclarations[i];
+                var boundNames = new List<string>();
+                d.GetBoundNames(boundNames);
+                declarations[i] = new State.LexicalVariableDeclaration
                 {
-                    var d = _lexicalDeclarations[i];
-                    var boundNames = new List<string>();
-                    d.GetBoundNames(boundNames);
-                    declarations[i] = new State.LexicalVariableDeclaration
-                    {
-                        IsConstantDeclaration = d.IsConstantDeclaration(),
-                        BoundNames = boundNames
-                    };
-                }
-                state.LexicalDeclarations = declarations;
+                    IsConstantDeclaration = d.IsConstantDeclaration(),
+                    BoundNames = boundNames
+                };
             }
+            state.LexicalDeclarations = declarations;
+        }
 
-            return state;
+        return state;
+    }
+
+    private static void GetBoundNames(
+        Node? parameter,
+        List<Key> target,
+        bool checkDuplicates,
+        ref bool _hasRestParameter,
+        ref bool _hasParameterExpressions,
+        ref bool _hasDuplicates,
+        ref bool hasArguments)
+    {
+        if (parameter is Identifier identifier)
+        {
+            _hasDuplicates |= checkDuplicates && target.Contains(identifier.Name);
+            target.Add(identifier.Name);
+            hasArguments |= identifier.Name == "arguments";
+            return;
         }
 
-        private static void GetBoundNames(
-            Node? parameter,
-            List<Key> target,
-            bool checkDuplicates,
-            ref bool _hasRestParameter,
-            ref bool _hasParameterExpressions,
-            ref bool _hasDuplicates,
-            ref bool hasArguments)
+        while (true)
         {
-            if (parameter is Identifier identifier)
+            if (parameter is RestElement restElement)
             {
-                _hasDuplicates |= checkDuplicates && target.Contains(identifier.Name);
-                target.Add(identifier.Name);
-                hasArguments |= identifier.Name == "arguments";
-                return;
+                _hasRestParameter = true;
+                _hasParameterExpressions = true;
+                parameter = restElement.Argument;
+                continue;
             }
 
-            while (true)
+            if (parameter is ArrayPattern arrayPattern)
             {
-                if (parameter is RestElement restElement)
+                _hasParameterExpressions = true;
+                ref readonly var arrayPatternElements = ref arrayPattern.Elements;
+                for (var i = 0; i < arrayPatternElements.Count; i++)
                 {
-                    _hasRestParameter = true;
-                    _hasParameterExpressions = true;
-                    parameter = restElement.Argument;
-                    continue;
+                    var expression = arrayPatternElements[i];
+                    GetBoundNames(
+                        expression,
+                        target,
+                        checkDuplicates,
+                        ref _hasRestParameter,
+                        ref _hasParameterExpressions,
+                        ref _hasDuplicates,
+                        ref hasArguments);
                 }
-
-                if (parameter is ArrayPattern arrayPattern)
+            }
+            else if (parameter is ObjectPattern objectPattern)
+            {
+                _hasParameterExpressions = true;
+                ref readonly var objectPatternProperties = ref objectPattern.Properties;
+                for (var i = 0; i < objectPatternProperties.Count; i++)
                 {
-                    _hasParameterExpressions = true;
-                    ref readonly var arrayPatternElements = ref arrayPattern.Elements;
-                    for (var i = 0; i < arrayPatternElements.Count; i++)
+                    var property = objectPatternProperties[i];
+                    if (property is Property p)
                     {
-                        var expression = arrayPatternElements[i];
                         GetBoundNames(
-                            expression,
+                            p.Value,
                             target,
                             checkDuplicates,
                             ref _hasRestParameter,
@@ -280,84 +311,64 @@ namespace Jint.Runtime.Interpreter
                             ref _hasDuplicates,
                             ref hasArguments);
                     }
-                }
-                else if (parameter is ObjectPattern objectPattern)
-                {
-                    _hasParameterExpressions = true;
-                    ref readonly var objectPatternProperties = ref objectPattern.Properties;
-                    for (var i = 0; i < objectPatternProperties.Count; i++)
+                    else
                     {
-                        var property = objectPatternProperties[i];
-                        if (property is Property p)
-                        {
-                            GetBoundNames(
-                                p.Value,
-                                target,
-                                checkDuplicates,
-                                ref _hasRestParameter,
-                                ref _hasParameterExpressions,
-                                ref _hasDuplicates,
-                                ref hasArguments);
-                        }
-                        else
-                        {
-                            _hasRestParameter = true;
-                            _hasParameterExpressions = true;
-                            parameter = ((RestElement) property).Argument;
-                            continue;
-                        }
+                        _hasRestParameter = true;
+                        _hasParameterExpressions = true;
+                        parameter = ((RestElement) property).Argument;
+                        continue;
                     }
                 }
-                else if (parameter is AssignmentPattern assignmentPattern)
-                {
-                    _hasParameterExpressions = true;
-                    parameter = assignmentPattern.Left;
-                    continue;
-                }
-
-                break;
             }
+            else if (parameter is AssignmentPattern assignmentPattern)
+            {
+                _hasParameterExpressions = true;
+                parameter = assignmentPattern.Left;
+                continue;
+            }
+
+            break;
         }
+    }
 
-        private static void ProcessParameters(
-            IFunction function,
-            State state,
-            out bool hasArguments)
-        {
-            hasArguments = false;
-            state.IsSimpleParameterList  = true;
+    private static void ProcessParameters(
+        IFunction function,
+        State state,
+        out bool hasArguments)
+    {
+        hasArguments = false;
+        state.IsSimpleParameterList  = true;
 
-            ref readonly var functionDeclarationParams = ref function.Params;
-            var count = functionDeclarationParams.Count;
-            var parameterNames = new List<Key>(count);
-            for (var i = 0; i < count; i++)
+        ref readonly var functionDeclarationParams = ref function.Params;
+        var count = functionDeclarationParams.Count;
+        var parameterNames = new List<Key>(count);
+        for (var i = 0; i < count; i++)
+        {
+            var parameter = functionDeclarationParams[i];
+            if (parameter is Identifier id)
             {
-                var parameter = functionDeclarationParams[i];
-                if (parameter is Identifier id)
+                state.HasDuplicates |= parameterNames.Contains(id.Name);
+                hasArguments = id.Name == "arguments";
+                parameterNames.Add(id.Name);
+                if (state.IsSimpleParameterList)
                 {
-                    state.HasDuplicates |= parameterNames.Contains(id.Name);
-                    hasArguments = id.Name == "arguments";
-                    parameterNames.Add(id.Name);
-                    if (state.IsSimpleParameterList)
-                    {
-                        state.Length++;
-                    }
-                }
-                else if (parameter.Type != Nodes.Literal)
-                {
-                    state.IsSimpleParameterList = false;
-                    GetBoundNames(
-                        parameter,
-                        parameterNames,
-                        checkDuplicates: true,
-                        ref state.HasRestParameter,
-                        ref state.HasParameterExpressions,
-                        ref state.HasDuplicates,
-                        ref hasArguments);
+                    state.Length++;
                 }
             }
-
-            state.ParameterNames = parameterNames.ToArray();
+            else if (parameter.Type != Nodes.Literal)
+            {
+                state.IsSimpleParameterList = false;
+                GetBoundNames(
+                    parameter,
+                    parameterNames,
+                    checkDuplicates: true,
+                    ref state.HasRestParameter,
+                    ref state.HasParameterExpressions,
+                    ref state.HasDuplicates,
+                    ref hasArguments);
+            }
         }
+
+        state.ParameterNames = parameterNames.ToArray();
     }
 }

+ 0 - 1
Jint/Runtime/Interpreter/Statements/JintStatement.cs

@@ -1,4 +1,3 @@
-using System.Diagnostics;
 using System.Runtime.CompilerServices;
 using Esprima;
 using Esprima.Ast;

+ 0 - 1
Jint/Runtime/Interpreter/Statements/JintSwitchStatement.cs

@@ -1,5 +1,4 @@
 using Esprima.Ast;
-using Jint.Native;
 using Jint.Runtime.Interpreter.Expressions;
 
 namespace Jint.Runtime.Interpreter.Statements