Browse Source

#451 remove tail recursion and faster environment records (#475)

Marko Lahma 7 years ago
parent
commit
d139547080

+ 10 - 3
Jint/Native/Object/ObjectInstance.cs

@@ -2,6 +2,7 @@
 using System.Collections.Generic;
 using System.Diagnostics.Contracts;
 using System.Dynamic;
+using System.Runtime.CompilerServices;
 using Jint.Native.Array;
 using Jint.Native.Boolean;
 using Jint.Native.Date;
@@ -136,7 +137,12 @@ namespace Jint.Native.Object
         public virtual JsValue Get(string propertyName)
         {
             var desc = GetProperty(propertyName);
+            return UnwrapJsValue(desc);
+        }
 
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        internal JsValue UnwrapJsValue(IPropertyDescriptor desc)
+        {
             if (desc == PropertyDescriptor.Undefined)
             {
                 return Undefined;
@@ -145,11 +151,10 @@ namespace Jint.Native.Object
             if (desc.IsDataDescriptor())
             {
                 var val = desc.Value;
-                return val != null ? val : Undefined;
+                return !ReferenceEquals(val, null) ? val : Undefined;
             }
 
-            var getter = desc.Get != null ? desc.Get : Undefined;
-
+            var getter = !ReferenceEquals(desc.Get, null) ? desc.Get : Undefined;
             if (getter.IsUndefined())
             {
                 return Undefined;
@@ -197,6 +202,7 @@ namespace Jint.Native.Object
         /// </summary>
         /// <param name="propertyName"></param>
         /// <returns></returns>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public IPropertyDescriptor GetProperty(string propertyName)
         {
             var prop = GetOwnProperty(propertyName);
@@ -367,6 +373,7 @@ namespace Jint.Native.Object
         /// </summary>
         /// <param name="propertyName"></param>
         /// <returns></returns>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public bool HasProperty(string propertyName)
         {
             return GetProperty(propertyName) != PropertyDescriptor.Undefined;

+ 20 - 6
Jint/Runtime/Environments/DeclarativeEnvironmentRecord.cs

@@ -1,4 +1,5 @@
-using Jint.Native;
+using System;
+using Jint.Native;
 
 namespace Jint.Runtime.Environments
 {
@@ -13,7 +14,7 @@ namespace Jint.Runtime.Environments
         private const string BindingNameArguments = "arguments";
         private Binding _argumentsBinding;
 
-        private readonly MruPropertyCache2<Binding> _bindings = new MruPropertyCache2<Binding>();
+        private MruPropertyCache2<Binding> _bindings;
 
         public DeclarativeEnvironmentRecord(Engine engine) : base(engine)
         {
@@ -27,7 +28,7 @@ namespace Jint.Runtime.Environments
                 return _argumentsBinding != null;
             }
 
-            return _bindings.ContainsKey(name);
+            return _bindings?.ContainsKey(name) == true;
         }
 
         public override void CreateMutableBinding(string name, bool canBeDeleted = false)
@@ -45,12 +46,21 @@ namespace Jint.Runtime.Environments
             }
             else
             {
+                if (_bindings == null)
+                {
+                    _bindings = new MruPropertyCache2<Binding>();
+                }
                 _bindings.Add(name, binding);
             }
         }
 
         public override void SetMutableBinding(string name, JsValue value, bool strict)
         {
+            if (_bindings == null)
+            {
+                _bindings = new MruPropertyCache2<Binding>();
+            }
+
             var binding = name == BindingNameArguments ? _argumentsBinding : _bindings[name];
             if (binding.Mutable)
             {
@@ -84,14 +94,14 @@ namespace Jint.Runtime.Environments
 
         public override bool DeleteBinding(string name)
         {
-            Binding binding;
+            Binding binding = null;
             if (name == BindingNameArguments)
             {
                 binding = _argumentsBinding;
             }
             else
             {
-                _bindings.TryGetValue(name, out binding);
+                _bindings?.TryGetValue(name, out binding);
             }
 
             if (binding == null)
@@ -140,6 +150,10 @@ namespace Jint.Runtime.Environments
             }
             else
             {
+                if (_bindings == null)
+                {
+                    _bindings = new MruPropertyCache2<Binding>();
+                }
                 _bindings.Add(name, binding);
             }
         }
@@ -161,7 +175,7 @@ namespace Jint.Runtime.Environments
         /// <returns>The array of all defined bindings</returns>
         public override string[] GetAllBindingNames()
         {
-            return _bindings.GetKeys();
+            return _bindings?.GetKeys() ?? Array.Empty<string>();
         }
     }
 }

+ 15 - 12
Jint/Runtime/Environments/LexicalEnvironment.cs

@@ -32,22 +32,25 @@ namespace Jint.Runtime.Environments
 
         public static Reference GetIdentifierReference(LexicalEnvironment lex, string name, bool strict)
         {
-            if (lex == null)
+            while (true)
             {
-                return new Reference(Undefined.Instance, name, strict);
-            }
+                if (lex == null)
+                {
+                    return new Reference(Undefined.Instance, name, strict);
+                }
 
-            if (lex.Record.HasBinding(name))
-            {
-                return new Reference(lex.Record, name, strict);
-            }
+                if (lex.Record.HasBinding(name))
+                {
+                    return new Reference(lex.Record, name, strict);
+                }
 
-            if (lex.Outer == null)
-            {
-                return new Reference(Undefined.Instance, name, strict);    
-            }
+                if (lex.Outer == null)
+                {
+                    return new Reference(Undefined.Instance, name, strict);
+                }
 
-            return GetIdentifierReference(lex.Outer, name, strict);
+                lex = lex.Outer;
+            }
         }
 
         public static LexicalEnvironment NewDeclarativeEnvironment(Engine engine, LexicalEnvironment outer = null)

+ 3 - 9
Jint/Runtime/Environments/ObjectEnvironmentRecord.cs

@@ -50,19 +50,13 @@ namespace Jint.Runtime.Environments
 
         public override JsValue GetBindingValue(string name, bool strict)
         {
-            // todo: can be optimized
-
-            if (!_bindingObject.HasProperty(name))
+            var desc = _bindingObject.GetProperty(name);
+            if (strict && desc == PropertyDescriptor.Undefined)
             {
-                if(!strict)
-                {
-                    return Undefined;
-                }
-
                 throw new JavaScriptException(_engine.ReferenceError);
             }
 
-            return _bindingObject.Get(name);
+            return UnwrapJsValue(desc);
         }
 
         public override bool DeleteBinding(string name)