[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc

msaboff at apple.com msaboff at apple.com
Wed Dec 22 13:32:01 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit cc2bdd51961371bd2229e246cfa129398374818a
Author: msaboff at apple.com <msaboff at apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Sat Sep 18 21:04:15 2010 +0000

    2010-09-18  Michael Saboff  <msaboff at apple.com>
    
            Reviewed by Gavin Barraclough.
    
            Added code to unroll regular expressions containing ^.
            Alternatives that begin with ^ are tagged during parsing
            and rolled up in containing sub expression structs.
            After parsing, a regular expression flagged as containing
            a ^ (a.k.a. BOL) is processed further in optimizeBOL().
            A copy of the disjunction is made excluding alternatives that
            are rooted with BOL.  The original alternatives are flagged
            to only be executed once.  The copy of the other alternatives are
            added to the original expression.
            In the case that all original alternatives are flagged, there
            won't be any looping alternatives.
            The JIT generator will emit code accordingly, executing the
            original alternatives once and then looping over the
            alternatives that aren't anchored with a BOL (if any).
            https://bugs.webkit.org/show_bug.cgi?id=45787
    
            * yarr/RegexCompiler.cpp:
            (JSC::Yarr::RegexPatternConstructor::assertionBOL):
            (JSC::Yarr::RegexPatternConstructor::atomParenthesesEnd):
            (JSC::Yarr::RegexPatternConstructor::copyDisjunction):
            (JSC::Yarr::RegexPatternConstructor::copyTerm):
            (JSC::Yarr::RegexPatternConstructor::optimizeBOL):
            (JSC::Yarr::compileRegex):
            * yarr/RegexJIT.cpp:
            (JSC::Yarr::RegexGenerator::generateDisjunction):
            * yarr/RegexPattern.h:
            (JSC::Yarr::PatternAlternative::PatternAlternative):
            (JSC::Yarr::PatternAlternative::setOnceThrough):
            (JSC::Yarr::PatternAlternative::onceThrough):
            (JSC::Yarr::PatternDisjunction::PatternDisjunction):
            (JSC::Yarr::RegexPattern::RegexPattern):
            (JSC::Yarr::RegexPattern::reset):
    2010-09-18  Michael Saboff  <msaboff at apple.com>
    
            Reviewed by Gavin Barraclough.
    
            Added new tests to check for proper handling of ^ in multiline
            regular expressions.  Added as part of
            https://bugs.webkit.org/show_bug.cgi?id=45787
    
            * fast/js/regexp-bol-with-multiline-expected.txt: Added.
            * fast/js/regexp-bol-with-multiline.html: Added.
            * fast/js/script-tests/regexp-bol-with-multiline.js: Added.
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@67790 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog
index eb8cf82..3dc5c77 100644
--- a/JavaScriptCore/ChangeLog
+++ b/JavaScriptCore/ChangeLog
@@ -1,3 +1,40 @@
+2010-09-18  Michael Saboff  <msaboff at apple.com>
+
+        Reviewed by Gavin Barraclough.
+
+        Added code to unroll regular expressions containing ^.
+        Alternatives that begin with ^ are tagged during parsing
+        and rolled up in containing sub expression structs.
+        After parsing, a regular expression flagged as containing
+        a ^ (a.k.a. BOL) is processed further in optimizeBOL().
+        A copy of the disjunction is made excluding alternatives that
+        are rooted with BOL.  The original alternatives are flagged
+        to only be executed once.  The copy of the other alternatives are
+        added to the original expression.
+        In the case that all original alternatives are flagged, there
+        won't be any looping alternatives.
+        The JIT generator will emit code accordingly, executing the
+        original alternatives once and then looping over the
+        alternatives that aren't anchored with a BOL (if any).
+        https://bugs.webkit.org/show_bug.cgi?id=45787
+
+        * yarr/RegexCompiler.cpp:
+        (JSC::Yarr::RegexPatternConstructor::assertionBOL):
+        (JSC::Yarr::RegexPatternConstructor::atomParenthesesEnd):
+        (JSC::Yarr::RegexPatternConstructor::copyDisjunction):
+        (JSC::Yarr::RegexPatternConstructor::copyTerm):
+        (JSC::Yarr::RegexPatternConstructor::optimizeBOL):
+        (JSC::Yarr::compileRegex):
+        * yarr/RegexJIT.cpp:
+        (JSC::Yarr::RegexGenerator::generateDisjunction):
+        * yarr/RegexPattern.h:
+        (JSC::Yarr::PatternAlternative::PatternAlternative):
+        (JSC::Yarr::PatternAlternative::setOnceThrough):
+        (JSC::Yarr::PatternAlternative::onceThrough):
+        (JSC::Yarr::PatternDisjunction::PatternDisjunction):
+        (JSC::Yarr::RegexPattern::RegexPattern):
+        (JSC::Yarr::RegexPattern::reset):
+
 2010-09-18  Patrick Gansterer  <paroga at paroga.com>
 
         Reviewed by Darin Adler.
diff --git a/JavaScriptCore/yarr/RegexCompiler.cpp b/JavaScriptCore/yarr/RegexCompiler.cpp
index fa87186..3343792 100644
--- a/JavaScriptCore/yarr/RegexCompiler.cpp
+++ b/JavaScriptCore/yarr/RegexCompiler.cpp
@@ -240,6 +240,7 @@ public:
     RegexPatternConstructor(RegexPattern& pattern)
         : m_pattern(pattern)
         , m_characterClassConstructor(pattern.m_ignoreCase)
+        , m_invertParentheticalAssertion(false)
     {
     }
 
@@ -255,6 +256,11 @@ public:
     
     void assertionBOL()
     {
+        if (!m_alternative->m_terms.size() & !m_invertParentheticalAssertion) {
+            m_alternative->m_startsWithBOL = true;
+            m_alternative->m_containsBOL = true;
+            m_pattern.m_containsBOL = true;
+        }
         m_alternative->m_terms.append(PatternTerm::BOL());
     }
     void assertionEOL()
@@ -358,15 +364,36 @@ public:
         m_pattern.m_disjunctions.append(parenthesesDisjunction);
         m_alternative->m_terms.append(PatternTerm(PatternTerm::TypeParentheticalAssertion, m_pattern.m_numSubpatterns + 1, parenthesesDisjunction, invert));
         m_alternative = parenthesesDisjunction->addNewAlternative();
+        m_invertParentheticalAssertion = invert;
     }
 
     void atomParenthesesEnd()
     {
         ASSERT(m_alternative->m_parent);
         ASSERT(m_alternative->m_parent->m_parent);
+
+        PatternDisjunction* parenthesisDisjunction = m_alternative->m_parent;
         m_alternative = m_alternative->m_parent->m_parent;
+
+        PatternTerm lastTerm = m_alternative->lastTerm();
+        
+        unsigned numParenAlternatives = parenthesisDisjunction->m_alternatives.size();
+        unsigned numBOLAnchoredAlts = 0;
+        // Bubble up BOL flags
+        for (unsigned i = 0; i < numParenAlternatives; i++) {
+            if (parenthesisDisjunction->m_alternatives[i]->m_startsWithBOL)
+                numBOLAnchoredAlts++;
+        }
+        
+        if (numBOLAnchoredAlts) {
+            m_alternative->m_containsBOL = true;
+            // If all the alternatives in parens start with BOL, then so does this one
+            if (numBOLAnchoredAlts == numParenAlternatives)
+                m_alternative->m_startsWithBOL = true;
+        }
         
-        m_alternative->lastTerm().parentheses.lastSubpatternId = m_pattern.m_numSubpatterns;
+        lastTerm.parentheses.lastSubpatternId = m_pattern.m_numSubpatterns;
+        m_invertParentheticalAssertion = false;
     }
 
     void atomBackReference(unsigned subpatternId)
@@ -397,32 +424,39 @@ public:
         m_alternative->m_terms.append(PatternTerm(subpatternId));
     }
 
-    PatternDisjunction* copyDisjunction(PatternDisjunction* disjunction)
+    // deep copy the argument disjunction.  If filterStartsWithBOL is true, 
+    // skip alternatives with m_startsWithBOL set true.
+    PatternDisjunction* copyDisjunction(PatternDisjunction* disjunction, bool filterStartsWithBOL = false)
     {
-        PatternDisjunction* newDisjunction = new PatternDisjunction();
-
-        newDisjunction->m_parent = disjunction->m_parent;
+        PatternDisjunction* newDisjunction = 0;
         for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) {
             PatternAlternative* alternative = disjunction->m_alternatives[alt];
-            PatternAlternative* newAlternative = newDisjunction->addNewAlternative();
-            for (unsigned i = 0; i < alternative->m_terms.size(); ++i)
-                newAlternative->m_terms.append(copyTerm(alternative->m_terms[i]));
+            if (!filterStartsWithBOL || !alternative->m_startsWithBOL) {
+                if (!newDisjunction) {
+                    newDisjunction = new PatternDisjunction();
+                    newDisjunction->m_parent = disjunction->m_parent;
+                }
+                PatternAlternative* newAlternative = newDisjunction->addNewAlternative();
+                for (unsigned i = 0; i < alternative->m_terms.size(); ++i)
+                    newAlternative->m_terms.append(copyTerm(alternative->m_terms[i], filterStartsWithBOL));
+            }
         }
-
-        m_pattern.m_disjunctions.append(newDisjunction);
+        
+        if (newDisjunction)
+            m_pattern.m_disjunctions.append(newDisjunction);
         return newDisjunction;
     }
-
-    PatternTerm copyTerm(PatternTerm& term)
+    
+    PatternTerm copyTerm(PatternTerm& term, bool filterStartsWithBOL = false)
     {
         if ((term.type != PatternTerm::TypeParenthesesSubpattern) && (term.type != PatternTerm::TypeParentheticalAssertion))
             return PatternTerm(term);
-
+        
         PatternTerm termCopy = term;
-        termCopy.parentheses.disjunction = copyDisjunction(termCopy.parentheses.disjunction);
+        termCopy.parentheses.disjunction = copyDisjunction(termCopy.parentheses.disjunction, filterStartsWithBOL);
         return termCopy;
     }
-
+    
     void quantifyAtom(unsigned min, unsigned max, bool greedy)
     {
         ASSERT(min <= max);
@@ -589,11 +623,40 @@ public:
         setupDisjunctionOffsets(m_pattern.m_body, 0, 0);
     }
 
+    void optimizeBOL()
+    {
+        // Look for expressions containing beginning of line (^) anchoring and unroll them.
+        // e.g. /^a|^b|c/ becomes /^a|^b|c/ which is executed once followed by /c/ which loops
+        // This code relies on the parsing code tagging alternatives with m_containsBOL and
+        // m_startsWithBOL and rolling those up to containing alternatives.
+        // At this point, this is only valid for non-multiline expressions.
+        PatternDisjunction* disjunction = m_pattern.m_body;
+        
+        if (!m_pattern.m_containsBOL || m_pattern.m_multiline)
+            return;
+        
+        PatternDisjunction* loopDisjunction = copyDisjunction(disjunction, true);
+
+        // Set alternatives in disjunction to "onceThrough"
+        for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt)
+            disjunction->m_alternatives[alt]->setOnceThrough();
+
+        if (loopDisjunction) {
+            // Move alternatives from loopDisjunction to disjunction
+            for (unsigned alt = 0; alt < loopDisjunction->m_alternatives.size(); ++alt)
+                disjunction->m_alternatives.append(loopDisjunction->m_alternatives[alt]);
+                
+            loopDisjunction->m_alternatives.clear();
+        }
+    }
+    
+    
 private:
     RegexPattern& m_pattern;
     PatternAlternative* m_alternative;
     CharacterClassConstructor m_characterClassConstructor;
     bool m_invertCharacterClass;
+    bool m_invertParentheticalAssertion;
 };
 
 
@@ -621,6 +684,8 @@ const char* compileRegex(const UString& patternString, RegexPattern& pattern)
         ASSERT(numSubpatterns == pattern.m_numSubpatterns);
     }
 
+    constructor.optimizeBOL();
+        
     constructor.setupOffsets();
 
     return 0;
diff --git a/JavaScriptCore/yarr/RegexJIT.cpp b/JavaScriptCore/yarr/RegexJIT.cpp
index 7818b52..d691bfd 100644
--- a/JavaScriptCore/yarr/RegexJIT.cpp
+++ b/JavaScriptCore/yarr/RegexJIT.cpp
@@ -1207,21 +1207,26 @@ class RegexGenerator : private MacroAssembler {
         TermGenerationState state(disjunction, 0);
         state.resetAlternative();
 
-        // Plant a check to see if there is sufficient input available to run the first alternative.
-        // Jumping back to the label 'firstAlternative' will get to this check, jumping to
-        // 'firstAlternativeInputChecked' will jump directly to matching the alternative having
-        // skipped this check.
-
-        Label firstAlternative(this);
-
         // check availability for the next alternative
         int countCheckedForCurrentAlternative = 0;
         int countToCheckForFirstAlternative = 0;
         bool hasShorterAlternatives = false;
+        bool setRepeatAlternativeLabels = false;
         JumpList notEnoughInputForPreviousAlternative;
+        Label firstAlternative;
+        Label firstAlternativeInputChecked;
 
+        // The label 'firstAlternative' is used to plant a check to see if there is 
+        // sufficient input available to run the first repeating alternative.
+        // The label 'firstAlternativeInputChecked' will jump directly to matching 
+        // the first repeating alternative having skipped this check.
+        
         if (state.alternativeValid()) {
             PatternAlternative* alternative = state.alternative();
+            if (!alternative->onceThrough()) {
+                firstAlternative = Label(this);
+                setRepeatAlternativeLabels = true;
+            }
             countToCheckForFirstAlternative = alternative->m_minimumSize;
             state.checkedTotal += countToCheckForFirstAlternative;
             if (countToCheckForFirstAlternative)
@@ -1229,7 +1234,8 @@ class RegexGenerator : private MacroAssembler {
             countCheckedForCurrentAlternative = countToCheckForFirstAlternative;
         }
 
-        Label firstAlternativeInputChecked(this);
+        if (setRepeatAlternativeLabels)
+            firstAlternativeInputChecked = Label(this);
 
         while (state.alternativeValid()) {
             // Track whether any alternatives are shorter than the first one.
@@ -1264,6 +1270,17 @@ class RegexGenerator : private MacroAssembler {
             // if there are any more alternatives, plant the check for input before looping.
             if (state.alternativeValid()) {
                 PatternAlternative* nextAlternative = state.alternative();
+                bool setAlternativeLoopLabel = false;
+                if (!setRepeatAlternativeLabels && !nextAlternative->onceThrough()) {
+                    // We have handled non-repeating alternatives, jump to next iteration 
+                    // and loop over repeating alternatives.
+                    state.jumpToBacktrack(jump(), this);
+
+                    firstAlternative = Label(this);
+                    setRepeatAlternativeLabels = true;
+                    setAlternativeLoopLabel = true;
+                }
+                
                 int countToCheckForNextAlternative = nextAlternative->m_minimumSize;
 
                 if (countCheckedForCurrentAlternative > countToCheckForNextAlternative) { // CASE 1: current alternative was longer than the next one.
@@ -1302,6 +1319,12 @@ class RegexGenerator : private MacroAssembler {
                     state.linkAlternativeBacktracks(this);
                 }
 
+                if (setAlternativeLoopLabel) {
+                    firstAlternativeInputChecked = Label(this);
+                    countToCheckForFirstAlternative = countToCheckForNextAlternative;
+                    setAlternativeLoopLabel = true;
+                }
+                
                 state.checkedTotal -= countCheckedForCurrentAlternative;
                 countCheckedForCurrentAlternative = countToCheckForNextAlternative;
                 state.checkedTotal += countCheckedForCurrentAlternative;
@@ -1358,29 +1381,33 @@ class RegexGenerator : private MacroAssembler {
             } else
                 store32(index, Address(output));
         }
-        // Check if there is sufficent input to run the first alternative again.
-        jumpIfAvailableInput(incrementForNextIter).linkTo(firstAlternativeInputChecked, this);
-        // No - insufficent input to run the first alteranative, are there any other alternatives we
-        // might need to check?  If so, the last check will have left the index incremented by
-        // (countToCheckForFirstAlternative + 1), so we need test whether countToCheckForFirstAlternative
-        // LESS input is available, to have the effect of just progressing the start position by 1
-        // from the last iteration.  If this check passes we can just jump up to the check associated
-        // with the first alternative in the loop.  This is a bit sad, since we'll end up trying the
-        // first alternative again, and this check will fail (otherwise the check planted just above
-        // here would have passed).  This is a bit sad, however it saves trying to do something more
-        // complex here in compilation, and in the common case we should end up coallescing the checks.
-        //
-        // FIXME: a nice improvement here may be to stop trying to match sooner, based on the least
-        // of the minimum-alternative-lengths.  E.g. if I have two alternatives of length 200 and 150,
-        // and a string of length 100, we'll end up looping index from 0 to 100, checking whether there
-        // is sufficient input to run either alternative (constantly failing).  If there had been only
-        // one alternative, or if the shorter alternative had come first, we would have terminated
-        // immediately. :-/
-        if (hasShorterAlternatives)
-            jumpIfAvailableInput(-countToCheckForFirstAlternative).linkTo(firstAlternative, this);
-        // index will now be a bit garbled (depending on whether 'hasShorterAlternatives' is true,
-        // it has either been incremented by 1 or by (countToCheckForFirstAlternative + 1) ... 
-        // but since we're about to return a failure this doesn't really matter!)
+        
+        // Loop if there are repeating alternatives.
+        if (setRepeatAlternativeLabels) {
+            // Check if there is sufficent input to run the first alternative again.
+            jumpIfAvailableInput(incrementForNextIter).linkTo(firstAlternativeInputChecked, this);
+            // No - insufficent input to run the first alteranative, are there any other alternatives we
+            // might need to check?  If so, the last check will have left the index incremented by
+            // (countToCheckForFirstAlternative + 1), so we need test whether countToCheckForFirstAlternative
+            // LESS input is available, to have the effect of just progressing the start position by 1
+            // from the last iteration.  If this check passes we can just jump up to the check associated
+            // with the first alternative in the loop.  This is a bit sad, since we'll end up trying the
+            // first alternative again, and this check will fail (otherwise the check planted just above
+            // here would have passed).  This is a bit sad, however it saves trying to do something more
+            // complex here in compilation, and in the common case we should end up coallescing the checks.
+            //
+            // FIXME: a nice improvement here may be to stop trying to match sooner, based on the least
+            // of the minimum-alternative-lengths.  E.g. if I have two alternatives of length 200 and 150,
+            // and a string of length 100, we'll end up looping index from 0 to 100, checking whether there
+            // is sufficient input to run either alternative (constantly failing).  If there had been only
+            // one alternative, or if the shorter alternative had come first, we would have terminated
+            // immediately. :-/
+            if (hasShorterAlternatives)
+                jumpIfAvailableInput(-countToCheckForFirstAlternative).linkTo(firstAlternative, this);
+            // index will now be a bit garbled (depending on whether 'hasShorterAlternatives' is true,
+            // it has either been incremented by 1 or by (countToCheckForFirstAlternative + 1) ... 
+            // but since we're about to return a failure this doesn't really matter!)
+        }
 
         if (m_pattern.m_body->m_callFrameSize)
             addPtr(Imm32(m_pattern.m_body->m_callFrameSize * sizeof(void*)), stackPointerRegister);
diff --git a/JavaScriptCore/yarr/RegexPattern.h b/JavaScriptCore/yarr/RegexPattern.h
index 61d6ad6..eecbd43 100644
--- a/JavaScriptCore/yarr/RegexPattern.h
+++ b/JavaScriptCore/yarr/RegexPattern.h
@@ -207,6 +207,10 @@ struct PatternTerm {
 struct PatternAlternative : FastAllocBase {
     PatternAlternative(PatternDisjunction* disjunction)
         : m_parent(disjunction)
+        , m_onceThrough(false)
+        , m_hasFixedSize(false)
+        , m_startsWithBOL(false)
+        , m_containsBOL(false)
     {
     }
 
@@ -221,16 +225,30 @@ struct PatternAlternative : FastAllocBase {
         ASSERT(m_terms.size());
         m_terms.shrink(m_terms.size() - 1);
     }
+    
+    void setOnceThrough()
+    {
+        m_onceThrough = true;
+    }
+    
+    bool onceThrough()
+    {
+        return m_onceThrough;
+    }
 
     Vector<PatternTerm> m_terms;
     PatternDisjunction* m_parent;
     unsigned m_minimumSize;
-    bool m_hasFixedSize;
+    bool m_onceThrough : 1;
+    bool m_hasFixedSize : 1;
+    bool m_startsWithBOL : 1;
+    bool m_containsBOL : 1;
 };
 
 struct PatternDisjunction : FastAllocBase {
     PatternDisjunction(PatternAlternative* parent = 0)
         : m_parent(parent)
+        , m_hasFixedSize(false)
     {
     }
     
@@ -269,9 +287,10 @@ struct RegexPattern {
     RegexPattern(bool ignoreCase, bool multiline)
         : m_ignoreCase(ignoreCase)
         , m_multiline(multiline)
+        , m_containsBackreferences(false)
+        , m_containsBOL(false)
         , m_numSubpatterns(0)
         , m_maxBackReference(0)
-        , m_containsBackreferences(false)
         , newlineCached(0)
         , digitsCached(0)
         , spacesCached(0)
@@ -294,6 +313,7 @@ struct RegexPattern {
         m_maxBackReference = 0;
 
         m_containsBackreferences = false;
+        m_containsBOL = false;
 
         newlineCached = 0;
         digitsCached = 0;
@@ -357,11 +377,12 @@ struct RegexPattern {
         return nonwordcharCached;
     }
 
-    bool m_ignoreCase;
-    bool m_multiline;
+    bool m_ignoreCase : 1;
+    bool m_multiline : 1;
+    bool m_containsBackreferences : 1;
+    bool m_containsBOL : 1;
     unsigned m_numSubpatterns;
     unsigned m_maxBackReference;
-    bool m_containsBackreferences;
     PatternDisjunction* m_body;
     Vector<PatternDisjunction*, 4> m_disjunctions;
     Vector<CharacterClass*> m_userCharacterClasses;
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 21bbc75..40e71e9 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,15 @@
+2010-09-18  Michael Saboff  <msaboff at apple.com>
+
+        Reviewed by Gavin Barraclough.
+
+        Added new tests to check for proper handling of ^ in multiline
+        regular expressions.  Added as part of
+        https://bugs.webkit.org/show_bug.cgi?id=45787
+
+        * fast/js/regexp-bol-with-multiline-expected.txt: Added.
+        * fast/js/regexp-bol-with-multiline.html: Added.
+        * fast/js/script-tests/regexp-bol-with-multiline.js: Added.
+
 2010-09-18  Dimitri Glazkov  <dglazkov at chromium.org>
 
         Remove duplicate expectations from platform/chromium-win-xp.
diff --git a/LayoutTests/fast/js/regexp-bol-with-multiline-expected.txt b/LayoutTests/fast/js/regexp-bol-with-multiline-expected.txt
new file mode 100644
index 0000000..48fd0fb
--- /dev/null
+++ b/LayoutTests/fast/js/regexp-bol-with-multiline-expected.txt
@@ -0,0 +1,14 @@
+Test for beginning of line (BOL or ^) matching in a multiline string
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS s.match(/^abc/) is null
+PASS s.match(/^abc/m) is ["abc"]
+PASS s.match(/(^|X)abc/) is null
+PASS s.match(/(^|X)abc/m) is ["abc",""]
+PASS s.match(/(^a|Xa)bc/m) is ["abc","a"]
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/regexp-bol-with-multiline.html b/LayoutTests/fast/js/regexp-bol-with-multiline.html
new file mode 100644
index 0000000..89606e7
--- /dev/null
+++ b/LayoutTests/fast/js/regexp-bol-with-multiline.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="resources/js-test-style.css">
+<script src="resources/js-test-pre.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script src="script-tests/regexp-bol-with-multiline.js"></script>
+<script src="resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/script-tests/regexp-bol-with-multiline.js b/LayoutTests/fast/js/script-tests/regexp-bol-with-multiline.js
new file mode 100644
index 0000000..4bb82cc
--- /dev/null
+++ b/LayoutTests/fast/js/script-tests/regexp-bol-with-multiline.js
@@ -0,0 +1,12 @@
+description(
+'Test for beginning of line (BOL or ^) matching in a multiline string</a>'
+);
+
+var s = "aced\nabc";
+shouldBeNull('s.match(/^abc/)');
+shouldBe('s.match(/^abc/m)', '["abc"]');
+shouldBeNull('s.match(/(^|X)abc/)');
+shouldBe('s.match(/(^|X)abc/m)', '["abc",""]');
+shouldBe('s.match(/(^a|Xa)bc/m)', '["abc","a"]');
+
+var successfullyParsed = true;

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list