Prechádzať zdrojové kódy

Backport improve environment handling performance and cleanup API (#1846)

Marko Lahma 1 rok pred
rodič
commit
a7dd50de29

+ 1 - 1
Jint/Runtime/Debugger/DebugScope.cs

@@ -57,7 +57,7 @@ namespace Jint.Runtime.Debugger
         /// <returns>Value of the binding</returns>
         public JsValue? GetBindingValue(string name)
         {
-            _record.TryGetBinding(new Environment.BindingName(name), strict: true, out _, out var result);
+            _record.TryGetBinding(new Environment.BindingName(name), out var result);
             return result;
         }
 

+ 3 - 3
Jint/Runtime/Descriptors/Specialized/ClrAccessDescriptor.cs

@@ -31,14 +31,14 @@ namespace Jint.Runtime.Descriptors.Specialized
 
         private JsValue DoGet(JsValue n)
         {
-            return _env.TryGetBinding(_name, false, out var binding, out _)
-                ? binding.Value
+            return _env.TryGetBinding(_name, out var value)
+                ? value
                 : JsValue.Undefined;
         }
 
         private void DoSet(JsValue n, JsValue o)
         {
-            _env.SetMutableBinding(_name.Key, o, true);
+            _env.SetMutableBinding(_name.Key, o, strict: true);
         }
     }
 }

+ 22 - 9
Jint/Runtime/Environments/DeclarativeEnvironment.cs

@@ -23,16 +23,16 @@ namespace Jint.Runtime.Environments
 
         internal sealed override bool HasBinding(Key name) => _dictionary is not null && _dictionary.ContainsKey(name);
 
-        internal override bool TryGetBinding(
-            BindingName name,
-            bool strict,
-            out Binding binding,
-            [NotNullWhen(true)] out JsValue? value)
+        internal override bool TryGetBinding(BindingName name, [NotNullWhen(true)] out JsValue? value)
         {
-            binding = default;
-            var success = _dictionary is not null &&_dictionary.TryGetValue(name.Key, out binding);
-            value = success && binding.IsInitialized() ? binding.Value : default;
-            return success;
+            if (_dictionary?.TryGetValue(name.Key, out var binding) == true)
+            {
+                value = binding.Value;
+                return true;
+            }
+
+            value = null;
+            return false;
         }
 
         internal void CreateMutableBindingAndInitialize(Key name, bool canBeDeleted, JsValue value)
@@ -75,6 +75,7 @@ namespace Jint.Runtime.Environments
                 {
                     ExceptionHelper.ThrowReferenceNameError(_engine.Realm, name);
                 }
+
                 CreateMutableBindingAndInitialize(name, canBeDeleted: true, value);
                 return;
             }
@@ -169,5 +170,17 @@ namespace Jint.Runtime.Environments
         {
             _dictionary = null;
         }
+
+        internal void TransferTo(List<Key> names, DeclarativeEnvironment env)
+        {
+            var source = _dictionary!;
+            var target = env._dictionary ??= new HybridDictionary<Binding>(names.Count, checkExistingKeys: true);
+            for (var j = 0; j < names.Count; j++)
+            {
+                var bn = names[j];
+                source.TryGetValue(bn, out var lastValue);
+                target[bn] = new Binding(lastValue.Value, canBeDeleted: false, mutable: true, strict: false);
+            }
+        }
     }
 }

+ 1 - 5
Jint/Runtime/Environments/Environment.cs

@@ -28,11 +28,7 @@ namespace Jint.Runtime.Environments
 
         internal abstract bool HasBinding(BindingName name);
 
-        internal abstract bool TryGetBinding(
-            BindingName name,
-            bool strict,
-            out Binding binding,
-            [NotNullWhen(true)] out JsValue? value);
+        internal abstract bool TryGetBinding(BindingName name, [NotNullWhen(true)] out JsValue? value);
 
         /// <summary>
         /// Creates a new mutable binding in an environment record.

+ 2 - 7
Jint/Runtime/Environments/GlobalEnvironment.cs

@@ -69,19 +69,14 @@ namespace Jint.Runtime.Environments
             return _global.HasProperty(name.Value);
         }
 
-        internal override bool TryGetBinding(
-            BindingName name,
-            bool strict,
-            out Binding binding,
-            [NotNullWhen(true)] out JsValue? value)
+        internal override bool TryGetBinding(BindingName name, [NotNullWhen(true)] out JsValue? value)
         {
-            if (_declarativeRecord._dictionary is not null && _declarativeRecord.TryGetBinding(name, strict, out binding, out value))
+            if (_declarativeRecord._dictionary is not null && _declarativeRecord.TryGetBinding(name, out value))
             {
                 return true;
             }
 
             // we unwrap by name
-            binding = default;
             value = default;
 
             // normal case is to find

+ 4 - 9
Jint/Runtime/Environments/JintEnvironment.cs

@@ -9,7 +9,7 @@ namespace Jint.Runtime.Environments
     {
         internal static bool TryGetIdentifierEnvironmentWithBinding(
             Environment env,
-            in Environment.BindingName name,
+            Environment.BindingName name,
             [NotNullWhen(true)] out Environment? record)
         {
             record = env;
@@ -34,8 +34,7 @@ namespace Jint.Runtime.Environments
 
         internal static bool TryGetIdentifierEnvironmentWithBindingValue(
             Environment env,
-            in Environment.BindingName name,
-            bool strict,
+            Environment.BindingName name,
             [NotNullWhen(true)] out Environment? record,
             [NotNullWhen(true)] out JsValue? value)
         {
@@ -44,16 +43,12 @@ namespace Jint.Runtime.Environments
 
             if (env._outerEnv is null)
             {
-                return ((GlobalEnvironment) env).TryGetBinding(name, strict, out _, out value);
+                return ((GlobalEnvironment) env).TryGetBinding(name, out value);
             }
 
             while (!ReferenceEquals(record, null))
             {
-                if (record.TryGetBinding(
-                    name,
-                    strict,
-                    out _,
-                    out value))
+                if (record.TryGetBinding(name, out value))
                 {
                     return true;
                 }

+ 2 - 3
Jint/Runtime/Environments/ModuleEnvironment.cs

@@ -47,16 +47,15 @@ internal sealed class ModuleEnvironment : DeclarativeEnvironment
         return base.GetBindingValue(name, strict);
     }
 
-    internal override bool TryGetBinding(BindingName name, bool strict, out Binding binding, [NotNullWhen(true)] out JsValue? value)
+    internal override bool TryGetBinding(BindingName name, [NotNullWhen(true)] out JsValue? value)
     {
         if (_importBindings.TryGetValue(name.Key, out var indirectBinding))
         {
             value = indirectBinding.Module._environment.GetBindingValue(indirectBinding.BindingName, strict: true);
-            binding = new(value, canBeDeleted: false, mutable: false, strict: true);
             return true;
         }
 
-        return base.TryGetBinding(name, strict, out binding, out value);
+        return base.TryGetBinding(name, out value);
     }
 
     /// <summary>

+ 2 - 9
Jint/Runtime/Environments/ObjectEnvironment.cs

@@ -67,15 +67,9 @@ namespace Jint.Runtime.Environments
             return _bindingObject.HasProperty(property);
         }
 
-        internal override bool TryGetBinding(
-            BindingName name,
-            bool strict,
-            out Binding binding,
-            [NotNullWhen(true)] out JsValue? value)
+        internal override bool TryGetBinding(BindingName name, [NotNullWhen(true)] out JsValue? value)
         {
             // we unwrap by name
-            binding = default;
-
             if (!HasProperty(name.Value))
             {
                 value = default;
@@ -153,8 +147,7 @@ namespace Jint.Runtime.Environments
 
         internal override JsValue GetBindingValue(Key name, bool strict)
         {
-            JsValue value;
-            if (!_bindingObject.TryGetValue(name.Name, out value) && strict)
+            if (!_bindingObject.TryGetValue(name.Name, out var value) && strict)
             {
                 ExceptionHelper.ThrowReferenceNameError(_engine.Realm, name.Name);
             }

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

@@ -49,7 +49,6 @@ namespace Jint.Runtime.Interpreter.Expressions
             if (_leftIdentifier is not null && JintEnvironment.TryGetIdentifierEnvironmentWithBindingValue(
                     engine.ExecutionContext.LexicalEnvironment,
                     _leftIdentifier.Identifier,
-                    StrictModeScope.IsStrictModeCode,
                     out var identifierEnvironment,
                     out var temp))
             {

+ 1 - 3
Jint/Runtime/Interpreter/Expressions/JintIdentifierExpression.cs

@@ -54,14 +54,12 @@ internal sealed class JintIdentifierExpression : JintExpression
             return identifier.CalculatedValue;
         }
 
-        var strict = StrictModeScope.IsStrictModeCode;
         var engine = context.Engine;
         var env = engine.ExecutionContext.LexicalEnvironment;
 
         if (JintEnvironment.TryGetIdentifierEnvironmentWithBindingValue(
                 env,
                 identifier,
-                strict,
                 out _,
                 out var value))
         {
@@ -72,7 +70,7 @@ internal sealed class JintIdentifierExpression : JintExpression
         }
         else
         {
-            var reference = engine._referencePool.Rent(JsValue.Undefined, identifier.Value, strict, thisValue: null);
+            var reference = engine._referencePool.Rent(JsValue.Undefined, identifier.Value, StrictModeScope.IsStrictModeCode, thisValue: null);
             value = engine.GetValue(reference, returnReferenceToPool: true);
         }
 

+ 6 - 10
Jint/Runtime/Interpreter/Expressions/JintMemberExpression.cs

@@ -57,21 +57,18 @@ namespace Jint.Runtime.Interpreter.Expressions
             }
 
             JsValue? actualThis = null;
-            string? baseReferenceName = null;
+            object? baseReferenceName = null;
             JsValue? baseValue = null;
-            var isStrictModeCode = StrictModeScope.IsStrictModeCode;
 
             var engine = context.Engine;
             if (_objectExpression is JintIdentifierExpression identifierExpression)
             {
                 var identifier = identifierExpression.Identifier;
                 baseReferenceName = identifier.Key.Name;
-                var strict = isStrictModeCode;
                 var env = engine.ExecutionContext.LexicalEnvironment;
                 JintEnvironment.TryGetIdentifierEnvironmentWithBindingValue(
                     env,
                     identifier,
-                    strict,
                     out _,
                     out baseValue);
             }
@@ -96,13 +93,12 @@ namespace Jint.Runtime.Interpreter.Expressions
                 }
                 if (baseReference is Reference reference)
                 {
-                    baseReferenceName = reference.ReferencedName.ToString();
-                    baseValue = engine.GetValue(reference, false);
-                    engine._referencePool.Return(reference);
+                    baseReferenceName = reference.ReferencedName;
+                    baseValue = engine.GetValue(reference, returnReferenceToPool: true);
                 }
                 else
                 {
-                    baseValue = engine.GetValue(baseReference, false);
+                    baseValue = engine.GetValue(baseReference, returnReferenceToPool: false);
                 }
             }
 
@@ -117,7 +113,7 @@ namespace Jint.Runtime.Interpreter.Expressions
                 // we can use base data types securely, object evaluation can mess things up
                 var referenceName = property.IsPrimitive()
                     ? TypeConverter.ToString(property)
-                    : _determinedProperty?.ToString() ?? baseReferenceName;
+                    : _determinedProperty?.ToString() ?? baseReferenceName?.ToString();
 
                 TypeConverter.CheckObjectCoercible(engine, baseValue, _memberExpression.Property, referenceName!);
             }
@@ -127,7 +123,7 @@ namespace Jint.Runtime.Interpreter.Expressions
                 return MakePrivateReference(engine, baseValue, property);
             }
 
-            return context.Engine._referencePool.Rent(baseValue, property, isStrictModeCode, thisValue: actualThis);
+            return context.Engine._referencePool.Rent(baseValue, property, StrictModeScope.IsStrictModeCode, thisValue: actualThis);
         }
 
         /// <summary>

+ 8 - 11
Jint/Runtime/Interpreter/Expressions/JintUpdateExpression.cs

@@ -1,5 +1,6 @@
 using Jint.Native;
 using Jint.Runtime.Environments;
+using Environment = Jint.Runtime.Environments.Environment;
 
 namespace Jint.Runtime.Interpreter.Expressions
 {
@@ -121,20 +122,16 @@ namespace Jint.Runtime.Interpreter.Expressions
 
         private JsValue? UpdateIdentifier(EvaluationContext context)
         {
-            var strict = StrictModeScope.IsStrictModeCode;
             var name = _leftIdentifier!.Identifier;
-            var engine = context.Engine;
-            var env = engine.ExecutionContext.LexicalEnvironment;
             if (JintEnvironment.TryGetIdentifierEnvironmentWithBindingValue(
-                env,
-                name,
-                strict,
-                out var environmentRecord,
-                out var value))
+                    context.Engine.ExecutionContext.LexicalEnvironment,
+                    name,
+                    out var environmentRecord,
+                    out var value))
             {
-                if (strict && _evalOrArguments)
+                if (_evalOrArguments && StrictModeScope.IsStrictModeCode)
                 {
-                    ExceptionHelper.ThrowSyntaxError(engine.Realm);
+                    ExceptionHelper.ThrowSyntaxError(context.Engine.Realm);
                 }
 
                 var isInteger = value._type == InternalTypes.Integer;
@@ -167,7 +164,7 @@ namespace Jint.Runtime.Interpreter.Expressions
                     }
                 }
 
-                environmentRecord.SetMutableBinding(name.Key.Name, newValue!, strict);
+                environmentRecord.SetMutableBinding(name.Key, newValue!, StrictModeScope.IsStrictModeCode);
                 if (_prefix)
                 {
                     return newValue;

+ 3 - 10
Jint/Runtime/Interpreter/Statements/JintForStatement.cs

@@ -170,17 +170,10 @@ namespace Jint.Runtime.Interpreter.Statements
         private void CreatePerIterationEnvironment(EvaluationContext context)
         {
             var engine = context.Engine;
-            var lastIterationEnv = engine.ExecutionContext.LexicalEnvironment;
-            var lastIterationEnvRec = lastIterationEnv;
-            var outer = lastIterationEnv._outerEnv;
-            var thisIterationEnv = JintEnvironment.NewDeclarativeEnvironment(engine, outer);
+            var lastIterationEnv = (DeclarativeEnvironment) engine.ExecutionContext.LexicalEnvironment;
+            var thisIterationEnv = JintEnvironment.NewDeclarativeEnvironment(engine, lastIterationEnv._outerEnv);
 
-            for (var j = 0; j < _boundNames!.Count; j++)
-            {
-                var bn = _boundNames[j];
-                var lastValue = lastIterationEnvRec.GetBindingValue(bn, true);
-                thisIterationEnv.CreateMutableBindingAndInitialize(bn, false, lastValue);
-            }
+            lastIterationEnv.TransferTo(_boundNames!, thisIterationEnv);
 
             engine.UpdateLexicalEnvironment(thisIterationEnv);
         }