Backed out changeset 6f8d311064d9 (bug 15396900) for bustages in bug1033946.js CLOSED TREE
authorNoemi Erli <nerli@mozilla.com>
Tue, 02 Apr 2019 05:38:56 +0300
changeset 467505 7d6ecc01c3974dd05dc69e72f2c3a95e23bf1f26
parent 467504 3305707514a18ff272af09a9e426819b9b47dc6a
child 467506 68ac00e863e05091280bf23765607af045cba3cc
push id35799
push usercbrindusan@mozilla.com
push dateTue, 02 Apr 2019 08:35:12 +0000
treeherdermozilla-central@ea0977445697 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs15396900, 1033946
milestone68.0a1
backs out6f8d311064d92c579cc6248f42890fee541bc213
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
Backed out changeset 6f8d311064d9 (bug 15396900) for bustages in bug1033946.js CLOSED TREE
dom/base/nsContentUtils.cpp
js/ipc/WrapperAnswer.cpp
js/ipc/WrapperOwner.cpp
js/public/RegExp.h
js/public/RegExpFlags.h
js/src/builtin/RegExp.cpp
js/src/builtin/TestingFunctions.cpp
js/src/frontend/BinAST.yaml
js/src/frontend/BinASTParser.cpp
js/src/frontend/Parser.cpp
js/src/frontend/TokenStream.cpp
js/src/frontend/TokenStream.h
js/src/irregexp/RegExpParser.cpp
js/src/irregexp/RegExpParser.h
js/src/jit/CodeGenerator.cpp
js/src/jit/MCallOptimize.cpp
js/src/jsapi-tests/testRegExp.cpp
js/src/jsapi-tests/tests.h
js/src/moz.build
js/src/vm/RegExpConstants.h
js/src/vm/RegExpObject.cpp
js/src/vm/RegExpObject.h
js/src/vm/RegExpShared.h
js/src/vm/RegExpStatics.h
js/src/vm/StructuredClone.cpp
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -6511,17 +6511,17 @@ bool nsContentUtils::IsPatternMatching(n
 
   // The pattern has to match the entire value.
   aPattern.InsertLiteral(u"^(?:", 0);
   aPattern.AppendLiteral(")$");
 
   JS::Rooted<JSObject*> re(
       cx,
       JS::NewUCRegExpObject(cx, static_cast<char16_t*>(aPattern.BeginWriting()),
-                            aPattern.Length(), JS::RegExpFlag::Unicode));
+                            aPattern.Length(), JS::RegExpFlags::Unicode));
   if (!re) {
     // Remove extra patterns added above to report with the original pattern.
     aPattern.Cut(0, 4);
     aPattern.Cut(aPattern.Length() - 2, 2);
     ReportPatternCompileFailure(aPattern, aDocument, cx);
     return true;
   }
 
--- a/js/ipc/WrapperAnswer.cpp
+++ b/js/ipc/WrapperAnswer.cpp
@@ -767,17 +767,17 @@ bool WrapperAnswer::RecvRegExpToShared(c
     return fail(jsapi, rs);
   }
   nsAutoJSString sourceStr;
   if (!sourceStr.init(cx, sourceJSStr)) {
     return fail(jsapi, rs);
   }
   source->Assign(sourceStr);
 
-  *flags = JS::GetRegExpFlags(cx, obj).value();
+  *flags = JS::GetRegExpFlags(cx, obj);
 
   return ok(rs);
 }
 
 bool WrapperAnswer::RecvGetPropertyKeys(const ObjectId& objId,
                                         const uint32_t& flags, ReturnStatus* rs,
                                         nsTArray<JSIDVariant>* ids) {
   if (!IsInAutomation()) {
--- a/js/ipc/WrapperOwner.cpp
+++ b/js/ipc/WrapperOwner.cpp
@@ -7,17 +7,16 @@
 
 #include "WrapperOwner.h"
 #include "JavaScriptLogging.h"
 #include "mozilla/Unused.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "jsfriendapi.h"
 #include "js/CharacterEncoding.h"
 #include "js/RegExp.h"
-#include "js/RegExpFlags.h"
 #include "xpcprivate.h"
 #include "WrapperFactory.h"
 
 #include "nsIDocShellTreeItem.h"
 #include "mozilla/dom/Document.h"
 
 using namespace js;
 using namespace JS;
@@ -829,18 +828,17 @@ RegExpShared* WrapperOwner::regexp_toSha
   }
   LOG_STACK();
 
   if (!ok(cx, status)) {
     return nullptr;
   }
 
   RootedObject regexp(cx);
-  regexp = JS::NewUCRegExpObject(cx, source.get(), source.Length(),
-                                 RegExpFlags(flags));
+  regexp = JS::NewUCRegExpObject(cx, source.get(), source.Length(), flags);
   if (!regexp) {
     return nullptr;
   }
 
   return js::RegExpToSharedNonInline(cx, regexp);
 }
 
 void CPOWProxyHandler::finalize(JSFreeOp* fop, JSObject* proxy) const {
--- a/js/public/RegExp.h
+++ b/js/public/RegExp.h
@@ -8,39 +8,64 @@
 
 #ifndef js_RegExp_h
 #define js_RegExp_h
 
 #include <stddef.h>  // size_t
 
 #include "jstypes.h"  // JS_PUBLIC_API
 
-#include "js/RegExpFlags.h"  // JS::RegExpFlags
 #include "js/RootingAPI.h"  // JS::{,Mutable}Handle
 #include "js/Value.h"       // JS::Value
 
 struct JSContext;
 class JSString;
 
 namespace JS {
 
 /**
+ * A namespace for all regular expression flags as they appear in the APIs below
+ * as flags values.
+ */
+struct RegExpFlags {
+ public:
+  /**
+   * Interpret regular expression source text case-insensitively by folding
+   * uppercase letters to lowercase, i.e. /i.
+   */
+  static constexpr unsigned IgnoreCase = 0b0'0001;
+
+  /**
+   * Act globally and find *all* matches (rather than stopping after just the
+   * first one), i.e. /g.
+   */
+  static constexpr unsigned Global = 0b0'0010;
+
+  /** Treat ^ and $ as begin and end of line, i.e. /m. */
+  static constexpr unsigned Multiline = 0b0'0100;
+
+  /** Only match starting from <regular expression>.lastIndex, i.e. /y. */
+  static constexpr unsigned Sticky = 0b0'1000;
+
+  /** Use Unicode semantics, i.e. /u. */
+  static constexpr unsigned Unicode = 0b1'0000;
+};
+
+/**
  * Create a new RegExp for the given Latin-1-encoded bytes and flags.
  */
 extern JS_PUBLIC_API JSObject* NewRegExpObject(JSContext* cx, const char* bytes,
-                                               size_t length,
-                                               RegExpFlags flags);
+                                               size_t length, unsigned flags);
 
 /**
  * Create a new RegExp for the given source and flags.
  */
 extern JS_PUBLIC_API JSObject* NewUCRegExpObject(JSContext* cx,
                                                  const char16_t* chars,
-                                                 size_t length,
-                                                 RegExpFlags flags);
+                                                 size_t length, unsigned flags);
 
 extern JS_PUBLIC_API bool SetRegExpInput(JSContext* cx, Handle<JSObject*> obj,
                                          Handle<JSString*> input);
 
 extern JS_PUBLIC_API bool ClearRegExpStatics(JSContext* cx,
                                              Handle<JSObject*> obj);
 
 extern JS_PUBLIC_API bool ExecuteRegExp(JSContext* cx, Handle<JSObject*> obj,
@@ -65,20 +90,20 @@ extern JS_PUBLIC_API bool ExecuteRegExpN
  * This method returns true with |*isRegExp == false| when passed an ES6 proxy
  * whose target is a RegExp, or when passed a revoked proxy.
  */
 extern JS_PUBLIC_API bool ObjectIsRegExp(JSContext* cx, Handle<JSObject*> obj,
                                          bool* isRegExp);
 
 /**
  * Given a RegExp object (or a wrapper around one), return the set of all
- * JS::RegExpFlag::* for it.
+ * JS::RegExpFlags::* for it.
  */
-extern JS_PUBLIC_API RegExpFlags GetRegExpFlags(JSContext* cx,
-                                                Handle<JSObject*> obj);
+extern JS_PUBLIC_API unsigned GetRegExpFlags(JSContext* cx,
+                                             Handle<JSObject*> obj);
 
 /**
  * Return the source text for a RegExp object (or a wrapper around one), or null
  * on failure.
  */
 extern JS_PUBLIC_API JSString* GetRegExpSource(JSContext* cx,
                                                Handle<JSObject*> obj);
 
deleted file mode 100644
--- a/js/public/RegExpFlags.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim: set ts=8 sts=2 et sw=2 tw=80:
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/* Regular expression flags. */
-
-#ifndef js_RegExpFlags_h
-#define js_RegExpFlags_h
-
-#include "mozilla/Assertions.h"  // MOZ_ASSERT
-#include "mozilla/Attributes.h"  // MOZ_IMPLICIT
-
-#include <stdint.h>  // uint8_t
-
-namespace JS {
-
-/**
- * Regular expression flag values, suitable for initializing a collection of
- * regular expression flags as defined below in |RegExpFlags|.  Flags are listed
- * in alphabetical order by syntax -- /g, /i, /m, /u, /y.
- */
-class RegExpFlag {
-  // WARNING TO SPIDERMONKEY HACKERS (embedders must assume these values can
-  // change):
-  //
-  // Flag-bit values appear in XDR and structured clone data formats, so none of
-  // these values can be changed (including to assign values in numerically
-  // ascending order) unless you also add a translation layer.
-
- public:
-  /**
-   * Act globally and find *all* matches (rather than stopping after just the
-   * first one), i.e. /g.
-   */
-  static constexpr uint8_t Global = 0b0'0010;
-
-  /**
-   * Interpret regular expression source text case-insensitively by folding
-   * uppercase letters to lowercase, i.e. /i.
-   */
-  static constexpr uint8_t IgnoreCase = 0b0'0001;
-
-  /** Treat ^ and $ as begin and end of line, i.e. /m. */
-  static constexpr uint8_t Multiline = 0b0'0100;
-
-  /** Use Unicode semantics, i.e. /u. */
-  static constexpr uint8_t Unicode = 0b1'0000;
-
-  /** Only match starting from <regular expression>.lastIndex, i.e. /y. */
-  static constexpr uint8_t Sticky = 0b0'1000;
-
-  /** No regular expression flags. */
-  static constexpr uint8_t NoFlags = 0b0'0000;
-
-  /** All regular expression flags. */
-  static constexpr uint8_t AllFlags = 0b1'1111;
-};
-
-/**
- * A collection of regular expression flags.  Individual flag values may be
- * combined into a collection using bitwise operators.
- */
-class RegExpFlags {
- public:
-  using Flag = uint8_t;
-
- private:
-  Flag flags_;
-
- public:
-  RegExpFlags() = default;
-
-  MOZ_IMPLICIT RegExpFlags(Flag flags) : flags_(flags) {
-    MOZ_ASSERT((flags & RegExpFlag::AllFlags) == flags,
-               "flags must not contain unrecognized flags");
-  }
-
-  RegExpFlags(const RegExpFlags&) = default;
-
-  bool operator==(const RegExpFlags& other) const {
-    return flags_ == other.flags_;
-  }
-
-  bool operator!=(const RegExpFlags& other) const { return !(*this == other); }
-
-  RegExpFlags operator&(Flag flag) const { return RegExpFlags(flags_ & flag); }
-
-  RegExpFlags operator|(Flag flag) const { return RegExpFlags(flags_ | flag); }
-
-  RegExpFlags operator^(Flag flag) const { return RegExpFlags(flags_ ^ flag); }
-
-  RegExpFlags operator~() const { return RegExpFlags(~flags_); }
-
-  bool global() const { return flags_ & RegExpFlag::Global; }
-  bool ignoreCase() const { return flags_ & RegExpFlag::Global; }
-  bool multiline() const { return flags_ & RegExpFlag::Multiline; }
-  bool unicode() const { return flags_ & RegExpFlag::Global; }
-  bool sticky() const { return flags_ & RegExpFlag::Sticky; }
-
-  explicit operator bool() const { return flags_ != 0; }
-
-  Flag value() const { return flags_; }
-};
-
-inline RegExpFlags& operator&=(RegExpFlags& flags, RegExpFlags::Flag flag) {
-  flags = flags & flag;
-  return flags;
-}
-
-inline RegExpFlags& operator|=(RegExpFlags& flags, RegExpFlags::Flag flag) {
-  flags = flags | flag;
-  return flags;
-}
-
-inline RegExpFlags& operator^=(RegExpFlags& flags, RegExpFlags::Flag flag) {
-  flags = flags ^ flag;
-  return flags;
-}
-
-}  // namespace JS
-
-#endif  // js_RegExpFlags_h
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -1,45 +1,40 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * vim: set ts=8 sts=2 et sw=2 tw=80:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "builtin/RegExp.h"
 
-#include "mozilla/Casting.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/TypeTraits.h"
 
 #include "frontend/TokenStream.h"
 #include "irregexp/RegExpParser.h"
 #include "jit/InlinableNatives.h"
 #include "js/PropertySpec.h"
-#include "js/RegExpFlags.h"  // JS::RegExpFlag, JS::RegExpFlags
 #include "util/StringBuffer.h"
 #include "util/Unicode.h"
 #include "vm/JSContext.h"
 #include "vm/RegExpStatics.h"
 #include "vm/SelfHosting.h"
 
 #include "vm/EnvironmentObject-inl.h"
 #include "vm/JSObject-inl.h"
 #include "vm/NativeObject-inl.h"
 #include "vm/ObjectOperations-inl.h"
 
 using namespace js;
 
-using mozilla::AssertedCast;
 using mozilla::CheckedInt;
 using mozilla::IsAsciiDigit;
 
 using JS::CompileOptions;
-using JS::RegExpFlag;
-using JS::RegExpFlags;
 
 /*
  * 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) {
@@ -187,26 +182,26 @@ bool js::ExecuteRegExpLegacy(JSContext* 
     rval.setBoolean(true);
     return true;
   }
 
   return CreateRegExpMatchResult(cx, input, matches, rval);
 }
 
 static bool CheckPatternSyntaxSlow(JSContext* cx, HandleAtom pattern,
-                                   RegExpFlags flags) {
+                                   RegExpFlag flags) {
   LifoAllocScope allocScope(&cx->tempLifoAlloc());
   CompileOptions options(cx);
   frontend::TokenStream dummyTokenStream(cx, options, nullptr, 0, nullptr);
   return irregexp::ParsePatternSyntax(dummyTokenStream, allocScope.alloc(),
-                                      pattern, flags.unicode());
+                                      pattern, flags & UnicodeFlag);
 }
 
 static RegExpShared* CheckPatternSyntax(JSContext* cx, HandleAtom pattern,
-                                        RegExpFlags flags) {
+                                        RegExpFlag flags) {
   // If we already have a RegExpShared for this pattern/flags, we can
   // avoid the much slower CheckPatternSyntaxSlow call.
 
   if (RegExpShared* shared = cx->zone()->regExps().maybeGet(pattern, flags)) {
 #ifdef DEBUG
     // Assert the pattern is valid.
     if (!CheckPatternSyntaxSlow(cx, pattern, flags)) {
       MOZ_ASSERT(cx->isThrowingOutOfMemory() || cx->isThrowingOverRecursed());
@@ -252,17 +247,17 @@ static bool RegExpInitializeIgnoringLast
     /* Step 2. */
     pattern = ToAtom<CanGC>(cx, patternValue);
     if (!pattern) {
       return false;
     }
   }
 
   /* Step 3. */
-  RegExpFlags flags = RegExpFlag::NoFlags;
+  RegExpFlag flags = RegExpFlag(0);
   if (!flagsValue.isUndefined()) {
     /* Step 4. */
     RootedString flagStr(cx, ToString<CanGC>(cx, flagsValue));
     if (!flagStr) {
       return false;
     }
 
     /* Step 5. */
@@ -363,17 +358,17 @@ MOZ_ALWAYS_INLINE bool regexp_compile_im
     }
 
     // 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());
 
     RootedAtom sourceAtom(cx);
-    RegExpFlags flags = RegExpFlag::NoFlags;
+    RegExpFlag flags;
     {
       // Step 3b.
       RegExpShared* shared = RegExpToShared(cx, patternObj);
       if (!shared) {
         return false;
       }
 
       sourceAtom = shared->getSource();
@@ -461,17 +456,17 @@ bool js::regexp_construct(JSContext* cx,
     return false;
   }
   if (cls == ESClass::RegExp) {
     // Beware!  |patternObj| might be a proxy into another compartment, so
     // don't assume |patternObj.is<RegExpObject>()|.
     RootedObject patternObj(cx, &patternValue.toObject());
 
     RootedAtom sourceAtom(cx);
-    RegExpFlags flags;
+    RegExpFlag flags;
     RootedRegExpShared shared(cx);
     {
       // Step 4.a.
       shared = RegExpToShared(cx, patternObj);
       if (!shared) {
         return false;
       }
       sourceAtom = shared->getSource();
@@ -495,31 +490,31 @@ bool js::regexp_construct(JSContext* cx,
     Rooted<RegExpObject*> regexp(cx, RegExpAlloc(cx, GenericObject, proto));
     if (!regexp) {
       return false;
     }
 
     // Step 8.
     if (args.hasDefined(1)) {
       // Step 4.c / 21.2.3.2.2 RegExpInitialize step 4.
-      RegExpFlags flagsArg = RegExpFlag::NoFlags;
+      RegExpFlag flagsArg = RegExpFlag(0);
       RootedString flagStr(cx, ToString<CanGC>(cx, args[1]));
       if (!flagStr) {
         return false;
       }
       if (!ParseRegExpFlags(cx, flagStr, &flagsArg)) {
         return false;
       }
 
       // Don't reuse the RegExpShared if we have different flags.
       if (flags != flagsArg) {
         shared = nullptr;
       }
 
-      if (!flags.unicode() && flagsArg.unicode()) {
+      if (!(flags & UnicodeFlag) && flagsArg & UnicodeFlag) {
         // Have to check syntax again when adding 'u' flag.
 
         // ES 2017 draft rev 9b49a888e9dfe2667008a01b2754c3662059ae56
         // 21.2.3.2.2 step 7.
         shared = CheckPatternSyntax(cx, sourceAtom, flagsArg);
         if (!shared) {
           return false;
         }
@@ -594,26 +589,26 @@ bool js::regexp_construct_raw_flags(JSCo
 
   // Step 4.a.
   RootedAtom sourceAtom(cx, AtomizeString(cx, args[0].toString()));
   if (!sourceAtom) {
     return false;
   }
 
   // Step 4.c.
-  RegExpFlags flags = AssertedCast<uint8_t>(int32_t(args[1].toNumber()));
+  int32_t flags = int32_t(args[1].toNumber());
 
   // Step 7.
   RegExpObject* regexp = RegExpAlloc(cx, GenericObject);
   if (!regexp) {
     return false;
   }
 
   // Step 8.
-  regexp->initAndZeroLastIndex(sourceAtom, flags, cx);
+  regexp->initAndZeroLastIndex(sourceAtom, RegExpFlag(flags), cx);
   args.rval().setObject(*regexp);
   return true;
 }
 
 MOZ_ALWAYS_INLINE bool IsRegExpPrototype(HandleValue v, JSContext* cx) {
   return (v.isObject() &&
           cx->global()->maybeGetRegExpPrototype() == &v.toObject());
 }
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -44,17 +44,16 @@
 #include "js/ArrayBuffer.h"  // JS::{DetachArrayBuffer,GetArrayBufferLengthAndData,NewArrayBufferWithContents}
 #include "js/CharacterEncoding.h"
 #include "js/CompilationAndEvaluation.h"
 #include "js/CompileOptions.h"
 #include "js/Debug.h"
 #include "js/HashTable.h"
 #include "js/LocaleSensitive.h"
 #include "js/PropertySpec.h"
-#include "js/RegExpFlags.h"  // JS::RegExpFlag, JS::RegExpFlags
 #include "js/SourceText.h"
 #include "js/StableStringChars.h"
 #include "js/StructuredClone.h"
 #include "js/UbiNode.h"
 #include "js/UbiNodeBreadthFirst.h"
 #include "js/UbiNodeShortestPaths.h"
 #include "js/UniquePtr.h"
 #include "js/Vector.h"
@@ -93,18 +92,16 @@
 
 using namespace js;
 
 using mozilla::ArrayLength;
 using mozilla::Maybe;
 
 using JS::AutoStableStringChars;
 using JS::CompileOptions;
-using JS::RegExpFlag;
-using JS::RegExpFlags;
 using JS::SourceOwnership;
 using JS::SourceText;
 
 // If fuzzingSafe is set, remove functionality that could cause problems with
 // fuzzers. Set this via the environment variable MOZ_FUZZING_SAFE.
 mozilla::Atomic<bool> fuzzingSafe(false);
 
 // If disableOOMFunctions is set, disable functionality that causes artificial
@@ -4850,17 +4847,17 @@ static bool ParseRegExp(JSContext* cx, u
     return false;
   }
 
   if (!args[0].isString()) {
     ReportUsageErrorASCII(cx, callee, "First argument must be a String");
     return false;
   }
 
-  RegExpFlags flags = RegExpFlag::NoFlags;
+  RegExpFlag flags = RegExpFlag(0);
   if (!args.get(1).isUndefined()) {
     if (!args.get(1).isString()) {
       ReportUsageErrorASCII(cx, callee,
                             "Second argument, if present, must be a String");
       return false;
     }
     RootedString flagStr(cx, args[1].toString());
     if (!ParseRegExpFlags(cx, flagStr, &flags)) {
@@ -4885,17 +4882,19 @@ static bool ParseRegExp(JSContext* cx, u
 
   CompileOptions options(cx);
   frontend::TokenStream dummyTokenStream(cx, options, nullptr, 0, nullptr);
 
   // Data lifetime is controlled by LifoAllocScope.
   LifoAllocScope allocScope(&cx->tempLifoAlloc());
   irregexp::RegExpCompileData data;
   if (!irregexp::ParsePattern(dummyTokenStream, allocScope.alloc(), pattern,
-                              match_only, flags, &data)) {
+                              flags & MultilineFlag, match_only,
+                              flags & UnicodeFlag, flags & IgnoreCaseFlag,
+                              flags & GlobalFlag, flags & StickyFlag, &data)) {
     return false;
   }
 
   RootedObject obj(
       cx, ConvertRegExpTreeToObject(cx, allocScope.alloc(), data.tree));
   if (!obj) {
     return false;
   }
--- a/js/src/frontend/BinAST.yaml
+++ b/js/src/frontend/BinAST.yaml
@@ -39,24 +39,21 @@ cpp:
     #include "mozilla/Vector.h"
 
     #include "frontend/BinAST-macros.h"
     #include "frontend/BinASTTokenReaderMultipart.h"
     #include "frontend/FullParseHandler.h"
     #include "frontend/ParseNode.h"
     #include "frontend/Parser.h"
     #include "frontend/SharedContext.h"
-    #include "js/RegExpFlags.h"  //  JS::RegExpFlag, JS::RegExpFlags
+
     #include "vm/RegExpObject.h"
 
     #include "frontend/ParseContext-inl.h"
 
-    using JS::RegExpFlag;
-    using JS::RegExpFlags;
-
     namespace js {
     namespace frontend {
 
     // Compare a bunch of `uint8_t` values (as returned by the tokenizer_) with
     // a string literal (and ONLY a string literal).
     template<typename Tok, size_t N>
     bool operator==(const typename Tok::Chars& left, const char (&right)[N]) {
       return Tok::equals(left, right);
@@ -1279,28 +1276,28 @@ LiteralPropertyName:
 LiteralRegExpExpression:
   fields:
     flags:
       block:
         replace: |
           Chars flags(cx_);
           MOZ_TRY(tokenizer_->readChars(flags));
   build: |
-    RegExpFlags reflags = RegExpFlag::NoFlags;
+    RegExpFlag reflags = NoFlags;
     for (auto c : flags) {
-      if (c == 'g' && !reflags.global()) {
-        reflags |= RegExpFlag::Global;
-      } else if (c == 'i' && !reflags.ignoreCase()) {
-        reflags |= RegExpFlag::IgnoreCase;
-      } else if (c == 'm' && !reflags.multiline()) {
-        reflags |= RegExpFlag::Multiline;
-      } else if (c == 'u' && !reflags.unicode()) {
-        reflags |= RegExpFlag::Unicode;
-      } else if (c == 'y' && !reflags.sticky()) {
-        reflags |= RegExpFlag::Sticky;
+      if (c == 'g' && !(reflags & GlobalFlag)) {
+        reflags = RegExpFlag(reflags | GlobalFlag);
+      } else if (c == 'i' && !(reflags & IgnoreCaseFlag)) {
+        reflags = RegExpFlag(reflags | IgnoreCaseFlag);
+      } else if (c == 'm' && !(reflags & MultilineFlag)) {
+        reflags = RegExpFlag(reflags | MultilineFlag);
+      } else if (c == 'y' && !(reflags & StickyFlag)) {
+        reflags = RegExpFlag(reflags | StickyFlag);
+      } else if (c == 'u' && !(reflags & UnicodeFlag)) {
+        reflags = RegExpFlag(reflags | UnicodeFlag);
       } else {
         return raiseError("Invalid regexp flags");
       }
     }
 
 
     Rooted<RegExpObject*> reobj(cx_);
     BINJS_TRY_VAR(reobj,
--- a/js/src/frontend/BinASTParser.cpp
+++ b/js/src/frontend/BinASTParser.cpp
@@ -19,24 +19,21 @@
 #include "mozilla/Vector.h"
 
 #include "frontend/BinAST-macros.h"
 #include "frontend/BinASTTokenReaderMultipart.h"
 #include "frontend/FullParseHandler.h"
 #include "frontend/ParseNode.h"
 #include "frontend/Parser.h"
 #include "frontend/SharedContext.h"
-#include "js/RegExpFlags.h"  // JS::RegExpFlag, JS::RegExpFlags
+
 #include "vm/RegExpObject.h"
 
 #include "frontend/ParseContext-inl.h"
 
-using JS::RegExpFlag;
-using JS::RegExpFlags;
-
 namespace js {
 namespace frontend {
 
 // Compare a bunch of `uint8_t` values (as returned by the tokenizer_) with
 // a string literal (and ONLY a string literal).
 template <typename Tok, size_t N>
 bool operator==(const typename Tok::Chars& left, const char (&right)[N]) {
   return Tok::equals(left, right);
@@ -3520,28 +3517,28 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
 #endif  // defined(DEBUG)
 
   RootedAtom pattern(cx_);
   MOZ_TRY_VAR(pattern, tokenizer_->readAtom());
   Chars flags(cx_);
   MOZ_TRY(tokenizer_->readChars(flags));
 
-  RegExpFlags reflags = RegExpFlag::NoFlags;
+  RegExpFlag reflags = NoFlags;
   for (auto c : flags) {
-    if (c == 'g' && !reflags.global()) {
-      reflags |= RegExpFlag::Global;
-    } else if (c == 'i' && !reflags.ignoreCase()) {
-      reflags |= RegExpFlag::IgnoreCase;
-    } else if (c == 'm' && !reflags.multiline()) {
-      reflags |= RegExpFlag::Multiline;
-    } else if (c == 'u' && !reflags.unicode()) {
-      reflags |= RegExpFlag::Unicode;
-    } else if (c == 'y' && !reflags.sticky()) {
-      reflags |= RegExpFlag::Sticky;
+    if (c == 'g' && !(reflags & GlobalFlag)) {
+      reflags = RegExpFlag(reflags | GlobalFlag);
+    } else if (c == 'i' && !(reflags & IgnoreCaseFlag)) {
+      reflags = RegExpFlag(reflags | IgnoreCaseFlag);
+    } else if (c == 'm' && !(reflags & MultilineFlag)) {
+      reflags = RegExpFlag(reflags | MultilineFlag);
+    } else if (c == 'y' && !(reflags & StickyFlag)) {
+      reflags = RegExpFlag(reflags | StickyFlag);
+    } else if (c == 'u' && !(reflags & UnicodeFlag)) {
+      reflags = RegExpFlag(reflags | UnicodeFlag);
     } else {
       return raiseError("Invalid regexp flags");
     }
   }
 
   Rooted<RegExpObject*> reobj(cx_);
   BINJS_TRY_VAR(reobj,
                 RegExpObject::create(cx_, pattern, reflags, TenuredObject));
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -37,17 +37,16 @@
 #include "builtin/ModuleObject.h"
 #include "builtin/SelfHostingDefines.h"
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/FoldConstants.h"
 #include "frontend/ModuleSharedContext.h"
 #include "frontend/ParseNode.h"
 #include "frontend/TokenStream.h"
 #include "irregexp/RegExpParser.h"
-#include "js/RegExpFlags.h"  // JS::RegExpFlags
 #include "vm/BytecodeUtil.h"
 #include "vm/JSAtom.h"
 #include "vm/JSContext.h"
 #include "vm/JSFunction.h"
 #include "vm/JSScript.h"
 #include "vm/RegExpObject.h"
 #include "vm/StringType.h"
 #include "wasm/AsmJS.h"
@@ -66,17 +65,16 @@ using mozilla::PodCopy;
 using mozilla::PodZero;
 using mozilla::PointerRangeSize;
 using mozilla::Some;
 using mozilla::Unused;
 using mozilla::Utf8Unit;
 
 using JS::AutoGCRooter;
 using JS::ReadOnlyCompileOptions;
-using JS::RegExpFlags;
 
 namespace js {
 namespace frontend {
 
 using DeclaredNamePtr = ParseContext::Scope::DeclaredNamePtr;
 using AddDeclaredNamePtr = ParseContext::Scope::AddDeclaredNamePtr;
 using BindingIter = ParseContext::Scope::BindingIter;
 using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr;
@@ -9254,17 +9252,17 @@ GeneralParser<ParseHandler, Unit>::noSub
 }
 
 template <typename Unit>
 RegExpLiteral* Parser<FullParseHandler, Unit>::newRegExp() {
   MOZ_ASSERT(!options().selfHostingMode);
 
   // Create the regexp and check its syntax.
   const auto& chars = tokenStream.getCharBuffer();
-  RegExpFlags flags = anyChars.currentToken().regExpFlags();
+  RegExpFlag flags = anyChars.currentToken().regExpFlags();
 
   Rooted<RegExpObject*> reobj(cx_);
   reobj = RegExpObject::create(cx_, chars.begin(), chars.length(), flags,
                                anyChars, TenuredObject);
   if (!reobj) {
     return null();
   }
 
@@ -9273,23 +9271,23 @@ RegExpLiteral* Parser<FullParseHandler, 
 
 template <typename Unit>
 SyntaxParseHandler::RegExpLiteralType
 Parser<SyntaxParseHandler, Unit>::newRegExp() {
   MOZ_ASSERT(!options().selfHostingMode);
 
   // Only check the regexp's syntax, but don't create a regexp object.
   const auto& chars = tokenStream.getCharBuffer();
-  RegExpFlags flags = anyChars.currentToken().regExpFlags();
+  RegExpFlag flags = anyChars.currentToken().regExpFlags();
 
   mozilla::Range<const char16_t> source(chars.begin(), chars.length());
   {
     LifoAllocScope scopeAlloc(&alloc_);
     if (!js::irregexp::ParsePatternSyntax(anyChars, scopeAlloc.alloc(), source,
-                                          flags.unicode())) {
+                                          flags & UnicodeFlag)) {
       return null();
     }
   }
 
   return handler_.newRegExp(SyntaxParseHandler::NodeGeneric, pos(), *this);
 }
 
 template <class ParseHandler, typename Unit>
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -29,17 +29,16 @@
 
 #include "jsexn.h"
 #include "jsnum.h"
 
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/Parser.h"
 #include "frontend/ReservedWords.h"
 #include "js/CharacterEncoding.h"
-#include "js/RegExpFlags.h"  // JS::RegExpFlags
 #include "js/UniquePtr.h"
 #include "util/StringBuffer.h"
 #include "util/Unicode.h"
 #include "vm/HelperThreads.h"
 #include "vm/JSAtom.h"
 #include "vm/JSContext.h"
 #include "vm/Realm.h"
 
@@ -52,18 +51,16 @@ using mozilla::IsAsciiDigit;
 using mozilla::IsTrailingUnit;
 using mozilla::MakeScopeExit;
 using mozilla::MakeSpan;
 using mozilla::Maybe;
 using mozilla::PointerRangeSize;
 using mozilla::Utf8Unit;
 
 using JS::ReadOnlyCompileOptions;
-using JS::RegExpFlag;
-using JS::RegExpFlags;
 
 struct ReservedWordInfo {
   const char* chars;  // C string with reserved word text
   js::frontend::TokenKind tokentype;
 };
 
 static const ReservedWordInfo reservedWords[] = {
 #define RESERVED_WORD_INFO(word, name, type) \
@@ -2317,44 +2314,44 @@ MOZ_MUST_USE bool TokenStreamSpecific<Un
 
     MOZ_ASSERT(!IsLineTerminator(AssertedCast<char32_t>(unit)));
     if (!this->charBuffer.append(unit)) {
       return badToken();
     }
   } while (true);
 
   int32_t unit;
-  RegExpFlags reflags = RegExpFlag::NoFlags;
+  RegExpFlag reflags = NoFlags;
   while (true) {
-    uint8_t flag;
+    RegExpFlag flag;
     unit = getCodeUnit();
     if (unit == 'g') {
-      flag = RegExpFlag::Global;
+      flag = GlobalFlag;
     } else if (unit == 'i') {
-      flag = RegExpFlag::IgnoreCase;
+      flag = IgnoreCaseFlag;
     } else if (unit == 'm') {
-      flag = RegExpFlag::Multiline;
+      flag = MultilineFlag;
+    } else if (unit == 'y') {
+      flag = StickyFlag;
     } else if (unit == 'u') {
-      flag = RegExpFlag::Unicode;
-    } else if (unit == 'y') {
-      flag = RegExpFlag::Sticky;
+      flag = UnicodeFlag;
     } else if (IsAsciiAlpha(unit)) {
-      flag = RegExpFlag::NoFlags;
+      flag = NoFlags;
     } else {
       break;
     }
 
-    if ((reflags & flag) || flag == RegExpFlag::NoFlags) {
+    if ((reflags & flag) || flag == NoFlags) {
       ungetCodeUnit(unit);
       char buf[2] = {char(unit), '\0'};
       error(JSMSG_BAD_REGEXP_FLAG, buf);
       return badToken();
     }
 
-    reflags |= flag;
+    reflags = RegExpFlag(reflags | flag);
   }
   ungetCodeUnit(unit);
 
   newRegExpToken(reflags, start, out);
   return true;
 }
 
 template <typename Unit, class AnyCharsAccess>
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -201,23 +201,23 @@
 #include <stdint.h>
 #include <stdio.h>
 
 #include "jspubtd.h"
 
 #include "frontend/ErrorReporter.h"
 #include "frontend/TokenKind.h"
 #include "js/CompileOptions.h"
-#include "js/RegExpFlags.h"  // JS::RegExpFlag, JS::RegExpFlags
 #include "js/UniquePtr.h"
 #include "js/Vector.h"
 #include "util/Text.h"
 #include "util/Unicode.h"
 #include "vm/ErrorReporting.h"
 #include "vm/JSAtom.h"
+#include "vm/RegExpConstants.h"
 #include "vm/StringType.h"
 
 struct JSContext;
 struct KeywordInfo;
 
 namespace js {
 
 class AutoKeepAtoms;
@@ -375,17 +375,17 @@ struct Token {
       /** Numeric literal's value. */
       double value;
 
       /** Does the numeric literal contain a '.'? */
       DecimalPoint decimalPoint;
     } number;
 
     /** Regular expression flags; use charBuffer to access source chars. */
-    JS::RegExpFlags reflags;
+    RegExpFlag reflags;
   } u;
 
 #ifdef DEBUG
   /** The modifier used to get this token. */
   Modifier modifier;
 
   /**
    * Exception for this modifier to permit modifier mismatches in certain
@@ -402,18 +402,19 @@ struct Token {
   }
 
   void setAtom(JSAtom* atom) {
     MOZ_ASSERT(type == TokenKind::String || type == TokenKind::TemplateHead ||
                type == TokenKind::NoSubsTemplate);
     u.atom = atom;
   }
 
-  void setRegExpFlags(JS::RegExpFlags flags) {
+  void setRegExpFlags(RegExpFlag flags) {
     MOZ_ASSERT(type == TokenKind::RegExp);
+    MOZ_ASSERT((flags & AllFlags) == flags);
     u.reflags = flags;
   }
 
   void setNumber(double n, DecimalPoint decimalPoint) {
     MOZ_ASSERT(type == TokenKind::Number);
     u.number.value = n;
     u.number.decimalPoint = decimalPoint;
   }
@@ -426,18 +427,19 @@ struct Token {
   }
 
   JSAtom* atom() const {
     MOZ_ASSERT(type == TokenKind::String || type == TokenKind::TemplateHead ||
                type == TokenKind::NoSubsTemplate);
     return u.atom;
   }
 
-  JS::RegExpFlags regExpFlags() const {
+  RegExpFlag regExpFlags() const {
     MOZ_ASSERT(type == TokenKind::RegExp);
+    MOZ_ASSERT((u.reflags & AllFlags) == u.reflags);
     return u.reflags;
   }
 
   double number() const {
     MOZ_ASSERT(type == TokenKind::Number);
     return u.number.value;
   }
 
@@ -1992,18 +1994,17 @@ class GeneralTokenStreamChars : public S
 
   void newPrivateNameToken(PropertyName* name, TokenStart start,
                            TokenStreamShared::Modifier modifier,
                            TokenKind* out) {
     Token* token = newToken(TokenKind::PrivateName, start, modifier, out);
     token->setName(name);
   }
 
-  void newRegExpToken(JS::RegExpFlags reflags, TokenStart start,
-                      TokenKind* out) {
+  void newRegExpToken(RegExpFlag reflags, TokenStart start, TokenKind* out) {
     Token* token =
         newToken(TokenKind::RegExp, start, TokenStreamShared::Operand, out);
     token->setRegExpFlags(reflags);
   }
 
   MOZ_COLD bool badToken();
 
   /**
@@ -2796,18 +2797,17 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
 // (Unit, AnyCharsAccess) pairs -- and that gets super-messy as AnyCharsAccess
 // *itself* is templated.  This symbol really isn't that huge compared to some
 // defined inline in TokenStreamSpecific, so just rely on the linker commoning
 // stuff up.
 template <typename Unit>
 template <class AnyCharsAccess>
 inline TokenStreamPosition<Unit>::TokenStreamPosition(
     AutoKeepAtoms& keepAtoms,
-    TokenStreamSpecific<Unit, AnyCharsAccess>& tokenStream)
-    : currentToken(tokenStream.anyCharsAccess().currentToken()) {
+    TokenStreamSpecific<Unit, AnyCharsAccess>& tokenStream) {
   TokenStreamAnyChars& anyChars = tokenStream.anyCharsAccess();
 
   buf =
       tokenStream.sourceUnits.addressOfNextCodeUnit(/* allowPoisoned = */ true);
   flags = anyChars.flags;
   lineno = anyChars.lineno;
   linebase = anyChars.linebase;
   prevLinebase = anyChars.prevLinebase;
--- a/js/src/irregexp/RegExpParser.cpp
+++ b/js/src/irregexp/RegExpParser.cpp
@@ -33,31 +33,27 @@
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Casting.h"
 #include "mozilla/Move.h"
 #include "mozilla/Range.h"
 
 #include "frontend/TokenStream.h"
 #include "gc/GC.h"
 #include "irregexp/RegExpCharacters.h"
-#include "js/RegExpFlags.h"  // JS::RegExpFlag, JS::RegExpFlags
 #include "util/StringBuffer.h"
 #include "util/Text.h"
 #include "util/Unicode.h"
 #include "vm/ErrorReporting.h"
 
 using namespace js;
 using namespace js::irregexp;
 
 using mozilla::AssertedCast;
 using mozilla::PointerRangeSize;
 
-using JS::RegExpFlag;
-using JS::RegExpFlags;
-
 // ----------------------------------------------------------------------------
 // RegExpBuilder
 
 RegExpBuilder::RegExpBuilder(LifoAlloc* alloc)
   : alloc(alloc),
     pending_empty_(false),
     characters_(nullptr)
 #ifdef DEBUG
@@ -239,31 +235,31 @@ RegExpBuilder::AddQuantifierToAtom(int m
     last_added_ = ADD_TERM;
 #endif
 }
 
 // ----------------------------------------------------------------------------
 // RegExpParser
 
 template <typename CharT>
-RegExpParser<CharT>::RegExpParser(frontend::TokenStreamAnyChars& ts,
-                                  LifoAlloc* alloc, RegExpFlags flags,
-                                  const CharT* chars, const CharT* end)
+RegExpParser<CharT>::RegExpParser(frontend::TokenStreamAnyChars& ts, LifoAlloc* alloc,
+                                  const CharT* chars, const CharT* end, bool multiline_mode,
+                                  bool unicode, bool ignore_case)
   : ts(ts),
     alloc(alloc),
     captures_(nullptr),
     start_(chars),
     next_pos_(start_),
     end_(end),
     current_(kEndMarker),
     capture_count_(0),
     has_more_(true),
-    multiline_(flags.multiline()),
-    unicode_(flags.unicode()),
-    ignore_case_(flags.ignoreCase()),
+    multiline_(multiline_mode),
+    unicode_(unicode),
+    ignore_case_(ignore_case),
     simple_(false),
     contains_anchor_(false),
     is_scanned_for_captures_(false)
 {
     Advance();
 }
 
 static size_t ComputeColumn(const Latin1Char* begin, const Latin1Char* end) {
@@ -1930,22 +1926,23 @@ RegExpParser<CharT>::ParseDisjunction()
 }
 
 template class irregexp::RegExpParser<Latin1Char>;
 template class irregexp::RegExpParser<char16_t>;
 
 template <typename CharT>
 static bool
 ParsePattern(frontend::TokenStreamAnyChars& ts, LifoAlloc& alloc,
-             const CharT* chars, size_t length, bool match_only,
-             RegExpFlags flags, RegExpCompileData* data)
+             const CharT* chars, size_t length,
+             bool multiline, bool match_only, bool unicode, bool ignore_case,
+             bool global, bool sticky, RegExpCompileData* data)
 {
     // We shouldn't strip pattern for exec, or test with global/sticky,
     // to reflect correct match position and lastIndex.
-    if (match_only && !flags.global() && !flags.sticky()) {
+    if (match_only && !global && !sticky) {
         // Try to strip a leading '.*' from the RegExp, but only if it is not
         // followed by a '?' (which will affect how the .* is parsed). This
         // pattern will affect the captures produced by the RegExp, but not
         // whether there is a match or not.
         if (length >= 3 && chars[0] == '.' && chars[1] == '*' && chars[2] != '?') {
             chars += 2;
             length -= 2;
         }
@@ -1956,47 +1953,46 @@ ParsePattern(frontend::TokenStreamAnyCha
         // are sure this will not affect how the RegExp is parsed.
         if (length >= 3 && !HasRegExpMetaChars(chars, length - 2) &&
             chars[length - 2] == '.' && chars[length - 1] == '*')
         {
             length -= 2;
         }
     }
 
-    RegExpParser<CharT> parser(ts, &alloc, flags, chars, chars + length);
+    RegExpParser<CharT> parser(ts, &alloc, chars, chars + length, multiline, unicode, ignore_case);
     data->tree = parser.ParsePattern();
     if (!data->tree)
         return false;
 
     data->simple = parser.simple();
     data->contains_anchor = parser.contains_anchor();
     data->capture_count = parser.captures_started();
     return true;
 }
 
 bool
-irregexp::ParsePattern(frontend::TokenStreamAnyChars& ts, LifoAlloc& alloc,
-                       JSAtom* str, bool match_only, RegExpFlags flags,
-                       RegExpCompileData* data)
+irregexp::ParsePattern(frontend::TokenStreamAnyChars& ts, LifoAlloc& alloc, JSAtom* str,
+                       bool multiline, bool match_only, bool unicode, bool ignore_case,
+                       bool global, bool sticky, RegExpCompileData* data)
 {
     JS::AutoCheckCannotGC nogc;
     return str->hasLatin1Chars()
            ? ::ParsePattern(ts, alloc, str->latin1Chars(nogc), str->length(),
-                            match_only, flags, data)
+                            multiline, match_only, unicode, ignore_case, global, sticky, data)
            : ::ParsePattern(ts, alloc, str->twoByteChars(nogc), str->length(),
-                            match_only, flags, data);
+                            multiline, match_only, unicode, ignore_case, global, sticky, data);
 }
 
 template <typename CharT>
 static bool
 ParsePatternSyntax(frontend::TokenStreamAnyChars& ts, LifoAlloc& alloc,
                    const CharT* chars, size_t length, bool unicode)
 {
-    RegExpParser<CharT> parser(ts, &alloc, unicode ? RegExpFlag::Unicode : 0,
-                               chars, chars + length);
+    RegExpParser<CharT> parser(ts, &alloc, chars, chars + length, false, unicode, false);
     return parser.ParsePattern() != nullptr;
 }
 
 bool
 irregexp::ParsePatternSyntax(frontend::TokenStreamAnyChars& ts, LifoAlloc& alloc, JSAtom* str,
                              bool unicode)
 {
     JS::AutoCheckCannotGC nogc;
--- a/js/src/irregexp/RegExpParser.h
+++ b/js/src/irregexp/RegExpParser.h
@@ -31,29 +31,29 @@
 #ifndef V8_PARSER_H_
 #define V8_PARSER_H_
 
 #include "mozilla/Range.h"
 
 #include <stdarg.h>
 
 #include "irregexp/RegExpAST.h"
-#include "js/RegExpFlags.h"
 
 namespace js {
 
 namespace frontend {
     class TokenStreamAnyChars;
 }
 
 namespace irregexp {
 
 extern bool
 ParsePattern(frontend::TokenStreamAnyChars& ts, LifoAlloc& alloc, JSAtom* str,
-             bool match_only, JS::RegExpFlags flags, RegExpCompileData* data);
+             bool multiline, bool match_only, bool unicode, bool ignore_case,
+             bool global, bool sticky, RegExpCompileData* data);
 
 extern bool
 ParsePatternSyntax(frontend::TokenStreamAnyChars& ts, LifoAlloc& alloc, JSAtom* str,
                    bool unicode);
 
 extern bool
 ParsePatternSyntax(frontend::TokenStreamAnyChars& ts, LifoAlloc& alloc,
                    const mozilla::Range<const char16_t> chars, bool unicode);
@@ -180,17 +180,18 @@ class RegExpBuilder
 // Characters parsed by RegExpParser can be either char16_t or kEndMarker.
 typedef uint32_t widechar;
 
 template <typename CharT>
 class RegExpParser
 {
   public:
     RegExpParser(frontend::TokenStreamAnyChars& ts, LifoAlloc* alloc,
-                 JS::RegExpFlags flags, const CharT* chars, const CharT* end);
+                 const CharT* chars, const CharT* end, bool multiline_mode, bool unicode,
+                 bool ignore_case);
 
     RegExpTree* ParsePattern();
     RegExpTree* ParseDisjunction();
     RegExpTree* ParseCharacterClass();
 
     // Parses a {...,...} quantifier and stores the range in the given
     // out parameters.
     bool ParseIntervalQuantifier(int* min_out, int* max_out);
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -39,17 +39,16 @@
 #include "jit/Linker.h"
 #include "jit/Lowering.h"
 #include "jit/MIRGenerator.h"
 #include "jit/MoveEmitter.h"
 #include "jit/RangeAnalysis.h"
 #include "jit/SharedICHelpers.h"
 #include "jit/StackSlotAllocator.h"
 #include "jit/VMFunctions.h"
-#include "js/RegExpFlags.h"  // JS::RegExpFlag
 #include "util/Unicode.h"
 #include "vm/AsyncFunction.h"
 #include "vm/AsyncIteration.h"
 #include "vm/EqualityOperations.h"  // js::SameValue
 #include "vm/MatchPairs.h"
 #include "vm/RegExpObject.h"
 #include "vm/RegExpStatics.h"
 #include "vm/StringType.h"
@@ -1939,17 +1938,17 @@ static bool PrepareAndExecuteRegExp(
 
   // ES6 21.2.2.2 step 2.
   // See RegExp.cpp ExecuteRegExp for more detail.
   {
     Label done;
 
     masm.branchTest32(Assembler::Zero,
                       Address(temp1, RegExpShared::offsetOfFlags()),
-                      Imm32(int32_t(JS::RegExpFlag::Unicode)), &done);
+                      Imm32(UnicodeFlag), &done);
 
     // If input is latin1, there should not be surrogate pair.
     masm.branchLatin1String(input, &done);
 
     // Check if |lastIndex > 0 && lastIndex < input->length()|.
     // lastIndex should already have no sign here.
     masm.branchTest32(Assembler::Zero, lastIndex, lastIndex, &done);
     masm.loadStringLength(input, temp2);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -19,17 +19,16 @@
 #include "builtin/TestingFunctions.h"
 #include "builtin/TypedObject.h"
 #include "jit/BaselineInspector.h"
 #include "jit/InlinableNatives.h"
 #include "jit/IonBuilder.h"
 #include "jit/Lowering.h"
 #include "jit/MIR.h"
 #include "jit/MIRGraph.h"
-#include "js/RegExpFlags.h"  // JS::RegExpFlag, JS::RegExpFlags
 #include "vm/ArgumentsObject.h"
 #include "vm/ArrayBufferObject.h"
 #include "vm/JSObject.h"
 #include "vm/ProxyObject.h"
 #include "vm/SelfHosting.h"
 #include "vm/SharedArrayObject.h"
 #include "vm/TypedArrayObject.h"
 #include "wasm/WasmInstance.h"
@@ -39,18 +38,16 @@
 #include "vm/NativeObject-inl.h"
 #include "vm/StringObject-inl.h"
 
 using mozilla::ArrayLength;
 using mozilla::AssertedCast;
 using mozilla::Maybe;
 
 using JS::DoubleNaNValue;
-using JS::RegExpFlag;
-using JS::RegExpFlags;
 using JS::TrackedOutcome;
 
 namespace js {
 namespace jit {
 
 // Returns true if |native| can be inlined cross-realm. Especially inlined
 // natives that can allocate objects or throw exceptions shouldn't be inlined
 // cross-realm without a careful analysis because we might use the wrong realm!
@@ -622,28 +619,28 @@ IonBuilder::InliningResult IonBuilder::i
     }
 
     MInstruction* byteOffset = addTypedArrayByteOffset(thisArg);
     current->push(byteOffset);
     return InliningStatus_Inlined;
   }
 
   // Try to optimize RegExp getters.
-  RegExpFlags mask = RegExpFlag::NoFlags;
+  RegExpFlag mask = NoFlags;
   if (RegExpObject::isOriginalFlagGetter(native, &mask)) {
     const Class* clasp = thisTypes->getKnownClass(constraints());
     if (clasp != &RegExpObject::class_) {
       return InliningStatus_NotInlined;
     }
 
     MLoadFixedSlot* flags =
         MLoadFixedSlot::New(alloc(), thisArg, RegExpObject::flagsSlot());
     current->add(flags);
     flags->setResultType(MIRType::Int32);
-    MConstant* maskConst = MConstant::New(alloc(), Int32Value(mask.value()));
+    MConstant* maskConst = MConstant::New(alloc(), Int32Value(mask));
     current->add(maskConst);
     MBitAnd* maskedFlag = MBitAnd::New(alloc(), flags, maskConst);
     maskedFlag->setInt32Specialization();
     current->add(maskedFlag);
 
     MDefinition* result = convertToBoolean(maskedFlag);
     current->push(result);
     return InliningStatus_Inlined;
--- a/js/src/jsapi-tests/testRegExp.cpp
+++ b/js/src/jsapi-tests/testRegExp.cpp
@@ -1,14 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "js/RegExp.h"
-#include "js/RegExpFlags.h"
 #include "jsapi-tests/tests.h"
 
 BEGIN_TEST(testObjectIsRegExp) {
   JS::RootedValue val(cx);
 
   bool isRegExp;
 
   EVAL("new Object", &val);
@@ -26,29 +25,26 @@ BEGIN_TEST(testObjectIsRegExp) {
 END_TEST(testObjectIsRegExp)
 
 BEGIN_TEST(testGetRegExpFlags) {
   JS::RootedValue val(cx);
   JS::RootedObject obj(cx);
 
   EVAL("/foopy/", &val);
   obj = val.toObjectOrNull();
-  CHECK_EQUAL(JS::GetRegExpFlags(cx, obj),
-              JS::RegExpFlags(JS::RegExpFlag::NoFlags));
+  CHECK_EQUAL(JS::GetRegExpFlags(cx, obj), 0u);
 
   EVAL("/foopy/g", &val);
   obj = val.toObjectOrNull();
-  CHECK_EQUAL(JS::GetRegExpFlags(cx, obj),
-              JS::RegExpFlags(JS::RegExpFlag::Global));
+  CHECK(JS::GetRegExpFlags(cx, obj) == JS::RegExpFlags::Global);
 
   EVAL("/foopy/gi", &val);
   obj = val.toObjectOrNull();
-  CHECK_EQUAL(
-      JS::GetRegExpFlags(cx, obj),
-      JS::RegExpFlags(JS::RegExpFlag::Global | JS::RegExpFlag::IgnoreCase));
+  CHECK(JS::GetRegExpFlags(cx, obj) ==
+        (JS::RegExpFlags::Global | JS::RegExpFlags::IgnoreCase));
 
   return true;
 }
 END_TEST(testGetRegExpFlags)
 
 BEGIN_TEST(testGetRegExpSource) {
   JS::RootedValue val(cx);
   JS::RootedObject obj(cx);
--- a/js/src/jsapi-tests/tests.h
+++ b/js/src/jsapi-tests/tests.h
@@ -15,17 +15,16 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include "gc/GC.h"
 #include "js/AllocPolicy.h"
 #include "js/CharacterEncoding.h"
 #include "js/Equality.h"  // JS::SameValue
-#include "js/RegExpFlags.h"  // JS::RegExpFlags
 #include "js/Vector.h"
 #include "vm/JSContext.h"
 
 /* Note: Aborts on OOM. */
 class JSAPITestString {
   js::Vector<char, 0, js::SystemAllocPolicy> chars;
 
  public:
@@ -155,36 +154,16 @@ class JSAPITest {
   }
 
   JSAPITestString toSource(int v) { return toSource((long)v); }
 
   JSAPITestString toSource(bool v) {
     return JSAPITestString(v ? "true" : "false");
   }
 
-  JSAPITestString toSource(JS::RegExpFlags flags) {
-    JSAPITestString str;
-    if (flags.global()) {
-      str += "g";
-    }
-    if (flags.ignoreCase()) {
-      str += "i";
-    }
-    if (flags.multiline()) {
-      str += "m";
-    }
-    if (flags.unicode()) {
-      str += "u";
-    }
-    if (flags.sticky()) {
-      str += "y";
-    }
-    return str;
-  }
-
   JSAPITestString toSource(JSAtom* v) {
     JS::RootedValue val(cx, JS::StringValue((JSString*)v));
     return jsvalToSource(val);
   }
 
   // Note that in some still-supported GCC versions (we think anything before
   // GCC 4.6), this template does not work when the second argument is
   // nullptr. It infers type U = long int. Use CHECK_NULL instead.
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -156,17 +156,16 @@ EXPORTS.js += [
     '../public/PropertyDescriptor.h',
     '../public/PropertySpec.h',
     '../public/ProtoKey.h',
     '../public/Proxy.h',
     '../public/Realm.h',
     '../public/RealmOptions.h',
     '../public/RefCounted.h',
     '../public/RegExp.h',
-    '../public/RegExpFlags.h',
     '../public/RequiredDefines.h',
     '../public/Result.h',
     '../public/RootingAPI.h',
     '../public/SavedFrameAPI.h',
     '../public/SharedArrayBuffer.h',
     '../public/SliceBudget.h',
     '../public/SourceText.h',
     '../public/StableStringChars.h',
--- a/js/src/vm/RegExpConstants.h
+++ b/js/src/vm/RegExpConstants.h
@@ -6,16 +6,34 @@
 
 #ifndef vm_RegExpConstants_h
 #define vm_RegExpConstants_h
 
 #include "builtin/SelfHostingDefines.h"
 
 namespace js {
 
+enum RegExpFlag : uint8_t {
+  IgnoreCaseFlag = 0x01,
+  GlobalFlag = 0x02,
+  MultilineFlag = 0x04,
+  StickyFlag = 0x08,
+  UnicodeFlag = 0x10,
+
+  NoFlags = 0x00,
+  AllFlags = 0x1f
+};
+
+static_assert(IgnoreCaseFlag == REGEXP_IGNORECASE_FLAG &&
+                  GlobalFlag == REGEXP_GLOBAL_FLAG &&
+                  MultilineFlag == REGEXP_MULTILINE_FLAG &&
+                  StickyFlag == REGEXP_STICKY_FLAG &&
+                  UnicodeFlag == REGEXP_UNICODE_FLAG,
+              "Flag values should be in sync with self-hosted JS");
+
 enum RegExpRunStatus {
   RegExpRunStatus_Error,
   RegExpRunStatus_Success,
   RegExpRunStatus_Success_NotFound
 };
 
 } /* namespace js */
 
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -10,26 +10,24 @@
 #include "mozilla/PodOperations.h"
 
 #include "builtin/String.h"
 #ifdef DEBUG
 #  include "jsutil.h"
 #endif
 
 #include "builtin/RegExp.h"
-#include "builtin/SelfHostingDefines.h"  // REGEXP_*_FLAG
 #include "frontend/TokenStream.h"
 #include "gc/HashUtil.h"
 #ifdef DEBUG
 #  include "irregexp/RegExpBytecode.h"
 #endif
 #include "irregexp/RegExpParser.h"
 #include "jit/VMFunctions.h"
 #include "js/RegExp.h"
-#include "js/RegExpFlags.h"  // JS::RegExpFlags
 #include "js/StableStringChars.h"
 #include "util/StringBuffer.h"
 #include "vm/MatchPairs.h"
 #include "vm/RegExpStatics.h"
 #include "vm/StringType.h"
 #include "vm/TraceLogging.h"
 #ifdef DEBUG
 #  include "util/Unicode.h"
@@ -39,35 +37,33 @@
 #include "vm/JSObject-inl.h"
 #include "vm/NativeObject-inl.h"
 #include "vm/Shape-inl.h"
 
 using namespace js;
 
 using JS::AutoStableStringChars;
 using JS::CompileOptions;
-using JS::RegExpFlag;
-using JS::RegExpFlags;
 using js::frontend::TokenStream;
 using mozilla::ArrayLength;
 using mozilla::DebugOnly;
 using mozilla::PodCopy;
 
 using JS::AutoCheckCannotGC;
 
-static_assert(RegExpFlag::Global == REGEXP_GLOBAL_FLAG,
-              "self-hosted JS and /g flag bits must agree");
-static_assert(RegExpFlag::IgnoreCase == REGEXP_IGNORECASE_FLAG,
-              "self-hosted JS and /i flag bits must agree");
-static_assert(RegExpFlag::Multiline == REGEXP_MULTILINE_FLAG,
-              "self-hosted JS and /m flag bits must agree");
-static_assert(RegExpFlag::Unicode == REGEXP_UNICODE_FLAG,
-              "self-hosted JS and /u flag bits must agree");
-static_assert(RegExpFlag::Sticky == REGEXP_STICKY_FLAG,
-              "self-hosted JS and /y flag bits must agree");
+static_assert(IgnoreCaseFlag == JS::RegExpFlags::IgnoreCase,
+              "public/internal /i flag bits must agree");
+static_assert(GlobalFlag == JS::RegExpFlags::Global,
+              "public/internal /g flag bits must agree");
+static_assert(MultilineFlag == JS::RegExpFlags::Multiline,
+              "public/internal /m flag bits must agree");
+static_assert(StickyFlag == JS::RegExpFlags::Sticky,
+              "public/internal /y flag bits must agree");
+static_assert(UnicodeFlag == JS::RegExpFlags::Unicode,
+              "public/internal /u flag bits must agree");
 
 RegExpObject* js::RegExpAlloc(JSContext* cx, NewObjectKind newKind,
                               HandleObject proto /* = nullptr */) {
   Rooted<RegExpObject*> regexp(
       cx, NewObjectWithClassProto<RegExpObject>(cx, proto, newKind));
   if (!regexp) {
     return nullptr;
   }
@@ -116,35 +112,35 @@ RegExpShared* RegExpObject::getShared(JS
   if (regexp->hasShared()) {
     return regexp->sharedRef();
   }
 
   return createShared(cx, regexp);
 }
 
 /* static */
-bool RegExpObject::isOriginalFlagGetter(JSNative native, RegExpFlags* mask) {
+bool RegExpObject::isOriginalFlagGetter(JSNative native, RegExpFlag* mask) {
   if (native == regexp_global) {
-    *mask = RegExpFlag::Global;
+    *mask = GlobalFlag;
     return true;
   }
   if (native == regexp_ignoreCase) {
-    *mask = RegExpFlag::IgnoreCase;
+    *mask = IgnoreCaseFlag;
     return true;
   }
   if (native == regexp_multiline) {
-    *mask = RegExpFlag::Multiline;
+    *mask = MultilineFlag;
     return true;
   }
   if (native == regexp_sticky) {
-    *mask = RegExpFlag::Sticky;
+    *mask = StickyFlag;
     return true;
   }
   if (native == regexp_unicode) {
-    *mask = RegExpFlag::Unicode;
+    *mask = UnicodeFlag;
     return true;
   }
 
   return false;
 }
 
 /* static */
 void RegExpObject::trace(JSTracer* trc, JSObject* obj) {
@@ -197,83 +193,83 @@ const Class RegExpObject::class_ = {
     &RegExpObjectClassOps, &RegExpObjectClassSpec};
 
 const Class RegExpObject::protoClass_ = {
     js_Object_str, JSCLASS_HAS_CACHED_PROTO(JSProto_RegExp), JS_NULL_CLASS_OPS,
     &RegExpObjectClassSpec};
 
 template <typename CharT>
 RegExpObject* RegExpObject::create(JSContext* cx, const CharT* chars,
-                                   size_t length, RegExpFlags flags,
+                                   size_t length, RegExpFlag flags,
                                    frontend::TokenStreamAnyChars& tokenStream,
                                    NewObjectKind newKind) {
   static_assert(mozilla::IsSame<CharT, char16_t>::value,
                 "this code may need updating if/when CharT encodes UTF-8");
 
   RootedAtom source(cx, AtomizeChars(cx, chars, length));
   if (!source) {
     return nullptr;
   }
 
   return create(cx, source, flags, tokenStream, newKind);
 }
 
 template RegExpObject* RegExpObject::create(
-    JSContext* cx, const char16_t* chars, size_t length, RegExpFlags flags,
+    JSContext* cx, const char16_t* chars, size_t length, RegExpFlag flags,
     frontend::TokenStreamAnyChars& tokenStream, NewObjectKind newKind);
 
 template <typename CharT>
 RegExpObject* RegExpObject::create(JSContext* cx, const CharT* chars,
-                                   size_t length, RegExpFlags flags,
+                                   size_t length, RegExpFlag flags,
                                    NewObjectKind newKind) {
   static_assert(mozilla::IsSame<CharT, char16_t>::value,
                 "this code may need updating if/when CharT encodes UTF-8");
 
   RootedAtom source(cx, AtomizeChars(cx, chars, length));
   if (!source) {
     return nullptr;
   }
 
   return create(cx, source, flags, newKind);
 }
 
 template RegExpObject* RegExpObject::create(JSContext* cx,
                                             const char16_t* chars,
-                                            size_t length, RegExpFlags flags,
+                                            size_t length, RegExpFlag flags,
                                             NewObjectKind newKind);
 
 RegExpObject* RegExpObject::create(JSContext* cx, HandleAtom source,
-                                   RegExpFlags flags,
+                                   RegExpFlag flags,
                                    frontend::TokenStreamAnyChars& tokenStream,
                                    NewObjectKind newKind) {
   LifoAllocScope allocScope(&cx->tempLifoAlloc());
   if (!irregexp::ParsePatternSyntax(tokenStream, allocScope.alloc(), source,
-                                    flags.unicode())) {
+                                    flags & UnicodeFlag)) {
     return nullptr;
   }
 
   Rooted<RegExpObject*> regexp(cx, RegExpAlloc(cx, newKind));
   if (!regexp) {
     return nullptr;
   }
 
   regexp->initAndZeroLastIndex(source, flags, cx);
 
   return regexp;
 }
 
 RegExpObject* RegExpObject::create(JSContext* cx, HandleAtom source,
-                                   RegExpFlags flags, NewObjectKind newKind) {
+                                   RegExpFlag flags, NewObjectKind newKind) {
   CompileOptions dummyOptions(cx);
   TokenStream dummyTokenStream(cx, dummyOptions, (const char16_t*)nullptr, 0,
                                nullptr);
 
   LifoAllocScope allocScope(&cx->tempLifoAlloc());
   if (!irregexp::ParsePatternSyntax(dummyTokenStream, allocScope.alloc(),
-                                    source, flags.unicode())) {
+                                    source, flags & UnicodeFlag)) {
     return nullptr;
   }
 
   Rooted<RegExpObject*> regexp(cx, RegExpAlloc(cx, newKind));
   if (!regexp) {
     return nullptr;
   }
 
@@ -303,26 +299,26 @@ Shape* RegExpObject::assignInitialShape(
 
   JS_STATIC_ASSERT(LAST_INDEX_SLOT == 0);
 
   /* The lastIndex property alone is writable but non-configurable. */
   return NativeObject::addDataProperty(cx, self, cx->names().lastIndex,
                                        LAST_INDEX_SLOT, JSPROP_PERMANENT);
 }
 
-void RegExpObject::initIgnoringLastIndex(JSAtom* source, RegExpFlags flags) {
+void RegExpObject::initIgnoringLastIndex(JSAtom* source, RegExpFlag flags) {
   // If this is a re-initialization with an existing RegExpShared, 'flags'
   // may not match getShared()->flags, so forget the RegExpShared.
   sharedRef() = nullptr;
 
   setSource(source);
   setFlags(flags);
 }
 
-void RegExpObject::initAndZeroLastIndex(JSAtom* source, RegExpFlags flags,
+void RegExpObject::initAndZeroLastIndex(JSAtom* source, RegExpFlag flags,
                                         JSContext* cx) {
   initIgnoringLastIndex(source, flags);
   zeroLastIndex(cx);
 }
 
 static MOZ_ALWAYS_INLINE bool IsRegExpLineTerminator(const JS::Latin1Char c) {
   return c == '\n' || c == '\r';
 }
@@ -897,17 +893,17 @@ bool js::StringHasRegExpMetaChars(JSLine
     return HasRegExpMetaChars(str->latin1Chars(nogc), str->length());
   }
 
   return HasRegExpMetaChars(str->twoByteChars(nogc), str->length());
 }
 
 /* RegExpShared */
 
-RegExpShared::RegExpShared(JSAtom* source, RegExpFlags flags)
+RegExpShared::RegExpShared(JSAtom* source, RegExpFlag flags)
     : source(source), flags(flags), canStringMatch(false), parenCount(0) {}
 
 void RegExpShared::traceChildren(JSTracer* trc) {
   // Discard code to avoid holding onto ExecutablePools.
   if (IsMarkingTrace(trc) && trc->runtime()->gc.isShrinkingGC()) {
     discardJitCode();
   }
 
@@ -955,17 +951,19 @@ bool RegExpShared::compile(JSContext* cx
   CompileOptions options(cx);
   frontend::TokenStream dummyTokenStream(cx, options, nullptr, 0, nullptr);
 
   /* Parse the pattern. The RegExpCompileData is allocated in LifoAlloc and
    * will only be live while LifoAllocScope is on stack. */
   LifoAllocScope allocScope(&cx->tempLifoAlloc());
   irregexp::RegExpCompileData data;
   if (!irregexp::ParsePattern(dummyTokenStream, allocScope.alloc(), pattern,
-                              mode == MatchOnly, re->getFlags(), &data)) {
+                              re->multiline(), mode == MatchOnly, re->unicode(),
+                              re->ignoreCase(), re->global(), re->sticky(),
+                              &data)) {
     return false;
   }
 
   re->parenCount = data.capture_count;
 
   JitCodeTables tables;
   irregexp::RegExpCode code = irregexp::CompilePattern(
       cx, allocScope.alloc(), re, &data, input, false /* global() */,
@@ -1247,17 +1245,17 @@ void RegExpRealm::sweep() {
 
   if (optimizableRegExpInstanceShape_ &&
       IsAboutToBeFinalized(&optimizableRegExpInstanceShape_)) {
     optimizableRegExpInstanceShape_.set(nullptr);
   }
 }
 
 RegExpShared* RegExpZone::get(JSContext* cx, HandleAtom source,
-                              RegExpFlags flags) {
+                              RegExpFlag flags) {
   DependentAddPtr<Set> p(cx, set_, Key(source, flags));
   if (p) {
     return *p;
   }
 
   auto shared = Allocate<RegExpShared>(cx);
   if (!shared) {
     return nullptr;
@@ -1269,17 +1267,17 @@ RegExpShared* RegExpZone::get(JSContext*
     ReportOutOfMemory(cx);
     return nullptr;
   }
 
   return shared;
 }
 
 RegExpShared* RegExpZone::get(JSContext* cx, HandleAtom atom, JSString* opt) {
-  RegExpFlags flags = RegExpFlag::NoFlags;
+  RegExpFlag flags = RegExpFlag(0);
   if (opt && !ParseRegExpFlags(cx, opt, &flags)) {
     return nullptr;
   }
 
   return get(cx, atom, flags);
 }
 
 size_t RegExpZone::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) {
@@ -1312,53 +1310,53 @@ JSObject* js::CloneRegExpObject(JSContex
   clone->initAndZeroLastIndex(shared->getSource(), shared->getFlags(), cx);
   clone->setShared(*shared);
 
   return clone;
 }
 
 template <typename CharT>
 static bool ParseRegExpFlags(const CharT* chars, size_t length,
-                             RegExpFlags* flagsOut, char16_t* invalidFlag) {
-  *flagsOut = RegExpFlag::NoFlags;
+                             RegExpFlag* flagsOut, char16_t* invalidFlag) {
+  *flagsOut = RegExpFlag(0);
 
   for (size_t i = 0; i < length; i++) {
-    uint8_t flag;
+    RegExpFlag flag;
     switch (chars[i]) {
+      case 'i':
+        flag = IgnoreCaseFlag;
+        break;
       case 'g':
-        flag = RegExpFlag::Global;
-        break;
-      case 'i':
-        flag = RegExpFlag::IgnoreCase;
+        flag = GlobalFlag;
         break;
       case 'm':
-        flag = RegExpFlag::Multiline;
+        flag = MultilineFlag;
+        break;
+      case 'y':
+        flag = StickyFlag;
         break;
       case 'u':
-        flag = RegExpFlag::Unicode;
-        break;
-      case 'y':
-        flag = RegExpFlag::Sticky;
+        flag = UnicodeFlag;
         break;
       default:
         *invalidFlag = chars[i];
         return false;
     }
     if (*flagsOut & flag) {
       *invalidFlag = chars[i];
       return false;
     }
-    *flagsOut |= flag;
+    *flagsOut = RegExpFlag(*flagsOut | flag);
   }
 
   return true;
 }
 
 bool js::ParseRegExpFlags(JSContext* cx, JSString* flagStr,
-                          RegExpFlags* flagsOut) {
+                          RegExpFlag* flagsOut) {
   JSLinearString* linear = flagStr->ensureLinear(cx);
   if (!linear) {
     return false;
   }
 
   size_t len = linear->length();
 
   bool ok;
@@ -1388,29 +1386,29 @@ bool js::ParseRegExpFlags(JSContext* cx,
 }
 
 template <XDRMode mode>
 XDRResult js::XDRScriptRegExpObject(XDRState<mode>* xdr,
                                     MutableHandle<RegExpObject*> objp) {
   /* NB: Keep this in sync with CloneScriptRegExpObject. */
 
   RootedAtom source(xdr->cx());
-  uint8_t flags = 0;
+  uint32_t flagsword = 0;
 
   if (mode == XDR_ENCODE) {
     MOZ_ASSERT(objp);
     RegExpObject& reobj = *objp;
     source = reobj.getSource();
-    flags = reobj.getFlags().value();
+    flagsword = reobj.getFlags();
   }
   MOZ_TRY(XDRAtom(xdr, &source));
-  MOZ_TRY(xdr->codeUint8(&flags));
+  MOZ_TRY(xdr->codeUint32(&flagsword));
   if (mode == XDR_DECODE) {
     RegExpObject* reobj = RegExpObject::create(
-        xdr->cx(), source, RegExpFlags(flags), TenuredObject);
+        xdr->cx(), source, RegExpFlag(flagsword), TenuredObject);
     if (!reobj) {
       return xdr->fail(JS::TranscodeResult_Throw);
     }
 
     objp.set(reobj);
   }
   return Ok();
 }
@@ -1440,36 +1438,37 @@ JS::ubi::Node::Size JS::ubi::Concrete<Re
   return js::gc::Arena::thingSize(gc::AllocKind::REGEXP_SHARED) +
          get().sizeOfExcludingThis(mallocSizeOf);
 }
 
 /*
  * Regular Expressions.
  */
 JS_PUBLIC_API JSObject* JS::NewRegExpObject(JSContext* cx, const char* bytes,
-                                            size_t length, RegExpFlags flags) {
+                                            size_t length, unsigned flags) {
   AssertHeapIsIdle();
   CHECK_THREAD(cx);
 
   UniqueTwoByteChars chars(InflateString(cx, bytes, length));
   if (!chars) {
     return nullptr;
   }
 
-  return RegExpObject::create(cx, chars.get(), length, flags, GenericObject);
+  return RegExpObject::create(cx, chars.get(), length, RegExpFlag(flags),
+                              GenericObject);
 }
 
 JS_PUBLIC_API JSObject* JS::NewUCRegExpObject(JSContext* cx,
                                               const char16_t* chars,
-                                              size_t length,
-                                              RegExpFlags flags) {
+                                              size_t length, unsigned flags) {
   AssertHeapIsIdle();
   CHECK_THREAD(cx);
 
-  return RegExpObject::create(cx, chars, length, flags, GenericObject);
+  return RegExpObject::create(cx, chars, length, RegExpFlag(flags),
+                              GenericObject);
 }
 
 JS_PUBLIC_API bool JS::SetRegExpInput(JSContext* cx, HandleObject obj,
                                       HandleString input) {
   AssertHeapIsIdle();
   CHECK_THREAD(cx);
   cx->check(input);
 
@@ -1544,23 +1543,23 @@ JS_PUBLIC_API bool JS::ObjectIsRegExp(JS
   if (!GetBuiltinClass(cx, obj, &cls)) {
     return false;
   }
 
   *isRegExp = cls == ESClass::RegExp;
   return true;
 }
 
-JS_PUBLIC_API RegExpFlags JS::GetRegExpFlags(JSContext* cx, HandleObject obj) {
+JS_PUBLIC_API unsigned JS::GetRegExpFlags(JSContext* cx, HandleObject obj) {
   AssertHeapIsIdle();
   CHECK_THREAD(cx);
 
   RegExpShared* shared = RegExpToShared(cx, obj);
   if (!shared) {
-    return RegExpFlag::NoFlags;
+    return false;
   }
   return shared->getFlags();
 }
 
 JS_PUBLIC_API JSString* JS::GetRegExpSource(JSContext* cx, HandleObject obj) {
   AssertHeapIsIdle();
   CHECK_THREAD(cx);
 
--- a/js/src/vm/RegExpObject.h
+++ b/js/src/vm/RegExpObject.h
@@ -10,17 +10,16 @@
 #define vm_RegExpObject_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/MemoryReporting.h"
 
 #include "builtin/SelfHostingDefines.h"
 #include "gc/Marking.h"
 #include "js/GCHashTable.h"
-#include "js/RegExpFlags.h"
 #include "proxy/Proxy.h"
 #include "vm/ArrayObject.h"
 #include "vm/JSContext.h"
 #include "vm/RegExpShared.h"
 #include "vm/Shape.h"
 
 /*
  * JavaScript Regular Expressions
@@ -66,29 +65,29 @@ class RegExpObject : public NativeObject
   static const Class protoClass_;
 
   // The maximum number of pairs a MatchResult can have, without having to
   // allocate a bigger MatchResult.
   static const size_t MaxPairCount = 14;
 
   template <typename CharT>
   static RegExpObject* create(JSContext* cx, const CharT* chars, size_t length,
-                              JS::RegExpFlags flags, NewObjectKind newKind);
+                              RegExpFlag flags, NewObjectKind newKind);
 
   template <typename CharT>
   static RegExpObject* create(JSContext* cx, const CharT* chars, size_t length,
-                              JS::RegExpFlags flags,
+                              RegExpFlag flags,
                               frontend::TokenStreamAnyChars& ts,
                               NewObjectKind kind);
 
   static RegExpObject* create(JSContext* cx, HandleAtom source,
-                              JS::RegExpFlags flags, NewObjectKind newKind);
+                              RegExpFlag flags, NewObjectKind newKind);
 
   static RegExpObject* create(JSContext* cx, HandleAtom source,
-                              JS::RegExpFlags flags,
+                              RegExpFlag flags,
                               frontend::TokenStreamAnyChars& ts,
                               NewObjectKind newKind);
 
   /*
    * Compute the initial shape to associate with fresh RegExp objects,
    * encoding their initial properties. Return the shape after
    * changing |obj|'s last property to it.
    */
@@ -127,30 +126,28 @@ class RegExpObject : public NativeObject
   }
 
   void setSource(JSAtom* source) { setSlot(SOURCE_SLOT, StringValue(source)); }
 
   /* Flags. */
 
   static unsigned flagsSlot() { return FLAGS_SLOT; }
 
-  JS::RegExpFlags getFlags() const {
-    return JS::RegExpFlags(getFixedSlot(FLAGS_SLOT).toInt32());
+  RegExpFlag getFlags() const {
+    return RegExpFlag(getFixedSlot(FLAGS_SLOT).toInt32());
   }
-  void setFlags(JS::RegExpFlags flags) {
-    setFixedSlot(FLAGS_SLOT, Int32Value(flags.value()));
-  }
+  void setFlags(RegExpFlag flags) { setSlot(FLAGS_SLOT, Int32Value(flags)); }
 
-  bool global() const { return getFlags().global(); }
-  bool ignoreCase() const { return getFlags().ignoreCase(); }
-  bool multiline() const { return getFlags().multiline(); }
-  bool unicode() const { return getFlags().unicode(); }
-  bool sticky() const { return getFlags().sticky(); }
+  bool ignoreCase() const { return getFlags() & IgnoreCaseFlag; }
+  bool global() const { return getFlags() & GlobalFlag; }
+  bool multiline() const { return getFlags() & MultilineFlag; }
+  bool sticky() const { return getFlags() & StickyFlag; }
+  bool unicode() const { return getFlags() & UnicodeFlag; }
 
-  static bool isOriginalFlagGetter(JSNative native, JS::RegExpFlags* mask);
+  static bool isOriginalFlagGetter(JSNative native, RegExpFlag* mask);
 
   static RegExpShared* getShared(JSContext* cx, Handle<RegExpObject*> regexp);
 
   bool hasShared() { return !!sharedRef(); }
 
   void setShared(RegExpShared& shared) {
     MOZ_ASSERT(!hasShared());
     sharedRef().init(&shared);
@@ -159,23 +156,22 @@ class RegExpObject : public NativeObject
   HeapPtrRegExpShared& sharedRef() {
     auto& ref = NativeObject::privateRef(PRIVATE_SLOT);
     return reinterpret_cast<HeapPtrRegExpShared&>(ref);
   }
 
   static void trace(JSTracer* trc, JSObject* obj);
   void trace(JSTracer* trc);
 
-  void initIgnoringLastIndex(JSAtom* source, JS::RegExpFlags flags);
+  void initIgnoringLastIndex(JSAtom* source, RegExpFlag flags);
 
   // NOTE: This method is *only* safe to call on RegExps that haven't been
   //       exposed to script, because it requires that the "lastIndex"
   //       property be writable.
-  void initAndZeroLastIndex(JSAtom* source, JS::RegExpFlags flags,
-                            JSContext* cx);
+  void initAndZeroLastIndex(JSAtom* source, RegExpFlag flags, JSContext* cx);
 
 #ifdef DEBUG
   static MOZ_MUST_USE bool dumpBytecode(JSContext* cx,
                                         Handle<RegExpObject*> regexp,
                                         bool match_only,
                                         HandleLinearString input);
 #endif
 
@@ -192,18 +188,17 @@ class RegExpObject : public NativeObject
 };
 
 /*
  * Parse regexp flags. Report an error and return false if an invalid
  * sequence of flags is encountered (repeat/invalid flag).
  *
  * N.B. flagStr must be rooted.
  */
-bool ParseRegExpFlags(JSContext* cx, JSString* flagStr,
-                      JS::RegExpFlags* flagsOut);
+bool ParseRegExpFlags(JSContext* cx, JSString* flagStr, RegExpFlag* flagsOut);
 
 // Assuming GetBuiltinClass(obj) is ESClass::RegExp, return a RegExpShared for
 // obj.
 inline RegExpShared* RegExpToShared(JSContext* cx, HandleObject obj) {
   if (obj->is<RegExpObject>()) {
     return RegExpObject::getShared(cx, obj.as<RegExpObject>());
   }
 
--- a/js/src/vm/RegExpShared.h
+++ b/js/src/vm/RegExpShared.h
@@ -16,17 +16,16 @@
 #include "mozilla/Assertions.h"
 #include "mozilla/MemoryReporting.h"
 
 #include "gc/Barrier.h"
 #include "gc/Heap.h"
 #include "gc/Marking.h"
 #include "gc/Zone.h"
 #include "js/AllocPolicy.h"
-#include "js/RegExpFlags.h"  // JS::RegExpFlag, JS::RegExpFlags
 #include "js/UbiNode.h"
 #include "js/Vector.h"
 #include "vm/ArrayObject.h"
 #include "vm/JSAtom.h"
 #include "vm/RegExpConstants.h"
 
 namespace js {
 
@@ -79,17 +78,17 @@ class RegExpShared : public gc::TenuredC
     bool compiled(ForceByteCodeEnum force = DontForceByteCode) const {
       return byteCode || (force == DontForceByteCode && jitCode);
     }
   };
 
   /* Source to the RegExp, for lazy compilation. */
   GCPtr<JSAtom*> source;
 
-  JS::RegExpFlags flags;
+  RegExpFlag flags;
   bool canStringMatch;
   size_t parenCount;
 
   RegExpCompilation compilationArray[4];
 
   static int CompilationIndex(CompilationMode mode, bool latin1) {
     switch (mode) {
       case Normal:
@@ -99,17 +98,17 @@ class RegExpShared : public gc::TenuredC
     }
     MOZ_CRASH();
   }
 
   // Tables referenced by JIT code.
   JitCodeTables tables;
 
   /* Internal functions. */
-  RegExpShared(JSAtom* source, JS::RegExpFlags flags);
+  RegExpShared(JSAtom* source, RegExpFlag flags);
 
   static bool compile(JSContext* cx, MutableHandleRegExpShared res,
                       HandleLinearString input, CompilationMode mode,
                       ForceByteCodeEnum force);
   static bool compile(JSContext* cx, MutableHandleRegExpShared res,
                       HandleAtom pattern, HandleLinearString input,
                       CompilationMode mode, ForceByteCodeEnum force);
 
@@ -144,23 +143,22 @@ class RegExpShared : public gc::TenuredC
     MOZ_ASSERT(isCompiled());
     return parenCount;
   }
 
   /* Accounts for the "0" (whole match) pair. */
   size_t pairCount() const { return getParenCount() + 1; }
 
   JSAtom* getSource() const { return source; }
-  JS::RegExpFlags getFlags() const { return flags; }
-
-  bool global() const { return flags.global(); }
-  bool ignoreCase() const { return flags.ignoreCase(); }
-  bool multiline() const { return flags.multiline(); }
-  bool unicode() const { return flags.unicode(); }
-  bool sticky() const { return flags.sticky(); }
+  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 latin1,
                   ForceByteCodeEnum force = DontForceByteCode) const {
     return compilation(mode, latin1).compiled(force);
   }
   bool isCompiled() const {
     return isCompiled(Normal, true) || isCompiled(Normal, false) ||
            isCompiled(MatchOnly, true) || isCompiled(MatchOnly, false);
@@ -194,32 +192,32 @@ class RegExpShared : public gc::TenuredC
 #ifdef DEBUG
   static bool dumpBytecode(JSContext* cx, MutableHandleRegExpShared res,
                            bool match_only, HandleLinearString input);
 #endif
 };
 
 class RegExpZone {
   struct Key {
-    JSAtom* atom = nullptr;
-    JS::RegExpFlags flags = JS::RegExpFlag::NoFlags;
+    JSAtom* atom;
+    uint16_t flag;
 
-    Key() = default;
-    Key(JSAtom* atom, JS::RegExpFlags flags) : atom(atom), flags(flags) {}
+    Key() : atom(nullptr), flag(0) {}
+    Key(JSAtom* atom, RegExpFlag flag) : atom(atom), flag(flag) {}
     MOZ_IMPLICIT Key(const ReadBarriered<RegExpShared*>& shared)
         : atom(shared.unbarrieredGet()->getSource()),
-          flags(shared.unbarrieredGet()->getFlags()) {}
+          flag(shared.unbarrieredGet()->getFlags()) {}
 
     typedef Key Lookup;
     static HashNumber hash(const Lookup& l) {
       HashNumber hash = DefaultHasher<JSAtom*>::hash(l.atom);
-      return mozilla::AddToHash(hash, l.flags.value());
+      return mozilla::AddToHash(hash, l.flag);
     }
     static bool match(Key l, Key r) {
-      return l.atom == r.atom && l.flags == r.flags;
+      return l.atom == r.atom && l.flag == r.flag;
     }
   };
 
   /*
    * The set of all RegExpShareds in the zone. On every GC, every RegExpShared
    * that was not marked is deleted and removed from the set.
    */
   using Set = JS::WeakCache<
@@ -228,22 +226,22 @@ class RegExpZone {
 
  public:
   explicit RegExpZone(Zone* zone);
 
   ~RegExpZone() { MOZ_ASSERT(set_.empty()); }
 
   bool empty() const { return set_.empty(); }
 
-  RegExpShared* maybeGet(JSAtom* source, JS::RegExpFlags flags) const {
+  RegExpShared* maybeGet(JSAtom* source, RegExpFlag flags) const {
     Set::Ptr p = set_.lookup(Key(source, flags));
     return p ? *p : nullptr;
   }
 
-  RegExpShared* get(JSContext* cx, HandleAtom source, JS::RegExpFlags flags);
+  RegExpShared* get(JSContext* cx, HandleAtom source, RegExpFlag flags);
 
   /* Like 'get', but compile 'maybeOpt' (if non-null). */
   RegExpShared* get(JSContext* cx, HandleAtom source, JSString* maybeOpt);
 
 #ifdef DEBUG
   void clear() { set_.clear(); }
 #endif
 
--- a/js/src/vm/RegExpStatics.h
+++ b/js/src/vm/RegExpStatics.h
@@ -24,17 +24,17 @@ class RegExpStatics {
   HeapPtr<JSLinearString*> matchesInput;
 
   /*
    * 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().
    */
   HeapPtr<JSAtom*> lazySource;
-  JS::RegExpFlags lazyFlags;
+  RegExpFlag lazyFlags;
   size_t lazyIndex;
 
   /* The latest RegExp input, set before execution. */
   HeapPtr<JSString*> pendingInput;
 
   /*
    * If non-zero, |matchesInput| and the |lazy*| fields may be used
    * to replay the last executed RegExp, and |matches| is invalid.
@@ -269,17 +269,17 @@ inline bool RegExpStatics::updateFromMat
 
   return true;
 }
 
 inline void RegExpStatics::clear() {
   matches.forgetArray();
   matchesInput = nullptr;
   lazySource = nullptr;
-  lazyFlags = JS::RegExpFlag::NoFlags;
+  lazyFlags = RegExpFlag(0);
   lazyIndex = size_t(-1);
   pendingInput = nullptr;
   pendingLazyEvaluation = false;
 }
 
 inline void RegExpStatics::setPendingInput(JSString* newInput) {
   pendingInput = newInput;
 }
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -23,17 +23,16 @@
  *     We serialize objects that appear in multiple places in the input as
  *     backreferences, using sequential integer indexes.
  *     See `JSStructuredCloneReader::allObjs`, our take on the "memory" map
  *     in the spec's StructuredDeserialize.
  */
 
 #include "js/StructuredClone.h"
 
-#include "mozilla/Casting.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/EndianUtils.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/RangedPtr.h"
 #include "mozilla/Unused.h"
 
 #include <algorithm>
 #include <memory>
@@ -42,17 +41,16 @@
 #include "jsapi.h"
 #include "jsdate.h"
 
 #include "builtin/DataViewObject.h"
 #include "builtin/MapObject.h"
 #include "js/ArrayBuffer.h"  // JS::{ArrayBufferHasData,DetachArrayBuffer,IsArrayBufferObject,New{,Mapped}ArrayBufferWithContents,ReleaseMappedArrayBufferContents}
 #include "js/Date.h"
 #include "js/GCHashTable.h"
-#include "js/RegExpFlags.h"        // JS::RegExpFlags
 #include "js/SharedArrayBuffer.h"  // JS::IsSharedArrayBufferObject
 #include "js/Wrapper.h"
 #include "vm/BigIntType.h"
 #include "vm/JSContext.h"
 #include "vm/RegExpObject.h"
 #include "vm/SavedFrame.h"
 #include "vm/SharedArrayObject.h"
 #include "vm/TypedArrayObject.h"
@@ -61,19 +59,17 @@
 
 #include "vm/InlineCharBuffer-inl.h"
 #include "vm/JSContext-inl.h"
 #include "vm/JSObject-inl.h"
 
 using namespace js;
 
 using JS::CanonicalizeNaN;
-using JS::RegExpFlags;
 using JS::RootedValueVector;
-using mozilla::AssertedCast;
 using mozilla::BitwiseCast;
 using mozilla::NativeEndian;
 using mozilla::NumbersAreIdentical;
 using mozilla::RangedPtr;
 
 // When you make updates here, make sure you consider whether you need to bump
 // the value of JS_STRUCTURED_CLONE_VERSION in js/public/StructuredClone.h.  You
 // will likely need to increment the version if anything at all changes in the
@@ -1668,17 +1664,17 @@ bool JSStructuredCloneWriter::startWrite
         }
         return out.writePair(SCTAG_BOOLEAN_OBJECT, unboxed.toBoolean());
       }
       case ESClass::RegExp: {
         RegExpShared* re = RegExpToShared(context(), obj);
         if (!re) {
           return false;
         }
-        return out.writePair(SCTAG_REGEXP_OBJECT, re->getFlags().value()) &&
+        return out.writePair(SCTAG_REGEXP_OBJECT, re->getFlags()) &&
                writeString(SCTAG_STRING, re->getSource());
       }
       case ESClass::ArrayBuffer: {
         if (JS::IsArrayBufferObject(obj) && JS::ArrayBufferHasData(obj)) {
           return writeArrayBuffer(obj);
         }
         break;
       }
@@ -2457,17 +2453,17 @@ bool JSStructuredCloneReader::startRead(
       if (!obj) {
         return false;
       }
       vp.setObject(*obj);
       break;
     }
 
     case SCTAG_REGEXP_OBJECT: {
-      RegExpFlags flags = AssertedCast<uint8_t>(data);
+      RegExpFlag flags = RegExpFlag(data);
       uint32_t tag2, stringData;
       if (!in.readPair(&tag2, &stringData)) {
         return false;
       }
       if (tag2 != SCTAG_STRING) {
         JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr,
                                   JSMSG_SC_BAD_SERIALIZED_DATA, "regexp");
         return false;