Bug 952898 - String.prototype.startsWith and .endsWith should throw when called with a regexp as first argument. r=jwalden
authorTill Schneidereit <till@tillschneidereit.net>
Fri, 10 Jan 2014 15:19:05 +0100
changeset 162949 71bb7391184e7c3aa1b9c2c98dc39f5dc16b4f20
parent 162948 441af05d123b8795d84024323c34d6298adf4796
child 162950 d20c762cc1b6b00b0560baa06534fba8c7eee992
push id25975
push userryanvm@gmail.com
push dateFri, 10 Jan 2014 19:46:47 +0000
treeherderautoland@e89afc241513 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalden
bugs952898
milestone29.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 952898 - String.prototype.startsWith and .endsWith should throw when called with a regexp as first argument. r=jwalden
js/src/jit-test/tests/basic/string-endswith.js
js/src/jit-test/tests/basic/string-startswith.js
js/src/js.msg
js/src/jsstr.cpp
--- a/js/src/jit-test/tests/basic/string-endswith.js
+++ b/js/src/jit-test/tests/basic/string-endswith.js
@@ -1,39 +1,262 @@
-assertEq("abc".endsWith("abc"), true);
-assertEq("abcd".endsWith("bcd"), true);
-assertEq("abc".endsWith("c"), true);
-assertEq("abc".endsWith("abcd"), false);
-assertEq("abc".endsWith("bbc"), false);
-assertEq("abc".endsWith("b"), false);
-assertEq("abc".endsWith("abc", 3), true);
-assertEq("abc".endsWith("bc", 3), true);
-assertEq("abc".endsWith("a", 3), false);
-assertEq("abc".endsWith("bc", 3), true);
-assertEq("abc".endsWith("a", 1), true);
-assertEq("abc".endsWith("abc", 1), false);
-assertEq("abc".endsWith("b", 2), true);
-assertEq("abc".endsWith("d", 2), false);
-assertEq("abc".endsWith("dcd", 2), false);
-assertEq("abc".endsWith("a", 42), false);
-assertEq("abc".endsWith("bc", Infinity), true);
-assertEq("abc".endsWith("a", Infinity), false);
-assertEq("abc".endsWith("bc", undefined), true);
-assertEq("abc".endsWith("bc", -43), false);
-assertEq("abc".endsWith("bc", -Infinity), false);
-assertEq("abc".endsWith("bc", NaN), false);
-var myobj = {toString : (function () "abc"), endsWith : String.prototype.endsWith};
-assertEq(myobj.endsWith("abc"), true);
-assertEq(myobj.endsWith("ab"), false);
-var gotStr = false, gotPos = false;
-myobj = {toString : (function () {
-    assertEq(gotPos, false);
-    gotStr = true;
-    return "xyz";
-}),
-endsWith : String.prototype.endsWith};
-var idx = {valueOf : (function () {
-    assertEq(gotStr, true);
-    gotPos = true;
-    return 42;
-})};
-myobj.endsWith("elephant", idx);
-assertEq(gotPos, true);
+/*
+* Copyright (c) 2013 Mathias Bynens. All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*/
+
+function assertThrows(fun, errorType) {
+  try {
+    fun();
+    assertEq(true, false, "Expected error, but none was thrown");
+  } catch (e) {
+    assertEq(e instanceof errorType, true, "Wrong error type thrown");
+  }
+}
+assertEq(String.prototype.endsWith.length, 1);
+assertEq(String.prototype.propertyIsEnumerable('endsWith'), false);
+
+assertEq('undefined'.endsWith(), true);
+assertEq('undefined'.endsWith(undefined), true);
+assertEq('undefined'.endsWith(null), false);
+assertEq('null'.endsWith(), false);
+assertEq('null'.endsWith(undefined), false);
+assertEq('null'.endsWith(null), true);
+
+assertEq('abc'.endsWith(), false);
+assertEq('abc'.endsWith(''), true);
+assertEq('abc'.endsWith('\0'), false);
+assertEq('abc'.endsWith('c'), true);
+assertEq('abc'.endsWith('b'), false);
+assertEq('abc'.endsWith('a'), false);
+assertEq('abc'.endsWith('ab'), false);
+assertEq('abc'.endsWith('bc'), true);
+assertEq('abc'.endsWith('abc'), true);
+assertEq('abc'.endsWith('bcd'), false);
+assertEq('abc'.endsWith('abcd'), false);
+assertEq('abc'.endsWith('bcde'), false);
+
+assertEq('abc'.endsWith('', NaN), true);
+assertEq('abc'.endsWith('\0', NaN), false);
+assertEq('abc'.endsWith('c', NaN), false);
+assertEq('abc'.endsWith('b', NaN), false);
+assertEq('abc'.endsWith('a', NaN), false);
+assertEq('abc'.endsWith('ab', NaN), false);
+assertEq('abc'.endsWith('bc', NaN), false);
+assertEq('abc'.endsWith('abc', NaN), false);
+assertEq('abc'.endsWith('bcd', NaN), false);
+assertEq('abc'.endsWith('abcd', NaN), false);
+assertEq('abc'.endsWith('bcde', NaN), false);
+
+assertEq('abc'.endsWith('', false), true);
+assertEq('abc'.endsWith('\0', false), false);
+assertEq('abc'.endsWith('c', false), false);
+assertEq('abc'.endsWith('b', false), false);
+assertEq('abc'.endsWith('a', false), false);
+assertEq('abc'.endsWith('ab', false), false);
+assertEq('abc'.endsWith('bc', false), false);
+assertEq('abc'.endsWith('abc', false), false);
+assertEq('abc'.endsWith('bcd', false), false);
+assertEq('abc'.endsWith('abcd', false), false);
+assertEq('abc'.endsWith('bcde', false), false);
+
+assertEq('abc'.endsWith('', undefined), true);
+assertEq('abc'.endsWith('\0', undefined), false);
+assertEq('abc'.endsWith('c', undefined), true);
+assertEq('abc'.endsWith('b', undefined), false);
+assertEq('abc'.endsWith('a', undefined), false);
+assertEq('abc'.endsWith('ab', undefined), false);
+assertEq('abc'.endsWith('bc', undefined), true);
+assertEq('abc'.endsWith('abc', undefined), true);
+assertEq('abc'.endsWith('bcd', undefined), false);
+assertEq('abc'.endsWith('abcd', undefined), false);
+assertEq('abc'.endsWith('bcde', undefined), false);
+
+assertEq('abc'.endsWith('', null), true);
+assertEq('abc'.endsWith('\0', null), false);
+assertEq('abc'.endsWith('c', null), false);
+assertEq('abc'.endsWith('b', null), false);
+assertEq('abc'.endsWith('a', null), false);
+assertEq('abc'.endsWith('ab', null), false);
+assertEq('abc'.endsWith('bc', null), false);
+assertEq('abc'.endsWith('abc', null), false);
+assertEq('abc'.endsWith('bcd', null), false);
+assertEq('abc'.endsWith('abcd', null), false);
+assertEq('abc'.endsWith('bcde', null), false);
+
+assertEq('abc'.endsWith('', -Infinity), true);
+assertEq('abc'.endsWith('\0', -Infinity), false);
+assertEq('abc'.endsWith('c', -Infinity), false);
+assertEq('abc'.endsWith('b', -Infinity), false);
+assertEq('abc'.endsWith('a', -Infinity), false);
+assertEq('abc'.endsWith('ab', -Infinity), false);
+assertEq('abc'.endsWith('bc', -Infinity), false);
+assertEq('abc'.endsWith('abc', -Infinity), false);
+assertEq('abc'.endsWith('bcd', -Infinity), false);
+assertEq('abc'.endsWith('abcd', -Infinity), false);
+assertEq('abc'.endsWith('bcde', -Infinity), false);
+
+assertEq('abc'.endsWith('', -1), true);
+assertEq('abc'.endsWith('\0', -1), false);
+assertEq('abc'.endsWith('c', -1), false);
+assertEq('abc'.endsWith('b', -1), false);
+assertEq('abc'.endsWith('a', -1), false);
+assertEq('abc'.endsWith('ab', -1), false);
+assertEq('abc'.endsWith('bc', -1), false);
+assertEq('abc'.endsWith('abc', -1), false);
+assertEq('abc'.endsWith('bcd', -1), false);
+assertEq('abc'.endsWith('abcd', -1), false);
+assertEq('abc'.endsWith('bcde', -1), false);
+
+assertEq('abc'.endsWith('', -0), true);
+assertEq('abc'.endsWith('\0', -0), false);
+assertEq('abc'.endsWith('c', -0), false);
+assertEq('abc'.endsWith('b', -0), false);
+assertEq('abc'.endsWith('a', -0), false);
+assertEq('abc'.endsWith('ab', -0), false);
+assertEq('abc'.endsWith('bc', -0), false);
+assertEq('abc'.endsWith('abc', -0), false);
+assertEq('abc'.endsWith('bcd', -0), false);
+assertEq('abc'.endsWith('abcd', -0), false);
+assertEq('abc'.endsWith('bcde', -0), false);
+
+assertEq('abc'.endsWith('', +0), true);
+assertEq('abc'.endsWith('\0', +0), false);
+assertEq('abc'.endsWith('c', +0), false);
+assertEq('abc'.endsWith('b', +0), false);
+assertEq('abc'.endsWith('a', +0), false);
+assertEq('abc'.endsWith('ab', +0), false);
+assertEq('abc'.endsWith('bc', +0), false);
+assertEq('abc'.endsWith('abc', +0), false);
+assertEq('abc'.endsWith('bcd', +0), false);
+assertEq('abc'.endsWith('abcd', +0), false);
+assertEq('abc'.endsWith('bcde', +0), false);
+
+assertEq('abc'.endsWith('', 1), true);
+assertEq('abc'.endsWith('\0', 1), false);
+assertEq('abc'.endsWith('c', 1), false);
+assertEq('abc'.endsWith('b', 1), false);
+assertEq('abc'.endsWith('ab', 1), false);
+assertEq('abc'.endsWith('bc', 1), false);
+assertEq('abc'.endsWith('abc', 1), false);
+assertEq('abc'.endsWith('bcd', 1), false);
+assertEq('abc'.endsWith('abcd', 1), false);
+assertEq('abc'.endsWith('bcde', 1), false);
+
+assertEq('abc'.endsWith('', 2), true);
+assertEq('abc'.endsWith('\0', 2), false);
+assertEq('abc'.endsWith('c', 2), false);
+assertEq('abc'.endsWith('b', 2), true);
+assertEq('abc'.endsWith('ab', 2), true);
+assertEq('abc'.endsWith('bc', 2), false);
+assertEq('abc'.endsWith('abc', 2), false);
+assertEq('abc'.endsWith('bcd', 2), false);
+assertEq('abc'.endsWith('abcd', 2), false);
+assertEq('abc'.endsWith('bcde', 2), false);
+
+assertEq('abc'.endsWith('', +Infinity), true);
+assertEq('abc'.endsWith('\0', +Infinity), false);
+assertEq('abc'.endsWith('c', +Infinity), true);
+assertEq('abc'.endsWith('b', +Infinity), false);
+assertEq('abc'.endsWith('a', +Infinity), false);
+assertEq('abc'.endsWith('ab', +Infinity), false);
+assertEq('abc'.endsWith('bc', +Infinity), true);
+assertEq('abc'.endsWith('abc', +Infinity), true);
+assertEq('abc'.endsWith('bcd', +Infinity), false);
+assertEq('abc'.endsWith('abcd', +Infinity), false);
+assertEq('abc'.endsWith('bcde', +Infinity), false);
+
+assertEq('abc'.endsWith('', true), true);
+assertEq('abc'.endsWith('\0', true), false);
+assertEq('abc'.endsWith('c', true), false);
+assertEq('abc'.endsWith('b', true), false);
+assertEq('abc'.endsWith('ab', true), false);
+assertEq('abc'.endsWith('bc', true), false);
+assertEq('abc'.endsWith('abc', true), false);
+assertEq('abc'.endsWith('bcd', true), false);
+assertEq('abc'.endsWith('abcd', true), false);
+assertEq('abc'.endsWith('bcde', true), false);
+
+assertEq('abc'.endsWith('', 'x'), true);
+assertEq('abc'.endsWith('\0', 'x'), false);
+assertEq('abc'.endsWith('c', 'x'), false);
+assertEq('abc'.endsWith('b', 'x'), false);
+assertEq('abc'.endsWith('a', 'x'), false);
+assertEq('abc'.endsWith('ab', 'x'), false);
+assertEq('abc'.endsWith('bc', 'x'), false);
+assertEq('abc'.endsWith('abc', 'x'), false);
+assertEq('abc'.endsWith('bcd', 'x'), false);
+assertEq('abc'.endsWith('abcd', 'x'), false);
+assertEq('abc'.endsWith('bcde', 'x'), false);
+
+assertEq('[a-z]+(bar)?'.endsWith('(bar)?'), true);
+assertThrows(function() { '[a-z]+(bar)?'.endsWith(/(bar)?/); }, TypeError);
+assertEq('[a-z]+(bar)?'.endsWith('[a-z]+', 6), true);
+assertThrows(function() { '[a-z]+(bar)?'.endsWith(/(bar)?/); }, TypeError);
+assertThrows(function() { '[a-z]+/(bar)?/'.endsWith(/(bar)?/); }, TypeError);
+var global = newGlobal();
+global.eval('this.re = /(bar)?/');
+assertThrows(function() { '[a-z]+/(bar)?/'.endsWith(global.re); }, TypeError);
+
+// http://mathiasbynens.be/notes/javascript-unicode#poo-test
+var string = 'I\xF1t\xEBrn\xE2ti\xF4n\xE0liz\xE6ti\xF8n\u2603\uD83D\uDCA9';
+assertEq(string.endsWith(''), true);
+assertEq(string.endsWith('\xF1t\xEBr'), false);
+assertEq(string.endsWith('\xF1t\xEBr', 5), true);
+assertEq(string.endsWith('\xE0liz\xE6'), false);
+assertEq(string.endsWith('\xE0liz\xE6', 16), true);
+assertEq(string.endsWith('\xF8n\u2603\uD83D\uDCA9'), true);
+assertEq(string.endsWith('\xF8n\u2603\uD83D\uDCA9', 23), true);
+assertEq(string.endsWith('\u2603'), false);
+assertEq(string.endsWith('\u2603', 21), true);
+assertEq(string.endsWith('\uD83D\uDCA9'), true);
+assertEq(string.endsWith('\uD83D\uDCA9', 23), true);
+
+assertThrows(function() { String.prototype.endsWith.call(undefined); }, TypeError);
+assertThrows(function() { String.prototype.endsWith.call(undefined, 'b'); }, TypeError);
+assertThrows(function() { String.prototype.endsWith.call(undefined, 'b', 4); }, TypeError);
+assertThrows(function() { String.prototype.endsWith.call(null); }, TypeError);
+assertThrows(function() { String.prototype.endsWith.call(null, 'b'); }, TypeError);
+assertThrows(function() { String.prototype.endsWith.call(null, 'b', 4); }, TypeError);
+assertEq(String.prototype.endsWith.call(42, '2'), true);
+assertEq(String.prototype.endsWith.call(42, '4'), false);
+assertEq(String.prototype.endsWith.call(42, 'b', 4), false);
+assertEq(String.prototype.endsWith.call(42, '2', 1), false);
+assertEq(String.prototype.endsWith.call(42, '2', 4), true);
+assertEq(String.prototype.endsWith.call({ 'toString': function() { return 'abc'; } }, 'b', 0), false);
+assertEq(String.prototype.endsWith.call({ 'toString': function() { return 'abc'; } }, 'b', 1), false);
+assertEq(String.prototype.endsWith.call({ 'toString': function() { return 'abc'; } }, 'b', 2), true);
+assertThrows(function() { String.prototype.endsWith.call({ 'toString': function() { throw RangeError(); } }, /./); }, RangeError);
+assertThrows(function() { String.prototype.endsWith.call({ 'toString': function() { return 'abc' } }, /./); }, TypeError);
+
+assertThrows(function() { String.prototype.endsWith.apply(undefined); }, TypeError);
+assertThrows(function() { String.prototype.endsWith.apply(undefined, ['b']); }, TypeError);
+assertThrows(function() { String.prototype.endsWith.apply(undefined, ['b', 4]); }, TypeError);
+assertThrows(function() { String.prototype.endsWith.apply(null); }, TypeError);
+assertThrows(function() { String.prototype.endsWith.apply(null, ['b']); }, TypeError);
+assertThrows(function() { String.prototype.endsWith.apply(null, ['b', 4]); }, TypeError);
+assertEq(String.prototype.endsWith.apply(42, ['2']), true);
+assertEq(String.prototype.endsWith.apply(42, ['4']), false);
+assertEq(String.prototype.endsWith.apply(42, ['b', 4]), false);
+assertEq(String.prototype.endsWith.apply(42, ['2', 1]), false);
+assertEq(String.prototype.endsWith.apply(42, ['2', 4]), true);
+assertEq(String.prototype.endsWith.apply({ 'toString': function() { return 'abc'; } }, ['b', 0]), false);
+assertEq(String.prototype.endsWith.apply({ 'toString': function() { return 'abc'; } }, ['b', 1]), false);
+assertEq(String.prototype.endsWith.apply({ 'toString': function() { return 'abc'; } }, ['b', 2]), true);
+assertThrows(function() { String.prototype.endsWith.apply({ 'toString': function() { throw RangeError(); } }, [/./]); }, RangeError);
+assertThrows(function() { String.prototype.endsWith.apply({ 'toString': function() { return 'abc' } }, [/./]); }, TypeError);
--- a/js/src/jit-test/tests/basic/string-startswith.js
+++ b/js/src/jit-test/tests/basic/string-startswith.js
@@ -1,39 +1,243 @@
-assertEq("abc".startsWith("abc"), true);
-assertEq("abcd".startsWith("abc"), true);
-assertEq("abc".startsWith("a"), true);
-assertEq("abc".startsWith("abcd"), false);
-assertEq("abc".startsWith("bcde"), false);
-assertEq("abc".startsWith("b"), false);
-assertEq("abc".startsWith("abc", 0), true);
-assertEq("abc".startsWith("bc", 0), false);
-assertEq("abc".startsWith("bc", 1), true);
-assertEq("abc".startsWith("c", 1), false);
-assertEq("abc".startsWith("abc", 1), false);
-assertEq("abc".startsWith("c", 2), true);
-assertEq("abc".startsWith("d", 2), false);
-assertEq("abc".startsWith("dcd", 2), false);
-assertEq("abc".startsWith("a", 42), false);
-assertEq("abc".startsWith("a", Infinity), false);
-assertEq("abc".startsWith("a", NaN), true);
-assertEq("abc".startsWith("b", NaN), false);
-assertEq("abc".startsWith("ab", -43), true);
-assertEq("abc".startsWith("ab", -Infinity), true);
-assertEq("abc".startsWith("bc", -42), false);
-assertEq("abc".startsWith("bc", -Infinity), false);
-var myobj = {toString : (function () "abc"), startsWith : String.prototype.startsWith};
-assertEq(myobj.startsWith("abc"), true);
-assertEq(myobj.startsWith("bc"), false);
-var gotStr = false, gotPos = false;
-myobj = {toString : (function () {
-    assertEq(gotPos, false);
-    gotStr = true;
-    return "xyz";
-}),
-startsWith : String.prototype.startsWith};
-var idx = {valueOf : (function () {
-    assertEq(gotStr, true);
-    gotPos = true;
-    return 42;
-})};
-myobj.startsWith("elephant", idx);
-assertEq(gotPos, true);
+/*
+* Copyright (c) 2013 Mathias Bynens. All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*/
+
+function assertThrows(fun, errorType) {
+  try {
+    fun();
+    assertEq(true, false, "Expected error, but none was thrown");
+  } catch (e) {
+    assertEq(e instanceof errorType, true, "Wrong error type thrown");
+  }
+}
+
+Object.prototype[1] = 2; // try to break `arguments[1]`
+
+assertEq(String.prototype.startsWith.length, 1);
+assertEq(String.prototype.propertyIsEnumerable('startsWith'), false);
+
+assertEq('undefined'.startsWith(), true);
+assertEq('undefined'.startsWith(undefined), true);
+assertEq('undefined'.startsWith(null), false);
+assertEq('null'.startsWith(), false);
+assertEq('null'.startsWith(undefined), false);
+assertEq('null'.startsWith(null), true);
+
+assertEq('abc'.startsWith(), false);
+assertEq('abc'.startsWith(''), true);
+assertEq('abc'.startsWith('\0'), false);
+assertEq('abc'.startsWith('a'), true);
+assertEq('abc'.startsWith('b'), false);
+assertEq('abc'.startsWith('ab'), true);
+assertEq('abc'.startsWith('bc'), false);
+assertEq('abc'.startsWith('abc'), true);
+assertEq('abc'.startsWith('bcd'), false);
+assertEq('abc'.startsWith('abcd'), false);
+assertEq('abc'.startsWith('bcde'), false);
+
+assertEq('abc'.startsWith('', NaN), true);
+assertEq('abc'.startsWith('\0', NaN), false);
+assertEq('abc'.startsWith('a', NaN), true);
+assertEq('abc'.startsWith('b', NaN), false);
+assertEq('abc'.startsWith('ab', NaN), true);
+assertEq('abc'.startsWith('bc', NaN), false);
+assertEq('abc'.startsWith('abc', NaN), true);
+assertEq('abc'.startsWith('bcd', NaN), false);
+assertEq('abc'.startsWith('abcd', NaN), false);
+assertEq('abc'.startsWith('bcde', NaN), false);
+
+assertEq('abc'.startsWith('', false), true);
+assertEq('abc'.startsWith('\0', false), false);
+assertEq('abc'.startsWith('a', false), true);
+assertEq('abc'.startsWith('b', false), false);
+assertEq('abc'.startsWith('ab', false), true);
+assertEq('abc'.startsWith('bc', false), false);
+assertEq('abc'.startsWith('abc', false), true);
+assertEq('abc'.startsWith('bcd', false), false);
+assertEq('abc'.startsWith('abcd', false), false);
+assertEq('abc'.startsWith('bcde', false), false);
+
+assertEq('abc'.startsWith('', undefined), true);
+assertEq('abc'.startsWith('\0', undefined), false);
+assertEq('abc'.startsWith('a', undefined), true);
+assertEq('abc'.startsWith('b', undefined), false);
+assertEq('abc'.startsWith('ab', undefined), true);
+assertEq('abc'.startsWith('bc', undefined), false);
+assertEq('abc'.startsWith('abc', undefined), true);
+assertEq('abc'.startsWith('bcd', undefined), false);
+assertEq('abc'.startsWith('abcd', undefined), false);
+assertEq('abc'.startsWith('bcde', undefined), false);
+
+assertEq('abc'.startsWith('', null), true);
+assertEq('abc'.startsWith('\0', null), false);
+assertEq('abc'.startsWith('a', null), true);
+assertEq('abc'.startsWith('b', null), false);
+assertEq('abc'.startsWith('ab', null), true);
+assertEq('abc'.startsWith('bc', null), false);
+assertEq('abc'.startsWith('abc', null), true);
+assertEq('abc'.startsWith('bcd', null), false);
+assertEq('abc'.startsWith('abcd', null), false);
+assertEq('abc'.startsWith('bcde', null), false);
+
+assertEq('abc'.startsWith('', -Infinity), true);
+assertEq('abc'.startsWith('\0', -Infinity), false);
+assertEq('abc'.startsWith('a', -Infinity), true);
+assertEq('abc'.startsWith('b', -Infinity), false);
+assertEq('abc'.startsWith('ab', -Infinity), true);
+assertEq('abc'.startsWith('bc', -Infinity), false);
+assertEq('abc'.startsWith('abc', -Infinity), true);
+assertEq('abc'.startsWith('bcd', -Infinity), false);
+assertEq('abc'.startsWith('abcd', -Infinity), false);
+assertEq('abc'.startsWith('bcde', -Infinity), false);
+
+assertEq('abc'.startsWith('', -1), true);
+assertEq('abc'.startsWith('\0', -1), false);
+assertEq('abc'.startsWith('a', -1), true);
+assertEq('abc'.startsWith('b', -1), false);
+assertEq('abc'.startsWith('ab', -1), true);
+assertEq('abc'.startsWith('bc', -1), false);
+assertEq('abc'.startsWith('abc', -1), true);
+assertEq('abc'.startsWith('bcd', -1), false);
+assertEq('abc'.startsWith('abcd', -1), false);
+assertEq('abc'.startsWith('bcde', -1), false);
+
+assertEq('abc'.startsWith('', -0), true);
+assertEq('abc'.startsWith('\0', -0), false);
+assertEq('abc'.startsWith('a', -0), true);
+assertEq('abc'.startsWith('b', -0), false);
+assertEq('abc'.startsWith('ab', -0), true);
+assertEq('abc'.startsWith('bc', -0), false);
+assertEq('abc'.startsWith('abc', -0), true);
+assertEq('abc'.startsWith('bcd', -0), false);
+assertEq('abc'.startsWith('abcd', -0), false);
+assertEq('abc'.startsWith('bcde', -0), false);
+
+assertEq('abc'.startsWith('', +0), true);
+assertEq('abc'.startsWith('\0', +0), false);
+assertEq('abc'.startsWith('a', +0), true);
+assertEq('abc'.startsWith('b', +0), false);
+assertEq('abc'.startsWith('ab', +0), true);
+assertEq('abc'.startsWith('bc', +0), false);
+assertEq('abc'.startsWith('abc', +0), true);
+assertEq('abc'.startsWith('bcd', +0), false);
+assertEq('abc'.startsWith('abcd', +0), false);
+assertEq('abc'.startsWith('bcde', +0), false);
+
+assertEq('abc'.startsWith('', 1), true);
+assertEq('abc'.startsWith('\0', 1), false);
+assertEq('abc'.startsWith('a', 1), false);
+assertEq('abc'.startsWith('b', 1), true);
+assertEq('abc'.startsWith('ab', 1), false);
+assertEq('abc'.startsWith('bc', 1), true);
+assertEq('abc'.startsWith('abc', 1), false);
+assertEq('abc'.startsWith('bcd', 1), false);
+assertEq('abc'.startsWith('abcd', 1), false);
+assertEq('abc'.startsWith('bcde', 1), false);
+
+assertEq('abc'.startsWith('', +Infinity), true);
+assertEq('abc'.startsWith('\0', +Infinity), false);
+assertEq('abc'.startsWith('a', +Infinity), false);
+assertEq('abc'.startsWith('b', +Infinity), false);
+assertEq('abc'.startsWith('ab', +Infinity), false);
+assertEq('abc'.startsWith('bc', +Infinity), false);
+assertEq('abc'.startsWith('abc', +Infinity), false);
+assertEq('abc'.startsWith('bcd', +Infinity), false);
+assertEq('abc'.startsWith('abcd', +Infinity), false);
+assertEq('abc'.startsWith('bcde', +Infinity), false);
+
+assertEq('abc'.startsWith('', true), true);
+assertEq('abc'.startsWith('\0', true), false);
+assertEq('abc'.startsWith('a', true), false);
+assertEq('abc'.startsWith('b', true), true);
+assertEq('abc'.startsWith('ab', true), false);
+assertEq('abc'.startsWith('bc', true), true);
+assertEq('abc'.startsWith('abc', true), false);
+assertEq('abc'.startsWith('bcd', true), false);
+assertEq('abc'.startsWith('abcd', true), false);
+assertEq('abc'.startsWith('bcde', true), false);
+
+assertEq('abc'.startsWith('', 'x'), true);
+assertEq('abc'.startsWith('\0', 'x'), false);
+assertEq('abc'.startsWith('a', 'x'), true);
+assertEq('abc'.startsWith('b', 'x'), false);
+assertEq('abc'.startsWith('ab', 'x'), true);
+assertEq('abc'.startsWith('bc', 'x'), false);
+assertEq('abc'.startsWith('abc', 'x'), true);
+assertEq('abc'.startsWith('bcd', 'x'), false);
+assertEq('abc'.startsWith('abcd', 'x'), false);
+assertEq('abc'.startsWith('bcde', 'x'), false);
+
+assertEq('[a-z]+(bar)?'.startsWith('[a-z]+'), true);
+assertThrows(function() { '[a-z]+(bar)?'.startsWith(/[a-z]+/); }, TypeError);
+assertEq('[a-z]+(bar)?'.startsWith('(bar)?', 6), true);
+assertThrows(function() { '[a-z]+(bar)?'.startsWith(/(bar)?/); }, TypeError);
+assertThrows(function() { '[a-z]+/(bar)?/'.startsWith(/(bar)?/); }, TypeError);
+var global = newGlobal();
+global.eval('this.re = /(bar)?/');
+assertThrows(function() { '[a-z]+/(bar)?/'.startsWith(global.re); }, TypeError);
+
+// http://mathiasbynens.be/notes/javascript-unicode#poo-test
+var string = 'I\xF1t\xEBrn\xE2ti\xF4n\xE0liz\xE6ti\xF8n\u2603\uD83D\uDCA9';
+assertEq(string.startsWith(''), true);
+assertEq(string.startsWith('\xF1t\xEBr'), false);
+assertEq(string.startsWith('\xF1t\xEBr', 1), true);
+assertEq(string.startsWith('\xE0liz\xE6'), false);
+assertEq(string.startsWith('\xE0liz\xE6', 11), true);
+assertEq(string.startsWith('\xF8n\u2603\uD83D\uDCA9'), false);
+assertEq(string.startsWith('\xF8n\u2603\uD83D\uDCA9', 18), true);
+assertEq(string.startsWith('\u2603'), false);
+assertEq(string.startsWith('\u2603', 20), true);
+assertEq(string.startsWith('\uD83D\uDCA9'), false);
+assertEq(string.startsWith('\uD83D\uDCA9', 21), true);
+
+assertThrows(function() { String.prototype.startsWith.call(undefined); }, TypeError);
+assertThrows(function() { String.prototype.startsWith.call(undefined, 'b'); }, TypeError);
+assertThrows(function() { String.prototype.startsWith.call(undefined, 'b', 4); }, TypeError);
+assertThrows(function() { String.prototype.startsWith.call(null); }, TypeError);
+assertThrows(function() { String.prototype.startsWith.call(null, 'b'); }, TypeError);
+assertThrows(function() { String.prototype.startsWith.call(null, 'b', 4); }, TypeError);
+assertEq(String.prototype.startsWith.call(42, '2'), false);
+assertEq(String.prototype.startsWith.call(42, '4'), true);
+assertEq(String.prototype.startsWith.call(42, 'b', 4), false);
+assertEq(String.prototype.startsWith.call(42, '2', 1), true);
+assertEq(String.prototype.startsWith.call(42, '2', 4), false);
+assertEq(String.prototype.startsWith.call({ 'toString': function() { return 'abc'; } }, 'b', 0), false);
+assertEq(String.prototype.startsWith.call({ 'toString': function() { return 'abc'; } }, 'b', 1), true);
+assertEq(String.prototype.startsWith.call({ 'toString': function() { return 'abc'; } }, 'b', 2), false);
+assertThrows(function() { String.prototype.startsWith.call({ 'toString': function() { throw RangeError(); } }, /./); }, RangeError);
+assertThrows(function() { String.prototype.startsWith.call({ 'toString': function() { return 'abc'; } }, /./); }, TypeError);
+
+assertThrows(function() { String.prototype.startsWith.apply(undefined); }, TypeError);
+assertThrows(function() { String.prototype.startsWith.apply(undefined, ['b']); }, TypeError);
+assertThrows(function() { String.prototype.startsWith.apply(undefined, ['b', 4]); }, TypeError);
+assertThrows(function() { String.prototype.startsWith.apply(null); }, TypeError);
+assertThrows(function() { String.prototype.startsWith.apply(null, ['b']); }, TypeError);
+assertThrows(function() { String.prototype.startsWith.apply(null, ['b', 4]); }, TypeError);
+assertEq(String.prototype.startsWith.apply(42, ['2']), false);
+assertEq(String.prototype.startsWith.apply(42, ['4']), true);
+assertEq(String.prototype.startsWith.apply(42, ['b', 4]), false);
+assertEq(String.prototype.startsWith.apply(42, ['2', 1]), true);
+assertEq(String.prototype.startsWith.apply(42, ['2', 4]), false);
+assertEq(String.prototype.startsWith.apply({ 'toString': function() { return 'abc'; } }, ['b', 0]), false);
+assertEq(String.prototype.startsWith.apply({ 'toString': function() { return 'abc'; } }, ['b', 1]), true);
+assertEq(String.prototype.startsWith.apply({ 'toString': function() { return 'abc'; } }, ['b', 2]), false);
+assertThrows(function() { String.prototype.startsWith.apply({ 'toString': function() { throw RangeError(); } }, [/./]); }, RangeError);
+assertThrows(function() { String.prototype.startsWith.apply({ 'toString': function() { return 'abc'; } }, [/./]); }, TypeError);
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -429,8 +429,9 @@ MSG_DEF(JSMSG_MODULE_SPEC_AFTER_FROM,   
 MSG_DEF(JSMSG_MODULES_NOT_IMPLEMENTED,  375, 0, JSEXN_SYNTAXERR, "modules are not implemented yet")
 MSG_DEF(JSMSG_EXPORT_DECL_AT_TOP_LEVEL, 376, 0, JSEXN_SYNTAXERR, "export declarations may only appear at top level")
 MSG_DEF(JSMSG_RC_AFTER_EXPORT_SPEC_LIST, 377, 0, JSEXN_SYNTAXERR, "missing '}' after export specifier list")
 MSG_DEF(JSMSG_NO_EXPORT_NAME,           378, 0, JSEXN_SYNTAXERR, "missing export name")
 MSG_DEF(JSMSG_DECLARATION_AFTER_EXPORT, 379, 0, JSEXN_SYNTAXERR, "missing declaration after 'export' keyword")
 MSG_DEF(JSMSG_INVALID_PROTOTYPE,        380, 0, JSEXN_TYPEERR, "prototype field is not an object")
 MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_TO_UNSIZED, 381, 0, JSEXN_TYPEERR, "cannot create a handle to an unsized type")
 MSG_DEF(JSMSG_SETPROTOTYPEOF_FAIL,      382, 0, JSEXN_TYPEERR, "[[SetPrototypeOf]] failed")
+MSG_DEF(JSMSG_INVALID_ARG_TYPE,         383, 3, JSEXN_TYPEERR, "Invalid type: {0} can't be a{1} {2}")
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -1417,125 +1417,137 @@ str_lastIndexOf(JSContext *cx, unsigned 
         }
       break_continue:;
     }
 
     args.rval().setInt32(-1);
     return true;
 }
 
-/* ES6 20120927 draft 15.5.4.22. */
+/* ES6 20131108 draft 21.1.3.18. */
 static bool
 str_startsWith(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // Steps 1, 2, and 3
     RootedString str(cx, ThisToStringForStringProto(cx, args));
     if (!str)
         return false;
 
-    // Steps 4 and 5
+    // Step 4
+    if (args.get(0).isObject() && IsObjectWithClass(args[0], ESClass_RegExp, cx)) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INVALID_ARG_TYPE,
+                             "first", "", "Regular Expression");
+        return false;
+    }
+
+    // Steps 5 and 6
     Rooted<JSLinearString*> searchStr(cx, ArgToRootedString(cx, args, 0));
     if (!searchStr)
         return false;
 
-    // Steps 6 and 7
+    // Steps 7 and 8
     uint32_t pos = 0;
     if (args.hasDefined(1)) {
         if (args[1].isInt32()) {
             int i = args[1].toInt32();
             pos = (i < 0) ? 0U : uint32_t(i);
         } else {
             double d;
             if (!ToInteger(cx, args[1], &d))
                 return false;
             pos = uint32_t(Min(Max(d, 0.0), double(UINT32_MAX)));
         }
     }
 
-    // Step 8
+    // Step 9
     uint32_t textLen = str->length();
     const jschar *textChars = str->getChars(cx);
     if (!textChars)
         return false;
 
-    // Step 9
+    // Step 10
     uint32_t start = Min(Max(pos, 0U), textLen);
 
-    // Step 10
+    // Step 11
     uint32_t searchLen = searchStr->length();
     const jschar *searchChars = searchStr->chars();
 
-    // Step 11
+    // Step 12
     if (searchLen + start < searchLen || searchLen + start > textLen) {
         args.rval().setBoolean(false);
         return true;
     }
 
-    // Steps 12 and 13
+    // Steps 13 and 14
     args.rval().setBoolean(PodEqual(textChars + start, searchChars, searchLen));
     return true;
 }
 
-/* ES6 20120708 draft 15.5.4.23. */
+/* ES6 20131108 draft 21.1.3.7. */
 static bool
 str_endsWith(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // Steps 1, 2, and 3
     RootedString str(cx, ThisToStringForStringProto(cx, args));
     if (!str)
         return false;
 
-    // Steps 4 and 5
+    // Step 4
+    if (args.get(0).isObject() && IsObjectWithClass(args[0], ESClass_RegExp, cx)) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INVALID_ARG_TYPE,
+                             "first", "", "Regular Expression");
+        return false;
+    }
+
+    // Steps 5 and 6
     Rooted<JSLinearString *> searchStr(cx, ArgToRootedString(cx, args, 0));
     if (!searchStr)
         return false;
 
-    // Step 6
+    // Step 7
     uint32_t textLen = str->length();
-
-    // Steps 7 and 8
+    const jschar *textChars = str->getChars(cx);
+    if (!textChars)
+        return false;
+
+    // Steps 8 and 9
     uint32_t pos = textLen;
     if (args.hasDefined(1)) {
         if (args[1].isInt32()) {
             int i = args[1].toInt32();
             pos = (i < 0) ? 0U : uint32_t(i);
         } else {
             double d;
             if (!ToInteger(cx, args[1], &d))
                 return false;
             pos = uint32_t(Min(Max(d, 0.0), double(UINT32_MAX)));
         }
     }
 
-    // Step 6
-    const jschar *textChars = str->getChars(cx);
-    if (!textChars)
-        return false;
-
-    // Step 9
+    // Step 10
     uint32_t end = Min(Max(pos, 0U), textLen);
 
-    // Step 10
+    // Step 11
     uint32_t searchLen = searchStr->length();
     const jschar *searchChars = searchStr->chars();
 
-    // Step 12
+    // Step 13 (reordered)
     if (searchLen > end) {
         args.rval().setBoolean(false);
         return true;
     }
 
-    // Step 11
+    // Step 12
     uint32_t start = end - searchLen;
 
-    // Steps 13 and 14
+    // Steps 14 and 15
     args.rval().setBoolean(PodEqual(textChars + start, searchChars, searchLen));
     return true;
 }
 
 static bool
 js_TrimString(JSContext *cx, Value *vp, bool trimLeft, bool trimRight)
 {
     CallReceiver call = CallReceiverFromVp(vp);