merge changes from maintbranch (1354, and relevant part of 1356); all
[p5sagit/p5-mst-13.2.git] / pp_hot.c
index 702e447..dc8935b 100644 (file)
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -250,8 +250,13 @@ PP(pp_aelemfast)
 {
     djSP;
     AV *av = GvAV((GV*)cSVOP->op_sv);
-    SV** svp = av_fetch(av, op->op_private, op->op_flags & OPf_MOD);
-    PUSHs(svp ? *svp : &sv_undef);
+    U32 lval = op->op_flags & OPf_MOD;
+    SV** svp = av_fetch(av, op->op_private, lval);
+    SV *sv = (svp ? *svp : &sv_undef);
+    EXTEND(SP, 1);
+    if (!lval && SvGMAGICAL(sv))       /* see note in pp_helem() */
+       sv = sv_mortalcopy(sv);
+    PUSHs(sv);
     RETURN;
 }
 
@@ -539,7 +544,8 @@ PP(pp_rv2hv)
     }
     else {
        dTARGET;
-       /* This bit is OK even when hv is really an AV */
+       if (SvTYPE(hv) == SVt_PVAV)
+           hv = avhv_keys((AV*)hv);
        if (HvFILL(hv))
            sv_setpvf(TARG, "%ld/%ld",
                      (long)HvFILL(hv), (long)HvMAX(hv) + 1);
@@ -625,7 +631,6 @@ PP(pp_aassign)
                hv_clear(hash);
 
                while (relem < lastrelem) {     /* gobble up all the rest */
-                   STRLEN len;
                    HE *didstore;
                    if (*relem)
                        sv = *(relem++);
@@ -644,14 +649,36 @@ PP(pp_aassign)
                    }
                    TAINT_NOT;
                }
-               if (relem == lastrelem && dowarn)
-                   warn("Odd number of elements in hash list");
+               if (relem == lastrelem) {
+                   if (*relem) {
+                       HE *didstore;
+                       if (dowarn) {
+                           if (relem == firstrelem &&
+                               SvROK(*relem) &&
+                               ( SvTYPE(SvRV(*relem)) == SVt_PVAV ||
+                                 SvTYPE(SvRV(*relem)) == SVt_PVHV ) )
+                               warn("Reference found where even-sized list expected");
+                           else
+                               warn("Odd number of elements in hash assignment");
+                       }
+                       tmpstr = NEWSV(29,0);
+                       didstore = hv_store_ent(hash,*relem,tmpstr,0);
+                       if (magic) {
+                           if (SvSMAGICAL(tmpstr))
+                               mg_set(tmpstr);
+                           if (!didstore)
+                               SvREFCNT_dec(tmpstr);
+                       }
+                       TAINT_NOT;
+                   }
+                   relem++;
+               }
            }
            break;
        default:
            if (SvTHINKFIRST(sv)) {
                if (SvREADONLY(sv) && curcop != &compiling) {
-                   if (sv != &sv_undef && sv != &sv_yes && sv != &sv_no)
+                   if (!SvIMMORTAL(sv))
                        DIE(no_modify);
                    if (relem <= lastrelem)
                        relem++;
@@ -763,7 +790,8 @@ PP(pp_match)
     I32 global;
     I32 safebase;
     char *truebase;
-    register REGEXP *prx = pm->op_pmregexp;
+    register REGEXP *rx = pm->op_pmregexp;
+    bool rxtainted;
     I32 gimme = GIMME;
     STRLEN len;
     I32 minmatch = 0;
@@ -782,40 +810,42 @@ PP(pp_match)
     strend = s + len;
     if (!s)
        DIE("panic: do_match");
+    rxtainted = ((pm->op_pmdynflags & PMdf_TAINTED) ||
+                (tainted && (pm->op_pmflags & PMf_RETAINT)));
     TAINT_NOT;
 
-    if (pm->op_pmflags & PMf_USED) {
+    if (pm->op_pmdynflags & PMdf_USED) {
       failure:
        if (gimme == G_ARRAY)
            RETURN;
        RETPUSHNO;
     }
 
-    if (!prx->prelen && curpm) {
+    if (!rx->prelen && curpm) {
        pm = curpm;
-       prx = pm->op_pmregexp;
+       rx = pm->op_pmregexp;
     }
-    if (prx->minlen > len) goto failure;
+    if (rx->minlen > len) goto failure;
 
-    screamer = ( (SvSCREAM(TARG) && prx->check_substr
-                 && SvTYPE(prx->check_substr) == SVt_PVBM
-                 && SvVALID(prx->check_substr)) 
+    screamer = ( (SvSCREAM(TARG) && rx->check_substr
+                 && SvTYPE(rx->check_substr) == SVt_PVBM
+                 && SvVALID(rx->check_substr)) 
                ? TARG : Nullsv);
     truebase = t = s;
     if (global = pm->op_pmflags & PMf_GLOBAL) {
-       prx->startp[0] = 0;
+       rx->startp[0] = 0;
        if (SvTYPE(TARG) >= SVt_PVMG && SvMAGIC(TARG)) {
            MAGIC* mg = mg_find(TARG, 'g');
            if (mg && mg->mg_len >= 0) {
-               prx->endp[0] = prx->startp[0] = s + mg->mg_len; 
+               rx->endp[0] = rx->startp[0] = s + mg->mg_len; 
                minmatch = (mg->mg_flags & MGf_MINMATCH);
                update_minmatch = 0;
            }
        }
     }
-    if (!prx->nparens && !global)
+    if (!rx->nparens && !global)
        gimme = G_SCALAR;                       /* accidental array context? */
-    safebase = (((gimme == G_ARRAY) || global || !prx->nparens)
+    safebase = (((gimme == G_ARRAY) || global || !rx->nparens)
                && !sawampersand);
     safebase = safebase ? 0  : REXEC_COPY_STR ;
     if (pm->op_pmflags & (PMf_MULTILINE|PMf_SINGLELINE)) {
@@ -824,36 +854,36 @@ PP(pp_match)
     }
 
 play_it_again:
-    if (global && prx->startp[0]) {
-       t = s = prx->endp[0];
-       if ((s + prx->minlen) > strend)
+    if (global && rx->startp[0]) {
+       t = s = rx->endp[0];
+       if ((s + rx->minlen) > strend)
            goto nope;
        if (update_minmatch++)
-           minmatch = (s == prx->startp[0]);
+           minmatch = (s == rx->startp[0]);
     }
-    if (prx->check_substr) {
-       if (!(prx->reganch & ROPT_NOSCAN)) { /* Floating checkstring. */
+    if (rx->check_substr) {
+       if (!(rx->reganch & ROPT_NOSCAN)) { /* Floating checkstring. */
            if ( screamer ) {
                I32 p = -1;
                
-               if (screamfirst[BmRARE(prx->check_substr)] < 0)
+               if (screamfirst[BmRARE(rx->check_substr)] < 0)
                    goto nope;
-               else if (!(s = screaminstr(TARG, prx->check_substr, 
-                                          prx->check_offset_min, 0, &p, 0)))
+               else if (!(s = screaminstr(TARG, rx->check_substr, 
+                                          rx->check_offset_min, 0, &p, 0)))
                    goto nope;
-               else if ((prx->reganch & ROPT_CHECK_ALL)
-                        && !sawampersand && !SvTAIL(prx->check_substr))
+               else if ((rx->reganch & ROPT_CHECK_ALL)
+                        && !sawampersand && !SvTAIL(rx->check_substr))
                    goto yup;
            }
-           else if (!(s = fbm_instr((unsigned char*)s + prx->check_offset_min,
+           else if (!(s = fbm_instr((unsigned char*)s + rx->check_offset_min,
                                     (unsigned char*)strend, 
-                                    prx->check_substr)))
+                                    rx->check_substr, 0)))
                goto nope;
-           else if ((prx->reganch & ROPT_CHECK_ALL) && !sawampersand)
+           else if ((rx->reganch & ROPT_CHECK_ALL) && !sawampersand)
                goto yup;
-           if (s && prx->check_offset_max < t - s) {
-               ++BmUSEFUL(prx->check_substr);
-               s -= prx->check_offset_max;
+           if (s && rx->check_offset_max < s - t) {
+               ++BmUSEFUL(rx->check_substr);
+               s -= rx->check_offset_max;
            }
            else
                s = t;
@@ -862,25 +892,25 @@ play_it_again:
           beginning of match, and the match is anchored at s. */
        else if (!multiline) {  /* Anchored near beginning of string. */
            I32 slen;
-           if (*SvPVX(prx->check_substr) != s[prx->check_offset_min]
-               || ((slen = SvCUR(prx->check_substr)) > 1
-                   && memNE(SvPVX(prx->check_substr), 
-                            s + prx->check_offset_min, slen)))
+           if (*SvPVX(rx->check_substr) != s[rx->check_offset_min]
+               || ((slen = SvCUR(rx->check_substr)) > 1
+                   && memNE(SvPVX(rx->check_substr), 
+                            s + rx->check_offset_min, slen)))
                goto nope;
        }
-       if (!prx->naughty && --BmUSEFUL(prx->check_substr) < 0
-           && prx->check_substr == prx->float_substr) {
-           SvREFCNT_dec(prx->check_substr);
-           prx->check_substr = Nullsv; /* opt is being useless */
-           prx->float_substr = Nullsv;
+       if (!rx->naughty && --BmUSEFUL(rx->check_substr) < 0
+           && rx->check_substr == rx->float_substr) {
+           SvREFCNT_dec(rx->check_substr);
+           rx->check_substr = Nullsv;  /* opt is being useless */
+           rx->float_substr = Nullsv;
        }
     }
-    if (regexec_flags(prx, s, strend, truebase, minmatch,
+    if (CALLREGEXEC(rx, s, strend, truebase, minmatch,
                      screamer, NULL, safebase))
     {
        curpm = pm;
        if (pm->op_pmflags & PMf_ONCE)
-           pm->op_pmflags |= PMf_USED;
+           pm->op_pmdynflags |= PMdf_USED;
        goto gotcha;
     }
     else
@@ -888,11 +918,13 @@ play_it_again:
     /*NOTREACHED*/
 
   gotcha:
-    TAINT_IF(RX_MATCH_TAINTED(prx));
+    if (rxtainted)
+       RX_MATCH_TAINTED_on(rx);
+    TAINT_IF(RX_MATCH_TAINTED(rx));
     if (gimme == G_ARRAY) {
        I32 iters, i, len;
 
-       iters = prx->nparens;
+       iters = rx->nparens;
        if (global && !iters)
            i = 1;
        else
@@ -903,16 +935,16 @@ play_it_again:
        for (i = !i; i <= iters; i++) {
            PUSHs(sv_newmortal());
            /*SUPPRESS 560*/
-           if ((s = prx->startp[i]) && prx->endp[i] ) {
-               len = prx->endp[i] - s;
+           if ((s = rx->startp[i]) && rx->endp[i] ) {
+               len = rx->endp[i] - s;
                sv_setpvn(*SP, s, len);
            }
        }
        if (global) {
-           truebase = prx->subbeg;
-           strend = prx->subend;
-           if (prx->startp[0] && prx->startp[0] == prx->endp[0])
-               ++prx->endp[0];
+           truebase = rx->subbeg;
+           strend = rx->subend;
+           if (rx->startp[0] && rx->startp[0] == rx->endp[0])
+               ++rx->endp[0];
            PUTBACK;                    /* EVAL blocks may use stack */
            goto play_it_again;
        }
@@ -928,9 +960,9 @@ play_it_again:
                sv_magic(TARG, (SV*)0, 'g', Nullch, 0);
                mg = mg_find(TARG, 'g');
            }
-           if (prx->startp[0]) {
-               mg->mg_len = prx->endp[0] - prx->subbeg;
-               if (prx->startp[0] == prx->endp[0])
+           if (rx->startp[0]) {
+               mg->mg_len = rx->endp[0] - rx->subbeg;
+               if (rx->startp[0] == rx->endp[0])
                    mg->mg_flags |= MGf_MINMATCH;
                else
                    mg->mg_flags &= ~MGf_MINMATCH;
@@ -941,35 +973,37 @@ play_it_again:
     }
 
 yup:                                   /* Confirmed by check_substr */
-    TAINT_IF(RX_MATCH_TAINTED(prx));
-    ++BmUSEFUL(prx->check_substr);
+    if (rxtainted)
+       RX_MATCH_TAINTED_on(rx);
+    TAINT_IF(RX_MATCH_TAINTED(rx));
+    ++BmUSEFUL(rx->check_substr);
     curpm = pm;
     if (pm->op_pmflags & PMf_ONCE)
-       pm->op_pmflags |= PMf_USED;
-    Safefree(prx->subbase);
-    prx->subbase = Nullch;
+       pm->op_pmdynflags |= PMdf_USED;
+    Safefree(rx->subbase);
+    rx->subbase = Nullch;
     if (global) {
-       prx->subbeg = truebase;
-       prx->subend = strend;
-       prx->startp[0] = s;
-       prx->endp[0] = s + SvCUR(prx->check_substr);
+       rx->subbeg = truebase;
+       rx->subend = strend;
+       rx->startp[0] = s;
+       rx->endp[0] = s + SvCUR(rx->check_substr);
        goto gotcha;
     }
     if (sawampersand) {
        char *tmps;
 
-       tmps = prx->subbase = savepvn(t, strend-t);
-       prx->subbeg = tmps;
-       prx->subend = tmps + (strend-t);
-       tmps = prx->startp[0] = tmps + (s - t);
-       prx->endp[0] = tmps + SvCUR(prx->check_substr);
+       tmps = rx->subbase = savepvn(t, strend-t);
+       rx->subbeg = tmps;
+       rx->subend = tmps + (strend-t);
+       tmps = rx->startp[0] = tmps + (s - t);
+       rx->endp[0] = tmps + SvCUR(rx->check_substr);
     }
     LEAVE_SCOPE(oldsave);
     RETPUSHYES;
 
 nope:
-    if (prx->check_substr)
-       ++BmUSEFUL(prx->check_substr);
+    if (rx->check_substr)
+       ++BmUSEFUL(rx->check_substr);
 
 ret_no:
     if (global && !(pm->op_pmflags & PMf_CONTINUE)) {
@@ -1019,8 +1053,11 @@ do_readline(void)
                    IoFLAGS(io) &= ~IOf_START;
                    IoLINES(io) = 0;
                    if (av_len(GvAVn(last_in_gv)) < 0) {
-                       SV *tmpstr = newSVpv("-", 1); /* assume stdin */
-                       av_push(GvAVn(last_in_gv), tmpstr);
+                       do_open(last_in_gv,"-",1,FALSE,0,0,Nullfp);
+                       sv_setpvn(GvSV(last_in_gv), "-", 1);
+                       SvSETMAGIC(GvSV(last_in_gv));
+                       fp = IoIFP(io);
+                       goto have_fp;
                    }
                }
                fp = nextargv(last_in_gv);
@@ -1077,7 +1114,10 @@ do_readline(void)
                       }
                    }
                    if ((tmpfp = PerlIO_open(tmpfnam,"w+","fop=dlt")) != NULL) {
-                       ok = ((wilddsc.dsc$a_pointer = tovmsspec(SvPVX(tmpglob),vmsspec)) != NULL);
+                       Stat_t st;
+                       if (!PerlLIO_stat(SvPVX(tmpglob),&st) && S_ISDIR(st.st_mode))
+                         ok = ((wilddsc.dsc$a_pointer = tovmspath(SvPVX(tmpglob),vmsspec)) != NULL);
+                       else ok = ((wilddsc.dsc$a_pointer = tovmsspec(SvPVX(tmpglob),vmsspec)) != NULL);
                        if (ok) wilddsc.dsc$w_length = (unsigned short int) strlen(wilddsc.dsc$a_pointer);
                        while (ok && ((sts = lib$find_file(&wilddsc,&rsdsc,&cxt,
                                                    &dfltdsc,NULL,NULL,NULL))&1)) {
@@ -1165,6 +1205,7 @@ do_readline(void)
        }
        RETURN;
     }
+  have_fp:
     if (gimme == G_SCALAR) {
        sv = TARG;
        if (SvROK(sv))
@@ -1279,6 +1320,7 @@ PP(pp_helem)
     HV *hv = (HV*)POPs;
     U32 lval = op->op_flags & OPf_MOD;
     U32 defer = op->op_private & OPpLVAL_DEFER;
+    SV *sv;
 
     if (SvTYPE(hv) == SVt_PVHV) {
        he = hv_fetch_ent(hv, keysv, lval && !defer, 0);
@@ -1315,7 +1357,16 @@ PP(pp_helem)
        else if (op->op_private & OPpDEREF)
            vivify_ref(*svp, op->op_private & OPpDEREF);
     }
-    PUSHs(svp ? *svp : &sv_undef);
+    sv = (svp ? *svp : &sv_undef);
+    /* This makes C<local $tied{foo} = $tied{foo}> possible.
+     * Pushing the magical RHS on to the stack is useless, since
+     * that magic is soon destined to be misled by the local(),
+     * and thus the later pp_sassign() will fail to mg_get() the
+     * old value.  This should also cure problems with delayed
+     * mg_get()s.  GSAR 98-07-03 */
+    if (!lval && SvGMAGICAL(sv))
+       sv = sv_mortalcopy(sv);
+    PUSHs(sv);
     RETURN;
 }
 
@@ -1388,6 +1439,38 @@ PP(pp_iter)
        DIE("panic: pp_iter");
 
     av = cx->blk_loop.iterary;
+    if (SvTYPE(av) != SVt_PVAV) {
+       /* iterate ($min .. $max) */
+       if (cx->blk_loop.iterlval) {
+           /* string increment */
+           register SV* cur = cx->blk_loop.iterlval;
+           STRLEN maxlen;
+           char *max = SvPV((SV*)av, maxlen);
+           if (!SvNIOK(cur) && SvCUR(cur) <= maxlen) {
+               sv_setsv(*cx->blk_loop.itervar, cur);
+               if (strEQ(SvPVX(cur), max))
+                   sv_setiv(cur, 0); /* terminate next time */
+               else
+                   sv_inc(cur);
+               RETPUSHYES;
+           }
+           RETPUSHNO;
+       }
+       /* integer increment */
+       if (cx->blk_loop.iterix > cx->blk_loop.itermax)
+           RETPUSHNO;
+
+       /* we know that the loop index SV is IV capable, so we can save
+        * some time by doing the essential work of sv_setiv() ourself.
+        */
+       sv = *cx->blk_loop.itervar;
+       (void)SvIOK_only(sv);
+       SvIVX(sv) = cx->blk_loop.iterix++;
+
+       RETPUSHYES;
+    }
+
+    /* iterate array */
     if (cx->blk_loop.iterix >= (av == curstack ? cx->blk_oldsp : AvFILL(av)))
        RETPUSHNO;
 
@@ -1442,7 +1525,7 @@ PP(pp_subst)
     bool rxtainted;
     char *orig;
     I32 safebase;
-    register REGEXP *prx = pm->op_pmregexp;
+    register REGEXP *rx = pm->op_pmregexp;
     STRLEN len;
     int force_on_match = 0;
     I32 oldsave = savestack_ix;
@@ -1466,6 +1549,10 @@ PP(pp_subst)
     s = SvPV(TARG, len);
     if (!SvPOKp(TARG) || SvTYPE(TARG) == SVt_PVGV)
        force_on_match = 1;
+    rxtainted = ((pm->op_pmdynflags & PMdf_TAINTED) ||
+                (tainted && (pm->op_pmflags & PMf_RETAINT)));
+    if (tainted)
+       rxtainted |= 2;
     TAINT_NOT;
 
   force_it:
@@ -1475,37 +1562,37 @@ PP(pp_subst)
     strend = s + len;
     maxiters = (strend - s) + 10;
 
-    if (!prx->prelen && curpm) {
+    if (!rx->prelen && curpm) {
        pm = curpm;
-       prx = pm->op_pmregexp;
+       rx = pm->op_pmregexp;
     }
-    screamer = ( (SvSCREAM(TARG) && prx->check_substr
-                 && SvTYPE(prx->check_substr) == SVt_PVBM
-                 && SvVALID(prx->check_substr)) 
+    screamer = ( (SvSCREAM(TARG) && rx->check_substr
+                 && SvTYPE(rx->check_substr) == SVt_PVBM
+                 && SvVALID(rx->check_substr)) 
                ? TARG : Nullsv);
-    safebase = (!prx->nparens && !sawampersand) ? 0 : REXEC_COPY_STR;
+    safebase = (!rx->nparens && !sawampersand) ? 0 : REXEC_COPY_STR;
     if (pm->op_pmflags & (PMf_MULTILINE|PMf_SINGLELINE)) {
        SAVEINT(multiline);
        multiline = pm->op_pmflags & PMf_MULTILINE;
     }
     orig = m = s;
-    if (prx->check_substr) {
-       if (!(prx->reganch & ROPT_NOSCAN)) { /* It floats. */
+    if (rx->check_substr) {
+       if (!(rx->reganch & ROPT_NOSCAN)) { /* It floats. */
            if (screamer) {
                I32 p = -1;
                
-               if (screamfirst[BmRARE(prx->check_substr)] < 0)
+               if (screamfirst[BmRARE(rx->check_substr)] < 0)
                    goto nope;
-               else if (!(s = screaminstr(TARG, prx->check_substr, prx->check_offset_min, 0, &p, 0)))
+               else if (!(s = screaminstr(TARG, rx->check_substr, rx->check_offset_min, 0, &p, 0)))
                    goto nope;
            }
-           else if (!(s = fbm_instr((unsigned char*)s + prx->check_offset_min, 
+           else if (!(s = fbm_instr((unsigned char*)s + rx->check_offset_min, 
                                     (unsigned char*)strend,
-                                    prx->check_substr)))
+                                    rx->check_substr, 0)))
                goto nope;
-           if (s && prx->check_offset_max < s - m) {
-               ++BmUSEFUL(prx->check_substr);
-               s -= prx->check_offset_max;
+           if (s && rx->check_offset_max < s - m) {
+               ++BmUSEFUL(rx->check_substr);
+               s -= rx->check_offset_max;
            }
            else
                s = m;
@@ -1514,17 +1601,17 @@ PP(pp_subst)
           beginning of match, and the match is anchored at s. */
        else if (!multiline) { /* Anchored at beginning of string. */
            I32 slen;
-           if (*SvPVX(prx->check_substr) != s[prx->check_offset_min]
-               || ((slen = SvCUR(prx->check_substr)) > 1
-                   && memNE(SvPVX(prx->check_substr), 
-                            s + prx->check_offset_min, slen)))
+           if (*SvPVX(rx->check_substr) != s[rx->check_offset_min]
+               || ((slen = SvCUR(rx->check_substr)) > 1
+                   && memNE(SvPVX(rx->check_substr), 
+                            s + rx->check_offset_min, slen)))
                goto nope;
        }
-       if (!prx->naughty && --BmUSEFUL(prx->check_substr) < 0
-           && prx->check_substr == prx->float_substr) {
-           SvREFCNT_dec(prx->check_substr);
-           prx->check_substr = Nullsv; /* opt is being useless */
-           prx->float_substr = Nullsv;
+       if (!rx->naughty && --BmUSEFUL(rx->check_substr) < 0
+           && rx->check_substr == rx->float_substr) {
+           SvREFCNT_dec(rx->check_substr);
+           rx->check_substr = Nullsv;  /* opt is being useless */
+           rx->float_substr = Nullsv;
        }
     }
 
@@ -1535,9 +1622,9 @@ PP(pp_subst)
     c = dstr ? SvPV(dstr, clen) : Nullch;
 
     /* can do inplace substitution? */
-    if (c && clen <= prx->minlen && (once || !(safebase & REXEC_COPY_STR))
-       && !(prx->reganch & ROPT_LOOKBEHIND_SEEN)) {
-       if (!regexec_flags(prx, s, strend, orig, 0, screamer, NULL, safebase)) {
+    if (c && clen <= rx->minlen && (once || !(safebase & REXEC_COPY_STR))
+       && !(rx->reganch & ROPT_LOOKBEHIND_SEEN)) {
+       if (!CALLREGEXEC(rx, s, strend, orig, 0, screamer, NULL, safebase)) {
            SPAGAIN;
            PUSHs(&sv_no);
            LEAVE_SCOPE(oldsave);
@@ -1552,13 +1639,13 @@ PP(pp_subst)
        curpm = pm;
        SvSCREAM_off(TARG);     /* disable possible screamer */
        if (once) {
-           rxtainted = RX_MATCH_TAINTED(prx);
-           if (prx->subbase) {
-               m = orig + (prx->startp[0] - prx->subbase);
-               d = orig + (prx->endp[0] - prx->subbase);
+           rxtainted |= RX_MATCH_TAINTED(rx);
+           if (rx->subbase) {
+               m = orig + (rx->startp[0] - rx->subbase);
+               d = orig + (rx->endp[0] - rx->subbase);
            } else {
-               m = prx->startp[0];
-               d = prx->endp[0];
+               m = rx->startp[0];
+               d = rx->endp[0];
            }
            s = orig;
            if (m - s > strend - d) {  /* faster to shorten from end */
@@ -1593,17 +1680,16 @@ PP(pp_subst)
            else {
                sv_chop(TARG, d);
            }
-           TAINT_IF(rxtainted);
+           TAINT_IF(rxtainted & 1);
            SPAGAIN;
            PUSHs(&sv_yes);
        }
        else {
-           rxtainted = 0;
            do {
                if (iters++ > maxiters)
                    DIE("Substitution loop");
-               rxtainted |= RX_MATCH_TAINTED(prx);
-               m = prx->startp[0];
+               rxtainted |= RX_MATCH_TAINTED(rx);
+               m = rx->startp[0];
                /*SUPPRESS 560*/
                if (i = m - s) {
                    if (s != d)
@@ -1614,19 +1700,20 @@ PP(pp_subst)
                    Copy(c, d, clen, char);
                    d += clen;
                }
-               s = prx->endp[0];
-           } while (regexec_flags(prx, s, strend, orig, s == m,
+               s = rx->endp[0];
+           } while (CALLREGEXEC(rx, s, strend, orig, s == m,
                              Nullsv, NULL, 0)); /* don't match same null twice */
            if (s != d) {
                i = strend - s;
                SvCUR_set(TARG, d - SvPVX(TARG) + i);
                Move(s, d, i+1, char);          /* include the NUL */
            }
-           TAINT_IF(rxtainted);
+           TAINT_IF(rxtainted & 1);
            SPAGAIN;
            PUSHs(sv_2mortal(newSViv((I32)iters)));
        }
        (void)SvPOK_only(TARG);
+       TAINT_IF(rxtainted);
        if (SvSMAGICAL(TARG)) {
            PUTBACK;
            mg_set(TARG);
@@ -1637,13 +1724,13 @@ PP(pp_subst)
        RETURN;
     }
 
-    if (regexec_flags(prx, s, strend, orig, 0, screamer, NULL, safebase)) {
+    if (CALLREGEXEC(rx, s, strend, orig, 0, screamer, NULL, safebase)) {
        if (force_on_match) {
            force_on_match = 0;
            s = SvPV_force(TARG, len);
            goto force_it;
        }
-       rxtainted = RX_MATCH_TAINTED(prx);
+       rxtainted |= RX_MATCH_TAINTED(rx);
        dstr = NEWSV(25, len);
        sv_setpvn(dstr, m, s-m);
        curpm = pm;
@@ -1656,26 +1743,24 @@ PP(pp_subst)
        do {
            if (iters++ > maxiters)
                DIE("Substitution loop");
-           rxtainted |= RX_MATCH_TAINTED(prx);
-           if (prx->subbase && prx->subbase != orig) {
+           rxtainted |= RX_MATCH_TAINTED(rx);
+           if (rx->subbase && rx->subbase != orig) {
                m = s;
                s = orig;
-               orig = prx->subbase;
+               orig = rx->subbase;
                s = orig + (m - s);
                strend = s + (strend - m);
            }
-           m = prx->startp[0];
+           m = rx->startp[0];
            sv_catpvn(dstr, s, m-s);
-           s = prx->endp[0];
+           s = rx->endp[0];
            if (clen)
                sv_catpvn(dstr, c, clen);
            if (once)
                break;
-       } while (regexec_flags(prx, s, strend, orig, s == m, Nullsv, NULL, safebase));
+       } while (CALLREGEXEC(rx, s, strend, orig, s == m, Nullsv, NULL, safebase));
        sv_catpvn(dstr, s, strend - s);
 
-       TAINT_IF(rxtainted);
-
        (void)SvOOK_off(TARG);
        Safefree(SvPVX(TARG));
        SvPVX(TARG) = SvPVX(dstr);
@@ -1684,18 +1769,21 @@ PP(pp_subst)
        SvPVX(dstr) = 0;
        sv_free(dstr);
 
+       TAINT_IF(rxtainted & 1);
+       SPAGAIN;
+       PUSHs(sv_2mortal(newSViv((I32)iters)));
+
        (void)SvPOK_only(TARG);
+       TAINT_IF(rxtainted);
        SvSETMAGIC(TARG);
        SvTAINT(TARG);
-       SPAGAIN;
-       PUSHs(sv_2mortal(newSViv((I32)iters)));
        LEAVE_SCOPE(oldsave);
        RETURN;
     }
     goto ret_no;
 
 nope:
-    ++BmUSEFUL(prx->check_substr);
+    ++BmUSEFUL(rx->check_substr);
 
 ret_no:         
     SPAGAIN;
@@ -1761,9 +1849,19 @@ PP(pp_leavesub)
     TAINT_NOT;
     if (gimme == G_SCALAR) {
        MARK = newsp + 1;
-       if (MARK <= SP)
-           *MARK = SvTEMP(TOPs) ? TOPs : sv_mortalcopy(TOPs);
-       else {
+       if (MARK <= SP) {
+           if (cxsub.cv && CvDEPTH(cxsub.cv) > 1) {
+               if (SvTEMP(TOPs)) {
+                   *MARK = SvREFCNT_inc(TOPs);
+                   FREETMPS;
+                   sv_2mortal(*MARK);
+               } else {
+                   FREETMPS;
+                   *MARK = sv_mortalcopy(TOPs);
+               }
+           } else
+               *MARK = SvTEMP(TOPs) ? TOPs : sv_mortalcopy(TOPs);
+       } else {
            MEXTEND(MARK, 0);
            *MARK = &sv_undef;
        }
@@ -1790,27 +1888,35 @@ STATIC CV *
 get_db_sub(SV **svp, CV *cv)
 {
     dTHR;
-    SV *oldsv = *svp;
-    GV *gv;
+    SV *dbsv = GvSV(DBsub);
+
+    if (!PERLDB_SUB_NN) {
+       GV *gv = CvGV(cv);
 
-    *svp = GvSV(DBsub);
-    save_item(*svp);
-    gv = CvGV(cv);
-    if ( (CvFLAGS(cv) & (CVf_ANON | CVf_CLONED))
-        || strEQ(GvNAME(gv), "END") 
-        || ((GvCV(gv) != cv) && /* Could be imported, and old sub redefined. */
-            !( (SvTYPE(oldsv) == SVt_PVGV) && (GvCV((GV*)oldsv) == cv)
-               && (gv = (GV*)oldsv) ))) {
-       /* Use GV from the stack as a fallback. */
-       /* GV is potentially non-unique, or contain different CV. */
-       sv_setsv(*svp, newRV((SV*)cv));
+       save_item(dbsv);
+       if ( (CvFLAGS(cv) & (CVf_ANON | CVf_CLONED))
+            || strEQ(GvNAME(gv), "END") 
+            || ((GvCV(gv) != cv) && /* Could be imported, and old sub redefined. */
+                !( (SvTYPE(*svp) == SVt_PVGV) && (GvCV((GV*)*svp) == cv)
+                   && (gv = (GV*)*svp) ))) {
+           /* Use GV from the stack as a fallback. */
+           /* GV is potentially non-unique, or contain different CV. */
+           sv_setsv(dbsv, newRV((SV*)cv));
+       }
+       else {
+           gv_efullname3(dbsv, gv, Nullch);
+       }
     }
     else {
-       gv_efullname3(*svp, gv, Nullch);
+       SvUPGRADE(dbsv, SVt_PVIV);
+       SvIOK_on(dbsv);
+       SAVEIV(SvIVX(dbsv));
+       SvIVX(dbsv) = (IV)cv;           /* Do it the quickest way  */
     }
-    cv = GvCV(DBsub);
+
     if (CvXSUB(cv))
        curcopdb = curcop;
+    cv = GvCV(DBsub);
     return cv;
 }
 
@@ -1979,8 +2085,9 @@ PP(pp_entersub)
         * (3) instead of (2) so we'd have to clone. Would the fact
         * that we released the mutex more quickly make up for this?
         */
-       svp = hv_fetch(thr->cvcache, (char *)cv, sizeof(cv), FALSE);
-       if (svp) {
+       if (threadnum &&
+           (svp = hv_fetch(thr->cvcache, (char *)cv, sizeof(cv), FALSE)))
+       {
            /* We already have a clone to use */
            MUTEX_UNLOCK(CvMUTEXP(cv));
            cv = *(CV**)svp;
@@ -2083,7 +2190,7 @@ PP(pp_entersub)
                curcopdb = NULL;
            }
            /* Do we need to open block here? XXXX */
-           (void)(*CvXSUB(cv))(THIS_ cv);
+           (void)(*CvXSUB(cv))(cv _PERL_OBJECT_THIS);
 
            /* Enforce some sanity in scalar context. */
            if (gimme == G_SCALAR && ++markix != stack_sp - stack_base ) {
@@ -2239,6 +2346,7 @@ PP(pp_aelem)
     AV* av = (AV*)POPs;
     U32 lval = op->op_flags & OPf_MOD;
     U32 defer = (op->op_private & OPpLVAL_DEFER) && (elem > AvFILL(av));
+    SV *sv;
 
     if (elem > 0)
        elem -= curcop->cop_arybase;
@@ -2265,7 +2373,10 @@ PP(pp_aelem)
        else if (op->op_private & OPpDEREF)
            vivify_ref(*svp, op->op_private & OPpDEREF);
     }
-    PUSHs(svp ? *svp : &sv_undef);
+    sv = (svp ? *svp : &sv_undef);
+    if (!lval && SvGMAGICAL(sv))       /* see note in pp_helem() */
+       sv = sv_mortalcopy(sv);
+    PUSHs(sv);
     RETURN;
 }
 
@@ -2336,7 +2447,9 @@ PP(pp_method)
            !(ob=(SV*)GvIO(iogv)))
        {
            if (!packname || !isIDFIRST(*packname))
-  DIE("Can't call method \"%s\" without a package or object reference", name);
+               DIE("Can't call method \"%s\" %s", name,
+                   SvOK(sv)? "without a package or object reference"
+                           : "on an undefined value");
            stash = gv_stashpvn(packname, packlen, TRUE);
            goto fetch;
        }