Changeset 200946 in webkit


Ignore:
Timestamp:
May 16, 2016 10:40:15 AM (8 years ago)
Author:
msaboff@apple.com
Message:

RegExp /y flag incorrect handling of mixed-length alternation
https://bugs.webkit.org/show_bug.cgi?id=157723

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

Previously for sticky patterns, we were bailing out and exiting when backtracking
alternatives with dissimilar match lengths. Deleted that code. Instead, for
sticky patterns we need to process the backtracking except for advancing to the
next input index.

  • yarr/YarrJIT.cpp:

(JSC::Yarr::YarrGenerator::backtrack):

LayoutTests:

Added tests for alternatives with shorter to longer lengths.

  • js/regexp-sticky-expected.txt:
  • js/script-tests/regexp-sticky.js:
Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r200945 r200946  
     12016-05-16  Michael Saboff  <msaboff@apple.com>
     2
     3        RegExp /y flag incorrect handling of mixed-length alternation
     4        https://bugs.webkit.org/show_bug.cgi?id=157723
     5
     6        Reviewed by Filip Pizlo.
     7
     8        Added tests for alternatives with shorter to longer lengths.
     9
     10        * js/regexp-sticky-expected.txt:
     11        * js/script-tests/regexp-sticky.js:
     12
    1132016-05-16  Brent Fulgham  <bfulgham@apple.com>
    214
  • trunk/LayoutTests/js/regexp-sticky-expected.txt

    r197869 r200946  
    77PASS Test lastIndex resets
    88PASS Ignore Case
    9 PASS Alternates
     9PASS Alternates, differing lengths long to short
     10PASS Alternates, differing lengths long to short with mutliple matches
     11PASS Alternates, differing lengths, short to long
    1012PASS BOL Anchored, starting at 0
    1113PASS BOL Anchored, starting at 1
  • trunk/LayoutTests/js/script-tests/regexp-sticky.js

    r197869 r200946  
    7373testStickyExec("Test lastIndex resets", /\d/y, "12345", 0, ["1", "2", "3", "4", "5", null, "1", "2", "3", "4", "5", null]);
    7474testStickyExec("Ignore Case", new RegExp("test", "iy"), "TESTtestTest", 0, ["TEST", "test", "Test", null]);
    75 testStickyExec("Alternates", new RegExp("Dog |Cat |Mouse ", "y"), "Mouse Dog Cat ", 0, ["Mouse ", "Dog ", "Cat ", null]);
     75testStickyExec("Alternates, differing lengths long to short", new RegExp("bb|a", "y"), "a", 0, ["a", null]);
     76testStickyExec("Alternates, differing lengths long to short with mutliple matches ", new RegExp("abc|ab|a", "y"), "aababcaabcab", 0, ["a", "ab", "abc", "a", "abc", "ab", null]);
     77testStickyExec("Alternates, differing lengths, short to long", new RegExp("Dog |Cat |Mouse ", "y"), "Mouse Dog Cat ", 0, ["Mouse ", "Dog ", "Cat ", null]);
    7678testStickyExec("BOL Anchored, starting at 0", /^X/y, "XXX", 0, ["X", null]);
    7779testStickyExec("BOL Anchored, starting at 1", /^X/y, "XXX", 1, [null, "X", null]);
  • trunk/Source/JavaScriptCore/ChangeLog

    r200933 r200946  
     12016-05-15  Michael Saboff  <msaboff@apple.com>
     2
     3        RegExp /y flag incorrect handling of mixed-length alternation
     4        https://bugs.webkit.org/show_bug.cgi?id=157723
     5
     6        Reviewed by Filip Pizlo.
     7
     8        Previously for sticky patterns, we were bailing out and exiting when backtracking
     9        alternatives with dissimilar match lengths.  Deleted that code.  Instead, for
     10        sticky patterns we need to process the backtracking except for advancing to the
     11        next input index.
     12
     13        * yarr/YarrJIT.cpp:
     14        (JSC::Yarr::YarrGenerator::backtrack):
     15
    1162016-05-15  Filip Pizlo  <fpizlo@apple.com>
    217
  • trunk/Source/JavaScriptCore/yarr/YarrJIT.cpp

    r197869 r200946  
    18891889                }
    18901890
    1891                 if (m_pattern.sticky()) {
    1892                     // We have failed matching from the initial index and we're a sticky expression.
    1893                     // We are done matching. Link failures for any reason to here.
    1894                     YarrOp* tempOp = beginOp;
    1895                     do {
    1896                         tempOp->m_jumps.link(this);
    1897                         tempOp = &m_ops[tempOp->m_nextOp];
    1898                     } while (tempOp->m_op != OpBodyAlternativeEnd);
    1899 
    1900                     removeCallFrame();
    1901                     generateFailReturn();
    1902                     break;
    1903                 }
    1904 
    19051891                // We can reach this point in the code in two ways:
    19061892                //  - Fallthrough from the code above (a repeating alternative backtracked out of its
     
    19661952                }
    19671953
    1968                 // Check whether there is sufficient input to loop. Increment the input position by
    1969                 // one, and check. Also add in the minimum disjunction size before checking - there
    1970                 // is no point in looping if we're just going to fail all the input checks around
    1971                 // the next iteration.
    1972                 ASSERT(alternative->m_minimumSize >= m_pattern.m_body->m_minimumSize);
    1973                 if (alternative->m_minimumSize == m_pattern.m_body->m_minimumSize) {
    1974                     // If the last alternative had the same minimum size as the disjunction,
    1975                     // just simply increment input pos by 1, no adjustment based on minimum size.
    1976                     add32(TrustedImm32(1), index);
    1977                 } else {
    1978                     // If the minumum for the last alternative was one greater than than that
    1979                     // for the disjunction, we're already progressed by 1, nothing to do!
    1980                     unsigned delta = (alternative->m_minimumSize - m_pattern.m_body->m_minimumSize) - 1;
    1981                     if (delta)
    1982                         sub32(Imm32(delta), index);
    1983                 }
    1984                 Jump matchFailed = jumpIfNoAvailableInput();
    1985 
    1986                 if (needsToUpdateMatchStart) {
    1987                     if (!m_pattern.m_body->m_minimumSize)
    1988                         setMatchStart(index);
     1954                if (!m_pattern.sticky()) {
     1955                    // Check whether there is sufficient input to loop. Increment the input position by
     1956                    // one, and check. Also add in the minimum disjunction size before checking - there
     1957                    // is no point in looping if we're just going to fail all the input checks around
     1958                    // the next iteration.
     1959                    ASSERT(alternative->m_minimumSize >= m_pattern.m_body->m_minimumSize);
     1960                    if (alternative->m_minimumSize == m_pattern.m_body->m_minimumSize) {
     1961                        // If the last alternative had the same minimum size as the disjunction,
     1962                        // just simply increment input pos by 1, no adjustment based on minimum size.
     1963                        add32(TrustedImm32(1), index);
     1964                    } else {
     1965                        // If the minumum for the last alternative was one greater than than that
     1966                        // for the disjunction, we're already progressed by 1, nothing to do!
     1967                        unsigned delta = (alternative->m_minimumSize - m_pattern.m_body->m_minimumSize) - 1;
     1968                        if (delta)
     1969                            sub32(Imm32(delta), index);
     1970                    }
     1971                    Jump matchFailed = jumpIfNoAvailableInput();
     1972
     1973                    if (needsToUpdateMatchStart) {
     1974                        if (!m_pattern.m_body->m_minimumSize)
     1975                            setMatchStart(index);
     1976                        else {
     1977                            move(index, regT0);
     1978                            sub32(Imm32(m_pattern.m_body->m_minimumSize), regT0);
     1979                            setMatchStart(regT0);
     1980                        }
     1981                    }
     1982
     1983                    // Calculate how much more input the first alternative requires than the minimum
     1984                    // for the body as a whole. If no more is needed then we dont need an additional
     1985                    // input check here - jump straight back up to the start of the first alternative.
     1986                    if (beginOp->m_alternative->m_minimumSize == m_pattern.m_body->m_minimumSize)
     1987                        jump(beginOp->m_reentry);
    19891988                    else {
    1990                         move(index, regT0);
    1991                         sub32(Imm32(m_pattern.m_body->m_minimumSize), regT0);
    1992                         setMatchStart(regT0);
     1989                        if (beginOp->m_alternative->m_minimumSize > m_pattern.m_body->m_minimumSize)
     1990                            add32(Imm32(beginOp->m_alternative->m_minimumSize - m_pattern.m_body->m_minimumSize), index);
     1991                        else
     1992                            sub32(Imm32(m_pattern.m_body->m_minimumSize - beginOp->m_alternative->m_minimumSize), index);
     1993                        checkInput().linkTo(beginOp->m_reentry, this);
     1994                        jump(firstInputCheckFailed);
    19931995                    }
    1994                 }
    1995 
    1996                 // Calculate how much more input the first alternative requires than the minimum
    1997                 // for the body as a whole. If no more is needed then we dont need an additional
    1998                 // input check here - jump straight back up to the start of the first alternative.
    1999                 if (beginOp->m_alternative->m_minimumSize == m_pattern.m_body->m_minimumSize)
    2000                     jump(beginOp->m_reentry);
    2001                 else {
    2002                     if (beginOp->m_alternative->m_minimumSize > m_pattern.m_body->m_minimumSize)
    2003                         add32(Imm32(beginOp->m_alternative->m_minimumSize - m_pattern.m_body->m_minimumSize), index);
    2004                     else
    2005                         sub32(Imm32(m_pattern.m_body->m_minimumSize - beginOp->m_alternative->m_minimumSize), index);
    2006                     checkInput().linkTo(beginOp->m_reentry, this);
    2007                     jump(firstInputCheckFailed);
    2008                 }
    2009 
    2010                 // We jump to here if we iterate to the point that there is insufficient input to
    2011                 // run any matches, and need to return a failure state from JIT code.
    2012                 matchFailed.link(this);
    2013 
     1996
     1997                    // We jump to here if we iterate to the point that there is insufficient input to
     1998                    // run any matches, and need to return a failure state from JIT code.
     1999                    matchFailed.link(this);
     2000                }
    20142001                removeCallFrame();
    20152002                generateFailReturn();
Note: See TracChangeset for help on using the changeset viewer.