Bug 1421398 - Implement Array.prototype.flatten and Array.prototype.flatMap in Nightly. r=anba,bz
authorTom Schuster <evilpies@gmail.com>
Wed, 17 Jan 2018 19:00:21 +0100
changeset 454199 8ae56bfed524fa53ac9c89f6f00fada73148ed10
parent 454198 b6d4b546fa1fd311f72ac4f3f1de4f249af3cc85
child 454200 6604ac0cc769b98652fd48d7d6ff3e2aa2902a71
push id1648
push usermtabara@mozilla.com
push dateThu, 01 Mar 2018 12:45:47 +0000
treeherdermozilla-release@cbb9688c2eeb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersanba, bz
bugs1421398
milestone59.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1421398 - Implement Array.prototype.flatten and Array.prototype.flatMap in Nightly. r=anba,bz
js/src/builtin/Array.js
js/src/jsarray.cpp
js/xpconnect/tests/chrome/test_xrayToJS.xul
--- a/js/src/builtin/Array.js
+++ b/js/src/builtin/Array.js
@@ -1107,16 +1107,115 @@ function ArrayConcat(arg1) {
 
     // Step 6.
     A.length = n;
 
     // Step 7.
     return A;
 }
 
+// https://tc39.github.io/proposal-flatMap/
+// January 16, 2018
+function ArrayFlatMap(mapperFunction/*, thisArg*/) {
+    // Step 1.
+    var O = ToObject(this);
+
+    // Step 2.
+    var sourceLen = ToLength(O.length);
+
+    // Step 3.
+    if (!IsCallable(mapperFunction))
+        ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, mapperFunction));
+
+    // Step 4.
+    var T = arguments.length > 1 ? arguments[1] : undefined;
+
+    // Step 5.
+    var A = ArraySpeciesCreate(O, 0);
+
+    // Step 6.
+    FlattenIntoArray(A, O, sourceLen, 0, 1, mapperFunction, T);
+
+    // Step 7.
+    return A;
+}
+
+// https://tc39.github.io/proposal-flatMap/
+// January 16, 2018
+function ArrayFlatten(/* depth */) {
+     // Step 1.
+    var O = ToObject(this);
+
+    // Step 2.
+    var sourceLen = ToLength(O.length);
+
+    // Step 3.
+    var depthNum = 1;
+
+    // Step 4.
+    if (arguments.length > 0 && arguments[0] !== undefined)
+        depthNum = ToInteger(arguments[0]);
+
+    // Step 5.
+    var A = ArraySpeciesCreate(O, 0);
+
+    // Step 6.
+    FlattenIntoArray(A, O, sourceLen, 0, depthNum);
+
+    // Step 7.
+    return A;
+}
+
+function FlattenIntoArray(target, source, sourceLen, start, depth, mapperFunction, thisArg) {
+    // Step 1.
+    var targetIndex = start;
+
+    // Steps 2-3.
+    for (var sourceIndex = 0; sourceIndex < sourceLen; sourceIndex++) {
+        // Steps 3.a-c.
+        if (sourceIndex in source) {
+            // Step 3.c.i.
+            var element = source[sourceIndex];
+
+            if (mapperFunction) {
+                // Step 3.c.ii.1.
+                assert(arguments.length === 7, "thisArg is present");
+
+                // Step 3.c.ii.2.
+                element = callContentFunction(mapperFunction, thisArg, element, sourceIndex, source);
+            }
+
+            // Step 3.c.iii.
+            var flattenable = IsArray(element);
+
+            // Step 3.c.iv.
+            if (flattenable && depth > 0) {
+                // Step 3.c.iv.1.
+                var elementLen = ToLength(element.length);
+
+                // Step 3.c.iv.2.
+                targetIndex = FlattenIntoArray(target, element, elementLen, targetIndex, depth - 1);
+            } else {
+                // Step 3.c.v.1.
+                if (targetIndex >= MAX_NUMERIC_INDEX)
+                    ThrowTypeError(JSMSG_TOO_LONG_ARRAY);
+
+                // Step 3.c.v.2.
+                _DefineDataProperty(target, targetIndex, element);
+
+                // Step 3.c.v.3.
+                targetIndex++;
+            }
+        }
+    }
+
+    // Step 4.
+    return targetIndex;
+}
+
 function ArrayStaticConcat(arr, arg1) {
     if (arguments.length < 1)
         ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.concat");
     var args = callFunction(std_Array_slice, arguments, 1);
     return callFunction(std_Function_apply, ArrayConcat, arr, args);
 }
 
 function ArrayStaticJoin(arr, separator) {
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -3544,16 +3544,22 @@ static const JSFunctionSpec array_method
     JS_SELF_HOSTED_FN("entries",     "ArrayEntries",     0,0),
     JS_SELF_HOSTED_FN("keys",        "ArrayKeys",        0,0),
 #ifdef NIGHTLY_BUILD
     JS_SELF_HOSTED_FN("values",      "ArrayValues",      0,0),
 #endif
 
     /* ES7 additions */
     JS_SELF_HOSTED_FN("includes",    "ArrayIncludes",    2,0),
+
+#ifdef NIGHTLY_BUILD
+    JS_SELF_HOSTED_FN("flatMap",     "ArrayFlatMap",     1,0),
+    JS_SELF_HOSTED_FN("flatten",     "ArrayFlatten",     0,0),
+#endif
+
     JS_FS_END
 };
 
 static const JSFunctionSpec array_static_methods[] = {
     JS_INLINABLE_FN("isArray",       array_isArray,        1,0, ArrayIsArray),
     JS_SELF_HOSTED_FN("concat",      "ArrayStaticConcat", 2,0),
     JS_SELF_HOSTED_FN("lastIndexOf", "ArrayStaticLastIndexOf", 2,0),
     JS_SELF_HOSTED_FN("indexOf",     "ArrayStaticIndexOf", 2,0),
--- a/js/xpconnect/tests/chrome/test_xrayToJS.xul
+++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul
@@ -202,16 +202,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   gPrototypeProperties['Array'] =
     ["length", "toSource", "toString", "toLocaleString", "join", "reverse", "sort", "push",
       "pop", "shift", "unshift", "splice", "concat", "slice", "lastIndexOf", "indexOf",
       "includes", "forEach", "map", "reduce", "reduceRight", "filter", "some", "every", "find",
       "findIndex", "copyWithin", "fill", Symbol.iterator, Symbol.unscopables, "entries", "keys",
       "constructor"];
   if (isNightlyBuild) {
     gPrototypeProperties['Array'].push("values");
+    gPrototypeProperties['Array'].push("flatten", "flatMap");
   }
   gConstructorProperties['Array'] =
     constructorProps(["join", "reverse", "sort", "push", "pop", "shift",
                       "unshift", "splice", "concat", "slice", "isArray",
                       "lastIndexOf", "indexOf", "forEach", "map", "filter",
                       "every", "some", "reduce", "reduceRight", "from", "of",
                       Symbol.species]);
   for (var c of typedArrayClasses) {