Bug 911578 - Use self-hosting intrinsic isPackedArray to optimize loops in array extras. r=jandem
authorTill Schneidereit <till@tillschneidereit.net>
Fri, 29 Nov 2013 17:54:36 +0100
changeset 158141 7b039ed2dbacc6f71b4e585f44f633402b1ad32d
parent 158140 d9f86fd4fa60ad3eb02031ccf7a10315c1a83f1f
child 158142 45b3da69a3873bf132bc9b40c52fc3c189852d82
push id25737
push usercbook@mozilla.com
push dateMon, 02 Dec 2013 11:42:38 +0000
treeherdermozilla-central@5b9a4d273114 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs911578
milestone28.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 911578 - Use self-hosting intrinsic isPackedArray to optimize loops in array extras. r=jandem
js/src/builtin/Array.js
--- a/js/src/builtin/Array.js
+++ b/js/src/builtin/Array.js
@@ -30,19 +30,26 @@ function ArrayIndexOf(searchElement/*, f
         /* Step a. */
         k = len + n;
         /* Step b. */
         if (k < 0)
             k = 0;
     }
 
     /* Step 9. */
-    for (; k < len; k++) {
-        if (k in O && O[k] === searchElement)
-            return k;
+    if (IsPackedArray(O)) {
+        for (; k < len; k++) {
+            if (O[k] === searchElement)
+                return k;
+        }
+    } else {
+        for (; k < len; k++) {
+            if (k in O && O[k] === searchElement)
+                return k;
+        }
     }
 
     /* Step 10. */
     return -1;
 }
 
 function ArrayStaticIndexOf(list, searchElement/*, fromIndex*/) {
     if (arguments.length < 1)
@@ -71,19 +78,26 @@ function ArrayLastIndexOf(searchElement/
     if (n > len - 1)
         k = len - 1;
     else if (n < 0)
         k = len + n;
     else
         k = n;
 
     /* Step 8. */
-    for (; k >= 0; k--) {
-        if (k in O && O[k] === searchElement)
-            return k;
+    if (IsPackedArray(O)) {
+        for (; k >= 0; k--) {
+            if (O[k] === searchElement)
+                return k;
+        }
+    } else {
+        for (; k >= 0; k--) {
+            if (k in O && O[k] === searchElement)
+                return k;
+        }
     }
 
     /* Step 9. */
     return -1;
 }
 
 function ArrayStaticLastIndexOf(list, searchElement/*, fromIndex*/) {
     if (arguments.length < 1)
@@ -113,23 +127,32 @@ function ArrayEvery(callbackfn/*, thisAr
     if (!IsCallable(callbackfn))
         ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
 
     /* Step 5. */
     var T = arguments.length > 1 ? arguments[1] : void 0;
 
     /* Steps 6-7. */
     /* Steps a (implicit), and d. */
-    for (var k = 0; k < len; k++) {
-        /* Step b */
-        if (k in O) {
+    if (IsPackedArray(O)) {
+        for (var k = 0; k < len; k++) {
+            /* Step b (omitted). */
             /* Step c. */
             if (!callFunction(callbackfn, T, O[k], k, O))
                 return false;
         }
+    } else {
+        for (var k = 0; k < len; k++) {
+            /* Step b. */
+            if (k in O) {
+                /* Step c. */
+                if (!callFunction(callbackfn, T, O[k], k, O))
+                    return false;
+            }
+        }
     }
 
     /* Step 8. */
     return true;
 }
 
 function ArrayStaticEvery(list, callbackfn/*, thisArg*/) {
     if (arguments.length < 2)
@@ -154,23 +177,32 @@ function ArraySome(callbackfn/*, thisArg
     if (!IsCallable(callbackfn))
         ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
 
     /* Step 5. */
     var T = arguments.length > 1 ? arguments[1] : void 0;
 
     /* Steps 6-7. */
     /* Steps a (implicit), and d. */
-    for (var k = 0; k < len; k++) {
-        /* Step b */
-        if (k in O) {
+    if (IsPackedArray(O)) {
+        for (var k = 0; k < len; k++) {
+            /* Step b (omitted). */
             /* Step c. */
             if (callFunction(callbackfn, T, O[k], k, O))
                 return true;
         }
+    } else {
+        for (var k = 0; k < len; k++) {
+            /* Step b */
+            if (k in O) {
+                /* Step c. */
+                if (callFunction(callbackfn, T, O[k], k, O))
+                    return true;
+            }
+        }
     }
 
     /* Step 8. */
     return false;
 }
 
 function ArrayStaticSome(list, callbackfn/*, thisArg*/) {
     if (arguments.length < 2)
@@ -195,22 +227,30 @@ function ArrayForEach(callbackfn/*, this
     if (!IsCallable(callbackfn))
         ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
 
     /* Step 5. */
     var T = arguments.length > 1 ? arguments[1] : void 0;
 
     /* Steps 6-7. */
     /* Steps a (implicit), and d. */
-    for (var k = 0; k < len; k++) {
-        /* Step b */
-        if (k in O) {
+    if (IsPackedArray(O)) {
+        for (var k = 0; k < len; k++) {
+            /* Step b (omitted). */
             /* Step c. */
             callFunction(callbackfn, T, O[k], k, O);
         }
+    } else {
+        for (var k = 0; k < len; k++) {
+            /* Step b. */
+            if (k in O) {
+                /* Step c. */
+                callFunction(callbackfn, T, O[k], k, O);
+            }
+        }
     }
 
     /* Step 8. */
     return void 0;
 }
 
 /* ES5 15.4.4.19. */
 function ArrayMap(callbackfn/*, thisArg*/) {
@@ -229,24 +269,34 @@ function ArrayMap(callbackfn/*, thisArg*
     /* Step 5. */
     var T = arguments.length > 1 ? arguments[1] : void 0;
 
     /* Step 6. */
     var A = NewDenseArray(len);
 
     /* Step 7-8. */
     /* Step a (implicit), and d. */
-    for (var k = 0; k < len; k++) {
-        /* Step b */
-        if (k in O) {
+    if (IsPackedArray(O)) {
+        for (var k = 0; k < len; k++) {
+            /* Step b (omitted). */
             /* Step c.i-iii. */
             var mappedValue = callFunction(callbackfn, T, O[k], k, O);
             // UnsafePutElements doesn't invoke setters, so we can use it here.
             UnsafePutElements(A, k, mappedValue);
         }
+    } else {
+        for (var k = 0; k < len; k++) {
+            /* Step b. */
+            if (k in O) {
+                /* Step c.i-iii. */
+                var mappedValue = callFunction(callbackfn, T, O[k], k, O);
+                // UnsafePutElements doesn't invoke setters, so we can use it here.
+                UnsafePutElements(A, k, mappedValue);
+            }
+        }
     }
 
     /* Step 9. */
     return A;
 }
 
 function ArrayStaticMap(list, callbackfn/*, thisArg*/) {
     if (arguments.length < 2)
@@ -278,45 +328,59 @@ function ArrayReduce(callbackfn/*, initi
     if (arguments.length === 0)
         ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.prototype.reduce');
     if (!IsCallable(callbackfn))
         ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
 
     /* Step 6. */
     var k = 0;
 
+    var isPacked = IsPackedArray(O);
+
     /* Steps 5, 7-8. */
     var accumulator;
     if (arguments.length > 1) {
         accumulator = arguments[1];
     } else {
         /* Step 5. */
         if (len === 0)
             ThrowError(JSMSG_EMPTY_ARRAY_REDUCE);
-        var kPresent = false;
-        for (; k < len; k++) {
-            if (k in O) {
-                accumulator = O[k];
-                kPresent = true;
-                k++;
-                break;
+        if (isPacked) {
+            accumulator = O[k++];
+        } else {
+            var kPresent = false;
+            for (; k < len; k++) {
+                if (k in O) {
+                    accumulator = O[k];
+                    kPresent = true;
+                    k++;
+                    break;
+                }
             }
+            if (!kPresent)
+              ThrowError(JSMSG_EMPTY_ARRAY_REDUCE);
         }
-        if (!kPresent)
-            ThrowError(JSMSG_EMPTY_ARRAY_REDUCE);
     }
 
     /* Step 9. */
     /* Steps a (implicit), and d. */
-    for (; k < len; k++) {
-        /* Step b */
-        if (k in O) {
+    if (isPacked) {
+        for (; k < len; k++) {
+            /* Step b (omitted). */
             /* Step c. */
             accumulator = callbackfn(accumulator, O[k], k, O);
         }
+    } else {
+        for (; k < len; k++) {
+            /* Step b. */
+            if (k in O) {
+                /* Step c. */
+                accumulator = callbackfn(accumulator, O[k], k, O);
+            }
+        }
     }
 
     /* Step 10. */
     return accumulator;
 }
 
 function ArrayStaticReduce(list, callbackfn) {
     if (arguments.length < 2)
@@ -341,45 +405,59 @@ function ArrayReduceRight(callbackfn/*, 
     if (arguments.length === 0)
         ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.prototype.reduce');
     if (!IsCallable(callbackfn))
         ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
 
     /* Step 6. */
     var k = len - 1;
 
+    var isPacked = IsPackedArray(O);
+
     /* Steps 5, 7-8. */
     var accumulator;
     if (arguments.length > 1) {
         accumulator = arguments[1];
     } else {
         /* Step 5. */
         if (len === 0)
             ThrowError(JSMSG_EMPTY_ARRAY_REDUCE);
-        var kPresent = false;
-        for (; k >= 0; k--) {
-            if (k in O) {
-                accumulator = O[k];
-                kPresent = true;
-                k--;
-                break;
+        if (isPacked) {
+            accumulator = O[k--];
+        } else {
+            var kPresent = false;
+            for (; k >= 0; k--) {
+                if (k in O) {
+                    accumulator = O[k];
+                    kPresent = true;
+                    k--;
+                    break;
+                }
             }
+            if (!kPresent)
+                ThrowError(JSMSG_EMPTY_ARRAY_REDUCE);
         }
-        if (!kPresent)
-            ThrowError(JSMSG_EMPTY_ARRAY_REDUCE);
     }
 
     /* Step 9. */
     /* Steps a (implicit), and d. */
-    for (; k >= 0; k--) {
-        /* Step b */
-        if (k in O) {
+    if (isPacked) {
+        for (; k >= 0; k--) {
+            /* Step b (omitted). */
             /* Step c. */
             accumulator = callbackfn(accumulator, O[k], k, O);
         }
+    } else {
+        for (; k >= 0; k--) {
+            /* Step b. */
+            if (k in O) {
+                /* Step c. */
+                accumulator = callbackfn(accumulator, O[k], k, O);
+            }
+        }
     }
 
     /* Step 10. */
     return accumulator;
 }
 
 function ArrayStaticReduceRight(list, callbackfn) {
     if (arguments.length < 2)
@@ -411,24 +489,35 @@ function ArrayFind(predicate/*, thisArg*
 
     /* Steps 8-9. */
     /* Steps a (implicit), and e. */
     /* Note: this will hang in some corner-case situations, because of IEEE-754 numbers'
      * imprecision for large values. Example:
      * var obj = { 18014398509481984: true, length: 18014398509481988 };
      * Array.prototype.find.call(obj, () => true);
      */
-    for (var k = 0; k < len; k++) {
-        /* Steps b and c (implicit) */
-        if (k in O) {
+    var k;
+    if (IsPackedArray(O)) {
+        for (k = 0; k < len; k++) {
+            /* Steps b (omitted) and c (implicit). */
             /* Step d. */
             var kValue = O[k];
             if (callFunction(predicate, T, kValue, k, O))
                 return kValue;
         }
+    } else {
+        for (k = 0; k < len; k++) {
+            /* Steps b and c (implicit). */
+            if (k in O) {
+                /* Step d. */
+                var kValue = O[k];
+                if (callFunction(predicate, T, kValue, k, O))
+                    return kValue;
+            }
+        }
     }
 
     /* Step 10. */
     return undefined;
 }
 
 /* ES6 draft 2013-05-14 15.4.3.23. */
 function ArrayFindIndex(predicate/*, thisArg*/) {
@@ -449,23 +538,33 @@ function ArrayFindIndex(predicate/*, thi
 
     /* Steps 8-9. */
     /* Steps a (implicit), and e. */
     /* Note: this will hang in some corner-case situations, because of IEEE-754 numbers'
      * imprecision for large values. Example:
      * var obj = { 18014398509481984: true, length: 18014398509481988 };
      * Array.prototype.find.call(obj, () => true);
      */
-    for (var k = 0; k < len; k++) {
-        /* Steps b and c (implicit) */
-        if (k in O) {
+    var k;
+    if (IsPackedArray(O)) {
+        for (k = 0; k < len; k++) {
+            /* Steps b (omitted) and c (implicit). */
             /* Step d. */
             if (callFunction(predicate, T, O[k], k, O))
                 return k;
         }
+    } else {
+        for (k = 0; k < len; k++) {
+            /* Steps b and c (implicit). */
+            if (k in O) {
+                /* Step d. */
+                if (callFunction(predicate, T, O[k], k, O))
+                    return k;
+            }
+        }
     }
 
     /* Step 10. */
     return -1;
 }
 
 #define ARRAY_ITERATOR_SLOT_ITERATED_OBJECT 0
 #define ARRAY_ITERATOR_SLOT_NEXT_INDEX 1