2007-11-15 Eric Seidel <eric@webkit.org>
[WebKit-https.git] / JavaScriptCore / pcre / pcre_exec.cpp
index f622abb3b09e74f3eebd00ffb6e8e5852d41d08b..f1a1e5706916bd4e2a40475ff502cb7d181cb0b7 100644 (file)
@@ -332,1642 +332,1641 @@ Returns:       MATCH_MATCH if matched            )  these values are >= 0
                  (e.g. stopped by repeated call or recursion limit)
 */
 
-static int match(USPTR eptr, const uschar *ecode, int offset_top, match_data *md)
+static int match(USPTR eptr, const uschar* ecode, int offset_top, match_data* md)
 {
-register int is_match = false;
-register int i;
-register int c;
-
-unsigned rdepth = 0;
-
-BOOL cur_is_word;
-BOOL prev_is_word;
-BOOL is_group_start = true;
-int min;
-BOOL minimize = false; /* Initialization not really needed, but some compilers think so. */
-
-/* The value 16 here is large enough that most regular expressions don't require
-any calls to pcre_stack_malloc, yet the amount of stack used for the array is
-modest enough that we don't run out of stack. */
-matchframe stackframes[16];
-matchframe *stackframesend = stackframes + sizeof(stackframes) / sizeof(stackframes[0]);
-
-matchframe *frame = stackframes;
-matchframe *newframe;
-
-/* The opcode jump table. */
+    register int is_match = false;
+    register int i;
+    register int c;
+    
+    unsigned rdepth = 0;
+    
+    BOOL cur_is_word;
+    BOOL prev_is_word;
+    BOOL is_group_start = true;
+    int min;
+    BOOL minimize = false; /* Initialization not really needed, but some compilers think so. */
+    
+    /* The value 16 here is large enough that most regular expressions don't require
+     any calls to pcre_stack_malloc, yet the amount of stack used for the array is
+     modest enough that we don't run out of stack. */
+    matchframe stackframes[16];
+    matchframe *stackframesend = stackframes + sizeof(stackframes) / sizeof(stackframes[0]);
+    
+    matchframe *frame = stackframes;
+    matchframe *newframe;
+    
+    /* The opcode jump table. */
 #ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
 #define EMIT_JUMP_TABLE_ENTRY(opcode) &&LABEL_OP_##opcode,
-static void* opcode_jump_table[256] = { FOR_EACH_OPCODE(EMIT_JUMP_TABLE_ENTRY) };
+    static void* opcode_jump_table[256] = { FOR_EACH_OPCODE(EMIT_JUMP_TABLE_ENTRY) };
 #undef EMIT_JUMP_TABLE_ENTRY
 #endif
-
-/* One-time setup of the opcode jump table. */
+    
+    /* One-time setup of the opcode jump table. */
 #ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
-i = 255;
-while (!opcode_jump_table[i])
-  opcode_jump_table[i--] = &&CAPTURING_BRACKET;
+    i = 255;
+    while (!opcode_jump_table[i])
+        opcode_jump_table[i--] = &&CAPTURING_BRACKET;
 #endif
-
+    
 #ifdef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION
-frame->where = &&RETURN;
+    frame->where = &&RETURN;
 #else
-frame->where = 0;
+    frame->where = 0;
 #endif
-
-frame->eptr = eptr;
-frame->ecode = ecode;
-frame->offset_top = offset_top;
-frame->eptrb = NULL;
-
-/* This is where control jumps back to to effect "recursion" */
-
+    
+    frame->eptr = eptr;
+    frame->ecode = ecode;
+    frame->offset_top = offset_top;
+    frame->eptrb = NULL;
+    
+    /* This is where control jumps back to to effect "recursion" */
+    
 RECURSE:
-
-/* OK, now we can get on with the real code of the function. Recursive calls
-are specified by the macro RMATCH and RRETURN is used to return. When
-NO_RECURSE is *not* defined, these just turn into a recursive call to match()
-and a "return", respectively (possibly with some debugging if DEBUG is
-defined). However, RMATCH isn't like a function call because it's quite a
-complicated macro. It has to be used in one particular way. This shouldn't,
-however, impact performance when true recursion is being used. */
-
-/* First check that we haven't called match() too many times, or that we
-haven't exceeded the recursive call limit. */
-
-if (md->match_call_count++ >= MATCH_LIMIT) RRETURN_ERROR(JSRegExpErrorMatchLimit);
-if (rdepth >= MATCH_LIMIT_RECURSION) RRETURN_ERROR(JSRegExpErrorRecursionLimit);
-
-/* At the start of a bracketed group, add the current subject pointer to the
-stack of such pointers, to be re-instated at the end of the group when we hit
-the closing ket. When match() is called in other circumstances, we don't add to
-this stack. */
-
-if (is_group_start)
-  {
-  frame->newptrb.epb_prev = frame->eptrb;
-  frame->newptrb.epb_saved_eptr = frame->eptr;
-  frame->eptrb = &frame->newptrb;
-  }
-
-/* Now start processing the operations. */
-
+    
+    /* OK, now we can get on with the real code of the function. Recursive calls
+     are specified by the macro RMATCH and RRETURN is used to return. When
+     NO_RECURSE is *not* defined, these just turn into a recursive call to match()
+     and a "return", respectively (possibly with some debugging if DEBUG is
+     defined). However, RMATCH isn't like a function call because it's quite a
+     complicated macro. It has to be used in one particular way. This shouldn't,
+     however, impact performance when true recursion is being used. */
+    
+    /* First check that we haven't called match() too many times, or that we
+     haven't exceeded the recursive call limit. */
+    
+    if (md->match_call_count++ >= MATCH_LIMIT)
+        RRETURN_ERROR(JSRegExpErrorMatchLimit);
+    if (rdepth >= MATCH_LIMIT_RECURSION)
+        RRETURN_ERROR(JSRegExpErrorRecursionLimit);
+    
+    /* At the start of a bracketed group, add the current subject pointer to the
+     stack of such pointers, to be re-instated at the end of the group when we hit
+     the closing ket. When match() is called in other circumstances, we don't add to
+     this stack. */
+    
+    if (is_group_start) {
+        frame->newptrb.epb_prev = frame->eptrb;
+        frame->newptrb.epb_saved_eptr = frame->eptr;
+        frame->eptrb = &frame->newptrb;
+    }
+    
+    /* Now start processing the operations. */
+    
 #ifndef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
-for (;;)
+    while (true)
 #endif
-  {
-
+    {
+        
 #ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
-  #define BEGIN_OPCODE(opcode) LABEL_OP_##opcode
-  #define NEXT_OPCODE goto *opcode_jump_table[*frame->ecode]
+#define BEGIN_OPCODE(opcode) LABEL_OP_##opcode
+#define NEXT_OPCODE goto *opcode_jump_table[*frame->ecode]
 #else
-  #define BEGIN_OPCODE(opcode) case OP_##opcode
-  #define NEXT_OPCODE continue
+#define BEGIN_OPCODE(opcode) case OP_##opcode
+#define NEXT_OPCODE continue
 #endif
-
+        
 #ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
-  NEXT_OPCODE;
-#else
-  switch (*frame->ecode)
-#endif
-    {
-    /* Non-capturing bracket: optimized */
-
-    BEGIN_OPCODE(BRA):
-    NON_CAPTURING_BRACKET:
-    DPRINTF(("start bracket 0\n"));
-    do
-      {
-      RMATCH(2, frame->ecode + 1 + LINK_SIZE, frame->eptrb, match_isgroup);
-      if (is_match) RRETURN;
-      frame->ecode += GET(frame->ecode, 1);
-      }
-    while (*frame->ecode == OP_ALT);
-    DPRINTF(("bracket 0 failed\n"));
-    RRETURN;
-
-    /* Skip over large extraction number data if encountered. */
-
-    BEGIN_OPCODE(BRANUMBER):
-    frame->ecode += 3;
-    NEXT_OPCODE;
-
-    /* End of the pattern. */
-
-    BEGIN_OPCODE(END):
-    md->end_match_ptr = frame->eptr;          /* Record where we ended */
-    md->end_offset_top = frame->offset_top;   /* and how many extracts were taken */
-    is_match = true;
-    RRETURN;
-
-    /* Assertion brackets. Check the alternative branches in turn - the
-    matching won't pass the KET for an assertion. If any one branch matches,
-    the assertion is true. Lookbehind assertions have an OP_REVERSE item at the
-    start of each branch to move the current point backwards, so the code at
-    this level is identical to the lookahead case. */
-
-    BEGIN_OPCODE(ASSERT):
-    do
-      {
-      RMATCH(6, frame->ecode + 1 + LINK_SIZE, NULL, match_isgroup);
-      if (is_match) break;
-      frame->ecode += GET(frame->ecode, 1);
-      }
-    while (*frame->ecode == OP_ALT);
-    if (*frame->ecode == OP_KET) RRETURN_NO_MATCH;
-
-    /* Continue from after the assertion, updating the offsets high water
-    mark, since extracts may have been taken during the assertion. */
-
-    do frame->ecode += GET(frame->ecode,1); while (*frame->ecode == OP_ALT);
-    frame->ecode += 1 + LINK_SIZE;
-    frame->offset_top = md->end_offset_top;
-    NEXT_OPCODE;
-
-    /* Negative assertion: all branches must fail to match */
-
-    BEGIN_OPCODE(ASSERT_NOT):
-    do
-      {
-      RMATCH(7, frame->ecode + 1 + LINK_SIZE, NULL, match_isgroup);
-      if (is_match) RRETURN_NO_MATCH;
-      frame->ecode += GET(frame->ecode,1);
-      }
-    while (*frame->ecode == OP_ALT);
-
-    frame->ecode += 1 + LINK_SIZE;
-    NEXT_OPCODE;
-
-    /* "Once" brackets are like assertion brackets except that after a match,
-    the point in the subject string is not moved back. Thus there can never be
-    a move back into the brackets. Friedl calls these "atomic" subpatterns.
-    Check the alternative branches in turn - the matching won't pass the KET
-    for this kind of subpattern. If any one branch matches, we carry on as at
-    the end of a normal bracket, leaving the subject pointer. */
-
-    BEGIN_OPCODE(ONCE):
-      frame->prev = frame->ecode;
-      frame->saved_eptr = frame->eptr;
-
-      do
-        {
-        RMATCH(9, frame->ecode + 1 + LINK_SIZE, frame->eptrb, match_isgroup);
-        if (is_match) break;
-        frame->ecode += GET(frame->ecode,1);
-        }
-      while (*frame->ecode == OP_ALT);
-
-      /* If hit the end of the group (which could be repeated), fail */
-
-      if (*frame->ecode != OP_ONCE && *frame->ecode != OP_ALT) RRETURN;
-
-      /* Continue as from after the assertion, updating the offsets high water
-      mark, since extracts may have been taken. */
-
-      do frame->ecode += GET(frame->ecode,1); while (*frame->ecode == OP_ALT);
-
-      frame->offset_top = md->end_offset_top;
-      frame->eptr = md->end_match_ptr;
-
-      /* For a non-repeating ket, just continue at this level. This also
-      happens for a repeating ket if no characters were matched in the group.
-      This is the forcible breaking of infinite loops as implemented in Perl
-      5.005. If there is an options reset, it will get obeyed in the normal
-      course of events. */
-
-      if (*frame->ecode == OP_KET || frame->eptr == frame->saved_eptr)
-        {
-        frame->ecode += 1+LINK_SIZE;
         NEXT_OPCODE;
-        }
-
-      /* The repeating kets try the rest of the pattern or restart from the
-      preceding bracket, in the appropriate order. We need to reset any options
-      that changed within the bracket before re-running it, so check the next
-      opcode. */
-
-      if (*frame->ecode == OP_KETRMIN)
-        {
-        RMATCH(10, frame->ecode + 1 + LINK_SIZE, frame->eptrb, 0);
-        if (is_match) RRETURN;
-        RMATCH(11, frame->prev, frame->eptrb, match_isgroup);
-        if (is_match) RRETURN;
-        }
-      else  /* OP_KETRMAX */
-        {
-        RMATCH(12, frame->prev, frame->eptrb, match_isgroup);
-        if (is_match) RRETURN;
-        RMATCH(13, frame->ecode + 1+LINK_SIZE, frame->eptrb, 0);
-        if (is_match) RRETURN;
-        }
-    RRETURN;
-
-    /* An alternation is the end of a branch; scan along to find the end of the
-    bracketed group and go to there. */
-
-    BEGIN_OPCODE(ALT):
-    do frame->ecode += GET(frame->ecode,1); while (*frame->ecode == OP_ALT);
-    NEXT_OPCODE;
-
-    /* BRAZERO and BRAMINZERO occur just before a bracket group, indicating
-    that it may occur zero times. It may repeat infinitely, or not at all -
-    i.e. it could be ()* or ()? in the pattern. Brackets with fixed upper
-    repeat limits are compiled as a number of copies, with the optional ones
-    preceded by BRAZERO or BRAMINZERO. */
-
-    BEGIN_OPCODE(BRAZERO):
-      {
-      frame->next = frame->ecode+1;
-      RMATCH(14, frame->next, frame->eptrb, match_isgroup);
-      if (is_match) RRETURN;
-      do frame->next += GET(frame->next,1); while (*frame->next == OP_ALT);
-      frame->ecode = frame->next + 1+LINK_SIZE;
-      }
-    NEXT_OPCODE;
-
-    BEGIN_OPCODE(BRAMINZERO):
-      {
-      frame->next = frame->ecode+1;
-      do frame->next += GET(frame->next,1); while (*frame->next == OP_ALT);
-      RMATCH(15, frame->next + 1+LINK_SIZE, frame->eptrb, match_isgroup);
-      if (is_match) RRETURN;
-      frame->ecode++;
-      }
-    NEXT_OPCODE;
-
-    /* End of a group, repeated or non-repeating. If we are at the end of
-    an assertion "group", stop matching and return MATCH_MATCH, but record the
-    current high water mark for use by positive assertions. Do this also
-    for the "once" (not-backup up) groups. */
-
-    BEGIN_OPCODE(KET):
-    BEGIN_OPCODE(KETRMIN):
-    BEGIN_OPCODE(KETRMAX):
-      frame->prev = frame->ecode - GET(frame->ecode, 1);
-      frame->saved_eptr = frame->eptrb->epb_saved_eptr;
-
-      /* Back up the stack of bracket start pointers. */
-
-      frame->eptrb = frame->eptrb->epb_prev;
-
-      if (*frame->prev == OP_ASSERT || *frame->prev == OP_ASSERT_NOT || *frame->prev == OP_ONCE)
-        {
-        md->end_match_ptr = frame->eptr;      /* For ONCE */
-        md->end_offset_top = frame->offset_top;
-        is_match = true;
-        RRETURN;
-        }
-
-      /* In all other cases except a conditional group we have to check the
-      group number back at the start and if necessary complete handling an
-      extraction by setting the offsets and bumping the high water mark. */
-
-        frame->number = *frame->prev - OP_BRA;
-
-        /* For extended extraction brackets (large number), we have to fish out
-        the number from a dummy opcode at the start. */
-
-        if (frame->number > EXTRACT_BASIC_MAX) frame->number = GET2(frame->prev, 2+LINK_SIZE);
-        frame->offset = frame->number << 1;
-
-#ifdef DEBUG
-        printf("end bracket %d", frame->number);
-        printf("\n");
+#else
+        switch (*frame->ecode)
 #endif
-
-        /* Test for a numbered group. This includes groups called as a result
-        of recursion. Note that whole-pattern recursion is coded as a recurse
-        into group 0, so it won't be picked up here. Instead, we catch it when
-        the OP_END is reached. */
-
-        if (frame->number > 0)
-          {
-          if (frame->offset >= md->offset_max) md->offset_overflow = true; else
-            {
-            md->offset_vector[frame->offset] =
-              md->offset_vector[md->offset_end - frame->number];
-            md->offset_vector[frame->offset+1] = frame->eptr - md->start_subject;
-            if (frame->offset_top <= frame->offset) frame->offset_top = frame->offset + 2;
-            }
-          }
-
-      /* For a non-repeating ket, just continue at this level. This also
-      happens for a repeating ket if no characters were matched in the group.
-      This is the forcible breaking of infinite loops as implemented in Perl
-      5.005. If there is an options reset, it will get obeyed in the normal
-      course of events. */
-
-      if (*frame->ecode == OP_KET || frame->eptr == frame->saved_eptr)
-        {
-        frame->ecode += 1 + LINK_SIZE;
-        NEXT_OPCODE;
-        }
-
-      /* The repeating kets try the rest of the pattern or restart from the
-      preceding bracket, in the appropriate order. */
-
-      if (*frame->ecode == OP_KETRMIN)
-        {
-        RMATCH(16, frame->ecode + 1+LINK_SIZE, frame->eptrb, 0);
-        if (is_match) RRETURN;
-        RMATCH(17, frame->prev, frame->eptrb, match_isgroup);
-        if (is_match) RRETURN;
-        }
-      else  /* OP_KETRMAX */
-        {
-        RMATCH(18, frame->prev, frame->eptrb, match_isgroup);
-        if (is_match) RRETURN;
-        RMATCH(19, frame->ecode + 1+LINK_SIZE, frame->eptrb, 0);
-        if (is_match) RRETURN;
-        }
-    RRETURN;
-
-    /* Start of subject, or after internal newline if multiline. */
-
-    BEGIN_OPCODE(CIRC):
-    if (frame->eptr != md->start_subject && (!md->multiline || !isNewline(frame->eptr[-1])))
-      RRETURN_NO_MATCH;
-    frame->ecode++;
-    NEXT_OPCODE;
-
-    /* End of subject, or before internal newline if multiline. */
-
-    BEGIN_OPCODE(DOLL):
-    if (frame->eptr < md->end_subject && (!md->multiline || !isNewline(*frame->eptr)))
-      RRETURN_NO_MATCH;
-    frame->ecode++;
-    NEXT_OPCODE;
-
-    /* Word boundary assertions */
-
-    BEGIN_OPCODE(NOT_WORD_BOUNDARY):
-    BEGIN_OPCODE(WORD_BOUNDARY):
-      /* Find out if the previous and current characters are "word" characters.
-      It takes a bit more work in UTF-8 mode. Characters > 128 are assumed to
-      be "non-word" characters. */
-
-        if (frame->eptr == md->start_subject) prev_is_word = false; else
-          {
-          const pcre_uchar *lastptr = frame->eptr - 1;
-          while(ISMIDCHAR(*lastptr)) lastptr--;
-          GETCHAR(c, lastptr);
-          prev_is_word = c < 128 && (md->ctypes[c] & ctype_word) != 0;
-          }
-        if (frame->eptr >= md->end_subject) cur_is_word = false; else
-          {
-          GETCHAR(c, frame->eptr);
-          cur_is_word = c < 128 && (md->ctypes[c] & ctype_word) != 0;
-          }
-
-      /* Now see if the situation is what we want */
-
-      if ((*frame->ecode++ == OP_WORD_BOUNDARY)?
-           cur_is_word == prev_is_word : cur_is_word != prev_is_word)
-        RRETURN_NO_MATCH;
-    NEXT_OPCODE;
-
-    /* Match a single character type; inline for speed */
-
-    BEGIN_OPCODE(ANY):
-    if (frame->eptr < md->end_subject && isNewline(*frame->eptr))
-      RRETURN_NO_MATCH;
-    if (frame->eptr++ >= md->end_subject) RRETURN_NO_MATCH;
-      while (frame->eptr < md->end_subject && ISMIDCHAR(*frame->eptr)) frame->eptr++;
-    frame->ecode++;
-    NEXT_OPCODE;
-
-    BEGIN_OPCODE(NOT_DIGIT):
-    if (frame->eptr >= md->end_subject) RRETURN_NO_MATCH;
-    GETCHARINCTEST(c, frame->eptr);
-    if (isASCIIDigit(c))
-      RRETURN_NO_MATCH;
-    frame->ecode++;
-    NEXT_OPCODE;
-
-    BEGIN_OPCODE(DIGIT):
-    if (frame->eptr >= md->end_subject) RRETURN_NO_MATCH;
-    GETCHARINCTEST(c, frame->eptr);
-    if (!isASCIIDigit(c))
-      RRETURN_NO_MATCH;
-    frame->ecode++;
-    NEXT_OPCODE;
-
-    BEGIN_OPCODE(NOT_WHITESPACE):
-    if (frame->eptr >= md->end_subject) RRETURN_NO_MATCH;
-    GETCHARINCTEST(c, frame->eptr);
-    if (c < 128 && (md->ctypes[c] & ctype_space) != 0)
-      RRETURN_NO_MATCH;
-    frame->ecode++;
-    NEXT_OPCODE;
-
-    BEGIN_OPCODE(WHITESPACE):
-    if (frame->eptr >= md->end_subject) RRETURN_NO_MATCH;
-    GETCHARINCTEST(c, frame->eptr);
-    if (c >= 128 || (md->ctypes[c] & ctype_space) == 0)
-      RRETURN_NO_MATCH;
-    frame->ecode++;
-    NEXT_OPCODE;
-
-    BEGIN_OPCODE(NOT_WORDCHAR):
-    if (frame->eptr >= md->end_subject) RRETURN_NO_MATCH;
-    GETCHARINCTEST(c, frame->eptr);
-    if (c < 128 && (md->ctypes[c] & ctype_word) != 0)
-      RRETURN_NO_MATCH;
-    frame->ecode++;
-    NEXT_OPCODE;
-
-    BEGIN_OPCODE(WORDCHAR):
-    if (frame->eptr >= md->end_subject) RRETURN_NO_MATCH;
-    GETCHARINCTEST(c, frame->eptr);
-    if (c >= 128 || (md->ctypes[c] & ctype_word) == 0)
-      RRETURN_NO_MATCH;
-    frame->ecode++;
-    NEXT_OPCODE;
-
-    /* Match a back reference, possibly repeatedly. Look past the end of the
-    item to see if there is repeat information following. The code is similar
-    to that for character classes, but repeated for efficiency. Then obey
-    similar code to character type repeats - written out again for speed.
-    However, if the referenced string is the empty string, always treat
-    it as matched, any number of times (otherwise there could be infinite
-    loops). */
-
-    BEGIN_OPCODE(REF):
-      frame->offset = GET2(frame->ecode, 1) << 1;               /* Doubled ref number */
-      frame->ecode += 3;                                 /* Advance past item */
-
-      /* If the reference is unset, set the length to be longer than the amount
-      of subject left; this ensures that every attempt at a match fails. We
-      can't just fail here, because of the possibility of quantifiers with zero
-      minima. */
-
-      frame->length = (frame->offset >= frame->offset_top || md->offset_vector[frame->offset] < 0)?
-        0 :
-        md->offset_vector[frame->offset+1] - md->offset_vector[frame->offset];
-
-      /* Set up for repetition, or handle the non-repeated case */
-
-      switch (*frame->ecode)
-        {
-        case OP_CRSTAR:
-        case OP_CRMINSTAR:
-        case OP_CRPLUS:
-        case OP_CRMINPLUS:
-        case OP_CRQUERY:
-        case OP_CRMINQUERY:
-        c = *frame->ecode++ - OP_CRSTAR;
-        minimize = (c & 1) != 0;
-        min = rep_min[c];                 /* Pick up values from tables; */
-        frame->max = rep_max[c];                 /* zero for max => infinity */
-        if (frame->max == 0) frame->max = INT_MAX;
-        break;
-
-        case OP_CRRANGE:
-        case OP_CRMINRANGE:
-        minimize = (*frame->ecode == OP_CRMINRANGE);
-        min = GET2(frame->ecode, 1);
-        frame->max = GET2(frame->ecode, 3);
-        if (frame->max == 0) frame->max = INT_MAX;
-        frame->ecode += 5;
-        break;
-
-        default:               /* No repeat follows */
-        if (!match_ref(frame->offset, frame->eptr, frame->length, md)) RRETURN_NO_MATCH;
-        frame->eptr += frame->length;
-        NEXT_OPCODE;
-        }
-
-      /* If the length of the reference is zero, just continue with the
-      main loop. */
-
-      if (frame->length == 0)
-        NEXT_OPCODE;
-
-      /* First, ensure the minimum number of matches are present. */
-
-      for (i = 1; i <= min; i++)
-        {
-        if (!match_ref(frame->offset, frame->eptr, frame->length, md)) RRETURN_NO_MATCH;
-        frame->eptr += frame->length;
-        }
-
-      /* If min = max, continue at the same level without recursion.
-      They are not both allowed to be zero. */
-
-      if (min == frame->max)
-        NEXT_OPCODE;
-
-      /* If minimizing, keep trying and advancing the pointer */
-
-      if (minimize)
-        {
-        for (frame->fi = min;; frame->fi++)
-          {
-          RMATCH(20, frame->ecode, frame->eptrb, 0);
-          if (is_match) RRETURN;
-          if (frame->fi >= frame->max || !match_ref(frame->offset, frame->eptr, frame->length, md))
-            RRETURN;
-          frame->eptr += frame->length;
-          }
-        /* Control never gets here */
-        }
-
-      /* If maximizing, find the longest string and work backwards */
-
-      else
-        {
-        frame->pp = frame->eptr;
-        for (i = min; i < frame->max; i++)
-          {
-          if (!match_ref(frame->offset, frame->eptr, frame->length, md)) break;
-          frame->eptr += frame->length;
-          }
-        while (frame->eptr >= frame->pp)
-          {
-          RMATCH(21, frame->ecode, frame->eptrb, 0);
-          if (is_match) RRETURN;
-          frame->eptr -= frame->length;
-          }
-        RRETURN_NO_MATCH;
-        }
-    /* Control never gets here */
-
-    /* Match a bit-mapped character class, possibly repeatedly. This op code is
-    used when all the characters in the class have values in the range 0-255,
-    and either the matching is caseful, or the characters are in the range
-    0-127 when UTF-8 processing is enabled. The only difference between
-    OP_CLASS and OP_NCLASS occurs when a data character outside the range is
-    encountered.
-
-    First, look past the end of the item to see if there is repeat information
-    following. Then obey similar code to character type repeats - written out
-    again for speed. */
-
-    BEGIN_OPCODE(NCLASS):
-    BEGIN_OPCODE(CLASS):
-      frame->data = frame->ecode + 1;                /* Save for matching */
-      frame->ecode += 33;                     /* Advance past the item */
-
-      switch (*frame->ecode)
-        {
-        case OP_CRSTAR:
-        case OP_CRMINSTAR:
-        case OP_CRPLUS:
-        case OP_CRMINPLUS:
-        case OP_CRQUERY:
-        case OP_CRMINQUERY:
-        c = *frame->ecode++ - OP_CRSTAR;
-        minimize = (c & 1) != 0;
-        min = rep_min[c];                 /* Pick up values from tables; */
-        frame->max = rep_max[c];                 /* zero for max => infinity */
-        if (frame->max == 0) frame->max = INT_MAX;
-        break;
-
-        case OP_CRRANGE:
-        case OP_CRMINRANGE:
-        minimize = (*frame->ecode == OP_CRMINRANGE);
-        min = GET2(frame->ecode, 1);
-        frame->max = GET2(frame->ecode, 3);
-        if (frame->max == 0) frame->max = INT_MAX;
-        frame->ecode += 5;
-        break;
-
-        default:               /* No repeat follows */
-        min = frame->max = 1;
-        break;
-        }
-
-      /* First, ensure the minimum number of matches are present. */
-
-        {
-        for (i = 1; i <= min; i++)
-          {
-          if (frame->eptr >= md->end_subject) RRETURN_NO_MATCH;
-          GETCHARINC(c, frame->eptr);
-          if (c > 255)
-            {
-            if (frame->data[-1] == OP_CLASS) RRETURN_NO_MATCH;
-            }
-          else
-            {
-            if ((frame->data[c/8] & (1 << (c&7))) == 0) RRETURN_NO_MATCH;
-            }
-          }
-        }
-
-      /* If max == min we can continue with the main loop without the
-      need to recurse. */
-
-      if (min == frame->max)
-        NEXT_OPCODE;      
-
-      /* If minimizing, keep testing the rest of the expression and advancing
-      the pointer while it matches the class. */
-      if (minimize)
-        {
-          {
-          for (frame->fi = min;; frame->fi++)
-            {
-            RMATCH(22, frame->ecode, frame->eptrb, 0);
-            if (is_match) RRETURN;
-            if (frame->fi >= frame->max || frame->eptr >= md->end_subject) RRETURN;
-            GETCHARINC(c, frame->eptr);
-            if (c > 255)
-              {
-              if (frame->data[-1] == OP_CLASS) RRETURN;
-              }
-            else
-              {
-              if ((frame->data[c/8] & (1 << (c&7))) == 0) RRETURN;
-              }
-            }
-          }
-        /* Control never gets here */
-        }
-      /* If maximizing, find the longest possible run, then work backwards. */
-      else
-        {
-        frame->pp = frame->eptr;
-
-          for (i = min; i < frame->max; i++)
-            {
-            int len = 1;
-            if (frame->eptr >= md->end_subject) break;
-            GETCHARLEN(c, frame->eptr, len);
-            if (c > 255)
-              {
-              if (frame->data[-1] == OP_CLASS) break;
-              }
-            else
-              {
-              if ((frame->data[c/8] & (1 << (c&7))) == 0) break;
-              }
-            frame->eptr += len;
-            }
-          for (;;)
-            {
-            RMATCH(24, frame->ecode, frame->eptrb, 0);
-            if (is_match) RRETURN;
-            if (frame->eptr-- == frame->pp) break;        /* Stop if tried at original pos */
-            BACKCHAR(frame->eptr);
-            }
-
-        RRETURN;
-        }
-    /* Control never gets here */
-
-    /* Match an extended character class. This opcode is encountered only
-    in UTF-8 mode, because that's the only time it is compiled. */
-
-    BEGIN_OPCODE(XCLASS):
-      frame->data = frame->ecode + 1 + LINK_SIZE;                /* Save for matching */
-      frame->ecode += GET(frame->ecode, 1);                      /* Advance past the item */
-
-      switch (*frame->ecode)
-        {
-        case OP_CRSTAR:
-        case OP_CRMINSTAR:
-        case OP_CRPLUS:
-        case OP_CRMINPLUS:
-        case OP_CRQUERY:
-        case OP_CRMINQUERY:
-        c = *frame->ecode++ - OP_CRSTAR;
-        minimize = (c & 1) != 0;
-        min = rep_min[c];                 /* Pick up values from tables; */
-        frame->max = rep_max[c];                 /* zero for max => infinity */
-        if (frame->max == 0) frame->max = INT_MAX;
-        break;
-
-        case OP_CRRANGE:
-        case OP_CRMINRANGE:
-        minimize = (*frame->ecode == OP_CRMINRANGE);
-        min = GET2(frame->ecode, 1);
-        frame->max = GET2(frame->ecode, 3);
-        if (frame->max == 0) frame->max = INT_MAX;
-        frame->ecode += 5;
-        break;
-
-        default:               /* No repeat follows */
-        min = frame->max = 1;
-        }
-
-      /* First, ensure the minimum number of matches are present. */
-
-      for (i = 1; i <= min; i++)
-        {
-        if (frame->eptr >= md->end_subject) RRETURN_NO_MATCH;
-        GETCHARINC(c, frame->eptr);
-        if (!_pcre_xclass(c, frame->data)) RRETURN_NO_MATCH;
-        }
-
-      /* If max == min we can continue with the main loop without the
-      need to recurse. */
-
-      if (min == frame->max)
-        NEXT_OPCODE;
-
-      /* If minimizing, keep testing the rest of the expression and advancing
-      the pointer while it matches the class. */
-
-      if (minimize)
-        {
-        for (frame->fi = min;; frame->fi++)
-          {
-          RMATCH(26, frame->ecode, frame->eptrb, 0);
-          if (is_match) RRETURN;
-          if (frame->fi >= frame->max || frame->eptr >= md->end_subject) RRETURN;
-          GETCHARINC(c, frame->eptr);
-          if (!_pcre_xclass(c, frame->data)) RRETURN;
-          }
-        /* Control never gets here */
-        }
-
-      /* If maximizing, find the longest possible run, then work backwards. */
-
-      else
-        {
-        frame->pp = frame->eptr;
-        for (i = min; i < frame->max; i++)
-          {
-          int len = 1;
-          if (frame->eptr >= md->end_subject) break;
-          GETCHARLEN(c, frame->eptr, len);
-          if (!_pcre_xclass(c, frame->data)) break;
-          frame->eptr += len;
-          }
-        for(;;)
-          {
-          RMATCH(27, frame->ecode, frame->eptrb, 0);
-          if (is_match) RRETURN;
-          if (frame->eptr-- == frame->pp) break;        /* Stop if tried at original pos */
-          BACKCHAR(frame->eptr)
-          }
-        RRETURN;
-        }
-
-    /* Control never gets here */
-
-    /* Match a single character, casefully */
-
-    BEGIN_OPCODE(CHAR):
-      frame->length = 1;
-      frame->ecode++;
-      GETUTF8CHARLEN(frame->fc, frame->ecode, frame->length);
-      {
-        int dc;
-        frame->ecode += frame->length;
-        switch (md->end_subject - frame->eptr)
         {
-          case 0:
-            RRETURN_NO_MATCH;
-          case 1:
-            dc = *frame->eptr++;
-            if (IS_LEADING_SURROGATE(dc))
-              RRETURN_NO_MATCH;
-            break;
-          default:
-            GETCHARINC(dc, frame->eptr);
-        }
-        if (frame->fc != dc) RRETURN_NO_MATCH;
-      }
-    NEXT_OPCODE;
-
-    /* Match a single character, caselessly */
-
-    BEGIN_OPCODE(CHARNC):
-      frame->length = 1;
-      frame->ecode++;
-      GETUTF8CHARLEN(frame->fc, frame->ecode, frame->length);
-
-      if (md->end_subject - frame->eptr == 0) RRETURN_NO_MATCH;
-
-        {
-        int dc;
-        if (md->end_subject - frame->eptr == 1) {
-          dc = *frame->eptr++;
-          if (IS_LEADING_SURROGATE(dc))
-            RRETURN_NO_MATCH;
-        } else
-        GETCHARINC(dc, frame->eptr);
-        frame->ecode += frame->length;
-
-        /* If we have Unicode property support, we can use it to test the other
-        case of the character, if there is one. */
-
-        if (frame->fc != dc)
-          {
-          if (dc != _pcre_ucp_othercase(frame->fc))
-            RRETURN_NO_MATCH;
-          }
-        }
-    NEXT_OPCODE;
-
-    /* Match a single ASCII character. */
-
-    BEGIN_OPCODE(ASCII_CHAR):
-    if (md->end_subject == frame->eptr)
-      RRETURN_NO_MATCH;
-    if (*frame->eptr != frame->ecode[1])
-      RRETURN_NO_MATCH;
-    ++frame->eptr;
-    frame->ecode += 2;
-    NEXT_OPCODE;
-
-    /* Match one of two cases of an ASCII character. */
-
-    BEGIN_OPCODE(ASCII_LETTER_NC):
-    if (md->end_subject == frame->eptr)
-      RRETURN_NO_MATCH;
-    if ((*frame->eptr | 0x20) != frame->ecode[1])
-      RRETURN_NO_MATCH;
-    ++frame->eptr;
-    frame->ecode += 2;
-    NEXT_OPCODE;
-
-    /* Match a single character repeatedly; different opcodes share code. */
-
-    BEGIN_OPCODE(EXACT):
-    min = frame->max = GET2(frame->ecode, 1);
-    minimize = false;
-    frame->ecode += 3;
-    goto REPEATCHAR;
-
-    BEGIN_OPCODE(UPTO):
-    BEGIN_OPCODE(MINUPTO):
-    min = 0;
-    frame->max = GET2(frame->ecode, 1);
-    minimize = *frame->ecode == OP_MINUPTO;
-    frame->ecode += 3;
-    goto REPEATCHAR;
-
-    BEGIN_OPCODE(STAR):
-    BEGIN_OPCODE(MINSTAR):
-    BEGIN_OPCODE(PLUS):
-    BEGIN_OPCODE(MINPLUS):
-    BEGIN_OPCODE(QUERY):
-    BEGIN_OPCODE(MINQUERY):
-    c = *frame->ecode++ - OP_STAR;
-    minimize = (c & 1) != 0;
-    min = rep_min[c];                 /* Pick up values from tables; */
-    frame->max = rep_max[c];                 /* zero for max => infinity */
-    if (frame->max == 0) frame->max = INT_MAX;
-
-    /* Common code for all repeated single-character matches. We can give
-    up quickly if there are fewer than the minimum number of characters left in
-    the subject. */
-
-    REPEATCHAR:
-
-      frame->length = 1;
-      GETUTF8CHARLEN(frame->fc, frame->ecode, frame->length);
-      if (min * (frame->fc > 0xFFFF ? 2 : 1) > md->end_subject - frame->eptr) RRETURN_NO_MATCH;
-      frame->ecode += frame->length;
-
-      if (frame->fc <= 0xFFFF)
-        {
-        int othercase = md->caseless ? _pcre_ucp_othercase(frame->fc) : -1;
-
-        for (i = 1; i <= min; i++)
-          {
-          if (*frame->eptr != frame->fc && *frame->eptr != othercase) RRETURN_NO_MATCH;
-          ++frame->eptr;
-          }
-
-        if (min == frame->max)
-          NEXT_OPCODE;
-
-        if (minimize)
-          {
-          frame->repeat_othercase = othercase;
-          for (frame->fi = min;; frame->fi++)
-            {
-            RMATCH(28, frame->ecode, frame->eptrb, 0);
-            if (is_match) RRETURN;
-            if (frame->fi >= frame->max || frame->eptr >= md->end_subject) RRETURN;
-            if (*frame->eptr != frame->fc && *frame->eptr != frame->repeat_othercase) RRETURN;
-            ++frame->eptr;
-            }
-          /* Control never gets here */
-          }
-        else
-          {
-          frame->pp = frame->eptr;
-          for (i = min; i < frame->max; i++)
-            {
-            if (frame->eptr >= md->end_subject) break;
-            if (*frame->eptr != frame->fc && *frame->eptr != othercase) break;
-            ++frame->eptr;
-            }
-          while (frame->eptr >= frame->pp)
-           {
-           RMATCH(29, frame->ecode, frame->eptrb, 0);
-           if (is_match) RRETURN;
-           --frame->eptr;
-           }
-          RRETURN_NO_MATCH;
-          }
-        /* Control never gets here */
-        }
-      else
-        {
-        /* No case on surrogate pairs, so no need to bother with "othercase". */
-
-        for (i = 1; i <= min; i++)
-          {
-          int nc;
-          GETCHAR(nc, frame->eptr);
-          if (nc != frame->fc) RRETURN_NO_MATCH;
-          frame->eptr += 2;
-          }
-
-        if (min == frame->max)
-          NEXT_OPCODE;
-
-        if (minimize)
-          {
-          for (frame->fi = min;; frame->fi++)
-            {
-            int nc;
-            RMATCH(30, frame->ecode, frame->eptrb, 0);
-            if (is_match) RRETURN;
-            if (frame->fi >= frame->max || frame->eptr >= md->end_subject) RRETURN;
-            GETCHAR(nc, frame->eptr);
-            if (*frame->eptr != frame->fc) RRETURN;
-            frame->eptr += 2;
-            }
-          /* Control never gets here */
-          }
-        else
-          {
-          frame->pp = frame->eptr;
-          for (i = min; i < frame->max; i++)
-            {
-            int nc;
-            if (frame->eptr > md->end_subject - 2) break;
-            GETCHAR(nc, frame->eptr);
-            if (*frame->eptr != frame->fc) break;
-            frame->eptr += 2;
-            }
-          while (frame->eptr >= frame->pp)
-           {
-           RMATCH(31, frame->ecode, frame->eptrb, 0);
-           if (is_match) RRETURN;
-           frame->eptr -= 2;
-           }
-          RRETURN_NO_MATCH;
-          }
-          /* Control never gets here */
-        }
-    /* Control never gets here */
-
-    /* Match a negated single one-byte character. The character we are
-    checking can be multibyte. */
-
-    BEGIN_OPCODE(NOT):
-    if (frame->eptr >= md->end_subject) RRETURN_NO_MATCH;
-    frame->ecode++;
-    GETCHARINCTEST(c, frame->eptr);
-    if (md->caseless)
-      {
-      if (c < 128)
-        c = md->lcc[c];
-      if (md->lcc[*frame->ecode++] == c) RRETURN_NO_MATCH;
-      }
-    else
-      {
-      if (*frame->ecode++ == c) RRETURN_NO_MATCH;
-      }
-    NEXT_OPCODE;
-
-    /* Match a negated single one-byte character repeatedly. This is almost a
-    repeat of the code for a repeated single character, but I haven't found a
-    nice way of commoning these up that doesn't require a test of the
-    positive/negative option for each character match. Maybe that wouldn't add
-    very much to the time taken, but character matching *is* what this is all
-    about... */
-
-    BEGIN_OPCODE(NOTEXACT):
-    min = frame->max = GET2(frame->ecode, 1);
-    minimize = false;
-    frame->ecode += 3;
-    goto REPEATNOTCHAR;
-
-    BEGIN_OPCODE(NOTUPTO):
-    BEGIN_OPCODE(NOTMINUPTO):
-    min = 0;
-    frame->max = GET2(frame->ecode, 1);
-    minimize = *frame->ecode == OP_NOTMINUPTO;
-    frame->ecode += 3;
-    goto REPEATNOTCHAR;
-
-    BEGIN_OPCODE(NOTSTAR):
-    BEGIN_OPCODE(NOTMINSTAR):
-    BEGIN_OPCODE(NOTPLUS):
-    BEGIN_OPCODE(NOTMINPLUS):
-    BEGIN_OPCODE(NOTQUERY):
-    BEGIN_OPCODE(NOTMINQUERY):
-    c = *frame->ecode++ - OP_NOTSTAR;
-    minimize = (c & 1) != 0;
-    min = rep_min[c];                 /* Pick up values from tables; */
-    frame->max = rep_max[c];                 /* zero for max => infinity */
-    if (frame->max == 0) frame->max = INT_MAX;
-
-    /* Common code for all repeated single-byte matches. We can give up quickly
-    if there are fewer than the minimum number of bytes left in the
-    subject. */
-
-    REPEATNOTCHAR:
-    if (min > md->end_subject - frame->eptr) RRETURN_NO_MATCH;
-    frame->fc = *frame->ecode++;
-
-    /* The code is duplicated for the caseless and caseful cases, for speed,
-    since matching characters is likely to be quite common. First, ensure the
-    minimum number of matches are present. If min = max, continue at the same
-    level without recursing. Otherwise, if minimizing, keep trying the rest of
-    the expression and advancing one matching character if failing, up to the
-    maximum. Alternatively, if maximizing, find the maximum number of
-    characters and work backwards. */
-
-    DPRINTF(("negative matching %c{%d,%d}\n", frame->fc, min, frame->max));
-
-    if (md->caseless)
-      {
-      if (frame->fc < 128)
-        frame->fc = md->lcc[frame->fc];
-
-        {
-        register int d;
-        for (i = 1; i <= min; i++)
-          {
-          GETCHARINC(d, frame->eptr);
-          if (d < 128) d = md->lcc[d];
-          if (frame->fc == d) RRETURN_NO_MATCH;
-          }
-        }
-
-      if (min == frame->max)
-        NEXT_OPCODE;      
-
-      if (minimize)
-        {
-          {
-          register int d;
-          for (frame->fi = min;; frame->fi++)
-            {
-            RMATCH(38, frame->ecode, frame->eptrb, 0);
-            if (is_match) RRETURN;
-            GETCHARINC(d, frame->eptr);
-            if (d < 128) d = md->lcc[d];
-            if (frame->fi >= frame->max || frame->eptr >= md->end_subject || frame->fc == d)
-              RRETURN;
-            }
-          }
-        /* Control never gets here */
-        }
-
-      /* Maximize case */
-
-      else
-        {
-        frame->pp = frame->eptr;
-
-          {
-          register int d;
-          for (i = min; i < frame->max; i++)
-            {
-            int len = 1;
-            if (frame->eptr >= md->end_subject) break;
-            GETCHARLEN(d, frame->eptr, len);
-            if (d < 128) d = md->lcc[d];
-            if (frame->fc == d) break;
-            frame->eptr += len;
-            }
-          for(;;)
-            {
-            RMATCH(40, frame->ecode, frame->eptrb, 0);
-            if (is_match) RRETURN;
-            if (frame->eptr-- == frame->pp) break;        /* Stop if tried at original pos */
-            BACKCHAR(frame->eptr);
-            }
-          }
-
-        RRETURN;
-        }
-      /* Control never gets here */
-      }
-
-    /* Caseful comparisons */
-
-    else
-      {
-        {
-        register int d;
-        for (i = 1; i <= min; i++)
-          {
-          GETCHARINC(d, frame->eptr);
-          if (frame->fc == d) RRETURN_NO_MATCH;
-          }
-        }
-
-      if (min == frame->max)
-        NEXT_OPCODE;
-
-      if (minimize)
-        {
-          {
-          register int d;
-          for (frame->fi = min;; frame->fi++)
-            {
-            RMATCH(42, frame->ecode, frame->eptrb, 0);
-            if (is_match) RRETURN;
-            GETCHARINC(d, frame->eptr);
-            if (frame->fi >= frame->max || frame->eptr >= md->end_subject || frame->fc == d)
-              RRETURN;
-            }
-          }
-        /* Control never gets here */
-        }
-
-      /* Maximize case */
-
-      else
-        {
-        frame->pp = frame->eptr;
-
-          {
-          register int d;
-          for (i = min; i < frame->max; i++)
-            {
-            int len = 1;
-            if (frame->eptr >= md->end_subject) break;
-            GETCHARLEN(d, frame->eptr, len);
-            if (frame->fc == d) break;
-            frame->eptr += len;
-            }
-          for(;;)
-            {
-            RMATCH(44, frame->ecode, frame->eptrb, 0);
-            if (is_match) RRETURN;
-            if (frame->eptr-- == frame->pp) break;        /* Stop if tried at original pos */
-            BACKCHAR(frame->eptr);
-            }
-          }
-
-        RRETURN;
-        }
-      }
-    /* Control never gets here */
-
-    /* Match a single character type repeatedly; several different opcodes
-    share code. This is very similar to the code for single characters, but we
-    repeat it in the interests of efficiency. */
-
-    BEGIN_OPCODE(TYPEEXACT):
-    min = frame->max = GET2(frame->ecode, 1);
-    minimize = true;
-    frame->ecode += 3;
-    goto REPEATTYPE;
-
-    BEGIN_OPCODE(TYPEUPTO):
-    BEGIN_OPCODE(TYPEMINUPTO):
-    min = 0;
-    frame->max = GET2(frame->ecode, 1);
-    minimize = *frame->ecode == OP_TYPEMINUPTO;
-    frame->ecode += 3;
-    goto REPEATTYPE;
-
-    BEGIN_OPCODE(TYPESTAR):
-    BEGIN_OPCODE(TYPEMINSTAR):
-    BEGIN_OPCODE(TYPEPLUS):
-    BEGIN_OPCODE(TYPEMINPLUS):
-    BEGIN_OPCODE(TYPEQUERY):
-    BEGIN_OPCODE(TYPEMINQUERY):
-    c = *frame->ecode++ - OP_TYPESTAR;
-    minimize = (c & 1) != 0;
-    min = rep_min[c];                 /* Pick up values from tables; */
-    frame->max = rep_max[c];                 /* zero for max => infinity */
-    if (frame->max == 0) frame->max = INT_MAX;
-
-    /* Common code for all repeated single character type matches. Note that
-    in UTF-8 mode, '.' matches a character of any length, but for the other
-    character types, the valid characters are all one-byte long. */
-
-    REPEATTYPE:
-    frame->ctype = *frame->ecode++;      /* Code for the character type */
-
-    /* First, ensure the minimum number of matches are present. Use inline
-    code for maximizing the speed, and do the type test once at the start
-    (i.e. keep it out of the loop). Also we can test that there are at least
-    the minimum number of bytes before we start. This isn't as effective in
-    UTF-8 mode, but it does no harm. Separate the UTF-8 code completely as that
-    is tidier. Also separate the UCP code, which can be the same for both UTF-8
-    and single-bytes. */
-
-    if (min > md->end_subject - frame->eptr) RRETURN_NO_MATCH;
-    if (min > 0)
-      {
-      switch(frame->ctype)
-        {
-        case OP_ANY:
-        for (i = 1; i <= min; i++)
-          {
-          if (frame->eptr >= md->end_subject || isNewline(*frame->eptr))
-            RRETURN_NO_MATCH;
-          ++frame->eptr;
-          while (frame->eptr < md->end_subject && ISMIDCHAR(*frame->eptr)) frame->eptr++;
-          }
-        break;
-
-        case OP_NOT_DIGIT:
-        for (i = 1; i <= min; i++)
-          {
-          if (frame->eptr >= md->end_subject) RRETURN_NO_MATCH;
-          GETCHARINC(c, frame->eptr);
-          if (isASCIIDigit(c))
-            RRETURN_NO_MATCH;
-          }
-        break;
-
-        case OP_DIGIT:
-        for (i = 1; i <= min; i++)
-          {
-          if (frame->eptr >= md->end_subject || !isASCIIDigit(*frame->eptr++))
-            RRETURN_NO_MATCH;
-          /* No need to skip more bytes - we know it's a 1-byte character */
-          }
-        break;
-
-        case OP_NOT_WHITESPACE:
-        for (i = 1; i <= min; i++)
-          {
-          if (frame->eptr >= md->end_subject ||
-             (*frame->eptr < 128 && (md->ctypes[*frame->eptr] & ctype_space) != 0))
-            RRETURN_NO_MATCH;
-          while (++frame->eptr < md->end_subject && ISMIDCHAR(*frame->eptr));
-          }
-        break;
-
-        case OP_WHITESPACE:
-        for (i = 1; i <= min; i++)
-          {
-          if (frame->eptr >= md->end_subject ||
-             *frame->eptr >= 128 || (md->ctypes[*frame->eptr++] & ctype_space) == 0)
-            RRETURN_NO_MATCH;
-          /* No need to skip more bytes - we know it's a 1-byte character */
-          }
-        break;
-
-        case OP_NOT_WORDCHAR:
-        for (i = 1; i <= min; i++)
-          {
-          if (frame->eptr >= md->end_subject ||
-             (*frame->eptr < 128 && (md->ctypes[*frame->eptr] & ctype_word) != 0))
-            RRETURN_NO_MATCH;
-          while (++frame->eptr < md->end_subject && ISMIDCHAR(*frame->eptr));
-          }
-        break;
-
-        case OP_WORDCHAR:
-        for (i = 1; i <= min; i++)
-          {
-          if (frame->eptr >= md->end_subject ||
-             *frame->eptr >= 128 || (md->ctypes[*frame->eptr++] & ctype_word) == 0)
-            RRETURN_NO_MATCH;
-          /* No need to skip more bytes - we know it's a 1-byte character */
-          }
-        break;
-
-        default:
-        ASSERT_NOT_REACHED();
-        RRETURN_ERROR(JSRegExpErrorInternal);
-        }  /* End switch(frame->ctype) */
-      }
-
-    /* If min = max, continue at the same level without recursing */
-
-    if (min == frame->max)
-      NEXT_OPCODE;    
-
-    /* If minimizing, we have to test the rest of the pattern before each
-    subsequent match. */
-
-    if (minimize)
-      {
-        {
-        for (frame->fi = min;; frame->fi++)
-          {
-          RMATCH(48, frame->ecode, frame->eptrb, 0);
-          if (is_match) RRETURN;
-          if (frame->fi >= frame->max || frame->eptr >= md->end_subject) RRETURN;
-
-          GETCHARINC(c, frame->eptr);
-          switch(frame->ctype)
-            {
-            case OP_ANY:
-            if (isNewline(c)) RRETURN;
-            break;
-
-            case OP_NOT_DIGIT:
-            if (isASCIIDigit(c))
-              RRETURN;
-            break;
-
-            case OP_DIGIT:
-            if (!isASCIIDigit(c))
-              RRETURN;
-            break;
-
-            case OP_NOT_WHITESPACE:
-            if (c < 128 && (md->ctypes[c] & ctype_space) != 0)
-              RRETURN;
-            break;
-
-            case OP_WHITESPACE:
-            if  (c >= 128 || (md->ctypes[c] & ctype_space) == 0)
-              RRETURN;
-            break;
-
-            case OP_NOT_WORDCHAR:
-            if (c < 128 && (md->ctypes[c] & ctype_word) != 0)
-              RRETURN;
-            break;
-
-            case OP_WORDCHAR:
-            if (c >= 128 || (md->ctypes[c] & ctype_word) == 0)
-              RRETURN;
-            break;
-
-            default:
-            ASSERT_NOT_REACHED();
-            RRETURN_ERROR(JSRegExpErrorInternal);
-            }
-          }
-        }
-      /* Control never gets here */
-      }
-
-    /* If maximizing it is worth using inline code for speed, doing the type
-    test once at the start (i.e. keep it out of the loop). */
-
-    else
-      {
-      frame->pp = frame->eptr;  /* Remember where we started */
-
-        switch(frame->ctype)
-          {
-          case OP_ANY:
-
-          /* Special code is required for UTF8, but when the maximum is unlimited
-          we don't need it, so we repeat the non-UTF8 code. This is probably
-          worth it, because .* is quite a common idiom. */
-
-          if (frame->max < INT_MAX)
-            {
-              {
-              for (i = min; i < frame->max; i++)
+                /* Non-capturing bracket: optimized */
+                
+                BEGIN_OPCODE(BRA):
+            NON_CAPTURING_BRACKET:
+                DPRINTF(("start bracket 0\n"));
+                do {
+                    RMATCH(2, frame->ecode + 1 + LINK_SIZE, frame->eptrb, match_isgroup);
+                    if (is_match)
+                        RRETURN;
+                    frame->ecode += GET(frame->ecode, 1);
+                } while (*frame->ecode == OP_ALT);
+                DPRINTF(("bracket 0 failed\n"));
+                RRETURN;
+                
+                /* Skip over large extraction number data if encountered. */
+                
+                BEGIN_OPCODE(BRANUMBER):
+                frame->ecode += 3;
+                NEXT_OPCODE;
+                
+                /* End of the pattern. */
+                
+                BEGIN_OPCODE(END):
+                md->end_match_ptr = frame->eptr;          /* Record where we ended */
+                md->end_offset_top = frame->offset_top;   /* and how many extracts were taken */
+                is_match = true;
+                RRETURN;
+                
+                /* Assertion brackets. Check the alternative branches in turn - the
+                 matching won't pass the KET for an assertion. If any one branch matches,
+                 the assertion is true. Lookbehind assertions have an OP_REVERSE item at the
+                 start of each branch to move the current point backwards, so the code at
+                 this level is identical to the lookahead case. */
+                
+                BEGIN_OPCODE(ASSERT):
+                do {
+                    RMATCH(6, frame->ecode + 1 + LINK_SIZE, NULL, match_isgroup);
+                    if (is_match) break;
+                    frame->ecode += GET(frame->ecode, 1);
+                } while (*frame->ecode == OP_ALT);
+                if (*frame->ecode == OP_KET)
+                    RRETURN_NO_MATCH;
+                
+                /* Continue from after the assertion, updating the offsets high water
+                 mark, since extracts may have been taken during the assertion. */
+                
+                do frame->ecode += GET(frame->ecode,1); while (*frame->ecode == OP_ALT);
+                frame->ecode += 1 + LINK_SIZE;
+                frame->offset_top = md->end_offset_top;
+                NEXT_OPCODE;
+                
+                /* Negative assertion: all branches must fail to match */
+                
+                BEGIN_OPCODE(ASSERT_NOT):
+                do {
+                    RMATCH(7, frame->ecode + 1 + LINK_SIZE, NULL, match_isgroup);
+                    if (is_match)
+                        RRETURN_NO_MATCH;
+                    frame->ecode += GET(frame->ecode,1);
+                } while (*frame->ecode == OP_ALT);
+                
+                frame->ecode += 1 + LINK_SIZE;
+                NEXT_OPCODE;
+                
+                /* "Once" brackets are like assertion brackets except that after a match,
+                 the point in the subject string is not moved back. Thus there can never be
+                 a move back into the brackets. Friedl calls these "atomic" subpatterns.
+                 Check the alternative branches in turn - the matching won't pass the KET
+                 for this kind of subpattern. If any one branch matches, we carry on as at
+                 the end of a normal bracket, leaving the subject pointer. */
+                
+                BEGIN_OPCODE(ONCE):
+                frame->prev = frame->ecode;
+                frame->saved_eptr = frame->eptr;
+                
+                do {
+                    RMATCH(9, frame->ecode + 1 + LINK_SIZE, frame->eptrb, match_isgroup);
+                    if (is_match)
+                        break;
+                    frame->ecode += GET(frame->ecode,1);
+                } while (*frame->ecode == OP_ALT);
+                
+                /* If hit the end of the group (which could be repeated), fail */
+                
+                if (*frame->ecode != OP_ONCE && *frame->ecode != OP_ALT)
+                    RRETURN;
+                
+                /* Continue as from after the assertion, updating the offsets high water
+                 mark, since extracts may have been taken. */
+                
+                do frame->ecode += GET(frame->ecode,1); while (*frame->ecode == OP_ALT);
+                
+                frame->offset_top = md->end_offset_top;
+                frame->eptr = md->end_match_ptr;
+                
+                /* For a non-repeating ket, just continue at this level. This also
+                 happens for a repeating ket if no characters were matched in the group.
+                 This is the forcible breaking of infinite loops as implemented in Perl
+                 5.005. If there is an options reset, it will get obeyed in the normal
+                 course of events. */
+                
+                if (*frame->ecode == OP_KET || frame->eptr == frame->saved_eptr) {
+                    frame->ecode += 1+LINK_SIZE;
+                    NEXT_OPCODE;
+                }
+                
+                /* The repeating kets try the rest of the pattern or restart from the
+                 preceding bracket, in the appropriate order. We need to reset any options
+                 that changed within the bracket before re-running it, so check the next
+                 opcode. */
+                
+                if (*frame->ecode == OP_KETRMIN) {
+                    RMATCH(10, frame->ecode + 1 + LINK_SIZE, frame->eptrb, 0);
+                    if (is_match)
+                        RRETURN;
+                    RMATCH(11, frame->prev, frame->eptrb, match_isgroup);
+                    if (is_match)
+                        RRETURN;
+                } else { /* OP_KETRMAX */
+                    RMATCH(12, frame->prev, frame->eptrb, match_isgroup);
+                    if (is_match)
+                        RRETURN;
+                    RMATCH(13, frame->ecode + 1+LINK_SIZE, frame->eptrb, 0);
+                    if (is_match)
+                        RRETURN;
+                }
+                RRETURN;
+                
+                /* An alternation is the end of a branch; scan along to find the end of the
+                 bracketed group and go to there. */
+                
+                BEGIN_OPCODE(ALT):
+                do frame->ecode += GET(frame->ecode,1); while (*frame->ecode == OP_ALT);
+                NEXT_OPCODE;
+                
+                /* BRAZERO and BRAMINZERO occur just before a bracket group, indicating
+                 that it may occur zero times. It may repeat infinitely, or not at all -
+                 i.e. it could be ()* or ()? in the pattern. Brackets with fixed upper
+                 repeat limits are compiled as a number of copies, with the optional ones
+                 preceded by BRAZERO or BRAMINZERO. */
+                
+                BEGIN_OPCODE(BRAZERO):
                 {
-                if (frame->eptr >= md->end_subject || isNewline(*frame->eptr)) break;
-                frame->eptr++;
-                while (frame->eptr < md->end_subject && (*frame->eptr & 0xc0) == 0x80) frame->eptr++;
+                    frame->next = frame->ecode+1;
+                    RMATCH(14, frame->next, frame->eptrb, match_isgroup);
+                    if (is_match)
+                        RRETURN;
+                    do frame->next += GET(frame->next,1); while (*frame->next == OP_ALT);
+                    frame->ecode = frame->next + 1+LINK_SIZE;
                 }
-              }
-            }
-
-          /* Handle unlimited UTF-8 repeat */
-
-          else
-            {
-              {
-              for (i = min; i < frame->max; i++)
+                NEXT_OPCODE;
+                
+                BEGIN_OPCODE(BRAMINZERO):
                 {
-                if (frame->eptr >= md->end_subject || isNewline(*frame->eptr)) break;
-                frame->eptr++;
+                    frame->next = frame->ecode+1;
+                    do frame->next += GET(frame->next,1); while (*frame->next == OP_ALT);
+                    RMATCH(15, frame->next + 1+LINK_SIZE, frame->eptrb, match_isgroup);
+                    if (is_match)
+                        RRETURN;
+                    frame->ecode++;
                 }
-              break;
-              }
-            }
-          break;
-
-          case OP_NOT_DIGIT:
-          for (i = min; i < frame->max; i++)
-            {
-            int len = 1;
-            if (frame->eptr >= md->end_subject) break;
-            GETCHARLEN(c, frame->eptr, len);
-            if (isASCIIDigit(c)) break;
-            frame->eptr+= len;
-            }
-          break;
-
-          case OP_DIGIT:
-          for (i = min; i < frame->max; i++)
-            {
-            int len = 1;
-            if (frame->eptr >= md->end_subject) break;
-            GETCHARLEN(c, frame->eptr, len);
-            if (!isASCIIDigit(c)) break;
-            frame->eptr+= len;
-            }
-          break;
-
-          case OP_NOT_WHITESPACE:
-          for (i = min; i < frame->max; i++)
-            {
-            int len = 1;
-            if (frame->eptr >= md->end_subject) break;
-            GETCHARLEN(c, frame->eptr, len);
-            if (c < 128 && (md->ctypes[c] & ctype_space) != 0) break;
-            frame->eptr+= len;
-            }
-          break;
-
-          case OP_WHITESPACE:
-          for (i = min; i < frame->max; i++)
-            {
-            int len = 1;
-            if (frame->eptr >= md->end_subject) break;
-            GETCHARLEN(c, frame->eptr, len);
-            if (c >= 128 ||(md->ctypes[c] & ctype_space) == 0) break;
-            frame->eptr+= len;
+                NEXT_OPCODE;
+                
+                /* End of a group, repeated or non-repeating. If we are at the end of
+                 an assertion "group", stop matching and return MATCH_MATCH, but record the
+                 current high water mark for use by positive assertions. Do this also
+                 for the "once" (not-backup up) groups. */
+                
+                BEGIN_OPCODE(KET):
+                BEGIN_OPCODE(KETRMIN):
+                BEGIN_OPCODE(KETRMAX):
+                frame->prev = frame->ecode - GET(frame->ecode, 1);
+                frame->saved_eptr = frame->eptrb->epb_saved_eptr;
+                
+                /* Back up the stack of bracket start pointers. */
+                
+                frame->eptrb = frame->eptrb->epb_prev;
+                
+                if (*frame->prev == OP_ASSERT || *frame->prev == OP_ASSERT_NOT || *frame->prev == OP_ONCE) {
+                    md->end_match_ptr = frame->eptr;      /* For ONCE */
+                    md->end_offset_top = frame->offset_top;
+                    is_match = true;
+                    RRETURN;
+                }
+                
+                /* In all other cases except a conditional group we have to check the
+                 group number back at the start and if necessary complete handling an
+                 extraction by setting the offsets and bumping the high water mark. */
+                
+                frame->number = *frame->prev - OP_BRA;
+                
+                /* For extended extraction brackets (large number), we have to fish out
+                 the number from a dummy opcode at the start. */
+                
+                if (frame->number > EXTRACT_BASIC_MAX)
+                    frame->number = GET2(frame->prev, 2+LINK_SIZE);
+                frame->offset = frame->number << 1;
+                
+#ifdef DEBUG
+                printf("end bracket %d", frame->number);
+                printf("\n");
+#endif
+                
+                /* Test for a numbered group. This includes groups called as a result
+                 of recursion. Note that whole-pattern recursion is coded as a recurse
+                 into group 0, so it won't be picked up here. Instead, we catch it when
+                 the OP_END is reached. */
+                
+                if (frame->number > 0) {
+                    if (frame->offset >= md->offset_max)
+                        md->offset_overflow = true;
+                    else {
+                        md->offset_vector[frame->offset] =
+                        md->offset_vector[md->offset_end - frame->number];
+                        md->offset_vector[frame->offset+1] = frame->eptr - md->start_subject;
+                        if (frame->offset_top <= frame->offset)
+                            frame->offset_top = frame->offset + 2;
+                    }
+                }
+                
+                /* For a non-repeating ket, just continue at this level. This also
+                 happens for a repeating ket if no characters were matched in the group.
+                 This is the forcible breaking of infinite loops as implemented in Perl
+                 5.005. If there is an options reset, it will get obeyed in the normal
+                 course of events. */
+                
+                if (*frame->ecode == OP_KET || frame->eptr == frame->saved_eptr) {
+                    frame->ecode += 1 + LINK_SIZE;
+                    NEXT_OPCODE;
+                }
+                
+                /* The repeating kets try the rest of the pattern or restart from the
+                 preceding bracket, in the appropriate order. */
+                
+                if (*frame->ecode == OP_KETRMIN) {
+                    RMATCH(16, frame->ecode + 1+LINK_SIZE, frame->eptrb, 0);
+                    if (is_match)
+                        RRETURN;
+                    RMATCH(17, frame->prev, frame->eptrb, match_isgroup);
+                    if (is_match)
+                        RRETURN;
+                } else { /* OP_KETRMAX */
+                    RMATCH(18, frame->prev, frame->eptrb, match_isgroup);
+                    if (is_match)
+                        RRETURN;
+                    RMATCH(19, frame->ecode + 1+LINK_SIZE, frame->eptrb, 0);
+                    if (is_match)
+                        RRETURN;
+                }
+                RRETURN;
+                
+                /* Start of subject, or after internal newline if multiline. */
+                
+                BEGIN_OPCODE(CIRC):
+                if (frame->eptr != md->start_subject && (!md->multiline || !isNewline(frame->eptr[-1])))
+                    RRETURN_NO_MATCH;
+                frame->ecode++;
+                NEXT_OPCODE;
+                
+                /* End of subject, or before internal newline if multiline. */
+                
+                BEGIN_OPCODE(DOLL):
+                if (frame->eptr < md->end_subject && (!md->multiline || !isNewline(*frame->eptr)))
+                    RRETURN_NO_MATCH;
+                frame->ecode++;
+                NEXT_OPCODE;
+                
+                /* Word boundary assertions */
+                
+                BEGIN_OPCODE(NOT_WORD_BOUNDARY):
+                BEGIN_OPCODE(WORD_BOUNDARY):
+                /* Find out if the previous and current characters are "word" characters.
+                 It takes a bit more work in UTF-8 mode. Characters > 128 are assumed to
+                 be "non-word" characters. */
+                
+                if (frame->eptr == md->start_subject)
+                    prev_is_word = false;
+                else {
+                    const pcre_uchar *lastptr = frame->eptr - 1;
+                    while(ISMIDCHAR(*lastptr))
+                        lastptr--;
+                    GETCHAR(c, lastptr);
+                    prev_is_word = c < 128 && (md->ctypes[c] & ctype_word) != 0;
+                }
+                if (frame->eptr >= md->end_subject)
+                    cur_is_word = false;
+                else {
+                    GETCHAR(c, frame->eptr);
+                    cur_is_word = c < 128 && (md->ctypes[c] & ctype_word) != 0;
+                }
+                
+                /* Now see if the situation is what we want */
+                
+                if ((*frame->ecode++ == OP_WORD_BOUNDARY) ? cur_is_word == prev_is_word : cur_is_word != prev_is_word)
+                    RRETURN_NO_MATCH;
+                NEXT_OPCODE;
+                
+                /* Match a single character type; inline for speed */
+                
+                BEGIN_OPCODE(ANY):
+                if (frame->eptr < md->end_subject && isNewline(*frame->eptr))
+                    RRETURN_NO_MATCH;
+                if (frame->eptr++ >= md->end_subject)
+                    RRETURN_NO_MATCH;
+                while (frame->eptr < md->end_subject && ISMIDCHAR(*frame->eptr))
+                    frame->eptr++;
+                frame->ecode++;
+                NEXT_OPCODE;
+                
+                BEGIN_OPCODE(NOT_DIGIT):
+                if (frame->eptr >= md->end_subject)
+                    RRETURN_NO_MATCH;
+                GETCHARINCTEST(c, frame->eptr);
+                if (isASCIIDigit(c))
+                    RRETURN_NO_MATCH;
+                frame->ecode++;
+                NEXT_OPCODE;
+                
+                BEGIN_OPCODE(DIGIT):
+                if (frame->eptr >= md->end_subject)
+                    RRETURN_NO_MATCH;
+                GETCHARINCTEST(c, frame->eptr);
+                if (!isASCIIDigit(c))
+                    RRETURN_NO_MATCH;
+                frame->ecode++;
+                NEXT_OPCODE;
+                
+                BEGIN_OPCODE(NOT_WHITESPACE):
+                if (frame->eptr >= md->end_subject)
+                    RRETURN_NO_MATCH;
+                GETCHARINCTEST(c, frame->eptr);
+                if (c < 128 && (md->ctypes[c] & ctype_space))
+                    RRETURN_NO_MATCH;
+                frame->ecode++;
+                NEXT_OPCODE;
+                
+                BEGIN_OPCODE(WHITESPACE):
+                if (frame->eptr >= md->end_subject)
+                    RRETURN_NO_MATCH;
+                GETCHARINCTEST(c, frame->eptr);
+                if (c >= 128 || !(md->ctypes[c] & ctype_space))
+                    RRETURN_NO_MATCH;
+                frame->ecode++;
+                NEXT_OPCODE;
+                
+                BEGIN_OPCODE(NOT_WORDCHAR):
+                if (frame->eptr >= md->end_subject)
+                    RRETURN_NO_MATCH;
+                GETCHARINCTEST(c, frame->eptr);
+                if (c < 128 && (md->ctypes[c] & ctype_word))
+                    RRETURN_NO_MATCH;
+                frame->ecode++;
+                NEXT_OPCODE;
+                
+                BEGIN_OPCODE(WORDCHAR):
+                if (frame->eptr >= md->end_subject)
+                    RRETURN_NO_MATCH;
+                GETCHARINCTEST(c, frame->eptr);
+                if (c >= 128 || !(md->ctypes[c] & ctype_word))
+                    RRETURN_NO_MATCH;
+                frame->ecode++;
+                NEXT_OPCODE;
+                
+                /* Match a back reference, possibly repeatedly. Look past the end of the
+                 item to see if there is repeat information following. The code is similar
+                 to that for character classes, but repeated for efficiency. Then obey
+                 similar code to character type repeats - written out again for speed.
+                 However, if the referenced string is the empty string, always treat
+                 it as matched, any number of times (otherwise there could be infinite
+                 loops). */
+                
+                BEGIN_OPCODE(REF):
+                frame->offset = GET2(frame->ecode, 1) << 1;               /* Doubled ref number */
+                frame->ecode += 3;                                 /* Advance past item */
+                
+                /* If the reference is unset, set the length to be longer than the amount
+                 of subject left; this ensures that every attempt at a match fails. We
+                 can't just fail here, because of the possibility of quantifiers with zero
+                 minima. */
+                
+                if (frame->offset >= frame->offset_top || md->offset_vector[frame->offset] < 0)
+                    frame->length = 0;
+                else
+                    frame->length = md->offset_vector[frame->offset+1] - md->offset_vector[frame->offset];
+                
+                /* Set up for repetition, or handle the non-repeated case */
+                
+                switch (*frame->ecode) {
+                case OP_CRSTAR:
+                case OP_CRMINSTAR:
+                case OP_CRPLUS:
+                case OP_CRMINPLUS:
+                case OP_CRQUERY:
+                case OP_CRMINQUERY:
+                    c = *frame->ecode++ - OP_CRSTAR;
+                    minimize = (c & 1) != 0;
+                    min = rep_min[c];                 /* Pick up values from tables; */
+                    frame->max = rep_max[c];                 /* zero for max => infinity */
+                    if (frame->max == 0)
+                        frame->max = INT_MAX;
+                    break;
+                    
+                case OP_CRRANGE:
+                case OP_CRMINRANGE:
+                    minimize = (*frame->ecode == OP_CRMINRANGE);
+                    min = GET2(frame->ecode, 1);
+                    frame->max = GET2(frame->ecode, 3);
+                    if (frame->max == 0)
+                        frame->max = INT_MAX;
+                    frame->ecode += 5;
+                    break;
+                
+                default:               /* No repeat follows */
+                    if (!match_ref(frame->offset, frame->eptr, frame->length, md))
+                        RRETURN_NO_MATCH;
+                    frame->eptr += frame->length;
+                    NEXT_OPCODE;
+                }
+                
+                /* If the length of the reference is zero, just continue with the
+                 main loop. */
+                
+                if (frame->length == 0)
+                    NEXT_OPCODE;
+                
+                /* First, ensure the minimum number of matches are present. */
+                
+                for (i = 1; i <= min; i++) {
+                    if (!match_ref(frame->offset, frame->eptr, frame->length, md))
+                        RRETURN_NO_MATCH;
+                    frame->eptr += frame->length;
+                }
+                
+                /* If min = max, continue at the same level without recursion.
+                 They are not both allowed to be zero. */
+                
+                if (min == frame->max)
+                    NEXT_OPCODE;
+                
+                /* If minimizing, keep trying and advancing the pointer */
+                
+                if (minimize) {
+                    for (frame->fi = min;; frame->fi++) {
+                        RMATCH(20, frame->ecode, frame->eptrb, 0);
+                        if (is_match)
+                            RRETURN;
+                        if (frame->fi >= frame->max || !match_ref(frame->offset, frame->eptr, frame->length, md))
+                            RRETURN;
+                        frame->eptr += frame->length;
+                    }
+                    ASSERT_NOT_REACHED();
+                }
+                
+                /* If maximizing, find the longest string and work backwards */
+                
+                else {
+                    frame->pp = frame->eptr;
+                    for (i = min; i < frame->max; i++) {
+                        if (!match_ref(frame->offset, frame->eptr, frame->length, md))
+                            break;
+                        frame->eptr += frame->length;
+                    }
+                    while (frame->eptr >= frame->pp) {
+                        RMATCH(21, frame->ecode, frame->eptrb, 0);
+                        if (is_match)
+                            RRETURN;
+                        frame->eptr -= frame->length;
+                    }
+                    RRETURN_NO_MATCH;
+                }
+                ASSERT_NOT_REACHED();
+                
+                /* Match a bit-mapped character class, possibly repeatedly. This op code is
+                 used when all the characters in the class have values in the range 0-255,
+                 and either the matching is caseful, or the characters are in the range
+                 0-127 when UTF-8 processing is enabled. The only difference between
+                 OP_CLASS and OP_NCLASS occurs when a data character outside the range is
+                 encountered.
+                 
+                 First, look past the end of the item to see if there is repeat information
+                 following. Then obey similar code to character type repeats - written out
+                 again for speed. */
+                
+                BEGIN_OPCODE(NCLASS):
+                BEGIN_OPCODE(CLASS):
+                frame->data = frame->ecode + 1;                /* Save for matching */
+                frame->ecode += 33;                     /* Advance past the item */
+                
+                switch (*frame->ecode) {
+                case OP_CRSTAR:
+                case OP_CRMINSTAR:
+                case OP_CRPLUS:
+                case OP_CRMINPLUS:
+                case OP_CRQUERY:
+                case OP_CRMINQUERY:
+                    c = *frame->ecode++ - OP_CRSTAR;
+                    minimize = (c & 1) != 0;
+                    min = rep_min[c];                 /* Pick up values from tables; */
+                    frame->max = rep_max[c];                 /* zero for max => infinity */
+                    if (frame->max == 0)
+                        frame->max = INT_MAX;
+                    break;
+                    
+                case OP_CRRANGE:
+                case OP_CRMINRANGE:
+                    minimize = (*frame->ecode == OP_CRMINRANGE);
+                    min = GET2(frame->ecode, 1);
+                    frame->max = GET2(frame->ecode, 3);
+                    if (frame->max == 0)
+                        frame->max = INT_MAX;
+                    frame->ecode += 5;
+                    break;
+                    
+                default:               /* No repeat follows */
+                    min = frame->max = 1;
+                    break;
+                }
+                
+                /* First, ensure the minimum number of matches are present. */
+                
+                for (i = 1; i <= min; i++) {
+                    if (frame->eptr >= md->end_subject)
+                        RRETURN_NO_MATCH;
+                    GETCHARINC(c, frame->eptr);
+                    if (c > 255) {
+                        if (frame->data[-1] == OP_CLASS)
+                            RRETURN_NO_MATCH;
+                    } else {
+                        if ((frame->data[c/8] & (1 << (c&7))) == 0)
+                            RRETURN_NO_MATCH;
+                    }
+                }
+                
+                /* If max == min we can continue with the main loop without the
+                 need to recurse. */
+                
+                if (min == frame->max)
+                    NEXT_OPCODE;      
+                
+                /* If minimizing, keep testing the rest of the expression and advancing
+                 the pointer while it matches the class. */
+                if (minimize) {
+                    {
+                        for (frame->fi = min;; frame->fi++) {
+                            RMATCH(22, frame->ecode, frame->eptrb, 0);
+                            if (is_match)
+                                RRETURN;
+                            if (frame->fi >= frame->max || frame->eptr >= md->end_subject)
+                                RRETURN;
+                            GETCHARINC(c, frame->eptr);
+                            if (c > 255) {
+                                if (frame->data[-1] == OP_CLASS)
+                                    RRETURN;
+                            } else {
+                                if ((frame->data[c/8] & (1 << (c&7))) == 0)
+                                    RRETURN;
+                            }
+                        }
+                    }
+                    ASSERT_NOT_REACHED();
+                }
+                /* If maximizing, find the longest possible run, then work backwards. */
+                else {
+                    frame->pp = frame->eptr;
+                    
+                    for (i = min; i < frame->max; i++) {
+                        int len = 1;
+                        if (frame->eptr >= md->end_subject)
+                            break;
+                        GETCHARLEN(c, frame->eptr, len);
+                        if (c > 255) {
+                            if (frame->data[-1] == OP_CLASS)
+                                break;
+                        } else {
+                            if ((frame->data[c/8] & (1 << (c&7))) == 0)
+                                break;
+                        }
+                        frame->eptr += len;
+                    }
+                    for (;;) {
+                        RMATCH(24, frame->ecode, frame->eptrb, 0);
+                        if (is_match)
+                            RRETURN;
+                        if (frame->eptr-- == frame->pp)
+                            break;        /* Stop if tried at original pos */
+                        BACKCHAR(frame->eptr);
+                    }
+                    
+                    RRETURN;
+                }
+                ASSERT_NOT_REACHED();
+                
+                /* Match an extended character class. This opcode is encountered only
+                 in UTF-8 mode, because that's the only time it is compiled. */
+                
+                BEGIN_OPCODE(XCLASS):
+                frame->data = frame->ecode + 1 + LINK_SIZE;                /* Save for matching */
+                frame->ecode += GET(frame->ecode, 1);                      /* Advance past the item */
+                
+                switch (*frame->ecode) {
+                case OP_CRSTAR:
+                case OP_CRMINSTAR:
+                case OP_CRPLUS:
+                case OP_CRMINPLUS:
+                case OP_CRQUERY:
+                case OP_CRMINQUERY:
+                    c = *frame->ecode++ - OP_CRSTAR;
+                    minimize = (c & 1) != 0;
+                    min = rep_min[c];                 /* Pick up values from tables; */
+                    frame->max = rep_max[c];                 /* zero for max => infinity */
+                    if (frame->max == 0)
+                        frame->max = INT_MAX;
+                    break;
+                    
+                case OP_CRRANGE:
+                case OP_CRMINRANGE:
+                    minimize = (*frame->ecode == OP_CRMINRANGE);
+                    min = GET2(frame->ecode, 1);
+                    frame->max = GET2(frame->ecode, 3);
+                    if (frame->max == 0)
+                        frame->max = INT_MAX;
+                    frame->ecode += 5;
+                    break;
+                    
+                default:               /* No repeat follows */
+                    min = frame->max = 1;
             }
-          break;
-
-          case OP_NOT_WORDCHAR:
-          for (i = min; i < frame->max; i++)
+                
+                /* First, ensure the minimum number of matches are present. */
+                
+                for (i = 1; i <= min; i++) {
+                    if (frame->eptr >= md->end_subject)
+                        RRETURN_NO_MATCH;
+                    GETCHARINC(c, frame->eptr);
+                    if (!_pcre_xclass(c, frame->data))
+                        RRETURN_NO_MATCH;
+                }
+                
+                /* If max == min we can continue with the main loop without the
+                 need to recurse. */
+                
+                if (min == frame->max)
+                    NEXT_OPCODE;
+                
+                /* If minimizing, keep testing the rest of the expression and advancing
+                 the pointer while it matches the class. */
+                
+                if (minimize) {
+                    for (frame->fi = min;; frame->fi++) {
+                        RMATCH(26, frame->ecode, frame->eptrb, 0);
+                        if (is_match)
+                            RRETURN;
+                        if (frame->fi >= frame->max || frame->eptr >= md->end_subject)
+                            RRETURN;
+                        GETCHARINC(c, frame->eptr);
+                        if (!_pcre_xclass(c, frame->data))
+                            RRETURN;
+                    }
+                    ASSERT_NOT_REACHED();
+                }
+                
+                /* If maximizing, find the longest possible run, then work backwards. */
+                
+                else {
+                    frame->pp = frame->eptr;
+                    for (i = min; i < frame->max; i++) {
+                        int len = 1;
+                        if (frame->eptr >= md->end_subject)
+                            break;
+                        GETCHARLEN(c, frame->eptr, len);
+                        if (!_pcre_xclass(c, frame->data))
+                            break;
+                        frame->eptr += len;
+                    }
+                    for(;;) {
+                        RMATCH(27, frame->ecode, frame->eptrb, 0);
+                        if (is_match)
+                            RRETURN;
+                        if (frame->eptr-- == frame->pp)
+                            break;        /* Stop if tried at original pos */
+                        BACKCHAR(frame->eptr)
+                    }
+                    RRETURN;
+                }
+                
+                ASSERT_NOT_REACHED();
+                
+                /* Match a single character, casefully */
+                
+                BEGIN_OPCODE(CHAR):
+                frame->length = 1;
+                frame->ecode++;
+                GETUTF8CHARLEN(frame->fc, frame->ecode, frame->length);
             {
-            int len = 1;
-            if (frame->eptr >= md->end_subject) break;
-            GETCHARLEN(c, frame->eptr, len);
-            if (c < 128 && (md->ctypes[c] & ctype_word) != 0) break;
-            frame->eptr+= len;
+                int dc;
+                frame->ecode += frame->length;
+                switch (md->end_subject - frame->eptr) {
+                case 0:
+                    RRETURN_NO_MATCH;
+                case 1:
+                    dc = *frame->eptr++;
+                    if (IS_LEADING_SURROGATE(dc))
+                        RRETURN_NO_MATCH;
+                    break;
+                    default:
+                    GETCHARINC(dc, frame->eptr);
+                }
+                if (frame->fc != dc)
+                    RRETURN_NO_MATCH;
             }
-          break;
-
-          case OP_WORDCHAR:
-          for (i = min; i < frame->max; i++)
+                NEXT_OPCODE;
+                
+                /* Match a single character, caselessly */
+                
+                BEGIN_OPCODE(CHARNC):
+                frame->length = 1;
+                frame->ecode++;
+                GETUTF8CHARLEN(frame->fc, frame->ecode, frame->length);
+                
+                if (md->end_subject - frame->eptr == 0)
+                    RRETURN_NO_MATCH;
+                
             {
-            int len = 1;
-            if (frame->eptr >= md->end_subject) break;
-            GETCHARLEN(c, frame->eptr, len);
-            if (c >= 128 || (md->ctypes[c] & ctype_word) == 0) break;
-            frame->eptr+= len;
+                int dc;
+                if (md->end_subject - frame->eptr == 1) {
+                    dc = *frame->eptr++;
+                    if (IS_LEADING_SURROGATE(dc))
+                        RRETURN_NO_MATCH;
+                } else
+                    GETCHARINC(dc, frame->eptr);
+                frame->ecode += frame->length;
+                
+                /* If we have Unicode property support, we can use it to test the other
+                 case of the character, if there is one. */
+                
+                if (frame->fc != dc) {
+                    if (dc != _pcre_ucp_othercase(frame->fc))
+                        RRETURN_NO_MATCH;
+                }
             }
-          break;
-
-          default:
-          ASSERT_NOT_REACHED();
-          RRETURN_ERROR(JSRegExpErrorInternal);
-          }
-
-        /* frame->eptr is now past the end of the maximum run */
-
-        for(;;)
-          {
-          RMATCH(52, frame->ecode, frame->eptrb, 0);
-          if (is_match) RRETURN;
-          if (frame->eptr-- == frame->pp) break;        /* Stop if tried at original pos */
-          BACKCHAR(frame->eptr);
-          }
-
-      /* Get here if we can't make it match with any permitted repetitions */
-
-      RRETURN;
-      }
-    /* Control never gets here */
-
-    BEGIN_OPCODE(CRMINPLUS):
-    BEGIN_OPCODE(CRMINQUERY):
-    BEGIN_OPCODE(CRMINRANGE):
-    BEGIN_OPCODE(CRMINSTAR):
-    BEGIN_OPCODE(CRPLUS):
-    BEGIN_OPCODE(CRQUERY):
-    BEGIN_OPCODE(CRRANGE):
-    BEGIN_OPCODE(CRSTAR):
-      ASSERT_NOT_REACHED();
-      RRETURN_ERROR(JSRegExpErrorInternal);
-
+                NEXT_OPCODE;
+                
+                /* Match a single ASCII character. */
+                
+                BEGIN_OPCODE(ASCII_CHAR):
+                if (md->end_subject == frame->eptr)
+                    RRETURN_NO_MATCH;
+                if (*frame->eptr != frame->ecode[1])
+                    RRETURN_NO_MATCH;
+                ++frame->eptr;
+                frame->ecode += 2;
+                NEXT_OPCODE;
+                
+                /* Match one of two cases of an ASCII character. */
+                
+                BEGIN_OPCODE(ASCII_LETTER_NC):
+                if (md->end_subject == frame->eptr)
+                    RRETURN_NO_MATCH;
+                if ((*frame->eptr | 0x20) != frame->ecode[1])
+                    RRETURN_NO_MATCH;
+                ++frame->eptr;
+                frame->ecode += 2;
+                NEXT_OPCODE;
+                
+                /* Match a single character repeatedly; different opcodes share code. */
+                
+                BEGIN_OPCODE(EXACT):
+                min = frame->max = GET2(frame->ecode, 1);
+                minimize = false;
+                frame->ecode += 3;
+                goto REPEATCHAR;
+                
+                BEGIN_OPCODE(UPTO):
+                BEGIN_OPCODE(MINUPTO):
+                min = 0;
+                frame->max = GET2(frame->ecode, 1);
+                minimize = *frame->ecode == OP_MINUPTO;
+                frame->ecode += 3;
+                goto REPEATCHAR;
+                
+                BEGIN_OPCODE(STAR):
+                BEGIN_OPCODE(MINSTAR):
+                BEGIN_OPCODE(PLUS):
+                BEGIN_OPCODE(MINPLUS):
+                BEGIN_OPCODE(QUERY):
+                BEGIN_OPCODE(MINQUERY):
+                c = *frame->ecode++ - OP_STAR;
+                minimize = (c & 1) != 0;
+                min = rep_min[c];                 /* Pick up values from tables; */
+                frame->max = rep_max[c];                 /* zero for max => infinity */
+                if (frame->max == 0)
+                    frame->max = INT_MAX;
+                
+                /* Common code for all repeated single-character matches. We can give
+                 up quickly if there are fewer than the minimum number of characters left in
+                 the subject. */
+                
+            REPEATCHAR:
+                
+                frame->length = 1;
+                GETUTF8CHARLEN(frame->fc, frame->ecode, frame->length);
+                if (min * (frame->fc > 0xFFFF ? 2 : 1) > md->end_subject - frame->eptr)
+                    RRETURN_NO_MATCH;
+                frame->ecode += frame->length;
+                
+                if (frame->fc <= 0xFFFF) {
+                    int othercase = md->caseless ? _pcre_ucp_othercase(frame->fc) : -1;
+                    
+                    for (i = 1; i <= min; i++) {
+                        if (*frame->eptr != frame->fc && *frame->eptr != othercase)
+                            RRETURN_NO_MATCH;
+                        ++frame->eptr;
+                    }
+                    
+                    if (min == frame->max)
+                        NEXT_OPCODE;
+                    
+                    if (minimize) {
+                        frame->repeat_othercase = othercase;
+                        for (frame->fi = min;; frame->fi++) {
+                            RMATCH(28, frame->ecode, frame->eptrb, 0);
+                            if (is_match)
+                                RRETURN;
+                            if (frame->fi >= frame->max || frame->eptr >= md->end_subject)
+                                RRETURN;
+                            if (*frame->eptr != frame->fc && *frame->eptr != frame->repeat_othercase)
+                                RRETURN;
+                            ++frame->eptr;
+                        }
+                        ASSERT_NOT_REACHED();
+                    } else {
+                        frame->pp = frame->eptr;
+                        for (i = min; i < frame->max; i++) {
+                            if (frame->eptr >= md->end_subject)
+                                break;
+                            if (*frame->eptr != frame->fc && *frame->eptr != othercase)
+                                break;
+                            ++frame->eptr;
+                        }
+                        while (frame->eptr >= frame->pp) {
+                            RMATCH(29, frame->ecode, frame->eptrb, 0);
+                            if (is_match)
+                                RRETURN;
+                            --frame->eptr;
+                        }
+                        RRETURN_NO_MATCH;
+                    }
+                    ASSERT_NOT_REACHED();
+                } else {
+                    /* No case on surrogate pairs, so no need to bother with "othercase". */
+                    
+                    for (i = 1; i <= min; i++) {
+                        int nc;
+                        GETCHAR(nc, frame->eptr);
+                        if (nc != frame->fc)
+                            RRETURN_NO_MATCH;
+                        frame->eptr += 2;
+                    }
+                    
+                    if (min == frame->max)
+                        NEXT_OPCODE;
+                    
+                    if (minimize) {
+                        for (frame->fi = min;; frame->fi++) {
+                            int nc;
+                            RMATCH(30, frame->ecode, frame->eptrb, 0);
+                            if (is_match)
+                                RRETURN;
+                            if (frame->fi >= frame->max || frame->eptr >= md->end_subject)
+                                RRETURN;
+                            GETCHAR(nc, frame->eptr);
+                            if (*frame->eptr != frame->fc)
+                                RRETURN;
+                            frame->eptr += 2;
+                        }
+                        ASSERT_NOT_REACHED();
+                    } else {
+                        frame->pp = frame->eptr;
+                        for (i = min; i < frame->max; i++) {
+                            int nc;
+                            if (frame->eptr > md->end_subject - 2)
+                                break;
+                            GETCHAR(nc, frame->eptr);
+                            if (*frame->eptr != frame->fc)
+                                break;
+                            frame->eptr += 2;
+                        }
+                        while (frame->eptr >= frame->pp) {
+                            RMATCH(31, frame->ecode, frame->eptrb, 0);
+                            if (is_match)
+                                RRETURN;
+                            frame->eptr -= 2;
+                        }
+                        RRETURN_NO_MATCH;
+                    }
+                    ASSERT_NOT_REACHED();
+                }
+                ASSERT_NOT_REACHED();
+                
+                /* Match a negated single one-byte character. The character we are
+                 checking can be multibyte. */
+                
+                BEGIN_OPCODE(NOT):
+                if (frame->eptr >= md->end_subject)
+                    RRETURN_NO_MATCH;
+                frame->ecode++;
+                GETCHARINCTEST(c, frame->eptr);
+                if (md->caseless) {
+                    if (c < 128)
+                        c = md->lcc[c];
+                    if (md->lcc[*frame->ecode++] == c)
+                        RRETURN_NO_MATCH;
+                } else {
+                    if (*frame->ecode++ == c)
+                        RRETURN_NO_MATCH;
+                }
+                NEXT_OPCODE;
+                
+                /* Match a negated single one-byte character repeatedly. This is almost a
+                 repeat of the code for a repeated single character, but I haven't found a
+                 nice way of commoning these up that doesn't require a test of the
+                 positive/negative option for each character match. Maybe that wouldn't add
+                 very much to the time taken, but character matching *is* what this is all
+                 about... */
+                
+                BEGIN_OPCODE(NOTEXACT):
+                min = frame->max = GET2(frame->ecode, 1);
+                minimize = false;
+                frame->ecode += 3;
+                goto REPEATNOTCHAR;
+                
+                BEGIN_OPCODE(NOTUPTO):
+                BEGIN_OPCODE(NOTMINUPTO):
+                min = 0;
+                frame->max = GET2(frame->ecode, 1);
+                minimize = *frame->ecode == OP_NOTMINUPTO;
+                frame->ecode += 3;
+                goto REPEATNOTCHAR;
+                
+                BEGIN_OPCODE(NOTSTAR):
+                BEGIN_OPCODE(NOTMINSTAR):
+                BEGIN_OPCODE(NOTPLUS):
+                BEGIN_OPCODE(NOTMINPLUS):
+                BEGIN_OPCODE(NOTQUERY):
+                BEGIN_OPCODE(NOTMINQUERY):
+                c = *frame->ecode++ - OP_NOTSTAR;
+                minimize = (c & 1) != 0;
+                min = rep_min[c];                 /* Pick up values from tables; */
+                frame->max = rep_max[c];                 /* zero for max => infinity */
+                if (frame->max == 0) frame->max = INT_MAX;
+                
+                /* Common code for all repeated single-byte matches. We can give up quickly
+                 if there are fewer than the minimum number of bytes left in the
+                 subject. */
+                
+            REPEATNOTCHAR:
+                if (min > md->end_subject - frame->eptr)
+                    RRETURN_NO_MATCH;
+                frame->fc = *frame->ecode++;
+                
+                /* The code is duplicated for the caseless and caseful cases, for speed,
+                 since matching characters is likely to be quite common. First, ensure the
+                 minimum number of matches are present. If min = max, continue at the same
+                 level without recursing. Otherwise, if minimizing, keep trying the rest of
+                 the expression and advancing one matching character if failing, up to the
+                 maximum. Alternatively, if maximizing, find the maximum number of
+                 characters and work backwards. */
+                
+                DPRINTF(("negative matching %c{%d,%d}\n", frame->fc, min, frame->max));
+                
+                if (md->caseless) {
+                    if (frame->fc < 128)
+                        frame->fc = md->lcc[frame->fc];
+                    
+                    {
+                        register int d;
+                        for (i = 1; i <= min; i++) {
+                            GETCHARINC(d, frame->eptr);
+                            if (d < 128)
+                                d = md->lcc[d];
+                            if (frame->fc == d)
+                                RRETURN_NO_MATCH;
+                        }
+                    }
+                    
+                    if (min == frame->max)
+                        NEXT_OPCODE;      
+                    
+                    if (minimize) {
+                        register int d;
+                        for (frame->fi = min;; frame->fi++) {
+                            RMATCH(38, frame->ecode, frame->eptrb, 0);
+                            if (is_match)
+                                RRETURN;
+                            GETCHARINC(d, frame->eptr);
+                            if (d < 128)
+                                d = md->lcc[d];
+                            if (frame->fi >= frame->max || frame->eptr >= md->end_subject || frame->fc == d)
+                                RRETURN;
+                        }
+                        ASSERT_NOT_REACHED();
+                    }
+                    
+                    /* Maximize case */
+                    
+                    else {
+                        frame->pp = frame->eptr;
+                        
+                        {
+                            register int d;
+                            for (i = min; i < frame->max; i++) {
+                                int len = 1;
+                                if (frame->eptr >= md->end_subject)
+                                    break;
+                                GETCHARLEN(d, frame->eptr, len);
+                                if (d < 128)
+                                    d = md->lcc[d];
+                                if (frame->fc == d)
+                                    break;
+                                frame->eptr += len;
+                            }
+                            for (;;) {
+                                RMATCH(40, frame->ecode, frame->eptrb, 0);
+                                if (is_match)
+                                    RRETURN;
+                                if (frame->eptr-- == frame->pp)
+                                    break;        /* Stop if tried at original pos */
+                                BACKCHAR(frame->eptr);
+                            }
+                        }
+                        
+                        RRETURN;
+                    }
+                    ASSERT_NOT_REACHED();
+                }
+                
+                /* Caseful comparisons */
+                
+                else {
+                    {
+                        register int d;
+                        for (i = 1; i <= min; i++) {
+                            GETCHARINC(d, frame->eptr);
+                            if (frame->fc == d)
+                                RRETURN_NO_MATCH;
+                        }
+                    }
+                    
+                    if (min == frame->max)
+                        NEXT_OPCODE;
+                    
+                    if (minimize) {
+                        register int d;
+                        for (frame->fi = min;; frame->fi++) {
+                            RMATCH(42, frame->ecode, frame->eptrb, 0);
+                            if (is_match)
+                                RRETURN;
+                            GETCHARINC(d, frame->eptr);
+                            if (frame->fi >= frame->max || frame->eptr >= md->end_subject || frame->fc == d)
+                                RRETURN;
+                        }
+                        ASSERT_NOT_REACHED();
+                    }
+                    
+                    /* Maximize case */
+                    
+                    else {
+                        frame->pp = frame->eptr;
+                        
+                        {
+                            register int d;
+                            for (i = min; i < frame->max; i++) {
+                                int len = 1;
+                                if (frame->eptr >= md->end_subject)
+                                    break;
+                                GETCHARLEN(d, frame->eptr, len);
+                                if (frame->fc == d)
+                                    break;
+                                frame->eptr += len;
+                            }
+                            for (;;) {
+                                RMATCH(44, frame->ecode, frame->eptrb, 0);
+                                if (is_match)
+                                    RRETURN;
+                                if (frame->eptr-- == frame->pp)
+                                    break;        /* Stop if tried at original pos */
+                                BACKCHAR(frame->eptr);
+                            }
+                        }
+                        
+                        RRETURN;
+                    }
+                }
+                ASSERT_NOT_REACHED();
+                
+                /* Match a single character type repeatedly; several different opcodes
+                 share code. This is very similar to the code for single characters, but we
+                 repeat it in the interests of efficiency. */
+                
+                BEGIN_OPCODE(TYPEEXACT):
+                min = frame->max = GET2(frame->ecode, 1);
+                minimize = true;
+                frame->ecode += 3;
+                goto REPEATTYPE;
+                
+                BEGIN_OPCODE(TYPEUPTO):
+                BEGIN_OPCODE(TYPEMINUPTO):
+                min = 0;
+                frame->max = GET2(frame->ecode, 1);
+                minimize = *frame->ecode == OP_TYPEMINUPTO;
+                frame->ecode += 3;
+                goto REPEATTYPE;
+                
+                BEGIN_OPCODE(TYPESTAR):
+                BEGIN_OPCODE(TYPEMINSTAR):
+                BEGIN_OPCODE(TYPEPLUS):
+                BEGIN_OPCODE(TYPEMINPLUS):
+                BEGIN_OPCODE(TYPEQUERY):
+                BEGIN_OPCODE(TYPEMINQUERY):
+                c = *frame->ecode++ - OP_TYPESTAR;
+                minimize = (c & 1) != 0;
+                min = rep_min[c];                 /* Pick up values from tables; */
+                frame->max = rep_max[c];                 /* zero for max => infinity */
+                if (frame->max == 0)
+                    frame->max = INT_MAX;
+                
+                /* Common code for all repeated single character type matches. Note that
+                 in UTF-8 mode, '.' matches a character of any length, but for the other
+                 character types, the valid characters are all one-byte long. */
+                
+            REPEATTYPE:
+                frame->ctype = *frame->ecode++;      /* Code for the character type */
+                
+                /* First, ensure the minimum number of matches are present. Use inline
+                 code for maximizing the speed, and do the type test once at the start
+                 (i.e. keep it out of the loop). Also we can test that there are at least
+                 the minimum number of bytes before we start. This isn't as effective in
+                 UTF-8 mode, but it does no harm. Separate the UTF-8 code completely as that
+                 is tidier. Also separate the UCP code, which can be the same for both UTF-8
+                 and single-bytes. */
+                
+                if (min > md->end_subject - frame->eptr)
+                    RRETURN_NO_MATCH;
+                if (min > 0) {
+                    switch(frame->ctype) {
+                        case OP_ANY:
+                            for (i = 1; i <= min; i++) {
+                                if (frame->eptr >= md->end_subject || isNewline(*frame->eptr))
+                                    RRETURN_NO_MATCH;
+                                ++frame->eptr;
+                                while (frame->eptr < md->end_subject && ISMIDCHAR(*frame->eptr))
+                                    frame->eptr++;
+                            }
+                            break;
+                            
+                            case OP_NOT_DIGIT:
+                            for (i = 1; i <= min; i++) {
+                                if (frame->eptr >= md->end_subject)
+                                    RRETURN_NO_MATCH;
+                                GETCHARINC(c, frame->eptr);
+                                if (isASCIIDigit(c))
+                                    RRETURN_NO_MATCH;
+                            }
+                            break;
+                            
+                            case OP_DIGIT:
+                            for (i = 1; i <= min; i++) {
+                                if (frame->eptr >= md->end_subject || !isASCIIDigit(*frame->eptr++))
+                                    RRETURN_NO_MATCH;
+                                /* No need to skip more bytes - we know it's a 1-byte character */
+                            }
+                            break;
+                            
+                            case OP_NOT_WHITESPACE:
+                            for (i = 1; i <= min; i++) {
+                                if (frame->eptr >= md->end_subject ||
+                                    (*frame->eptr < 128 && (md->ctypes[*frame->eptr] & ctype_space) != 0))
+                                    RRETURN_NO_MATCH;
+                                while (++frame->eptr < md->end_subject && ISMIDCHAR(*frame->eptr));
+                            }
+                            break;
+                            
+                            case OP_WHITESPACE:
+                            for (i = 1; i <= min; i++) {
+                                if (frame->eptr >= md->end_subject ||
+                                    *frame->eptr >= 128 || (md->ctypes[*frame->eptr++] & ctype_space) == 0)
+                                    RRETURN_NO_MATCH;
+                                /* No need to skip more bytes - we know it's a 1-byte character */
+                            }
+                            break;
+                            
+                            case OP_NOT_WORDCHAR:
+                            for (i = 1; i <= min; i++) {
+                                if (frame->eptr >= md->end_subject ||
+                                    (*frame->eptr < 128 && (md->ctypes[*frame->eptr] & ctype_word) != 0))
+                                    RRETURN_NO_MATCH;
+                                while (++frame->eptr < md->end_subject && ISMIDCHAR(*frame->eptr));
+                            }
+                            break;
+                            
+                            case OP_WORDCHAR:
+                            for (i = 1; i <= min; i++) {
+                                if (frame->eptr >= md->end_subject ||
+                                    *frame->eptr >= 128 || (md->ctypes[*frame->eptr++] & ctype_word) == 0)
+                                    RRETURN_NO_MATCH;
+                                /* No need to skip more bytes - we know it's a 1-byte character */
+                            }
+                            break;
+                            
+                            default:
+                            ASSERT_NOT_REACHED();
+                            RRETURN_ERROR(JSRegExpErrorInternal);
+                    }  /* End switch(frame->ctype) */
+                }
+                
+                /* If min = max, continue at the same level without recursing */
+                
+                if (min == frame->max)
+                    NEXT_OPCODE;    
+                
+                /* If minimizing, we have to test the rest of the pattern before each
+                 subsequent match. */
+                
+                if (minimize) {
+                    for (frame->fi = min;; frame->fi++) {
+                        RMATCH(48, frame->ecode, frame->eptrb, 0);
+                        if (is_match)
+                            RRETURN;
+                        if (frame->fi >= frame->max || frame->eptr >= md->end_subject)
+                            RRETURN;
+                        
+                        GETCHARINC(c, frame->eptr);
+                        switch(frame->ctype) {
+                        case OP_ANY:
+                            if (isNewline(c))
+                                RRETURN;
+                            break;
+                            
+                        case OP_NOT_DIGIT:
+                            if (isASCIIDigit(c))
+                                RRETURN;
+                            break;
+                            
+                        case OP_DIGIT:
+                            if (!isASCIIDigit(c))
+                                RRETURN;
+                            break;
+                            
+                        case OP_NOT_WHITESPACE:
+                            if (c < 128 && (md->ctypes[c] & ctype_space))
+                                RRETURN;
+                            break;
+                            
+                        case OP_WHITESPACE:
+                            if  (c >= 128 || !(md->ctypes[c] & ctype_space))
+                                RRETURN;
+                            break;
+                            
+                        case OP_NOT_WORDCHAR:
+                            if (c < 128 && (md->ctypes[c] & ctype_word))
+                                RRETURN;
+                            break;
+                            
+                        case OP_WORDCHAR:
+                            if (c >= 128 || !(md->ctypes[c] & ctype_word))
+                                RRETURN;
+                            break;
+                            
+                        default:
+                            ASSERT_NOT_REACHED();
+                            RRETURN_ERROR(JSRegExpErrorInternal);
+                        }
+                    }
+                    ASSERT_NOT_REACHED();
+                }
+                
+                /* If maximizing it is worth using inline code for speed, doing the type
+                 test once at the start (i.e. keep it out of the loop). */
+                
+                else {
+                    frame->pp = frame->eptr;  /* Remember where we started */
+                    
+                    switch(frame->ctype) {
+                        case OP_ANY:
+                            
+                            /* Special code is required for UTF8, but when the maximum is unlimited
+                             we don't need it, so we repeat the non-UTF8 code. This is probably
+                             worth it, because .* is quite a common idiom. */
+                            
+                            if (frame->max < INT_MAX) {
+                                for (i = min; i < frame->max; i++) {
+                                    if (frame->eptr >= md->end_subject || isNewline(*frame->eptr))
+                                        break;
+                                    frame->eptr++;
+                                    while (frame->eptr < md->end_subject && (*frame->eptr & 0xc0) == 0x80)
+                                        frame->eptr++;
+                                }
+                            }
+                            
+                            /* Handle unlimited UTF-8 repeat */
+                            
+                            else {
+                                for (i = min; i < frame->max; i++) {
+                                    if (frame->eptr >= md->end_subject || isNewline(*frame->eptr))
+                                        break;
+                                    frame->eptr++;
+                                }
+                                break;
+                            }
+                            break;
+                            
+                            case OP_NOT_DIGIT:
+                            for (i = min; i < frame->max; i++) {
+                                int len = 1;
+                                if (frame->eptr >= md->end_subject)
+                                    break;
+                                GETCHARLEN(c, frame->eptr, len);
+                                if (isASCIIDigit(c))
+                                    break;
+                                frame->eptr+= len;
+                            }
+                            break;
+                            
+                            case OP_DIGIT:
+                            for (i = min; i < frame->max; i++) {
+                                int len = 1;
+                                if (frame->eptr >= md->end_subject)
+                                    break;
+                                GETCHARLEN(c, frame->eptr, len);
+                                if (!isASCIIDigit(c))
+                                    break;
+                                frame->eptr+= len;
+                            }
+                            break;
+                            
+                            case OP_NOT_WHITESPACE:
+                            for (i = min; i < frame->max; i++) {
+                                int len = 1;
+                                if (frame->eptr >= md->end_subject)
+                                    break;
+                                GETCHARLEN(c, frame->eptr, len);
+                                if (c < 128 && (md->ctypes[c] & ctype_space))
+                                    break;
+                                frame->eptr+= len;
+                            }
+                            break;
+                            
+                            case OP_WHITESPACE:
+                            for (i = min; i < frame->max; i++) {
+                                int len = 1;
+                                if (frame->eptr >= md->end_subject)
+                                    break;
+                                GETCHARLEN(c, frame->eptr, len);
+                                if (c >= 128 || !(md->ctypes[c] & ctype_space))
+                                    break;
+                                frame->eptr+= len;
+                            }
+                            break;
+                            
+                            case OP_NOT_WORDCHAR:
+                            for (i = min; i < frame->max; i++) {
+                                int len = 1;
+                                if (frame->eptr >= md->end_subject)
+                                    break;
+                                GETCHARLEN(c, frame->eptr, len);
+                                if (c < 128 && (md->ctypes[c] & ctype_word))
+                                    break;
+                                frame->eptr+= len;
+                            }
+                            break;
+                            
+                            case OP_WORDCHAR:
+                            for (i = min; i < frame->max; i++) {
+                                int len = 1;
+                                if (frame->eptr >= md->end_subject)
+                                    break;
+                                GETCHARLEN(c, frame->eptr, len);
+                                if (c >= 128 || !(md->ctypes[c] & ctype_word))
+                                    break;
+                                frame->eptr+= len;
+                            }
+                            break;
+                            
+                            default:
+                            ASSERT_NOT_REACHED();
+                            RRETURN_ERROR(JSRegExpErrorInternal);
+                    }
+                    
+                    /* frame->eptr is now past the end of the maximum run */
+                    
+                    for (;;) {
+                        RMATCH(52, frame->ecode, frame->eptrb, 0);
+                        if (is_match)
+                            RRETURN;
+                        if (frame->eptr-- == frame->pp)
+                            break;        /* Stop if tried at original pos */
+                        BACKCHAR(frame->eptr);
+                    }
+                    
+                    /* Get here if we can't make it match with any permitted repetitions */
+                    
+                    RRETURN;
+                }
+                ASSERT_NOT_REACHED();
+                
+                BEGIN_OPCODE(CRMINPLUS):
+                BEGIN_OPCODE(CRMINQUERY):
+                BEGIN_OPCODE(CRMINRANGE):
+                BEGIN_OPCODE(CRMINSTAR):
+                BEGIN_OPCODE(CRPLUS):
+                BEGIN_OPCODE(CRQUERY):
+                BEGIN_OPCODE(CRRANGE):
+                BEGIN_OPCODE(CRSTAR):
+                ASSERT_NOT_REACHED();
+                RRETURN_ERROR(JSRegExpErrorInternal);
+                
 #ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
-    CAPTURING_BRACKET:
+            CAPTURING_BRACKET:
 #else
-    default:
+                default:
 #endif
-      /* Opening capturing bracket. If there is space in the offset vector, save
-      the current subject position in the working slot at the top of the vector. We
-      mustn't change the current values of the data slot, because they may be set
-      from a previous iteration of this group, and be referred to by a reference
-      inside the group.
-
-      If the bracket fails to match, we need to restore this value and also the
-      values of the final offsets, in case they were set by a previous iteration of
-      the same bracket.
-
-      If there isn't enough space in the offset vector, treat this as if it were a
-      non-capturing bracket. Don't worry about setting the flag for the error case
-      here; that is handled in the code for KET. */
-
-      ASSERT(*frame->ecode > OP_BRA);
-
-        frame->number = *frame->ecode - OP_BRA;
-
-        /* For extended extraction brackets (large number), we have to fish out the
-        number from a dummy opcode at the start. */
-
-        if (frame->number > EXTRACT_BASIC_MAX)
-          frame->number = GET2(frame->ecode, 2+LINK_SIZE);
-        frame->offset = frame->number << 1;
-
+                /* Opening capturing bracket. If there is space in the offset vector, save
+                 the current subject position in the working slot at the top of the vector. We
+                 mustn't change the current values of the data slot, because they may be set
+                 from a previous iteration of this group, and be referred to by a reference
+                 inside the group.
+                 
+                 If the bracket fails to match, we need to restore this value and also the
+                 values of the final offsets, in case they were set by a previous iteration of
+                 the same bracket.
+                 
+                 If there isn't enough space in the offset vector, treat this as if it were a
+                 non-capturing bracket. Don't worry about setting the flag for the error case
+                 here; that is handled in the code for KET. */
+                
+                ASSERT(*frame->ecode > OP_BRA);
+                
+                frame->number = *frame->ecode - OP_BRA;
+                
+                /* For extended extraction brackets (large number), we have to fish out the
+                 number from a dummy opcode at the start. */
+                
+                if (frame->number > EXTRACT_BASIC_MAX)
+                    frame->number = GET2(frame->ecode, 2+LINK_SIZE);
+                frame->offset = frame->number << 1;
+                
 #ifdef DEBUG
-        printf("start bracket %d subject=", frame->number);
-        pchars(frame->eptr, 16, true, md);
-        printf("\n");
+                printf("start bracket %d subject=", frame->number);
+                pchars(frame->eptr, 16, true, md);
+                printf("\n");
 #endif
-
-        if (frame->offset < md->offset_max)
-          {
-          frame->save_offset1 = md->offset_vector[frame->offset];
-          frame->save_offset2 = md->offset_vector[frame->offset + 1];
-          frame->save_offset3 = md->offset_vector[md->offset_end - frame->number];
-
-          DPRINTF(("saving %d %d %d\n", frame->save_offset1, frame->save_offset2, frame->save_offset3));
-          md->offset_vector[md->offset_end - frame->number] = frame->eptr - md->start_subject;
-
-          do
-            {
-            RMATCH(1, frame->ecode + 1 + LINK_SIZE, frame->eptrb, match_isgroup);
-            if (is_match) RRETURN;
-            frame->ecode += GET(frame->ecode, 1);
-            }
-          while (*frame->ecode == OP_ALT);
-
-          DPRINTF(("bracket %d failed\n", frame->number));
-
-          md->offset_vector[frame->offset] = frame->save_offset1;
-          md->offset_vector[frame->offset + 1] = frame->save_offset2;
-          md->offset_vector[md->offset_end - frame->number] = frame->save_offset3;
-
-          RRETURN;
-          }
-
-        /* Insufficient room for saving captured contents */
-
-        goto NON_CAPTURING_BRACKET;
-    }
-
-  /* Do not stick any code in here without much thought; it is assumed
-  that "continue" in the code above comes out to here to repeat the main
-  loop. */
-
-  } /* End of main loop */
-
-/* Control never reaches here */
-
+                
+                if (frame->offset < md->offset_max) {
+                    frame->save_offset1 = md->offset_vector[frame->offset];
+                    frame->save_offset2 = md->offset_vector[frame->offset + 1];
+                    frame->save_offset3 = md->offset_vector[md->offset_end - frame->number];
+                    
+                    DPRINTF(("saving %d %d %d\n", frame->save_offset1, frame->save_offset2, frame->save_offset3));
+                    md->offset_vector[md->offset_end - frame->number] = frame->eptr - md->start_subject;
+                    
+                    do {
+                        RMATCH(1, frame->ecode + 1 + LINK_SIZE, frame->eptrb, match_isgroup);
+                        if (is_match) RRETURN;
+                        frame->ecode += GET(frame->ecode, 1);
+                    } while (*frame->ecode == OP_ALT);
+                    
+                    DPRINTF(("bracket %d failed\n", frame->number));
+                    
+                    md->offset_vector[frame->offset] = frame->save_offset1;
+                    md->offset_vector[frame->offset + 1] = frame->save_offset2;
+                    md->offset_vector[md->offset_end - frame->number] = frame->save_offset3;
+                    
+                    RRETURN;
+                }
+                
+                /* Insufficient room for saving captured contents */
+                
+                goto NON_CAPTURING_BRACKET;
+        }
+        
+        /* Do not stick any code in here without much thought; it is assumed
+         that "continue" in the code above comes out to here to repeat the main
+         loop. */
+        
+    } /* End of main loop */
+    
+    ASSERT_NOT_REACHED();
+    
 #ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION
-
+    
 RRETURN_SWITCH:
-switch (frame->where)
-  {
-  case 0: goto RETURN;
-  case 1: goto RRETURN_1;
-  case 2: goto RRETURN_2;
-  case 6: goto RRETURN_6;
-  case 7: goto RRETURN_7;
-  case 9: goto RRETURN_9;
-  case 10: goto RRETURN_10;
-  case 11: goto RRETURN_11;
-  case 12: goto RRETURN_12;
-  case 13: goto RRETURN_13;
-  case 14: goto RRETURN_14;
-  case 15: goto RRETURN_15;
-  case 16: goto RRETURN_16;
-  case 17: goto RRETURN_17;
-  case 18: goto RRETURN_18;
-  case 19: goto RRETURN_19;
-  case 20: goto RRETURN_20;
-  case 21: goto RRETURN_21;
-  case 22: goto RRETURN_22;
-  case 24: goto RRETURN_24;
-  case 26: goto RRETURN_26;
-  case 27: goto RRETURN_27;
-  case 28: goto RRETURN_28;
-  case 29: goto RRETURN_29;
-  case 30: goto RRETURN_30;
-  case 31: goto RRETURN_31;
-  case 38: goto RRETURN_38;
-  case 40: goto RRETURN_40;
-  case 42: goto RRETURN_42;
-  case 44: goto RRETURN_44;
-  case 48: goto RRETURN_48;
-  case 52: goto RRETURN_52;
-  }
-
-abort();
-RRETURN_ERROR(JSRegExpErrorInternal);
-
+    switch (frame->where)
+    {
+        case 0: goto RETURN;
+        case 1: goto RRETURN_1;
+        case 2: goto RRETURN_2;
+        case 6: goto RRETURN_6;
+        case 7: goto RRETURN_7;
+        case 9: goto RRETURN_9;
+        case 10: goto RRETURN_10;
+        case 11: goto RRETURN_11;
+        case 12: goto RRETURN_12;
+        case 13: goto RRETURN_13;
+        case 14: goto RRETURN_14;
+        case 15: goto RRETURN_15;
+        case 16: goto RRETURN_16;
+        case 17: goto RRETURN_17;
+        case 18: goto RRETURN_18;
+        case 19: goto RRETURN_19;
+        case 20: goto RRETURN_20;
+        case 21: goto RRETURN_21;
+        case 22: goto RRETURN_22;
+        case 24: goto RRETURN_24;
+        case 26: goto RRETURN_26;
+        case 27: goto RRETURN_27;
+        case 28: goto RRETURN_28;
+        case 29: goto RRETURN_29;
+        case 30: goto RRETURN_30;
+        case 31: goto RRETURN_31;
+        case 38: goto RRETURN_38;
+        case 40: goto RRETURN_40;
+        case 42: goto RRETURN_42;
+        case 44: goto RRETURN_44;
+        case 48: goto RRETURN_48;
+        case 52: goto RRETURN_52;
+    }
+    
+    abort();
+    RRETURN_ERROR(JSRegExpErrorInternal);
+    
 #endif
-
+    
 RETURN:
     return is_match ? MATCH_MATCH : MATCH_NOMATCH;
-
+    
 RETURN_ERROR:
     while (!(frame >= stackframes && frame < stackframesend)) {
         newframe = frame->prevframe;