JavaScriptCore:
authordarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 1 Jan 2008 19:16:06 +0000 (19:16 +0000)
committerdarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 1 Jan 2008 19:16:06 +0000 (19:16 +0000)
        Reviewed by Geoff.

        - fix http://bugs.webkit.org/show_bug.cgi?id=16648
          REGRESSION (r28165): Yuku.com navigation prints "jsRegExpExecute failed with result -2"
          <rdar://problem/5646486> REGRESSION (r28165): Layout test fast/regex/test1 fails intermittently

        Fixes 34 failing test cases in the fast/regex/test1.html test.

        Restored the stack which prevents infinite loops for brackets that match the empty
        string; it had been removed as an optimization.

        Unfortunately, restoring this stack causes the regular expression test in SunSpider
        to be 1.095x as slow and the overall test to be 1.004x as slow. Maybe we can find
        a correct optimization to restore the speed!

        It's possible the original change was on the right track but just off by one.

        * pcre/pcre_exec.cpp: Add back eptrblock, but name it BracketChainNode.
        (MatchStack::pushNewFrame): Add back the logic needed here.
        (startNewGroup): Ditto.
        (match): Ditto.

LayoutTests:

        Reviewed by Geoff.

        - updated test results for https://bugs.webkit.org/show_bug.cgi?id=16648

        * fast/regex/test1-expected.txt: Update results changed by restoring the logic to
        avoid failing on infinite repeats of brackets that match the empty string.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@29066 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JavaScriptCore/ChangeLog
JavaScriptCore/pcre/pcre_exec.cpp
LayoutTests/ChangeLog
LayoutTests/fast/regex/test1-expected.txt

index b813b719c896ddf54ef0938281d45b3bb22ab4c9..39f290396776568d54a955351d3754d9d3c15986 100644 (file)
@@ -1,3 +1,27 @@
+2008-01-01  Darin Adler  <darin@apple.com>
+
+        Reviewed by Geoff.
+
+        - fix http://bugs.webkit.org/show_bug.cgi?id=16648
+          REGRESSION (r28165): Yuku.com navigation prints "jsRegExpExecute failed with result -2"
+          <rdar://problem/5646486> REGRESSION (r28165): Layout test fast/regex/test1 fails intermittently
+
+        Fixes 34 failing test cases in the fast/regex/test1.html test.
+
+        Restored the stack which prevents infinite loops for brackets that match the empty
+        string; it had been removed as an optimization.
+
+        Unfortunately, restoring this stack causes the regular expression test in SunSpider
+        to be 1.095x as slow and the overall test to be 1.004x as slow. Maybe we can find
+        a correct optimization to restore the speed!
+
+        It's possible the original change was on the right track but just off by one.
+
+        * pcre/pcre_exec.cpp: Add back eptrblock, but name it BracketChainNode.
+        (MatchStack::pushNewFrame): Add back the logic needed here.
+        (startNewGroup): Ditto.
+        (match): Ditto.
+
 2008-01-01  Darin Adler  <darin@apple.com>
 
         Reviewed by Geoff.
index 2004f86916f640d052caead658fd77ebd301aa57..eeb4b102d5d83147c6dcdfe40b9438574b109537 100644 (file)
@@ -66,6 +66,14 @@ typedef int ReturnLocation;
 typedef void* ReturnLocation;
 #endif
 
+/* Structure for building a chain of data for holding the values of
+the subject pointer at the start of each bracket, used to detect when
+an empty string has been matched by a bracket to break infinite loops. */ 
+struct BracketChainNode {
+    BracketChainNode* previousBracket;
+    const UChar* bracketStart;
+};
+
 struct MatchFrame {
     ReturnLocation returnLocation;
     struct MatchFrame* previousFrame;
@@ -75,7 +83,7 @@ struct MatchFrame {
         const UChar* subjectPtr;
         const unsigned char* instructionPtr;
         int offsetTop;
-        const UChar* subpatternStart;
+        BracketChainNode* bracketChain;
     } args;
     
     
@@ -101,7 +109,7 @@ struct MatchFrame {
         int saveOffset2;
         int saveOffset3;
         
-        const UChar* subpatternStart;
+        BracketChainNode bracketChainNode;
     } locals;
 };
 
@@ -313,7 +321,7 @@ struct MatchStack {
         return new MatchFrame;
     }
     
-    inline void pushNewFrame(const unsigned char* instructionPtr, const UChar* subpatternStart, ReturnLocation returnLocation)
+    inline void pushNewFrame(const unsigned char* instructionPtr, BracketChainNode* bracketChain, ReturnLocation returnLocation)
     {
         MatchFrame* newframe = allocateNextFrame();
         newframe->previousFrame = currentFrame;
@@ -321,7 +329,7 @@ struct MatchStack {
         newframe->args.subjectPtr = currentFrame->args.subjectPtr;
         newframe->args.offsetTop = currentFrame->args.offsetTop;
         newframe->args.instructionPtr = instructionPtr;
-        newframe->args.subpatternStart = subpatternStart;
+        newframe->args.bracketChain = bracketChain;
         newframe->returnLocation = returnLocation;
         size++;
 
@@ -375,7 +383,9 @@ static inline void startNewGroup(MatchFrame* currentFrame)
      the closing ket. When match() is called in other circumstances, we don't add to
      this stack. */
     
-    currentFrame->locals.subpatternStart = currentFrame->args.subpatternStart;
+    currentFrame->locals.bracketChainNode.previousBracket = currentFrame->args.bracketChain;
+    currentFrame->locals.bracketChainNode.bracketStart = currentFrame->args.subjectPtr;
+    currentFrame->args.bracketChain = &currentFrame->locals.bracketChainNode;
 }
 
 // FIXME: "minimize" means "not greedy", we should invert the callers to ask for "greedy" to be less confusing
@@ -425,7 +435,7 @@ static int match(const UChar* subjectPtr, const unsigned char* instructionPtr, i
     stack.currentFrame->args.subjectPtr = subjectPtr;
     stack.currentFrame->args.instructionPtr = instructionPtr;
     stack.currentFrame->args.offsetTop = offsetTop;
-    stack.currentFrame->args.subpatternStart = 0;
+    stack.currentFrame->args.bracketChain = 0;
     startNewGroup(stack.currentFrame);
     
     /* This is where control jumps back to to effect "recursion" */
@@ -461,7 +471,7 @@ RECURSE:
             NON_CAPTURING_BRACKET:
                 DPRINTF(("start bracket 0\n"));
                 do {
-                    RECURSIVE_MATCH_STARTNG_NEW_GROUP(2, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.subpatternStart);
+                    RECURSIVE_MATCH_STARTNG_NEW_GROUP(2, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain);
                     if (isMatch)
                         RRETURN;
                     stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1);
@@ -535,7 +545,7 @@ RECURSE:
                 
             BEGIN_OPCODE(BRAZERO): {
                 stack.currentFrame->locals.startOfRepeatingBracket = stack.currentFrame->args.instructionPtr + 1;
-                RECURSIVE_MATCH_STARTNG_NEW_GROUP(14, stack.currentFrame->locals.startOfRepeatingBracket, stack.currentFrame->args.subpatternStart);
+                RECURSIVE_MATCH_STARTNG_NEW_GROUP(14, stack.currentFrame->locals.startOfRepeatingBracket, stack.currentFrame->args.bracketChain);
                 if (isMatch)
                     RRETURN;
                 advanceToEndOfBracket(stack.currentFrame->locals.startOfRepeatingBracket);
@@ -546,7 +556,7 @@ RECURSE:
             BEGIN_OPCODE(BRAMINZERO): {
                 stack.currentFrame->locals.startOfRepeatingBracket = stack.currentFrame->args.instructionPtr + 1;
                 advanceToEndOfBracket(stack.currentFrame->locals.startOfRepeatingBracket);
-                RECURSIVE_MATCH_STARTNG_NEW_GROUP(15, stack.currentFrame->locals.startOfRepeatingBracket + 1 + LINK_SIZE, stack.currentFrame->args.subpatternStart);
+                RECURSIVE_MATCH_STARTNG_NEW_GROUP(15, stack.currentFrame->locals.startOfRepeatingBracket + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain);
                 if (isMatch)
                     RRETURN;
                 stack.currentFrame->args.instructionPtr++;
@@ -562,8 +572,11 @@ RECURSE:
             BEGIN_OPCODE(KETRMIN):
             BEGIN_OPCODE(KETRMAX):
                 stack.currentFrame->locals.instructionPtrAtStartOfOnce = stack.currentFrame->args.instructionPtr - getLinkValue(stack.currentFrame->args.instructionPtr + 1);
-                stack.currentFrame->args.subpatternStart = stack.currentFrame->locals.subpatternStart;
-                stack.currentFrame->locals.subpatternStart = stack.currentFrame->previousFrame->args.subpatternStart;
+                stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.bracketChain->bracketStart;
+
+                /* Back up the stack of bracket start pointers. */
+
+                stack.currentFrame->args.bracketChain = stack.currentFrame->args.bracketChain->previousBracket;
 
                 if (*stack.currentFrame->locals.instructionPtrAtStartOfOnce == OP_ASSERT || *stack.currentFrame->locals.instructionPtrAtStartOfOnce == OP_ASSERT_NOT) {
                     md.endOffsetTop = stack.currentFrame->args.offsetTop;
@@ -621,17 +634,17 @@ RECURSE:
                  preceding bracket, in the appropriate order. */
                 
                 if (*stack.currentFrame->args.instructionPtr == OP_KETRMIN) {
-                    RECURSIVE_MATCH(16, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.subpatternStart);
+                    RECURSIVE_MATCH(16, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain);
                     if (isMatch)
                         RRETURN;
-                    RECURSIVE_MATCH_STARTNG_NEW_GROUP(17, stack.currentFrame->locals.instructionPtrAtStartOfOnce, stack.currentFrame->args.subpatternStart);
+                    RECURSIVE_MATCH_STARTNG_NEW_GROUP(17, stack.currentFrame->locals.instructionPtrAtStartOfOnce, stack.currentFrame->args.bracketChain);
                     if (isMatch)
                         RRETURN;
                 } else { /* OP_KETRMAX */
-                    RECURSIVE_MATCH_STARTNG_NEW_GROUP(18, stack.currentFrame->locals.instructionPtrAtStartOfOnce, stack.currentFrame->args.subpatternStart);
+                    RECURSIVE_MATCH_STARTNG_NEW_GROUP(18, stack.currentFrame->locals.instructionPtrAtStartOfOnce, stack.currentFrame->args.bracketChain);
                     if (isMatch)
                         RRETURN;
-                    RECURSIVE_MATCH(19, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.subpatternStart);
+                    RECURSIVE_MATCH(19, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain);
                     if (isMatch)
                         RRETURN;
                 }
@@ -805,7 +818,7 @@ RECURSE:
                 
                 if (minimize) {
                     for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
-                        RECURSIVE_MATCH(20, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.subpatternStart);
+                        RECURSIVE_MATCH(20, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
                         if (isMatch)
                             RRETURN;
                         if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || !matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md))
@@ -825,7 +838,7 @@ RECURSE:
                         stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length;
                     }
                     while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) {
-                        RECURSIVE_MATCH(21, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.subpatternStart);
+                        RECURSIVE_MATCH(21, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
                         if (isMatch)
                             RRETURN;
                         stack.currentFrame->args.subjectPtr -= stack.currentFrame->locals.length;
@@ -900,7 +913,7 @@ RECURSE:
                  the pointer while it matches the class. */
                 if (minimize) {
                     for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
-                        RECURSIVE_MATCH(22, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.subpatternStart);
+                        RECURSIVE_MATCH(22, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
                         if (isMatch)
                             RRETURN;
                         if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject)
@@ -934,7 +947,7 @@ RECURSE:
                         ++stack.currentFrame->args.subjectPtr;
                     }
                     for (;;) {
-                        RECURSIVE_MATCH(24, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.subpatternStart);
+                        RECURSIVE_MATCH(24, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
                         if (isMatch)
                             RRETURN;
                         if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction)
@@ -996,7 +1009,7 @@ RECURSE:
                 
                 if (minimize) {
                     for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
-                        RECURSIVE_MATCH(26, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.subpatternStart);
+                        RECURSIVE_MATCH(26, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
                         if (isMatch)
                             RRETURN;
                         if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject)
@@ -1021,7 +1034,7 @@ RECURSE:
                         ++stack.currentFrame->args.subjectPtr;
                     }
                     for(;;) {
-                        RECURSIVE_MATCH(27, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.subpatternStart);
+                        RECURSIVE_MATCH(27, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
                         if (isMatch)
                             RRETURN;
                         if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction)
@@ -1133,7 +1146,7 @@ RECURSE:
                     if (minimize) {
                         stack.currentFrame->locals.repeatOthercase = othercase;
                         for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
-                            RECURSIVE_MATCH(28, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.subpatternStart);
+                            RECURSIVE_MATCH(28, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
                             if (isMatch)
                                 RRETURN;
                             if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject)
@@ -1153,7 +1166,7 @@ RECURSE:
                             ++stack.currentFrame->args.subjectPtr;
                         }
                         while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) {
-                            RECURSIVE_MATCH(29, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.subpatternStart);
+                            RECURSIVE_MATCH(29, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
                             if (isMatch)
                                 RRETURN;
                             --stack.currentFrame->args.subjectPtr;
@@ -1175,7 +1188,7 @@ RECURSE:
                     
                     if (minimize) {
                         for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
-                            RECURSIVE_MATCH(30, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.subpatternStart);
+                            RECURSIVE_MATCH(30, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
                             if (isMatch)
                                 RRETURN;
                             if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject)
@@ -1195,7 +1208,7 @@ RECURSE:
                             stack.currentFrame->args.subjectPtr += 2;
                         }
                         while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) {
-                            RECURSIVE_MATCH(31, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.subpatternStart);
+                            RECURSIVE_MATCH(31, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
                             if (isMatch)
                                 RRETURN;
                             stack.currentFrame->args.subjectPtr -= 2;
@@ -1290,7 +1303,7 @@ RECURSE:
                     
                     if (minimize) {
                         for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
-                            RECURSIVE_MATCH(38, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.subpatternStart);
+                            RECURSIVE_MATCH(38, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
                             if (isMatch)
                                 RRETURN;
                             int d = *stack.currentFrame->args.subjectPtr++;
@@ -1318,7 +1331,7 @@ RECURSE:
                             ++stack.currentFrame->args.subjectPtr;
                         }
                         for (;;) {
-                            RECURSIVE_MATCH(40, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.subpatternStart);
+                            RECURSIVE_MATCH(40, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
                             if (isMatch)
                                 RRETURN;
                             if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction)
@@ -1344,7 +1357,7 @@ RECURSE:
                     
                     if (minimize) {
                         for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
-                            RECURSIVE_MATCH(42, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.subpatternStart);
+                            RECURSIVE_MATCH(42, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
                             if (isMatch)
                                 RRETURN;
                             int d = *stack.currentFrame->args.subjectPtr++;
@@ -1368,7 +1381,7 @@ RECURSE:
                             ++stack.currentFrame->args.subjectPtr;
                         }
                         for (;;) {
-                            RECURSIVE_MATCH(44, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.subpatternStart);
+                            RECURSIVE_MATCH(44, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
                             if (isMatch)
                                 RRETURN;
                             if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction)
@@ -1494,7 +1507,7 @@ RECURSE:
                 
                 if (minimize) {
                     for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
-                        RECURSIVE_MATCH(48, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.subpatternStart);
+                        RECURSIVE_MATCH(48, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
                         if (isMatch)
                             RRETURN;
                         if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject)
@@ -1634,7 +1647,7 @@ RECURSE:
                     /* stack.currentFrame->args.subjectPtr is now past the end of the maximum run */
                     
                     for (;;) {
-                        RECURSIVE_MATCH(52, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.subpatternStart);
+                        RECURSIVE_MATCH(52, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
                         if (isMatch)
                             RRETURN;
                         if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction)
@@ -1703,7 +1716,7 @@ RECURSE:
                     md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number] = stack.currentFrame->args.subjectPtr - md.startSubject;
                     
                     do {
-                        RECURSIVE_MATCH_STARTNG_NEW_GROUP(1, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.subpatternStart);
+                        RECURSIVE_MATCH_STARTNG_NEW_GROUP(1, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain);
                         if (isMatch)
                             RRETURN;
                         stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1);
index 661bfa502bfb87bb2f4ef7e7059dc8f86c992a1e..33e3f10de8fba9316d637c706ccda4e080633976 100644 (file)
@@ -1,3 +1,12 @@
+2008-01-01  Darin Adler  <darin@apple.com>
+
+        Reviewed by Geoff.
+
+        - updated test results for https://bugs.webkit.org/show_bug.cgi?id=16648
+
+        * fast/regex/test1-expected.txt: Update results changed by restoring the logic to
+        avoid failing on infinite repeats of brackets that match the empty string.
+
 2008-01-01  Eric Seidel  <eric@webkit.org>
 
         Reviewed by Alexey.
index 7fd8f14814ca044287c837fcb22db9ffca1bd2ed..97e778f8d6d7783e8bb192e11b92a64fbc45c310 100644 (file)
@@ -1259,50 +1259,50 @@ FAILED TO COMPILE
 FAILED TO COMPILE
 
 /(abc|)+/
-    abc: FAIL. Actual results: "null"
-    abcabc: FAIL. Actual results: "null"
-    abcabcabc: FAIL. Actual results: "null"
-    xyz      : FAIL. Actual results: "null"
+    abc: PASS
+    abcabc: PASS
+    abcabcabc: PASS
+    xyz      : PASS
 
 /([a]*)*/
-    a: FAIL. Actual results: "null"
-    aaaaa : FAIL. Actual results: "null"
+    a: PASS
+    aaaaa : PASS
 
 /([ab]*)*/
-    a: FAIL. Actual results: "null"
-    b: FAIL. Actual results: "null"
-    ababab: FAIL. Actual results: "null"
-    aaaabcde: FAIL. Actual results: "null"
-    bbbb    : FAIL. Actual results: "null"
+    a: PASS
+    b: PASS
+    ababab: PASS
+    aaaabcde: PASS
+    bbbb    : PASS
 
 /([^a]*)*/
-    b: FAIL. Actual results: "null"
-    bbbb: FAIL. Actual results: "null"
-    aaa   : FAIL. Actual results: "null"
+    b: PASS
+    bbbb: PASS
+    aaa   : PASS
 
 /([^ab]*)*/
-    cccc: FAIL. Actual results: "null"
-    abab  : FAIL. Actual results: "null"
+    cccc: PASS
+    abab  : PASS
 
 /([a]*?)*/
-    a: FAIL. Actual results: "null"
-    aaaa : FAIL. Actual results: "null"
+    a: PASS
+    aaaa : PASS
 
 /([ab]*?)*/
-    a: FAIL. Actual results: "null"
-    b: FAIL. Actual results: "null"
-    abab: FAIL. Actual results: "null"
-    baba   : FAIL. Actual results: "null"
+    a: PASS
+    b: PASS
+    abab: PASS
+    baba   : PASS
 
 /([^a]*?)*/
-    b: FAIL. Actual results: "null"
-    bbbb: FAIL. Actual results: "null"
-    aaa   : FAIL. Actual results: "null"
+    b: PASS
+    bbbb: PASS
+    aaa   : PASS
 
 /([^ab]*?)*/
-    c: FAIL. Actual results: "null"
-    cccc: FAIL. Actual results: "null"
-    baba   : FAIL. Actual results: "null"
+    c: PASS
+    cccc: PASS
+    baba   : PASS
 
 /(?>a*)*/
 FAILED TO COMPILE
@@ -2366,8 +2366,8 @@ FAILED TO COMPILE
 
 /^(?:a?b?)*$/
     \: FAIL. Actual results: "null"
-    a: FAIL. Actual results: "null"
-    ab: FAIL. Actual results: "null"
+    a: PASS
+    ab: PASS
     aaa   : FAIL. Actual results: "null"
     *** Failers
     dbcb: PASS
@@ -2865,30 +2865,30 @@ FAILED TO COMPILE
 FAILED TO COMPILE
 
 /^(a()*)*/
-    aaaa: FAIL. Actual results: "null"
+    aaaa: FAIL. Actual results: "a,a,"
 
 /^(?:a(?:(?:))*)*/
-    aaaa: FAIL. Actual results: "null"
+    aaaa: FAIL. Actual results: "a"
 
 /^(a()+)+/
-    aaaa: FAIL. Actual results: "null"
+    aaaa: PASS
 
 /^(?:a(?:(?:))+)+/
-    aaaa: FAIL. Actual results: "null"
+    aaaa: PASS
 
 /(a){0,3}(?(1)b|(c|))*D/
 FAILED TO COMPILE
 
 /(a|)*\d/
   aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: PASS
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4: FAIL. Actual results: "null"
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4: PASS
 
 /(?>a|)*\d/
 FAILED TO COMPILE
 
 /(?:a|)*\d/
   aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: PASS
-  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4: FAIL. Actual results: "null"
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4: PASS
 
 /\Z/g
 Global regex, cannot test matching via JS
@@ -2904,7 +2904,7 @@ FAILED TO COMPILE
 FAILED TO COMPILE
 
 /(.*(.)?)*/
-    abcd: FAIL. Actual results: "null"
+    abcd: FAIL. Actual results: "abcd,,"
 
 /( (A | (?(1)0|) )*   )/x
 Unsupported modifiers: x