[Pcre-svn] [726] code/trunk/pcre_jit_compile.c: Refactoring …

トップ ページ
このメッセージを削除
著者: Subversion repository
日付:  
To: pcre-svn
題目: [Pcre-svn] [726] code/trunk/pcre_jit_compile.c: Refactoring atomic block data saving.
Revision: 726
          http://vcs.pcre.org/viewvc?view=rev&revision=726
Author:   zherczeg
Date:     2011-10-09 19:53:25 +0100 (Sun, 09 Oct 2011)


Log Message:
-----------
Refactoring atomic block data saving. The new code is considerably simpler and use less memory. OP_ONCE_NC is also supported.

Modified Paths:
--------------
    code/trunk/pcre_jit_compile.c


Modified: code/trunk/pcre_jit_compile.c
===================================================================
--- code/trunk/pcre_jit_compile.c    2011-10-09 16:26:33 UTC (rev 725)
+++ code/trunk/pcre_jit_compile.c    2011-10-09 18:53:25 UTC (rev 726)
@@ -352,21 +352,19 @@
 /* Two local variables for possessive quantifiers (char1 cannot use them). */
 #define POSSESSIVE0      (2 * sizeof(sljit_w))
 #define POSSESSIVE1      (3 * sizeof(sljit_w))
-/* Head of the saved local variables */
-#define LOCALS_HEAD      (4 * sizeof(sljit_w))
 /* Head of the last recursion. */
-#define RECURSIVE_HEAD   (5 * sizeof(sljit_w))
+#define RECURSIVE_HEAD   (4 * sizeof(sljit_w))
 /* Max limit of recursions. */
-#define CALL_LIMIT       (7 * sizeof(sljit_w))
+#define CALL_LIMIT       (5 * sizeof(sljit_w))
 /* Last known position of the requested byte. */
-#define REQ_BYTE_PTR     (8 * sizeof(sljit_w))
+#define REQ_BYTE_PTR     (6 * sizeof(sljit_w))
 /* End pointer of the first line. */
-#define FIRSTLINE_END    (9 * sizeof(sljit_w))
+#define FIRSTLINE_END    (7 * sizeof(sljit_w))
 /* The output vector is stored on the stack, and contains pointers
 to characters. The vector data is divided into two groups: the first
 group contains the start / end character pointers, and the second is
 the start pointers when the end of the capturing group has not yet reached. */
-#define OVECTOR_START    (10 * sizeof(sljit_w))
+#define OVECTOR_START    (8 * sizeof(sljit_w))
 #define OVECTOR(i)       (OVECTOR_START + (i) * sizeof(sljit_w))
 #define OVECTOR_PRIV(i)  (common->cbraptr + (i) * sizeof(sljit_w))
 #define PRIV(cc)         (common->localptrs[(cc) - common->start])
@@ -571,6 +569,7 @@
   case OP_ASSERTBACK_NOT:
   case OP_REVERSE:
   case OP_ONCE:
+  case OP_ONCE_NC:
   case OP_BRA:
   case OP_BRAPOS:
   case OP_COND:
@@ -609,6 +608,7 @@
     case OP_ASSERTBACK:
     case OP_ASSERTBACK_NOT:
     case OP_ONCE:
+    case OP_ONCE_NC:
     case OP_BRAPOS:
     case OP_SBRA:
     case OP_SBRAPOS:
@@ -654,6 +654,7 @@
     case OP_ASSERTBACK:
     case OP_ASSERTBACK_NOT:
     case OP_ONCE:
+    case OP_ONCE_NC:
     case OP_BRAPOS:
     case OP_SBRA:
     case OP_SBRAPOS:
@@ -693,10 +694,8 @@
 static int get_framesize(compiler_common *common, uschar *cc, BOOL recursive)
 {
 uschar *ccend = bracketend(cc);
-uschar *end;
 int length = 0;
 BOOL possessive = FALSE;
-BOOL needs_frame = FALSE;
 BOOL setsom_found = FALSE;


 if (!recursive && (*cc == OP_CBRAPOS || *cc == OP_SCBRAPOS))
@@ -720,28 +719,6 @@
     cc += (*cc == OP_SET_SOM) ? 1 : 1 + LINK_SIZE;
     break;


-    case OP_ASSERT:
-    case OP_ASSERT_NOT:
-    case OP_ASSERTBACK:
-    case OP_ASSERTBACK_NOT:
-    case OP_ONCE:
-    if (needs_frame || length > 0)
-      {
-      cc = bracketend(cc);
-      break;
-      }
-    /* Check whether a frame must be created. */
-    end = bracketend(cc);
-    while (cc < end)
-      {
-      if (*cc == OP_SET_SOM || *cc == OP_CBRA || *cc == OP_CBRAPOS
-          || *cc == OP_SCBRA || *cc == OP_SCBRAPOS || *cc == OP_RECURSE)
-    needs_frame = TRUE;
-      cc = next_opcode(common, cc);
-      SLJIT_ASSERT(cc != NULL);
-      }
-    break;
-
     case OP_CBRA:
     case OP_CBRAPOS:
     case OP_SCBRA:
@@ -757,33 +734,25 @@
     }


/* Possessive quantifiers can use a special case. */
-if (SLJIT_UNLIKELY(possessive) && !needs_frame && length == 3 + 2)
+if (SLJIT_UNLIKELY(possessive) && length == 3)
return -1;

if (length > 0)
- return length + 2;
-return needs_frame ? 0 : -1;
+ return length + 1;
+return -1;
}

static void init_frame(compiler_common *common, uschar *cc, int stackpos, int stacktop, BOOL recursive)
{
-/* TMP2 must contain STACK_TOP - (-STACK(stackpos)) */
DEFINE_COMPILER;
uschar *ccend = bracketend(cc);
BOOL setsom_found = FALSE;
int offset;

-if (stackpos < stacktop)
- {
- SLJIT_ASSERT(stackpos + 1 == stacktop);
- return;
- }
+/* >= 1 + shortest item size (2) */
+SLJIT_ASSERT(stackpos >= stacktop + 2);

 stackpos = STACK(stackpos);
-OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS_HEAD);
-OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS_HEAD, TMP2, 0);
-OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacktop), TMP1, 0);
-
 if (recursive || (*cc != OP_CBRAPOS && *cc != OP_SCBRAPOS))
   cc = next_opcode(common, cc);
 SLJIT_ASSERT(cc != NULL);
@@ -804,14 +773,6 @@
     cc += (*cc == OP_SET_SOM) ? 1 : 1 + LINK_SIZE;
     break;


-    case OP_ASSERT:
-    case OP_ASSERT_NOT:
-    case OP_ASSERTBACK:
-    case OP_ASSERTBACK_NOT:
-    case OP_ONCE:
-    cc = bracketend(cc);
-    break;
-
     case OP_CBRA:
     case OP_CBRAPOS:
     case OP_SCBRA:
@@ -836,7 +797,7 @@
     }


OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, frame_end);
-SLJIT_ASSERT(stackpos == STACK(stacktop + 1));
+SLJIT_ASSERT(stackpos == STACK(stacktop));
}

 static SLJIT_INLINE int get_localsize(compiler_common *common, uschar *cc, uschar *ccend)
@@ -853,6 +814,7 @@
     case OP_ASSERTBACK:
     case OP_ASSERTBACK_NOT:
     case OP_ONCE:
+    case OP_ONCE_NC:
     case OP_BRAPOS:
     case OP_SBRA:
     case OP_SBRAPOS:
@@ -955,6 +917,7 @@
       case OP_ASSERTBACK:
       case OP_ASSERTBACK_NOT:
       case OP_ONCE:
+      case OP_ONCE_NC:
       case OP_BRAPOS:
       case OP_SBRA:
       case OP_SBRAPOS:
@@ -1966,15 +1929,13 @@
 static void do_revertframes(compiler_common *common)
 {
 DEFINE_COMPILER;
-struct sljit_jump *earlyexit;
 struct sljit_jump *jump;
 struct sljit_label *mainloop;


sljit_emit_fast_enter(compiler, RETURN_ADDR, 0, 1, 5, 5, common->localsize);
-OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS_HEAD);
+OP1(SLJIT_MOV, TMP1, 0, STACK_TOP, 0);

/* Drop frames until we reach STACK_TOP. */
-earlyexit = CMP(SLJIT_C_LESS, TMP1, 0, STACK_TOP, 0);
mainloop = LABEL();
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), 0);
jump = CMP(SLJIT_C_SIG_LESS_EQUAL, TMP2, 0, SLJIT_IMM, frame_end);
@@ -1987,10 +1948,6 @@
JUMPHERE(jump);
jump = CMP(SLJIT_C_NOT_EQUAL, TMP2, 0, SLJIT_IMM, frame_end);
/* End of dropping frames. */
-OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), sizeof(sljit_w));
-OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS_HEAD, TMP1, 0);
-CMPTO(SLJIT_C_GREATER_EQUAL, TMP1, 0, STACK_TOP, 0, mainloop);
-JUMPHERE(earlyexit);
sljit_emit_fast_return(compiler, RETURN_ADDR, 0);

 JUMPHERE(jump);
@@ -3632,30 +3589,33 @@
   if (common->accept != NULL)
     set_jumps(common->accept, common->acceptlabel);


+  /* Reset stack. */
   if (framesize < 0)
     OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
+  else {
+    if ((opcode != OP_ASSERT_NOT && opcode != OP_ASSERTBACK_NOT) || conditional)
+      {
+      /* We don't need to keep the STR_PTR, only the previous localptr. */
+      OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_IMM, (framesize + 1) * sizeof(sljit_w));
+      }
+    else
+      {
+      OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
+      add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
+      }
+  }


   if (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT)
     {
     /* We know that STR_PTR was stored on the top of the stack. */
     if (conditional)
-      {
-      if (framesize < 0)
-        OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), 0);
-      else
-        {
-        OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
-        OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(TMP1), (framesize + 1) * sizeof(sljit_w));
-        }
-      }
+      OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), 0);
     else if (bra == OP_BRAZERO)
       {
       if (framesize < 0)
         OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), 0);
       else
         {
-        OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
-        add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
         OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), framesize * sizeof(sljit_w));
         OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), (framesize + 1) * sizeof(sljit_w));
         OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, TMP1, 0);
@@ -3663,14 +3623,10 @@
       OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_w));
       OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
       }
-    else if (bra == OP_BRAMINZERO)
+    else if (framesize >= 0)
       {
-      if (framesize >= 0)
-        {
-        OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
-        add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
-        OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_MEM1(STACK_TOP), framesize * sizeof(sljit_w));
-        }
+      /* For OP_BRA and OP_BRAMINZERO. */
+      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_MEM1(STACK_TOP), framesize * sizeof(sljit_w));
       }
     }
   add_jump(compiler, found, JUMP(SLJIT_JUMP));
@@ -3697,6 +3653,7 @@
   /* Assert is failed. */
   if (conditional || bra == OP_BRAZERO)
     OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+
   if (framesize < 0)
     {
     /* The topmost item should be 0. */
@@ -3708,8 +3665,6 @@
   else
     {
     OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
-    if (framesize > 0)
-      OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(2));
     /* The topmost item should be 0. */
     if (bra == OP_BRAZERO)
       {
@@ -3719,8 +3674,6 @@
     else
       free_stack(common, framesize + 2);
     OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, TMP1, 0);
-    if (framesize > 0)
-      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS_HEAD, TMP2, 0);
     }
   jump = JUMP(SLJIT_JUMP);
   if (bra != OP_BRAZERO)
@@ -3743,17 +3696,18 @@
     }
   else
     {
-    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
-    OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(TMP1), (framesize + 1) * sizeof(sljit_w));
-    if (bra == OP_BRAZERO)
+    if (bra == OP_BRA)
       {
-      allocate_stack(common, 1);
-      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+      /* We don't need to keep the STR_PTR, only the previous localptr. */
+      OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_IMM, (framesize + 1) * sizeof(sljit_w));
+      OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), 0);
       }
-    else if (bra == OP_BRAMINZERO)
+    else
       {
-      allocate_stack(common, 1);
-      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+      /* We don't need to keep the STR_PTR, only the previous localptr. */
+      OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_IMM, (framesize + 2) * sizeof(sljit_w));
+      OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), bra == OP_BRAZERO ? STR_PTR : SLJIT_IMM, 0);
       }
     }


@@ -3790,8 +3744,6 @@
     {
     OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
     OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
-    if (framesize > 0)
-      OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(2));
     /* The topmost item should be 0. */
     if (bra != OP_BRA)
       {
@@ -3801,8 +3753,6 @@
     else
       free_stack(common, framesize + 2);
     OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, TMP1, 0);
-    if (framesize > 0)
-      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS_HEAD, TMP2, 0);
     }


   if (bra == OP_BRAZERO)
@@ -3873,10 +3823,11 @@
     M - Any values pushed by the current alternative. Can be empty, or anything.


   The next list shows the possible content of a bracket:
-  (|)     OP_*BRA  | OP_ALT ...         M A
-  (?()|)  OP_*COND | OP_ALT             M A
-  (?>|)   OP_ONCE  | OP_ALT ...         [stack trace] M A
-                                        Or nothing, if trace is unnecessary
+  (|)     OP_*BRA    | OP_ALT ...         M A
+  (?()|)  OP_*COND   | OP_ALT             M A
+  (?>|)   OP_ONCE    | OP_ALT ...         [stack trace] M A
+  (?>|)   OP_ONCE_NC | OP_ALT ...         [stack trace] M A
+                                          Or nothing, if trace is unnecessary
 */


static uschar *compile_bracket_hotpath(compiler_common *common, uschar *cc, fallback_common *parent)
@@ -3923,6 +3874,8 @@
has_alternatives = *cc == OP_ALT || opcode == OP_COND || opcode == OP_SCOND;
if (SLJIT_UNLIKELY(opcode == OP_COND) && (*cc == OP_KETRMAX || *cc == OP_KETRMIN))
opcode = OP_SCOND;
+if (SLJIT_UNLIKELY(opcode == OP_ONCE_NC))
+ opcode = OP_ONCE;

 if (opcode == OP_CBRA || opcode == OP_SCBRA)
   {
@@ -4130,11 +4083,15 @@
       OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_MEM1(STACK_TOP), 0);
       }
     }
-  else if (ket == OP_KETRMAX)
+  else
     {
-    /* TMP2 which is set here used by OP_KETRMAX below. */
-    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
-    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP2), (FALLBACK_AS(bracket_fallback)->u.framesize + 1) * sizeof(sljit_w));
+    stacksize = (ket == OP_KETRMIN || ket == OP_KETRMAX || has_alternatives) ? 2 : 1;
+    OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_IMM, (FALLBACK_AS(bracket_fallback)->u.framesize + stacksize) * sizeof(sljit_w));
+    if (ket == OP_KETRMAX)
+      {
+      /* TMP2 which is set here used by OP_KETRMAX below. */
+      OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+      }
     }
   }


@@ -4368,9 +4325,8 @@
     {
     if (opcode == OP_CBRAPOS || opcode == OP_SCBRAPOS)
       {
+      OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_IMM, stacksize * sizeof(sljit_w));
       OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), cbraprivptr);
-      if (!zero)
-        OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
       OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset + 1), STR_PTR, 0);
       OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), cbraprivptr, STR_PTR, 0);
       OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(offset), TMP1, 0);
@@ -4378,6 +4334,7 @@
     else
       {
       OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
+      OP2(SLJIT_ADD, STACK_TOP, 0, TMP2, 0, SLJIT_IMM, stacksize * sizeof(sljit_w));
       if (opcode == OP_SBRAPOS)
         OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), (framesize + 1) * sizeof(sljit_w));
       OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), (framesize + 1) * sizeof(sljit_w), STR_PTR, 0);
@@ -4386,13 +4343,12 @@
     if (opcode == OP_SBRAPOS || opcode == OP_SCBRAPOS)
       add_jump(compiler, &emptymatch, CMP(SLJIT_C_EQUAL, TMP1, 0, STR_PTR, 0));


-    /* TMP2 must be set above. */
     if (!zero)
       {
       if (framesize < 0)
         OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize - 1), SLJIT_IMM, 0);
       else
-        OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), (stacksize - 1) * sizeof(sljit_w), SLJIT_IMM, 0);
+        OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
       }
     }
   JUMPTO(SLJIT_JUMP, loop);
@@ -4414,6 +4370,7 @@
     {
     if (opcode == OP_CBRAPOS || opcode == OP_SCBRAPOS)
       {
+      /* Last alternative. */
       if (*cc == OP_KETRPOS)
         OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
       OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), cbraprivptr);
@@ -4946,6 +4903,7 @@
     break;


     case OP_ONCE:
+    case OP_ONCE_NC:
     case OP_BRA:
     case OP_CBRA:
     case OP_COND:
@@ -5176,7 +5134,6 @@
 DEFINE_COMPILER;
 uschar *cc = current->cc;
 uschar bra = OP_BRA;
-struct sljit_jump *jump;
 struct sljit_jump *brajump = NULL;


SLJIT_ASSERT(*cc != OP_BRAMINZERO);
@@ -5222,19 +5179,12 @@
{
OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), CURRENT_AS(assert_fallback)->localptr);
add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), CURRENT_AS(assert_fallback)->localptr, SLJIT_MEM1(STACK_TOP), CURRENT_AS(assert_fallback)->framesize * sizeof(sljit_w));

set_jumps(current->topfallbacks, LABEL());
}
else
- {
- jump = JUMP(SLJIT_JUMP);
-
set_jumps(current->topfallbacks, LABEL());
- OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), CURRENT_AS(assert_fallback)->localptr);
- add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
- JUMPHERE(jump);
- }
-OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), CURRENT_AS(assert_fallback)->localptr, SLJIT_MEM1(STACK_TOP), CURRENT_AS(assert_fallback)->framesize * sizeof(sljit_w));

if (bra == OP_BRAZERO)
{
@@ -5281,6 +5231,8 @@
offset = (GET2(ccbegin, 1 + LINK_SIZE)) << 1;
if (SLJIT_UNLIKELY(opcode == OP_COND) && (*cc == OP_KETRMAX || *cc == OP_KETRMIN))
opcode = OP_SCOND;
+if (SLJIT_UNLIKELY(opcode == OP_ONCE_NC))
+ opcode = OP_ONCE;

 if (ket == OP_KETRMAX)
   {
@@ -5431,22 +5383,26 @@
     /* There is a similar code in compile_bracket_hotpath. */
     if (opcode == OP_ONCE)
       {
-      if (CURRENT_AS(bracket_fallback)->u.framesize >= 0)
+      if (CURRENT_AS(bracket_fallback)->u.framesize < 0)
         {
+        OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
+        /* TMP2 which is set here used by OP_KETRMAX below. */
         if (ket == OP_KETRMAX)
+          OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), 0);
+        else if (ket == OP_KETRMIN)
           {
-          OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
-          OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP2), (CURRENT_AS(bracket_fallback)->u.framesize + 1) * sizeof(sljit_w));
+          /* Move the STR_PTR to the localptr. */
+          OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_MEM1(STACK_TOP), 0);
           }
         }
       else
         {
-        OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr);
-        /* The register which is set here used by OP_KETRMAX below. */
+        OP2(SLJIT_ADD, STACK_TOP, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_IMM, (CURRENT_AS(bracket_fallback)->u.framesize + 2) * sizeof(sljit_w));
         if (ket == OP_KETRMAX)
-          OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), 0);
-        else if (ket == OP_KETRMIN)
-          OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), localptr, SLJIT_MEM1(STACK_TOP), 0);
+          {
+          /* TMP2 which is set here used by OP_KETRMAX below. */
+          OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+          }
         }
       }


@@ -5544,11 +5500,7 @@
     {
     /* Reset head and drop saved frame. */
     stacksize = (ket == OP_KETRMAX || ket == OP_KETRMIN || *cc == OP_ALT) ? 2 : 1;
-    if (CURRENT_AS(bracket_fallback)->u.framesize > 0)
-      OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(stacksize));
     free_stack(common, CURRENT_AS(bracket_fallback)->u.framesize + stacksize);
-    if (CURRENT_AS(bracket_fallback)->u.framesize > 0)
-      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS_HEAD, TMP1, 0);
     }
   else if (ket == OP_KETRMAX || (*cc == OP_ALT && ket != OP_KETRMIN))
     {
@@ -5632,10 +5584,8 @@
   {
   jump = JUMP(SLJIT_JUMP);
   set_jumps(current->topfallbacks, LABEL());
-  /* Drop the stack frame and restore LOCALS_HEAD. */
-  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(CURRENT_AS(bracketpos_fallback)->stacksize - CURRENT_AS(bracketpos_fallback)->framesize));
+  /* Drop the stack frame. */
   free_stack(common, CURRENT_AS(bracketpos_fallback)->stacksize);
-  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS_HEAD, TMP1, 0);
   JUMPHERE(jump);
   }
 OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), CURRENT_AS(bracketpos_fallback)->localptr, SLJIT_MEM1(STACK_TOP), CURRENT_AS(bracketpos_fallback)->framesize * sizeof(sljit_w));
@@ -5769,6 +5719,7 @@
     break;


     case OP_ONCE:
+    case OP_ONCE_NC:
     case OP_BRA:
     case OP_CBRA:
     case OP_COND:
@@ -5840,10 +5791,7 @@
 copy_locals(common, ccbegin, ccend, TRUE, localsize + framesize + alternativesize, framesize + alternativesize);
 OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), RECURSIVE_HEAD, STACK_TOP, 0);
 if (needsframe)
-  {
-  OP2(SLJIT_SUB, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, -STACK(framesize + alternativesize - 1));
   init_frame(common, cc, framesize + alternativesize - 1, alternativesize, FALSE);
-  }


if (alternativesize > 0)
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
@@ -5880,8 +5828,6 @@
}
/* None of them matched. */
OP1(SLJIT_MOV, TMP3, 0, SLJIT_IMM, 0);
-if (needsframe)
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS_HEAD, SLJIT_MEM1(STACK_TOP), STACK(alternativesize));
jump = JUMP(SLJIT_JUMP);

set_jumps(common->accept, LABEL());
@@ -5889,9 +5835,9 @@
if (needsframe)
{
OP1(SLJIT_MOV, TMP3, 0, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0));
- OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (localsize + framesize + alternativesize) * sizeof(sljit_w));
+ OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + alternativesize) * sizeof(sljit_w));
add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
- OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (localsize + framesize + alternativesize) * sizeof(sljit_w));
+ OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + alternativesize) * sizeof(sljit_w));
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), OVECTOR(0), TMP3, 0);
}
OP1(SLJIT_MOV, TMP3, 0, SLJIT_IMM, 1);
@@ -6031,7 +5977,6 @@
reset_ovector(common, (re->top_bracket + 1) * 2);
if ((re->flags & PCRE_REQCHSET) != 0)
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), REQ_BYTE_PTR, SLJIT_TEMPORARY_REG1, 0);
-OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_LOCALS_REG), LOCALS_HEAD, SLJIT_IMM, 0);

OP1(SLJIT_MOV, ARGUMENTS, 0, SLJIT_GENERAL_REG1, 0);
OP1(SLJIT_MOV, TMP1, 0, SLJIT_GENERAL_REG1, 0);