Invalid flags in a RegExp literal should be an early SyntaxError
https://bugs.webkit.org/show_bug.cgi?id=195514

Reviewed by Darin Adler.

JSTests:

* test262/expectations.yaml:
Mark 4 test cases as passing.

* stress/regexp-syntax-error-invalid-flags.js:
* stress/regress-161995.js: Removed.
Update existing test, merging in an older test for the same behavior.

Source/JavaScriptCore:

Currently we're throwing a *runtime* SyntaxError; this should occur at parse time.

  12.2.8.1 Static Semantics: Early Errors
    PrimaryExpression : RegularExpressionLiteral
      - It is a Syntax Error if BodyText of RegularExpressionLiteral cannot be recognized
        using the goal symbol Pattern of the ECMAScript RegExp grammar specified in 21.2.1.
      - It is a Syntax Error if FlagText of RegularExpressionLiteral contains any code points
        other than "g", "i", "m",  "s", "u", or "y", or if it contains the same code point more than once.

In fixing this, let's also move flag handling from runtime/ to yarr/.

* yarr/YarrSyntaxChecker.cpp:
(JSC::Yarr::checkSyntax):
Check flags before checking pattern.

* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Sources.txt:
* bytecompiler/NodesCodegen.cpp:
(JSC::RegExpNode::emitBytecode):
* inspector/ContentSearchUtilities.cpp:
(Inspector::ContentSearchUtilities::findMagicComment):
* runtime/CachedTypes.cpp:
* runtime/RegExp.cpp:
(JSC::RegExp::RegExp):
(JSC::RegExp::createWithoutCaching):
(JSC::RegExp::create):
(JSC::regExpFlags): Deleted.
* runtime/RegExp.h:
* runtime/RegExpCache.cpp:
(JSC::RegExpCache::lookupOrCreate):
(JSC::RegExpCache::ensureEmptyRegExpSlow):
* runtime/RegExpCache.h:
* runtime/RegExpConstructor.cpp:
(JSC::toFlags):
(JSC::regExpCreate):
(JSC::constructRegExp):
* runtime/RegExpKey.h:
(JSC::RegExpKey::RegExpKey):
(WTF::HashTraits<JSC::RegExpKey>::constructDeletedValue):
(WTF::HashTraits<JSC::RegExpKey>::isDeletedValue):
(): Deleted.
* runtime/RegExpPrototype.cpp:
(JSC::regExpProtoFuncCompile):
* testRegExp.cpp:
(parseRegExpLine):
* yarr/RegularExpression.cpp:
(JSC::Yarr::RegularExpression::Private::compile):
* yarr/YarrFlags.cpp: Added.
(JSC::Yarr::parseFlags):
* yarr/YarrFlags.h: Added.
* yarr/YarrInterpreter.h:
(JSC::Yarr::BytecodePattern::ignoreCase const):
(JSC::Yarr::BytecodePattern::multiline const):
(JSC::Yarr::BytecodePattern::sticky const):
(JSC::Yarr::BytecodePattern::unicode const):
(JSC::Yarr::BytecodePattern::dotAll const):
* yarr/YarrPattern.cpp:
(JSC::Yarr::YarrPattern::compile):
(JSC::Yarr::YarrPattern::YarrPattern):
(JSC::Yarr::YarrPattern::dumpPattern):
* yarr/YarrPattern.h:
(JSC::Yarr::YarrPattern::global const):
(JSC::Yarr::YarrPattern::ignoreCase const):
(JSC::Yarr::YarrPattern::multiline const):
(JSC::Yarr::YarrPattern::sticky const):
(JSC::Yarr::YarrPattern::unicode const):
(JSC::Yarr::YarrPattern::dotAll const):
Move flag handling to Yarr and modernize API.

Source/WebCore:

* bindings/js/SerializedScriptValue.cpp:
(WebCore::CloneDeserializer::readTerminal):
Consume YarrFlags.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@242699 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog
index 52b6a7b..f3dea19 100644
--- a/JSTests/ChangeLog
+++ b/JSTests/ChangeLog
@@ -1,3 +1,17 @@
+2019-03-10  Ross Kirsling  <ross.kirsling@sony.com>
+
+        Invalid flags in a RegExp literal should be an early SyntaxError
+        https://bugs.webkit.org/show_bug.cgi?id=195514
+
+        Reviewed by Darin Adler.
+
+        * test262/expectations.yaml:
+        Mark 4 test cases as passing.
+
+        * stress/regexp-syntax-error-invalid-flags.js:
+        * stress/regress-161995.js: Removed.
+        Update existing test, merging in an older test for the same behavior.
+
 2019-03-08  Mark Lam  <mark.lam@apple.com>
 
         Stack overflow crash in JSC::JSObject::hasInstance.
diff --git a/JSTests/stress/regexp-syntax-error-invalid-flags.js b/JSTests/stress/regexp-syntax-error-invalid-flags.js
index a4961ba..7787107 100644
--- a/JSTests/stress/regexp-syntax-error-invalid-flags.js
+++ b/JSTests/stress/regexp-syntax-error-invalid-flags.js
@@ -1,23 +1,17 @@
-function shouldThrow(func, errorMessage) {
-    var errorThrown = false;
-    var error = null;
+function shouldThrowSyntaxError(script) {
+    let error;
     try {
-        func();
+        eval(script);
     } catch (e) {
-        errorThrown = true;
         error = e;
     }
-    if (!errorThrown)
+
+    if (!error)
         throw new Error('not thrown');
-    if (String(error) !== errorMessage)
+    if (String(error) !== 'SyntaxError: Invalid regular expression: invalid flags')
         throw new Error(`bad error: ${String(error)}`);
 }
 
-function test()
-{
-    return /Hello/cocoa;
-}
-noInline(test);
-
-for (var i = 0; i < 1e4; ++i)
-    shouldThrow(test, `SyntaxError: Invalid regular expression: invalid flags`);
+shouldThrowSyntaxError('/Hello/cocoa');
+shouldThrowSyntaxError('/a/Z');
+shouldThrowSyntaxError('/./ii');
diff --git a/JSTests/stress/regress-161995.js b/JSTests/stress/regress-161995.js
deleted file mode 100644
index 604e939..0000000
--- a/JSTests/stress/regress-161995.js
+++ /dev/null
@@ -1,14 +0,0 @@
-// Regression test for 161995.
-
-function testStatic()
-{
-    return /a/Z;
-}
-
-try {
-    testStatic();
-    throw "Expected a SyntaxEerror for bad RegExp flags, but didn't get one.";
-} catch(e) {
-    if (e != "SyntaxError: Invalid regular expression: invalid flags")
-        throw "Incorrect exception for bad RegExp flags.  Got: " + e;
-}
diff --git a/JSTests/test262/expectations.yaml b/JSTests/test262/expectations.yaml
index d3267b7..10a0aa8 100644
--- a/JSTests/test262/expectations.yaml
+++ b/JSTests/test262/expectations.yaml
@@ -2396,12 +2396,6 @@
 test/language/literals/numeric/numeric-separator-literal-sign-plus-dds-nsl-dd.js:
   default: 'SyntaxError: No identifiers allowed directly after numeric literal'
   strict mode: 'SyntaxError: No identifiers allowed directly after numeric literal'
-test/language/literals/regexp/early-err-bad-flag.js:
-  default: 'Test262: This statement should not be evaluated.'
-  strict mode: 'Test262: This statement should not be evaluated.'
-test/language/literals/regexp/early-err-dup-flag.js:
-  default: 'Test262: This statement should not be evaluated.'
-  strict mode: 'Test262: This statement should not be evaluated.'
 test/language/literals/regexp/named-groups/invalid-dangling-groupname-2-u.js:
   default: 'Test262: This statement should not be evaluated.'
   strict mode: 'Test262: This statement should not be evaluated.'
diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt
index 878eaf2..f03d0ad 100644
--- a/Source/JavaScriptCore/CMakeLists.txt
+++ b/Source/JavaScriptCore/CMakeLists.txt
@@ -1000,6 +1000,7 @@
     yarr/RegularExpression.h
     yarr/Yarr.h
     yarr/YarrErrorCode.h
+    yarr/YarrFlags.h
     yarr/YarrInterpreter.h
     yarr/YarrJIT.h
     yarr/YarrParser.h
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index be78ec5..142fa4b 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,80 @@
+2019-03-10  Ross Kirsling  <ross.kirsling@sony.com>
+
+        Invalid flags in a RegExp literal should be an early SyntaxError
+        https://bugs.webkit.org/show_bug.cgi?id=195514
+
+        Reviewed by Darin Adler.
+
+        Currently we're throwing a *runtime* SyntaxError; this should occur at parse time. 
+
+          12.2.8.1 Static Semantics: Early Errors
+            PrimaryExpression : RegularExpressionLiteral
+              - It is a Syntax Error if BodyText of RegularExpressionLiteral cannot be recognized
+                using the goal symbol Pattern of the ECMAScript RegExp grammar specified in 21.2.1.
+              - It is a Syntax Error if FlagText of RegularExpressionLiteral contains any code points
+                other than "g", "i", "m",  "s", "u", or "y", or if it contains the same code point more than once.
+
+        In fixing this, let's also move flag handling from runtime/ to yarr/.
+
+        * yarr/YarrSyntaxChecker.cpp:
+        (JSC::Yarr::checkSyntax):
+        Check flags before checking pattern.
+
+        * CMakeLists.txt:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * Sources.txt:
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::RegExpNode::emitBytecode):
+        * inspector/ContentSearchUtilities.cpp:
+        (Inspector::ContentSearchUtilities::findMagicComment):
+        * runtime/CachedTypes.cpp:
+        * runtime/RegExp.cpp:
+        (JSC::RegExp::RegExp):
+        (JSC::RegExp::createWithoutCaching):
+        (JSC::RegExp::create):
+        (JSC::regExpFlags): Deleted.
+        * runtime/RegExp.h:
+        * runtime/RegExpCache.cpp:
+        (JSC::RegExpCache::lookupOrCreate):
+        (JSC::RegExpCache::ensureEmptyRegExpSlow):
+        * runtime/RegExpCache.h:
+        * runtime/RegExpConstructor.cpp:
+        (JSC::toFlags):
+        (JSC::regExpCreate):
+        (JSC::constructRegExp):
+        * runtime/RegExpKey.h:
+        (JSC::RegExpKey::RegExpKey):
+        (WTF::HashTraits<JSC::RegExpKey>::constructDeletedValue):
+        (WTF::HashTraits<JSC::RegExpKey>::isDeletedValue):
+        (): Deleted.
+        * runtime/RegExpPrototype.cpp:
+        (JSC::regExpProtoFuncCompile):
+        * testRegExp.cpp:
+        (parseRegExpLine):
+        * yarr/RegularExpression.cpp:
+        (JSC::Yarr::RegularExpression::Private::compile):
+        * yarr/YarrFlags.cpp: Added.
+        (JSC::Yarr::parseFlags):
+        * yarr/YarrFlags.h: Added.
+        * yarr/YarrInterpreter.h:
+        (JSC::Yarr::BytecodePattern::ignoreCase const):
+        (JSC::Yarr::BytecodePattern::multiline const):
+        (JSC::Yarr::BytecodePattern::sticky const):
+        (JSC::Yarr::BytecodePattern::unicode const):
+        (JSC::Yarr::BytecodePattern::dotAll const):
+        * yarr/YarrPattern.cpp:
+        (JSC::Yarr::YarrPattern::compile):
+        (JSC::Yarr::YarrPattern::YarrPattern):
+        (JSC::Yarr::YarrPattern::dumpPattern):
+        * yarr/YarrPattern.h:
+        (JSC::Yarr::YarrPattern::global const):
+        (JSC::Yarr::YarrPattern::ignoreCase const):
+        (JSC::Yarr::YarrPattern::multiline const):
+        (JSC::Yarr::YarrPattern::sticky const):
+        (JSC::Yarr::YarrPattern::unicode const):
+        (JSC::Yarr::YarrPattern::dotAll const):
+        Move flag handling to Yarr and modernize API.
+
 2019-03-09  Robin Morisset  <rmorisset@apple.com>
 
         Compilation can be shrunk by 8 bytes
diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
index e48a64b..bb19f60 100644
--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
@@ -1339,6 +1339,7 @@
 		A1D792FD1B43864B004516F5 /* IntlNumberFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = A1D792F71B43864B004516F5 /* IntlNumberFormat.h */; };
 		A1D792FF1B43864B004516F5 /* IntlNumberFormatConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = A1D792F91B43864B004516F5 /* IntlNumberFormatConstructor.h */; };
 		A1D793011B43864B004516F5 /* IntlNumberFormatPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = A1D792FB1B43864B004516F5 /* IntlNumberFormatPrototype.h */; };
+		A3FF9BC72234749100B1A9AB /* YarrFlags.h in Headers */ = {isa = PBXBuildFile; fileRef = A3FF9BC52234746600B1A9AB /* YarrFlags.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		A503FA1A188E0FB000110F14 /* JavaScriptCallFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = A503FA14188E0FAF00110F14 /* JavaScriptCallFrame.h */; };
 		A503FA1E188E0FB000110F14 /* JSJavaScriptCallFramePrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = A503FA18188E0FB000110F14 /* JSJavaScriptCallFramePrototype.h */; };
 		A503FA21188EFF6800110F14 /* ScriptBreakpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = A503FA1F188EFF6800110F14 /* ScriptBreakpoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -4086,6 +4087,8 @@
 		A1E0451B1C25B4B100BB663C /* StringPrototype.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = StringPrototype.js; sourceTree = "<group>"; };
 		A1FE1EB01C2C537E00A289FF /* DatePrototype.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = DatePrototype.js; sourceTree = "<group>"; };
 		A27958D7FA1142B0AC9E364D /* WasmContextInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmContextInlines.h; sourceTree = "<group>"; };
+		A3FF9BC52234746600B1A9AB /* YarrFlags.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YarrFlags.h; path = yarr/YarrFlags.h; sourceTree = "<group>"; };
+		A3FF9BC62234746600B1A9AB /* YarrFlags.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = YarrFlags.cpp; path = yarr/YarrFlags.cpp; sourceTree = "<group>"; };
 		A503FA13188E0FAF00110F14 /* JavaScriptCallFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JavaScriptCallFrame.cpp; sourceTree = "<group>"; };
 		A503FA14188E0FAF00110F14 /* JavaScriptCallFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JavaScriptCallFrame.h; sourceTree = "<group>"; };
 		A503FA15188E0FB000110F14 /* JSJavaScriptCallFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSJavaScriptCallFrame.cpp; sourceTree = "<group>"; };
@@ -7303,6 +7306,8 @@
 				65C6BEE021128C3B006849C3 /* YarrDisassembler.h */,
 				E3282BB91FE930A300EDAF71 /* YarrErrorCode.cpp */,
 				E3282BBA1FE930A400EDAF71 /* YarrErrorCode.h */,
+				A3FF9BC62234746600B1A9AB /* YarrFlags.cpp */,
+				A3FF9BC52234746600B1A9AB /* YarrFlags.h */,
 				86704B7D12DBA33700A9FE7B /* YarrInterpreter.cpp */,
 				86704B7E12DBA33700A9FE7B /* YarrInterpreter.h */,
 				86704B7F12DBA33700A9FE7B /* YarrJIT.cpp */,
@@ -9896,6 +9901,7 @@
 				9959E92E1BD17FA4001AA413 /* xxd.pl in Headers */,
 				451539B912DC994500EF7AC4 /* Yarr.h in Headers */,
 				E3282BBB1FE930AF00EDAF71 /* YarrErrorCode.h in Headers */,
+				A3FF9BC72234749100B1A9AB /* YarrFlags.h in Headers */,
 				86704B8512DBA33700A9FE7B /* YarrInterpreter.h in Headers */,
 				86704B8712DBA33700A9FE7B /* YarrJIT.h in Headers */,
 				86704B8812DBA33700A9FE7B /* YarrParser.h in Headers */,
diff --git a/Source/JavaScriptCore/Sources.txt b/Source/JavaScriptCore/Sources.txt
index 60fcff0..b7c8e24 100644
--- a/Source/JavaScriptCore/Sources.txt
+++ b/Source/JavaScriptCore/Sources.txt
@@ -1045,6 +1045,7 @@
 yarr/YarrCanonicalizeUCS2.cpp
 yarr/YarrDisassembler.cpp
 yarr/YarrErrorCode.cpp
+yarr/YarrFlags.cpp
 yarr/YarrInterpreter.cpp
 yarr/YarrJIT.cpp
 yarr/YarrPattern.cpp
diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index df9dfd8..f07592b 100644
--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -41,6 +41,7 @@
 #include "Lexer.h"
 #include "Parser.h"
 #include "StackAlignment.h"
+#include "YarrFlags.h"
 #include <wtf/Assertions.h>
 #include <wtf/Threading.h>
 #include <wtf/text/StringBuilder.h>
@@ -141,9 +142,13 @@
 {
     if (dst == generator.ignoredResult())
         return nullptr;
-    RegExp* regExp = RegExp::create(*generator.vm(), m_pattern.string(), regExpFlags(m_flags.string()));
+
+    auto flags = Yarr::parseFlags(m_flags.string());
+    ASSERT(flags.hasValue());
+    RegExp* regExp = RegExp::create(*generator.vm(), m_pattern.string(), flags.value());
     if (regExp->isValid())
         return generator.emitNewRegExp(generator.finalDestination(dst), regExp);
+
     const char* messageCharacters = regExp->errorMessage();
     const Identifier& message = generator.parserArena().identifierArena().makeIdentifier(generator.vm(), bitwise_cast<const LChar*>(messageCharacters), strlen(messageCharacters));
     generator.emitThrowStaticError(ErrorType::SyntaxError, message);
diff --git a/Source/JavaScriptCore/inspector/ContentSearchUtilities.cpp b/Source/JavaScriptCore/inspector/ContentSearchUtilities.cpp
index dd878ff..c8de078 100644
--- a/Source/JavaScriptCore/inspector/ContentSearchUtilities.cpp
+++ b/Source/JavaScriptCore/inspector/ContentSearchUtilities.cpp
@@ -31,6 +31,7 @@
 
 #include "RegularExpression.h"
 #include "Yarr.h"
+#include "YarrFlags.h"
 #include "YarrInterpreter.h"
 #include <wtf/BumpPointerAllocator.h>
 #include <wtf/StdLibExtras.h>
@@ -167,7 +168,7 @@
         return String();
 
     JSC::Yarr::ErrorCode error { JSC::Yarr::ErrorCode::NoError };
-    YarrPattern pattern(patternString, JSC::RegExpFlags::FlagMultiline, error);
+    YarrPattern pattern(patternString, JSC::Yarr::Flags::Multiline, error);
     ASSERT(!hasError(error));
     BumpPointerAllocator regexAllocator;
     auto bytecodePattern = byteCompile(pattern, &regexAllocator);
diff --git a/Source/JavaScriptCore/runtime/CachedTypes.cpp b/Source/JavaScriptCore/runtime/CachedTypes.cpp
index 0344869..e6df5d3 100644
--- a/Source/JavaScriptCore/runtime/CachedTypes.cpp
+++ b/Source/JavaScriptCore/runtime/CachedTypes.cpp
@@ -28,7 +28,6 @@
 
 #include "BytecodeCacheVersion.h"
 #include "BytecodeLivenessAnalysis.h"
-#include "JSCast.h"
 #include "JSImmutableButterfly.h"
 #include "JSTemplateObjectDescriptor.h"
 #include "ScopedArgumentsTable.h"
@@ -40,13 +39,16 @@
 #include "UnlinkedModuleProgramCodeBlock.h"
 #include "UnlinkedProgramCodeBlock.h"
 #include <wtf/FastMalloc.h>
-#include <wtf/Forward.h>
 #include <wtf/Optional.h>
 #include <wtf/UUID.h>
 #include <wtf/text/AtomicStringImpl.h>
 
 namespace JSC {
 
+namespace Yarr {
+enum class Flags : uint8_t;
+}
+
 template <typename T, typename = void>
 struct SourceTypeImpl {
     using type = T;
@@ -1111,7 +1113,7 @@
 
 private:
     CachedString m_patternString;
-    RegExpFlags m_flags;
+    OptionSet<Yarr::Flags> m_flags;
 };
 
 class CachedTemplateObjectDescriptor : public CachedObject<TemplateObjectDescriptor> {
diff --git a/Source/JavaScriptCore/runtime/RegExp.cpp b/Source/JavaScriptCore/runtime/RegExp.cpp
index 05de498..93ad2e9 100644
--- a/Source/JavaScriptCore/runtime/RegExp.cpp
+++ b/Source/JavaScriptCore/runtime/RegExp.cpp
@@ -28,7 +28,6 @@
 #include "JSCInlines.h"
 #include "RegExpCache.h"
 #include "RegExpInlines.h"
-#include "Yarr.h"
 #include "YarrJIT.h"
 #include <wtf/Assertions.h>
 
@@ -36,56 +35,6 @@
 
 const ClassInfo RegExp::s_info = { "RegExp", nullptr, nullptr, nullptr, CREATE_METHOD_TABLE(RegExp) };
 
-RegExpFlags regExpFlags(const String& string)
-{
-    RegExpFlags flags = NoFlags;
-
-    for (unsigned i = 0; i < string.length(); ++i) {
-        switch (string[i]) {
-        case 'g':
-            if (flags & FlagGlobal)
-                return InvalidFlags;
-            flags = static_cast<RegExpFlags>(flags | FlagGlobal);
-            break;
-
-        case 'i':
-            if (flags & FlagIgnoreCase)
-                return InvalidFlags;
-            flags = static_cast<RegExpFlags>(flags | FlagIgnoreCase);
-            break;
-
-        case 'm':
-            if (flags & FlagMultiline)
-                return InvalidFlags;
-            flags = static_cast<RegExpFlags>(flags | FlagMultiline);
-            break;
-
-        case 's':
-            if (flags & FlagDotAll)
-                return InvalidFlags;
-            flags = static_cast<RegExpFlags>(flags | FlagDotAll);
-            break;
-            
-        case 'u':
-            if (flags & FlagUnicode)
-                return InvalidFlags;
-            flags = static_cast<RegExpFlags>(flags | FlagUnicode);
-            break;
-                
-        case 'y':
-            if (flags & FlagSticky)
-                return InvalidFlags;
-            flags = static_cast<RegExpFlags>(flags | FlagSticky);
-            break;
-
-        default:
-            return InvalidFlags;
-        }
-    }
-
-    return flags;
-}
-
 #if REGEXP_FUNC_TEST_DATA_GEN
 const char* const RegExpFunctionalTestCollector::s_fileName = "/tmp/RegExpTestsData";
 RegExpFunctionalTestCollector* RegExpFunctionalTestCollector::s_instance = 0;
@@ -210,11 +159,12 @@
 }
 #endif
 
-RegExp::RegExp(VM& vm, const String& patternString, RegExpFlags flags)
+RegExp::RegExp(VM& vm, const String& patternString, OptionSet<Yarr::Flags> flags)
     : JSCell(vm, vm.regExpStructure.get())
     , m_patternString(patternString)
     , m_flags(flags)
 {
+    ASSERT(m_flags != Yarr::Flags::DeletedValue);
 }
 
 void RegExp::finishCreation(VM& vm)
@@ -249,14 +199,14 @@
     return Base::estimatedSize(cell, vm) + regexDataSize;
 }
 
-RegExp* RegExp::createWithoutCaching(VM& vm, const String& patternString, RegExpFlags flags)
+RegExp* RegExp::createWithoutCaching(VM& vm, const String& patternString, OptionSet<Yarr::Flags> flags)
 {
     RegExp* regExp = new (NotNull, allocateCell<RegExp>(vm.heap)) RegExp(vm, patternString, flags);
     regExp->finishCreation(vm);
     return regExp;
 }
 
-RegExp* RegExp::create(VM& vm, const String& patternString, RegExpFlags flags)
+RegExp* RegExp::create(VM& vm, const String& patternString, OptionSet<Yarr::Flags> flags)
 {
     return vm.regExpCache()->lookupOrCreate(patternString, flags);
 }
diff --git a/Source/JavaScriptCore/runtime/RegExp.h b/Source/JavaScriptCore/runtime/RegExp.h
index 03add45..35b7a4b 100644
--- a/Source/JavaScriptCore/runtime/RegExp.h
+++ b/Source/JavaScriptCore/runtime/RegExp.h
@@ -38,8 +38,6 @@
 struct RegExpRepresentation;
 class VM;
 
-JS_EXPORT_PRIVATE RegExpFlags regExpFlags(const String&);
-
 class RegExp final : public JSCell {
     friend class CachedRegExp;
 
@@ -47,23 +45,23 @@
     typedef JSCell Base;
     static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
 
-    JS_EXPORT_PRIVATE static RegExp* create(VM&, const String& pattern, RegExpFlags);
+    JS_EXPORT_PRIVATE static RegExp* create(VM&, const String& pattern, OptionSet<Yarr::Flags>);
     static const bool needsDestruction = true;
     static void destroy(JSCell*);
     static size_t estimatedSize(JSCell*, VM&);
     JS_EXPORT_PRIVATE static void dumpToStream(const JSCell*, PrintStream&);
 
-    bool global() const { return m_flags & FlagGlobal; }
-    bool ignoreCase() const { return m_flags & FlagIgnoreCase; }
-    bool multiline() const { return m_flags & FlagMultiline; }
-    bool sticky() const { return m_flags & FlagSticky; }
+    bool global() const { return m_flags.contains(Yarr::Flags::Global); }
+    bool ignoreCase() const { return m_flags.contains(Yarr::Flags::IgnoreCase); }
+    bool multiline() const { return m_flags.contains(Yarr::Flags::Multiline); }
+    bool sticky() const { return m_flags.contains(Yarr::Flags::Sticky); }
     bool globalOrSticky() const { return global() || sticky(); }
-    bool unicode() const { return m_flags & FlagUnicode; }
-    bool dotAll() const { return m_flags & FlagDotAll; }
+    bool unicode() const { return m_flags.contains(Yarr::Flags::Unicode); }
+    bool dotAll() const { return m_flags.contains(Yarr::Flags::DotAll); }
 
     const String& pattern() const { return m_patternString; }
 
-    bool isValid() const { return !Yarr::hasError(m_constructionErrorCode) && m_flags != InvalidFlags; }
+    bool isValid() const { return !Yarr::hasError(m_constructionErrorCode); }
     const char* errorMessage() const { return Yarr::errorMessage(m_constructionErrorCode); }
     JSObject* errorToThrow(ExecState* exec) { return Yarr::errorToThrow(exec, m_constructionErrorCode); }
     void reset()
@@ -136,9 +134,9 @@
 
 private:
     friend class RegExpCache;
-    RegExp(VM&, const String&, RegExpFlags);
+    RegExp(VM&, const String&, OptionSet<Yarr::Flags>);
 
-    static RegExp* createWithoutCaching(VM&, const String&, RegExpFlags);
+    static RegExp* createWithoutCaching(VM&, const String&, OptionSet<Yarr::Flags>);
 
     enum RegExpState : uint8_t {
         ParseError,
@@ -161,7 +159,7 @@
 
     String m_patternString;
     RegExpState m_state { NotCompiled };
-    RegExpFlags m_flags;
+    OptionSet<Yarr::Flags> m_flags;
     ConcurrentJSLock m_lock;
     Yarr::ErrorCode m_constructionErrorCode { Yarr::ErrorCode::NoError };
     unsigned m_numSubpatterns { 0 };
diff --git a/Source/JavaScriptCore/runtime/RegExpCache.cpp b/Source/JavaScriptCore/runtime/RegExpCache.cpp
index d76bb39..6308695 100644
--- a/Source/JavaScriptCore/runtime/RegExpCache.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpCache.cpp
@@ -35,7 +35,7 @@
 
 namespace JSC {
 
-RegExp* RegExpCache::lookupOrCreate(const String& patternString, RegExpFlags flags)
+RegExp* RegExpCache::lookupOrCreate(const String& patternString, OptionSet<Yarr::Flags> flags)
 {
     RegExpKey key(flags, patternString);
     if (RegExp* regExp = m_weakCache.get(key))
@@ -58,7 +58,7 @@
 
 RegExp* RegExpCache::ensureEmptyRegExpSlow(VM& vm)
 {
-    RegExp* regExp = RegExp::create(vm, "", NoFlags);
+    RegExp* regExp = RegExp::create(vm, "", { });
     m_emptyRegExp.set(vm, regExp);
     return regExp;
 }
diff --git a/Source/JavaScriptCore/runtime/RegExpCache.h b/Source/JavaScriptCore/runtime/RegExpCache.h
index bbda63f..083a111 100644
--- a/Source/JavaScriptCore/runtime/RegExpCache.h
+++ b/Source/JavaScriptCore/runtime/RegExpCache.h
@@ -36,6 +36,10 @@
 
 namespace JSC {
 
+namespace Yarr {
+enum class Flags : uint8_t;
+}
+
 class RegExpCache : private WeakHandleOwner {
     WTF_MAKE_FAST_ALLOCATED;
 
@@ -63,7 +67,7 @@
 
     RegExp* ensureEmptyRegExpSlow(VM&);
 
-    RegExp* lookupOrCreate(const WTF::String& patternString, RegExpFlags);
+    RegExp* lookupOrCreate(const WTF::String& patternString, OptionSet<Yarr::Flags>);
     void addToStrongCache(RegExp*);
     RegExpCacheMap m_weakCache; // Holds all regular expressions currently live.
     int m_nextEntryInStrongCache;
diff --git a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp
index 88a6331..6da496f 100644
--- a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp
@@ -24,10 +24,10 @@
 
 #include "Error.h"
 #include "GetterSetter.h"
-#include "JSCInlines.h"
 #include "RegExpGlobalDataInlines.h"
 #include "RegExpPrototype.h"
 #include "StructureInlines.h"
+#include "YarrFlags.h"
 
 namespace JSC {
 
@@ -177,23 +177,22 @@
     return structure;
 }
 
-inline RegExpFlags toFlags(ExecState* exec, JSValue flags)
+inline OptionSet<Yarr::Flags> toFlags(ExecState* exec, JSValue flags)
 {
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
 
     if (flags.isUndefined())
-        return NoFlags;
-    JSString* flagsString = flags.toStringOrNull(exec);
-    EXCEPTION_ASSERT(!!scope.exception() == !flagsString);
-    if (UNLIKELY(!flagsString))
-        return InvalidFlags;
-
-    RegExpFlags result = regExpFlags(flagsString->value(exec));
-    RETURN_IF_EXCEPTION(scope, InvalidFlags);
-    if (result == InvalidFlags)
+        return { };
+    
+    auto result = Yarr::parseFlags(flags.toWTFString(exec));
+    RETURN_IF_EXCEPTION(scope, { });
+    if (!result) {
         throwSyntaxError(exec, scope, "Invalid flags supplied to RegExp constructor."_s);
-    return result;
+        return { };
+    }
+
+    return result.value();
 }
 
 static JSObject* regExpCreate(ExecState* exec, JSGlobalObject* globalObject, JSValue newTarget, JSValue patternArg, JSValue flagsArg)
@@ -204,10 +203,8 @@
     String pattern = patternArg.isUndefined() ? emptyString() : patternArg.toWTFString(exec);
     RETURN_IF_EXCEPTION(scope, nullptr);
 
-    RegExpFlags flags = toFlags(exec, flagsArg);
-    EXCEPTION_ASSERT(!!scope.exception() == (flags == InvalidFlags));
-    if (UNLIKELY(flags == InvalidFlags))
-        return nullptr;
+    auto flags = toFlags(exec, flagsArg);
+    RETURN_IF_EXCEPTION(scope, nullptr);
 
     RegExp* regExp = RegExp::create(vm, pattern, flags);
     if (UNLIKELY(!regExp->isValid())) {
@@ -246,12 +243,10 @@
         RETURN_IF_EXCEPTION(scope, nullptr);
 
         if (!flagsArg.isUndefined()) {
-            RegExpFlags flags = toFlags(exec, flagsArg);
-            EXCEPTION_ASSERT(!!scope.exception() == (flags == InvalidFlags));
-            if (flags == InvalidFlags)
-                return nullptr;
-            regExp = RegExp::create(vm, regExp->pattern(), flags);
+            auto flags = toFlags(exec, flagsArg);
+            RETURN_IF_EXCEPTION(scope, nullptr);
 
+            regExp = RegExp::create(vm, regExp->pattern(), flags);
             if (UNLIKELY(!regExp->isValid())) {
                 throwException(exec, scope, regExp->errorToThrow(exec));
                 return nullptr;
diff --git a/Source/JavaScriptCore/runtime/RegExpKey.h b/Source/JavaScriptCore/runtime/RegExpKey.h
index d01e40a..141d70d 100644
--- a/Source/JavaScriptCore/runtime/RegExpKey.h
+++ b/Source/JavaScriptCore/runtime/RegExpKey.h
@@ -27,50 +27,38 @@
 
 #pragma once
 
+#include "YarrFlags.h"
+#include <wtf/OptionSet.h>
 #include <wtf/text/StringHash.h>
-#include <wtf/text/WTFString.h>
 
 namespace JSC {
 
-enum RegExpFlags : int8_t {
-    NoFlags = 0,
-    FlagGlobal = 1,
-    FlagIgnoreCase = 2,
-    FlagMultiline = 4,
-    FlagSticky = 8,
-    FlagUnicode = 16,
-    FlagDotAll = 32,
-    InvalidFlags = 64,
-    DeletedValueFlags = -1
-};
-
 struct RegExpKey {
-    RegExpFlags flagsValue;
+    OptionSet<Yarr::Flags> flagsValue;
     RefPtr<StringImpl> pattern;
 
     RegExpKey()
-        : flagsValue(NoFlags)
     {
     }
 
-    RegExpKey(RegExpFlags flags)
+    RegExpKey(OptionSet<Yarr::Flags> flags)
         : flagsValue(flags)
     {
     }
 
-    RegExpKey(RegExpFlags flags, const String& pattern)
+    RegExpKey(OptionSet<Yarr::Flags> flags, const String& pattern)
         : flagsValue(flags)
         , pattern(pattern.impl())
     {
     }
 
-    RegExpKey(RegExpFlags flags, RefPtr<StringImpl>&& pattern)
+    RegExpKey(OptionSet<Yarr::Flags> flags, RefPtr<StringImpl>&& pattern)
         : flagsValue(flags)
         , pattern(WTFMove(pattern))
     {
     }
 
-    RegExpKey(RegExpFlags flags, const RefPtr<StringImpl>& pattern)
+    RegExpKey(OptionSet<Yarr::Flags> flags, const RefPtr<StringImpl>& pattern)
         : flagsValue(flags)
         , pattern(pattern)
     {
@@ -107,7 +95,7 @@
 
 template<> struct HashTraits<JSC::RegExpKey> : GenericHashTraits<JSC::RegExpKey> {
     static const bool emptyValueIsZero = true;
-    static void constructDeletedValue(JSC::RegExpKey& slot) { slot.flagsValue = JSC::DeletedValueFlags; }
-    static bool isDeletedValue(const JSC::RegExpKey& value) { return value.flagsValue == JSC::DeletedValueFlags; }
+    static void constructDeletedValue(JSC::RegExpKey& slot) { slot.flagsValue = JSC::Yarr::Flags::DeletedValue; }
+    static bool isDeletedValue(const JSC::RegExpKey& value) { return value.flagsValue == JSC::Yarr::Flags::DeletedValue; }
 };
 } // namespace WTF
diff --git a/Source/JavaScriptCore/runtime/RegExpPrototype.cpp b/Source/JavaScriptCore/runtime/RegExpPrototype.cpp
index 2ce0b2d..5cc819d 100644
--- a/Source/JavaScriptCore/runtime/RegExpPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpPrototype.cpp
@@ -29,16 +29,15 @@
 #include "JSCInlines.h"
 #include "JSCJSValue.h"
 #include "JSFunction.h"
-#include "JSObject.h"
 #include "JSStringInlines.h"
 #include "Lexer.h"
 #include "ObjectPrototype.h"
-#include "RegExp.h"
 #include "RegExpCache.h"
 #include "RegExpObject.h"
 #include "RegExpObjectInlines.h"
 #include "StringObject.h"
 #include "StringRecursionChecker.h"
+#include "YarrFlags.h"
 #include <wtf/text/StringBuilder.h>
 
 namespace JSC {
@@ -149,14 +148,12 @@
         String pattern = arg0.isUndefined() ? emptyString() : arg0.toWTFString(exec);
         RETURN_IF_EXCEPTION(scope, encodedJSValue());
 
-        RegExpFlags flags = NoFlags;
-        if (!arg1.isUndefined()) {
-            flags = regExpFlags(arg1.toWTFString(exec));
-            RETURN_IF_EXCEPTION(scope, encodedJSValue());
-            if (flags == InvalidFlags)
-                return throwVMError(exec, scope, createSyntaxError(exec, "Invalid flags supplied to RegExp constructor."_s));
-        }
-        regExp = RegExp::create(vm, pattern, flags);
+        auto flags = arg1.isUndefined() ? makeOptional(OptionSet<Yarr::Flags> { }) : Yarr::parseFlags(arg1.toWTFString(exec));
+        RETURN_IF_EXCEPTION(scope, encodedJSValue());
+        if (!flags)
+            return throwVMError(exec, scope, createSyntaxError(exec, "Invalid flags supplied to RegExp constructor."_s));
+
+        regExp = RegExp::create(vm, pattern, flags.value());
     }
 
     if (!regExp->isValid())
diff --git a/Source/JavaScriptCore/testRegExp.cpp b/Source/JavaScriptCore/testRegExp.cpp
index 5091b71..cd0df24 100644
--- a/Source/JavaScriptCore/testRegExp.cpp
+++ b/Source/JavaScriptCore/testRegExp.cpp
@@ -24,6 +24,7 @@
 #include "InitializeThreading.h"
 #include "JSCInlines.h"
 #include "JSGlobalObject.h"
+#include "YarrFlags.h"
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -328,11 +329,18 @@
 
     ++i;
 
-    RegExp* r = RegExp::create(vm, pattern.toString(), regExpFlags(line + i));
+    auto flags = Yarr::parseFlags(line + i);
+    if (!flags) {
+        *regexpError = Yarr::errorMessage(Yarr::ErrorCode::InvalidRegularExpressionFlags);
+        return nullptr;
+    }
+
+    RegExp* r = RegExp::create(vm, pattern.toString(), flags.value());
     if (!r->isValid()) {
         *regexpError = r->errorMessage();
         return nullptr;
     }
+
     return r;
 }
 
diff --git a/Source/JavaScriptCore/yarr/RegularExpression.cpp b/Source/JavaScriptCore/yarr/RegularExpression.cpp
index 1dcede6..f121579 100644
--- a/Source/JavaScriptCore/yarr/RegularExpression.cpp
+++ b/Source/JavaScriptCore/yarr/RegularExpression.cpp
@@ -29,6 +29,7 @@
 #include "RegularExpression.h"
 
 #include "Yarr.h"
+#include "YarrFlags.h"
 #include "YarrInterpreter.h"
 #include <wtf/Assertions.h>
 #include <wtf/BumpPointerAllocator.h>
@@ -55,16 +56,16 @@
 
     std::unique_ptr<JSC::Yarr::BytecodePattern> compile(const String& patternString, TextCaseSensitivity caseSensitivity, MultilineMode multilineMode, UnicodeMode unicodeMode)
     {
-        RegExpFlags flags = NoFlags;
+        OptionSet<JSC::Yarr::Flags> flags;
 
         if (caseSensitivity == TextCaseInsensitive)
-            flags = static_cast<RegExpFlags>(flags | FlagIgnoreCase);
+            flags.add(Flags::IgnoreCase);
 
         if (multilineMode == MultilineEnabled)
-            flags = static_cast<RegExpFlags>(flags | FlagMultiline);
+            flags.add(Flags::Multiline);
 
         if (unicodeMode == UnicodeAwareMode)
-            flags = static_cast<RegExpFlags>(flags | FlagUnicode);
+            flags.add(Flags::Unicode);
 
         JSC::Yarr::YarrPattern pattern(patternString, flags, m_constructionErrorCode);
         if (JSC::Yarr::hasError(m_constructionErrorCode)) {
diff --git a/Source/JavaScriptCore/yarr/YarrFlags.cpp b/Source/JavaScriptCore/yarr/YarrFlags.cpp
new file mode 100644
index 0000000..51379f6
--- /dev/null
+++ b/Source/JavaScriptCore/yarr/YarrFlags.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2019 Sony Interactive Entertainment Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "YarrFlags.h"
+
+#include <wtf/OptionSet.h>
+#include <wtf/text/StringView.h>
+
+namespace JSC { namespace Yarr {
+
+Optional<OptionSet<Flags>> parseFlags(StringView string)
+{
+    OptionSet<Flags> flags;
+    for (auto character : string.codeUnits()) {
+        switch (character) {
+        case 'g':
+            if (flags.contains(Flags::Global))
+                return WTF::nullopt;
+            flags.add(Flags::Global);
+            break;
+
+        case 'i':
+            if (flags.contains(Flags::IgnoreCase))
+                return WTF::nullopt;
+            flags.add(Flags::IgnoreCase);
+            break;
+
+        case 'm':
+            if (flags.contains(Flags::Multiline))
+                return WTF::nullopt;
+            flags.add(Flags::Multiline);
+            break;
+
+        case 's':
+            if (flags.contains(Flags::DotAll))
+                return WTF::nullopt;
+            flags.add(Flags::DotAll);
+            break;
+            
+        case 'u':
+            if (flags.contains(Flags::Unicode))
+                return WTF::nullopt;
+            flags.add(Flags::Unicode);
+            break;
+                
+        case 'y':
+            if (flags.contains(Flags::Sticky))
+                return WTF::nullopt;
+            flags.add(Flags::Sticky);
+            break;
+
+        default:
+            return WTF::nullopt;
+        }
+    }
+
+    return makeOptional(flags);
+}
+
+} } // namespace JSC::Yarr
diff --git a/Source/JavaScriptCore/yarr/YarrFlags.h b/Source/JavaScriptCore/yarr/YarrFlags.h
new file mode 100644
index 0000000..7ae4dcb
--- /dev/null
+++ b/Source/JavaScriptCore/yarr/YarrFlags.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2019 Sony Interactive Entertainment Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/Forward.h>
+#include <wtf/Optional.h>
+
+namespace JSC { namespace Yarr {
+
+enum class Flags : uint8_t {
+    Global = 1 << 0,
+    IgnoreCase = 1 << 1,
+    Multiline = 1 << 2,
+    Sticky = 1 << 3,
+    Unicode = 1 << 4,
+    DotAll = 1 << 5,
+    DeletedValue = 1 << 6
+};
+
+JS_EXPORT_PRIVATE Optional<OptionSet<Flags>> parseFlags(StringView);
+
+} } // namespace JSC::Yarr
diff --git a/Source/JavaScriptCore/yarr/YarrInterpreter.h b/Source/JavaScriptCore/yarr/YarrInterpreter.h
index a319cb3..4b85bed 100644
--- a/Source/JavaScriptCore/yarr/YarrInterpreter.h
+++ b/Source/JavaScriptCore/yarr/YarrInterpreter.h
@@ -26,6 +26,7 @@
 #pragma once
 
 #include "ConcurrentJSLock.h"
+#include "YarrFlags.h"
 #include "YarrPattern.h"
 
 namespace WTF {
@@ -367,14 +368,14 @@
 
     size_t estimatedSizeInBytes() const { return m_body->estimatedSizeInBytes(); }
     
-    bool ignoreCase() const { return m_flags & FlagIgnoreCase; }
-    bool multiline() const { return m_flags & FlagMultiline; }
-    bool sticky() const { return m_flags & FlagSticky; }
-    bool unicode() const { return m_flags & FlagUnicode; }
-    bool dotAll() const { return m_flags & FlagDotAll; }
+    bool ignoreCase() const { return m_flags.contains(Flags::IgnoreCase); }
+    bool multiline() const { return m_flags.contains(Flags::Multiline); }
+    bool sticky() const { return m_flags.contains(Flags::Sticky); }
+    bool unicode() const { return m_flags.contains(Flags::Unicode); }
+    bool dotAll() const { return m_flags.contains(Flags::DotAll); }
 
     std::unique_ptr<ByteDisjunction> m_body;
-    RegExpFlags m_flags;
+    OptionSet<Flags> m_flags;
     // Each BytecodePattern is associated with a RegExp, each RegExp is associated
     // with a VM.  Cache a pointer to out VM's m_regExpAllocator.
     BumpPointerAllocator* m_allocator;
diff --git a/Source/JavaScriptCore/yarr/YarrPattern.cpp b/Source/JavaScriptCore/yarr/YarrPattern.cpp
index 36fc4d2..171f1c7 100644
--- a/Source/JavaScriptCore/yarr/YarrPattern.cpp
+++ b/Source/JavaScriptCore/yarr/YarrPattern.cpp
@@ -36,7 +36,6 @@
 #include <wtf/StackPointer.h>
 #include <wtf/Threading.h>
 #include <wtf/Vector.h>
-#include <wtf/text/WTFString.h>
 
 namespace JSC { namespace Yarr {
 
@@ -1110,9 +1109,6 @@
 {
     YarrPatternConstructor constructor(*this, stackLimit);
 
-    if (m_flags == InvalidFlags)
-        return ErrorCode::InvalidRegularExpressionFlags;
-
     {
         ErrorCode error = parse(constructor, patternString, unicode());
         if (hasError(error))
@@ -1152,7 +1148,7 @@
     return ErrorCode::NoError;
 }
 
-YarrPattern::YarrPattern(const String& pattern, RegExpFlags flags, ErrorCode& error, void* stackLimit)
+YarrPattern::YarrPattern(const String& pattern, OptionSet<Flags> flags, ErrorCode& error, void* stackLimit)
     : m_containsBackreferences(false)
     , m_containsBOL(false)
     , m_containsUnsignedLengthPattern(false)
@@ -1160,6 +1156,7 @@
     , m_saveInitialStartValue(false)
     , m_flags(flags)
 {
+    ASSERT(m_flags != Flags::DeletedValue);
     error = compile(pattern, stackLimit);
 }
 
@@ -1420,7 +1417,7 @@
     out.print("RegExp pattern for ");
     dumpPatternString(out, patternString);
 
-    if (m_flags != NoFlags) {
+    if (m_flags) {
         bool printSeperator = false;
         out.print(" (");
         if (global()) {
diff --git a/Source/JavaScriptCore/yarr/YarrPattern.h b/Source/JavaScriptCore/yarr/YarrPattern.h
index afb4e5c..c6e7fb2 100644
--- a/Source/JavaScriptCore/yarr/YarrPattern.h
+++ b/Source/JavaScriptCore/yarr/YarrPattern.h
@@ -26,14 +26,15 @@
 
 #pragma once
 
-#include "RegExpKey.h"
 #include "YarrErrorCode.h"
+#include "YarrFlags.h"
 #include "YarrUnicodeProperties.h"
 #include <wtf/CheckedArithmetic.h>
 #include <wtf/HashMap.h>
+#include <wtf/OptionSet.h>
 #include <wtf/PrintStream.h>
 #include <wtf/Vector.h>
-#include <wtf/text/WTFString.h>
+#include <wtf/text/StringHash.h>
 
 namespace JSC { namespace Yarr {
 
@@ -352,7 +353,7 @@
 
 
 struct YarrPattern {
-    JS_EXPORT_PRIVATE YarrPattern(const String& pattern, RegExpFlags, ErrorCode&, void* stackLimit = nullptr);
+    JS_EXPORT_PRIVATE YarrPattern(const String& pattern, OptionSet<Flags>, ErrorCode&, void* stackLimit = nullptr);
 
     void resetForReparsing()
     {
@@ -507,19 +508,19 @@
     void dumpPattern(const String& pattern);
     void dumpPattern(PrintStream& out, const String& pattern);
 
-    bool global() const { return m_flags & FlagGlobal; }
-    bool ignoreCase() const { return m_flags & FlagIgnoreCase; }
-    bool multiline() const { return m_flags & FlagMultiline; }
-    bool sticky() const { return m_flags & FlagSticky; }
-    bool unicode() const { return m_flags & FlagUnicode; }
-    bool dotAll() const { return m_flags & FlagDotAll; }
+    bool global() const { return m_flags.contains(Flags::Global); }
+    bool ignoreCase() const { return m_flags.contains(Flags::IgnoreCase); }
+    bool multiline() const { return m_flags.contains(Flags::Multiline); }
+    bool sticky() const { return m_flags.contains(Flags::Sticky); }
+    bool unicode() const { return m_flags.contains(Flags::Unicode); }
+    bool dotAll() const { return m_flags.contains(Flags::DotAll); }
 
     bool m_containsBackreferences : 1;
     bool m_containsBOL : 1;
     bool m_containsUnsignedLengthPattern : 1;
     bool m_hasCopiedParenSubexpressions : 1;
     bool m_saveInitialStartValue : 1;
-    RegExpFlags m_flags;
+    OptionSet<Flags> m_flags;
     unsigned m_numSubpatterns { 0 };
     unsigned m_maxBackReference { 0 };
     unsigned m_initialStartValueFrameLocation { 0 };
diff --git a/Source/JavaScriptCore/yarr/YarrSyntaxChecker.cpp b/Source/JavaScriptCore/yarr/YarrSyntaxChecker.cpp
index 0e0f635..86b0e67 100644
--- a/Source/JavaScriptCore/yarr/YarrSyntaxChecker.cpp
+++ b/Source/JavaScriptCore/yarr/YarrSyntaxChecker.cpp
@@ -26,9 +26,9 @@
 #include "config.h"
 #include "YarrSyntaxChecker.h"
 
+#include "YarrFlags.h"
 #include "YarrParser.h"
 #include <wtf/Optional.h>
-#include <wtf/text/WTFString.h>
 
 namespace JSC { namespace Yarr {
 
@@ -58,7 +58,12 @@
 ErrorCode checkSyntax(const String& pattern, const String& flags)
 {
     SyntaxChecker syntaxChecker;
-    return parse(syntaxChecker, pattern, flags.contains('u'));
+
+    auto parsedFlags = parseFlags(flags);
+    if (!parsedFlags)
+        return ErrorCode::InvalidRegularExpressionFlags;
+
+    return parse(syntaxChecker, pattern, parsedFlags->contains(Flags::Unicode));
 }
 
 }} // JSC::Yarr
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index f61f393..4cc0b62 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,14 @@
+2019-03-10  Ross Kirsling  <ross.kirsling@sony.com>
+
+        Invalid flags in a RegExp literal should be an early SyntaxError
+        https://bugs.webkit.org/show_bug.cgi?id=195514
+
+        Reviewed by Darin Adler.
+
+        * bindings/js/SerializedScriptValue.cpp:
+        (WebCore::CloneDeserializer::readTerminal):
+        Consume YarrFlags.
+
 2019-03-10  Tim Horton  <timothy_horton@apple.com>
 
         Add SPI to retrieve the set of text inputs in a given rect, and later focus one
diff --git a/Source/WebCore/bindings/js/SerializedScriptValue.cpp b/Source/WebCore/bindings/js/SerializedScriptValue.cpp
index d5e191f..776ec43 100644
--- a/Source/WebCore/bindings/js/SerializedScriptValue.cpp
+++ b/Source/WebCore/bindings/js/SerializedScriptValue.cpp
@@ -56,7 +56,6 @@
 #include "SharedBuffer.h"
 #include "WebCoreJSClientData.h"
 #include <JavaScriptCore/APICast.h>
-#include <JavaScriptCore/ArrayBuffer.h>
 #include <JavaScriptCore/BooleanObject.h>
 #include <JavaScriptCore/CatchScope.h>
 #include <JavaScriptCore/DateInstance.h>
@@ -81,6 +80,7 @@
 #include <JavaScriptCore/TypedArrayInlines.h>
 #include <JavaScriptCore/TypedArrays.h>
 #include <JavaScriptCore/WasmModule.h>
+#include <JavaScriptCore/YarrFlags.h>
 #include <limits>
 #include <wtf/MainThread.h>
 #include <wtf/RunLoop.h>
@@ -2891,10 +2891,10 @@
             CachedStringRef flags;
             if (!readStringData(flags))
                 return JSValue();
-            RegExpFlags reFlags = regExpFlags(flags->string());
-            ASSERT(reFlags != InvalidFlags);
+            auto reFlags = Yarr::parseFlags(flags->string());
+            ASSERT(reFlags.hasValue());
             VM& vm = m_exec->vm();
-            RegExp* regExp = RegExp::create(vm, pattern->string(), reFlags);
+            RegExp* regExp = RegExp::create(vm, pattern->string(), reFlags.value());
             return RegExpObject::create(vm, m_globalObject->regExpStructure(), regExp);
         }
         case ObjectReferenceTag: {