This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
fix refcount of rex attached to PL_reg_curpm
[perl5.git] / regexec.c
index 46484df..a20b60a 100644 (file)
--- a/regexec.c
+++ b/regexec.c
@@ -87,9 +87,6 @@
 
 #define UTF_PATTERN ((PL_reg_flags & RF_utf8) != 0)
 
-#define RS_init                1               /* eval environment created */
-#define RS_set         2               /* replsv value is set */
-
 #ifndef STATIC
 #define        STATIC  static
 #endif
 
 static void restore_pos(pTHX_ void *arg);
 
-#define REGCP_PAREN_ELEMS 4
-#define REGCP_OTHER_ELEMS 5
+#define REGCP_PAREN_ELEMS 3
+#define REGCP_OTHER_ELEMS 3
 #define REGCP_FRAME_ELEMS 1
 /* REGCP_FRAME_ELEMS are not part of the REGCP_OTHER_ELEMS and
  * are needed for the regexp context stack bookkeeping. */
 
 STATIC CHECKPOINT
-S_regcppush(pTHX_ I32 parenfloor)
+S_regcppush(pTHX_ const regexp *rex, I32 parenfloor)
 {
     dVAR;
     const int retval = PL_savestack_ix;
     const int paren_elems_to_push = (PL_regsize - parenfloor) * REGCP_PAREN_ELEMS;
     const UV total_elems = paren_elems_to_push + REGCP_OTHER_ELEMS;
     const UV elems_shifted = total_elems << SAVE_TIGHT_SHIFT;
-    int p;
+    I32 p;
     GET_RE_DEBUG_FLAGS_DECL;
 
+    PERL_ARGS_ASSERT_REGCPPUSH;
+
     if (paren_elems_to_push < 0)
        Perl_croak(aTHX_ "panic: paren_elems_to_push, %i < 0",
                   paren_elems_to_push);
@@ -363,25 +362,31 @@ S_regcppush(pTHX_ I32 parenfloor)
 
     SSGROW(total_elems + REGCP_FRAME_ELEMS);
     
-    for (p = PL_regsize; p > parenfloor; p--) {
+    DEBUG_BUFFERS_r(
+       if ((int)PL_regsize > (int)parenfloor)
+           PerlIO_printf(Perl_debug_log,
+               "rex=0x%"UVxf" offs=0x%"UVxf": saving capture indices:\n",
+               PTR2UV(rex),
+               PTR2UV(rex->offs)
+           );
+    );
+    for (p = parenfloor+1; p <= (I32)PL_regsize;  p++) {
 /* REGCP_PARENS_ELEMS are pushed per pairs of parentheses. */
-       SSPUSHINT(PL_regoffs[p].end);
-       SSPUSHINT(PL_regoffs[p].start);
-       SSPUSHPTR(PL_reg_start_tmp[p]);
-       SSPUSHINT(p);
+       SSPUSHINT(rex->offs[p].end);
+       SSPUSHINT(rex->offs[p].start);
+       SSPUSHINT(rex->offs[p].start_tmp);
        DEBUG_BUFFERS_r(PerlIO_printf(Perl_debug_log,
-         "     saving \\%"UVuf" %"IVdf"(%"IVdf")..%"IVdf"\n",
-                     (UV)p, (IV)PL_regoffs[p].start,
-                     (IV)(PL_reg_start_tmp[p] - PL_bostr),
-                     (IV)PL_regoffs[p].end
+           "    \\%"UVuf": %"IVdf"(%"IVdf")..%"IVdf"\n",
+           (UV)p,
+           (IV)rex->offs[p].start,
+           (IV)rex->offs[p].start_tmp,
+           (IV)rex->offs[p].end
        ));
     }
 /* REGCP_OTHER_ELEMS are pushed in any case, parentheses or no. */
-    SSPUSHPTR(PL_regoffs);
     SSPUSHINT(PL_regsize);
-    SSPUSHINT(*PL_reglastparen);
-    SSPUSHINT(*PL_reglastcloseparen);
-    SSPUSHPTR(PL_reginput);
+    SSPUSHINT(rex->lastparen);
+    SSPUSHINT(rex->lastcloseparen);
     SSPUSHUV(SAVEt_REGCONTEXT | elems_shifted); /* Magic cookie. */
 
     return retval;
@@ -403,12 +408,12 @@ S_regcppush(pTHX_ I32 parenfloor)
                (IV)(cp), (IV)PL_savestack_ix));                \
     regcpblow(cp)
 
-STATIC char *
-S_regcppop(pTHX_ const regexp *rex)
+STATIC void
+S_regcppop(pTHX_ regexp *rex)
 {
     dVAR;
     UV i;
-    char *input;
+    U32 paren;
     GET_RE_DEBUG_FLAGS_DECL;
 
     PERL_ARGS_ASSERT_REGCPPOP;
@@ -417,38 +422,38 @@ S_regcppop(pTHX_ const regexp *rex)
     i = SSPOPUV;
     assert((i & SAVE_MASK) == SAVEt_REGCONTEXT); /* Check that the magic cookie is there. */
     i >>= SAVE_TIGHT_SHIFT; /* Parentheses elements to pop. */
-    input = (char *) SSPOPPTR;
-    *PL_reglastcloseparen = SSPOPINT;
-    *PL_reglastparen = SSPOPINT;
+    rex->lastcloseparen = SSPOPINT;
+    rex->lastparen = SSPOPINT;
     PL_regsize = SSPOPINT;
-    PL_regoffs=(regexp_paren_pair *) SSPOPPTR;
 
     i -= REGCP_OTHER_ELEMS;
     /* Now restore the parentheses context. */
+    DEBUG_BUFFERS_r(
+       if (i || rex->lastparen + 1 <= rex->nparens)
+           PerlIO_printf(Perl_debug_log,
+               "rex=0x%"UVxf" offs=0x%"UVxf": restoring capture indices to:\n",
+               PTR2UV(rex),
+               PTR2UV(rex->offs)
+           );
+    );
+    paren = PL_regsize;
     for ( ; i > 0; i -= REGCP_PAREN_ELEMS) {
        I32 tmps;
-       U32 paren = (U32)SSPOPINT;
-       PL_reg_start_tmp[paren] = (char *) SSPOPPTR;
-       PL_regoffs[paren].start = SSPOPINT;
+       rex->offs[paren].start_tmp = SSPOPINT;
+       rex->offs[paren].start = SSPOPINT;
        tmps = SSPOPINT;
-       if (paren <= *PL_reglastparen)
-           PL_regoffs[paren].end = tmps;
-       DEBUG_BUFFERS_r(
-           PerlIO_printf(Perl_debug_log,
-                         "     restoring \\%"UVuf" to %"IVdf"(%"IVdf")..%"IVdf"%s\n",
-                         (UV)paren, (IV)PL_regoffs[paren].start,
-                         (IV)(PL_reg_start_tmp[paren] - PL_bostr),
-                         (IV)PL_regoffs[paren].end,
-                         (paren > *PL_reglastparen ? "(no)" : ""));
+       if (paren <= rex->lastparen)
+           rex->offs[paren].end = tmps;
+       DEBUG_BUFFERS_r( PerlIO_printf(Perl_debug_log,
+           "    \\%"UVuf": %"IVdf"(%"IVdf")..%"IVdf"%s\n",
+           (UV)paren,
+           (IV)rex->offs[paren].start,
+           (IV)rex->offs[paren].start_tmp,
+           (IV)rex->offs[paren].end,
+           (paren > rex->lastparen ? "(skipped)" : ""));
        );
+       paren--;
     }
-    DEBUG_BUFFERS_r(
-       if (*PL_reglastparen + 1 <= rex->nparens) {
-           PerlIO_printf(Perl_debug_log,
-                         "     restoring \\%"IVdf"..\\%"IVdf" to undef\n",
-                         (IV)(*PL_reglastparen + 1), (IV)rex->nparens);
-       }
-    );
 #if 1
     /* It would seem that the similar code in regtry()
      * already takes care of this, and in fact it is in
@@ -459,13 +464,17 @@ S_regcppop(pTHX_ const regexp *rex)
      * this code seems to be necessary or otherwise
      * this erroneously leaves $1 defined: "1" =~ /^(?:(\d)x)?\d$/
      * --jhi updated by dapm */
-    for (i = *PL_reglastparen + 1; i <= rex->nparens; i++) {
+    for (i = rex->lastparen + 1; i <= rex->nparens; i++) {
        if (i > PL_regsize)
-           PL_regoffs[i].start = -1;
-       PL_regoffs[i].end = -1;
+           rex->offs[i].start = -1;
+       rex->offs[i].end = -1;
+       DEBUG_BUFFERS_r( PerlIO_printf(Perl_debug_log,
+           "    \\%"UVuf": %s   ..-1 undeffing\n",
+           (UV)i,
+           (i > PL_regsize) ? "-1" : "  "
+       ));
     }
 #endif
-    return input;
 }
 
 #define regcpblow(cp) LEAVE_SCOPE(cp)  /* Ignores regcppush()ed data. */
@@ -561,6 +570,7 @@ Perl_re_intuit_start(pTHX_ REGEXP * const rx, SV *sv, char *strpos,
     I32 ml_anch;
     register char *other_last = NULL;  /* other substr checked before this */
     char *check_at = NULL;             /* check substr found at this pos */
+    char *checked_upto = NULL;          /* how far into the string we have already checked using find_byclass*/
     const I32 multiline = prog->extflags & RXf_PMf_MULTILINE;
     RXi_GET_DECL(prog,progi);
 #ifdef DEBUGGING
@@ -569,6 +579,8 @@ Perl_re_intuit_start(pTHX_ REGEXP * const rx, SV *sv, char *strpos,
     GET_RE_DEBUG_FLAGS_DECL;
 
     PERL_ARGS_ASSERT_RE_INTUIT_START;
+    PERL_UNUSED_ARG(flags);
+    PERL_UNUSED_ARG(data);
 
     RX_MATCH_UTF8_set(rx,utf8_target);
 
@@ -687,6 +699,8 @@ Perl_re_intuit_start(pTHX_ REGEXP * const rx, SV *sv, char *strpos,
     {
         I32 srch_start_shift = start_shift;
         I32 srch_end_shift = end_shift;
+        U8* start_point;
+        U8* end_point;
         if (srch_start_shift < 0 && strbeg - s > srch_start_shift) {
            srch_end_shift -= ((strbeg - s) - srch_start_shift); 
            srch_start_shift = strbeg - s;
@@ -699,42 +713,6 @@ Perl_re_intuit_start(pTHX_ REGEXP * const rx, SV *sv, char *strpos,
             (IV)prog->check_end_shift);
     });       
         
-    if ((flags & REXEC_SCREAM) && SvSCREAM(sv)) {
-       I32 p = -1;                     /* Internal iterator of scream. */
-       I32 * const pp = data ? data->scream_pos : &p;
-       const MAGIC *mg;
-       bool found = FALSE;
-
-       assert(SvMAGICAL(sv));
-       mg = mg_find(sv, PERL_MAGIC_study);
-       assert(mg);
-
-       if (mg->mg_private == 1) {
-           found = ((U8 *)mg->mg_ptr)[BmRARE(check)] != (U8)~0;
-       } else if (mg->mg_private == 2) {
-           found = ((U16 *)mg->mg_ptr)[BmRARE(check)] != (U16)~0;
-       } else {
-           assert (mg->mg_private == 4);
-           found = ((U32 *)mg->mg_ptr)[BmRARE(check)] != (U32)~0;
-       }
-
-       if (found
-           || ( BmRARE(check) == '\n'
-                && (BmPREVIOUS(check) == SvCUR(check) - 1)
-                && SvTAIL(check) ))
-           s = screaminstr(sv, check,
-                           srch_start_shift + (s - strbeg), srch_end_shift, pp, 0);
-       else
-           goto fail_finish;
-       /* we may be pointing at the wrong string */
-       if (s && RXp_MATCH_COPIED(prog))
-           s = strbeg + (s - SvPVX_const(sv));
-       if (data)
-           *data->scream_olds = s;
-    }
-    else {
-        U8* start_point;
-        U8* end_point;
         if (prog->extflags & RXf_CANY_SEEN) {
             start_point= (U8*)(s + srch_start_shift);
             end_point= (U8*)(strend - srch_end_shift);
@@ -752,7 +730,6 @@ Perl_re_intuit_start(pTHX_ REGEXP * const rx, SV *sv, char *strpos,
        s = fbm_instr( start_point, end_point,
                      check, multiline ? FBMrf_MULTILINE : 0);
     }
-    }
     /* Update the count-of-usability, remove useless subpatterns,
        unshift s.  */
 
@@ -1090,12 +1067,16 @@ Perl_re_intuit_start(pTHX_ REGEXP * const rx, SV *sv, char *strpos,
         else 
             endpos= strend;
                    
-        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)));
-       
+        if (checked_upto < s)
+           checked_upto = s;
+        DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log, "start_shift: %"IVdf" check_at: %"IVdf" s: %"IVdf" endpos: %"IVdf" checked_upto: %"IVdf"\n",
+                                      (IV)start_shift, (IV)(check_at - strbeg), (IV)(s - strbeg), (IV)(endpos - strbeg), (IV)(checked_upto- strbeg)));
+
        t = s;
-        s = find_byclass(prog, progi->regstclass, s, endpos, NULL);
-       if (!s) {
+        s = find_byclass(prog, progi->regstclass, checked_upto, endpos, NULL);
+       if (s) {
+           checked_upto = s;
+       } else {
 #ifdef DEBUGGING
            const char *what = NULL;
 #endif
@@ -1108,6 +1089,9 @@ Perl_re_intuit_start(pTHX_ REGEXP * const rx, SV *sv, char *strpos,
                                   "This position contradicts STCLASS...\n") );
            if ((prog->extflags & RXf_ANCH) && !ml_anch)
                goto fail;
+           checked_upto = HOPBACKc(endpos, start_shift);
+           DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log, "start_shift: %"IVdf" check_at: %"IVdf" endpos: %"IVdf" checked_upto: %"IVdf"\n",
+                                      (IV)start_shift, (IV)(check_at - strbeg), (IV)(endpos - strbeg), (IV)(checked_upto- strbeg)));
            /* Contradict one of substrings */
            if (prog->anchored_substr || prog->anchored_utf8) {
                if ((utf8_target ? prog->anchored_utf8 : prog->anchored_substr) == check) {
@@ -2099,7 +2083,7 @@ Perl_regexec_flags(pTHX_ REGEXP * const rx, char *stringarg, register char *stre
     }
 
     PL_reg_flags = 0;
-    PL_reg_eval_set = 0;
+    PL_reg_state.re_state_eval_setup_done = FALSE;
     PL_reg_maxiter = 0;
 
     if (RX_UTF8(rx))
@@ -2165,6 +2149,12 @@ Perl_regexec_flags(pTHX_ REGEXP * const rx, char *stringarg, register char *stre
         swap = prog->offs;
         /* do we need a save destructor here for eval dies? */
         Newxz(prog->offs, (prog->nparens + 1), regexp_paren_pair);
+       DEBUG_BUFFERS_r(PerlIO_printf(Perl_debug_log,
+           "rex=0x%"UVxf" saving  offs: orig=0x%"UVxf" new=0x%"UVxf"\n",
+           PTR2UV(prog),
+           PTR2UV(swap),
+           PTR2UV(prog->offs)
+       ));
     }
     if (!(flags & REXEC_CHECKED) && (prog->check_substr != NULL || prog->check_utf8 != NULL)) {
        re_scream_pos_data d;
@@ -2357,15 +2347,9 @@ Perl_regexec_flags(pTHX_ REGEXP * const rx, char *stringarg, register char *stre
        dontbother = end_shift;
        strend = HOPc(strend, -dontbother);
        while ( (s <= last) &&
-               ((flags & REXEC_SCREAM) && SvSCREAM(sv)
-                ? (s = screaminstr(sv, must, HOP3c(s, back_min, (back_min<0 ? strbeg : strend)) - strbeg,
-                                   end_shift, &scream_pos, 0))
-                : (s = fbm_instr((unsigned char*)HOP3(s, back_min, (back_min<0 ? strbeg : strend)),
+               (s = fbm_instr((unsigned char*)HOP3(s, back_min, (back_min<0 ? strbeg : strend)),
                                  (unsigned char*)strend, must,
-                                 multiline ? FBMrf_MULTILINE : 0))) ) {
-           /* we may be pointing at the wrong string */
-           if ((flags & REXEC_SCREAM) && RXp_MATCH_COPIED(prog))
-               s = strbeg + (s - SvPVX_const(sv));
+                                 multiline ? FBMrf_MULTILINE : 0)) ) {
            DEBUG_EXECUTE_r( did_match = 1 );
            if (HOPc(s, -back_max) > last1) {
                last1 = HOPc(s, -back_min);
@@ -2431,24 +2415,15 @@ Perl_regexec_flags(pTHX_ REGEXP * const rx, char *stringarg, register char *stre
            /* Trim the end. */
            char *last= NULL;
            SV* float_real;
+           STRLEN len;
+           const char *little;
 
            if (!(utf8_target ? prog->float_utf8 : prog->float_substr))
                utf8_target ? to_utf8_substr(prog) : to_byte_substr(prog);
            float_real = utf8_target ? prog->float_utf8 : prog->float_substr;
 
-           if ((flags & REXEC_SCREAM) && SvSCREAM(sv)) {
-               last = screaminstr(sv, float_real, s - strbeg,
-                                  end_shift, &scream_pos, 1); /* last one */
-               if (!last)
-                   last = scream_olds; /* Only one occurrence. */
-               /* we may be pointing at the wrong string */
-               else if (RXp_MATCH_COPIED(prog))
-                   s = strbeg + (s - SvPVX_const(sv));
-           }
-           else {
-               STRLEN len;
-                const char * const little = SvPV_const(float_real, len);
-               if (SvTAIL(float_real)) {
+            little = SvPV_const(float_real, len);
+           if (SvTAIL(float_real)) {
                    /* This means that float_real contains an artificial \n on the end
                     * due to the presence of something like this: /foo$/
                     * where we can match both "foo" and "foo\n" at the end of the string.
@@ -2494,13 +2469,12 @@ Perl_regexec_flags(pTHX_ REGEXP * const rx, char *stringarg, register char *stre
                        /* multiline match, so we have to search for a place where the full string is located */
                        goto find_last;
                    }
-               } else {
+           } else {
                  find_last:
                    if (len)
                        last = rninstr(s, strend, little, little + len);
                    else
                        last = strend;  /* matching "$" */
-               }
            }
            if (!last) {
                /* at one point this block contained a comment which was probably
@@ -2541,10 +2515,18 @@ Perl_regexec_flags(pTHX_ REGEXP * const rx, char *stringarg, register char *stre
     goto phooey;
 
 got_it:
+    DEBUG_BUFFERS_r(
+       if (swap)
+           PerlIO_printf(Perl_debug_log,
+               "rex=0x%"UVxf" freeing offs: 0x%"UVxf"\n",
+               PTR2UV(prog),
+               PTR2UV(swap)
+           );
+    );
     Safefree(swap);
     RX_MATCH_TAINTED_set(rx, PL_reg_flags & RF_tainted);
 
-    if (PL_reg_eval_set)
+    if (PL_reg_state.re_state_eval_setup_done)
        restore_pos(aTHX_ prog);
     if (RXp_PAREN_NAMES(prog)) 
         (void)hv_iterinit(RXp_PAREN_NAMES(prog));
@@ -2585,10 +2567,16 @@ got_it:
 phooey:
     DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log, "%sMatch failed%s\n",
                          PL_colors[4], PL_colors[5]));
-    if (PL_reg_eval_set)
+    if (PL_reg_state.re_state_eval_setup_done)
        restore_pos(aTHX_ prog);
     if (swap) {
         /* we failed :-( roll it back */
+       DEBUG_BUFFERS_r(PerlIO_printf(Perl_debug_log,
+           "rex=0x%"UVxf" rolling back offs: freeing=0x%"UVxf" restoring=0x%"UVxf"\n",
+           PTR2UV(prog),
+           PTR2UV(prog->offs),
+           PTR2UV(swap)
+       ));
         Safefree(prog->offs);
         prog->offs = swap;
     }
@@ -2597,6 +2585,16 @@ phooey:
 }
 
 
+/* Set which rex is pointed to by PL_reg_state, handling ref counting.
+ * Do inc before dec, in case old and new rex are the same */
+#define SET_reg_curpm(Re2) \
+    if (PL_reg_state.re_state_eval_setup_done) {    \
+       (void)ReREFCNT_inc(Re2);                    \
+       ReREFCNT_dec(PM_GETRE(PL_reg_curpm));       \
+       PM_SETRE((PL_reg_curpm), (Re2));            \
+    }
+
+
 /*
  - regtry - try match at specific point
  */
@@ -2614,22 +2612,12 @@ S_regtry(pTHX_ regmatch_info *reginfo, char **startpos)
 
     reginfo->cutpoint=NULL;
 
-    if ((prog->extflags & RXf_EVAL_SEEN) && !PL_reg_eval_set) {
+    if ((prog->extflags & RXf_EVAL_SEEN)
+       && !PL_reg_state.re_state_eval_setup_done)
+    {
        MAGIC *mg;
 
-       PL_reg_eval_set = RS_init;
-       DEBUG_EXECUTE_r(DEBUG_s(
-           PerlIO_printf(Perl_debug_log, "  setting stack tmpbase at %"IVdf"\n",
-                         (IV)(PL_stack_sp - PL_stack_base));
-           ));
-       SAVESTACK_CXPOS();
-       cxstack[cxstack_ix].blk_oldsp = PL_stack_sp - PL_stack_base;
-       /* Otherwise OP_NEXTSTATE will free whatever on stack now.  */
-       SAVETMPS;
-       /* Apparently this is not needed, judging by wantarray. */
-       /* SAVEI8(cxstack[cxstack_ix].blk_gimme);
-          cxstack[cxstack_ix].blk_gimme = G_SCALAR; */
-
+       PL_reg_state.re_state_eval_setup_done = TRUE;
        if (reginfo->sv) {
            /* Make $_ available to executed code. */
            if (reginfo->sv != DEFSV) {
@@ -2665,16 +2653,7 @@ S_regtry(pTHX_ regmatch_info *reginfo, char **startpos)
             }
 #endif      
         }
-#ifdef USE_ITHREADS
-       /* It seems that non-ithreads works both with and without this code.
-          So for efficiency reasons it seems best not to have the code
-          compiled when it is not needed.  */
-       /* This is safe against NULLs: */
-       ReREFCNT_dec(PM_GETRE(PL_reg_curpm));
-       /* PM_reg_curpm owns a reference to this regexp.  */
-       (void)ReREFCNT_inc(rx);
-#endif
-       PM_SETRE(PL_reg_curpm, rx);
+       SET_reg_curpm(rx);
        PL_reg_oldcurpm = PL_curpm;
        PL_curpm = PL_reg_curpm;
        if (RXp_MATCH_COPIED(prog)) {
@@ -2693,30 +2672,22 @@ S_regtry(pTHX_ regmatch_info *reginfo, char **startpos)
        prog->subbeg = PL_bostr;
        prog->sublen = PL_regeol - PL_bostr; /* strend may have been modified */
     }
-    DEBUG_EXECUTE_r(PL_reg_starttry = *startpos);
+#ifdef DEBUGGING
+    PL_reg_starttry = *startpos;
+#endif
     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_regoffs = prog->offs;
-    if (PL_reg_start_tmpl <= prog->nparens) {
-       PL_reg_start_tmpl = prog->nparens*3/2 + 3;
-        if(PL_reg_start_tmp)
-            Renew(PL_reg_start_tmp, PL_reg_start_tmpl, char*);
-        else
-            Newx(PL_reg_start_tmp, PL_reg_start_tmpl, char*);
-    }
 
     /* XXXX What this code is doing here?!!!  There should be no need
-       to do this again and again, PL_reglastparen should take care of
+       to do this again and again, prog->lastparen should take care of
        this!  --ilya*/
 
     /* 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
+     * prog->lastparen), is not needed at all by the test suite
      * (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
@@ -2725,9 +2696,9 @@ S_regtry(pTHX_ regmatch_info *reginfo, char **startpos)
      * --jhi updated by dapm */
 #if 1
     if (prog->nparens) {
-       regexp_paren_pair *pp = PL_regoffs;
+       regexp_paren_pair *pp = prog->offs;
        register I32 i;
-       for (i = prog->nparens; i > (I32)*PL_reglastparen; i--) {
+       for (i = prog->nparens; i > (I32)prog->lastparen; i--) {
            ++pp;
            pp->start = -1;
            pp->end = -1;
@@ -2736,7 +2707,7 @@ S_regtry(pTHX_ regmatch_info *reginfo, char **startpos)
 #endif
     REGCP_SET(lastcp);
     if (regmatch(reginfo, progi->program + 1)) {
-       PL_regoffs[0].end = PL_reginput - PL_bostr;
+       prog->offs[0].end = PL_reginput - PL_bostr;
        return 1;
     }
     if (reginfo->cutpoint)
@@ -3072,8 +3043,8 @@ S_reg_check_named_buff_matched(pTHX_ const regexp *rex, const regnode *scan)
     PERL_ARGS_ASSERT_REG_CHECK_NAMED_BUFF_MATCHED;
 
     for ( n=0; n<SvIVX(sv_dat); n++ ) {
-        if ((I32)*PL_reglastparen >= nums[n] &&
-            PL_regoffs[nums[n]].end != -1)
+        if ((I32)rex->lastparen >= nums[n] &&
+            rex->offs[nums[n]].end != -1)
         {
             return nums[n];
         }
@@ -3101,10 +3072,6 @@ S_clear_backtrack_stack(pTHX_ void *p)
 }
 
 
-#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)
 {
@@ -3166,10 +3133,22 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                                false: plain (?=foo)
                                true:  used as a condition: (?(?=foo))
                            */
+    PAD* last_pad = NULL;
+    dMULTICALL;
+    I32 gimme = G_SCALAR;
+    CV *caller_cv = NULL;      /* who called us */
+    CV *last_pushed_cv = NULL; /* most recently called (?{}) CV */
+
 #ifdef DEBUGGING
     GET_RE_DEBUG_FLAGS_DECL;
 #endif
 
+    /* shut up 'may be used uninitialized' compiler warnings for dMULTICALL */
+    multicall_oldcatch = 0;
+    multicall_cv = NULL;
+    cx = NULL;
+
+
     PERL_ARGS_ASSERT_REGMATCH;
 
     DEBUG_OPTIMISE_r( DEBUG_EXECUTE_r({
@@ -3219,10 +3198,6 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
 
       reenter_switch:
 
-       assert(PL_reglastparen == &rex->lastparen);
-       assert(PL_reglastcloseparen == &rex->lastcloseparen);
-       assert(PL_regoffs == rex->offs);
-
        switch (state_num) {
        case BOL:
            if (locinput == PL_bostr)
@@ -3249,14 +3224,14 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
 
        case KEEPS:
            /* update the startpoint */
-           st->u.keeper.val = PL_regoffs[0].start;
+           st->u.keeper.val = rex->offs[0].start;
            PL_reginput = locinput;
-           PL_regoffs[0].start = locinput - PL_bostr;
+           rex->offs[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;
+           rex->offs[0].start = st->u.keeper.val;
            sayNO_SILENT;
            /*NOT-REACHED*/
        case EOL:
@@ -3406,7 +3381,6 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                U32 charcount = 0; /* how many input chars we have matched */
                U32 accepted = 0; /* have we seen any accepting states? */
 
-               ST.B = next;
                ST.jump = trie->jump;
                ST.me = scan;
                ST.firstpos = NULL;
@@ -3510,9 +3484,10 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
        case TRIE_next_fail: /* we failed - try next alternative */
             if ( ST.jump) {
                 REGCP_UNWIND(ST.cp);
-               for (n = *PL_reglastparen; n > ST.lastparen; n--)
-                   PL_regoffs[n].end = -1;
-               *PL_reglastparen = n;
+               for (n = rex->lastparen; n > ST.lastparen; n--)
+                   rex->offs[n].end = -1;
+               rex->lastparen = n;
+               rex->lastcloseparen = ST.lastcloseparen;
            }
            if (!--ST.accepted) {
                DEBUG_EXECUTE_r({
@@ -3546,7 +3521,8 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
             }
 
             if ( ST.jump) {
-                ST.lastparen = *PL_reglastparen;
+                ST.lastparen = rex->lastparen;
+                ST.lastcloseparen = rex->lastcloseparen;
                REGCP_SET(ST.cp);
             }
 
@@ -3603,9 +3579,9 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                PL_reginput = (char *)uc;
            }
 
-           scan = (ST.jump && ST.jump[ST.nextword]) 
-                       ? ST.me + ST.jump[ST.nextword]
-                       : ST.B;
+           scan = ST.me + ((ST.jump && ST.jump[ST.nextword])
+                           ? ST.jump[ST.nextword]
+                           : NEXT_OFF(ST.me));
 
            DEBUG_EXECUTE_r({
                PerlIO_printf( Perl_debug_log,
@@ -4191,11 +4167,11 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
            n = ARG(scan);  /* which paren pair */
 
          do_nref_ref_common:
-           ln = PL_regoffs[n].start;
+           ln = rex->offs[n].start;
            PL_reg_leftiter = PL_reg_maxiter;           /* Void cache */
-           if (*PL_reglastparen < n || ln == -1)
+           if (rex->lastparen < n || ln == -1)
                sayNO;                  /* Do not match unless seen CLOSEn. */
-           if (ln == PL_regoffs[n].end)
+           if (ln == rex->offs[n].end)
                break;
 
            s = PL_bostr + ln;
@@ -4209,7 +4185,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                    * not going off the end given by PL_regeol, and returns in
                    * limit upon success, how much of the current input was
                    * matched */
-               if (! foldEQ_utf8_flags(s, NULL, PL_regoffs[n].end - ln, utf8_target,
+               if (! foldEQ_utf8_flags(s, NULL, rex->offs[n].end - ln, utf8_target,
                                    locinput, &limit, 0, utf8_target, utf8_fold_flags))
                {
                    sayNO;
@@ -4224,7 +4200,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                (type == REF ||
                 UCHARAT(s) != fold_array[nextchr]))
                sayNO;
-           ln = PL_regoffs[n].end - ln;
+           ln = rex->offs[n].end - ln;
            if (locinput + ln > PL_regeol)
                sayNO;
            if (ln > 1 && (type == REF
@@ -4265,7 +4241,6 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
            re_sv = rex_sv;
             re = rex;
             rei = rexi;
-            (void)ReREFCNT_inc(rex_sv);
             if (OP(scan)==GOSUB) {
                 startpoint = scan + ARG2L(scan);
                 ST.close_paren = ARG(scan);
@@ -4284,13 +4259,15 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
             }    
            {
                /* execute the code in the {...} */
+
                dSP;
-               SV ** const before = SP;
-               OP_4tree * const oop = PL_op;
+               SV ** before;
+               OP * const oop = PL_op;
                COP * const ocurcop = PL_curcop;
-               PAD *old_comppad;
+               OP *nop;
                char *saved_regeol = PL_regeol;
                struct re_save_state saved_state;
+               CV *newcv;
 
                /* To not corrupt the existing regex state while executing the
                 * eval we would normally put it on the save stack, like with
@@ -4308,24 +4285,99 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                 */
                Copy(&PL_reg_state, &saved_state, 1, struct re_save_state);
 
+               PL_reg_state.re_reparsing = FALSE;
+
+               if (!caller_cv)
+                   caller_cv = find_runcv(NULL);
+
                n = ARG(scan);
-               PL_op = (OP_4tree*)rexi->data->data[n];
+
+               if (rexi->data->what[n] == 'r') { /* code from an external qr */
+                   newcv = ((struct regexp *)SvANY(
+                                               (REGEXP*)(rexi->data->data[n])
+                                           ))->qr_anoncv
+                                       ;
+                   nop = (OP*)rexi->data->data[n+1];
+               }
+               else if (rexi->data->what[n] == 'l') { /* literal code */
+                   newcv = caller_cv;
+                   nop = (OP*)rexi->data->data[n];
+                   assert(CvDEPTH(newcv));
+               }
+               else {
+                   /* literal with own CV */
+                   assert(rexi->data->what[n] == 'L');
+                   newcv = rex->qr_anoncv;
+                   nop = (OP*)rexi->data->data[n];
+               }
+
+               /* the initial nextstate you would normally execute
+                * at the start of an eval (which would cause error
+                * messages to come from the eval), may be optimised
+                * away from the execution path in the regex code blocks;
+                * so manually set PL_curcop to it initially */
+               {
+                   OP *o = cUNOPx(nop)->op_first;
+                   assert(o->op_type == OP_NULL);
+                   if (o->op_targ == OP_SCOPE) {
+                       o = cUNOPo->op_first;
+                   }
+                   else {
+                       assert(o->op_targ == OP_LEAVE);
+                       o = cUNOPo->op_first;
+                       assert(o->op_type == OP_ENTER);
+                       o = o->op_sibling;
+                   }
+
+                   if (o->op_type != OP_STUB) {
+                       assert(    o->op_type == OP_NEXTSTATE
+                               || o->op_type == OP_DBSTATE
+                               || (o->op_type == OP_NULL
+                                   &&  (  o->op_targ == OP_NEXTSTATE
+                                       || o->op_targ == OP_DBSTATE
+                                       )
+                                   )
+                       );
+                       PL_curcop = (COP*)o;
+                   }
+               }
+               nop = nop->op_next;
+
                DEBUG_STATE_r( PerlIO_printf(Perl_debug_log, 
-                   "  re_eval 0x%"UVxf"\n", PTR2UV(PL_op)) );
-               /* wrap the call in two SAVECOMPPADs. This ensures that
-                * when the save stack is eventually unwound, all the
-                * accumulated SAVEt_CLEARSV's will be processed with
-                * interspersed SAVEt_COMPPAD's to ensure that lexicals
-                * are cleared in the right pad */
-               SAVECOMPPAD();
-               PAD_SAVE_LOCAL(old_comppad, (PAD*)rexi->data->data[n + 2]);
-               PL_regoffs[0].end = PL_reg_magic->mg_len = locinput - PL_bostr;
+                   "  re EVAL PL_op=0x%"UVxf"\n", PTR2UV(nop)) );
+
+               /* normally if we're about to execute code from the same
+                * CV that we used previously, we just use the existing
+                * CX stack entry. However, its possible that in the
+                * meantime we may have backtracked, popped from the save
+                * stack, and undone the SAVECOMPPAD(s) associated with
+                * PUSH_MULTICALL; in which case PL_comppad no longer
+                * points to newcv's pad. */
+               if (newcv != last_pushed_cv || PL_comppad != last_pad)
+               {
+                   I32 depth = (newcv == caller_cv) ? 0 : 1;
+                   if (last_pushed_cv) {
+                       CHANGE_MULTICALL_WITHDEPTH(newcv, depth);
+                   }
+                   else {
+                       PUSH_MULTICALL_WITHDEPTH(newcv, depth);
+                   }
+                   last_pushed_cv = newcv;
+               }
+               last_pad = PL_comppad;
+
+               rex->offs[0].end = PL_reg_magic->mg_len = locinput - PL_bostr;
 
                 if (sv_yes_mark) {
                     SV *sv_mrk = get_sv("REGMARK", 1);
                     sv_setsv(sv_mrk, sv_yes_mark);
                 }
 
+               /* we don't use MULTICALL here as we want to call the
+                * first op of the block of interest, rather than the
+                * first op of the sub */
+               before = SP;
+               PL_op = nop;
                CALLRUNOPS(aTHX);                       /* Scalar context. */
                SPAGAIN;
                if (SP == before)
@@ -4337,9 +4389,11 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
 
                Copy(&saved_state, &PL_reg_state, 1, struct re_save_state);
 
+               /* *** Note that at this point we don't restore
+                * PL_comppad, (or pop the CxSUB) on the assumption it may
+                * be used again soon. This is safe as long as nothing
+                * in the regexp code uses the pad ! */
                PL_op = oop;
-               SAVECOMPPAD();
-               PAD_RESTORE_LOCAL(old_comppad);
                PL_curcop = ocurcop;
                PL_regeol = saved_regeol;
                if (!logical) {
@@ -4431,25 +4485,12 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                );              
                startpoint = rei->program + 1;
                        ST.close_paren = 0; /* only used for GOSUB */
-                       /* borrowed from regtry */
-                if (PL_reg_start_tmpl <= re->nparens) {
-                    PL_reg_start_tmpl = re->nparens*3/2 + 3;
-                    if(PL_reg_start_tmp)
-                        Renew(PL_reg_start_tmp, PL_reg_start_tmpl, char*);
-                    else
-                        Newx(PL_reg_start_tmp, PL_reg_start_tmpl, char*);
-                }                      
 
         eval_recurse_doit: /* Share code with GOSUB below this line */                         
                /* run the pattern returned from (??{...}) */
-               ST.cp = regcppush(0);   /* Save *all* the positions. */
+               ST.cp = regcppush(rex, 0);      /* Save *all* the positions. */
                REGCP_SET(ST.lastcp);
                
-               PL_regoffs = re->offs; /* essentially NOOP on GOSUB */
-               
-               /* see regtry, specifically PL_reglast(?:close)?paren is a pointer! (i dont know why) :dmq */
-               PL_reglastparen = &re->lastparen;
-               PL_reglastcloseparen = &re->lastcloseparen;
                re->lastparen = 0;
                re->lastcloseparen = 0;
 
@@ -4468,7 +4509,8 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
 
                ST.prev_rex = rex_sv;
                ST.prev_curlyx = cur_curlyx;
-               SETREX(rex_sv,re_sv);
+               rex_sv = re_sv;
+               SET_reg_curpm(rex_sv);
                rex = re;
                rexi = rei;
                cur_curlyx = NULL;
@@ -4488,20 +4530,14 @@ 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; 
-           ReREFCNT_dec(rex_sv);
-           SETREX(rex_sv,ST.prev_rex);
+           rex_sv = ST.prev_rex;
+           SET_reg_curpm(rex_sv);
            rex = (struct regexp *)SvANY(rex_sv);
            rexi = RXi_GET(rex);
            regcpblow(ST.cp);
            cur_eval = ST.prev_eval;
            cur_curlyx = ST.prev_curlyx;
 
-           /* rex was changed so update the pointer in PL_reglastparen and PL_reglastcloseparen */
-           PL_reglastparen = &rex->lastparen;
-           PL_reglastcloseparen = &rex->lastcloseparen;
-           /* also update PL_regoffs */
-           PL_regoffs = rex->offs;
-           
            /* XXXX This is too dramatic a measure... */
            PL_reg_maxiter = 0;
             if ( nochange_depth )
@@ -4512,13 +4548,10 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
        case EVAL_AB_fail: /* unsuccessfully ran A or B in (??{A})B */
            /* note: this is called twice; first after popping B, then A */
            PL_reg_flags ^= ST.toggle_reg_flags; 
-           ReREFCNT_dec(rex_sv);
-           SETREX(rex_sv,ST.prev_rex);
+           rex_sv = ST.prev_rex;
+           SET_reg_curpm(rex_sv);
            rex = (struct regexp *)SvANY(rex_sv);
            rexi = RXi_GET(rex); 
-           /* rex was changed so update the pointer in PL_reglastparen and PL_reglastcloseparen */
-           PL_reglastparen = &rex->lastparen;
-           PL_reglastcloseparen = &rex->lastcloseparen;
 
            PL_reginput = locinput;
            REGCP_UNWIND(ST.lastcp);
@@ -4534,20 +4567,41 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
 
        case OPEN:
            n = ARG(scan);  /* which paren pair */
-           PL_reg_start_tmp[n] = locinput;
+           rex->offs[n].start_tmp = locinput - PL_bostr;
            if (n > PL_regsize)
                PL_regsize = n;
+           DEBUG_BUFFERS_r(PerlIO_printf(Perl_debug_log,
+               "rex=0x%"UVxf" offs=0x%"UVxf": \\%"UVuf": set %"IVdf" tmp; regsize=%"UVuf"\n",
+               PTR2UV(rex),
+               PTR2UV(rex->offs),
+               (UV)n,
+               (IV)rex->offs[n].start_tmp,
+               (UV)PL_regsize
+           ));
             lastopen = n;
            break;
+
+/* XXX really need to log other places start/end are set too */
+#define CLOSE_CAPTURE \
+    rex->offs[n].start = rex->offs[n].start_tmp; \
+    rex->offs[n].end = locinput - PL_bostr; \
+    DEBUG_BUFFERS_r(PerlIO_printf(Perl_debug_log, \
+       "rex=0x%"UVxf" offs=0x%"UVxf": \\%"UVuf": set %"IVdf"..%"IVdf"\n", \
+       PTR2UV(rex), \
+       PTR2UV(rex->offs), \
+       (UV)n, \
+       (IV)rex->offs[n].start, \
+       (IV)rex->offs[n].end \
+    ))
+
        case CLOSE:
            n = ARG(scan);  /* which paren pair */
-           PL_regoffs[n].start = PL_reg_start_tmp[n] - PL_bostr;
-           PL_regoffs[n].end = locinput - PL_bostr;
+           CLOSE_CAPTURE;
            /*if (n > PL_regsize)
                PL_regsize = n;*/
-           if (n > *PL_reglastparen)
-               *PL_reglastparen = n;
-           *PL_reglastcloseparen = n;
+           if (n > rex->lastparen)
+               rex->lastparen = n;
+           rex->lastcloseparen = n;
             if (cur_eval && cur_eval->u.eval.close_paren == n) {
                goto fake_end;
            }    
@@ -4562,14 +4616,12 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
                     if ( OP(cursor)==CLOSE ){
                         n = ARG(cursor);
                         if ( n <= lastopen ) {
-                            PL_regoffs[n].start
-                               = PL_reg_start_tmp[n] - PL_bostr;
-                            PL_regoffs[n].end = locinput - PL_bostr;
+                           CLOSE_CAPTURE;
                             /*if (n > PL_regsize)
                             PL_regsize = n;*/
-                            if (n > *PL_reglastparen)
-                                *PL_reglastparen = n;
-                            *PL_reglastcloseparen = n;
+                            if (n > rex->lastparen)
+                                rex->lastparen = n;
+                            rex->lastcloseparen = n;
                             if ( n == ARG(scan) || (cur_eval &&
                                 cur_eval->u.eval.close_paren == n))
                                 break;
@@ -4581,7 +4633,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog)
            /*NOTREACHED*/          
        case GROUPP:
            n = ARG(scan);  /* which paren pair */
-           sw = cBOOL(*PL_reglastparen >= n && PL_regoffs[n].end != -1);
+           sw = cBOOL(rex->lastparen >= n && rex->offs[n].end != -1);
            break;
        case NGROUPP:
            /* reg_check_named_buff_matched returns 0 for no match */
@@ -4704,8 +4756,8 @@ NULL
 
            /* XXXX Probably it is better to teach regpush to support
               parenfloor > PL_regsize... */
-           if (parenfloor > (I32)*PL_reglastparen)
-               parenfloor = *PL_reglastparen; /* Pessimization... */
+           if (parenfloor > (I32)rex->lastparen)
+               parenfloor = rex->lastparen; /* Pessimization... */
 
            ST.prev_curlyx= cur_curlyx;
            cur_curlyx = st;
@@ -4765,7 +4817,7 @@ NULL
            /* First just match a string of min A's. */
 
            if (n < min) {
-               ST.cp = regcppush(cur_curlyx->u.curlyx.parenfloor);
+               ST.cp = regcppush(rex, cur_curlyx->u.curlyx.parenfloor);
                cur_curlyx->u.curlyx.lastloc = locinput;
                REGCP_SET(ST.lastcp);
 
@@ -4841,7 +4893,7 @@ NULL
            if (cur_curlyx->u.curlyx.minmod) {
                ST.save_curlyx = cur_curlyx;
                cur_curlyx = cur_curlyx->u.curlyx.prev_curlyx;
-               ST.cp = regcppush(ST.save_curlyx->u.curlyx.parenfloor);
+               ST.cp = regcppush(rex, ST.save_curlyx->u.curlyx.parenfloor);
                REGCP_SET(ST.lastcp);
                PUSH_YES_STATE_GOTO(WHILEM_B_min, ST.save_curlyx->u.curlyx.B);
                /* NOTREACHED */
@@ -4850,7 +4902,7 @@ NULL
            /* Prefer A over B for maximal matching. */
 
            if (n < max) { /* More greed allowed? */
-               ST.cp = regcppush(cur_curlyx->u.curlyx.parenfloor);
+               ST.cp = regcppush(rex, cur_curlyx->u.curlyx.parenfloor);
                cur_curlyx->u.curlyx.lastloc = locinput;
                REGCP_SET(ST.lastcp);
                PUSH_STATE_GOTO(WHILEM_A_max, A);
@@ -4936,7 +4988,7 @@ NULL
            /* Try grabbing another A and see if it helps. */
            PL_reginput = locinput;
            cur_curlyx->u.curlyx.lastloc = locinput;
-           ST.cp = regcppush(cur_curlyx->u.curlyx.parenfloor);
+           ST.cp = regcppush(rex, cur_curlyx->u.curlyx.parenfloor);
            REGCP_SET(ST.lastcp);
            PUSH_STATE_GOTO(WHILEM_A_min,
                /*A*/ NEXTOPER(ST.save_curlyx->u.curlyx.me) + EXTRA_STEP_2ARGS);
@@ -4954,7 +5006,8 @@ NULL
 
        case BRANCH:        /*  /(...|A|...)/ */
            scan = NEXTOPER(scan); /* scan now points to inner node */
-           ST.lastparen = *PL_reglastparen;
+           ST.lastparen = rex->lastparen;
+           ST.lastcloseparen = rex->lastcloseparen;
            ST.next_branch = next;
            REGCP_SET(ST.cp);
            PL_reginput = locinput;
@@ -4988,10 +5041,10 @@ NULL
                no_final = 0;
            }
            REGCP_UNWIND(ST.cp);
-           for (n = *PL_reglastparen; n > ST.lastparen; n--)
-               PL_regoffs[n].end = -1;
-           *PL_reglastparen = n;
-           /*dmq: *PL_reglastcloseparen = n; */
+           for (n = rex->lastparen; n > ST.lastparen; n--)
+               rex->offs[n].end = -1;
+           rex->lastparen = n;
+           rex->lastcloseparen = ST.lastcloseparen;
            scan = ST.next_branch;
            /* no more branches? */
            if (!scan || (OP(scan) != BRANCH && OP(scan) != BRANCHJ)) {
@@ -5025,13 +5078,14 @@ NULL
            ST.me = scan;
            scan = NEXTOPER(scan) + NODE_STEP_REGNODE;
 
+           ST.lastparen      = rex->lastparen;
+           ST.lastcloseparen = rex->lastcloseparen;
+
            /* if paren positive, emulate an OPEN/CLOSE around A */
            if (ST.me->flags) {
                U32 paren = ST.me->flags;
                if (paren > PL_regsize)
                    PL_regsize = paren;
-               if (paren > *PL_reglastparen)
-                   *PL_reglastparen = paren;
                scan += NEXT_OFF(scan); /* Skip former OPEN. */
            }
            ST.A = scan;
@@ -5157,16 +5211,18 @@ NULL
            }
 
            if (ST.me->flags) {
-               /* mark current A as captured */
+               /* emulate CLOSE: mark current A as captured */
                I32 paren = ST.me->flags;
                if (ST.count) {
-                   PL_regoffs[paren].start
+                   rex->offs[paren].start
                        = HOPc(PL_reginput, -ST.alen) - PL_bostr;
-                   PL_regoffs[paren].end = PL_reginput - PL_bostr;
-                   /*dmq: *PL_reglastcloseparen = paren; */
+                   rex->offs[paren].end = PL_reginput - PL_bostr;
+                   if ((U32)paren > rex->lastparen)
+                       rex->lastparen = paren;
+                   rex->lastcloseparen = paren;
                }
                else
-                   PL_regoffs[paren].end = -1;
+                   rex->offs[paren].end = -1;
                if (cur_eval && cur_eval->u.eval.close_paren &&
                    cur_eval->u.eval.close_paren == (U32)ST.me->flags) 
                {
@@ -5182,6 +5238,8 @@ NULL
 
        case CURLYM_B_fail: /* just failed to match a B */
            REGCP_UNWIND(ST.cp);
+           rex->lastparen      = ST.lastparen;
+           rex->lastcloseparen = ST.lastcloseparen;
            if (ST.minmod) {
                I32 max = ARG2(ST.me);
                if (max != REG_INFTY && ST.count == max)
@@ -5201,12 +5259,17 @@ NULL
 #define CURLY_SETPAREN(paren, success) \
     if (paren) { \
        if (success) { \
-           PL_regoffs[paren].start = HOPc(locinput, -1) - PL_bostr; \
-           PL_regoffs[paren].end = locinput - PL_bostr; \
-           *PL_reglastcloseparen = paren; \
+           rex->offs[paren].start = HOPc(locinput, -1) - PL_bostr; \
+           rex->offs[paren].end = locinput - PL_bostr; \
+           if (paren > rex->lastparen) \
+               rex->lastparen = paren; \
+           rex->lastcloseparen = paren; \
+       } \
+       else { \
+           rex->offs[paren].end = -1; \
+           rex->lastparen      = ST.lastparen; \
+           rex->lastcloseparen = ST.lastcloseparen; \
        } \
-       else \
-           PL_regoffs[paren].end = -1; \
     }
 
        case STAR:              /*  /A*B/ where A is width 1 */
@@ -5223,10 +5286,10 @@ NULL
            goto repeat;
        case CURLYN:            /*  /(A){m,n}B/ where A is width 1 */
            ST.paren = scan->flags;     /* Which paren to set */
+           ST.lastparen      = rex->lastparen;
+           ST.lastcloseparen = rex->lastcloseparen;
            if (ST.paren > PL_regsize)
                PL_regsize = ST.paren;
-           if (ST.paren > *PL_reglastparen)
-               *PL_reglastparen = ST.paren;
            ST.min = ARG1(scan);  /* min to match */
            ST.max = ARG2(scan);  /* max to match */
            if (cur_eval && cur_eval->u.eval.close_paren &&
@@ -5290,16 +5353,11 @@ NULL
                    }
                    else { /* UTF_PATTERN */
                        if (IS_TEXTFU(text_node) || IS_TEXTF(text_node)) {
-                            STRLEN ulen1, ulen2;
-                            U8 tmpbuf1[UTF8_MAXBYTES_CASE+1];
-                            U8 tmpbuf2[UTF8_MAXBYTES_CASE+1];
-
-                            /* XXX probably should be using foldcase */
-                            to_utf8_lower((U8*)s, tmpbuf1, &ulen1);
-                            to_utf8_upper((U8*)s, tmpbuf2, &ulen2);
-                            ST.c1 = utf8n_to_uvchr(tmpbuf1, UTF8_MAXLEN, 0,
-                                                   uniflags);
-                            ST.c2 = utf8n_to_uvchr(tmpbuf2, UTF8_MAXLEN, 0,
+                            STRLEN ulen;
+                            U8 tmpbuf[UTF8_MAXBYTES_CASE+1];
+
+                            to_utf8_fold((U8*)s, tmpbuf, &ulen);
+                            ST.c1 = ST.c2 = utf8n_to_uvchr(tmpbuf, UTF8_MAXLEN, 0,
                                                    uniflags);
                        }
                        else {
@@ -5375,8 +5433,6 @@ 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)
-               PL_regoffs[ST.paren].end = -1;
 
            PL_reginput = locinput;     /* Could be reset... */
            REGCP_UNWIND(ST.cp);
@@ -5453,8 +5509,6 @@ NULL
 
        case CURLY_B_min_fail:
            /* failed to find B in a non-greedy match where c1,c2 invalid */
-           if (ST.paren && ST.count)
-               PL_regoffs[ST.paren].end = -1;
 
            REGCP_UNWIND(ST.cp);
            /* failed -- move forward one */
@@ -5500,8 +5554,6 @@ NULL
            /* FALL THROUGH */
        case CURLY_B_max_fail:
            /* failed to find B in a greedy match */
-           if (ST.paren && ST.count)
-               PL_regoffs[ST.paren].end = -1;
 
            REGCP_UNWIND(ST.cp);
            /*  back up. */
@@ -5522,16 +5574,12 @@ NULL
                PL_reg_flags ^= st->u.eval.toggle_reg_flags; 
 
                st->u.eval.prev_rex = rex_sv;           /* inner */
-               SETREX(rex_sv,cur_eval->u.eval.prev_rex);
+               st->u.eval.cp = regcppush(rex, 0); /* Save *all* the positions. */
+               rex_sv = cur_eval->u.eval.prev_rex;
+               SET_reg_curpm(rex_sv);
                rex = (struct regexp *)SvANY(rex_sv);
                rexi = RXi_GET(rex);
                cur_curlyx = cur_eval->u.eval.prev_curlyx;
-               (void)ReREFCNT_inc(rex_sv);
-               st->u.eval.cp = regcppush(0);   /* Save *all* the positions. */
-
-               /* rex was changed so update the pointer in PL_reglastparen and PL_reglastcloseparen */
-               PL_reglastparen = &rex->lastparen;
-               PL_reglastcloseparen = &rex->lastcloseparen;
 
                REGCP_SET(st->u.eval.lastcp);
                PL_reginput = locinput;
@@ -5889,7 +5937,7 @@ yes:
     DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log, "%sMatch successful!%s\n",
                          PL_colors[4], PL_colors[5]));
 
-    if (PL_reg_eval_set) {
+    if (PL_reg_state.re_state_eval_setup_done) {
        /* each successfully executed (?{...}) block does the equivalent of
         *   local $^R = do {...}
         * When popping the save stack, all these locals would be undone;
@@ -5955,6 +6003,12 @@ no_silent:
         sv_setsv(sv_mrk, sv_yes_mark);
     }
 
+
+    if (last_pushed_cv) {
+       dSP;
+       POP_MULTICALL;
+    }
+
     /* clean up; in particular, free all slabs above current one */
     LEAVE_SCOPE(oldsave);
 
@@ -7035,7 +7089,7 @@ restore_pos(pTHX_ void *arg)
 {
     dVAR;
     regexp * const rex = (regexp *)arg;
-    if (PL_reg_eval_set) {
+    if (PL_reg_state.re_state_eval_setup_done) {
        if (PL_reg_oldsaved) {
            rex->subbeg = PL_reg_oldsaved;
            rex->sublen = PL_reg_oldsavedlen;
@@ -7045,7 +7099,7 @@ restore_pos(pTHX_ void *arg)
            RXp_MATCH_COPIED_on(rex);
        }
        PL_reg_magic->mg_len = PL_reg_oldpos;
-       PL_reg_eval_set = 0;
+       PL_reg_state.re_state_eval_setup_done = FALSE;
        PL_curpm = PL_reg_oldcurpm;
     }  
 }
@@ -7118,8 +7172,8 @@ S_to_byte_substr(pTHX_ register regexp *prog)
  * Local variables:
  * c-indentation-style: bsd
  * c-basic-offset: 4
- * indent-tabs-mode: t
+ * indent-tabs-mode: nil
  * End:
  *
- * ex: set ts=8 sts=4 sw=4 noet:
+ * ex: set ts=8 sts=4 sw=4 et:
  */