This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Abolish RXf_UTF8. Store the UTF-8-ness of the pattern with SvUTF8().
[perl5.git] / regexec.c
index e34af4d..dfe71f7 100644 (file)
--- a/regexec.c
+++ b/regexec.c
@@ -56,7 +56,7 @@
  ****    Alterations to Henry's code are...
  ****
  ****    Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
  ****    Alterations to Henry's code are...
  ****
  ****    Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- ****    2000, 2001, 2002, 2003, 2004, 2005, 2006, by Larry Wall and others
+ ****    2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 by Larry Wall and others
  ****
  ****    You may distribute under the terms of either the GNU General Public
  ****    License or the Artistic License, as specified in the README file.
  ****
  ****    You may distribute under the terms of either the GNU General Public
  ****    License or the Artistic License, as specified in the README file.
 /* TODO: Combine JUMPABLE and HAS_TEXT to cache OP(rn) */
 
 /* for use after a quantifier and before an EXACT-like node -- japhy */
 /* TODO: Combine JUMPABLE and HAS_TEXT to cache OP(rn) */
 
 /* for use after a quantifier and before an EXACT-like node -- japhy */
-#define JUMPABLE(rn) ( \
-    OP(rn) == OPEN || OP(rn) == CLOSE || OP(rn) == EVAL || \
+/* it would be nice to rework regcomp.sym to generate this stuff. sigh */
+#define JUMPABLE(rn) (      \
+    OP(rn) == OPEN ||       \
+    (OP(rn) == CLOSE && (!cur_eval || cur_eval->u.eval.close_paren != ARG(rn))) || \
+    OP(rn) == EVAL ||   \
     OP(rn) == SUSPEND || OP(rn) == IFMATCH || \
     OP(rn) == PLUS || OP(rn) == MINMOD || \
     OP(rn) == SUSPEND || OP(rn) == IFMATCH || \
     OP(rn) == PLUS || OP(rn) == MINMOD || \
+    OP(rn) == KEEPS || (PL_regkind[OP(rn)] == VERB) || \
     (PL_regkind[OP(rn)] == CURLY && ARG1(rn) > 0) \
 )
     (PL_regkind[OP(rn)] == CURLY && ARG1(rn) > 0) \
 )
+#define IS_EXACT(rn) (PL_regkind[OP(rn)] == EXACT)
 
 
-#define HAS_TEXT(rn) ( \
-    PL_regkind[OP(rn)] == EXACT || PL_regkind[OP(rn)] == REF \
-)
+#define HAS_TEXT(rn) ( IS_EXACT(rn) || PL_regkind[OP(rn)] == REF )
+
+#if 0 
+/* Currently these are only used when PL_regkind[OP(rn)] == EXACT so
+   we don't need this definition. */
+#define IS_TEXT(rn)   ( OP(rn)==EXACT   || OP(rn)==REF   || OP(rn)==NREF   )
+#define IS_TEXTF(rn)  ( OP(rn)==EXACTF  || OP(rn)==REFF  || OP(rn)==NREFF  )
+#define IS_TEXTFL(rn) ( OP(rn)==EXACTFL || OP(rn)==REFFL || OP(rn)==NREFFL )
+
+#else
+/* ... so we use this as its faster. */
+#define IS_TEXT(rn)   ( OP(rn)==EXACT   )
+#define IS_TEXTF(rn)  ( OP(rn)==EXACTF  )
+#define IS_TEXTFL(rn) ( OP(rn)==EXACTFL )
+
+#endif
 
 /*
   Search for mandatory following text node; for lookahead, the text must
 
 /*
   Search for mandatory following text node; for lookahead, the text must
@@ -166,25 +184,24 @@ S_regcppush(pTHX_ I32 parenfloor)
     if (paren_elems_to_push < 0)
        Perl_croak(aTHX_ "panic: paren_elems_to_push < 0");
 
     if (paren_elems_to_push < 0)
        Perl_croak(aTHX_ "panic: paren_elems_to_push < 0");
 
-#define REGCP_OTHER_ELEMS 8
+#define REGCP_OTHER_ELEMS 7
     SSGROW(paren_elems_to_push + REGCP_OTHER_ELEMS);
     
     for (p = PL_regsize; p > parenfloor; p--) {
 /* REGCP_PARENS_ELEMS are pushed per pairs of parentheses. */
     SSGROW(paren_elems_to_push + REGCP_OTHER_ELEMS);
     
     for (p = PL_regsize; p > parenfloor; p--) {
 /* REGCP_PARENS_ELEMS are pushed per pairs of parentheses. */
-       SSPUSHINT(PL_regendp[p]);
-       SSPUSHINT(PL_regstartp[p]);
+       SSPUSHINT(PL_regoffs[p].end);
+       SSPUSHINT(PL_regoffs[p].start);
        SSPUSHPTR(PL_reg_start_tmp[p]);
        SSPUSHINT(p);
        SSPUSHPTR(PL_reg_start_tmp[p]);
        SSPUSHINT(p);
-       DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log,
+       DEBUG_BUFFERS_r(PerlIO_printf(Perl_debug_log,
          "     saving \\%"UVuf" %"IVdf"(%"IVdf")..%"IVdf"\n",
          "     saving \\%"UVuf" %"IVdf"(%"IVdf")..%"IVdf"\n",
-                     (UV)p, (IV)PL_regstartp[p],
+                     (UV)p, (IV)PL_regoffs[p].start,
                      (IV)(PL_reg_start_tmp[p] - PL_bostr),
                      (IV)(PL_reg_start_tmp[p] - PL_bostr),
-                     (IV)PL_regendp[p]
+                     (IV)PL_regoffs[p].end
        ));
     }
 /* REGCP_OTHER_ELEMS are pushed in any case, parentheses or no. */
        ));
     }
 /* REGCP_OTHER_ELEMS are pushed in any case, parentheses or no. */
-    SSPUSHPTR(PL_regstartp);
-    SSPUSHPTR(PL_regendp);
+    SSPUSHPTR(PL_regoffs);
     SSPUSHINT(PL_regsize);
     SSPUSHINT(*PL_reglastparen);
     SSPUSHINT(*PL_reglastcloseparen);
     SSPUSHINT(PL_regsize);
     SSPUSHINT(*PL_reglastparen);
     SSPUSHINT(*PL_reglastcloseparen);
@@ -231,8 +248,7 @@ S_regcppop(pTHX_ const regexp *rex)
     *PL_reglastcloseparen = SSPOPINT;
     *PL_reglastparen = SSPOPINT;
     PL_regsize = SSPOPINT;
     *PL_reglastcloseparen = SSPOPINT;
     *PL_reglastparen = SSPOPINT;
     PL_regsize = SSPOPINT;
-    PL_regendp=(I32 *) SSPOPPTR;
-    PL_regstartp=(I32 *) SSPOPPTR;
+    PL_regoffs=(regexp_paren_pair *) SSPOPPTR;
 
     
     /* Now restore the parentheses context. */
 
     
     /* Now restore the parentheses context. */
@@ -241,20 +257,20 @@ S_regcppop(pTHX_ const regexp *rex)
        I32 tmps;
        U32 paren = (U32)SSPOPINT;
        PL_reg_start_tmp[paren] = (char *) SSPOPPTR;
        I32 tmps;
        U32 paren = (U32)SSPOPINT;
        PL_reg_start_tmp[paren] = (char *) SSPOPPTR;
-       PL_regstartp[paren] = SSPOPINT;
+       PL_regoffs[paren].start = SSPOPINT;
        tmps = SSPOPINT;
        if (paren <= *PL_reglastparen)
        tmps = SSPOPINT;
        if (paren <= *PL_reglastparen)
-           PL_regendp[paren] = tmps;
-       DEBUG_EXECUTE_r(
+           PL_regoffs[paren].end = tmps;
+       DEBUG_BUFFERS_r(
            PerlIO_printf(Perl_debug_log,
                          "     restoring \\%"UVuf" to %"IVdf"(%"IVdf")..%"IVdf"%s\n",
            PerlIO_printf(Perl_debug_log,
                          "     restoring \\%"UVuf" to %"IVdf"(%"IVdf")..%"IVdf"%s\n",
-                         (UV)paren, (IV)PL_regstartp[paren],
+                         (UV)paren, (IV)PL_regoffs[paren].start,
                          (IV)(PL_reg_start_tmp[paren] - PL_bostr),
                          (IV)(PL_reg_start_tmp[paren] - PL_bostr),
-                         (IV)PL_regendp[paren],
+                         (IV)PL_regoffs[paren].end,
                          (paren > *PL_reglastparen ? "(no)" : ""));
        );
     }
                          (paren > *PL_reglastparen ? "(no)" : ""));
        );
     }
-    DEBUG_EXECUTE_r(
+    DEBUG_BUFFERS_r(
        if (*PL_reglastparen + 1 <= rex->nparens) {
            PerlIO_printf(Perl_debug_log,
                          "     restoring \\%"IVdf"..\\%"IVdf" to undef\n",
        if (*PL_reglastparen + 1 <= rex->nparens) {
            PerlIO_printf(Perl_debug_log,
                          "     restoring \\%"IVdf"..\\%"IVdf" to undef\n",
@@ -269,13 +285,12 @@ S_regcppop(pTHX_ const regexp *rex)
      * requiring null fields (pat.t#187 and split.t#{13,14}
      * (as of patchlevel 7877)  will fail.  Then again,
      * this code seems to be necessary or otherwise
      * requiring null fields (pat.t#187 and split.t#{13,14}
      * (as of patchlevel 7877)  will fail.  Then again,
      * this code seems to be necessary or otherwise
-     * building DynaLoader will fail:
-     * "Error: '*' not in typemap in DynaLoader.xs, line 164"
-     * --jhi */
+     * this erroneously leaves $1 defined: "1" =~ /^(?:(\d)x)?\d$/
+     * --jhi updated by dapm */
     for (i = *PL_reglastparen + 1; i <= rex->nparens; i++) {
        if (i > PL_regsize)
     for (i = *PL_reglastparen + 1; i <= rex->nparens; i++) {
        if (i > PL_regsize)
-           PL_regstartp[i] = -1;
-       PL_regendp[i] = -1;
+           PL_regoffs[i].start = -1;
+       PL_regoffs[i].end = -1;
     }
 #endif
     return input;
     }
 #endif
     return input;
@@ -292,7 +307,7 @@ S_regcppop(pTHX_ const regexp *rex)
  - pregexec - match a regexp against a string
  */
 I32
  - pregexec - match a regexp against a string
  */
 I32
-Perl_pregexec(pTHX_ register regexp *prog, char *stringarg, register char *strend,
+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 */
         char *strbeg, I32 minend, SV *screamer, U32 nosave)
 /* strend: pointer to null at end of string */
 /* strbeg: real beginning of string */
@@ -356,10 +371,11 @@ Perl_pregexec(pTHX_ register regexp *prog, char *stringarg, register char *stren
    deleted from the finite automaton. */
 
 char *
    deleted from the finite automaton. */
 
 char *
-Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos,
-                    char *strend, U32 flags, re_scream_pos_data *data)
+Perl_re_intuit_start(pTHX_ REGEXP * const rx, SV *sv, char *strpos,
+                    char *strend, const U32 flags, re_scream_pos_data *data)
 {
     dVAR;
 {
     dVAR;
+    struct regexp *const prog = (struct regexp *)SvANY(rx);
     register I32 start_shift = 0;
     /* Should be nonnegative! */
     register I32 end_shift   = 0;
     register I32 start_shift = 0;
     /* Should be nonnegative! */
     register I32 end_shift   = 0;
@@ -372,19 +388,20 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos,
     register char *other_last = NULL;  /* other substr checked before this */
     char *check_at = NULL;             /* check substr found at this pos */
     const I32 multiline = prog->extflags & RXf_PMf_MULTILINE;
     register char *other_last = NULL;  /* other substr checked before this */
     char *check_at = NULL;             /* check substr found at this pos */
     const I32 multiline = prog->extflags & RXf_PMf_MULTILINE;
+    RXi_GET_DECL(prog,progi);
 #ifdef DEBUGGING
     const char * const i_strpos = strpos;
 #endif
 
     GET_RE_DEBUG_FLAGS_DECL;
 
 #ifdef DEBUGGING
     const char * const i_strpos = strpos;
 #endif
 
     GET_RE_DEBUG_FLAGS_DECL;
 
-    RX_MATCH_UTF8_set(prog,do_utf8);
+    RX_MATCH_UTF8_set(rx,do_utf8);
 
 
-    if (prog->extflags & RXf_UTF8) {
+    if (RX_UTF8(rx)) {
        PL_reg_flags |= RF_utf8;
     }
     DEBUG_EXECUTE_r( 
        PL_reg_flags |= RF_utf8;
     }
     DEBUG_EXECUTE_r( 
-        debug_start_match(prog, do_utf8, strpos, strend, 
+        debug_start_match(rx, do_utf8, strpos, strend, 
             sv ? "Guessing start of match in sv for"
                : "Guessing start of match in string for");
              );
             sv ? "Guessing start of match in sv for"
                : "Guessing start of match in string for");
              );
@@ -482,10 +499,10 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos,
        /* end shift should be non negative here */
     }
 
        /* end shift should be non negative here */
     }
 
-#ifdef DEBUGGING       /* 7/99: reports of failure (with the older version) */
+#ifdef QDEBUGGING      /* 7/99: reports of failure (with the older version) */
     if (end_shift < 0)
        Perl_croak(aTHX_ "panic: end_shift: %"IVdf" pattern:\n%s\n ",
     if (end_shift < 0)
        Perl_croak(aTHX_ "panic: end_shift: %"IVdf" pattern:\n%s\n ",
-                  (IV)end_shift, prog->precomp);
+                  (IV)end_shift, RX_PRECOMP(prog));
 #endif
 
   restart:
 #endif
 
   restart:
@@ -520,7 +537,7 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos,
        else
            goto fail_finish;
        /* we may be pointing at the wrong string */
        else
            goto fail_finish;
        /* we may be pointing at the wrong string */
-       if (s && RX_MATCH_COPIED(prog))
+       if (s && RXp_MATCH_COPIED(prog))
            s = strbeg + (s - SvPVX_const(sv));
        if (data)
            *data->scream_olds = s;
            s = strbeg + (s - SvPVX_const(sv));
        if (data)
            *data->scream_olds = s;
@@ -821,7 +838,7 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos,
        }
        DEBUG_EXECUTE_r( if (ml_anch)
            PerlIO_printf(Perl_debug_log, "Position at offset %ld does not contradict /%s^%s/m...\n",
        }
        DEBUG_EXECUTE_r( if (ml_anch)
            PerlIO_printf(Perl_debug_log, "Position at offset %ld does not contradict /%s^%s/m...\n",
-                       (long)(strpos - i_strpos), PL_colors[0], PL_colors[1]);
+                         (long)(strpos - i_strpos), PL_colors[0], PL_colors[1]);
        );
       success_at_start:
        if (!(prog->intflags & PREGf_NAUGHTY)   /* XXXX If strpos moved? */
        );
       success_at_start:
        if (!(prog->intflags & PREGf_NAUGHTY)   /* XXXX If strpos moved? */
@@ -857,7 +874,7 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos,
     /* XXXX BmUSEFUL already changed, maybe multiple change is meaningful... */
     /* trie stclasses are too expensive to use here, we are better off to
        leave it to regmatch itself */
     /* XXXX BmUSEFUL already changed, maybe multiple change is meaningful... */
     /* trie stclasses are too expensive to use here, we are better off to
        leave it to regmatch itself */
-    if (prog->regstclass && PL_regkind[OP(prog->regstclass)]!=TRIE) {
+    if (progi->regstclass && PL_regkind[OP(progi->regstclass)]!=TRIE) {
        /* minlen == 0 is possible if regstclass is \b or \B,
           and the fixed substr is ''$.
           Since minlen is already taken into account, s+1 is before strend;
        /* minlen == 0 is possible if regstclass is \b or \B,
           and the fixed substr is ''$.
           Since minlen is already taken into account, s+1 is before strend;
@@ -866,9 +883,9 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos,
           regstclass does not come from lookahead...  */
        /* If regstclass takes bytelength more than 1: If charlength==1, OK.
           This leaves EXACTF only, which is dealt with in find_byclass().  */
           regstclass does not come from lookahead...  */
        /* If regstclass takes bytelength more than 1: If charlength==1, OK.
           This leaves EXACTF only, which is dealt with in find_byclass().  */
-        const U8* const str = (U8*)STRING(prog->regstclass);
-        const int cl_l = (PL_regkind[OP(prog->regstclass)] == EXACT
-                   ? CHR_DIST(str+STR_LEN(prog->regstclass), str)
+        const U8* const str = (U8*)STRING(progi->regstclass);
+        const int cl_l = (PL_regkind[OP(progi->regstclass)] == EXACT
+                   ? CHR_DIST(str+STR_LEN(progi->regstclass), str)
                    : 1);
        char * endpos;
        if (prog->anchored_substr || prog->anchored_utf8 || ml_anch)
                    : 1);
        char * endpos;
        if (prog->anchored_substr || prog->anchored_utf8 || ml_anch)
@@ -878,11 +895,11 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos,
         else 
             endpos= strend;
                    
         else 
             endpos= strend;
                    
-        DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log, "start_shift: %"IVdf" check_at: %d s: %d endpos: %d\n",
-                                     (IV)start_shift, check_at - strbeg, s - strbeg, endpos - strbeg));
+        DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log, "start_shift: %"IVdf" check_at: %"IVdf" s: %"IVdf" endpos: %"IVdf"\n",
+                                     (IV)start_shift, (IV)(check_at - strbeg), (IV)(s - strbeg), (IV)(endpos - strbeg)));
        
        t = s;
        
        t = s;
-        s = find_byclass(prog, prog->regstclass, s, endpos, NULL);
+        s = find_byclass(prog, progi->regstclass, s, endpos, NULL);
        if (!s) {
 #ifdef DEBUGGING
            const char *what = NULL;
        if (!s) {
 #ifdef DEBUGGING
            const char *what = NULL;
@@ -973,10 +990,14 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos,
     return NULL;
 }
 
     return NULL;
 }
 
+#define DECL_TRIE_TYPE(scan) \
+    const enum { trie_plain, trie_utf8, trie_utf8_fold, trie_latin_utf8_fold } \
+                   trie_type = (scan->flags != EXACT) \
+                             ? (do_utf8 ? trie_utf8_fold : (UTF ? trie_latin_utf8_fold : trie_plain)) \
+                              : (do_utf8 ? trie_utf8 : trie_plain)
 
 
-
-#define REXEC_TRIE_READ_CHAR(trie_type, trie, uc, uscan, len, uvc, charid,  \
-foldlen, foldbuf, uniflags) STMT_START {                                    \
+#define REXEC_TRIE_READ_CHAR(trie_type, trie, widecharmap, uc, uscan, len,  \
+uvc, charid, foldlen, foldbuf, uniflags) STMT_START {                       \
     switch (trie_type) {                                                    \
     case trie_utf8_fold:                                                    \
        if ( foldlen>0 ) {                                                  \
     switch (trie_type) {                                                    \
     case trie_utf8_fold:                                                    \
        if ( foldlen>0 ) {                                                  \
@@ -991,6 +1012,19 @@ foldlen, foldbuf, uniflags) STMT_START {                                    \
            uscan = foldbuf + UNISKIP( uvc );                               \
        }                                                                   \
        break;                                                              \
            uscan = foldbuf + UNISKIP( uvc );                               \
        }                                                                   \
        break;                                                              \
+    case trie_latin_utf8_fold:                                              \
+       if ( foldlen>0 ) {                                                  \
+           uvc = utf8n_to_uvuni( uscan, UTF8_MAXLEN, &len, uniflags );     \
+           foldlen -= len;                                                 \
+           uscan += len;                                                   \
+           len=0;                                                          \
+       } else {                                                            \
+           len = 1;                                                        \
+           uvc = to_uni_fold( *(U8*)uc, foldbuf, &foldlen );               \
+           foldlen -= UNISKIP( uvc );                                      \
+           uscan = foldbuf + UNISKIP( uvc );                               \
+       }                                                                   \
+       break;                                                              \
     case trie_utf8:                                                         \
        uvc = utf8n_to_uvuni( (U8*)uc, UTF8_MAXLEN, &len, uniflags );       \
        break;                                                              \
     case trie_utf8:                                                         \
        uvc = utf8n_to_uvuni( (U8*)uc, UTF8_MAXLEN, &len, uniflags );       \
        break;                                                              \
@@ -1004,8 +1038,8 @@ foldlen, foldbuf, uniflags) STMT_START {                                    \
     }                                                                       \
     else {                                                                  \
        charid = 0;                                                         \
     }                                                                       \
     else {                                                                  \
        charid = 0;                                                         \
-       if (trie->widecharmap) {                                            \
-           SV** const svpp = hv_fetch(trie->widecharmap,                   \
+       if (widecharmap) {                                                  \
+           SV** const svpp = hv_fetch(widecharmap,                         \
                        (char*)&uvc, sizeof(UV), 0);                        \
            if (svpp)                                                       \
                charid = (U16)SvIV(*svpp);                                  \
                        (char*)&uvc, sizeof(UV), 0);                        \
            if (svpp)                                                       \
                charid = (U16)SvIV(*svpp);                                  \
@@ -1013,12 +1047,14 @@ foldlen, foldbuf, uniflags) STMT_START {                                    \
     }                                                                       \
 } STMT_END
 
     }                                                                       \
 } STMT_END
 
-#define REXEC_FBC_EXACTISH_CHECK(CoNd)                  \
+#define REXEC_FBC_EXACTISH_CHECK(CoNd)                 \
+{                                                      \
+    char *my_strend= (char *)strend;                   \
     if ( (CoNd)                                        \
         && (ln == len ||                              \
     if ( (CoNd)                                        \
         && (ln == len ||                              \
-            ibcmp_utf8(s, NULL, 0,  do_utf8,          \
+            !ibcmp_utf8(s, &my_strend, 0,  do_utf8,   \
                        m, NULL, ln, (bool)UTF))       \
                        m, NULL, ln, (bool)UTF))       \
-        && (!reginfo || regtry(reginfo, &s)) )         \
+        && (!reginfo || regtry(reginfo, &s)) )        \
        goto got_it;                                   \
     else {                                             \
         U8 foldbuf[UTF8_MAXBYTES_CASE+1];             \
        goto got_it;                                   \
     else {                                             \
         U8 foldbuf[UTF8_MAXBYTES_CASE+1];             \
@@ -1026,15 +1062,14 @@ foldlen, foldbuf, uniflags) STMT_START {                                    \
         f = to_utf8_fold(tmpbuf, foldbuf, &foldlen);  \
         if ( f != c                                   \
              && (f == c1 || f == c2)                  \
         f = to_utf8_fold(tmpbuf, foldbuf, &foldlen);  \
         if ( f != c                                   \
              && (f == c1 || f == c2)                  \
-             && (ln == foldlen ||                     \
-                 !ibcmp_utf8((char *) foldbuf,        \
-                             NULL, foldlen, do_utf8,  \
-                             m,                       \
-                             NULL, ln, (bool)UTF))    \
-             && (!reginfo || regtry(reginfo, &s)) )    \
+             && (ln == len ||                         \
+               !ibcmp_utf8(s, &my_strend, 0,  do_utf8,\
+                             m, NULL, ln, (bool)UTF)) \
+             && (!reginfo || regtry(reginfo, &s)) )   \
              goto got_it;                             \
     }                                                  \
              goto got_it;                             \
     }                                                  \
-    s += len
+}                                                      \
+s += len
 
 #define REXEC_FBC_EXACTISH_SCAN(CoNd)                     \
 STMT_START {                                              \
 
 #define REXEC_FBC_EXACTISH_SCAN(CoNd)                     \
 STMT_START {                                              \
@@ -1093,6 +1128,15 @@ REXEC_FBC_SCAN(                                       \
 if ((!reginfo || regtry(reginfo, &s))) \
     goto got_it
 
 if ((!reginfo || regtry(reginfo, &s))) \
     goto got_it
 
+#define REXEC_FBC_CSCAN(CoNdUtF8,CoNd)                         \
+    if (do_utf8) {                                             \
+       REXEC_FBC_UTF8_CLASS_SCAN(CoNdUtF8);                   \
+    }                                                          \
+    else {                                                     \
+       REXEC_FBC_CLASS_SCAN(CoNd);                            \
+    }                                                          \
+    break
+    
 #define REXEC_FBC_CSCAN_PRELOAD(UtFpReLoAd,CoNdUtF8,CoNd)      \
     if (do_utf8) {                                             \
        UtFpReLoAd;                                            \
 #define REXEC_FBC_CSCAN_PRELOAD(UtFpReLoAd,CoNdUtF8,CoNd)      \
     if (do_utf8) {                                             \
        UtFpReLoAd;                                            \
@@ -1136,7 +1180,8 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s,
        char *e;
        register I32 tmp = 1;   /* Scratch variable? */
        register const bool do_utf8 = PL_reg_match_utf8;
        char *e;
        register I32 tmp = 1;   /* Scratch variable? */
        register const bool do_utf8 = PL_reg_match_utf8;
-
+        RXi_GET_DECL(prog,progi);
+        
        /* We know what class it must start with. */
        switch (OP(c)) {
        case ANYOF:
        /* We know what class it must start with. */
        switch (OP(c)) {
        case ANYOF:
@@ -1183,15 +1228,28 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s,
                U8 *sm = (U8 *) m;
                U8 tmpbuf1[UTF8_MAXBYTES_CASE+1];
                U8 tmpbuf2[UTF8_MAXBYTES_CASE+1];
                U8 *sm = (U8 *) m;
                U8 tmpbuf1[UTF8_MAXBYTES_CASE+1];
                U8 tmpbuf2[UTF8_MAXBYTES_CASE+1];
-               const U32 uniflags = UTF8_ALLOW_DEFAULT;
-
-               to_utf8_lower((U8*)m, tmpbuf1, &ulen1);
-               to_utf8_upper((U8*)m, tmpbuf2, &ulen2);
-
+               /* used by commented-out code below */
+               /*const U32 uniflags = UTF8_ALLOW_DEFAULT;*/
+               
+                /* XXX: Since the node will be case folded at compile
+                   time this logic is a little odd, although im not 
+                   sure that its actually wrong. --dmq */
+                   
+               c1 = to_utf8_lower((U8*)m, tmpbuf1, &ulen1);
+               c2 = to_utf8_upper((U8*)m, tmpbuf2, &ulen2);
+
+               /* XXX: This is kinda strange. to_utf8_XYZ returns the 
+                   codepoint of the first character in the converted
+                   form, yet originally we did the extra step. 
+                   No tests fail by commenting this code out however
+                   so Ive left it out. -- dmq.
+                   
                c1 = utf8n_to_uvchr(tmpbuf1, UTF8_MAXBYTES_CASE, 
                                    0, uniflags);
                c2 = utf8n_to_uvchr(tmpbuf2, UTF8_MAXBYTES_CASE,
                                    0, uniflags);
                c1 = utf8n_to_uvchr(tmpbuf1, UTF8_MAXBYTES_CASE, 
                                    0, uniflags);
                c2 = utf8n_to_uvchr(tmpbuf2, UTF8_MAXBYTES_CASE,
                                    0, uniflags);
+                */
+                
                lnc = 0;
                while (sm < ((U8 *) m + ln)) {
                    lnc++;
                lnc = 0;
                while (sm < ((U8 *) m + ln)) {
                    lnc++;
@@ -1226,24 +1284,33 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s,
             * matching (called "loose matching" in Unicode).
             * ibcmp_utf8() will do just that. */
 
             * matching (called "loose matching" in Unicode).
             * ibcmp_utf8() will do just that. */
 
-           if (do_utf8) {
+           if (do_utf8 || UTF) {
                UV c, f;
                U8 tmpbuf [UTF8_MAXBYTES+1];
                UV c, f;
                U8 tmpbuf [UTF8_MAXBYTES+1];
-               STRLEN len, foldlen;
+               STRLEN len = 1;
+               STRLEN foldlen;
                const U32 uniflags = UTF8_ALLOW_DEFAULT;
                if (c1 == c2) {
                    /* Upper and lower of 1st char are equal -
                     * probably not a "letter". */
                    while (s <= e) {
                const U32 uniflags = UTF8_ALLOW_DEFAULT;
                if (c1 == c2) {
                    /* Upper and lower of 1st char are equal -
                     * probably not a "letter". */
                    while (s <= e) {
-                       c = utf8n_to_uvchr((U8*)s, UTF8_MAXBYTES, &len,
+                       if (do_utf8) {
+                           c = utf8n_to_uvchr((U8*)s, UTF8_MAXBYTES, &len,
                                           uniflags);
                                           uniflags);
+                        } else {
+                            c = *((U8*)s);
+                        }                                        
                        REXEC_FBC_EXACTISH_CHECK(c == c1);
                    }
                }
                else {
                    while (s <= e) {
                        REXEC_FBC_EXACTISH_CHECK(c == c1);
                    }
                }
                else {
                    while (s <= e) {
-                     c = utf8n_to_uvchr((U8*)s, UTF8_MAXBYTES, &len,
+                       if (do_utf8) {
+                           c = utf8n_to_uvchr((U8*)s, UTF8_MAXBYTES, &len,
                                           uniflags);
                                           uniflags);
+                        } else {
+                            c = *((U8*)s);
+                        }
 
                        /* Handle some of the three Greek sigmas cases.
                         * Note that not all the possible combinations
 
                        /* Handle some of the three Greek sigmas cases.
                         * Note that not all the possible combinations
@@ -1261,6 +1328,7 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s,
                }
            }
            else {
                }
            }
            else {
+               /* Neither pattern nor string are UTF8 */
                if (c1 == c2)
                    REXEC_FBC_EXACTISH_SCAN(*(U8*)s == c1);
                else
                if (c1 == c2)
                    REXEC_FBC_EXACTISH_SCAN(*(U8*)s == c1);
                else
@@ -1407,17 +1475,41 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s,
                !isDIGIT_LC_utf8((U8*)s),
                !isDIGIT_LC(*s)
            );
                !isDIGIT_LC_utf8((U8*)s),
                !isDIGIT_LC(*s)
            );
+       case LNBREAK:
+           REXEC_FBC_CSCAN(
+               is_LNBREAK_utf8(s),
+               is_LNBREAK_latin1(s)
+           );
+       case VERTWS:
+           REXEC_FBC_CSCAN(
+               is_VERTWS_utf8(s),
+               is_VERTWS_latin1(s)
+           );
+       case NVERTWS:
+           REXEC_FBC_CSCAN(
+               !is_VERTWS_utf8(s),
+               !is_VERTWS_latin1(s)
+           );
+       case HORIZWS:
+           REXEC_FBC_CSCAN(
+               is_HORIZWS_utf8(s),
+               is_HORIZWS_latin1(s)
+           );
+       case NHORIZWS:
+           REXEC_FBC_CSCAN(
+               !is_HORIZWS_utf8(s),
+               !is_HORIZWS_latin1(s)
+           );      
        case AHOCORASICKC:
        case AHOCORASICK: 
            {
        case AHOCORASICKC:
        case AHOCORASICK: 
            {
-               const enum { trie_plain, trie_utf8, trie_utf8_fold }
-                   trie_type = do_utf8 ?
-                         (c->flags == EXACT ? trie_utf8 : trie_utf8_fold)
-                       : trie_plain;
+               DECL_TRIE_TYPE(c);
                 /* what trie are we using right now */
                reg_ac_data *aho
                 /* what trie are we using right now */
                reg_ac_data *aho
-                   = (reg_ac_data*)prog->data->data[ ARG( c ) ];
-               reg_trie_data *trie=aho->trie;
+                   = (reg_ac_data*)progi->data->data[ ARG( c ) ];
+               reg_trie_data *trie
+                   = (reg_trie_data*)progi->data->data[ aho->trie ];
+               HV *widecharmap = (HV*) progi->data->data[ aho->trie + 1 ];
 
                const char *last_start = strend - trie->minlen;
 #ifdef DEBUGGING
 
                const char *last_start = strend - trie->minlen;
 #ifdef DEBUGGING
@@ -1428,8 +1520,8 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s,
                U8 **points; /* map of where we were in the input string
                                when reading a given char. For ASCII this
                                is unnecessary overhead as the relationship
                U8 **points; /* map of where we were in the input string
                                when reading a given char. For ASCII this
                                is unnecessary overhead as the relationship
-                               is always 1:1, but for unicode, especially
-                               case folded unicode this is not true. */
+                               is always 1:1, but for Unicode, especially
+                               case folded Unicode this is not true. */
                U8 foldbuf[ UTF8_MAXBYTES_CASE + 1 ];
                U8 *bitmap=NULL;
 
                U8 foldbuf[ UTF8_MAXBYTES_CASE + 1 ];
                U8 *bitmap=NULL;
 
@@ -1520,8 +1612,9 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s,
                             
                         }
                         points[pointpos++ % maxlen]= uc;
                             
                         }
                         points[pointpos++ % maxlen]= uc;
-                       REXEC_TRIE_READ_CHAR(trie_type, trie, uc, uscan, len,
-                           uvc, charid, foldlen, foldbuf, uniflags);
+                       REXEC_TRIE_READ_CHAR(trie_type, trie, widecharmap, uc,
+                                            uscan, len, uvc, charid, foldlen,
+                                            foldbuf, uniflags);
                         DEBUG_TRIE_EXECUTE_r({
                             dump_exec_pos( (char *)uc, c, strend, real_start, 
                                 s,   do_utf8 );
                         DEBUG_TRIE_EXECUTE_r({
                             dump_exec_pos( (char *)uc, c, strend, real_start, 
                                 s,   do_utf8 );
@@ -1594,8 +1687,8 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s,
                         s = (char*)leftmost;
                         DEBUG_TRIE_EXECUTE_r({
                             PerlIO_printf( 
                         s = (char*)leftmost;
                         DEBUG_TRIE_EXECUTE_r({
                             PerlIO_printf( 
-                                Perl_debug_log,"Matches word #%"UVxf" at position %d. Trying full pattern...\n",
-                                (UV)accepted_word, s - real_start
+                                Perl_debug_log,"Matches word #%"UVxf" at position %"IVdf". Trying full pattern...\n",
+                                (UV)accepted_word, (IV)(s - real_start)
                             );
                         });
                         if (!reginfo || regtry(reginfo, &s)) {
                             );
                         });
                         if (!reginfo || regtry(reginfo, &s)) {
@@ -1626,11 +1719,31 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s,
        return s;
 }
 
        return s;
 }
 
+static void 
+S_swap_match_buff (pTHX_ regexp *prog) {
+    regexp_paren_pair *t;
+
+    if (!prog->swap) {
+    /* We have to be careful. If the previous successful match
+       was from this regex we don't want a subsequent paritally
+       successful match to clobber the old results. 
+       So when we detect this possibility we add a swap buffer
+       to the re, and switch the buffer each match. If we fail
+       we switch it back, otherwise we leave it swapped.
+    */
+        Newxz(prog->swap, (prog->nparens + 1), regexp_paren_pair);
+    }
+    t = prog->swap;
+    prog->swap = prog->offs;
+    prog->offs = t;
+}    
+
+
 /*
  - regexec_flags - match a regexp against a string
  */
 I32
 /*
  - regexec_flags - match a regexp against a string
  */
 I32
-Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char *strend,
+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 */
              char *strbeg, I32 minend, SV *sv, void *data, U32 flags)
 /* strend: pointer to null at end of string */
 /* strbeg: real beginning of string */
@@ -1641,6 +1754,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char *
 /* nosave: For optimizations. */
 {
     dVAR;
 /* nosave: For optimizations. */
 {
     dVAR;
+    struct regexp *const prog = (struct regexp *)SvANY(rx);
     /*register*/ char *s;
     register regnode *c;
     /*register*/ char *startpos = stringarg;
     /*register*/ char *s;
     register regnode *c;
     /*register*/ char *startpos = stringarg;
@@ -1649,11 +1763,11 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char *
     I32 end_shift = 0;                 /* Same for the end. */         /* CC */
     I32 scream_pos = -1;               /* Internal iterator of scream. */
     char *scream_olds = NULL;
     I32 end_shift = 0;                 /* Same for the end. */         /* CC */
     I32 scream_pos = -1;               /* Internal iterator of scream. */
     char *scream_olds = NULL;
-    SV* const oreplsv = GvSV(PL_replgv);
     const bool do_utf8 = (bool)DO_UTF8(sv);
     I32 multiline;
     const bool do_utf8 = (bool)DO_UTF8(sv);
     I32 multiline;
-
+    RXi_GET_DECL(prog,progi);
     regmatch_info reginfo;  /* create some info to pass to regtry etc */
     regmatch_info reginfo;  /* create some info to pass to regtry etc */
+    bool swap_on_fail = 0;
 
     GET_RE_DEBUG_FLAGS_DECL;
 
 
     GET_RE_DEBUG_FLAGS_DECL;
 
@@ -1666,11 +1780,11 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char *
     }
 
     multiline = prog->extflags & RXf_PMf_MULTILINE;
     }
 
     multiline = prog->extflags & RXf_PMf_MULTILINE;
-    reginfo.prog = prog;
+    reginfo.prog = rx;  /* Yes, sorry that this is confusing.  */
 
 
-    RX_MATCH_UTF8_set(prog, do_utf8);
+    RX_MATCH_UTF8_set(rx, do_utf8);
     DEBUG_EXECUTE_r( 
     DEBUG_EXECUTE_r( 
-        debug_start_match(prog, do_utf8, startpos, strend, 
+        debug_start_match(rx, do_utf8, startpos, strend, 
         "Matching");
     );
 
         "Matching");
     );
 
@@ -1684,7 +1798,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char *
 
     
     /* Check validity of program. */
 
     
     /* Check validity of program. */
-    if (UCHARAT(prog->program) != REG_MAGIC) {
+    if (UCHARAT(progi->program) != REG_MAGIC) {
        Perl_croak(aTHX_ "corrupted regexp program");
     }
 
        Perl_croak(aTHX_ "corrupted regexp program");
     }
 
@@ -1692,7 +1806,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char *
     PL_reg_eval_set = 0;
     PL_reg_maxiter = 0;
 
     PL_reg_eval_set = 0;
     PL_reg_maxiter = 0;
 
-    if (prog->extflags & RXf_UTF8)
+    if (RX_UTF8(rx))
        PL_reg_flags |= RF_utf8;
 
     /* Mark beginning of line for ^ and lookbehind. */
        PL_reg_flags |= RF_utf8;
 
     /* Mark beginning of line for ^ and lookbehind. */
@@ -1726,38 +1840,21 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char *
            }
        }
        else if (data) {
            }
        }
        else if (data) {
-           reginfo.ganch = strbeg + (UV)data;
+           reginfo.ganch = strbeg + PTR2UV(data);
        } else                          /* pos() not defined */
            reginfo.ganch = strbeg;
     }
        } else                          /* pos() not defined */
            reginfo.ganch = strbeg;
     }
-    if (PL_curpm && (PM_GETRE(PL_curpm) == prog)) {
-        I32 *t;
-        if (!prog->swap) {
-        /* We have to be careful. If the previous successful match
-           was from this regex we don't want a subsequent paritally
-           successful match to clobber the old results. 
-           So when we detect this possibility we add a swap buffer
-           to the re, and switch the buffer each match. If we fail
-           we switch it back, otherwise we leave it swapped.
-        */
-            Newxz(prog->swap, 1, regexp_paren_ofs);
-            /* no need to copy these */
-            Newxz(prog->swap->startp, prog->nparens + 1, I32);
-            Newxz(prog->swap->endp, prog->nparens + 1, I32);
-        }
-        t = prog->swap->startp;
-        prog->swap->startp = prog->startp;
-        prog->startp = t;
-        t = prog->swap->endp;
-        prog->swap->endp = prog->endp;
-        prog->endp = t;
+    if (PL_curpm && (PM_GETRE(PL_curpm) == rx)) {
+        swap_on_fail = 1;
+        swap_match_buff(prog); /* do we need a save destructor here for
+                                  eval dies? */
     }
     if (!(flags & REXEC_CHECKED) && (prog->check_substr != NULL || prog->check_utf8 != NULL)) {
        re_scream_pos_data d;
 
        d.scream_olds = &scream_olds;
        d.scream_pos = &scream_pos;
     }
     if (!(flags & REXEC_CHECKED) && (prog->check_substr != NULL || prog->check_utf8 != NULL)) {
        re_scream_pos_data d;
 
        d.scream_olds = &scream_olds;
        d.scream_pos = &scream_pos;
-       s = re_intuit_start(prog, sv, s, strend, flags, &d);
+       s = re_intuit_start(rx, sv, s, strend, flags, &d);
        if (!s) {
            DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log, "Not present...\n"));
            goto phooey;        /* not present */
        if (!s) {
            DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log, "Not present...\n"));
            goto phooey;        /* not present */
@@ -1787,10 +1884,10 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char *
                    if (regtry(&reginfo, &s))
                        goto got_it;
                  after_try:
                    if (regtry(&reginfo, &s))
                        goto got_it;
                  after_try:
-                   if (s >= end)
+                   if (s > end)
                        goto phooey;
                    if (prog->extflags & RXf_USE_INTUIT) {
                        goto phooey;
                    if (prog->extflags & RXf_USE_INTUIT) {
-                       s = re_intuit_start(prog, sv, s + 1, strend, flags, NULL);
+                       s = re_intuit_start(rx, sv, s + 1, strend, flags, NULL);
                        if (!s)
                            goto phooey;
                    }
                        if (!s)
                            goto phooey;
                    }
@@ -1914,7 +2011,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char *
                                  (unsigned char*)strend, must,
                                  multiline ? FBMrf_MULTILINE : 0))) ) {
            /* we may be pointing at the wrong string */
                                  (unsigned char*)strend, must,
                                  multiline ? FBMrf_MULTILINE : 0))) ) {
            /* we may be pointing at the wrong string */
-           if ((flags & REXEC_SCREAM) && RX_MATCH_COPIED(prog))
+           if ((flags & REXEC_SCREAM) && RXp_MATCH_COPIED(prog))
                s = strbeg + (s - SvPVX_const(sv));
            DEBUG_EXECUTE_r( did_match = 1 );
            if (HOPc(s, -back_max) > last1) {
                s = strbeg + (s - SvPVX_const(sv));
            DEBUG_EXECUTE_r( did_match = 1 );
            if (HOPc(s, -back_max) > last1) {
@@ -1952,9 +2049,9 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char *
         });                
        goto phooey;
     }
         });                
        goto phooey;
     }
-    else if ( (c = prog->regstclass) ) {
+    else if ( (c = progi->regstclass) ) {
        if (minlen) {
        if (minlen) {
-           const OPCODE op = OP(prog->regstclass);
+           const OPCODE op = OP(progi->regstclass);
            /* don't bother with what can't match */
            if (PL_regkind[op] != EXACT && op != CANY && PL_regkind[op] != TRIE)
                strend = HOPc(strend, -(minlen - 1));
            /* don't bother with what can't match */
            if (PL_regkind[op] != EXACT && op != CANY && PL_regkind[op] != TRIE)
                strend = HOPc(strend, -(minlen - 1));
@@ -1963,7 +2060,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char *
            SV * const prop = sv_newmortal();
            regprop(prog, prop, c);
            {
            SV * const prop = sv_newmortal();
            regprop(prog, prop, c);
            {
-               RE_PV_QUOTED_DECL(quoted,UTF,PERL_DEBUG_PAD_ZERO(1),
+               RE_PV_QUOTED_DECL(quoted,do_utf8,PERL_DEBUG_PAD_ZERO(1),
                    s,strend-s,60);
                PerlIO_printf(Perl_debug_log,
                    "Matching stclass %.*s against %s (%d chars)\n",
                    s,strend-s,60);
                PerlIO_printf(Perl_debug_log,
                    "Matching stclass %.*s against %s (%d chars)\n",
@@ -1992,7 +2089,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char *
                if (!last)
                    last = scream_olds; /* Only one occurrence. */
                /* we may be pointing at the wrong string */
                if (!last)
                    last = scream_olds; /* Only one occurrence. */
                /* we may be pointing at the wrong string */
-               else if (RX_MATCH_COPIED(prog))
+               else if (RXp_MATCH_COPIED(prog))
                    s = strbeg + (s - SvPVX_const(sv));
            }
            else {
                    s = strbeg + (s - SvPVX_const(sv));
            }
            else {
@@ -2049,22 +2146,16 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char *
     goto phooey;
 
 got_it:
     goto phooey;
 
 got_it:
-    RX_MATCH_TAINTED_set(prog, PL_reg_flags & RF_tainted);
+    RX_MATCH_TAINTED_set(rx, PL_reg_flags & RF_tainted);
 
 
-    if (PL_reg_eval_set) {
-       /* Preserve the current value of $^R */
-       if (oreplsv != GvSV(PL_replgv))
-           sv_setsv(oreplsv, GvSV(PL_replgv));/* So that when GvSV(replgv) is
-                                                 restored, the value remains
-                                                 the same. */
+    if (PL_reg_eval_set)
        restore_pos(aTHX_ prog);
        restore_pos(aTHX_ prog);
-    }
     if (prog->paren_names) 
         (void)hv_iterinit(prog->paren_names);
 
     /* make sure $`, $&, $', and $digit will work later */
     if ( !(flags & REXEC_NOT_FIRST) ) {
     if (prog->paren_names) 
         (void)hv_iterinit(prog->paren_names);
 
     /* make sure $`, $&, $', and $digit will work later */
     if ( !(flags & REXEC_NOT_FIRST) ) {
-       RX_MATCH_COPY_FREE(prog);
+       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 (flags & REXEC_COPY_STR) {
            const I32 i = PL_regeol - startpos + (stringarg - strbeg);
 #ifdef PERL_OLD_COPY_ON_WRITE
@@ -2081,7 +2172,7 @@ got_it:
            } else
 #endif
            {
            } else
 #endif
            {
-               RX_MATCH_COPIED_on(prog);
+               RX_MATCH_COPIED_on(rx);
                s = savepvn(strbeg, i);
                prog->subbeg = s;
            }
                s = savepvn(strbeg, i);
                prog->subbeg = s;
            }
@@ -2100,16 +2191,10 @@ phooey:
                          PL_colors[4], PL_colors[5]));
     if (PL_reg_eval_set)
        restore_pos(aTHX_ prog);
                          PL_colors[4], PL_colors[5]));
     if (PL_reg_eval_set)
        restore_pos(aTHX_ prog);
-    if (prog->swap) {
+    if (swap_on_fail) 
         /* we failed :-( roll it back */
         /* we failed :-( roll it back */
-        I32 *t;
-        t = prog->swap->startp;
-        prog->swap->startp = prog->startp;
-        prog->startp = t;
-        t = prog->swap->endp;
-        prog->swap->endp = prog->endp;
-        prog->endp = t;
-    }
+        swap_match_buff(prog);
+    
     return 0;
 }
 
     return 0;
 }
 
@@ -2121,10 +2206,10 @@ STATIC I32                      /* 0 failure, 1 success */
 S_regtry(pTHX_ regmatch_info *reginfo, char **startpos)
 {
     dVAR;
 S_regtry(pTHX_ regmatch_info *reginfo, char **startpos)
 {
     dVAR;
-    register I32 *sp;
-    register I32 *ep;
     CHECKPOINT lastcp;
     CHECKPOINT lastcp;
-    regexp *prog = reginfo->prog;
+    REGEXP *const rx = reginfo->prog;
+    regexp *const prog = (struct regexp *)SvANY(rx);
+    RXi_GET_DECL(prog,progi);
     GET_RE_DEBUG_FLAGS_DECL;
     reginfo->cutpoint=NULL;
 
     GET_RE_DEBUG_FLAGS_DECL;
     reginfo->cutpoint=NULL;
 
@@ -2179,10 +2264,10 @@ S_regtry(pTHX_ regmatch_info *reginfo, char **startpos)
             }
 #endif      
         }
             }
 #endif      
         }
-       PM_SETRE(PL_reg_curpm, prog);
+       PM_SETRE(PL_reg_curpm, rx);
        PL_reg_oldcurpm = PL_curpm;
        PL_curpm = PL_reg_curpm;
        PL_reg_oldcurpm = PL_curpm;
        PL_curpm = PL_reg_curpm;
-       if (RX_MATCH_COPIED(prog)) {
+       if (RXp_MATCH_COPIED(prog)) {
            /*  Here is a serious problem: we cannot rewrite subbeg,
                since it may be needed if this match fails.  Thus
                $` inside (?{}) could fail... */
            /*  Here is a serious problem: we cannot rewrite subbeg,
                since it may be needed if this match fails.  Thus
                $` inside (?{}) could fail... */
@@ -2191,7 +2276,7 @@ S_regtry(pTHX_ regmatch_info *reginfo, char **startpos)
 #ifdef PERL_OLD_COPY_ON_WRITE
            PL_nrs = prog->saved_copy;
 #endif
 #ifdef PERL_OLD_COPY_ON_WRITE
            PL_nrs = prog->saved_copy;
 #endif
-           RX_MATCH_COPIED_off(prog);
+           RXp_MATCH_COPIED_off(prog);
        }
        else
            PL_reg_oldsaved = NULL;
        }
        else
            PL_reg_oldsaved = NULL;
@@ -2199,15 +2284,14 @@ S_regtry(pTHX_ regmatch_info *reginfo, char **startpos)
        prog->sublen = PL_regeol - PL_bostr; /* strend may have been modified */
     }
     DEBUG_EXECUTE_r(PL_reg_starttry = *startpos);
        prog->sublen = PL_regeol - PL_bostr; /* strend may have been modified */
     }
     DEBUG_EXECUTE_r(PL_reg_starttry = *startpos);
-    prog->startp[0] = *startpos - PL_bostr;
+    prog->offs[0].start = *startpos - PL_bostr;
     PL_reginput = *startpos;
     PL_reglastparen = &prog->lastparen;
     PL_reglastcloseparen = &prog->lastcloseparen;
     prog->lastparen = 0;
     prog->lastcloseparen = 0;
     PL_regsize = 0;
     PL_reginput = *startpos;
     PL_reglastparen = &prog->lastparen;
     PL_reglastcloseparen = &prog->lastcloseparen;
     prog->lastparen = 0;
     prog->lastcloseparen = 0;
     PL_regsize = 0;
-    PL_regstartp = prog->startp;
-    PL_regendp = prog->endp;
+    PL_regoffs = prog->offs;
     if (PL_reg_start_tmpl <= prog->nparens) {
        PL_reg_start_tmpl = prog->nparens*3/2 + 3;
         if(PL_reg_start_tmp)
     if (PL_reg_start_tmpl <= prog->nparens) {
        PL_reg_start_tmpl = prog->nparens*3/2 + 3;
         if(PL_reg_start_tmp)
@@ -2223,27 +2307,26 @@ S_regtry(pTHX_ regmatch_info *reginfo, char **startpos)
     /* Tests pat.t#187 and split.t#{13,14} seem to depend on this code.
      * Actually, the code in regcppop() (which Ilya may be meaning by
      * PL_reglastparen), is not needed at all by the test suite
     /* Tests pat.t#187 and split.t#{13,14} seem to depend on this code.
      * Actually, the code in regcppop() (which Ilya may be meaning by
      * PL_reglastparen), is not needed at all by the test suite
-     * (op/regexp, op/pat, op/split), but that code is needed, oddly
-     * enough, for building DynaLoader, or otherwise this
-     * "Error: '*' not in typemap in DynaLoader.xs, line 164"
-     * will happen.  Meanwhile, this code *is* needed for the
+     * (op/regexp, op/pat, op/split), but that code is needed otherwise
+     * this erroneously leaves $1 defined: "1" =~ /^(?:(\d)x)?\d$/
+     * Meanwhile, this code *is* needed for the
      * above-mentioned test suite tests to succeed.  The common theme
      * on those tests seems to be returning null fields from matches.
      * above-mentioned test suite tests to succeed.  The common theme
      * on those tests seems to be returning null fields from matches.
-     * --jhi */
+     * --jhi updated by dapm */
 #if 1
 #if 1
-    sp = PL_regstartp;
-    ep = PL_regendp;
     if (prog->nparens) {
     if (prog->nparens) {
+       regexp_paren_pair *pp = PL_regoffs;
        register I32 i;
        for (i = prog->nparens; i > (I32)*PL_reglastparen; i--) {
        register I32 i;
        for (i = prog->nparens; i > (I32)*PL_reglastparen; i--) {
-           *++sp = -1;
-           *++ep = -1;
+           ++pp;
+           pp->start = -1;
+           pp->end = -1;
        }
     }
 #endif
     REGCP_SET(lastcp);
        }
     }
 #endif
     REGCP_SET(lastcp);
-    if (regmatch(reginfo, prog->program + 1)) {
-       PL_regendp[0] = PL_reginput - PL_bostr;
+    if (regmatch(reginfo, progi->program + 1)) {
+       PL_regoffs[0].end = PL_reginput - PL_bostr;
        return 1;
     }
     if (reginfo->cutpoint)
        return 1;
     }
     if (reginfo->cutpoint)
@@ -2285,7 +2368,7 @@ S_regtry(pTHX_ regmatch_info *reginfo, char **startpos)
 STATIC regmatch_state *
 S_push_slab(pTHX)
 {
 STATIC regmatch_state *
 S_push_slab(pTHX)
 {
-#if PERL_VERSION < 9
+#if PERL_VERSION < 9 && !defined(PERL_CORE)
     dMY_CXT;
 #endif
     regmatch_slab *s = PL_regmatch_slab->next;
     dMY_CXT;
 #endif
     regmatch_slab *s = PL_regmatch_slab->next;
@@ -2456,7 +2539,7 @@ regmatch(), slabs allocated since entry are freed.
        PerlIO_printf(Perl_debug_log,                       \
            "    %*s"pp" %s%s%s%s%s\n",                     \
            depth*2, "",                                    \
        PerlIO_printf(Perl_debug_log,                       \
            "    %*s"pp" %s%s%s%s%s\n",                     \
            depth*2, "",                                    \
-           reg_name[st->resume_state],                     \
+           PL_reg_name[st->resume_state],                     \
            ((st==yes_state||st==mark_state) ? "[" : ""),   \
            ((st==yes_state) ? "Y" : ""),                   \
            ((st==mark_state) ? "M" : ""),                  \
            ((st==yes_state||st==mark_state) ? "[" : ""),   \
            ((st==yes_state) ? "Y" : ""),                   \
            ((st==mark_state) ? "M" : ""),                  \
@@ -2470,15 +2553,15 @@ regmatch(), slabs allocated since entry are freed.
 #ifdef DEBUGGING
 
 STATIC void
 #ifdef DEBUGGING
 
 STATIC void
-S_debug_start_match(pTHX_ const regexp *prog, const bool do_utf8, 
+S_debug_start_match(pTHX_ const REGEXP *prog, const bool do_utf8, 
     const char *start, const char *end, const char *blurb)
 {
     const char *start, const char *end, const char *blurb)
 {
-    const bool utf8_pat= prog->extflags & RXf_UTF8 ? 1 : 0;
+    const bool utf8_pat = RX_UTF8(prog) ? 1 : 0;
     if (!PL_colorset)   
             reginitcolors();    
     {
         RE_PV_QUOTED_DECL(s0, utf8_pat, PERL_DEBUG_PAD_ZERO(0), 
     if (!PL_colorset)   
             reginitcolors();    
     {
         RE_PV_QUOTED_DECL(s0, utf8_pat, PERL_DEBUG_PAD_ZERO(0), 
-            prog->precomp, prog->prelen, 60);   
+            RX_PRECOMP(prog), RX_PRELEN(prog), 60);   
         
         RE_PV_QUOTED_DECL(s1, do_utf8, PERL_DEBUG_PAD_ZERO(1), 
             start, end - start, 60); 
         
         RE_PV_QUOTED_DECL(s1, do_utf8, PERL_DEBUG_PAD_ZERO(1), 
             start, end - start, 60); 
@@ -2569,11 +2652,12 @@ S_dump_exec_pos(pTHX_ const char *locinput,
 STATIC I32
 S_reg_check_named_buff_matched(pTHX_ const regexp *rex, const regnode *scan) {
     I32 n;
 STATIC I32
 S_reg_check_named_buff_matched(pTHX_ const regexp *rex, const regnode *scan) {
     I32 n;
-    SV *sv_dat=(SV*)rex->data->data[ ARG( scan ) ];
+    RXi_GET_DECL(rex,rexi);
+    SV *sv_dat=(SV*)rexi->data->data[ ARG( scan ) ];
     I32 *nums=(I32*)SvPVX(sv_dat);
     for ( n=0; n<SvIVX(sv_dat); n++ ) {
         if ((I32)*PL_reglastparen >= nums[n] &&
     I32 *nums=(I32*)SvPVX(sv_dat);
     for ( n=0; n<SvIVX(sv_dat); n++ ) {
         if ((I32)*PL_reglastparen >= nums[n] &&
-            PL_regendp[nums[n]] != -1)
+            PL_regoffs[nums[n]].end != -1)
         {
             return nums[n];
         }
         {
             return nums[n];
         }
@@ -2581,20 +2665,45 @@ S_reg_check_named_buff_matched(pTHX_ const regexp *rex, const regnode *scan) {
     return 0;
 }
 
     return 0;
 }
 
+
+/* free all slabs above current one  - called during LEAVE_SCOPE */
+
+STATIC void
+S_clear_backtrack_stack(pTHX_ void *p)
+{
+    regmatch_slab *s = PL_regmatch_slab->next;
+    PERL_UNUSED_ARG(p);
+
+    if (!s)
+       return;
+    PL_regmatch_slab->next = NULL;
+    while (s) {
+       regmatch_slab * const osl = s;
+       s = s->next;
+       Safefree(osl);
+    }
+}
+
+
+#define SETREX(Re1,Re2) \
+    if (PL_reg_eval_set) PM_SETRE((PL_reg_curpm), (Re2)); \
+    Re1 = (Re2)
+
 STATIC I32                     /* 0 failure, 1 success */
 S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
 {
 STATIC I32                     /* 0 failure, 1 success */
 S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
 {
-#if PERL_VERSION < 9
+#if PERL_VERSION < 9 && !defined(PERL_CORE)
     dMY_CXT;
 #endif
     dVAR;
     register const bool do_utf8 = PL_reg_match_utf8;
     const U32 uniflags = UTF8_ALLOW_DEFAULT;
 
     dMY_CXT;
 #endif
     dVAR;
     register const bool do_utf8 = PL_reg_match_utf8;
     const U32 uniflags = UTF8_ALLOW_DEFAULT;
 
-    regexp *rex = reginfo->prog;
-
-    regmatch_slab  *orig_slab;
-    regmatch_state *orig_state;
+    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;
 
     /* the current state. This is a cached copy of PL_regmatch_state */
     register regmatch_state *st;
@@ -2609,7 +2718,11 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
 
     bool result = 0;       /* return value of S_regmatch */
     int depth = 0;         /* depth of backtrack stack */
 
     bool result = 0;       /* return value of S_regmatch */
     int depth = 0;         /* depth of backtrack stack */
-    int nochange_depth = 0; /* depth of GOSUB recursion with nochange*/
+    U32 nochange_depth = 0; /* depth of GOSUB recursion with nochange */
+    const U32 max_nochange_depth =
+        (3 * rex->nparens > MAX_RECURSE_EVAL_NOCHANGE_DEPTH) ?
+        3 * rex->nparens : MAX_RECURSE_EVAL_NOCHANGE_DEPTH;
+            
     regmatch_state *yes_state = NULL; /* state to pop to on success of
                                                            subpattern */
     /* mark_state piggy backs on the yes_state logic so that when we unwind 
     regmatch_state *yes_state = NULL; /* state to pop to on success of
                                                            subpattern */
     /* mark_state piggy backs on the yes_state logic so that when we unwind 
@@ -2628,6 +2741,8 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                                during a successfull match */
     U32 lastopen = 0;       /* last open we saw */
     bool has_cutgroup = RX_HAS_CUTGROUP(rex) ? 1 : 0;   
                                during a successfull match */
     U32 lastopen = 0;       /* last open we saw */
     bool has_cutgroup = RX_HAS_CUTGROUP(rex) ? 1 : 0;   
+
+    SV* const oreplsv = GvSV(PL_replgv);
                
     
     /* these three flags are set by various ops to signal information to
                
     
     /* these three flags are set by various ops to signal information to
@@ -2649,9 +2764,9 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
     GET_RE_DEBUG_FLAGS_DECL;
 #endif
 
     GET_RE_DEBUG_FLAGS_DECL;
 #endif
 
-    DEBUG_OPTIMISE_r( {    
+    DEBUG_OPTIMISE_r( DEBUG_EXECUTE_r({
            PerlIO_printf(Perl_debug_log,"regmatch start\n");
            PerlIO_printf(Perl_debug_log,"regmatch start\n");
-    });
+    }));
     /* on first ever call to regmatch, allocate first slab */
     if (!PL_regmatch_slab) {
        Newx(PL_regmatch_slab, 1, regmatch_slab);
     /* on first ever call to regmatch, allocate first slab */
     if (!PL_regmatch_slab) {
        Newx(PL_regmatch_slab, 1, regmatch_slab);
@@ -2660,10 +2775,10 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
        PL_regmatch_state = SLAB_FIRST(PL_regmatch_slab);
     }
 
        PL_regmatch_state = SLAB_FIRST(PL_regmatch_slab);
     }
 
-    /* remember current high-water mark for exit */
-    /* XXX this should be done with SAVE* instead */
-    orig_slab  = PL_regmatch_slab;
-    orig_state = PL_regmatch_state;
+    oldsave = PL_savestack_ix;
+    SAVEDESTRUCTOR_X(S_clear_backtrack_stack, NULL);
+    SAVEVPTR(PL_regmatch_slab);
+    SAVEVPTR(PL_regmatch_state);
 
     /* grab next free state slot */
     st = ++PL_regmatch_state;
 
     /* grab next free state slot */
     st = ++PL_regmatch_state;
@@ -2683,10 +2798,10 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
             
            PerlIO_printf(Perl_debug_log,
                    "%3"IVdf":%*s%s(%"IVdf")\n",
             
            PerlIO_printf(Perl_debug_log,
                    "%3"IVdf":%*s%s(%"IVdf")\n",
-                   (IV)(scan - rex->program), depth*2, "",
+                   (IV)(scan - rexi->program), depth*2, "",
                    SvPVX_const(prop),
                    (PL_regkind[OP(scan)] == END || !rnext) ? 
                    SvPVX_const(prop),
                    (PL_regkind[OP(scan)] == END || !rnext) ? 
-                       0 : (IV)(rnext - rex->program));
+                       0 : (IV)(rnext - rexi->program));
        });
 
        next = scan + NEXT_OFF(scan);
        });
 
        next = scan + NEXT_OFF(scan);
@@ -2718,6 +2833,19 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
            if (locinput == reginfo->ganch)
                break;
            sayNO;
            if (locinput == reginfo->ganch)
                break;
            sayNO;
+
+       case KEEPS:
+           /* update the startpoint */
+           st->u.keeper.val = PL_regoffs[0].start;
+           PL_reginput = locinput;
+           PL_regoffs[0].start = locinput - PL_bostr;
+           PUSH_STATE_GOTO(KEEPS_next, next);
+           /*NOT-REACHED*/
+       case KEEPS_next_fail:
+           /* rollback the start point change */
+           PL_regoffs[0].start = st->u.keeper.val;
+           sayNO_SILENT;
+           /*NOT-REACHED*/
        case EOL:
                goto seol;
        case MEOL:
        case EOL:
                goto seol;
        case MEOL:
@@ -2786,14 +2914,12 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
        case TRIE:
            {
                 /* what type of TRIE am I? (utf8 makes this contextual) */
        case TRIE:
            {
                 /* what type of TRIE am I? (utf8 makes this contextual) */
-               const enum { trie_plain, trie_utf8, trie_utf8_fold }
-                   trie_type = do_utf8 ?
-                         (scan->flags == EXACT ? trie_utf8 : trie_utf8_fold)
-                       : trie_plain;
+                DECL_TRIE_TYPE(scan);
 
                 /* what trie are we using right now */
                reg_trie_data * const trie
 
                 /* what trie are we using right now */
                reg_trie_data * const trie
-                   = (reg_trie_data*)rex->data->data[ ARG( scan ) ];
+                   = (reg_trie_data*)rexi->data->data[ ARG( scan ) ];
+               HV * widecharmap = (HV *)rexi->data->data[ ARG( scan ) + 1 ];
                 U32 state = trie->startstate;
 
                if (trie->bitmap && trie_type != trie_utf8_fold &&
                 U32 state = trie->startstate;
 
                if (trie->bitmap && trie_type != trie_utf8_fold &&
@@ -2830,7 +2956,6 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                ST.B = next;
                ST.jump = trie->jump;
                ST.me = scan;
                ST.B = next;
                ST.jump = trie->jump;
                ST.me = scan;
-                
                /*
                   traverse the TRIE keeping track of all accepting states
                   we transition through until we get to a failing node.
                /*
                   traverse the TRIE keeping track of all accepting states
                   we transition through until we get to a failing node.
@@ -2851,7 +2976,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                    if ( got_wordnum ) {
                        if ( ! ST.accepted ) {
                            ENTER;
                    if ( got_wordnum ) {
                        if ( ! ST.accepted ) {
                            ENTER;
-                           SAVETMPS;
+                           /* SAVETMPS; */ /* XXX is this necessary? dmq */
                            bufflen = TRIE_INITAL_ACCEPT_BUFFLEN;
                            sv_accept_buff=newSV(bufflen *
                                            sizeof(reg_trie_accepted) - 1);
                            bufflen = TRIE_INITAL_ACCEPT_BUFFLEN;
                            sv_accept_buff=newSV(bufflen *
                                            sizeof(reg_trie_accepted) - 1);
@@ -2889,8 +3014,9 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                    });
 
                    if ( base ) {
                    });
 
                    if ( base ) {
-                       REXEC_TRIE_READ_CHAR(trie_type, trie, uc, uscan, len,
-                           uvc, charid, foldlen, foldbuf, uniflags);
+                       REXEC_TRIE_READ_CHAR(trie_type, trie, widecharmap, uc,
+                                            uscan, len, uvc, charid, foldlen,
+                                            foldbuf, uniflags);
 
                        if (charid &&
                             (base + charid > trie->uniquecharcount )
 
                        if (charid &&
                             (base + charid > trie->uniquecharcount )
@@ -2927,19 +3053,31 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                        PL_colors[4], (IV)ST.accepted, PL_colors[5] );
                );
            }}
                        PL_colors[4], (IV)ST.accepted, PL_colors[5] );
                );
            }}
-
-           /* FALL THROUGH */
+            goto trie_first_try; /* jump into the fail handler */
+           /* NOTREACHED */
        case TRIE_next_fail: /* we failed - try next alterative */
        case TRIE_next_fail: /* we failed - try next alterative */
+            if ( ST.jump) {
+                REGCP_UNWIND(ST.cp);
+               for (n = *PL_reglastparen; n > ST.lastparen; n--)
+                   PL_regoffs[n].end = -1;
+               *PL_reglastparen = n;
+           }
+          trie_first_try:
             if (do_cutgroup) {
                 do_cutgroup = 0;
                 no_final = 0;
             }
             if (do_cutgroup) {
                 do_cutgroup = 0;
                 no_final = 0;
             }
+
+            if ( ST.jump) {
+                ST.lastparen = *PL_reglastparen;
+               REGCP_SET(ST.cp);
+            }          
            if ( ST.accepted == 1 ) {
                /* only one choice left - just continue */
                DEBUG_EXECUTE_r({
            if ( ST.accepted == 1 ) {
                /* only one choice left - just continue */
                DEBUG_EXECUTE_r({
-                   reg_trie_data * const trie
-                       = (reg_trie_data*)rex->data->data[ ARG(ST.me) ];
-                   SV ** const tmp = av_fetch( trie->words, 
+                   AV *const trie_words
+                       = (AV *) rexi->data->data[ARG(ST.me)+TRIE_WORDS_OFFSET];
+                   SV ** const tmp = av_fetch( trie_words, 
                        ST.accept_buff[ 0 ].wordnum-1, 0 );
                    SV *sv= tmp ? sv_newmortal() : NULL;
                    
                        ST.accept_buff[ 0 ].wordnum-1, 0 );
                    SV *sv= tmp ? sv_newmortal() : NULL;
                    
@@ -2974,8 +3112,8 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                
                continue; /* execute rest of RE */
            }
                
                continue; /* execute rest of RE */
            }
-
-           if (!ST.accepted-- ) {
+           
+           if ( !ST.accepted-- ) {
                DEBUG_EXECUTE_r({
                    PerlIO_printf( Perl_debug_log,
                        "%*s  %sTRIE failed...%s\n",
                DEBUG_EXECUTE_r({
                    PerlIO_printf( Perl_debug_log,
                        "%*s  %sTRIE failed...%s\n",
@@ -2986,7 +3124,8 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                FREETMPS;
                LEAVE;
                sayNO_SILENT;
                FREETMPS;
                LEAVE;
                sayNO_SILENT;
-           }
+               /*NOTREACHED*/
+           } 
 
            /*
               There are at least two accepting states left.  Presumably
 
            /*
               There are at least two accepting states left.  Presumably
@@ -3018,9 +3157,9 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                }
 
                DEBUG_EXECUTE_r({
                }
 
                DEBUG_EXECUTE_r({
-                   reg_trie_data * const trie
-                       = (reg_trie_data*)rex->data->data[ ARG(ST.me) ];
-                   SV ** const tmp = av_fetch( trie->words, 
+                   AV *const trie_words
+                       = (AV *) rexi->data->data[ARG(ST.me)+TRIE_WORDS_OFFSET];
+                   SV ** const tmp = av_fetch( trie_words, 
                        ST.accept_buff[ best ].wordnum - 1, 0 );
                    regnode *nextop=(!ST.jump || !ST.jump[ST.accept_buff[best].wordnum]) ? 
                                    ST.B : 
                        ST.accept_buff[ best ].wordnum - 1, 0 );
                    regnode *nextop=(!ST.jump || !ST.jump[ST.accept_buff[best].wordnum]) ? 
                                    ST.B : 
@@ -3048,18 +3187,10 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                PL_reginput = (char *)ST.accept_buff[ best ].endpos;
                if ( !ST.jump || !ST.jump[ST.accept_buff[best].wordnum]) {
                    scan = ST.B;
                PL_reginput = (char *)ST.accept_buff[ best ].endpos;
                if ( !ST.jump || !ST.jump[ST.accept_buff[best].wordnum]) {
                    scan = ST.B;
-                   /* NOTREACHED */
                } else {
                    scan = ST.me + ST.jump[ST.accept_buff[best].wordnum];
                } else {
                    scan = ST.me + ST.jump[ST.accept_buff[best].wordnum];
-                   /* NOTREACHED */
-                }
-                if (has_cutgroup) {
-                    PUSH_YES_STATE_GOTO(TRIE_next, scan);    
-                    /* NOTREACHED */
-                } else {
-                    PUSH_STATE_GOTO(TRIE_next, scan);
-                    /* NOTREACHED */
                 }
                 }
+                PUSH_YES_STATE_GOTO(TRIE_next, scan);    
                 /* NOTREACHED */
            }
            /* NOTREACHED */
                 /* NOTREACHED */
            }
            /* NOTREACHED */
@@ -3139,8 +3270,9 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                      * pack("U0U*", 0xDF) =~ /ss/i,
                      * the 0xC3 0x9F are the UTF-8
                      * byte sequence for the U+00DF. */
                      * pack("U0U*", 0xDF) =~ /ss/i,
                      * the 0xC3 0x9F are the UTF-8
                      * byte sequence for the U+00DF. */
+
                     if (!(do_utf8 &&
                     if (!(do_utf8 &&
-                          toLOWER(s[0]) == 's' &&
+                          toLOWER(s[0]) == 's' &&
                           ln >= 2 &&
                           toLOWER(s[1]) == 's' &&
                           (U8)l[0] == 0xC3 &&
                           ln >= 2 &&
                           toLOWER(s[1]) == 's' &&
                           (U8)l[0] == 0xC3 &&
@@ -3435,17 +3567,17 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
            n = ARG(scan);  /* which paren pair */
            type = OP(scan);
          do_ref:  
            n = ARG(scan);  /* which paren pair */
            type = OP(scan);
          do_ref:  
-           ln = PL_regstartp[n];
+           ln = PL_regoffs[n].start;
            PL_reg_leftiter = PL_reg_maxiter;           /* Void cache */
            if (*PL_reglastparen < n || ln == -1)
                sayNO;                  /* Do not match unless seen CLOSEn. */
            PL_reg_leftiter = PL_reg_maxiter;           /* Void cache */
            if (*PL_reglastparen < n || ln == -1)
                sayNO;                  /* Do not match unless seen CLOSEn. */
-           if (ln == PL_regendp[n])
+           if (ln == PL_regoffs[n].end)
                break;
 
            s = PL_bostr + ln;
            if (do_utf8 && type != REF) {       /* REF can do byte comparison */
                char *l = locinput;
                break;
 
            s = PL_bostr + ln;
            if (do_utf8 && type != REF) {       /* REF can do byte comparison */
                char *l = locinput;
-               const char *e = PL_bostr + PL_regendp[n];
+               const char *e = PL_bostr + PL_regoffs[n].end;
                /*
                 * Note that we can't do the "other character" lookup trick as
                 * in the 8-bit case (no pun intended) because in Unicode we
                /*
                 * Note that we can't do the "other character" lookup trick as
                 * in the 8-bit case (no pun intended) because in Unicode we
@@ -3478,7 +3610,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                 (UCHARAT(s) != (type == REFF
                                  ? PL_fold : PL_fold_locale)[nextchr])))
                sayNO;
                 (UCHARAT(s) != (type == REFF
                                  ? PL_fold : PL_fold_locale)[nextchr])))
                sayNO;
-           ln = PL_regendp[n] - ln;
+           ln = PL_regoffs[n].end - ln;
            if (locinput + ln > PL_regeol)
                sayNO;
            if (ln > 1 && (type == REF
            if (locinput + ln > PL_regeol)
                sayNO;
            if (ln > 1 && (type == REF
@@ -3501,35 +3633,39 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
 #define ST st->u.eval
        {
            SV *ret;
 #define ST st->u.eval
        {
            SV *ret;
+           SV *re_sv;
             regexp *re;
             regexp *re;
+            regexp_internal *rei;
             regnode *startpoint;
 
        case GOSTART:
             regnode *startpoint;
 
        case GOSTART:
-       case GOSUB: /*    /(...(?1))/      */
-            if (cur_eval && cur_eval->locinput==locinput) {
+       case GOSUB: /*    /(...(?1))/   /(...(?&foo))/   */
+           if (cur_eval && cur_eval->locinput==locinput) {
                 if (cur_eval->u.eval.close_paren == (U32)ARG(scan)) 
                     Perl_croak(aTHX_ "Infinite recursion in regex");
                 if (cur_eval->u.eval.close_paren == (U32)ARG(scan)) 
                     Perl_croak(aTHX_ "Infinite recursion in regex");
-                if ( ++nochange_depth > MAX_RECURSE_EVAL_NOCHANGE_DEPTH ) 
+                if ( ++nochange_depth > max_nochange_depth )
                     Perl_croak(aTHX_ 
                         "Pattern subroutine nesting without pos change"
                         " exceeded limit in regex");
             } else {
                 nochange_depth = 0;
             }
                     Perl_croak(aTHX_ 
                         "Pattern subroutine nesting without pos change"
                         " exceeded limit in regex");
             } else {
                 nochange_depth = 0;
             }
+           re_sv = rex_sv;
             re = rex;
             re = rex;
-            (void)ReREFCNT_inc(rex);
+            rei = rexi;
+            (void)ReREFCNT_inc(rex_sv);
             if (OP(scan)==GOSUB) {
                 startpoint = scan + ARG2L(scan);
                 ST.close_paren = ARG(scan);
             } else {
             if (OP(scan)==GOSUB) {
                 startpoint = scan + ARG2L(scan);
                 ST.close_paren = ARG(scan);
             } else {
-                startpoint = re->program+1;
+                startpoint = rei->program+1;
                 ST.close_paren = 0;
             }
             goto eval_recurse_doit;
             /* NOTREACHED */
         case EVAL:  /*   /(?{A})B/   /(??{A})B/  and /(?(?{A})X|Y)B/   */        
             if (cur_eval && cur_eval->locinput==locinput) {
                 ST.close_paren = 0;
             }
             goto eval_recurse_doit;
             /* NOTREACHED */
         case EVAL:  /*   /(?{A})B/   /(??{A})B/  and /(?(?{A})X|Y)B/   */        
             if (cur_eval && cur_eval->locinput==locinput) {
-                if ( ++nochange_depth > MAX_RECURSE_EVAL_NOCHANGE_DEPTH ) 
+               if ( ++nochange_depth > max_nochange_depth )
                     Perl_croak(aTHX_ "EVAL without pos change exceeded limit in regex");
             } else {
                 nochange_depth = 0;
                     Perl_croak(aTHX_ "EVAL without pos change exceeded limit in regex");
             } else {
                 nochange_depth = 0;
@@ -3543,11 +3679,16 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                PAD *old_comppad;
            
                n = ARG(scan);
                PAD *old_comppad;
            
                n = ARG(scan);
-               PL_op = (OP_4tree*)rex->data->data[n];
+               PL_op = (OP_4tree*)rexi->data->data[n];
                DEBUG_STATE_r( PerlIO_printf(Perl_debug_log, 
                    "  re_eval 0x%"UVxf"\n", PTR2UV(PL_op)) );
                DEBUG_STATE_r( PerlIO_printf(Perl_debug_log, 
                    "  re_eval 0x%"UVxf"\n", PTR2UV(PL_op)) );
-               PAD_SAVE_LOCAL(old_comppad, (PAD*)rex->data->data[n + 2]);
-               PL_regendp[0] = PL_reg_magic->mg_len = locinput - PL_bostr;
+               PAD_SAVE_LOCAL(old_comppad, (PAD*)rexi->data->data[n + 2]);
+               PL_regoffs[0].end = PL_reg_magic->mg_len = locinput - PL_bostr;
+
+                if (sv_yes_mark) {
+                    SV *sv_mrk = get_sv("REGMARK", 1);
+                    sv_setsv(sv_mrk, sv_yes_mark);
+                }
 
                CALLRUNOPS(aTHX);                       /* Scalar context. */
                SPAGAIN;
 
                CALLRUNOPS(aTHX);                       /* Scalar context. */
                SPAGAIN;
@@ -3572,44 +3713,83 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                {
                    /* extract RE object from returned value; compiling if
                     * necessary */
                {
                    /* extract RE object from returned value; compiling if
                     * necessary */
-
                    MAGIC *mg = NULL;
                    MAGIC *mg = NULL;
-                   const SV *sv;
-                   if(SvROK(ret) && SvSMAGICAL(sv = SvRV(ret)))
-                       mg = mg_find(sv, PERL_MAGIC_qr);
-                   else if (SvSMAGICAL(ret)) {
-                       if (SvGMAGICAL(ret))
+                   REGEXP *rx = NULL;
+
+                   if (SvROK(ret)) {
+                       SV *const sv = SvRV(ret);
+
+                       if (SvTYPE(sv) == SVt_REGEXP) {
+                           rx = sv;
+                       } else if (SvSMAGICAL(sv)) {
+                           mg = mg_find(sv, PERL_MAGIC_qr);
+                           assert(mg);
+                       }
+                   } else if (SvTYPE(ret) == SVt_REGEXP) {
+                       rx = 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);
                            sv_unmagic(ret, PERL_MAGIC_qr);
-                       else
+                       }
+                       else {
                            mg = mg_find(ret, PERL_MAGIC_qr);
                            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) {
                    }
 
                    if (mg) {
-                       re = (regexp *)mg->mg_obj;
-                       (void)ReREFCNT_inc(re);
+                       rx = mg->mg_obj; /*XXX:dmq*/
+                       assert(rx);
+                   }
+                   if (rx) {
+                       rx = reg_temp_copy(rx);
                    }
                    else {
                    }
                    else {
-                       STRLEN len;
-                       const char * const t = SvPV_const(ret, len);
-                       PMOP pm;
+                       U32 pm_flags = 0;
                        const I32 osize = PL_regsize;
 
                        const I32 osize = PL_regsize;
 
-                       Zero(&pm, 1, PMOP);
-                       if (DO_UTF8(ret)) pm.op_pmdynflags |= PMdf_DYN_UTF8;
-                       re = CALLREGCOMP((char*)t, (char*)t + len, &pm);
+                       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.  */
+                           STRLEN len;
+                           const char *const p = SvPV(ret, len);
+                           ret = newSVpvn_flags(p, len, SVs_TEMP);
+                       }
+                       rx = CALLREGCOMP(ret, pm_flags);
                        if (!(SvFLAGS(ret)
                              & (SVs_TEMP | SVs_PADTMP | SVf_READONLY
                        if (!(SvFLAGS(ret)
                              & (SVs_TEMP | SVs_PADTMP | SVf_READONLY
-                               | SVs_GMG)))
-                           sv_magic(ret,(SV*)ReREFCNT_inc(re),
-                                       PERL_MAGIC_qr,0,0);
+                                | SVs_GMG))) {
+                           /* This isn't a first class regexp. Instead, it's
+                              caching a regexp onto an existing, Perl visible
+                              scalar.  */
+                           sv_magic(ret, rx, PERL_MAGIC_qr, 0, 0);
+                       }
                        PL_regsize = osize;
                    }
                        PL_regsize = osize;
                    }
+                   re_sv = rx;
+                   re = (struct regexp *)SvANY(rx);
                }
                }
+                RXp_MATCH_COPIED_off(re);
+                re->subbeg = rex->subbeg;
+                re->sublen = rex->sublen;
+               rei = RXi_GET(re);
                 DEBUG_EXECUTE_r(
                 DEBUG_EXECUTE_r(
-                    debug_start_match(re, do_utf8, locinput, PL_regeol, 
+                    debug_start_match(re_sv, do_utf8, locinput, PL_regeol, 
                         "Matching embedded");
                );              
                         "Matching embedded");
                );              
-               startpoint = re->program + 1;
+               startpoint = rei->program + 1;
                        ST.close_paren = 0; /* only used for GOSUB */
                        /* borrowed from regtry */
                 if (PL_reg_start_tmpl <= re->nparens) {
                        ST.close_paren = 0; /* only used for GOSUB */
                        /* borrowed from regtry */
                 if (PL_reg_start_tmpl <= re->nparens) {
@@ -3625,8 +3805,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                ST.cp = regcppush(0);   /* Save *all* the positions. */
                REGCP_SET(ST.lastcp);
                
                ST.cp = regcppush(0);   /* Save *all* the positions. */
                REGCP_SET(ST.lastcp);
                
-               PL_regstartp = re->startp; /* essentially NOOP on GOSUB */
-               PL_regendp = re->endp;     /* essentially NOOP on GOSUB */
+               PL_regoffs = re->offs; /* essentially NOOP on GOSUB */
                
                *PL_reglastparen = 0;
                *PL_reglastcloseparen = 0;
                
                *PL_reglastparen = 0;
                *PL_reglastcloseparen = 0;
@@ -3637,15 +3816,17 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                PL_reg_maxiter = 0;
 
                ST.toggle_reg_flags = PL_reg_flags;
                PL_reg_maxiter = 0;
 
                ST.toggle_reg_flags = PL_reg_flags;
-               if (re->extflags & RXf_UTF8)
+               if (RX_UTF8(re_sv))
                    PL_reg_flags |= RF_utf8;
                else
                    PL_reg_flags &= ~RF_utf8;
                ST.toggle_reg_flags ^= PL_reg_flags; /* diff of old and new */
 
                    PL_reg_flags |= RF_utf8;
                else
                    PL_reg_flags &= ~RF_utf8;
                ST.toggle_reg_flags ^= PL_reg_flags; /* diff of old and new */
 
-               ST.prev_rex = rex;
+               ST.prev_rex = rex_sv;
                ST.prev_curlyx = cur_curlyx;
                ST.prev_curlyx = cur_curlyx;
+               SETREX(rex_sv,re_sv);
                rex = re;
                rex = re;
+               rexi = rei;
                cur_curlyx = NULL;
                ST.B = next;
                ST.prev_eval = cur_eval;
                cur_curlyx = NULL;
                ST.B = next;
                ST.prev_eval = cur_eval;
@@ -3663,21 +3844,27 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
        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; 
        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);
-           rex = ST.prev_rex;
+           ReREFCNT_dec(rex_sv);
+           SETREX(rex_sv,ST.prev_rex);
+           rex = (struct regexp *)SvANY(rex_sv);
+           rexi = RXi_GET(rex);
            regcpblow(ST.cp);
            cur_eval = ST.prev_eval;
            cur_curlyx = ST.prev_curlyx;
            /* XXXX This is too dramatic a measure... */
            PL_reg_maxiter = 0;
            regcpblow(ST.cp);
            cur_eval = ST.prev_eval;
            cur_curlyx = ST.prev_curlyx;
            /* XXXX This is too dramatic a measure... */
            PL_reg_maxiter = 0;
+            if ( nochange_depth )
+               nochange_depth--;
            sayYES;
 
 
        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; 
            sayYES;
 
 
        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);
-           rex = ST.prev_rex;
+           ReREFCNT_dec(rex_sv);
+           SETREX(rex_sv,ST.prev_rex);
+           rex = (struct regexp *)SvANY(rex_sv);
+           rexi = RXi_GET(rex); 
            PL_reginput = locinput;
            REGCP_UNWIND(ST.lastcp);
            regcppop(rex);
            PL_reginput = locinput;
            REGCP_UNWIND(ST.lastcp);
            regcppop(rex);
@@ -3685,6 +3872,8 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
            cur_curlyx = ST.prev_curlyx;
            /* XXXX This is too dramatic a measure... */
            PL_reg_maxiter = 0;
            cur_curlyx = ST.prev_curlyx;
            /* XXXX This is too dramatic a measure... */
            PL_reg_maxiter = 0;
+           if ( nochange_depth )
+               nochange_depth--;
            sayNO_SILENT;
 #undef ST
 
            sayNO_SILENT;
 #undef ST
 
@@ -3697,8 +3886,8 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
            break;
        case CLOSE:
            n = ARG(scan);  /* which paren pair */
            break;
        case CLOSE:
            n = ARG(scan);  /* which paren pair */
-           PL_regstartp[n] = PL_reg_start_tmp[n] - PL_bostr;
-           PL_regendp[n] = locinput - PL_bostr;
+           PL_regoffs[n].start = PL_reg_start_tmp[n] - PL_bostr;
+           PL_regoffs[n].end = locinput - PL_bostr;
            /*if (n > PL_regsize)
                PL_regsize = n;*/
            if (n > *PL_reglastparen)
            /*if (n > PL_regsize)
                PL_regsize = n;*/
            if (n > *PL_reglastparen)
@@ -3718,8 +3907,9 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                     if ( OP(cursor)==CLOSE ){
                         n = ARG(cursor);
                         if ( n <= lastopen ) {
                     if ( OP(cursor)==CLOSE ){
                         n = ARG(cursor);
                         if ( n <= lastopen ) {
-                            PL_regstartp[n] = PL_reg_start_tmp[n] - PL_bostr;
-                            PL_regendp[n] = locinput - PL_bostr;
+                            PL_regoffs[n].start
+                               = PL_reg_start_tmp[n] - PL_bostr;
+                            PL_regoffs[n].end = locinput - PL_bostr;
                             /*if (n > PL_regsize)
                             PL_regsize = n;*/
                             if (n > *PL_reglastparen)
                             /*if (n > PL_regsize)
                             PL_regsize = n;*/
                             if (n > *PL_reglastparen)
@@ -3736,7 +3926,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
            /*NOTREACHED*/          
        case GROUPP:
            n = ARG(scan);  /* which paren pair */
            /*NOTREACHED*/          
        case GROUPP:
            n = ARG(scan);  /* which paren pair */
-           sw = (bool)(*PL_reglastparen >= n && PL_regendp[n] != -1);
+           sw = (bool)(*PL_reglastparen >= n && PL_regoffs[n].end != -1);
            break;
        case NGROUPP:
            /* reg_check_named_buff_matched returns 0 for no match */
            break;
        case NGROUPP:
            /* reg_check_named_buff_matched returns 0 for no match */
@@ -3884,15 +4074,6 @@ NULL
        }
 
        case CURLYX_end: /* just finished matching all of A*B */
        }
 
        case CURLYX_end: /* just finished matching all of A*B */
-           if (PL_reg_eval_set){
-               SV *pres= GvSV(PL_replgv);
-               SvREFCNT_inc(pres);
-               regcpblow(ST.cp);
-               sv_setsv(GvSV(PL_replgv), pres);
-               SvREFCNT_dec(pres);
-           } else {
-               regcpblow(ST.cp);
-           }
            cur_curlyx = ST.prev_curlyx;
            sayYES;
            /* NOTREACHED */
            cur_curlyx = ST.prev_curlyx;
            sayYES;
            /* NOTREACHED */
@@ -4113,12 +4294,6 @@ NULL
 
        case BRANCH:        /*  /(...|A|...)/ */
            scan = NEXTOPER(scan); /* scan now points to inner node */
 
        case BRANCH:        /*  /(...|A|...)/ */
            scan = NEXTOPER(scan); /* scan now points to inner node */
-           if ((!next || (OP(next) != BRANCH && OP(next) != BRANCHJ)) 
-               && !has_cutgroup)
-           {
-               /* last branch; skip state push and jump direct to node */
-               continue;
-            }
            ST.lastparen = *PL_reglastparen;
            ST.next_branch = next;
            REGCP_SET(ST.cp);
            ST.lastparen = *PL_reglastparen;
            ST.next_branch = next;
            REGCP_SET(ST.cp);
@@ -4134,7 +4309,7 @@ NULL
         case CUTGROUP:
             PL_reginput = locinput;
             sv_yes_mark = st->u.mark.mark_name = scan->flags ? NULL :
         case CUTGROUP:
             PL_reginput = locinput;
             sv_yes_mark = st->u.mark.mark_name = scan->flags ? NULL :
-                (SV*)rex->data->data[ ARG( scan ) ];
+                (SV*)rexi->data->data[ ARG( scan ) ];
             PUSH_STATE_GOTO(CUTGROUP_next,next);
             /* NOTREACHED */
         case CUTGROUP_next_fail:
             PUSH_STATE_GOTO(CUTGROUP_next,next);
             /* NOTREACHED */
         case CUTGROUP_next_fail:
@@ -4154,7 +4329,7 @@ NULL
            }
            REGCP_UNWIND(ST.cp);
            for (n = *PL_reglastparen; n > ST.lastparen; n--)
            }
            REGCP_UNWIND(ST.cp);
            for (n = *PL_reglastparen; n > ST.lastparen; n--)
-               PL_regendp[n] = -1;
+               PL_regoffs[n].end = -1;
            *PL_reglastparen = n;
            /*dmq: *PL_reglastcloseparen = n; */
            scan = ST.next_branch;
            *PL_reglastparen = n;
            /*dmq: *PL_reglastcloseparen = n; */
            scan = ST.next_branch;
@@ -4271,14 +4446,23 @@ NULL
                    regnode *text_node = ST.B;
                    if (! HAS_TEXT(text_node))
                        FIND_NEXT_IMPT(text_node);
                    regnode *text_node = ST.B;
                    if (! HAS_TEXT(text_node))
                        FIND_NEXT_IMPT(text_node);
-                   if (HAS_TEXT(text_node)
-                       && PL_regkind[OP(text_node)] != REF)
+                   /* this used to be 
+                       
+                       (HAS_TEXT(text_node) && PL_regkind[OP(text_node)] == EXACT)
+                       
+                       But the former is redundant in light of the latter.
+                       
+                       if this changes back then the macro for 
+                       IS_TEXT and friends need to change.
+                    */
+                   if (PL_regkind[OP(text_node)] == EXACT)
                    {
                    {
+                       
                        ST.c1 = (U8)*STRING(text_node);
                        ST.c2 =
                        ST.c1 = (U8)*STRING(text_node);
                        ST.c2 =
-                           (OP(text_node) == EXACTF || OP(text_node) == REFF)
+                           (IS_TEXTF(text_node))
                            ? PL_fold[ST.c1]
                            ? PL_fold[ST.c1]
-                           : (OP(text_node) == EXACTFL || OP(text_node) == REFFL)
+                           : (IS_TEXTFL(text_node))
                                ? PL_fold_locale[ST.c1]
                                : ST.c1;
                    }
                                ? PL_fold_locale[ST.c1]
                                : ST.c1;
                    }
@@ -4296,6 +4480,12 @@ NULL
                    && UCHARAT(PL_reginput) != ST.c2)
            {
                /* simulate B failing */
                    && UCHARAT(PL_reginput) != ST.c2)
            {
                /* simulate B failing */
+               DEBUG_OPTIMISE_r(
+                   PerlIO_printf(Perl_debug_log,
+                       "%*s  CURLYM Fast bail c1=%"IVdf" c2=%"IVdf"\n",
+                       (int)(REPORT_CODE_OFF+(depth*2)),"",
+                       (IV)ST.c1,(IV)ST.c2
+               ));
                state_num = CURLYM_B_fail;
                goto reenter_switch;
            }
                state_num = CURLYM_B_fail;
                goto reenter_switch;
            }
@@ -4304,13 +4494,13 @@ NULL
                /* mark current A as captured */
                I32 paren = ST.me->flags;
                if (ST.count) {
                /* mark current A as captured */
                I32 paren = ST.me->flags;
                if (ST.count) {
-                   PL_regstartp[paren]
+                   PL_regoffs[paren].start
                        = HOPc(PL_reginput, -ST.alen) - PL_bostr;
                        = HOPc(PL_reginput, -ST.alen) - PL_bostr;
-                   PL_regendp[paren] = PL_reginput - PL_bostr;
+                   PL_regoffs[paren].end = PL_reginput - PL_bostr;
                    /*dmq: *PL_reglastcloseparen = paren; */
                }
                else
                    /*dmq: *PL_reglastcloseparen = paren; */
                }
                else
-                   PL_regendp[paren] = -1;
+                   PL_regoffs[paren].end = -1;
                if (cur_eval && cur_eval->u.eval.close_paren &&
                    cur_eval->u.eval.close_paren == (U32)ST.me->flags) 
                {
                if (cur_eval && cur_eval->u.eval.close_paren &&
                    cur_eval->u.eval.close_paren == (U32)ST.me->flags) 
                {
@@ -4344,12 +4534,12 @@ NULL
 #define CURLY_SETPAREN(paren, success) \
     if (paren) { \
        if (success) { \
 #define CURLY_SETPAREN(paren, success) \
     if (paren) { \
        if (success) { \
-           PL_regstartp[paren] = HOPc(locinput, -1) - PL_bostr; \
-           PL_regendp[paren] = locinput - PL_bostr; \
+           PL_regoffs[paren].start = HOPc(locinput, -1) - PL_bostr; \
+           PL_regoffs[paren].end = locinput - PL_bostr; \
            *PL_reglastcloseparen = paren; \
        } \
        else \
            *PL_reglastcloseparen = paren; \
        } \
        else \
-           PL_regendp[paren] = -1; \
+           PL_regoffs[paren].end = -1; \
     }
 
        case STAR:              /*  /A*B/ where A is width 1 */
     }
 
        case STAR:              /*  /A*B/ where A is width 1 */
@@ -4406,22 +4596,28 @@ NULL
                if (! HAS_TEXT(text_node))
                    ST.c1 = ST.c2 = CHRTEST_VOID;
                else {
                if (! HAS_TEXT(text_node))
                    ST.c1 = ST.c2 = CHRTEST_VOID;
                else {
-                   if (PL_regkind[OP(text_node)] == REF) {
+                   if ( PL_regkind[OP(text_node)] != EXACT ) {
                        ST.c1 = ST.c2 = CHRTEST_VOID;
                        goto assume_ok_easy;
                    }
                    else
                        s = (U8*)STRING(text_node);
                        ST.c1 = ST.c2 = CHRTEST_VOID;
                        goto assume_ok_easy;
                    }
                    else
                        s = (U8*)STRING(text_node);
-
+                    
+                    /*  Currently we only get here when 
+                        
+                        PL_rekind[OP(text_node)] == EXACT
+                    
+                        if this changes back then the macro for IS_TEXT and 
+                        friends need to change. */
                    if (!UTF) {
                        ST.c2 = ST.c1 = *s;
                    if (!UTF) {
                        ST.c2 = ST.c1 = *s;
-                       if (OP(text_node) == EXACTF || OP(text_node) == REFF)
+                       if (IS_TEXTF(text_node))
                            ST.c2 = PL_fold[ST.c1];
                            ST.c2 = PL_fold[ST.c1];
-                       else if (OP(text_node) == EXACTFL || OP(text_node) == REFFL)
+                       else if (IS_TEXTFL(text_node))
                            ST.c2 = PL_fold_locale[ST.c1];
                    }
                    else { /* UTF */
                            ST.c2 = PL_fold_locale[ST.c1];
                    }
                    else { /* UTF */
-                       if (OP(text_node) == EXACTF || OP(text_node) == REFF) {
+                       if (IS_TEXTF(text_node)) {
                             STRLEN ulen1, ulen2;
                             U8 tmpbuf1[UTF8_MAXBYTES_CASE+1];
                             U8 tmpbuf2[UTF8_MAXBYTES_CASE+1];
                             STRLEN ulen1, ulen2;
                             U8 tmpbuf1[UTF8_MAXBYTES_CASE+1];
                             U8 tmpbuf2[UTF8_MAXBYTES_CASE+1];
@@ -4516,7 +4712,7 @@ NULL
        case CURLY_B_min_known_fail:
            /* failed to find B in a non-greedy match where c1,c2 valid */
            if (ST.paren && ST.count)
        case CURLY_B_min_known_fail:
            /* failed to find B in a non-greedy match where c1,c2 valid */
            if (ST.paren && ST.count)
-               PL_regendp[ST.paren] = -1;
+               PL_regoffs[ST.paren].end = -1;
 
            PL_reginput = locinput;     /* Could be reset... */
            REGCP_UNWIND(ST.cp);
 
            PL_reginput = locinput;     /* Could be reset... */
            REGCP_UNWIND(ST.cp);
@@ -4594,7 +4790,7 @@ NULL
        case CURLY_B_min_fail:
            /* failed to find B in a non-greedy match where c1,c2 invalid */
            if (ST.paren && ST.count)
        case CURLY_B_min_fail:
            /* failed to find B in a non-greedy match where c1,c2 invalid */
            if (ST.paren && ST.count)
-               PL_regendp[ST.paren] = -1;
+               PL_regoffs[ST.paren].end = -1;
 
            REGCP_UNWIND(ST.cp);
            /* failed -- move forward one */
 
            REGCP_UNWIND(ST.cp);
            /* failed -- move forward one */
@@ -4641,7 +4837,7 @@ NULL
        case CURLY_B_max_fail:
            /* failed to find B in a greedy match */
            if (ST.paren && ST.count)
        case CURLY_B_max_fail:
            /* failed to find B in a greedy match */
            if (ST.paren && ST.count)
-               PL_regendp[ST.paren] = -1;
+               PL_regoffs[ST.paren].end = -1;
 
            REGCP_UNWIND(ST.cp);
            /*  back up. */
 
            REGCP_UNWIND(ST.cp);
            /*  back up. */
@@ -4657,16 +4853,16 @@ NULL
            if (cur_eval) {
                /* we've just finished A in /(??{A})B/; now continue with B */
                I32 tmpix;
            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.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;              /* inner */
-               rex    = cur_eval->u.eval.prev_rex;     /* outer */
+               st->u.eval.prev_rex = rex_sv;           /* inner */
+               SETREX(rex_sv,cur_eval->u.eval.prev_rex);
+               rex = (struct regexp *)SvANY(rex_sv);
+               rexi = RXi_GET(rex);
                cur_curlyx = cur_eval->u.eval.prev_curlyx;
                cur_curlyx = cur_eval->u.eval.prev_curlyx;
-               ReREFCNT_inc(rex);
+               ReREFCNT_inc(rex_sv);
                st->u.eval.cp = regcppush(0);   /* Save *all* the positions. */
                REGCP_SET(st->u.eval.lastcp);
                PL_reginput = locinput;
                st->u.eval.cp = regcppush(0);   /* Save *all* the positions. */
                REGCP_SET(st->u.eval.lastcp);
                PL_reginput = locinput;
@@ -4683,7 +4879,10 @@ NULL
                DEBUG_EXECUTE_r(
                    PerlIO_printf(Perl_debug_log, "%*s  EVAL trying tail ... %"UVxf"\n",
                                      REPORT_CODE_OFF+depth*2, "",PTR2UV(cur_eval)););
                DEBUG_EXECUTE_r(
                    PerlIO_printf(Perl_debug_log, "%*s  EVAL trying tail ... %"UVxf"\n",
                                      REPORT_CODE_OFF+depth*2, "",PTR2UV(cur_eval)););
-               PUSH_YES_STATE_GOTO(EVAL_AB,
+                if ( nochange_depth )
+                   nochange_depth--;
+
+                PUSH_YES_STATE_GOTO(EVAL_AB,
                        st->u.eval.prev_eval->u.eval.B); /* match B */
            }
 
                        st->u.eval.prev_eval->u.eval.B); /* match B */
            }
 
@@ -4785,7 +4984,7 @@ NULL
        case PRUNE:
            PL_reginput = locinput;
            if (!scan->flags)
        case PRUNE:
            PL_reginput = locinput;
            if (!scan->flags)
-               sv_yes_mark = sv_commit = (SV*)rex->data->data[ ARG( scan ) ];
+               sv_yes_mark = sv_commit = (SV*)rexi->data->data[ ARG( scan ) ];
            PUSH_STATE_GOTO(COMMIT_next,next);
            /* NOTREACHED */
        case COMMIT_next_fail:
            PUSH_STATE_GOTO(COMMIT_next,next);
            /* NOTREACHED */
        case COMMIT_next_fail:
@@ -4799,7 +4998,7 @@ NULL
         case MARKPOINT:
             ST.prev_mark = mark_state;
             ST.mark_name = sv_commit = sv_yes_mark 
         case MARKPOINT:
             ST.prev_mark = mark_state;
             ST.mark_name = sv_commit = sv_yes_mark 
-                = (SV*)rex->data->data[ ARG( scan ) ];
+                = (SV*)rexi->data->data[ ARG( scan ) ];
             mark_state = st;
             ST.mark_loc = PL_reginput = locinput;
             PUSH_YES_STATE_GOTO(MARKPOINT_next,next);
             mark_state = st;
             ST.mark_loc = PL_reginput = locinput;
             PUSH_YES_STATE_GOTO(MARKPOINT_next,next);
@@ -4820,7 +5019,7 @@ NULL
                         PerlIO_printf(Perl_debug_log,
                            "%*s  %ssetting cutpoint to mark:%"SVf"...%s\n",
                            REPORT_CODE_OFF+depth*2, "", 
                         PerlIO_printf(Perl_debug_log,
                            "%*s  %ssetting cutpoint to mark:%"SVf"...%s\n",
                            REPORT_CODE_OFF+depth*2, "", 
-                           PL_colors[4], sv_commit, PL_colors[5]);
+                           PL_colors[4], SVfARG(sv_commit), PL_colors[5]);
                });
             }
             mark_state = ST.prev_mark;
                });
             }
             mark_state = ST.prev_mark;
@@ -4831,16 +5030,16 @@ NULL
         case SKIP:
             PL_reginput = locinput;
             if (scan->flags) {
         case SKIP:
             PL_reginput = locinput;
             if (scan->flags) {
-                /* (*CUT) : if we fail we cut here*/
+                /* (*SKIP) : if we fail we cut here*/
                 ST.mark_name = NULL;
                 ST.mark_loc = locinput;
                 PUSH_STATE_GOTO(SKIP_next,next);    
             } else {
                 ST.mark_name = NULL;
                 ST.mark_loc = locinput;
                 PUSH_STATE_GOTO(SKIP_next,next);    
             } else {
-                /* (*CUT:NAME) : if there is a (*MARK:NAME) fail where it was, 
+                /* (*SKIP:NAME) : if there is a (*MARK:NAME) fail where it was, 
                    otherwise do nothing.  Meaning we need to scan 
                  */
                 regmatch_state *cur = mark_state;
                    otherwise do nothing.  Meaning we need to scan 
                  */
                 regmatch_state *cur = mark_state;
-                SV *find = (SV*)rex->data->data[ ARG( scan ) ];
+                SV *find = (SV*)rexi->data->data[ ARG( scan ) ];
                 
                 while (cur) {
                     if ( sv_eq( cur->u.mark.mark_name, 
                 
                 while (cur) {
                     if ( sv_eq( cur->u.mark.mark_name, 
@@ -4852,7 +5051,7 @@ NULL
                     cur = cur->u.mark.prev_mark;
                 }
             }    
                     cur = cur->u.mark.prev_mark;
                 }
             }    
-            /* Didn't find our (*MARK:NAME) so ignore this (*CUT:NAME) */
+            /* Didn't find our (*MARK:NAME) so ignore this (*SKIP:NAME) */
             break;    
        case SKIP_next_fail:
            if (ST.mark_name) {
             break;    
        case SKIP_next_fail:
            if (ST.mark_name) {
@@ -4873,6 +5072,55 @@ NULL
             sayNO;
             /* NOTREACHED */
 #undef ST
             sayNO;
             /* NOTREACHED */
 #undef ST
+        case FOLDCHAR:
+            n = ARG(scan);
+            if ( n == (U32)what_len_TRICKYFOLD(locinput,do_utf8,ln) ) {
+                locinput += ln;
+            } else if ( 0xDF == n && !do_utf8 && !UTF ) {
+                sayNO;
+            } else  {
+                U8 folded[UTF8_MAXBYTES_CASE+1];
+                STRLEN foldlen;
+                const char * const l = locinput;
+                char *e = PL_regeol;
+                to_uni_fold(n, folded, &foldlen);
+
+               if (ibcmp_utf8((const char*) folded, 0,  foldlen, 1,
+                              l, &e, 0,  do_utf8)) {
+                        sayNO;
+                }
+                locinput = e;
+            } 
+            nextchr = UCHARAT(locinput);  
+            break;
+        case LNBREAK:
+            if ((n=is_LNBREAK(locinput,do_utf8))) {
+                locinput += n;
+                nextchr = UCHARAT(locinput);
+            } else
+                sayNO;
+            break;
+
+#define CASE_CLASS(nAmE)                              \
+        case nAmE:                                    \
+            if ((n=is_##nAmE(locinput,do_utf8))) {    \
+                locinput += n;                        \
+                nextchr = UCHARAT(locinput);          \
+            } else                                    \
+                sayNO;                                \
+            break;                                    \
+        case N##nAmE:                                 \
+            if ((n=is_##nAmE(locinput,do_utf8))) {    \
+                sayNO;                                \
+            } else {                                  \
+                locinput += UTF8SKIP(locinput);       \
+                nextchr = UCHARAT(locinput);          \
+            }                                         \
+            break
+
+        CASE_CLASS(VERTWS);
+        CASE_CLASS(HORIZWS);
+#undef CASE_CLASS
 
        default:
            PerlIO_printf(Perl_error_log, "%"UVxf" %d\n",
 
        default:
            PerlIO_printf(Perl_error_log, "%"UVxf" %d\n",
@@ -4908,7 +5156,7 @@ NULL
                     }
                     PerlIO_printf(Perl_error_log, "%*s#%-3d %-10s %s\n",
                         REPORT_CODE_OFF + 2 + depth * 2,"",
                     }
                     PerlIO_printf(Perl_error_log, "%*s#%-3d %-10s %s\n",
                         REPORT_CODE_OFF + 2 + depth * 2,"",
-                        curd, reg_name[cur->resume_state],
+                        curd, PL_reg_name[cur->resume_state],
                         (curyes == cur) ? "yes" : ""
                     );
                     if (curyes == cur)
                         (curyes == cur) ? "yes" : ""
                     );
                     if (curyes == cur)
@@ -4987,6 +5235,15 @@ yes:
     DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log, "%sMatch successful!%s\n",
                          PL_colors[4], PL_colors[5]));
 
     DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log, "%sMatch successful!%s\n",
                          PL_colors[4], PL_colors[5]));
 
+    if (PL_reg_eval_set) {
+       /* each successfully executed (?{...}) block does the equivalent of
+        *   local $^R = do {...}
+        * When popping the save stack, all these locals would be undone;
+        * bypass this by setting the outermost saved $^R to the latest
+        * value */
+       if (oreplsv != GvSV(PL_replgv))
+           sv_setsv(oreplsv, GvSV(PL_replgv));
+    }
     result = 1;
     goto final_exit;
 
     result = 1;
     goto final_exit;
 
@@ -5043,20 +5300,9 @@ no_silent:
         sv_setsv(sv_err, sv_commit);
         sv_setsv(sv_mrk, sv_yes_mark);
     }
         sv_setsv(sv_err, sv_commit);
         sv_setsv(sv_mrk, sv_yes_mark);
     }
-    /* restore original high-water mark */
-    PL_regmatch_slab  = orig_slab;
-    PL_regmatch_state = orig_state;
-
-    /* free all slabs above current one */
-    if (orig_slab->next) {
-       regmatch_slab *sl = orig_slab->next;
-       orig_slab->next = NULL;
-       while (sl) {
-           regmatch_slab * const osl = sl;
-           sl = sl->next;
-           Safefree(osl);
-       }
-    }
+
+    /* clean up; in particular, free all slabs above current one */
+    LEAVE_SCOPE(oldsave);
 
     return result;
 }
 
     return result;
 }
@@ -5078,6 +5324,9 @@ S_regrepeat(pTHX_ const regexp *prog, const regnode *p, I32 max, int depth)
     register char *loceol = PL_regeol;
     register I32 hardcount = 0;
     register bool do_utf8 = PL_reg_match_utf8;
     register char *loceol = PL_regeol;
     register I32 hardcount = 0;
     register bool do_utf8 = PL_reg_match_utf8;
+#ifndef DEBUGGING
+    PERL_UNUSED_ARG(depth);
+#endif
 
     scan = PL_reginput;
     if (max == REG_INFTY)
 
     scan = PL_reginput;
     if (max == REG_INFTY)
@@ -5240,8 +5489,8 @@ S_regrepeat(pTHX_ const regexp *prog, const regnode *p, I32 max, int depth)
        } else {
            while (scan < loceol && !isSPACE(*scan))
                scan++;
        } else {
            while (scan < loceol && !isSPACE(*scan))
                scan++;
-           break;
        }
        }
+       break;
     case NSPACEL:
        PL_reg_flags |= RF_tainted;
        if (do_utf8) {
     case NSPACEL:
        PL_reg_flags |= RF_tainted;
        if (do_utf8) {
@@ -5283,7 +5532,77 @@ S_regrepeat(pTHX_ const regexp *prog, const regnode *p, I32 max, int depth)
            while (scan < loceol && !isDIGIT(*scan))
                scan++;
        }
            while (scan < loceol && !isDIGIT(*scan))
                scan++;
        }
+    case LNBREAK:
+        if (do_utf8) {
+           loceol = PL_regeol;
+           while (hardcount < max && scan < loceol && (c=is_LNBREAK_utf8(scan))) {
+               scan += c;
+               hardcount++;
+           }
+       } else {
+           /*
+             LNBREAK can match two latin chars, which is ok,
+             because we have a null terminated string, but we
+             have to use hardcount in this situation
+           */
+           while (scan < loceol && (c=is_LNBREAK_latin1(scan)))  {
+               scan+=c;
+               hardcount++;
+           }
+       }       
+       break;
+    case HORIZWS:
+        if (do_utf8) {
+           loceol = PL_regeol;
+           while (hardcount < max && scan < loceol && (c=is_HORIZWS_utf8(scan))) {
+               scan += c;
+               hardcount++;
+           }
+       } else {
+           while (scan < loceol && is_HORIZWS_latin1(scan)) 
+               scan++;         
+       }       
+       break;
+    case NHORIZWS:
+        if (do_utf8) {
+           loceol = PL_regeol;
+           while (hardcount < max && scan < loceol && !is_HORIZWS_utf8(scan)) {
+               scan += UTF8SKIP(scan);
+               hardcount++;
+           }
+       } else {
+           while (scan < loceol && !is_HORIZWS_latin1(scan))
+               scan++;
+
+       }       
        break;
        break;
+    case VERTWS:
+        if (do_utf8) {
+           loceol = PL_regeol;
+           while (hardcount < max && scan < loceol && (c=is_VERTWS_utf8(scan))) {
+               scan += c;
+               hardcount++;
+           }
+       } else {
+           while (scan < loceol && is_VERTWS_latin1(scan)) 
+               scan++;
+
+       }       
+       break;
+    case NVERTWS:
+        if (do_utf8) {
+           loceol = PL_regeol;
+           while (hardcount < max && scan < loceol && !is_VERTWS_utf8(scan)) {
+               scan += UTF8SKIP(scan);
+               hardcount++;
+           }
+       } else {
+           while (scan < loceol && !is_VERTWS_latin1(scan)) 
+               scan++;
+          
+       }       
+       break;
+
     default:           /* Called on something of 0 width. */
        break;          /* So match right here or not at all. */
     }
     default:           /* Called on something of 0 width. */
        break;          /* So match right here or not at all. */
     }
@@ -5321,7 +5640,8 @@ Perl_regclass_swash(pTHX_ const regexp *prog, register const regnode* node, bool
     SV *sw  = NULL;
     SV *si  = NULL;
     SV *alt = NULL;
     SV *sw  = NULL;
     SV *si  = NULL;
     SV *alt = NULL;
-    const struct reg_data * const data = prog ? prog->data : NULL;
+    RXi_GET_DECL(prog,progi);
+    const struct reg_data * const data = prog ? progi->data : NULL;
 
     if (data && data->count) {
        const U32 n = ARG(node);
 
     if (data && data->count) {
        const U32 n = ARG(node);
@@ -5336,8 +5656,8 @@ Perl_regclass_swash(pTHX_ const regexp *prog, register const regnode* node, bool
             * documentation of these array elements. */
 
            si = *ary;
             * documentation of these array elements. */
 
            si = *ary;
-           a  = SvROK(ary[1]) ? &ary[1] : 0;
-           b  = SvTYPE(ary[2]) == SVt_PVAV ? &ary[2] : 0;
+           a  = SvROK(ary[1]) ? &ary[1] : NULL;
+           b  = SvTYPE(ary[2]) == SVt_PVAV ? &ary[2] : NULL;
 
            if (a)
                sw = *a;
 
            if (a)
                sw = *a;
@@ -5583,7 +5903,7 @@ restore_pos(pTHX_ void *arg)
 #ifdef PERL_OLD_COPY_ON_WRITE
            rex->saved_copy = PL_nrs;
 #endif
 #ifdef PERL_OLD_COPY_ON_WRITE
            rex->saved_copy = PL_nrs;
 #endif
-           RX_MATCH_COPIED_on(rex);
+           RXp_MATCH_COPIED_on(rex);
        }
        PL_reg_magic->mg_len = PL_reg_oldpos;
        PL_reg_eval_set = 0;
        }
        PL_reg_magic->mg_len = PL_reg_oldpos;
        PL_reg_eval_set = 0;
@@ -5594,56 +5914,60 @@ restore_pos(pTHX_ void *arg)
 STATIC void
 S_to_utf8_substr(pTHX_ register regexp *prog)
 {
 STATIC void
 S_to_utf8_substr(pTHX_ register regexp *prog)
 {
-    if (prog->float_substr && !prog->float_utf8) {
-       SV* const sv = newSVsv(prog->float_substr);
-       prog->float_utf8 = sv;
-       sv_utf8_upgrade(sv);
-       if (SvTAIL(prog->float_substr))
-           SvTAIL_on(sv);
-       if (prog->float_substr == prog->check_substr)
-           prog->check_utf8 = sv;
-    }
-    if (prog->anchored_substr && !prog->anchored_utf8) {
-       SV* const sv = newSVsv(prog->anchored_substr);
-       prog->anchored_utf8 = sv;
-       sv_utf8_upgrade(sv);
-       if (SvTAIL(prog->anchored_substr))
-           SvTAIL_on(sv);
-       if (prog->anchored_substr == prog->check_substr)
-           prog->check_utf8 = sv;
-    }
+    int i = 1;
+    do {
+       if (prog->substrs->data[i].substr
+           && !prog->substrs->data[i].utf8_substr) {
+           SV* const sv = newSVsv(prog->substrs->data[i].substr);
+           prog->substrs->data[i].utf8_substr = sv;
+           sv_utf8_upgrade(sv);
+           if (SvVALID(prog->substrs->data[i].substr)) {
+               const U8 flags = BmFLAGS(prog->substrs->data[i].substr);
+               if (flags & FBMcf_TAIL) {
+                   /* Trim the trailing \n that fbm_compile added last
+                      time.  */
+                   SvCUR_set(sv, SvCUR(sv) - 1);
+                   /* Whilst this makes the SV technically "invalid" (as its
+                      buffer is no longer followed by "\0") when fbm_compile()
+                      adds the "\n" back, a "\0" is restored.  */
+               }
+               fbm_compile(sv, flags);
+           }
+           if (prog->substrs->data[i].substr == prog->check_substr)
+               prog->check_utf8 = sv;
+       }
+    } while (i--);
 }
 
 STATIC void
 S_to_byte_substr(pTHX_ register regexp *prog)
 {
     dVAR;
 }
 
 STATIC void
 S_to_byte_substr(pTHX_ register regexp *prog)
 {
     dVAR;
-    if (prog->float_utf8 && !prog->float_substr) {
-       SV* sv = newSVsv(prog->float_utf8);
-       prog->float_substr = sv;
-       if (sv_utf8_downgrade(sv, TRUE)) {
-           if (SvTAIL(prog->float_utf8))
-               SvTAIL_on(sv);
-       } else {
-           SvREFCNT_dec(sv);
-           prog->float_substr = sv = &PL_sv_undef;
-       }
-       if (prog->float_utf8 == prog->check_utf8)
-           prog->check_substr = sv;
-    }
-    if (prog->anchored_utf8 && !prog->anchored_substr) {
-       SV* sv = newSVsv(prog->anchored_utf8);
-       prog->anchored_substr = sv;
-       if (sv_utf8_downgrade(sv, TRUE)) {
-           if (SvTAIL(prog->anchored_utf8))
-               SvTAIL_on(sv);
-       } else {
-           SvREFCNT_dec(sv);
-           prog->anchored_substr = sv = &PL_sv_undef;
+    int i = 1;
+    do {
+       if (prog->substrs->data[i].utf8_substr
+           && !prog->substrs->data[i].substr) {
+           SV* sv = newSVsv(prog->substrs->data[i].utf8_substr);
+           if (sv_utf8_downgrade(sv, TRUE)) {
+               if (SvVALID(prog->substrs->data[i].utf8_substr)) {
+                   const U8 flags
+                       = BmFLAGS(prog->substrs->data[i].utf8_substr);
+                   if (flags & FBMcf_TAIL) {
+                       /* Trim the trailing \n that fbm_compile added last
+                          time.  */
+                       SvCUR_set(sv, SvCUR(sv) - 1);
+                   }
+                   fbm_compile(sv, flags);
+               }           
+           } else {
+               SvREFCNT_dec(sv);
+               sv = &PL_sv_undef;
+           }
+           prog->substrs->data[i].substr = sv;
+           if (prog->substrs->data[i].utf8_substr == prog->check_utf8)
+               prog->check_substr = sv;
        }
        }
-       if (prog->anchored_utf8 == prog->check_utf8)
-           prog->check_substr = sv;
-    }
+    } while (i--);
 }
 
 /*
 }
 
 /*