This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
pp_match(): factor out some common code
[perl5.git] / pp_hot.c
index 14b2878..ca2dfc4 100644 (file)
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -322,7 +322,7 @@ PP(pp_concat)
  * I suspect that the mg_get is no longer needed, but while padav
  * differs, it can't share this function */
 
-void
+STATIC void
 S_pushav(pTHX_ AV* const av)
 {
     dSP;
@@ -783,7 +783,7 @@ PP(pp_print)
            Move(MARK, MARK + 1, (SP - MARK) + 1, SV*);
            ++SP;
        }
-       return Perl_tied_method(aTHX_ "PRINT", mark - 1, MUTABLE_SV(io),
+       return Perl_tied_method(aTHX_ SV_CONST(PRINT), mark - 1, MUTABLE_SV(io),
                                mg,
                                (G_SCALAR | TIED_METHOD_ARGUMENTS_ON_STACK
                                 | (PL_op->op_type == OP_SAY
@@ -950,19 +950,19 @@ PP(pp_rv2av)
 }
 
 STATIC void
-S_do_oddball(pTHX_ HV *hash, SV **relem, SV **firstrelem)
+S_do_oddball(pTHX_ SV **oddkey, SV **firstkey)
 {
     dVAR;
 
     PERL_ARGS_ASSERT_DO_ODDBALL;
 
-    if (*relem) {
+    if (*oddkey) {
         if (ckWARN(WARN_MISC)) {
            const char *err;
-           if (relem == firstrelem &&
-               SvROK(*relem) &&
-               (SvTYPE(SvRV(*relem)) == SVt_PVAV ||
-                SvTYPE(SvRV(*relem)) == SVt_PVHV))
+           if (oddkey == firstkey &&
+               SvROK(*oddkey) &&
+               (SvTYPE(SvRV(*oddkey)) == SVt_PVAV ||
+                SvTYPE(SvRV(*oddkey)) == SVt_PVHV))
            {
                err = "Reference found where even-sized list expected";
            }
@@ -992,11 +992,12 @@ PP(pp_aassign)
     HV *hash;
     I32 i;
     int magic;
-    int duplicates = 0;
-    SV **firsthashrelem = NULL;        /* "= 0" keeps gcc 2.95 quiet  */
+    U32 lval = 0;
 
     PL_delaymagic = DM_DELAY;          /* catch simultaneous items */
     gimme = GIMME_V;
+    if (gimme == G_ARRAY)
+        lval = PL_op->op_flags & OPf_MOD || LVRET;
 
     /* If there's a common identifier on both sides we have to take
      * special care that assigning the identifier on the left doesn't
@@ -1074,50 +1075,76 @@ PP(pp_aassign)
            break;
        case SVt_PVHV: {                                /* normal hash */
                SV *tmpstr;
+                int odd;
+                int duplicates = 0;
                SV** topelem = relem;
+                SV **firsthashrelem = relem;
 
                hash = MUTABLE_HV(sv);
                magic = SvMAGICAL(hash) != 0;
+
+                odd = ((lastrelem - firsthashrelem)&1)? 0 : 1;
+                if ( odd ) {
+                    do_oddball(lastrelem, firsthashrelem);
+                    /* we have firstlelem to reuse, it's not needed anymore
+                    */
+                    *(lastrelem+1) = &PL_sv_undef;
+                }
+
                ENTER;
                SAVEFREESV(SvREFCNT_inc_simple_NN(sv));
                hv_clear(hash);
-               firsthashrelem = relem;
-
-               while (relem < lastrelem) {     /* gobble up all the rest */
+               while (relem < lastrelem+odd) { /* gobble up all the rest */
                    HE *didstore;
-                   ODD:
-                   sv = *relem ? gimme == G_ARRAY ? sv_mortalcopy(*relem) : *relem : &PL_sv_no;
-                   relem++;
-                   tmpstr = sv_newmortal();
-                   if (*relem)
-                       sv_setsv(tmpstr,*relem);        /* value */
+                    assert(*relem);
+                   /* Copy the key if aassign is called in lvalue context,
+                      to avoid having the next op modify our rhs.  Copy
+                      it also if it is gmagical, lest it make the
+                      hv_store_ent call below croak, leaking the value. */
+                   sv = lval || SvGMAGICAL(*relem)
+                        ? sv_mortalcopy(*relem)
+                        : *relem;
                    relem++;
+                    assert(*relem);
+                   SvGETMAGIC(*relem);
+                    tmpstr = newSV(0);
+                   sv_setsv_nomg(tmpstr,*relem++);     /* value */
                    if (gimme == G_ARRAY) {
                        if (hv_exists_ent(hash, sv, 0))
                            /* key overwrites an existing entry */
                            duplicates += 2;
                        else {
                            /* copy element back: possibly to an earlier
-                            * stack location if we encountered dups earlier */
+                            * stack location if we encountered dups earlier,
+                            * possibly to a later stack location if odd */
                            *topelem++ = sv;
                            *topelem++ = tmpstr;
                        }
                    }
                    didstore = hv_store_ent(hash,sv,tmpstr,0);
-                   if (didstore) SvREFCNT_inc_simple_void_NN(tmpstr);
                    if (magic) {
-                       if (SvSMAGICAL(tmpstr))
-                           mg_set(tmpstr);
-                   }
+                       if (!didstore) sv_2mortal(tmpstr);
+                       SvSETMAGIC(tmpstr);
+                    }
                    TAINT_NOT;
                }
-               if (relem == lastrelem) {
-                   do_oddball(hash, relem, firsthashrelem);
-                    /* we have lelem to reuse, it's not needed anymore */
-                    *(relem+1) = NULL;
-                   goto ODD;
-               }
                LEAVE;
+                if (duplicates && gimme == G_ARRAY) {
+                    /* at this point we have removed the duplicate key/value
+                     * pairs from the stack, but the remaining values may be
+                     * wrong; i.e. with (a 1 a 2 b 3) on the stack we've removed
+                     * the (a 2), but the stack now probably contains
+                     * (a <freed> b 3), because { hv_save(a,1); hv_save(a,2) }
+                     * obliterates the earlier key. So refresh all values. */
+                    lastrelem -= duplicates;
+                    relem = firsthashrelem;
+                    while (relem < lastrelem+odd) {
+                        HE *he;
+                        he = hv_fetch_ent(hash, *relem++, 0, 0);
+                        *relem++ = (he ? HeVAL(he) : &PL_sv_undef);
+                    }
+                }
+                if (odd && gimme == G_ARRAY) lastrelem++;
            }
            break;
        default:
@@ -1146,10 +1173,10 @@ PP(pp_aassign)
     }
     if (PL_delaymagic & ~DM_DELAY) {
        /* Will be used to set PL_tainting below */
-       UV tmp_uid  = PerlProc_getuid();
-       UV tmp_euid = PerlProc_geteuid();
-       UV tmp_gid  = PerlProc_getgid();
-       UV tmp_egid = PerlProc_getegid();
+       Uid_t tmp_uid  = PerlProc_getuid();
+       Uid_t tmp_euid = PerlProc_geteuid();
+       Gid_t tmp_gid  = PerlProc_getgid();
+       Gid_t tmp_egid = PerlProc_getegid();
 
        if (PL_delaymagic & DM_UID) {
 #ifdef HAS_SETRESUID
@@ -1216,6 +1243,12 @@ PP(pp_aassign)
            tmp_egid = PerlProc_getegid();
        }
        TAINTING_set( TAINTING_get | (tmp_uid && (tmp_euid != tmp_uid || tmp_egid != tmp_gid)) );
+#ifdef NO_TAINT_SUPPORT
+        PERL_UNUSED_VAR(tmp_uid);
+        PERL_UNUSED_VAR(tmp_euid);
+        PERL_UNUSED_VAR(tmp_gid);
+        PERL_UNUSED_VAR(tmp_egid);
+#endif
     }
     PL_delaymagic = 0;
 
@@ -1227,32 +1260,16 @@ PP(pp_aassign)
        SETi(lastrelem - firstrelem + 1);
     }
     else {
-       if (ary)
+       if (ary || hash)
+           /* note that in this case *firstlelem may have been overwritten
+              by sv_undef in the odd hash case */
            SP = lastrelem;
-       else if (hash) {
-           if (duplicates) {
-               /* at this point we have removed the duplicate key/value
-                * pairs from the stack, but the remaining values may be
-                * wrong; i.e. with (a 1 a 2 b 3) on the stack we've removed
-                * the (a 2), but the stack now probably contains
-                * (a <freed> b 3), because { hv_save(a,1); hv_save(a,2) }
-                * obliterates the earlier key. So refresh all values. */
-               lastrelem -= duplicates;
-               relem = firsthashrelem;
-               while (relem <= lastrelem) {
-                   HE *he;
-                   sv = *relem++;
-                   he = hv_fetch_ent(hash, sv, 0, 0);
-                   *relem++ = (he ? HeVAL(he) : &PL_sv_undef);
-               }
-           }
-           SP = ((lastrelem - firsthashrelem)&1)? lastrelem : lastrelem+1;
-       }
-       else
+       else {
            SP = firstrelem + (lastlelem - firstlelem);
-       lelem = firstlelem + (relem - firstrelem);
-       while (relem <= SP)
-           *relem++ = (lelem <= lastlelem) ? *lelem++ : &PL_sv_undef;
+            lelem = firstlelem + (relem - firstrelem);
+            while (relem <= SP)
+                *relem++ = (lelem <= lastlelem) ? *lelem++ : &PL_sv_undef;
+        }
     }
 
     RETURN;
@@ -1341,8 +1358,6 @@ PP(pp_match)
                 (TAINT_get && (pm->op_pmflags & PMf_RETAINT)));
     TAINT_NOT;
 
-    RX_MATCH_UTF8_set(rx, DO_UTF8(TARG));
-
     /* We need to know this in case we fail out early - pos() must be reset */
     global = dynpm->op_pmflags & PMf_GLOBAL;
 
@@ -1375,10 +1390,9 @@ PP(pp_match)
 
     /* XXXX What part of this is needed with true \G-support? */
     if (global) {
+       MAGIC * const mg = mg_find_mglob(TARG);
        RX_OFFS(rx)[0].start = -1;
-       if (SvTYPE(TARG) >= SVt_PVMG && SvMAGIC(TARG)) {
-           MAGIC* const mg = mg_find(TARG, PERL_MAGIC_regex_global);
-           if (mg && mg->mg_len >= 0) {
+       if (mg && mg->mg_len >= 0) {
                if (!(RX_EXTFLAGS(rx) & RXf_GPOS_SEEN))
                    RX_OFFS(rx)[0].end = RX_OFFS(rx)[0].start = mg->mg_len;
                else if (RX_EXTFLAGS(rx) & RXf_ANCH_GPOS) {
@@ -1390,7 +1404,6 @@ PP(pp_match)
                    RX_OFFS(rx)[0].end = RX_OFFS(rx)[0].start = mg->mg_len;
                minmatch = (mg->mg_flags & MGf_MINMATCH) ? RX_GOFS(rx) + 1 : 0;
                update_minmatch = 0;
-           }
        }
     }
 #ifdef PERL_SAWAMPERSAND
@@ -1421,19 +1434,14 @@ PP(pp_match)
     }
     if (RX_EXTFLAGS(rx) & RXf_USE_INTUIT &&
        DO_UTF8(TARG) == (RX_UTF8(rx) != 0)) {
-       /* FIXME - can PL_bostr be made const char *?  */
-       PL_bostr = (char *)truebase;
-       s = CALLREG_INTUIT_START(rx, TARG, (char *)s, (char *)strend, r_flags, NULL);
+       s = CALLREG_INTUIT_START(rx, TARG, truebase,
+                        (char *)s, (char *)strend, r_flags, NULL);
 
        if (!s)
            goto nope;
-#ifdef PERL_SAWAMPERSAND
        if ( (RX_EXTFLAGS(rx) & RXf_CHECK_ALL)
-            && !PL_sawampersand
-            && !(RX_EXTFLAGS(rx) & RXf_PMf_KEEPCOPY)
             && !SvROK(TARG))   /* Cannot trust since INTUIT cannot guess ^ */
            goto yup;
-#endif
     }
     if (!CALLREGEXEC(rx, (char*)s, (char *)strend, (char*)truebase,
                     minmatch, TARG, NUM2PTR(void*, gpos), r_flags))
@@ -1452,6 +1460,23 @@ PP(pp_match)
     if (rxtainted)
        RX_MATCH_TAINTED_on(rx);
     TAINT_IF(RX_MATCH_TAINTED(rx));
+
+    /* update pos */
+
+    if (global && (gimme != G_ARRAY || (dynpm->op_pmflags & PMf_CONTINUE))) {
+        MAGIC *mg = mg_find_mglob(TARG);
+        if (!mg) {
+            mg = sv_magicext_mglob(TARG);
+        }
+        if (RX_OFFS(rx)[0].start != -1) {
+            mg->mg_len = RX_OFFS(rx)[0].end;
+            if (RX_OFFS(rx)[0].start + RX_GOFS(rx) == (UV)RX_OFFS(rx)[0].end)
+                mg->mg_flags |= MGf_MINMATCH;
+            else
+                mg->mg_flags &= ~MGf_MINMATCH;
+        }
+    }
+
     if (gimme == G_ARRAY) {
        const I32 nparens = RX_NPARENS(rx);
        I32 i = (global && !nparens) ? 1 : 0;
@@ -1476,26 +1501,6 @@ PP(pp_match)
            }
        }
        if (global) {
-           if (dynpm->op_pmflags & PMf_CONTINUE) {
-               MAGIC* mg = NULL;
-               if (SvTYPE(TARG) >= SVt_PVMG && SvMAGIC(TARG))
-                   mg = mg_find(TARG, PERL_MAGIC_regex_global);
-               if (!mg) {
-#ifdef PERL_OLD_COPY_ON_WRITE
-                   if (SvIsCOW(TARG))
-                       sv_force_normal_flags(TARG, 0);
-#endif
-                   mg = sv_magicext(TARG, NULL, PERL_MAGIC_regex_global,
-                                    &PL_vtbl_mglob, NULL, 0);
-               }
-               if (RX_OFFS(rx)[0].start != -1) {
-                   mg->mg_len = RX_OFFS(rx)[0].end;
-                   if (RX_OFFS(rx)[0].start + RX_GOFS(rx) == (UV)RX_OFFS(rx)[0].end)
-                       mg->mg_flags |= MGf_MINMATCH;
-                   else
-                       mg->mg_flags &= ~MGf_MINMATCH;
-               }
-           }
            had_zerolen = (RX_OFFS(rx)[0].start != -1
                           && (RX_OFFS(rx)[0].start + RX_GOFS(rx)
                               == (UV)RX_OFFS(rx)[0].end));
@@ -1509,35 +1514,12 @@ PP(pp_match)
        RETURN;
     }
     else {
-       if (global) {
-           MAGIC* mg;
-           if (SvTYPE(TARG) >= SVt_PVMG && SvMAGIC(TARG))
-               mg = mg_find(TARG, PERL_MAGIC_regex_global);
-           else
-               mg = NULL;
-           if (!mg) {
-#ifdef PERL_OLD_COPY_ON_WRITE
-               if (SvIsCOW(TARG))
-                   sv_force_normal_flags(TARG, 0);
-#endif
-               mg = sv_magicext(TARG, NULL, PERL_MAGIC_regex_global,
-                                &PL_vtbl_mglob, NULL, 0);
-           }
-           if (RX_OFFS(rx)[0].start != -1) {
-               mg->mg_len = RX_OFFS(rx)[0].end;
-               if (RX_OFFS(rx)[0].start + RX_GOFS(rx) == (UV)RX_OFFS(rx)[0].end)
-                   mg->mg_flags |= MGf_MINMATCH;
-               else
-                   mg->mg_flags &= ~MGf_MINMATCH;
-           }
-       }
        LEAVE_SCOPE(oldsave);
        RETPUSHYES;
     }
 
-#ifdef PERL_SAWAMPERSAND
 yup:                                   /* Confirmed by INTUIT */
-#endif
+    assert(!RX_NPARENS(rx));
     if (rxtainted)
        RX_MATCH_TAINTED_on(rx);
     TAINT_IF(RX_MATCH_TAINTED(rx));
@@ -1549,67 +1531,25 @@ yup:                                    /* Confirmed by INTUIT */
         dynpm->op_pmflags |= PMf_USED;
 #endif
     }
-    if (RX_MATCH_COPIED(rx))
-       Safefree(RX_SUBBEG(rx));
-    RX_MATCH_COPIED_off(rx);
-    RX_SUBBEG(rx) = NULL;
+
+    RX_MATCH_UTF8_set(rx, cBOOL(DO_UTF8(rx)));
+    if ( !(r_flags & REXEC_NOT_FIRST) )
+        Perl_reg_set_capture_string(aTHX_ rx,
+                                    (char*)truebase, (char *)strend,
+                                    TARG, r_flags, cBOOL(DO_UTF8(TARG)));
+
+    /* skipping regexec means that indices for $&, $-[0] etc weren't set */
+    RX_OFFS(rx)[0].start = s - truebase;
+    RX_OFFS(rx)[0].end =
+        RX_MATCH_UTF8(rx)
+            ? (char*)utf8_hop((U8*)s, RX_MINLENRET(rx)) - truebase
+            : s - truebase + RX_MINLENRET(rx);
+
     if (global) {
-       /* FIXME - should rx->subbeg be const char *?  */
-       RX_SUBBEG(rx) = (char *) truebase;
-       RX_SUBOFFSET(rx) = 0;
-       RX_SUBCOFFSET(rx) = 0;
-       RX_OFFS(rx)[0].start = s - truebase;
-       if (RX_MATCH_UTF8(rx)) {
-           char * const t = (char*)utf8_hop((U8*)s, RX_MINLENRET(rx));
-           RX_OFFS(rx)[0].end = t - truebase;
-       }
-       else {
-           RX_OFFS(rx)[0].end = s - truebase + RX_MINLENRET(rx);
-       }
-       RX_SUBLEN(rx) = strend - truebase;
        goto gotcha;
     }
-#ifdef PERL_SAWAMPERSAND
-    if (PL_sawampersand || RX_EXTFLAGS(rx) & RXf_PMf_KEEPCOPY)
-#endif
-    {
-       I32 off;
-#ifdef PERL_ANY_COW
-       if (SvCANCOW(TARG)) {
-           if (DEBUG_C_TEST) {
-               PerlIO_printf(Perl_debug_log,
-                             "Copy on write: pp_match $& capture, type %d, truebase=%p, t=%p, difference %d\n",
-                             (int) SvTYPE(TARG), (void*)truebase, (void*)t,
-                             (int)(t-truebase));
-           }
-           RX_SAVED_COPY(rx) = sv_setsv_cow(RX_SAVED_COPY(rx), TARG);
-           RX_SUBBEG(rx)
-               = (char *) SvPVX_const(RX_SAVED_COPY(rx)) + (t - truebase);
-           assert (SvPOKp(RX_SAVED_COPY(rx)));
-       } else
-#endif
-       {
 
-           RX_SUBBEG(rx) = savepvn(t, strend - t);
-#ifdef PERL_ANY_COW
-           RX_SAVED_COPY(rx) = NULL;
-#endif
-       }
-       RX_SUBLEN(rx) = strend - t;
-       RX_SUBOFFSET(rx) = 0;
-       RX_SUBCOFFSET(rx) = 0;
-       RX_MATCH_COPIED_on(rx);
-       off = RX_OFFS(rx)[0].start = s - t;
-       RX_OFFS(rx)[0].end = off + RX_MINLENRET(rx);
-    }
-#ifdef PERL_SAWAMPERSAND
-    else {                     /* startp/endp are used by @- @+. */
-       RX_OFFS(rx)[0].start = s - truebase;
-       RX_OFFS(rx)[0].end = s - truebase + RX_MINLENRET(rx);
-    }
-#endif
     /* match via INTUIT shouldn't have any captures. Let @-, @+, $^N know */
-    assert(!RX_NPARENS(rx));
     RX_LASTPAREN(rx) = RX_LASTCLOSEPAREN(rx) = 0;
     LEAVE_SCOPE(oldsave);
     RETPUSHYES;
@@ -1617,11 +1557,9 @@ yup:                                     /* Confirmed by INTUIT */
 nope:
 ret_no:
     if (global && !(dynpm->op_pmflags & PMf_CONTINUE)) {
-       if (SvTYPE(TARG) >= SVt_PVMG && SvMAGIC(TARG)) {
-           MAGIC* const mg = mg_find(TARG, PERL_MAGIC_regex_global);
+           MAGIC* const mg = mg_find_mglob(TARG);
            if (mg)
                mg->mg_len = -1;
-       }
     }
     LEAVE_SCOPE(oldsave);
     if (gimme == G_ARRAY)
@@ -1644,7 +1582,7 @@ Perl_do_readline(pTHX)
     if (io) {
        const MAGIC *const mg = SvTIED_mg((const SV *)io, PERL_MAGIC_tiedscalar);
        if (mg) {
-           Perl_tied_method(aTHX_ "READLINE", SP, MUTABLE_SV(io), mg, gimme, 0);
+           Perl_tied_method(aTHX_ SV_CONST(READLINE), SP, MUTABLE_SV(io), mg, gimme, 0);
            if (gimme == G_SCALAR) {
                SPAGAIN;
                SvSetSV_nosteal(TARG, TOPs);
@@ -1802,7 +1740,7 @@ Perl_do_readline(pTHX)
                }
            }
            for (t1 = SvPVX_const(sv); *t1; t1++)
-               if (!isALNUMC(*t1) &&
+               if (!isALPHANUMERIC(*t1) &&
                    strchr("$&*(){}[]'\";\\|?<>~`", *t1))
                        break;
            if (*t1 && PerlLIO_lstat(SvPVX_const(sv), &PL_statbuf) < 0) {
@@ -2028,8 +1966,12 @@ PP(pp_iter)
                 *itersvp = NULL;
                 Perl_croak(aTHX_ "Use of freed value in iteration");
             }
-            SvTEMP_off(sv);
-            SvREFCNT_inc_simple_void_NN(sv);
+            if (SvPADTMP(sv) && !IS_PADGV(sv))
+                sv = newSVsv(sv);
+            else {
+                SvTEMP_off(sv);
+                SvREFCNT_inc_simple_void_NN(sv);
+            }
         }
         else
             sv = &PL_sv_undef;
@@ -2073,12 +2015,11 @@ the pattern is marked as tainted. This means that subsequent usage, such
 as /x$r/, will set PL_tainted using TAINT_set, and thus RXf_TAINTED,
 on the new pattern too.
 
-During execution of a pattern, locale-variant ops such as ALNUML set the
-local flag RF_tainted. At the end of execution, the engine sets the
-RXf_TAINTED_SEEN on the pattern if RF_tainted got set, or clears it
-otherwise.
+At the start of execution of a pattern, the RXf_TAINTED_SEEN flag on the
+regex is cleared; during execution, locale-variant ops such as POSIXL may
+set RXf_TAINTED_SEEN.
 
-In addition, RXf_TAINTED_SEEN is used post-execution by the get magic code
+RXf_TAINTED_SEEN is used post-execution by the get magic code
 of $1 et al to indicate whether the returned value should be tainted.
 It is the responsibility of the caller of the pattern (i.e. pp_match,
 pp_subst etc) to set this flag for any other circumstances where $1 needs
@@ -2209,14 +2150,12 @@ PP(pp_subst)
        TAINT_NOT;
     }
 
-    RX_MATCH_UTF8_set(rx, DO_UTF8(TARG));
-
   force_it:
     if (!pm || !s)
        DIE(aTHX_ "panic: pp_subst, pm=%p, s=%p", pm, s);
 
     strend = s + len;
-    slen = RX_MATCH_UTF8(rx) ? utf8_length((U8*)s, (U8*)strend) : len;
+    slen = DO_UTF8(TARG) ? utf8_length((U8*)s, (U8*)strend) : len;
     maxiters = 2 * slen + 10;  /* We can match twice at each
                                   position, once with zero-length,
                                   second time with non-zero. */
@@ -2240,8 +2179,7 @@ PP(pp_subst)
 
     orig = m = s;
     if (RX_EXTFLAGS(rx) & RXf_USE_INTUIT) {
-       PL_bostr = orig;
-       s = CALLREG_INTUIT_START(rx, TARG, s, strend, r_flags, NULL);
+       s = CALLREG_INTUIT_START(rx, TARG, orig, s, strend, r_flags, NULL);
 
        if (!s)
            goto ret_no;
@@ -2298,7 +2236,7 @@ PP(pp_subst)
 #endif
         && (I32)clen <= RX_MINLENRET(rx)
         && (once || !(r_flags & REXEC_COPY_STR))
-       && !(RX_EXTFLAGS(rx) & (RXf_LOOKBEHIND_SEEN|RXf_MODIFIES_VARS))
+        && !(RX_EXTFLAGS(rx) & RXf_NO_INPLACE_SUBST)
        && (!doutf8 || SvUTF8(TARG))
        && !(rpm->op_pmflags & PMf_NONDESTRUCT))
     {
@@ -2563,6 +2501,10 @@ PP(pp_grepwhile)
        SAVEVPTR(PL_curpm);
 
        src = PL_stack_base[*PL_markstack_ptr];
+       if (SvPADTMP(src) && !IS_PADGV(src)) {
+           src = PL_stack_base[*PL_markstack_ptr] = sv_mortalcopy(src);
+           PL_tmps_floor++;
+       }
        SvTEMP_off(src);
        if (PL_op->op_private & OPpGREP_LEX)
            PAD_SVl(PL_op->op_targ) = src;
@@ -2708,7 +2650,6 @@ PP(pp_entersub)
     }
 
     ENTER;
-    SAVETMPS;
 
   retry:
     if (CvCLONE(cv) && ! CvCLONED(cv))
@@ -2797,28 +2738,29 @@ try_autoload:
            cx->blk_sub.argarray = av;
            ++MARK;
 
-           if (items > AvMAX(av) + 1) {
-               SV **ary = AvALLOC(av);
-               if (AvARRAY(av) != ary) {
-                   AvMAX(av) += AvARRAY(av) - AvALLOC(av);
-                   AvARRAY(av) = ary;
-               }
-               if (items > AvMAX(av) + 1) {
-                   AvMAX(av) = items - 1;
-                   Renew(ary,items,SV*);
-                   AvALLOC(av) = ary;
-                   AvARRAY(av) = ary;
-               }
-           }
+           if (items - 1 > AvMAX(av)) {
+                SV **ary = AvALLOC(av);
+                AvMAX(av) = items - 1;
+                Renew(ary, items, SV*);
+                AvALLOC(av) = ary;
+                AvARRAY(av) = ary;
+            }
+
            Copy(MARK,AvARRAY(av),items,SV*);
            AvFILLp(av) = items - 1;
        
+           MARK = AvARRAY(av);
            while (items--) {
                if (*MARK)
+               {
+                   if (SvPADTMP(*MARK) && !IS_PADGV(*MARK))
+                       *MARK = sv_mortalcopy(*MARK);
                    SvTEMP_off(*MARK);
+               }
                MARK++;
            }
        }
+       SAVETMPS;
        if ((cx->blk_u16 & OPpENTERSUB_LVAL_MASK) == OPpLVAL_INTRO &&
            !CvLVALUE(cv))
            DIE(aTHX_ "Can't modify non-lvalue subroutine call");
@@ -2834,8 +2776,15 @@ try_autoload:
     else {
        I32 markix = TOPMARK;
 
+       SAVETMPS;
        PUTBACK;
 
+       if (((PL_op->op_private
+              & PUSHSUB_GET_LVALUE_MASK(Perl_is_lvalue_sub)
+             ) & OPpENTERSUB_LVAL_MASK) == OPpLVAL_INTRO &&
+           !CvLVALUE(cv))
+           DIE(aTHX_ "Can't modify non-lvalue subroutine call");
+
        if (!hasargs) {
            /* Need to copy @_ to stack. Alternative may be to
             * switch stack to @_, and copy return values
@@ -2884,8 +2833,15 @@ Perl_sub_crush_depth(pTHX_ CV *cv)
     if (CvANON(cv))
        Perl_warner(aTHX_ packWARN(WARN_RECURSION), "Deep recursion on anonymous subroutine");
     else {
-       SV* const tmpstr = sv_newmortal();
-       gv_efullname3(tmpstr, CvGV(cv), NULL);
+        HEK *const hek = CvNAME_HEK(cv);
+        SV *tmpstr;
+        if (hek) {
+            tmpstr = sv_2mortal(newSVhek(hek));
+        }
+        else {
+            tmpstr = sv_newmortal();
+            gv_efullname3(tmpstr, CvGV(cv), NULL);
+        }
        Perl_warner(aTHX_ packWARN(WARN_RECURSION), "Deep recursion on subroutine \"%"SVf"\"",
                    SVfARG(tmpstr));
     }
@@ -3057,6 +3013,19 @@ S_method_common(pTHX_ SV* meth, U32* hashp)
     if (SvROK(sv))
        ob = MUTABLE_SV(SvRV(sv));
     else if (!SvOK(sv)) goto undefined;
+    else if (isGV_with_GP(sv)) {
+       if (!GvIO(sv))
+           Perl_croak(aTHX_ "Can't call method \"%"SVf"\" "
+                            "without a package or object reference",
+                             SVfARG(meth));
+       ob = sv;
+       if (SvTYPE(ob) == SVt_PVLV && LvTYPE(ob) == 'y') {
+           assert(!LvTARGLEN(ob));
+           ob = LvTARG(ob);
+           assert(ob);
+       }
+       *(PL_stack_base + TOPMARK + 1) = sv_2mortal(newRV(ob));
+    }
     else {
        /* this isn't a reference */
        GV* iogv;
@@ -3105,10 +3074,9 @@ S_method_common(pTHX_ SV* meth, U32* hashp)
        *(PL_stack_base + TOPMARK + 1) = sv_2mortal(newRV(MUTABLE_SV(iogv)));
     }
 
-    /* if we got here, ob should be a reference or a glob */
+    /* if we got here, ob should be an object or a glob */
     if (!ob || !(SvOBJECT(ob)
-                || (SvTYPE(ob) == SVt_PVGV 
-                    && isGV_with_GP(ob)
+                || (isGV_with_GP(ob)
                     && (ob = MUTABLE_SV(GvIO((const GV *)ob)))
                     && SvOBJECT(ob))))
     {