Backed out changeset 537d40121b6d (bug 887016)
authorTooru Fujisawa <arai_a@mac.com>
Mon, 28 Mar 2016 06:49:54 +0900
changeset 290652 248bb4773adfc0c076922468f938f8567076b528
parent 290651 0fd465ec1e2c279f7ae3d9c4243c1d6c2f597c43
child 290653 592fbf849342b06d080078bc654f119b023c6b58
push id19656
push usergwagner@mozilla.com
push dateMon, 04 Apr 2016 13:43:23 +0000
treeherderb2g-inbound@e99061fde28a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs887016
milestone48.0a1
backs out537d40121b6d4c80071e02aeaa95712fdfdcb107
Backed out changeset 537d40121b6d (bug 887016)
js/src/builtin/RegExp.cpp
js/src/builtin/RegExp.js
js/src/builtin/String.js
js/src/jit-test/tests/ion/testStringMatch.js
js/src/jit/Lowering.cpp
js/src/js.msg
js/src/jsstr.cpp
js/src/jsstr.h
js/src/tests/ecma_6/RegExp/RegExpExec-exec.js
js/src/tests/ecma_6/RegExp/RegExpExec-return.js
js/src/tests/ecma_6/RegExp/constructor-constructor.js
js/src/tests/ecma_6/RegExp/match-this.js
js/src/tests/ecma_6/RegExp/match-trace.js
js/src/tests/ecma_6/RegExp/match.js
js/src/tests/ecma_6/String/match.js
js/src/vm/GlobalObject.cpp
js/src/vm/SelfHosting.cpp
js/xpconnect/tests/chrome/test_xrayToJS.xul
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -639,17 +639,16 @@ const JSPropertySpec js::regexp_properti
 const JSFunctionSpec js::regexp_methods[] = {
 #if JS_HAS_TOSOURCE
     JS_SELF_HOSTED_FN(js_toSource_str, "RegExpToString", 0, 0),
 #endif
     JS_SELF_HOSTED_FN(js_toString_str, "RegExpToString", 0, 0),
     JS_FN("compile",        regexp_compile,     2,0),
     JS_SELF_HOSTED_FN("exec", "RegExp_prototype_Exec", 1,0),
     JS_SELF_HOSTED_FN("test", "RegExpTest" ,    1,0),
-    JS_SELF_HOSTED_SYM_FN(match, "RegExpMatch", 1,0),
     JS_FS_END
 };
 
 #define STATIC_PAREN_GETTER_CODE(parenNum)                                      \
     if (!res->createParen(cx, parenNum, args.rval()))                           \
         return false;                                                           \
     if (args.rval().isUndefined())                                              \
         args.rval().setString(cx->runtime()->emptyString);                      \
--- a/js/src/builtin/RegExp.js
+++ b/js/src/builtin/RegExp.js
@@ -51,107 +51,16 @@ function RegExpToString()
     // Steps 5-6.
     var flags = R.flags;
 
     // Step 7.
     return '/' + pattern + '/' + flags;
 }
 _SetCanonicalName(RegExpToString, "toString");
 
-// ES 2016 draft Mar 25, 2016 21.2.5.2.3.
-function AdvanceStringIndex(S, index) {
-    // Step 1.
-    assert(typeof S === "string", "Expected string as 1st argument");
-
-    // Step 2.
-    assert(index >= 0 && index <= MAX_NUMERIC_INDEX, "Expected integer as 2nd argument");
-
-    // Step 3 (skipped).
-
-    // Step 4 (skipped).
-
-    // Step 5.
-    var length = S.length;
-
-    // Step 6.
-    if (index + 1 >= length)
-        return index + 1;
-
-    // Step 7.
-    var first = callFunction(std_String_charCodeAt, S, index);
-
-    // Step 8.
-    if (first < 0xD800 || first > 0xDBFF)
-        return index + 1;
-
-    // Step 9.
-    var second = callFunction(std_String_charCodeAt, S, index + 1);
-
-    // Step 10.
-    if (second < 0xDC00 || second > 0xDFFF)
-        return index + 1;
-
-    // Step 11.
-    return index + 2;
-}
-
-// ES 2016 draft Mar 25, 2016 21.2.5.6.
-function RegExpMatch(string) {
-    // Step 1.
-    var rx = this;
-
-    // Step 2.
-    if (!IsObject(rx))
-        ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, rx === null ? "null" : typeof rx);
-
-    // Step 3.
-    var S = ToString(string);
-
-    // Steps 4-5.
-    if (!rx.global)
-        return RegExpExec(rx, S, false);
-
-    // Step 6.a.
-    var fullUnicode = !!rx.unicode;
-
-    // Step 6.b.
-    rx.lastIndex = 0;
-
-    // Step 6.c.
-    var A = [];
-
-    // Step 6.d.
-    var n = 0;
-
-    // Step 6.e.
-    while (true) {
-        // Step 6.e.i.
-        var result = RegExpExec(rx, S, false);
-
-        // Step 6.e.ii.
-        if (result === null)
-          return (n === 0) ? null : A;
-
-        // Step 6.e.iii.1.
-        var matchStr = ToString(result[0]);
-
-        // Step 6.e.iii.2.
-        _DefineDataProperty(A, n, matchStr);
-
-        // Step 6.e.iii.4.
-        if (matchStr === "") {
-            var lastIndex = ToLength(rx.lastIndex);
-            rx.lastIndex = fullUnicode ? AdvanceStringIndex(S, lastIndex) : lastIndex + 1;
-        }
-
-        // Step 6.e.iii.5.
-        n++;
-    }
-}
-
 // ES6 21.2.5.2.
 // NOTE: This is not RegExpExec (21.2.5.2.1).
 function RegExp_prototype_Exec(string) {
     // Steps 1-3.
     var R = this;
     if (!IsObject(R) || !IsRegExpObject(R))
         return callFunction(CallRegExpMethodIfWrapped, R, string, "RegExp_prototype_Exec");
 
--- a/js/src/builtin/String.js
+++ b/js/src/builtin/String.js
@@ -1,81 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*global intl_Collator: false, */
 
-function StringProtoHasNoMatch() {
-    var ObjectProto = GetBuiltinPrototype("Object");
-    var StringProto = GetBuiltinPrototype("String");
-    if (!ObjectHasPrototype(StringProto, ObjectProto))
-        return false;
-    return !(std_match in StringProto);
-}
-
-function IsStringMatchOptimizable() {
-    var RegExpProto = GetBuiltinPrototype("RegExp");
-    // If RegExpPrototypeOptimizable succeeds, `exec` and `@@match` are
-    // guaranteed to be data properties.
-    return RegExpPrototypeOptimizable(RegExpProto) &&
-           RegExpProto.exec === RegExp_prototype_Exec &&
-           RegExpProto[std_match] === RegExpMatch;
-}
-
-// ES 2016 draft Mar 25, 2016 21.1.3.11.
-function String_match(regexp) {
-    // Step 1.
-    RequireObjectCoercible(this);
-
-    // Step 2.
-    var isPatternString = (typeof regexp === "string");
-    if (!(isPatternString && StringProtoHasNoMatch()) && regexp !== undefined && regexp !== null) {
-        // Step 2.a.
-        var matcher = GetMethod(regexp, std_match);
-
-        // Step 2.b.
-        if (matcher !== undefined)
-            return callContentFunction(matcher, regexp, this);
-    }
-
-    // Step 3.
-    var S = ToString(this);
-
-    // FIXME: Non-standard flags argument (bug 1108382).
-    var flags = undefined;
-    if (arguments.length > 1) {
-        if (IsMatchFlagsArgumentEnabled())
-            flags = arguments[1];
-        WarnOnceAboutFlagsArgument();
-    } else {
-        if (isPatternString && IsStringMatchOptimizable()) {
-            var flatResult = FlatStringMatch(S, regexp);
-            if (flatResult !== undefined)
-                return flatResult;
-        }
-    }
-
-    // Step 4.
-    var rx = RegExpCreate(regexp, flags);
-
-    // Step 5 (optimized case).
-    if (IsStringMatchOptimizable() && !flags)
-        return RegExpMatcher(rx, S, 0, false);
-
-    // Step 5.
-    return callContentFunction(GetMethod(rx, std_match), rx, S);
-}
-
-function String_generic_match(thisValue, regexp) {
-    if (thisValue === undefined)
-        ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.match');
-    return callFunction(String_match, thisValue, regexp);
-}
-
 /* ES6 Draft Oct 14, 2014 21.1.3.19 */
 function String_substring(start, end) {
     // Steps 1-3.
     RequireObjectCoercible(this);
     var str = ToString(this);
 
     // Step 4.
     var len = str.length;
deleted file mode 100644
--- a/js/src/jit-test/tests/ion/testStringMatch.js
+++ /dev/null
@@ -1,119 +0,0 @@
-setJitCompilerOption("ion.warmup.trigger", 4);
-
-function testBasic() {
-  var f = function() {
-    var result = "abc".match("b");
-    assertEq(result.length, 1);
-    assertEq(result.index, 1);
-    assertEq(result[0], "b");
-  };
-  for (var i = 0; i < 40; i++) {
-    f();
-  }
-}
-testBasic();
-
-function testMod(apply, unapply) {
-  var f = function(applied) {
-    var result = "abc".match("b");
-    assertEq(result.length, 1);
-    if (applied) {
-      assertEq(result[0], "mod");
-    } else {
-      assertEq(result.index, 1);
-      assertEq(result[0], "b");
-    }
-  };
-  var applied = false;
-  for (var i = 0; i < 120; i++) {
-    f(applied);
-    if (i == 40) {
-      apply();
-      applied = true;
-    }
-    if (i == 80) {
-      unapply();
-      applied = false;
-    }
-  }
-}
-testMod(() => {
-  String.prototype[Symbol.match] = () => ["mod"];
-}, () => {
-  delete String.prototype[Symbol.match];
-});
-testMod(() => {
-  Object.prototype[Symbol.match] = () => ["mod"];
-}, () => {
-  delete Object.prototype[Symbol.match];
-});
-
-testMod(() => {
-  Object.setPrototypeOf(String.prototype, {
-    [Symbol.match]: () => ["mod"]
-  });
-}, () => {
-  Object.setPrototypeOf(String.prototype, Object.prototype);
-});
-
-var orig_exec = RegExp.prototype.exec;
-testMod(() => {
-  RegExp.prototype.exec = () => ["mod"];
-}, () => {
-  RegExp.prototype.exec = orig_exec;
-});
-
-var orig_match = RegExp.prototype[Symbol.match];
-testMod(() => {
-  RegExp.prototype[Symbol.match] = () => ["mod"];
-}, () => {
-  RegExp.prototype[Symbol.match] = orig_match;
-});
-
-var observed = false;
-function testObserved(apply, unapply) {
-  var f = function(applied) {
-    observed = false;
-    var result = "abc".match("b."); // Use meta char to avoid flat match.
-    assertEq(result.length, 1);
-    assertEq(result.index, 1);
-    assertEq(result[0], "bc");
-    assertEq(observed, applied);
-  };
-  var applied = false;
-  for (var i = 0; i < 120; i++) {
-    f(applied);
-    if (i == 40) {
-      apply();
-      applied = true;
-    }
-    if (i == 80) {
-      unapply();
-      applied = false;
-    }
-  }
-}
-
-var orig_global = Object.getOwnPropertyDescriptor(RegExp.prototype, "global");
-testObserved(() => {
-  Object.defineProperty(RegExp.prototype, "global", {
-    get: function() {
-      observed = true;
-      return false;
-    }
-  });
-}, () => {
-  Object.defineProperty(RegExp.prototype, "global", orig_global);
-});
-
-var orig_sticky = Object.getOwnPropertyDescriptor(RegExp.prototype, "sticky");
-testObserved(() => {
-  Object.defineProperty(RegExp.prototype, "sticky", {
-    get: function() {
-      observed = true;
-      return false;
-    }
-  });
-}, () => {
-  Object.defineProperty(RegExp.prototype, "sticky", orig_sticky);
-});
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -2185,16 +2185,17 @@ MustCloneRegExpForCall(MCall* call, uint
 
     JSFunction* target = call->getSingleTarget();
     if (!target || !target->isNative())
         return true;
 
     if (useIndex == MCall::IndexOfArgument(0) &&
         (target->native() == str_split ||
          target->native() == str_replace ||
+         target->native() == str_match ||
          target->native() == str_search))
     {
         return false;
     }
 
     return true;
 }
 
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -439,17 +439,16 @@ MSG_DEF(JSMSG_INVALID_LOCALE_MATCHER,  1
 MSG_DEF(JSMSG_INVALID_OPTION_VALUE,    2, JSEXN_RANGEERR, "invalid value {1} for option {0}")
 MSG_DEF(JSMSG_INVALID_TIME_ZONE,       1, JSEXN_RANGEERR, "invalid time zone in DateTimeFormat(): {0}")
 MSG_DEF(JSMSG_UNDEFINED_CURRENCY,      0, JSEXN_TYPEERR, "undefined currency in NumberFormat() with currency style")
 
 // RegExp
 MSG_DEF(JSMSG_BACK_REF_OUT_OF_RANGE,   0, JSEXN_SYNTAXERR, "back reference out of range in regular expression")
 MSG_DEF(JSMSG_BAD_CLASS_RANGE,         0, JSEXN_SYNTAXERR, "invalid range in character class")
 MSG_DEF(JSMSG_ESCAPE_AT_END_OF_REGEXP, 0, JSEXN_SYNTAXERR, "\\ at end of pattern")
-MSG_DEF(JSMSG_EXEC_NOT_OBJORNULL,      0, JSEXN_TYPEERR, "RegExp exec method should return object or null")
 MSG_DEF(JSMSG_INVALID_DECIMAL_ESCAPE, 0, JSEXN_SYNTAXERR, "invalid decimal escape in regular expression")
 MSG_DEF(JSMSG_INVALID_GROUP,           0, JSEXN_SYNTAXERR, "invalid regexp group")
 MSG_DEF(JSMSG_INVALID_IDENTITY_ESCAPE, 0, JSEXN_SYNTAXERR, "invalid identity escape in regular expression")
 MSG_DEF(JSMSG_INVALID_UNICODE_ESCAPE,  0, JSEXN_SYNTAXERR, "invalid unicode escape in regular expression")
 MSG_DEF(JSMSG_MISSING_PAREN,           0, JSEXN_SYNTAXERR, "unterminated parenthetical")
 MSG_DEF(JSMSG_NEWREGEXP_FLAGGED,       0, JSEXN_TYPEERR, "can't supply flags when constructing one RegExp from another")
 MSG_DEF(JSMSG_NOTHING_TO_REPEAT,       0, JSEXN_SYNTAXERR, "nothing to repeat")
 MSG_DEF(JSMSG_NUMBERS_OUT_OF_ORDER,    0, JSEXN_SYNTAXERR, "numbers out of order in {} quantifier.")
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -2255,16 +2255,42 @@ class MOZ_STACK_CLASS StringRegExpGuard
 
   private:
     StringRegExpGuard(const StringRegExpGuard&) = delete;
     void operator=(const StringRegExpGuard&) = delete;
 };
 
 } /* anonymous namespace */
 
+static bool
+DoMatchLocal(JSContext* cx, const CallArgs& args, RegExpStatics* res, HandleLinearString input,
+             RegExpShared& re)
+{
+    ScopedMatchPairs matches(&cx->tempLifoAlloc());
+    bool sticky = re.sticky();
+    RegExpRunStatus status = re.execute(cx, input, 0, sticky, &matches, nullptr);
+    if (status == RegExpRunStatus_Error)
+        return false;
+
+    if (status == RegExpRunStatus_Success_NotFound) {
+        args.rval().setNull();
+        return true;
+    }
+
+    if (!res->updateFromMatchPairs(cx, input, matches))
+        return false;
+
+    RootedValue rval(cx);
+    if (!CreateRegExpMatchResult(cx, input, matches, &rval))
+        return false;
+
+    args.rval().set(rval);
+    return true;
+}
+
 /* ES6 21.2.5.2.3. */
 static size_t
 AdvanceStringIndex(HandleLinearString input, size_t length, size_t index, bool unicode)
 {
     /* Steps 1-3 (implicit). */
 
     /* Step 4: If input is latin1, there is no surrogate pair. */
     if (!unicode || input->hasLatin1Chars())
@@ -2290,16 +2316,209 @@ AdvanceStringIndex(HandleLinearString in
     /* Step 10. */
     if (!unicode::IsTrailSurrogate(second))
         return index + 1;
 
     /* Step 11. */
     return index + 2;
 }
 
+/* ES5 15.5.4.10 step 8. */
+static bool
+DoMatchGlobal(JSContext* cx, const CallArgs& args, RegExpStatics* res, HandleLinearString input,
+              StringRegExpGuard& g)
+{
+    // Step 8a.
+    //
+    // This single zeroing of "lastIndex" covers all "lastIndex" changes in the
+    // rest of String.prototype.match, particularly in steps 8f(i) and
+    // 8f(iii)(2)(a).  Here's why.
+    //
+    // The inputs to the calls to RegExp.prototype.exec are a RegExp object
+    // whose .global is true and a string.  The only side effect of a call in
+    // these circumstances is that the RegExp's .lastIndex will be modified to
+    // the next starting index after the discovered match (or to 0 if there's
+    // no remaining match).  Because .lastIndex is a non-configurable data
+    // property and no script-controllable code executes after step 8a, passing
+    // step 8a implies *every* .lastIndex set succeeds.  String.prototype.match
+    // calls RegExp.prototype.exec repeatedly, and the last call doesn't match,
+    // so the final value of .lastIndex is 0: exactly the state after step 8a
+    // succeeds.  No spec step lets script observe intermediate .lastIndex
+    // values.
+    //
+    // The arrays returned by RegExp.prototype.exec always have a string at
+    // index 0, for which [[Get]]s have no side effects.
+    //
+    // Filling in a new array using [[DefineOwnProperty]] is unobservable.
+    //
+    // This is a tricky point, because after this set, our implementation *can*
+    // fail.  The key is that script can't distinguish these failure modes from
+    // one where, in spec terms, we fail immediately after step 8a.  That *in
+    // reality* we might have done extra matching work, or created a partial
+    // results array to return, or hit an interrupt, is irrelevant.  The
+    // script can't tell we did any of those things but didn't update
+    // .lastIndex.  Thus we can optimize steps 8b onward however we want,
+    // including eliminating intermediate .lastIndex sets, as long as we don't
+    // add ways for script to observe the intermediate states.
+    //
+    // In short: it's okay to cheat (by setting .lastIndex to 0, once) because
+    // we can't get caught.
+    if (!g.zeroLastIndex(cx))
+        return false;
+
+    // Step 8b.
+    AutoValueVector elements(cx);
+
+    size_t lastSuccessfulStart = 0;
+
+    // The loop variables from steps 8c-e aren't needed, as we use different
+    // techniques from the spec to implement step 8f's loop.
+
+    // Step 8f.
+    ScopedMatchPairs matches(&cx->tempLifoAlloc());
+    size_t charsLen = input->length();
+    RegExpShared& re = g.regExp();
+    bool unicode = re.unicode();
+    bool sticky = re.sticky();
+    for (size_t searchIndex = 0; searchIndex <= charsLen; ) {
+        if (!CheckForInterrupt(cx))
+            return false;
+
+        // Steps 8f(i-ii), minus "lastIndex" updates (see above).
+        RegExpRunStatus status = re.execute(cx, input, searchIndex, sticky, &matches, nullptr);
+        if (status == RegExpRunStatus_Error)
+            return false;
+
+        // Step 8f(ii).
+        if (status == RegExpRunStatus_Success_NotFound)
+            break;
+
+        lastSuccessfulStart = searchIndex;
+        MatchPair& match = matches[0];
+
+        // Steps 8f(iii)(1-3).
+        searchIndex = match.isEmpty()
+                      ? AdvanceStringIndex(input, charsLen, match.limit, unicode)
+                      : match.limit;
+
+        // Step 8f(iii)(4-5).
+        JSLinearString* str = NewDependentString(cx, input, match.start, match.length());
+        if (!str)
+            return false;
+        if (!elements.append(StringValue(str)))
+            return false;
+    }
+
+    // Step 8g.
+    if (elements.empty()) {
+        args.rval().setNull();
+        return true;
+    }
+
+    // The last *successful* match updates the RegExpStatics. (Interestingly,
+    // this implies that String.prototype.match's semantics aren't those
+    // implied by the RegExp.prototype.exec calls in the ES5 algorithm.)
+    res->updateLazily(cx, input, &re, lastSuccessfulStart, sticky);
+
+    // Steps 8b, 8f(iii)(5-6), 8h.
+    JSObject* array = NewDenseCopiedArray(cx, elements.length(), elements.begin());
+    if (!array)
+        return false;
+
+    args.rval().setObject(*array);
+    return true;
+}
+
+static bool
+BuildFlatMatchArray(JSContext* cx, HandleString textstr, const FlatMatch& fm, CallArgs* args)
+{
+    if (fm.match() < 0) {
+        args->rval().setNull();
+        return true;
+    }
+
+    /* Get the templateObject that defines the shape and type of the output object */
+    JSObject* templateObject = cx->compartment()->regExps.getOrCreateMatchResultTemplateObject(cx);
+    if (!templateObject)
+        return false;
+
+    RootedArrayObject arr(cx, NewDenseFullyAllocatedArrayWithTemplate(cx, 1, templateObject));
+    if (!arr)
+        return false;
+
+    /* Store a Value for each pair. */
+    arr->setDenseInitializedLength(1);
+    arr->initDenseElement(0, StringValue(fm.pattern()));
+
+    /* Set the |index| property. (TemplateObject positions it in slot 0) */
+    arr->setSlot(0, Int32Value(fm.match()));
+
+    /* Set the |input| property. (TemplateObject positions it in slot 1) */
+    arr->setSlot(1, StringValue(textstr));
+
+#ifdef DEBUG
+    RootedValue test(cx);
+    RootedId id(cx, NameToId(cx->names().index));
+    if (!NativeGetProperty(cx, arr, id, &test))
+        return false;
+    MOZ_ASSERT(test == arr->getSlot(0));
+    id = NameToId(cx->names().input);
+    if (!NativeGetProperty(cx, arr, id, &test))
+        return false;
+    MOZ_ASSERT(test == arr->getSlot(1));
+#endif
+
+    args->rval().setObject(*arr);
+    return true;
+}
+
+/* ES5 15.5.4.10. */
+bool
+js::str_match(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    /* Steps 1-2. */
+    RootedString str(cx, ThisToStringForStringProto(cx, args));
+    if (!str)
+        return false;
+
+    /* Steps 3-4, plus the trailing-argument "flags" extension. */
+    StringRegExpGuard g(cx);
+    if (!g.init(cx, args, true))
+        return false;
+
+    /* Fast path when the search pattern can be searched for as a string. */
+    if (const FlatMatch* fm = g.tryFlatMatch(cx, str, 1, args.length()))
+        return BuildFlatMatchArray(cx, str, *fm, &args);
+
+    /* Return if there was an error in tryFlatMatch. */
+    if (cx->isExceptionPending())
+        return false;
+
+    /* Create regular-expression internals as needed to perform the match. */
+    if (!g.normalizeRegExp(cx, false, 1, args))
+        return false;
+
+    RegExpStatics* res = cx->global()->getRegExpStatics(cx);
+    if (!res)
+        return false;
+
+    RootedLinearString linearStr(cx, str->ensureLinear(cx));
+    if (!linearStr)
+        return false;
+
+    /* Steps 5-6, 7. */
+    if (!g.regExp().global())
+        return DoMatchLocal(cx, args, res, linearStr, g.regExp());
+
+    /* Steps 6, 8. */
+    return DoMatchGlobal(cx, args, res, linearStr, g);
+}
+
 bool
 js::str_search(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedString str(cx, ThisToStringForStringProto(cx, args));
     if (!str)
         return false;
 
@@ -3987,17 +4206,17 @@ static const JSFunctionSpec string_metho
     JS_FN("localeCompare",     str_localeCompare,     1,JSFUN_GENERIC_NATIVE),
 #endif
     JS_SELF_HOSTED_FN("repeat", "String_repeat",      1,0),
 #if EXPOSE_INTL_API
     JS_FN("normalize",         str_normalize,         0,JSFUN_GENERIC_NATIVE),
 #endif
 
     /* Perl-ish methods (search is actually Python-esque). */
-    JS_SELF_HOSTED_FN("match", "String_match",        1,0),
+    JS_FN("match",             str_match,             1,JSFUN_GENERIC_NATIVE),
     JS_FN("search",            str_search,            1,JSFUN_GENERIC_NATIVE),
     JS_INLINABLE_FN("replace", str_replace,           2,JSFUN_GENERIC_NATIVE, StringReplace),
     JS_INLINABLE_FN("split",   str_split,             2,JSFUN_GENERIC_NATIVE, StringSplit),
     JS_SELF_HOSTED_FN("substr", "String_substr",      2,0),
 
     /* Python-esque sequence methods. */
     JS_FN("concat",            str_concat,            1,JSFUN_GENERIC_NATIVE),
     JS_SELF_HOSTED_FN("slice", "String_slice",        2,0),
@@ -4142,18 +4361,16 @@ static const JSFunctionSpec string_stati
     JS_INLINABLE_FN("fromCharCode", js::str_fromCharCode, 1, 0, StringFromCharCode),
 
     JS_SELF_HOSTED_FN("fromCodePoint",   "String_static_fromCodePoint", 1,0),
     JS_SELF_HOSTED_FN("raw",             "String_static_raw",           2,JSFUN_HAS_REST),
     JS_SELF_HOSTED_FN("substring",       "String_static_substring",     3,0),
     JS_SELF_HOSTED_FN("substr",          "String_static_substr",        3,0),
     JS_SELF_HOSTED_FN("slice",           "String_static_slice",         3,0),
 
-    JS_SELF_HOSTED_FN("match",           "String_generic_match",        2,0),
-
     // This must be at the end because of bug 853075: functions listed after
     // self-hosted methods aren't available in self-hosted code.
 #if EXPOSE_INTL_API
     JS_SELF_HOSTED_FN("localeCompare",   "String_static_localeCompare", 2,0),
 #endif
     JS_FS_END
 };
 
@@ -5175,132 +5392,8 @@ js::PutEscapedStringImpl(char* buffer, s
 
 template size_t
 js::PutEscapedString(char* buffer, size_t bufferSize, const Latin1Char* chars, size_t length,
                      uint32_t quote);
 
 template size_t
 js::PutEscapedString(char* buffer, size_t bufferSize, const char16_t* chars, size_t length,
                      uint32_t quote);
-
-static bool
-FlatStringMatchHelper(JSContext* cx, HandleString str, HandleString pattern, bool* isFlat, int32_t* match)
-{
-    RootedLinearString linearPattern(cx, pattern->ensureLinear(cx));
-    if (!linearPattern)
-        return false;
-
-    static const size_t MAX_FLAT_PAT_LEN = 256;
-    if (linearPattern->length() > MAX_FLAT_PAT_LEN || StringHasRegExpMetaChars(linearPattern)) {
-        *isFlat = false;
-        return true;
-    }
-
-    *isFlat = true;
-    if (str->isRope()) {
-        if (!RopeMatch(cx, &str->asRope(), linearPattern, match))
-            return false;
-    } else {
-        *match = StringMatch(&str->asLinear(), linearPattern);
-    }
-
-    return true;
-}
-
-static bool
-BuildFlatMatchArray(JSContext* cx, HandleString str, HandleString pattern, int32_t match,
-                    MutableHandleValue rval)
-{
-    if (match < 0) {
-        rval.setNull();
-        return true;
-    }
-
-    /* Get the templateObject that defines the shape and type of the output object */
-    JSObject* templateObject = cx->compartment()->regExps.getOrCreateMatchResultTemplateObject(cx);
-    if (!templateObject)
-        return false;
-
-    RootedArrayObject arr(cx, NewDenseFullyAllocatedArrayWithTemplate(cx, 1, templateObject));
-    if (!arr)
-        return false;
-
-    /* Store a Value for each pair. */
-    arr->setDenseInitializedLength(1);
-    arr->initDenseElement(0, StringValue(pattern));
-
-    /* Set the |index| property. (TemplateObject positions it in slot 0) */
-    arr->setSlot(0, Int32Value(match));
-
-    /* Set the |input| property. (TemplateObject positions it in slot 1) */
-    arr->setSlot(1, StringValue(str));
-
-#ifdef DEBUG
-    RootedValue test(cx);
-    RootedId id(cx, NameToId(cx->names().index));
-    if (!NativeGetProperty(cx, arr, id, &test))
-        return false;
-    MOZ_ASSERT(test == arr->getSlot(0));
-    id = NameToId(cx->names().input);
-    if (!NativeGetProperty(cx, arr, id, &test))
-        return false;
-    MOZ_ASSERT(test == arr->getSlot(1));
-#endif
-
-    rval.setObject(*arr);
-    return true;
-}
-
-#ifdef DEBUG
-static bool
-CallIsStringOptimizable(JSContext* cx, const char* name, bool* result)
-{
-    JSAtom* atom = Atomize(cx, name, strlen(name));
-    if (!atom)
-        return false;
-    RootedPropertyName propName(cx, atom->asPropertyName());
-
-    RootedValue funcVal(cx);
-    if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), propName, propName, 0, &funcVal))
-        return false;
-
-    InvokeArgs args(cx);
-    if (!args.init(0))
-        return false;
-    args.setCallee(funcVal);
-    args.setThis(UndefinedValue());
-    if (!Invoke(cx, args))
-        return false;
-
-    *result = args.rval().toBoolean();
-    return true;
-}
-#endif
-
-bool
-js::FlatStringMatch(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    MOZ_ASSERT(args.length() == 2);
-    MOZ_ASSERT(args[0].isString());
-    MOZ_ASSERT(args[1].isString());
-#ifdef DEBUG
-    bool isOptimizable = false;
-    if (!CallIsStringOptimizable(cx, "IsStringMatchOptimizable", &isOptimizable))
-        return false;
-    MOZ_ASSERT(isOptimizable);
-#endif
-
-    RootedString str(cx,args[0].toString());
-    RootedString pattern(cx, args[1].toString());
-
-    bool isFlat = false;
-    int32_t match = 0;
-    if (!FlatStringMatchHelper(cx, str, pattern, &isFlat, &match))
-        return false;
-
-    if (!isFlat) {
-        args.rval().setUndefined();
-        return true;
-    }
-
-    return BuildFlatMatchArray(cx, str, pattern, match, args.rval());
-}
--- a/js/src/jsstr.h
+++ b/js/src/jsstr.h
@@ -426,16 +426,19 @@ FileEscapedString(FILE* fp, const char* 
 {
     Fprinter out(fp);
     bool res = EscapedStringPrinter(out, chars, length, quote);
     out.finish();
     return res;
 }
 
 bool
+str_match(JSContext* cx, unsigned argc, Value* vp);
+
+bool
 str_search(JSContext* cx, unsigned argc, Value* vp);
 
 bool
 str_split(JSContext* cx, unsigned argc, Value* vp);
 
 JSObject*
 str_split_string(JSContext* cx, HandleObjectGroup group, HandleString str, HandleString sep);
 
@@ -445,14 +448,11 @@ str_flat_replace_string(JSContext *cx, H
 
 JSString*
 str_replace_string_raw(JSContext* cx, HandleString string, HandleString pattern,
                        HandleString replacement);
 
 extern bool
 StringConstructor(JSContext* cx, unsigned argc, Value* vp);
 
-extern bool
-FlatStringMatch(JSContext* cx, unsigned argc, Value* vp);
-
 } /* namespace js */
 
 #endif /* jsstr_h */
deleted file mode 100644
--- a/js/src/tests/ecma_6/RegExp/RegExpExec-exec.js
+++ /dev/null
@@ -1,18 +0,0 @@
-var BUGNUMBER = 887016;
-var summary = "RegExpExec should throw if exec property of non-RegExp is not callable";
-
-print(BUGNUMBER + ": " + summary);
-
-for (var exec of [null, 0, false, undefined, ""]) {
-  // RegExp with non-callable exec
-  var re = /a/;
-  re.exec = exec;
-  RegExp.prototype[Symbol.match].call(re, "foo");
-
-  // non-RegExp with non-callable exec
-  assertThrowsInstanceOf(() => RegExp.prototype[Symbol.match].call({ exec }, "foo"),
-                         TypeError);
-}
-
-if (typeof reportCompare === "function")
-    reportCompare(true, true);
deleted file mode 100644
--- a/js/src/tests/ecma_6/RegExp/RegExpExec-return.js
+++ /dev/null
@@ -1,31 +0,0 @@
-var BUGNUMBER = 887016;
-var summary = "RegExpExec should throw if returned value is not an object nor null.";
-
-print(BUGNUMBER + ": " + summary);
-
-for (var ret of [null, {}, [], /a/]) {
-  assertEq(RegExp.prototype[Symbol.match].call({
-    get global() {
-      return false;
-    },
-    exec(S) {
-      return ret;
-    }
-  }, "foo"), ret);
-}
-
-for (ret of [undefined, 1, true, false, Symbol.iterator]) {
-  assertThrowsInstanceOf(() => {
-    RegExp.prototype[Symbol.match].call({
-      get global() {
-        return false;
-      },
-      exec(S) {
-        return ret;
-      }
-    }, "foo");
-  }, TypeError);
-}
-
-if (typeof reportCompare === "function")
-    reportCompare(true, true);
--- a/js/src/tests/ecma_6/RegExp/constructor-constructor.js
+++ b/js/src/tests/ecma_6/RegExp/constructor-constructor.js
@@ -20,34 +20,16 @@ assertEq(RegExp(re) === re, false);
 assertEq(RegExp(re).toString(), re.toString());
 
 
 re = new Proxy(/a/, {
   get(that, name) {
     return that[name];
   }
 });
-assertEq(RegExp(re), re);
-re = new Proxy(/a/, {
-  get(that, name) {
-    if (name == "constructor") {
-      return function() {};
-    }
-    return that[name];
-  }
-});
-assertEq(RegExp(re) === re, false);
-re = new Proxy(/a/, {
-  get(that, name) {
-    if (name == Symbol.match) {
-      return undefined;
-    }
-    return that[name];
-  }
-});
 assertEq(RegExp(re) === re, false);
 
 re = new Proxy(g.eval(`/a/`), {
   get(that, name) {
     return that[name];
   }
 });
 assertEq(RegExp(re) === re, false);
deleted file mode 100644
--- a/js/src/tests/ecma_6/RegExp/match-this.js
+++ /dev/null
@@ -1,12 +0,0 @@
-var BUGNUMBER = 887016;
-var summary = "RegExp.prototype[@@match] should check this value.";
-
-print(BUGNUMBER + ": " + summary);
-
-for (var v of [null, 1, true, undefined, "", Symbol.iterator]) {
-  assertThrowsInstanceOf(() => RegExp.prototype[Symbol.match].call(v),
-                         TypeError);
-}
-
-if (typeof reportCompare === "function")
-    reportCompare(true, true);
deleted file mode 100644
--- a/js/src/tests/ecma_6/RegExp/match-trace.js
+++ /dev/null
@@ -1,147 +0,0 @@
-var BUGNUMBER = 887016;
-var summary = "Trace RegExp.prototype[@@match] behavior.";
-
-print(BUGNUMBER + ": " + summary);
-
-var n;
-var log;
-var target;
-var global;
-var unicode;
-var logProxy;
-
-var execResult;
-var lastIndexResult;
-var lastIndexExpected;
-
-function P(A) {
-  return new Proxy(A, {
-    get(that, name) {
-      if (logProxy)
-        log += "get:result[" + name + "],";
-      return that[name];
-    }
-  });
-}
-
-var myRegExp = {
-  get global() {
-    log += "get:global,";
-    return global;
-  },
-  get lastIndex() {
-    log += "get:lastIndex,";
-    return lastIndexResult[n];
-  },
-  set lastIndex(v) {
-    log += "set:lastIndex,";
-    assertEq(v, lastIndexExpected[n]);
-  },
-  get unicode() {
-    log += "get:unicode,";
-    return unicode;
-  },
-  get exec() {
-    log += "get:exec,";
-    return function(S) {
-      log += "call:exec,";
-      assertEq(S, target);
-      return execResult[n++];
-    };
-  },
-};
-
-function reset() {
-  n = 0;
-  log = "";
-  target = "abcAbcABC";
-  global = true;
-  unicode = false;
-  logProxy = true;
-}
-
-// Trace global with non-empty match.
-reset();
-execResult        = [    P(["abc"]), P(["ABC"]), null ];
-lastIndexResult   = [ ,  ,           ,                ];
-lastIndexExpected = [ 0, ,           ,                ];
-var ret = RegExp.prototype[Symbol.match].call(myRegExp, target);
-assertEq(JSON.stringify(ret), `["abc","ABC"]`);
-assertEq(log,
-         "get:global," +
-         "get:unicode," +
-         "set:lastIndex," +
-         "get:exec,call:exec,get:result[0]," +
-         "get:exec,call:exec,get:result[0]," +
-         "get:exec,call:exec,");
-
-// Trace global with empty match.
-reset();
-execResult        = [    P([""]), P([""]), null ];
-lastIndexResult   = [ ,  4,       20,           ];
-lastIndexExpected = [ 0, 5,       21,           ];
-ret = RegExp.prototype[Symbol.match].call(myRegExp, target);
-assertEq(JSON.stringify(ret), `["",""]`);
-assertEq(log,
-         "get:global," +
-         "get:unicode," +
-         "set:lastIndex," +
-         "get:exec,call:exec,get:result[0],get:lastIndex,set:lastIndex," +
-         "get:exec,call:exec,get:result[0],get:lastIndex,set:lastIndex," +
-         "get:exec,call:exec,");
-
-// Trace global and unicode with empty match.
-// 1. not surrogate pair
-// 2. lead surrogate pair
-// 3. trail surrogate pair
-// 4. lead surrogate pair without trail surrogate pair
-// 5. index overflow
-reset();
-unicode = true;
-//        0123     4     5678
-target = "___\uD83D\uDC38___\uD83D";
-execResult        = [    P([""]), P([""]), P([""]), P([""]), P([""]), null ];
-lastIndexResult   = [ ,  2,       3,       4,       8,       9,            ];
-lastIndexExpected = [ 0, 3,       5,       5,       9,       10,           ];
-ret = RegExp.prototype[Symbol.match].call(myRegExp, target);
-assertEq(JSON.stringify(ret), `["","","","",""]`);
-assertEq(log,
-         "get:global," +
-         "get:unicode," +
-         "set:lastIndex," +
-         "get:exec,call:exec,get:result[0],get:lastIndex,set:lastIndex," +
-         "get:exec,call:exec,get:result[0],get:lastIndex,set:lastIndex," +
-         "get:exec,call:exec,get:result[0],get:lastIndex,set:lastIndex," +
-         "get:exec,call:exec,get:result[0],get:lastIndex,set:lastIndex," +
-         "get:exec,call:exec,get:result[0],get:lastIndex,set:lastIndex," +
-         "get:exec,call:exec,");
-
-// Trace global with no match.
-reset();
-execResult        = [    null ];
-lastIndexResult   = [ ,       ];
-lastIndexExpected = [ 0,      ];
-ret = RegExp.prototype[Symbol.match].call(myRegExp, target);
-assertEq(ret, null);
-assertEq(log,
-         "get:global," +
-         "get:unicode," +
-         "set:lastIndex," +
-         "get:exec,call:exec,");
-
-// Trace non-global.
-reset();
-global = false;
-execResult        = [ P(["abc"]) ];
-lastIndexResult   = [];
-lastIndexExpected = [];
-ret = RegExp.prototype[Symbol.match].call(myRegExp, target);
-// ret is the Proxy on non-global case, disable logging.
-logProxy = false;
-assertEq(JSON.stringify(ret), `["abc"]`);
-assertEq(log,
-         "get:global," +
-         "get:exec,call:exec,");
-
-if (typeof reportCompare === "function")
-    reportCompare(true, true);
deleted file mode 100644
--- a/js/src/tests/ecma_6/RegExp/match.js
+++ /dev/null
@@ -1,36 +0,0 @@
-var BUGNUMBER = 887016;
-var summary = "Implement RegExp.prototype[@@match].";
-
-print(BUGNUMBER + ": " + summary);
-
-assertEq(RegExp.prototype[Symbol.match].name, "[Symbol.match]");
-assertEq(RegExp.prototype[Symbol.match].length, 1);
-var desc = Object.getOwnPropertyDescriptor(RegExp.prototype, Symbol.match);
-assertEq(desc.configurable, true);
-assertEq(desc.enumerable, false);
-assertEq(desc.writable, true);
-
-var re = /a/;
-var v = re[Symbol.match]("abcAbcABC");
-assertEq(Array.isArray(v), true);
-assertEq(v.length, 1);
-assertEq(v[0], "a");
-
-re = /d/;
-v = re[Symbol.match]("abcAbcABC");
-assertEq(v, null);
-
-re = /a/ig;
-v = re[Symbol.match]("abcAbcABC");
-assertEq(Array.isArray(v), true);
-assertEq(v.length, 3);
-assertEq(v[0], "a");
-assertEq(v[1], "A");
-assertEq(v[2], "A");
-
-re = /d/g;
-v = re[Symbol.match]("abcAbcABC");
-assertEq(v, null);
-
-if (typeof reportCompare === "function")
-    reportCompare(true, true);
deleted file mode 100644
--- a/js/src/tests/ecma_6/String/match.js
+++ /dev/null
@@ -1,31 +0,0 @@
-var BUGNUMBER = 887016;
-var summary = "Call RegExp.prototype[@@match] from String.prototype.match.";
-
-print(BUGNUMBER + ": " + summary);
-
-var called = 0;
-var myRegExp = {
-  [Symbol.match](S) {
-    assertEq(S, "abcAbcABC");
-    called++;
-    return 42;
-  }
-};
-assertEq("abcAbcABC".match(myRegExp), 42);
-assertEq(called, 1);
-
-var origMatch = RegExp.prototype[Symbol.match];
-
-called = 0;
-RegExp.prototype[Symbol.match] = function(S) {
-  assertEq(S, "abcAbcABC");
-  called++;
-  return 43;
-};
-assertEq("abcAbcABC".match("abc"), 43);
-assertEq(called, 1);
-
-RegExp.prototype[Symbol.match] = origMatch;
-
-if (typeof reportCompare === "function")
-    reportCompare(true, true);
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -448,24 +448,16 @@ GlobalObject::initSelfHostingBuiltins(JS
     RootedValue std_iterator(cx);
     std_iterator.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::iterator));
     if (!JS_DefineProperty(cx, global, "std_iterator", std_iterator,
                            JSPROP_PERMANENT | JSPROP_READONLY))
     {
         return false;
     }
 
-    RootedValue std_match(cx);
-    std_match.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::match));
-    if (!JS_DefineProperty(cx, global, "std_match", std_match,
-                           JSPROP_PERMANENT | JSPROP_READONLY))
-    {
-        return false;
-    }
-
     RootedValue std_species(cx);
     std_species.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::species));
     if (!JS_DefineProperty(cx, global, "std_species", std_species,
                            JSPROP_PERMANENT | JSPROP_READONLY))
     {
         return false;
     }
 
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -13,17 +13,16 @@
 
 #include "jsarray.h"
 #include "jscntxt.h"
 #include "jscompartment.h"
 #include "jsdate.h"
 #include "jsfriendapi.h"
 #include "jsfun.h"
 #include "jshashutil.h"
-#include "jsstr.h"
 #include "jsweakmap.h"
 #include "jswrapper.h"
 #include "selfhosted.out.h"
 
 #include "builtin/Intl.h"
 #include "builtin/MapObject.h"
 #include "builtin/ModuleObject.h"
 #include "builtin/Object.h"
@@ -2070,42 +2069,16 @@ intrinsic_captureCurrentStack(JSContext*
     RootedObject stack(cx);
     if (!JS::CaptureCurrentStack(cx, &stack, maxFrameCount))
         return false;
 
     args.rval().setObject(*stack);
     return true;
 }
 
-static bool
-IsMatchFlagsArgumentEnabled(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    MOZ_ASSERT(args.length() == 0);
-
-    args.rval().setBoolean(cx->runtime()->options().matchFlagArgument());
-    return true;
-}
-
-static bool
-WarnOnceAboutFlagsArgument(JSContext* cx, unsigned argc, Value* vp)
-{
-    if (!cx->compartment()->warnedAboutFlagsArgument) {
-        if (!JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, GetErrorMessage, nullptr,
-                                          cx->runtime()->options().matchFlagArgument()
-                                          ? JSMSG_DEPRECATED_FLAGS_ARG
-                                          : JSMSG_OBSOLETE_FLAGS_ARG))
-        {
-            return false;
-        }
-        cx->compartment()->warnedAboutFlagsArgument = true;
-    }
-    return true;
-}
-
 // The self-hosting global isn't initialized with the normal set of builtins.
 // Instead, individual C++-implemented functions that're required by
 // self-hosted code are defined as global functions. Accessing these
 // functions via a content compartment's builtins would be unsafe, because
 // content script might have changed the builtins' prototypes' members.
 // Installing the whole set of builtins in the self-hosting compartment, OTOH,
 // would be wasteful: it increases memory usage and initialization time for
 // self-hosting compartment.
@@ -2153,16 +2126,17 @@ static const JSFunctionSpec intrinsic_fu
 
     JS_FN("std_Set_has",                         SetObject::has,               1,0),
     JS_FN("std_Set_iterator",                    SetObject::values,            0,0),
 
     JS_INLINABLE_FN("std_String_fromCharCode",   str_fromCharCode,             1,0, StringFromCharCode),
     JS_INLINABLE_FN("std_String_charCodeAt",     str_charCodeAt,               1,0, StringCharCodeAt),
     JS_FN("std_String_indexOf",                  str_indexOf,                  1,0),
     JS_FN("std_String_lastIndexOf",              str_lastIndexOf,              1,0),
+    JS_FN("std_String_match",                    str_match,                    1,0),
     JS_INLINABLE_FN("std_String_replace",        str_replace,                  2,0, StringReplace),
     JS_INLINABLE_FN("std_String_split",          str_split,                    2,0, StringSplit),
     JS_FN("std_String_startsWith",               str_startsWith,               1,0),
     JS_FN("std_String_toLowerCase",              str_toLowerCase,              0,0),
     JS_FN("std_String_toUpperCase",              str_toUpperCase,              0,0),
 
     JS_FN("std_WeakMap_has",                     WeakMap_has,                  1,0),
     JS_FN("std_WeakMap_get",                     WeakMap_get,                  2,0),
@@ -2415,26 +2389,21 @@ static const JSFunctionSpec intrinsic_fu
     JS_INLINABLE_FN("RegExpTester", RegExpTester, 4,0,
                     RegExpTester),
     JS_FN("RegExpCreate", intrinsic_RegExpCreate, 2,0),
     JS_INLINABLE_FN("RegExpPrototypeOptimizable", RegExpPrototypeOptimizable, 1,0,
                     RegExpPrototypeOptimizable),
     JS_INLINABLE_FN("RegExpInstanceOptimizable", RegExpInstanceOptimizable, 1,0,
                     RegExpInstanceOptimizable),
 
-    JS_FN("FlatStringMatch", FlatStringMatch, 2,0),
-
     // See builtin/RegExp.h for descriptions of the regexp_* functions.
     JS_FN("regexp_exec_no_statics", regexp_exec_no_statics, 2,0),
     JS_FN("regexp_test_no_statics", regexp_test_no_statics, 2,0),
     JS_FN("regexp_construct", regexp_construct_self_hosting, 2,0),
 
-    JS_FN("IsMatchFlagsArgumentEnabled", IsMatchFlagsArgumentEnabled, 0,0),
-    JS_FN("WarnOnceAboutFlagsArgument", WarnOnceAboutFlagsArgument, 0,0),
-
     JS_FN("IsModule", intrinsic_IsInstanceOfBuiltin<ModuleObject>, 1, 0),
     JS_FN("CallModuleMethodIfWrapped",
           CallNonGenericSelfhostedMethod<Is<ModuleObject>>, 2, 0),
     JS_FN("HostResolveImportedModule", intrinsic_HostResolveImportedModule, 2, 0),
     JS_FN("GetModuleEnvironment", intrinsic_GetModuleEnvironment, 1, 0),
     JS_FN("CreateModuleEnvironment", intrinsic_CreateModuleEnvironment, 1, 0),
     JS_FN("CreateImportBinding", intrinsic_CreateImportBinding, 4, 0),
     JS_FN("CreateNamespaceBinding", intrinsic_CreateNamespaceBinding, 3, 0),
--- a/js/xpconnect/tests/chrome/test_xrayToJS.xul
+++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul
@@ -222,17 +222,16 @@ https://bugzilla.mozilla.org/show_bug.cg
 
   gPrototypeProperties['Function'] =
     ["constructor", "toSource", "toString", "apply", "call", "bind",
      "isGenerator", "length", "name", "arguments", "caller"];
   gConstructorProperties['Function'] = constructorProps([])
 
   gPrototypeProperties['RegExp'] =
     ["constructor", "toSource", "toString", "compile", "exec", "test",
-     Symbol.match,
      "flags", "global", "ignoreCase", "multiline", "source", "sticky", "unicode",
      "lastIndex"];
   gConstructorProperties['RegExp'] =
     constructorProps(["input", "lastMatch", "lastParen",
                       "leftContext", "rightContext", "$1", "$2", "$3", "$4",
                       "$5", "$6", "$7", "$8", "$9", "$_", "$&", "$+",
                       "$`", "$'"])