summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/arrays
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit-test/tests/arrays')
-rw-r--r--js/src/jit-test/tests/arrays/apply-optimization.js58
-rw-r--r--js/src/jit-test/tests/arrays/bug-1811789.js14
-rw-r--r--js/src/jit-test/tests/arrays/bug1423173.js13
-rw-r--r--js/src/jit-test/tests/arrays/bug1673221.js5
-rw-r--r--js/src/jit-test/tests/arrays/bug1693328.js12
-rw-r--r--js/src/jit-test/tests/arrays/change-array-by-copy.js106
-rw-r--r--js/src/jit-test/tests/arrays/defineProperty-redundant.js10
-rw-r--r--js/src/jit-test/tests/arrays/fillwithundefined-length-nonwriteable.js16
-rw-r--r--js/src/jit-test/tests/arrays/from-async-oom.js26
-rw-r--r--js/src/jit-test/tests/arrays/ion-pop-denseinitializedlength-less-than-length.js49
-rw-r--r--js/src/jit-test/tests/arrays/ion-pop-nonwritable-length.js48
-rw-r--r--js/src/jit-test/tests/arrays/ion-push-nonwritable-length.js61
-rw-r--r--js/src/jit-test/tests/arrays/ion-shift-nonwritable-length.js59
-rw-r--r--js/src/jit-test/tests/arrays/length-set-after-define-nonconfigurable.js7
-rw-r--r--js/src/jit-test/tests/arrays/length-set-after-has-sparse.js9
-rw-r--r--js/src/jit-test/tests/arrays/new-array-int-undefined-args.js2
-rw-r--r--js/src/jit-test/tests/arrays/new-array-undefined-undefined-more-args-1.js6
-rw-r--r--js/src/jit-test/tests/arrays/new-array-undefined-undefined-more-args-2.js6
-rw-r--r--js/src/jit-test/tests/arrays/nonwritable-length-grow-capacity.js2
-rw-r--r--js/src/jit-test/tests/arrays/pop-nonarray-nonwritable-length.js13
-rw-r--r--js/src/jit-test/tests/arrays/pop-nonwritable-length-denseinitializedlength-below-length.js49
-rw-r--r--js/src/jit-test/tests/arrays/push-densely-loopy-nonwritable-length.js56
-rw-r--r--js/src/jit-test/tests/arrays/push-densely-nonwritable-length.js31
-rw-r--r--js/src/jit-test/tests/arrays/push-slowly-loopy-nonwritable-length.js51
-rw-r--r--js/src/jit-test/tests/arrays/push-slowly-nonwritable-length.js24
-rw-r--r--js/src/jit-test/tests/arrays/reverse-frozen.js6
-rw-r--r--js/src/jit-test/tests/arrays/reverse-nonarray-nonwritable-element.js13
-rw-r--r--js/src/jit-test/tests/arrays/setelem-one-past-nonwritable-length.js20
-rw-r--r--js/src/jit-test/tests/arrays/slice-sparse-getter.js12
-rw-r--r--js/src/jit-test/tests/arrays/slice.js37
-rw-r--r--js/src/jit-test/tests/arrays/sort-getter-only.js29
-rw-r--r--js/src/jit-test/tests/arrays/sort-update-types.js20
-rw-r--r--js/src/jit-test/tests/arrays/species-redefine-getter.js20
-rw-r--r--js/src/jit-test/tests/arrays/splice-nonwritable-length.js53
-rw-r--r--js/src/jit-test/tests/arrays/spreadcall-optimization.js45
-rw-r--r--js/src/jit-test/tests/arrays/spreadnew-optimization.js51
-rw-r--r--js/src/jit-test/tests/arrays/spreadsupercall-optimization.js59
-rw-r--r--js/src/jit-test/tests/arrays/std_Array-prototype.js6
-rw-r--r--js/src/jit-test/tests/arrays/to-spliced-dense-elements.js13
-rw-r--r--js/src/jit-test/tests/arrays/too-long-array-splice.js10
-rw-r--r--js/src/jit-test/tests/arrays/unshift-nonwritable-length.js61
41 files changed, 1188 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/arrays/apply-optimization.js b/js/src/jit-test/tests/arrays/apply-optimization.js
new file mode 100644
index 0000000000..fc62da910f
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/apply-optimization.js
@@ -0,0 +1,58 @@
+function make(k) {
+ var a = new Array(k);
+ for ( let i=0 ; i < k ; i++ )
+ a[i] = {}
+ return a;
+}
+
+function g() {
+ return arguments.length;
+}
+
+function f(a) {
+ var sum = 0;
+ for ( let i=0 ; i < 1000 ; i++ )
+ sum += g.apply(null, a);
+ return sum;
+}
+
+function F2() {
+ var sum = 0;
+ for ( let i=0 ; i < 1000 ; i++ )
+ sum += g.apply(null, arguments);
+ return sum;
+}
+
+function F(a) {
+ return F2.apply(null, a);
+}
+
+function time(k, t) {
+ var then = Date.now();
+ assertEq(t(), 1000*k);
+ var now = Date.now();
+ return now - then;
+}
+
+function p(v) {
+ // Uncomment to see timings
+ // print(v);
+}
+
+f(make(200));
+
+// There is currently a cutoff after 375 where we bailout in order to avoid
+// handling very large stack frames. This slows the operation down by a factor
+// of 100 or so.
+
+p(time(374, () => f(make(374))));
+p(time(375, () => f(make(375))));
+p(time(376, () => f(make(376))));
+p(time(377, () => f(make(377))));
+
+F(make(200));
+
+p(time(374, () => F(make(374))));
+p(time(375, () => F(make(375))));
+p(time(376, () => F(make(376))));
+p(time(377, () => F(make(377))));
diff --git a/js/src/jit-test/tests/arrays/bug-1811789.js b/js/src/jit-test/tests/arrays/bug-1811789.js
new file mode 100644
index 0000000000..335fb4051b
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/bug-1811789.js
@@ -0,0 +1,14 @@
+// |jit-test| --enable-change-array-by-copy
+
+load(libdir + "asserts.js");
+
+function f5() { }
+
+function f0() {
+ const v15 = new Uint8Array();
+ f5 &&= v15;
+ const v17 = new Uint8Array();
+ const v16 = wrapWithProto(v17, f5);
+ v16.with();
+}
+assertThrowsInstanceOf(() => f0(), RangeError);
diff --git a/js/src/jit-test/tests/arrays/bug1423173.js b/js/src/jit-test/tests/arrays/bug1423173.js
new file mode 100644
index 0000000000..38e584ce36
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/bug1423173.js
@@ -0,0 +1,13 @@
+// |jit-test| --baseline-eager
+Array.prototype.push(1);
+Object.freeze([].__proto__);
+var x = [];
+var c = 0;
+for (var j = 0; j < 5; ++j) {
+ try {
+ x.push(function() {});
+ } catch (e) {
+ c++;
+ }
+}
+assertEq(c, j);
diff --git a/js/src/jit-test/tests/arrays/bug1673221.js b/js/src/jit-test/tests/arrays/bug1673221.js
new file mode 100644
index 0000000000..497c4befec
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/bug1673221.js
@@ -0,0 +1,5 @@
+let x = [7];
+x.splice(0, {valueOf() { x.length = 2; return 0; }}, 5);
+assertEq(x.length, 2);
+assertEq(x[0], 5);
+assertEq(x[1], 7);
diff --git a/js/src/jit-test/tests/arrays/bug1693328.js b/js/src/jit-test/tests/arrays/bug1693328.js
new file mode 100644
index 0000000000..2494dbe2b0
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/bug1693328.js
@@ -0,0 +1,12 @@
+function bar() {}
+
+function foo() {
+ const v2 = [0,0];
+ v2[16777217] = "a";
+ v2.length = 2;
+ bar(...v2);
+}
+
+for (var i = 0; i < 100; i++) {
+ foo();
+}
diff --git a/js/src/jit-test/tests/arrays/change-array-by-copy.js b/js/src/jit-test/tests/arrays/change-array-by-copy.js
new file mode 100644
index 0000000000..2061d5f243
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/change-array-by-copy.js
@@ -0,0 +1,106 @@
+// |jit-test| --enable-change-array-by-copy
+
+load(libdir + 'array-compare.js');
+load(libdir + "asserts.js");
+
+var sequence = [1, 2, 3];
+let reversedSequence = sequence.toReversed();
+assertEq(arraysEqual(sequence, [1, 2, 3]), true);
+assertEq(arraysEqual(reversedSequence, [3, 2, 1]), true);
+
+sequence = [87, 3, 5, 888, 321, 42];
+var sortedSequence = sequence.toSorted((x, y) => (x >= y));
+assertEq(arraysEqual(sequence, [87, 3, 5, 888, 321, 42]), true);
+assertEq(arraysEqual(sortedSequence, [3, 5, 42, 87, 321, 888]), true);
+
+sequence = ["the", "quick", "fox", "jumped", "over", "the", "lazy", "dog"];
+sortedSequence = sequence.toSorted();
+assertEq(arraysEqual(sequence, ["the", "quick", "fox", "jumped", "over", "the", "lazy", "dog"]), true);
+assertEq(arraysEqual(sortedSequence, ["dog", "fox", "jumped", "lazy", "over", "quick", "the", "the"]), true);
+
+/* Test that the correct exception is thrown with a
+ non-function comparefn argument */
+assertThrowsInstanceOf(() => sequence.toSorted([1, 2, 3]), TypeError);
+
+/* toSpliced */
+/* examples from:
+ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice */
+
+function unchanged(a) {
+ assertEq(arraysEqual(a, ['angel', 'clown', 'mandarin', 'sturgeon']), true);
+}
+
+// Remove no elements before index 2, insert "drum"
+let myFish = ['angel', 'clown', 'mandarin', 'sturgeon']
+var myFishSpliced = myFish.toSpliced(2, 0, 'drum')
+unchanged(myFish);
+assertEq(arraysEqual(myFishSpliced, ['angel', 'clown', 'drum', 'mandarin', 'sturgeon']), true);
+
+
+// Remove no elements before index 2, insert "drum" and "guitar"
+var myFishSpliced = myFish.toSpliced(2, 0, 'drum', 'guitar');
+unchanged(myFish);
+assertEq(arraysEqual(myFishSpliced, ['angel', 'clown', 'drum', 'guitar', 'mandarin', 'sturgeon']), true);
+
+// Remove 1 element at index 3
+let myFish1 = ['angel', 'clown', 'drum', 'mandarin', 'sturgeon']
+myFishSpliced = myFish1.toSpliced(3, 1);
+assertEq(arraysEqual(myFish1, ['angel', 'clown', 'drum', 'mandarin', 'sturgeon']), true);
+assertEq(arraysEqual(myFishSpliced, ['angel', 'clown', 'drum', 'sturgeon']), true);
+
+// Remove 1 element at index 2, and insert 'trumpet'
+let myFish2 = ['angel', 'clown', 'drum', 'sturgeon']
+myFishSpliced = myFish2.toSpliced(2, 1, 'trumpet');
+assertEq(arraysEqual(myFish2, ['angel', 'clown', 'drum', 'sturgeon']), true);
+assertEq(arraysEqual(myFishSpliced, ['angel', 'clown', 'trumpet', 'sturgeon']), true);
+
+// Remove 2 elements at index 0, and insert 'parrot', 'anemone', and 'blue'
+let myFish3 = ['angel', 'clown', 'trumpet', 'sturgeon']
+myFishSpliced = myFish3.toSpliced(0, 2, 'parrot', 'anemone', 'blue');
+assertEq(arraysEqual(myFish3, ['angel', 'clown', 'trumpet', 'sturgeon']), true);
+assertEq(arraysEqual(myFishSpliced, ['parrot', 'anemone', 'blue', 'trumpet', 'sturgeon']), true);
+
+// Remove 2 elements, starting at index 2
+let myFish4 = ['parrot', 'anemone', 'blue', 'trumpet', 'sturgeon']
+myFishSpliced = myFish4.toSpliced(2, 2);
+assertEq(arraysEqual(myFish4, ['parrot', 'anemone', 'blue', 'trumpet', 'sturgeon']), true);
+assertEq(arraysEqual(myFishSpliced, ['parrot', 'anemone', 'sturgeon']), true);
+
+// Remove 1 element from index -2
+myFishSpliced = myFish.toSpliced(-2, 1);
+unchanged(myFish);
+assertEq(arraysEqual(myFishSpliced, ['angel', 'clown', 'sturgeon']), true);
+
+// Remove all elements, starting from index 2
+myFishSpliced = myFish.toSpliced(2);
+unchanged(myFish);
+assertEq(arraysEqual(myFishSpliced, ['angel', 'clown']), true);
+
+/* with */
+sequence = [1, 2, 3];
+let seq_with = sequence.with(1, 42);
+assertEq(arraysEqual(sequence, [1, 2, 3]), true);
+assertEq(arraysEqual(seq_with, [1, 42, 3]), true);
+assertEq(arraysEqual(sequence.with(-0, 42), [42, 2, 3]), true);
+
+/* false/true => index 0/1 */
+assertEq(arraysEqual(sequence.with(false, 42), [42, 2, 3]), true);
+assertEq(arraysEqual(sequence.with(true, 42), [1, 42, 3]), true);
+
+/* null => 0 */
+assertEq(arraysEqual(sequence.with(null, 42), [42, 2, 3]), true);
+/* [] => 0 */
+assertEq(arraysEqual(sequence.with([], 42), [42, 2, 3]), true);
+
+assertEq(arraysEqual(sequence.with("2", 42), [1, 2, 42]), true);
+
+/* Non-numeric indices => 0 */
+assertEq(arraysEqual(sequence.with("monkeys", 42), [42, 2, 3]), true);
+assertEq(arraysEqual(sequence.with(undefined, 42), [42, 2, 3]), true);
+assertEq(arraysEqual(sequence.with(function() {}, 42), [42, 2, 3]), true);
+
+assertThrowsInstanceOf(() => sequence.with(3, 42), RangeError);
+assertThrowsInstanceOf(() => sequence.with(5, 42), RangeError);
+assertThrowsInstanceOf(() => sequence.with(-10, 42), RangeError);
+assertThrowsInstanceOf(() => sequence.with(Infinity, 42), RangeError);
+
diff --git a/js/src/jit-test/tests/arrays/defineProperty-redundant.js b/js/src/jit-test/tests/arrays/defineProperty-redundant.js
new file mode 100644
index 0000000000..7e46ffc08a
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/defineProperty-redundant.js
@@ -0,0 +1,10 @@
+var array = [123];
+Object.freeze(array);
+Object.defineProperty(array, 0, {});
+Object.defineProperty(array, 0, {abc: 1});
+Object.defineProperty(array, 0, {value: 123});
+Object.defineProperty(array, 0, {writable: false});
+Object.defineProperty(array, 0, {enumerable: true});
+Object.defineProperty(array, 0, {configurable: false});
+Object.defineProperty(array, 0, {value: 123, writable: false,
+ enumerable: true, configurable: false});
diff --git a/js/src/jit-test/tests/arrays/fillwithundefined-length-nonwriteable.js b/js/src/jit-test/tests/arrays/fillwithundefined-length-nonwriteable.js
new file mode 100644
index 0000000000..852d84116c
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/fillwithundefined-length-nonwriteable.js
@@ -0,0 +1,16 @@
+var called = false;
+var a = [/* hole */, undefined, {
+ toString() {
+ if (!called) {
+ called = true;
+ a.length = 3;
+ Object.defineProperty(a, "length", {writable:false});
+ }
+ return 0;
+ }
+}, 0];
+a.sort();
+
+assertEq(a.length, 3);
+assertEq(a[1], 0);
+assertEq(a[2], undefined);
diff --git a/js/src/jit-test/tests/arrays/from-async-oom.js b/js/src/jit-test/tests/arrays/from-async-oom.js
new file mode 100644
index 0000000000..8c01b12b43
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/from-async-oom.js
@@ -0,0 +1,26 @@
+// |jit-test| --enable-array-from-async; skip-if: !Array.fromAsync|| !('oomTest' in this)
+
+// Basic Smoke Test
+async function* asyncGen(n) {
+ for (let i = 0; i < n; i++) {
+ yield i * 2;
+ }
+}
+
+function test() {
+ Array.fromAsync(asyncGen(4)).then((x) => {
+ assertEq(Array.isArray(x), true);
+ assertEq(x.length, 4);
+ assertEq(x[0], 0);
+ assertEq(x[1], 2);
+ assertEq(x[2], 4);
+ assertEq(x[3], 6);
+ done = true;
+ }
+ );
+
+ drainJobQueue();
+}
+
+oomTest(test);
+
diff --git a/js/src/jit-test/tests/arrays/ion-pop-denseinitializedlength-less-than-length.js b/js/src/jit-test/tests/arrays/ion-pop-denseinitializedlength-less-than-length.js
new file mode 100644
index 0000000000..9f4bda0236
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/ion-pop-denseinitializedlength-less-than-length.js
@@ -0,0 +1,49 @@
+load(libdir + "asserts.js");
+
+function f(arr)
+{
+ arr.pop();
+}
+
+var N = 100;
+
+function test()
+{
+ // Create an array of arrays, to be iterated over for [].pop-calling. We
+ // can't just loop on pop on a single array with non-writable length because
+ // pop throws when called on an array with non-writable length.
+ var arrs = [];
+ for (var i = 0; i < N; i++)
+ arrs.push([0, 1, 2, 3]);
+
+ // Test Ion-pop where dense initialized length < length.
+ var a = [0, 1, 2];
+ a.length = 4;
+
+ arrs.push(a);
+
+ for (var i = 0, sz = arrs.length; i < sz; i++)
+ f(arrs[i]);
+
+ return arrs;
+}
+
+var arrs = test();
+assertEq(arrs.length, N + 1);
+for (var i = 0; i < N; i++)
+{
+ assertEq(arrs[i].length, 3, "unexpected length for arrs[" + i + "]");
+ assertEq(arrs[i][0], 0, "bad element for arrs[" + i + "][0]");
+ assertEq(arrs[i][1], 1, "bad element for arrs[" + i + "][1]");
+ assertEq(arrs[i][2], 2, "bad element for arrs[" + i + "][2]");
+ assertEq(3 in arrs[i], false, "shouldn't be a third element");
+ assertEq(arrs[i][3], undefined);
+}
+
+var a = arrs[N];
+assertEq(a.length, 3, "unexpected length for arrs[" + i + "]");
+assertEq(a[0], 0, "bad element for arrs[" + i + "][0]");
+assertEq(a[1], 1, "bad element for arrs[" + i + "][1]");
+assertEq(a[2], 2, "bad element for arrs[" + i + "][2]");
+assertEq(3 in a, false, "shouldn't be a third element");
+assertEq(a[3], undefined);
diff --git a/js/src/jit-test/tests/arrays/ion-pop-nonwritable-length.js b/js/src/jit-test/tests/arrays/ion-pop-nonwritable-length.js
new file mode 100644
index 0000000000..acecd0a2c0
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/ion-pop-nonwritable-length.js
@@ -0,0 +1,48 @@
+load(libdir + "asserts.js");
+
+function f(arr)
+{
+ arr.pop();
+}
+
+var N = 100;
+
+function test(out)
+{
+ // Create an array of arrays, to be iterated over for [].pop-calling. We
+ // can't just loop on pop on a single array with non-writable length because
+ // pop throws when called on an array with non-writable length.
+ var arrs = out.arrs = [];
+ for (var i = 0; i < N; i++)
+ arrs.push([0, 1, 2, 3]);
+
+ // Use a much-greater capacity than the eventual non-writable length.
+ var a = [0, 1, 2, 3, 4, 5, 6, 7];
+ Object.defineProperty(a, "length", { writable: false, value: 4 });
+
+ arrs.push(a);
+
+ for (var i = 0, sz = arrs.length; i < sz; i++)
+ f(arrs[i]);
+}
+
+var obj = {};
+
+assertThrowsInstanceOf(function() { test(obj); }, TypeError);
+
+var arrs = obj.arrs;
+assertEq(arrs.length, N + 1);
+for (var i = 0; i < N; i++)
+{
+ assertEq(arrs[i].length, 3, "unexpected length for arrs[" + i + "]");
+ assertEq(arrs[i][0], 0, "bad element for arrs[" + i + "][0]");
+ assertEq(arrs[i][1], 1, "bad element for arrs[" + i + "][1]");
+ assertEq(arrs[i][2], 2, "bad element for arrs[" + i + "][2]");
+ assertEq(3 in arrs[i], false, "shouldn't be a third element");
+ assertEq(arrs[i][3], undefined);
+}
+
+var a = arrs[N];
+assertEq(a.hasOwnProperty(3), false, "should have been deleted before throw");
+assertEq(a[3], undefined);
+assertEq(a.length, 4, "length shouldn't have been changed");
diff --git a/js/src/jit-test/tests/arrays/ion-push-nonwritable-length.js b/js/src/jit-test/tests/arrays/ion-push-nonwritable-length.js
new file mode 100644
index 0000000000..5149103169
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/ion-push-nonwritable-length.js
@@ -0,0 +1,61 @@
+function f(arr)
+{
+ assertEq(arr.push(4), 5); // if it doesn't throw :-)
+}
+
+function test(out)
+{
+ // Create an array of arrays, to be iterated over for [].push-calling. We
+ // can't just loop on push on a single array with non-writable length because
+ // push throws when called on an array with non-writable length.
+ var arrs = out.arrs = [];
+ for (var i = 0; i < 100; i++)
+ arrs.push([0, 1, 2, 3]);
+
+ // Use a much-greater capacity than the eventual non-writable length, so that
+ // the inline-push will work.
+ var a = [0, 1, 2, 3, 4, 5, 6, 7];
+ Object.defineProperty(a, "length", { writable: false, value: 4 });
+
+ arrs.push(a);
+
+ for (var i = 0, sz = arrs.length; i < sz; i++)
+ {
+ var arr = arrs[i];
+ f(arr);
+ }
+}
+
+var obj = {};
+var a, arrs;
+
+try
+{
+ test(obj);
+ throw new Error("didn't throw!");
+}
+catch (e)
+{
+ assertEq(e instanceof TypeError, true, "expected TypeError, got " + e);
+
+ arrs = obj.arrs;
+ assertEq(arrs.length, 101);
+ for (var i = 0; i < 100; i++)
+ {
+ assertEq(arrs[i].length, 5, "unexpected length for arrs[" + i + "]");
+ assertEq(arrs[i][0], 0, "bad element for arrs[" + i + "][0]");
+ assertEq(arrs[i][1], 1, "bad element for arrs[" + i + "][1]");
+ assertEq(arrs[i][2], 2, "bad element for arrs[" + i + "][2]");
+ assertEq(arrs[i][3], 3, "bad element for arrs[" + i + "][3]");
+ assertEq(arrs[i][4], 4, "bad element for arrs[" + i + "][4]");
+ }
+
+ a = arrs[100];
+ assertEq(a[0], 0, "bad element for a[" + i + "]");
+ assertEq(a[1], 1, "bad element for a[" + i + "]");
+ assertEq(a[2], 2, "bad element for a[" + i + "]");
+ assertEq(a[3], 3, "bad element for a[" + i + "]");
+ assertEq(a.hasOwnProperty(4), false, "element addition should have thrown");
+ assertEq(a[4], undefined);
+ assertEq(a.length, 4, "length shouldn't have been changed");
+}
diff --git a/js/src/jit-test/tests/arrays/ion-shift-nonwritable-length.js b/js/src/jit-test/tests/arrays/ion-shift-nonwritable-length.js
new file mode 100644
index 0000000000..119271f201
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/ion-shift-nonwritable-length.js
@@ -0,0 +1,59 @@
+function f(arr)
+{
+ assertEq(arr.shift(), 0);
+}
+
+function test(out)
+{
+ // Create an array of arrays, to be iterated over for [].shift-calling. We
+ // can't just loop on shift on a single array with non-writable length because
+ // shift throws when called on an array with non-writable length.
+ var arrs = out.arrs = [];
+ for (var i = 0; i < 100; i++)
+ arrs.push([0, 1, 2, 3]);
+
+ // Use a much-greater capacity than the eventual non-writable length.
+ var a = [0, 1, 2, 3, 4, 5, 6, 7];
+ Object.defineProperty(a, "length", { writable: false, value: 4 });
+
+ arrs.push(a);
+
+ for (var i = 0, sz = arrs.length; i < sz; i++)
+ {
+ var arr = arrs[i];
+ f(arr);
+ }
+}
+
+var obj = {};
+var a, arrs;
+
+try
+{
+ test(obj);
+ throw new Error("didn't throw!");
+}
+catch (e)
+{
+ assertEq(e instanceof TypeError, true, "expected TypeError, got " + e);
+
+ arrs = obj.arrs;
+ assertEq(arrs.length, 101);
+ for (var i = 0; i < 100; i++)
+ {
+ assertEq(arrs[i].length, 3, "unexpected length for arrs[" + i + "]");
+ assertEq(arrs[i][0], 1, "bad element for arrs[" + i + "][0]");
+ assertEq(arrs[i][1], 2, "bad element for arrs[" + i + "][1]");
+ assertEq(arrs[i][2], 3, "bad element for arrs[" + i + "][2]");
+ assertEq(3 in arrs[i], false, "shouldn't be a third element");
+ assertEq(arrs[i][3], undefined);
+ }
+
+ a = arrs[100];
+ assertEq(a[0], 1, "bad element for a[" + i + "]");
+ assertEq(a[1], 2, "bad element for a[" + i + "]");
+ assertEq(a[2], 3, "bad element for a[" + i + "]");
+ assertEq(a.hasOwnProperty(3), false, "should have been deleted before throw");
+ assertEq(a[3], undefined);
+ assertEq(a.length, 4, "length shouldn't have been changed");
+}
diff --git a/js/src/jit-test/tests/arrays/length-set-after-define-nonconfigurable.js b/js/src/jit-test/tests/arrays/length-set-after-define-nonconfigurable.js
new file mode 100644
index 0000000000..3841540565
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/length-set-after-define-nonconfigurable.js
@@ -0,0 +1,7 @@
+var arr = [1];
+Object.defineProperty(arr, 1, { value: undefined, configurable: false });
+
+// no particular reason for 9 -- just enough to trigger property-cache code,
+// maybe start JITting a little
+for (var y = 0; y < 9; y++)
+ arr.length = 1;
diff --git a/js/src/jit-test/tests/arrays/length-set-after-has-sparse.js b/js/src/jit-test/tests/arrays/length-set-after-has-sparse.js
new file mode 100644
index 0000000000..44e662661b
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/length-set-after-has-sparse.js
@@ -0,0 +1,9 @@
+var arr = [];
+Object.defineProperty(arr, 4, {
+ configurable: true,
+ enumerable: false,
+ writable: false,
+ value: undefined
+});
+for (var y = 0; y < 2; y++)
+ arr.length = 0;
diff --git a/js/src/jit-test/tests/arrays/new-array-int-undefined-args.js b/js/src/jit-test/tests/arrays/new-array-int-undefined-args.js
new file mode 100644
index 0000000000..56ac8e64d4
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/new-array-int-undefined-args.js
@@ -0,0 +1,2 @@
+for (var i = 0; i < 1e4; i++)
+ assertEq(new Array(0, undefined).length, 2, "bad, i: " + i);
diff --git a/js/src/jit-test/tests/arrays/new-array-undefined-undefined-more-args-1.js b/js/src/jit-test/tests/arrays/new-array-undefined-undefined-more-args-1.js
new file mode 100644
index 0000000000..e4a9e1a88c
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/new-array-undefined-undefined-more-args-1.js
@@ -0,0 +1,6 @@
+for (var i = 0; i < 1e4; i++)
+{
+ assertEq(typeof new Array(undefined, undefined, 1, 2, 3, 4).sort()[0],
+ "number",
+ "bad, i: " + i);
+}
diff --git a/js/src/jit-test/tests/arrays/new-array-undefined-undefined-more-args-2.js b/js/src/jit-test/tests/arrays/new-array-undefined-undefined-more-args-2.js
new file mode 100644
index 0000000000..cf81504938
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/new-array-undefined-undefined-more-args-2.js
@@ -0,0 +1,6 @@
+for (var i = 0; i < 1e4; i++)
+{
+ assertEq(new Array(undefined, undefined, 1, 2, 3, 4).length,
+ 6,
+ "bad, i: " + i);
+}
diff --git a/js/src/jit-test/tests/arrays/nonwritable-length-grow-capacity.js b/js/src/jit-test/tests/arrays/nonwritable-length-grow-capacity.js
new file mode 100644
index 0000000000..160689bea0
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/nonwritable-length-grow-capacity.js
@@ -0,0 +1,2 @@
+var arr = Object.defineProperty([], "length", { writable: false, value: 12 });
+arr[11] = true;
diff --git a/js/src/jit-test/tests/arrays/pop-nonarray-nonwritable-length.js b/js/src/jit-test/tests/arrays/pop-nonarray-nonwritable-length.js
new file mode 100644
index 0000000000..22a5b706b5
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/pop-nonarray-nonwritable-length.js
@@ -0,0 +1,13 @@
+// Array.prototype.pop does a strict assignment to this.length even if the
+// caller is nonstrict. Bug 886087.
+
+load(libdir + "asserts.js");
+
+// obj.length is read-only
+var obj = {pop: [].pop, 0: "zero"};
+Object.defineProperty(obj, "length", {configurable: true, value: 1, writable: false});
+assertThrowsInstanceOf(() => obj.pop(), TypeError);
+
+// obj.length has only a getter
+obj = {pop: [].pop, 0: "zero", get length() { return 1; }};
+assertThrowsInstanceOf(() => obj.pop(), TypeError);
diff --git a/js/src/jit-test/tests/arrays/pop-nonwritable-length-denseinitializedlength-below-length.js b/js/src/jit-test/tests/arrays/pop-nonwritable-length-denseinitializedlength-below-length.js
new file mode 100644
index 0000000000..9330f775ba
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/pop-nonwritable-length-denseinitializedlength-below-length.js
@@ -0,0 +1,49 @@
+load(libdir + "asserts.js");
+
+function f(arr)
+{
+ assertEq(arr.pop(), undefined); // if it doesn't throw
+}
+
+var N = 100;
+
+function basic(out)
+{
+ // Create an array of arrays, to be iterated over for [].pop-calling. We
+ // can't just loop on pop on a single array with non-writable length because
+ // pop throws when called on an array with non-writable length.
+ var arrs = out.arrs = [];
+ for (var i = 0; i < N; i++)
+ {
+ var arr = [0, 1, 2, 3, 4];
+ arr.length = 6;
+ arrs.push(arr);
+ }
+
+ var a = [0, 1, 2, 3, 4];
+ Object.defineProperty(a, "length", { writable: false, value: 6 });
+
+ arrs.push(a);
+
+ for (var i = 0, sz = arrs.length; i < sz; i++)
+ f(arrs[i]);
+}
+
+var obj = {};
+var arrs, a;
+
+assertThrowsInstanceOf(function() { basic(obj); }, TypeError);
+
+var arrs = obj.arrs;
+assertEq(arrs.length, N + 1);
+for (var i = 0; i < N; i++)
+{
+ assertEq(arrs[i].length, 5, "unexpected length for arrs[" + i + "]");
+ assertEq(arrs[i].hasOwnProperty(5), false,
+ "element not deleted for arrs[" + i + "]");
+}
+
+var a = arrs[N];
+assertEq(a.hasOwnProperty(5), false);
+assertEq(a[5], undefined);
+assertEq(a.length, 6);
diff --git a/js/src/jit-test/tests/arrays/push-densely-loopy-nonwritable-length.js b/js/src/jit-test/tests/arrays/push-densely-loopy-nonwritable-length.js
new file mode 100644
index 0000000000..e09ed09645
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/push-densely-loopy-nonwritable-length.js
@@ -0,0 +1,56 @@
+// Force recognition of a known-constant.
+var push = Array.prototype.push;
+
+function f(arr)
+{
+ // Push an actual constant to trigger JIT-inlining of the effect of the push.
+ push.call(arr, 99);
+}
+
+function basic(out)
+{
+ // Create an array of arrays, to be iterated over for [].push-calling. We
+ // can't just loop on push on a single array with non-writable length because
+ // push throws when called on an array with non-writable length.
+ var arrs = out.arrs = [];
+ for (var i = 0; i < 100; i++)
+ arrs.push([]);
+
+ // Use a much-greater capacity than the eventual non-writable length.
+ var a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
+ Object.defineProperty(a, "length", { writable: false, value: 6 });
+
+ arrs.push(a);
+
+ for (var i = 0, sz = arrs.length; i < sz; i++)
+ {
+ var arr = arrs[i];
+ f(arr);
+ }
+}
+
+var obj = {};
+var arrs, a;
+
+try
+{
+ basic(obj);
+ throw new Error("didn't throw!");
+}
+catch (e)
+{
+ assertEq(e instanceof TypeError, true, "expected TypeError, got " + e);
+
+ arrs = obj.arrs;
+ assertEq(arrs.length, 101);
+ for (var i = 0; i < 100; i++)
+ {
+ assertEq(arrs[i].length, 1, "unexpected length for arrs[" + i + "]");
+ assertEq(arrs[i][0], 99, "bad element for arrs[" + i + "]");
+ }
+
+ a = arrs[100];
+ assertEq(a.hasOwnProperty(6), false);
+ assertEq(a[6], undefined);
+ assertEq(a.length, 6);
+}
diff --git a/js/src/jit-test/tests/arrays/push-densely-nonwritable-length.js b/js/src/jit-test/tests/arrays/push-densely-nonwritable-length.js
new file mode 100644
index 0000000000..9c26661cb7
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/push-densely-nonwritable-length.js
@@ -0,0 +1,31 @@
+function f(arr, v)
+{
+ arr.push(v);
+}
+
+function basic(out)
+{
+ // Use a much-greater capacity than the eventual non-writable length.
+ var a = out.a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
+ Object.defineProperty(a, "length", { writable: false, value: 6 });
+
+ f(a, 99);
+}
+
+var obj = {};
+var a;
+
+try
+{
+ basic(obj);
+ throw new Error("didn't throw!");
+}
+catch (e)
+{
+ assertEq(e instanceof TypeError, true, "expected TypeError, got " + e);
+
+ a = obj.a;
+ assertEq(a.hasOwnProperty(6), false);
+ assertEq(a[6], undefined);
+ assertEq(a.length, 6);
+}
diff --git a/js/src/jit-test/tests/arrays/push-slowly-loopy-nonwritable-length.js b/js/src/jit-test/tests/arrays/push-slowly-loopy-nonwritable-length.js
new file mode 100644
index 0000000000..79d8587153
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/push-slowly-loopy-nonwritable-length.js
@@ -0,0 +1,51 @@
+load(libdir + "asserts.js");
+
+function f(arr, v1, v2)
+{
+ // Ensure array_push_slowly is called by passing more than one argument.
+ arr.push(v1, v2);
+}
+
+var N = 100;
+
+function test(out)
+{
+ // Create an array of arrays, to be iterated over for [].push-calling. We
+ // can't just loop on push on a single array with non-writable length because
+ // push throws when called on an array with non-writable length.
+ var arrs = out.arrs = [];
+ for (var i = 0; i < N; i++)
+ arrs.push([]);
+
+ // Use a much-greater capacity than the eventual non-writable length.
+ var a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
+ Object.defineProperty(a, "length", { writable: false, value: 6 });
+
+ arrs.push(a);
+
+ for (var i = 0, sz = arrs.length; i < sz; i++)
+ {
+ var arr = arrs[i];
+ f(arr, 8675309, 3141592);
+ }
+}
+
+var obj = {};
+
+assertThrowsInstanceOf(function() { test(obj); }, TypeError);
+
+var arrs = obj.arrs;
+assertEq(arrs.length, N + 1);
+for (var i = 0; i < N; i++)
+{
+ assertEq(arrs[i].length, 2, "unexpected length for arrs[" + i + "]");
+ assertEq(arrs[i][0], 8675309, "bad element for arrs[" + i + "][0]");
+ assertEq(arrs[i][1], 3141592, "bad element for arrs[" + i + "][1]");
+}
+
+var a = arrs[N];
+assertEq(a.hasOwnProperty(6), false);
+assertEq(a[6], undefined);
+assertEq(a.hasOwnProperty(7), false);
+assertEq(a[7], undefined);
+assertEq(a.length, 6);
diff --git a/js/src/jit-test/tests/arrays/push-slowly-nonwritable-length.js b/js/src/jit-test/tests/arrays/push-slowly-nonwritable-length.js
new file mode 100644
index 0000000000..9cfc455844
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/push-slowly-nonwritable-length.js
@@ -0,0 +1,24 @@
+load(libdir + "asserts.js");
+
+function f(arr, v1, v2)
+{
+ // Ensure array_push_slowly is called by passing more than one argument.
+ arr.push(v1, v2);
+}
+
+function basic()
+{
+ // Use a much-greater capacity than the eventual non-writable length.
+ var a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
+ Object.defineProperty(a, "length", { writable: false, value: 6 });
+
+ assertThrowsInstanceOf(() => f(a, 8675309, 3141592), TypeError);
+
+ assertEq(a.hasOwnProperty(6), false);
+ assertEq(a[6], undefined);
+ assertEq(a.hasOwnProperty(7), false);
+ assertEq(a[7], undefined);
+ assertEq(a.length, 6);
+}
+
+basic();
diff --git a/js/src/jit-test/tests/arrays/reverse-frozen.js b/js/src/jit-test/tests/arrays/reverse-frozen.js
new file mode 100644
index 0000000000..d2f32b78d2
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/reverse-frozen.js
@@ -0,0 +1,6 @@
+// |jit-test| error: TypeError
+
+x = [0];
+x.length = 9;
+Object.freeze(x);
+x.reverse();
diff --git a/js/src/jit-test/tests/arrays/reverse-nonarray-nonwritable-element.js b/js/src/jit-test/tests/arrays/reverse-nonarray-nonwritable-element.js
new file mode 100644
index 0000000000..bca75a96b3
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/reverse-nonarray-nonwritable-element.js
@@ -0,0 +1,13 @@
+// Array.prototype.reverse does a strict assignment to this.length even if the
+// caller is nonstrict. Bug 886087.
+
+load(libdir + "asserts.js");
+
+// obj[1] is read-only
+var obj = {0: "zero", length: 2, reverse: [].reverse};
+Object.defineProperty(obj, "1", {configurable: true, value: "one", writable: false});
+assertThrowsInstanceOf(() => obj.reverse(), TypeError);
+
+// obj[1] has only a getter
+Object.defineProperty(obj, "1", {configurable: true, get: () => "one"});
+assertThrowsInstanceOf(() => obj.reverse(), TypeError);
diff --git a/js/src/jit-test/tests/arrays/setelem-one-past-nonwritable-length.js b/js/src/jit-test/tests/arrays/setelem-one-past-nonwritable-length.js
new file mode 100644
index 0000000000..7ea5971c05
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/setelem-one-past-nonwritable-length.js
@@ -0,0 +1,20 @@
+function f(arr, i, v)
+{
+ arr[i] = v;
+}
+
+function test()
+{
+ // Use a much-greater capacity than the eventual non-writable length.
+ var a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
+ Object.defineProperty(a, "length", { writable: false, value: 6 });
+
+ for (var i = 0; i < 100; i++)
+ f(a, a.length, i);
+
+ assertEq(a.hasOwnProperty(6), false);
+ assertEq(a[6], undefined);
+ assertEq(a.length, 6);
+}
+
+test();
diff --git a/js/src/jit-test/tests/arrays/slice-sparse-getter.js b/js/src/jit-test/tests/arrays/slice-sparse-getter.js
new file mode 100644
index 0000000000..9416349ce5
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/slice-sparse-getter.js
@@ -0,0 +1,12 @@
+// Indexed getters can add new properties that slice should not ignore.
+var arr = [];
+Object.defineProperty(arr, 10000, {get: function() {
+ arr[10001] = 4;
+ return 3;
+}});
+arr[10010] = 6;
+
+var res = arr.slice(8000);
+assertEq(res[2000], 3);
+assertEq(res[2001], 4);
+assertEq(res[2010], 6);
diff --git a/js/src/jit-test/tests/arrays/slice.js b/js/src/jit-test/tests/arrays/slice.js
new file mode 100644
index 0000000000..ad4f66f633
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/slice.js
@@ -0,0 +1,37 @@
+let invoked = false;
+Object.defineProperty(Array.prototype, '0', {set: function () {
+ invoked = true;
+}});
+
+let result = [1, 2, 3].slice(1);
+assertEq(invoked, false);
+
+let proxy = new Proxy({}, {
+ get: function (target, name, proxy) {
+ switch (name) {
+ case "length":
+ return 2;
+ case "0":
+ return 15;
+ case "1":
+ // Should not invoke [[Get]] for this hole.
+ default:
+ assertEq(false, true);
+ }
+ },
+ has: function (target, name) {
+ switch (name) {
+ case "0":
+ return true;
+ case "1":
+ return false;
+ default:
+ assertEq(false, true);
+ }
+ }
+})
+result = Array.prototype.slice.call(proxy, 0);
+assertEq(result.length, 2);
+assertEq(0 in result, true);
+assertEq(1 in result, false);
+assertEq(result[0], 15);
diff --git a/js/src/jit-test/tests/arrays/sort-getter-only.js b/js/src/jit-test/tests/arrays/sort-getter-only.js
new file mode 100644
index 0000000000..d17e8556d6
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/sort-getter-only.js
@@ -0,0 +1,29 @@
+// The property assignments in Array.prototype.sort are strict assignments.
+
+load(libdir + "asserts.js");
+
+var a = ["A", , "B", "C", "D"];
+var normalArrayElementDesc = Object.getOwnPropertyDescriptor(a, 0);
+var getterDesc = {
+ get: function () { return "F"; },
+ set: undefined,
+ enumerable: true,
+ configurable: false
+};
+Object.defineProperty(a, 1, getterDesc);
+
+// a.sort is permitted to try to delete a[1] or to try to assign a[1], but it
+// must try one or the other. Either one will fail, throwing a TypeError.
+assertThrowsInstanceOf(() => a.sort(), TypeError);
+
+// a.sort() is not permitted to delete the nonconfigurable property.
+assertDeepEq(Object.getOwnPropertyDescriptor(a, 1), getterDesc);
+
+// The values left in the other elements of a are unspecified; some or all may
+// have been deleted.
+for (var i = 0; i < a.length; i++) {
+ if (i !== 1 && a.hasOwnProperty(i)) {
+ normalArrayElementDesc.value = a[i];
+ assertDeepEq(Object.getOwnPropertyDescriptor(a, i), normalArrayElementDesc);
+ }
+}
diff --git a/js/src/jit-test/tests/arrays/sort-update-types.js b/js/src/jit-test/tests/arrays/sort-update-types.js
new file mode 100644
index 0000000000..ab0063fd49
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/sort-update-types.js
@@ -0,0 +1,20 @@
+Object.setPrototypeOf(Array.prototype, {
+ get 0() {
+ Object.setPrototypeOf(Array.prototype, Object.prototype);
+ return "159".repeat(5).substring(2, 5);
+ }
+});
+
+var array = [
+ /*0*/, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+];
+
+array.sort();
+
+gc();
+
+var r = array[array.length - 1] * 1;
+assertEq(r, 915);
diff --git a/js/src/jit-test/tests/arrays/species-redefine-getter.js b/js/src/jit-test/tests/arrays/species-redefine-getter.js
new file mode 100644
index 0000000000..94ab329c08
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/species-redefine-getter.js
@@ -0,0 +1,20 @@
+// Ensure the HadGetterSetterChange flag is set.
+Object.defineProperty(Array, "foo", {configurable: true, get: function() {}});
+Object.defineProperty(Array, "foo", {configurable: true, get: function() {}});
+
+// Initialize ArraySpeciesLookup.
+let a = [1, 2, 3];
+for (let i = 0; i < 5; i++) {
+ assertEq(a.slice().length, 3);
+}
+
+// Redefine the Array[Symbol.species] getter without changing its attributes/shape.
+let count = 0;
+Object.defineProperty(Array, Symbol.species,
+ {get: function() { count++; }, enumerable: false, configurable: true});
+
+// Ensure ArraySpeciesLookup now deoptimizes and calls the getter.
+for (let i = 0; i < 5; i++) {
+ assertEq(a.slice().length, 3);
+}
+assertEq(count, 5);
diff --git a/js/src/jit-test/tests/arrays/splice-nonwritable-length.js b/js/src/jit-test/tests/arrays/splice-nonwritable-length.js
new file mode 100644
index 0000000000..233eb027bc
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/splice-nonwritable-length.js
@@ -0,0 +1,53 @@
+load(libdir + "asserts.js");
+
+function f(arr)
+{
+ assertEq(arr.splice(1, 2, 9, 8, 7, 6).length, 2); // if it doesn't throw :-)
+}
+
+var N = 100;
+
+function test(out)
+{
+ // Create an array of arrays, to be iterated over for [].splice-calling.
+ var arrs = out.arrs = [];
+ for (var i = 0; i < N; i++)
+ arrs.push([0, 1, 2, 3]);
+
+ // Use a much-greater capacity than the eventual non-writable length, just for
+ // variability.
+ var a = [0, 1, 2, 3, 4, 5, 6, 7];
+ Object.defineProperty(a, "length", { writable: false, value: 4 });
+
+ arrs.push(a);
+
+ for (var i = 0, sz = arrs.length; i < sz; i++)
+ f(arrs[i]);
+}
+
+var obj = {};
+assertThrowsInstanceOf(function() { test(obj); }, TypeError);
+
+var arrs = obj.arrs;
+assertEq(arrs.length, N + 1);
+for (var i = 0; i < N; i++)
+{
+ assertEq(arrs[i].length, 6, "unexpected length for arrs[" + i + "]");
+ assertEq(arrs[i][0], 0, "bad element for arrs[" + i + "][0]");
+ assertEq(arrs[i][1], 9, "bad element for arrs[" + i + "][1]");
+ assertEq(arrs[i][2], 8, "bad element for arrs[" + i + "][2]");
+ assertEq(arrs[i][3], 7, "bad element for arrs[" + i + "][3]");
+ assertEq(arrs[i][4], 6, "bad element for arrs[" + i + "][4]");
+ assertEq(arrs[i][5], 3, "bad element for arrs[" + i + "][5]");
+}
+
+var a = arrs[N];
+assertEq(a[0], 0, "bad element for a[0]");
+assertEq(a[1], 1, "bad element for a[1]");
+assertEq(a[2], 2, "bad element for a[2]");
+assertEq(a[3], 3, "bad element for a[3]");
+assertEq(a.hasOwnProperty(4), false, "shouldn't have added any elements");
+assertEq(a[4], undefined);
+assertEq(a.hasOwnProperty(5), false, "shouldn't have added any elements");
+assertEq(a[5], undefined);
+assertEq(a.length, 4, "length shouldn't have been changed");
diff --git a/js/src/jit-test/tests/arrays/spreadcall-optimization.js b/js/src/jit-test/tests/arrays/spreadcall-optimization.js
new file mode 100644
index 0000000000..7273f24a0f
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/spreadcall-optimization.js
@@ -0,0 +1,45 @@
+// Test case adapted from "apply-optimization.js" to test SpreadCall instead of FunApply.
+
+// Uses fewer iterations than "apply-optimization.js" to keep the overall runtime reasonable.
+const iterations = 40;
+
+function make(k) {
+ var a = new Array(k);
+ for ( let i=0 ; i < k ; i++ )
+ a[i] = {}
+ return a;
+}
+
+function g() {
+ return arguments.length;
+}
+
+function f(a) {
+ var sum = 0;
+ for ( let i=0 ; i < iterations ; i++ )
+ sum += g(...a);
+ return sum;
+}
+
+function time(k, t) {
+ var then = Date.now();
+ assertEq(t(), iterations*k);
+ var now = Date.now();
+ return now - then;
+}
+
+function p(v) {
+ // Uncomment to see timings
+ // print(v);
+}
+
+f(make(200));
+
+// There is currently a cutoff after 375 where we bailout in order to avoid
+// handling very large stack frames. This slows the operation down by a factor
+// of 100 or so.
+
+p(time(374, () => f(make(374))));
+p(time(375, () => f(make(375))));
+p(time(376, () => f(make(376))));
+p(time(377, () => f(make(377))));
diff --git a/js/src/jit-test/tests/arrays/spreadnew-optimization.js b/js/src/jit-test/tests/arrays/spreadnew-optimization.js
new file mode 100644
index 0000000000..d676bdb753
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/spreadnew-optimization.js
@@ -0,0 +1,51 @@
+// Test case adapted from "apply-optimization.js" to test SpreadNew instead of FunApply.
+
+// Uses fewer iterations than "apply-optimization.js" to keep the overall runtime reasonable.
+const iterations = 40;
+
+function make(k) {
+ var a = new Array(k);
+ for ( let i=0 ; i < k ; i++ )
+ a[i] = {}
+ return a;
+}
+
+function g() {
+ // Ensure |new.target| and |this| are correct.
+ assertEq(new.target, g);
+ assertEq(typeof this, "object");
+ assertEq(Object.getPrototypeOf(this), g.prototype);
+
+ // Returns a Number object, because constructor calls need to return an object!
+ return new Number(arguments.length);
+}
+
+function f(a) {
+ var sum = 0;
+ for ( let i=0 ; i < iterations ; i++ )
+ sum += new g(...a);
+ return sum;
+}
+
+function time(k, t) {
+ var then = Date.now();
+ assertEq(t(), iterations*k);
+ var now = Date.now();
+ return now - then;
+}
+
+function p(v) {
+ // Uncomment to see timings
+ // print(v);
+}
+
+f(make(200));
+
+// There is currently a cutoff after 375 where we bailout in order to avoid
+// handling very large stack frames. This slows the operation down by a factor
+// of 100 or so.
+
+p(time(374, () => f(make(374))));
+p(time(375, () => f(make(375))));
+p(time(376, () => f(make(376))));
+p(time(377, () => f(make(377))));
diff --git a/js/src/jit-test/tests/arrays/spreadsupercall-optimization.js b/js/src/jit-test/tests/arrays/spreadsupercall-optimization.js
new file mode 100644
index 0000000000..7c37d79930
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/spreadsupercall-optimization.js
@@ -0,0 +1,59 @@
+// Test case adapted from "apply-optimization.js" to test SpreadNew instead of FunApply.
+
+// Uses fewer iterations than "apply-optimization.js" to keep the overall runtime reasonable.
+const iterations = 40;
+
+function make(k) {
+ var a = new Array(k);
+ for ( let i=0 ; i < k ; i++ )
+ a[i] = {}
+ return a;
+}
+
+class Base {
+ constructor() {
+ // Ensure |new.target| and |this| are correct.
+ assertEq(new.target, g);
+ assertEq(typeof this, "object");
+ assertEq(Object.getPrototypeOf(this), g.prototype);
+
+ // Returns a Number object, because constructor calls need to return an object!
+ return new Number(arguments.length);
+ }
+}
+
+class g extends Base {
+ constructor(...args) {
+ super(...args);
+ }
+}
+
+function f(a) {
+ var sum = 0;
+ for ( let i=0 ; i < iterations ; i++ )
+ sum += new g(...a);
+ return sum;
+}
+
+function time(k, t) {
+ var then = Date.now();
+ assertEq(t(), iterations*k);
+ var now = Date.now();
+ return now - then;
+}
+
+function p(v) {
+ // Uncomment to see timings
+ // print(v);
+}
+
+f(make(200));
+
+// There is currently a cutoff after 375 where we bailout in order to avoid
+// handling very large stack frames. This slows the operation down by a factor
+// of 100 or so.
+
+p(time(374, () => f(make(374))));
+p(time(375, () => f(make(375))));
+p(time(376, () => f(make(376))));
+p(time(377, () => f(make(377))));
diff --git a/js/src/jit-test/tests/arrays/std_Array-prototype.js b/js/src/jit-test/tests/arrays/std_Array-prototype.js
new file mode 100644
index 0000000000..89ebde5d00
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/std_Array-prototype.js
@@ -0,0 +1,6 @@
+Object.prototype.prototype = {};
+assertEq(Object.getPrototypeOf([].concat()), Array.prototype);
+assertEq(Object.getPrototypeOf([].map(x => x)), Array.prototype);
+assertEq(Object.getPrototypeOf([].filter(x => x)), Array.prototype);
+assertEq(Object.getPrototypeOf([].slice()), Array.prototype);
+assertEq(Object.getPrototypeOf([].splice()), Array.prototype);
diff --git a/js/src/jit-test/tests/arrays/to-spliced-dense-elements.js b/js/src/jit-test/tests/arrays/to-spliced-dense-elements.js
new file mode 100644
index 0000000000..fa8749c85c
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/to-spliced-dense-elements.js
@@ -0,0 +1,13 @@
+// |jit-test| --enable-change-array-by-copy
+
+for (let i = 0; i < 1000; ++i) {
+ let arr = [0];
+ let result = arr.toSpliced(0, 0, 1, 2, 3);
+ assertEq(result.length, 4);
+}
+
+for (let i = 0; i < 1000; ++i) {
+ let arr = [0];
+ let result = arr.toSpliced(1, 0, 1, 2, 3);
+ assertEq(result.length, 4);
+}
diff --git a/js/src/jit-test/tests/arrays/too-long-array-splice.js b/js/src/jit-test/tests/arrays/too-long-array-splice.js
new file mode 100644
index 0000000000..d691cc929f
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/too-long-array-splice.js
@@ -0,0 +1,10 @@
+// |jit-test| allow-oom
+// array.splice should throw if array.length is too large.
+
+var length = 4294967295;
+var array = new Array(length);
+
+// Disable any fast paths by adding an indexed property on the prototype chain.
+Array.prototype[0] = 0;
+
+array.splice(100);
diff --git a/js/src/jit-test/tests/arrays/unshift-nonwritable-length.js b/js/src/jit-test/tests/arrays/unshift-nonwritable-length.js
new file mode 100644
index 0000000000..db95c5f2ef
--- /dev/null
+++ b/js/src/jit-test/tests/arrays/unshift-nonwritable-length.js
@@ -0,0 +1,61 @@
+load(libdir + "asserts.js");
+
+function f(arr)
+{
+ assertEq(arr.unshift(3, 5, 7, 9), 8); // if it doesn't throw :-)
+}
+
+var N = 100;
+
+function test(out)
+{
+ // Create an array of arrays, to be iterated over for [].unshift-calling. We
+ // can't just loop on unshift on a single array with non-writable length
+ // because unshift throws when called on an array with non-writable length.
+ var arrs = out.arrs = [];
+ for (var i = 0; i < N; i++)
+ arrs.push([0, 1, 2, 3]);
+
+ // Use a much-greater capacity than the eventual non-writable length, just for
+ // variability.
+ var a = [0, 1, 2, 3, 4, 5, 6, 7];
+ Object.defineProperty(a, "length", { writable: false, value: 4 });
+
+ arrs.push(a);
+
+ for (var i = 0, sz = arrs.length; i < sz; i++)
+ f(arrs[i]);
+}
+
+var obj = {};
+assertThrowsInstanceOf(function() { test(obj); }, TypeError);
+
+var arrs = obj.arrs;
+assertEq(arrs.length, N + 1);
+for (var i = 0; i < N; i++)
+{
+ assertEq(arrs[i].length, 8, "unexpected length for arrs[" + i + "]");
+ assertEq(arrs[i][0], 3, "bad element for arrs[" + i + "][0]");
+ assertEq(arrs[i][1], 5, "bad element for arrs[" + i + "][1]");
+ assertEq(arrs[i][2], 7, "bad element for arrs[" + i + "][2]");
+ assertEq(arrs[i][3], 9, "bad element for arrs[" + i + "][3]");
+ assertEq(arrs[i][4], 0, "bad element for arrs[" + i + "][4]");
+ assertEq(arrs[i][5], 1, "bad element for arrs[" + i + "][5]");
+ assertEq(arrs[i][6], 2, "bad element for arrs[" + i + "][6]");
+ assertEq(arrs[i][7], 3, "bad element for arrs[" + i + "][7]");
+}
+
+var a = arrs[N];
+assertEq(a[0], 0, "bad element for a[0]");
+assertEq(a[1], 1, "bad element for a[1]");
+assertEq(a[2], 2, "bad element for a[2]");
+assertEq(a[3], 3, "bad element for a[3]");
+assertEq(a.hasOwnProperty(4), false, "shouldn't have added any elements");
+assertEq(a[4], undefined);
+assertEq(a.hasOwnProperty(5), false, "shouldn't have added any elements");
+assertEq(a[5], undefined);
+assertEq(a.hasOwnProperty(6), false, "shouldn't have added any elements");
+assertEq(a[6], undefined);
+assertEq(a.hasOwnProperty(7), false, "shouldn't have added any elements");
+assertEq(a[7], undefined);
+assertEq(a.length, 4, "length shouldn't have been changed");