diff options
Diffstat (limited to 'js/src/tests/ecma_6/extensions')
17 files changed, 1096 insertions, 0 deletions
diff --git a/js/src/tests/ecma_6/extensions/ArrayBuffer-slice-arguments-detaching.js b/js/src/tests/ecma_6/extensions/ArrayBuffer-slice-arguments-detaching.js new file mode 100644 index 000000000..1ff5c1ad5 --- /dev/null +++ b/js/src/tests/ecma_6/extensions/ArrayBuffer-slice-arguments-detaching.js @@ -0,0 +1,81 @@ +// |reftest| skip-if(!xulRuntime.shell) -- needs detachArrayBuffer() +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var gTestfile = "ArrayBuffer-slice-arguments-detaching.js"; +//----------------------------------------------------------------------------- +var BUGNUMBER = 991981; +var summary = + "ArrayBuffer.prototype.slice shouldn't misbehave horribly if " + + "index-argument conversion detaches the ArrayBuffer being sliced"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +function testStart() +{ + var ab = new ArrayBuffer(0x1000); + + var start = + { + valueOf: function() + { + detachArrayBuffer(ab); + gc(); + return 0x800; + } + }; + + var ok = false; + try + { + ab.slice(start); + } + catch (e) + { + ok = true; + } + assertEq(ok, true, "start weirdness should have thrown"); + assertEq(ab.byteLength, 0, "detaching should work for start weirdness"); +} +testStart(); + +function testEnd() +{ + var ab = new ArrayBuffer(0x1000); + + var end = + { + valueOf: function() + { + detachArrayBuffer(ab); + gc(); + return 0x1000; + } + }; + + var ok = false; + try + { + ab.slice(0x800, end); + } + catch (e) + { + ok = true; + } + assertEq(ok, true, "byteLength weirdness should have thrown"); + assertEq(ab.byteLength, 0, "detaching should work for byteLength weirdness"); +} +testEnd(); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/extensions/DataView-construct-arguments-detaching.js b/js/src/tests/ecma_6/extensions/DataView-construct-arguments-detaching.js new file mode 100644 index 000000000..14659f1d2 --- /dev/null +++ b/js/src/tests/ecma_6/extensions/DataView-construct-arguments-detaching.js @@ -0,0 +1,81 @@ +// |reftest| skip-if(!xulRuntime.shell) -- needs detachArrayBuffer() +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var gTestfile = "DataView-construct-arguments-detaching.js"; +//----------------------------------------------------------------------------- +var BUGNUMBER = 991981; +var summary = + "new DataView(...) shouldn't misbehave horribly if index-argument " + + "conversion detaches the ArrayBuffer to be viewed"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +function testByteOffset() +{ + var ab = new ArrayBuffer(0x1000); + + var start = + { + valueOf: function() + { + detachArrayBuffer(ab); + gc(); + return 0x800; + } + }; + + var ok = false; + try + { + new DataView(ab, start); + } + catch (e) + { + ok = true; + } + assertEq(ok, true, "byteOffset weirdness should have thrown"); + assertEq(ab.byteLength, 0, "detaching should work for byteOffset weirdness"); +} +testByteOffset(); + +function testByteLength() +{ + var ab = new ArrayBuffer(0x1000); + + var len = + { + valueOf: function() + { + detachArrayBuffer(ab); + gc(); + return 0x800; + } + }; + + var ok = false; + try + { + new DataView(ab, 0x800, len); + } + catch (e) + { + ok = true; + } + assertEq(ok, true, "byteLength weirdness should have thrown"); + assertEq(ab.byteLength, 0, "detaching should work for byteLength weirdness"); +} +testByteLength(); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/extensions/DataView-set-arguments-detaching.js b/js/src/tests/ecma_6/extensions/DataView-set-arguments-detaching.js new file mode 100644 index 000000000..b05ec480d --- /dev/null +++ b/js/src/tests/ecma_6/extensions/DataView-set-arguments-detaching.js @@ -0,0 +1,85 @@ +// |reftest| skip-if(!xulRuntime.shell) -- needs detachArrayBuffer() +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var gTestfile = "DataView-set-arguments-detaching.js"; +//----------------------------------------------------------------------------- +var BUGNUMBER = 991981; +var summary = + "DataView.prototype.set* methods shouldn't misbehave horribly if " + + "index-argument conversion detaches the ArrayBuffer being modified"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +function testIndex() +{ + var ab = new ArrayBuffer(0x1000); + + var dv = new DataView(ab); + + var start = + { + valueOf: function() + { + detachArrayBuffer(ab); + gc(); + return 0xFFF; + } + }; + + var ok = false; + try + { + dv.setUint8(start, 0x42); + } + catch (e) + { + ok = true; + } + assertEq(ok, true, "should have thrown"); + assertEq(ab.byteLength, 0, "should have been detached correctly"); +} +testIndex(); + +function testValue() +{ + var ab = new ArrayBuffer(0x100000); + + var dv = new DataView(ab); + + var value = + { + valueOf: function() + { + detachArrayBuffer(ab); + gc(); + return 0x42; + } + }; + + var ok = false; + try + { + dv.setUint8(0xFFFFF, value); + } + catch (e) + { + ok = true; + } + assertEq(ok, true, "should have thrown"); + assertEq(ab.byteLength, 0, "should have been detached correctly"); +} +testValue(); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/extensions/RegExp-replace-lastParen.js b/js/src/tests/ecma_6/extensions/RegExp-replace-lastParen.js new file mode 100644 index 000000000..d06bfe7cd --- /dev/null +++ b/js/src/tests/ecma_6/extensions/RegExp-replace-lastParen.js @@ -0,0 +1,12 @@ +var BUGNUMBER = 1263118; +var summary = "RegExp.prototype[@@replace] with non-standard $+ substitution."; + +print(BUGNUMBER + ": " + summary); + +assertEq(/(a)(b)(c)/[Symbol.replace]("abc", "[$+]"), "[c]"); +assertEq(/(a)(b)c/[Symbol.replace]("abc", "[$+]"), "[b]"); +assertEq(/(a)bc/[Symbol.replace]("abc", "[$+]"), "[a]"); +assertEq(/abc/[Symbol.replace]("abc", "[$+]"), "[]"); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/extensions/String-match-flags.js b/js/src/tests/ecma_6/extensions/String-match-flags.js new file mode 100644 index 000000000..b1a382fdf --- /dev/null +++ b/js/src/tests/ecma_6/extensions/String-match-flags.js @@ -0,0 +1,27 @@ +var BUGNUMBER = 1263139; +var summary = "String.prototype.match with non-string non-standard flags argument."; + +print(BUGNUMBER + ": " + summary); + +var called; +var flags = { + toString() { + called = true; + return ""; + } +}; + +called = false; +"a".match("a", flags); +assertEq(called, false); + +called = false; +"a".search("a", flags); +assertEq(called, false); + +called = false; +"a".replace("a", "b", flags); +assertEq(called, false); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/extensions/TypedArray-set-object-funky-length-detaches.js b/js/src/tests/ecma_6/extensions/TypedArray-set-object-funky-length-detaches.js new file mode 100644 index 000000000..7379bf9a4 --- /dev/null +++ b/js/src/tests/ecma_6/extensions/TypedArray-set-object-funky-length-detaches.js @@ -0,0 +1,66 @@ +// |reftest| skip-if(!xulRuntime.shell) -- needs detachArrayBuffer() +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var gTestfile = "set-object-funky-length-detaches.js"; +//----------------------------------------------------------------------------- +var BUGNUMBER = 991981; +var summary = + "%TypedArray%.prototype.set(object w/funky length property, offset) " + + "shouldn't misbehave if the funky length property detaches this typed " + + "array's buffer"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var ctors = [Int8Array, Uint8Array, Uint8ClampedArray, + Int16Array, Uint16Array, + Int32Array, Uint32Array, + Float32Array, Float64Array]; +ctors.forEach(function(TypedArray) { + var buf = new ArrayBuffer(512 * 1024); + var ta = new TypedArray(buf); + + var arraylike = + { + 0: 17, + 1: 42, + 2: 3, + 3: 99, + 4: 37, + 5: 9, + 6: 72, + 7: 31, + 8: 22, + 9: 0, + get length() + { + detachArrayBuffer(buf); + return 10; + } + }; + + var passed = false; + try + { + ta.set(arraylike, 0x1234); + } + catch (e) + { + passed = true; + } + + assertEq(passed, true); +}); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/extensions/TypedArray-subarray-arguments-detaching.js b/js/src/tests/ecma_6/extensions/TypedArray-subarray-arguments-detaching.js new file mode 100644 index 000000000..a6349657c --- /dev/null +++ b/js/src/tests/ecma_6/extensions/TypedArray-subarray-arguments-detaching.js @@ -0,0 +1,112 @@ +// |reftest| skip-if(!xulRuntime.shell) -- needs detachArrayBuffer() +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var gTestfile = "TypedArray-subarray-arguments-detaching.js"; +//----------------------------------------------------------------------------- +var BUGNUMBER = 991981; +var summary = + "%TypedArray.prototype.subarray shouldn't misbehave horribly if " + + "index-argument conversion detaches the underlying ArrayBuffer"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +function testBegin() +{ + var ab = new ArrayBuffer(0x1000); + + var begin = + { + valueOf: function() + { + detachArrayBuffer(ab); + return 0x800; + } + }; + + var ta = new Uint8Array(ab); + + var ok = false; + try + { + ta.subarray(begin); + } + catch (e) + { + ok = true; + } + assertEq(ok, true, "start weirdness should have thrown"); + assertEq(ab.byteLength, 0, "detaching should work for start weirdness"); +} +testBegin(); + +function testBeginWithEnd() +{ + var ab = new ArrayBuffer(0x1000); + + var begin = + { + valueOf: function() + { + detachArrayBuffer(ab); + return 0x800; + } + }; + + var ta = new Uint8Array(ab); + + var ok = false; + try + { + ta.subarray(begin, 0x1000); + } + catch (e) + { + ok = true; + } + assertEq(ok, true, "start weirdness should have thrown"); + assertEq(ab.byteLength, 0, "detaching should work for start weirdness"); +} +testBeginWithEnd(); + +function testEnd() +{ + var ab = new ArrayBuffer(0x1000); + + var end = + { + valueOf: function() + { + detachArrayBuffer(ab); + return 0x1000; + } + }; + + var ta = new Uint8Array(ab); + + var ok = false; + try + { + ta.subarray(0x800, end); + } + catch (e) + { + ok = true; + } + assertEq(ok, true, "start weirdness should have thrown"); + assertEq(ab.byteLength, 0, "detaching should work for start weirdness"); +} +testEnd(); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/extensions/array-isArray-proxy-recursion.js b/js/src/tests/ecma_6/extensions/array-isArray-proxy-recursion.js new file mode 100644 index 000000000..ca2907a99 --- /dev/null +++ b/js/src/tests/ecma_6/extensions/array-isArray-proxy-recursion.js @@ -0,0 +1,41 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 1282047; +var summary = 'Infinite recursion via Array.isArray on a proxy'; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var proxy = Proxy.revocable([], {}).proxy; + +// A depth of 100000 ought to be enough for any platform to consume its entire +// stack, hopefully without making any recalcitrant platforms time out. If no +// timeout happens, the assertEq checks for the proper expected value. +for (var i = 0; i < 1e5; i++) + proxy = new Proxy(proxy, {}); + +try +{ + assertEq(Array.isArray(proxy), true); + + // If we reach here, it's cool, we just didn't consume the entire stack. +} +catch (e) +{ + assertEq(e instanceof InternalError, true, + "should have thrown for over-recursion"); +} + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/extensions/browser.js b/js/src/tests/ecma_6/extensions/browser.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/js/src/tests/ecma_6/extensions/browser.js diff --git a/js/src/tests/ecma_6/extensions/element-setting-ToNumber-detaches.js b/js/src/tests/ecma_6/extensions/element-setting-ToNumber-detaches.js new file mode 100644 index 000000000..82e0c0d87 --- /dev/null +++ b/js/src/tests/ecma_6/extensions/element-setting-ToNumber-detaches.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!xulRuntime.shell) -- needs detachArrayBuffer() +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ +"use strict"; // make test fail when limitation below is fixed + +var gTestfile = 'element-setting-ToNumber-detaches.js'; +//----------------------------------------------------------------------------- +var BUGNUMBER = 1001547; +var summary = + "Don't assert assigning into memory detached while converting the value to " + + "assign into a number"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +// Technically per current spec the element-sets should throw in strict mode, +// but we just silently do nothing for now, somewhat due to limitations of our +// internal MOP (which can't easily say "try this special behavior, else fall +// back on normal logic"), somewhat because it's consistent with current +// behavior (as of this test's addition) for out-of-bounds sets. + +var ab = new ArrayBuffer(64); +var ta = new Uint32Array(ab); +ta[4] = { valueOf() { detachArrayBuffer(ab); return 5; } }; + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/extensions/for-loop-with-lexical-declaration-and-nested-function-statement.js b/js/src/tests/ecma_6/extensions/for-loop-with-lexical-declaration-and-nested-function-statement.js new file mode 100644 index 000000000..9f6fd6467 --- /dev/null +++ b/js/src/tests/ecma_6/extensions/for-loop-with-lexical-declaration-and-nested-function-statement.js @@ -0,0 +1,130 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var gTestfile = + "for-loop-with-lexical-declaration-and-nested-function-statement.js"; +//----------------------------------------------------------------------------- +var BUGNUMBER = 1149797; +var summary = + "Don't assert when freshening the scope chain for a for-loop whose head " + + "contains a lexical declaration, where the loop body might add more " + + "bindings at runtime"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +for (let x = 0; x < 9; ++x) { + function q1() {} +} + +{ + for (let x = 0; x < 9; ++x) { + function q2() {} + } +} + +function f1() +{ + for (let x = 0; x < 9; ++x) { + function q3() {} + } +} +f1(); + +function f2() +{ + { + for (let x = 0; x < 9; ++x) { + function q4() {} + } + } +} +f2(); + +for (let x = 0; x < 9; ++x) +{ + // deliberately inside a block statement + function q5() {} +} + +{ + for (let x = 0; x < 9; ++x) + { + // deliberately inside a block statement + function q6() {} + } +} + +function g1() +{ + for (let x = 0; x < 9; ++x) + { + // deliberately inside a block statement + function q7() {} + } +} +g1(); + +function g2() +{ + { + for (let x = 0; x < 9; ++x) + { + // deliberately inside a block statement + function q8() {} + } + } +} +g2(); + +for (let x = 0; x < 9; ++x) { + (function() { + eval("function q9() {}"); + })(); +} + +{ + for (let x = 0; x < 9; ++x) + { + // deliberately inside a block statement + (function() { + eval("function q10() {}"); + })(); + } +} + +function h1() +{ + for (let x = 0; x < 9; ++x) + { + // deliberately inside a block statement + (function() { + eval("function q11() {}"); + })(); + } +} +h1(); + +function h2() +{ + { + for (let x = 0; x < 9; ++x) + { + // deliberately inside a block statement + (function() { eval("function q12() {}"); })(); + } + } +} +h2(); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/extensions/keyword-unescaped-requirement-modules.js b/js/src/tests/ecma_6/extensions/keyword-unescaped-requirement-modules.js new file mode 100644 index 000000000..260948cfe --- /dev/null +++ b/js/src/tests/ecma_6/extensions/keyword-unescaped-requirement-modules.js @@ -0,0 +1,99 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 1204027; +var summary = + "Escape sequences aren't allowed in bolded grammar tokens (that is, in " + + "keywords, possibly contextual keywords)"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var badModules = + [ + "\\u0069mport f from 'g'", + "i\\u006dport g from 'h'", + "import * \\u0061s foo", + "import {} fro\\u006d 'bar'", + "import { x \\u0061s y } from 'baz'", + + "\\u0065xport function f() {}", + "e\\u0078port function g() {}", + "export * fro\\u006d 'fnord'", + "export d\\u0065fault var x = 3;", + "export { q } fro\\u006d 'qSupplier';", + + ]; + +if (typeof parseModule === "function") +{ + for (var module of badModules) + { + assertThrowsInstanceOf(() => parseModule(module), SyntaxError, + "bad behavior for: " + module); + } +} + +if (typeof Reflect.parse === "function") +{ + var twoStatementAST = + Reflect.parse(`let x = 0; + export { x } /* ASI should trigger here */ + fro\\u006D`, + { target: "module" }); + + var statements = twoStatementAST.body; + assertEq(statements.length, 3, + "should have two items in the module, not one ExportDeclaration"); + assertEq(statements[0].type, "VariableDeclaration"); + assertEq(statements[1].type, "ExportDeclaration"); + assertEq(statements[2].type, "ExpressionStatement"); + assertEq(statements[2].expression.name, "from"); + + var oneStatementAST = + Reflect.parse(`export { x } /* no ASI here */ + from 'foo'`, + { target: "module" }); + + assertEq(oneStatementAST.body.length, 1); + assertEq(oneStatementAST.body[0].type, "ExportDeclaration"); + + twoStatementAST = + Reflect.parse(`export { x } from "bar" + /bar/g`, + { target: "module" }); + + statements = twoStatementAST.body; + assertEq(statements.length, 2, + "should have two items in the module, not one ExportDeclaration"); + assertEq(statements[0].type, "ExportDeclaration"); + assertEq(statements[1].type, "ExpressionStatement"); + assertEq(statements[1].expression.type, "Literal"); + assertEq(statements[1].expression.value.toString(), "/bar/g"); + + twoStatementAST = + Reflect.parse(`export * from "bar" + /bar/g`, + { target: "module" }); + + statements = twoStatementAST.body; + assertEq(statements.length, 2, + "should have two items in the module, not one ExportDeclaration"); + assertEq(statements[0].type, "ExportDeclaration"); + assertEq(statements[1].type, "ExpressionStatement"); + assertEq(statements[1].expression.type, "Literal"); + assertEq(statements[1].expression.value.toString(), "/bar/g"); +} + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/extensions/keyword-unescaped-requirement.js b/js/src/tests/ecma_6/extensions/keyword-unescaped-requirement.js new file mode 100644 index 000000000..20d3555e3 --- /dev/null +++ b/js/src/tests/ecma_6/extensions/keyword-unescaped-requirement.js @@ -0,0 +1,43 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 1204027; +var summary = + "Escape sequences aren't allowed in bolded grammar tokens (that is, in " + + "keywords, possibly contextual keywords)"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var randomExtensions = + [ + "for \\u0065ach (var x in []);", + "for e\\u0061ch (var x in []);", + "[0 for \\u0065ach (var x in [])]", + "[0 for e\\u0061ch (var x in [])]", + "(0 for \\u0065ach (var x in []))", + "(0 for e\\u0061ch (var x in []))", + + // Soon to be not an extension, maybe... + "(for (x \\u006ff [1]) x)", + "(for (x o\\u0066 [1]) x)", + ]; + +for (var extension of randomExtensions) +{ + assertThrowsInstanceOf(() => Function(extension), SyntaxError, + "bad behavior for: " + extension); +} + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/extensions/new-cross-compartment.js b/js/src/tests/ecma_6/extensions/new-cross-compartment.js new file mode 100644 index 000000000..5df437520 --- /dev/null +++ b/js/src/tests/ecma_6/extensions/new-cross-compartment.js @@ -0,0 +1,42 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 1178653; +var summary = + "|new| on a cross-compartment wrapper to a non-constructor shouldn't assert"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var g = newGlobal(); + +var otherStr = new g.String("foo"); +assertEq(otherStr instanceof g.String, true); +assertEq(otherStr.valueOf(), "foo"); + +// THIS IS WRONG. |new| itself should throw if !IsConstructor(constructor), +// meaning this global's TypeError should be used. The problem ultimately is +// that wrappers conflate callable/constructible, so any old function from +// another global appears to be both. Somebody fix bug XXXXXX! +try +{ + var constructor = g.parseInt; + new constructor(); + throw new Error("no error thrown"); +} +catch (e) +{ + assertEq(e instanceof g.TypeError, true, + "THIS REALLY SHOULD BE |e instanceof TypeError|"); +} + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/extensions/reentrant-RegExp-creation-and-gc-during-new-RegExp-pattern-ToString.js b/js/src/tests/ecma_6/extensions/reentrant-RegExp-creation-and-gc-during-new-RegExp-pattern-ToString.js new file mode 100644 index 000000000..0ec0b493e --- /dev/null +++ b/js/src/tests/ecma_6/extensions/reentrant-RegExp-creation-and-gc-during-new-RegExp-pattern-ToString.js @@ -0,0 +1,41 @@ +// |reftest| skip-if(!xulRuntime.shell) -- needs gc (newGlobal/evaluate are shimmed) +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var gTestfile = + "reentrant-RegExp-creation-and-gc-during-new-RegExp-pattern-ToString.js"; +//----------------------------------------------------------------------------- +var BUGNUMBER = 1253099; +var summary = + "Don't assert when, in |new RegExp(pat)|, stringifying |pat| creates " + + "another RegExp and then performs a GC"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +// The fresh global object is required to ensure that the outer |new RegExp| +// is the first RegExp created in the global (other than RegExp.prototype). +newGlobal().evaluate(` +var createsRegExpAndCallsGCWhenStringified = + { + toString: function() { + new RegExp("a"); + gc(); + return "q"; + } + }; + +assertEq(new RegExp(createsRegExpAndCallsGCWhenStringified).source, "q"); +`); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/extensions/setImmutablePrototype.js b/js/src/tests/ecma_6/extensions/setImmutablePrototype.js new file mode 100644 index 000000000..9226dcce2 --- /dev/null +++ b/js/src/tests/ecma_6/extensions/setImmutablePrototype.js @@ -0,0 +1,195 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +var gTestfile = "setImmutablePrototype.js"; +//----------------------------------------------------------------------------- +var BUGNUMBER = 1052139; +var summary = + "Implement JSAPI and a shell function to prevent modifying an extensible " + + "object's [[Prototype]]"; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +if (typeof evaluate !== "function") +{ + // Not totally faithful semantics, but approximately close enough for this + // test's purposes. + evaluate = eval; +} + +var usingRealSetImmutablePrototype = true; + +if (typeof setImmutablePrototype !== "function") +{ + usingRealSetImmutablePrototype = false; + + if (typeof SpecialPowers !== "undefined") + { + setImmutablePrototype = + SpecialPowers.Cu.getJSTestingFunctions().setImmutablePrototype; + } +} + +if (typeof wrap !== "function") +{ + // good enough + wrap = function(x) { return x; }; +} + +function setViaProtoSetter(obj, newProto) +{ + var setter = + Object.getOwnPropertyDescriptor(Object.prototype, "__proto__").set; + setter.call(obj, newProto); +} + +function checkPrototypeMutationFailure(obj, desc) +{ + var initialProto = Object.getPrototypeOf(obj); + + // disconnected from any [[Prototype]] chains for use on any object at all + var newProto = Object.create(null); + + function tryMutate(func, method) + { + try + { + func(obj, newProto); + throw new Error(desc + ": no error thrown, prototype " + + (Object.getPrototypeOf(obj) === initialProto + ? "wasn't" + : "was") + + " changed"); + } + catch (e) + { + // Note: This is always a TypeError from *this* global object, because + // Object.setPrototypeOf and the __proto__ setter come from *this* + // global object. + assertEq(e instanceof TypeError, true, + desc + ": should have thrown TypeError setting [[Prototype]] " + + "via " + method + ", got " + e); + assertEq(Object.getPrototypeOf(obj), initialProto, + desc + ": shouldn't observe [[Prototype]] change"); + } + } + + tryMutate(Object.setPrototypeOf, "Object.setPrototypeOf"); + tryMutate(setViaProtoSetter, "__proto__ setter"); +} + +function runNormalTests(global) +{ + if (typeof setImmutablePrototype !== "function") + { + print("no testable setImmutablePrototype function available, skipping tests"); + return; + } + + // regular old object, non-null [[Prototype]] + + var emptyLiteral = global.evaluate("({})"); + assertEq(setImmutablePrototype(emptyLiteral), true); + checkPrototypeMutationFailure(emptyLiteral, "empty literal"); + + // regular old object, null [[Prototype]] + + var nullProto = global.Object.create(null); + assertEq(setImmutablePrototype(nullProto), true); + checkPrototypeMutationFailure(nullProto, "nullProto"); + + // Shocker: SpecialPowers's little mind doesn't understand proxies. Abort. + if (!usingRealSetImmutablePrototype) + return; + + // direct proxies + + var emptyTarget = global.evaluate("({})"); + var directProxy = new global.Proxy(emptyTarget, {}); + assertEq(setImmutablePrototype(directProxy), true); + checkPrototypeMutationFailure(directProxy, "direct proxy to empty target"); + checkPrototypeMutationFailure(emptyTarget, "empty target"); + + var anotherTarget = global.evaluate("({})"); + var anotherDirectProxy = new global.Proxy(anotherTarget, {}); + assertEq(setImmutablePrototype(anotherTarget), true); + checkPrototypeMutationFailure(anotherDirectProxy, "another direct proxy to empty target"); + checkPrototypeMutationFailure(anotherTarget, "another empty target"); + + var nestedTarget = global.evaluate("({})"); + var nestedProxy = new global.Proxy(new Proxy(nestedTarget, {}), {}); + assertEq(setImmutablePrototype(nestedProxy), true); + checkPrototypeMutationFailure(nestedProxy, "nested proxy to empty target"); + checkPrototypeMutationFailure(nestedTarget, "nested target"); + + // revocable proxies + + var revocableTarget = global.evaluate("({})"); + var revocable = global.Proxy.revocable(revocableTarget, {}); + assertEq(setImmutablePrototype(revocable.proxy), true); + checkPrototypeMutationFailure(revocableTarget, "revocable target"); + checkPrototypeMutationFailure(revocable.proxy, "revocable proxy"); + + assertEq(revocable.revoke(), undefined); + try + { + setImmutablePrototype(revocable.proxy); + throw new Error("expected to throw on revoked proxy"); + } + catch (e) + { + // Note: This is a TypeError from |global|, because the proxy's + // |setImmutablePrototype| method is what actually throws here. + // (Usually the method simply sets |*succeeded| to false and the + // caller handles or throws as needed after that. But not here.) + assertEq(e instanceof global.TypeError, true, + "expected TypeError, instead threw " + e); + } + + var anotherRevocableTarget = global.evaluate("({})"); + assertEq(setImmutablePrototype(anotherRevocableTarget), true); + checkPrototypeMutationFailure(anotherRevocableTarget, "another revocable target"); + + var anotherRevocable = global.Proxy.revocable(anotherRevocableTarget, {}); + checkPrototypeMutationFailure(anotherRevocable.proxy, "another revocable target"); + + assertEq(anotherRevocable.revoke(), undefined); + try + { + var rv = setImmutablePrototype(anotherRevocable.proxy); + throw new Error("expected to throw on another revoked proxy, returned " + rv); + } + catch (e) + { + // NOTE: Again from |global|, as above. + assertEq(e instanceof global.TypeError, true, + "expected TypeError, instead threw " + e); + } +} + +var global = this; +runNormalTests(global); // same-global + +if (typeof newGlobal === "function") +{ + var otherGlobal = newGlobal(); + var subsumingNothing = newGlobal({ principal: 0 }); + var subsumingEverything = newGlobal({ principal: ~0 }); + + runNormalTests(otherGlobal); // cross-global + runNormalTests(subsumingNothing); + runNormalTests(subsumingEverything); +} + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_6/extensions/shell.js b/js/src/tests/ecma_6/extensions/shell.js new file mode 100644 index 000000000..4d731295d --- /dev/null +++ b/js/src/tests/ecma_6/extensions/shell.js @@ -0,0 +1,5 @@ +// NOTE: This only turns on 1.8.5 in shell builds. The browser requires the +// futzing in js/src/tests/browser.js (which only turns on 1.8, the most +// the browser supports). +if (typeof version != 'undefined') + version(185); |