<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[225695] trunk/Source/JavaScriptCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/225695">225695</a></dd>
<dt>Author</dt> <dd>msaboff@apple.com</dd>
<dt>Date</dt> <dd>2017-12-08 12:32:42 -0800 (Fri, 08 Dec 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>YARR: JIT RegExps with greedy parenthesized sub patterns
https://bugs.webkit.org/show_bug.cgi?id=180538

Reviewed by JF Bastien.

This patch adds JIT support for regular expressions containing greedy counted
parenthesis.  An example expression that couldn't be JIT'ed before is /q(a|b)*q/.

Just like in the interpreter, expressions with nested parenthetical subpatterns
require saving the results of previous matches of the parentheses contents along
with any associated state.  This saved state is needed in the case that we need
to backtrack.  This state is called ParenContext within the code space allocated
for this ParenContext is managed using a simple block allocator within the JIT'ed
code.  The raw space managed by this allocator is passed into the JIT'ed function.

Since this fixed sized space may be exceeded, this patch adds a fallback mechanism.
If the JIT'ed code exhausts all its ParenContext space, it returns a new error
JSRegExpJITCodeFailure.  The caller will then bytecompile and interpret the
expression.

Due to increased register usage by the parenthesis handling code, the use of
registers by the JIT engine was restructured, with registers used for Unicode
pattern matching replaced with constants.

Reworked some of the context structures that are used across the interpreter
and JIT implementations to make them a little more uniform and to handle the
needs of JIT'ing the new parentheses forms.

To help with development and debugging of this code, compiled patterns dumping
code was enhanced.  Also added the ability to also dump interpreter ByteCodes.

* runtime/RegExp.cpp:
(JSC::byteCodeCompilePattern):
(JSC::RegExp::byteCodeCompileIfNecessary):
(JSC::RegExp::compile):
(JSC::RegExp::compileMatchOnly):
* runtime/RegExp.h:
* runtime/RegExpInlines.h:
(JSC::RegExp::matchInline):
* testRegExp.cpp:
(parseRegExpLine):
(runFromFiles):
* yarr/Yarr.h:
* yarr/YarrInterpreter.cpp:
(JSC::Yarr::ByteCompiler::compile):
(JSC::Yarr::ByteCompiler::dumpDisjunction):
* yarr/YarrJIT.cpp:
(JSC::Yarr::YarrGenerator::ParenContextSizes::ParenContextSizes):
(JSC::Yarr::YarrGenerator::ParenContextSizes::numSubpatterns):
(JSC::Yarr::YarrGenerator::ParenContextSizes::frameSlots):
(JSC::Yarr::YarrGenerator::ParenContext::sizeFor):
(JSC::Yarr::YarrGenerator::ParenContext::nextOffset):
(JSC::Yarr::YarrGenerator::ParenContext::beginOffset):
(JSC::Yarr::YarrGenerator::ParenContext::matchAmountOffset):
(JSC::Yarr::YarrGenerator::ParenContext::subpatternOffset):
(JSC::Yarr::YarrGenerator::ParenContext::savedFrameOffset):
(JSC::Yarr::YarrGenerator::initParenContextFreeList):
(JSC::Yarr::YarrGenerator::allocatePatternContext):
(JSC::Yarr::YarrGenerator::freePatternContext):
(JSC::Yarr::YarrGenerator::savePatternContext):
(JSC::Yarr::YarrGenerator::restorePatternContext):
(JSC::Yarr::YarrGenerator::tryReadUnicodeCharImpl):
(JSC::Yarr::YarrGenerator::storeToFrame):
(JSC::Yarr::YarrGenerator::generateJITFailReturn):
(JSC::Yarr::YarrGenerator::clearMatches):
(JSC::Yarr::YarrGenerator::generate):
(JSC::Yarr::YarrGenerator::backtrack):
(JSC::Yarr::YarrGenerator::opCompileParenthesesSubpattern):
(JSC::Yarr::YarrGenerator::generateEnter):
(JSC::Yarr::YarrGenerator::generateReturn):
(JSC::Yarr::YarrGenerator::YarrGenerator):
(JSC::Yarr::YarrGenerator::compile):
* yarr/YarrJIT.h:
(JSC::Yarr::YarrCodeBlock::execute):
* yarr/YarrPattern.cpp:
(JSC::Yarr::indentForNestingLevel):
(JSC::Yarr::dumpUChar32):
(JSC::Yarr::dumpCharacterClass):
(JSC::Yarr::PatternTerm::dump):
(JSC::Yarr::YarrPattern::dumpPattern):
* yarr/YarrPattern.h:
(JSC::Yarr::PatternTerm::containsAnyCaptures):
(JSC::Yarr::BackTrackInfoParenthesesOnce::returnAddressIndex):
(JSC::Yarr::BackTrackInfoParentheses::beginIndex):
(JSC::Yarr::BackTrackInfoParentheses::returnAddressIndex):
(JSC::Yarr::BackTrackInfoParentheses::matchAmountIndex):
(JSC::Yarr::BackTrackInfoParentheses::patternContextHeadIndex):
(JSC::Yarr::BackTrackInfoAlternative::offsetIndex): Deleted.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeRegExpcpp">trunk/Source/JavaScriptCore/runtime/RegExp.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeRegExph">trunk/Source/JavaScriptCore/runtime/RegExp.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeRegExpInlinesh">trunk/Source/JavaScriptCore/runtime/RegExpInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoretestRegExpcpp">trunk/Source/JavaScriptCore/testRegExp.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreyarrYarrh">trunk/Source/JavaScriptCore/yarr/Yarr.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreyarrYarrInterpretercpp">trunk/Source/JavaScriptCore/yarr/YarrInterpreter.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreyarrYarrJITcpp">trunk/Source/JavaScriptCore/yarr/YarrJIT.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreyarrYarrJITh">trunk/Source/JavaScriptCore/yarr/YarrJIT.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreyarrYarrPatterncpp">trunk/Source/JavaScriptCore/yarr/YarrPattern.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreyarrYarrPatternh">trunk/Source/JavaScriptCore/yarr/YarrPattern.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (225694 => 225695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog    2017-12-08 20:32:20 UTC (rev 225694)
+++ trunk/Source/JavaScriptCore/ChangeLog       2017-12-08 20:32:42 UTC (rev 225695)
</span><span class="lines">@@ -1,3 +1,94 @@
</span><ins>+2017-12-08  Michael Saboff  <msaboff@apple.com>
+
+        YARR: JIT RegExps with greedy parenthesized sub patterns
+        https://bugs.webkit.org/show_bug.cgi?id=180538
+
+        Reviewed by JF Bastien.
+
+        This patch adds JIT support for regular expressions containing greedy counted
+        parenthesis.  An example expression that couldn't be JIT'ed before is /q(a|b)*q/.
+
+        Just like in the interpreter, expressions with nested parenthetical subpatterns
+        require saving the results of previous matches of the parentheses contents along
+        with any associated state.  This saved state is needed in the case that we need
+        to backtrack.  This state is called ParenContext within the code space allocated
+        for this ParenContext is managed using a simple block allocator within the JIT'ed
+        code.  The raw space managed by this allocator is passed into the JIT'ed function.
+
+        Since this fixed sized space may be exceeded, this patch adds a fallback mechanism.
+        If the JIT'ed code exhausts all its ParenContext space, it returns a new error
+        JSRegExpJITCodeFailure.  The caller will then bytecompile and interpret the
+        expression.
+
+        Due to increased register usage by the parenthesis handling code, the use of
+        registers by the JIT engine was restructured, with registers used for Unicode
+        pattern matching replaced with constants.
+
+        Reworked some of the context structures that are used across the interpreter
+        and JIT implementations to make them a little more uniform and to handle the
+        needs of JIT'ing the new parentheses forms.
+
+        To help with development and debugging of this code, compiled patterns dumping
+        code was enhanced.  Also added the ability to also dump interpreter ByteCodes.
+
+        * runtime/RegExp.cpp:
+        (JSC::byteCodeCompilePattern):
+        (JSC::RegExp::byteCodeCompileIfNecessary):
+        (JSC::RegExp::compile):
+        (JSC::RegExp::compileMatchOnly):
+        * runtime/RegExp.h:
+        * runtime/RegExpInlines.h:
+        (JSC::RegExp::matchInline):
+        * testRegExp.cpp:
+        (parseRegExpLine):
+        (runFromFiles):
+        * yarr/Yarr.h:
+        * yarr/YarrInterpreter.cpp:
+        (JSC::Yarr::ByteCompiler::compile):
+        (JSC::Yarr::ByteCompiler::dumpDisjunction):
+        * yarr/YarrJIT.cpp:
+        (JSC::Yarr::YarrGenerator::ParenContextSizes::ParenContextSizes):
+        (JSC::Yarr::YarrGenerator::ParenContextSizes::numSubpatterns):
+        (JSC::Yarr::YarrGenerator::ParenContextSizes::frameSlots):
+        (JSC::Yarr::YarrGenerator::ParenContext::sizeFor):
+        (JSC::Yarr::YarrGenerator::ParenContext::nextOffset):
+        (JSC::Yarr::YarrGenerator::ParenContext::beginOffset):
+        (JSC::Yarr::YarrGenerator::ParenContext::matchAmountOffset):
+        (JSC::Yarr::YarrGenerator::ParenContext::subpatternOffset):
+        (JSC::Yarr::YarrGenerator::ParenContext::savedFrameOffset):
+        (JSC::Yarr::YarrGenerator::initParenContextFreeList):
+        (JSC::Yarr::YarrGenerator::allocatePatternContext):
+        (JSC::Yarr::YarrGenerator::freePatternContext):
+        (JSC::Yarr::YarrGenerator::savePatternContext):
+        (JSC::Yarr::YarrGenerator::restorePatternContext):
+        (JSC::Yarr::YarrGenerator::tryReadUnicodeCharImpl):
+        (JSC::Yarr::YarrGenerator::storeToFrame):
+        (JSC::Yarr::YarrGenerator::generateJITFailReturn):
+        (JSC::Yarr::YarrGenerator::clearMatches):
+        (JSC::Yarr::YarrGenerator::generate):
+        (JSC::Yarr::YarrGenerator::backtrack):
+        (JSC::Yarr::YarrGenerator::opCompileParenthesesSubpattern):
+        (JSC::Yarr::YarrGenerator::generateEnter):
+        (JSC::Yarr::YarrGenerator::generateReturn):
+        (JSC::Yarr::YarrGenerator::YarrGenerator):
+        (JSC::Yarr::YarrGenerator::compile):
+        * yarr/YarrJIT.h:
+        (JSC::Yarr::YarrCodeBlock::execute):
+        * yarr/YarrPattern.cpp:
+        (JSC::Yarr::indentForNestingLevel):
+        (JSC::Yarr::dumpUChar32):
+        (JSC::Yarr::dumpCharacterClass):
+        (JSC::Yarr::PatternTerm::dump):
+        (JSC::Yarr::YarrPattern::dumpPattern):
+        * yarr/YarrPattern.h:
+        (JSC::Yarr::PatternTerm::containsAnyCaptures):
+        (JSC::Yarr::BackTrackInfoParenthesesOnce::returnAddressIndex):
+        (JSC::Yarr::BackTrackInfoParentheses::beginIndex):
+        (JSC::Yarr::BackTrackInfoParentheses::returnAddressIndex):
+        (JSC::Yarr::BackTrackInfoParentheses::matchAmountIndex):
+        (JSC::Yarr::BackTrackInfoParentheses::patternContextHeadIndex):
+        (JSC::Yarr::BackTrackInfoAlternative::offsetIndex): Deleted.
+
</ins><span class="cx"> 2017-12-08  Joseph Pecoraro  <pecoraro@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Web Inspector: CRASH at InspectorConsoleAgent::enable when iterating mutable list of buffered console messages
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeRegExpcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/RegExp.cpp (225694 => 225695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/RegExp.cpp   2017-12-08 20:32:20 UTC (rev 225694)
+++ trunk/Source/JavaScriptCore/runtime/RegExp.cpp      2017-12-08 20:32:42 UTC (rev 225695)
</span><span class="lines">@@ -271,6 +271,30 @@
</span><span class="cx">     return vm.regExpCache()->lookupOrCreate(patternString, flags);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+
+static std::unique_ptr<Yarr::BytecodePattern> byteCodeCompilePattern(VM* vm, Yarr::YarrPattern& pattern)
+{
+    return Yarr::byteCompile(pattern, &vm->m_regExpAllocator, &vm->m_regExpAllocatorLock);
+}
+
+void RegExp::byteCodeCompileIfNecessary(VM* vm)
+{
+    if (m_regExpBytecode)
+        return;
+
+    Yarr::YarrPattern pattern(m_patternString, m_flags, &m_constructionError, vm->stackLimit());
+    if (m_constructionError) {
+        RELEASE_ASSERT_NOT_REACHED();
+#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE)
+        m_state = ParseError;
+        return;
+#endif
+    }
+    ASSERT(m_numSubpatterns == pattern.m_numSubpatterns);
+
+    m_regExpBytecode = byteCodeCompilePattern(vm, pattern);
+}
+
</ins><span class="cx"> void RegExp::compile(VM* vm, Yarr::YarrCharSize charSize)
</span><span class="cx"> {
</span><span class="cx">     ConcurrentJSLocker locker(m_lock);
</span><span class="lines">@@ -303,8 +327,11 @@
</span><span class="cx">     UNUSED_PARAM(charSize);
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+    if (Options::dumpCompiledRegExpPatterns())
+        dataLog("Can't JIT this regular expression: \"", m_patternString, "\"\n");
+
</ins><span class="cx">     m_state = ByteCode;
</span><del>-    m_regExpBytecode = Yarr::byteCompile(pattern, &vm->m_regExpAllocator, &vm->m_regExpAllocatorLock);
</del><ins>+    m_regExpBytecode = byteCodeCompilePattern(vm, pattern);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> int RegExp::match(VM& vm, const String& s, unsigned startOffset, Vector<int>& ovector)
</span><span class="lines">@@ -356,8 +383,11 @@
</span><span class="cx">     UNUSED_PARAM(charSize);
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+    if (Options::dumpCompiledRegExpPatterns())
+        dataLog("Can't JIT this regular expression: \"", m_patternString, "\"\n");
+
</ins><span class="cx">     m_state = ByteCode;
</span><del>-    m_regExpBytecode = Yarr::byteCompile(pattern, &vm->m_regExpAllocator, &vm->m_regExpAllocatorLock);
</del><ins>+    m_regExpBytecode = byteCodeCompilePattern(vm, pattern);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> MatchResult RegExp::match(VM& vm, const String& s, unsigned startOffset)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeRegExph"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/RegExp.h (225694 => 225695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/RegExp.h     2017-12-08 20:32:20 UTC (rev 225694)
+++ trunk/Source/JavaScriptCore/runtime/RegExp.h        2017-12-08 20:32:42 UTC (rev 225695)
</span><span class="lines">@@ -140,6 +140,8 @@
</span><span class="cx"> 
</span><span class="cx">     RegExpState m_state;
</span><span class="cx"> 
</span><ins>+    void byteCodeCompileIfNecessary(VM*);
+
</ins><span class="cx">     void compile(VM*, Yarr::YarrCharSize);
</span><span class="cx">     void compileIfNecessary(VM&, Yarr::YarrCharSize);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeRegExpInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/RegExpInlines.h (225694 => 225695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/RegExpInlines.h      2017-12-08 20:32:20 UTC (rev 225694)
+++ trunk/Source/JavaScriptCore/runtime/RegExpInlines.h 2017-12-08 20:32:42 UTC (rev 225695)
</span><span class="lines">@@ -110,11 +110,25 @@
</span><span class="cx"> 
</span><span class="cx">     int result;
</span><span class="cx"> #if ENABLE(YARR_JIT)
</span><ins>+#ifdef JIT_ALL_PARENS_EXPRESSIONS
+    char patternContextBuffer[patternContextBufferSize];
+#define EXTRA_JIT_PARAMS  , patternContextBuffer, patternContextBufferSize
+#else
+#define EXTRA_JIT_PARAMS
+#endif
+
</ins><span class="cx">     if (m_state == JITCode) {
</span><span class="cx">         if (s.is8Bit())
</span><del>-            result = m_regExpJITCode.execute(s.characters8(), startOffset, s.length(), offsetVector).start;
</del><ins>+            result = m_regExpJITCode.execute(s.characters8(), startOffset, s.length(), offsetVector EXTRA_JIT_PARAMS).start;
</ins><span class="cx">         else
</span><del>-            result = m_regExpJITCode.execute(s.characters16(), startOffset, s.length(), offsetVector).start;
</del><ins>+            result = m_regExpJITCode.execute(s.characters16(), startOffset, s.length(), offsetVector EXTRA_JIT_PARAMS).start;
+
+        if (result == Yarr::JSRegExpJITCodeFailure) {
+            // JIT'ed code couldn't handle expression, so punt back to the interpreter.
+            byteCodeCompileIfNecessary(&vm);
+            result = Yarr::interpret(m_regExpBytecode.get(), s, startOffset, reinterpret_cast<unsigned*>(offsetVector));
+        }
+
</ins><span class="cx"> #if ENABLE(YARR_JIT_DEBUG)
</span><span class="cx">         matchCompareWithInterpreter(s, startOffset, offsetVector, result);
</span><span class="cx"> #endif
</span><span class="lines">@@ -199,15 +213,30 @@
</span><span class="cx">     compileIfNecessaryMatchOnly(vm, s.is8Bit() ? Yarr::Char8 : Yarr::Char16);
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(YARR_JIT)
</span><ins>+#ifdef JIT_ALL_PARENS_EXPRESSIONS
+    char patternContextBuffer[patternContextBufferSize];
+#define EXTRA_JIT_PARAMS  , patternContextBuffer, patternContextBufferSize
+#else
+#define EXTRA_JIT_PARAMS
+#endif
+
+    MatchResult result;
+
</ins><span class="cx">     if (m_state == JITCode) {
</span><del>-        MatchResult result = s.is8Bit() ?
-            m_regExpJITCode.execute(s.characters8(), startOffset, s.length()) :
-            m_regExpJITCode.execute(s.characters16(), startOffset, s.length());
</del><ins>+        if (s.is8Bit())
+            result = m_regExpJITCode.execute(s.characters8(), startOffset, s.length() EXTRA_JIT_PARAMS);
+        else
+            result = m_regExpJITCode.execute(s.characters16(), startOffset, s.length() EXTRA_JIT_PARAMS);
+
</ins><span class="cx"> #if ENABLE(REGEXP_TRACING)
</span><span class="cx">         if (!result)
</span><span class="cx">             m_rtMatchOnlyFoundCount++;
</span><span class="cx"> #endif
</span><del>-        return result;
</del><ins>+        if (result.start != static_cast<size_t>(Yarr::JSRegExpJITCodeFailure))
+            return result;
+
+        // JIT'ed code couldn't handle expression, so punt back to the interpreter.
+        byteCodeCompileIfNecessary(&vm);
</ins><span class="cx">     }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestRegExpcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/testRegExp.cpp (225694 => 225695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/testRegExp.cpp       2017-12-08 20:32:20 UTC (rev 225694)
+++ trunk/Source/JavaScriptCore/testRegExp.cpp  2017-12-08 20:32:42 UTC (rev 225695)
</span><span class="lines">@@ -315,10 +315,10 @@
</span><span class="cx">     return -1;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static RegExp* parseRegExpLine(VM& vm, char* line, int lineLength)
</del><ins>+static RegExp* parseRegExpLine(VM& vm, char* line, int lineLength, const char** regexpError)
</ins><span class="cx"> {
</span><span class="cx">     StringBuilder pattern;
</span><del>-    
</del><ins>+
</ins><span class="cx">     if (line[0] != '/')
</span><span class="cx">         return 0;
</span><span class="cx"> 
</span><span class="lines">@@ -330,9 +330,11 @@
</span><span class="cx">     ++i;
</span><span class="cx"> 
</span><span class="cx">     RegExp* r = RegExp::create(vm, pattern.toString(), regExpFlags(line + i));
</span><del>-    if (r->isValid())
-        return r;
-    return nullptr;
</del><ins>+    if (!r->isValid()) {
+        *regexpError = r->errorMessage();
+        return nullptr;
+    }
+    return r;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static RegExpTest* parseTestLine(char* line, int lineLength)
</span><span class="lines">@@ -431,6 +433,7 @@
</span><span class="cx">         size_t lineLength = 0;
</span><span class="cx">         char* linePtr = 0;
</span><span class="cx">         unsigned int lineNumber = 0;
</span><ins>+        const char* regexpError = nullptr;
</ins><span class="cx"> 
</span><span class="cx">         while ((linePtr = fgets(&lineBuffer[0], MaxLineLength, testCasesFile))) {
</span><span class="cx">             lineLength = strlen(linePtr);
</span><span class="lines">@@ -444,7 +447,11 @@
</span><span class="cx">                 continue;
</span><span class="cx"> 
</span><span class="cx">             if (linePtr[0] == '/') {
</span><del>-                regexp = parseRegExpLine(vm, linePtr, lineLength);
</del><ins>+                regexp = parseRegExpLine(vm, linePtr, lineLength, &regexpError);
+                if (!regexp) {
+                    failures++;
+                    fprintf(stderr, "Failure on line %u. '%s' %s\n", lineNumber, linePtr, regexpError);
+                }
</ins><span class="cx">             } else if (linePtr[0] == ' ') {
</span><span class="cx">                 RegExpTest* regExpTest = parseTestLine(linePtr, lineLength);
</span><span class="cx">                 
</span><span class="lines">@@ -461,10 +468,10 @@
</span><span class="cx">             } else if (linePtr[0] == '-') {
</span><span class="cx">                 tests++;
</span><span class="cx">                 regexp = 0; // Reset the live regexp to avoid confusing other subsequent tests
</span><del>-                bool successfullyParsed = parseRegExpLine(vm, linePtr + 1, lineLength - 1);
</del><ins>+                bool successfullyParsed = parseRegExpLine(vm, linePtr + 1, lineLength - 1, &regexpError);
</ins><span class="cx">                 if (successfullyParsed) {
</span><span class="cx">                     failures++;
</span><del>-                    fprintf(stderr, "Failure on line %u. '%s' is not a valid regexp\n", lineNumber, linePtr + 1);
</del><ins>+                    fprintf(stderr, "Failure on line %u. '%s' %s\n", lineNumber, linePtr + 1, regexpError);
</ins><span class="cx">                 }
</span><span class="cx">             }
</span><span class="cx">         }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreyarrYarrh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/yarr/Yarr.h (225694 => 225695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/yarr/Yarr.h  2017-12-08 20:32:20 UTC (rev 225694)
+++ trunk/Source/JavaScriptCore/yarr/Yarr.h     2017-12-08 20:32:42 UTC (rev 225695)
</span><span class="lines">@@ -36,9 +36,9 @@
</span><span class="cx"> #define YarrStackSpaceForBackTrackInfoBackReference 2
</span><span class="cx"> #define YarrStackSpaceForBackTrackInfoAlternative 1 // One per alternative.
</span><span class="cx"> #define YarrStackSpaceForBackTrackInfoParentheticalAssertion 1
</span><del>-#define YarrStackSpaceForBackTrackInfoParenthesesOnce 1 // Only for !fixed quantifiers.
</del><ins>+#define YarrStackSpaceForBackTrackInfoParenthesesOnce 2
</ins><span class="cx"> #define YarrStackSpaceForBackTrackInfoParenthesesTerminal 1
</span><del>-#define YarrStackSpaceForBackTrackInfoParentheses 2
</del><ins>+#define YarrStackSpaceForBackTrackInfoParentheses 4
</ins><span class="cx"> #define YarrStackSpaceForDotStarEnclosure 1
</span><span class="cx"> 
</span><span class="cx"> static const unsigned quantifyInfinite = UINT_MAX;
</span><span class="lines">@@ -52,9 +52,10 @@
</span><span class="cx">     JSRegExpMatch = 1,
</span><span class="cx">     JSRegExpNoMatch = 0,
</span><span class="cx">     JSRegExpErrorNoMatch = -1,
</span><del>-    JSRegExpErrorHitLimit = -2,
-    JSRegExpErrorNoMemory = -3,
-    JSRegExpErrorInternal = -4
</del><ins>+    JSRegExpJITCodeFailure = -2,
+    JSRegExpErrorHitLimit = -3,
+    JSRegExpErrorNoMemory = -4,
+    JSRegExpErrorInternal = -5,
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> enum YarrCharSize {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreyarrYarrInterpretercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/yarr/YarrInterpreter.cpp (225694 => 225695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/yarr/YarrInterpreter.cpp     2017-12-08 20:32:20 UTC (rev 225694)
+++ trunk/Source/JavaScriptCore/yarr/YarrInterpreter.cpp        2017-12-08 20:32:42 UTC (rev 225695)
</span><span class="lines">@@ -27,6 +27,7 @@
</span><span class="cx"> #include "config.h"
</span><span class="cx"> #include "YarrInterpreter.h"
</span><span class="cx"> 
</span><ins>+#include "Options.h"
</ins><span class="cx"> #include "SuperSampler.h"
</span><span class="cx"> #include "Yarr.h"
</span><span class="cx"> #include "YarrCanonicalize.h"
</span><span class="lines">@@ -1669,6 +1670,11 @@
</span><span class="cx">         emitDisjunction(m_pattern.m_body);
</span><span class="cx">         regexEnd();
</span><span class="cx"> 
</span><ins>+#ifndef NDEBUG
+        if (Options::dumpCompiledRegExpPatterns())
+            dumpDisjunction(m_bodyDisjunction.get());
+#endif
+
</ins><span class="cx">         return std::make_unique<BytecodePattern>(WTFMove(m_bodyDisjunction), m_allParenthesesInfo, m_pattern, allocator, lock);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -1829,16 +1835,6 @@
</span><span class="cx">         return beginTerm;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-#ifndef NDEBUG
-    void dumpDisjunction(ByteDisjunction* disjunction)
-    {
-        dataLogF("ByteDisjunction(%p):\n\t", disjunction);
-        for (unsigned i = 0; i < disjunction->terms.size(); ++i)
-            dataLogF("{ %d } ", disjunction->terms[i].type);
-        dataLogF("\n");
-    }
-#endif
-
</del><span class="cx">     void closeAlternative(int beginTerm)
</span><span class="cx">     {
</span><span class="cx">         int origBeginTerm = beginTerm;
</span><span class="lines">@@ -2111,7 +2107,245 @@
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">     }
</span><ins>+#ifndef NDEBUG
+    void dumpDisjunction(ByteDisjunction* disjunction, unsigned nesting = 0)
+    {
+        PrintStream& out = WTF::dataFile();
</ins><span class="cx"> 
</span><ins>+        unsigned termIndexNest = 0;
+
+        if (!nesting) {
+            out.printf("ByteDisjunction(%p):\n", disjunction);
+            nesting = 1;
+        } else {
+            termIndexNest = nesting - 1;
+            nesting = 2;
+        }
+
+        auto outputTermIndexAndNest = [&](size_t index, unsigned termNesting) {
+            for (unsigned nestingDepth = 0; nestingDepth < termIndexNest; nestingDepth++)
+                out.print("  ");
+            out.printf("%4lu", index);
+            for (unsigned nestingDepth = 0; nestingDepth < termNesting; nestingDepth++)
+                out.print("  ");
+        };
+
+        auto dumpQuantity = [&](ByteTerm& term) {
+            if (term.atom.quantityType == QuantifierFixedCount && term.atom.quantityMinCount == 1 && term.atom.quantityMaxCount == 1)
+                return;
+
+            out.print(" {", term.atom.quantityMinCount);
+            if (term.atom.quantityMinCount != term.atom.quantityMaxCount) {
+                if (term.atom.quantityMaxCount == UINT_MAX)
+                    out.print(",inf");
+                else
+                    out.print(",", term.atom.quantityMaxCount);
+            }
+            out.print("}");
+            if (term.atom.quantityType == QuantifierGreedy)
+                out.print(" greedy");
+            else if (term.atom.quantityType == QuantifierNonGreedy)
+                out.print(" non-greedy");
+        };
+
+        auto dumpCaptured = [&](ByteTerm& term) {
+            if (term.capture())
+                out.print(" captured (#", term.atom.subpatternId, ")");
+        };
+
+        auto dumpInverted = [&](ByteTerm& term) {
+            if (term.invert())
+                out.print(" inverted");
+        };
+
+        auto dumpInputPosition = [&](ByteTerm& term) {
+            out.printf(" inputPosition %u", term.inputPosition);
+        };
+
+        auto dumpCharacter = [&](ByteTerm& term) {
+            out.print(" ");
+            dumpUChar32(out, term.atom.patternCharacter);
+        };
+
+        auto dumpCharClass = [&](ByteTerm& term) {
+            out.print(" ");
+            dumpCharacterClass(out, &m_pattern, term.atom.characterClass);
+        };
+
+        for (size_t idx = 0; idx < disjunction->terms.size(); ++idx) {
+            ByteTerm term = disjunction->terms[idx];
+
+            bool outputNewline = true;
+
+            switch (term.type) {
+            case ByteTerm::TypeBodyAlternativeBegin:
+                outputTermIndexAndNest(idx, nesting++);
+                out.print("BodyAlternativeBegin");
+                if (term.alternative.onceThrough)
+                    out.print(" onceThrough");
+                break;
+            case ByteTerm::TypeBodyAlternativeDisjunction:
+                outputTermIndexAndNest(idx, nesting - 1);
+                out.print("BodyAlternativeDisjunction");
+                break;
+            case ByteTerm::TypeBodyAlternativeEnd:
+                outputTermIndexAndNest(idx, --nesting);
+                out.print("BodyAlternativeEnd");
+                break;
+            case ByteTerm::TypeAlternativeBegin:
+                outputTermIndexAndNest(idx, nesting++);
+                out.print("AlternativeBegin");
+                break;
+            case ByteTerm::TypeAlternativeDisjunction:
+                outputTermIndexAndNest(idx, nesting - 1);
+                out.print("AlternativeDisjunction");
+                break;
+            case ByteTerm::TypeAlternativeEnd:
+                outputTermIndexAndNest(idx, --nesting);
+                out.print("AlternativeEnd");
+                break;
+            case ByteTerm::TypeSubpatternBegin:
+                outputTermIndexAndNest(idx, nesting++);
+                out.print("SubpatternBegin");
+                break;
+            case ByteTerm::TypeSubpatternEnd:
+                outputTermIndexAndNest(idx, --nesting);
+                out.print("SubpatternEnd");
+                break;
+            case ByteTerm::TypeAssertionBOL:
+                outputTermIndexAndNest(idx, nesting);
+                out.print("AssertionBOL");
+                break;
+            case ByteTerm::TypeAssertionEOL:
+                outputTermIndexAndNest(idx, nesting);
+                out.print("AssertionEOL");
+                break;
+            case ByteTerm::TypeAssertionWordBoundary:
+                outputTermIndexAndNest(idx, nesting);
+                out.print("AssertionWordBoundary");
+                break;
+            case ByteTerm::TypePatternCharacterOnce:
+                outputTermIndexAndNest(idx, nesting);
+                out.print("PatternCharacterOnce");
+                dumpInverted(term);
+                dumpInputPosition(term);
+                dumpCharacter(term);
+                dumpQuantity(term);
+                break;
+            case ByteTerm::TypePatternCharacterFixed:
+                outputTermIndexAndNest(idx, nesting);
+                out.print("PatternCharacterFixed");
+                dumpInverted(term);
+                dumpInputPosition(term);
+                dumpCharacter(term);
+                out.print(" {", term.atom.quantityMinCount, "}");
+                break;
+            case ByteTerm::TypePatternCharacterGreedy:
+                outputTermIndexAndNest(idx, nesting);
+                out.print("PatternCharacterGreedy");
+                dumpInverted(term);
+                dumpInputPosition(term);
+                dumpCharacter(term);
+                dumpQuantity(term);
+                break;
+            case ByteTerm::TypePatternCharacterNonGreedy:
+                outputTermIndexAndNest(idx, nesting);
+                out.print("PatternCharacterNonGreedy");
+                dumpInverted(term);
+                dumpInputPosition(term);
+                dumpCharacter(term);
+                dumpQuantity(term);
+                break;
+            case ByteTerm::TypePatternCasedCharacterOnce:
+                outputTermIndexAndNest(idx, nesting);
+                out.print("PatternCasedCharacterOnce");
+                break;
+            case ByteTerm::TypePatternCasedCharacterFixed:
+                outputTermIndexAndNest(idx, nesting);
+                out.print("PatternCasedCharacterFixed");
+                break;
+            case ByteTerm::TypePatternCasedCharacterGreedy:
+                outputTermIndexAndNest(idx, nesting);
+                out.print("PatternCasedCharacterGreedy");
+                break;
+            case ByteTerm::TypePatternCasedCharacterNonGreedy:
+                outputTermIndexAndNest(idx, nesting);
+                out.print("PatternCasedCharacterNonGreedy");
+                break;
+            case ByteTerm::TypeCharacterClass:
+                outputTermIndexAndNest(idx, nesting);
+                out.print("CharacterClass");
+                dumpInverted(term);
+                dumpInputPosition(term);
+                dumpCharClass(term);
+                dumpQuantity(term);
+                break;
+            case ByteTerm::TypeBackReference:
+                outputTermIndexAndNest(idx, nesting);
+                out.print("BackReference #", term.atom.subpatternId);
+                dumpQuantity(term);
+                break;
+            case ByteTerm::TypeParenthesesSubpattern:
+                outputTermIndexAndNest(idx, nesting);
+                out.print("ParenthesesSubpattern");
+                dumpCaptured(term);
+                dumpInverted(term);
+                dumpInputPosition(term);
+                dumpQuantity(term);
+                out.print("\n");
+                outputNewline = false;
+                dumpDisjunction(term.atom.parenthesesDisjunction, nesting);
+                break;
+            case ByteTerm::TypeParenthesesSubpatternOnceBegin:
+                outputTermIndexAndNest(idx, nesting++);
+                out.print("ParenthesesSubpatternOnceBegin");
+                dumpCaptured(term);
+                dumpInverted(term);
+                dumpInputPosition(term);
+                break;
+            case ByteTerm::TypeParenthesesSubpatternOnceEnd:
+                outputTermIndexAndNest(idx, --nesting);
+                out.print("ParenthesesSubpatternOnceEnd");
+                break;
+            case ByteTerm::TypeParenthesesSubpatternTerminalBegin:
+                outputTermIndexAndNest(idx, nesting++);
+                out.print("ParenthesesSubpatternTerminalBegin");
+                dumpInverted(term);
+                dumpInputPosition(term);
+                break;
+            case ByteTerm::TypeParenthesesSubpatternTerminalEnd:
+                outputTermIndexAndNest(idx, --nesting);
+                out.print("ParenthesesSubpatternTerminalEnd");
+                break;
+            case ByteTerm::TypeParentheticalAssertionBegin:
+                outputTermIndexAndNest(idx, nesting++);
+                out.print("ParentheticalAssertionBegin");
+                dumpInverted(term);
+                dumpInputPosition(term);
+                break;
+            case ByteTerm::TypeParentheticalAssertionEnd:
+                outputTermIndexAndNest(idx, --nesting);
+                out.print("ParentheticalAssertionEnd");
+                break;
+            case ByteTerm::TypeCheckInput:
+                outputTermIndexAndNest(idx, nesting);
+                out.print("CheckInput ", term.checkInputCount);
+                break;
+            case ByteTerm::TypeUncheckInput:
+                outputTermIndexAndNest(idx, nesting);
+                out.print("UncheckInput ", term.checkInputCount);
+                break;
+            case ByteTerm::TypeDotStarEnclosure:
+                outputTermIndexAndNest(idx, nesting);
+                out.print("DotStarEnclosure");
+                break;
+            }
+            if (outputNewline)
+                out.print("\n");
+        }
+    }
+#endif
+
</ins><span class="cx"> private:
</span><span class="cx">     YarrPattern& m_pattern;
</span><span class="cx">     std::unique_ptr<ByteDisjunction> m_bodyDisjunction;
</span><span class="lines">@@ -2152,7 +2386,7 @@
</span><span class="cx"> COMPILE_ASSERT(sizeof(BackTrackInfoAlternative) == (YarrStackSpaceForBackTrackInfoAlternative * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoAlternative);
</span><span class="cx"> COMPILE_ASSERT(sizeof(BackTrackInfoParentheticalAssertion) == (YarrStackSpaceForBackTrackInfoParentheticalAssertion * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParentheticalAssertion);
</span><span class="cx"> COMPILE_ASSERT(sizeof(BackTrackInfoParenthesesOnce) == (YarrStackSpaceForBackTrackInfoParenthesesOnce * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParenthesesOnce);
</span><del>-COMPILE_ASSERT(sizeof(Interpreter<UChar>::BackTrackInfoParentheses) == (YarrStackSpaceForBackTrackInfoParentheses * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParentheses);
</del><ins>+COMPILE_ASSERT(sizeof(Interpreter<UChar>::BackTrackInfoParentheses) <= (YarrStackSpaceForBackTrackInfoParentheses * sizeof(uintptr_t)), CheckYarrStackSpaceForBackTrackInfoParentheses);
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> } }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreyarrYarrJITcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/yarr/YarrJIT.cpp (225694 => 225695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/yarr/YarrJIT.cpp     2017-12-08 20:32:20 UTC (rev 225694)
+++ trunk/Source/JavaScriptCore/yarr/YarrJIT.cpp        2017-12-08 20:32:42 UTC (rev 225695)
</span><span class="lines">@@ -58,20 +58,25 @@
</span><span class="cx"> 
</span><span class="cx"> #define HAVE_INITIAL_START_REG
</span><span class="cx"> #elif CPU(ARM64)
</span><ins>+    // Argument registers
</ins><span class="cx">     static const RegisterID input = ARM64Registers::x0;
</span><span class="cx">     static const RegisterID index = ARM64Registers::x1;
</span><span class="cx">     static const RegisterID length = ARM64Registers::x2;
</span><span class="cx">     static const RegisterID output = ARM64Registers::x3;
</span><ins>+    static const RegisterID freelistRegister = ARM64Registers::x4;
+    static const RegisterID freelistSizeRegister = ARM64Registers::x5;
</ins><span class="cx"> 
</span><del>-    static const RegisterID regT0 = ARM64Registers::x4;
-    static const RegisterID regT1 = ARM64Registers::x5;
-    static const RegisterID regUnicodeInputAndTrail = ARM64Registers::x6;
-    static const RegisterID regUnicodeTemp = ARM64Registers::x7;
-    static const RegisterID initialStart = ARM64Registers::x8;
-    static const RegisterID supplementaryPlanesBase = ARM64Registers::x9;
-    static const RegisterID surrogateTagMask = ARM64Registers::x10;
-    static const RegisterID leadingSurrogateTag = ARM64Registers::x11;
-    static const RegisterID trailingSurrogateTag = ARM64Registers::x12;
</del><ins>+    // Scratch registers
+    static const RegisterID regT0 = ARM64Registers::x6;
+    static const RegisterID regT1 = ARM64Registers::x7;
+    static const RegisterID regT2 = ARM64Registers::x8;
+    static const RegisterID remainingMatchCount = ARM64Registers::x9;
+    static const RegisterID regUnicodeInputAndTrail = ARM64Registers::x10;
+    static const RegisterID initialStart = ARM64Registers::x11;
+    static const RegisterID supplementaryPlanesBase = ARM64Registers::x12;
+    static const RegisterID surrogateTagMask = ARM64Registers::x13;
+    static const RegisterID leadingSurrogateTag = ARM64Registers::x14;
+    static const RegisterID trailingSurrogateTag = ARM64Registers::x15;
</ins><span class="cx"> 
</span><span class="cx">     static const RegisterID returnRegister = ARM64Registers::x0;
</span><span class="cx">     static const RegisterID returnRegister2 = ARM64Registers::x1;
</span><span class="lines">@@ -105,10 +110,13 @@
</span><span class="cx">     static const RegisterID returnRegister2 = X86Registers::edx;
</span><span class="cx"> #elif CPU(X86_64)
</span><span class="cx"> #if !OS(WINDOWS)
</span><ins>+    // Argument registers
</ins><span class="cx">     static const RegisterID input = X86Registers::edi;
</span><span class="cx">     static const RegisterID index = X86Registers::esi;
</span><span class="cx">     static const RegisterID length = X86Registers::edx;
</span><span class="cx">     static const RegisterID output = X86Registers::ecx;
</span><ins>+    static const RegisterID freelistRegister = X86Registers::r8;
+    static const RegisterID freelistSizeRegister = X86Registers::r9; // Only used during initialization.
</ins><span class="cx"> #else
</span><span class="cx">     // If the return value doesn't fit in 64bits, its destination is pointed by rcx and the parameters are shifted.
</span><span class="cx">     // http://msdn.microsoft.com/en-us/library/7572ztz4.aspx
</span><span class="lines">@@ -119,23 +127,23 @@
</span><span class="cx">     static const RegisterID output = X86Registers::r10;
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+    // Scratch registers
</ins><span class="cx">     static const RegisterID regT0 = X86Registers::eax;
</span><span class="cx"> #if !OS(WINDOWS)
</span><del>-    static const RegisterID regT1 = X86Registers::r8;
</del><ins>+    static const RegisterID regT1 = X86Registers::r9;
+    static const RegisterID regT2 = X86Registers::r10;
</ins><span class="cx"> #else
</span><span class="cx">     static const RegisterID regT1 = X86Registers::ecx;
</span><ins>+    static const RegisterID regT2 = X86Registers::edi;
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx">     static const RegisterID initialStart = X86Registers::ebx;
</span><span class="cx"> #if !OS(WINDOWS)
</span><del>-    static const RegisterID regUnicodeInputAndTrail = X86Registers::r9;
-    static const RegisterID regUnicodeTemp = X86Registers::r10;
</del><ins>+    static const RegisterID remainingMatchCount = X86Registers::r12;
</ins><span class="cx"> #else
</span><del>-    static const RegisterID regUnicodeInputAndTrail = X86Registers::esi;
-    static const RegisterID regUnicodeTemp = X86Registers::edi;
</del><ins>+    static const RegisterID remainingMatchCount = X86Registers::esi;
</ins><span class="cx"> #endif
</span><del>-    static const RegisterID supplementaryPlanesBase = X86Registers::r12;
-    static const RegisterID surrogateTagMask = X86Registers::r13;
</del><ins>+    static const RegisterID regUnicodeInputAndTrail = X86Registers::r13;
</ins><span class="cx">     static const RegisterID leadingSurrogateTag = X86Registers::r14;
</span><span class="cx">     static const RegisterID trailingSurrogateTag = X86Registers::r15;
</span><span class="cx"> 
</span><span class="lines">@@ -142,10 +150,155 @@
</span><span class="cx">     static const RegisterID returnRegister = X86Registers::eax;
</span><span class="cx">     static const RegisterID returnRegister2 = X86Registers::edx;
</span><span class="cx"> 
</span><ins>+    const TrustedImm32 supplementaryPlanesBase = TrustedImm32(0x10000);
+    const TrustedImm32 surrogateTagMask = TrustedImm32(0xfffffc00);
</ins><span class="cx"> #define HAVE_INITIAL_START_REG
</span><span class="cx"> #define JIT_UNICODE_EXPRESSIONS
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+#ifdef JIT_ALL_PARENS_EXPRESSIONS
+    struct ParenContextSizes {
+        size_t m_numSubpatterns;
+        size_t m_frameSlots;
+
+        ParenContextSizes(size_t numSubpatterns, size_t frameSlots)
+            : m_numSubpatterns(numSubpatterns)
+            , m_frameSlots(frameSlots)
+        {
+        }
+
+        size_t numSubpatterns() { return m_numSubpatterns; }
+
+        size_t frameSlots() { return m_frameSlots; }
+    };
+
+    struct ParenContext {
+        struct ParenContext* next;
+        uint32_t begin;
+        uint32_t matchAmount;
+        struct Subpatterns {
+            unsigned start;
+            unsigned end;
+        } subpatterns[0];
+        uintptr_t frameSlots[0];
+
+        static size_t sizeFor(ParenContextSizes& parenContextSizes)
+        {
+            return sizeof(ParenContext) + sizeof(Subpatterns) * parenContextSizes.numSubpatterns() + sizeof(uintptr_t) * parenContextSizes.frameSlots();
+        }
+
+        static ptrdiff_t nextOffset()
+        {
+            return offsetof(ParenContext, next);
+        }
+
+        static ptrdiff_t beginOffset()
+        {
+            return offsetof(ParenContext, begin);
+        }
+
+        static ptrdiff_t matchAmountOffset()
+        {
+            return offsetof(ParenContext, matchAmount);
+        }
+
+        static ptrdiff_t subpatternOffset(size_t subpattern)
+        {
+            return offsetof(ParenContext, subpatterns) + (subpattern - 1) * sizeof(Subpatterns);
+        }
+
+        static ptrdiff_t savedFrameOffset(ParenContextSizes& parenContextSizes)
+        {
+            return offsetof(ParenContext, subpatterns) + (parenContextSizes.numSubpatterns()) * sizeof(Subpatterns);
+        }
+    };
+
+    void initParenContextFreeList()
+    {
+        RegisterID parenContextPointer = regT0;
+        RegisterID nextParenContextPointer = regT2;
+
+        size_t parenContextSize = ParenContext::sizeFor(m_parenContextSizes);
+
+        parenContextSize = WTF::roundUpToMultipleOf<sizeof(uintptr_t)>(parenContextSize);
+
+        // Check that the paren context is a reasonable size.
+        if (parenContextSize > INT16_MAX)
+            m_abortExecution.append(jump());
+
+        Jump emptyFreeList = branchTestPtr(Zero, freelistRegister);
+        move(freelistRegister, parenContextPointer);
+        addPtr(TrustedImm32(parenContextSize), freelistRegister, nextParenContextPointer);
+        addPtr(freelistRegister, freelistSizeRegister);
+        subPtr(TrustedImm32(parenContextSize), freelistSizeRegister);
+
+        Label loopTop(this);
+        Jump initDone = branchPtr(Above, nextParenContextPointer, freelistSizeRegister);
+        storePtr(nextParenContextPointer, Address(parenContextPointer, ParenContext::nextOffset()));
+        move(nextParenContextPointer, parenContextPointer);
+        addPtr(TrustedImm32(parenContextSize), parenContextPointer, nextParenContextPointer);
+        jump(loopTop);
+
+        initDone.link(this);
+        storePtr(TrustedImmPtr(0), Address(parenContextPointer, ParenContext::nextOffset()));
+        emptyFreeList.link(this);
+    }
+
+    void allocatePatternContext(RegisterID result)
+    {
+        m_abortExecution.append(branchTestPtr(Zero, freelistRegister));
+        sub32(TrustedImm32(1), remainingMatchCount);
+        m_hitMatchLimit.append(branchTestPtr(Zero, remainingMatchCount));
+        move(freelistRegister, result);
+        loadPtr(Address(freelistRegister, ParenContext::nextOffset()), freelistRegister);
+    }
+
+    void freePatternContext(RegisterID headPtrRegister, RegisterID newHeadPtrRegister)
+    {
+        loadPtr(Address(headPtrRegister, ParenContext::nextOffset()), newHeadPtrRegister);
+        storePtr(freelistRegister, Address(headPtrRegister, ParenContext::nextOffset()));
+        move(headPtrRegister, freelistRegister);
+    }
+
+    void savePatternContext(RegisterID patternContextReg, RegisterID tempReg, unsigned firstSubpattern, unsigned lastSubpattern, unsigned subpatternBaseFrameLocation)
+    {
+        store32(index, Address(patternContextReg, ParenContext::beginOffset()));
+        loadFromFrame(subpatternBaseFrameLocation + BackTrackInfoParentheses::matchAmountIndex(), tempReg);
+        store32(tempReg, Address(patternContextReg, ParenContext::matchAmountOffset()));
+        if (compileMode == IncludeSubpatterns) {
+            for (unsigned subpattern = firstSubpattern; subpattern <= lastSubpattern; subpattern++) {
+                loadPtr(Address(output, (subpattern << 1) * sizeof(unsigned)), tempReg);
+                storePtr(tempReg, Address(patternContextReg, ParenContext::subpatternOffset(subpattern)));
+                clearSubpatternStart(subpattern);
+            }
+        }
+        subpatternBaseFrameLocation += YarrStackSpaceForBackTrackInfoParentheses;
+        for (unsigned frameLocation = subpatternBaseFrameLocation; frameLocation < m_parenContextSizes.frameSlots(); frameLocation++) {
+            loadFromFrame(frameLocation, tempReg);
+            storePtr(tempReg, Address(patternContextReg, ParenContext::savedFrameOffset(m_parenContextSizes) + frameLocation * sizeof(uintptr_t)));
+        }
+    }
+
+    void restorePatternContext(RegisterID patternContextReg, RegisterID tempReg, unsigned firstSubpattern, unsigned lastSubpattern, unsigned subpatternBaseFrameLocation)
+    {
+        load32(Address(patternContextReg, ParenContext::beginOffset()), index);
+        storeToFrame(index, subpatternBaseFrameLocation + BackTrackInfoParentheses::beginIndex());
+        load32(Address(patternContextReg, ParenContext::matchAmountOffset()), tempReg);
+        storeToFrame(tempReg, subpatternBaseFrameLocation + BackTrackInfoParentheses::matchAmountIndex());
+        if (compileMode == IncludeSubpatterns) {
+            for (unsigned subpattern = firstSubpattern; subpattern <= lastSubpattern; subpattern++) {
+                loadPtr(Address(patternContextReg, ParenContext::subpatternOffset(subpattern)), tempReg);
+                storePtr(tempReg, Address(output, (subpattern << 1) * sizeof(unsigned)));
+            }
+        }
+        subpatternBaseFrameLocation += YarrStackSpaceForBackTrackInfoParentheses;
+        for (unsigned frameLocation = subpatternBaseFrameLocation; frameLocation < m_parenContextSizes.frameSlots(); frameLocation++) {
+            loadPtr(Address(patternContextReg, ParenContext::savedFrameOffset(m_parenContextSizes) + frameLocation * sizeof(uintptr_t)), tempReg);
+            storeToFrame(tempReg, frameLocation);
+        }
+    }
+#endif
+
</ins><span class="cx">     void optimizeAlternative(PatternAlternative* alternative)
</span><span class="cx">     {
</span><span class="cx">         if (!alternative->m_terms.size())
</span><span class="lines">@@ -354,14 +507,14 @@
</span><span class="cx"> 
</span><span class="cx">         JumpList notUnicode;
</span><span class="cx">         load16Unaligned(regUnicodeInputAndTrail, resultReg);
</span><del>-        and32(surrogateTagMask, resultReg, regUnicodeTemp);
-        notUnicode.append(branch32(NotEqual, regUnicodeTemp, leadingSurrogateTag));
</del><ins>+        and32(surrogateTagMask, resultReg, regT2);
+        notUnicode.append(branch32(NotEqual, regT2, leadingSurrogateTag));
</ins><span class="cx">         addPtr(TrustedImm32(2), regUnicodeInputAndTrail);
</span><del>-        getEffectiveAddress(BaseIndex(input, length, TimesTwo), regUnicodeTemp);
-        notUnicode.append(branchPtr(AboveOrEqual, regUnicodeInputAndTrail, regUnicodeTemp));
</del><ins>+        getEffectiveAddress(BaseIndex(input, length, TimesTwo), regT2);
+        notUnicode.append(branch32(AboveOrEqual, regUnicodeInputAndTrail, regT2));
</ins><span class="cx">         load16Unaligned(Address(regUnicodeInputAndTrail), regUnicodeInputAndTrail);
</span><del>-        and32(surrogateTagMask, regUnicodeInputAndTrail, regUnicodeTemp);
-        notUnicode.append(branch32(NotEqual, regUnicodeTemp, trailingSurrogateTag));
</del><ins>+        and32(surrogateTagMask, regUnicodeInputAndTrail, regT2);
+        notUnicode.append(branch32(NotEqual, regT2, trailingSurrogateTag));
</ins><span class="cx">         sub32(leadingSurrogateTag, resultReg);
</span><span class="cx">         sub32(trailingSurrogateTag, regUnicodeInputAndTrail);
</span><span class="cx">         lshift32(TrustedImm32(10), resultReg);
</span><span class="lines">@@ -422,6 +575,13 @@
</span><span class="cx">         poke(imm, frameLocation);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+#if CPU(ARM64) || CPU(X86_64)
+    void storeToFrame(TrustedImmPtr imm, unsigned frameLocation)
+    {
+        poke(imm, frameLocation);
+    }
+#endif
+
</ins><span class="cx">     DataLabelPtr storeToFrameWithPatch(unsigned frameLocation)
</span><span class="cx">     {
</span><span class="cx">         return storePtrWithPatch(TrustedImmPtr(0), Address(stackPointerRegister, frameLocation * sizeof(void*)));
</span><span class="lines">@@ -467,7 +627,30 @@
</span><span class="cx">         generateReturn();
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    // Used to record subpatters, should only be called if compileMode is IncludeSubpatterns.
</del><ins>+    void generateJITFailReturn()
+    {
+        if (m_abortExecution.empty() && m_hitMatchLimit.empty())
+            return;
+
+        JumpList finishExiting;
+        if (!m_abortExecution.empty()) {
+            m_abortExecution.link(this);
+            move(TrustedImmPtr((void*)static_cast<size_t>(-2)), returnRegister);
+            finishExiting.append(jump());
+        }
+
+        if (!m_hitMatchLimit.empty()) {
+            m_hitMatchLimit.link(this);
+            move(TrustedImmPtr((void*)static_cast<size_t>(-1)), returnRegister);
+        }
+
+        finishExiting.link(this);
+        removeCallFrame();
+        move(TrustedImm32(0), returnRegister2);
+        generateReturn();
+    }
+
+    // Used to record subpatterns, should only be called if compileMode is IncludeSubpatterns.
</ins><span class="cx">     void setSubpatternStart(RegisterID reg, unsigned subpattern)
</span><span class="cx">     {
</span><span class="cx">         ASSERT(subpattern);
</span><span class="lines">@@ -487,6 +670,12 @@
</span><span class="cx">         store32(TrustedImm32(-1), Address(output, (subpattern << 1) * sizeof(int)));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void clearMatches(unsigned subpattern, unsigned lastSubpattern)
+    {
+        for (; subpattern <= lastSubpattern; subpattern++)
+            clearSubpatternStart(subpattern);
+    }
+
</ins><span class="cx">     // We use one of three different strategies to track the start of the current match,
</span><span class="cx">     // while matching.
</span><span class="cx">     // 1) If the pattern has a fixed size, do nothing! - we calculate the value lazily
</span><span class="lines">@@ -529,7 +718,7 @@
</span><span class="cx">         OpNestedAlternativeNext,
</span><span class="cx">         OpNestedAlternativeEnd,
</span><span class="cx">         // Used for alternatives in subpatterns where there is only a single
</span><del>-        // alternative (backtrackingis easier in these cases), or for alternatives
</del><ins>+        // alternative (backtracking is easier in these cases), or for alternatives
</ins><span class="cx">         // which never need to be backtracked (those in parenthetical assertions,
</span><span class="cx">         // terminal subpatterns).
</span><span class="cx">         OpSimpleNestedAlternativeBegin,
</span><span class="lines">@@ -541,6 +730,9 @@
</span><span class="cx">         // Used to wrap 'Terminal' subpattern matches (at the end of the regexp).
</span><span class="cx">         OpParenthesesSubpatternTerminalBegin,
</span><span class="cx">         OpParenthesesSubpatternTerminalEnd,
</span><ins>+        // Used to wrap generic captured matches
+        OpParenthesesSubpatternBegin,
+        OpParenthesesSubpatternEnd,
</ins><span class="cx">         // Used to wrap parenthetical assertions.
</span><span class="cx">         OpParentheticalAssertionBegin,
</span><span class="cx">         OpParentheticalAssertionEnd,
</span><span class="lines">@@ -1768,10 +1960,7 @@
</span><span class="cx">                 // In the non-simple case, store a 'return address' so we can backtrack correctly.
</span><span class="cx">                 if (op.m_op == OpNestedAlternativeNext) {
</span><span class="cx">                     unsigned parenthesesFrameLocation = term->frameLocation;
</span><del>-                    unsigned alternativeFrameLocation = parenthesesFrameLocation;
-                    if (term->quantityType != QuantifierFixedCount)
-                        alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce;
-                    op.m_returnAddress = storeToFrameWithPatch(alternativeFrameLocation);
</del><ins>+                    op.m_returnAddress = storeToFrameWithPatch(parenthesesFrameLocation + BackTrackInfoParentheses::returnAddressIndex());
</ins><span class="cx">                 }
</span><span class="cx"> 
</span><span class="cx">                 if (term->quantityType != QuantifierFixedCount && !m_ops[op.m_previousOp].m_alternative->m_minimumSize) {
</span><span class="lines">@@ -1818,10 +2007,7 @@
</span><span class="cx">                 // In the non-simple case, store a 'return address' so we can backtrack correctly.
</span><span class="cx">                 if (op.m_op == OpNestedAlternativeEnd) {
</span><span class="cx">                     unsigned parenthesesFrameLocation = term->frameLocation;
</span><del>-                    unsigned alternativeFrameLocation = parenthesesFrameLocation;
-                    if (term->quantityType != QuantifierFixedCount)
-                        alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce;
-                    op.m_returnAddress = storeToFrameWithPatch(alternativeFrameLocation);
</del><ins>+                    op.m_returnAddress = storeToFrameWithPatch(parenthesesFrameLocation + BackTrackInfoParentheses::returnAddressIndex());
</ins><span class="cx">                 }
</span><span class="cx"> 
</span><span class="cx">                 if (term->quantityType != QuantifierFixedCount && !m_ops[op.m_previousOp].m_alternative->m_minimumSize) {
</span><span class="lines">@@ -1963,7 +2149,7 @@
</span><span class="cx">                     pastBreakpoint.link(this);
</span><span class="cx">                 }
</span><span class="cx"> 
</span><del>-                // We know that the match is non-zero, we can accept it  and
</del><ins>+                // We know that the match is non-zero, we can accept it and
</ins><span class="cx">                 // loop back up to the head of the subpattern.
</span><span class="cx">                 jump(beginOp.m_reentry);
</span><span class="cx"> 
</span><span class="lines">@@ -1973,6 +2159,131 @@
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="cx"> 
</span><ins>+            // OpParenthesesSubpatternBegin/End
+            //
+            // These nodes support generic subpatterns.
+            case OpParenthesesSubpatternBegin: {
+#ifdef JIT_ALL_PARENS_EXPRESSIONS
+                PatternTerm* term = op.m_term;
+                unsigned parenthesesFrameLocation = term->frameLocation;
+
+                // Upon entry to a Greedy quantified set of parenthese store the index.
+                // We'll use this for two purposes:
+                //  - To indicate which iteration we are on of mathing the remainder of
+                //    the expression after the parentheses - the first, including the
+                //    match within the parentheses, or the second having skipped over them.
+                //  - To check for empty matches, which must be rejected.
+                //
+                // At the head of a NonGreedy set of parentheses we'll immediately set the
+                // value on the stack to -1 (indicating a match skipping the subpattern),
+                // and plant a jump to the end. We'll also plant a label to backtrack to
+                // to reenter the subpattern later, with a store to set up index on the
+                // second iteration.
+                //
+                // FIXME: for capturing parens, could use the index in the capture array?
+                if (term->quantityType == QuantifierGreedy || term->quantityType == QuantifierNonGreedy) {
+                    storeToFrame(TrustedImm32(0), parenthesesFrameLocation + BackTrackInfoParentheses::matchAmountIndex());
+                    storeToFrame(TrustedImmPtr(0), parenthesesFrameLocation + BackTrackInfoParentheses::patternContextHeadIndex());
+
+                    if (term->quantityType == QuantifierNonGreedy) {
+                        storeToFrame(TrustedImm32(-1), parenthesesFrameLocation + BackTrackInfoParentheses::beginIndex());
+                        op.m_jumps.append(jump());
+                    }
+                    
+                    op.m_reentry = label();
+                    RegisterID currPatternContextReg = regT0;
+                    RegisterID newPatternContextReg = regT1;
+
+                    loadFromFrame(parenthesesFrameLocation + BackTrackInfoParentheses::patternContextHeadIndex(), currPatternContextReg);
+                    allocatePatternContext(newPatternContextReg);
+                    storePtr(currPatternContextReg, newPatternContextReg);
+                    storeToFrame(newPatternContextReg, parenthesesFrameLocation + BackTrackInfoParentheses::patternContextHeadIndex());
+                    savePatternContext(newPatternContextReg, regT2, term->parentheses.subpatternId, term->parentheses.lastSubpatternId, parenthesesFrameLocation);
+                    storeToFrame(index, parenthesesFrameLocation + BackTrackInfoParentheses::beginIndex());
+                }
+
+                // If the parenthese are capturing, store the starting index value to the
+                // captures array, offsetting as necessary.
+                //
+                // FIXME: could avoid offsetting this value in JIT code, apply
+                // offsets only afterwards, at the point the results array is
+                // being accessed.
+                if (term->capture() && compileMode == IncludeSubpatterns) {
+                    const RegisterID indexTemporary = regT0;
+                    unsigned inputOffset = (m_checkedOffset - term->inputPosition).unsafeGet();
+                    if (term->quantityType == QuantifierFixedCount)
+                        inputOffset += term->parentheses.disjunction->m_minimumSize;
+                    if (inputOffset) {
+                        move(index, indexTemporary);
+                        sub32(Imm32(inputOffset), indexTemporary);
+                        setSubpatternStart(indexTemporary, term->parentheses.subpatternId);
+                    } else
+                        setSubpatternStart(index, term->parentheses.subpatternId);
+                }
+#else // !JIT_ALL_PARENS_EXPRESSIONS
+                RELEASE_ASSERT_NOT_REACHED();
+#endif
+                break;
+            }
+            case OpParenthesesSubpatternEnd: {
+#ifdef JIT_ALL_PARENS_EXPRESSIONS
+                PatternTerm* term = op.m_term;
+                unsigned parenthesesFrameLocation = term->frameLocation;
+
+                // Runtime ASSERT to make sure that the nested alternative handled the
+                // "no input consumed" check.
+                if (!ASSERT_DISABLED && term->quantityType != QuantifierFixedCount && !term->parentheses.disjunction->m_minimumSize) {
+                    Jump pastBreakpoint;
+                    pastBreakpoint = branch32(NotEqual, index, Address(stackPointerRegister, parenthesesFrameLocation * sizeof(void*)));
+                    abortWithReason(YARRNoInputConsumed);
+                    pastBreakpoint.link(this);
+                }
+
+                const RegisterID countTemporary = regT1;
+
+                YarrOp& beginOp = m_ops[op.m_previousOp];
+                loadFromFrame(parenthesesFrameLocation + BackTrackInfoParentheses::matchAmountIndex(), countTemporary);
+                add32(TrustedImm32(1), countTemporary);
+                storeToFrame(countTemporary, parenthesesFrameLocation + BackTrackInfoParentheses::matchAmountIndex());
+
+                // If the parenthese are capturing, store the ending index value to the
+                // captures array, offsetting as necessary.
+                //
+                // FIXME: could avoid offsetting this value in JIT code, apply
+                // offsets only afterwards, at the point the results array is
+                // being accessed.
+                if (term->capture() && compileMode == IncludeSubpatterns) {
+                    const RegisterID indexTemporary = regT0;
+                    
+                    unsigned inputOffset = (m_checkedOffset - term->inputPosition).unsafeGet();
+                    if (inputOffset) {
+                        move(index, indexTemporary);
+                        sub32(Imm32(inputOffset), indexTemporary);
+                        setSubpatternEnd(indexTemporary, term->parentheses.subpatternId);
+                    } else
+                        setSubpatternEnd(index, term->parentheses.subpatternId);
+                }
+
+                // If the parentheses are quantified Greedy then add a label to jump back
+                // to if get a failed match from after the parentheses. For NonGreedy
+                // parentheses, link the jump from before the subpattern to here.
+                if (term->quantityType == QuantifierGreedy) {
+                    if (term->quantityMaxCount != quantifyInfinite)
+                        branch32(Below, countTemporary, Imm32(term->quantityMaxCount.unsafeGet())).linkTo(beginOp.m_reentry, this);
+                    else
+                        jump(beginOp.m_reentry);
+                    
+                    op.m_reentry = label();
+                } else if (term->quantityType == QuantifierNonGreedy) {
+                    YarrOp& beginOp = m_ops[op.m_previousOp];
+                    beginOp.m_jumps.link(this);
+                }
+#else // !JIT_ALL_PARENS_EXPRESSIONS
+                RELEASE_ASSERT_NOT_REACHED();
+#endif
+                break;
+            }
+
</ins><span class="cx">             // OpParentheticalAssertionBegin/End
</span><span class="cx">             case OpParentheticalAssertionBegin: {
</span><span class="cx">                 PatternTerm* term = op.m_term;
</span><span class="lines">@@ -2391,10 +2702,7 @@
</span><span class="cx"> 
</span><span class="cx">                     // Plant a jump to the return address.
</span><span class="cx">                     unsigned parenthesesFrameLocation = term->frameLocation;
</span><del>-                    unsigned alternativeFrameLocation = parenthesesFrameLocation;
-                    if (term->quantityType != QuantifierFixedCount)
-                        alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce;
-                    loadFromFrameAndJump(alternativeFrameLocation);
</del><ins>+                    loadFromFrameAndJump(parenthesesFrameLocation + BackTrackInfoParentheses::returnAddressIndex());
</ins><span class="cx"> 
</span><span class="cx">                     // Link the DataLabelPtr associated with the end of the last
</span><span class="cx">                     // alternative to this point.
</span><span class="lines">@@ -2425,7 +2733,7 @@
</span><span class="cx">                 PatternTerm* term = op.m_term;
</span><span class="cx">                 ASSERT(term->quantityMaxCount == 1);
</span><span class="cx"> 
</span><del>-                // We only need to backtrack to thispoint if capturing or greedy.
</del><ins>+                // We only need to backtrack to this point if capturing or greedy.
</ins><span class="cx">                 if ((term->capture() && compileMode == IncludeSubpatterns) || term->quantityType == QuantifierGreedy) {
</span><span class="cx">                     m_backtrackingState.link(this);
</span><span class="cx"> 
</span><span class="lines">@@ -2459,7 +2767,7 @@
</span><span class="cx">                     // are currently in a state where we had skipped over the subpattern
</span><span class="cx">                     // (in which case the flag value on the stack will be -1).
</span><span class="cx">                     unsigned parenthesesFrameLocation = term->frameLocation;
</span><del>-                    Jump hadSkipped = branch32(Equal, Address(stackPointerRegister, parenthesesFrameLocation * sizeof(void*)), TrustedImm32(-1));
</del><ins>+                    Jump hadSkipped = branch32(Equal, Address(stackPointerRegister, (parenthesesFrameLocation + BackTrackInfoParenthesesOnce::beginIndex()) * sizeof(void*)), TrustedImm32(-1));
</ins><span class="cx"> 
</span><span class="cx">                     if (term->quantityType == QuantifierGreedy) {
</span><span class="cx">                         // For Greedy parentheses, we skip after having already tried going
</span><span class="lines">@@ -2503,6 +2811,108 @@
</span><span class="cx">                 m_backtrackingState.append(op.m_jumps);
</span><span class="cx">                 break;
</span><span class="cx"> 
</span><ins>+            // OpParenthesesSubpatternBegin/End
+            //
+            // When we are backtracking back out of a capturing subpattern we need
+            // to clear the start index in the matches output array, to record that
+            // this subpattern has not been captured.
+            //
+            // When backtracking back out of a Greedy quantified subpattern we need
+            // to catch this, and try running the remainder of the alternative after
+            // the subpattern again, skipping the parentheses.
+            //
+            // Upon backtracking back into a quantified set of parentheses we need to
+            // check whether we were currently skipping the subpattern. If not, we
+            // can backtrack into them, if we were we need to either backtrack back
+            // out of the start of the parentheses, or jump back to the forwards
+            // matching start, depending of whether the match is Greedy or NonGreedy.
+            case OpParenthesesSubpatternBegin: {
+#ifdef JIT_ALL_PARENS_EXPRESSIONS
+                PatternTerm* term = op.m_term;
+                unsigned parenthesesFrameLocation = term->frameLocation;
+
+                if (term->quantityType == QuantifierGreedy) {
+                    m_backtrackingState.link(this);
+
+                    if (term->quantityType == QuantifierGreedy) {
+                        RegisterID currPatternContextReg = regT0;
+                        RegisterID newPatternContextReg = regT1;
+
+                        loadFromFrame(parenthesesFrameLocation + BackTrackInfoParentheses::patternContextHeadIndex(), currPatternContextReg);
+
+                        restorePatternContext(currPatternContextReg, regT2, term->parentheses.subpatternId, term->parentheses.lastSubpatternId, parenthesesFrameLocation);
+
+                        freePatternContext(currPatternContextReg, newPatternContextReg);
+                        storeToFrame(newPatternContextReg, parenthesesFrameLocation + BackTrackInfoParentheses::patternContextHeadIndex());
+                        const RegisterID countTemporary = regT0;
+                        loadFromFrame(parenthesesFrameLocation + BackTrackInfoParentheses::matchAmountIndex(), countTemporary);
+                        Jump zeroLengthMatch = branchTest32(Zero, countTemporary);
+
+                        sub32(TrustedImm32(1), countTemporary);
+                        storeToFrame(countTemporary, parenthesesFrameLocation + BackTrackInfoParentheses::matchAmountIndex());
+
+                        jump(m_ops[op.m_nextOp].m_reentry);
+
+                        zeroLengthMatch.link(this);
+
+                        // Clear the flag in the stackframe indicating we didn't run through the subpattern.
+                        storeToFrame(TrustedImm32(-1), parenthesesFrameLocation + BackTrackInfoParentheses::beginIndex());
+
+                        jump(m_ops[op.m_nextOp].m_reentry);
+                    }
+
+                    // If Greedy, jump to the end.
+                    if (term->quantityType == QuantifierGreedy) {
+                        // A backtrack from after the parentheses, when skipping the subpattern,
+                        // will jump back to here.
+                        op.m_jumps.link(this);
+                    }
+
+                    m_backtrackingState.fallthrough();
+                }
+#else // !JIT_ALL_PARENS_EXPRESSIONS
+                RELEASE_ASSERT_NOT_REACHED();
+#endif
+                break;
+            }
+            case OpParenthesesSubpatternEnd: {
+#ifdef JIT_ALL_PARENS_EXPRESSIONS
+                PatternTerm* term = op.m_term;
+
+                if (term->quantityType != QuantifierFixedCount) {
+                    m_backtrackingState.link(this);
+
+                    // Check whether we should backtrack back into the parentheses, or if we
+                    // are currently in a state where we had skipped over the subpattern
+                    // (in which case the flag value on the stack will be -1).
+                    unsigned parenthesesFrameLocation = term->frameLocation;
+                    Jump hadSkipped = branch32(Equal, Address(stackPointerRegister, (parenthesesFrameLocation  + BackTrackInfoParentheses::beginIndex()) * sizeof(void*)), TrustedImm32(-1));
+
+                    if (term->quantityType == QuantifierGreedy) {
+                        // For Greedy parentheses, we skip after having already tried going
+                        // through the subpattern, so if we get here we're done.
+                        YarrOp& beginOp = m_ops[op.m_previousOp];
+                        beginOp.m_jumps.append(hadSkipped);
+                    } else {
+                        // For NonGreedy parentheses, we try skipping the subpattern first,
+                        // so if we get here we need to try running through the subpattern
+                        // next. Jump back to the start of the parentheses in the forwards
+                        // matching path.
+                        ASSERT(term->quantityType == QuantifierNonGreedy);
+                        YarrOp& beginOp = m_ops[op.m_previousOp];
+                        hadSkipped.linkTo(beginOp.m_reentry, this);
+                    }
+
+                    m_backtrackingState.fallthrough();
+                }
+
+                m_backtrackingState.append(op.m_jumps);
+#else // !JIT_ALL_PARENS_EXPRESSIONS
+                RELEASE_ASSERT_NOT_REACHED();
+#endif
+                break;
+            }
+
</ins><span class="cx">             // OpParentheticalAssertionBegin/End
</span><span class="cx">             case OpParentheticalAssertionBegin: {
</span><span class="cx">                 PatternTerm* term = op.m_term;
</span><span class="lines">@@ -2562,9 +2972,9 @@
</span><span class="cx">     // Emits ops for a subpattern (set of parentheses). These consist
</span><span class="cx">     // of a set of alternatives wrapped in an outer set of nodes for
</span><span class="cx">     // the parentheses.
</span><del>-    // Supported types of parentheses are 'Once' (quantityMaxCount == 1)
-    // and 'Terminal' (non-capturing parentheses quantified as greedy
-    // and infinite).
</del><ins>+    // Supported types of parentheses are 'Once' (quantityMaxCount == 1),
+    // 'Terminal' (non-capturing parentheses quantified as greedy
+    // and infinite), and 0 based greedy quantified parentheses.
</ins><span class="cx">     // Alternatives will use the 'Simple' set of ops if either the
</span><span class="cx">     // subpattern is terminal (in which case we will never need to
</span><span class="cx">     // backtrack), or if the subpattern only contains one alternative.
</span><span class="lines">@@ -2584,6 +2994,8 @@
</span><span class="cx">         // need to restore the capture from the first subpattern upon a
</span><span class="cx">         // failure in the second.
</span><span class="cx">         if (term->quantityMinCount && term->quantityMinCount != term->quantityMaxCount) {
</span><ins>+            if (Options::dumpCompiledRegExpPatterns())
+                dataLogF("Can't JIT a variable counted parenthesis with a non-zero minimum\n");
</ins><span class="cx">             m_shouldFallBack = true;
</span><span class="cx">             return;
</span><span class="cx">         } if (term->quantityMaxCount == 1 && !term->parentheses.isCopy) {
</span><span class="lines">@@ -2602,9 +3014,31 @@
</span><span class="cx">             parenthesesBeginOpCode = OpParenthesesSubpatternTerminalBegin;
</span><span class="cx">             parenthesesEndOpCode = OpParenthesesSubpatternTerminalEnd;
</span><span class="cx">         } else {
</span><ins>+#ifdef JIT_ALL_PARENS_EXPRESSIONS
+            // We only handle generic parenthesis with greedy counts.
+            if (term->quantityType != QuantifierGreedy) {
+                // This subpattern is not supported by the JIT.
+                m_shouldFallBack = true;
+                return;
+            }
+
+            m_containsNestedSubpatterns = true;
+
+            // Select the 'Generic' nodes.
+            parenthesesBeginOpCode = OpParenthesesSubpatternBegin;
+            parenthesesEndOpCode = OpParenthesesSubpatternEnd;
+
+            // If there is more than one alternative we cannot use the 'simple' nodes.
+            if (term->parentheses.disjunction->m_alternatives.size() != 1) {
+                alternativeBeginOpCode = OpNestedAlternativeBegin;
+                alternativeNextOpCode = OpNestedAlternativeNext;
+                alternativeEndOpCode = OpNestedAlternativeEnd;
+            }
+#else
</ins><span class="cx">             // This subpattern is not supported by the JIT.
</span><span class="cx">             m_shouldFallBack = true;
</span><span class="cx">             return;
</span><ins>+#endif
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         size_t parenBegin = m_ops.size();
</span><span class="lines">@@ -2831,18 +3265,21 @@
</span><span class="cx">         if (m_pattern.m_saveInitialStartValue)
</span><span class="cx">             push(X86Registers::ebx);
</span><span class="cx"> 
</span><del>-        if (m_decodeSurrogatePairs) {
</del><ins>+#ifdef JIT_ALL_PARENS_EXPRESSIONS
+        if (m_containsNestedSubpatterns) {
</ins><span class="cx"> #if OS(WINDOWS)
</span><span class="cx">             push(X86Registers::edi);
</span><span class="cx">             push(X86Registers::esi);
</span><span class="cx"> #endif
</span><span class="cx">             push(X86Registers::r12);
</span><ins>+        }
+#endif
+
+        if (m_decodeSurrogatePairs) {
</ins><span class="cx">             push(X86Registers::r13);
</span><span class="cx">             push(X86Registers::r14);
</span><span class="cx">             push(X86Registers::r15);
</span><span class="cx"> 
</span><del>-            move(TrustedImm32(0x10000), supplementaryPlanesBase);
-            move(TrustedImm32(0xfffffc00), surrogateTagMask);
</del><span class="cx">             move(TrustedImm32(0xd800), leadingSurrogateTag);
</span><span class="cx">             move(TrustedImm32(0xdc00), trailingSurrogateTag);
</span><span class="cx">         }
</span><span class="lines">@@ -2912,6 +3349,10 @@
</span><span class="cx">             pop(X86Registers::r15);
</span><span class="cx">             pop(X86Registers::r14);
</span><span class="cx">             pop(X86Registers::r13);
</span><ins>+        }
+
+#ifdef JIT_ALL_PARENS_EXPRESSIONS
+        if (m_containsNestedSubpatterns) {
</ins><span class="cx">             pop(X86Registers::r12);
</span><span class="cx"> #if OS(WINDOWS)
</span><span class="cx">             pop(X86Registers::esi);
</span><span class="lines">@@ -2918,6 +3359,7 @@
</span><span class="cx">             pop(X86Registers::edi);
</span><span class="cx"> #endif
</span><span class="cx">         }
</span><ins>+#endif
</ins><span class="cx"> 
</span><span class="cx">         if (m_pattern.m_saveInitialStartValue)
</span><span class="cx">             pop(X86Registers::ebx);
</span><span class="lines">@@ -2949,6 +3391,10 @@
</span><span class="cx">         , m_decodeSurrogatePairs(m_charSize == Char16 && m_pattern.unicode())
</span><span class="cx">         , m_unicodeIgnoreCase(m_pattern.unicode() && m_pattern.ignoreCase())
</span><span class="cx">         , m_canonicalMode(m_pattern.unicode() ? CanonicalMode::Unicode : CanonicalMode::UCS2)
</span><ins>+#ifdef JIT_ALL_PARENS_EXPRESSIONS
+        , m_containsNestedSubpatterns(false)
+        , m_parenContextSizes(compileMode == IncludeSubpatterns ? m_pattern.m_numSubpatterns : 0, m_pattern.m_body->m_callFrameSize)
+#endif
</ins><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -2961,6 +3407,15 @@
</span><span class="cx">         }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+        // We need to compile before generating code since we set flags based on compilation that
+        // are used during generation.
+        opCompileBody(m_pattern.m_body);
+        
+        if (m_shouldFallBack) {
+            jitObject.setFallBack(true);
+            return;
+        }
+        
</ins><span class="cx">         generateEnter();
</span><span class="cx"> 
</span><span class="cx">         Jump hasInput = checkInput();
</span><span class="lines">@@ -2967,6 +3422,11 @@
</span><span class="cx">         generateFailReturn();
</span><span class="cx">         hasInput.link(this);
</span><span class="cx"> 
</span><ins>+#ifdef JIT_ALL_PARENS_EXPRESSIONS
+        if (m_containsNestedSubpatterns)
+            move(TrustedImm32(matchLimit), remainingMatchCount);
+#endif
+
</ins><span class="cx">         if (compileMode == IncludeSubpatterns) {
</span><span class="cx">             for (unsigned i = 0; i < m_pattern.m_numSubpatterns + 1; ++i)
</span><span class="cx">                 store32(TrustedImm32(-1), Address(output, (i << 1) * sizeof(int)));
</span><span class="lines">@@ -2977,6 +3437,11 @@
</span><span class="cx"> 
</span><span class="cx">         initCallFrame();
</span><span class="cx"> 
</span><ins>+#ifdef JIT_ALL_PARENS_EXPRESSIONS
+        if (m_containsNestedSubpatterns)
+            initParenContextFreeList();
+#endif
+        
</ins><span class="cx">         if (m_pattern.m_saveInitialStartValue) {
</span><span class="cx"> #ifdef HAVE_INITIAL_START_REG
</span><span class="cx">             move(index, initialStart);
</span><span class="lines">@@ -2985,18 +3450,13 @@
</span><span class="cx"> #endif
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        opCompileBody(m_pattern.m_body);
-
-        if (m_shouldFallBack) {
-            jitObject.setFallBack(true);
-            return;
-        }
-
</del><span class="cx">         generate();
</span><span class="cx">         backtrack();
</span><span class="cx"> 
</span><span class="cx">         generateTryReadUnicodeCharacterHelper();
</span><span class="cx"> 
</span><ins>+        generateJITFailReturn();
+
</ins><span class="cx">         LinkBuffer linkBuffer(*this, REGEXP_CODE_ID, JITCompilationCanFail);
</span><span class="cx">         if (linkBuffer.didFailToAllocate()) {
</span><span class="cx">             jitObject.setFallBack(true);
</span><span class="lines">@@ -3040,6 +3500,12 @@
</span><span class="cx">     bool m_decodeSurrogatePairs;
</span><span class="cx">     bool m_unicodeIgnoreCase;
</span><span class="cx">     CanonicalMode m_canonicalMode;
</span><ins>+#ifdef JIT_ALL_PARENS_EXPRESSIONS
+    bool m_containsNestedSubpatterns;
+    ParenContextSizes m_parenContextSizes;
+#endif
+    JumpList m_abortExecution;
+    JumpList m_hitMatchLimit;
</ins><span class="cx">     Vector<Call> m_tryReadUnicodeCharacterCalls;
</span><span class="cx">     Label m_tryReadUnicodeCharacterEntry;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreyarrYarrJITh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/yarr/YarrJIT.h (225694 => 225695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/yarr/YarrJIT.h       2017-12-08 20:32:20 UTC (rev 225694)
+++ trunk/Source/JavaScriptCore/yarr/YarrJIT.h  2017-12-08 20:32:42 UTC (rev 225695)
</span><span class="lines">@@ -38,6 +38,11 @@
</span><span class="cx"> #define YARR_CALL
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+#if CPU(ARM64) || (CPU(X86_64) && !OS(WINDOWS))
+#define JIT_ALL_PARENS_EXPRESSIONS
+constexpr size_t patternContextBufferSize = 8192; // Space caller allocates to save nested parenthesis context
+#endif
+
</ins><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><span class="cx"> class VM;
</span><span class="lines">@@ -47,10 +52,17 @@
</span><span class="cx"> 
</span><span class="cx"> class YarrCodeBlock {
</span><span class="cx"> #if CPU(X86_64) || CPU(ARM64)
</span><ins>+#ifdef JIT_ALL_PARENS_EXPRESSIONS
+    typedef MatchResult (*YarrJITCode8)(const LChar* input, unsigned start, unsigned length, int* output, void* freeParenContext, unsigned parenContextSize) YARR_CALL;
+    typedef MatchResult (*YarrJITCode16)(const UChar* input, unsigned start, unsigned length, int* output, void* freeParenContext, unsigned parenContextSize) YARR_CALL;
+    typedef MatchResult (*YarrJITCodeMatchOnly8)(const LChar* input, unsigned start, unsigned length, void*, void* freeParenContext, unsigned parenContextSize) YARR_CALL;
+    typedef MatchResult (*YarrJITCodeMatchOnly16)(const UChar* input, unsigned start, unsigned length, void*, void* freeParenContext, unsigned parenContextSize) YARR_CALL;
+#else
</ins><span class="cx">     typedef MatchResult (*YarrJITCode8)(const LChar* input, unsigned start, unsigned length, int* output) YARR_CALL;
</span><span class="cx">     typedef MatchResult (*YarrJITCode16)(const UChar* input, unsigned start, unsigned length, int* output) YARR_CALL;
</span><span class="cx">     typedef MatchResult (*YarrJITCodeMatchOnly8)(const LChar* input, unsigned start, unsigned length) YARR_CALL;
</span><span class="cx">     typedef MatchResult (*YarrJITCodeMatchOnly16)(const UChar* input, unsigned start, unsigned length) YARR_CALL;
</span><ins>+#endif
</ins><span class="cx"> #else
</span><span class="cx">     typedef EncodedMatchResult (*YarrJITCode8)(const LChar* input, unsigned start, unsigned length, int* output) YARR_CALL;
</span><span class="cx">     typedef EncodedMatchResult (*YarrJITCode16)(const UChar* input, unsigned start, unsigned length, int* output) YARR_CALL;
</span><span class="lines">@@ -81,6 +93,31 @@
</span><span class="cx">     void set8BitCodeMatchOnly(MacroAssemblerCodeRef matchOnly) { m_matchOnly8 = matchOnly; }
</span><span class="cx">     void set16BitCodeMatchOnly(MacroAssemblerCodeRef matchOnly) { m_matchOnly16 = matchOnly; }
</span><span class="cx"> 
</span><ins>+#ifdef JIT_ALL_PARENS_EXPRESSIONS
+    MatchResult execute(const LChar* input, unsigned start, unsigned length, int* output, void* freeParenContext, unsigned parenContextSize)
+    {
+        ASSERT(has8BitCode());
+        return MatchResult(reinterpret_cast<YarrJITCode8>(m_ref8.code().executableAddress())(input, start, length, output, freeParenContext, parenContextSize));
+    }
+
+    MatchResult execute(const UChar* input, unsigned start, unsigned length, int* output, void* freeParenContext, unsigned parenContextSize)
+    {
+        ASSERT(has16BitCode());
+        return MatchResult(reinterpret_cast<YarrJITCode16>(m_ref16.code().executableAddress())(input, start, length, output, freeParenContext, parenContextSize));
+    }
+
+    MatchResult execute(const LChar* input, unsigned start, unsigned length, void* freeParenContext, unsigned parenContextSize)
+    {
+        ASSERT(has8BitCodeMatchOnly());
+        return MatchResult(reinterpret_cast<YarrJITCodeMatchOnly8>(m_matchOnly8.code().executableAddress())(input, start, length, 0, freeParenContext, parenContextSize));
+    }
+
+    MatchResult execute(const UChar* input, unsigned start, unsigned length, void* freeParenContext, unsigned parenContextSize)
+    {
+        ASSERT(has16BitCodeMatchOnly());
+        return MatchResult(reinterpret_cast<YarrJITCodeMatchOnly16>(m_matchOnly16.code().executableAddress())(input, start, length, 0, freeParenContext, parenContextSize));
+    }
+#else
</ins><span class="cx">     MatchResult execute(const LChar* input, unsigned start, unsigned length, int* output)
</span><span class="cx">     {
</span><span class="cx">         ASSERT(has8BitCode());
</span><span class="lines">@@ -104,6 +141,7 @@
</span><span class="cx">         ASSERT(has16BitCodeMatchOnly());
</span><span class="cx">         return MatchResult(reinterpret_cast<YarrJITCodeMatchOnly16>(m_matchOnly16.code().executableAddress())(input, start, length));
</span><span class="cx">     }
</span><ins>+#endif
</ins><span class="cx"> 
</span><span class="cx"> #if ENABLE(REGEXP_TRACING)
</span><span class="cx">     void *get8BitMatchOnlyAddr()
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreyarrYarrPatterncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/yarr/YarrPattern.cpp (225694 => 225695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/yarr/YarrPattern.cpp 2017-12-08 20:32:20 UTC (rev 225694)
+++ trunk/Source/JavaScriptCore/yarr/YarrPattern.cpp    2017-12-08 20:32:42 UTC (rev 225695)
</span><span class="lines">@@ -828,8 +828,7 @@
</span><span class="cx">                 // Note: for fixed once parentheses we will ensure at least the minimum is available; others are on their own.
</span><span class="cx">                 term.frameLocation = currentCallFrameSize;
</span><span class="cx">                 if (term.quantityMaxCount == 1 && !term.parentheses.isCopy) {
</span><del>-                    if (term.quantityType != QuantifierFixedCount)
-                        currentCallFrameSize += YarrStackSpaceForBackTrackInfoParenthesesOnce;
</del><ins>+                    currentCallFrameSize += YarrStackSpaceForBackTrackInfoParenthesesOnce;
</ins><span class="cx">                     error = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, currentInputPosition.unsafeGet(), currentCallFrameSize);
</span><span class="cx">                     if (error)
</span><span class="cx">                         return error;
</span><span class="lines">@@ -845,11 +844,10 @@
</span><span class="cx">                     term.inputPosition = currentInputPosition.unsafeGet();
</span><span class="cx">                 } else {
</span><span class="cx">                     term.inputPosition = currentInputPosition.unsafeGet();
</span><del>-                    unsigned ignoredCallFrameSize;
-                    error = setupDisjunctionOffsets(term.parentheses.disjunction, 0, currentInputPosition.unsafeGet(), ignoredCallFrameSize);
</del><ins>+                    currentCallFrameSize += YarrStackSpaceForBackTrackInfoParentheses;
+                    error = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, currentInputPosition.unsafeGet(), currentCallFrameSize);
</ins><span class="cx">                     if (error)
</span><span class="cx">                         return error;
</span><del>-                    currentCallFrameSize += YarrStackSpaceForBackTrackInfoParentheses;
</del><span class="cx">                 }
</span><span class="cx">                 // Fixed count of 1 could be accepted, if they have a fixed size *AND* if all alternatives are of the same length.
</span><span class="cx">                 alternative->m_hasFixedSize = false;
</span><span class="lines">@@ -1185,7 +1183,7 @@
</span><span class="cx">     *error = compile(pattern, stackLimit);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static void indentForNestingLevel(PrintStream& out, unsigned nestingDepth)
</del><ins>+void indentForNestingLevel(PrintStream& out, unsigned nestingDepth)
</ins><span class="cx"> {
</span><span class="cx">     out.print("    ");
</span><span class="cx">     for (; nestingDepth; --nestingDepth)
</span><span class="lines">@@ -1192,7 +1190,7 @@
</span><span class="cx">         out.print("  ");
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static void dumpUChar32(PrintStream& out, UChar32 c)
</del><ins>+void dumpUChar32(PrintStream& out, UChar32 c)
</ins><span class="cx"> {
</span><span class="cx">     if (c >= ' '&& c <= 0xff)
</span><span class="cx">         out.printf("'%c'", static_cast<char>(c));
</span><span class="lines">@@ -1200,6 +1198,79 @@
</span><span class="cx">         out.printf("0x%04x", c);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void dumpCharacterClass(PrintStream& out, YarrPattern* pattern, CharacterClass* characterClass)
+{
+    if (characterClass == pattern->anyCharacterClass())
+        out.print("<any character>");
+    else if (characterClass == pattern->newlineCharacterClass())
+        out.print("<newline>");
+    else if (characterClass == pattern->digitsCharacterClass())
+        out.print("<digits>");
+    else if (characterClass == pattern->spacesCharacterClass())
+        out.print("<whitespace>");
+    else if (characterClass == pattern->wordcharCharacterClass())
+        out.print("<word>");
+    else if (characterClass == pattern->wordUnicodeIgnoreCaseCharCharacterClass())
+        out.print("<unicode ignore case>");
+    else if (characterClass == pattern->nondigitsCharacterClass())
+        out.print("<non-digits>");
+    else if (characterClass == pattern->nonspacesCharacterClass())
+        out.print("<non-whitespace>");
+    else if (characterClass == pattern->nonwordcharCharacterClass())
+        out.print("<non-word>");
+    else if (characterClass == pattern->nonwordUnicodeIgnoreCaseCharCharacterClass())
+        out.print("<unicode non-ignore case>");
+    else {
+        bool needMatchesRangesSeperator = false;
+
+        auto dumpMatches = [&] (const char* prefix, Vector<UChar32> matches) {
+            size_t matchesSize = matches.size();
+            if (matchesSize) {
+                if (needMatchesRangesSeperator)
+                    out.print(",");
+                needMatchesRangesSeperator = true;
+
+                out.print(prefix, ":(");
+                for (size_t i = 0; i < matchesSize; ++i) {
+                    if (i)
+                        out.print(",");
+                    dumpUChar32(out, matches[i]);
+                }
+                out.print(")");
+            }
+        };
+
+        auto dumpRanges = [&] (const char* prefix, Vector<CharacterRange> ranges) {
+            size_t rangeSize = ranges.size();
+            if (rangeSize) {
+                if (needMatchesRangesSeperator)
+                    out.print(",");
+                needMatchesRangesSeperator = true;
+
+                out.print(prefix, " ranges:(");
+                for (size_t i = 0; i < rangeSize; ++i) {
+                    if (i)
+                        out.print(",");
+                    CharacterRange range = ranges[i];
+                    out.print("(");
+                    dumpUChar32(out, range.begin);
+                    out.print("..");
+                    dumpUChar32(out, range.end);
+                    out.print(")");
+                }
+                out.print(")");
+            }
+        };
+
+        out.print("[");
+        dumpMatches("ASCII", characterClass->m_matches);
+        dumpRanges("ASCII", characterClass->m_ranges);
+        dumpMatches("Unicode", characterClass->m_matchesUnicode);
+        dumpRanges("Unicode", characterClass->m_rangesUnicode);
+        out.print("]");
+    }
+}
+
</ins><span class="cx"> void PatternAlternative::dump(PrintStream& out, YarrPattern* thisPattern, unsigned nestingDepth)
</span><span class="cx"> {
</span><span class="cx">     out.print("minimum size: ", m_minimumSize);
</span><span class="lines">@@ -1239,8 +1310,10 @@
</span><span class="cx"> {
</span><span class="cx">     indentForNestingLevel(out, nestingDepth);
</span><span class="cx"> 
</span><del>-    if (invert() && (type != TypeParenthesesSubpattern && type != TypeParentheticalAssertion))
-        out.print("not ");
</del><ins>+    if (type != TypeParenthesesSubpattern && type != TypeParentheticalAssertion) {
+        if (invert())
+            out.print("not ");
+    }
</ins><span class="cx"> 
</span><span class="cx">     switch (type) {
</span><span class="cx">     case TypeAssertionBOL:
</span><span class="lines">@@ -1254,6 +1327,7 @@
</span><span class="cx">         break;
</span><span class="cx">     case TypePatternCharacter:
</span><span class="cx">         out.printf("character ");
</span><ins>+        out.printf("inputPosition %u ", inputPosition);
</ins><span class="cx">         if (thisPattern->ignoreCase() && isASCIIAlpha(patternCharacter)) {
</span><span class="cx">             dumpUChar32(out, toASCIIUpper(patternCharacter));
</span><span class="cx">             out.print("/");
</span><span class="lines">@@ -1375,16 +1449,17 @@
</span><span class="cx">         if (parentheses.isTerminal)
</span><span class="cx">             out.print(",terminal");
</span><span class="cx"> 
</span><del>-        if (quantityMaxCount != 1 || parentheses.isCopy || quantityType != QuantifierFixedCount)
-            out.println(",frame location ", frameLocation);
-        else
-            out.println();
</del><ins>+        out.println(",frame location ", frameLocation);
</ins><span class="cx"> 
</span><span class="cx">         if (parentheses.disjunction->m_alternatives.size() > 1) {
</span><span class="cx">             indentForNestingLevel(out, nestingDepth + 1);
</span><span class="cx">             unsigned alternativeFrameLocation = frameLocation;
</span><del>-            if (quantityType != QuantifierFixedCount)
</del><ins>+            if (quantityMaxCount == 1 && !parentheses.isCopy)
</ins><span class="cx">                 alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesOnce;
</span><ins>+            else if (parentheses.isTerminal)
+                alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParenthesesTerminal;
+            else
+                alternativeFrameLocation += YarrStackSpaceForBackTrackInfoParentheses;
</ins><span class="cx">             out.println("alternative list,frame location ", alternativeFrameLocation);
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -1461,6 +1536,8 @@
</span><span class="cx">         out.print(")");
</span><span class="cx">     }
</span><span class="cx">     out.print(":\n");
</span><ins>+    if (m_body->m_callFrameSize)
+        out.print("    callframe size: ", m_body->m_callFrameSize, "\n");
</ins><span class="cx">     m_body->dump(out, this);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreyarrYarrPatternh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/yarr/YarrPattern.h (225694 => 225695)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/yarr/YarrPattern.h   2017-12-08 20:32:20 UTC (rev 225694)
+++ trunk/Source/JavaScriptCore/yarr/YarrPattern.h      2017-12-08 20:32:42 UTC (rev 225695)
</span><span class="lines">@@ -227,7 +227,13 @@
</span><span class="cx">     {
</span><span class="cx">         return m_capture;
</span><span class="cx">     }
</span><del>-    
</del><ins>+
+    bool containsAnyCaptures()
+    {
+        ASSERT(this->type == TypeParenthesesSubpattern);
+        return parentheses.lastSubpatternId >= parentheses.subpatternId;
+    }
+
</ins><span class="cx">     void quantify(unsigned count, QuantifierType type)
</span><span class="cx">     {
</span><span class="cx">         quantityMinCount = 0;
</span><span class="lines">@@ -549,6 +555,10 @@
</span><span class="cx">     HashMap<unsigned, CharacterClass*> unicodePropertiesCached;
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+    void indentForNestingLevel(PrintStream&, unsigned);
+    void dumpUChar32(PrintStream&, UChar32);
+    void dumpCharacterClass(PrintStream&, YarrPattern*, CharacterClass*);
+
</ins><span class="cx">     struct BackTrackInfoPatternCharacter {
</span><span class="cx">         uintptr_t begin; // Only needed for unicode patterns
</span><span class="cx">         uintptr_t matchAmount;
</span><span class="lines">@@ -574,9 +584,9 @@
</span><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     struct BackTrackInfoAlternative {
</span><del>-        uintptr_t offset;
-
-        static unsigned offsetIndex() { return offsetof(BackTrackInfoAlternative, offset) / sizeof(uintptr_t); }
</del><ins>+        union {
+            uintptr_t offset;
+        };
</ins><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     struct BackTrackInfoParentheticalAssertion {
</span><span class="lines">@@ -587,8 +597,10 @@
</span><span class="cx"> 
</span><span class="cx">     struct BackTrackInfoParenthesesOnce {
</span><span class="cx">         uintptr_t begin;
</span><ins>+        uintptr_t returnAddress;
</ins><span class="cx"> 
</span><span class="cx">         static unsigned beginIndex() { return offsetof(BackTrackInfoParenthesesOnce, begin) / sizeof(uintptr_t); }
</span><ins>+        static unsigned returnAddressIndex() { return offsetof(BackTrackInfoParenthesesOnce, returnAddress) / sizeof(uintptr_t); }
</ins><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     struct BackTrackInfoParenthesesTerminal {
</span><span class="lines">@@ -597,4 +609,16 @@
</span><span class="cx">         static unsigned beginIndex() { return offsetof(BackTrackInfoParenthesesTerminal, begin) / sizeof(uintptr_t); }
</span><span class="cx">     };
</span><span class="cx"> 
</span><ins>+    struct BackTrackInfoParentheses {
+        uintptr_t begin;
+        uintptr_t returnAddress;
+        uintptr_t matchAmount;
+        uintptr_t patternContextHead;
+
+        static unsigned beginIndex() { return offsetof(BackTrackInfoParentheses, begin) / sizeof(uintptr_t); }
+        static unsigned returnAddressIndex() { return offsetof(BackTrackInfoParentheses, returnAddress) / sizeof(uintptr_t); }
+        static unsigned matchAmountIndex() { return offsetof(BackTrackInfoParentheses, matchAmount) / sizeof(uintptr_t); }
+        static unsigned patternContextHeadIndex() { return offsetof(BackTrackInfoParentheses, patternContextHead) / sizeof(uintptr_t); }
+    };
+
</ins><span class="cx"> } } // namespace JSC::Yarr
</span></span></pre>
</div>
</div>

</body>
</html>