Просмотр исходного кода

Flatten declarative record instance creation lookups (#2040)

Marko Lahma 6 месяцев назад
Родитель
Сommit
815fa32fb4

+ 35 - 21
Jint/Collections/HybridDictionary.cs

@@ -119,40 +119,39 @@ internal sealed class HybridDictionary<TValue> : IEngineDictionary<Key, TValue>,
         currentValue = updater(currentValue, state);
     }
 
-    private bool SwitchToDictionary(Key key, TValue value, bool tryAdd)
+    private bool SwitchToDictionary(Key key, TValue value, bool tryAdd, int capacity = InitialDictionarySize)
     {
-        var dictionary = new StringDictionarySlim<TValue>(InitialDictionarySize);
-        foreach (var pair in _list)
-        {
-            dictionary[pair.Key] = pair.Value;
-        }
+        SwitchToDictionary(capacity);
 
-        bool result;
         if (tryAdd)
         {
-            result = dictionary.TryAdd(key, value);
-        }
-        else
-        {
-            dictionary[key] = value;
-            result = true;
+            return _dictionary.TryAdd(key, value);
         }
 
-        _dictionary = dictionary;
-        _list = null;
-        return result;
+        _dictionary[key] = value;
+        return true;
+    }
+
+    private ref TValue SwitchToDictionary(Key key, int capacity = InitialDictionarySize)
+    {
+        SwitchToDictionary(capacity);
+        return ref _dictionary[key];
     }
 
-    private ref TValue SwitchToDictionary(Key key)
+    private void SwitchToDictionary(int capacity = InitialDictionarySize)
     {
-        var dictionary = new StringDictionarySlim<TValue>(InitialDictionarySize);
-        foreach (var pair in _list)
+        var dictionary = new StringDictionarySlim<TValue>(capacity);
+
+        if (_list is not null)
         {
-            dictionary[pair.Key] = pair.Value;
+            foreach (var pair in _list)
+            {
+                dictionary[pair.Key] = pair.Value;
+            }
         }
+
         _dictionary = dictionary;
         _list = null;
-        return ref dictionary[key];
     }
 
     public int Count
@@ -161,6 +160,21 @@ internal sealed class HybridDictionary<TValue> : IEngineDictionary<Key, TValue>,
         get => _dictionary?.Count ?? _list?.Count ?? 0;
     }
 
+    public void EnsureCapacity(int capacity)
+    {
+        if (_dictionary is not null)
+        {
+            // not implemented yet
+            return;
+        }
+
+        if (capacity >= CutoverPoint)
+        {
+            SwitchToDictionary(capacity);
+        }
+    }
+
+
     public bool TryAdd(Key key, TValue value)
     {
         if (_dictionary != null)

+ 14 - 14
Jint/Engine.cs

@@ -2,6 +2,7 @@
 using System.Collections.Concurrent;
 using System.Diagnostics.CodeAnalysis;
 using System.Runtime.CompilerServices;
+using Jint.Collections;
 using Jint.Native;
 using Jint.Native.Function;
 using Jint.Native.Generator;
@@ -1096,7 +1097,7 @@ public sealed partial class Engine : IDisposable
         // Else,
         //     Perform ? IteratorBindingInitialization for formals with iteratorRecord and env as arguments.
 
-        Environment varEnv;
+        DeclarativeEnvironment varEnv;
         if (!hasParameterExpressions)
         {
             // NOTE: Only a single lexical environment is needed for the parameters and top-level vars.
@@ -1130,7 +1131,7 @@ public sealed partial class Engine : IDisposable
         // NOTE: Annex B.3.3.1 adds additional steps at this point.
         // A https://tc39.es/ecma262/#sec-web-compat-functiondeclarationinstantiation
 
-        Environment lexEnv;
+        DeclarativeEnvironment lexEnv;
         if (!strict)
         {
             lexEnv = JintEnvironment.NewDeclarativeEnvironment(this, varEnv);
@@ -1146,21 +1147,20 @@ public sealed partial class Engine : IDisposable
 
         UpdateLexicalEnvironment(lexEnv);
 
-        if (configuration.LexicalDeclarations.Length > 0)
+        if (configuration.LexicalDeclarations.Count > 0)
         {
-            foreach (var d in configuration.LexicalDeclarations)
+            var dictionary = lexEnv._dictionary ??= new HybridDictionary<Binding>(configuration.LexicalDeclarations.Count, checkExistingKeys: true);
+            dictionary.EnsureCapacity(dictionary.Count + configuration.LexicalDeclarations.Count);
+            for (var i = 0; i < configuration.LexicalDeclarations.Count; i++)
             {
-                for (var j = 0; j < d.BoundNames.Count; j++)
+                var d = configuration.LexicalDeclarations[i];
+                if (d.IsConstantDeclaration)
                 {
-                    var dn = d.BoundNames[j];
-                    if (d.IsConstantDeclaration)
-                    {
-                        lexEnv.CreateImmutableBinding(dn, strict: true);
-                    }
-                    else
-                    {
-                        lexEnv.CreateMutableBinding(dn, canBeDeleted: false);
-                    }
+                    dictionary[d.BoundName] = new Binding(null!, canBeDeleted: false, mutable: false, strict);
+                }
+                else
+                {
+                    dictionary[d.BoundName] = new Binding(null!, canBeDeleted: false, mutable: true, strict: false);
                 }
             }
         }

+ 1 - 0
Jint/Native/Function/Function.cs

@@ -318,6 +318,7 @@ public abstract partial class Function : ObjectInstance, ICallable
     /// <summary>
     /// https://tc39.es/ecma262/#sec-prepareforordinarycall
     /// </summary>
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
     internal ref readonly ExecutionContext PrepareForOrdinaryCall(JsValue newTarget)
     {
         var callerContext = _engine.ExecutionContext;

+ 13 - 20
Jint/Runtime/Interpreter/JintFunctionDefinition.cs

@@ -196,21 +196,14 @@ internal sealed class JintFunctionDefinition
         public List<Key>? VarNames;
         public LinkedList<FunctionDeclaration>? FunctionsToInitialize;
         public readonly HashSet<Key> FunctionNames = new();
-        public LexicalVariableDeclaration[] LexicalDeclarations = Array.Empty<LexicalVariableDeclaration>();
+        public List<LexicalVariableDeclaration> LexicalDeclarations = [];
         public HashSet<Key>? ParameterBindings;
         public List<VariableValuePair>? VarsToInitialize;
 
-        internal struct VariableValuePair
-        {
-            public Key Name;
-            public JsValue? InitialValue;
-        }
+        internal readonly record struct VariableValuePair(Key Name, JsValue? InitialValue);
 
-        internal struct LexicalVariableDeclaration
-        {
-            public bool IsConstantDeclaration;
-            public List<Key> BoundNames;
-        }
+        [StructLayout(LayoutKind.Auto)]
+        internal readonly record struct LexicalVariableDeclaration(Key BoundName, bool IsConstantDeclaration);
     }
 
     internal static State BuildState(IFunction function)
@@ -332,19 +325,19 @@ internal sealed class JintFunctionDefinition
 
         if (hoistingScope._lexicalDeclarations != null)
         {
-            var _lexicalDeclarations = hoistingScope._lexicalDeclarations;
-            var lexicalDeclarationsCount = _lexicalDeclarations.Count;
-            var declarations = new State.LexicalVariableDeclaration[lexicalDeclarationsCount];
+            var boundNames = new List<Key>();
+            var lexicalDeclarations = hoistingScope._lexicalDeclarations;
+            var lexicalDeclarationsCount = lexicalDeclarations.Count;
+            var declarations = new List<State.LexicalVariableDeclaration>(lexicalDeclarationsCount);
             for (var i = 0; i < lexicalDeclarationsCount; i++)
             {
-                var d = _lexicalDeclarations[i];
-                var boundNames = new List<Key>();
+                var d = lexicalDeclarations[i];
+                boundNames.Clear();
                 d.GetBoundNames(boundNames);
-                declarations[i] = new State.LexicalVariableDeclaration
+                for (var j = 0; j < boundNames.Count; j++)
                 {
-                    IsConstantDeclaration = d.IsConstantDeclaration(),
-                    BoundNames = boundNames
-                };
+                    declarations.Add(new State.LexicalVariableDeclaration(boundNames[j], d.IsConstantDeclaration()));
+                }
             }
             state.LexicalDeclarations = declarations;
         }