This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
regmatch(): do nextchr=*locinput at top of loop
[perl5.git] / regexec.c
index 73c71f5..da9b640 100644 (file)
--- a/regexec.c
+++ b/regexec.c
@@ -80,6 +80,9 @@
 #  include "regcomp.h"
 #endif
 
+#include "inline_invlist.c"
+#include "unicode_constants.h"
+
 #define RF_tainted     1       /* tainted information used? e.g. locale */
 #define RF_warned      2               /* warned about big count? */
 
 #define HOP3c(pos,off,lim) ((char*)HOP3(pos,off,lim))
 
 /* these are unrolled below in the CCC_TRY_XXX defined */
-#ifdef EBCDIC
-    /* Often 'str' is a hard-coded utf8 string instead of utfebcdic. so just
-     * skip the check on EBCDIC platforms */
-#   define LOAD_UTF8_CHARCLASS(class,str) LOAD_UTF8_CHARCLASS_NO_CHECK(class)
-#else
-#   define LOAD_UTF8_CHARCLASS(class,str) STMT_START { \
+#define LOAD_UTF8_CHARCLASS(class,str) STMT_START { \
     if (!CAT2(PL_utf8_,class)) { \
        bool ok; \
        ENTER; save_re_context(); \
        ok=CAT2(is_utf8_,class)((const U8*)str); \
+        PERL_UNUSED_VAR(ok); \
        assert(ok); assert(CAT2(PL_utf8_,class)); LEAVE; } } STMT_END
-#endif
-
 /* Doesn't do an assert to verify that is correct */
 #define LOAD_UTF8_CHARCLASS_NO_CHECK(class) STMT_START { \
     if (!CAT2(PL_utf8_,class)) { \
 #define LOAD_UTF8_CHARCLASS_SPACE() LOAD_UTF8_CHARCLASS(space," ")
 
 #define LOAD_UTF8_CHARCLASS_GCB()  /* Grapheme cluster boundaries */        \
-       LOAD_UTF8_CHARCLASS(X_begin, " ");                                  \
-       LOAD_UTF8_CHARCLASS(X_non_hangul, "A");                             \
-       /* These are utf8 constants, and not utf-ebcdic constants, so the   \
-           * assert should likely and hopefully fail on an EBCDIC machine */ \
-       LOAD_UTF8_CHARCLASS(X_extend, "\xcc\x80"); /* U+0300 */             \
-                                                                           \
-       /* No asserts are done for these, in case called on an early        \
-           * Unicode version in which they map to nothing */               \
-       LOAD_UTF8_CHARCLASS_NO_CHECK(X_prepend);/* U+0E40 "\xe0\xb9\x80" */ \
-       LOAD_UTF8_CHARCLASS_NO_CHECK(X_L);          /* U+1100 "\xe1\x84\x80" */ \
-       LOAD_UTF8_CHARCLASS_NO_CHECK(X_LV);     /* U+AC00 "\xea\xb0\x80" */ \
-       LOAD_UTF8_CHARCLASS_NO_CHECK(X_LVT);    /* U+AC01 "\xea\xb0\x81" */ \
-       LOAD_UTF8_CHARCLASS_NO_CHECK(X_LV_LVT_V);/* U+AC01 "\xea\xb0\x81" */\
-       LOAD_UTF8_CHARCLASS_NO_CHECK(X_T);      /* U+11A8 "\xe1\x86\xa8" */ \
-       LOAD_UTF8_CHARCLASS_NO_CHECK(X_V)       /* U+1160 "\xe1\x85\xa0" */  
+        /* No asserts are done for some of these, in case called on a   */  \
+        /* Unicode version in which they map to nothing */                  \
+       LOAD_UTF8_CHARCLASS(X_regular_begin, HYPHEN_UTF8);                          \
+       LOAD_UTF8_CHARCLASS(X_extend, COMBINING_GRAVE_ACCENT_UTF8);         \
 
 #define PLACEHOLDER    /* Something for the preprocessor to grab onto */
 
        if (POS_OR_NEG (UTF8_TEST)) {                                         \
            sayNO;                                                            \
        }                                                                     \
-       locinput += PL_utf8skip[nextchr];                                     \
-       nextchr = UCHARAT(locinput);                                          \
-       break;                                                                \
     }                                                                         \
-    if (POS_OR_NEG (FUNC(nextchr))) {                                         \
-       sayNO;                                                                \
+    else if (POS_OR_NEG (FUNC(nextchr))) {                                    \
+            sayNO;                                                            \
     }                                                                         \
-    nextchr = UCHARAT(++locinput);                                            \
-    break;
+    goto increment_locinput;
 
 /* Handle the non-locale cases for a character class and its complement.  It
  * calls _CCC_TRY_CODE with a ! to complement the test for the character class.
            sayNO;                                                            \
        }                                                                     \
        /* Matched a utf8-invariant, so don't have to worry about utf8 */     \
-       nextchr = UCHARAT(++locinput);                                        \
+       locinput++;                                        \
        break;                                                                \
     case NNAMEA:                                                              \
        if (locinput >= PL_regeol || FUNCA(nextchr)) {                        \
            sayNO;                                                            \
        }                                                                     \
-       if (utf8_target) {                                                    \
-           locinput += PL_utf8skip[nextchr];                                 \
-           nextchr = UCHARAT(locinput);                                      \
-       }                                                                     \
-       else {                                                                \
-           nextchr = UCHARAT(++locinput);                                    \
-       }                                                                     \
-       break;                                                                \
+        goto increment_locinput;                                              \
     /* Generate the non-locale cases */                                       \
     _CCC_TRY_NONLOCALE(NAME, NNAME, FUNC, CLASS, STR)
 
 
 static void restore_pos(pTHX_ void *arg);
 
-#define REGCP_PAREN_ELEMS 4
-#define REGCP_OTHER_ELEMS 4
+#define REGCP_PAREN_ELEMS 3
+#define REGCP_OTHER_ELEMS 3
 #define REGCP_FRAME_ELEMS 1
 /* REGCP_FRAME_ELEMS are not part of the REGCP_OTHER_ELEMS and
  * are needed for the regexp context stack bookkeeping. */
@@ -346,7 +321,7 @@ S_regcppush(pTHX_ const regexp *rex, I32 parenfloor)
     const int paren_elems_to_push = (PL_regsize - parenfloor) * REGCP_PAREN_ELEMS;
     const UV total_elems = paren_elems_to_push + REGCP_OTHER_ELEMS;
     const UV elems_shifted = total_elems << SAVE_TIGHT_SHIFT;
-    int p;
+    I32 p;
     GET_RE_DEBUG_FLAGS_DECL;
 
     PERL_ARGS_ASSERT_REGCPPUSH;
@@ -362,24 +337,31 @@ S_regcppush(pTHX_ const regexp *rex, I32 parenfloor)
 
     SSGROW(total_elems + REGCP_FRAME_ELEMS);
     
-    for (p = PL_regsize; p > parenfloor; p--) {
+    DEBUG_BUFFERS_r(
+       if ((int)PL_regsize > (int)parenfloor)
+           PerlIO_printf(Perl_debug_log,
+               "rex=0x%"UVxf" offs=0x%"UVxf": saving capture indices:\n",
+               PTR2UV(rex),
+               PTR2UV(rex->offs)
+           );
+    );
+    for (p = parenfloor+1; p <= (I32)PL_regsize;  p++) {
 /* REGCP_PARENS_ELEMS are pushed per pairs of parentheses. */
        SSPUSHINT(rex->offs[p].end);
        SSPUSHINT(rex->offs[p].start);
-       SSPUSHPTR(PL_reg_start_tmp[p]);
-       SSPUSHINT(p);
+       SSPUSHINT(rex->offs[p].start_tmp);
        DEBUG_BUFFERS_r(PerlIO_printf(Perl_debug_log,
-         "     saving \\%"UVuf" %"IVdf"(%"IVdf")..%"IVdf"\n",
-                     (UV)p, (IV)rex->offs[p].start,
-                     (IV)(PL_reg_start_tmp[p] - PL_bostr),
-                     (IV)rex->offs[p].end
+           "    \\%"UVuf": %"IVdf"(%"IVdf")..%"IVdf"\n",
+           (UV)p,
+           (IV)rex->offs[p].start,
+           (IV)rex->offs[p].start_tmp,
+           (IV)rex->offs[p].end
        ));
     }
 /* REGCP_OTHER_ELEMS are pushed in any case, parentheses or no. */
     SSPUSHINT(PL_regsize);
     SSPUSHINT(rex->lastparen);
     SSPUSHINT(rex->lastcloseparen);
-    SSPUSHPTR(PL_reginput);
     SSPUSHUV(SAVEt_REGCONTEXT | elems_shifted); /* Magic cookie. */
 
     return retval;
@@ -401,12 +383,19 @@ S_regcppush(pTHX_ const regexp *rex, I32 parenfloor)
                (IV)(cp), (IV)PL_savestack_ix));                \
     regcpblow(cp)
 
-STATIC char *
+#define UNWIND_PAREN(lp, lcp)               \
+    for (n = rex->lastparen; n > lp; n--)   \
+        rex->offs[n].end = -1;              \
+    rex->lastparen = n;                     \
+    rex->lastcloseparen = lcp;
+
+
+STATIC void
 S_regcppop(pTHX_ regexp *rex)
 {
     dVAR;
     UV i;
-    char *input;
+    U32 paren;
     GET_RE_DEBUG_FLAGS_DECL;
 
     PERL_ARGS_ASSERT_REGCPPOP;
@@ -415,37 +404,38 @@ S_regcppop(pTHX_ regexp *rex)
     i = SSPOPUV;
     assert((i & SAVE_MASK) == SAVEt_REGCONTEXT); /* Check that the magic cookie is there. */
     i >>= SAVE_TIGHT_SHIFT; /* Parentheses elements to pop. */
-    input = (char *) SSPOPPTR;
     rex->lastcloseparen = SSPOPINT;
     rex->lastparen = SSPOPINT;
     PL_regsize = SSPOPINT;
 
     i -= REGCP_OTHER_ELEMS;
     /* Now restore the parentheses context. */
+    DEBUG_BUFFERS_r(
+       if (i || rex->lastparen + 1 <= rex->nparens)
+           PerlIO_printf(Perl_debug_log,
+               "rex=0x%"UVxf" offs=0x%"UVxf": restoring capture indices to:\n",
+               PTR2UV(rex),
+               PTR2UV(rex->offs)
+           );
+    );
+    paren = PL_regsize;
     for ( ; i > 0; i -= REGCP_PAREN_ELEMS) {
        I32 tmps;
-       U32 paren = (U32)SSPOPINT;
-       PL_reg_start_tmp[paren] = (char *) SSPOPPTR;
+       rex->offs[paren].start_tmp = SSPOPINT;
        rex->offs[paren].start = SSPOPINT;
        tmps = SSPOPINT;
        if (paren <= rex->lastparen)
            rex->offs[paren].end = tmps;
-       DEBUG_BUFFERS_r(
-           PerlIO_printf(Perl_debug_log,
-                         "     restoring \\%"UVuf" to %"IVdf"(%"IVdf")..%"IVdf"%s\n",
-                         (UV)paren, (IV)rex->offs[paren].start,
-                         (IV)(PL_reg_start_tmp[paren] - PL_bostr),
-                         (IV)rex->offs[paren].end,
-                         (paren > rex->lastparen ? "(no)" : ""));
+       DEBUG_BUFFERS_r( PerlIO_printf(Perl_debug_log,
+           "    \\%"UVuf": %"IVdf"(%"IVdf")..%"IVdf"%s\n",
+           (UV)paren,
+           (IV)rex->offs[paren].start,
+           (IV)rex->offs[paren].start_tmp,
+           (IV)rex->offs[paren].end,
+           (paren > rex->lastparen ? "(skipped)" : ""));
        );
+       paren--;
     }
-    DEBUG_BUFFERS_r(
-       if (rex->lastparen + 1 <= rex->nparens) {
-           PerlIO_printf(Perl_debug_log,
-                         "     restoring \\%"IVdf"..\\%"IVdf" to undef\n",
-                         (IV)(rex->lastparen + 1), (IV)rex->nparens);
-       }
-    );
 #if 1
     /* It would seem that the similar code in regtry()
      * already takes care of this, and in fact it is in
@@ -460,9 +450,25 @@ S_regcppop(pTHX_ regexp *rex)
        if (i > PL_regsize)
            rex->offs[i].start = -1;
        rex->offs[i].end = -1;
+       DEBUG_BUFFERS_r( PerlIO_printf(Perl_debug_log,
+           "    \\%"UVuf": %s   ..-1 undeffing\n",
+           (UV)i,
+           (i > PL_regsize) ? "-1" : "  "
+       ));
     }
 #endif
-    return input;
+}
+
+/* restore the parens and associated vars at savestack position ix,
+ * but without popping the stack */
+
+STATIC void
+S_regcp_restore(pTHX_ regexp *rex, I32 ix)
+{
+    I32 tmpix = PL_savestack_ix;
+    PL_savestack_ix = ix;
+    regcppop(rex);
+    PL_savestack_ix = tmpix;
 }
 
 #define regcpblow(cp) LEAVE_SCOPE(cp)  /* Ignores regcppush()ed data. */
@@ -478,10 +484,13 @@ S_regcppop(pTHX_ regexp *rex)
 I32
 Perl_pregexec(pTHX_ REGEXP * const prog, char* stringarg, register char *strend,
         char *strbeg, I32 minend, SV *screamer, U32 nosave)
-/* strend: pointer to null at end of string */
-/* strbeg: real beginning of string */
-/* minend: end of match must be >=minend after stringarg. */
-/* nosave: For optimizations. */
+/* stringarg: the point in the string at which to begin matching */
+/* strend:    pointer to null at end of string */
+/* strbeg:    real beginning of string */
+/* minend:    end of match must be >= minend bytes after stringarg. */
+/* screamer:  SV being matched: only used for utf8 flag, pos() etc; string
+ *            itself is accessed via the pointers above */
+/* nosave:    For optimizations. */
 {
     PERL_ARGS_ASSERT_PREGEXEC;
 
@@ -547,16 +556,16 @@ Perl_re_intuit_start(pTHX_ REGEXP * const rx, SV *sv, char *strpos,
 {
     dVAR;
     struct regexp *const prog = (struct regexp *)SvANY(rx);
-    register I32 start_shift = 0;
+    I32 start_shift = 0;
     /* Should be nonnegative! */
-    register I32 end_shift   = 0;
-    register char *s;
-    register SV *check;
+    I32 end_shift   = 0;
+    char *s;
+    SV *check;
     char *strbeg;
     char *t;
     const bool utf8_target = (sv && SvUTF8(sv)) ? 1 : 0; /* if no sv we have to assume bytes */
     I32 ml_anch;
-    register char *other_last = NULL;  /* other substr checked before this */
+    char *other_last = NULL;   /* other substr checked before this */
     char *check_at = NULL;             /* check substr found at this pos */
     char *checked_upto = NULL;          /* how far into the string we have already checked using find_byclass*/
     const I32 multiline = prog->extflags & RXf_PMf_MULTILINE;
@@ -1397,12 +1406,12 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s,
        const U8 *fold_array;   /* array for folding ords < 256 */
        STRLEN ln;
        STRLEN lnc;
-       register STRLEN uskip;
+       STRLEN uskip;
        U8 c1;
        U8 c2;
        char *e;
-       register I32 tmp = 1;   /* Scratch variable? */
-       register const bool utf8_target = PL_reg_match_utf8;
+       I32 tmp = 1;    /* Scratch variable? */
+       const bool utf8_target = PL_reg_match_utf8;
        UV utf8_fold_flags = 0;
         RXi_GET_DECL(prog,progi);
 
@@ -1782,6 +1791,20 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s,
                !is_HORIZWS_latin1(s)
            );      
            break;
+       case POSIXA:
+           /* Don't need to worry about utf8, as it can match only a single
+            * byte invariant character.  The flag in this node type is the
+            * class number to pass to _generic_isCC() to build a mask for
+            * searching in PL_charclass[] */
+           REXEC_FBC_CLASS_SCAN( _generic_isCC_A(*s, FLAGS(c)));
+           break;
+       case NPOSIXA:
+           REXEC_FBC_CSCAN(
+               !_generic_isCC_A(*s, FLAGS(c)),
+               !_generic_isCC_A(*s, FLAGS(c))
+           );
+           break;
+
        case AHOCORASICKC:
        case AHOCORASICK: 
            {
@@ -2013,18 +2036,22 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s,
 I32
 Perl_regexec_flags(pTHX_ REGEXP * const rx, char *stringarg, register char *strend,
              char *strbeg, I32 minend, SV *sv, void *data, U32 flags)
-/* strend: pointer to null at end of string */
-/* strbeg: real beginning of string */
-/* minend: end of match must be >=minend after stringarg. */
-/* data: May be used for some additional optimizations. 
-         Currently its only used, with a U32 cast, for transmitting 
-         the ganch offset when doing a /g match. This will change */
-/* nosave: For optimizations. */
+/* stringarg: the point in the string at which to begin matching */
+/* strend:    pointer to null at end of string */
+/* strbeg:    real beginning of string */
+/* minend:    end of match must be >= minend bytes after stringarg. */
+/* sv:        SV being matched: only used for utf8 flag, pos() etc; string
+ *            itself is accessed via the pointers above */
+/* data:      May be used for some additional optimizations.
+              Currently its only used, with a U32 cast, for transmitting
+              the ganch offset when doing a /g match. This will change */
+/* nosave:    For optimizations. */
+
 {
     dVAR;
     struct regexp *const prog = (struct regexp *)SvANY(rx);
     /*register*/ char *s;
-    register regnode *c;
+    regnode *c;
     /*register*/ char *startpos = stringarg;
     I32 minlen;                /* must match at least this many chars */
     I32 dontbother = 0;        /* how many characters not to try at end */
@@ -2137,6 +2164,12 @@ Perl_regexec_flags(pTHX_ REGEXP * const rx, char *stringarg, register char *stre
         swap = prog->offs;
         /* do we need a save destructor here for eval dies? */
         Newxz(prog->offs, (prog->nparens + 1), regexp_paren_pair);
+       DEBUG_BUFFERS_r(PerlIO_printf(Perl_debug_log,
+           "rex=0x%"UVxf" saving  offs: orig=0x%"UVxf" new=0x%"UVxf"\n",
+           PTR2UV(prog),
+           PTR2UV(swap),
+           PTR2UV(prog->offs)
+       ));
     }
     if (!(flags & REXEC_CHECKED) && (prog->check_substr != NULL || prog->check_utf8 != NULL)) {
        re_scream_pos_data d;
@@ -2497,6 +2530,14 @@ Perl_regexec_flags(pTHX_ REGEXP * const rx, char *stringarg, register char *stre
     goto phooey;
 
 got_it:
+    DEBUG_BUFFERS_r(
+       if (swap)
+           PerlIO_printf(Perl_debug_log,
+               "rex=0x%"UVxf" freeing offs: 0x%"UVxf"\n",
+               PTR2UV(prog),
+               PTR2UV(swap)
+           );
+    );
     Safefree(swap);
     RX_MATCH_TAINTED_set(rx, PL_reg_flags & RF_tainted);
 
@@ -2507,9 +2548,7 @@ got_it:
 
     /* make sure $`, $&, $', and $digit will work later */
     if ( !(flags & REXEC_NOT_FIRST) ) {
-       RX_MATCH_COPY_FREE(rx);
        if (flags & REXEC_COPY_STR) {
-           const I32 i = PL_regeol - startpos + (stringarg - strbeg);
 #ifdef PERL_OLD_COPY_ON_WRITE
            if ((SvIsCOW(sv)
                 || (SvFLAGS(sv) & CAN_COW_MASK) == CAN_COW_FLAGS)) {
@@ -2518,20 +2557,109 @@ got_it:
                                  "Copy on write: regexp capture, type %d\n",
                                  (int) SvTYPE(sv));
                }
+                RX_MATCH_COPY_FREE(rx);
                prog->saved_copy = sv_setsv_cow(prog->saved_copy, sv);
                prog->subbeg = (char *)SvPVX_const(prog->saved_copy);
                assert (SvPOKp(prog->saved_copy));
+                prog->sublen  = PL_regeol - strbeg;
+                prog->suboffset = 0;
+                prog->subcoffset = 0;
            } else
 #endif
            {
-               RX_MATCH_COPIED_on(rx);
-               s = savepvn(strbeg, i);
-               prog->subbeg = s;
-           }
-           prog->sublen = i;
+                I32 min = 0;
+                I32 max = PL_regeol - strbeg;
+                I32 sublen;
+
+                if (    (flags & REXEC_COPY_SKIP_POST)
+                    && !(RX_EXTFLAGS(rx) & RXf_PMf_KEEPCOPY) /* //p */
+                    && !(PL_sawampersand & SAWAMPERSAND_RIGHT)
+                ) { /* don't copy $' part of string */
+                    U32 n = 0;
+                    max = -1;
+                    /* calculate the right-most part of the string covered
+                     * by a capture. Due to look-ahead, this may be to
+                     * the right of $&, so we have to scan all captures */
+                    while (n <= prog->lastparen) {
+                        if (prog->offs[n].end > max)
+                            max = prog->offs[n].end;
+                        n++;
+                    }
+                    if (max == -1)
+                        max = (PL_sawampersand & SAWAMPERSAND_LEFT)
+                                ? prog->offs[0].start
+                                : 0;
+                    assert(max >= 0 && max <= PL_regeol - strbeg);
+                }
+
+                if (    (flags & REXEC_COPY_SKIP_PRE)
+                    && !(RX_EXTFLAGS(rx) & RXf_PMf_KEEPCOPY) /* //p */
+                    && !(PL_sawampersand & SAWAMPERSAND_LEFT)
+                ) { /* don't copy $` part of string */
+                    U32 n = 0;
+                    min = max;
+                    /* calculate the left-most part of the string covered
+                     * by a capture. Due to look-behind, this may be to
+                     * the left of $&, so we have to scan all captures */
+                    while (min && n <= prog->lastparen) {
+                        if (   prog->offs[n].start != -1
+                            && prog->offs[n].start < min)
+                        {
+                            min = prog->offs[n].start;
+                        }
+                        n++;
+                    }
+                    if ((PL_sawampersand & SAWAMPERSAND_RIGHT)
+                        && min >  prog->offs[0].end
+                    )
+                        min = prog->offs[0].end;
+
+                }
+
+                assert(min >= 0 && min <= max && min <= PL_regeol - strbeg);
+                sublen = max - min;
+
+                if (RX_MATCH_COPIED(rx)) {
+                    if (sublen > prog->sublen)
+                        prog->subbeg =
+                                (char*)saferealloc(prog->subbeg, sublen+1);
+                }
+                else
+                    prog->subbeg = (char*)safemalloc(sublen+1);
+                Copy(strbeg + min, prog->subbeg, sublen, char);
+                prog->subbeg[sublen] = '\0';
+                prog->suboffset = min;
+                prog->sublen = sublen;
+                RX_MATCH_COPIED_on(rx);
+           }
+            prog->subcoffset = prog->suboffset;
+            if (prog->suboffset && utf8_target) {
+                /* Convert byte offset to chars.
+                 * XXX ideally should only compute this if @-/@+
+                 * has been seen, a la PL_sawampersand ??? */
+
+                /* If there's a direct correspondence between the
+                 * string which we're matching and the original SV,
+                 * then we can use the utf8 len cache associated with
+                 * the SV. In particular, it means that under //g,
+                 * sv_pos_b2u() will use the previously cached
+                 * position to speed up working out the new length of
+                 * subcoffset, rather than counting from the start of
+                 * the string each time. This stops
+                 *   $x = "\x{100}" x 1E6; 1 while $x =~ /(.)/g;
+                 * from going quadratic */
+                if (SvPOKp(sv) && SvPVX(sv) == strbeg)
+                    sv_pos_b2u(sv, &(prog->subcoffset));
+                else
+                    prog->subcoffset = utf8_length((U8*)strbeg,
+                                        (U8*)(strbeg+prog->suboffset));
+            }
        }
        else {
+            RX_MATCH_COPY_FREE(rx);
            prog->subbeg = strbeg;
+           prog->suboffset = 0;
+           prog->subcoffset = 0;
            prog->sublen = PL_regeol - strbeg;  /* strend may have been modified */
        }
     }
@@ -2545,6 +2673,12 @@ phooey:
        restore_pos(aTHX_ prog);
     if (swap) {
         /* we failed :-( roll it back */
+       DEBUG_BUFFERS_r(PerlIO_printf(Perl_debug_log,
+           "rex=0x%"UVxf" rolling back offs: freeing=0x%"UVxf" restoring=0x%"UVxf"\n",
+           PTR2UV(prog),
+           PTR2UV(prog->offs),
+           PTR2UV(swap)
+       ));
         Safefree(prog->offs);
         prog->offs = swap;
     }
@@ -2553,16 +2687,27 @@ phooey:
 }
 
 
+/* Set which rex is pointed to by PL_reg_state, handling ref counting.
+ * Do inc before dec, in case old and new rex are the same */
+#define SET_reg_curpm(Re2) \
+    if (PL_reg_state.re_state_eval_setup_done) {    \
+       (void)ReREFCNT_inc(Re2);                    \
+       ReREFCNT_dec(PM_GETRE(PL_reg_curpm));       \
+       PM_SETRE((PL_reg_curpm), (Re2));            \
+    }
+
+
 /*
  - regtry - try match at specific point
  */
 STATIC I32                     /* 0 failure, 1 success */
-S_regtry(pTHX_ regmatch_info *reginfo, char **startpos)
+S_regtry(pTHX_ regmatch_info *reginfo, char **startposp)
 {
     dVAR;
     CHECKPOINT lastcp;
     REGEXP *const rx = reginfo->prog;
     regexp *const prog = (struct regexp *)SvANY(rx);
+    I32 result;
     RXi_GET_DECL(prog,progi);
     GET_RE_DEBUG_FLAGS_DECL;
 
@@ -2611,16 +2756,7 @@ S_regtry(pTHX_ regmatch_info *reginfo, char **startpos)
             }
 #endif      
         }
-#ifdef USE_ITHREADS
-       /* It seems that non-ithreads works both with and without this code.
-          So for efficiency reasons it seems best not to have the code
-          compiled when it is not needed.  */
-       /* This is safe against NULLs: */
-       ReREFCNT_dec(PM_GETRE(PL_reg_curpm));
-       /* PM_reg_curpm owns a reference to this regexp.  */
-       (void)ReREFCNT_inc(rx);
-#endif
-       PM_SETRE(PL_reg_curpm, rx);
+       SET_reg_curpm(rx);
        PL_reg_oldcurpm = PL_curpm;
        PL_curpm = PL_reg_curpm;
        if (RXp_MATCH_COPIED(prog)) {
@@ -2629,6 +2765,8 @@ S_regtry(pTHX_ regmatch_info *reginfo, char **startpos)
                $` inside (?{}) could fail... */
            PL_reg_oldsaved = prog->subbeg;
            PL_reg_oldsavedlen = prog->sublen;
+           PL_reg_oldsavedoffset = prog->suboffset;
+           PL_reg_oldsavedcoffset = prog->suboffset;
 #ifdef PERL_OLD_COPY_ON_WRITE
            PL_nrs = prog->saved_copy;
 #endif
@@ -2637,21 +2775,17 @@ S_regtry(pTHX_ regmatch_info *reginfo, char **startpos)
        else
            PL_reg_oldsaved = NULL;
        prog->subbeg = PL_bostr;
+       prog->suboffset = 0;
+       prog->subcoffset = 0;
        prog->sublen = PL_regeol - PL_bostr; /* strend may have been modified */
     }
-    DEBUG_EXECUTE_r(PL_reg_starttry = *startpos);
-    prog->offs[0].start = *startpos - PL_bostr;
-    PL_reginput = *startpos;
+#ifdef DEBUGGING
+    PL_reg_starttry = *startposp;
+#endif
+    prog->offs[0].start = *startposp - PL_bostr;
     prog->lastparen = 0;
     prog->lastcloseparen = 0;
     PL_regsize = 0;
-    if (PL_reg_start_tmpl <= prog->nparens) {
-       PL_reg_start_tmpl = prog->nparens*3/2 + 3;
-        if(PL_reg_start_tmp)
-            Renew(PL_reg_start_tmp, PL_reg_start_tmpl, char*);
-        else
-            Newx(PL_reg_start_tmp, PL_reg_start_tmpl, char*);
-    }
 
     /* XXXX What this code is doing here?!!!  There should be no need
        to do this again and again, prog->lastparen should take care of
@@ -2669,7 +2803,7 @@ S_regtry(pTHX_ regmatch_info *reginfo, char **startpos)
 #if 1
     if (prog->nparens) {
        regexp_paren_pair *pp = prog->offs;
-       register I32 i;
+       I32 i;
        for (i = prog->nparens; i > (I32)prog->lastparen; i--) {
            ++pp;
            pp->start = -1;
@@ -2678,12 +2812,13 @@ S_regtry(pTHX_ regmatch_info *reginfo, char **startpos)
     }
 #endif
     REGCP_SET(lastcp);
-    if (regmatch(reginfo, progi->program + 1)) {
-       prog->offs[0].end = PL_reginput - PL_bostr;
+    result = regmatch(reginfo, *startposp, progi->program + 1);
+    if (result != -1) {
+       prog->offs[0].end = result;
        return 1;
     }
     if (reginfo->cutpoint)
-        *startpos= reginfo->cutpoint;
+        *startposp= reginfo->cutpoint;
     REGCP_UNWIND(lastcp);
     return 0;
 }
@@ -2735,20 +2870,23 @@ S_push_slab(pTHX)
 
 /* push a new state then goto it */
 
-#define PUSH_STATE_GOTO(state, node) \
+#define PUSH_STATE_GOTO(state, node, input) \
+    pushinput = input; \
     scan = node; \
     st->resume_state = state; \
     goto push_state;
 
 /* push a new state with success backtracking, then goto it */
 
-#define PUSH_YES_STATE_GOTO(state, node) \
+#define PUSH_YES_STATE_GOTO(state, node, input) \
+    pushinput = input; \
     scan = node; \
     st->resume_state = state; \
     goto push_yes_state;
 
 
 
+
 /*
 
 regmatch() - main matching routine
@@ -2814,7 +2952,7 @@ implementation:
        // push a yes backtrack state with a resume value of
        // IFMATCH_A/IFMATCH_A_fail, then continue execution at the
        // first node of A:
-       PUSH_YES_STATE_GOTO(IFMATCH_A, A);
+       PUSH_YES_STATE_GOTO(IFMATCH_A, A, newinput);
        // NOTREACHED
 
     case IFMATCH_A: // we have successfully executed A; now continue with B
@@ -2851,8 +2989,8 @@ The topmost backtrack state, pointed to by st, is usually free. If you
 want to claim it, populate any ST.foo fields in it with values you wish to
 save, then do one of
 
-       PUSH_STATE_GOTO(resume_state, node);
-       PUSH_YES_STATE_GOTO(resume_state, node);
+       PUSH_STATE_GOTO(resume_state, node, newinput);
+       PUSH_YES_STATE_GOTO(resume_state, node, newinput);
 
 which sets that backtrack state's resume value to 'resume_state', pushes a
 new free entry to the top of the backtrack stack, then goes to 'node'.
@@ -3044,33 +3182,30 @@ S_clear_backtrack_stack(pTHX_ void *p)
 }
 
 
-#define SETREX(Re1,Re2) \
-    if (PL_reg_state.re_state_eval_setup_done) \
-       PM_SETRE((PL_reg_curpm), (Re2)); \
-    Re1 = (Re2)
-
-STATIC I32                     /* 0 failure, 1 success */
-S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
+/* returns -1 on failure, $+[0] on success */
+STATIC I32
+S_regmatch(pTHX_ regmatch_info *reginfo, char *startpos, regnode *prog)
 {
 #if PERL_VERSION < 9 && !defined(PERL_CORE)
     dMY_CXT;
 #endif
     dVAR;
-    register const bool utf8_target = PL_reg_match_utf8;
+    const bool utf8_target = PL_reg_match_utf8;
     const U32 uniflags = UTF8_ALLOW_DEFAULT;
     REGEXP *rex_sv = reginfo->prog;
     regexp *rex = (struct regexp *)SvANY(rex_sv);
     RXi_GET_DECL(rex,rexi);
     I32        oldsave;
     /* the current state. This is a cached copy of PL_regmatch_state */
-    register regmatch_state *st;
+    regmatch_state *st;
     /* cache heavy used fields of st in registers */
-    register regnode *scan;
-    register regnode *next;
-    register U32 n = 0;        /* general value; init to avoid compiler warning */
-    register I32 ln = 0; /* len or last;  init to avoid compiler warning */
-    register char *locinput = PL_reginput;
-    register I32 nextchr;   /* is always set to UCHARAT(locinput) */
+    regnode *scan;
+    regnode *next;
+    U32 n = 0; /* general value; init to avoid compiler warning */
+    I32 ln = 0; /* len or last;  init to avoid compiler warning */
+    char *locinput = startpos;
+    char *pushinput; /* where to continue after a PUSH */
+    I32 nextchr;   /* is always set to UCHARAT(locinput) */
 
     bool result = 0;       /* return value of S_regmatch */
     int depth = 0;         /* depth of backtrack stack */
@@ -3088,7 +3223,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
     U32 state_num;
     bool no_final = 0;      /* prevent failure from backtracking? */
     bool do_cutgroup = 0;   /* no_final only until next branch/trie entry */
-    char *startpoint = PL_reginput;
+    char *startpoint = locinput;
     SV *popmark = NULL;     /* are we looking for a mark? */
     SV *sv_commit = NULL;   /* last mark name seen in failure */
     SV *sv_yes_mark = NULL; /* last mark name we have seen 
@@ -3115,6 +3250,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
     I32 gimme = G_SCALAR;
     CV *caller_cv = NULL;      /* who called us */
     CV *last_pushed_cv = NULL; /* most recently called (?{}) CV */
+    CHECKPOINT runops_cp;      /* savestack position before executing EVAL */
 
 #ifdef DEBUGGING
     GET_RE_DEBUG_FLAGS_DECL;
@@ -3124,6 +3260,8 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
     multicall_oldcatch = 0;
     multicall_cv = NULL;
     cx = NULL;
+    PERL_UNUSED_VAR(multicall_cop);
+    PERL_UNUSED_VAR(newsp);
 
 
     PERL_ARGS_ASSERT_REGMATCH;
@@ -3175,6 +3313,9 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
 
       reenter_switch:
 
+        nextchr = UCHARAT(locinput);
+        assert(nextchr >= 0);
+
        switch (state_num) {
        case BOL:
            if (locinput == PL_bostr)
@@ -3202,9 +3343,8 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
        case KEEPS:
            /* update the startpoint */
            st->u.keeper.val = rex->offs[0].start;
-           PL_reginput = locinput;
            rex->offs[0].start = locinput - PL_bostr;
-           PUSH_STATE_GOTO(KEEPS_next, next);
+           PUSH_STATE_GOTO(KEEPS_next, next, locinput);
            /*NOT-REACHED*/
        case KEEPS_next_fail:
            /* rollback the start point change */
@@ -3231,32 +3371,17 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
        case SANY:
            if (!nextchr && locinput >= PL_regeol)
                sayNO;
-           if (utf8_target) {
-               locinput += PL_utf8skip[nextchr];
-               if (locinput > PL_regeol)
-                   sayNO;
-               nextchr = UCHARAT(locinput);
-           }
-           else
-               nextchr = UCHARAT(++locinput);
-           break;
+            goto increment_locinput;
        case CANY:
            if (!nextchr && locinput >= PL_regeol)
                sayNO;
-           nextchr = UCHARAT(++locinput);
+           locinput++;
            break;
        case REG_ANY:
            if ((!nextchr && locinput >= PL_regeol) || nextchr == '\n')
                sayNO;
-           if (utf8_target) {
-               locinput += PL_utf8skip[nextchr];
-               if (locinput > PL_regeol)
-                   sayNO;
-               nextchr = UCHARAT(locinput);
-           }
-           else
-               nextchr = UCHARAT(++locinput);
-           break;
+            goto increment_locinput;
+
 
 #undef  ST
 #define ST st->u.trie
@@ -3264,14 +3389,14 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
             /* In this case the charclass data is available inline so
                we can fail fast without a lot of extra overhead. 
              */
-            if(!ANYOF_BITMAP_TEST(scan, *locinput)) {
+            if(!ANYOF_BITMAP_TEST(scan, nextchr)) {
                 DEBUG_EXECUTE_r(
                     PerlIO_printf(Perl_debug_log,
                               "%*s  %sfailed to match trie start class...%s\n",
                               REPORT_CODE_OFF+depth*2, "", PL_colors[4], PL_colors[5])
                 );
                 sayNO_SILENT;
-                /* NOTREACHED */
+                assert(0); /* NOTREACHED */
             }
             /* FALL THROUGH */
        case TRIE:
@@ -3329,7 +3454,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                HV * widecharmap = MUTABLE_HV(rexi->data->data[ ARG( scan ) + 1 ]);
                 U32 state = trie->startstate;
 
-                if (trie->bitmap && !TRIE_BITMAP_TEST(trie,*locinput) ) {
+                if (trie->bitmap && !TRIE_BITMAP_TEST(trie, nextchr) ) {
                    if (trie->states[ state ].wordnum) {
                         DEBUG_EXECUTE_r(
                             PerlIO_printf(Perl_debug_log,
@@ -3358,7 +3483,6 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                U32 charcount = 0; /* how many input chars we have matched */
                U32 accepted = 0; /* have we seen any accepting states? */
 
-               ST.B = next;
                ST.jump = trie->jump;
                ST.me = scan;
                ST.firstpos = NULL;
@@ -3457,14 +3581,14 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                );
                goto trie_first_try; /* jump into the fail handler */
            }}
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
 
        case TRIE_next_fail: /* we failed - try next alternative */
+        {
+            U8 *uc;
             if ( ST.jump) {
                 REGCP_UNWIND(ST.cp);
-               for (n = rex->lastparen; n > ST.lastparen; n--)
-                   rex->offs[n].end = -1;
-               rex->lastparen = n;
+                UNWIND_PAREN(ST.lastparen, ST.lastcloseparen);
            }
            if (!--ST.accepted) {
                DEBUG_EXECUTE_r({
@@ -3479,10 +3603,10 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
            {
                /* Find next-highest word to process.  Note that this code
                 * is O(N^2) per trie run (O(N) per branch), so keep tight */
-               register U16 min = 0;
-               register U16 word;
-               register U16 const nextword = ST.nextword;
-               register reg_trie_wordinfo * const wordinfo
+               U16 min = 0;
+               U16 word;
+               U16 const nextword = ST.nextword;
+               reg_trie_wordinfo * const wordinfo
                    = ((reg_trie_data*)rexi->data->data[ARG(ST.me)])->wordinfo;
                for (word=ST.topword; word; word=wordinfo[word].prev) {
                    if (word > nextword && (!min || word < min))
@@ -3499,13 +3623,13 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
 
             if ( ST.jump) {
                 ST.lastparen = rex->lastparen;
+                ST.lastcloseparen = rex->lastcloseparen;
                REGCP_SET(ST.cp);
             }
 
            /* find start char of end of current word */
            {
                U32 chars; /* how many chars to skip */
-               U8 *uc = ST.firstpos;
                reg_trie_data * const trie
                    = (reg_trie_data*)rexi->data->data[ARG(ST.me)];
 
@@ -3513,6 +3637,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                            >=  ST.firstchars);
                chars = (trie->wordinfo[ST.nextword].len - trie->prefixlen)
                            - ST.firstchars;
+               uc = ST.firstpos;
 
                if (ST.longfold) {
                    /* the hard option - fold each char in turn and find
@@ -3552,12 +3677,11 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                    else
                        uc += chars;
                }
-               PL_reginput = (char *)uc;
            }
 
-           scan = (ST.jump && ST.jump[ST.nextword]) 
-                       ? ST.me + ST.jump[ST.nextword]
-                       : ST.B;
+           scan = ST.me + ((ST.jump && ST.jump[ST.nextword])
+                           ? ST.jump[ST.nextword]
+                           : NEXT_OFF(ST.me));
 
            DEBUG_EXECUTE_r({
                PerlIO_printf( Perl_debug_log,
@@ -3570,8 +3694,8 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
            });
 
            if (ST.accepted > 1 || has_cutgroup) {
-               PUSH_STATE_GOTO(TRIE_next, scan);
-               /* NOTREACHED */
+               PUSH_STATE_GOTO(TRIE_next, scan, (char*)uc);
+               assert(0); /* NOTREACHED */
            }
            /* only one choice left - just continue */
            DEBUG_EXECUTE_r({
@@ -3593,10 +3717,10 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                    PL_colors[5] );
            });
 
-           locinput = PL_reginput;
-           nextchr = UCHARAT(locinput);
+           locinput = (char*)uc;
            continue; /* execute rest of RE */
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
+        }
 #undef  ST
 
        case EXACT: {
@@ -3608,35 +3732,59 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                const char * const e = s + ln;
 
                if (utf8_target) {
-                   /* The target is utf8, the pattern is not utf8. */
+                    /* The target is utf8, the pattern is not utf8.
+                     * Above-Latin1 code points can't match the pattern;
+                     * invariants match exactly, and the other Latin1 ones need
+                     * to be downgraded to a single byte in order to do the
+                     * comparison.  (If we could be confident that the target
+                     * is not malformed, this could be refactored to have fewer
+                     * tests by just assuming that if the first bytes match, it
+                     * is an invariant, but there are tests in the test suite
+                     * dealing with (??{...}) which violate this) */
                    while (s < e) {
-                       STRLEN ulen;
                        if (l >= PL_regeol)
                             sayNO;
-                       if (NATIVE_TO_UNI(*(U8*)s) !=
-                           utf8n_to_uvuni((U8*)l, UTF8_MAXBYTES, &ulen,
-                                           uniflags))
-                            sayNO;
-                       l += ulen;
-                       s ++;
+                        if (UTF8_IS_ABOVE_LATIN1(* (U8*) l)) {
+                            sayNO;
+                        }
+                        if (UTF8_IS_INVARIANT(*(U8*)l)) {
+                           if (*l != *s) {
+                                sayNO;
+                            }
+                            l++;
+                        }
+                        else {
+                            if (TWO_BYTE_UTF8_TO_UNI(*l, *(l+1)) != * (U8*) s) {
+                                sayNO;
+                            }
+                            l += 2;
+                        }
+                       s++;
                    }
                }
                else {
                    /* The target is not utf8, the pattern is utf8. */
                    while (s < e) {
-                       STRLEN ulen;
-                       if (l >= PL_regeol)
-                           sayNO;
-                       if (NATIVE_TO_UNI(*((U8*)l)) !=
-                           utf8n_to_uvuni((U8*)s, UTF8_MAXBYTES, &ulen,
-                                          uniflags))
-                           sayNO;
-                       s += ulen;
-                       l ++;
+                        if (l >= PL_regeol || UTF8_IS_ABOVE_LATIN1(* (U8*) s))
+                        {
+                            sayNO;
+                        }
+                        if (UTF8_IS_INVARIANT(*(U8*)s)) {
+                           if (*s != *l) {
+                                sayNO;
+                            }
+                            s++;
+                        }
+                        else {
+                            if (TWO_BYTE_UTF8_TO_UNI(*s, *(s+1)) != * (U8*) l) {
+                                sayNO;
+                            }
+                            s += 2;
+                        }
+                       l++;
                    }
                }
                locinput = l;
-               nextchr = UCHARAT(locinput);
                break;
            }
            /* The target and the pattern have the same utf8ness. */
@@ -3648,7 +3796,6 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
            if (ln > 1 && memNE(s, locinput, ln))
                sayNO;
            locinput += ln;
-           nextchr = UCHARAT(locinput);
            break;
            }
        case EXACTFL: {
@@ -3698,7 +3845,6 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                    sayNO;
                }
                locinput = e;
-               nextchr = UCHARAT(locinput);
                break;
            }
 
@@ -3713,7 +3859,6 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
            if (ln > 1 && ! folder(s, locinput, ln))
                sayNO;
            locinput += ln;
-           nextchr = UCHARAT(locinput);
            break;
        }
 
@@ -3805,17 +3950,14 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                if (!reginclass(rex, scan, (U8*)locinput, &inclasslen, utf8_target))
                    sayNO;
                locinput += inclasslen;
-               nextchr = UCHARAT(locinput);
                break;
            }
            else {
-               if (nextchr < 0)
-                   nextchr = UCHARAT(locinput);
                if (!nextchr && locinput >= PL_regeol)
                    sayNO;
                if (!REGINCLASS(rex, scan, (U8*)locinput))
                    sayNO;
-               nextchr = UCHARAT(++locinput);
+               locinput++;
                break;
            }
            break;
@@ -3837,6 +3979,19 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                DIGITA, NDIGITA, isDIGIT_A,
                digit, "0");
 
+        case POSIXA:
+            if (locinput >= PL_regeol || ! _generic_isCC_A(nextchr, FLAGS(scan))) {
+                sayNO;
+            }
+            /* Matched a utf8-invariant, so don't have to worry about utf8 */
+            locinput++;
+            break;
+        case NPOSIXA:
+            if (locinput >= PL_regeol || _generic_isCC_A(nextchr, FLAGS(scan))) {
+                sayNO;
+            }
+            goto increment_locinput;
+
        case CLUMP: /* Match \X: logical Unicode character.  This is defined as
                       a Unicode extended Grapheme Cluster */
            /* From http://www.unicode.org/reports/tr29 (5.2 version).  An
@@ -3846,43 +4001,20 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
               | Prepend* Begin Extend*
               | .
 
-              Begin is (Hangul-syllable | ! Control)
-              Extend is (Grapheme_Extend | Spacing_Mark)
-              Control is [ GCB_Control CR LF ]
-
-              The discussion below shows how the code for CLUMP is derived
-              from this regex.  Note that most of these concepts are from
-              property values of the Grapheme Cluster Boundary (GCB) property.
-              No code point can have multiple property values for a given
-              property.  Thus a code point in Prepend can't be in Control, but
-              it must be in !Control.  This is why Control above includes
-              GCB_Control plus CR plus LF.  The latter two are used in the GCB
-              property separately, and so can't be in GCB_Control, even though
-              they logically are controls.  Control is not the same as gc=cc,
-              but includes format and other characters as well.
-
-              The Unicode definition of Hangul-syllable is:
-                  L+
-                  | (L* ( ( V | LV ) V* | LVT ) T*)
-                  | T+ 
-                 )
-              Each of these is a value for the GCB property, and hence must be
-              disjoint, so the order they are tested is immaterial, so the
-              above can safely be changed to
-                  T+
-                  | L+
-                  | (L* ( LVT | ( V | LV ) V*) T*)
-
-              The last two terms can be combined like this:
-                  L* ( L
-                       | (( LVT | ( V | LV ) V*) T*))
-
-              And refactored into this:
-                  L* (L | LVT T* | V  V* T* | LV  V* T*)
-
-              That means that if we have seen any L's at all we can quit
-              there, but if the next character is an LVT, a V, or an LV we
-              should keep going.
+               Begin is:           ( Special_Begin | ! Control )
+               Special_Begin is:   ( Regional-Indicator+ | Hangul-syllable )
+               Extend is:          ( Grapheme_Extend | Spacing_Mark )
+               Control is:         [ GCB_Control  CR  LF ]
+               Hangul-syllable is: ( T+ | ( L* ( L | ( LVT | ( V | LV ) V* ) T* ) ))
+
+               If we create a 'Regular_Begin' = Begin - Special_Begin, then
+               we can rewrite
+
+                   Begin is ( Regular_Begin + Special Begin )
+
+               It turns out that 98.4% of all Unicode code points match
+               Regular_Begin.  Doing it this way eliminates a table match in
+               the previous implementation for almost all Unicode code points.
 
               There is a subtlety with Prepend* which showed up in testing.
               Note that the Begin, and only the Begin is required in:
@@ -3914,6 +4046,8 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                    locinput += 2;
                }
                else {
+                    STRLEN len;
+
                    /* In case have to backtrack to beginning, then match '.' */
                    char *starting = locinput;
 
@@ -3922,22 +4056,23 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
 
                    LOAD_UTF8_CHARCLASS_GCB();
 
-                   /* Match (prepend)* */
-                   while (locinput < PL_regeol
-                          && swash_fetch(PL_utf8_X_prepend,
-                                         (U8*)locinput, utf8_target))
-                   {
-                       previous_prepend = locinput;
-                       locinput += UTF8SKIP(locinput);
-                   }
+                    /* Match (prepend)*   */
+                    while (locinput < PL_regeol
+                           && (len = is_GCB_Prepend_utf8(locinput)))
+                    {
+                        previous_prepend = locinput;
+                        locinput += len;
+                    }
 
                    /* As noted above, if we matched a prepend character, but
                     * the next thing won't match, back off the last prepend we
                     * matched, as it is guaranteed to match the begin */
                    if (previous_prepend
                        && (locinput >=  PL_regeol
-                           || ! swash_fetch(PL_utf8_X_begin,
-                                            (U8*)locinput, utf8_target)))
+                           || (! swash_fetch(PL_utf8_X_regular_begin,
+                                            (U8*)locinput, utf8_target)
+                                && ! is_GCB_SPECIAL_BEGIN_utf8(locinput)))
+                        )
                    {
                        locinput = previous_prepend;
                    }
@@ -3947,108 +4082,99 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                     * moved locinput forward, we tested the result just above
                     * and it either passed, or we backed off so that it will
                     * now pass */
-                   if (! swash_fetch(PL_utf8_X_begin, (U8*)locinput, utf8_target)) {
+                   if (swash_fetch(PL_utf8_X_regular_begin,
+                                    (U8*)locinput, utf8_target)) {
+                        locinput += UTF8SKIP(locinput);
+                    }
+                    else if (! is_GCB_SPECIAL_BEGIN_utf8(locinput)) {
 
                        /* Here did not match the required 'Begin' in the
                         * second term.  So just match the very first
                         * character, the '.' of the final term of the regex */
                        locinput = starting + UTF8SKIP(starting);
+                        goto exit_utf8;
                    } else {
 
-                       /* Here is the beginning of a character that can have
-                        * an extender.  It is either a hangul syllable, or a
-                        * non-control */
-                       if (swash_fetch(PL_utf8_X_non_hangul,
-                                       (U8*)locinput, utf8_target))
-                       {
-
-                           /* Here not a Hangul syllable, must be a
-                            * ('!  * Control') */
-                           locinput += UTF8SKIP(locinput);
-                       } else {
-
-                           /* Here is a Hangul syllable.  It can be composed
-                            * of several individual characters.  One
-                            * possibility is T+ */
-                           if (swash_fetch(PL_utf8_X_T,
-                                           (U8*)locinput, utf8_target))
-                           {
-                               while (locinput < PL_regeol
-                                       && swash_fetch(PL_utf8_X_T,
-                                                       (U8*)locinput, utf8_target))
-                               {
-                                   locinput += UTF8SKIP(locinput);
-                               }
-                           } else {
-
-                               /* Here, not T+, but is a Hangul.  That means
-                                * it is one of the others: L, LV, LVT or V,
-                                * and matches:
-                                * L* (L | LVT T* | V  V* T* | LV  V* T*) */
-
-                               /* Match L*           */
-                               while (locinput < PL_regeol
-                                       && swash_fetch(PL_utf8_X_L,
-                                                       (U8*)locinput, utf8_target))
-                               {
-                                   locinput += UTF8SKIP(locinput);
-                               }
+                        /* Here is a special begin.  It can be composed of
+                         * several individual characters.  One possibility is
+                         * RI+ */
+                        if ((len = is_GCB_RI_utf8(locinput))) {
+                            locinput += len;
+                            while (locinput < PL_regeol
+                                   && (len = is_GCB_RI_utf8(locinput)))
+                            {
+                                locinput += len;
+                            }
+                        } else if ((len = is_GCB_T_utf8(locinput))) {
+                            /* Another possibility is T+ */
+                            locinput += len;
+                            while (locinput < PL_regeol
+                                && (len = is_GCB_T_utf8(locinput)))
+                            {
+                                locinput += len;
+                            }
+                        } else {
+
+                            /* Here, neither RI+ nor T+; must be some other
+                             * Hangul.  That means it is one of the others: L,
+                             * LV, LVT or V, and matches:
+                             * L* (L | LVT T* | V * V* T* | LV  V* T*) */
+
+                            /* Match L*           */
+                            while (locinput < PL_regeol
+                                   && (len = is_GCB_L_utf8(locinput)))
+                            {
+                                locinput += len;
+                            }
 
-                               /* Here, have exhausted L*.  If the next
-                                * character is not an LV, LVT nor V, it means
-                                * we had to have at least one L, so matches L+
-                                * in the original equation, we have a complete
-                                * hangul syllable.  Are done. */
-
-                               if (locinput < PL_regeol
-                                   && swash_fetch(PL_utf8_X_LV_LVT_V,
-                                                   (U8*)locinput, utf8_target))
-                               {
-
-                                   /* Otherwise keep going.  Must be LV, LVT
-                                    * or V.  See if LVT */
-                                   if (swash_fetch(PL_utf8_X_LVT,
-                                                   (U8*)locinput, utf8_target))
-                                   {
-                                       locinput += UTF8SKIP(locinput);
-                                   } else {
-
-                                       /* Must be  V or LV.  Take it, then
-                                        * match V*     */
-                                       locinput += UTF8SKIP(locinput);
-                                       while (locinput < PL_regeol
-                                               && swash_fetch(PL_utf8_X_V,
-                                                        (U8*)locinput, utf8_target))
-                                       {
-                                           locinput += UTF8SKIP(locinput);
-                                       }
-                                   }
+                            /* Here, have exhausted L*.  If the next character
+                             * is not an LV, LVT nor V, it means we had to have
+                             * at least one L, so matches L+ in the original
+                             * equation, we have a complete hangul syllable.
+                             * Are done. */
+
+                            if (locinput < PL_regeol
+                                && is_GCB_LV_LVT_V_utf8(locinput))
+                            {
+
+                                /* Otherwise keep going.  Must be LV, LVT or V.
+                                 * See if LVT */
+                                if (is_utf8_X_LVT((U8*)locinput)) {
+                                    locinput += UTF8SKIP(locinput);
+                                } else {
+
+                                    /* Must be  V or LV.  Take it, then match
+                                     * V*     */
+                                    locinput += UTF8SKIP(locinput);
+                                    while (locinput < PL_regeol
+                                           && (len = is_GCB_V_utf8(locinput)))
+                                    {
+                                        locinput += len;
+                                    }
+                                }
 
-                                   /* And any of LV, LVT, or V can be followed
-                                    * by T*            */
-                                   while (locinput < PL_regeol
-                                          && swash_fetch(PL_utf8_X_T,
-                                                          (U8*)locinput,
-                                                          utf8_target))
-                                   {
-                                       locinput += UTF8SKIP(locinput);
-                                   }
-                               }
-                           }
-                       }
+                                /* And any of LV, LVT, or V can be followed
+                                 * by T*            */
+                                while (locinput < PL_regeol
+                                       && (len = is_GCB_T_utf8(locinput)))
+                                {
+                                    locinput += len;
+                                }
+                            }
+                        }
+                    }
 
-                       /* Match any extender */
-                       while (locinput < PL_regeol
-                               && swash_fetch(PL_utf8_X_extend,
-                                               (U8*)locinput, utf8_target))
-                       {
-                           locinput += UTF8SKIP(locinput);
-                       }
-                   }
+                    /* Match any extender */
+                    while (locinput < PL_regeol
+                            && swash_fetch(PL_utf8_X_extend,
+                                            (U8*)locinput, utf8_target))
+                    {
+                        locinput += UTF8SKIP(locinput);
+                    }
                }
+            exit_utf8:
                if (locinput > PL_regeol) sayNO;
            }
-           nextchr = UCHARAT(locinput);
            break;
             
        case NREFFL:
@@ -4167,7 +4293,6 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                    sayNO;
                }
                locinput = limit;
-               nextchr = UCHARAT(locinput);
                break;
            }
 
@@ -4184,7 +4309,6 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                           : ! folder(s, locinput, ln)))
                sayNO;
            locinput += ln;
-           nextchr = UCHARAT(locinput);
            break;
        }
        case NOTHING:
@@ -4217,7 +4341,6 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
            re_sv = rex_sv;
             re = rex;
             rei = rexi;
-            (void)ReREFCNT_inc(rex_sv);
             if (OP(scan)==GOSUB) {
                 startpoint = scan + ARG2L(scan);
                 ST.close_paren = ARG(scan);
@@ -4226,7 +4349,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                 ST.close_paren = 0;
             }
             goto eval_recurse_doit;
-            /* NOTREACHED */
+            assert(0); /* NOTREACHED */
         case EVAL:  /*   /(?{A})B/   /(??{A})B/  and /(?(?{A})X|Y)B/   */        
             if (cur_eval && cur_eval->locinput==locinput) {
                if ( ++nochange_depth > max_nochange_depth )
@@ -4246,6 +4369,10 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                struct re_save_state saved_state;
                CV *newcv;
 
+               /* save *all* paren positions */
+               regcppush(rex, 0);
+               REGCP_SET(runops_cp);
+
                /* To not corrupt the existing regex state while executing the
                 * eval we would normally put it on the save stack, like with
                 * save_re_context. However, re-evals have a weird scoping so we
@@ -4288,6 +4415,26 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                    nop = (OP*)rexi->data->data[n];
                }
 
+               /* normally if we're about to execute code from the same
+                * CV that we used previously, we just use the existing
+                * CX stack entry. However, its possible that in the
+                * meantime we may have backtracked, popped from the save
+                * stack, and undone the SAVECOMPPAD(s) associated with
+                * PUSH_MULTICALL; in which case PL_comppad no longer
+                * points to newcv's pad. */
+               if (newcv != last_pushed_cv || PL_comppad != last_pad)
+               {
+                   I32 depth = (newcv == caller_cv) ? 0 : 1;
+                   if (last_pushed_cv) {
+                       CHANGE_MULTICALL_WITHDEPTH(newcv, depth);
+                   }
+                   else {
+                       PUSH_MULTICALL_WITHDEPTH(newcv, depth);
+                   }
+                   last_pushed_cv = newcv;
+               }
+               last_pad = PL_comppad;
+
                /* the initial nextstate you would normally execute
                 * at the start of an eval (which would cause error
                 * messages to come from the eval), may be optimised
@@ -4323,26 +4470,6 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                DEBUG_STATE_r( PerlIO_printf(Perl_debug_log, 
                    "  re EVAL PL_op=0x%"UVxf"\n", PTR2UV(nop)) );
 
-               /* normally if we're about to execute code from the same
-                * CV that we used previously, we just use the existing
-                * CX stack entry. However, its possible that in the
-                * meantime we may have backtracked, popped from the save
-                * stack, and undone the SAVECOMPPAD(s) associated with
-                * PUSH_MULTICALL; in which case PL_comppad no longer
-                * points to newcv's pad. */
-               if (newcv != last_pushed_cv || PL_comppad != last_pad)
-               {
-                   I32 depth = (newcv == caller_cv) ? 0 : 1;
-                   if (last_pushed_cv) {
-                       CHANGE_MULTICALL_WITHDEPTH(newcv, depth);
-                   }
-                   else {
-                       PUSH_MULTICALL_WITHDEPTH(newcv, depth);
-                   }
-                   last_pushed_cv = newcv;
-               }
-               last_pad = PL_comppad;
-
                rex->offs[0].end = PL_reg_magic->mg_len = locinput - PL_bostr;
 
                 if (sv_yes_mark) {
@@ -4364,6 +4491,44 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                    PUTBACK;
                }
 
+               /* before restoring everything, evaluate the returned
+                * value, so that 'uninit' warnings don't use the wrong
+                * PL_op or pad. Also need to process any magic vars
+                * (e.g. $1) *before* parentheses are restored */
+
+               PL_op = NULL;
+
+                re_sv = NULL;
+               if (logical == 0)        /*   (?{})/   */
+                   sv_setsv(save_scalar(PL_replgv), ret); /* $^R */
+               else if (logical == 1) { /*   /(?(?{...})X|Y)/    */
+                   sw = cBOOL(SvTRUE(ret));
+                   logical = 0;
+               }
+               else {                   /*  /(??{})  */
+                   /*  if its overloaded, let the regex compiler handle
+                    *  it; otherwise extract regex, or stringify  */
+                   if (!SvAMAGIC(ret)) {
+                       SV *sv = ret;
+                       if (SvROK(sv))
+                           sv = SvRV(sv);
+                       if (SvTYPE(sv) == SVt_REGEXP)
+                           re_sv = (REGEXP*) sv;
+                       else if (SvSMAGICAL(sv)) {
+                           MAGIC *mg = mg_find(sv, PERL_MAGIC_qr);
+                           if (mg)
+                               re_sv = (REGEXP *) mg->mg_obj;
+                       }
+
+                       /* force any magic, undef warnings here */
+                       if (!re_sv) {
+                           ret = sv_mortalcopy(ret);
+                           (void) SvPV_force_nolen(ret);
+                       }
+                   }
+
+               }
+
                Copy(&saved_state, &PL_reg_state, 1, struct re_save_state);
 
                /* *** Note that at this point we don't restore
@@ -4373,88 +4538,66 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                PL_op = oop;
                PL_curcop = ocurcop;
                PL_regeol = saved_regeol;
-               if (!logical) {
-                   /* /(?{...})/ */
-                   sv_setsv(save_scalar(PL_replgv), ret);
+               S_regcp_restore(aTHX_ rex, runops_cp);
+
+               if (logical != 2)
                    break;
-               }
            }
-           if (logical == 2) { /* Postponed subexpression: /(??{...})/ */
+
+               /* only /(??{})/  from now on */
                logical = 0;
                {
                    /* extract RE object from returned value; compiling if
                     * necessary */
-                   MAGIC *mg = NULL;
-                   REGEXP *rx = NULL;
-
-                   if (SvROK(ret)) {
-                       SV *const sv = SvRV(ret);
-
-                       if (SvTYPE(sv) == SVt_REGEXP) {
-                           rx = (REGEXP*) sv;
-                       } else if (SvSMAGICAL(sv)) {
-                           mg = mg_find(sv, PERL_MAGIC_qr);
-                           assert(mg);
-                       }
-                   } else if (SvTYPE(ret) == SVt_REGEXP) {
-                       rx = (REGEXP*) ret;
-                   } else if (SvSMAGICAL(ret)) {
-                       if (SvGMAGICAL(ret)) {
-                           /* I don't believe that there is ever qr magic
-                              here.  */
-                           assert(!mg_find(ret, PERL_MAGIC_qr));
-                           sv_unmagic(ret, PERL_MAGIC_qr);
-                       }
-                       else {
-                           mg = mg_find(ret, PERL_MAGIC_qr);
-                           /* testing suggests mg only ends up non-NULL for
-                              scalars who were upgraded and compiled in the
-                              else block below. In turn, this is only
-                              triggered in the "postponed utf8 string" tests
-                              in t/op/pat.t  */
-                       }
-                   }
 
-                   if (mg) {
-                       rx = (REGEXP *) mg->mg_obj; /*XXX:dmq*/
-                       assert(rx);
-                   }
-                   if (rx) {
-                       rx = reg_temp_copy(NULL, rx);
+                   if (re_sv) {
+                       re_sv = reg_temp_copy(NULL, re_sv);
                    }
                    else {
                        U32 pm_flags = 0;
                        const I32 osize = PL_regsize;
 
-                       if (DO_UTF8(ret)) {
-                           assert (SvUTF8(ret));
-                       } else if (SvUTF8(ret)) {
-                           /* Not doing UTF-8, despite what the SV says. Is
-                              this only if we're trapped in use 'bytes'?  */
-                           /* Make a copy of the octet sequence, but without
-                              the flag on, as the compiler now honours the
-                              SvUTF8 flag on ret.  */
+                       if (SvUTF8(ret) && IN_BYTES) {
+                           /* In use 'bytes': make a copy of the octet
+                            * sequence, but without the flag on */
                            STRLEN len;
                            const char *const p = SvPV(ret, len);
                            ret = newSVpvn_flags(p, len, SVs_TEMP);
                        }
-                       rx = CALLREGCOMP(ret, pm_flags);
+                       if (rex->intflags & PREGf_USE_RE_EVAL)
+                           pm_flags |= PMf_USE_RE_EVAL;
+
+                       /* if we got here, it should be an engine which
+                        * supports compiling code blocks and stuff */
+                       assert(rex->engine && rex->engine->op_comp);
+                        assert(!(scan->flags & ~RXf_PMf_COMPILETIME));
+                       re_sv = rex->engine->op_comp(aTHX_ &ret, 1, NULL,
+                                   rex->engine, NULL, NULL,
+                                    /* copy /msix etc to inner pattern */
+                                    scan->flags,
+                                    pm_flags);
+
                        if (!(SvFLAGS(ret)
                              & (SVs_TEMP | SVs_PADTMP | SVf_READONLY
                                 | SVs_GMG))) {
                            /* This isn't a first class regexp. Instead, it's
                               caching a regexp onto an existing, Perl visible
                               scalar.  */
-                           sv_magic(ret, MUTABLE_SV(rx), PERL_MAGIC_qr, 0, 0);
+                           sv_magic(ret, MUTABLE_SV(re_sv), PERL_MAGIC_qr, 0, 0);
                        }
                        PL_regsize = osize;
+                       /* safe to do now that any $1 etc has been
+                        * interpolated into the new pattern string and
+                        * compiled */
+                       S_regcp_restore(aTHX_ rex, runops_cp);
                    }
-                   re_sv = rx;
-                   re = (struct regexp *)SvANY(rx);
+                   re = (struct regexp *)SvANY(re_sv);
                }
                 RXp_MATCH_COPIED_off(re);
                 re->subbeg = rex->subbeg;
                 re->sublen = rex->sublen;
+                re->suboffset = rex->suboffset;
+                re->subcoffset = rex->subcoffset;
                rei = RXi_GET(re);
                 DEBUG_EXECUTE_r(
                     debug_start_match(re_sv, utf8_target, locinput, PL_regeol,
@@ -4462,25 +4605,15 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                );              
                startpoint = rei->program + 1;
                        ST.close_paren = 0; /* only used for GOSUB */
-                       /* borrowed from regtry */
-                if (PL_reg_start_tmpl <= re->nparens) {
-                    PL_reg_start_tmpl = re->nparens*3/2 + 3;
-                    if(PL_reg_start_tmp)
-                        Renew(PL_reg_start_tmp, PL_reg_start_tmpl, char*);
-                    else
-                        Newx(PL_reg_start_tmp, PL_reg_start_tmpl, char*);
-                }                      
 
         eval_recurse_doit: /* Share code with GOSUB below this line */                         
                /* run the pattern returned from (??{...}) */
                ST.cp = regcppush(rex, 0);      /* Save *all* the positions. */
                REGCP_SET(ST.lastcp);
                
-               /* see regtry, specifically PL_reglast(?:close)?paren is a pointer! (i dont know why) :dmq */
                re->lastparen = 0;
                re->lastcloseparen = 0;
 
-               PL_reginput = locinput;
                PL_regsize = 0;
 
                /* XXXX This is too dramatic a measure... */
@@ -4495,7 +4628,8 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
 
                ST.prev_rex = rex_sv;
                ST.prev_curlyx = cur_curlyx;
-               SETREX(rex_sv,re_sv);
+               rex_sv = re_sv;
+               SET_reg_curpm(rex_sv);
                rex = re;
                rexi = rei;
                cur_curlyx = NULL;
@@ -4503,20 +4637,15 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                ST.prev_eval = cur_eval;
                cur_eval = st;
                /* now continue from first node in postoned RE */
-               PUSH_YES_STATE_GOTO(EVAL_AB, startpoint);
-               /* NOTREACHED */
-           }
-           /* logical is 1,   /(?(?{...})X|Y)/ */
-           sw = cBOOL(SvTRUE(ret));
-           logical = 0;
-           break;
+               PUSH_YES_STATE_GOTO(EVAL_AB, startpoint, locinput);
+               assert(0); /* NOTREACHED */
        }
 
        case EVAL_AB: /* cleanup after a successful (??{A})B */
            /* note: this is called twice; first after popping B, then A */
            PL_reg_flags ^= ST.toggle_reg_flags; 
-           ReREFCNT_dec(rex_sv);
-           SETREX(rex_sv,ST.prev_rex);
+           rex_sv = ST.prev_rex;
+           SET_reg_curpm(rex_sv);
            rex = (struct regexp *)SvANY(rex_sv);
            rexi = RXi_GET(rex);
            regcpblow(ST.cp);
@@ -4533,12 +4662,11 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
        case EVAL_AB_fail: /* unsuccessfully ran A or B in (??{A})B */
            /* note: this is called twice; first after popping B, then A */
            PL_reg_flags ^= ST.toggle_reg_flags; 
-           ReREFCNT_dec(rex_sv);
-           SETREX(rex_sv,ST.prev_rex);
+           rex_sv = ST.prev_rex;
+           SET_reg_curpm(rex_sv);
            rex = (struct regexp *)SvANY(rex_sv);
            rexi = RXi_GET(rex); 
 
-           PL_reginput = locinput;
            REGCP_UNWIND(ST.lastcp);
            regcppop(rex);
            cur_eval = ST.prev_eval;
@@ -4552,15 +4680,36 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
 
        case OPEN:
            n = ARG(scan);  /* which paren pair */
-           PL_reg_start_tmp[n] = locinput;
+           rex->offs[n].start_tmp = locinput - PL_bostr;
            if (n > PL_regsize)
                PL_regsize = n;
+           DEBUG_BUFFERS_r(PerlIO_printf(Perl_debug_log,
+               "rex=0x%"UVxf" offs=0x%"UVxf": \\%"UVuf": set %"IVdf" tmp; regsize=%"UVuf"\n",
+               PTR2UV(rex),
+               PTR2UV(rex->offs),
+               (UV)n,
+               (IV)rex->offs[n].start_tmp,
+               (UV)PL_regsize
+           ));
             lastopen = n;
            break;
+
+/* XXX really need to log other places start/end are set too */
+#define CLOSE_CAPTURE \
+    rex->offs[n].start = rex->offs[n].start_tmp; \
+    rex->offs[n].end = locinput - PL_bostr; \
+    DEBUG_BUFFERS_r(PerlIO_printf(Perl_debug_log, \
+       "rex=0x%"UVxf" offs=0x%"UVxf": \\%"UVuf": set %"IVdf"..%"IVdf"\n", \
+       PTR2UV(rex), \
+       PTR2UV(rex->offs), \
+       (UV)n, \
+       (IV)rex->offs[n].start, \
+       (IV)rex->offs[n].end \
+    ))
+
        case CLOSE:
            n = ARG(scan);  /* which paren pair */
-           rex->offs[n].start = PL_reg_start_tmp[n] - PL_bostr;
-           rex->offs[n].end = locinput - PL_bostr;
+           CLOSE_CAPTURE;
            /*if (n > PL_regsize)
                PL_regsize = n;*/
            if (n > rex->lastparen)
@@ -4580,9 +4729,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                     if ( OP(cursor)==CLOSE ){
                         n = ARG(cursor);
                         if ( n <= lastopen ) {
-                            rex->offs[n].start
-                               = PL_reg_start_tmp[n] - PL_bostr;
-                            rex->offs[n].end = locinput - PL_bostr;
+                           CLOSE_CAPTURE;
                             /*if (n > PL_regsize)
                             PL_regsize = n;*/
                             if (n > rex->lastparen)
@@ -4739,21 +4886,20 @@ NULL
            ST.count = -1;      /* this will be updated by WHILEM */
            ST.lastloc = NULL;  /* this will be updated by WHILEM */
 
-           PL_reginput = locinput;
-           PUSH_YES_STATE_GOTO(CURLYX_end, PREVOPER(next));
-           /* NOTREACHED */
+           PUSH_YES_STATE_GOTO(CURLYX_end, PREVOPER(next), locinput);
+           assert(0); /* NOTREACHED */
        }
 
        case CURLYX_end: /* just finished matching all of A*B */
            cur_curlyx = ST.prev_curlyx;
            sayYES;
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
 
        case CURLYX_end_fail: /* just failed to match all of A*B */
            regcpblow(ST.cp);
            cur_curlyx = ST.prev_curlyx;
            sayNO;
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
 
 
 #undef ST
@@ -4773,7 +4919,6 @@ NULL
            ST.cache_offset = 0;
            ST.cache_mask = 0;
            
-           PL_reginput = locinput;
 
            DEBUG_EXECUTE_r( PerlIO_printf(Perl_debug_log,
                  "%*s  whilem: matched %ld out of %d..%d\n",
@@ -4787,8 +4932,8 @@ NULL
                cur_curlyx->u.curlyx.lastloc = locinput;
                REGCP_SET(ST.lastcp);
 
-               PUSH_STATE_GOTO(WHILEM_A_pre, A);
-               /* NOTREACHED */
+               PUSH_STATE_GOTO(WHILEM_A_pre, A, locinput);
+               assert(0); /* NOTREACHED */
            }
 
            /* If degenerate A matches "", assume A done. */
@@ -4861,8 +5006,9 @@ NULL
                cur_curlyx = cur_curlyx->u.curlyx.prev_curlyx;
                ST.cp = regcppush(rex, ST.save_curlyx->u.curlyx.parenfloor);
                REGCP_SET(ST.lastcp);
-               PUSH_YES_STATE_GOTO(WHILEM_B_min, ST.save_curlyx->u.curlyx.B);
-               /* NOTREACHED */
+               PUSH_YES_STATE_GOTO(WHILEM_B_min, ST.save_curlyx->u.curlyx.B,
+                                    locinput);
+               assert(0); /* NOTREACHED */
            }
 
            /* Prefer A over B for maximal matching. */
@@ -4871,25 +5017,25 @@ NULL
                ST.cp = regcppush(rex, cur_curlyx->u.curlyx.parenfloor);
                cur_curlyx->u.curlyx.lastloc = locinput;
                REGCP_SET(ST.lastcp);
-               PUSH_STATE_GOTO(WHILEM_A_max, A);
-               /* NOTREACHED */
+               PUSH_STATE_GOTO(WHILEM_A_max, A, locinput);
+               assert(0); /* NOTREACHED */
            }
            goto do_whilem_B_max;
        }
-       /* NOTREACHED */
+       assert(0); /* NOTREACHED */
 
        case WHILEM_B_min: /* just matched B in a minimal match */
        case WHILEM_B_max: /* just matched B in a maximal match */
            cur_curlyx = ST.save_curlyx;
            sayYES;
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
 
        case WHILEM_B_max_fail: /* just failed to match B in a maximal match */
            cur_curlyx = ST.save_curlyx;
            cur_curlyx->u.curlyx.lastloc = ST.save_lastloc;
            cur_curlyx->u.curlyx.count--;
            CACHEsayNO;
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
 
        case WHILEM_A_min_fail: /* just failed to match A in a minimal match */
            /* FALL THROUGH */
@@ -4899,12 +5045,11 @@ NULL
            cur_curlyx->u.curlyx.lastloc = ST.save_lastloc;
            cur_curlyx->u.curlyx.count--;
            CACHEsayNO;
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
 
        case WHILEM_A_max_fail: /* just failed to match A in a maximal match */
            REGCP_UNWIND(ST.lastcp);
            regcppop(rex);      /* Restore some previous $<digit>s? */
-           PL_reginput = locinput;
            DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log,
                "%*s  whilem: failed, trying continuation...\n",
                REPORT_CODE_OFF+depth*2, "")
@@ -4924,8 +5069,9 @@ NULL
            /* now try B */
            ST.save_curlyx = cur_curlyx;
            cur_curlyx = cur_curlyx->u.curlyx.prev_curlyx;
-           PUSH_YES_STATE_GOTO(WHILEM_B_max, ST.save_curlyx->u.curlyx.B);
-           /* NOTREACHED */
+           PUSH_YES_STATE_GOTO(WHILEM_B_max, ST.save_curlyx->u.curlyx.B,
+                                locinput);
+           assert(0); /* NOTREACHED */
 
        case WHILEM_B_min_fail: /* just failed to match B in a minimal match */
            cur_curlyx = ST.save_curlyx;
@@ -4952,13 +5098,13 @@ NULL
                "%*s  trying longer...\n", REPORT_CODE_OFF+depth*2, "")
            );
            /* Try grabbing another A and see if it helps. */
-           PL_reginput = locinput;
            cur_curlyx->u.curlyx.lastloc = locinput;
            ST.cp = regcppush(rex, cur_curlyx->u.curlyx.parenfloor);
            REGCP_SET(ST.lastcp);
            PUSH_STATE_GOTO(WHILEM_A_min,
-               /*A*/ NEXTOPER(ST.save_curlyx->u.curlyx.me) + EXTRA_STEP_2ARGS);
-           /* NOTREACHED */
+               /*A*/ NEXTOPER(ST.save_curlyx->u.curlyx.me) + EXTRA_STEP_2ARGS,
+                locinput);
+           assert(0); /* NOTREACHED */
 
 #undef  ST
 #define ST st->u.branch
@@ -4973,43 +5119,39 @@ NULL
        case BRANCH:        /*  /(...|A|...)/ */
            scan = NEXTOPER(scan); /* scan now points to inner node */
            ST.lastparen = rex->lastparen;
+           ST.lastcloseparen = rex->lastcloseparen;
            ST.next_branch = next;
            REGCP_SET(ST.cp);
-           PL_reginput = locinput;
 
            /* Now go into the branch */
            if (has_cutgroup) {
-               PUSH_YES_STATE_GOTO(BRANCH_next, scan);    
+               PUSH_YES_STATE_GOTO(BRANCH_next, scan, locinput);
            } else {
-               PUSH_STATE_GOTO(BRANCH_next, scan);
+               PUSH_STATE_GOTO(BRANCH_next, scan, locinput);
            }
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
         case CUTGROUP:
-            PL_reginput = locinput;
             sv_yes_mark = st->u.mark.mark_name = scan->flags ? NULL :
                 MUTABLE_SV(rexi->data->data[ ARG( scan ) ]);
-            PUSH_STATE_GOTO(CUTGROUP_next,next);
-            /* NOTREACHED */
+            PUSH_STATE_GOTO(CUTGROUP_next, next, locinput);
+            assert(0); /* NOTREACHED */
         case CUTGROUP_next_fail:
             do_cutgroup = 1;
             no_final = 1;
             if (st->u.mark.mark_name)
                 sv_commit = st->u.mark.mark_name;
             sayNO;         
-            /* NOTREACHED */
+            assert(0); /* NOTREACHED */
         case BRANCH_next:
             sayYES;
-            /* NOTREACHED */
+            assert(0); /* NOTREACHED */
        case BRANCH_next_fail: /* that branch failed; try the next, if any */
            if (do_cutgroup) {
                do_cutgroup = 0;
                no_final = 0;
            }
            REGCP_UNWIND(ST.cp);
-           for (n = rex->lastparen; n > ST.lastparen; n--)
-               rex->offs[n].end = -1;
-           rex->lastparen = n;
-           /*dmq: rex->lastcloseparen = n; */
+            UNWIND_PAREN(ST.lastparen, ST.lastcloseparen);
            scan = ST.next_branch;
            /* no more branches? */
            if (!scan || (OP(scan) != BRANCH && OP(scan) != BRANCHJ)) {
@@ -5023,7 +5165,7 @@ NULL
                sayNO_SILENT;
             }
            continue; /* execute next BRANCH[J] op */
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
     
        case MINMOD:
            minmod = 1;
@@ -5043,13 +5185,14 @@ NULL
            ST.me = scan;
            scan = NEXTOPER(scan) + NODE_STEP_REGNODE;
 
+           ST.lastparen      = rex->lastparen;
+           ST.lastcloseparen = rex->lastcloseparen;
+
            /* if paren positive, emulate an OPEN/CLOSE around A */
            if (ST.me->flags) {
                U32 paren = ST.me->flags;
                if (paren > PL_regsize)
                    PL_regsize = paren;
-               if (paren > rex->lastparen)
-                   rex->lastparen = paren;
                scan += NEXT_OFF(scan); /* Skip former OPEN. */
            }
            ST.A = scan;
@@ -5065,26 +5208,22 @@ NULL
                goto curlym_do_B;
 
          curlym_do_A: /* execute the A in /A{m,n}B/  */
-           PL_reginput = locinput;
-           PUSH_YES_STATE_GOTO(CURLYM_A, ST.A); /* match A */
-           /* NOTREACHED */
+           PUSH_YES_STATE_GOTO(CURLYM_A, ST.A, locinput); /* match A */
+           assert(0); /* NOTREACHED */
 
        case CURLYM_A: /* we've just matched an A */
-           locinput = st->locinput;
-           nextchr = UCHARAT(locinput);
-
            ST.count++;
            /* after first match, determine A's length: u.curlym.alen */
            if (ST.count == 1) {
                if (PL_reg_match_utf8) {
-                   char *s = locinput;
-                   while (s < PL_reginput) {
+                   char *s = st->locinput;
+                   while (s < locinput) {
                        ST.alen++;
                        s += UTF8SKIP(s);
                    }
                }
                else {
-                   ST.alen = PL_reginput - locinput;
+                   ST.alen = locinput - st->locinput;
                }
                if (ST.alen == 0)
                    ST.count = ST.minmod ? ARG1(ST.me) : ARG2(ST.me);
@@ -5096,8 +5235,6 @@ NULL
                          (IV) ST.count, (IV)ST.alen)
            );
 
-           locinput = PL_reginput;
-                       
            if (cur_eval && cur_eval->u.eval.close_paren && 
                cur_eval->u.eval.close_paren == (U32)ST.me->flags) 
                goto fake_end;
@@ -5118,7 +5255,6 @@ NULL
                sayNO;
 
          curlym_do_B: /* execute the B in /A{m,n}B/  */
-           PL_reginput = locinput;
            if (ST.c1 == CHRTEST_UNINIT) {
                /* calculate c1 and c2 for possible match of 1st char
                 * following curly */
@@ -5160,8 +5296,8 @@ NULL
                    "", (IV)ST.count)
                );
            if (ST.c1 != CHRTEST_VOID
-                   && UCHARAT(PL_reginput) != ST.c1
-                   && UCHARAT(PL_reginput) != ST.c2)
+                   && nextchr != ST.c1
+                   && nextchr != ST.c2)
            {
                /* simulate B failing */
                DEBUG_OPTIMISE_r(
@@ -5175,13 +5311,15 @@ NULL
            }
 
            if (ST.me->flags) {
-               /* mark current A as captured */
+               /* emulate CLOSE: mark current A as captured */
                I32 paren = ST.me->flags;
                if (ST.count) {
                    rex->offs[paren].start
-                       = HOPc(PL_reginput, -ST.alen) - PL_bostr;
-                   rex->offs[paren].end = PL_reginput - PL_bostr;
-                   /*dmq: rex->lastcloseparen = paren; */
+                       = HOPc(locinput, -ST.alen) - PL_bostr;
+                   rex->offs[paren].end = locinput - PL_bostr;
+                   if ((U32)paren > rex->lastparen)
+                       rex->lastparen = paren;
+                   rex->lastcloseparen = paren;
                }
                else
                    rex->offs[paren].end = -1;
@@ -5195,11 +5333,12 @@ NULL
                }
            }
            
-           PUSH_STATE_GOTO(CURLYM_B, ST.B); /* match B */
-           /* NOTREACHED */
+           PUSH_STATE_GOTO(CURLYM_B, ST.B, locinput); /* match B */
+           assert(0); /* NOTREACHED */
 
        case CURLYM_B_fail: /* just failed to match a B */
            REGCP_UNWIND(ST.cp);
+            UNWIND_PAREN(ST.lastparen, ST.lastcloseparen);
            if (ST.minmod) {
                I32 max = ARG2(ST.me);
                if (max != REG_INFTY && ST.count == max)
@@ -5211,6 +5350,7 @@ NULL
                sayNO;
            ST.count--;
            locinput = HOPc(locinput, -ST.alen);
+            nextchr = UCHARAT(locinput);
            goto curlym_do_B; /* try to match B */
 
 #undef ST
@@ -5221,10 +5361,15 @@ NULL
        if (success) { \
            rex->offs[paren].start = HOPc(locinput, -1) - PL_bostr; \
            rex->offs[paren].end = locinput - PL_bostr; \
+           if (paren > rex->lastparen) \
+               rex->lastparen = paren; \
            rex->lastcloseparen = paren; \
        } \
-       else \
+       else \
            rex->offs[paren].end = -1; \
+           rex->lastparen      = ST.lastparen; \
+           rex->lastcloseparen = ST.lastcloseparen; \
+       } \
     }
 
        case STAR:              /*  /A*B/ where A is width 1 */
@@ -5241,10 +5386,10 @@ NULL
            goto repeat;
        case CURLYN:            /*  /(A){m,n}B/ where A is width 1 */
            ST.paren = scan->flags;     /* Which paren to set */
+           ST.lastparen      = rex->lastparen;
+           ST.lastcloseparen = rex->lastcloseparen;
            if (ST.paren > PL_regsize)
                PL_regsize = ST.paren;
-           if (ST.paren > rex->lastparen)
-               rex->lastparen = ST.paren;
            ST.min = ARG1(scan);  /* min to match */
            ST.max = ARG2(scan);  /* max to match */
            if (cur_eval && cur_eval->u.eval.close_paren &&
@@ -5328,13 +5473,14 @@ NULL
 
            ST.A = scan;
            ST.B = next;
-           PL_reginput = locinput;
            if (minmod) {
+                char *li = locinput;
                minmod = 0;
-               if (ST.min && regrepeat(rex, ST.A, ST.min, depth) < ST.min)
+               if (ST.min && regrepeat(rex, &li, ST.A, ST.min, depth) < ST.min)
                    sayNO;
+                locinput = li;
+                nextchr = UCHARAT(locinput);
                ST.count = ST.min;
-               locinput = PL_reginput;
                REGCP_SET(ST.cp);
                if (ST.c1 == CHRTEST_VOID)
                    goto curly_try_B_min;
@@ -5364,10 +5510,14 @@ NULL
 
            }
            else {
-               ST.count = regrepeat(rex, ST.A, ST.max, depth);
-               locinput = PL_reginput;
+                /* avoid taking address of locinput, so it can remain
+                 * a register var */
+                char *li = locinput;
+               ST.count = regrepeat(rex, &li, ST.A, ST.max, depth);
                if (ST.count < ST.min)
                    sayNO;
+                locinput = li;
+                nextchr = UCHARAT(locinput);
                if ((ST.count > ST.min)
                    && (PL_regkind[OP(ST.B)] == EOL) && (OP(ST.B) != MEOL))
                {
@@ -5377,22 +5527,22 @@ NULL
                    /* ...except that $ and \Z can match before *and* after
                       newline at the end.  Consider "\n\n" =~ /\n+\Z\n/.
                       We may back off by one in this case. */
-                   if (UCHARAT(PL_reginput - 1) == '\n' && OP(ST.B) != EOS)
+                   if (UCHARAT(locinput - 1) == '\n' && OP(ST.B) != EOS)
                        ST.min--;
                }
                REGCP_SET(ST.cp);
                goto curly_try_B_max;
            }
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
 
 
        case CURLY_B_min_known_fail:
            /* failed to find B in a non-greedy match where c1,c2 valid */
-           if (ST.paren && ST.count)
-               rex->offs[ST.paren].end = -1;
 
-           PL_reginput = locinput;     /* Could be reset... */
            REGCP_UNWIND(ST.cp);
+            if (ST.paren) {
+                UNWIND_PAREN(ST.lastparen, ST.lastcloseparen);
+            }
            /* Couldn't or didn't -- move forward. */
            ST.oldloc = locinput;
            if (utf8_target)
@@ -5447,34 +5597,43 @@ NULL
                }
                if (locinput > ST.maxpos)
                    sayNO;
-               /* PL_reginput == oldloc now */
                if (n) {
+                    /* In /a{m,n}b/, ST.oldloc is at "a" x m, locinput is
+                     * at b; check that everything between oldloc and
+                     * locinput matches */
+                    char *li = ST.oldloc;
                    ST.count += n;
-                   if (regrepeat(rex, ST.A, n, depth) < n)
+                   if (regrepeat(rex, &li, ST.A, n, depth) < n)
                        sayNO;
+                    assert(n == REG_INFTY || locinput == li);
                }
-               PL_reginput = locinput;
                CURLY_SETPAREN(ST.paren, ST.count);
                if (cur_eval && cur_eval->u.eval.close_paren && 
                    cur_eval->u.eval.close_paren == (U32)ST.paren) {
                    goto fake_end;
                }
-               PUSH_STATE_GOTO(CURLY_B_min_known, ST.B);
+               PUSH_STATE_GOTO(CURLY_B_min_known, ST.B, locinput);
            }
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
 
 
        case CURLY_B_min_fail:
            /* failed to find B in a non-greedy match where c1,c2 invalid */
-           if (ST.paren && ST.count)
-               rex->offs[ST.paren].end = -1;
 
            REGCP_UNWIND(ST.cp);
+            if (ST.paren) {
+                UNWIND_PAREN(ST.lastparen, ST.lastcloseparen);
+            }
            /* failed -- move forward one */
-           PL_reginput = locinput;
-           if (regrepeat(rex, ST.A, 1, depth)) {
+            {
+                char *li = locinput;
+                if (!regrepeat(rex, &li, ST.A, 1, depth)) {
+                    sayNO;
+                }
+                locinput = li;
+            }
+            {
                ST.count++;
-               locinput = PL_reginput;
                if (ST.count <= ST.max || (ST.max == REG_INFTY &&
                        ST.count > 0)) /* count overflow ? */
                {
@@ -5484,11 +5643,10 @@ NULL
                        cur_eval->u.eval.close_paren == (U32)ST.paren) {
                         goto fake_end;
                     }
-                   PUSH_STATE_GOTO(CURLY_B_min, ST.B);
+                   PUSH_STATE_GOTO(CURLY_B_min, ST.B, locinput);
                }
            }
-           sayNO;
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
 
 
        curly_try_B_max:
@@ -5500,27 +5658,28 @@ NULL
            {
                UV c = 0;
                if (ST.c1 != CHRTEST_VOID)
-                   c = utf8_target ? utf8n_to_uvchr((U8*)PL_reginput,
+                   c = utf8_target ? utf8n_to_uvchr((U8*)locinput,
                                           UTF8_MAXBYTES, 0, uniflags)
-                               : (UV) UCHARAT(PL_reginput);
+                               : (UV) UCHARAT(locinput);
                /* If it could work, try it. */
                if (ST.c1 == CHRTEST_VOID || c == (UV)ST.c1 || c == (UV)ST.c2) {
                    CURLY_SETPAREN(ST.paren, ST.count);
-                   PUSH_STATE_GOTO(CURLY_B_max, ST.B);
-                   /* NOTREACHED */
+                   PUSH_STATE_GOTO(CURLY_B_max, ST.B, locinput);
+                   assert(0); /* NOTREACHED */
                }
            }
            /* FALL THROUGH */
        case CURLY_B_max_fail:
            /* failed to find B in a greedy match */
-           if (ST.paren && ST.count)
-               rex->offs[ST.paren].end = -1;
 
            REGCP_UNWIND(ST.cp);
+            if (ST.paren) {
+                UNWIND_PAREN(ST.lastparen, ST.lastcloseparen);
+            }
            /*  back up. */
            if (--ST.count < ST.min)
                sayNO;
-           PL_reginput = locinput = HOPc(locinput, -1);
+           locinput = HOPc(locinput, -1);
            goto curly_try_B_max;
 
 #undef ST
@@ -5529,28 +5688,23 @@ NULL
            fake_end:
            if (cur_eval) {
                /* we've just finished A in /(??{A})B/; now continue with B */
-               I32 tmpix;
                st->u.eval.toggle_reg_flags
                            = cur_eval->u.eval.toggle_reg_flags;
                PL_reg_flags ^= st->u.eval.toggle_reg_flags; 
 
                st->u.eval.prev_rex = rex_sv;           /* inner */
                st->u.eval.cp = regcppush(rex, 0); /* Save *all* the positions. */
-               SETREX(rex_sv,cur_eval->u.eval.prev_rex);
+               rex_sv = cur_eval->u.eval.prev_rex;
+               SET_reg_curpm(rex_sv);
                rex = (struct regexp *)SvANY(rex_sv);
                rexi = RXi_GET(rex);
                cur_curlyx = cur_eval->u.eval.prev_curlyx;
-               (void)ReREFCNT_inc(rex_sv);
 
                REGCP_SET(st->u.eval.lastcp);
-               PL_reginput = locinput;
 
                /* Restore parens of the outer rex without popping the
                 * savestack */
-               tmpix = PL_savestack_ix;
-               PL_savestack_ix = cur_eval->u.eval.lastcp;
-               regcppop(rex);
-               PL_savestack_ix = tmpix;
+               S_regcp_restore(aTHX_ rex, cur_eval->u.eval.lastcp);
 
                st->u.eval.prev_eval = cur_eval;
                cur_eval = cur_eval->u.eval.prev_eval;
@@ -5560,8 +5714,8 @@ NULL
                 if ( nochange_depth )
                    nochange_depth--;
 
-                PUSH_YES_STATE_GOTO(EVAL_AB,
-                       st->u.eval.prev_eval->u.eval.B); /* match B */
+                PUSH_YES_STATE_GOTO(EVAL_AB, st->u.eval.prev_eval->u.eval.B,
+                                    locinput); /* match B */
            }
 
            if (locinput < reginfo->till) {
@@ -5574,7 +5728,6 @@ NULL
                                                      
                sayNO_SILENT;           /* Cannot match: too short. */
            }
-           PL_reginput = locinput;     /* put where regtry can find it */
            sayYES;                     /* Success! */
 
        case SUCCEED: /* successful SUSPEND/UNLESSM/IFMATCH/CURLYM */
@@ -5582,15 +5735,17 @@ NULL
            PerlIO_printf(Perl_debug_log,
                "%*s  %ssubpattern success...%s\n",
                REPORT_CODE_OFF+depth*2, "", PL_colors[4], PL_colors[5]));
-           PL_reginput = locinput;     /* put where regtry can find it */
            sayYES;                     /* Success! */
 
 #undef  ST
 #define ST st->u.ifmatch
 
+        {
+            char *newstart;
+
        case SUSPEND:   /* (?>A) */
            ST.wanted = 1;
-           PL_reginput = locinput;
+           newstart = locinput;
            goto do_ifmatch;    
 
        case UNLESSM:   /* -ve lookaround: (?!A), or with flags, (?<!A) */
@@ -5615,10 +5770,10 @@ NULL
                        next = NULL;
                    break;
                }
-               PL_reginput = s;
+               newstart = s;
            }
            else
-               PL_reginput = locinput;
+               newstart = locinput;
 
          do_ifmatch:
            ST.me = scan;
@@ -5626,8 +5781,9 @@ NULL
            logical = 0; /* XXX: reset state of logical once it has been saved into ST */
            
            /* execute body of (?...A) */
-           PUSH_YES_STATE_GOTO(IFMATCH_A, NEXTOPER(NEXTOPER(scan)));
-           /* NOTREACHED */
+           PUSH_YES_STATE_GOTO(IFMATCH_A, NEXTOPER(NEXTOPER(scan)), newstart);
+           assert(0); /* NOTREACHED */
+        }
 
        case IFMATCH_A_fail: /* body of (?...A) failed */
            ST.wanted = !ST.wanted;
@@ -5640,11 +5796,9 @@ NULL
            else if (!ST.wanted)
                sayNO;
 
-           if (OP(ST.me) == SUSPEND)
-               locinput = PL_reginput;
-           else {
-               locinput = PL_reginput = st->locinput;
-               nextchr = UCHARAT(locinput);
+           if (OP(ST.me) != SUSPEND) {
+                /* restore old position except for (?>...) */
+               locinput = st->locinput;
            }
            scan = ST.me + ARG(ST.me);
            if (scan == ST.me)
@@ -5662,17 +5816,16 @@ NULL
            reginfo->cutpoint = PL_regeol;
            /* FALLTHROUGH */
        case PRUNE:
-           PL_reginput = locinput;
            if (!scan->flags)
                sv_yes_mark = sv_commit = MUTABLE_SV(rexi->data->data[ ARG( scan ) ]);
-           PUSH_STATE_GOTO(COMMIT_next,next);
-           /* NOTREACHED */
+           PUSH_STATE_GOTO(COMMIT_next, next, locinput);
+           assert(0); /* NOTREACHED */
        case COMMIT_next_fail:
            no_final = 1;    
            /* FALLTHROUGH */       
        case OPFAIL:
            sayNO;
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
 
 #define ST st->u.mark
         case MARKPOINT:
@@ -5680,13 +5833,13 @@ NULL
             ST.mark_name = sv_commit = sv_yes_mark 
                 = MUTABLE_SV(rexi->data->data[ ARG( scan ) ]);
             mark_state = st;
-            ST.mark_loc = PL_reginput = locinput;
-            PUSH_YES_STATE_GOTO(MARKPOINT_next,next);
-            /* NOTREACHED */
+            ST.mark_loc = locinput;
+            PUSH_YES_STATE_GOTO(MARKPOINT_next, next, locinput);
+            assert(0); /* NOTREACHED */
         case MARKPOINT_next:
             mark_state = ST.prev_mark;
             sayYES;
-            /* NOTREACHED */
+            assert(0); /* NOTREACHED */
         case MARKPOINT_next_fail:
             if (popmark && sv_eq(ST.mark_name,popmark)) 
             {
@@ -5706,14 +5859,13 @@ NULL
             sv_yes_mark = mark_state ? 
                 mark_state->u.mark.mark_name : NULL;
             sayNO;
-            /* NOTREACHED */
+            assert(0); /* NOTREACHED */
         case SKIP:
-            PL_reginput = locinput;
             if (scan->flags) {
                 /* (*SKIP) : if we fail we cut here*/
                 ST.mark_name = NULL;
                 ST.mark_loc = locinput;
-                PUSH_STATE_GOTO(SKIP_next,next);    
+                PUSH_STATE_GOTO(SKIP_next,next, locinput);
             } else {
                 /* (*SKIP:NAME) : if there is a (*MARK:NAME) fail where it was, 
                    otherwise do nothing.  Meaning we need to scan 
@@ -5726,7 +5878,7 @@ NULL
                                 find ) ) 
                     {
                         ST.mark_name = find;
-                        PUSH_STATE_GOTO( SKIP_next, next );
+                        PUSH_STATE_GOTO( SKIP_next, next, locinput);
                     }
                     cur = cur->u.mark.prev_mark;
                 }
@@ -5750,12 +5902,11 @@ NULL
             } 
             no_final = 1; 
             sayNO;
-            /* NOTREACHED */
+            assert(0); /* NOTREACHED */
 #undef ST
         case LNBREAK:
             if ((n=is_LNBREAK(locinput,utf8_target))) {
                 locinput += n;
-                nextchr = UCHARAT(locinput);
             } else
                 sayNO;
             break;
@@ -5766,7 +5917,6 @@ NULL
                sayNO;                                \
             if ((n=is_##nAmE(locinput,utf8_target))) {    \
                 locinput += n;                        \
-                nextchr = UCHARAT(locinput);          \
             } else                                    \
                 sayNO;                                \
             break;                                    \
@@ -5777,7 +5927,6 @@ NULL
                 sayNO;                                \
             } else {                                  \
                 locinput += UTF8SKIP(locinput);       \
-                nextchr = UCHARAT(locinput);          \
             }                                         \
             break
 
@@ -5789,13 +5938,25 @@ NULL
            PerlIO_printf(Perl_error_log, "%"UVxf" %d\n",
                          PTR2UV(scan), OP(scan));
            Perl_croak(aTHX_ "regexp memory corruption");
+
+        /* this is a point to jump to in order to increment
+         * locinput by one character */
+        increment_locinput:
+            if (utf8_target) {
+                locinput += PL_utf8skip[nextchr];
+                if (locinput > PL_regeol)
+                    sayNO;
+            }
+            else
+                locinput++;
+            break;
            
        } /* end switch */ 
 
         /* switch break jumps here */
        scan = next; /* prepare to execute the next op and ... */
        continue;    /* ... jump back to the top, reusing st */
-       /* NOTREACHED */
+       assert(0); /* NOTREACHED */
 
       push_yes_state:
        /* push a state that backtracks on success */
@@ -5835,11 +5996,10 @@ NULL
                newst = S_push_slab(aTHX);
            PL_regmatch_state = newst;
 
-           locinput = PL_reginput;
-           nextchr = UCHARAT(locinput);
+           locinput = pushinput;
            st = newst;
            continue;
-           /* NOTREACHED */
+           assert(0); /* NOTREACHED */
        }
     }
 
@@ -5887,10 +6047,8 @@ yes:
        yes_state = st->u.yes.prev_yes_state;
        PL_regmatch_state = st;
         
-        if (no_final) {
+        if (no_final)
             locinput= st->locinput;
-            nextchr = UCHARAT(locinput);
-        }
        state_num = st->resume_state + no_final;
        goto reenter_switch;
     }
@@ -5935,7 +6093,6 @@ no_silent:
        }
        PL_regmatch_state = st;
        locinput= st->locinput;
-       nextchr = UCHARAT(locinput);
 
        DEBUG_STATE_pp("pop");
        depth--;
@@ -5968,31 +6125,35 @@ no_silent:
     if (last_pushed_cv) {
        dSP;
        POP_MULTICALL;
+        PERL_UNUSED_VAR(SP);
     }
 
     /* clean up; in particular, free all slabs above current one */
     LEAVE_SCOPE(oldsave);
 
-    return result;
+    assert(!result ||  locinput - PL_bostr >= 0);
+    return result ?  locinput - PL_bostr : -1;
 }
 
 /*
  - regrepeat - repeatedly match something simple, report how many
- */
-/*
- * [This routine now assumes that it will only match on things of length 1.
- * That was true before, but now we assume scan - reginput is the count,
- * rather than incrementing count on every character.  [Er, except utf8.]]
+ *
+ * startposp - pointer a pointer to the start position.  This is updated
+ *             to point to the byte following the highest successful
+ *             match.
+ * p         - the regnode to be repeatedly matched against.
+ * max       - maximum number of characters to match.
+ * depth     - (for debugging) backtracking depth.
  */
 STATIC I32
-S_regrepeat(pTHX_ const regexp *prog, const regnode *p, I32 max, int depth)
+S_regrepeat(pTHX_ const regexp *prog, char **startposp, const regnode *p, I32 max, int depth)
 {
     dVAR;
-    register char *scan;
-    register I32 c;
-    register char *loceol = PL_regeol;
-    register I32 hardcount = 0;
-    register bool utf8_target = PL_reg_match_utf8;
+    char *scan;
+    I32 c;
+    char *loceol = PL_regeol;
+    I32 hardcount = 0;
+    bool utf8_target = PL_reg_match_utf8;
     UV utf8_flags;
 #ifndef DEBUGGING
     PERL_UNUSED_ARG(depth);
@@ -6000,7 +6161,7 @@ S_regrepeat(pTHX_ const regexp *prog, const regnode *p, I32 max, int depth)
 
     PERL_ARGS_ASSERT_REGREPEAT;
 
-    scan = PL_reginput;
+    scan = *startposp;
     if (max == REG_INFTY)
        max = I32_MAX;
     else if (max < loceol - scan)
@@ -6224,6 +6385,24 @@ S_regrepeat(pTHX_ const regexp *prog, const regnode *p, I32 max, int depth)
            scan++;
        }
        break;
+
+    case POSIXA:
+       while (scan < loceol && _generic_isCC_A((U8) *scan, FLAGS(p))) {
+           scan++;
+       }
+       break;
+    case NPOSIXA:
+       if (utf8_target) {
+           while (scan < loceol && ! _generic_isCC_A((U8) *scan, FLAGS(p))) {
+               scan += UTF8SKIP(scan);
+           }
+       }
+       else {
+           while (scan < loceol && ! _generic_isCC_A((U8) *scan, FLAGS(p))) {
+               scan++;
+           }
+       }
+       break;
     case NALNUMA:
        if (utf8_target) {
            while (scan < loceol && ! isWORDCHAR_A((U8) *scan)) {
@@ -6506,8 +6685,8 @@ S_regrepeat(pTHX_ const regexp *prog, const regnode *p, I32 max, int depth)
     if (hardcount)
        c = hardcount;
     else
-       c = scan - PL_reginput;
-    PL_reginput = scan;
+       c = scan - *startposp;
+    *startposp = scan;
 
     DEBUG_r({
        GET_RE_DEBUG_FLAGS_DECL;
@@ -6569,7 +6748,7 @@ S_core_regclass_swash(pTHX_ const regexp *prog, register const regnode* node, bo
            SV * const rv = MUTABLE_SV(data->data[n]);
            AV * const av = MUTABLE_AV(SvRV(rv));
            SV **const ary = AvARRAY(av);
-           bool invlist_has_user_defined_property;
+           U8 swash_init_flags = _CORE_SWASH_INIT_ACCEPT_INVLIST;
        
            si = *ary;  /* ary[0] = the string to initialize the swash with */
 
@@ -6578,11 +6757,12 @@ S_core_regclass_swash(pTHX_ const regexp *prog, register const regnode* node, bo
             * that inversion list has any user-defined properties in it. */
            if (av_len(av) >= 3) {
                invlist = ary[3];
-               invlist_has_user_defined_property = cBOOL(SvUV(ary[4]));
+               if (SvUV(ary[4])) {
+                    swash_init_flags |= _CORE_SWASH_INIT_USER_DEFINED_PROPERTY;
+                }
            }
            else {
                invlist = NULL;
-               invlist_has_user_defined_property = FALSE;
            }
 
            /* Element [1] is reserved for the set-up swash.  If already there,
@@ -6597,10 +6777,8 @@ S_core_regclass_swash(pTHX_ const regexp *prog, register const regnode* node, bo
                                      si,
                                      1, /* binary */
                                      0, /* not from tr/// */
-                                     FALSE, /* is error if can't find
-                                               property */
                                      invlist,
-                                     invlist_has_user_defined_property);
+                                     &swash_init_flags);
                (void)av_store(av, 1, sw);
            }
 
@@ -6615,20 +6793,14 @@ S_core_regclass_swash(pTHX_ const regexp *prog, register const regnode* node, bo
        
     if (listsvp) {
        SV* matches_string = newSVpvn("", 0);
-       SV** invlistsvp;
 
        /* Use the swash, if any, which has to have incorporated into it all
         * possibilities */
-       if (   sw
-           && SvROK(sw)
-           && SvTYPE(SvRV(sw)) == SVt_PVHV
-           && (invlistsvp = hv_fetchs(MUTABLE_HV(SvRV(sw)), "INVLIST", FALSE)))
-       {
-           invlist = *invlistsvp;
-       }
-       else if (si && si != &PL_sv_undef) {
+       if ((! sw || (invlist = _get_swash_invlist(sw)) == NULL)
+            && (si && si != &PL_sv_undef))
+        {
 
-           /* If no swash, use the input nitialization string, if available */
+           /* If no swash, use the input initialization string, if available */
            sv_catsv(matches_string, si);
        }
 
@@ -6948,9 +7120,18 @@ S_reginclass(pTHX_ const regexp * const prog, register const regnode * const n,
                if (! utf8_target) Safefree(utf8_p);
            }
        }
+
+        if (UNICODE_IS_SUPER(c)
+            && (flags & ANYOF_WARN_SUPER)
+            && ckWARN_d(WARN_NON_UNICODE))
+        {
+            Perl_warner(aTHX_ packWARN(WARN_NON_UNICODE),
+                "Code point 0x%04"UVXf" is not Unicode, all \\p{} matches fail; all \\P{} matches succeed", c);
+        }
     }
 
-    return (flags & ANYOF_INVERT) ? !match : match;
+    /* The xor complements the return if to invert: 1^1 = 0, 1^0 = 1 */
+    return cBOOL(flags & ANYOF_INVERT) ^ match;
 }
 
 STATIC U8 *
@@ -7054,6 +7235,8 @@ restore_pos(pTHX_ void *arg)
        if (PL_reg_oldsaved) {
            rex->subbeg = PL_reg_oldsaved;
            rex->sublen = PL_reg_oldsavedlen;
+           rex->suboffset = PL_reg_oldsavedoffset;
+           rex->subcoffset = PL_reg_oldsavedcoffset;
 #ifdef PERL_OLD_COPY_ON_WRITE
            rex->saved_copy = PL_nrs;
 #endif
@@ -7129,6 +7312,74 @@ S_to_byte_substr(pTHX_ register regexp *prog)
     } while (i--);
 }
 
+/* These constants are for finding GCB=LV and GCB=LVT.  These are for the
+ * pre-composed Hangul syllables, which are all in a contiguous block and
+ * arranged there in such a way so as to facilitate alorithmic determination of
+ * their characteristics.  As such, they don't need a swash, but can be
+ * determined by simple arithmetic.  Almost all are GCB=LVT, but every 28th one
+ * is a GCB=LV */
+#define SBASE 0xAC00    /* Start of block */
+#define SCount 11172    /* Length of block */
+#define TCount 28
+
+#if 0   /* This routine is not currently used */
+PERL_STATIC_INLINE bool
+S_is_utf8_X_LV(pTHX_ const U8 *p)
+{
+    /* Unlike most other similarly named routines here, this does not create a
+     * swash, so swash_fetch() cannot be used on PL_utf8_X_LV. */
+
+    dVAR;
+
+    UV cp = valid_utf8_to_uvchr(p, NULL);
+
+    PERL_ARGS_ASSERT_IS_UTF8_X_LV;
+
+    /* The earliest Unicode releases did not have these precomposed Hangul
+     * syllables.  Set to point to undef in that case, so will return false on
+     * every call */
+    if (! PL_utf8_X_LV) {   /* Set up if this is the first time called */
+        PL_utf8_X_LV = swash_init("utf8", "_X_GCB_LV", &PL_sv_undef, 1, 0);
+        if (_invlist_len(_get_swash_invlist(PL_utf8_X_LV)) == 0) {
+            SvREFCNT_dec(PL_utf8_X_LV);
+            PL_utf8_X_LV = &PL_sv_undef;
+        }
+    }
+
+    return (PL_utf8_X_LV != &PL_sv_undef
+            && cp >= SBASE && cp < SBASE + SCount
+            && (cp - SBASE) % TCount == 0); /* Only every TCount one is LV */
+}
+#endif
+
+PERL_STATIC_INLINE bool
+S_is_utf8_X_LVT(pTHX_ const U8 *p)
+{
+    /* Unlike most other similarly named routines here, this does not create a
+     * swash, so swash_fetch() cannot be used on PL_utf8_X_LVT. */
+
+    dVAR;
+
+    UV cp = valid_utf8_to_uvchr(p, NULL);
+
+    PERL_ARGS_ASSERT_IS_UTF8_X_LVT;
+
+    /* The earliest Unicode releases did not have these precomposed Hangul
+     * syllables.  Set to point to undef in that case, so will return false on
+     * every call */
+    if (! PL_utf8_X_LVT) {   /* Set up if this is the first time called */
+        PL_utf8_X_LVT = swash_init("utf8", "_X_GCB_LVT", &PL_sv_undef, 1, 0);
+        if (_invlist_len(_get_swash_invlist(PL_utf8_X_LVT)) == 0) {
+            SvREFCNT_dec(PL_utf8_X_LVT);
+            PL_utf8_X_LVT = &PL_sv_undef;
+        }
+    }
+
+    return (PL_utf8_X_LVT != &PL_sv_undef
+            && cp >= SBASE && cp < SBASE + SCount
+            && (cp - SBASE) % TCount != 0); /* All but every TCount one is LV */
+}
+
 /*
  * Local variables:
  * c-indentation-style: bsd