This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
perltodo.pod: error message todo
[perl5.git] / pp_hot.c
index 8420757..57fa328 100644 (file)
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -1,7 +1,7 @@
 /*    pp_hot.c
  *
  *    Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- *    2000, 2001, 2002, 2003, 2004, 2005, 2006, by Larry Wall and others
+ *    2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 by Larry Wall and others
  *
  *    You may distribute under the terms of either the GNU General Public
  *    License or the Artistic License, as specified in the README file.
@@ -39,7 +39,14 @@ PP(pp_const)
 {
     dVAR;
     dSP;
-    XPUSHs(cSVOP_sv);
+    if ( PL_op->op_flags & OPf_SPECIAL )
+        /* This is a const op added to hold the hints hash for
+           pp_entereval. The hash can be modified by the code
+           being eval'ed, so we return a copy instead. */
+        XPUSHs(sv_2mortal((SV*)Perl_hv_copy_hints_hv(aTHX_ (HV*)cSVOP_sv)));
+    else
+        /* Normal const. */
+        XPUSHs(cSVOP_sv);
     RETURN;
 }
 
@@ -120,12 +127,6 @@ PP(pp_sassign)
        SV * const temp = left;
        left = right; right = temp;
     }
-    else if (PL_op->op_private & OPpASSIGN_STATE) {
-       if (SvPADSTALE(right))
-           SvPADSTALE_off(right);
-       else
-           RETURN; /* ignore assignment */
-    }
     if (PL_tainting && PL_tainted && !SvTAINTED(left))
        TAINT_NOT;
     if (PL_op->op_private & OPpASSIGN_CV_TO_GV) {
@@ -150,7 +151,7 @@ PP(pp_sassign)
                SV *const value = SvRV(cv);
 
                SvUPGRADE((SV *)gv, SVt_RV);
-               SvROK_on(gv);
+               SvPCS_IMPORTED_on(gv);
                SvRV_set(gv, value);
                SvREFCNT_inc_simple_void(value);
                SETs(right);
@@ -167,23 +168,44 @@ PP(pp_sassign)
        if (!got_coderef) {
            /* We've been returned a constant rather than a full subroutine,
               but they expect a subroutine reference to apply.  */
-           ENTER;
-           SvREFCNT_inc_void(SvRV(cv));
-           /* newCONSTSUB takes a reference count on the passed in SV
-              from us.  We set the name to NULL, otherwise we get into
-              all sorts of fun as the reference to our new sub is
-              donated to the GV that we're about to assign to.
-           */
-           SvRV_set(left, (SV *)newCONSTSUB(GvSTASH(right), NULL,
+           if (SvROK(cv)) {
+               ENTER;
+               SvREFCNT_inc_void(SvRV(cv));
+               /* newCONSTSUB takes a reference count on the passed in SV
+                  from us.  We set the name to NULL, otherwise we get into
+                  all sorts of fun as the reference to our new sub is
+                  donated to the GV that we're about to assign to.
+               */
+               SvRV_set(left, (SV *)newCONSTSUB(GvSTASH(right), NULL,
                                                 SvRV(cv)));
-           SvREFCNT_dec(cv);
-           LEAVE;
-       }
+               SvREFCNT_dec(cv);
+               LEAVE;
+           } else {
+               /* What can happen for the corner case *{"BONK"} = \&{"BONK"};
+                  is that
+                  First:   ops for \&{"BONK"}; return us the constant in the
+                           symbol table
+                  Second:  ops for *{"BONK"} cause that symbol table entry
+                           (and our reference to it) to be upgraded from RV
+                           to typeblob)
+                  Thirdly: We get here. cv is actually PVGV now, and its
+                           GvCV() is actually the subroutine we're looking for
+
+                  So change the reference so that it points to the subroutine
+                  of that typeglob, as that's what they were after all along.
+               */
+               GV *const upgraded = (GV *) cv;
+               CV *const source = GvCV(upgraded);
 
-       if (strEQ(GvNAME(right),"isa")) {
-           GvCVGEN(right) = 0;
-           ++PL_sub_generation;
+               assert(source);
+               assert(CvFLAGS(source) & CVf_CONST);
+
+               SvREFCNT_inc_void(source);
+               SvREFCNT_dec(upgraded);
+               SvRV_set(left, (SV *)source);
+           }
        }
+
     }
     SvSetMagicSV(right, left);
     SETs(right);
@@ -430,12 +452,13 @@ PP(pp_defined)
                --SP;
             RETURNOP(cLOGOP->op_other);
         }
-    } else if (op_type == OP_DEFINED) {
+    }
+    else {
+       /* OP_DEFINED */
         sv = POPs;
         if (!sv || !SvANY(sv))
             RETPUSHNO;
-    } else
-        DIE(aTHX_ "panic:  Invalid op (%s) in pp_defined()", OP_NAME(PL_op));
+    }
 
     defined = FALSE;
     switch (SvTYPE(sv)) {
@@ -473,8 +496,11 @@ PP(pp_defined)
 
 PP(pp_add)
 {
-    dVAR; dSP; dATARGET; bool useleft; tryAMAGICbin(add,opASSIGN);
-    useleft = USE_LEFT(TOPm1s);
+    dVAR; dSP; dATARGET; bool useleft; SV *svl, *svr;
+    tryAMAGICbin(add,opASSIGN);
+    svl = sv_2num(TOPm1s);
+    svr = sv_2num(TOPs);
+    useleft = USE_LEFT(svl);
 #ifdef PERL_PRESERVE_IVUV
     /* We must see if we can perform the addition with integers if possible,
        as the integer code detects overflow while the NV code doesn't.
@@ -522,8 +548,8 @@ PP(pp_add)
        unsigned code below is actually shorter than the old code. :-)
     */
 
-    SvIV_please(TOPs);
-    if (SvIOK(TOPs)) {
+    SvIV_please(svr);
+    if (SvIOK(svr)) {
        /* Unless the left argument is integer in range we are going to have to
           use NV maths. Hence only attempt to coerce the right argument if
           we know the left is integer.  */
@@ -539,12 +565,12 @@ PP(pp_add)
               lots of code to speed up what is probably a rarish case.  */
        } else {
            /* Left operand is defined, so is it IV? */
-           SvIV_please(TOPm1s);
-           if (SvIOK(TOPm1s)) {
-               if ((auvok = SvUOK(TOPm1s)))
-                   auv = SvUVX(TOPm1s);
+           SvIV_please(svl);
+           if (SvIOK(svl)) {
+               if ((auvok = SvUOK(svl)))
+                   auv = SvUVX(svl);
                else {
-                   register const IV aiv = SvIVX(TOPm1s);
+                   register const IV aiv = SvIVX(svl);
                    if (aiv >= 0) {
                        auv = aiv;
                        auvok = 1;      /* Now acting as a sign flag.  */
@@ -559,12 +585,12 @@ PP(pp_add)
            bool result_good = 0;
            UV result;
            register UV buv;
-           bool buvok = SvUOK(TOPs);
+           bool buvok = SvUOK(svr);
        
            if (buvok)
-               buv = SvUVX(TOPs);
+               buv = SvUVX(svr);
            else {
-               register const IV biv = SvIVX(TOPs);
+               register const IV biv = SvIVX(svr);
                if (biv >= 0) {
                    buv = biv;
                    buvok = 1;
@@ -622,13 +648,14 @@ PP(pp_add)
     }
 #endif
     {
-       dPOPnv;
+       NV value = SvNV(svr);
+       (void)POPs;
        if (!useleft) {
            /* left operand is undef, treat as zero. + 0.0 is identity. */
            SETn(value);
            RETURN;
        }
-       SETn( value + TOPn );
+       SETn( value + SvNV(svl) );
        RETURN;
     }
 }
@@ -782,23 +809,30 @@ PP(pp_print)
 PP(pp_rv2av)
 {
     dVAR; dSP; dTOPss;
-    AV *av;
+    const I32 gimme = GIMME_V;
+    static const char return_array_to_lvalue_scalar[] = "Can't return array to lvalue scalar context";
+    static const char return_hash_to_lvalue_scalar[] = "Can't return hash to lvalue scalar context";
+    static const char an_array[] = "an ARRAY";
+    static const char a_hash[] = "a HASH";
+    const bool is_pp_rv2av = PL_op->op_type == OP_RV2AV;
+    const svtype type = is_pp_rv2av ? SVt_PVAV : SVt_PVHV;
 
     if (SvROK(sv)) {
       wasref:
-       tryAMAGICunDEREF(to_av);
+       tryAMAGICunDEREF_var(is_pp_rv2av ? to_av_amg : to_hv_amg);
 
-       av = (AV*)SvRV(sv);
-       if (SvTYPE(av) != SVt_PVAV)
-           DIE(aTHX_ "Not an ARRAY reference");
+       sv = SvRV(sv);
+       if (SvTYPE(sv) != type)
+           DIE(aTHX_ "Not %s reference", is_pp_rv2av ? an_array : a_hash);
        if (PL_op->op_flags & OPf_REF) {
-           SETs((SV*)av);
+           SETs(sv);
            RETURN;
        }
        else if (LVRET) {
-           if (GIMME == G_SCALAR)
-               Perl_croak(aTHX_ "Can't return array to lvalue scalar context");
-           SETs((SV*)av);
+           if (gimme != G_ARRAY)
+               Perl_croak(aTHX_ is_pp_rv2av ? return_array_to_lvalue_scalar
+                          : return_hash_to_lvalue_scalar);
+           SETs(sv);
            RETURN;
        }
        else if (PL_op->op_flags & OPf_MOD
@@ -806,17 +840,17 @@ PP(pp_rv2av)
            Perl_croak(aTHX_ PL_no_localize_ref);
     }
     else {
-       if (SvTYPE(sv) == SVt_PVAV) {
-           av = (AV*)sv;
+       if (SvTYPE(sv) == type) {
            if (PL_op->op_flags & OPf_REF) {
-               SETs((SV*)av);
+               SETs(sv);
                RETURN;
            }
            else if (LVRET) {
-               if (GIMME == G_SCALAR)
-                   Perl_croak(aTHX_ "Can't return array to lvalue"
-                              " scalar context");
-               SETs((SV*)av);
+               if (gimme != G_ARRAY)
+                   Perl_croak(aTHX_
+                              is_pp_rv2av ? return_array_to_lvalue_scalar
+                              : return_hash_to_lvalue_scalar);
+               SETs(sv);
                RETURN;
            }
        }
@@ -829,56 +863,38 @@ PP(pp_rv2av)
                    if (SvROK(sv))
                        goto wasref;
                }
-               if (!SvOK(sv)) {
-                   if (PL_op->op_flags & OPf_REF ||
-                     PL_op->op_private & HINT_STRICT_REFS)
-                       DIE(aTHX_ PL_no_usym, "an ARRAY");
-                   if (ckWARN(WARN_UNINITIALIZED))
-                       report_uninit(sv);
-                   if (GIMME == G_ARRAY) {
-                       (void)POPs;
-                       RETURN;
-                   }
-                   RETSETUNDEF;
-               }
-               if ((PL_op->op_flags & OPf_SPECIAL) &&
-                   !(PL_op->op_flags & OPf_MOD))
-               {
-                   gv = (GV*)gv_fetchsv(sv, 0, SVt_PVAV);
-                   if (!gv
-                       && (!is_gv_magical_sv(sv,0)
-                           || !(gv = (GV*)gv_fetchsv(sv, GV_ADD, SVt_PVAV))))
-                   {
-                       RETSETUNDEF;
-                   }
-               }
-               else {
-                   if (PL_op->op_private & HINT_STRICT_REFS)
-                       DIE(aTHX_ PL_no_symref_sv, sv, "an ARRAY");
-                   gv = (GV*)gv_fetchsv(sv, GV_ADD, SVt_PVAV);
-               }
+               gv = Perl_softref2xv(aTHX_ sv, is_pp_rv2av ? an_array : a_hash,
+                                    type, &sp);
+               if (!gv)
+                   RETURN;
            }
            else {
                gv = (GV*)sv;
            }
-           av = GvAVn(gv);
+           sv = is_pp_rv2av ? (SV*)GvAVn(gv) : (SV*)GvHVn(gv);
            if (PL_op->op_private & OPpLVAL_INTRO)
-               av = save_ary(gv);
+               sv = is_pp_rv2av ? (SV*)save_ary(gv) : (SV*)save_hash(gv);
            if (PL_op->op_flags & OPf_REF) {
-               SETs((SV*)av);
+               SETs(sv);
                RETURN;
            }
            else if (LVRET) {
-               if (GIMME == G_SCALAR)
-                   Perl_croak(aTHX_ "Can't return array to lvalue"
-                              " scalar context");
-               SETs((SV*)av);
+               if (gimme != G_ARRAY)
+                   Perl_croak(aTHX_
+                              is_pp_rv2av ? return_array_to_lvalue_scalar
+                              : return_hash_to_lvalue_scalar);
+               SETs(sv);
                RETURN;
            }
        }
     }
 
-    if (GIMME == G_ARRAY) {
+    if (is_pp_rv2av) {
+       AV *const av = (AV*)sv;
+       /* The guts of pp_rv2av, with no intenting change to preserve history
+          (until such time as we get tools that can do blame annotation across
+          whitespace changes.  */
+    if (gimme == G_ARRAY) {
        const I32 maxarg = AvFILL(av) + 1;
        (void)POPs;                     /* XXXX May be optimized away? */
        EXTEND(SP, maxarg);
@@ -897,122 +913,24 @@ PP(pp_rv2av)
        }
        SP += maxarg;
     }
-    else if (GIMME_V == G_SCALAR) {
+    else if (gimme == G_SCALAR) {
        dTARGET;
        const I32 maxarg = AvFILL(av) + 1;
        SETi(maxarg);
     }
-    RETURN;
-}
-
-PP(pp_rv2hv)
-{
-    dVAR; dSP; dTOPss;
-    HV *hv;
-    const I32 gimme = GIMME_V;
-    static const char return_hash_to_lvalue_scalar[] = "Can't return hash to lvalue scalar context";
-
-    if (SvROK(sv)) {
-      wasref:
-       tryAMAGICunDEREF(to_hv);
-
-       hv = (HV*)SvRV(sv);
-       if (SvTYPE(hv) != SVt_PVHV)
-           DIE(aTHX_ "Not a HASH reference");
-       if (PL_op->op_flags & OPf_REF) {
-           SETs((SV*)hv);
-           RETURN;
-       }
-       else if (LVRET) {
-           if (gimme != G_ARRAY)
-               Perl_croak(aTHX_ return_hash_to_lvalue_scalar );
-           SETs((SV*)hv);
-           RETURN;
-       }
-       else if (PL_op->op_flags & OPf_MOD
-               && PL_op->op_private & OPpLVAL_INTRO)
-           Perl_croak(aTHX_ PL_no_localize_ref);
-    }
-    else {
-       if (SvTYPE(sv) == SVt_PVHV) {
-           hv = (HV*)sv;
-           if (PL_op->op_flags & OPf_REF) {
-               SETs((SV*)hv);
-               RETURN;
-           }
-           else if (LVRET) {
-               if (gimme != G_ARRAY)
-                   Perl_croak(aTHX_ return_hash_to_lvalue_scalar );
-               SETs((SV*)hv);
-               RETURN;
-           }
-       }
-       else {
-           GV *gv;
-       
-           if (SvTYPE(sv) != SVt_PVGV) {
-               if (SvGMAGICAL(sv)) {
-                   mg_get(sv);
-                   if (SvROK(sv))
-                       goto wasref;
-               }
-               if (!SvOK(sv)) {
-                   if (PL_op->op_flags & OPf_REF ||
-                     PL_op->op_private & HINT_STRICT_REFS)
-                       DIE(aTHX_ PL_no_usym, "a HASH");
-                   if (ckWARN(WARN_UNINITIALIZED))
-                       report_uninit(sv);
-                   if (gimme == G_ARRAY) {
-                       SP--;
-                       RETURN;
-                   }
-                   RETSETUNDEF;
-               }
-               if ((PL_op->op_flags & OPf_SPECIAL) &&
-                   !(PL_op->op_flags & OPf_MOD))
-               {
-                   gv = (GV*)gv_fetchsv(sv, 0, SVt_PVHV);
-                   if (!gv
-                       && (!is_gv_magical_sv(sv,0)
-                           || !(gv = (GV*)gv_fetchsv(sv, GV_ADD, SVt_PVHV))))
-                   {
-                       RETSETUNDEF;
-                   }
-               }
-               else {
-                   if (PL_op->op_private & HINT_STRICT_REFS)
-                       DIE(aTHX_ PL_no_symref_sv, sv, "a HASH");
-                   gv = (GV*)gv_fetchsv(sv, GV_ADD, SVt_PVHV);
-               }
-           }
-           else {
-               gv = (GV*)sv;
-           }
-           hv = GvHVn(gv);
-           if (PL_op->op_private & OPpLVAL_INTRO)
-               hv = save_hash(gv);
-           if (PL_op->op_flags & OPf_REF) {
-               SETs((SV*)hv);
-               RETURN;
-           }
-           else if (LVRET) {
-               if (gimme != G_ARRAY)
-                   Perl_croak(aTHX_ return_hash_to_lvalue_scalar );
-               SETs((SV*)hv);
-               RETURN;
-           }
-       }
-    }
-
+    } else {
+       /* The guts of pp_rv2hv  */
     if (gimme == G_ARRAY) { /* array wanted */
-       *PL_stack_sp = (SV*)hv;
+       *PL_stack_sp = sv;
        return do_kv();
     }
     else if (gimme == G_SCALAR) {
        dTARGET;
-    TARG = Perl_hv_scalar(aTHX_ hv);
+    TARG = Perl_hv_scalar(aTHX_ (HV*)sv);
+       SPAGAIN;
        SETTARG;
     }
+    }
     RETURN;
 }
 
@@ -1071,7 +989,6 @@ PP(pp_aassign)
     int duplicates = 0;
     SV **firsthashrelem = NULL;        /* "= 0" keeps gcc 2.95 quiet  */
 
-
     PL_delaymagic = DM_DELAY;          /* catch simultaneous items */
     gimme = GIMME_V;
 
@@ -1088,12 +1005,6 @@ PP(pp_aassign)
            }
        }
     }
-    if (PL_op->op_private & OPpASSIGN_STATE) {
-       if (SvPADSTALE(*firstlelem))
-           SvPADSTALE_off(*firstlelem);
-       else
-           RETURN; /* ignore assignment */
-    }
 
     relem = firstrelem;
     lelem = firstlelem;
@@ -1124,6 +1035,8 @@ PP(pp_aassign)
                }
                TAINT_NOT;
            }
+           if (PL_delaymagic & DM_ARRAY)
+               SvSETMAGIC((SV*)ary);
            break;
        case SVt_PVHV: {                                /* normal hash */
                SV *tmpstr;
@@ -1270,6 +1183,7 @@ PP(pp_aassign)
        while (relem <= SP)
            *relem++ = (lelem <= lastlelem) ? *lelem++ : &PL_sv_undef;
     }
+
     RETURN;
 }
 
@@ -1277,12 +1191,15 @@ PP(pp_qr)
 {
     dVAR; dSP;
     register PMOP * const pm = cPMOP;
+    REGEXP * rx = PM_GETRE(pm);
+    SV * const pkg = CALLREG_PACKAGE(rx);
     SV * const rv = sv_newmortal();
-    SV * const sv = newSVrv(rv, "Regexp");
-    if (pm->op_pmdynflags & PMdf_TAINTED)
+    SV * const sv = newSVrv(rv, SvPV_nolen(pkg));
+    if (rx->extflags & RXf_TAINTED)
         SvTAINTED_on(rv);
-    sv_magic(sv,(SV*)ReREFCNT_inc(PM_GETRE(pm)), PERL_MAGIC_qr,0,0);
-    RETURNX(PUSHs(rv));
+    sv_magic(sv,(SV*)ReREFCNT_inc(rx), PERL_MAGIC_qr,0,0);
+    XPUSHs(rv);
+    RETURN;
 }
 
 PP(pp_match)
@@ -1320,20 +1237,28 @@ PP(pp_match)
     if (!s)
        DIE(aTHX_ "panic: pp_match");
     strend = s + len;
-    rxtainted = ((pm->op_pmdynflags & PMdf_TAINTED) ||
+    rxtainted = ((rx->extflags & RXf_TAINTED) ||
                 (PL_tainted && (pm->op_pmflags & PMf_RETAINT)));
     TAINT_NOT;
 
     RX_MATCH_UTF8_set(rx, DO_UTF8(TARG));
 
     /* PMdf_USED is set after a ?? matches once */
-    if (pm->op_pmdynflags & PMdf_USED) {
+    if (
+#ifdef USE_ITHREADS
+        SvREADONLY(PL_regex_pad[pm->op_pmoffset])
+#else
+        pm->op_pmflags & PMf_USED
+#endif
+    ) {
       failure:
        if (gimme == G_ARRAY)
            RETURN;
        RETPUSHNO;
     }
 
+
+
     /* empty pattern special-cased to use last successful pattern if possible */
     if (!rx->prelen && PL_curpm) {
        pm = PL_curpm;
@@ -1347,61 +1272,71 @@ PP(pp_match)
 
     /* XXXX What part of this is needed with true \G-support? */
     if ((global = dynpm->op_pmflags & PMf_GLOBAL)) {
-       rx->startp[0] = -1;
+       rx->offs[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 (!(rx->reganch & ROPT_GPOS_SEEN))
-                   rx->endp[0] = rx->startp[0] = mg->mg_len;
-               else if (rx->reganch & ROPT_ANCH_GPOS) {
+               if (!(rx->extflags & RXf_GPOS_SEEN))
+                   rx->offs[0].end = rx->offs[0].start = mg->mg_len;
+               else if (rx->extflags & RXf_ANCH_GPOS) {
                    r_flags |= REXEC_IGNOREPOS;
-                   rx->endp[0] = rx->startp[0] = mg->mg_len;
-               } else if (rx->reganch & ROPT_GPOS_FLOAT) 
+                   rx->offs[0].end = rx->offs[0].start = mg->mg_len;
+               } else if (rx->extflags & RXf_GPOS_FLOAT) 
                    gpos = mg->mg_len;
                else 
-                   rx->endp[0] = rx->startp[0] = mg->mg_len;
+                   rx->offs[0].end = rx->offs[0].start = mg->mg_len;
                minmatch = (mg->mg_flags & MGf_MINMATCH) ? rx->gofs + 1 : 0;
                update_minmatch = 0;
            }
        }
     }
-    /* remove comment to get faster /g but possibly unsafe $1 vars after a
-       match. Test for the unsafe vars will fail as well*/
-    if (( /* !global &&  */ rx->nparens) 
-           || SvTEMP(TARG) || PL_sawampersand || (pm->op_pmflags & PMf_EVAL))
+    /* XXX: comment out !global get safe $1 vars after a
+       match, BUT be aware that this leads to dramatic slowdowns on
+       /g matches against large strings.  So far a solution to this problem
+       appears to be quite tricky.
+       Test for the unsafe vars are TODO for now. */
+    if ((  !global &&  rx->nparens) 
+           || SvTEMP(TARG) || PL_sawampersand ||
+           (rx->extflags & (RXf_EVAL_SEEN|RXf_PMf_KEEPCOPY)))
        r_flags |= REXEC_COPY_STR;
     if (SvSCREAM(TARG))
        r_flags |= REXEC_SCREAM;
 
 play_it_again:
-    if (global && rx->startp[0] != -1) {
-       t = s = rx->endp[0] + truebase - rx->gofs;
+    if (global && rx->offs[0].start != -1) {
+       t = s = rx->offs[0].end + truebase - rx->gofs;
        if ((s + rx->minlen) > strend || s < truebase)
            goto nope;
        if (update_minmatch++)
            minmatch = had_zerolen;
     }
-    if (rx->reganch & RE_USE_INTUIT &&
-       DO_UTF8(TARG) == ((rx->reganch & ROPT_UTF8) != 0)) {
+    if (rx->extflags & RXf_USE_INTUIT &&
+       DO_UTF8(TARG) == ((rx->extflags & RXf_UTF8) != 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);
 
        if (!s)
            goto nope;
-       if ( (rx->reganch & ROPT_CHECK_ALL)
+       if ( (rx->extflags & RXf_CHECK_ALL)
             && !PL_sawampersand
-            && ((rx->reganch & ROPT_NOSCAN)
-                || !((rx->reganch & RE_INTUIT_TAIL)
+            && !(rx->extflags & RXf_PMf_KEEPCOPY)
+            && ((rx->extflags & RXf_NOSCAN)
+                || !((rx->extflags & RXf_INTUIT_TAIL)
                      && (r_flags & REXEC_SCREAM)))
             && !SvROK(TARG))   /* Cannot trust since INTUIT cannot guess ^ */
            goto yup;
     }
-    if (CALLREGEXEC(rx, (char*)s, (char *)strend, (char*)truebase, minmatch, TARG, (void*)gpos, r_flags))
+    if (CALLREGEXEC(rx, (char*)s, (char *)strend, (char*)truebase, minmatch, TARG, INT2PTR(void*, gpos), r_flags))
     {
        PL_curpm = pm;
-       if (dynpm->op_pmflags & PMf_ONCE)
-           dynpm->op_pmdynflags |= PMdf_USED;
+       if (dynpm->op_pmflags & PMf_ONCE) {
+#ifdef USE_ITHREADS
+            SvREADONLY_on(PL_regex_pad[dynpm->op_pmoffset]);
+#else
+           dynpm->op_pmflags |= PMf_USED;
+#endif
+        }
        goto gotcha;
     }
     else
@@ -1421,10 +1356,10 @@ play_it_again:
        EXTEND_MORTAL(nparens + i);
        for (i = !i; i <= nparens; i++) {
            PUSHs(sv_newmortal());
-           if ((rx->startp[i] != -1) && rx->endp[i] != -1 ) {
-               const I32 len = rx->endp[i] - rx->startp[i];
-               s = rx->startp[i] + truebase;
-               if (rx->endp[i] < 0 || rx->startp[i] < 0 ||
+           if ((rx->offs[i].start != -1) && rx->offs[i].end != -1 ) {
+               const I32 len = rx->offs[i].end - rx->offs[i].start;
+               s = rx->offs[i].start + truebase;
+               if (rx->offs[i].end < 0 || rx->offs[i].start < 0 ||
                    len < 0 || len > strend - s)
                    DIE(aTHX_ "panic: pp_match start/end pointers");
                sv_setpvn(*SP, s, len);
@@ -1445,16 +1380,17 @@ play_it_again:
                    mg = sv_magicext(TARG, NULL, PERL_MAGIC_regex_global,
                                     &PL_vtbl_mglob, NULL, 0);
                }
-               if (rx->startp[0] != -1) {
-                   mg->mg_len = rx->endp[0];
-                   if (rx->startp[0] + rx->gofs == rx->endp[0])
+               if (rx->offs[0].start != -1) {
+                   mg->mg_len = rx->offs[0].end;
+                   if (rx->offs[0].start + rx->gofs == (UV)rx->offs[0].end)
                        mg->mg_flags |= MGf_MINMATCH;
                    else
                        mg->mg_flags &= ~MGf_MINMATCH;
                }
            }
-           had_zerolen = (rx->startp[0] != -1
-                          && rx->startp[0] + rx->gofs == rx->endp[0]);
+           had_zerolen = (rx->offs[0].start != -1
+                          && (rx->offs[0].start + rx->gofs
+                              == (UV)rx->offs[0].end));
            PUTBACK;                    /* EVAL blocks may use stack */
            r_flags |= REXEC_IGNOREPOS | REXEC_NOT_FIRST;
            goto play_it_again;
@@ -1479,9 +1415,9 @@ play_it_again:
                mg = sv_magicext(TARG, NULL, PERL_MAGIC_regex_global,
                                 &PL_vtbl_mglob, NULL, 0);
            }
-           if (rx->startp[0] != -1) {
-               mg->mg_len = rx->endp[0];
-               if (rx->startp[0] + rx->gofs == rx->endp[0])
+           if (rx->offs[0].start != -1) {
+               mg->mg_len = rx->offs[0].end;
+               if (rx->offs[0].start + rx->gofs == (UV)rx->offs[0].end)
                    mg->mg_flags |= MGf_MINMATCH;
                else
                    mg->mg_flags &= ~MGf_MINMATCH;
@@ -1496,8 +1432,13 @@ yup:                                     /* Confirmed by INTUIT */
        RX_MATCH_TAINTED_on(rx);
     TAINT_IF(RX_MATCH_TAINTED(rx));
     PL_curpm = pm;
-    if (dynpm->op_pmflags & PMf_ONCE)
-       dynpm->op_pmdynflags |= PMdf_USED;
+    if (dynpm->op_pmflags & PMf_ONCE) {
+#ifdef USE_ITHREADS
+        SvREADONLY_on(PL_regex_pad[dynpm->op_pmoffset]);
+#else
+        dynpm->op_pmflags |= PMf_USED;
+#endif
+    }
     if (RX_MATCH_COPIED(rx))
        Safefree(rx->subbeg);
     RX_MATCH_COPIED_off(rx);
@@ -1505,25 +1446,25 @@ yup:                                    /* Confirmed by INTUIT */
     if (global) {
        /* FIXME - should rx->subbeg be const char *?  */
        rx->subbeg = (char *) truebase;
-       rx->startp[0] = s - truebase;
+       rx->offs[0].start = s - truebase;
        if (RX_MATCH_UTF8(rx)) {
            char * const t = (char*)utf8_hop((U8*)s, rx->minlenret);
-           rx->endp[0] = t - truebase;
+           rx->offs[0].end = t - truebase;
        }
        else {
-           rx->endp[0] = s - truebase + rx->minlenret;
+           rx->offs[0].end = s - truebase + rx->minlenret;
        }
        rx->sublen = strend - truebase;
        goto gotcha;
     }
-    if (PL_sawampersand) {
+    if (PL_sawampersand || rx->extflags & RXf_PMf_KEEPCOPY) {
        I32 off;
 #ifdef PERL_OLD_COPY_ON_WRITE
        if (SvIsCOW(TARG) || (SvFLAGS(TARG) & CAN_COW_MASK) == CAN_COW_FLAGS) {
            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), truebase, t,
+                             (int) SvTYPE(TARG), (void*)truebase, (void*)t,
                              (int)(t-truebase));
            }
            rx->saved_copy = sv_setsv_cow(rx->saved_copy, TARG);
@@ -1540,13 +1481,15 @@ yup:                                    /* Confirmed by INTUIT */
        }
        rx->sublen = strend - t;
        RX_MATCH_COPIED_on(rx);
-       off = rx->startp[0] = s - t;
-       rx->endp[0] = off + rx->minlenret;
+       off = rx->offs[0].start = s - t;
+       rx->offs[0].end = off + rx->minlenret;
     }
     else {                     /* startp/endp are used by @- @+. */
-       rx->startp[0] = s - truebase;
-       rx->endp[0] = s - truebase + rx->minlenret;
+       rx->offs[0].start = s - truebase;
+       rx->offs[0].end = s - truebase + rx->minlenret;
     }
+    /* including rx->nparens in the below code seems highly suspicious.
+       -dmq */
     rx->nparens = rx->lastparen = rx->lastcloseparen = 0;      /* used by @-, @+, and $^N */
     LEAVE_SCOPE(oldsave);
     RETPUSHYES;
@@ -1650,6 +1593,8 @@ Perl_do_readline(pTHX)
   have_fp:
     if (gimme == G_SCALAR) {
        sv = TARG;
+       if (type == OP_RCATLINE && SvGMAGICAL(sv))
+           mg_get(sv);
        if (SvROK(sv)) {
            if (type == OP_RCATLINE)
                SvPV_force_nolen(sv);
@@ -1836,7 +1781,7 @@ PP(pp_helem)
            SV* lv;
            SV* key2;
            if (!defer) {
-               DIE(aTHX_ PL_no_helem_sv, keysv);
+               DIE(aTHX_ PL_no_helem_sv, SVfARG(keysv));
            }
            lv = sv_newmortal();
            sv_upgrade(lv, SVt_PVLV);
@@ -2047,8 +1992,7 @@ PP(pp_iter)
        if (lv)
            SvREFCNT_dec(LvTARG(lv));
        else {
-           lv = cx->blk_loop.iterlval = newSV(0);
-           sv_upgrade(lv, SVt_PVLV);
+           lv = cx->blk_loop.iterlval = newSV_type(SVt_PVLV);
            LvTYPE(lv) = 'y';
            sv_magic(lv, NULL, PERL_MAGIC_defelem, NULL, 0);
        }
@@ -2118,7 +2062,8 @@ PP(pp_subst)
        !is_cow &&
 #endif
        (SvREADONLY(TARG)
-       || ( (SvTYPE(TARG) == SVt_PVGV || SvTYPE(TARG) > SVt_PVLV)
+        || ( ((SvTYPE(TARG) == SVt_PVGV && isGV_with_GP(TARG))
+              || SvTYPE(TARG) > SVt_PVLV)
             && !(SvTYPE(TARG) == SVt_PVGV && SvFAKE(TARG)))))
        DIE(aTHX_ PL_no_modify);
     PUTBACK;
@@ -2126,7 +2071,7 @@ PP(pp_subst)
     s = SvPV_mutable(TARG, len);
     if (!SvPOKp(TARG) || SvTYPE(TARG) == SVt_PVGV)
        force_on_match = 1;
-    rxtainted = ((pm->op_pmdynflags & PMdf_TAINTED) ||
+    rxtainted = ((rx->extflags & RXf_TAINTED) ||
                 (PL_tainted && (pm->op_pmflags & PMf_RETAINT)));
     if (PL_tainted)
        rxtainted |= 2;
@@ -2149,23 +2094,24 @@ PP(pp_subst)
        rx = PM_GETRE(pm);
     }
     r_flags = (rx->nparens || SvTEMP(TARG) || PL_sawampersand
-           || (pm->op_pmflags & PMf_EVAL))
+           || (rx->extflags & (RXf_EVAL_SEEN|RXf_PMf_KEEPCOPY)) )
               ? REXEC_COPY_STR : 0;
     if (SvSCREAM(TARG))
        r_flags |= REXEC_SCREAM;
 
     orig = m = s;
-    if (rx->reganch & RE_USE_INTUIT) {
+    if (rx->extflags & RXf_USE_INTUIT) {
        PL_bostr = orig;
        s = CALLREG_INTUIT_START(rx, TARG, s, strend, r_flags, NULL);
 
        if (!s)
            goto nope;
        /* How to do it in subst? */
-/*     if ( (rx->reganch & ROPT_CHECK_ALL)
+/*     if ( (rx->extflags & RXf_CHECK_ALL)
             && !PL_sawampersand
-            && ((rx->reganch & ROPT_NOSCAN)
-                || !((rx->reganch & RE_INTUIT_TAIL)
+            && !(rx->extflags & RXf_KEEPCOPY)
+            && ((rx->extflags & RXf_NOSCAN)
+                || !((rx->extflags & RXf_INTUIT_TAIL)
                      && (r_flags & REXEC_SCREAM))))
            goto yup;
 */
@@ -2203,7 +2149,7 @@ PP(pp_subst)
        && !is_cow
 #endif
        && (I32)clen <= rx->minlenret && (once || !(r_flags & REXEC_COPY_STR))
-       && !(rx->reganch & ROPT_LOOKBEHIND_SEEN)
+       && !(rx->extflags & RXf_LOOKBEHIND_SEEN)
        && (!doutf8 || SvUTF8(TARG))) {
        if (!CALLREGEXEC(rx, s, strend, orig, 0, TARG, NULL,
                         r_flags | REXEC_CHECKED))
@@ -2229,8 +2175,8 @@ PP(pp_subst)
        SvSCREAM_off(TARG);     /* disable possible screamer */
        if (once) {
            rxtainted |= RX_MATCH_TAINTED(rx);
-           m = orig + rx->startp[0];
-           d = orig + rx->endp[0];
+           m = orig + rx->offs[0].start;
+           d = orig + rx->offs[0].end;
            s = orig;
            if (m - s > strend - d) {  /* faster to shorten from end */
                if (clen) {
@@ -2272,7 +2218,7 @@ PP(pp_subst)
                if (iters++ > maxiters)
                    DIE(aTHX_ "Substitution loop");
                rxtainted |= RX_MATCH_TAINTED(rx);
-               m = rx->startp[0] + orig;
+               m = rx->offs[0].start + orig;
                if ((i = m - s)) {
                    if (s != d)
                        Move(s, d, i, char);
@@ -2282,7 +2228,7 @@ PP(pp_subst)
                    Copy(c, d, clen, char);
                    d += clen;
                }
-               s = rx->endp[0] + orig;
+               s = rx->offs[0].end + orig;
            } while (CALLREGEXEC(rx, s, strend, orig, s == m,
                                 TARG, NULL,
                                 /* don't match same null twice */
@@ -2331,7 +2277,7 @@ PP(pp_subst)
            register PERL_CONTEXT *cx;
            SPAGAIN;
            PUSHSUBST(cx);
-           RETURNOP(cPMOP->op_pmreplroot);
+           RETURNOP(cPMOP->op_pmreplrootu.op_pmreplroot);
        }
        r_flags |= REXEC_IGNOREPOS | REXEC_NOT_FIRST;
        do {
@@ -2345,12 +2291,12 @@ PP(pp_subst)
                s = orig + (m - s);
                strend = s + (strend - m);
            }
-           m = rx->startp[0] + orig;
+           m = rx->offs[0].start + orig;
            if (doutf8 && !SvUTF8(dstr))
                sv_catpvn_utf8_upgrade(dstr, s, m - s, nsv);
             else
                sv_catpvn(dstr, s, m-s);
-           s = rx->endp[0] + orig;
+           s = rx->offs[0].end + orig;
            if (clen)
                sv_catpvn(dstr, c, clen);
            if (once)
@@ -2680,45 +2626,6 @@ PP(pp_leavesublv)
     return cx->blk_sub.retop;
 }
 
-
-STATIC CV *
-S_get_db_sub(pTHX_ SV **svp, CV *cv)
-{
-    dVAR;
-    SV * const dbsv = GvSVn(PL_DBsub);
-
-    save_item(dbsv);
-    if (!PERLDB_SUB_NN) {
-       GV * const 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(*svp) == SVt_PVGV) && (GvCV((GV*)*svp) == cv) ))) {
-           /* Use GV from the stack as a fallback. */
-           /* GV is potentially non-unique, or contain different CV. */
-           SV * const tmp = newRV((SV*)cv);
-           sv_setsv(dbsv, tmp);
-           SvREFCNT_dec(tmp);
-       }
-       else {
-           gv_efullname3(dbsv, gv, NULL);
-       }
-    }
-    else {
-       const int type = SvTYPE(dbsv);
-       if (type < SVt_PVIV && type != SVt_IV)
-           sv_upgrade(dbsv, SVt_PVIV);
-       (void)SvIOK_on(dbsv);
-       SvIV_set(dbsv, PTR2IV(cv));     /* Do it the quickest way  */
-    }
-
-    if (CvISXSUB(cv))
-       PL_curcopdb = PL_curcop;
-    cv = GvCV(PL_DBsub);
-    return cv;
-}
-
 PP(pp_entersub)
 {
     dVAR; dSP; dPOPss;
@@ -2746,6 +2653,7 @@ PP(pp_entersub)
     default:
        if (!SvROK(sv)) {
            const char *sym;
+           STRLEN len;
            if (sv == &PL_sv_yes) {             /* unfound import, ignore */
                if (hasargs)
                    SP = PL_stack_base + POPMARK;
@@ -2755,16 +2663,22 @@ PP(pp_entersub)
                mg_get(sv);
                if (SvROK(sv))
                    goto got_rv;
-               sym = SvPOKp(sv) ? SvPVX_const(sv) : NULL;
+               if (SvPOKp(sv)) {
+                   sym = SvPVX_const(sv);
+                   len = SvCUR(sv);
+               } else {
+                   sym = NULL;
+                   len = 0;
+               }
            }
            else {
-               sym = SvPV_nolen_const(sv);
+               sym = SvPV_const(sv, len);
             }
            if (!sym)
                DIE(aTHX_ PL_no_usym, "a subroutine");
            if (PL_op->op_private & HINT_STRICT_REFS)
                DIE(aTHX_ PL_no_symref, sym, "a subroutine");
-           cv = get_cv(sym, TRUE);
+           cv = get_cvn_flags(sym, len, GV_ADD|SvUTF8(sv));
            break;
        }
   got_rv:
@@ -2813,7 +2727,7 @@ try_autoload:
            else {
                sub_name = sv_newmortal();
                gv_efullname3(sub_name, gv, NULL);
-               DIE(aTHX_ "Undefined subroutine &%"SVf" called", (void*)sub_name);
+               DIE(aTHX_ "Undefined subroutine &%"SVf" called", SVfARG(sub_name));
            }
        }
        if (!cv)
@@ -2823,10 +2737,11 @@ try_autoload:
 
     gimme = GIMME_V;
     if ((PL_op->op_private & OPpENTERSUB_DB) && GvCV(PL_DBsub) && !CvNODEBUG(cv)) {
-        if (CvASSERTION(cv) && PL_DBassertion)
-           sv_setiv(PL_DBassertion, 1);
-       
-       cv = get_db_sub(&sv, cv);
+        Perl_get_db_sub(aTHX_ &sv, cv);
+        if (CvISXSUB(cv))
+            PL_curcopdb = PL_curcop;
+        cv = GvCV(PL_DBsub);
+
        if (!cv || (!CvXSUB(cv) && !CvSTART(cv)))
            DIE(aTHX_ "No DB::sub routine defined");
     }
@@ -2897,7 +2812,7 @@ try_autoload:
            sub_crush_depth(cv);
 #if 0
        DEBUG_S(PerlIO_printf(Perl_debug_log,
-                             "%p entersub returning %p\n", thr, CvSTART(cv)));
+                             "%p entersub returning %p\n", (void*)thr, (void*)CvSTART(cv)));
 #endif
        RETURNOP(CvSTART(cv));
     }
@@ -2953,7 +2868,7 @@ Perl_sub_crush_depth(pTHX_ CV *cv)
        SV* const tmpstr = sv_newmortal();
        gv_efullname3(tmpstr, CvGV(cv), NULL);
        Perl_warner(aTHX_ packWARN(WARN_RECURSION), "Deep recursion on subroutine \"%"SVf"\"",
-                   (void*)tmpstr);
+                   SVfARG(tmpstr));
     }
 }
 
@@ -2971,7 +2886,7 @@ PP(pp_aelem)
     if (SvROK(elemsv) && !SvGAMAGIC(elemsv) && ckWARN(WARN_MISC))
        Perl_warner(aTHX_ packWARN(WARN_MISC),
                    "Use of reference \"%"SVf"\" as array index",
-                   (void*)elemsv);
+                   SVfARG(elemsv));
     if (elem > 0)
        elem -= CopARYBASE_get(PL_curcop);
     if (SvTYPE(av) != SVt_PVAV)
@@ -3123,12 +3038,12 @@ S_method_common(pTHX_ SV* meth, U32* hashp)
                                    : "on an undefined value");
            }
            /* assume it's a package name */
-           stash = gv_stashpvn(packname, packlen, FALSE);
+           stash = gv_stashpvn(packname, packlen, 0);
            if (!stash)
                packsv = sv;
             else {
                SV* const ref = newSViv(PTR2IV(stash));
-               hv_store(PL_stashcache, packname, packlen, ref, 0);
+               (void)hv_store(PL_stashcache, packname, packlen, ref, 0);
            }
            goto fetch;
        }
@@ -3142,6 +3057,7 @@ S_method_common(pTHX_ SV* meth, U32* hashp)
                     && SvOBJECT(ob))))
     {
        Perl_croak(aTHX_ "Can't call method \"%s\" on unblessed reference",
+                  (SvSCREAM(meth) && strEQ(name,"isa")) ? "DOES" :
                   name);
     }
 
@@ -3157,7 +3073,8 @@ S_method_common(pTHX_ SV* meth, U32* hashp)
        if (he) {
            gv = (GV*)HeVAL(he);
            if (isGV(gv) && GvCV(gv) &&
-               (!GvCVGEN(gv) || GvCVGEN(gv) == PL_sub_generation))
+               (!GvCVGEN(gv) || GvCVGEN(gv)
+                  == (PL_sub_generation + HvMROMETA(stash)->cache_gen)))
                return (SV*)GvCV(gv);
        }
     }
@@ -3184,16 +3101,24 @@ S_method_common(pTHX_ SV* meth, U32* hashp)
        }
        if (!sep || ((sep - name) == 5 && strnEQ(name, "SUPER", 5))) {
            /* the method name is unqualified or starts with SUPER:: */
+#ifndef USE_ITHREADS
+           if (sep)
+               stash = CopSTASH(PL_curcop);
+#else
            bool need_strlen = 1;
            if (sep) {
                packname = CopSTASHPV(PL_curcop);
            }
-           else if (stash) {
+           else
+#endif
+           if (stash) {
                HEK * const packhek = HvNAME_HEK(stash);
                if (packhek) {
                    packname = HEK_KEY(packhek);
                    packlen = HEK_LEN(packhek);
+#ifdef USE_ITHREADS
                    need_strlen = 0;
+#endif
                } else {
                    goto croak;
                }
@@ -3204,8 +3129,10 @@ S_method_common(pTHX_ SV* meth, U32* hashp)
                Perl_croak(aTHX_
                           "Can't use anonymous symbol table for method lookup");
            }
-           else if (need_strlen)
+#ifdef USE_ITHREADS
+           if (need_strlen)
                packlen = strlen(packname);
+#endif
 
        }
        else {
@@ -3215,7 +3142,7 @@ S_method_common(pTHX_ SV* meth, U32* hashp)
        }
        
        /* we're relying on gv_fetchmethod not autovivifying the stash */
-       if (gv_stashpvn(packname, packlen, FALSE)) {
+       if (gv_stashpvn(packname, packlen, 0)) {
            Perl_croak(aTHX_
                       "Can't locate object method \"%s\" via package \"%.*s\"",
                       leaf, (int)packlen, packname);