Title: [215000] releases/WebKitGTK/webkit-2.14
Revision
215000
Author
carlo...@webkit.org
Date
2017-04-06 01:23:15 -0700 (Thu, 06 Apr 2017)

Log Message

Merge r210837 - Nested parenthesized regular expressions with non-zero minimum counts appear to hang and use lots of memory
https://bugs.webkit.org/show_bug.cgi?id=167125

Reviewed by Filip Pizlo.

JSTests:

* microbenchmarks/regexp-nested-nonzero-min-counted-parens.js: Added.
New test with limits that run slow and take a reasonable amount of memory
before the change and run fast, using little memory with the change.

Source/_javascript_Core:

Changed Yarr to handle nested parenthesized subexpressions where the minimum count is
not 0 directly in the Yarr interpreter.  Previously we'd factor an _expression_ like
(a|b)+ into (a|b)(a|b)* with special handling for captures.  This factoring was done
using a deep copy that doubled the size of the resulting expresion for each nested
parenthesized subexpression.  Now the Yarr interpreter can directly process a regexp
like (a|b){2,42}.

The parser will allow one level of nested, non-zero minimum, counted parenthesis using
the old copy method.  After one level, it will generate parenthesis terms with a non-zero
minimum.   Such an _expression_ wasn't handled by the Yarr JIT before the change, so this
change isn't a performance regression.

Added a minimum count to the YarrPattern and ByteTerm classes, and then factored that
minimum into the interpreter.  A non-zero minimum is only handled by the Yarr interpreter.
If the Yarr JIT see such a term, it punts back to the interpreter.

* yarr/YarrInterpreter.cpp:
(JSC::Yarr::Interpreter::backtrackPatternCharacter):
(JSC::Yarr::Interpreter::backtrackPatternCasedCharacter):
(JSC::Yarr::Interpreter::matchCharacterClass):
(JSC::Yarr::Interpreter::backtrackCharacterClass):
(JSC::Yarr::Interpreter::matchBackReference):
(JSC::Yarr::Interpreter::backtrackBackReference):
(JSC::Yarr::Interpreter::matchParenthesesOnceBegin):
(JSC::Yarr::Interpreter::matchParenthesesOnceEnd):
(JSC::Yarr::Interpreter::backtrackParenthesesOnceBegin):
(JSC::Yarr::Interpreter::backtrackParenthesesOnceEnd):
(JSC::Yarr::Interpreter::matchParenthesesTerminalBegin):
(JSC::Yarr::Interpreter::backtrackParenthesesTerminalBegin):
(JSC::Yarr::Interpreter::matchParentheticalAssertionBegin):
(JSC::Yarr::Interpreter::matchParentheticalAssertionEnd):
(JSC::Yarr::Interpreter::backtrackParentheticalAssertionBegin):
(JSC::Yarr::Interpreter::backtrackParentheticalAssertionEnd):
(JSC::Yarr::Interpreter::matchParentheses):
(JSC::Yarr::Interpreter::backtrackParentheses):
(JSC::Yarr::Interpreter::matchDisjunction):
(JSC::Yarr::ByteCompiler::atomPatternCharacter):
(JSC::Yarr::ByteCompiler::atomCharacterClass):
(JSC::Yarr::ByteCompiler::atomBackReference):
(JSC::Yarr::ByteCompiler::atomParentheticalAssertionEnd):
(JSC::Yarr::ByteCompiler::atomParenthesesSubpatternEnd):
(JSC::Yarr::ByteCompiler::atomParenthesesOnceEnd):
(JSC::Yarr::ByteCompiler::atomParenthesesTerminalEnd):
(JSC::Yarr::ByteCompiler::emitDisjunction):
* yarr/YarrInterpreter.h:
(JSC::Yarr::ByteTerm::ByteTerm):
* yarr/YarrJIT.cpp:
(JSC::Yarr::YarrGenerator::generatePatternCharacterOnce):
(JSC::Yarr::YarrGenerator::generatePatternCharacterFixed):
(JSC::Yarr::YarrGenerator::generatePatternCharacterGreedy):
(JSC::Yarr::YarrGenerator::backtrackPatternCharacterNonGreedy):
(JSC::Yarr::YarrGenerator::generateCharacterClassFixed):
(JSC::Yarr::YarrGenerator::generateCharacterClassGreedy):
(JSC::Yarr::YarrGenerator::backtrackCharacterClassNonGreedy):
(JSC::Yarr::YarrGenerator::generateTerm):
(JSC::Yarr::YarrGenerator::backtrackTerm):
(JSC::Yarr::YarrGenerator::generate):
(JSC::Yarr::YarrGenerator::backtrack):
(JSC::Yarr::YarrGenerator::opCompileParenthesesSubpattern):
* yarr/YarrPattern.cpp:
(JSC::Yarr::YarrPatternConstructor::copyTerm):
(JSC::Yarr::YarrPatternConstructor::quantifyAtom):
(JSC::Yarr::YarrPatternConstructor::checkForTerminalParentheses):
(JSC::Yarr::YarrPattern::YarrPattern):
* yarr/YarrPattern.h:
(JSC::Yarr::PatternTerm::PatternTerm):
(JSC::Yarr::PatternTerm::quantify):
(JSC::Yarr::YarrPattern::reset):

Modified Paths

Added Paths

Diff

Modified: releases/WebKitGTK/webkit-2.14/JSTests/ChangeLog (214999 => 215000)


--- releases/WebKitGTK/webkit-2.14/JSTests/ChangeLog	2017-04-06 08:05:31 UTC (rev 214999)
+++ releases/WebKitGTK/webkit-2.14/JSTests/ChangeLog	2017-04-06 08:23:15 UTC (rev 215000)
@@ -1,3 +1,14 @@
+2017-01-17  Michael Saboff  <msab...@apple.com>
+
+        Nested parenthesized regular expressions with non-zero minimum counts appear to hang and use lots of memory
+        https://bugs.webkit.org/show_bug.cgi?id=167125
+
+        Reviewed by Filip Pizlo.
+
+        * microbenchmarks/regexp-nested-nonzero-min-counted-parens.js: Added.
+        New test with limits that run slow and take a reasonable amount of memory
+        before the change and run fast, using little memory with the change.
+
 2016-11-15  Mark Lam  <mark....@apple.com>
 
         The jsc shell's setImpureGetterDelegate() should ensure that the set value is an ImpureGetter.

Added: releases/WebKitGTK/webkit-2.14/JSTests/microbenchmarks/regexp-nested-nonzero-min-counted-parens.js (0 => 215000)


--- releases/WebKitGTK/webkit-2.14/JSTests/microbenchmarks/regexp-nested-nonzero-min-counted-parens.js	                        (rev 0)
+++ releases/WebKitGTK/webkit-2.14/JSTests/microbenchmarks/regexp-nested-nonzero-min-counted-parens.js	2017-04-06 08:23:15 UTC (rev 215000)
@@ -0,0 +1,11 @@
+// This checks that we didn't regress the performance of regular expressions with nested, counted parenthesis
+// where the minimum count is not 0.
+
+/$($($($($($($($($($($($($($($($($($($($(${-2,16}+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+/.exec("a");
+
+/$(?:$(?:$(?:$(?:$(?:$(?:$(?:$(?:$(?:$(?:$(?:$(?:$(?:$(?:$(?:$(?:$(?:$(?:$(?:$(?:${-2,16}+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+/.exec("a");
+
+/$(?=$(?=$(?=$(?=$(?=$(?=$(?=$(?=$(?=$(?=$(?=$(?=$(?=$(?=$(?=$(?=$(?=$(?=$(?=$(?=${-2,16}+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+)+/.exec("a");
+
+
+

Modified: releases/WebKitGTK/webkit-2.14/Source/_javascript_Core/ChangeLog (214999 => 215000)


--- releases/WebKitGTK/webkit-2.14/Source/_javascript_Core/ChangeLog	2017-04-06 08:05:31 UTC (rev 214999)
+++ releases/WebKitGTK/webkit-2.14/Source/_javascript_Core/ChangeLog	2017-04-06 08:23:15 UTC (rev 215000)
@@ -1,3 +1,79 @@
+2017-01-17  Michael Saboff  <msab...@apple.com>
+
+        Nested parenthesized regular expressions with non-zero minimum counts appear to hang and use lots of memory
+        https://bugs.webkit.org/show_bug.cgi?id=167125
+
+        Reviewed by Filip Pizlo.
+
+        Changed Yarr to handle nested parenthesized subexpressions where the minimum count is
+        not 0 directly in the Yarr interpreter.  Previously we'd factor an _expression_ like
+        (a|b)+ into (a|b)(a|b)* with special handling for captures.  This factoring was done
+        using a deep copy that doubled the size of the resulting expresion for each nested 
+        parenthesized subexpression.  Now the Yarr interpreter can directly process a regexp
+        like (a|b){2,42}.  
+
+        The parser will allow one level of nested, non-zero minimum, counted parenthesis using
+        the old copy method.  After one level, it will generate parenthesis terms with a non-zero
+        minimum.   Such an _expression_ wasn't handled by the Yarr JIT before the change, so this
+        change isn't a performance regression.
+
+        Added a minimum count to the YarrPattern and ByteTerm classes, and then factored that
+        minimum into the interpreter.  A non-zero minimum is only handled by the Yarr interpreter.
+        If the Yarr JIT see such a term, it punts back to the interpreter.
+
+        * yarr/YarrInterpreter.cpp:
+        (JSC::Yarr::Interpreter::backtrackPatternCharacter):
+        (JSC::Yarr::Interpreter::backtrackPatternCasedCharacter):
+        (JSC::Yarr::Interpreter::matchCharacterClass):
+        (JSC::Yarr::Interpreter::backtrackCharacterClass):
+        (JSC::Yarr::Interpreter::matchBackReference):
+        (JSC::Yarr::Interpreter::backtrackBackReference):
+        (JSC::Yarr::Interpreter::matchParenthesesOnceBegin):
+        (JSC::Yarr::Interpreter::matchParenthesesOnceEnd):
+        (JSC::Yarr::Interpreter::backtrackParenthesesOnceBegin):
+        (JSC::Yarr::Interpreter::backtrackParenthesesOnceEnd):
+        (JSC::Yarr::Interpreter::matchParenthesesTerminalBegin):
+        (JSC::Yarr::Interpreter::backtrackParenthesesTerminalBegin):
+        (JSC::Yarr::Interpreter::matchParentheticalAssertionBegin):
+        (JSC::Yarr::Interpreter::matchParentheticalAssertionEnd):
+        (JSC::Yarr::Interpreter::backtrackParentheticalAssertionBegin):
+        (JSC::Yarr::Interpreter::backtrackParentheticalAssertionEnd):
+        (JSC::Yarr::Interpreter::matchParentheses):
+        (JSC::Yarr::Interpreter::backtrackParentheses):
+        (JSC::Yarr::Interpreter::matchDisjunction):
+        (JSC::Yarr::ByteCompiler::atomPatternCharacter):
+        (JSC::Yarr::ByteCompiler::atomCharacterClass):
+        (JSC::Yarr::ByteCompiler::atomBackReference):
+        (JSC::Yarr::ByteCompiler::atomParentheticalAssertionEnd):
+        (JSC::Yarr::ByteCompiler::atomParenthesesSubpatternEnd):
+        (JSC::Yarr::ByteCompiler::atomParenthesesOnceEnd):
+        (JSC::Yarr::ByteCompiler::atomParenthesesTerminalEnd):
+        (JSC::Yarr::ByteCompiler::emitDisjunction):
+        * yarr/YarrInterpreter.h:
+        (JSC::Yarr::ByteTerm::ByteTerm):
+        * yarr/YarrJIT.cpp:
+        (JSC::Yarr::YarrGenerator::generatePatternCharacterOnce):
+        (JSC::Yarr::YarrGenerator::generatePatternCharacterFixed):
+        (JSC::Yarr::YarrGenerator::generatePatternCharacterGreedy):
+        (JSC::Yarr::YarrGenerator::backtrackPatternCharacterNonGreedy):
+        (JSC::Yarr::YarrGenerator::generateCharacterClassFixed):
+        (JSC::Yarr::YarrGenerator::generateCharacterClassGreedy):
+        (JSC::Yarr::YarrGenerator::backtrackCharacterClassNonGreedy):
+        (JSC::Yarr::YarrGenerator::generateTerm):
+        (JSC::Yarr::YarrGenerator::backtrackTerm):
+        (JSC::Yarr::YarrGenerator::generate):
+        (JSC::Yarr::YarrGenerator::backtrack):
+        (JSC::Yarr::YarrGenerator::opCompileParenthesesSubpattern):
+        * yarr/YarrPattern.cpp:
+        (JSC::Yarr::YarrPatternConstructor::copyTerm):
+        (JSC::Yarr::YarrPatternConstructor::quantifyAtom):
+        (JSC::Yarr::YarrPatternConstructor::checkForTerminalParentheses):
+        (JSC::Yarr::YarrPattern::YarrPattern):
+        * yarr/YarrPattern.h:
+        (JSC::Yarr::PatternTerm::PatternTerm):
+        (JSC::Yarr::PatternTerm::quantify):
+        (JSC::Yarr::YarrPattern::reset):
+
 2016-11-15  Mark Lam  <mark....@apple.com>
 
         The jsc shell's setImpureGetterDelegate() should ensure that the set value is an ImpureGetter.

Modified: releases/WebKitGTK/webkit-2.14/Source/_javascript_Core/yarr/YarrInterpreter.cpp (214999 => 215000)


--- releases/WebKitGTK/webkit-2.14/Source/_javascript_Core/yarr/YarrInterpreter.cpp	2017-04-06 08:05:31 UTC (rev 214999)
+++ releases/WebKitGTK/webkit-2.14/Source/_javascript_Core/yarr/YarrInterpreter.cpp	2017-04-06 08:23:15 UTC (rev 215000)
@@ -438,7 +438,7 @@
             break;
 
         case QuantifierNonGreedy:
-            if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
+            if ((backTrack->matchAmount < term.atom.quantityMaxCount) && input.checkInput(1)) {
                 ++backTrack->matchAmount;
                 if (checkCharacter(term.atom.patternCharacter, term.inputPosition + 1))
                     return true;
@@ -467,7 +467,7 @@
             break;
 
         case QuantifierNonGreedy:
-            if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
+            if ((backTrack->matchAmount < term.atom.quantityMaxCount) && input.checkInput(1)) {
                 ++backTrack->matchAmount;
                 if (checkCasedCharacter(term.atom.casedCharacter.lo, term.atom.casedCharacter.hi, term.inputPosition + 1))
                     return true;
@@ -489,7 +489,7 @@
             if (unicode) {
                 backTrack->begin = input.getPos();
                 unsigned matchAmount = 0;
-                for (matchAmount = 0; matchAmount < term.atom.quantityCount; ++matchAmount) {
+                for (matchAmount = 0; matchAmount < term.atom.quantityMaxCount; ++matchAmount) {
                     if (!checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition - matchAmount)) {
                         input.setPos(backTrack->begin);
                         return false;
@@ -499,7 +499,7 @@
                 return true;
             }
 
-            for (unsigned matchAmount = 0; matchAmount < term.atom.quantityCount; ++matchAmount) {
+            for (unsigned matchAmount = 0; matchAmount < term.atom.quantityMaxCount; ++matchAmount) {
                 if (!checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition - matchAmount))
                     return false;
             }
@@ -510,7 +510,7 @@
             unsigned position = input.getPos();
             backTrack->begin = position;
             unsigned matchAmount = 0;
-            while ((matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
+            while ((matchAmount < term.atom.quantityMaxCount) && input.checkInput(1)) {
                 if (!checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition + 1)) {
                     input.setPos(position);
                     break;
@@ -565,7 +565,7 @@
             break;
 
         case QuantifierNonGreedy:
-            if ((backTrack->matchAmount < term.atom.quantityCount) && input.checkInput(1)) {
+            if ((backTrack->matchAmount < term.atom.quantityMaxCount) && input.checkInput(1)) {
                 ++backTrack->matchAmount;
                 if (checkCharacterClass(term.atom.characterClass, term.invert(), term.inputPosition + 1))
                     return true;
@@ -602,7 +602,7 @@
         switch (term.atom.quantityType) {
         case QuantifierFixedCount: {
             backTrack->begin = input.getPos();
-            for (unsigned matchAmount = 0; matchAmount < term.atom.quantityCount; ++matchAmount) {
+            for (unsigned matchAmount = 0; matchAmount < term.atom.quantityMaxCount; ++matchAmount) {
                 if (!tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition)) {
                     input.setPos(backTrack->begin);
                     return false;
@@ -613,7 +613,7 @@
 
         case QuantifierGreedy: {
             unsigned matchAmount = 0;
-            while ((matchAmount < term.atom.quantityCount) && tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition))
+            while ((matchAmount < term.atom.quantityMaxCount) && tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition))
                 ++matchAmount;
             backTrack->matchAmount = matchAmount;
             return true;
@@ -647,7 +647,7 @@
 
         switch (term.atom.quantityType) {
         case QuantifierFixedCount:
-            // for quantityCount == 1, could rewind.
+            // for quantityMaxCount == 1, could rewind.
             input.setPos(backTrack->begin);
             break;
 
@@ -660,7 +660,7 @@
             break;
 
         case QuantifierNonGreedy:
-            if ((backTrack->matchAmount < term.atom.quantityCount) && tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition)) {
+            if ((backTrack->matchAmount < term.atom.quantityMaxCount) && tryConsumeBackReference(matchBegin, matchEnd, term.inputPosition)) {
                 ++backTrack->matchAmount;
                 return true;
             }
@@ -708,7 +708,7 @@
     bool matchParenthesesOnceBegin(ByteTerm& term, DisjunctionContext* context)
     {
         ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
-        ASSERT(term.atom.quantityCount == 1);
+        ASSERT(term.atom.quantityMaxCount == 1);
 
         BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast<BackTrackInfoParenthesesOnce*>(context->frame + term.frameLocation);
 
@@ -738,7 +738,7 @@
     bool matchParenthesesOnceEnd(ByteTerm& term, DisjunctionContext* context)
     {
         ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceEnd);
-        ASSERT(term.atom.quantityCount == 1);
+        ASSERT(term.atom.quantityMaxCount == 1);
 
         if (term.capture()) {
             unsigned subpatternId = term.atom.subpatternId;
@@ -755,7 +755,7 @@
     bool backtrackParenthesesOnceBegin(ByteTerm& term, DisjunctionContext* context)
     {
         ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
-        ASSERT(term.atom.quantityCount == 1);
+        ASSERT(term.atom.quantityMaxCount == 1);
 
         BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast<BackTrackInfoParenthesesOnce*>(context->frame + term.frameLocation);
 
@@ -785,7 +785,7 @@
     bool backtrackParenthesesOnceEnd(ByteTerm& term, DisjunctionContext* context)
     {
         ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceEnd);
-        ASSERT(term.atom.quantityCount == 1);
+        ASSERT(term.atom.quantityMaxCount == 1);
 
         BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast<BackTrackInfoParenthesesOnce*>(context->frame + term.frameLocation);
 
@@ -823,7 +823,7 @@
     {
         ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalBegin);
         ASSERT(term.atom.quantityType == QuantifierGreedy);
-        ASSERT(term.atom.quantityCount == quantifyInfinite);
+        ASSERT(term.atom.quantityMaxCount == quantifyInfinite);
         ASSERT(!term.capture());
 
         BackTrackInfoParenthesesTerminal* backTrack = reinterpret_cast<BackTrackInfoParenthesesTerminal*>(context->frame + term.frameLocation);
@@ -849,7 +849,7 @@
     {
         ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalBegin);
         ASSERT(term.atom.quantityType == QuantifierGreedy);
-        ASSERT(term.atom.quantityCount == quantifyInfinite);
+        ASSERT(term.atom.quantityMaxCount == quantifyInfinite);
         ASSERT(!term.capture());
 
         // If we backtrack to this point, we have failed to match this iteration of the parens.
@@ -869,7 +869,7 @@
     bool matchParentheticalAssertionBegin(ByteTerm& term, DisjunctionContext* context)
     {
         ASSERT(term.type == ByteTerm::TypeParentheticalAssertionBegin);
-        ASSERT(term.atom.quantityCount == 1);
+        ASSERT(term.atom.quantityMaxCount == 1);
 
         BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast<BackTrackInfoParentheticalAssertion*>(context->frame + term.frameLocation);
 
@@ -880,7 +880,7 @@
     bool matchParentheticalAssertionEnd(ByteTerm& term, DisjunctionContext* context)
     {
         ASSERT(term.type == ByteTerm::TypeParentheticalAssertionEnd);
-        ASSERT(term.atom.quantityCount == 1);
+        ASSERT(term.atom.quantityMaxCount == 1);
 
         BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast<BackTrackInfoParentheticalAssertion*>(context->frame + term.frameLocation);
 
@@ -898,7 +898,7 @@
     bool backtrackParentheticalAssertionBegin(ByteTerm& term, DisjunctionContext* context)
     {
         ASSERT(term.type == ByteTerm::TypeParentheticalAssertionBegin);
-        ASSERT(term.atom.quantityCount == 1);
+        ASSERT(term.atom.quantityMaxCount == 1);
 
         // We've failed to match parens; if they are inverted, this is win!
         if (term.invert()) {
@@ -912,7 +912,7 @@
     bool backtrackParentheticalAssertionEnd(ByteTerm& term, DisjunctionContext* context)
     {
         ASSERT(term.type == ByteTerm::TypeParentheticalAssertionEnd);
-        ASSERT(term.atom.quantityCount == 1);
+        ASSERT(term.atom.quantityMaxCount == 1);
 
         BackTrackInfoParentheticalAssertion* backTrack = reinterpret_cast<BackTrackInfoParentheticalAssertion*>(context->frame + term.frameLocation);
 
@@ -932,22 +932,27 @@
         backTrack->matchAmount = 0;
         backTrack->lastContext = 0;
 
-        switch (term.atom.quantityType) {
-        case QuantifierFixedCount: {
+        ASSERT(term.atom.quantityType != QuantifierFixedCount || term.atom.quantityMinCount == term.atom.quantityMaxCount);
+
+        unsigned minimumMatchCount = term.atom.quantityMinCount;
+        JSRegExpResult fixedMatchResult;
+
+        // Handle fixed matches and the minimum part of a variable length match.
+        if (minimumMatchCount) {
             // While we haven't yet reached our fixed limit,
-            while (backTrack->matchAmount < term.atom.quantityCount) {
+            while (backTrack->matchAmount < minimumMatchCount) {
                 // Try to do a match, and it it succeeds, add it to the list.
                 ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
-                JSRegExpResult result = matchDisjunction(disjunctionBody, context->getDisjunctionContext(term));
-                if (result == JSRegExpMatch)
+                fixedMatchResult = matchDisjunction(disjunctionBody, context->getDisjunctionContext(term));
+                if (fixedMatchResult == JSRegExpMatch)
                     appendParenthesesDisjunctionContext(backTrack, context);
                 else {
                     // The match failed; try to find an alternate point to carry on from.
                     resetMatches(term, context);
                     freeParenthesesDisjunctionContext(context);
-
-                    if (result != JSRegExpNoMatch)
-                        return result;
+                    
+                    if (fixedMatchResult != JSRegExpNoMatch)
+                        return fixedMatchResult;
                     JSRegExpResult backtrackResult = parenthesesDoBacktrack(term, backTrack);
                     if (backtrackResult != JSRegExpMatch)
                         return backtrackResult;
@@ -954,14 +959,18 @@
                 }
             }
 
-            ASSERT(backTrack->matchAmount == term.atom.quantityCount);
             ParenthesesDisjunctionContext* context = backTrack->lastContext;
             recordParenthesesMatch(term, context);
+        }
+
+        switch (term.atom.quantityType) {
+        case QuantifierFixedCount: {
+            ASSERT(backTrack->matchAmount == term.atom.quantityMaxCount);
             return JSRegExpMatch;
         }
 
         case QuantifierGreedy: {
-            while (backTrack->matchAmount < term.atom.quantityCount) {
+            while (backTrack->matchAmount < term.atom.quantityMaxCount) {
                 ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
                 JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term));
                 if (result == JSRegExpMatch)
@@ -1011,7 +1020,7 @@
 
         switch (term.atom.quantityType) {
         case QuantifierFixedCount: {
-            ASSERT(backTrack->matchAmount == term.atom.quantityCount);
+            ASSERT(backTrack->matchAmount == term.atom.quantityMaxCount);
 
             ParenthesesDisjunctionContext* context = 0;
             JSRegExpResult result = parenthesesDoBacktrack(term, backTrack);
@@ -1020,7 +1029,7 @@
                 return result;
 
             // While we haven't yet reached our fixed limit,
-            while (backTrack->matchAmount < term.atom.quantityCount) {
+            while (backTrack->matchAmount < term.atom.quantityMaxCount) {
                 // Try to do a match, and it it succeeds, add it to the list.
                 context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
                 result = matchDisjunction(disjunctionBody, context->getDisjunctionContext(term));
@@ -1040,7 +1049,7 @@
                 }
             }
 
-            ASSERT(backTrack->matchAmount == term.atom.quantityCount);
+            ASSERT(backTrack->matchAmount == term.atom.quantityMaxCount);
             context = backTrack->lastContext;
             recordParenthesesMatch(term, context);
             return JSRegExpMatch;
@@ -1053,7 +1062,7 @@
             ParenthesesDisjunctionContext* context = backTrack->lastContext;
             JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term), true);
             if (result == JSRegExpMatch) {
-                while (backTrack->matchAmount < term.atom.quantityCount) {
+                while (backTrack->matchAmount < term.atom.quantityMaxCount) {
                     ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
                     JSRegExpResult parenthesesResult = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term));
                     if (parenthesesResult == JSRegExpMatch)
@@ -1086,7 +1095,7 @@
 
         case QuantifierNonGreedy: {
             // If we've not reached the limit, try to add one more match.
-            if (backTrack->matchAmount < term.atom.quantityCount) {
+            if (backTrack->matchAmount < term.atom.quantityMaxCount) {
                 ParenthesesDisjunctionContext* context = allocParenthesesDisjunctionContext(disjunctionBody, output, term);
                 JSRegExpResult result = matchNonZeroDisjunction(disjunctionBody, context->getDisjunctionContext(term));
                 if (result == JSRegExpMatch) {
@@ -1223,7 +1232,7 @@
         case ByteTerm::TypePatternCharacterFixed: {
             if (unicode) {
                 if (!U_IS_BMP(currentTerm().atom.patternCharacter)) {
-                    for (unsigned matchAmount = 0; matchAmount < currentTerm().atom.quantityCount; ++matchAmount) {
+                    for (unsigned matchAmount = 0; matchAmount < currentTerm().atom.quantityMaxCount; ++matchAmount) {
                         if (!checkSurrogatePair(currentTerm().atom.patternCharacter, currentTerm().inputPosition - 2 * matchAmount)) {
                             BACKTRACK();
                         }
@@ -1233,7 +1242,7 @@
             }
             unsigned position = input.getPos(); // May need to back out reading a surrogate pair.
 
-            for (unsigned matchAmount = 0; matchAmount < currentTerm().atom.quantityCount; ++matchAmount) {
+            for (unsigned matchAmount = 0; matchAmount < currentTerm().atom.quantityMaxCount; ++matchAmount) {
                 if (!checkCharacter(currentTerm().atom.patternCharacter, currentTerm().inputPosition - matchAmount)) {
                     input.setPos(position);
                     BACKTRACK();
@@ -1245,7 +1254,7 @@
             BackTrackInfoPatternCharacter* backTrack = reinterpret_cast<BackTrackInfoPatternCharacter*>(context->frame + currentTerm().frameLocation);
             unsigned matchAmount = 0;
             unsigned position = input.getPos(); // May need to back out reading a surrogate pair.
-            while ((matchAmount < currentTerm().atom.quantityCount) && input.checkInput(1)) {
+            while ((matchAmount < currentTerm().atom.quantityMaxCount) && input.checkInput(1)) {
                 if (!checkCharacter(currentTerm().atom.patternCharacter, currentTerm().inputPosition + 1)) {
                     input.setPos(position);
                     break;
@@ -1272,7 +1281,7 @@
 
                 unsigned position = input.getPos(); // May need to back out reading a surrogate pair.
                 
-                for (unsigned matchAmount = 0; matchAmount < currentTerm().atom.quantityCount; ++matchAmount) {
+                for (unsigned matchAmount = 0; matchAmount < currentTerm().atom.quantityMaxCount; ++matchAmount) {
                     if (!checkCasedCharacter(currentTerm().atom.casedCharacter.lo, currentTerm().atom.casedCharacter.hi, currentTerm().inputPosition - matchAmount)) {
                         input.setPos(position);
                         BACKTRACK();
@@ -1281,7 +1290,7 @@
                 MATCH_NEXT();
             }
 
-            for (unsigned matchAmount = 0; matchAmount < currentTerm().atom.quantityCount; ++matchAmount) {
+            for (unsigned matchAmount = 0; matchAmount < currentTerm().atom.quantityMaxCount; ++matchAmount) {
                 if (!checkCasedCharacter(currentTerm().atom.casedCharacter.lo, currentTerm().atom.casedCharacter.hi, currentTerm().inputPosition - matchAmount))
                     BACKTRACK();
             }
@@ -1294,7 +1303,7 @@
             ASSERT(!unicode || U_IS_BMP(currentTerm().atom.patternCharacter));
 
             unsigned matchAmount = 0;
-            while ((matchAmount < currentTerm().atom.quantityCount) && input.checkInput(1)) {
+            while ((matchAmount < currentTerm().atom.quantityMaxCount) && input.checkInput(1)) {
                 if (!checkCasedCharacter(currentTerm().atom.casedCharacter.lo, currentTerm().atom.casedCharacter.hi, currentTerm().inputPosition + 1)) {
                     input.uncheckInput(1);
                     break;
@@ -1622,7 +1631,7 @@
         m_bodyDisjunction->terms.append(ByteTerm::WordBoundary(invert, inputPosition));
     }
 
-    void atomPatternCharacter(UChar32 ch, unsigned inputPosition, unsigned frameLocation, Checked<unsigned> quantityCount, QuantifierType quantityType)
+    void atomPatternCharacter(UChar32 ch, unsigned inputPosition, unsigned frameLocation, Checked<unsigned> quantityMaxCount, QuantifierType quantityType)
     {
         if (m_pattern.ignoreCase()) {
             UChar32 lo = u_tolower(ch);
@@ -1629,30 +1638,30 @@
             UChar32 hi = u_toupper(ch);
 
             if (lo != hi) {
-                m_bodyDisjunction->terms.append(ByteTerm(lo, hi, inputPosition, frameLocation, quantityCount, quantityType));
+                m_bodyDisjunction->terms.append(ByteTerm(lo, hi, inputPosition, frameLocation, quantityMaxCount, quantityType));
                 return;
             }
         }
 
-        m_bodyDisjunction->terms.append(ByteTerm(ch, inputPosition, frameLocation, quantityCount, quantityType));
+        m_bodyDisjunction->terms.append(ByteTerm(ch, inputPosition, frameLocation, quantityMaxCount, quantityType));
     }
 
-    void atomCharacterClass(CharacterClass* characterClass, bool invert, unsigned inputPosition, unsigned frameLocation, Checked<unsigned> quantityCount, QuantifierType quantityType)
+    void atomCharacterClass(CharacterClass* characterClass, bool invert, unsigned inputPosition, unsigned frameLocation, Checked<unsigned> quantityMaxCount, QuantifierType quantityType)
     {
         m_bodyDisjunction->terms.append(ByteTerm(characterClass, invert, inputPosition));
 
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityCount = quantityCount.unsafeGet();
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityMaxCount = quantityMaxCount.unsafeGet();
         m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityType = quantityType;
         m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
     }
 
-    void atomBackReference(unsigned subpatternId, unsigned inputPosition, unsigned frameLocation, Checked<unsigned> quantityCount, QuantifierType quantityType)
+    void atomBackReference(unsigned subpatternId, unsigned inputPosition, unsigned frameLocation, Checked<unsigned> quantityMaxCount, QuantifierType quantityType)
     {
         ASSERT(subpatternId);
 
         m_bodyDisjunction->terms.append(ByteTerm::BackReference(subpatternId, inputPosition));
 
-        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityCount = quantityCount.unsafeGet();
+        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityMaxCount = quantityMaxCount.unsafeGet();
         m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityType = quantityType;
         m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
     }
@@ -1713,7 +1722,7 @@
         m_currentAlternativeIndex = beginTerm + 1;
     }
 
-    void atomParentheticalAssertionEnd(unsigned inputPosition, unsigned frameLocation, Checked<unsigned> quantityCount, QuantifierType quantityType)
+    void atomParentheticalAssertionEnd(unsigned inputPosition, unsigned frameLocation, Checked<unsigned> quantityMaxCount, QuantifierType quantityType)
     {
         unsigned beginTerm = popParenthesesStack();
         closeAlternative(beginTerm + 1);
@@ -1729,9 +1738,9 @@
         m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm;
         m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation;
 
-        m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount.unsafeGet();
+        m_bodyDisjunction->terms[beginTerm].atom.quantityMaxCount = quantityMaxCount.unsafeGet();
         m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
-        m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount.unsafeGet();
+        m_bodyDisjunction->terms[endTerm].atom.quantityMaxCount = quantityMaxCount.unsafeGet();
         m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType;
     }
 
@@ -1811,7 +1820,7 @@
         m_bodyDisjunction->terms[endIndex].frameLocation = frameLocation;
     }
 
-    void atomParenthesesSubpatternEnd(unsigned lastSubpatternId, unsigned inputPosition, unsigned frameLocation, Checked<unsigned> quantityCount, QuantifierType quantityType, unsigned callFrameSize = 0)
+    void atomParenthesesSubpatternEnd(unsigned lastSubpatternId, unsigned inputPosition, unsigned frameLocation, Checked<unsigned> quantityMinCount, Checked<unsigned> quantityMaxCount, QuantifierType quantityType, unsigned callFrameSize = 0)
     {
         unsigned beginTerm = popParenthesesStack();
         closeAlternative(beginTerm + 1);
@@ -1840,12 +1849,13 @@
         m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction.get(), capture, inputPosition));
         m_allParenthesesInfo.append(WTFMove(parenthesesDisjunction));
 
-        m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount.unsafeGet();
+        m_bodyDisjunction->terms[beginTerm].atom.quantityMinCount = quantityMinCount.unsafeGet();
+        m_bodyDisjunction->terms[beginTerm].atom.quantityMaxCount = quantityMaxCount.unsafeGet();
         m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
         m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation;
     }
 
-    void atomParenthesesOnceEnd(unsigned inputPosition, unsigned frameLocation, Checked<unsigned> quantityCount, QuantifierType quantityType)
+    void atomParenthesesOnceEnd(unsigned inputPosition, unsigned frameLocation, Checked<unsigned> quantityMinCount, Checked<unsigned> quantityMaxCount, QuantifierType quantityType)
     {
         unsigned beginTerm = popParenthesesStack();
         closeAlternative(beginTerm + 1);
@@ -1861,13 +1871,15 @@
         m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm;
         m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation;
 
-        m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount.unsafeGet();
+        m_bodyDisjunction->terms[beginTerm].atom.quantityMinCount = quantityMinCount.unsafeGet();
+        m_bodyDisjunction->terms[beginTerm].atom.quantityMaxCount = quantityMaxCount.unsafeGet();
         m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
-        m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount.unsafeGet();
+        m_bodyDisjunction->terms[endTerm].atom.quantityMinCount = quantityMinCount.unsafeGet();
+        m_bodyDisjunction->terms[endTerm].atom.quantityMaxCount = quantityMaxCount.unsafeGet();
         m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType;
     }
 
-    void atomParenthesesTerminalEnd(unsigned inputPosition, unsigned frameLocation, Checked<unsigned> quantityCount, QuantifierType quantityType)
+    void atomParenthesesTerminalEnd(unsigned inputPosition, unsigned frameLocation, Checked<unsigned> quantityMinCount, Checked<unsigned> quantityMaxCount, QuantifierType quantityType)
     {
         unsigned beginTerm = popParenthesesStack();
         closeAlternative(beginTerm + 1);
@@ -1883,9 +1895,11 @@
         m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm;
         m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation;
 
-        m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount.unsafeGet();
+        m_bodyDisjunction->terms[beginTerm].atom.quantityMinCount = quantityMinCount.unsafeGet();
+        m_bodyDisjunction->terms[beginTerm].atom.quantityMaxCount = quantityMaxCount.unsafeGet();
         m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
-        m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount.unsafeGet();
+        m_bodyDisjunction->terms[endTerm].atom.quantityMinCount = quantityMinCount.unsafeGet();
+        m_bodyDisjunction->terms[endTerm].atom.quantityMaxCount = quantityMaxCount.unsafeGet();
         m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType;
     }
 
@@ -1960,15 +1974,15 @@
                     break;
 
                 case PatternTerm::TypePatternCharacter:
-                    atomPatternCharacter(term.patternCharacter, currentCountAlreadyChecked - term.inputPosition, term.frameLocation, term.quantityCount, term.quantityType);
+                    atomPatternCharacter(term.patternCharacter, currentCountAlreadyChecked - term.inputPosition, term.frameLocation, term.quantityMaxCount, term.quantityType);
                     break;
 
                 case PatternTerm::TypeCharacterClass:
-                    atomCharacterClass(term.characterClass, term.invert(), currentCountAlreadyChecked- term.inputPosition, term.frameLocation, term.quantityCount, term.quantityType);
+                    atomCharacterClass(term.characterClass, term.invert(), currentCountAlreadyChecked- term.inputPosition, term.frameLocation, term.quantityMaxCount, term.quantityType);
                     break;
 
                 case PatternTerm::TypeBackReference:
-                    atomBackReference(term.backReferenceSubpatternId, currentCountAlreadyChecked - term.inputPosition, term.frameLocation, term.quantityCount, term.quantityType);
+                    atomBackReference(term.backReferenceSubpatternId, currentCountAlreadyChecked - term.inputPosition, term.frameLocation, term.quantityMaxCount, term.quantityType);
                         break;
 
                 case PatternTerm::TypeForwardReference:
@@ -1976,7 +1990,7 @@
 
                 case PatternTerm::TypeParenthesesSubpattern: {
                     unsigned disjunctionAlreadyCheckedCount = 0;
-                    if (term.quantityCount == 1 && !term.parentheses.isCopy) {
+                    if (term.quantityMaxCount == 1 && !term.parentheses.isCopy) {
                         unsigned alternativeFrameLocation = term.frameLocation;
                         // For QuantifierFixedCount we pre-check the minimum size; for greedy/non-greedy we reserve a slot in the frame.
                         if (term.quantityType == QuantifierFixedCount)
@@ -1987,19 +2001,19 @@
                         unsigned delegateEndInputOffset = currentCountAlreadyChecked - term.inputPosition;
                         atomParenthesesOnceBegin(term.parentheses.subpatternId, term.capture(), disjunctionAlreadyCheckedCount + delegateEndInputOffset, term.frameLocation, alternativeFrameLocation);
                         emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, disjunctionAlreadyCheckedCount);
-                        atomParenthesesOnceEnd(delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType);
+                        atomParenthesesOnceEnd(delegateEndInputOffset, term.frameLocation, term.quantityMinCount, term.quantityMaxCount, term.quantityType);
                     } else if (term.parentheses.isTerminal) {
                         ASSERT(currentCountAlreadyChecked >= term.inputPosition);
                         unsigned delegateEndInputOffset = currentCountAlreadyChecked - term.inputPosition;
                         atomParenthesesTerminalBegin(term.parentheses.subpatternId, term.capture(), disjunctionAlreadyCheckedCount + delegateEndInputOffset, term.frameLocation, term.frameLocation + YarrStackSpaceForBackTrackInfoParenthesesOnce);
                         emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, disjunctionAlreadyCheckedCount);
-                        atomParenthesesTerminalEnd(delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType);
+                        atomParenthesesTerminalEnd(delegateEndInputOffset, term.frameLocation, term.quantityMinCount, term.quantityMaxCount, term.quantityType);
                     } else {
                         ASSERT(currentCountAlreadyChecked >= term.inputPosition);
                         unsigned delegateEndInputOffset = currentCountAlreadyChecked - term.inputPosition;
                         atomParenthesesSubpatternBegin(term.parentheses.subpatternId, term.capture(), disjunctionAlreadyCheckedCount + delegateEndInputOffset, term.frameLocation, 0);
                         emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, 0);
-                        atomParenthesesSubpatternEnd(term.parentheses.lastSubpatternId, delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType, term.parentheses.disjunction->m_callFrameSize);
+                        atomParenthesesSubpatternEnd(term.parentheses.lastSubpatternId, delegateEndInputOffset, term.frameLocation, term.quantityMinCount, term.quantityMaxCount, term.quantityType, term.parentheses.disjunction->m_callFrameSize);
                     }
                     break;
                 }
@@ -2018,7 +2032,7 @@
 
                     atomParentheticalAssertionBegin(term.parentheses.subpatternId, term.invert(), term.frameLocation, alternativeFrameLocation);
                     emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, positiveInputOffset - uncheckAmount);
-                    atomParentheticalAssertionEnd(0, term.frameLocation, term.quantityCount, term.quantityType);
+                    atomParentheticalAssertionEnd(0, term.frameLocation, term.quantityMaxCount, term.quantityType);
                     if (uncheckAmount) {
                         checkInput(uncheckAmount);
                         currentCountAlreadyChecked += uncheckAmount;

Modified: releases/WebKitGTK/webkit-2.14/Source/_javascript_Core/yarr/YarrInterpreter.h (214999 => 215000)


--- releases/WebKitGTK/webkit-2.14/Source/_javascript_Core/yarr/YarrInterpreter.h	2017-04-06 08:05:31 UTC (rev 214999)
+++ releases/WebKitGTK/webkit-2.14/Source/_javascript_Core/yarr/YarrInterpreter.h	2017-04-06 08:23:15 UTC (rev 215000)
@@ -88,7 +88,8 @@
                 unsigned parenthesesWidth;
             };
             QuantifierType quantityType;
-            unsigned quantityCount;
+            unsigned quantityMinCount;
+            unsigned quantityMaxCount;
         } atom;
         struct {
             int next;
@@ -111,6 +112,12 @@
         , m_capture(false)
         , m_invert(false)
     {
+        atom.patternCharacter = ch;
+        atom.quantityType = quantityType;
+        atom.quantityMinCount = quantityCount.unsafeGet();
+        atom.quantityMaxCount = quantityCount.unsafeGet();
+        inputPosition = inputPos;
+
         switch (quantityType) {
         case QuantifierFixedCount:
             type = (quantityCount == 1) ? ByteTerm::TypePatternCharacterOnce : ByteTerm::TypePatternCharacterFixed;
@@ -122,11 +129,6 @@
             type = ByteTerm::TypePatternCharacterNonGreedy;
             break;
         }
-
-        atom.patternCharacter = ch;
-        atom.quantityType = quantityType;
-        atom.quantityCount = quantityCount.unsafeGet();
-        inputPosition = inputPos;
     }
 
     ByteTerm(UChar32 lo, UChar32 hi, unsigned inputPos, unsigned frameLocation, Checked<unsigned> quantityCount, QuantifierType quantityType)
@@ -149,7 +151,8 @@
         atom.casedCharacter.lo = lo;
         atom.casedCharacter.hi = hi;
         atom.quantityType = quantityType;
-        atom.quantityCount = quantityCount.unsafeGet();
+        atom.quantityMinCount = quantityCount.unsafeGet();
+        atom.quantityMaxCount = quantityCount.unsafeGet();
         inputPosition = inputPos;
     }
 
@@ -160,7 +163,8 @@
     {
         atom.characterClass = characterClass;
         atom.quantityType = QuantifierFixedCount;
-        atom.quantityCount = 1;
+        atom.quantityMinCount = 1;
+        atom.quantityMaxCount = 1;
         inputPosition = inputPos;
     }
 
@@ -172,7 +176,8 @@
         atom.subpatternId = subpatternId;
         atom.parenthesesDisjunction = parenthesesInfo;
         atom.quantityType = QuantifierFixedCount;
-        atom.quantityCount = 1;
+        atom.quantityMinCount = 1;
+        atom.quantityMaxCount = 1;
         inputPosition = inputPos;
     }
     
@@ -182,7 +187,8 @@
         , m_invert(invert)
     {
         atom.quantityType = QuantifierFixedCount;
-        atom.quantityCount = 1;
+        atom.quantityMinCount = 1;
+        atom.quantityMaxCount = 1;
     }
 
     ByteTerm(Type type, unsigned subpatternId, bool capture, bool invert, unsigned inputPos)
@@ -192,7 +198,8 @@
     {
         atom.subpatternId = subpatternId;
         atom.quantityType = QuantifierFixedCount;
-        atom.quantityCount = 1;
+        atom.quantityMinCount = 1;
+        atom.quantityMaxCount = 1;
         inputPosition = inputPos;
     }
 

Modified: releases/WebKitGTK/webkit-2.14/Source/_javascript_Core/yarr/YarrJIT.cpp (214999 => 215000)


--- releases/WebKitGTK/webkit-2.14/Source/_javascript_Core/yarr/YarrJIT.cpp	2017-04-06 08:05:31 UTC (rev 214999)
+++ releases/WebKitGTK/webkit-2.14/Source/_javascript_Core/yarr/YarrJIT.cpp	2017-04-06 08:23:15 UTC (rev 215000)
@@ -464,7 +464,7 @@
         OpSimpleNestedAlternativeBegin,
         OpSimpleNestedAlternativeNext,
         OpSimpleNestedAlternativeEnd,
-        // Used to wrap 'Once' subpattern matches (quantityCount == 1).
+        // Used to wrap 'Once' subpattern matches (quantityMaxCount == 1).
         OpParenthesesSubpatternOnceBegin,
         OpParenthesesSubpatternOnceEnd,
         // Used to wrap 'Terminal' subpattern matches (at the end of the regexp).
@@ -841,7 +841,7 @@
             
             if (nextTerm->type != PatternTerm::TypePatternCharacter
                 || nextTerm->quantityType != QuantifierFixedCount
-                || nextTerm->quantityCount != 1
+                || nextTerm->quantityMaxCount != 1
                 || nextTerm->inputPosition != (startTermPosition + numberCharacters))
                 break;
 
@@ -924,10 +924,10 @@
         const RegisterID countRegister = regT1;
 
         move(index, countRegister);
-        sub32(Imm32(term->quantityCount.unsafeGet()), countRegister);
+        sub32(Imm32(term->quantityMaxCount.unsafeGet()), countRegister);
 
         Label loop(this);
-        readCharacter(m_checkedOffset - term->inputPosition - term->quantityCount, character, countRegister);
+        readCharacter(m_checkedOffset - term->inputPosition - term->quantityMaxCount, character, countRegister);
         // For case-insesitive compares, non-ascii characters that have different
         // upper & lower case representations are converted to a character class.
         ASSERT(!m_pattern.ignoreCase() || isASCIIAlpha(ch) || isCanonicallyUnique(ch));
@@ -965,10 +965,10 @@
 
             add32(TrustedImm32(1), countRegister);
             add32(TrustedImm32(1), index);
-            if (term->quantityCount == quantifyInfinite)
+            if (term->quantityMaxCount == quantifyInfinite)
                 jump(loop);
             else
-                branch32(NotEqual, countRegister, Imm32(term->quantityCount.unsafeGet())).linkTo(loop, this);
+                branch32(NotEqual, countRegister, Imm32(term->quantityMaxCount.unsafeGet())).linkTo(loop, this);
 
             failures.link(this);
         }
@@ -1020,8 +1020,8 @@
         if (!((ch > 0xff) && (m_charSize == Char8))) {
             JumpList nonGreedyFailures;
             nonGreedyFailures.append(atEndOfInput());
-            if (term->quantityCount != quantifyInfinite)
-                nonGreedyFailures.append(branch32(Equal, countRegister, Imm32(term->quantityCount.unsafeGet())));
+            if (term->quantityMaxCount != quantifyInfinite)
+                nonGreedyFailures.append(branch32(Equal, countRegister, Imm32(term->quantityMaxCount.unsafeGet())));
             nonGreedyFailures.append(jumpIfCharNotEquals(ch, m_checkedOffset - term->inputPosition, character));
 
             add32(TrustedImm32(1), countRegister);
@@ -1067,11 +1067,11 @@
         const RegisterID countRegister = regT1;
 
         move(index, countRegister);
-        sub32(Imm32(term->quantityCount.unsafeGet()), countRegister);
+        sub32(Imm32(term->quantityMaxCount.unsafeGet()), countRegister);
 
         Label loop(this);
         JumpList matchDest;
-        readCharacter(m_checkedOffset - term->inputPosition - term->quantityCount, character, countRegister);
+        readCharacter(m_checkedOffset - term->inputPosition - term->quantityMaxCount, character, countRegister);
         matchCharacterClass(character, matchDest, term->characterClass);
 
         if (term->invert())
@@ -1116,8 +1116,8 @@
 
         add32(TrustedImm32(1), countRegister);
         add32(TrustedImm32(1), index);
-        if (term->quantityCount != quantifyInfinite) {
-            branch32(NotEqual, countRegister, Imm32(term->quantityCount.unsafeGet())).linkTo(loop, this);
+        if (term->quantityMaxCount != quantifyInfinite) {
+            branch32(NotEqual, countRegister, Imm32(term->quantityMaxCount.unsafeGet())).linkTo(loop, this);
             failures.append(jump());
         } else
             jump(loop);
@@ -1169,7 +1169,7 @@
         loadFromFrame(term->frameLocation, countRegister);
 
         nonGreedyFailures.append(atEndOfInput());
-        nonGreedyFailures.append(branch32(Equal, countRegister, Imm32(term->quantityCount.unsafeGet())));
+        nonGreedyFailures.append(branch32(Equal, countRegister, Imm32(term->quantityMaxCount.unsafeGet())));
 
         JumpList matchDest;
         readCharacter(m_checkedOffset - term->inputPosition, character);
@@ -1265,7 +1265,7 @@
         case PatternTerm::TypePatternCharacter:
             switch (term->quantityType) {
             case QuantifierFixedCount:
-                if (term->quantityCount == 1)
+                if (term->quantityMaxCount == 1)
                     generatePatternCharacterOnce(opIndex);
                 else
                     generatePatternCharacterFixed(opIndex);
@@ -1282,7 +1282,7 @@
         case PatternTerm::TypeCharacterClass:
             switch (term->quantityType) {
             case QuantifierFixedCount:
-                if (term->quantityCount == 1)
+                if (term->quantityMaxCount == 1)
                     generateCharacterClassOnce(opIndex);
                 else
                     generateCharacterClassFixed(opIndex);
@@ -1331,7 +1331,7 @@
         case PatternTerm::TypePatternCharacter:
             switch (term->quantityType) {
             case QuantifierFixedCount:
-                if (term->quantityCount == 1)
+                if (term->quantityMaxCount == 1)
                     backtrackPatternCharacterOnce(opIndex);
                 else
                     backtrackPatternCharacterFixed(opIndex);
@@ -1348,7 +1348,7 @@
         case PatternTerm::TypeCharacterClass:
             switch (term->quantityType) {
             case QuantifierFixedCount:
-                if (term->quantityCount == 1)
+                if (term->quantityMaxCount == 1)
                     backtrackCharacterClassOnce(opIndex);
                 else
                     backtrackCharacterClassFixed(opIndex);
@@ -1617,7 +1617,7 @@
                 PatternTerm* term = op.m_term;
                 unsigned parenthesesFrameLocation = term->frameLocation;
                 const RegisterID indexTemporary = regT0;
-                ASSERT(term->quantityCount == 1);
+                ASSERT(term->quantityMaxCount == 1);
 
                 // Upon entry to a Greedy quantified set of parenthese store the index.
                 // We'll use this for two purposes:
@@ -1664,7 +1664,7 @@
             case OpParenthesesSubpatternOnceEnd: {
                 PatternTerm* term = op.m_term;
                 const RegisterID indexTemporary = regT0;
-                ASSERT(term->quantityCount == 1);
+                ASSERT(term->quantityMaxCount == 1);
 
                 // Runtime ASSERT to make sure that the nested alternative handled the
                 // "no input consumed" check.
@@ -1707,7 +1707,7 @@
             case OpParenthesesSubpatternTerminalBegin: {
                 PatternTerm* term = op.m_term;
                 ASSERT(term->quantityType == QuantifierGreedy);
-                ASSERT(term->quantityCount == quantifyInfinite);
+                ASSERT(term->quantityMaxCount == quantifyInfinite);
                 ASSERT(!term->capture());
 
                 // Upon entry set a label to loop back to.
@@ -2191,7 +2191,7 @@
             // matching start, depending of whether the match is Greedy or NonGreedy.
             case OpParenthesesSubpatternOnceBegin: {
                 PatternTerm* term = op.m_term;
-                ASSERT(term->quantityCount == 1);
+                ASSERT(term->quantityMaxCount == 1);
 
                 // We only need to backtrack to thispoint if capturing or greedy.
                 if ((term->capture() && compileMode == IncludeSubpatterns) || term->quantityType == QuantifierGreedy) {
@@ -2330,7 +2330,7 @@
     // Emits ops for a subpattern (set of parentheses). These consist
     // of a set of alternatives wrapped in an outer set of nodes for
     // the parentheses.
-    // Supported types of parentheses are 'Once' (quantityCount == 1)
+    // Supported types of parentheses are 'Once' (quantityMaxCount == 1)
     // and 'Terminal' (non-capturing parentheses quantified as greedy
     // and infinite).
     // Alternatives will use the 'Simple' set of ops if either the
@@ -2351,7 +2351,10 @@
         // comes where the subpattern is capturing, in which case we would
         // need to restore the capture from the first subpattern upon a
         // failure in the second.
-        if (term->quantityCount == 1 && !term->parentheses.isCopy) {
+        if (term->quantityMinCount && term->quantityMinCount != term->quantityMaxCount) {
+            m_shouldFallBack = true;
+            return;
+        } if (term->quantityMaxCount == 1 && !term->parentheses.isCopy) {
             // Select the 'Once' nodes.
             parenthesesBeginOpCode = OpParenthesesSubpatternOnceBegin;
             parenthesesEndOpCode = OpParenthesesSubpatternOnceEnd;

Modified: releases/WebKitGTK/webkit-2.14/Source/_javascript_Core/yarr/YarrPattern.cpp (214999 => 215000)


--- releases/WebKitGTK/webkit-2.14/Source/_javascript_Core/yarr/YarrPattern.cpp	2017-04-06 08:05:31 UTC (rev 214999)
+++ releases/WebKitGTK/webkit-2.14/Source/_javascript_Core/yarr/YarrPattern.cpp	2017-04-06 08:23:15 UTC (rev 215000)
@@ -522,6 +522,7 @@
         
         PatternTerm termCopy = term;
         termCopy.parentheses.disjunction = copyDisjunction(termCopy.parentheses.disjunction, filterStartsWithBOL);
+        m_pattern.m_hasCopiedParenSubexpressions = true;
         return termCopy;
     }
     
@@ -537,7 +538,7 @@
 
         PatternTerm& term = m_alternative->lastTerm();
         ASSERT(term.type > PatternTerm::TypeAssertionWordBoundary);
-        ASSERT((term.quantityCount == 1) && (term.quantityType == QuantifierFixedCount));
+        ASSERT(term.quantityMinCount == 1 && term.quantityMaxCount == 1 && term.quantityType == QuantifierFixedCount);
 
         if (term.type == PatternTerm::TypeParentheticalAssertion) {
             // If an assertion is quantified with a minimum count of zero, it can simply be removed.
@@ -559,12 +560,12 @@
             return;
         }
 
-        if (min == 0)
-            term.quantify(max, greedy   ? QuantifierGreedy : QuantifierNonGreedy);
-        else if (min == max)
-            term.quantify(min, QuantifierFixedCount);
+        if (min == max)
+            term.quantify(min, max, QuantifierFixedCount);
+        else if (!min || (term.type == PatternTerm::TypeParenthesesSubpattern && m_pattern.m_hasCopiedParenSubexpressions))
+            term.quantify(min, max, greedy ? QuantifierGreedy : QuantifierNonGreedy);
         else {
-            term.quantify(min, QuantifierFixedCount);
+            term.quantify(min, min, QuantifierFixedCount);
             m_alternative->m_terms.append(copyTerm(term));
             // NOTE: this term is interesting from an analysis perspective, in that it can be ignored.....
             m_alternative->lastTerm().quantify((max == quantifyInfinite) ? max : max - min, greedy ? QuantifierGreedy : QuantifierNonGreedy);
@@ -614,9 +615,9 @@
                     currentCallFrameSize += YarrStackSpaceForBackTrackInfoPatternCharacter;
                     alternative->m_hasFixedSize = false;
                 } else if (m_pattern.unicode()) {
-                    currentInputPosition += U16_LENGTH(term.patternCharacter) * term.quantityCount;
+                    currentInputPosition += U16_LENGTH(term.patternCharacter) * term.quantityMaxCount;
                 } else
-                    currentInputPosition += term.quantityCount;
+                    currentInputPosition += term.quantityMaxCount;
                 break;
 
             case PatternTerm::TypeCharacterClass:
@@ -628,16 +629,16 @@
                 } else if (m_pattern.unicode()) {
                     term.frameLocation = currentCallFrameSize;
                     currentCallFrameSize += YarrStackSpaceForBackTrackInfoCharacterClass;
-                    currentInputPosition += term.quantityCount;
+                    currentInputPosition += term.quantityMaxCount;
                     alternative->m_hasFixedSize = false;
                 } else
-                    currentInputPosition += term.quantityCount;
+                    currentInputPosition += term.quantityMaxCount;
                 break;
 
             case PatternTerm::TypeParenthesesSubpattern:
                 // Note: for fixed once parentheses we will ensure at least the minimum is available; others are on their own.
                 term.frameLocation = currentCallFrameSize;
-                if (term.quantityCount == 1 && !term.parentheses.isCopy) {
+                if (term.quantityMaxCount == 1 && !term.parentheses.isCopy) {
                     if (term.quantityType != QuantifierFixedCount)
                         currentCallFrameSize += YarrStackSpaceForBackTrackInfoParenthesesOnce;
                     error = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, currentInputPosition.unsafeGet(), currentCallFrameSize);
@@ -754,7 +755,8 @@
                 PatternTerm& term = terms.last();
                 if (term.type == PatternTerm::TypeParenthesesSubpattern
                     && term.quantityType == QuantifierGreedy
-                    && term.quantityCount == quantifyInfinite
+                    && term.quantityMinCount == 0
+                    && term.quantityMaxCount == quantifyInfinite
                     && !term.capture())
                     term.parentheses.isTerminal = true;
             }
@@ -951,6 +953,7 @@
     : m_containsBackreferences(false)
     , m_containsBOL(false)
     , m_containsUnsignedLengthPattern(false)
+    , m_hasCopiedParenSubexpressions(false)
     , m_flags(flags)
     , m_numSubpatterns(0)
     , m_maxBackReference(0)

Modified: releases/WebKitGTK/webkit-2.14/Source/_javascript_Core/yarr/YarrPattern.h (214999 => 215000)


--- releases/WebKitGTK/webkit-2.14/Source/_javascript_Core/yarr/YarrPattern.h	2017-04-06 08:05:31 UTC (rev 214999)
+++ releases/WebKitGTK/webkit-2.14/Source/_javascript_Core/yarr/YarrPattern.h	2017-04-06 08:23:15 UTC (rev 215000)
@@ -109,7 +109,8 @@
         } anchors;
     };
     QuantifierType quantityType;
-    Checked<unsigned> quantityCount;
+    Checked<unsigned> quantityMinCount;
+    Checked<unsigned> quantityMaxCount;
     unsigned inputPosition;
     unsigned frameLocation;
 
@@ -120,7 +121,7 @@
     {
         patternCharacter = ch;
         quantityType = QuantifierFixedCount;
-        quantityCount = 1;
+        quantityMinCount = quantityMaxCount = 1;
     }
 
     PatternTerm(CharacterClass* charClass, bool invert)
@@ -130,7 +131,7 @@
     {
         characterClass = charClass;
         quantityType = QuantifierFixedCount;
-        quantityCount = 1;
+        quantityMinCount = quantityMaxCount = 1;
     }
 
     PatternTerm(Type type, unsigned subpatternId, PatternDisjunction* disjunction, bool capture = false, bool invert = false)
@@ -143,7 +144,7 @@
         parentheses.isCopy = false;
         parentheses.isTerminal = false;
         quantityType = QuantifierFixedCount;
-        quantityCount = 1;
+        quantityMinCount = quantityMaxCount = 1;
     }
     
     PatternTerm(Type type, bool invert = false)
@@ -152,7 +153,7 @@
         , m_invert(invert)
     {
         quantityType = QuantifierFixedCount;
-        quantityCount = 1;
+        quantityMinCount = quantityMaxCount = 1;
     }
 
     PatternTerm(unsigned spatternId)
@@ -162,7 +163,7 @@
     {
         backReferenceSubpatternId = spatternId;
         quantityType = QuantifierFixedCount;
-        quantityCount = 1;
+        quantityMinCount = quantityMaxCount = 1;
     }
 
     PatternTerm(bool bolAnchor, bool eolAnchor)
@@ -173,7 +174,7 @@
         anchors.bolAnchor = bolAnchor;
         anchors.eolAnchor = eolAnchor;
         quantityType = QuantifierFixedCount;
-        quantityCount = 1;
+        quantityMinCount = quantityMaxCount = 1;
     }
     
     static PatternTerm ForwardReference()
@@ -208,9 +209,20 @@
     
     void quantify(unsigned count, QuantifierType type)
     {
-        quantityCount = count;
+        quantityMinCount = 0;
+        quantityMaxCount = count;
         quantityType = type;
     }
+
+    void quantify(unsigned minCount, unsigned maxCount, QuantifierType type)
+    {
+        // Currently only Parentheses can specify a non-zero min with a different max.
+        ASSERT(this->type == TypeParenthesesSubpattern || !minCount || minCount == maxCount);
+        ASSERT(minCount <= maxCount);
+        quantityMinCount = minCount;
+        quantityMaxCount = maxCount;
+        quantityType = type;
+    }
 };
 
 struct PatternAlternative {
@@ -334,6 +346,7 @@
         m_containsBackreferences = false;
         m_containsBOL = false;
         m_containsUnsignedLengthPattern = false;
+        m_hasCopiedParenSubexpressions = false;
 
         newlineCached = 0;
         digitsCached = 0;
@@ -439,7 +452,8 @@
 
     bool m_containsBackreferences : 1;
     bool m_containsBOL : 1;
-    bool m_containsUnsignedLengthPattern : 1; 
+    bool m_containsUnsignedLengthPattern : 1;
+    bool m_hasCopiedParenSubexpressions : 1;
     RegExpFlags m_flags;
     unsigned m_numSubpatterns;
     unsigned m_maxBackReference;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to