2
0
Эх сурвалжийг харах

Merge pull request #268 from sebastienros/perf/arguments

Initialize the arguments object lazily
Sébastien Ros 9 жил өмнө
parent
commit
7c97081cfa

+ 1 - 1
Jint/Jint.csproj

@@ -72,7 +72,7 @@
     <Compile Include="Native\Error\ErrorPrototype.cs" />
     <Compile Include="Native\Error\ErrorConstructor.cs" />
     <Compile Include="Native\Error\ErrorInstance.cs" />
-    <Compile Include="Native\Argument\ArgumentsObject.cs" />
+    <Compile Include="Native\Argument\ArgumentsInstance.cs" />
     <Compile Include="Native\Function\FunctionPrototype.cs" />
     <Compile Include="Native\Function\ThrowTypeError.cs" />
     <Compile Include="Native\Function\EvalFunctionInstance.cs" />

+ 72 - 42
Jint/Native/Argument/ArgumentsObject.cs → Jint/Native/Argument/ArgumentsInstance.cs

@@ -14,62 +14,84 @@ namespace Jint.Native.Argument
     /// </summary>
     public class ArgumentsInstance : ObjectInstance
     {
-        public ArgumentsInstance(Engine engine) : base(engine)
+        private ArgumentsInstance(Engine engine, Action<ArgumentsInstance> initializer) : base(engine)
         {
-            // todo: complete implementation
+            _initializer = initializer;
+            _initialized = false;
         }
 
         public bool Strict { get; set; }
 
-        public static ArgumentsInstance CreateArgumentsObject(Engine engine, FunctionInstance func, string[] names, JsValue[] args, EnvironmentRecord env, bool strict)
+        private Action<ArgumentsInstance> _initializer;
+        private bool _initialized;
+
+        protected override void EnsureInitialized()
         {
-            var len = args.Length;
-            var obj = new ArgumentsInstance(engine);
-            obj.Prototype = engine.Object.PrototypeObject;
-            obj.Extensible = true;
-            obj.FastAddProperty("length", len, true, false, true);
-            obj.Strict = strict;
-            var map = engine.Object.Construct(Arguments.Empty);
-            var mappedNamed = new List<string>();
-            var indx = 0;
-            while (indx <= len - 1)
+            if(_initialized)
             {
-                var indxStr = TypeConverter.ToString(indx);
-                var val = args[indx];
-                obj.FastAddProperty(indxStr, val, true, true, true);
-                if (indx < names.Length)
+                return;
+            }
+
+            _initialized = true;
+
+            _initializer(this);
+        }
+
+        public static ArgumentsInstance CreateArgumentsObject(Engine engine, FunctionInstance func, string[] names, JsValue[] args, EnvironmentRecord env, bool strict)
+        {
+            var obj = new ArgumentsInstance(engine, self => 
+            {                
+                var len = args.Length;
+                self.FastAddProperty("length", len, true, false, true);
+                var map = engine.Object.Construct(Arguments.Empty);
+                var mappedNamed = new List<string>();
+                var indx = 0;
+                while (indx <= len - 1)
                 {
-                    var name = names[indx];
-                    if (!strict && !mappedNamed.Contains(name))
+                    var indxStr = TypeConverter.ToString(indx);
+                    var val = args[indx];
+                    self.FastAddProperty(indxStr, val, true, true, true);
+                    if (indx < names.Length)
                     {
-                        mappedNamed.Add(name);
-                        Func<JsValue, JsValue> g = n => env.GetBindingValue(name, false);
-                        var p = new Action<JsValue, JsValue>((n, o) => env.SetMutableBinding(name, o, true));
+                        var name = names[indx];
+                        if (!strict && !mappedNamed.Contains(name))
+                        {
+                            mappedNamed.Add(name);
+                            Func<JsValue, JsValue> g = n => env.GetBindingValue(name, false);
+                            var p = new Action<JsValue, JsValue>((n, o) => env.SetMutableBinding(name, o, true));
 
-                        map.DefineOwnProperty(indxStr, new ClrAccessDescriptor(engine, g, p) { Configurable = true }, false);
+                            map.DefineOwnProperty(indxStr, new ClrAccessDescriptor(engine, g, p) { Configurable = true }, false);
+                        }
                     }
+                    indx++;
                 }
-                indx++;
-            }
 
-            // step 12
-            if (mappedNamed.Count > 0)
-            {
-                obj.ParameterMap = map;
-            }
+                // step 12
+                if (mappedNamed.Count > 0)
+                {
+                    self.ParameterMap = map;
+                }
 
-            // step 13
-            if (!strict)
-            {
-                obj.FastAddProperty("callee",func, true, false, true);
-            }
-            // step 14
-            else
-            {
-                var thrower = engine.Function.ThrowTypeError;
-                obj.DefineOwnProperty("caller", new PropertyDescriptor(get: thrower, set: thrower, enumerable:false, configurable:false), false);
-                obj.DefineOwnProperty("callee", new PropertyDescriptor(get: thrower, set: thrower, enumerable: false, configurable: false), false);
-            }
+                // step 13
+                if (!strict)
+                {
+                    self.FastAddProperty("callee", func, true, false, true);
+                }
+                // step 14
+                else
+                {
+                    var thrower = engine.Function.ThrowTypeError;
+                    self.DefineOwnProperty("caller", new PropertyDescriptor(get: thrower, set: thrower, enumerable: false, configurable: false), false);
+                    self.DefineOwnProperty("callee", new PropertyDescriptor(get: thrower, set: thrower, enumerable: false, configurable: false), false);
+                }
+            });
+
+            // These properties are pre-initialized as their don't trigger
+            // the EnsureInitialized() event and are cheap
+            obj.Prototype = engine.Object.PrototypeObject;
+            obj.Extensible = true;
+            obj.Strict = strict;
+            
 
             return obj;
         }
@@ -87,6 +109,8 @@ namespace Jint.Native.Argument
 
         public override PropertyDescriptor GetOwnProperty(string propertyName)
         {
+            EnsureInitialized();
+
             if (!Strict && ParameterMap != null)
             {
                 var desc = base.GetOwnProperty(propertyName);
@@ -112,6 +136,8 @@ namespace Jint.Native.Argument
         /// for arrays
         public override void Put(string propertyName, JsValue value, bool throwOnError)
         {
+            EnsureInitialized();
+
             if (!CanPut(propertyName))
             {
                 if (throwOnError)
@@ -148,6 +174,8 @@ namespace Jint.Native.Argument
 
         public override bool DefineOwnProperty(string propertyName, PropertyDescriptor desc, bool throwOnError)
         {
+            EnsureInitialized();
+
             if (!Strict && ParameterMap != null)
             {
                 var map = ParameterMap;
@@ -188,6 +216,8 @@ namespace Jint.Native.Argument
 
         public override bool Delete(string propertyName, bool throwOnError)
         {
+            EnsureInitialized();
+
             if (!Strict && ParameterMap != null)
             {
                 var map = ParameterMap;

+ 0 - 6
Jint/Native/Number/NumberPrototype.cs

@@ -281,12 +281,6 @@ namespace Jint.Native.Number
                 return "-" + ToNumberString(-m);
             }
 
-            var l = (long)m;
-            if(l == m)
-            {
-                return l.ToString(CultureInfo.InvariantCulture);
-            }
-
             // V8 FastDtoa can't convert all numbers, so try it first but
             // fall back to old DToA in case it fails
             var result = FastDtoa.NumberToString(m);

+ 13 - 0
Jint/Native/Object/ObjectInstance.cs

@@ -39,16 +39,19 @@ namespace Jint.Native.Object
 
         public virtual IEnumerable<KeyValuePair<string, PropertyDescriptor>> GetOwnProperties()
         {
+            EnsureInitialized();
             return Properties;
         }
 
         public virtual bool HasOwnProperty(string p)
         {
+            EnsureInitialized();
             return Properties.ContainsKey(p);
         }
 
         public virtual void RemoveOwnProperty(string p)
         {
+            EnsureInitialized();
             Properties.Remove(p);
         }
 
@@ -95,6 +98,8 @@ namespace Jint.Native.Object
         /// <returns></returns>
         public virtual PropertyDescriptor GetOwnProperty(string propertyName)
         {
+            EnsureInitialized();
+
             PropertyDescriptor x;
             if (Properties.TryGetValue(propertyName, out x))
             {
@@ -121,6 +126,7 @@ namespace Jint.Native.Object
 
         protected virtual void SetOwnProperty(string propertyName, PropertyDescriptor desc)
         {
+            EnsureInitialized();
             Properties[propertyName] = desc;
         }
 
@@ -306,6 +312,8 @@ namespace Jint.Native.Object
         /// <returns></returns>
         public JsValue DefaultValue(Types hint)
         {
+            EnsureInitialized();
+
             if (hint == Types.String || (hint == Types.None && Class == "Date"))
             {
                 var toString = Get("toString").TryCast<ICallable>();
@@ -599,6 +607,11 @@ namespace Jint.Native.Object
             SetOwnProperty(name, value);
         }
 
+        protected virtual void EnsureInitialized()
+        {
+
+        }
+
         public override string ToString()
         {
             return TypeConverter.ToString(this);