diff options
Diffstat (limited to '')
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"); |