js/src/builtin/Array.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/builtin/Array.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1127 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 + /* ES5 15.4.4.14. */
     1.9 +function ArrayIndexOf(searchElement/*, fromIndex*/) {
    1.10 +    /* Step 1. */
    1.11 +    var O = ToObject(this);
    1.12 +
    1.13 +    /* Steps 2-3. */
    1.14 +    var len = TO_UINT32(O.length);
    1.15 +
    1.16 +    /* Step 4. */
    1.17 +    if (len === 0)
    1.18 +        return -1;
    1.19 +
    1.20 +    /* Step 5. */
    1.21 +    var n = arguments.length > 1 ? ToInteger(arguments[1]) : 0;
    1.22 +
    1.23 +    /* Step 6. */
    1.24 +    if (n >= len)
    1.25 +        return -1;
    1.26 +
    1.27 +    var k;
    1.28 +    /* Step 7. */
    1.29 +    if (n >= 0)
    1.30 +        k = n;
    1.31 +    /* Step 8. */
    1.32 +    else {
    1.33 +        /* Step a. */
    1.34 +        k = len + n;
    1.35 +        /* Step b. */
    1.36 +        if (k < 0)
    1.37 +            k = 0;
    1.38 +    }
    1.39 +
    1.40 +    /* Step 9. */
    1.41 +    if (IsPackedArray(O)) {
    1.42 +        for (; k < len; k++) {
    1.43 +            if (O[k] === searchElement)
    1.44 +                return k;
    1.45 +        }
    1.46 +    } else {
    1.47 +        for (; k < len; k++) {
    1.48 +            if (k in O && O[k] === searchElement)
    1.49 +                return k;
    1.50 +        }
    1.51 +    }
    1.52 +
    1.53 +    /* Step 10. */
    1.54 +    return -1;
    1.55 +}
    1.56 +
    1.57 +function ArrayStaticIndexOf(list, searchElement/*, fromIndex*/) {
    1.58 +    if (arguments.length < 1)
    1.59 +        ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.indexOf');
    1.60 +    var fromIndex = arguments.length > 2 ? arguments[2] : 0;
    1.61 +    return callFunction(ArrayIndexOf, list, searchElement, fromIndex);
    1.62 +}
    1.63 +
    1.64 +/* ES5 15.4.4.15. */
    1.65 +function ArrayLastIndexOf(searchElement/*, fromIndex*/) {
    1.66 +    /* Step 1. */
    1.67 +    var O = ToObject(this);
    1.68 +
    1.69 +    /* Steps 2-3. */
    1.70 +    var len = TO_UINT32(O.length);
    1.71 +
    1.72 +    /* Step 4. */
    1.73 +    if (len === 0)
    1.74 +        return -1;
    1.75 +
    1.76 +    /* Step 5. */
    1.77 +    var n = arguments.length > 1 ? ToInteger(arguments[1]) : len - 1;
    1.78 +
    1.79 +    /* Steps 6-7. */
    1.80 +    var k;
    1.81 +    if (n > len - 1)
    1.82 +        k = len - 1;
    1.83 +    else if (n < 0)
    1.84 +        k = len + n;
    1.85 +    else
    1.86 +        k = n;
    1.87 +
    1.88 +    /* Step 8. */
    1.89 +    if (IsPackedArray(O)) {
    1.90 +        for (; k >= 0; k--) {
    1.91 +            if (O[k] === searchElement)
    1.92 +                return k;
    1.93 +        }
    1.94 +    } else {
    1.95 +        for (; k >= 0; k--) {
    1.96 +            if (k in O && O[k] === searchElement)
    1.97 +                return k;
    1.98 +        }
    1.99 +    }
   1.100 +
   1.101 +    /* Step 9. */
   1.102 +    return -1;
   1.103 +}
   1.104 +
   1.105 +function ArrayStaticLastIndexOf(list, searchElement/*, fromIndex*/) {
   1.106 +    if (arguments.length < 1)
   1.107 +        ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.lastIndexOf');
   1.108 +    var fromIndex;
   1.109 +    if (arguments.length > 2) {
   1.110 +        fromIndex = arguments[2];
   1.111 +    } else {
   1.112 +        var O = ToObject(list);
   1.113 +        var len = TO_UINT32(O.length);
   1.114 +        fromIndex = len - 1;
   1.115 +    }
   1.116 +    return callFunction(ArrayLastIndexOf, list, searchElement, fromIndex);
   1.117 +}
   1.118 +
   1.119 +/* ES5 15.4.4.16. */
   1.120 +function ArrayEvery(callbackfn/*, thisArg*/) {
   1.121 +    /* Step 1. */
   1.122 +    var O = ToObject(this);
   1.123 +
   1.124 +    /* Steps 2-3. */
   1.125 +    var len = TO_UINT32(O.length);
   1.126 +
   1.127 +    /* Step 4. */
   1.128 +    if (arguments.length === 0)
   1.129 +        ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.prototype.every');
   1.130 +    if (!IsCallable(callbackfn))
   1.131 +        ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
   1.132 +
   1.133 +    /* Step 5. */
   1.134 +    var T = arguments.length > 1 ? arguments[1] : void 0;
   1.135 +
   1.136 +    /* Steps 6-7. */
   1.137 +    /* Steps a (implicit), and d. */
   1.138 +    for (var k = 0; k < len; k++) {
   1.139 +        /* Step b */
   1.140 +        if (k in O) {
   1.141 +            /* Step c. */
   1.142 +            if (!callFunction(callbackfn, T, O[k], k, O))
   1.143 +                return false;
   1.144 +        }
   1.145 +    }
   1.146 +
   1.147 +    /* Step 8. */
   1.148 +    return true;
   1.149 +}
   1.150 +
   1.151 +function ArrayStaticEvery(list, callbackfn/*, thisArg*/) {
   1.152 +    if (arguments.length < 2)
   1.153 +        ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.every');
   1.154 +    if (!IsCallable(callbackfn))
   1.155 +        ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(1, callbackfn));
   1.156 +    var T = arguments.length > 2 ? arguments[2] : void 0;
   1.157 +    return callFunction(ArrayEvery, list, callbackfn, T);
   1.158 +}
   1.159 +
   1.160 +/* ES5 15.4.4.17. */
   1.161 +function ArraySome(callbackfn/*, thisArg*/) {
   1.162 +    /* Step 1. */
   1.163 +    var O = ToObject(this);
   1.164 +
   1.165 +    /* Steps 2-3. */
   1.166 +    var len = TO_UINT32(O.length);
   1.167 +
   1.168 +    /* Step 4. */
   1.169 +    if (arguments.length === 0)
   1.170 +        ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.prototype.some');
   1.171 +    if (!IsCallable(callbackfn))
   1.172 +        ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
   1.173 +
   1.174 +    /* Step 5. */
   1.175 +    var T = arguments.length > 1 ? arguments[1] : void 0;
   1.176 +
   1.177 +    /* Steps 6-7. */
   1.178 +    /* Steps a (implicit), and d. */
   1.179 +    for (var k = 0; k < len; k++) {
   1.180 +        /* Step b */
   1.181 +        if (k in O) {
   1.182 +            /* Step c. */
   1.183 +            if (callFunction(callbackfn, T, O[k], k, O))
   1.184 +                return true;
   1.185 +        }
   1.186 +    }
   1.187 +
   1.188 +    /* Step 8. */
   1.189 +    return false;
   1.190 +}
   1.191 +
   1.192 +function ArrayStaticSome(list, callbackfn/*, thisArg*/) {
   1.193 +    if (arguments.length < 2)
   1.194 +        ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.some');
   1.195 +    if (!IsCallable(callbackfn))
   1.196 +        ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(1, callbackfn));
   1.197 +    var T = arguments.length > 2 ? arguments[2] : void 0;
   1.198 +    return callFunction(ArraySome, list, callbackfn, T);
   1.199 +}
   1.200 +
   1.201 +/* ES5 15.4.4.18. */
   1.202 +function ArrayForEach(callbackfn/*, thisArg*/) {
   1.203 +    /* Step 1. */
   1.204 +    var O = ToObject(this);
   1.205 +
   1.206 +    /* Steps 2-3. */
   1.207 +    var len = TO_UINT32(O.length);
   1.208 +
   1.209 +    /* Step 4. */
   1.210 +    if (arguments.length === 0)
   1.211 +        ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.prototype.forEach');
   1.212 +    if (!IsCallable(callbackfn))
   1.213 +        ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
   1.214 +
   1.215 +    /* Step 5. */
   1.216 +    var T = arguments.length > 1 ? arguments[1] : void 0;
   1.217 +
   1.218 +    /* Steps 6-7. */
   1.219 +    /* Steps a (implicit), and d. */
   1.220 +    for (var k = 0; k < len; k++) {
   1.221 +        /* Step b */
   1.222 +        if (k in O) {
   1.223 +            /* Step c. */
   1.224 +            callFunction(callbackfn, T, O[k], k, O);
   1.225 +        }
   1.226 +    }
   1.227 +
   1.228 +    /* Step 8. */
   1.229 +    return void 0;
   1.230 +}
   1.231 +
   1.232 +/* ES5 15.4.4.19. */
   1.233 +function ArrayMap(callbackfn/*, thisArg*/) {
   1.234 +    /* Step 1. */
   1.235 +    var O = ToObject(this);
   1.236 +
   1.237 +    /* Step 2-3. */
   1.238 +    var len = TO_UINT32(O.length);
   1.239 +
   1.240 +    /* Step 4. */
   1.241 +    if (arguments.length === 0)
   1.242 +        ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.prototype.map');
   1.243 +    if (!IsCallable(callbackfn))
   1.244 +        ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
   1.245 +
   1.246 +    /* Step 5. */
   1.247 +    var T = arguments.length > 1 ? arguments[1] : void 0;
   1.248 +
   1.249 +    /* Step 6. */
   1.250 +    var A = NewDenseArray(len);
   1.251 +
   1.252 +    /* Step 7-8. */
   1.253 +    /* Step a (implicit), and d. */
   1.254 +    for (var k = 0; k < len; k++) {
   1.255 +        /* Step b */
   1.256 +        if (k in O) {
   1.257 +            /* Step c.i-iii. */
   1.258 +            var mappedValue = callFunction(callbackfn, T, O[k], k, O);
   1.259 +            // UnsafePutElements doesn't invoke setters, so we can use it here.
   1.260 +            UnsafePutElements(A, k, mappedValue);
   1.261 +        }
   1.262 +    }
   1.263 +
   1.264 +    /* Step 9. */
   1.265 +    return A;
   1.266 +}
   1.267 +
   1.268 +function ArrayStaticMap(list, callbackfn/*, thisArg*/) {
   1.269 +    if (arguments.length < 2)
   1.270 +        ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.map');
   1.271 +    if (!IsCallable(callbackfn))
   1.272 +        ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(1, callbackfn));
   1.273 +    var T = arguments.length > 2 ? arguments[2] : void 0;
   1.274 +    return callFunction(ArrayMap, list, callbackfn, T);
   1.275 +}
   1.276 +
   1.277 +function ArrayStaticForEach(list, callbackfn/*, thisArg*/) {
   1.278 +    if (arguments.length < 2)
   1.279 +        ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.forEach');
   1.280 +    if (!IsCallable(callbackfn))
   1.281 +        ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(1, callbackfn));
   1.282 +    var T = arguments.length > 2 ? arguments[2] : void 0;
   1.283 +    callFunction(ArrayForEach, list, callbackfn, T);
   1.284 +}
   1.285 +
   1.286 +/* ES5 15.4.4.21. */
   1.287 +function ArrayReduce(callbackfn/*, initialValue*/) {
   1.288 +    /* Step 1. */
   1.289 +    var O = ToObject(this);
   1.290 +
   1.291 +    /* Steps 2-3. */
   1.292 +    var len = TO_UINT32(O.length);
   1.293 +
   1.294 +    /* Step 4. */
   1.295 +    if (arguments.length === 0)
   1.296 +        ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.prototype.reduce');
   1.297 +    if (!IsCallable(callbackfn))
   1.298 +        ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
   1.299 +
   1.300 +    /* Step 6. */
   1.301 +    var k = 0;
   1.302 +
   1.303 +    /* Steps 5, 7-8. */
   1.304 +    var accumulator;
   1.305 +    if (arguments.length > 1) {
   1.306 +        accumulator = arguments[1];
   1.307 +    } else {
   1.308 +        /* Step 5. */
   1.309 +        if (len === 0)
   1.310 +            ThrowError(JSMSG_EMPTY_ARRAY_REDUCE);
   1.311 +        if (IsPackedArray(O)) {
   1.312 +            accumulator = O[k++];
   1.313 +        } else {
   1.314 +            var kPresent = false;
   1.315 +            for (; k < len; k++) {
   1.316 +                if (k in O) {
   1.317 +                    accumulator = O[k];
   1.318 +                    kPresent = true;
   1.319 +                    k++;
   1.320 +                    break;
   1.321 +                }
   1.322 +            }
   1.323 +            if (!kPresent)
   1.324 +              ThrowError(JSMSG_EMPTY_ARRAY_REDUCE);
   1.325 +        }
   1.326 +    }
   1.327 +
   1.328 +    /* Step 9. */
   1.329 +    /* Steps a (implicit), and d. */
   1.330 +    for (; k < len; k++) {
   1.331 +        /* Step b */
   1.332 +        if (k in O) {
   1.333 +            /* Step c. */
   1.334 +            accumulator = callbackfn(accumulator, O[k], k, O);
   1.335 +        }
   1.336 +    }
   1.337 +
   1.338 +    /* Step 10. */
   1.339 +    return accumulator;
   1.340 +}
   1.341 +
   1.342 +function ArrayStaticReduce(list, callbackfn) {
   1.343 +    if (arguments.length < 2)
   1.344 +        ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.reduce');
   1.345 +    if (!IsCallable(callbackfn))
   1.346 +        ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(1, callbackfn));
   1.347 +    if (arguments.length > 2)
   1.348 +        return callFunction(ArrayReduce, list, callbackfn, arguments[2]);
   1.349 +    else
   1.350 +        return callFunction(ArrayReduce, list, callbackfn);
   1.351 +}
   1.352 +
   1.353 +/* ES5 15.4.4.22. */
   1.354 +function ArrayReduceRight(callbackfn/*, initialValue*/) {
   1.355 +    /* Step 1. */
   1.356 +    var O = ToObject(this);
   1.357 +
   1.358 +    /* Steps 2-3. */
   1.359 +    var len = TO_UINT32(O.length);
   1.360 +
   1.361 +    /* Step 4. */
   1.362 +    if (arguments.length === 0)
   1.363 +        ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.prototype.reduce');
   1.364 +    if (!IsCallable(callbackfn))
   1.365 +        ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
   1.366 +
   1.367 +    /* Step 6. */
   1.368 +    var k = len - 1;
   1.369 +
   1.370 +    /* Steps 5, 7-8. */
   1.371 +    var accumulator;
   1.372 +    if (arguments.length > 1) {
   1.373 +        accumulator = arguments[1];
   1.374 +    } else {
   1.375 +        /* Step 5. */
   1.376 +        if (len === 0)
   1.377 +            ThrowError(JSMSG_EMPTY_ARRAY_REDUCE);
   1.378 +        if (IsPackedArray(O)) {
   1.379 +            accumulator = O[k--];
   1.380 +        } else {
   1.381 +            var kPresent = false;
   1.382 +            for (; k >= 0; k--) {
   1.383 +                if (k in O) {
   1.384 +                    accumulator = O[k];
   1.385 +                    kPresent = true;
   1.386 +                    k--;
   1.387 +                    break;
   1.388 +                }
   1.389 +            }
   1.390 +            if (!kPresent)
   1.391 +                ThrowError(JSMSG_EMPTY_ARRAY_REDUCE);
   1.392 +        }
   1.393 +    }
   1.394 +
   1.395 +    /* Step 9. */
   1.396 +    /* Steps a (implicit), and d. */
   1.397 +    for (; k >= 0; k--) {
   1.398 +        /* Step b */
   1.399 +        if (k in O) {
   1.400 +            /* Step c. */
   1.401 +            accumulator = callbackfn(accumulator, O[k], k, O);
   1.402 +        }
   1.403 +    }
   1.404 +
   1.405 +    /* Step 10. */
   1.406 +    return accumulator;
   1.407 +}
   1.408 +
   1.409 +function ArrayStaticReduceRight(list, callbackfn) {
   1.410 +    if (arguments.length < 2)
   1.411 +        ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.reduceRight');
   1.412 +    if (!IsCallable(callbackfn))
   1.413 +        ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(1, callbackfn));
   1.414 +    if (arguments.length > 2)
   1.415 +        return callFunction(ArrayReduceRight, list, callbackfn, arguments[2]);
   1.416 +    else
   1.417 +        return callFunction(ArrayReduceRight, list, callbackfn);
   1.418 +}
   1.419 +
   1.420 +/* ES6 draft 2013-05-14 15.4.3.23. */
   1.421 +function ArrayFind(predicate/*, thisArg*/) {
   1.422 +    /* Steps 1-2. */
   1.423 +    var O = ToObject(this);
   1.424 +
   1.425 +    /* Steps 3-5. */
   1.426 +    var len = ToInteger(O.length);
   1.427 +
   1.428 +    /* Step 6. */
   1.429 +    if (arguments.length === 0)
   1.430 +        ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.prototype.find');
   1.431 +    if (!IsCallable(predicate))
   1.432 +        ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, predicate));
   1.433 +
   1.434 +    /* Step 7. */
   1.435 +    var T = arguments.length > 1 ? arguments[1] : undefined;
   1.436 +
   1.437 +    /* Steps 8-9. */
   1.438 +    /* Steps a (implicit), and e. */
   1.439 +    /* Note: this will hang in some corner-case situations, because of IEEE-754 numbers'
   1.440 +     * imprecision for large values. Example:
   1.441 +     * var obj = { 18014398509481984: true, length: 18014398509481988 };
   1.442 +     * Array.prototype.find.call(obj, () => true);
   1.443 +     */
   1.444 +    for (var k = 0; k < len; k++) {
   1.445 +        /* Steps b and c (implicit) */
   1.446 +        if (k in O) {
   1.447 +            /* Step d. */
   1.448 +            var kValue = O[k];
   1.449 +            if (callFunction(predicate, T, kValue, k, O))
   1.450 +                return kValue;
   1.451 +        }
   1.452 +    }
   1.453 +
   1.454 +    /* Step 10. */
   1.455 +    return undefined;
   1.456 +}
   1.457 +
   1.458 +/* ES6 draft 2013-05-14 15.4.3.23. */
   1.459 +function ArrayFindIndex(predicate/*, thisArg*/) {
   1.460 +    /* Steps 1-2. */
   1.461 +    var O = ToObject(this);
   1.462 +
   1.463 +    /* Steps 3-5. */
   1.464 +    var len = ToInteger(O.length);
   1.465 +
   1.466 +    /* Step 6. */
   1.467 +    if (arguments.length === 0)
   1.468 +        ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.prototype.find');
   1.469 +    if (!IsCallable(predicate))
   1.470 +        ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, predicate));
   1.471 +
   1.472 +    /* Step 7. */
   1.473 +    var T = arguments.length > 1 ? arguments[1] : undefined;
   1.474 +
   1.475 +    /* Steps 8-9. */
   1.476 +    /* Steps a (implicit), and e. */
   1.477 +    /* Note: this will hang in some corner-case situations, because of IEEE-754 numbers'
   1.478 +     * imprecision for large values. Example:
   1.479 +     * var obj = { 18014398509481984: true, length: 18014398509481988 };
   1.480 +     * Array.prototype.find.call(obj, () => true);
   1.481 +     */
   1.482 +    for (var k = 0; k < len; k++) {
   1.483 +        /* Steps b and c (implicit) */
   1.484 +        if (k in O) {
   1.485 +            /* Step d. */
   1.486 +            if (callFunction(predicate, T, O[k], k, O))
   1.487 +                return k;
   1.488 +        }
   1.489 +    }
   1.490 +
   1.491 +    /* Step 10. */
   1.492 +    return -1;
   1.493 +}
   1.494 +
   1.495 +// ES6 draft 2014-04-05 22.1.3.6
   1.496 +function ArrayFill(value, start = 0, end = undefined) {
   1.497 +    // Steps 1-2.
   1.498 +    var O = ToObject(this);
   1.499 +
   1.500 +    // Steps 3-5.
   1.501 +    // FIXME: Array operations should use ToLength (bug 924058).
   1.502 +    var len = ToInteger(O.length);
   1.503 +
   1.504 +    // Steps 6-7.
   1.505 +    var relativeStart = ToInteger(start);
   1.506 +
   1.507 +    // Step 8.
   1.508 +    var k = relativeStart < 0
   1.509 +            ? std_Math_max(len + relativeStart, 0)
   1.510 +            : std_Math_min(relativeStart, len);
   1.511 +
   1.512 +    // Steps 9-10.
   1.513 +    var relativeEnd = end === undefined ? len : ToInteger(end);
   1.514 +
   1.515 +    // Step 11.
   1.516 +    var final = relativeEnd < 0
   1.517 +                ? std_Math_max(len + relativeEnd, 0)
   1.518 +                : std_Math_min(relativeEnd, len);
   1.519 +
   1.520 +    // Step 12.
   1.521 +    for (; k < final; k++) {
   1.522 +        O[k] = value;
   1.523 +    }
   1.524 +
   1.525 +    // Step 13.
   1.526 +    return O;
   1.527 +}
   1.528 +
   1.529 +#define ARRAY_ITERATOR_SLOT_ITERATED_OBJECT 0
   1.530 +#define ARRAY_ITERATOR_SLOT_NEXT_INDEX 1
   1.531 +#define ARRAY_ITERATOR_SLOT_ITEM_KIND 2
   1.532 +
   1.533 +#define ITEM_KIND_VALUE 0
   1.534 +#define ITEM_KIND_KEY_AND_VALUE 1
   1.535 +#define ITEM_KIND_KEY 2
   1.536 +
   1.537 +// ES6 draft specification, section 22.1.5.1, version 2013-09-05.
   1.538 +function CreateArrayIteratorAt(obj, kind, n) {
   1.539 +    var iteratedObject = ToObject(obj);
   1.540 +    var iterator = NewArrayIterator();
   1.541 +    UnsafeSetReservedSlot(iterator, ARRAY_ITERATOR_SLOT_ITERATED_OBJECT, iteratedObject);
   1.542 +    UnsafeSetReservedSlot(iterator, ARRAY_ITERATOR_SLOT_NEXT_INDEX, n);
   1.543 +    UnsafeSetReservedSlot(iterator, ARRAY_ITERATOR_SLOT_ITEM_KIND, kind);
   1.544 +    return iterator;
   1.545 +}
   1.546 +function CreateArrayIterator(obj, kind) {
   1.547 +    return CreateArrayIteratorAt(obj, kind, 0);
   1.548 +}
   1.549 +
   1.550 +function ArrayIteratorIdentity() {
   1.551 +    return this;
   1.552 +}
   1.553 +
   1.554 +function ArrayIteratorNext() {
   1.555 +    // FIXME: ArrayIterator prototype should not pass this test.  Bug 924059.
   1.556 +    if (!IsObject(this) || !IsArrayIterator(this))
   1.557 +        ThrowError(JSMSG_INCOMPATIBLE_METHOD, "ArrayIterator", "next", ToString(this));
   1.558 +
   1.559 +    var a = UnsafeGetReservedSlot(this, ARRAY_ITERATOR_SLOT_ITERATED_OBJECT);
   1.560 +    var index = UnsafeGetReservedSlot(this, ARRAY_ITERATOR_SLOT_NEXT_INDEX);
   1.561 +    var itemKind = UnsafeGetReservedSlot(this, ARRAY_ITERATOR_SLOT_ITEM_KIND);
   1.562 +
   1.563 +    // FIXME: This should be ToLength, which clamps at 2**53.  Bug 924058.
   1.564 +    if (index >= TO_UINT32(a.length)) {
   1.565 +        // When the above is changed to ToLength, use +1/0 here instead
   1.566 +        // of MAX_UINT32.
   1.567 +        UnsafeSetReservedSlot(this, ARRAY_ITERATOR_SLOT_NEXT_INDEX, 0xffffffff);
   1.568 +        return { value: undefined, done: true };
   1.569 +    }
   1.570 +
   1.571 +    UnsafeSetReservedSlot(this, ARRAY_ITERATOR_SLOT_NEXT_INDEX, index + 1);
   1.572 +
   1.573 +    if (itemKind === ITEM_KIND_VALUE)
   1.574 +        return { value: a[index], done: false };
   1.575 +
   1.576 +    if (itemKind === ITEM_KIND_KEY_AND_VALUE) {
   1.577 +        var pair = NewDenseArray(2);
   1.578 +        pair[0] = index;
   1.579 +        pair[1] = a[index];
   1.580 +        return { value: pair, done : false };
   1.581 +    }
   1.582 +
   1.583 +    assert(itemKind === ITEM_KIND_KEY, itemKind);
   1.584 +    return { value: index, done: false };
   1.585 +}
   1.586 +
   1.587 +function ArrayValuesAt(n) {
   1.588 +    return CreateArrayIteratorAt(this, ITEM_KIND_VALUE, n);
   1.589 +}
   1.590 +
   1.591 +function ArrayValues() {
   1.592 +    return CreateArrayIterator(this, ITEM_KIND_VALUE);
   1.593 +}
   1.594 +
   1.595 +function ArrayEntries() {
   1.596 +    return CreateArrayIterator(this, ITEM_KIND_KEY_AND_VALUE);
   1.597 +}
   1.598 +
   1.599 +function ArrayKeys() {
   1.600 +    return CreateArrayIterator(this, ITEM_KIND_KEY);
   1.601 +}
   1.602 +
   1.603 +#ifdef ENABLE_PARALLEL_JS
   1.604 +
   1.605 +/*
   1.606 + * Strawman spec:
   1.607 + *   http://wiki.ecmascript.org/doku.php?id=strawman:data_parallelism
   1.608 + */
   1.609 +
   1.610 +/**
   1.611 + * Creates a new array by applying |func(e, i, self)| for each element |e|
   1.612 + * with index |i|.
   1.613 + */
   1.614 +function ArrayMapPar(func, mode) {
   1.615 +  if (!IsCallable(func))
   1.616 +    ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, func));
   1.617 +
   1.618 +  var self = ToObject(this);
   1.619 +  var length = self.length;
   1.620 +  var buffer = NewDenseArray(length);
   1.621 +
   1.622 +  parallel: for (;;) {
   1.623 +    // Avoid parallel compilation if we are already nested in another
   1.624 +    // parallel section or the user told us not to parallelize. The
   1.625 +    // use of a for (;;) loop is working around some ion limitations:
   1.626 +    //
   1.627 +    // - Breaking out of named blocks does not currently work (bug 684384);
   1.628 +    // - Unreachable Code Elim. can't properly handle if (a && b) (bug 669796)
   1.629 +    if (ShouldForceSequential())
   1.630 +      break parallel;
   1.631 +    if (!TRY_PARALLEL(mode))
   1.632 +      break parallel;
   1.633 +
   1.634 +    var slicesInfo = ComputeSlicesInfo(length);
   1.635 +    ForkJoin(mapThread, 0, slicesInfo.count, ForkJoinMode(mode));
   1.636 +    return buffer;
   1.637 +  }
   1.638 +
   1.639 +  // Sequential fallback:
   1.640 +  ASSERT_SEQUENTIAL_IS_OK(mode);
   1.641 +  for (var i = 0; i < length; i++)
   1.642 +    UnsafePutElements(buffer, i, func(self[i], i, self));
   1.643 +  return buffer;
   1.644 +
   1.645 +  function mapThread(workerId, sliceStart, sliceEnd) {
   1.646 +    var sliceShift = slicesInfo.shift;
   1.647 +    var sliceId;
   1.648 +    while (GET_SLICE(sliceStart, sliceEnd, sliceId)) {
   1.649 +      var indexStart = SLICE_START_INDEX(sliceShift, sliceId);
   1.650 +      var indexEnd = SLICE_END_INDEX(sliceShift, indexStart, length);
   1.651 +      for (var i = indexStart; i < indexEnd; i++)
   1.652 +        UnsafePutElements(buffer, i, func(self[i], i, self));
   1.653 +    }
   1.654 +    return sliceId;
   1.655 +  }
   1.656 +
   1.657 +  return undefined;
   1.658 +}
   1.659 +
   1.660 +/**
   1.661 + * Reduces the elements in an array in parallel. Order is not fixed and |func|
   1.662 + * is assumed to be associative.
   1.663 + */
   1.664 +function ArrayReducePar(func, mode) {
   1.665 +  if (!IsCallable(func))
   1.666 +    ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, func));
   1.667 +
   1.668 +  var self = ToObject(this);
   1.669 +  var length = self.length;
   1.670 +
   1.671 +  if (length === 0)
   1.672 +    ThrowError(JSMSG_EMPTY_ARRAY_REDUCE);
   1.673 +
   1.674 +  parallel: for (;;) { // see ArrayMapPar() to explain why for(;;) etc
   1.675 +    if (ShouldForceSequential())
   1.676 +      break parallel;
   1.677 +    if (!TRY_PARALLEL(mode))
   1.678 +      break parallel;
   1.679 +
   1.680 +    var slicesInfo = ComputeSlicesInfo(length);
   1.681 +    var numSlices = slicesInfo.count;
   1.682 +    var subreductions = NewDenseArray(numSlices);
   1.683 +
   1.684 +    ForkJoin(reduceThread, 0, numSlices, ForkJoinMode(mode));
   1.685 +
   1.686 +    var accumulator = subreductions[0];
   1.687 +    for (var i = 1; i < numSlices; i++)
   1.688 +      accumulator = func(accumulator, subreductions[i]);
   1.689 +    return accumulator;
   1.690 +  }
   1.691 +
   1.692 +  // Sequential fallback:
   1.693 +  ASSERT_SEQUENTIAL_IS_OK(mode);
   1.694 +  var accumulator = self[0];
   1.695 +  for (var i = 1; i < length; i++)
   1.696 +    accumulator = func(accumulator, self[i]);
   1.697 +  return accumulator;
   1.698 +
   1.699 +  function reduceThread(workerId, sliceStart, sliceEnd) {
   1.700 +    var sliceShift = slicesInfo.shift;
   1.701 +    var sliceId;
   1.702 +    while (GET_SLICE(sliceStart, sliceEnd, sliceId)) {
   1.703 +      var indexStart = SLICE_START_INDEX(sliceShift, sliceId);
   1.704 +      var indexEnd = SLICE_END_INDEX(sliceShift, indexStart, length);
   1.705 +      var accumulator = self[indexStart];
   1.706 +      for (var i = indexStart + 1; i < indexEnd; i++)
   1.707 +        accumulator = func(accumulator, self[i]);
   1.708 +      UnsafePutElements(subreductions, sliceId, accumulator);
   1.709 +    }
   1.710 +    return sliceId;
   1.711 +  }
   1.712 +
   1.713 +  return undefined;
   1.714 +}
   1.715 +
   1.716 +/**
   1.717 + * Returns an array [s_0, ..., s_N] where |s_i| is equal to the reduction (as
   1.718 + * per |reduce()|) of elements |0..i|. This is the generalization of partial
   1.719 + * sum.
   1.720 + */
   1.721 +function ArrayScanPar(func, mode) {
   1.722 +  if (!IsCallable(func))
   1.723 +    ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, func));
   1.724 +
   1.725 +  var self = ToObject(this);
   1.726 +  var length = self.length;
   1.727 +
   1.728 +  if (length === 0)
   1.729 +    ThrowError(JSMSG_EMPTY_ARRAY_REDUCE);
   1.730 +
   1.731 +  var buffer = NewDenseArray(length);
   1.732 +
   1.733 +  parallel: for (;;) { // see ArrayMapPar() to explain why for(;;) etc
   1.734 +    if (ShouldForceSequential())
   1.735 +      break parallel;
   1.736 +    if (!TRY_PARALLEL(mode))
   1.737 +      break parallel;
   1.738 +
   1.739 +    var slicesInfo = ComputeSlicesInfo(length);
   1.740 +    var numSlices = slicesInfo.count;
   1.741 +
   1.742 +    // Scan slices individually (see comment on phase1()).
   1.743 +    ForkJoin(phase1, 0, numSlices, ForkJoinMode(mode));
   1.744 +
   1.745 +    // Compute intermediates array (see comment on phase2()).
   1.746 +    var intermediates = [];
   1.747 +    var accumulator = buffer[finalElement(0)];
   1.748 +    ARRAY_PUSH(intermediates, accumulator);
   1.749 +    for (var i = 1; i < numSlices - 1; i++) {
   1.750 +      accumulator = func(accumulator, buffer[finalElement(i)]);
   1.751 +      ARRAY_PUSH(intermediates, accumulator);
   1.752 +    }
   1.753 +
   1.754 +    // Complete each slice using intermediates array (see comment on phase2()).
   1.755 +    //
   1.756 +    // We start from slice 1 instead of 0 since there is no work to be done
   1.757 +    // for slice 0.
   1.758 +    if (numSlices > 1)
   1.759 +      ForkJoin(phase2, 1, numSlices, ForkJoinMode(mode));
   1.760 +    return buffer;
   1.761 +  }
   1.762 +
   1.763 +  // Sequential fallback:
   1.764 +  ASSERT_SEQUENTIAL_IS_OK(mode);
   1.765 +  scan(self[0], 0, length);
   1.766 +  return buffer;
   1.767 +
   1.768 +  function scan(accumulator, start, end) {
   1.769 +    UnsafePutElements(buffer, start, accumulator);
   1.770 +    for (var i = start + 1; i < end; i++) {
   1.771 +      accumulator = func(accumulator, self[i]);
   1.772 +      UnsafePutElements(buffer, i, accumulator);
   1.773 +    }
   1.774 +    return accumulator;
   1.775 +  }
   1.776 +
   1.777 +  /**
   1.778 +   * In phase 1, we divide the source array into |numSlices| slices and
   1.779 +   * compute scan on each slice sequentially as if it were the entire
   1.780 +   * array. This function is responsible for computing one of those
   1.781 +   * slices.
   1.782 +   *
   1.783 +   * So, if we have an array [A,B,C,D,E,F,G,H,I], |numSlices === 3|,
   1.784 +   * and our function |func| is sum, then we would wind up computing a
   1.785 +   * result array like:
   1.786 +   *
   1.787 +   *     [A, A+B, A+B+C, D, D+E, D+E+F, G, G+H, G+H+I]
   1.788 +   *      ^~~~~~~~~~~~^  ^~~~~~~~~~~~^  ^~~~~~~~~~~~~^
   1.789 +   *      Slice 0        Slice 1        Slice 2
   1.790 +   *
   1.791 +   * Read on in phase2 to see what we do next!
   1.792 +   */
   1.793 +  function phase1(workerId, sliceStart, sliceEnd) {
   1.794 +    var sliceShift = slicesInfo.shift;
   1.795 +    var sliceId;
   1.796 +    while (GET_SLICE(sliceStart, sliceEnd, sliceId)) {
   1.797 +      var indexStart = SLICE_START_INDEX(sliceShift, sliceId);
   1.798 +      var indexEnd = SLICE_END_INDEX(sliceShift, indexStart, length);
   1.799 +      scan(self[indexStart], indexStart, indexEnd);
   1.800 +    }
   1.801 +    return sliceId;
   1.802 +  }
   1.803 +
   1.804 +  /**
   1.805 +   * Computes the index of the final element computed by the slice |sliceId|.
   1.806 +   */
   1.807 +  function finalElement(sliceId) {
   1.808 +    var sliceShift = slicesInfo.shift;
   1.809 +    return SLICE_END_INDEX(sliceShift, SLICE_START_INDEX(sliceShift, sliceId), length) - 1;
   1.810 +  }
   1.811 +
   1.812 +  /**
   1.813 +   * After computing the phase1 results, we compute an
   1.814 +   * |intermediates| array. |intermediates[i]| contains the result
   1.815 +   * of reducing the final value from each preceding slice j<i with
   1.816 +   * the final value of slice i. So, to continue our previous
   1.817 +   * example, the intermediates array would contain:
   1.818 +   *
   1.819 +   *   [A+B+C, (A+B+C)+(D+E+F), ((A+B+C)+(D+E+F))+(G+H+I)]
   1.820 +   *
   1.821 +   * Here I have used parenthesization to make clear the order of
   1.822 +   * evaluation in each case.
   1.823 +   *
   1.824 +   *   An aside: currently the intermediates array is computed
   1.825 +   *   sequentially. In principle, we could compute it in parallel,
   1.826 +   *   at the cost of doing duplicate work. This did not seem
   1.827 +   *   particularly advantageous to me, particularly as the number
   1.828 +   *   of slices is typically quite small (one per core), so I opted
   1.829 +   *   to just compute it sequentially.
   1.830 +   *
   1.831 +   * Phase 2 combines the results of phase1 with the intermediates
   1.832 +   * array to produce the final scan results. The idea is to
   1.833 +   * reiterate over each element S[i] in the slice |sliceId|, which
   1.834 +   * currently contains the result of reducing with S[0]...S[i]
   1.835 +   * (where S0 is the first thing in the slice), and combine that
   1.836 +   * with |intermediate[sliceId-1]|, which represents the result of
   1.837 +   * reducing everything in the input array prior to the slice.
   1.838 +   *
   1.839 +   * To continue with our example, in phase 1 we computed slice 1 to
   1.840 +   * be [D, D+E, D+E+F]. We will combine those results with
   1.841 +   * |intermediates[1-1]|, which is |A+B+C|, so that the final
   1.842 +   * result is [(A+B+C)+D, (A+B+C)+(D+E), (A+B+C)+(D+E+F)]. Again I
   1.843 +   * am using parentheses to clarify how these results were reduced.
   1.844 +   */
   1.845 +  function phase2(workerId, sliceStart, sliceEnd) {
   1.846 +    var sliceShift = slicesInfo.shift;
   1.847 +    var sliceId;
   1.848 +    while (GET_SLICE(sliceStart, sliceEnd, sliceId)) {
   1.849 +      var indexPos = SLICE_START_INDEX(sliceShift, sliceId);
   1.850 +      var indexEnd = SLICE_END_INDEX(sliceShift, indexPos, length);
   1.851 +      var intermediate = intermediates[sliceId - 1];
   1.852 +      for (; indexPos < indexEnd; indexPos++)
   1.853 +        UnsafePutElements(buffer, indexPos, func(intermediate, buffer[indexPos]));
   1.854 +    }
   1.855 +    return sliceId;
   1.856 +  }
   1.857 +
   1.858 +  return undefined;
   1.859 +}
   1.860 +
   1.861 +/**
   1.862 + * |scatter()| redistributes the elements in the array into a new array.
   1.863 + *
   1.864 + * - targets: The index targets[i] indicates where the ith element
   1.865 + *   should appear in the result.
   1.866 + *
   1.867 + * - defaultValue: what value to use for indices in the output array that
   1.868 + *   are never targeted.
   1.869 + *
   1.870 + * - conflictFunc: The conflict function. Used to resolve what
   1.871 + *   happens if two indices i and j in the source array are targeted
   1.872 + *   as the same destination (i.e., targets[i] === targets[j]), then
   1.873 + *   the final result is determined by applying func(targets[i],
   1.874 + *   targets[j]). If no conflict function is provided, it is an error
   1.875 + *   if targets[i] === targets[j].
   1.876 + *
   1.877 + * - length: length of the output array (if not specified, uses the
   1.878 + *   length of the input).
   1.879 + *
   1.880 + * - mode: internal debugging specification.
   1.881 + */
   1.882 +function ArrayScatterPar(targets, defaultValue, conflictFunc, length, mode) {
   1.883 +  if (conflictFunc && !IsCallable(conflictFunc))
   1.884 +    ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(2, conflictFunc));
   1.885 +
   1.886 +  var self = ToObject(this);
   1.887 +
   1.888 +  if (length === undefined)
   1.889 +    length = self.length;
   1.890 +
   1.891 +  var targetsLength = std_Math_min(targets.length, self.length);
   1.892 +
   1.893 +  if (!IS_UINT32(targetsLength) || !IS_UINT32(length))
   1.894 +    ThrowError(JSMSG_BAD_ARRAY_LENGTH);
   1.895 +
   1.896 +  // FIXME: Bug 965609: Find a better parallel startegy for scatter.
   1.897 +
   1.898 +  // Sequential fallback:
   1.899 +  ASSERT_SEQUENTIAL_IS_OK(mode);
   1.900 +  return seq();
   1.901 +
   1.902 +  function seq() {
   1.903 +    var buffer = NewDenseArray(length);
   1.904 +    var conflicts = NewDenseArray(length);
   1.905 +
   1.906 +    for (var i = 0; i < length; i++) {
   1.907 +      UnsafePutElements(buffer, i, defaultValue);
   1.908 +      UnsafePutElements(conflicts, i, false);
   1.909 +    }
   1.910 +
   1.911 +    for (var i = 0; i < targetsLength; i++) {
   1.912 +      var x = self[i];
   1.913 +      var t = checkTarget(i, targets[i]);
   1.914 +      if (conflicts[t])
   1.915 +        x = collide(x, buffer[t]);
   1.916 +
   1.917 +      UnsafePutElements(buffer, t, x, conflicts, t, true);
   1.918 +    }
   1.919 +
   1.920 +    return buffer;
   1.921 +  }
   1.922 +
   1.923 +  function collide(elem1, elem2) {
   1.924 +    if (conflictFunc === undefined)
   1.925 +      ThrowError(JSMSG_PAR_ARRAY_SCATTER_CONFLICT);
   1.926 +
   1.927 +    return conflictFunc(elem1, elem2);
   1.928 +  }
   1.929 +
   1.930 +  function checkTarget(i, t) {
   1.931 +    if (TO_INT32(t) !== t)
   1.932 +      ThrowError(JSMSG_PAR_ARRAY_SCATTER_BAD_TARGET, i);
   1.933 +
   1.934 +    if (t < 0 || t >= length)
   1.935 +      ThrowError(JSMSG_PAR_ARRAY_SCATTER_BOUNDS);
   1.936 +
   1.937 +    // It's not enough to return t, as -0 | 0 === -0.
   1.938 +    return TO_INT32(t);
   1.939 +  }
   1.940 +
   1.941 +  return undefined;
   1.942 +}
   1.943 +
   1.944 +/**
   1.945 + * The filter operation applied in parallel.
   1.946 + */
   1.947 +function ArrayFilterPar(func, mode) {
   1.948 +  if (!IsCallable(func))
   1.949 +    ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, func));
   1.950 +
   1.951 +  var self = ToObject(this);
   1.952 +  var length = self.length;
   1.953 +
   1.954 +  parallel: for (;;) { // see ArrayMapPar() to explain why for(;;) etc
   1.955 +    if (ShouldForceSequential())
   1.956 +      break parallel;
   1.957 +    if (!TRY_PARALLEL(mode))
   1.958 +      break parallel;
   1.959 +
   1.960 +    var slicesInfo = ComputeSlicesInfo(length);
   1.961 +
   1.962 +    // Step 1. Compute which items from each slice of the result buffer should
   1.963 +    // be preserved. When we're done, we have a uint8 array |survivors|
   1.964 +    // containing 0 or 1 for each source element, indicating which members of
   1.965 +    // the chunk survived. We also keep an array |counts| containing the total
   1.966 +    // number of items that are being preserved from within one slice.
   1.967 +    var numSlices = slicesInfo.count;
   1.968 +    var counts = NewDenseArray(numSlices);
   1.969 +    for (var i = 0; i < numSlices; i++)
   1.970 +      UnsafePutElements(counts, i, 0);
   1.971 +
   1.972 +    var survivors = new Uint8Array(length);
   1.973 +    ForkJoin(findSurvivorsThread, 0, numSlices, ForkJoinMode(mode));
   1.974 +
   1.975 +    // Step 2. Compress the slices into one contiguous set.
   1.976 +    var count = 0;
   1.977 +    for (var i = 0; i < numSlices; i++)
   1.978 +      count += counts[i];
   1.979 +    var buffer = NewDenseArray(count);
   1.980 +    if (count > 0)
   1.981 +      ForkJoin(copySurvivorsThread, 0, numSlices, ForkJoinMode(mode));
   1.982 +
   1.983 +    return buffer;
   1.984 +  }
   1.985 +
   1.986 +  // Sequential fallback:
   1.987 +  ASSERT_SEQUENTIAL_IS_OK(mode);
   1.988 +  var buffer = [];
   1.989 +  for (var i = 0; i < length; i++) {
   1.990 +    var elem = self[i];
   1.991 +    if (func(elem, i, self))
   1.992 +      ARRAY_PUSH(buffer, elem);
   1.993 +  }
   1.994 +  return buffer;
   1.995 +
   1.996 +  /**
   1.997 +   * As described above, our goal is to determine which items we will preserve
   1.998 +   * from a given slice, storing "to-keep" bits into 32-bit chunks.
   1.999 +   */
  1.1000 +  function findSurvivorsThread(workerId, sliceStart, sliceEnd) {
  1.1001 +    var sliceShift = slicesInfo.shift;
  1.1002 +    var sliceId;
  1.1003 +    while (GET_SLICE(sliceStart, sliceEnd, sliceId)) {
  1.1004 +      var count = 0;
  1.1005 +      var indexStart = SLICE_START_INDEX(sliceShift, sliceId);
  1.1006 +      var indexEnd = SLICE_END_INDEX(sliceShift, indexStart, length);
  1.1007 +      for (var indexPos = indexStart; indexPos < indexEnd; indexPos++) {
  1.1008 +        var keep = !!func(self[indexPos], indexPos, self);
  1.1009 +        UnsafePutElements(survivors, indexPos, keep);
  1.1010 +        count += keep;
  1.1011 +      }
  1.1012 +      UnsafePutElements(counts, sliceId, count);
  1.1013 +    }
  1.1014 +    return sliceId;
  1.1015 +  }
  1.1016 +
  1.1017 +  /**
  1.1018 +   * Copies the survivors from this slice into the correct position. Note
  1.1019 +   * that this is an idempotent operation that does not invoke user
  1.1020 +   * code. Therefore, we don't expect bailouts and make an effort to proceed
  1.1021 +   * chunk by chunk or avoid duplicating work.
  1.1022 +   */
  1.1023 +  function copySurvivorsThread(workerId, sliceStart, sliceEnd) {
  1.1024 +    var sliceShift = slicesInfo.shift;
  1.1025 +    var sliceId;
  1.1026 +    while (GET_SLICE(sliceStart, sliceEnd, sliceId)) {
  1.1027 +      // Total up the items preserved by previous slices.
  1.1028 +      var total = 0;
  1.1029 +      for (var i = 0; i < sliceId + 1; i++)
  1.1030 +        total += counts[i];
  1.1031 +
  1.1032 +      // Are we done?
  1.1033 +      var count = total - counts[sliceId];
  1.1034 +      if (count === total)
  1.1035 +        continue;
  1.1036 +
  1.1037 +      var indexStart = SLICE_START_INDEX(sliceShift, sliceId);
  1.1038 +      var indexEnd = SLICE_END_INDEX(sliceShift, indexStart, length);
  1.1039 +      for (var indexPos = indexStart; indexPos < indexEnd; indexPos++) {
  1.1040 +        if (survivors[indexPos]) {
  1.1041 +          UnsafePutElements(buffer, count++, self[indexPos]);
  1.1042 +          if (count == total)
  1.1043 +            break;
  1.1044 +        }
  1.1045 +      }
  1.1046 +    }
  1.1047 +
  1.1048 +    return sliceId;
  1.1049 +  }
  1.1050 +
  1.1051 +  return undefined;
  1.1052 +}
  1.1053 +
  1.1054 +/**
  1.1055 + * "Comprehension form": This is the function invoked for
  1.1056 + * |Array.{build,buildPar}(len, fn)| It creates a new array with length |len|
  1.1057 + * where index |i| is equal to |fn(i)|.
  1.1058 + *
  1.1059 + * The final |mode| argument is an internal argument used only during our
  1.1060 + * unit-testing.
  1.1061 + */
  1.1062 +function ArrayStaticBuild(length, func) {
  1.1063 +  if (!IS_UINT32(length))
  1.1064 +    ThrowError(JSMSG_BAD_ARRAY_LENGTH);
  1.1065 +  if (!IsCallable(func))
  1.1066 +    ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(1, func));
  1.1067 +
  1.1068 +  var buffer = NewDenseArray(length);
  1.1069 +
  1.1070 +  for (var i = 0; i < length; i++)
  1.1071 +    UnsafePutElements(buffer, i, func(i));
  1.1072 +
  1.1073 +  return buffer;
  1.1074 +}
  1.1075 +
  1.1076 +function ArrayStaticBuildPar(length, func, mode) {
  1.1077 +  if (!IS_UINT32(length))
  1.1078 +    ThrowError(JSMSG_BAD_ARRAY_LENGTH);
  1.1079 +  if (!IsCallable(func))
  1.1080 +    ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(1, func));
  1.1081 +
  1.1082 +  var buffer = NewDenseArray(length);
  1.1083 +
  1.1084 +  parallel: for (;;) {
  1.1085 +    if (ShouldForceSequential())
  1.1086 +      break parallel;
  1.1087 +    if (!TRY_PARALLEL(mode))
  1.1088 +      break parallel;
  1.1089 +
  1.1090 +    var slicesInfo = ComputeSlicesInfo(length);
  1.1091 +    ForkJoin(constructThread, 0, slicesInfo.count, ForkJoinMode(mode));
  1.1092 +    return buffer;
  1.1093 +  }
  1.1094 +
  1.1095 +  // Sequential fallback:
  1.1096 +  ASSERT_SEQUENTIAL_IS_OK(mode);
  1.1097 +  for (var i = 0; i < length; i++)
  1.1098 +    UnsafePutElements(buffer, i, func(i));
  1.1099 +  return buffer;
  1.1100 +
  1.1101 +  function constructThread(workerId, sliceStart, sliceEnd) {
  1.1102 +    var sliceShift = slicesInfo.shift;
  1.1103 +    var sliceId;
  1.1104 +    while (GET_SLICE(sliceStart, sliceEnd, sliceId)) {
  1.1105 +      var indexStart = SLICE_START_INDEX(sliceShift, sliceId);
  1.1106 +      var indexEnd = SLICE_END_INDEX(sliceShift, indexStart, length);
  1.1107 +      for (var i = indexStart; i < indexEnd; i++)
  1.1108 +        UnsafePutElements(buffer, i, func(i));
  1.1109 +    }
  1.1110 +    return sliceId;
  1.1111 +  }
  1.1112 +
  1.1113 +  return undefined;
  1.1114 +}
  1.1115 +
  1.1116 +/*
  1.1117 + * Mark the main operations as clone-at-callsite for better precision.
  1.1118 + * This is slightly overkill, as all that we really need is to
  1.1119 + * specialize to the receiver and the elemental function, but in
  1.1120 + * practice this is likely not so different, since element functions
  1.1121 + * are often used in exactly one place.
  1.1122 + */
  1.1123 +SetScriptHints(ArrayMapPar,         { cloneAtCallsite: true });
  1.1124 +SetScriptHints(ArrayReducePar,      { cloneAtCallsite: true });
  1.1125 +SetScriptHints(ArrayScanPar,        { cloneAtCallsite: true });
  1.1126 +SetScriptHints(ArrayScatterPar,     { cloneAtCallsite: true });
  1.1127 +SetScriptHints(ArrayFilterPar,      { cloneAtCallsite: true });
  1.1128 +SetScriptHints(ArrayStaticBuildPar, { cloneAtCallsite: true });
  1.1129 +
  1.1130 +#endif /* ENABLE_PARALLEL_JS */

mercurial