Bug 1263340 - Part 3: Use internal slot for sticky flag in RegExp native functions. r=h4writer
authorTooru Fujisawa <arai_a@mac.com>
Sat, 23 Apr 2016 03:09:37 +0900
changeset 294586 86d33031bbd3f7173d8efbc1d5da8bb22352c53f
parent 294585 83a3c6e64690599b3ee426185c9d95efc51d16e3
child 294587 8b08faebf408b352fde6504d33b3faaf6149a62f
push id30208
push usercbook@mozilla.com
push dateMon, 25 Apr 2016 09:55:37 +0000
treeherdermozilla-central@1c6385ae1fe7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersh4writer
bugs1263340
milestone48.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 1263340 - Part 3: Use internal slot for sticky flag in RegExp native functions. r=h4writer
js/src/builtin/RegExp.cpp
js/src/builtin/RegExp.h
js/src/builtin/RegExp.js
js/src/builtin/RegExpGlobalReplaceOpt.h.js
js/src/builtin/RegExpLocalReplaceOpt.h.js
js/src/builtin/String.js
js/src/jit/CodeGenerator.cpp
js/src/jit/Lowering.cpp
js/src/jit/MCallOptimize.cpp
js/src/jit/MIR.h
js/src/jit/Recover.cpp
js/src/jit/TypePolicy.cpp
js/src/jit/arm/Assembler-arm.h
js/src/jit/arm64/Assembler-arm64.h
js/src/jit/mips-shared/Assembler-mips-shared.h
js/src/jit/shared/LIR-shared.h
js/src/jit/x64/Assembler-x64.h
js/src/jit/x86/Assembler-x86.h
js/src/vm/RegExpObject.cpp
js/src/vm/RegExpObject.h
js/src/vm/RegExpStatics.cpp
js/src/vm/RegExpStatics.h
js/src/vm/SelfHosting.cpp
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -23,17 +23,20 @@
 
 using namespace js;
 using namespace js::unicode;
 
 using mozilla::CheckedInt;
 using mozilla::ArrayLength;
 using mozilla::Maybe;
 
-/* ES6 21.2.5.2.2 steps 19-29. */
+/*
+ * ES 2017 draft rev 6a13789aa9e7c6de4e96b7d3e24d9e6eba6584ad 21.2.5.2.2
+ * steps 3, 16-25.
+ */
 bool
 js::CreateRegExpMatchResult(JSContext* cx, HandleString input, const MatchPairs& matches,
                             MutableHandleValue rval)
 {
     MOZ_ASSERT(input);
 
     /*
      * Create the (slow) result array for a match.
@@ -48,22 +51,22 @@ js::CreateRegExpMatchResult(JSContext* c
     /* Get the templateObject that defines the shape and type of the output object */
     JSObject* templateObject = cx->compartment()->regExps.getOrCreateMatchResultTemplateObject(cx);
     if (!templateObject)
         return false;
 
     size_t numPairs = matches.length();
     MOZ_ASSERT(numPairs > 0);
 
-    /* Step 19. */
+    /* Step 17. */
     RootedArrayObject arr(cx, NewDenseFullyAllocatedArrayWithTemplate(cx, numPairs, templateObject));
     if (!arr)
         return false;
 
-    /* Steps 27-28
+    /* Steps 22-24.
      * Store a Value for each pair. */
     for (size_t i = 0; i < numPairs; i++) {
         const MatchPair& pair = matches[i];
 
         if (pair.isUndefined()) {
             MOZ_ASSERT(i != 0); /* Since we had a match, first pair must be present. */
             arr->setDenseInitializedLength(i + 1);
             arr->initDenseElement(i, UndefinedValue());
@@ -71,66 +74,69 @@ js::CreateRegExpMatchResult(JSContext* c
             JSLinearString* str = NewDependentString(cx, input, pair.start, pair.length());
             if (!str)
                 return false;
             arr->setDenseInitializedLength(i + 1);
             arr->initDenseElement(i, StringValue(str));
         }
     }
 
-    /* Step 24 (reordered)
+    /* Step 20 (reordered).
      * Set the |index| property. (TemplateObject positions it in slot 0) */
     arr->setSlot(0, Int32Value(matches[0].start));
 
-    /* Step 25 (reordered)
+    /* Step 21 (reordered).
      * Set the |input| property. (TemplateObject positions it in slot 1) */
     arr->setSlot(1, StringValue(input));
 
 #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
 
-    /* Step 29. */
+    /* Step 25. */
     rval.setObject(*arr);
     return true;
 }
 
 static int32_t
 CreateRegExpSearchResult(JSContext* cx, const MatchPairs& matches)
 {
     /* Fit the start and limit of match into a int32_t. */
     uint32_t position = matches[0].start;
     uint32_t lastIndex = matches[0].limit;
     MOZ_ASSERT(position < 0x8000);
     MOZ_ASSERT(lastIndex < 0x8000);
     return position | (lastIndex << 15);
 }
 
-/* ES6 21.2.5.2.2 steps 3, 14-17, except 15.a.i-ii, 15.c.i.1-2. */
+/*
+ * ES 2017 draft rev 6a13789aa9e7c6de4e96b7d3e24d9e6eba6584ad 21.2.5.2.2
+ * steps 3, 9-14, except 12.a.i, 12.c.i.1.
+ */
 static RegExpRunStatus
 ExecuteRegExpImpl(JSContext* cx, RegExpStatics* res, RegExpShared& re, HandleLinearString input,
-                  size_t searchIndex, bool sticky, MatchPairs* matches, size_t* endIndex)
+                  size_t searchIndex, MatchPairs* matches, size_t* endIndex)
 {
-    RegExpRunStatus status = re.execute(cx, input, searchIndex, sticky, matches, endIndex);
+    RegExpRunStatus status = re.execute(cx, input, searchIndex, matches, endIndex);
 
     /* Out of spec: Update RegExpStatics. */
     if (status == RegExpRunStatus_Success && res) {
         if (matches) {
             if (!res->updateFromMatchPairs(cx, input, *matches))
                 return RegExpRunStatus_Error;
         } else {
-            res->updateLazily(cx, input, &re, searchIndex, sticky);
+            res->updateLazily(cx, input, &re, searchIndex);
         }
     }
     return status;
 }
 
 /* Legacy ExecuteRegExp behavior is baked into the JSAPI. */
 bool
 js::ExecuteRegExpLegacy(JSContext* cx, RegExpStatics* res, RegExpObject& reobj,
@@ -138,17 +144,17 @@ js::ExecuteRegExpLegacy(JSContext* cx, R
                         MutableHandleValue rval)
 {
     RegExpGuard shared(cx);
     if (!reobj.getShared(cx, &shared))
         return false;
 
     ScopedMatchPairs matches(&cx->tempLifoAlloc());
 
-    RegExpRunStatus status = ExecuteRegExpImpl(cx, res, *shared, input, *lastIndex, reobj.sticky(),
+    RegExpRunStatus status = ExecuteRegExpImpl(cx, res, *shared, input, *lastIndex,
                                                &matches, nullptr);
     if (status == RegExpRunStatus_Error)
         return false;
 
     if (status == RegExpRunStatus_Success_NotFound) {
         /* ExecuteRegExp() previously returned an array or null. */
         rval.setNull();
         return true;
@@ -353,89 +359,89 @@ static bool
 regexp_compile(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Steps 1-2. */
     return CallNonGenericMethod<IsRegExpObject, regexp_compile_impl>(cx, args);
 }
 
-/* ES6 21.2.3.1. */
+/*
+ * ES 2017 draft rev 6a13789aa9e7c6de4e96b7d3e24d9e6eba6584ad 21.2.3.1.
+ */
 bool
 js::regexp_construct(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    // Steps 1-2.
+    // Steps 1.
     bool patternIsRegExp;
     if (!IsRegExp(cx, args.get(0), &patternIsRegExp))
         return false;
 
-
     // We can delay step 3 and step 4a until later, during
     // GetPrototypeFromCallableConstructor calls. Accessing the new.target
     // and the callee from the stack is unobservable.
     if (!args.isConstructing()) {
-        // Step 4b.
+        // Step 3.b.
         if (patternIsRegExp && !args.hasDefined(1)) {
             RootedObject patternObj(cx, &args[0].toObject());
 
-            // Steps 4b.i-ii.
+            // Step 3.b.i.
             RootedValue patternConstructor(cx);
             if (!GetProperty(cx, patternObj, patternObj, cx->names().constructor, &patternConstructor))
                 return false;
 
-            // Step 4b.iii.
+            // Step 3.b.ii.
             if (patternConstructor.isObject() && patternConstructor.toObject() == args.callee()) {
                 args.rval().set(args[0]);
                 return true;
             }
         }
     }
 
     RootedValue patternValue(cx, args.get(0));
 
-    // Step 5.
+    // Step 4.
     ESClassValue cls;
     if (!GetClassOfValue(cx, patternValue, &cls))
         return false;
     if (cls == ESClass_RegExp) {
         // Beware!  |patternObj| might be a proxy into another compartment, so
         // don't assume |patternObj.is<RegExpObject>()|.  For the same reason,
         // don't reuse the RegExpShared below.
         RootedObject patternObj(cx, &patternValue.toObject());
 
-        // Step 5
         RootedAtom sourceAtom(cx);
         RegExpFlag flags;
         {
-            // Step 5.a.
+            // Step 4.a.
             RegExpGuard g(cx);
             if (!RegExpToShared(cx, patternObj, &g))
                 return false;
             sourceAtom = g->getSource();
 
             if (!args.hasDefined(1)) {
-                // Step 5b.
+                // Step 4.b.
                 flags = g->getFlags();
             }
         }
 
-        // Steps 8-9.
+        // Step 7.
         RootedObject proto(cx);
         if (!GetPrototypeFromCallableConstructor(cx, args, &proto))
             return false;
 
         Rooted<RegExpObject*> regexp(cx, RegExpAlloc(cx, proto));
         if (!regexp)
             return false;
 
-        // Step 10.
+        // Step 8.
         if (args.hasDefined(1)) {
-            // Step 5c / 21.2.3.2.2 RegExpInitialize step 5.
+            // Step 4.c / 21.2.3.2.2 RegExpInitialize step 4.
             flags = RegExpFlag(0);
             RootedString flagStr(cx, ToString<CanGC>(cx, args[1]));
             if (!flagStr)
                 return false;
             if (!ParseRegExpFlags(cx, flagStr, &flags))
                 return false;
         }
 
@@ -443,46 +449,46 @@ js::regexp_construct(JSContext* cx, unsi
 
         args.rval().setObject(*regexp);
         return true;
     }
 
     RootedValue P(cx);
     RootedValue F(cx);
 
-    // Step 6.
+    // Step 5.
     if (patternIsRegExp) {
         RootedObject patternObj(cx, &patternValue.toObject());
 
-        // Steps 6a-b.
+        // Step 5.a.
         if (!GetProperty(cx, patternObj, patternObj, cx->names().source, &P))
             return false;
 
-        // Steps 6c-d.
+        // Step 5.b.
         F = args.get(1);
         if (F.isUndefined()) {
             if (!GetProperty(cx, patternObj, patternObj, cx->names().flags, &F))
                 return false;
         }
     } else {
-        // Steps 7a-b.
+        // Steps 6.a-b.
         P = patternValue;
         F = args.get(1);
     }
 
-    // Steps 8-9.
+    // Step 7.
     RootedObject proto(cx);
     if (!GetPrototypeFromCallableConstructor(cx, args, &proto))
         return false;
 
     Rooted<RegExpObject*> regexp(cx, RegExpAlloc(cx, proto));
     if (!regexp)
         return false;
 
-    // Step 10.
+    // Step 8.
     if (!RegExpInitializeIgnoringLastIndex(cx, regexp, P, F))
         return false;
     regexp->zeroLastIndex(cx);
 
     args.rval().setObject(*regexp);
     return true;
 }
 
@@ -506,16 +512,53 @@ js::regexp_construct_self_hosting(JSCont
     if (!RegExpInitializeIgnoringLastIndex(cx, regexp, args[0], args.get(1)))
         return false;
     regexp->zeroLastIndex(cx);
 
     args.rval().setObject(*regexp);
     return true;
 }
 
+/*
+ * ES 2017 draft rev 6a13789aa9e7c6de4e96b7d3e24d9e6eba6584ad 21.2.3.1
+ * steps 4, 7-8.
+ * Ignore sticky flag of flags argument, for optimized path in @@split.
+ */
+bool
+js::regexp_construct_no_sticky(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    MOZ_ASSERT(args.length() == 2);
+    MOZ_ASSERT(!args.isConstructing());
+
+    Rooted<RegExpObject*> rx(cx, &args[0].toObject().as<RegExpObject>());
+
+    // Step 4.a.
+    RootedAtom sourceAtom(cx, rx->getSource());
+
+    // Step 4.c.
+    RootedString flagStr(cx, args[1].toString());
+    RegExpFlag flags = RegExpFlag(0);
+    if (!ParseRegExpFlags(cx, flagStr, &flags))
+        return false;
+
+    // Ignore sticky flag.
+    flags = RegExpFlag(flags & ~StickyFlag);
+
+    // Step 7.
+    Rooted<RegExpObject*> regexp(cx, RegExpAlloc(cx));
+    if (!regexp)
+        return false;
+
+    // Step 8.
+    regexp->initAndZeroLastIndex(sourceAtom, flags, cx);
+    args.rval().setObject(*regexp);
+    return true;
+}
+
 /* ES6 draft rev32 21.2.5.4. */
 MOZ_ALWAYS_INLINE bool
 regexp_global_impl(JSContext* cx, const CallArgs& args)
 {
     MOZ_ASSERT(IsRegExpObject(args.thisv()));
     Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
 
     /* Steps 4-6. */
@@ -800,20 +843,23 @@ IsTrailSurrogateWithLeadSurrogate(JSCont
     if (index <= 0 || size_t(index) >= input->length())
         return false;
 
     return input->hasLatin1Chars()
            ? IsTrailSurrogateWithLeadSurrogateImpl<Latin1Char>(cx, input, index)
            : IsTrailSurrogateWithLeadSurrogateImpl<char16_t>(cx, input, index);
 }
 
-/* ES6 21.2.5.2.2 steps 3, 11-17, except 15.a.i-ii, 15.c.i.1-2. */
+/*
+ * ES 2017 draft rev 6a13789aa9e7c6de4e96b7d3e24d9e6eba6584ad 21.2.5.2.2
+ * steps 3, 9-14, except 12.a.i, 12.c.i.1.
+ */
 static RegExpRunStatus
 ExecuteRegExp(JSContext* cx, HandleObject regexp, HandleString string,
-              int32_t lastIndex, bool sticky,
+              int32_t lastIndex,
               MatchPairs* matches, size_t* endIndex, RegExpStaticsUpdate staticsUpdate)
 {
     /*
      * WARNING: Despite the presence of spec step comment numbers, this
      *          algorithm isn't consistent with any ES6 version, draft or
      *          otherwise.  YOU HAVE BEEN WARNED.
      */
 
@@ -835,22 +881,23 @@ ExecuteRegExp(JSContext* cx, HandleObjec
 
     RootedLinearString input(cx, string->ensureLinear(cx));
     if (!input)
         return RegExpRunStatus_Error;
 
     /* Handled by caller */
     MOZ_ASSERT(lastIndex >= 0 && size_t(lastIndex) <= input->length());
 
-    /* Steps 4-10 performed by the caller. */
+    /* Steps 4-8 performed by the caller. */
 
-    /* Steps 12-13. */
+    /* Step 10. */
     if (reobj->unicode()) {
         /*
-         * ES6 21.2.2.2 step 2.
+         * ES 2017 draft rev 6a13789aa9e7c6de4e96b7d3e24d9e6eba6584ad
+         * 21.2.2.2 step 2.
          *   Let listIndex be the index into Input of the character that was
          *   obtained from element index of str.
          *
          * In the spec, pattern match is performed with decoded Unicode code
          * points, but our implementation performs it with UTF-16 encoded
          * string.  In step 2, we should decrement lastIndex (index) if it
          * points the trail surrogate that has corresponding lead surrogate.
          *
@@ -864,214 +911,217 @@ ExecuteRegExp(JSContext* cx, HandleObjec
          * different values for `result.index` under certain conditions.
          * However, the spec will change to match our implementation's
          * behavior. See https://github.com/tc39/ecma262/issues/128.
          */
         if (IsTrailSurrogateWithLeadSurrogate(cx, input, lastIndex))
             lastIndex--;
     }
 
-    /* Steps 3, 14-17, except 15.a.i-ii, 15.c.i.1-2. */
-    RegExpRunStatus status = ExecuteRegExpImpl(cx, res, *re, input, lastIndex, sticky, matches, endIndex);
+    /* Steps 3, 11-14, except 12.a.i, 12.c.i.1. */
+    RegExpRunStatus status = ExecuteRegExpImpl(cx, res, *re, input, lastIndex, matches, endIndex);
     if (status == RegExpRunStatus_Error)
         return RegExpRunStatus_Error;
 
-    /* Steps 15.a.i-ii, 18 are done by Self-hosted function. */
+    /* Steps 12.a.i, 12.c.i.i, 15 are done by Self-hosted function. */
 
     return status;
 }
 
-/* ES6 21.2.5.2.2 steps 3, 11-29, except 15.a.i-ii, 15.c.i.1-2, 18. */
+/*
+ * ES 2017 draft rev 6a13789aa9e7c6de4e96b7d3e24d9e6eba6584ad 21.2.5.2.2
+ * steps 3, 9-25, except 12.a.i, 12.c.i.1, 15.
+ */
 static bool
 RegExpMatcherImpl(JSContext* cx, HandleObject regexp, HandleString string,
-                  int32_t lastIndex, bool sticky,
-                  RegExpStaticsUpdate staticsUpdate, MutableHandleValue rval)
+                  int32_t lastIndex, RegExpStaticsUpdate staticsUpdate, MutableHandleValue rval)
 {
     /* Execute regular expression and gather matches. */
     ScopedMatchPairs matches(&cx->tempLifoAlloc());
 
-    /* Steps 3, 11-17, except 15.a.i-ii, 15.c.i.1-2. */
-    RegExpRunStatus status = ExecuteRegExp(cx, regexp, string, lastIndex, sticky,
+    /* Steps 3, 9-14, except 12.a.i, 12.c.i.1. */
+    RegExpRunStatus status = ExecuteRegExp(cx, regexp, string, lastIndex,
                                            &matches, nullptr, staticsUpdate);
     if (status == RegExpRunStatus_Error)
         return false;
 
-    /* Steps 15.a, 15.c. */
+    /* Steps 12.a, 12.c. */
     if (status == RegExpRunStatus_Success_NotFound) {
         rval.setNull();
         return true;
     }
 
-    /* Steps 19-29 */
+    /* Steps 16-25 */
     return CreateRegExpMatchResult(cx, string, matches, rval);
 }
 
-/* ES6 21.2.5.2.2 steps 3, 11-29, except 15.a.i-ii, 15.c.i.1-2, 18. */
+/*
+ * ES 2017 draft rev 6a13789aa9e7c6de4e96b7d3e24d9e6eba6584ad 21.2.5.2.2
+ * steps 3, 9-25, except 12.a.i, 12.c.i.1, 15.
+ */
 bool
 js::RegExpMatcher(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    MOZ_ASSERT(args.length() == 4);
+    MOZ_ASSERT(args.length() == 3);
     MOZ_ASSERT(IsRegExpObject(args[0]));
     MOZ_ASSERT(args[1].isString());
     MOZ_ASSERT(args[2].isNumber());
-    MOZ_ASSERT(args[3].isBoolean());
 
     RootedObject regexp(cx, &args[0].toObject());
     RootedString string(cx, args[1].toString());
     RootedValue lastIndexVal(cx, args[2]);
-    bool sticky = ToBoolean(args[3]);
 
     int32_t lastIndex = 0;
     if (!ToInt32(cx, lastIndexVal, &lastIndex))
         return false;
 
-    /* Steps 3, 11-29, except 15.a.i-ii, 15.c.i.1-2, 18. */
-    return RegExpMatcherImpl(cx, regexp, string, lastIndex, sticky,
+    /* Steps 3, 9-25, except 12.a.i, 12.c.i.1, 15. */
+    return RegExpMatcherImpl(cx, regexp, string, lastIndex,
                              UpdateRegExpStatics, args.rval());
 }
 
 /*
  * Separate interface for use by IonMonkey.
  * This code cannot re-enter Ion code.
  */
 bool
 js::RegExpMatcherRaw(JSContext* cx, HandleObject regexp, HandleString input,
-                     int32_t lastIndex, bool sticky,
+                     int32_t lastIndex,
                      MatchPairs* maybeMatches, MutableHandleValue output)
 {
     MOZ_ASSERT(lastIndex >= 0);
 
     // The MatchPairs will always be passed in, but RegExp execution was
     // successful only if the pairs have actually been filled in.
     if (maybeMatches && maybeMatches->pairsRaw()[0] >= 0)
         return CreateRegExpMatchResult(cx, input, *maybeMatches, output);
-    return RegExpMatcherImpl(cx, regexp, input, lastIndex, sticky,
+    return RegExpMatcherImpl(cx, regexp, input, lastIndex,
                              UpdateRegExpStatics, output);
 }
 
 /*
- * ES6 21.2.5.2.2 steps 3, 11-29, except 15.a.i-ii, 15.c.i.1-2, 18.
+ * ES 2017 draft rev 6a13789aa9e7c6de4e96b7d3e24d9e6eba6584ad 21.2.5.2.2
+ * steps 3, 9-25, except 12.a.i, 12.c.i.1, 15.
  * This code is inlined in CodeGenerator.cpp generateRegExpSearcherStub,
  * changes to this code need to get reflected in there too.
  */
 static bool
 RegExpSearcherImpl(JSContext* cx, HandleObject regexp, HandleString string,
-                  int32_t lastIndex, bool sticky,
-                  RegExpStaticsUpdate staticsUpdate, int32_t* result)
+                   int32_t lastIndex, RegExpStaticsUpdate staticsUpdate, int32_t* result)
 {
     /* Execute regular expression and gather matches. */
     ScopedMatchPairs matches(&cx->tempLifoAlloc());
 
-    /* Steps 3, 11-17, except 15.a.i-ii, 15.c.i.1-2. */
-    RegExpRunStatus status = ExecuteRegExp(cx, regexp, string, lastIndex, sticky,
+    /* Steps 3, 9-14, except 12.a.i, 12.c.i.1. */
+    RegExpRunStatus status = ExecuteRegExp(cx, regexp, string, lastIndex,
                                            &matches, nullptr, staticsUpdate);
     if (status == RegExpRunStatus_Error)
         return false;
 
-    /* Steps 15.a, 15.c. */
+    /* Steps 12.a, 12.c. */
     if (status == RegExpRunStatus_Success_NotFound) {
         *result = -1;
         return true;
     }
 
-    /* Steps 19-29 */
+    /* Steps 16-25 */
     *result = CreateRegExpSearchResult(cx, matches);
     return true;
 }
 
-/* ES6 21.2.5.2.2 steps 3, 11-29, except 15.a.i-ii, 15.c.i.1-2, 18. */
+/*
+ * ES 2017 draft rev 6a13789aa9e7c6de4e96b7d3e24d9e6eba6584ad 21.2.5.2.2
+ * steps 3, 9-25, except 12.a.i, 12.c.i.1, 15.
+ */
 bool
 js::RegExpSearcher(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    MOZ_ASSERT(args.length() == 4);
+    MOZ_ASSERT(args.length() == 3);
     MOZ_ASSERT(IsRegExpObject(args[0]));
     MOZ_ASSERT(args[1].isString());
     MOZ_ASSERT(args[2].isNumber());
-    MOZ_ASSERT(args[3].isBoolean());
 
     RootedObject regexp(cx, &args[0].toObject());
     RootedString string(cx, args[1].toString());
     RootedValue lastIndexVal(cx, args[2]);
-    bool sticky = ToBoolean(args[3]);
 
     int32_t lastIndex = 0;
     if (!ToInt32(cx, lastIndexVal, &lastIndex))
         return false;
 
-    /* Steps 3, 11-29, except 15.a.i-ii, 15.c.i.1-2, 18. */
+    /* Steps 3, 9-25, except 12.a.i, 12.c.i.1, 15. */
     int32_t result = 0;
-    if (!RegExpSearcherImpl(cx, regexp, string, lastIndex, sticky, UpdateRegExpStatics, &result))
+    if (!RegExpSearcherImpl(cx, regexp, string, lastIndex, UpdateRegExpStatics, &result))
         return false;
 
     args.rval().setInt32(result);
     return true;
 }
 
 /*
  * Separate interface for use by IonMonkey.
  * This code cannot re-enter Ion code.
  */
 bool
 js::RegExpSearcherRaw(JSContext* cx, HandleObject regexp, HandleString input,
-                      int32_t lastIndex, bool sticky,
-                      MatchPairs* maybeMatches, int32_t* result)
+                      int32_t lastIndex, MatchPairs* maybeMatches, int32_t* result)
 {
     MOZ_ASSERT(lastIndex >= 0);
 
     // The MatchPairs will always be passed in, but RegExp execution was
     // successful only if the pairs have actually been filled in.
     if (maybeMatches && maybeMatches->pairsRaw()[0] >= 0) {
         *result = CreateRegExpSearchResult(cx, *maybeMatches);
         return true;
     }
-    return RegExpSearcherImpl(cx, regexp, input, lastIndex, sticky,
+    return RegExpSearcherImpl(cx, regexp, input, lastIndex,
                               UpdateRegExpStatics, result);
 }
 
 bool
 js::regexp_exec_no_statics(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 2);
     MOZ_ASSERT(IsRegExpObject(args[0]));
     MOZ_ASSERT(args[1].isString());
 
     RootedObject regexp(cx, &args[0].toObject());
     RootedString string(cx, args[1].toString());
 
-    return RegExpMatcherImpl(cx, regexp, string, 0, false,
+    return RegExpMatcherImpl(cx, regexp, string, 0,
                              DontUpdateRegExpStatics, args.rval());
 }
 
-/* ES6 21.2.5.2.2 steps 3, 11-17, except 15.a.i-ii, 15.c.i.1-2. */
+/*
+ * ES 2017 draft rev 6a13789aa9e7c6de4e96b7d3e24d9e6eba6584ad 21.2.5.2.2
+ * steps 3, 9-14, except 12.a.i, 12.c.i.1.
+ */
 bool
 js::RegExpTester(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    MOZ_ASSERT(args.length() == 4);
+    MOZ_ASSERT(args.length() == 3);
     MOZ_ASSERT(IsRegExpObject(args[0]));
     MOZ_ASSERT(args[1].isString());
     MOZ_ASSERT(args[2].isNumber());
-    MOZ_ASSERT(args[3].isBoolean());
 
     RootedObject regexp(cx, &args[0].toObject());
     RootedString string(cx, args[1].toString());
     RootedValue lastIndexVal(cx, args[2]);
-    bool sticky = ToBoolean(args[3]);
 
     int32_t lastIndex = 0;
     if (!ToInt32(cx, lastIndexVal, &lastIndex))
         return false;
 
-    /* Steps 3, 11-17, except 15.a.i-ii, 15.c.i.1-2. */
+    /* Steps 3, 9-14, except 12.a.i, 12.c.i.1. */
     size_t endIndex = 0;
-    RegExpRunStatus status = ExecuteRegExp(cx, regexp, string,
-                                           lastIndex, sticky,
+    RegExpRunStatus status = ExecuteRegExp(cx, regexp, string, lastIndex,
                                            nullptr, &endIndex, UpdateRegExpStatics);
 
     if (status == RegExpRunStatus_Error)
         return false;
 
     if (status == RegExpRunStatus_Success) {
         MOZ_ASSERT(endIndex <= INT32_MAX);
         args.rval().setInt32(int32_t(endIndex));
@@ -1082,22 +1132,22 @@ js::RegExpTester(JSContext* cx, unsigned
 }
 
 /*
  * Separate interface for use by IonMonkey.
  * This code cannot re-enter Ion code.
  */
 bool
 js::RegExpTesterRaw(JSContext* cx, HandleObject regexp, HandleString input,
-                    int32_t lastIndex, bool sticky, int32_t* endIndex)
+                    int32_t lastIndex, int32_t* endIndex)
 {
     MOZ_ASSERT(lastIndex >= 0);
 
     size_t endIndexTmp = 0;
-    RegExpRunStatus status = ExecuteRegExp(cx, regexp, input, lastIndex, sticky,
+    RegExpRunStatus status = ExecuteRegExp(cx, regexp, input, lastIndex,
                                            nullptr, &endIndexTmp, UpdateRegExpStatics);
 
     if (status == RegExpRunStatus_Success) {
         MOZ_ASSERT(endIndexTmp <= INT32_MAX);
         *endIndex = int32_t(endIndexTmp);
         return true;
     }
     if (status == RegExpRunStatus_Success_NotFound) {
@@ -1115,17 +1165,17 @@ js::regexp_test_no_statics(JSContext* cx
     MOZ_ASSERT(args.length() == 2);
     MOZ_ASSERT(IsRegExpObject(args[0]));
     MOZ_ASSERT(args[1].isString());
 
     RootedObject regexp(cx, &args[0].toObject());
     RootedString string(cx, args[1].toString());
 
     size_t ignored = 0;
-    RegExpRunStatus status = ExecuteRegExp(cx, regexp, string, 0, false,
+    RegExpRunStatus status = ExecuteRegExp(cx, regexp, string, 0,
                                            nullptr, &ignored, DontUpdateRegExpStatics);
     args.rval().setBoolean(status == RegExpRunStatus_Success);
     return status != RegExpRunStatus_Error;
 }
 
 static void
 GetParen(JSLinearString* matched, JS::Value capture, JSSubString* out)
 {
--- a/js/src/builtin/RegExp.h
+++ b/js/src/builtin/RegExp.h
@@ -40,33 +40,31 @@ bool
 CreateRegExpMatchResult(JSContext* cx, HandleString input, const MatchPairs& matches,
                         MutableHandleValue rval);
 
 extern bool
 RegExpMatcher(JSContext* cx, unsigned argc, Value* vp);
 
 extern bool
 RegExpMatcherRaw(JSContext* cx, HandleObject regexp, HandleString input,
-                 int32_t lastIndex, bool sticky,
-                 MatchPairs* maybeMatches, MutableHandleValue output);
+                 int32_t lastIndex, MatchPairs* maybeMatches, MutableHandleValue output);
 
 extern bool
 RegExpSearcher(JSContext* cx, unsigned argc, Value* vp);
 
 extern bool
 RegExpSearcherRaw(JSContext* cx, HandleObject regexp, HandleString input,
-                  int32_t lastIndex, bool sticky,
-                  MatchPairs* maybeMatches, int32_t* result);
+                  int32_t lastIndex, MatchPairs* maybeMatches, int32_t* result);
 
 extern bool
 RegExpTester(JSContext* cx, unsigned argc, Value* vp);
 
 extern bool
 RegExpTesterRaw(JSContext* cx, HandleObject regexp, HandleString input,
-                int32_t lastIndex, bool sticky, int32_t* endIndex);
+                int32_t lastIndex, int32_t* endIndex);
 
 /*
  * The following functions are for use by self-hosted code.
  */
 
 /*
  * Behaves like regexp.exec(string), but doesn't set RegExp statics.
  *
@@ -88,16 +86,26 @@ regexp_test_no_statics(JSContext* cx, un
  * pattern and flags should be string, and should be called without |new|.
  *
  * Usage: re = regexp_construct(pattern)
  *        re = regexp_construct(pattern, flags)
  */
 extern bool
 regexp_construct_self_hosting(JSContext* cx, unsigned argc, Value* vp);
 
+/*
+ * Behaves like RegExp(pattern, string).
+ * pattern should be a RegExp object, and flags should be a string,
+ * and should be called without |new|.
+ * Dedicated function for RegExp.prototype.split optimized path.
+ * sticky flag is ignored.
+ */
+extern bool
+regexp_construct_no_sticky(JSContext* cx, unsigned argc, Value* vp);
+
 extern bool
 IsRegExp(JSContext* cx, HandleValue value, bool* result);
 
 extern bool
 RegExpCreate(JSContext* cx, HandleValue pattern, HandleValue flags, MutableHandleValue rval);
 
 extern bool
 RegExpPrototypeOptimizable(JSContext* cx, unsigned argc, Value* vp);
--- a/js/src/builtin/RegExp.js
+++ b/js/src/builtin/RegExp.js
@@ -412,23 +412,20 @@ function RegExpGlobalReplaceShortOpt(rx,
     rx.lastIndex = 0;
 
     // Step 12 (reordered).
     var accumulatedResult = "";
 
     // Step 13 (reordered).
     var nextSourcePosition = 0;
 
-    var flags = UnsafeGetInt32FromReservedSlot(rx, REGEXP_FLAGS_SLOT);
-    var sticky = !!(flags & REGEXP_STICKY_FLAG);
-
     // Step 11.
     while (true) {
         // Step 11.a.
-        var result = RegExpSearcher(rx, S, lastIndex, sticky);
+        var result = RegExpSearcher(rx, S, lastIndex);
 
         // Step 11.b.
         if (result === -1)
             break;
 
         var position = result & 0x7fff;
         lastIndex = (result >> 15) & 0x7fff;
 
@@ -518,21 +515,18 @@ function RegExpSearch(string) {
     if (!IsObject(rx))
         ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, rx === null ? "null" : typeof rx);
 
     // Step 3.
     var S = ToString(string);
 
     var result;
     if (IsRegExpMethodOptimizable(rx) && S.length < 0x7fff) {
-        var flags = UnsafeGetInt32FromReservedSlot(rx, REGEXP_FLAGS_SLOT);
-        var sticky = !!(flags & REGEXP_STICKY_FLAG);
-
         // Step 6.
-        result = RegExpSearcher(rx, S, 0, sticky);
+        result = RegExpSearcher(rx, S, 0);
 
         // Step 8.
         if (result === -1)
             return -1;
 
         // Step 9.
         return result & 0x7fff;
     }
@@ -585,42 +579,52 @@ function RegExpSplit(string, limit) {
     var C = SpeciesConstructor(rx, GetBuiltinConstructor("RegExp"));
 
     // Step 5.
     var flags = ToString(rx.flags);
 
     // Steps 6-7.
     var unicodeMatching = callFunction(std_String_includes, flags, "u");
 
-    // Steps 8-9.
-    var newFlags;
-    if (callFunction(std_String_includes, flags, "y"))
-        newFlags = flags;
-    else
-        newFlags = flags + "y";
+    // Step 14 (reordered).
+    var size = S.length;
+
+    var optimizable = IsRegExpSplitOptimizable(C);
+    var splitter;
+    if (optimizable && size !== 0) {
+        // Steps 8-9 (skipped).
 
-    // Step 10.
-    var splitter = new C(rx, newFlags);
+        // Step 10.
+        // If split operation is optimizable, perform non-sticky match.
+        splitter = regexp_construct_no_sticky(rx, flags);
+    } else {
+        // Steps 8-9.
+        var newFlags;
+        if (callFunction(std_String_includes, flags, "y"))
+            newFlags = flags;
+        else
+            newFlags = flags + "y";
+
+        // Step 10.
+        splitter = new C(rx, newFlags);
+    }
 
     // Step 11.
     var A = [];
 
     // Step 12.
     var lengthA = 0;
 
     // Step 13.
     var lim;
     if (limit === undefined)
         lim = MAX_NUMERIC_INDEX;
     else
         lim = limit >>> 0;
 
-    // Step 14.
-    var size = S.length;
-
     // Step 16;
     var p = 0;
 
     // Step 16;
     if (lim === 0)
         return A;
 
     // Step 17.
@@ -634,31 +638,28 @@ function RegExpSplit(string, limit) {
 
         // Step 17.d.
         _DefineDataProperty(A, 0, S);
 
         // Step 17.e.
         return A;
     }
 
-    var optimizable = IsRegExpSplitOptimizable(C);
-
     // Step 18.
     var q = p;
 
     // Step 19.
     while (q < size) {
         var e;
         if (optimizable) {
             // Step 19.a (skipped).
             // splitter.lastIndex is not used.
 
             // Step 19.b.
-            // Directly call RegExpMatcher to ignore flags and find first match.
-            z = RegExpMatcher(splitter, S, q, false);
+            z = RegExpMatcher(splitter, S, q);
 
             // Step 19.c.
             if (z === null)
                 break;
 
             // splitter.lastIndex is not updated.
             q = z.index;
             if (q >= size)
@@ -792,57 +793,54 @@ function RegExpBuiltinExec(R, S, forTest
     // Steps 1-2 (skipped).
 
     // Step 4.
     var lastIndex = ToLength(R.lastIndex);
 
     // Step 5.
     var flags = UnsafeGetInt32FromReservedSlot(R, REGEXP_FLAGS_SLOT);
 
-    // Step 6.
-    var global = !!(flags & REGEXP_GLOBAL_FLAG);
-
-    // Step 7.
-    var sticky = !!(flags & REGEXP_STICKY_FLAG);
+    // Steps 6-7.
+    var globalOrSticky = !!(flags & (REGEXP_GLOBAL_FLAG | REGEXP_STICKY_FLAG));
 
     // Step 8.
-    if (!global && !sticky) {
+    if (!globalOrSticky) {
         lastIndex = 0;
     } else {
         if (lastIndex > S.length) {
             // Steps 12.a.i-ii, 12.c.i.1-2.
             R.lastIndex = 0;
             return forTest ? false : null;
         }
     }
 
     if (forTest) {
         // Steps 3, 9-25, except 12.a.i-ii, 12.c.i.1-2, 15.
-        var endIndex = RegExpTester(R, S, lastIndex, sticky);
+        var endIndex = RegExpTester(R, S, lastIndex);
         if (endIndex == -1) {
             // Steps 12.a.i-ii, 12.c.i.1-2.
             R.lastIndex = 0;
             return false;
         }
 
         // Step 15.
-        if (global || sticky)
+        if (globalOrSticky)
             R.lastIndex = endIndex;
 
         return true;
     }
 
     // Steps 3, 9-25, except 12.a.i-ii, 12.c.i.1-2, 15.
-    var result = RegExpMatcher(R, S, lastIndex, sticky);
+    var result = RegExpMatcher(R, S, lastIndex);
     if (result === null) {
         // Steps 12.a.i-ii, 12.c.i.1-2.
         R.lastIndex = 0;
     } else {
         // Step 15.
-        if (global || sticky)
+        if (globalOrSticky)
             R.lastIndex = result.index + result[0].length;
     }
 
     return result;
 }
 
 // ES6 21.2.5.13.
 function RegExpTest(string) {
--- a/js/src/builtin/RegExpGlobalReplaceOpt.h.js
+++ b/js/src/builtin/RegExpGlobalReplaceOpt.h.js
@@ -29,23 +29,20 @@ function FUNC_NAME(rx, S, lengthS, repla
     rx.lastIndex = 0;
 
     // Step 12 (reordered).
     var accumulatedResult = "";
 
     // Step 13 (reordered).
     var nextSourcePosition = 0;
 
-    var flags = UnsafeGetInt32FromReservedSlot(rx, REGEXP_FLAGS_SLOT);
-    var sticky = !!(flags & REGEXP_STICKY_FLAG);
-
     // Step 11.
     while (true) {
         // Step 11.a.
-        var result = RegExpMatcher(rx, S, lastIndex, sticky);
+        var result = RegExpMatcher(rx, S, lastIndex);
 
         // Step 11.b.
         if (result === null)
             break;
 
 #if defined(FUNCTIONAL) || defined(SUBSTITUTION)
         // Steps 14.a-b.
         var nCaptures = std_Math_max(result.length - 1, 0);
--- a/js/src/builtin/RegExpLocalReplaceOpt.h.js
+++ b/js/src/builtin/RegExpLocalReplaceOpt.h.js
@@ -31,17 +31,17 @@ function FUNC_NAME(rx, S, lengthS, repla
             rx.lastIndex = 0;
             return S;
         }
     } else {
         lastIndex = 0;
     }
 
     // Step 11.a.
-    var result = RegExpMatcher(rx, S, lastIndex, sticky);
+    var result = RegExpMatcher(rx, S, lastIndex);
 
     // Step 11.b.
     if (result === null) {
         rx.lastIndex = 0;
         return S;
     }
 
     // Steps 11.c, 12-13, 14.a-b (skipped).
--- a/js/src/builtin/String.js
+++ b/js/src/builtin/String.js
@@ -54,17 +54,17 @@ function String_match(regexp) {
         }
     }
 
     // Step 4.
     var rx = RegExpCreate(regexp, flags);
 
     // Step 5 (optimized case).
     if (IsStringMatchOptimizable() && !flags)
-        return RegExpMatcher(rx, S, 0, false);
+        return RegExpMatcher(rx, S, 0);
 
     // 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');
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -1036,17 +1036,17 @@ RegExpPairCountAddress(MacroAssembler& m
 }
 
 // Prepare an InputOutputData and optional MatchPairs which space has been
 // allocated for on the stack, and try to execute a RegExp on a string input.
 // If the RegExp was successfully executed and matched the input, fallthrough,
 // otherwise jump to notFound or failure.
 static bool
 PrepareAndExecuteRegExp(JSContext* cx, MacroAssembler& masm, Register regexp, Register input,
-                        Register lastIndex, Register sticky,
+                        Register lastIndex,
                         Register temp1, Register temp2, Register temp3,
                         size_t inputOutputDataStartOffset,
                         RegExpShared::CompilationMode mode,
                         Label* notFound, Label* failure)
 {
     size_t matchPairsStartOffset = inputOutputDataStartOffset + sizeof(irregexp::InputOutputData);
     size_t pairsVectorStartOffset = RegExpPairsVectorStartOffset(inputOutputDataStartOffset);
 
@@ -1147,49 +1147,28 @@ PrepareAndExecuteRegExp(JSContext* cx, M
     // Load the code pointer for the type of input string we have, and compute
     // the input start/end pointers in the InputOutputData.
     Register codePointer = temp1;
     {
         masm.loadStringChars(input, temp2);
         masm.storePtr(temp2, inputStartAddress);
         masm.loadStringLength(input, temp3);
 
-        Label stickyCode, done;
-        masm.branchTest32(Assembler::NonZero, sticky, sticky, &stickyCode);
+        Label isLatin1, done;
+        masm.branchLatin1String(input, &isLatin1);
         {
-            Label isLatin1;
-            masm.branchLatin1String(input, &isLatin1);
-            {
-                masm.lshiftPtr(Imm32(1), temp3);
-                masm.loadPtr(Address(temp1, RegExpShared::offsetOfNotStickyTwoByteJitCode(mode)),
-                             codePointer);
-            }
-            masm.jump(&done);
-            {
-                masm.bind(&isLatin1);
-                masm.loadPtr(Address(temp1, RegExpShared::offsetOfNotStickyLatin1JitCode(mode)),
-                             codePointer);
-            }
+            masm.lshiftPtr(Imm32(1), temp3);
+            masm.loadPtr(Address(temp1, RegExpShared::offsetOfTwoByteJitCode(mode)),
+                         codePointer);
         }
         masm.jump(&done);
         {
-            masm.bind(&stickyCode);
-            Label isLatin1;
-            masm.branchLatin1String(input, &isLatin1);
-            {
-                masm.lshiftPtr(Imm32(1), temp3);
-                masm.loadPtr(Address(temp1, RegExpShared::offsetOfStickyTwoByteJitCode(mode)),
-                             codePointer);
-            }
-            masm.jump(&done);
-            {
-                masm.bind(&isLatin1);
-                masm.loadPtr(Address(temp1, RegExpShared::offsetOfStickyLatin1JitCode(mode)),
-                             codePointer);
-            }
+            masm.bind(&isLatin1);
+            masm.loadPtr(Address(temp1, RegExpShared::offsetOfLatin1JitCode(mode)),
+                         codePointer);
         }
         masm.bind(&done);
 
         masm.addPtr(temp3, temp2);
         masm.storePtr(temp2, inputEndAddress);
     }
 
     // Check the RegExpShared has been compiled for this type of input.
@@ -1205,18 +1184,16 @@ PrepareAndExecuteRegExp(JSContext* cx, M
         masm.computeEffectiveAddress(endIndexAddress, temp2);
         masm.storePtr(temp2, endIndexAddress);
     }
     masm.storePtr(lastIndex, startIndexAddress);
     masm.store32(Imm32(0), matchResultAddress);
 
     // Save any volatile inputs.
     LiveGeneralRegisterSet volatileRegs;
-    if (sticky.volatile_())
-        volatileRegs.add(sticky);
     if (lastIndex.volatile_())
         volatileRegs.add(lastIndex);
     if (input.volatile_())
         volatileRegs.add(input);
     if (regexp.volatile_())
         volatileRegs.add(regexp);
 
     // Execute the RegExp.
@@ -1235,25 +1212,23 @@ PrepareAndExecuteRegExp(JSContext* cx, M
 
     // Lazily update the RegExpStatics.
     masm.movePtr(ImmPtr(res), temp1);
 
     Address pendingInputAddress(temp1, RegExpStatics::offsetOfPendingInput());
     Address matchesInputAddress(temp1, RegExpStatics::offsetOfMatchesInput());
     Address lazySourceAddress(temp1, RegExpStatics::offsetOfLazySource());
     Address lazyIndexAddress(temp1, RegExpStatics::offsetOfLazyIndex());
-    Address lazyStickyAddress(temp1, RegExpStatics::offsetOfLazySticky());
 
     masm.patchableCallPreBarrier(pendingInputAddress, MIRType_String);
     masm.patchableCallPreBarrier(matchesInputAddress, MIRType_String);
     masm.patchableCallPreBarrier(lazySourceAddress, MIRType_String);
 
     masm.storePtr(input, pendingInputAddress);
     masm.storePtr(input, matchesInputAddress);
-    masm.storePtr(sticky, lazyStickyAddress);
     masm.storePtr(lastIndex, Address(temp1, RegExpStatics::offsetOfLazyIndex()));
     masm.store32(Imm32(1), Address(temp1, RegExpStatics::offsetOfPendingLazyEvaluation()));
 
     masm.loadPtr(Address(regexp, NativeObject::getFixedSlotOffset(RegExpObject::PRIVATE_SLOT)), temp2);
     masm.loadPtr(Address(temp2, RegExpShared::offsetOfSource()), temp3);
     masm.storePtr(temp3, lazySourceAddress);
     masm.load32(Address(temp2, RegExpShared::offsetOfFlags()), temp3);
     masm.store32(temp3, Address(temp1, RegExpStatics::offsetOfLazyFlags()));
@@ -1498,46 +1473,43 @@ CreateMatchResultFallback(MacroAssembler
 }
 
 JitCode*
 JitCompartment::generateRegExpMatcherStub(JSContext* cx)
 {
     Register regexp = RegExpMatcherRegExpReg;
     Register input = RegExpMatcherStringReg;
     Register lastIndex = RegExpMatcherLastIndexReg;
-    Register sticky = RegExpMatcherStickyReg;
     ValueOperand result = JSReturnOperand;
 
     // We are free to clobber all registers, as LRegExpMatcher is a call instruction.
     AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
     regs.take(input);
     regs.take(regexp);
     regs.take(lastIndex);
-    regs.take(sticky);
 
     // temp5 is used in single byte instructions when creating dependent
     // strings, and has restrictions on which register it can be on some
     // platforms.
     Register temp5;
     {
         AllocatableGeneralRegisterSet oregs = regs;
         do {
             temp5 = oregs.takeAny();
         } while (!MacroAssembler::canUseInSingleByteInstruction(temp5));
         regs.take(temp5);
     }
 
     Register temp1 = regs.takeAny();
     Register temp2 = regs.takeAny();
-
-    Register maybeTemp3 = InvalidReg;
+    Register temp3 = regs.takeAny();
+
     Register maybeTemp4 = InvalidReg;
     if (!regs.empty()) {
         // There are not enough registers on x86.
-        maybeTemp3 = regs.takeAny();
         maybeTemp4 = regs.takeAny();
     }
 
     ArrayObject* templateObject = cx->compartment()->regExps.getOrCreateMatchResultTemplateObject(cx);
     if (!templateObject)
         return nullptr;
 
     // The template object should have enough space for the maximum number of
@@ -1546,17 +1518,17 @@ JitCompartment::generateRegExpMatcherStu
                gc::GetGCKindSlots(templateObject->asTenured().getAllocKind()));
 
     MacroAssembler masm(cx);
 
     // The InputOutputData is placed above the return address on the stack.
     size_t inputOutputDataStartOffset = sizeof(void*);
 
     Label notFound, oolEntry;
-    if (!PrepareAndExecuteRegExp(cx, masm, regexp, input, lastIndex, sticky,
+    if (!PrepareAndExecuteRegExp(cx, masm, regexp, input, lastIndex,
                                  temp1, temp2, temp5, inputOutputDataStartOffset,
                                  RegExpShared::Normal, &notFound, &oolEntry))
     {
         return nullptr;
     }
 
     // Construct the result.
     Register object = temp1;
@@ -1610,25 +1582,23 @@ JitCompartment::generateRegExpMatcherStu
     // Loop to construct the match strings. There are two different loops,
     // depending on whether the input is latin1.
     CreateDependentString depStr[2];
     {
         Label isLatin1, done;
         masm.branchLatin1String(input, &isLatin1);
 
         Label* failure = &oolEntry;
-        Register temp3 = (maybeTemp3 == InvalidReg) ? sticky : maybeTemp3;
-        Register temp4 = (maybeTemp3 == InvalidReg) ? lastIndex : maybeTemp4;
+        Register temp4 = (maybeTemp4 == InvalidReg) ? lastIndex : maybeTemp4;
 
         Label failureRestore;
-        if (maybeTemp3 == InvalidReg) {
+        if (maybeTemp4 == InvalidReg) {
             failure = &failureRestore;
 
-            // Save sticky and lastIndex values to temporary space.
-            masm.store32(sticky, Address(object, elementsOffset + ObjectElements::offsetOfInitializedLength()));
+            // Save lastIndex value to temporary space.
             masm.store32(lastIndex, Address(object, elementsOffset + ObjectElements::offsetOfLength()));
         }
 
         for (int isLatin = 0; isLatin <= 1; isLatin++) {
             if (isLatin)
                 masm.bind(&isLatin1);
 
             Label matchLoop;
@@ -1648,26 +1618,24 @@ JitCompartment::generateRegExpMatcherStu
             masm.storeValue(UndefinedValue(), stringAddress);
             masm.bind(&storeDone);
 
             masm.add32(Imm32(1), matchIndex);
             masm.branch32(Assembler::LessThanOrEqual, pairCountAddress, matchIndex, &done);
             masm.jump(&matchLoop);
         }
 
-        if (maybeTemp3 == InvalidReg) {
-            // Restore sticky and lastIndex values from temporary space, both
-            // for success and failure cases.
-
-            masm.load32(Address(object, elementsOffset + ObjectElements::offsetOfInitializedLength()), sticky);
+        if (maybeTemp4 == InvalidReg) {
+            // Restore lastIndex value from temporary space, both for success
+            // and failure cases.
+
             masm.load32(Address(object, elementsOffset + ObjectElements::offsetOfLength()), lastIndex);
             masm.jump(&done);
 
             masm.bind(&failureRestore);
-            masm.load32(Address(object, elementsOffset + ObjectElements::offsetOfInitializedLength()), sticky);
             masm.load32(Address(object, elementsOffset + ObjectElements::offsetOfLength()), lastIndex);
 
             // Restore the match object for failure case.
             masm.store32(Imm32(templateObject->getDenseInitializedLength()),
                          Address(object, elementsOffset + ObjectElements::offsetOfInitializedLength()));
             masm.store32(Imm32(templateObject->length()),
                          Address(object, elementsOffset + ObjectElements::offsetOfLength()));
             masm.jump(&oolEntry);
@@ -1681,40 +1649,37 @@ JitCompartment::generateRegExpMatcherStu
     masm.store32(matchIndex, Address(object, elementsOffset + ObjectElements::offsetOfLength()));
 
     masm.loadPtr(Address(object, NativeObject::offsetOfSlots()), temp2);
 
     MOZ_ASSERT(templateObject->numFixedSlots() == 0);
     MOZ_ASSERT(templateObject->lookupPure(cx->names().index)->slot() == 0);
     MOZ_ASSERT(templateObject->lookupPure(cx->names().input)->slot() == 1);
 
-    // sticky is now free, because no more ool entry happens.
-    masm.load32(pairsVectorAddress, sticky);
-    masm.storeValue(JSVAL_TYPE_INT32, sticky, Address(temp2, 0));
+    masm.load32(pairsVectorAddress, temp3);
+    masm.storeValue(JSVAL_TYPE_INT32, temp3, Address(temp2, 0));
     masm.storeValue(JSVAL_TYPE_STRING, input, Address(temp2, sizeof(Value)));
 
     // All done!
     masm.tagValue(JSVAL_TYPE_OBJECT, object, result);
     masm.ret();
 
     masm.bind(&notFound);
     masm.moveValue(NullValue(), result);
     masm.ret();
 
     // Fallback paths for CreateDependentString and createGCObject.
     // Need to save all registers in use when they were called.
     LiveRegisterSet regsToSave(RegisterSet::Volatile());
     regsToSave.addUnchecked(regexp);
     regsToSave.addUnchecked(input);
     regsToSave.addUnchecked(lastIndex);
-    regsToSave.addUnchecked(sticky);
     regsToSave.addUnchecked(temp1);
     regsToSave.addUnchecked(temp2);
-    if (maybeTemp3 != InvalidReg)
-        regsToSave.addUnchecked(maybeTemp3);
+    regsToSave.addUnchecked(temp3);
     if (maybeTemp4 != InvalidReg)
         regsToSave.addUnchecked(maybeTemp4);
     regsToSave.addUnchecked(temp5);
 
     for (int isLatin = 0; isLatin <= 1; isLatin++)
         depStr[isLatin].generateFallback(masm, regsToSave);
 
     masm.bind(&matchResultFallback);
@@ -1756,41 +1721,38 @@ class OutOfLineRegExpMatcher : public Ou
     }
 
     LRegExpMatcher* lir() const {
         return lir_;
     }
 };
 
 typedef bool (*RegExpMatcherRawFn)(JSContext* cx, HandleObject regexp, HandleString input,
-                                   int32_t lastIndex, bool sticky,
+                                   int32_t lastIndex,
                                    MatchPairs* pairs, MutableHandleValue output);
 static const VMFunction RegExpMatcherRawInfo = FunctionInfo<RegExpMatcherRawFn>(RegExpMatcherRaw);
 
 void
 CodeGenerator::visitOutOfLineRegExpMatcher(OutOfLineRegExpMatcher* ool)
 {
     LRegExpMatcher* lir = ool->lir();
-    Register sticky = ToRegister(lir->sticky());
     Register lastIndex = ToRegister(lir->lastIndex());
     Register input = ToRegister(lir->string());
     Register regexp = ToRegister(lir->regexp());
 
     AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
-    regs.take(sticky);
     regs.take(lastIndex);
     regs.take(input);
     regs.take(regexp);
     Register temp = regs.takeAny();
 
     masm.computeEffectiveAddress(Address(masm.getStackPointer(),
         sizeof(irregexp::InputOutputData)), temp);
 
     pushArg(temp);
-    pushArg(sticky);
     pushArg(lastIndex);
     pushArg(input);
     pushArg(regexp);
 
     // We are not using oolCallVM because we are in a Call, and that live
     // registers are already saved by the the register allocator.
     callVM(RegExpMatcherRawInfo, lir);
 
@@ -1798,33 +1760,29 @@ CodeGenerator::visitOutOfLineRegExpMatch
 }
 
 void
 CodeGenerator::visitRegExpMatcher(LRegExpMatcher* lir)
 {
     MOZ_ASSERT(ToRegister(lir->regexp()) == RegExpMatcherRegExpReg);
     MOZ_ASSERT(ToRegister(lir->string()) == RegExpMatcherStringReg);
     MOZ_ASSERT(ToRegister(lir->lastIndex()) == RegExpMatcherLastIndexReg);
-    MOZ_ASSERT(ToRegister(lir->sticky()) == RegExpMatcherStickyReg);
     MOZ_ASSERT(GetValueOutput(lir) == JSReturnOperand);
 
 #if defined(JS_NUNBOX32)
     MOZ_ASSERT(RegExpMatcherRegExpReg != JSReturnReg_Type);
     MOZ_ASSERT(RegExpMatcherRegExpReg != JSReturnReg_Data);
     MOZ_ASSERT(RegExpMatcherStringReg != JSReturnReg_Type);
     MOZ_ASSERT(RegExpMatcherStringReg != JSReturnReg_Data);
     MOZ_ASSERT(RegExpMatcherLastIndexReg != JSReturnReg_Type);
     MOZ_ASSERT(RegExpMatcherLastIndexReg != JSReturnReg_Data);
-    MOZ_ASSERT(RegExpMatcherStickyReg != JSReturnReg_Type);
-    MOZ_ASSERT(RegExpMatcherStickyReg != JSReturnReg_Data);
 #elif defined(JS_PUNBOX64)
     MOZ_ASSERT(RegExpMatcherRegExpReg != JSReturnReg);
     MOZ_ASSERT(RegExpMatcherStringReg != JSReturnReg);
     MOZ_ASSERT(RegExpMatcherLastIndexReg != JSReturnReg);
-    MOZ_ASSERT(RegExpMatcherStickyReg != JSReturnReg);
 #endif
 
     masm.reserveStack(RegExpReservedStack);
 
     OutOfLineRegExpMatcher* ool = new(alloc()) OutOfLineRegExpMatcher(lir);
     addOutOfLineCode(ool, lir->mir());
 
     JitCode* regExpMatcherStub = gen->compartment->jitCompartment()->regExpMatcherStubNoBarrier();
@@ -1839,37 +1797,35 @@ static const int32_t RegExpSearcherResul
 static const int32_t RegExpSearcherResultFailed = -2;
 
 JitCode*
 JitCompartment::generateRegExpSearcherStub(JSContext* cx)
 {
     Register regexp = RegExpTesterRegExpReg;
     Register input = RegExpTesterStringReg;
     Register lastIndex = RegExpTesterLastIndexReg;
-    Register sticky = RegExpTesterStickyReg;
     Register result = ReturnReg;
 
     // We are free to clobber all registers, as LRegExpSearcher is a call instruction.
     AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
     regs.take(input);
     regs.take(regexp);
     regs.take(lastIndex);
-    regs.take(sticky);
 
     Register temp1 = regs.takeAny();
     Register temp2 = regs.takeAny();
     Register temp3 = regs.takeAny();
 
     MacroAssembler masm(cx);
 
     // The InputOutputData is placed above the return address on the stack.
     size_t inputOutputDataStartOffset = sizeof(void*);
 
     Label notFound, oolEntry;
-    if (!PrepareAndExecuteRegExp(cx, masm, regexp, input, lastIndex, sticky,
+    if (!PrepareAndExecuteRegExp(cx, masm, regexp, input, lastIndex,
                                  temp1, temp2, temp3, inputOutputDataStartOffset,
                                  RegExpShared::Normal, &notFound, &oolEntry))
     {
         return nullptr;
     }
 
     size_t pairsVectorStartOffset = RegExpPairsVectorStartOffset(inputOutputDataStartOffset);
     Address stringIndexAddress(masm.getStackPointer(),
@@ -1921,41 +1877,38 @@ class OutOfLineRegExpSearcher : public O
     }
 
     LRegExpSearcher* lir() const {
         return lir_;
     }
 };
 
 typedef bool (*RegExpSearcherRawFn)(JSContext* cx, HandleObject regexp, HandleString input,
-                                    int32_t lastIndex, bool sticky,
+                                    int32_t lastIndex,
                                     MatchPairs* pairs, int32_t* result);
 static const VMFunction RegExpSearcherRawInfo = FunctionInfo<RegExpSearcherRawFn>(RegExpSearcherRaw);
 
 void
 CodeGenerator::visitOutOfLineRegExpSearcher(OutOfLineRegExpSearcher* ool)
 {
     LRegExpSearcher* lir = ool->lir();
-    Register sticky = ToRegister(lir->sticky());
     Register lastIndex = ToRegister(lir->lastIndex());
     Register input = ToRegister(lir->string());
     Register regexp = ToRegister(lir->regexp());
 
     AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
-    regs.take(sticky);
     regs.take(lastIndex);
     regs.take(input);
     regs.take(regexp);
     Register temp = regs.takeAny();
 
     masm.computeEffectiveAddress(Address(masm.getStackPointer(),
         sizeof(irregexp::InputOutputData)), temp);
 
     pushArg(temp);
-    pushArg(sticky);
     pushArg(lastIndex);
     pushArg(input);
     pushArg(regexp);
 
     // We are not using oolCallVM because we are in a Call, and that live
     // registers are already saved by the the register allocator.
     callVM(RegExpSearcherRawInfo, lir);
 
@@ -1963,23 +1916,21 @@ CodeGenerator::visitOutOfLineRegExpSearc
 }
 
 void
 CodeGenerator::visitRegExpSearcher(LRegExpSearcher* lir)
 {
     MOZ_ASSERT(ToRegister(lir->regexp()) == RegExpTesterRegExpReg);
     MOZ_ASSERT(ToRegister(lir->string()) == RegExpTesterStringReg);
     MOZ_ASSERT(ToRegister(lir->lastIndex()) == RegExpTesterLastIndexReg);
-    MOZ_ASSERT(ToRegister(lir->sticky()) == RegExpTesterStickyReg);
     MOZ_ASSERT(ToRegister(lir->output()) == ReturnReg);
 
     MOZ_ASSERT(RegExpTesterRegExpReg != ReturnReg);
     MOZ_ASSERT(RegExpTesterStringReg != ReturnReg);
     MOZ_ASSERT(RegExpTesterLastIndexReg != ReturnReg);
-    MOZ_ASSERT(RegExpTesterStickyReg != ReturnReg);
 
     masm.reserveStack(RegExpReservedStack);
 
     OutOfLineRegExpSearcher* ool = new(alloc()) OutOfLineRegExpSearcher(lir);
     addOutOfLineCode(ool, lir->mir());
 
     JitCode* regExpSearcherStub = gen->compartment->jitCompartment()->regExpSearcherStubNoBarrier();
     masm.call(regExpSearcherStub);
@@ -1993,40 +1944,38 @@ static const int32_t RegExpTesterResultN
 static const int32_t RegExpTesterResultFailed = -2;
 
 JitCode*
 JitCompartment::generateRegExpTesterStub(JSContext* cx)
 {
     Register regexp = RegExpTesterRegExpReg;
     Register input = RegExpTesterStringReg;
     Register lastIndex = RegExpTesterLastIndexReg;
-    Register sticky = RegExpTesterStickyReg;
     Register result = ReturnReg;
 
     MacroAssembler masm(cx);
 
 #ifdef JS_USE_LINK_REGISTER
     masm.pushReturnAddress();
 #endif
 
     // We are free to clobber all registers, as LRegExpTester is a call instruction.
     AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
     regs.take(input);
     regs.take(regexp);
     regs.take(lastIndex);
-    regs.take(sticky);
 
     Register temp1 = regs.takeAny();
     Register temp2 = regs.takeAny();
     Register temp3 = regs.takeAny();
 
     masm.reserveStack(sizeof(irregexp::InputOutputData));
 
     Label notFound, oolEntry;
-    if (!PrepareAndExecuteRegExp(cx, masm, regexp, input, lastIndex, sticky,
+    if (!PrepareAndExecuteRegExp(cx, masm, regexp, input, lastIndex,
                                  temp1, temp2, temp3, 0,
                                  RegExpShared::MatchOnly, &notFound, &oolEntry))
     {
         return nullptr;
     }
 
     Label done;
 
@@ -2075,29 +2024,27 @@ class OutOfLineRegExpTester : public Out
     }
 
     LRegExpTester* lir() const {
         return lir_;
     }
 };
 
 typedef bool (*RegExpTesterRawFn)(JSContext* cx, HandleObject regexp, HandleString input,
-                                  int32_t lastIndex, bool sticky, int32_t* result);
+                                  int32_t lastIndex, int32_t* result);
 static const VMFunction RegExpTesterRawInfo = FunctionInfo<RegExpTesterRawFn>(RegExpTesterRaw);
 
 void
 CodeGenerator::visitOutOfLineRegExpTester(OutOfLineRegExpTester* ool)
 {
     LRegExpTester* lir = ool->lir();
-    Register sticky = ToRegister(lir->sticky());
     Register lastIndex = ToRegister(lir->lastIndex());
     Register input = ToRegister(lir->string());
     Register regexp = ToRegister(lir->regexp());
 
-    pushArg(sticky);
     pushArg(lastIndex);
     pushArg(input);
     pushArg(regexp);
 
     // We are not using oolCallVM because we are in a Call, and that live
     // registers are already saved by the the register allocator.
     callVM(RegExpTesterRawInfo, lir);
 
@@ -2105,23 +2052,21 @@ CodeGenerator::visitOutOfLineRegExpTeste
 }
 
 void
 CodeGenerator::visitRegExpTester(LRegExpTester* lir)
 {
     MOZ_ASSERT(ToRegister(lir->regexp()) == RegExpTesterRegExpReg);
     MOZ_ASSERT(ToRegister(lir->string()) == RegExpTesterStringReg);
     MOZ_ASSERT(ToRegister(lir->lastIndex()) == RegExpTesterLastIndexReg);
-    MOZ_ASSERT(ToRegister(lir->sticky()) == RegExpTesterStickyReg);
     MOZ_ASSERT(ToRegister(lir->output()) == ReturnReg);
 
     MOZ_ASSERT(RegExpTesterRegExpReg != ReturnReg);
     MOZ_ASSERT(RegExpTesterStringReg != ReturnReg);
     MOZ_ASSERT(RegExpTesterLastIndexReg != ReturnReg);
-    MOZ_ASSERT(RegExpTesterStickyReg != ReturnReg);
 
     OutOfLineRegExpTester* ool = new(alloc()) OutOfLineRegExpTester(lir);
     addOutOfLineCode(ool, lir->mir());
 
     JitCode* regExpTesterStub = gen->compartment->jitCompartment()->regExpTesterStubNoBarrier();
     masm.call(regExpTesterStub);
 
     masm.branch32(Assembler::Equal, ReturnReg, Imm32(RegExpTesterResultFailed), ool->entry());
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -2252,54 +2252,48 @@ LIRGenerator::visitRegExp(MRegExp* ins)
 }
 
 void
 LIRGenerator::visitRegExpMatcher(MRegExpMatcher* ins)
 {
     MOZ_ASSERT(ins->regexp()->type() == MIRType_Object);
     MOZ_ASSERT(ins->string()->type() == MIRType_String);
     MOZ_ASSERT(ins->lastIndex()->type() == MIRType_Int32);
-    MOZ_ASSERT(ins->sticky()->type() == MIRType_Boolean);
 
     LRegExpMatcher* lir = new(alloc()) LRegExpMatcher(useFixedAtStart(ins->regexp(), RegExpMatcherRegExpReg),
                                                       useFixedAtStart(ins->string(), RegExpMatcherStringReg),
-                                                      useFixedAtStart(ins->lastIndex(), RegExpMatcherLastIndexReg),
-                                                      useFixedAtStart(ins->sticky(), RegExpMatcherStickyReg));
+                                                      useFixedAtStart(ins->lastIndex(), RegExpMatcherLastIndexReg));
     defineReturn(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
 LIRGenerator::visitRegExpSearcher(MRegExpSearcher* ins)
 {
     MOZ_ASSERT(ins->regexp()->type() == MIRType_Object);
     MOZ_ASSERT(ins->string()->type() == MIRType_String);
     MOZ_ASSERT(ins->lastIndex()->type() == MIRType_Int32);
-    MOZ_ASSERT(ins->sticky()->type() == MIRType_Boolean);
 
     LRegExpSearcher* lir = new(alloc()) LRegExpSearcher(useFixedAtStart(ins->regexp(), RegExpTesterRegExpReg),
                                                         useFixedAtStart(ins->string(), RegExpTesterStringReg),
-                                                        useFixedAtStart(ins->lastIndex(), RegExpTesterLastIndexReg),
-                                                        useFixedAtStart(ins->sticky(), RegExpTesterStickyReg));
+                                                        useFixedAtStart(ins->lastIndex(), RegExpTesterLastIndexReg));
     defineReturn(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
 LIRGenerator::visitRegExpTester(MRegExpTester* ins)
 {
     MOZ_ASSERT(ins->regexp()->type() == MIRType_Object);
     MOZ_ASSERT(ins->string()->type() == MIRType_String);
     MOZ_ASSERT(ins->lastIndex()->type() == MIRType_Int32);
-    MOZ_ASSERT(ins->sticky()->type() == MIRType_Boolean);
 
     LRegExpTester* lir = new(alloc()) LRegExpTester(useFixedAtStart(ins->regexp(), RegExpTesterRegExpReg),
                                                     useFixedAtStart(ins->string(), RegExpTesterStringReg),
-                                                    useFixedAtStart(ins->lastIndex(), RegExpTesterLastIndexReg),
-                                                    useFixedAtStart(ins->sticky(), RegExpTesterStickyReg));
+                                                    useFixedAtStart(ins->lastIndex(), RegExpTesterLastIndexReg));
     defineReturn(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
 LIRGenerator::visitRegExpPrototypeOptimizable(MRegExpPrototypeOptimizable* ins)
 {
     MOZ_ASSERT(ins->object()->type() == MIRType_Object);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -1720,52 +1720,48 @@ IonBuilder::inlineStrCharAt(CallInfo& ca
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineRegExpMatcher(CallInfo& callInfo)
 {
     // This is called from Self-hosted JS, after testing each argument,
     // most of following tests should be passed.
 
-    if (callInfo.argc() != 4 || callInfo.constructing()) {
+    if (callInfo.argc() != 3 || callInfo.constructing()) {
         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
         return InliningStatus_NotInlined;
     }
 
     MDefinition* rxArg = callInfo.getArg(0);
     MDefinition* strArg = callInfo.getArg(1);
     MDefinition* lastIndexArg = callInfo.getArg(2);
-    MDefinition* stickyArg = callInfo.getArg(3);
 
     if (rxArg->type() != MIRType_Object)
         return InliningStatus_NotInlined;
 
     TemporaryTypeSet* rxTypes = rxArg->resultTypeSet();
     const Class* clasp = rxTypes ? rxTypes->getKnownClass(constraints()) : nullptr;
     if (clasp != &RegExpObject::class_)
         return InliningStatus_NotInlined;
 
     if (strArg->mightBeType(MIRType_Object))
         return InliningStatus_NotInlined;
 
     if (lastIndexArg->type() != MIRType_Int32)
         return InliningStatus_NotInlined;
 
-    if (stickyArg->type() != MIRType_Boolean)
-        return InliningStatus_NotInlined;
-
     JSContext* cx = GetJitContext()->cx;
     if (!cx->compartment()->jitCompartment()->ensureRegExpMatcherStubExists(cx)) {
         cx->clearPendingException(); // OOM or overrecursion.
         return InliningStatus_NotInlined;
     }
 
     callInfo.setImplicitlyUsedUnchecked();
 
-    MInstruction* matcher = MRegExpMatcher::New(alloc(), rxArg, strArg, lastIndexArg, stickyArg);
+    MInstruction* matcher = MRegExpMatcher::New(alloc(), rxArg, strArg, lastIndexArg);
     current->add(matcher);
     current->push(matcher);
 
     if (!resumeAfter(matcher))
         return InliningStatus_Error;
 
     if (!pushTypeBarrier(matcher, getInlineReturnTypeSet(), BarrierKind::TypeSet))
         return InliningStatus_Error;
@@ -1774,52 +1770,48 @@ IonBuilder::inlineRegExpMatcher(CallInfo
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineRegExpSearcher(CallInfo& callInfo)
 {
     // This is called from Self-hosted JS, after testing each argument,
     // most of following tests should be passed.
 
-    if (callInfo.argc() != 4 || callInfo.constructing()) {
+    if (callInfo.argc() != 3 || callInfo.constructing()) {
         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
         return InliningStatus_NotInlined;
     }
 
     MDefinition* rxArg = callInfo.getArg(0);
     MDefinition* strArg = callInfo.getArg(1);
     MDefinition* lastIndexArg = callInfo.getArg(2);
-    MDefinition* stickyArg = callInfo.getArg(3);
 
     if (rxArg->type() != MIRType_Object)
         return InliningStatus_NotInlined;
 
     TemporaryTypeSet* regexpTypes = rxArg->resultTypeSet();
     const Class* clasp = regexpTypes ? regexpTypes->getKnownClass(constraints()) : nullptr;
     if (clasp != &RegExpObject::class_)
         return InliningStatus_NotInlined;
 
     if (strArg->mightBeType(MIRType_Object))
         return InliningStatus_NotInlined;
 
     if (lastIndexArg->type() != MIRType_Int32)
         return InliningStatus_NotInlined;
 
-    if (stickyArg->type() != MIRType_Boolean)
-        return InliningStatus_NotInlined;
-
     JSContext* cx = GetJitContext()->cx;
     if (!cx->compartment()->jitCompartment()->ensureRegExpSearcherStubExists(cx)) {
         cx->clearPendingException(); // OOM or overrecursion.
         return InliningStatus_Error;
     }
 
     callInfo.setImplicitlyUsedUnchecked();
 
-    MInstruction* searcher = MRegExpSearcher::New(alloc(), rxArg, strArg, lastIndexArg, stickyArg);
+    MInstruction* searcher = MRegExpSearcher::New(alloc(), rxArg, strArg, lastIndexArg);
     current->add(searcher);
     current->push(searcher);
 
     if (!resumeAfter(searcher))
         return InliningStatus_Error;
 
     if (!pushTypeBarrier(searcher, getInlineReturnTypeSet(), BarrierKind::TypeSet))
         return InliningStatus_Error;
@@ -1828,52 +1820,48 @@ IonBuilder::inlineRegExpSearcher(CallInf
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineRegExpTester(CallInfo& callInfo)
 {
     // This is called from Self-hosted JS, after testing each argument,
     // most of following tests should be passed.
 
-    if (callInfo.argc() != 4 || callInfo.constructing()) {
+    if (callInfo.argc() != 3 || callInfo.constructing()) {
         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
         return InliningStatus_NotInlined;
     }
 
     MDefinition* rxArg = callInfo.getArg(0);
     MDefinition* strArg = callInfo.getArg(1);
     MDefinition* lastIndexArg = callInfo.getArg(2);
-    MDefinition* stickyArg = callInfo.getArg(3);
 
     if (rxArg->type() != MIRType_Object)
         return InliningStatus_NotInlined;
 
     TemporaryTypeSet* rxTypes = rxArg->resultTypeSet();
     const Class* clasp = rxTypes ? rxTypes->getKnownClass(constraints()) : nullptr;
     if (clasp != &RegExpObject::class_)
         return InliningStatus_NotInlined;
 
     if (strArg->mightBeType(MIRType_Object))
         return InliningStatus_NotInlined;
 
     if (lastIndexArg->type() != MIRType_Int32)
         return InliningStatus_NotInlined;
 
-    if (stickyArg->type() != MIRType_Boolean)
-        return InliningStatus_NotInlined;
-
     JSContext* cx = GetJitContext()->cx;
     if (!cx->compartment()->jitCompartment()->ensureRegExpTesterStubExists(cx)) {
         cx->clearPendingException(); // OOM or overrecursion.
         return InliningStatus_NotInlined;
     }
 
     callInfo.setImplicitlyUsedUnchecked();
 
-    MInstruction* tester = MRegExpTester::New(alloc(), rxArg, strArg, lastIndexArg, stickyArg);
+    MInstruction* tester = MRegExpTester::New(alloc(), rxArg, strArg, lastIndexArg);
     current->add(tester);
     current->push(tester);
 
     if (!resumeAfter(tester))
         return InliningStatus_Error;
 
     return InliningStatus_Inlined;
 }
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -7896,169 +7896,151 @@ class MRegExp : public MNullaryInstructi
         return AliasSet::None();
     }
     bool possiblyCalls() const override {
         return true;
     }
 };
 
 class MRegExpMatcher
-  : public MAryInstruction<4>,
-    public Mix4Policy<ObjectPolicy<0>,
+  : public MAryInstruction<3>,
+    public Mix3Policy<ObjectPolicy<0>,
                       StringPolicy<1>,
-                      IntPolicy<2>,
-                      BooleanPolicy<3> >::Data
+                      IntPolicy<2> >::Data
 {
   private:
 
-    MRegExpMatcher(MDefinition* regexp, MDefinition* string, MDefinition* lastIndex,
-                   MDefinition* sticky)
-      : MAryInstruction<4>()
+    MRegExpMatcher(MDefinition* regexp, MDefinition* string, MDefinition* lastIndex)
+      : MAryInstruction<3>()
     {
         initOperand(0, regexp);
         initOperand(1, string);
         initOperand(2, lastIndex);
-        initOperand(3, sticky);
 
         setMovable();
         // May be object or null.
         setResultType(MIRType_Value);
     }
 
   public:
     INSTRUCTION_HEADER(RegExpMatcher)
 
     static MRegExpMatcher* New(TempAllocator& alloc, MDefinition* regexp, MDefinition* string,
-                               MDefinition* lastIndex, MDefinition* sticky)
-    {
-        return new(alloc) MRegExpMatcher(regexp, string, lastIndex, sticky);
+                               MDefinition* lastIndex)
+    {
+        return new(alloc) MRegExpMatcher(regexp, string, lastIndex);
     }
 
     MDefinition* regexp() const {
         return getOperand(0);
     }
     MDefinition* string() const {
         return getOperand(1);
     }
     MDefinition* lastIndex() const {
         return getOperand(2);
     }
-    MDefinition* sticky() const {
-        return getOperand(3);
-    }
 
     bool writeRecoverData(CompactBufferWriter& writer) const override;
 
     bool canRecoverOnBailout() const override {
         return true;
     }
 
     bool possiblyCalls() const override {
         return true;
     }
 };
 
 class MRegExpSearcher
-  : public MAryInstruction<4>,
-    public Mix4Policy<ObjectPolicy<0>,
+  : public MAryInstruction<3>,
+    public Mix3Policy<ObjectPolicy<0>,
                       StringPolicy<1>,
-                      IntPolicy<2>,
-                      BooleanPolicy<3> >::Data
+                      IntPolicy<2> >::Data
 {
   private:
 
-    MRegExpSearcher(MDefinition* regexp, MDefinition* string, MDefinition* lastIndex,
-                    MDefinition* sticky)
-      : MAryInstruction<4>()
+    MRegExpSearcher(MDefinition* regexp, MDefinition* string, MDefinition* lastIndex)
+      : MAryInstruction<3>()
     {
         initOperand(0, regexp);
         initOperand(1, string);
         initOperand(2, lastIndex);
-        initOperand(3, sticky);
 
         setMovable();
         setResultType(MIRType_Int32);
     }
 
   public:
     INSTRUCTION_HEADER(RegExpSearcher)
 
     static MRegExpSearcher* New(TempAllocator& alloc, MDefinition* regexp, MDefinition* string,
-                                MDefinition* lastIndex, MDefinition* sticky)
-    {
-        return new(alloc) MRegExpSearcher(regexp, string, lastIndex, sticky);
+                                MDefinition* lastIndex)
+    {
+        return new(alloc) MRegExpSearcher(regexp, string, lastIndex);
     }
 
     MDefinition* regexp() const {
         return getOperand(0);
     }
     MDefinition* string() const {
         return getOperand(1);
     }
     MDefinition* lastIndex() const {
         return getOperand(2);
     }
-    MDefinition* sticky() const {
-        return getOperand(3);
-    }
 
     bool writeRecoverData(CompactBufferWriter& writer) const override;
 
     bool canRecoverOnBailout() const override {
         return true;
     }
 
     bool possiblyCalls() const override {
         return true;
     }
 };
 
 class MRegExpTester
-  : public MAryInstruction<4>,
-    public Mix4Policy<ObjectPolicy<0>,
+  : public MAryInstruction<3>,
+    public Mix3Policy<ObjectPolicy<0>,
                       StringPolicy<1>,
-                      IntPolicy<2>,
-                      BooleanPolicy<3> >::Data
+                      IntPolicy<2> >::Data
 {
   private:
 
-    MRegExpTester(MDefinition* regexp, MDefinition* string, MDefinition* lastIndex,
-                  MDefinition* sticky)
-      : MAryInstruction<4>()
+    MRegExpTester(MDefinition* regexp, MDefinition* string, MDefinition* lastIndex)
+      : MAryInstruction<3>()
     {
         initOperand(0, regexp);
         initOperand(1, string);
         initOperand(2, lastIndex);
-        initOperand(3, sticky);
 
         setMovable();
         setResultType(MIRType_Int32);
     }
 
   public:
     INSTRUCTION_HEADER(RegExpTester)
 
     static MRegExpTester* New(TempAllocator& alloc, MDefinition* regexp, MDefinition* string,
-                              MDefinition* lastIndex, MDefinition* sticky)
-    {
-        return new(alloc) MRegExpTester(regexp, string, lastIndex, sticky);
+                              MDefinition* lastIndex)
+    {
+        return new(alloc) MRegExpTester(regexp, string, lastIndex);
     }
 
     MDefinition* regexp() const {
         return getOperand(0);
     }
     MDefinition* string() const {
         return getOperand(1);
     }
     MDefinition* lastIndex() const {
         return getOperand(2);
     }
-    MDefinition* sticky() const {
-        return getOperand(3);
-    }
 
     bool possiblyCalls() const override {
         return true;
     }
 
     bool writeRecoverData(CompactBufferWriter& writer) const override;
     bool canRecoverOnBailout() const override {
         return true;
--- a/js/src/jit/Recover.cpp
+++ b/js/src/jit/Recover.cpp
@@ -1008,20 +1008,19 @@ RRegExpMatcher::RRegExpMatcher(CompactBu
 {}
 
 bool
 RRegExpMatcher::recover(JSContext* cx, SnapshotIterator& iter) const
 {
     RootedObject regexp(cx, &iter.read().toObject());
     RootedString input(cx, iter.read().toString());
     int32_t lastIndex = iter.read().toInt32();
-    bool sticky = iter.read().toBoolean();
 
     RootedValue result(cx);
-    if (!RegExpMatcherRaw(cx, regexp, input, lastIndex, sticky, nullptr, &result))
+    if (!RegExpMatcherRaw(cx, regexp, input, lastIndex, nullptr, &result))
         return false;
 
     iter.storeInstructionResult(result);
     return true;
 }
 
 bool
 MRegExpSearcher::writeRecoverData(CompactBufferWriter& writer) const
@@ -1035,20 +1034,19 @@ RRegExpSearcher::RRegExpSearcher(Compact
 {}
 
 bool
 RRegExpSearcher::recover(JSContext* cx, SnapshotIterator& iter) const
 {
     RootedObject regexp(cx, &iter.read().toObject());
     RootedString input(cx, iter.read().toString());
     int32_t lastIndex = iter.read().toInt32();
-    bool sticky = iter.read().toBoolean();
 
     int32_t result;
-    if (!RegExpSearcherRaw(cx, regexp, input, lastIndex, sticky, nullptr, &result))
+    if (!RegExpSearcherRaw(cx, regexp, input, lastIndex, nullptr, &result))
         return false;
 
     RootedValue resultVal(cx);
     resultVal.setInt32(result);
     iter.storeInstructionResult(resultVal);
     return true;
 }
 
@@ -1064,20 +1062,19 @@ RRegExpTester::RRegExpTester(CompactBuff
 { }
 
 bool
 RRegExpTester::recover(JSContext* cx, SnapshotIterator& iter) const
 {
     RootedString string(cx, iter.read().toString());
     RootedObject regexp(cx, &iter.read().toObject());
     int32_t lastIndex = iter.read().toInt32();
-    bool sticky = iter.read().toBoolean();
     int32_t endIndex;
 
-    if (!js::RegExpTesterRaw(cx, regexp, string, lastIndex, sticky, &endIndex))
+    if (!js::RegExpTesterRaw(cx, regexp, string, lastIndex, &endIndex))
         return false;
 
     RootedValue result(cx);
     result.setInt32(endIndex);
     iter.storeInstructionResult(result);
     return true;
 }
 
--- a/js/src/jit/TypePolicy.cpp
+++ b/js/src/jit/TypePolicy.cpp
@@ -1222,17 +1222,17 @@ FilterTypeSetPolicy::adjustInputs(TempAl
     _(Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2> >)         \
     _(Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2> >) \
     _(Mix3Policy<ObjectPolicy<0>, ObjectPolicy<1>, BoxPolicy<2> >)      \
     _(Mix3Policy<ObjectPolicy<0>, ObjectPolicy<1>, IntPolicy<2> >)      \
     _(Mix3Policy<ObjectPolicy<0>, ObjectPolicy<1>, ObjectPolicy<2> >)   \
     _(Mix3Policy<StringPolicy<0>, IntPolicy<1>, IntPolicy<2>>)          \
     _(Mix3Policy<StringPolicy<0>, ObjectPolicy<1>, StringPolicy<2> >)   \
     _(Mix3Policy<StringPolicy<0>, StringPolicy<1>, StringPolicy<2> >)   \
-    _(Mix4Policy<ObjectPolicy<0>, StringPolicy<1>, IntPolicy<2>, BooleanPolicy<3>>) \
+    _(Mix3Policy<ObjectPolicy<0>, StringPolicy<1>, IntPolicy<2>>)       \
     _(Mix4Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2>, IntPolicy<3>>) \
     _(Mix4Policy<ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2>, TruncateToInt32Policy<3> >) \
     _(Mix3Policy<ObjectPolicy<0>, CacheIdPolicy<1>, NoFloatPolicy<2>>)  \
     _(Mix4Policy<SimdScalarPolicy<0>, SimdScalarPolicy<1>, SimdScalarPolicy<2>, SimdScalarPolicy<3> >) \
     _(MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >)                        \
     _(MixPolicy<ConvertToStringPolicy<0>, ConvertToStringPolicy<1> >)   \
     _(MixPolicy<ConvertToStringPolicy<0>, ObjectPolicy<1> >)            \
     _(MixPolicy<DoublePolicy<0>, DoublePolicy<1> >)                     \
--- a/js/src/jit/arm/Assembler-arm.h
+++ b/js/src/jit/arm/Assembler-arm.h
@@ -160,23 +160,21 @@ static MOZ_CONSTEXPR_VAR Register AsmJSI
 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD0 = r0;
 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD1 = r1;
 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD2 = r4;
 
 // Registerd used in RegExpMatcher instruction (do not use JSReturnOperand).
 static MOZ_CONSTEXPR_VAR Register RegExpMatcherRegExpReg = CallTempReg0;
 static MOZ_CONSTEXPR_VAR Register RegExpMatcherStringReg = CallTempReg1;
 static MOZ_CONSTEXPR_VAR Register RegExpMatcherLastIndexReg = CallTempReg2;
-static MOZ_CONSTEXPR_VAR Register RegExpMatcherStickyReg = CallTempReg3;
 
 // Registerd used in RegExpTester instruction (do not use ReturnReg).
 static MOZ_CONSTEXPR_VAR Register RegExpTesterRegExpReg = CallTempReg0;
 static MOZ_CONSTEXPR_VAR Register RegExpTesterStringReg = CallTempReg1;
 static MOZ_CONSTEXPR_VAR Register RegExpTesterLastIndexReg = CallTempReg2;
-static MOZ_CONSTEXPR_VAR Register RegExpTesterStickyReg = CallTempReg3;
 
 static MOZ_CONSTEXPR_VAR FloatRegister d0  = {FloatRegisters::d0, VFPRegister::Double};
 static MOZ_CONSTEXPR_VAR FloatRegister d1  = {FloatRegisters::d1, VFPRegister::Double};
 static MOZ_CONSTEXPR_VAR FloatRegister d2  = {FloatRegisters::d2, VFPRegister::Double};
 static MOZ_CONSTEXPR_VAR FloatRegister d3  = {FloatRegisters::d3, VFPRegister::Double};
 static MOZ_CONSTEXPR_VAR FloatRegister d4  = {FloatRegisters::d4, VFPRegister::Double};
 static MOZ_CONSTEXPR_VAR FloatRegister d5  = {FloatRegisters::d5, VFPRegister::Double};
 static MOZ_CONSTEXPR_VAR FloatRegister d6  = {FloatRegisters::d6, VFPRegister::Double};
--- a/js/src/jit/arm64/Assembler-arm64.h
+++ b/js/src/jit/arm64/Assembler-arm64.h
@@ -133,23 +133,21 @@ static constexpr Register AsmJSIonExitRe
 static constexpr Register AsmJSIonExitRegD0 = r0;
 static constexpr Register AsmJSIonExitRegD1 = r1;
 static constexpr Register AsmJSIonExitRegD2 = r4;
 
 // Registerd used in RegExpMatcher instruction (do not use JSReturnOperand).
 static MOZ_CONSTEXPR_VAR Register RegExpMatcherRegExpReg = CallTempReg0;
 static MOZ_CONSTEXPR_VAR Register RegExpMatcherStringReg = CallTempReg1;
 static MOZ_CONSTEXPR_VAR Register RegExpMatcherLastIndexReg = CallTempReg2;
-static MOZ_CONSTEXPR_VAR Register RegExpMatcherStickyReg = CallTempReg3;
 
 // Registerd used in RegExpTester instruction (do not use ReturnReg).
 static MOZ_CONSTEXPR_VAR Register RegExpTesterRegExpReg = CallTempReg0;
 static MOZ_CONSTEXPR_VAR Register RegExpTesterStringReg = CallTempReg1;
 static MOZ_CONSTEXPR_VAR Register RegExpTesterLastIndexReg = CallTempReg2;
-static MOZ_CONSTEXPR_VAR Register RegExpTesterStickyReg = CallTempReg3;
 
 static constexpr Register JSReturnReg_Type = r3;
 static constexpr Register JSReturnReg_Data = r2;
 
 static constexpr FloatRegister NANReg = { FloatRegisters::d14, FloatRegisters::Single };
 // N.B. r8 isn't listed as an aapcs temp register, but we can use it as such because we never
 // use return-structs.
 static constexpr Register CallTempNonArgRegs[] = { r8, r9, r10, r11, r12, r13, r14, r15 };
--- a/js/src/jit/mips-shared/Assembler-mips-shared.h
+++ b/js/src/jit/mips-shared/Assembler-mips-shared.h
@@ -124,23 +124,21 @@ static MOZ_CONSTEXPR_VAR Register AsmJSI
 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD0 = a0;
 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD1 = a1;
 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD2 = t0;
 
 // Registerd used in RegExpMatcher instruction (do not use JSReturnOperand).
 static MOZ_CONSTEXPR_VAR Register RegExpMatcherRegExpReg = CallTempReg0;
 static MOZ_CONSTEXPR_VAR Register RegExpMatcherStringReg = CallTempReg1;
 static MOZ_CONSTEXPR_VAR Register RegExpMatcherLastIndexReg = CallTempReg2;
-static MOZ_CONSTEXPR_VAR Register RegExpMatcherStickyReg = CallTempReg3;
 
 // Registerd used in RegExpTester instruction (do not use ReturnReg).
 static MOZ_CONSTEXPR_VAR Register RegExpTesterRegExpReg = CallTempReg0;
 static MOZ_CONSTEXPR_VAR Register RegExpTesterStringReg = CallTempReg1;
 static MOZ_CONSTEXPR_VAR Register RegExpTesterLastIndexReg = CallTempReg2;
-static MOZ_CONSTEXPR_VAR Register RegExpTesterStickyReg = CallTempReg3;
 
 static MOZ_CONSTEXPR_VAR uint32_t CodeAlignment = 4;
 
 // This boolean indicates whether we support SIMD instructions flavoured for
 // this architecture or not. Rather than a method in the LIRGenerator, it is
 // here such that it is accessible from the entire codebase. Once full support
 // for SIMD is reached on all tier-1 platforms, this constant can be deleted.
 static MOZ_CONSTEXPR_VAR bool SupportsSimd = false;
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -4305,106 +4305,94 @@ class LRegExp : public LCallInstructionH
   public:
     LIR_HEADER(RegExp)
 
     const MRegExp* mir() const {
         return mir_->toRegExp();
     }
 };
 
-class LRegExpMatcher : public LCallInstructionHelper<BOX_PIECES, 4, 0>
+class LRegExpMatcher : public LCallInstructionHelper<BOX_PIECES, 3, 0>
 {
   public:
     LIR_HEADER(RegExpMatcher)
 
     LRegExpMatcher(const LAllocation& regexp, const LAllocation& string,
-                   const LAllocation& lastIndex, const LAllocation& sticky)
+                   const LAllocation& lastIndex)
     {
         setOperand(0, regexp);
         setOperand(1, string);
         setOperand(2, lastIndex);
-        setOperand(3, sticky);
     }
 
     const LAllocation* regexp() {
         return getOperand(0);
     }
     const LAllocation* string() {
         return getOperand(1);
     }
     const LAllocation* lastIndex() {
         return getOperand(2);
     }
-    const LAllocation* sticky() {
-        return getOperand(3);
-    }
 
     const MRegExpMatcher* mir() const {
         return mir_->toRegExpMatcher();
     }
 };
 
-class LRegExpSearcher : public LCallInstructionHelper<1, 4, 0>
+class LRegExpSearcher : public LCallInstructionHelper<1, 3, 0>
 {
   public:
     LIR_HEADER(RegExpSearcher)
 
     LRegExpSearcher(const LAllocation& regexp, const LAllocation& string,
-                    const LAllocation& lastIndex, const LAllocation& sticky)
+                    const LAllocation& lastIndex)
     {
         setOperand(0, regexp);
         setOperand(1, string);
         setOperand(2, lastIndex);
-        setOperand(3, sticky);
     }
 
     const LAllocation* regexp() {
         return getOperand(0);
     }
     const LAllocation* string() {
         return getOperand(1);
     }
     const LAllocation* lastIndex() {
         return getOperand(2);
     }
-    const LAllocation* sticky() {
-        return getOperand(3);
-    }
 
     const MRegExpSearcher* mir() const {
         return mir_->toRegExpSearcher();
     }
 };
 
-class LRegExpTester : public LCallInstructionHelper<1, 4, 0>
+class LRegExpTester : public LCallInstructionHelper<1, 3, 0>
 {
   public:
     LIR_HEADER(RegExpTester)
 
     LRegExpTester(const LAllocation& regexp, const LAllocation& string,
-                  const LAllocation& lastIndex, const LAllocation& sticky)
+                  const LAllocation& lastIndex)
     {
         setOperand(0, regexp);
         setOperand(1, string);
         setOperand(2, lastIndex);
-        setOperand(3, sticky);
     }
 
     const LAllocation* regexp() {
         return getOperand(0);
     }
     const LAllocation* string() {
         return getOperand(1);
     }
     const LAllocation* lastIndex() {
         return getOperand(2);
     }
-    const LAllocation* sticky() {
-        return getOperand(3);
-    }
 
     const MRegExpTester* mir() const {
         return mir_->toRegExpTester();
     }
 };
 
 class LRegExpPrototypeOptimizable : public LInstructionHelper<1, 1, 1>
 {
--- a/js/src/jit/x64/Assembler-x64.h
+++ b/js/src/jit/x64/Assembler-x64.h
@@ -162,23 +162,21 @@ static MOZ_CONSTEXPR_VAR Register AsmJSI
 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD0 = rax;
 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD1 = rdi;
 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD2 = rbx;
 
 // Registerd used in RegExpMatcher instruction (do not use JSReturnOperand).
 static MOZ_CONSTEXPR_VAR Register RegExpMatcherRegExpReg = CallTempReg0;
 static MOZ_CONSTEXPR_VAR Register RegExpMatcherStringReg = CallTempReg1;
 static MOZ_CONSTEXPR_VAR Register RegExpMatcherLastIndexReg = CallTempReg2;
-static MOZ_CONSTEXPR_VAR Register RegExpMatcherStickyReg = CallTempReg4;
 
 // Registerd used in RegExpTester instruction (do not use ReturnReg).
 static MOZ_CONSTEXPR_VAR Register RegExpTesterRegExpReg = CallTempReg1;
 static MOZ_CONSTEXPR_VAR Register RegExpTesterStringReg = CallTempReg2;
 static MOZ_CONSTEXPR_VAR Register RegExpTesterLastIndexReg = CallTempReg3;
-static MOZ_CONSTEXPR_VAR Register RegExpTesterStickyReg = CallTempReg4;
 
 class ABIArgGenerator
 {
 #if defined(XP_WIN)
     unsigned regIndex_;
 #else
     unsigned intRegIndex_;
     unsigned floatRegIndex_;
--- a/js/src/jit/x86/Assembler-x86.h
+++ b/js/src/jit/x86/Assembler-x86.h
@@ -103,23 +103,21 @@ static MOZ_CONSTEXPR_VAR Register AsmJSI
 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD0 = edi;
 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD1 = eax;
 static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD2 = esi;
 
 // Registerd used in RegExpMatcher instruction (do not use JSReturnOperand).
 static MOZ_CONSTEXPR_VAR Register RegExpMatcherRegExpReg = CallTempReg0;
 static MOZ_CONSTEXPR_VAR Register RegExpMatcherStringReg = CallTempReg1;
 static MOZ_CONSTEXPR_VAR Register RegExpMatcherLastIndexReg = CallTempReg2;
-static MOZ_CONSTEXPR_VAR Register RegExpMatcherStickyReg = CallTempReg4;
 
 // Registerd used in RegExpTester instruction (do not use ReturnReg).
 static MOZ_CONSTEXPR_VAR Register RegExpTesterRegExpReg = CallTempReg0;
 static MOZ_CONSTEXPR_VAR Register RegExpTesterStringReg = CallTempReg2;
 static MOZ_CONSTEXPR_VAR Register RegExpTesterLastIndexReg = CallTempReg3;
-static MOZ_CONSTEXPR_VAR Register RegExpTesterStickyReg = CallTempReg4;
 
 // GCC stack is aligned on 16 bytes. Ion does not maintain this for internal
 // calls. asm.js code does.
 #if defined(__GNUC__)
 static MOZ_CONSTEXPR_VAR uint32_t ABIStackAlignment = 16;
 #else
 static MOZ_CONSTEXPR_VAR uint32_t ABIStackAlignment = 4;
 #endif
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -603,28 +603,28 @@ RegExpShared::trace(JSTracer* trc)
     for (size_t i = 0; i < ArrayLength(compilationArray); i++) {
         RegExpCompilation& compilation = compilationArray[i];
         TraceNullableEdge(trc, &compilation.jitCode, "RegExpShared code");
     }
 }
 
 bool
 RegExpShared::compile(JSContext* cx, HandleLinearString input,
-                      CompilationMode mode, bool sticky, ForceByteCodeEnum force)
+                      CompilationMode mode, ForceByteCodeEnum force)
 {
     TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime());
     AutoTraceLog logCompile(logger, TraceLogger_IrregexpCompile);
 
     RootedAtom pattern(cx, source);
-    return compile(cx, pattern, input, mode, sticky, force);
+    return compile(cx, pattern, input, mode, force);
 }
 
 bool
 RegExpShared::compile(JSContext* cx, HandleAtom pattern, HandleLinearString input,
-                      CompilationMode mode, bool sticky, ForceByteCodeEnum force)
+                      CompilationMode mode, ForceByteCodeEnum force)
 {
     if (!ignoreCase() && !StringHasRegExpMetaChars(pattern))
         canStringMatch = true;
 
     CompileOptions options(cx);
     TokenStream dummyTokenStream(cx, options, nullptr, 0, nullptr);
 
     LifoAllocScope scope(&cx->tempLifoAlloc());
@@ -640,53 +640,53 @@ RegExpShared::compile(JSContext* cx, Han
     this->parenCount = data.capture_count;
 
     irregexp::RegExpCode code = irregexp::CompilePattern(cx, this, &data, input,
                                                          false /* global() */,
                                                          ignoreCase(),
                                                          input->hasLatin1Chars(),
                                                          mode == MatchOnly,
                                                          force == ForceByteCode,
-                                                         sticky, unicode());
+                                                         sticky(), unicode());
     if (code.empty())
         return false;
 
     MOZ_ASSERT(!code.jitCode || !code.byteCode);
     MOZ_ASSERT_IF(force == ForceByteCode, code.byteCode);
 
-    RegExpCompilation& compilation = this->compilation(mode, sticky, input->hasLatin1Chars());
+    RegExpCompilation& compilation = this->compilation(mode, input->hasLatin1Chars());
     if (code.jitCode)
         compilation.jitCode = code.jitCode;
     else if (code.byteCode)
         compilation.byteCode = code.byteCode;
 
     return true;
 }
 
 bool
 RegExpShared::compileIfNecessary(JSContext* cx, HandleLinearString input,
-                                 CompilationMode mode, bool sticky, ForceByteCodeEnum force)
+                                 CompilationMode mode, ForceByteCodeEnum force)
 {
-    if (isCompiled(mode, sticky, input->hasLatin1Chars(), force))
+    if (isCompiled(mode, input->hasLatin1Chars(), force))
         return true;
-    return compile(cx, input, mode, sticky, force);
+    return compile(cx, input, mode, force);
 }
 
 RegExpRunStatus
-RegExpShared::execute(JSContext* cx, HandleLinearString input, size_t start, bool sticky,
+RegExpShared::execute(JSContext* cx, HandleLinearString input, size_t start,
                       MatchPairs* matches, size_t* endIndex)
 {
     MOZ_ASSERT_IF(matches, !endIndex);
     MOZ_ASSERT_IF(!matches, endIndex);
     TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime());
 
     CompilationMode mode = matches ? Normal : MatchOnly;
 
     /* Compile the code at point-of-use. */
-    if (!compileIfNecessary(cx, input, mode, sticky, DontForceByteCode))
+    if (!compileIfNecessary(cx, input, mode, DontForceByteCode))
         return RegExpRunStatus_Error;
 
     /*
      * Ensure sufficient memory for output vector.
      * No need to initialize it. The RegExp engine fills them in on a match.
      */
     if (matches && !matches->allocOrExpandArray(pairCount())) {
         ReportOutOfMemory(cx);
@@ -696,17 +696,17 @@ RegExpShared::execute(JSContext* cx, Han
     size_t length = input->length();
 
     // Reset the Irregexp backtrack stack if it grows during execution.
     irregexp::RegExpStackScope stackScope(cx->runtime());
 
     if (canStringMatch) {
         MOZ_ASSERT(pairCount() == 1);
         size_t sourceLength = source->length();
-        if (sticky) {
+        if (sticky()) {
             // First part checks size_t overflow.
             if (sourceLength + start < sourceLength || sourceLength + start > length)
                 return RegExpRunStatus_Success_NotFound;
             if (!HasSubstringAt(input, source, start))
                 return RegExpRunStatus_Success_NotFound;
 
             if (matches) {
                 (*matches)[0].start = start;
@@ -730,17 +730,17 @@ RegExpShared::execute(JSContext* cx, Han
             matches->checkAgainst(length);
         } else if (endIndex) {
             *endIndex = res + sourceLength;
         }
         return RegExpRunStatus_Success;
     }
 
     do {
-        jit::JitCode* code = compilation(mode, sticky, input->hasLatin1Chars()).jitCode;
+        jit::JitCode* code = compilation(mode, input->hasLatin1Chars()).jitCode;
         if (!code)
             break;
 
         RegExpRunStatus result;
         {
             AutoTraceLog logJIT(logger, TraceLogger_IrregexpExecute);
             AutoCheckCannotGC nogc;
             if (input->hasLatin1Chars()) {
@@ -769,20 +769,20 @@ RegExpShared::execute(JSContext* cx, Han
         MOZ_ASSERT(result == RegExpRunStatus_Success);
 
         if (matches)
             matches->checkAgainst(length);
         return RegExpRunStatus_Success;
     } while (false);
 
     // Compile bytecode for the RegExp if necessary.
-    if (!compileIfNecessary(cx, input, mode, sticky, ForceByteCode))
+    if (!compileIfNecessary(cx, input, mode, ForceByteCode))
         return RegExpRunStatus_Error;
 
-    uint8_t* byteCode = compilation(mode, sticky, input->hasLatin1Chars()).byteCode;
+    uint8_t* byteCode = compilation(mode, input->hasLatin1Chars()).byteCode;
     AutoTraceLog logInterpreter(logger, TraceLogger_IrregexpExecute);
 
     AutoStableStringChars inputChars(cx);
     if (!inputChars.init(cx, input))
         return RegExpRunStatus_Error;
 
     RegExpRunStatus result;
     if (inputChars.isLatin1()) {
--- a/js/src/vm/RegExpObject.h
+++ b/js/src/vm/RegExpObject.h
@@ -130,54 +130,54 @@ class RegExpShared
     /* Source to the RegExp, for lazy compilation. */
     RelocatablePtrAtom source;
 
     RegExpFlag         flags;
     size_t             parenCount;
     bool               canStringMatch;
     bool               marked_;
 
-    RegExpCompilation  compilationArray[8];
+    RegExpCompilation  compilationArray[4];
 
-    static int CompilationIndex(CompilationMode mode, bool sticky, bool latin1) {
+    static int CompilationIndex(CompilationMode mode, bool latin1) {
         switch (mode) {
-          case Normal:    return sticky ? (latin1 ? 0 : 1) : (latin1 ? 2 : 3);
-          case MatchOnly: return sticky ? (latin1 ? 4 : 5) : (latin1 ? 6 : 7);
+          case Normal:    return latin1 ? 0 : 1;
+          case MatchOnly: return latin1 ? 2 : 3;
         }
         MOZ_CRASH();
     }
 
     // Tables referenced by JIT code.
     Vector<uint8_t*, 0, SystemAllocPolicy> tables;
 
     /* Internal functions. */
     bool compile(JSContext* cx, HandleLinearString input,
-                 CompilationMode mode, bool sticky, ForceByteCodeEnum force);
+                 CompilationMode mode, ForceByteCodeEnum force);
     bool compile(JSContext* cx, HandleAtom pattern, HandleLinearString input,
-                 CompilationMode mode, bool sticky, ForceByteCodeEnum force);
+                 CompilationMode mode, ForceByteCodeEnum force);
 
     bool compileIfNecessary(JSContext* cx, HandleLinearString input,
-                            CompilationMode mode, bool sticky, ForceByteCodeEnum force);
+                            CompilationMode mode, ForceByteCodeEnum force);
 
-    const RegExpCompilation& compilation(CompilationMode mode, bool sticky, bool latin1) const {
-        return compilationArray[CompilationIndex(mode, sticky, latin1)];
+    const RegExpCompilation& compilation(CompilationMode mode, bool latin1) const {
+        return compilationArray[CompilationIndex(mode, latin1)];
     }
 
-    RegExpCompilation& compilation(CompilationMode mode, bool sticky, bool latin1) {
-        return compilationArray[CompilationIndex(mode, sticky, latin1)];
+    RegExpCompilation& compilation(CompilationMode mode, bool latin1) {
+        return compilationArray[CompilationIndex(mode, latin1)];
     }
 
   public:
     RegExpShared(JSAtom* source, RegExpFlag flags);
     ~RegExpShared();
 
     // Execute this RegExp on input starting from searchIndex, filling in
     // matches if specified and otherwise only determining if there is a match.
     RegExpRunStatus execute(JSContext* cx, HandleLinearString input, size_t searchIndex,
-                            bool sticky, MatchPairs* matches, size_t* endIndex);
+                            MatchPairs* matches, size_t* endIndex);
 
     // Register a table with this RegExpShared, and take ownership.
     bool addTable(uint8_t* table) {
         return tables.append(table);
     }
 
     /* Accessors */
 
@@ -192,25 +192,23 @@ class RegExpShared
     JSAtom* getSource() const           { return source; }
     RegExpFlag getFlags() const         { return flags; }
     bool ignoreCase() const             { return flags & IgnoreCaseFlag; }
     bool global() const                 { return flags & GlobalFlag; }
     bool multiline() const              { return flags & MultilineFlag; }
     bool sticky() const                 { return flags & StickyFlag; }
     bool unicode() const                { return flags & UnicodeFlag; }
 
-    bool isCompiled(CompilationMode mode, bool sticky, bool latin1,
+    bool isCompiled(CompilationMode mode, bool latin1,
                     ForceByteCodeEnum force = DontForceByteCode) const {
-        return compilation(mode, sticky, latin1).compiled(force);
+        return compilation(mode, latin1).compiled(force);
     }
     bool isCompiled() const {
-        return isCompiled(Normal, true, true) || isCompiled(Normal, true, false)
-            || isCompiled(Normal, false, true) || isCompiled(Normal, false, false)
-            || isCompiled(MatchOnly, true, true) || isCompiled(MatchOnly, true, false)
-            || isCompiled(MatchOnly, false, true) || isCompiled(MatchOnly, false, false);
+        return isCompiled(Normal, true) || isCompiled(Normal, false)
+            || isCompiled(MatchOnly, true) || isCompiled(MatchOnly, false);
     }
 
     void trace(JSTracer* trc);
     bool needsSweep(JSRuntime* rt);
 
     bool marked() const { return marked_; }
     void clearMarked() { marked_ = false; }
 
@@ -221,34 +219,24 @@ class RegExpShared
     static size_t offsetOfFlags() {
         return offsetof(RegExpShared, flags);
     }
 
     static size_t offsetOfParenCount() {
         return offsetof(RegExpShared, parenCount);
     }
 
-    static size_t offsetOfStickyLatin1JitCode(CompilationMode mode) {
+    static size_t offsetOfLatin1JitCode(CompilationMode mode) {
         return offsetof(RegExpShared, compilationArray)
-             + (CompilationIndex(mode, true, true) * sizeof(RegExpCompilation))
+             + (CompilationIndex(mode, true) * sizeof(RegExpCompilation))
              + offsetof(RegExpCompilation, jitCode);
     }
-    static size_t offsetOfNotStickyLatin1JitCode(CompilationMode mode) {
-        return offsetof(RegExpShared, compilationArray)
-             + (CompilationIndex(mode, false, true) * sizeof(RegExpCompilation))
-             + offsetof(RegExpCompilation, jitCode);
-    }
-    static size_t offsetOfStickyTwoByteJitCode(CompilationMode mode) {
+    static size_t offsetOfTwoByteJitCode(CompilationMode mode) {
         return offsetof(RegExpShared, compilationArray)
-             + (CompilationIndex(mode, true, false) * sizeof(RegExpCompilation))
-             + offsetof(RegExpCompilation, jitCode);
-    }
-    static size_t offsetOfNotStickyTwoByteJitCode(CompilationMode mode) {
-        return offsetof(RegExpShared, compilationArray)
-             + (CompilationIndex(mode, false, false) * sizeof(RegExpCompilation))
+             + (CompilationIndex(mode, false) * sizeof(RegExpCompilation))
              + offsetof(RegExpCompilation, jitCode);
     }
 
     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
 };
 
 /*
  * Extend the lifetime of a given RegExpShared to at least the lifetime of
--- a/js/src/vm/RegExpStatics.cpp
+++ b/js/src/vm/RegExpStatics.cpp
@@ -85,17 +85,17 @@ RegExpStatics::executeLazy(JSContext* cx
 
     /*
      * It is not necessary to call aboutToWrite(): evaluation of
      * implicit copies is safe.
      */
 
     /* Execute the full regular expression. */
     RootedLinearString input(cx, matchesInput);
-    RegExpRunStatus status = g->execute(cx, input, lazyIndex, lazySticky, &this->matches, nullptr);
+    RegExpRunStatus status = g->execute(cx, input, lazyIndex, &this->matches, nullptr);
     if (status == RegExpRunStatus_Error)
         return false;
 
     /*
      * RegExpStatics are only updated on successful (matching) execution.
      * Re-running the same expression must therefore produce a matching result.
      */
     MOZ_ASSERT(status == RegExpRunStatus_Success);
--- a/js/src/vm/RegExpStatics.h
+++ b/js/src/vm/RegExpStatics.h
@@ -26,17 +26,16 @@ class RegExpStatics
     /*
      * The previous RegExp input, used to resolve lazy state.
      * A raw RegExpShared cannot be stored because it may be in
      * a different compartment via evalcx().
      */
     RelocatablePtrAtom      lazySource;
     RegExpFlag              lazyFlags;
     size_t                  lazyIndex;
-    bool                    lazySticky;
 
     /* The latest RegExp input, set before execution. */
     RelocatablePtrString    pendingInput;
 
     /*
      * If non-zero, |matchesInput| and the |lazy*| fields may be used
      * to replay the last executed RegExp, and |matches| is invalid.
      */
@@ -59,17 +58,17 @@ class RegExpStatics
     bool createDependent(JSContext* cx, size_t start, size_t end, MutableHandleValue out);
 
     struct InitBuffer {};
     explicit RegExpStatics(InitBuffer) {}
 
   public:
     /* Mutators. */
     inline void updateLazily(JSContext* cx, JSLinearString* input,
-                             RegExpShared* shared, size_t lastIndex, bool sticky);
+                             RegExpShared* shared, size_t lastIndex);
     inline bool updateFromMatchPairs(JSContext* cx, JSLinearString* input, MatchPairs& newPairs);
 
     inline void clear();
 
     /* Corresponds to JSAPI functionality to set the pending RegExp input. */
     void reset(JSContext* cx, JSString* newInput) {
         clear();
         pendingInput = newInput;
@@ -130,20 +129,16 @@ class RegExpStatics
     static size_t offsetOfLazyFlags() {
         return offsetof(RegExpStatics, lazyFlags);
     }
 
     static size_t offsetOfLazyIndex() {
         return offsetof(RegExpStatics, lazyIndex);
     }
 
-    static size_t offsetOfLazySticky() {
-        return offsetof(RegExpStatics, lazySticky);
-    }
-
     static size_t offsetOfPendingLazyEvaluation() {
         return offsetof(RegExpStatics, pendingLazyEvaluation);
     }
 };
 
 inline bool
 RegExpStatics::createDependent(JSContext* cx, size_t start, size_t end, MutableHandleValue out)
 {
@@ -322,28 +317,27 @@ RegExpStatics::getRightContext(JSSubStri
     }
     MOZ_ASSERT(matches[0].limit <= int(matchesInput->length()));
     size_t length = matchesInput->length() - matches[0].limit;
     out->init(matchesInput, matches[0].limit, length);
 }
 
 inline void
 RegExpStatics::updateLazily(JSContext* cx, JSLinearString* input,
-                            RegExpShared* shared, size_t lastIndex, bool sticky)
+                            RegExpShared* shared, size_t lastIndex)
 {
     MOZ_ASSERT(input && shared);
 
     BarrieredSetPair<JSString, JSLinearString>(cx->zone(),
                                                pendingInput, input,
                                                matchesInput, input);
 
     lazySource = shared->source;
     lazyFlags = shared->flags;
     lazyIndex = lastIndex;
-    lazySticky = sticky;
     pendingLazyEvaluation = 1;
 }
 
 inline bool
 RegExpStatics::updateFromMatchPairs(JSContext* cx, JSLinearString* input, MatchPairs& newPairs)
 {
     MOZ_ASSERT(input);
 
@@ -367,17 +361,16 @@ RegExpStatics::updateFromMatchPairs(JSCo
 inline void
 RegExpStatics::clear()
 {
     matches.forgetArray();
     matchesInput = nullptr;
     lazySource = nullptr;
     lazyFlags = RegExpFlag(0);
     lazyIndex = size_t(-1);
-    lazySticky = false;
     pendingInput = nullptr;
     pendingLazyEvaluation = false;
 }
 
 inline void
 RegExpStatics::setPendingInput(JSString* newInput)
 {
     pendingInput = newInput;
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -2574,16 +2574,17 @@ static const JSFunctionSpec intrinsic_fu
     JS_INLINABLE_FN("StringSplitString", intrinsic_StringSplitString, 2, 0,
                     IntrinsicStringSplitString),
     JS_FN("StringSplitStringLimit", intrinsic_StringSplitStringLimit, 3, 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("regexp_construct_no_sticky", regexp_construct_no_sticky, 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),