This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Eliminate SVt_RV, and use SVt_IV to store plain references.
[perl5.git] / pp.c
diff --git a/pp.c b/pp.c
index 253126d..08ebe5e 100644 (file)
--- a/pp.c
+++ b/pp.c
@@ -1,7 +1,7 @@
 /*    pp.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.
@@ -61,7 +61,8 @@ PP(pp_padav)
     dVAR; dSP; dTARGET;
     I32 gimme;
     if (PL_op->op_private & OPpLVAL_INTRO)
-       SAVECLEARSV(PAD_SVl(PL_op->op_targ));
+       if (!(PL_op->op_private & OPpPAD_STATE))
+           SAVECLEARSV(PAD_SVl(PL_op->op_targ));
     EXTEND(SP, 1);
     if (PL_op->op_flags & OPf_REF) {
        PUSHs(TARG);
@@ -104,7 +105,8 @@ PP(pp_padhv)
 
     XPUSHs(TARG);
     if (PL_op->op_private & OPpLVAL_INTRO)
-       SAVECLEARSV(PAD_SVl(PL_op->op_targ));
+       if (!(PL_op->op_private & OPpPAD_STATE))
+           SAVECLEARSV(PAD_SVl(PL_op->op_targ));
     if (PL_op->op_flags & OPf_REF)
        RETURN;
     else if (LVRET) {
@@ -170,8 +172,8 @@ PP(pp_rv2gv)
                        const char * const name = CopSTASHPV(PL_curcop);
                        gv = newGVgen(name);
                    }
-                   if (SvTYPE(sv) < SVt_RV)
-                       sv_upgrade(sv, SVt_RV);
+                   if (SvTYPE(sv) < SVt_PV && SvTYPE(sv) != SVt_IV)
+                       sv_upgrade(sv, SVt_IV);
                    else if (SvPVX_const(sv)) {
                        SvPV_free(sv);
                        SvLEN_set(sv, 0);
@@ -220,6 +222,50 @@ PP(pp_rv2gv)
     RETURN;
 }
 
+/* Helper function for pp_rv2sv and pp_rv2av  */
+GV *
+Perl_softref2xv(pTHX_ SV *const sv, const char *const what, const U32 type,
+               SV ***spp)
+{
+    dVAR;
+    GV *gv;
+
+    if (PL_op->op_private & HINT_STRICT_REFS) {
+       if (SvOK(sv))
+           Perl_die(aTHX_ PL_no_symref_sv, sv, what);
+       else
+           Perl_die(aTHX_ PL_no_usym, what);
+    }
+    if (!SvOK(sv)) {
+       if (PL_op->op_flags & OPf_REF)
+           Perl_die(aTHX_ PL_no_usym, what);
+       if (ckWARN(WARN_UNINITIALIZED))
+           report_uninit(sv);
+       if (type != SVt_PV && GIMME_V == G_ARRAY) {
+           (*spp)--;
+           return NULL;
+       }
+       **spp = &PL_sv_undef;
+       return NULL;
+    }
+    if ((PL_op->op_flags & OPf_SPECIAL) &&
+       !(PL_op->op_flags & OPf_MOD))
+       {
+           gv = gv_fetchsv(sv, 0, type);
+           if (!gv
+               && (!is_gv_magical_sv(sv,0)
+                   || !(gv = gv_fetchsv(sv, GV_ADD, type))))
+               {
+                   **spp = &PL_sv_undef;
+                   return NULL;
+               }
+       }
+    else {
+       gv = gv_fetchsv(sv, GV_ADD, type);
+    }
+    return gv;
+}
+
 PP(pp_rv2sv)
 {
     dVAR; dSP; dTOPss;
@@ -237,6 +283,7 @@ PP(pp_rv2sv)
        case SVt_PVFM:
        case SVt_PVIO:
            DIE(aTHX_ "Not a SCALAR reference");
+       default: NOOP;
        }
     }
     else {
@@ -248,33 +295,9 @@ PP(pp_rv2sv)
                if (SvROK(sv))
                    goto wasref;
            }
-           if (PL_op->op_private & HINT_STRICT_REFS) {
-               if (SvOK(sv))
-                   DIE(aTHX_ PL_no_symref_sv, sv, "a SCALAR");
-               else
-                   DIE(aTHX_ PL_no_usym, "a SCALAR");
-           }
-           if (!SvOK(sv)) {
-               if (PL_op->op_flags & OPf_REF)
-                   DIE(aTHX_ PL_no_usym, "a SCALAR");
-               if (ckWARN(WARN_UNINITIALIZED))
-                   report_uninit(sv);
-               RETSETUNDEF;
-           }
-           if ((PL_op->op_flags & OPf_SPECIAL) &&
-               !(PL_op->op_flags & OPf_MOD))
-           {
-               gv = (GV*)gv_fetchsv(sv, 0, SVt_PV);
-               if (!gv
-                   && (!is_gv_magical_sv(sv, 0)
-                       || !(gv = (GV*)gv_fetchsv(sv, GV_ADD, SVt_PV))))
-               {
-                   RETSETUNDEF;
-               }
-           }
-           else {
-               gv = (GV*)gv_fetchsv(sv, GV_ADD, SVt_PV);
-           }
+           gv = Perl_softref2xv(aTHX_ sv, "a SCALAR", SVt_PV, &sp);
+           if (!gv)
+               RETURN;
        }
        sv = GvSVn(gv);
     }
@@ -300,8 +323,7 @@ PP(pp_av2arylen)
     AV * const av = (AV*)TOPs;
     SV ** const sv = Perl_av_arylen_p(aTHX_ (AV*)av);
     if (!*sv) {
-       *sv = newSV(0);
-       sv_upgrade(*sv, SVt_PVMG);
+       *sv = newSV_type(SVt_PVMG);
        sv_magic(*sv, (SV*)av, PERL_MAGIC_arylen, NULL, 0);
     }
     SETs(*sv);
@@ -346,7 +368,7 @@ PP(pp_rv2cv)
 {
     dVAR; dSP;
     GV *gv;
-    HV *stash;
+    HV *stash_unused;
     const I32 flags = (PL_op->op_flags & OPf_SPECIAL)
        ? 0
        : ((PL_op->op_private & (OPpLVAL_INTRO|OPpMAY_RETURN_CONSTANT)) == OPpMAY_RETURN_CONSTANT)
@@ -355,7 +377,7 @@ PP(pp_rv2cv)
     /* We usually try to add a non-existent subroutine in case of AUTOLOAD. */
     /* (But not in defined().) */
 
-    CV *cv = sv_2cv(TOPs, &stash, &gv, flags);
+    CV *cv = sv_2cv(TOPs, &stash_unused, &gv, flags);
     if (cv) {
        if (CvCLONE(cv))
            cv = (CV*)sv_2mortal((SV*)cv_clone(cv));
@@ -384,18 +406,25 @@ PP(pp_prototype)
     SV *ret = &PL_sv_undef;
 
     if (SvPOK(TOPs) && SvCUR(TOPs) >= 7) {
-       const char * const s = SvPVX_const(TOPs);
+       const char * s = SvPVX_const(TOPs);
        if (strnEQ(s, "CORE::", 6)) {
-           const int code = keyword(s + 6, SvCUR(TOPs) - 6);
+           const int code = keyword(s + 6, SvCUR(TOPs) - 6, 1);
            if (code < 0) {     /* Overridable. */
 #define MAX_ARGS_OP ((sizeof(I32) - 1) * 2)
-               int i = 0, n = 0, seen_question = 0;
+               int i = 0, n = 0, seen_question = 0, defgv = 0;
                I32 oa;
                char str[ MAX_ARGS_OP * 2 + 2 ]; /* One ';', one '\0' */
 
                if (code == -KEY_chop || code == -KEY_chomp
                        || code == -KEY_exec || code == -KEY_system)
                    goto set;
+               if (code == -KEY_mkdir) {
+                   ret = sv_2mortal(newSVpvs("_;$"));
+                   goto set;
+               }
+               if (code == -KEY_readpipe) {
+                   s = "CORE::backtick";
+               }
                while (i < MAXO) {      /* The slow way. */
                    if (strEQ(s + 6, PL_op_name[i])
                        || strEQ(s + 6, PL_op_desc[i]))
@@ -406,9 +435,10 @@ PP(pp_prototype)
                }
                goto nonesuch;          /* Should not happen... */
              found:
+               defgv = PL_opargs[i] & OA_DEFGV;
                oa = PL_opargs[i] >> OASHIFT;
                while (oa) {
-                   if (oa & OA_OPTIONAL && !seen_question) {
+                   if (oa & OA_OPTIONAL && !seen_question && !defgv) {
                        seen_question = 1;
                        str[n++] = ';';
                    }
@@ -422,6 +452,8 @@ PP(pp_prototype)
                    str[n++] = ("?$@@%&*$")[oa & (OA_OPTIONAL - 1)];
                    oa = oa >> 4;
                }
+               if (defgv && str[n - 1] == '$')
+                   str[n - 1] = '_';
                str[n++] = '\0';
                ret = sv_2mortal(newSVpvn(str, n - 1));
            }
@@ -504,7 +536,7 @@ S_refto(pTHX_ SV *sv)
        SvREFCNT_inc_void_NN(sv);
     }
     rv = sv_newmortal();
-    sv_upgrade(rv, SVt_RV);
+    sv_upgrade(rv, SVt_IV);
     SvRV_set(rv, sv);
     SvROK_on(rv);
     return rv;
@@ -545,7 +577,7 @@ PP(pp_bless)
        if (len == 0 && ckWARN(WARN_MISC))
            Perl_warner(aTHX_ packWARN(WARN_MISC),
                   "Explicit blessing to '' (assuming package main)");
-       stash = gv_stashpvn(ptr, len, TRUE);
+       stash = gv_stashpvn(ptr, len, GV_ADD);
     }
 
     (void)sv_bless(TOPs, stash);
@@ -641,7 +673,7 @@ PP(pp_study)
     }
     s = (unsigned char*)(SvPV(sv, len));
     pos = len;
-    if (pos <= 0 || !SvPOK(sv)) {
+    if (pos <= 0 || !SvPOK(sv) || SvUTF8(sv)) {
        /* No point in studying a zero length string, and not safe to study
           anything that doesn't appear to be a simple scalar (and hence might
           change between now and when the regexp engine runs without our set
@@ -796,6 +828,15 @@ PP(pp_undef)
            SvSetMagicSV(sv, &PL_sv_undef);
        else {
            GP *gp;
+            HV *stash;
+
+            /* undef *Foo:: */
+            if((stash = GvHV((GV*)sv)) && HvNAME_get(stash))
+                mro_isa_changed_in(stash);
+            /* undef *Pkg::meth_name ... */
+            else if(GvCVu((GV*)sv) && (stash = GvSTASH((GV*)sv)) && HvNAME_get(stash))
+                mro_method_changed_in(stash);
+
            gp_free((GV*)sv);
            Newxz(gp, 1, GP);
            GvGP(sv) = gp_ref(gp);
@@ -880,28 +921,30 @@ PP(pp_postdec)
 
 PP(pp_pow)
 {
-    dVAR; dSP; dATARGET;
+    dVAR; dSP; dATARGET; SV *svl, *svr;
 #ifdef PERL_PRESERVE_IVUV
     bool is_int = 0;
 #endif
     tryAMAGICbin(pow,opASSIGN);
+    svl = sv_2num(TOPm1s);
+    svr = sv_2num(TOPs);
 #ifdef PERL_PRESERVE_IVUV
     /* For integer to integer power, we do the calculation by hand wherever
        we're sure it is safe; otherwise we call pow() and try to convert to
        integer afterwards. */
     {
-       SvIV_please(TOPs);
-       if (SvIOK(TOPs)) {
-           SvIV_please(TOPm1s);
-           if (SvIOK(TOPm1s)) {
+       SvIV_please(svr);
+       if (SvIOK(svr)) {
+           SvIV_please(svl);
+           if (SvIOK(svl)) {
                UV power;
                bool baseuok;
                UV baseuv;
 
-               if (SvUOK(TOPs)) {
-                   power = SvUVX(TOPs);
+               if (SvUOK(svr)) {
+                   power = SvUVX(svr);
                } else {
-                   const IV iv = SvIVX(TOPs);
+                   const IV iv = SvIVX(svr);
                    if (iv >= 0) {
                        power = iv;
                    } else {
@@ -909,11 +952,11 @@ PP(pp_pow)
                    }
                }
 
-               baseuok = SvUOK(TOPm1s);
+               baseuok = SvUOK(svl);
                if (baseuok) {
-                   baseuv = SvUVX(TOPm1s);
+                   baseuv = SvUVX(svl);
                } else {
-                   const IV iv = SvIVX(TOPm1s);
+                   const IV iv = SvIVX(svl);
                    if (iv >= 0) {
                        baseuv = iv;
                        baseuok = TRUE; /* effectively it's a UV now */
@@ -948,7 +991,7 @@ PP(pp_pow)
                    }
                     SP--;
                     SETn( result );
-                    SvIV_please(TOPs);
+                    SvIV_please(svr);
                     RETURN;
                } else {
                    register unsigned int highbit = 8 * sizeof(UV);
@@ -997,7 +1040,9 @@ PP(pp_pow)
   float_it:
 #endif    
     {
-       dPOPTOPnnrl;
+       NV right = SvNV(svr);
+       NV left  = SvNV(svl);
+       (void)POPs;
 
 #if defined(USE_LONG_DOUBLE) && defined(HAS_AIX_POWL_NEG_BASE_BUG)
     /*
@@ -1041,7 +1086,7 @@ PP(pp_pow)
 
 #ifdef PERL_PRESERVE_IVUV
        if (is_int)
-           SvIV_please(TOPs);
+           SvIV_please(svr);
 #endif
        RETURN;
     }
@@ -1049,18 +1094,21 @@ PP(pp_pow)
 
 PP(pp_multiply)
 {
-    dVAR; dSP; dATARGET; tryAMAGICbin(mult,opASSIGN);
+    dVAR; dSP; dATARGET; SV *svl, *svr;
+    tryAMAGICbin(mult,opASSIGN);
+    svl = sv_2num(TOPm1s);
+    svr = sv_2num(TOPs);
 #ifdef PERL_PRESERVE_IVUV
-    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.  */
        /* Left operand is defined, so is it IV? */
-       SvIV_please(TOPm1s);
-       if (SvIOK(TOPm1s)) {
-           bool auvok = SvUOK(TOPm1s);
-           bool buvok = SvUOK(TOPs);
+       SvIV_please(svl);
+       if (SvIOK(svl)) {
+           bool auvok = SvUOK(svl);
+           bool buvok = SvUOK(svr);
            const UV topmask = (~ (UV)0) << (4 * sizeof (UV));
            const UV botmask = ~((~ (UV)0) << (4 * sizeof (UV)));
            UV alow;
@@ -1069,9 +1117,9 @@ PP(pp_multiply)
            UV bhigh;
 
            if (auvok) {
-               alow = SvUVX(TOPm1s);
+               alow = SvUVX(svl);
            } else {
-               const IV aiv = SvIVX(TOPm1s);
+               const IV aiv = SvIVX(svl);
                if (aiv >= 0) {
                    alow = aiv;
                    auvok = TRUE; /* effectively it's a UV now */
@@ -1080,9 +1128,9 @@ PP(pp_multiply)
                }
            }
            if (buvok) {
-               blow = SvUVX(TOPs);
+               blow = SvUVX(svr);
            } else {
-               const IV biv = SvIVX(TOPs);
+               const IV biv = SvIVX(svr);
                if (biv >= 0) {
                    blow = biv;
                    buvok = TRUE; /* effectively it's a UV now */
@@ -1156,11 +1204,13 @@ PP(pp_multiply)
                    }
                } /* product_middle too large */
            } /* ahigh && bhigh */
-       } /* SvIOK(TOPm1s) */
-    } /* SvIOK(TOPs) */
+       } /* SvIOK(svl) */
+    } /* SvIOK(svr) */
 #endif
     {
-      dPOPTOPnnrl;
+      NV right = SvNV(svr);
+      NV left  = SvNV(svl);
+      (void)POPs;
       SETn( left * right );
       RETURN;
     }
@@ -1168,7 +1218,10 @@ PP(pp_multiply)
 
 PP(pp_divide)
 {
-    dVAR; dSP; dATARGET; tryAMAGICbin(div,opASSIGN);
+    dVAR; dSP; dATARGET; SV *svl, *svr;
+    tryAMAGICbin(div,opASSIGN);
+    svl = sv_2num(TOPm1s);
+    svr = sv_2num(TOPs);
     /* Only try to do UV divide first
        if ((SLOPPYDIVIDE is true) or
            (PERL_PRESERVE_IVUV is true and one or both SV is a UV too large
@@ -1191,20 +1244,20 @@ PP(pp_divide)
 #endif
 
 #ifdef PERL_TRY_UV_DIVIDE
-    SvIV_please(TOPs);
-    if (SvIOK(TOPs)) {
-        SvIV_please(TOPm1s);
-        if (SvIOK(TOPm1s)) {
-            bool left_non_neg = SvUOK(TOPm1s);
-            bool right_non_neg = SvUOK(TOPs);
+    SvIV_please(svr);
+    if (SvIOK(svr)) {
+        SvIV_please(svl);
+        if (SvIOK(svl)) {
+            bool left_non_neg = SvUOK(svl);
+            bool right_non_neg = SvUOK(svr);
             UV left;
             UV right;
 
             if (right_non_neg) {
-                right = SvUVX(TOPs);
+                right = SvUVX(svr);
             }
            else {
-               const IV biv = SvIVX(TOPs);
+               const IV biv = SvIVX(svr);
                 if (biv >= 0) {
                     right = biv;
                     right_non_neg = TRUE; /* effectively it's a UV now */
@@ -1222,10 +1275,10 @@ PP(pp_divide)
                 DIE(aTHX_ "Illegal division by zero");
 
             if (left_non_neg) {
-                left = SvUVX(TOPm1s);
+                left = SvUVX(svl);
             }
            else {
-               const IV aiv = SvIVX(TOPm1s);
+               const IV aiv = SvIVX(svl);
                 if (aiv >= 0) {
                     left = aiv;
                     left_non_neg = TRUE; /* effectively it's a UV now */
@@ -1273,8 +1326,14 @@ PP(pp_divide)
     } /* right wasn't SvIOK */
 #endif /* PERL_TRY_UV_DIVIDE */
     {
-       dPOPPOPnnrl;
+       NV right = SvNV(svr);
+       NV left  = SvNV(svl);
+       (void)POPs;(void)POPs;
+#if defined(NAN_COMPARE_BROKEN) && defined(Perl_isnan)
+       if (! Perl_isnan(right) && right == 0.0)
+#else
        if (right == 0.0)
+#endif
            DIE(aTHX_ "Illegal division by zero");
        PUSHn( left / right );
        RETURN;
@@ -1293,14 +1352,15 @@ PP(pp_modulo)
        bool dright_valid = FALSE;
        NV dright = 0.0;
        NV dleft  = 0.0;
-
-        SvIV_please(TOPs);
-        if (SvIOK(TOPs)) {
-            right_neg = !SvUOK(TOPs);
+        SV * svl;
+        SV * const svr = sv_2num(TOPs);
+        SvIV_please(svr);
+        if (SvIOK(svr)) {
+            right_neg = !SvUOK(svr);
             if (!right_neg) {
-                right = SvUVX(POPs);
+                right = SvUVX(svr);
             } else {
-               const IV biv = SvIVX(POPs);
+               const IV biv = SvIVX(svr);
                 if (biv >= 0) {
                     right = biv;
                     right_neg = FALSE; /* effectively it's a UV now */
@@ -1310,7 +1370,7 @@ PP(pp_modulo)
             }
         }
         else {
-           dright = POPn;
+           dright = SvNV(svr);
            right_neg = dright < 0;
            if (right_neg)
                dright = -dright;
@@ -1321,18 +1381,20 @@ PP(pp_modulo)
                 use_double = TRUE;
             }
        }
+       sp--;
 
         /* At this point use_double is only true if right is out of range for
            a UV.  In range NV has been rounded down to nearest UV and
            use_double false.  */
-        SvIV_please(TOPs);
-       if (!use_double && SvIOK(TOPs)) {
-            if (SvIOK(TOPs)) {
-                left_neg = !SvUOK(TOPs);
+        svl = sv_2num(TOPs);
+        SvIV_please(svl);
+       if (!use_double && SvIOK(svl)) {
+            if (SvIOK(svl)) {
+                left_neg = !SvUOK(svl);
                 if (!left_neg) {
-                    left = SvUVX(POPs);
+                    left = SvUVX(svl);
                 } else {
-                   const IV aiv = SvIVX(POPs);
+                   const IV aiv = SvIVX(svl);
                     if (aiv >= 0) {
                         left = aiv;
                         left_neg = FALSE; /* effectively it's a UV now */
@@ -1343,7 +1405,7 @@ PP(pp_modulo)
             }
         }
        else {
-           dleft = POPn;
+           dleft = SvNV(svl);
            left_neg = dleft < 0;
            if (left_neg)
                dleft = -dleft;
@@ -1371,6 +1433,7 @@ PP(pp_modulo)
                 }
             }
         }
+       sp--;
        if (use_double) {
            NV dans;
 
@@ -1439,7 +1502,7 @@ PP(pp_repeat)
              count = (IV)nv;
     }
     else
-        count = SvIVx(sv);
+        count = SvIV(sv);
     if (GIMME == G_ARRAY && PL_op->op_private & OPpREPEAT_DOLIST) {
        dMARK;
        static const char oom_list_extend[] = "Out of memory during list extend";
@@ -1505,7 +1568,7 @@ PP(pp_repeat)
                SvCUR_set(TARG, 0);
            else {
                const STRLEN max = (UV)count * len;
-               if (len > ((MEM_SIZE)~0)/count)
+               if (len > MEM_SIZE_MAX / count)
                     Perl_croak(aTHX_ oom_string_extend);
                MEM_WRAP_CHECK_1(max, char, oom_string_extend);
                SvGROW(TARG, max + 1);
@@ -1536,13 +1599,16 @@ PP(pp_repeat)
 
 PP(pp_subtract)
 {
-    dVAR; dSP; dATARGET; bool useleft; tryAMAGICbin(subtr,opASSIGN);
-    useleft = USE_LEFT(TOPm1s);
+    dVAR; dSP; dATARGET; bool useleft; SV *svl, *svr;
+    tryAMAGICbin(subtr,opASSIGN);
+    svl = sv_2num(TOPm1s);
+    svr = sv_2num(TOPs);
+    useleft = USE_LEFT(svl);
 #ifdef PERL_PRESERVE_IVUV
     /* See comments in pp_add (in pp_hot.c) about Overflow, and how
        "bad things" happen if you rely on signed integers wrapping.  */
-    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.  */
@@ -1556,12 +1622,12 @@ PP(pp_subtract)
            /* left operand is undef, treat as zero.  */
        } 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.  */
@@ -1576,12 +1642,12 @@ PP(pp_subtract)
            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;
@@ -1638,15 +1704,16 @@ PP(pp_subtract)
        }
     }
 #endif
-    useleft = USE_LEFT(TOPm1s);
     {
-       dPOPnv;
+       NV value = SvNV(svr);
+       (void)POPs;
+
        if (!useleft) {
            /* left operand is undef, treat as zero - value */
            SETn(-value);
            RETURN;
        }
-       SETn( TOPn - value );
+       SETn( SvNV(svl) - value );
        RETURN;
     }
 }
@@ -2328,7 +2395,7 @@ PP(pp_negate)
 {
     dVAR; dSP; dTARGET; tryAMAGICun(neg);
     {
-       dTOPss;
+       SV * const sv = sv_2num(TOPs);
        const int flags = SvFLAGS(sv);
        SvGETMAGIC(sv);
        if ((flags & SVf_IOK) || ((flags & (SVp_IOK | SVp_NOK)) == SVp_IOK)) {
@@ -2534,8 +2601,12 @@ PP(pp_i_divide)
     }
 }
 
+#if defined(__GLIBC__) && IVSIZE == 8
 STATIC
 PP(pp_i_modulo_0)
+#else
+PP(pp_i_modulo)
+#endif
 {
      /* This is the vanilla old i_modulo. */
      dVAR; dSP; dATARGET; tryAMAGICbin(modulo,opASSIGN);
@@ -2555,6 +2626,7 @@ PP(pp_i_modulo_0)
 #if defined(__GLIBC__) && IVSIZE == 8
 STATIC
 PP(pp_i_modulo_1)
+
 {
      /* This is the i_modulo with the workaround for the _moddi3 bug
       * in (at least) glibc 2.2.5 (the PERL_ABS() the workaround).
@@ -2572,7 +2644,6 @@ PP(pp_i_modulo_1)
          RETURN;
      }
 }
-#endif
 
 PP(pp_i_modulo)
 {
@@ -2592,7 +2663,6 @@ PP(pp_i_modulo)
           * opcode dispatch table if that is the case, remembering to
           * also apply the workaround so that this first round works
           * right, too.  See [perl #9402] for more information. */
-#if defined(__GLIBC__) && IVSIZE == 8
          {
               IV l =   3;
               IV r = -10;
@@ -2608,7 +2678,6 @@ PP(pp_i_modulo)
                    right = PERL_ABS(right);
               }
          }
-#endif
          /* avoid FPE_INTOVF on some platforms when left is IV_MIN */
          if (right == -1)
              SETi( 0 );
@@ -2617,6 +2686,7 @@ PP(pp_i_modulo)
          RETURN;
      }
 }
+#endif
 
 PP(pp_i_add)
 {
@@ -2826,22 +2896,24 @@ PP(pp_int)
 {
     dVAR; dSP; dTARGET; tryAMAGICun(int);
     {
-      const IV iv = TOPi; /* attempt to convert to IV if possible. */
+      SV * const sv = sv_2num(TOPs);
+      const IV iv = SvIV(sv);
       /* XXX it's arguable that compiler casting to IV might be subtly
         different from modf (for numbers inside (IV_MIN,UV_MAX)) in which
         else preferring IV has introduced a subtle behaviour change bug. OTOH
         relying on floating point to be accurate is a bug.  */
 
-      if (!SvOK(TOPs))
+      if (!SvOK(sv)) {
         SETu(0);
-      else if (SvIOK(TOPs)) {
-       if (SvIsUV(TOPs)) {
-           const UV uv = TOPu;
-           SETu(uv);
-       else
+      }
+      else if (SvIOK(sv)) {
+       if (SvIsUV(sv))
+           SETu(SvUV(sv));
+       else
            SETi(iv);
-      } else {
-         const NV value = TOPn;
+      }
+      else {
+         const NV value = SvNV(sv);
          if (value >= 0.0) {
              if (value < (NV)UV_MAX + 0.5) {
                  SETu(U_V(value));
@@ -2865,15 +2937,17 @@ PP(pp_abs)
 {
     dVAR; dSP; dTARGET; tryAMAGICun(abs);
     {
+      SV * const sv = sv_2num(TOPs);
       /* This will cache the NV value if string isn't actually integer  */
-      const IV iv = TOPi;
+      const IV iv = SvIV(sv);
 
-      if (!SvOK(TOPs))
+      if (!SvOK(sv)) {
         SETu(0);
-      else if (SvIOK(TOPs)) {
+      }
+      else if (SvIOK(sv)) {
        /* IVX is precise  */
-       if (SvIsUV(TOPs)) {
-         SETu(TOPu);   /* force it to be numeric only */
+       if (SvIsUV(sv)) {
+         SETu(SvUV(sv));       /* force it to be numeric only */
        } else {
          if (iv >= 0) {
            SETi(iv);
@@ -2888,7 +2962,7 @@ PP(pp_abs)
          }
        }
       } else{
-       const NV value = TOPn;
+       const NV value = SvNV(sv);
        if (value < 0.0)
          SETn(-value);
        else
@@ -3124,8 +3198,6 @@ PP(pp_substr)
                sv_upgrade(TARG, SVt_PVLV);
                sv_magic(TARG, NULL, PERL_MAGIC_substr, NULL, 0);
            }
-           else
-               SvOK_off(TARG);
 
            LvTYPE(TARG) = 'x';
            if (LvTARG(TARG) != sv) {
@@ -3207,7 +3279,7 @@ PP(pp_index)
        if (little_utf8 && !PL_encoding) {
            /* Well, maybe instead we might be able to downgrade the small
               string?  */
-           char * const pv = (char*)bytes_from_utf8(little_p, &llen,
+           char * const pv = (char*)bytes_from_utf8((U8 *)little_p, &llen,
                                                     &little_utf8);
            if (little_utf8) {
                /* If the large string is ISO-8859-1, and it's not possible to
@@ -3299,6 +3371,8 @@ PP(pp_index)
 PP(pp_sprintf)
 {
     dVAR; dSP; dMARK; dORIGMARK; dTARGET;
+    if (SvTAINTED(MARK[1]))
+       TAINT_PROPER("sprintf");
     do_sprintf(TARG, SP-MARK, MARK+1);
     TAINT_IF(SvTAINTED(TARG));
     SP = ORIGMARK;
@@ -3309,20 +3383,20 @@ PP(pp_sprintf)
 PP(pp_ord)
 {
     dVAR; dSP; dTARGET;
+
     SV *argsv = POPs;
     STRLEN len;
     const U8 *s = (U8*)SvPV_const(argsv, len);
-    SV *tmpsv;
 
     if (PL_encoding && SvPOK(argsv) && !DO_UTF8(argsv)) {
-        tmpsv = sv_2mortal(newSVsv(argsv));
+        SV * const tmpsv = sv_2mortal(newSVsv(argsv));
         s = (U8*)sv_recode_to_utf8(tmpsv, PL_encoding);
         argsv = tmpsv;
     }
 
     XPUSHu(DO_UTF8(argsv) ?
           utf8n_to_uvchr(s, UTF8_MAXBYTES, 0, UTF8_ALLOW_ANYUV) :
-          (*s & 0xff));
+          (UV)(*s & 0xff));
 
     RETURN;
 }
@@ -3365,20 +3439,21 @@ PP(pp_chr)
     *tmps++ = (char)value;
     *tmps = '\0';
     (void)SvPOK_only(TARG);
+
     if (PL_encoding && !IN_BYTES) {
         sv_recode_to_utf8(TARG, PL_encoding);
        tmps = SvPVX(TARG);
        if (SvCUR(TARG) == 0 || !is_utf8_string((U8*)tmps, SvCUR(TARG)) ||
-           memEQ(tmps, "\xef\xbf\xbd\0", 4)) {
-           SvGROW(TARG, 3);
+           UNICODE_IS_REPLACEMENT(utf8_to_uvchr((U8*)tmps, NULL))) {
+           SvGROW(TARG, 2);
            tmps = SvPVX(TARG);
-           SvCUR_set(TARG, 2);
-           *tmps++ = (U8)UTF8_EIGHT_BIT_HI(value);
-           *tmps++ = (U8)UTF8_EIGHT_BIT_LO(value);
+           SvCUR_set(TARG, 1);
+           *tmps++ = (char)value;
            *tmps = '\0';
-           SvUTF8_on(TARG);
+           SvUTF8_off(TARG);
        }
     }
+
     XPUSHs(TARG);
     RETURN;
 }
@@ -3453,7 +3528,7 @@ PP(pp_ucfirst)
     if (SvOK(source)) {
        s = (const U8*)SvPV_nomg_const(source, slen);
     } else {
-       s = "";
+       s = (const U8*)"";
        slen = 0;
     }
 
@@ -3466,14 +3541,14 @@ PP(pp_ucfirst)
            toLOWER_utf8(s, tmpbuf, &tculen);
        }
        /* If the two differ, we definately cannot do inplace.  */
-       inplace = ulen == tculen;
+       inplace = (ulen == tculen);
        need = slen + 1 - ulen + tculen;
     } else {
        doing_utf8 = FALSE;
        need = slen + 1;
     }
 
-    if (SvPADTMP(source) && !SvREADONLY(source) && inplace) {
+    if (SvPADTMP(source) && !SvREADONLY(source) && inplace && SvTEMP(source)) {
        /* We can convert in place.  */
 
        dest = source;
@@ -3484,7 +3559,7 @@ PP(pp_ucfirst)
        dest = TARG;
 
        SvUPGRADE(dest, SVt_PV);
-       d = SvGROW(dest, need);
+       d = (U8*)SvGROW(dest, need);
        (void)SvPOK_only(dest);
 
        SETs(dest);
@@ -3556,7 +3631,7 @@ PP(pp_uc)
     SvGETMAGIC(source);
 
     if (SvPADTMP(source) && !SvREADONLY(source) && !SvAMAGIC(source)
-       && !DO_UTF8(source)) {
+       && SvTEMP(source) && !DO_UTF8(source)) {
        /* We can convert in place.  */
 
        dest = source;
@@ -3577,13 +3652,13 @@ PP(pp_uc)
        if (SvOK(source)) {
            s = (const U8*)SvPV_nomg_const(source, len);
        } else {
-           s = "";
+           s = (const U8*)"";
            len = 0;
        }
        min = len + 1;
 
        SvUPGRADE(dest, SVt_PV);
-       d = SvGROW(dest, min);
+       d = (U8*)SvGROW(dest, min);
        (void)SvPOK_only(dest);
 
        SETs(dest);
@@ -3656,7 +3731,7 @@ PP(pp_lc)
     SvGETMAGIC(source);
 
     if (SvPADTMP(source) && !SvREADONLY(source) && !SvAMAGIC(source)
-       && !DO_UTF8(source)) {
+       && SvTEMP(source) && !DO_UTF8(source)) {
        /* We can convert in place.  */
 
        dest = source;
@@ -3677,13 +3752,13 @@ PP(pp_lc)
        if (SvOK(source)) {
            s = (const U8*)SvPV_nomg_const(source, len);
        } else {
-           s = "";
+           s = (const U8*)"";
            len = 0;
        }
        min = len + 1;
 
        SvUPGRADE(dest, SVt_PV);
-       d = SvGROW(dest, min);
+       d = (U8*)SvGROW(dest, min);
        (void)SvPOK_only(dest);
 
        SETs(dest);
@@ -3823,7 +3898,7 @@ PP(pp_aslice)
            register SV **svp;
            I32 max = -1;
            for (svp = MARK + 1; svp <= SP; svp++) {
-               const I32 elem = SvIVx(*svp);
+               const I32 elem = SvIV(*svp);
                if (elem > max)
                    max = elem;
            }
@@ -3832,7 +3907,7 @@ PP(pp_aslice)
        }
        while (++MARK <= SP) {
            register SV **svp;
-           I32 elem = SvIVx(*MARK);
+           I32 elem = SvIV(*MARK);
 
            if (elem > 0)
                elem -= arybase;
@@ -3854,13 +3929,74 @@ PP(pp_aslice)
     RETURN;
 }
 
+PP(pp_aeach)
+{
+    dVAR;
+    dSP;
+    AV *array = (AV*)POPs;
+    const I32 gimme = GIMME_V;
+    I32 *iterp = Perl_av_iter_p(aTHX_ array);
+    const IV current = (*iterp)++;
+
+    if (current > av_len(array)) {
+       *iterp = 0;
+       if (gimme == G_SCALAR)
+           RETPUSHUNDEF;
+       else
+           RETURN;
+    }
+
+    EXTEND(SP, 2);
+    mPUSHi(CopARYBASE_get(PL_curcop) + current);
+    if (gimme == G_ARRAY) {
+       SV **const element = av_fetch(array, current, 0);
+        PUSHs(element ? *element : &PL_sv_undef);
+    }
+    RETURN;
+}
+
+PP(pp_akeys)
+{
+    dVAR;
+    dSP;
+    AV *array = (AV*)POPs;
+    const I32 gimme = GIMME_V;
+
+    *Perl_av_iter_p(aTHX_ array) = 0;
+
+    if (gimme == G_SCALAR) {
+       dTARGET;
+       PUSHi(av_len(array) + 1);
+    }
+    else if (gimme == G_ARRAY) {
+        IV n = Perl_av_len(aTHX_ array);
+        IV i = CopARYBASE_get(PL_curcop);
+
+        EXTEND(SP, n + 1);
+
+       if (PL_op->op_type == OP_AKEYS) {
+           n += i;
+           for (;  i <= n;  i++) {
+               mPUSHi(i);
+           }
+       }
+       else {
+           for (i = 0;  i <= n;  i++) {
+               SV *const *const elem = Perl_av_fetch(aTHX_ array, i, 0);
+               PUSHs(elem ? *elem : &PL_sv_undef);
+           }
+       }
+    }
+    RETURN;
+}
+
 /* Associative arrays. */
 
 PP(pp_each)
 {
     dVAR;
     dSP;
-    HV * const hash = (HV*)POPs;
+    HV * hash = (HV*)POPs;
     HE *entry;
     const I32 gimme = GIMME_V;
 
@@ -4017,11 +4153,11 @@ PP(pp_hslice)
         }
 
         he = hv_fetch_ent(hv, keysv, lval, 0);
-        svp = he ? &HeVAL(he) : 0;
+        svp = he ? &HeVAL(he) : NULL;
 
         if (lval) {
             if (!svp || *svp == &PL_sv_undef) {
-                DIE(aTHX_ PL_no_helem_sv, keysv);
+                DIE(aTHX_ PL_no_helem_sv, SVfARG(keysv));
             }
             if (localizing) {
                if (HvNAME_get(hv) && isGV(*svp))
@@ -4033,7 +4169,7 @@ PP(pp_hslice)
                        STRLEN keylen;
                        const char * const key = SvPV_const(keysv, keylen);
                        SAVEDELETE(hv, savepvn(key,keylen),
-                                  SvUTF8(keysv) ? -keylen : keylen);
+                                  SvUTF8(keysv) ? -(I32)keylen : (I32)keylen);
                    }
                }
             }
@@ -4072,13 +4208,13 @@ PP(pp_lslice)
     SV ** const firstlelem = PL_stack_base + POPMARK + 1;
     register SV ** const firstrelem = lastlelem + 1;
     const I32 arybase = CopARYBASE_get(PL_curcop);
-    I32 is_something_there = PL_op->op_flags & OPf_MOD;
+    I32 is_something_there = FALSE;
 
     register const I32 max = lastrelem - lastlelem;
     register SV **lelem;
 
     if (GIMME != G_ARRAY) {
-       I32 ix = SvIVx(*lastlelem);
+       I32 ix = SvIV(*lastlelem);
        if (ix < 0)
            ix += max;
        else
@@ -4097,7 +4233,7 @@ PP(pp_lslice)
     }
 
     for (lelem = firstlelem; lelem <= lastlelem; lelem++) {
-       I32 ix = SvIVx(*lelem);
+       I32 ix = SvIV(*lelem);
        if (ix < 0)
            ix += max;
        else
@@ -4121,16 +4257,17 @@ PP(pp_anonlist)
 {
     dVAR; dSP; dMARK; dORIGMARK;
     const I32 items = SP - MARK;
-    SV * const av = sv_2mortal((SV*)av_make(items, MARK+1));
+    SV * const av = (SV *) av_make(items, MARK+1);
     SP = ORIGMARK;             /* av_make() might realloc stack_sp */
-    XPUSHs(av);
+    XPUSHs(sv_2mortal((PL_op->op_flags & OPf_SPECIAL)
+                     ? newRV_noinc(av) : av));
     RETURN;
 }
 
 PP(pp_anonhash)
 {
     dVAR; dSP; dMARK; dORIGMARK;
-    HV* const hv = (HV*)sv_2mortal((SV*)newHV());
+    HV* const hv = newHV();
 
     while (MARK < SP) {
        SV * const key = *++MARK;
@@ -4142,7 +4279,8 @@ PP(pp_anonhash)
        (void)hv_store_ent(hv,key,val,0);
     }
     SP = ORIGMARK;
-    XPUSHs((SV*)hv);
+    XPUSHs(sv_2mortal((PL_op->op_flags & OPf_SPECIAL)
+                     ? newRV_noinc((SV*) hv) : (SV*)hv));
     RETURN;
 }
 
@@ -4174,7 +4312,7 @@ PP(pp_splice)
     SP++;
 
     if (++MARK < SP) {
-       offset = i = SvIVx(*MARK);
+       offset = i = SvIV(*MARK);
        if (offset < 0)
            offset += AvFILLp(ary) + 1;
        else
@@ -4262,7 +4400,7 @@ PP(pp_splice)
                    *dst-- = *src--;
            }
            dst = AvARRAY(ary);
-           SvPV_set(ary, (char*)(AvARRAY(ary) - diff)); /* diff is negative */
+           AvARRAY(ary) = AvARRAY(ary) - diff; /* diff is negative */
            AvMAX(ary) += diff;
        }
        else {
@@ -4298,7 +4436,7 @@ PP(pp_splice)
                    dst = src - diff;
                    Move(src, dst, offset, SV*);
                }
-               SvPV_set(ary, (char*)(AvARRAY(ary) - diff));/* diff is positive */
+               AvARRAY(ary) = AvARRAY(ary) - diff;/* diff is positive */
                AvMAX(ary) += diff;
                AvFILLp(ary) += diff;
            }
@@ -4354,7 +4492,7 @@ PP(pp_splice)
 PP(pp_push)
 {
     dVAR; dSP; dMARK; dORIGMARK; dTARGET;
-    register AV *ary = (AV*)*++MARK;
+    register AV * const ary = (AV*)*++MARK;
     const MAGIC * const mg = SvTIED_mg((SV*)ary, PERL_MAGIC_tied);
 
     if (mg) {
@@ -4369,12 +4507,17 @@ PP(pp_push)
        PUSHi( AvFILL(ary) + 1 );
     }
     else {
+       PL_delaymagic = DM_DELAY;
        for (++MARK; MARK <= SP; MARK++) {
            SV * const sv = newSV(0);
            if (*MARK)
                sv_setsv(sv, *MARK);
            av_store(ary, AvFILLp(ary)+1, sv);
        }
+       if (PL_delaymagic & DM_ARRAY)
+           mg_set((SV*)ary);
+
+       PL_delaymagic = 0;
        SP = ORIGMARK;
        PUSHi( AvFILLp(ary) + 1 );
     }
@@ -4532,18 +4675,20 @@ PP(pp_split)
        DIE(aTHX_ "panic: pp_split");
     rx = PM_GETRE(pm);
 
-    TAINT_IF((pm->op_pmflags & PMf_LOCALE) &&
-            (pm->op_pmflags & (PMf_WHITE | PMf_SKIPWHITE)));
+    TAINT_IF((rx->extflags & RXf_PMf_LOCALE) &&
+            (rx->extflags & (RXf_WHITE | RXf_SKIPWHITE)));
 
     RX_MATCH_UTF8_set(rx, do_utf8);
 
-    if (pm->op_pmreplroot) {
 #ifdef USE_ITHREADS
-       ary = GvAVn((GV*)PAD_SVl(INT2PTR(PADOFFSET, pm->op_pmreplroot)));
+    if (pm->op_pmreplrootu.op_pmtargetoff) {
+       ary = GvAVn((GV*)PAD_SVl(pm->op_pmreplrootu.op_pmtargetoff));
+    }
 #else
-       ary = GvAVn((GV*)pm->op_pmreplroot);
-#endif
+    if (pm->op_pmreplrootu.op_pmtargetgv) {
+       ary = GvAVn(pm->op_pmreplrootu.op_pmtargetgv);
     }
+#endif
     else if (gimme != G_ARRAY)
        ary = GvAVn(PL_defgv);
     else
@@ -4573,8 +4718,12 @@ PP(pp_split)
     }
     base = SP - PL_stack_base;
     orig = s;
-    if (pm->op_pmflags & PMf_SKIPWHITE) {
-       if (pm->op_pmflags & PMf_LOCALE) {
+    if (rx->extflags & RXf_SKIPWHITE) {
+       if (do_utf8) {
+           while (*s == ' ' || is_utf8_space((U8*)s))
+               s += UTF8SKIP(s);
+       }
+       else if (rx->extflags & RXf_PMf_LOCALE) {
            while (isSPACE_LC(*s))
                s++;
        }
@@ -4583,19 +4732,32 @@ PP(pp_split)
                s++;
        }
     }
-    if (pm->op_pmflags & PMf_MULTILINE) {
+    if (rx->extflags & PMf_MULTILINE) {
        multiline = 1;
     }
 
     if (!limit)
        limit = maxiters + 2;
-    if (pm->op_pmflags & PMf_WHITE) {
+    if (rx->extflags & RXf_WHITE) {
        while (--limit) {
            m = s;
-           while (m < strend &&
-                  !((pm->op_pmflags & PMf_LOCALE)
-                    ? isSPACE_LC(*m) : isSPACE(*m)))
-               ++m;
+           /* this one uses 'm' and is a negative test */
+           if (do_utf8) {
+               while (m < strend && !( *m == ' ' || is_utf8_space((U8*)m) )) {
+                   const int t = UTF8SKIP(m);
+                   /* is_utf8_space returns FALSE for malform utf8 */
+                   if (strend - m < t)
+                       m = strend;
+                   else
+                       m += t;
+               }
+            } else if (rx->extflags & RXf_PMf_LOCALE) {
+               while (m < strend && !isSPACE_LC(*m))
+                   ++m;
+            } else {
+                while (m < strend && !isSPACE(*m))
+                    ++m;
+            }  
            if (m >= strend)
                break;
 
@@ -4606,14 +4768,26 @@ PP(pp_split)
                (void)SvUTF8_on(dstr);
            XPUSHs(dstr);
 
-           s = m + 1;
-           while (s < strend &&
-                  ((pm->op_pmflags & PMf_LOCALE)
-                   ? isSPACE_LC(*s) : isSPACE(*s)))
-               ++s;
+           /* skip the whitespace found last */
+           if (do_utf8)
+               s = m + UTF8SKIP(m);
+           else
+               s = m + 1;
+
+           /* this one uses 's' and is a positive test */
+           if (do_utf8) {
+               while (s < strend && ( *s == ' ' || is_utf8_space((U8*)s) ))
+                   s +=  UTF8SKIP(s);
+            } else if (rx->extflags & RXf_PMf_LOCALE) {
+               while (s < strend && isSPACE_LC(*s))
+                   ++s;
+            } else {
+                while (s < strend && isSPACE(*s))
+                    ++s;
+            }      
        }
     }
-    else if (rx->precomp[0] == '^' && rx->precomp[1] == '\0') {
+    else if (rx->extflags & RXf_START_ONLY) {
        while (--limit) {
            for (m = s; m < strend && *m != '\n'; m++)
                ;
@@ -4629,15 +4803,62 @@ PP(pp_split)
            s = m;
        }
     }
-    else if (do_utf8 == ((rx->reganch & ROPT_UTF8) != 0) &&
-            (rx->reganch & RE_USE_INTUIT) && !rx->nparens
-            && (rx->reganch & ROPT_CHECK_ALL)
-            && !(rx->reganch & ROPT_ANCH)) {
-       const int tail = (rx->reganch & RE_INTUIT_TAIL);
-       SV * const csv = CALLREG_INTUIT_STRING(aTHX_ rx);
+    else if (rx->extflags & RXf_NULL && !(s >= strend)) {
+        /*
+          Pre-extend the stack, either the number of bytes or
+          characters in the string or a limited amount, triggered by:
+
+          my ($x, $y) = split //, $str;
+            or
+          split //, $str, $i;
+        */
+        const U32 items = limit - 1; 
+        if (items < slen)
+            EXTEND(SP, items);
+        else
+            EXTEND(SP, slen);
+
+        if (do_utf8) {
+            while (--limit) {
+                /* keep track of how many bytes we skip over */
+                m = s;
+                s += UTF8SKIP(s);
+                dstr = newSVpvn(m, s-m);
+
+                if (make_mortal)
+                    sv_2mortal(dstr);
+
+                (void)SvUTF8_on(dstr);
+                PUSHs(dstr);
+
+                if (s >= strend)
+                    break;
+            }
+        } else {
+            while (--limit) {
+                dstr = newSVpvn(s, 1);
+
+                s++;
 
-       len = rx->minlen;
-       if (len == 1 && !(rx->reganch & ROPT_UTF8) && !tail) {
+                if (make_mortal)
+                    sv_2mortal(dstr);
+
+                PUSHs(dstr);
+
+                if (s >= strend)
+                    break;
+            }
+        }
+    }
+    else if (do_utf8 == ((rx->extflags & RXf_UTF8) != 0) &&
+            (rx->extflags & RXf_USE_INTUIT) && !rx->nparens
+            && (rx->extflags & RXf_CHECK_ALL)
+            && !(rx->extflags & RXf_ANCH)) {
+       const int tail = (rx->extflags & RXf_INTUIT_TAIL);
+       SV * const csv = CALLREG_INTUIT_STRING(rx);
+
+       len = rx->minlenret;
+       if (len == 1 && !(rx->extflags & RXf_UTF8) && !tail) {
            const char c = *SvPV_nolen_const(csv);
            while (--limit) {
                for (m = s; m < strend && *m != c; m++)
@@ -4684,7 +4905,7 @@ PP(pp_split)
        {
            I32 rex_return;
            PUTBACK;
-           rex_return = CALLREGEXEC(aTHX_ rx, (char*)s, (char*)strend, (char*)orig, 1 ,
+           rex_return = CALLREGEXEC(rx, (char*)s, (char*)strend, (char*)orig, 1 ,
                            sv, NULL, 0);
            SPAGAIN;
            if (rex_return == 0)
@@ -4697,7 +4918,7 @@ PP(pp_split)
                s = orig + (m - s);
                strend = s + (strend - m);
            }
-           m = rx->startp[0] + orig;
+           m = rx->offs[0].start + orig;
            dstr = newSVpvn(s, m-s);
            if (make_mortal)
                sv_2mortal(dstr);
@@ -4707,8 +4928,8 @@ PP(pp_split)
            if (rx->nparens) {
                I32 i;
                for (i = 1; i <= (I32)rx->nparens; i++) {
-                   s = rx->startp[i] + orig;
-                   m = rx->endp[i] + orig;
+                   s = rx->offs[i].start + orig;
+                   m = rx->offs[i].end + orig;
 
                    /* japhy (07/27/01) -- the (m && s) test doesn't catch
                       parens that didn't match -- they should be set to
@@ -4725,7 +4946,7 @@ PP(pp_split)
                    XPUSHs(dstr);
                }
            }
-           s = rx->endp[0] + orig;
+           s = rx->offs[0].end + orig;
        }
     }
 
@@ -4798,6 +5019,19 @@ PP(pp_split)
     RETURN;
 }
 
+PP(pp_once)
+{
+    dSP;
+    SV *const sv = PAD_SVl(PL_op->op_targ);
+
+    if (SvPADSTALE(sv)) {
+       /* First time. */
+       SvPADSTALE_off(sv);
+       RETURNOP(cLOGOP->op_other);
+    }
+    RETURNOP(cLOGOP->op_next);
+}
+
 PP(pp_lock)
 {
     dVAR;