Bläddra i källkod

LibJS: Bring FlattenIntoArray closer to the specification

This fixes the incorrect exception order and missing exception checks
that were caused by the implementation not conforming exactly to the
specification.
Idan Horowitz 4 år sedan
förälder
incheckning
271eeadf25
1 ändrade filer med 30 tillägg och 22 borttagningar
  1. 30 22
      Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp

+ 30 - 22
Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp

@@ -1303,12 +1303,10 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::keys)
 }
 
 // 23.1.3.10.1 FlattenIntoArray ( target, source, sourceLen, start, depth [ , mapperFunction [ , thisArg ] ] ), https://tc39.es/ecma262/#sec-flattenintoarray
-static size_t flatten_into_array(VM& vm, GlobalObject& global_object, Array& new_array, Object& array, size_t target_index, double depth, Function* mapper_func = {}, Value this_arg = {})
+static size_t flatten_into_array(GlobalObject& global_object, Object& new_array, Object& array, size_t array_length, size_t target_index, double depth, Function* mapper_func = {}, Value this_arg = {})
 {
     VERIFY(!mapper_func || (!this_arg.is_empty() && depth == 1));
-    auto array_length = length_of_array_like(global_object, array);
-    if (vm.exception())
-        return {};
+    auto& vm = global_object.vm();
 
     for (size_t j = 0; j < array_length; ++j) {
         auto value_exists = array.has_property(j);
@@ -1328,20 +1326,25 @@ static size_t flatten_into_array(VM& vm, GlobalObject& global_object, Array& new
         }
 
         if (depth > 0 && value.is_array(global_object)) {
-            target_index = flatten_into_array(vm, global_object, new_array, value.as_array(), target_index, depth - 1);
+            auto length = length_of_array_like(global_object, value.as_array());
+            if (vm.exception())
+                return {};
+            target_index = flatten_into_array(global_object, new_array, value.as_array(), length, target_index, depth - 1);
             if (vm.exception())
                 return {};
             continue;
         }
+
+        if (target_index >= MAX_ARRAY_LIKE_INDEX) {
+            vm.throw_exception<TypeError>(global_object, ErrorType::InvalidIndex);
+            return {};
+        }
+
+        new_array.put(target_index, value);
         if (vm.exception())
             return {};
-        if (!value.is_empty()) {
-            new_array.put(target_index, value);
-            if (vm.exception())
-                return {};
 
-            ++target_index;
-        }
+        ++target_index;
     }
     return target_index;
 }
@@ -1353,20 +1356,21 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::flat)
     if (!this_object)
         return {};
 
-    auto* new_array = Array::create(global_object);
+    auto length = length_of_array_like(global_object, *this_object);
+    if (vm.exception())
+        return {};
 
     double depth = 1;
-    if (vm.argument_count() > 0) {
-        auto depth_argument = vm.argument(0);
-        if (!depth_argument.is_undefined()) {
-            auto depth_num = depth_argument.to_integer_or_infinity(global_object);
-            if (vm.exception())
-                return {};
-            depth = max(depth_num, 0.0);
-        }
+    if (!vm.argument(0).is_undefined()) {
+        auto depth_num = vm.argument(0).to_integer_or_infinity(global_object);
+        if (vm.exception())
+            return {};
+        depth = max(depth_num, 0.0);
     }
 
-    flatten_into_array(vm, global_object, *new_array, *this_object, 0, depth);
+    auto* new_array = Array::create(global_object);
+
+    flatten_into_array(global_object, *new_array, *this_object, length, 0, depth);
     if (vm.exception())
         return {};
     return new_array;
@@ -1379,6 +1383,10 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::flat_map)
     if (!this_object)
         return {};
 
+    auto length = length_of_array_like(global_object, *this_object);
+    if (vm.exception())
+        return {};
+
     auto* mapper_function = callback_from_args(global_object, "flatMap");
     if (!mapper_function)
         return {};
@@ -1388,7 +1396,7 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::flat_map)
     // FIXME: Use ArraySpeciesCreate.
     auto new_array = Array::create(global_object);
 
-    flatten_into_array(vm, global_object, *new_array, *this_object, 0, 1, mapper_function, this_argument);
+    flatten_into_array(global_object, *new_array, *this_object, length, 0, 1, mapper_function, this_argument);
     if (vm.exception())
         return {};