|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 /* ES5 15.4.4.14. */ |
|
6 function ArrayIndexOf(searchElement/*, fromIndex*/) { |
|
7 /* Step 1. */ |
|
8 var O = ToObject(this); |
|
9 |
|
10 /* Steps 2-3. */ |
|
11 var len = TO_UINT32(O.length); |
|
12 |
|
13 /* Step 4. */ |
|
14 if (len === 0) |
|
15 return -1; |
|
16 |
|
17 /* Step 5. */ |
|
18 var n = arguments.length > 1 ? ToInteger(arguments[1]) : 0; |
|
19 |
|
20 /* Step 6. */ |
|
21 if (n >= len) |
|
22 return -1; |
|
23 |
|
24 var k; |
|
25 /* Step 7. */ |
|
26 if (n >= 0) |
|
27 k = n; |
|
28 /* Step 8. */ |
|
29 else { |
|
30 /* Step a. */ |
|
31 k = len + n; |
|
32 /* Step b. */ |
|
33 if (k < 0) |
|
34 k = 0; |
|
35 } |
|
36 |
|
37 /* Step 9. */ |
|
38 if (IsPackedArray(O)) { |
|
39 for (; k < len; k++) { |
|
40 if (O[k] === searchElement) |
|
41 return k; |
|
42 } |
|
43 } else { |
|
44 for (; k < len; k++) { |
|
45 if (k in O && O[k] === searchElement) |
|
46 return k; |
|
47 } |
|
48 } |
|
49 |
|
50 /* Step 10. */ |
|
51 return -1; |
|
52 } |
|
53 |
|
54 function ArrayStaticIndexOf(list, searchElement/*, fromIndex*/) { |
|
55 if (arguments.length < 1) |
|
56 ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.indexOf'); |
|
57 var fromIndex = arguments.length > 2 ? arguments[2] : 0; |
|
58 return callFunction(ArrayIndexOf, list, searchElement, fromIndex); |
|
59 } |
|
60 |
|
61 /* ES5 15.4.4.15. */ |
|
62 function ArrayLastIndexOf(searchElement/*, fromIndex*/) { |
|
63 /* Step 1. */ |
|
64 var O = ToObject(this); |
|
65 |
|
66 /* Steps 2-3. */ |
|
67 var len = TO_UINT32(O.length); |
|
68 |
|
69 /* Step 4. */ |
|
70 if (len === 0) |
|
71 return -1; |
|
72 |
|
73 /* Step 5. */ |
|
74 var n = arguments.length > 1 ? ToInteger(arguments[1]) : len - 1; |
|
75 |
|
76 /* Steps 6-7. */ |
|
77 var k; |
|
78 if (n > len - 1) |
|
79 k = len - 1; |
|
80 else if (n < 0) |
|
81 k = len + n; |
|
82 else |
|
83 k = n; |
|
84 |
|
85 /* Step 8. */ |
|
86 if (IsPackedArray(O)) { |
|
87 for (; k >= 0; k--) { |
|
88 if (O[k] === searchElement) |
|
89 return k; |
|
90 } |
|
91 } else { |
|
92 for (; k >= 0; k--) { |
|
93 if (k in O && O[k] === searchElement) |
|
94 return k; |
|
95 } |
|
96 } |
|
97 |
|
98 /* Step 9. */ |
|
99 return -1; |
|
100 } |
|
101 |
|
102 function ArrayStaticLastIndexOf(list, searchElement/*, fromIndex*/) { |
|
103 if (arguments.length < 1) |
|
104 ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.lastIndexOf'); |
|
105 var fromIndex; |
|
106 if (arguments.length > 2) { |
|
107 fromIndex = arguments[2]; |
|
108 } else { |
|
109 var O = ToObject(list); |
|
110 var len = TO_UINT32(O.length); |
|
111 fromIndex = len - 1; |
|
112 } |
|
113 return callFunction(ArrayLastIndexOf, list, searchElement, fromIndex); |
|
114 } |
|
115 |
|
116 /* ES5 15.4.4.16. */ |
|
117 function ArrayEvery(callbackfn/*, thisArg*/) { |
|
118 /* Step 1. */ |
|
119 var O = ToObject(this); |
|
120 |
|
121 /* Steps 2-3. */ |
|
122 var len = TO_UINT32(O.length); |
|
123 |
|
124 /* Step 4. */ |
|
125 if (arguments.length === 0) |
|
126 ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.prototype.every'); |
|
127 if (!IsCallable(callbackfn)) |
|
128 ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn)); |
|
129 |
|
130 /* Step 5. */ |
|
131 var T = arguments.length > 1 ? arguments[1] : void 0; |
|
132 |
|
133 /* Steps 6-7. */ |
|
134 /* Steps a (implicit), and d. */ |
|
135 for (var k = 0; k < len; k++) { |
|
136 /* Step b */ |
|
137 if (k in O) { |
|
138 /* Step c. */ |
|
139 if (!callFunction(callbackfn, T, O[k], k, O)) |
|
140 return false; |
|
141 } |
|
142 } |
|
143 |
|
144 /* Step 8. */ |
|
145 return true; |
|
146 } |
|
147 |
|
148 function ArrayStaticEvery(list, callbackfn/*, thisArg*/) { |
|
149 if (arguments.length < 2) |
|
150 ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.every'); |
|
151 if (!IsCallable(callbackfn)) |
|
152 ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(1, callbackfn)); |
|
153 var T = arguments.length > 2 ? arguments[2] : void 0; |
|
154 return callFunction(ArrayEvery, list, callbackfn, T); |
|
155 } |
|
156 |
|
157 /* ES5 15.4.4.17. */ |
|
158 function ArraySome(callbackfn/*, thisArg*/) { |
|
159 /* Step 1. */ |
|
160 var O = ToObject(this); |
|
161 |
|
162 /* Steps 2-3. */ |
|
163 var len = TO_UINT32(O.length); |
|
164 |
|
165 /* Step 4. */ |
|
166 if (arguments.length === 0) |
|
167 ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.prototype.some'); |
|
168 if (!IsCallable(callbackfn)) |
|
169 ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn)); |
|
170 |
|
171 /* Step 5. */ |
|
172 var T = arguments.length > 1 ? arguments[1] : void 0; |
|
173 |
|
174 /* Steps 6-7. */ |
|
175 /* Steps a (implicit), and d. */ |
|
176 for (var k = 0; k < len; k++) { |
|
177 /* Step b */ |
|
178 if (k in O) { |
|
179 /* Step c. */ |
|
180 if (callFunction(callbackfn, T, O[k], k, O)) |
|
181 return true; |
|
182 } |
|
183 } |
|
184 |
|
185 /* Step 8. */ |
|
186 return false; |
|
187 } |
|
188 |
|
189 function ArrayStaticSome(list, callbackfn/*, thisArg*/) { |
|
190 if (arguments.length < 2) |
|
191 ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.some'); |
|
192 if (!IsCallable(callbackfn)) |
|
193 ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(1, callbackfn)); |
|
194 var T = arguments.length > 2 ? arguments[2] : void 0; |
|
195 return callFunction(ArraySome, list, callbackfn, T); |
|
196 } |
|
197 |
|
198 /* ES5 15.4.4.18. */ |
|
199 function ArrayForEach(callbackfn/*, thisArg*/) { |
|
200 /* Step 1. */ |
|
201 var O = ToObject(this); |
|
202 |
|
203 /* Steps 2-3. */ |
|
204 var len = TO_UINT32(O.length); |
|
205 |
|
206 /* Step 4. */ |
|
207 if (arguments.length === 0) |
|
208 ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.prototype.forEach'); |
|
209 if (!IsCallable(callbackfn)) |
|
210 ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn)); |
|
211 |
|
212 /* Step 5. */ |
|
213 var T = arguments.length > 1 ? arguments[1] : void 0; |
|
214 |
|
215 /* Steps 6-7. */ |
|
216 /* Steps a (implicit), and d. */ |
|
217 for (var k = 0; k < len; k++) { |
|
218 /* Step b */ |
|
219 if (k in O) { |
|
220 /* Step c. */ |
|
221 callFunction(callbackfn, T, O[k], k, O); |
|
222 } |
|
223 } |
|
224 |
|
225 /* Step 8. */ |
|
226 return void 0; |
|
227 } |
|
228 |
|
229 /* ES5 15.4.4.19. */ |
|
230 function ArrayMap(callbackfn/*, thisArg*/) { |
|
231 /* Step 1. */ |
|
232 var O = ToObject(this); |
|
233 |
|
234 /* Step 2-3. */ |
|
235 var len = TO_UINT32(O.length); |
|
236 |
|
237 /* Step 4. */ |
|
238 if (arguments.length === 0) |
|
239 ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.prototype.map'); |
|
240 if (!IsCallable(callbackfn)) |
|
241 ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn)); |
|
242 |
|
243 /* Step 5. */ |
|
244 var T = arguments.length > 1 ? arguments[1] : void 0; |
|
245 |
|
246 /* Step 6. */ |
|
247 var A = NewDenseArray(len); |
|
248 |
|
249 /* Step 7-8. */ |
|
250 /* Step a (implicit), and d. */ |
|
251 for (var k = 0; k < len; k++) { |
|
252 /* Step b */ |
|
253 if (k in O) { |
|
254 /* Step c.i-iii. */ |
|
255 var mappedValue = callFunction(callbackfn, T, O[k], k, O); |
|
256 // UnsafePutElements doesn't invoke setters, so we can use it here. |
|
257 UnsafePutElements(A, k, mappedValue); |
|
258 } |
|
259 } |
|
260 |
|
261 /* Step 9. */ |
|
262 return A; |
|
263 } |
|
264 |
|
265 function ArrayStaticMap(list, callbackfn/*, thisArg*/) { |
|
266 if (arguments.length < 2) |
|
267 ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.map'); |
|
268 if (!IsCallable(callbackfn)) |
|
269 ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(1, callbackfn)); |
|
270 var T = arguments.length > 2 ? arguments[2] : void 0; |
|
271 return callFunction(ArrayMap, list, callbackfn, T); |
|
272 } |
|
273 |
|
274 function ArrayStaticForEach(list, callbackfn/*, thisArg*/) { |
|
275 if (arguments.length < 2) |
|
276 ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.forEach'); |
|
277 if (!IsCallable(callbackfn)) |
|
278 ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(1, callbackfn)); |
|
279 var T = arguments.length > 2 ? arguments[2] : void 0; |
|
280 callFunction(ArrayForEach, list, callbackfn, T); |
|
281 } |
|
282 |
|
283 /* ES5 15.4.4.21. */ |
|
284 function ArrayReduce(callbackfn/*, initialValue*/) { |
|
285 /* Step 1. */ |
|
286 var O = ToObject(this); |
|
287 |
|
288 /* Steps 2-3. */ |
|
289 var len = TO_UINT32(O.length); |
|
290 |
|
291 /* Step 4. */ |
|
292 if (arguments.length === 0) |
|
293 ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.prototype.reduce'); |
|
294 if (!IsCallable(callbackfn)) |
|
295 ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn)); |
|
296 |
|
297 /* Step 6. */ |
|
298 var k = 0; |
|
299 |
|
300 /* Steps 5, 7-8. */ |
|
301 var accumulator; |
|
302 if (arguments.length > 1) { |
|
303 accumulator = arguments[1]; |
|
304 } else { |
|
305 /* Step 5. */ |
|
306 if (len === 0) |
|
307 ThrowError(JSMSG_EMPTY_ARRAY_REDUCE); |
|
308 if (IsPackedArray(O)) { |
|
309 accumulator = O[k++]; |
|
310 } else { |
|
311 var kPresent = false; |
|
312 for (; k < len; k++) { |
|
313 if (k in O) { |
|
314 accumulator = O[k]; |
|
315 kPresent = true; |
|
316 k++; |
|
317 break; |
|
318 } |
|
319 } |
|
320 if (!kPresent) |
|
321 ThrowError(JSMSG_EMPTY_ARRAY_REDUCE); |
|
322 } |
|
323 } |
|
324 |
|
325 /* Step 9. */ |
|
326 /* Steps a (implicit), and d. */ |
|
327 for (; k < len; k++) { |
|
328 /* Step b */ |
|
329 if (k in O) { |
|
330 /* Step c. */ |
|
331 accumulator = callbackfn(accumulator, O[k], k, O); |
|
332 } |
|
333 } |
|
334 |
|
335 /* Step 10. */ |
|
336 return accumulator; |
|
337 } |
|
338 |
|
339 function ArrayStaticReduce(list, callbackfn) { |
|
340 if (arguments.length < 2) |
|
341 ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.reduce'); |
|
342 if (!IsCallable(callbackfn)) |
|
343 ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(1, callbackfn)); |
|
344 if (arguments.length > 2) |
|
345 return callFunction(ArrayReduce, list, callbackfn, arguments[2]); |
|
346 else |
|
347 return callFunction(ArrayReduce, list, callbackfn); |
|
348 } |
|
349 |
|
350 /* ES5 15.4.4.22. */ |
|
351 function ArrayReduceRight(callbackfn/*, initialValue*/) { |
|
352 /* Step 1. */ |
|
353 var O = ToObject(this); |
|
354 |
|
355 /* Steps 2-3. */ |
|
356 var len = TO_UINT32(O.length); |
|
357 |
|
358 /* Step 4. */ |
|
359 if (arguments.length === 0) |
|
360 ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.prototype.reduce'); |
|
361 if (!IsCallable(callbackfn)) |
|
362 ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn)); |
|
363 |
|
364 /* Step 6. */ |
|
365 var k = len - 1; |
|
366 |
|
367 /* Steps 5, 7-8. */ |
|
368 var accumulator; |
|
369 if (arguments.length > 1) { |
|
370 accumulator = arguments[1]; |
|
371 } else { |
|
372 /* Step 5. */ |
|
373 if (len === 0) |
|
374 ThrowError(JSMSG_EMPTY_ARRAY_REDUCE); |
|
375 if (IsPackedArray(O)) { |
|
376 accumulator = O[k--]; |
|
377 } else { |
|
378 var kPresent = false; |
|
379 for (; k >= 0; k--) { |
|
380 if (k in O) { |
|
381 accumulator = O[k]; |
|
382 kPresent = true; |
|
383 k--; |
|
384 break; |
|
385 } |
|
386 } |
|
387 if (!kPresent) |
|
388 ThrowError(JSMSG_EMPTY_ARRAY_REDUCE); |
|
389 } |
|
390 } |
|
391 |
|
392 /* Step 9. */ |
|
393 /* Steps a (implicit), and d. */ |
|
394 for (; k >= 0; k--) { |
|
395 /* Step b */ |
|
396 if (k in O) { |
|
397 /* Step c. */ |
|
398 accumulator = callbackfn(accumulator, O[k], k, O); |
|
399 } |
|
400 } |
|
401 |
|
402 /* Step 10. */ |
|
403 return accumulator; |
|
404 } |
|
405 |
|
406 function ArrayStaticReduceRight(list, callbackfn) { |
|
407 if (arguments.length < 2) |
|
408 ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.reduceRight'); |
|
409 if (!IsCallable(callbackfn)) |
|
410 ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(1, callbackfn)); |
|
411 if (arguments.length > 2) |
|
412 return callFunction(ArrayReduceRight, list, callbackfn, arguments[2]); |
|
413 else |
|
414 return callFunction(ArrayReduceRight, list, callbackfn); |
|
415 } |
|
416 |
|
417 /* ES6 draft 2013-05-14 15.4.3.23. */ |
|
418 function ArrayFind(predicate/*, thisArg*/) { |
|
419 /* Steps 1-2. */ |
|
420 var O = ToObject(this); |
|
421 |
|
422 /* Steps 3-5. */ |
|
423 var len = ToInteger(O.length); |
|
424 |
|
425 /* Step 6. */ |
|
426 if (arguments.length === 0) |
|
427 ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.prototype.find'); |
|
428 if (!IsCallable(predicate)) |
|
429 ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, predicate)); |
|
430 |
|
431 /* Step 7. */ |
|
432 var T = arguments.length > 1 ? arguments[1] : undefined; |
|
433 |
|
434 /* Steps 8-9. */ |
|
435 /* Steps a (implicit), and e. */ |
|
436 /* Note: this will hang in some corner-case situations, because of IEEE-754 numbers' |
|
437 * imprecision for large values. Example: |
|
438 * var obj = { 18014398509481984: true, length: 18014398509481988 }; |
|
439 * Array.prototype.find.call(obj, () => true); |
|
440 */ |
|
441 for (var k = 0; k < len; k++) { |
|
442 /* Steps b and c (implicit) */ |
|
443 if (k in O) { |
|
444 /* Step d. */ |
|
445 var kValue = O[k]; |
|
446 if (callFunction(predicate, T, kValue, k, O)) |
|
447 return kValue; |
|
448 } |
|
449 } |
|
450 |
|
451 /* Step 10. */ |
|
452 return undefined; |
|
453 } |
|
454 |
|
455 /* ES6 draft 2013-05-14 15.4.3.23. */ |
|
456 function ArrayFindIndex(predicate/*, thisArg*/) { |
|
457 /* Steps 1-2. */ |
|
458 var O = ToObject(this); |
|
459 |
|
460 /* Steps 3-5. */ |
|
461 var len = ToInteger(O.length); |
|
462 |
|
463 /* Step 6. */ |
|
464 if (arguments.length === 0) |
|
465 ThrowError(JSMSG_MISSING_FUN_ARG, 0, 'Array.prototype.find'); |
|
466 if (!IsCallable(predicate)) |
|
467 ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, predicate)); |
|
468 |
|
469 /* Step 7. */ |
|
470 var T = arguments.length > 1 ? arguments[1] : undefined; |
|
471 |
|
472 /* Steps 8-9. */ |
|
473 /* Steps a (implicit), and e. */ |
|
474 /* Note: this will hang in some corner-case situations, because of IEEE-754 numbers' |
|
475 * imprecision for large values. Example: |
|
476 * var obj = { 18014398509481984: true, length: 18014398509481988 }; |
|
477 * Array.prototype.find.call(obj, () => true); |
|
478 */ |
|
479 for (var k = 0; k < len; k++) { |
|
480 /* Steps b and c (implicit) */ |
|
481 if (k in O) { |
|
482 /* Step d. */ |
|
483 if (callFunction(predicate, T, O[k], k, O)) |
|
484 return k; |
|
485 } |
|
486 } |
|
487 |
|
488 /* Step 10. */ |
|
489 return -1; |
|
490 } |
|
491 |
|
492 // ES6 draft 2014-04-05 22.1.3.6 |
|
493 function ArrayFill(value, start = 0, end = undefined) { |
|
494 // Steps 1-2. |
|
495 var O = ToObject(this); |
|
496 |
|
497 // Steps 3-5. |
|
498 // FIXME: Array operations should use ToLength (bug 924058). |
|
499 var len = ToInteger(O.length); |
|
500 |
|
501 // Steps 6-7. |
|
502 var relativeStart = ToInteger(start); |
|
503 |
|
504 // Step 8. |
|
505 var k = relativeStart < 0 |
|
506 ? std_Math_max(len + relativeStart, 0) |
|
507 : std_Math_min(relativeStart, len); |
|
508 |
|
509 // Steps 9-10. |
|
510 var relativeEnd = end === undefined ? len : ToInteger(end); |
|
511 |
|
512 // Step 11. |
|
513 var final = relativeEnd < 0 |
|
514 ? std_Math_max(len + relativeEnd, 0) |
|
515 : std_Math_min(relativeEnd, len); |
|
516 |
|
517 // Step 12. |
|
518 for (; k < final; k++) { |
|
519 O[k] = value; |
|
520 } |
|
521 |
|
522 // Step 13. |
|
523 return O; |
|
524 } |
|
525 |
|
526 #define ARRAY_ITERATOR_SLOT_ITERATED_OBJECT 0 |
|
527 #define ARRAY_ITERATOR_SLOT_NEXT_INDEX 1 |
|
528 #define ARRAY_ITERATOR_SLOT_ITEM_KIND 2 |
|
529 |
|
530 #define ITEM_KIND_VALUE 0 |
|
531 #define ITEM_KIND_KEY_AND_VALUE 1 |
|
532 #define ITEM_KIND_KEY 2 |
|
533 |
|
534 // ES6 draft specification, section 22.1.5.1, version 2013-09-05. |
|
535 function CreateArrayIteratorAt(obj, kind, n) { |
|
536 var iteratedObject = ToObject(obj); |
|
537 var iterator = NewArrayIterator(); |
|
538 UnsafeSetReservedSlot(iterator, ARRAY_ITERATOR_SLOT_ITERATED_OBJECT, iteratedObject); |
|
539 UnsafeSetReservedSlot(iterator, ARRAY_ITERATOR_SLOT_NEXT_INDEX, n); |
|
540 UnsafeSetReservedSlot(iterator, ARRAY_ITERATOR_SLOT_ITEM_KIND, kind); |
|
541 return iterator; |
|
542 } |
|
543 function CreateArrayIterator(obj, kind) { |
|
544 return CreateArrayIteratorAt(obj, kind, 0); |
|
545 } |
|
546 |
|
547 function ArrayIteratorIdentity() { |
|
548 return this; |
|
549 } |
|
550 |
|
551 function ArrayIteratorNext() { |
|
552 // FIXME: ArrayIterator prototype should not pass this test. Bug 924059. |
|
553 if (!IsObject(this) || !IsArrayIterator(this)) |
|
554 ThrowError(JSMSG_INCOMPATIBLE_METHOD, "ArrayIterator", "next", ToString(this)); |
|
555 |
|
556 var a = UnsafeGetReservedSlot(this, ARRAY_ITERATOR_SLOT_ITERATED_OBJECT); |
|
557 var index = UnsafeGetReservedSlot(this, ARRAY_ITERATOR_SLOT_NEXT_INDEX); |
|
558 var itemKind = UnsafeGetReservedSlot(this, ARRAY_ITERATOR_SLOT_ITEM_KIND); |
|
559 |
|
560 // FIXME: This should be ToLength, which clamps at 2**53. Bug 924058. |
|
561 if (index >= TO_UINT32(a.length)) { |
|
562 // When the above is changed to ToLength, use +1/0 here instead |
|
563 // of MAX_UINT32. |
|
564 UnsafeSetReservedSlot(this, ARRAY_ITERATOR_SLOT_NEXT_INDEX, 0xffffffff); |
|
565 return { value: undefined, done: true }; |
|
566 } |
|
567 |
|
568 UnsafeSetReservedSlot(this, ARRAY_ITERATOR_SLOT_NEXT_INDEX, index + 1); |
|
569 |
|
570 if (itemKind === ITEM_KIND_VALUE) |
|
571 return { value: a[index], done: false }; |
|
572 |
|
573 if (itemKind === ITEM_KIND_KEY_AND_VALUE) { |
|
574 var pair = NewDenseArray(2); |
|
575 pair[0] = index; |
|
576 pair[1] = a[index]; |
|
577 return { value: pair, done : false }; |
|
578 } |
|
579 |
|
580 assert(itemKind === ITEM_KIND_KEY, itemKind); |
|
581 return { value: index, done: false }; |
|
582 } |
|
583 |
|
584 function ArrayValuesAt(n) { |
|
585 return CreateArrayIteratorAt(this, ITEM_KIND_VALUE, n); |
|
586 } |
|
587 |
|
588 function ArrayValues() { |
|
589 return CreateArrayIterator(this, ITEM_KIND_VALUE); |
|
590 } |
|
591 |
|
592 function ArrayEntries() { |
|
593 return CreateArrayIterator(this, ITEM_KIND_KEY_AND_VALUE); |
|
594 } |
|
595 |
|
596 function ArrayKeys() { |
|
597 return CreateArrayIterator(this, ITEM_KIND_KEY); |
|
598 } |
|
599 |
|
600 #ifdef ENABLE_PARALLEL_JS |
|
601 |
|
602 /* |
|
603 * Strawman spec: |
|
604 * http://wiki.ecmascript.org/doku.php?id=strawman:data_parallelism |
|
605 */ |
|
606 |
|
607 /** |
|
608 * Creates a new array by applying |func(e, i, self)| for each element |e| |
|
609 * with index |i|. |
|
610 */ |
|
611 function ArrayMapPar(func, mode) { |
|
612 if (!IsCallable(func)) |
|
613 ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, func)); |
|
614 |
|
615 var self = ToObject(this); |
|
616 var length = self.length; |
|
617 var buffer = NewDenseArray(length); |
|
618 |
|
619 parallel: for (;;) { |
|
620 // Avoid parallel compilation if we are already nested in another |
|
621 // parallel section or the user told us not to parallelize. The |
|
622 // use of a for (;;) loop is working around some ion limitations: |
|
623 // |
|
624 // - Breaking out of named blocks does not currently work (bug 684384); |
|
625 // - Unreachable Code Elim. can't properly handle if (a && b) (bug 669796) |
|
626 if (ShouldForceSequential()) |
|
627 break parallel; |
|
628 if (!TRY_PARALLEL(mode)) |
|
629 break parallel; |
|
630 |
|
631 var slicesInfo = ComputeSlicesInfo(length); |
|
632 ForkJoin(mapThread, 0, slicesInfo.count, ForkJoinMode(mode)); |
|
633 return buffer; |
|
634 } |
|
635 |
|
636 // Sequential fallback: |
|
637 ASSERT_SEQUENTIAL_IS_OK(mode); |
|
638 for (var i = 0; i < length; i++) |
|
639 UnsafePutElements(buffer, i, func(self[i], i, self)); |
|
640 return buffer; |
|
641 |
|
642 function mapThread(workerId, sliceStart, sliceEnd) { |
|
643 var sliceShift = slicesInfo.shift; |
|
644 var sliceId; |
|
645 while (GET_SLICE(sliceStart, sliceEnd, sliceId)) { |
|
646 var indexStart = SLICE_START_INDEX(sliceShift, sliceId); |
|
647 var indexEnd = SLICE_END_INDEX(sliceShift, indexStart, length); |
|
648 for (var i = indexStart; i < indexEnd; i++) |
|
649 UnsafePutElements(buffer, i, func(self[i], i, self)); |
|
650 } |
|
651 return sliceId; |
|
652 } |
|
653 |
|
654 return undefined; |
|
655 } |
|
656 |
|
657 /** |
|
658 * Reduces the elements in an array in parallel. Order is not fixed and |func| |
|
659 * is assumed to be associative. |
|
660 */ |
|
661 function ArrayReducePar(func, mode) { |
|
662 if (!IsCallable(func)) |
|
663 ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, func)); |
|
664 |
|
665 var self = ToObject(this); |
|
666 var length = self.length; |
|
667 |
|
668 if (length === 0) |
|
669 ThrowError(JSMSG_EMPTY_ARRAY_REDUCE); |
|
670 |
|
671 parallel: for (;;) { // see ArrayMapPar() to explain why for(;;) etc |
|
672 if (ShouldForceSequential()) |
|
673 break parallel; |
|
674 if (!TRY_PARALLEL(mode)) |
|
675 break parallel; |
|
676 |
|
677 var slicesInfo = ComputeSlicesInfo(length); |
|
678 var numSlices = slicesInfo.count; |
|
679 var subreductions = NewDenseArray(numSlices); |
|
680 |
|
681 ForkJoin(reduceThread, 0, numSlices, ForkJoinMode(mode)); |
|
682 |
|
683 var accumulator = subreductions[0]; |
|
684 for (var i = 1; i < numSlices; i++) |
|
685 accumulator = func(accumulator, subreductions[i]); |
|
686 return accumulator; |
|
687 } |
|
688 |
|
689 // Sequential fallback: |
|
690 ASSERT_SEQUENTIAL_IS_OK(mode); |
|
691 var accumulator = self[0]; |
|
692 for (var i = 1; i < length; i++) |
|
693 accumulator = func(accumulator, self[i]); |
|
694 return accumulator; |
|
695 |
|
696 function reduceThread(workerId, sliceStart, sliceEnd) { |
|
697 var sliceShift = slicesInfo.shift; |
|
698 var sliceId; |
|
699 while (GET_SLICE(sliceStart, sliceEnd, sliceId)) { |
|
700 var indexStart = SLICE_START_INDEX(sliceShift, sliceId); |
|
701 var indexEnd = SLICE_END_INDEX(sliceShift, indexStart, length); |
|
702 var accumulator = self[indexStart]; |
|
703 for (var i = indexStart + 1; i < indexEnd; i++) |
|
704 accumulator = func(accumulator, self[i]); |
|
705 UnsafePutElements(subreductions, sliceId, accumulator); |
|
706 } |
|
707 return sliceId; |
|
708 } |
|
709 |
|
710 return undefined; |
|
711 } |
|
712 |
|
713 /** |
|
714 * Returns an array [s_0, ..., s_N] where |s_i| is equal to the reduction (as |
|
715 * per |reduce()|) of elements |0..i|. This is the generalization of partial |
|
716 * sum. |
|
717 */ |
|
718 function ArrayScanPar(func, mode) { |
|
719 if (!IsCallable(func)) |
|
720 ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, func)); |
|
721 |
|
722 var self = ToObject(this); |
|
723 var length = self.length; |
|
724 |
|
725 if (length === 0) |
|
726 ThrowError(JSMSG_EMPTY_ARRAY_REDUCE); |
|
727 |
|
728 var buffer = NewDenseArray(length); |
|
729 |
|
730 parallel: for (;;) { // see ArrayMapPar() to explain why for(;;) etc |
|
731 if (ShouldForceSequential()) |
|
732 break parallel; |
|
733 if (!TRY_PARALLEL(mode)) |
|
734 break parallel; |
|
735 |
|
736 var slicesInfo = ComputeSlicesInfo(length); |
|
737 var numSlices = slicesInfo.count; |
|
738 |
|
739 // Scan slices individually (see comment on phase1()). |
|
740 ForkJoin(phase1, 0, numSlices, ForkJoinMode(mode)); |
|
741 |
|
742 // Compute intermediates array (see comment on phase2()). |
|
743 var intermediates = []; |
|
744 var accumulator = buffer[finalElement(0)]; |
|
745 ARRAY_PUSH(intermediates, accumulator); |
|
746 for (var i = 1; i < numSlices - 1; i++) { |
|
747 accumulator = func(accumulator, buffer[finalElement(i)]); |
|
748 ARRAY_PUSH(intermediates, accumulator); |
|
749 } |
|
750 |
|
751 // Complete each slice using intermediates array (see comment on phase2()). |
|
752 // |
|
753 // We start from slice 1 instead of 0 since there is no work to be done |
|
754 // for slice 0. |
|
755 if (numSlices > 1) |
|
756 ForkJoin(phase2, 1, numSlices, ForkJoinMode(mode)); |
|
757 return buffer; |
|
758 } |
|
759 |
|
760 // Sequential fallback: |
|
761 ASSERT_SEQUENTIAL_IS_OK(mode); |
|
762 scan(self[0], 0, length); |
|
763 return buffer; |
|
764 |
|
765 function scan(accumulator, start, end) { |
|
766 UnsafePutElements(buffer, start, accumulator); |
|
767 for (var i = start + 1; i < end; i++) { |
|
768 accumulator = func(accumulator, self[i]); |
|
769 UnsafePutElements(buffer, i, accumulator); |
|
770 } |
|
771 return accumulator; |
|
772 } |
|
773 |
|
774 /** |
|
775 * In phase 1, we divide the source array into |numSlices| slices and |
|
776 * compute scan on each slice sequentially as if it were the entire |
|
777 * array. This function is responsible for computing one of those |
|
778 * slices. |
|
779 * |
|
780 * So, if we have an array [A,B,C,D,E,F,G,H,I], |numSlices === 3|, |
|
781 * and our function |func| is sum, then we would wind up computing a |
|
782 * result array like: |
|
783 * |
|
784 * [A, A+B, A+B+C, D, D+E, D+E+F, G, G+H, G+H+I] |
|
785 * ^~~~~~~~~~~~^ ^~~~~~~~~~~~^ ^~~~~~~~~~~~~^ |
|
786 * Slice 0 Slice 1 Slice 2 |
|
787 * |
|
788 * Read on in phase2 to see what we do next! |
|
789 */ |
|
790 function phase1(workerId, sliceStart, sliceEnd) { |
|
791 var sliceShift = slicesInfo.shift; |
|
792 var sliceId; |
|
793 while (GET_SLICE(sliceStart, sliceEnd, sliceId)) { |
|
794 var indexStart = SLICE_START_INDEX(sliceShift, sliceId); |
|
795 var indexEnd = SLICE_END_INDEX(sliceShift, indexStart, length); |
|
796 scan(self[indexStart], indexStart, indexEnd); |
|
797 } |
|
798 return sliceId; |
|
799 } |
|
800 |
|
801 /** |
|
802 * Computes the index of the final element computed by the slice |sliceId|. |
|
803 */ |
|
804 function finalElement(sliceId) { |
|
805 var sliceShift = slicesInfo.shift; |
|
806 return SLICE_END_INDEX(sliceShift, SLICE_START_INDEX(sliceShift, sliceId), length) - 1; |
|
807 } |
|
808 |
|
809 /** |
|
810 * After computing the phase1 results, we compute an |
|
811 * |intermediates| array. |intermediates[i]| contains the result |
|
812 * of reducing the final value from each preceding slice j<i with |
|
813 * the final value of slice i. So, to continue our previous |
|
814 * example, the intermediates array would contain: |
|
815 * |
|
816 * [A+B+C, (A+B+C)+(D+E+F), ((A+B+C)+(D+E+F))+(G+H+I)] |
|
817 * |
|
818 * Here I have used parenthesization to make clear the order of |
|
819 * evaluation in each case. |
|
820 * |
|
821 * An aside: currently the intermediates array is computed |
|
822 * sequentially. In principle, we could compute it in parallel, |
|
823 * at the cost of doing duplicate work. This did not seem |
|
824 * particularly advantageous to me, particularly as the number |
|
825 * of slices is typically quite small (one per core), so I opted |
|
826 * to just compute it sequentially. |
|
827 * |
|
828 * Phase 2 combines the results of phase1 with the intermediates |
|
829 * array to produce the final scan results. The idea is to |
|
830 * reiterate over each element S[i] in the slice |sliceId|, which |
|
831 * currently contains the result of reducing with S[0]...S[i] |
|
832 * (where S0 is the first thing in the slice), and combine that |
|
833 * with |intermediate[sliceId-1]|, which represents the result of |
|
834 * reducing everything in the input array prior to the slice. |
|
835 * |
|
836 * To continue with our example, in phase 1 we computed slice 1 to |
|
837 * be [D, D+E, D+E+F]. We will combine those results with |
|
838 * |intermediates[1-1]|, which is |A+B+C|, so that the final |
|
839 * result is [(A+B+C)+D, (A+B+C)+(D+E), (A+B+C)+(D+E+F)]. Again I |
|
840 * am using parentheses to clarify how these results were reduced. |
|
841 */ |
|
842 function phase2(workerId, sliceStart, sliceEnd) { |
|
843 var sliceShift = slicesInfo.shift; |
|
844 var sliceId; |
|
845 while (GET_SLICE(sliceStart, sliceEnd, sliceId)) { |
|
846 var indexPos = SLICE_START_INDEX(sliceShift, sliceId); |
|
847 var indexEnd = SLICE_END_INDEX(sliceShift, indexPos, length); |
|
848 var intermediate = intermediates[sliceId - 1]; |
|
849 for (; indexPos < indexEnd; indexPos++) |
|
850 UnsafePutElements(buffer, indexPos, func(intermediate, buffer[indexPos])); |
|
851 } |
|
852 return sliceId; |
|
853 } |
|
854 |
|
855 return undefined; |
|
856 } |
|
857 |
|
858 /** |
|
859 * |scatter()| redistributes the elements in the array into a new array. |
|
860 * |
|
861 * - targets: The index targets[i] indicates where the ith element |
|
862 * should appear in the result. |
|
863 * |
|
864 * - defaultValue: what value to use for indices in the output array that |
|
865 * are never targeted. |
|
866 * |
|
867 * - conflictFunc: The conflict function. Used to resolve what |
|
868 * happens if two indices i and j in the source array are targeted |
|
869 * as the same destination (i.e., targets[i] === targets[j]), then |
|
870 * the final result is determined by applying func(targets[i], |
|
871 * targets[j]). If no conflict function is provided, it is an error |
|
872 * if targets[i] === targets[j]. |
|
873 * |
|
874 * - length: length of the output array (if not specified, uses the |
|
875 * length of the input). |
|
876 * |
|
877 * - mode: internal debugging specification. |
|
878 */ |
|
879 function ArrayScatterPar(targets, defaultValue, conflictFunc, length, mode) { |
|
880 if (conflictFunc && !IsCallable(conflictFunc)) |
|
881 ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(2, conflictFunc)); |
|
882 |
|
883 var self = ToObject(this); |
|
884 |
|
885 if (length === undefined) |
|
886 length = self.length; |
|
887 |
|
888 var targetsLength = std_Math_min(targets.length, self.length); |
|
889 |
|
890 if (!IS_UINT32(targetsLength) || !IS_UINT32(length)) |
|
891 ThrowError(JSMSG_BAD_ARRAY_LENGTH); |
|
892 |
|
893 // FIXME: Bug 965609: Find a better parallel startegy for scatter. |
|
894 |
|
895 // Sequential fallback: |
|
896 ASSERT_SEQUENTIAL_IS_OK(mode); |
|
897 return seq(); |
|
898 |
|
899 function seq() { |
|
900 var buffer = NewDenseArray(length); |
|
901 var conflicts = NewDenseArray(length); |
|
902 |
|
903 for (var i = 0; i < length; i++) { |
|
904 UnsafePutElements(buffer, i, defaultValue); |
|
905 UnsafePutElements(conflicts, i, false); |
|
906 } |
|
907 |
|
908 for (var i = 0; i < targetsLength; i++) { |
|
909 var x = self[i]; |
|
910 var t = checkTarget(i, targets[i]); |
|
911 if (conflicts[t]) |
|
912 x = collide(x, buffer[t]); |
|
913 |
|
914 UnsafePutElements(buffer, t, x, conflicts, t, true); |
|
915 } |
|
916 |
|
917 return buffer; |
|
918 } |
|
919 |
|
920 function collide(elem1, elem2) { |
|
921 if (conflictFunc === undefined) |
|
922 ThrowError(JSMSG_PAR_ARRAY_SCATTER_CONFLICT); |
|
923 |
|
924 return conflictFunc(elem1, elem2); |
|
925 } |
|
926 |
|
927 function checkTarget(i, t) { |
|
928 if (TO_INT32(t) !== t) |
|
929 ThrowError(JSMSG_PAR_ARRAY_SCATTER_BAD_TARGET, i); |
|
930 |
|
931 if (t < 0 || t >= length) |
|
932 ThrowError(JSMSG_PAR_ARRAY_SCATTER_BOUNDS); |
|
933 |
|
934 // It's not enough to return t, as -0 | 0 === -0. |
|
935 return TO_INT32(t); |
|
936 } |
|
937 |
|
938 return undefined; |
|
939 } |
|
940 |
|
941 /** |
|
942 * The filter operation applied in parallel. |
|
943 */ |
|
944 function ArrayFilterPar(func, mode) { |
|
945 if (!IsCallable(func)) |
|
946 ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, func)); |
|
947 |
|
948 var self = ToObject(this); |
|
949 var length = self.length; |
|
950 |
|
951 parallel: for (;;) { // see ArrayMapPar() to explain why for(;;) etc |
|
952 if (ShouldForceSequential()) |
|
953 break parallel; |
|
954 if (!TRY_PARALLEL(mode)) |
|
955 break parallel; |
|
956 |
|
957 var slicesInfo = ComputeSlicesInfo(length); |
|
958 |
|
959 // Step 1. Compute which items from each slice of the result buffer should |
|
960 // be preserved. When we're done, we have a uint8 array |survivors| |
|
961 // containing 0 or 1 for each source element, indicating which members of |
|
962 // the chunk survived. We also keep an array |counts| containing the total |
|
963 // number of items that are being preserved from within one slice. |
|
964 var numSlices = slicesInfo.count; |
|
965 var counts = NewDenseArray(numSlices); |
|
966 for (var i = 0; i < numSlices; i++) |
|
967 UnsafePutElements(counts, i, 0); |
|
968 |
|
969 var survivors = new Uint8Array(length); |
|
970 ForkJoin(findSurvivorsThread, 0, numSlices, ForkJoinMode(mode)); |
|
971 |
|
972 // Step 2. Compress the slices into one contiguous set. |
|
973 var count = 0; |
|
974 for (var i = 0; i < numSlices; i++) |
|
975 count += counts[i]; |
|
976 var buffer = NewDenseArray(count); |
|
977 if (count > 0) |
|
978 ForkJoin(copySurvivorsThread, 0, numSlices, ForkJoinMode(mode)); |
|
979 |
|
980 return buffer; |
|
981 } |
|
982 |
|
983 // Sequential fallback: |
|
984 ASSERT_SEQUENTIAL_IS_OK(mode); |
|
985 var buffer = []; |
|
986 for (var i = 0; i < length; i++) { |
|
987 var elem = self[i]; |
|
988 if (func(elem, i, self)) |
|
989 ARRAY_PUSH(buffer, elem); |
|
990 } |
|
991 return buffer; |
|
992 |
|
993 /** |
|
994 * As described above, our goal is to determine which items we will preserve |
|
995 * from a given slice, storing "to-keep" bits into 32-bit chunks. |
|
996 */ |
|
997 function findSurvivorsThread(workerId, sliceStart, sliceEnd) { |
|
998 var sliceShift = slicesInfo.shift; |
|
999 var sliceId; |
|
1000 while (GET_SLICE(sliceStart, sliceEnd, sliceId)) { |
|
1001 var count = 0; |
|
1002 var indexStart = SLICE_START_INDEX(sliceShift, sliceId); |
|
1003 var indexEnd = SLICE_END_INDEX(sliceShift, indexStart, length); |
|
1004 for (var indexPos = indexStart; indexPos < indexEnd; indexPos++) { |
|
1005 var keep = !!func(self[indexPos], indexPos, self); |
|
1006 UnsafePutElements(survivors, indexPos, keep); |
|
1007 count += keep; |
|
1008 } |
|
1009 UnsafePutElements(counts, sliceId, count); |
|
1010 } |
|
1011 return sliceId; |
|
1012 } |
|
1013 |
|
1014 /** |
|
1015 * Copies the survivors from this slice into the correct position. Note |
|
1016 * that this is an idempotent operation that does not invoke user |
|
1017 * code. Therefore, we don't expect bailouts and make an effort to proceed |
|
1018 * chunk by chunk or avoid duplicating work. |
|
1019 */ |
|
1020 function copySurvivorsThread(workerId, sliceStart, sliceEnd) { |
|
1021 var sliceShift = slicesInfo.shift; |
|
1022 var sliceId; |
|
1023 while (GET_SLICE(sliceStart, sliceEnd, sliceId)) { |
|
1024 // Total up the items preserved by previous slices. |
|
1025 var total = 0; |
|
1026 for (var i = 0; i < sliceId + 1; i++) |
|
1027 total += counts[i]; |
|
1028 |
|
1029 // Are we done? |
|
1030 var count = total - counts[sliceId]; |
|
1031 if (count === total) |
|
1032 continue; |
|
1033 |
|
1034 var indexStart = SLICE_START_INDEX(sliceShift, sliceId); |
|
1035 var indexEnd = SLICE_END_INDEX(sliceShift, indexStart, length); |
|
1036 for (var indexPos = indexStart; indexPos < indexEnd; indexPos++) { |
|
1037 if (survivors[indexPos]) { |
|
1038 UnsafePutElements(buffer, count++, self[indexPos]); |
|
1039 if (count == total) |
|
1040 break; |
|
1041 } |
|
1042 } |
|
1043 } |
|
1044 |
|
1045 return sliceId; |
|
1046 } |
|
1047 |
|
1048 return undefined; |
|
1049 } |
|
1050 |
|
1051 /** |
|
1052 * "Comprehension form": This is the function invoked for |
|
1053 * |Array.{build,buildPar}(len, fn)| It creates a new array with length |len| |
|
1054 * where index |i| is equal to |fn(i)|. |
|
1055 * |
|
1056 * The final |mode| argument is an internal argument used only during our |
|
1057 * unit-testing. |
|
1058 */ |
|
1059 function ArrayStaticBuild(length, func) { |
|
1060 if (!IS_UINT32(length)) |
|
1061 ThrowError(JSMSG_BAD_ARRAY_LENGTH); |
|
1062 if (!IsCallable(func)) |
|
1063 ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(1, func)); |
|
1064 |
|
1065 var buffer = NewDenseArray(length); |
|
1066 |
|
1067 for (var i = 0; i < length; i++) |
|
1068 UnsafePutElements(buffer, i, func(i)); |
|
1069 |
|
1070 return buffer; |
|
1071 } |
|
1072 |
|
1073 function ArrayStaticBuildPar(length, func, mode) { |
|
1074 if (!IS_UINT32(length)) |
|
1075 ThrowError(JSMSG_BAD_ARRAY_LENGTH); |
|
1076 if (!IsCallable(func)) |
|
1077 ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(1, func)); |
|
1078 |
|
1079 var buffer = NewDenseArray(length); |
|
1080 |
|
1081 parallel: for (;;) { |
|
1082 if (ShouldForceSequential()) |
|
1083 break parallel; |
|
1084 if (!TRY_PARALLEL(mode)) |
|
1085 break parallel; |
|
1086 |
|
1087 var slicesInfo = ComputeSlicesInfo(length); |
|
1088 ForkJoin(constructThread, 0, slicesInfo.count, ForkJoinMode(mode)); |
|
1089 return buffer; |
|
1090 } |
|
1091 |
|
1092 // Sequential fallback: |
|
1093 ASSERT_SEQUENTIAL_IS_OK(mode); |
|
1094 for (var i = 0; i < length; i++) |
|
1095 UnsafePutElements(buffer, i, func(i)); |
|
1096 return buffer; |
|
1097 |
|
1098 function constructThread(workerId, sliceStart, sliceEnd) { |
|
1099 var sliceShift = slicesInfo.shift; |
|
1100 var sliceId; |
|
1101 while (GET_SLICE(sliceStart, sliceEnd, sliceId)) { |
|
1102 var indexStart = SLICE_START_INDEX(sliceShift, sliceId); |
|
1103 var indexEnd = SLICE_END_INDEX(sliceShift, indexStart, length); |
|
1104 for (var i = indexStart; i < indexEnd; i++) |
|
1105 UnsafePutElements(buffer, i, func(i)); |
|
1106 } |
|
1107 return sliceId; |
|
1108 } |
|
1109 |
|
1110 return undefined; |
|
1111 } |
|
1112 |
|
1113 /* |
|
1114 * Mark the main operations as clone-at-callsite for better precision. |
|
1115 * This is slightly overkill, as all that we really need is to |
|
1116 * specialize to the receiver and the elemental function, but in |
|
1117 * practice this is likely not so different, since element functions |
|
1118 * are often used in exactly one place. |
|
1119 */ |
|
1120 SetScriptHints(ArrayMapPar, { cloneAtCallsite: true }); |
|
1121 SetScriptHints(ArrayReducePar, { cloneAtCallsite: true }); |
|
1122 SetScriptHints(ArrayScanPar, { cloneAtCallsite: true }); |
|
1123 SetScriptHints(ArrayScatterPar, { cloneAtCallsite: true }); |
|
1124 SetScriptHints(ArrayFilterPar, { cloneAtCallsite: true }); |
|
1125 SetScriptHints(ArrayStaticBuildPar, { cloneAtCallsite: true }); |
|
1126 |
|
1127 #endif /* ENABLE_PARALLEL_JS */ |