summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/basic/expression-autopsy.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit-test/tests/basic/expression-autopsy.js')
-rw-r--r--js/src/jit-test/tests/basic/expression-autopsy.js286
1 files changed, 286 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/basic/expression-autopsy.js b/js/src/jit-test/tests/basic/expression-autopsy.js
new file mode 100644
index 0000000000..bbdcaf8bea
--- /dev/null
+++ b/js/src/jit-test/tests/basic/expression-autopsy.js
@@ -0,0 +1,286 @@
+load(libdir + "asserts.js");
+load(libdir + "iteration.js");
+
+function check_one(expected, f, err) {
+ var failed = true;
+ try {
+ f();
+ failed = false;
+ } catch (ex) {
+ assertEq(ex.constructor.name, "TypeError");
+ var s = ex.message;
+ assertEq(s.slice(-err.length), err);
+ assertEq(s.slice(-(err.length + expected.length), -err.length), expected);
+ }
+ if (!failed)
+ throw new Error("didn't fail");
+}
+ieval = eval;
+function check(expr, expected=expr, testStrict=true) {
+ var end, err;
+ for ([end, err] of [[".random_prop", " is undefined"], ["()", " is not a function"]]) {
+ var statement = "o = {};" + expr + end, f;
+ var cases = [
+ // Global scope
+ function () {
+ ieval("var o, undef;\n" + statement);
+ },
+ // Function scope
+ Function("o", "undef", statement),
+ // Function scope with variables
+ Function("var o, undef;\n" + statement),
+ // Function scope with some different arugments
+ Function("arg1", "arg2", "var o, undef;\n" + statement),
+ // Deoptimized function scope
+ Function("o", "undef", "with (Object) {}\n" + statement),
+ // Inside with
+ Function("with (Object) { " + statement + " }"),
+ // Closure
+ Function("o", "undef", "function myfunc() { return o + undef; }\n" + statement),
+ // Let definitions in a block
+ Function("{ let o, undef;\n" + statement + "}"),
+ // Let in a switch
+ Function("var x = 4; switch (x) { case 4: let o, undef;" + statement + "\ncase 6: break;}"),
+ // Try-catch blocks
+ Function("o", "undef", "try { let q = 4; try { let p = 4; } catch (e) {} } catch (e) {} { let o, undef; " + statement + " }"),
+ // Let in for-in (uses with to prevent jit compilation: bug 942804, bug 831120 and bug 1041586)
+ Function("with ({}) {} var undef, o; for (let z in [1, 2]) { " + statement + " }"),
+ ];
+
+ if (testStrict) {
+ // Strict mode.
+ cases.push(Function("o", "undef", "\"use strict\";\n" + statement));
+ }
+
+ for (var f of cases) {
+ check_one(expected, f, err);
+ }
+ }
+}
+
+check("undef");
+check("o.b");
+check("o.length");
+check("o[true]");
+check("o[false]");
+check("o[null]");
+check("o[0]");
+check("o[1]");
+check("o[3]");
+check("o[256]");
+check("o[65536]");
+check("o[268435455]");
+check("o['1.1']");
+check("o[4 + 'h']", "o['4h']");
+check("ieval(undef)", "ieval(...)");
+check("ieval.call()", "ieval.call()");
+check("ieval(...[])", "ieval(...)");
+check("ieval(...[undef])", "ieval(...)");
+check("ieval(...[undef, undef])", "ieval(...)");
+check("(o[0] = 4).foo", "o[0].foo");
+// NOTE: This one produces different output in strict mode since "this" is
+// undefined in that case.
+check("this.x", "this.x", false);
+
+for (let tok of ["|", "^", "&", "==", "!==", "===", "!==", "<", "<=", ">", ">=",
+ ">>", "<<", ">>>", "+", "-", "*", "/", "%"]) {
+ check("o[(undef " + tok + " 4)]");
+}
+
+check("o[(!o)]");
+check("o[(~o)]");
+check("o[(+ o)]");
+check("o[(- o)]");
+
+check("o[(!(o + 1))]");
+check("o[(~(o + 1))]");
+check("o[(+ (o + 1))]");
+check("o[(- (o + 1))]");
+
+// A few one off tests
+check_one("6", (function () { 6() }), " is not a function");
+check_one("4", (function() { (4||eval)(); }), " is not a function");
+check_one("0", (function () { Array.prototype.reverse.call('123'); }), " is read-only");
+check_one("[...][Symbol.iterator]().next().value",
+ function () { ieval("{ let x; var [a, b, [c0, c1]] = [x, x, x]; }") }, " is undefined");
+check_one("(void 1)", function() { (void 1)(); }, " is not a function");
+check_one("(void o[1])", function() { var o = []; (void o[1])() }, " is not a function");
+
+check_one("(typeof 1)", function() { (typeof 1)(); }, " is not a function");
+check_one("(typeof o[1])", function() { var o = []; (typeof o[1])() }, " is not a function");
+
+check_one("(delete foo)",
+ function() { (delete foo)(); },
+ " is not a function");
+check_one("(delete obj.foo)",
+ function() { var obj = {}; (delete obj.foo)(); },
+ " is not a function");
+check_one("(delete obj.foo)",
+ function() { "use strict"; var obj = {}; (delete obj.foo)(); },
+ " is not a function");
+check_one("(delete obj[y])",
+ function() { var obj = {}, y = {}; (delete obj[y])(); },
+ " is not a function");
+check_one("(delete obj[y])",
+ function() { "use strict"; var obj = {}, y = {}; (delete obj[y])(); },
+ " is not a function");
+
+check_one("foo.apply()",
+ function() { function foo() {} foo.apply()(); },
+ " is not a function");
+
+check_one("super()",
+ function() {
+ class X extends Object {
+ constructor() {
+ super()();
+ }
+ }
+ new X();
+ },
+ " is not a function");
+check_one("super(...)",
+ function() {
+ class X extends Object {
+ constructor() {
+ super(...[])();
+ }
+ }
+ new X();
+ },
+ " is not a function");
+
+check_one("super.a",
+ function() {
+ class X extends Object {
+ test() {
+ super.a();
+ }
+ }
+ var x = new X();
+ x.test();
+ },
+ " is not a function");
+
+check_one("super[a]",
+ function() {
+ var a = "a";
+ class X extends Object {
+ test() {
+ super[a]();
+ }
+ }
+ var x = new X();
+ x.test();
+ },
+ " is not a function");
+
+check_one("super.a()",
+ function() {
+ class Y {
+ a() {
+ return 5;
+ }
+ }
+
+ class X extends Y {
+ test() {
+ super.a()();
+ }
+ }
+
+ var x = new X();
+ x.test();
+ },
+ " is not a function");
+
+check_one("super[a]()",
+ function() {
+ class Y {
+ a() {
+ return 5;
+ }
+ }
+
+ var a = "a";
+ class X extends Y {
+ test() {
+ super[a]()();
+ }
+ }
+
+ var x = new X();
+ x.test();
+ },
+ " is not a function");
+
+check_one("super[1]",
+ function() {
+ class X extends Object {
+ foo() {
+ return super[1]();
+ }
+ }
+ new X().foo();
+ },
+ " is not a function");
+
+check_one("eval(...)",
+ function() { eval("")(); },
+ " is not a function");
+check_one("eval(...)",
+ function() { "use strict"; eval("")(); },
+ " is not a function");
+check_one("eval(...)",
+ function() { eval(...[""])(); },
+ " is not a function");
+check_one("eval(...)",
+ function() { "use strict"; eval(...[""])(); },
+ " is not a function");
+
+check_one("(new foo())",
+ function() { function foo() {}; new foo()(); },
+ " is not a function");
+check_one("(new foo(...))",
+ function() { function foo() {}; new foo(...[])(); },
+ " is not a function");
+check_one("(new foo.x())",
+ function() { var foo = { x: function() {} }; new foo.x()(); },
+ " is not a function");
+check_one("(new foo.x(...))",
+ function() { var foo = { x: function() {} }; new foo.x(...[])(); },
+ " is not a function");
+
+check_one("[...].foo",
+ function() { [undefined].foo(); },
+ " is not a function");
+check_one("[...].foo",
+ function() { [undefined, ...[]].foo(); },
+ " is not a function");
+
+check_one("[...][Symbol.iterator]().next().value",
+ function () { var [{x}] = [null, {}]; }, " is null");
+check_one("[...][Symbol.iterator]().next().value",
+ function () { var [{x}] = [void 0, {}]; }, " is undefined");
+
+check_one("(a += b)",
+ function() { var a, b; (a += b)(); },
+ " is not a function");
+
+try {
+ (function() {
+ "use strict";
+ var o = [];
+ Object.freeze(o);
+ o[0] = "foo";
+ }());
+ throw new Error("didn't throw");
+} catch (e) {
+ assertEq(e instanceof TypeError, true,
+ "expected TypeError, got " + e);
+ assertEq(e.message,
+ "can't define array index property past the end of an array with non-writable length");
+}
+
+// Check fallback behavior
+assertThrowsInstanceOf(function () { for (let x of undefined) {} }, TypeError);