Browse Source

Fix array issues (#1325)

Marko Lahma 2 years ago
parent
commit
ca6c0d679a

+ 17 - 0
Jint.Tests/Runtime/ArrayTests.cs

@@ -194,5 +194,22 @@ namespace Jint.Tests.Runtime
 
             engine.Execute(code);
         }
+
+        [Fact]
+        public void ArrayConstructorFromHoles()
+        {
+            _engine.Evaluate("var a = Array(...[,,]);");
+            Assert.True(_engine.Evaluate("\"0\" in a").AsBoolean());
+            Assert.True(_engine.Evaluate("\"1\" in a").AsBoolean());
+            Assert.Equal("undefinedundefined", _engine.Evaluate("'' + a[0] + a[1]"));
+        }
+
+        [Fact]
+        public void ArrayIsSubclassable()
+        {
+            _engine.Evaluate("class C extends Array {}");
+            _engine.Evaluate("var c = new C();");
+            Assert.True(_engine.Evaluate("c.map(Boolean) instanceof C").AsBoolean());
+        }
     }
 }

+ 2 - 1
Jint/Native/Array/ArrayPrototype.cs

@@ -442,7 +442,8 @@ namespace Jint.Native.Array
         /// </summary>
         private JsValue Map(JsValue thisObj, JsValue[] arguments)
         {
-            if (thisObj is ArrayInstance arrayInstance && !arrayInstance.HasOwnProperty(CommonProperties.Constructor))
+            if (thisObj is ArrayInstance { CanUseFastAccess: true } arrayInstance
+                && !arrayInstance.HasOwnProperty(CommonProperties.Constructor))
             {
                 return arrayInstance.Map(arguments);
             }

+ 9 - 12
Jint/Runtime/Interpreter/Expressions/JintArrayExpression.cs

@@ -17,16 +17,15 @@ namespace Jint.Runtime.Interpreter.Expressions
 
         protected override void Initialize(EvaluationContext context)
         {
-            var engine = context.Engine;
-            var node = (ArrayExpression) _expression;
-            _expressions = new JintExpression[node.Elements.Count];
-            for (var n = 0; n < _expressions.Length; n++)
+            ref readonly var elements = ref ((ArrayExpression) _expression).Elements;
+            var expressions = _expressions = new JintExpression[((ArrayExpression) _expression).Elements.Count];
+            for (var n = 0; n < expressions.Length; n++)
             {
-                var expr = node.Elements[n];
+                var expr = elements[n];
                 if (expr != null)
                 {
                     var expression = Build(expr);
-                    _expressions[n] = expression;
+                    expressions[n] = expression;
                     _hasSpreads |= expr.Type == Nodes.SpreadElement;
                 }
             }
@@ -45,11 +44,9 @@ namespace Jint.Runtime.Interpreter.Expressions
             {
                 if (expr == null)
                 {
-                    arrayIndexCounter++;
-                    continue;
+                    a.SetIndexValue(arrayIndexCounter++, null, updateLength: false);
                 }
-
-                if (_hasSpreads && expr is JintSpreadExpression jse)
+                else if (_hasSpreads && expr is JintSpreadExpression jse)
                 {
                     jse.GetValueAndCheckIterator(context, out var objectInstance, out var iterator);
                     // optimize for array
@@ -87,8 +84,8 @@ namespace Jint.Runtime.Interpreter.Expressions
         private sealed class ArraySpreadProtocol : IteratorProtocol
         {
             private readonly ArrayInstance _instance;
-            internal long _index;
-            internal uint _addedCount = 0;
+            private long _index;
+            internal uint _addedCount;
 
             public ArraySpreadProtocol(
                 Engine engine,

+ 3 - 5
Jint/Runtime/Interpreter/Expressions/JintExpression.cs

@@ -419,15 +419,13 @@ namespace Jint.Runtime.Interpreter.Expressions
                 {
                     jse.GetValueAndCheckIterator(context, out var objectInstance, out var iterator);
                     // optimize for array unless someone has touched the iterator
-                    if (objectInstance is ArrayInstance ai && ai.HasOriginalIterator)
+                    if (objectInstance is ArrayInstance { HasOriginalIterator: true } ai)
                     {
                         var length = ai.GetLength();
                         for (uint j = 0; j < length; ++j)
                         {
-                            if (ai.TryGetValue(j, out var value))
-                            {
-                                args.Add(value);
-                            }
+                            ai.TryGetValue(j, out var value);
+                            args.Add(value);
                         }
                     }
                     else