Fix for [perl #37886] strict 'refs' doesn't apply inside defined
[p5sagit/p5-mst-13.2.git] / pp.c
diff --git a/pp.c b/pp.c
index 150dadd..eeb82c0 100644 (file)
--- a/pp.c
+++ b/pp.c
@@ -53,11 +53,6 @@ PP(pp_stub)
     RETURN;
 }
 
-PP(pp_scalar)
-{
-    return NORMAL;
-}
-
 /* Pushy stuff. */
 
 PP(pp_padav)
@@ -83,7 +78,7 @@ PP(pp_padav)
        if (SvMAGICAL(TARG)) {
            U32 i;
            for (i=0; i < (U32)maxarg; i++) {
-               SV ** const svp = av_fetch((AV*)TARG, i, FALSE);
+               SV * const * const svp = av_fetch((AV*)TARG, i, FALSE);
                SP[i+1] = (svp) ? *svp : &PL_sv_undef;
            }
        }
@@ -127,11 +122,6 @@ PP(pp_padhv)
     RETURN;
 }
 
-PP(pp_padany)
-{
-    DIE(aTHX_ "NOT IMPL LINE %d",__LINE__);
-}
-
 /* Translations. */
 
 PP(pp_rv2gv)
@@ -170,13 +160,13 @@ PP(pp_rv2gv)
                    GV *gv;
                    if (cUNOP->op_targ) {
                        STRLEN len;
-                       SV *namesv = PAD_SV(cUNOP->op_targ);
-                       const char *name = SvPV(namesv, len);
+                       SV * const namesv = PAD_SV(cUNOP->op_targ);
+                       const char * const name = SvPV(namesv, len);
                        gv = (GV*)NEWSV(0,0);
                        gv_init(gv, CopSTASH(PL_curcop), name, len, 0);
                    }
                    else {
-                       const char *name = CopSTASHPV(PL_curcop);
+                       const char * const name = CopSTASHPV(PL_curcop);
                        gv = newGVgen(name);
                    }
                    if (SvTYPE(sv) < SVt_RV)
@@ -248,9 +238,14 @@ 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 ||
-                   PL_op->op_private & HINT_STRICT_REFS)
+               if (PL_op->op_flags & OPf_REF)
                    DIE(aTHX_ PL_no_usym, "a SCALAR");
                if (ckWARN(WARN_UNINITIALIZED))
                    report_uninit(sv);
@@ -268,8 +263,6 @@ PP(pp_rv2sv)
                }
            }
            else {
-               if (PL_op->op_private & HINT_STRICT_REFS)
-                   DIE(aTHX_ PL_no_symref_sv, sv, "a SCALAR");
                gv = (GV*)gv_fetchsv(sv, TRUE, SVt_PV);
            }
        }
@@ -374,7 +367,7 @@ PP(pp_prototype)
 
     ret = &PL_sv_undef;
     if (SvPOK(TOPs) && SvCUR(TOPs) >= 7) {
-       const char *s = SvPVX_const(TOPs);
+       const char * const s = SvPVX_const(TOPs);
        if (strnEQ(s, "CORE::", 6)) {
            const int code = keyword(s + 6, SvCUR(TOPs) - 6);
            if (code < 0) {     /* Overridable. */
@@ -505,8 +498,8 @@ PP(pp_ref)
     const char *pv;
     SV * const sv = POPs;
 
-    if (sv && SvGMAGICAL(sv))
-       mg_get(sv);
+    if (sv)
+       SvGETMAGIC(sv);
 
     if (!sv || !SvROK(sv))
        RETPUSHNO;
@@ -531,7 +524,7 @@ PP(pp_bless)
        if (ssv && !SvGMAGICAL(ssv) && !SvAMAGIC(ssv) && SvROK(ssv))
            Perl_croak(aTHX_ "Attempt to bless into a reference");
        ptr = SvPV_const(ssv,len);
-       if (ckWARN(WARN_MISC) && len == 0)
+       if (len == 0 && ckWARN(WARN_MISC))
            Perl_warner(aTHX_ packWARN(WARN_MISC),
                   "Explicit blessing to '' (assuming package main)");
        stash = gv_stashpvn(ptr, len, TRUE);
@@ -642,8 +635,8 @@ PP(pp_study)
     if (pos > PL_maxscream) {
        if (PL_maxscream < 0) {
            PL_maxscream = pos + 80;
-           New(301, PL_screamfirst, 256, I32);
-           New(302, PL_screamnext, PL_maxscream, I32);
+           Newx(PL_screamfirst, 256, I32);
+           Newx(PL_screamnext, PL_maxscream, I32);
        }
        else {
            PL_maxscream = pos + pos / 4;
@@ -710,7 +703,7 @@ PP(pp_chop)
     while (MARK < SP)
        do_chop(TARG, *++MARK);
     SP = ORIGMARK;
-    PUSHTARG;
+    XPUSHTARG;
     RETURN;
 }
 
@@ -728,41 +721,10 @@ PP(pp_chomp)
 
     while (SP > MARK)
        count += do_chomp(POPs);
-    PUSHi(count);
+    XPUSHi(count);
     RETURN;
 }
 
-PP(pp_defined)
-{
-    dSP;
-    register SV* const sv = POPs;
-
-    if (!sv || !SvANY(sv))
-       RETPUSHNO;
-    switch (SvTYPE(sv)) {
-    case SVt_PVAV:
-       if (AvMAX(sv) >= 0 || SvGMAGICAL(sv)
-               || (SvRMAGICAL(sv) && mg_find(sv, PERL_MAGIC_tied)))
-           RETPUSHYES;
-       break;
-    case SVt_PVHV:
-       if (HvARRAY(sv) || SvGMAGICAL(sv)
-               || (SvRMAGICAL(sv) && mg_find(sv, PERL_MAGIC_tied)))
-           RETPUSHYES;
-       break;
-    case SVt_PVCV:
-       if (CvROOT(sv) || CvXSUB(sv))
-           RETPUSHYES;
-       break;
-    default:
-       if (SvGMAGICAL(sv))
-           mg_get(sv);
-       if (SvOK(sv))
-           RETPUSHYES;
-    }
-    RETPUSHNO;
-}
-
 PP(pp_undef)
 {
     dSP;
@@ -789,14 +751,14 @@ PP(pp_undef)
        hv_undef((HV*)sv);
        break;
     case SVt_PVCV:
-       if (ckWARN(WARN_MISC) && cv_const_sv((CV*)sv))
+       if (cv_const_sv((CV*)sv) && ckWARN(WARN_MISC))
            Perl_warner(aTHX_ packWARN(WARN_MISC), "Constant subroutine %s undefined",
                 CvANON((CV*)sv) ? "(anonymous)" : GvENAME(CvGV((CV*)sv)));
        /* FALL THROUGH */
     case SVt_PVFM:
        {
            /* let user-undef'd sub keep its identity */
-           GV* gv = CvGV((CV*)sv);
+           GV* const gv = CvGV((CV*)sv);
            cv_undef((CV*)sv);
            CvGV((CV*)sv) = gv;
        }
@@ -807,7 +769,7 @@ PP(pp_undef)
        else {
            GP *gp;
            gp_free((GV*)sv);
-           Newz(602, gp, 1, GP);
+           Newxz(gp, 1, GP);
            GvGP(sv) = gp_ref(gp);
            GvSV(sv) = NEWSV(72,0);
            GvLINE(sv) = CopLINE(PL_curcop);
@@ -900,36 +862,37 @@ PP(pp_pow)
        we're sure it is safe; otherwise we call pow() and try to convert to
        integer afterwards. */
     {
-        SvIV_please(TOPm1s);
-        if (SvIOK(TOPm1s)) {
-            bool baseuok = SvUOK(TOPm1s);
-            UV baseuv;
+       SvIV_please(TOPs);
+       if (SvIOK(TOPs)) {
+           SvIV_please(TOPm1s);
+           if (SvIOK(TOPm1s)) {
+               UV power;
+               bool baseuok;
+               UV baseuv;
 
-            if (baseuok) {
-                baseuv = SvUVX(TOPm1s);
-            } else {
-               const IV iv = SvIVX(TOPm1s);
-                if (iv >= 0) {
-                    baseuv = iv;
-                    baseuok = TRUE; /* effectively it's a UV now */
-                } else {
-                    baseuv = -iv; /* abs, baseuok == false records sign */
-                }
-            }
-            SvIV_please(TOPs);
-            if (SvIOK(TOPs)) {
-                UV power;
+               if (SvUOK(TOPs)) {
+                   power = SvUVX(TOPs);
+               } else {
+                   const IV iv = SvIVX(TOPs);
+                   if (iv >= 0) {
+                       power = iv;
+                   } else {
+                       goto float_it; /* Can't do negative powers this way.  */
+                   }
+               }
 
-                if (SvUOK(TOPs)) {
-                    power = SvUVX(TOPs);
-                } else {
-                    IV iv = SvIVX(TOPs);
-                    if (iv >= 0) {
-                        power = iv;
-                    } else {
-                        goto float_it; /* Can't do negative powers this way.  */
-                    }
-                }
+               baseuok = SvUOK(TOPm1s);
+               if (baseuok) {
+                   baseuv = SvUVX(TOPm1s);
+               } else {
+                   const IV iv = SvIVX(TOPm1s);
+                   if (iv >= 0) {
+                       baseuv = iv;
+                       baseuok = TRUE; /* effectively it's a UV now */
+                   } else {
+                       baseuv = -iv; /* abs, baseuok == false records sign */
+                   }
+               }
                 /* now we have integer ** positive integer. */
                 is_int = 1;
 
@@ -945,34 +908,28 @@ PP(pp_pow)
                        programmers to notice ** not doing what they mean. */
                     NV result = 1.0;
                     NV base = baseuok ? baseuv : -(NV)baseuv;
-                    int n = 0;
-
-                    for (; power; base *= base, n++) {
-                        /* Do I look like I trust gcc with long longs here?
-                           Do I hell.  */
-                       const UV bit = (UV)1 << (UV)n;
-                        if (power & bit) {
-                            result *= base;
-                            /* Only bother to clear the bit if it is set.  */
-                            power -= bit;
-                           /* Avoid squaring base again if we're done. */
-                           if (power == 0) break;
-                        }
-                    }
+
+                   if (power & 1) {
+                       result *= base;
+                   }
+                   while (power >>= 1) {
+                       base *= base;
+                       if (power & 1) {
+                           result *= base;
+                       }
+                   }
                     SP--;
                     SETn( result );
                     SvIV_please(TOPs);
                     RETURN;
                } else {
                    register unsigned int highbit = 8 * sizeof(UV);
-                   register unsigned int lowbit = 0;
-                   register unsigned int diff;
-                   bool odd_power = (bool)(power & 1);
-                   while ((diff = (highbit - lowbit) >> 1)) {
-                       if (baseuv & ~((1 << (lowbit + diff)) - 1))
-                           lowbit += diff;
-                       else 
-                           highbit -= diff;
+                   register unsigned int diff = 8 * sizeof(UV);
+                   while (diff >>= 1) {
+                       highbit -= diff;
+                       if (baseuv >> highbit) {
+                           highbit += diff;
+                       }
                    }
                    /* we now have baseuv < 2 ** highbit */
                    if (power * highbit <= 8 * sizeof(UV)) {
@@ -980,13 +937,14 @@ PP(pp_pow)
                           on same algorithm as above */
                        register UV result = 1;
                        register UV base = baseuv;
-                       register int n = 0;
-                       for (; power; base *= base, n++) {
-                           register const UV bit = (UV)1 << (UV)n;
-                           if (power & bit) {
+                       const bool odd_power = (bool)(power & 1);
+                       if (odd_power) {
+                           result *= base;
+                       }
+                       while (power >>= 1) {
+                           base *= base;
+                           if (power & 1) {
                                result *= base;
-                               power -= bit;
-                               if (power == 0) break;
                            }
                        }
                        SP--;
@@ -1305,7 +1263,7 @@ PP(pp_modulo)
                 if (!left_neg) {
                     left = SvUVX(POPs);
                 } else {
-                    IV aiv = SvIVX(POPs);
+                   const IV aiv = SvIVX(POPs);
                     if (aiv >= 0) {
                         left = aiv;
                         left_neg = FALSE; /* effectively it's a UV now */
@@ -1388,8 +1346,7 @@ PP(pp_repeat)
   {
     register IV count;
     dPOPss;
-    if (SvGMAGICAL(sv))
-        mg_get(sv);
+    SvGETMAGIC(sv);
     if (SvIOKp(sv)) {
         if (SvUOK(sv)) {
              const UV uv = SvUV(sv);
@@ -1398,7 +1355,7 @@ PP(pp_repeat)
              else
                   count = uv;
         } else {
-             IV iv = SvIV(sv);
+             const IV iv = SvIV(sv);
              if (iv < 0)
                   count = 0;
              else
@@ -1416,12 +1373,10 @@ PP(pp_repeat)
         count = SvIVx(sv);
     if (GIMME == G_ARRAY && PL_op->op_private & OPpREPEAT_DOLIST) {
        dMARK;
-       I32 items = SP - MARK;
-       I32 max;
-       static const char oom_list_extend[] =
-         "Out of memory during list extend";
+       static const char oom_list_extend[] = "Out of memory during list extend";
+       const I32 items = SP - MARK;
+       const I32 max = items * count;
 
-       max = items * count;
        MEM_WRAP_CHECK_1(max, SV*, oom_list_extend);
        /* Did the max computation overflow? */
        if (items > 0 && max > 0 && (max < items || max < count))
@@ -1467,7 +1422,7 @@ PP(pp_repeat)
            SP -= items;
     }
     else {     /* Note: mark already snarfed by pp_list */
-       SV *tmpstr = POPs;
+       SV * const tmpstr = POPs;
        STRLEN len;
        bool isutf;
        static const char oom_string_extend[] =
@@ -1650,11 +1605,11 @@ PP(pp_right_shift)
     {
       const IV shift = POPi;
       if (PL_op->op_private & HINT_INTEGER) {
-       IV i = TOPi;
+       const IV i = TOPi;
        SETi(i >> shift);
       }
       else {
-       UV u = TOPu;
+       const UV u = TOPu;
        SETu(u >> shift);
       }
       RETURN;
@@ -1979,8 +1934,8 @@ PP(pp_ne)
     if (SvIOK(TOPs)) {
        SvIV_please(TOPm1s);
        if (SvIOK(TOPm1s)) {
-           bool auvok = SvUOK(TOPm1s);
-           bool buvok = SvUOK(TOPs);
+           const bool auvok = SvUOK(TOPm1s);
+           const bool buvok = SvUOK(TOPs);
        
            if (auvok == buvok) { /* ## IV == IV or UV == UV ## */
                 /* Casting IV to UV before comparison isn't going to matter
@@ -2038,8 +1993,8 @@ PP(pp_ncmp)
     dSP; dTARGET; tryAMAGICbin(ncmp,0);
 #ifndef NV_PRESERVES_UV
     if (SvROK(TOPs) && !SvAMAGIC(TOPs) && SvROK(TOPm1s) && !SvAMAGIC(TOPm1s)) {
-        UV right = PTR2UV(SvRV(POPs));
-        UV left = PTR2UV(SvRV(TOPs));
+       const UV right = PTR2UV(SvRV(POPs));
+       const UV left = PTR2UV(SvRV(TOPs));
        SETi((left > right) - (left < right));
        RETURN;
     }
@@ -2137,54 +2092,40 @@ PP(pp_ncmp)
     }
 }
 
-PP(pp_slt)
+PP(pp_sle)
 {
-    dSP; tryAMAGICbinSET(slt,0);
-    {
-      dPOPTOPssrl;
-      const int cmp = (IN_LOCALE_RUNTIME
-                ? sv_cmp_locale(left, right)
-                : sv_cmp(left, right));
-      SETs(boolSV(cmp < 0));
-      RETURN;
-    }
-}
+    dSP;
 
-PP(pp_sgt)
-{
-    dSP; tryAMAGICbinSET(sgt,0);
-    {
-      dPOPTOPssrl;
-      const int cmp = (IN_LOCALE_RUNTIME
-                ? sv_cmp_locale(left, right)
-                : sv_cmp(left, right));
-      SETs(boolSV(cmp > 0));
-      RETURN;
-    }
-}
+    int amg_type = sle_amg;
+    int multiplier = 1;
+    int rhs = 1;
 
-PP(pp_sle)
-{
-    dSP; tryAMAGICbinSET(sle,0);
-    {
-      dPOPTOPssrl;
-      const int cmp = (IN_LOCALE_RUNTIME
-                ? sv_cmp_locale(left, right)
-                : sv_cmp(left, right));
-      SETs(boolSV(cmp <= 0));
-      RETURN;
+    switch (PL_op->op_type) {
+    case OP_SLT:
+       amg_type = slt_amg;
+       /* cmp < 0 */
+       rhs = 0;
+       break;
+    case OP_SGT:
+       amg_type = sgt_amg;
+       /* cmp > 0 */
+       multiplier = -1;
+       rhs = 0;
+       break;
+    case OP_SGE:
+       amg_type = sge_amg;
+       /* cmp >= 0 */
+       multiplier = -1;
+       break;
     }
-}
 
-PP(pp_sge)
-{
-    dSP; tryAMAGICbinSET(sge,0);
+    tryAMAGICbinSET_var(amg_type,0);
     {
       dPOPTOPssrl;
       const int cmp = (IN_LOCALE_RUNTIME
                 ? sv_cmp_locale(left, right)
                 : sv_cmp(left, right));
-      SETs(boolSV(cmp >= 0));
+      SETs(boolSV(cmp * multiplier < rhs));
       RETURN;
     }
 }
@@ -2227,8 +2168,8 @@ PP(pp_bit_and)
     dSP; dATARGET; tryAMAGICbin(band,opASSIGN);
     {
       dPOPTOPssrl;
-      if (SvGMAGICAL(left)) mg_get(left);
-      if (SvGMAGICAL(right)) mg_get(right);
+      SvGETMAGIC(left);
+      SvGETMAGIC(right);
       if (SvNIOKp(left) || SvNIOKp(right)) {
        if (PL_op->op_private & HINT_INTEGER) {
          const IV i = SvIV_nomg(left) & SvIV_nomg(right);
@@ -2252,8 +2193,8 @@ PP(pp_bit_xor)
     dSP; dATARGET; tryAMAGICbin(bxor,opASSIGN);
     {
       dPOPTOPssrl;
-      if (SvGMAGICAL(left)) mg_get(left);
-      if (SvGMAGICAL(right)) mg_get(right);
+      SvGETMAGIC(left);
+      SvGETMAGIC(right);
       if (SvNIOKp(left) || SvNIOKp(right)) {
        if (PL_op->op_private & HINT_INTEGER) {
          const IV i = (USE_LEFT(left) ? SvIV_nomg(left) : 0) ^ SvIV_nomg(right);
@@ -2277,8 +2218,8 @@ PP(pp_bit_or)
     dSP; dATARGET; tryAMAGICbin(bor,opASSIGN);
     {
       dPOPTOPssrl;
-      if (SvGMAGICAL(left)) mg_get(left);
-      if (SvGMAGICAL(right)) mg_get(right);
+      SvGETMAGIC(left);
+      SvGETMAGIC(right);
       if (SvNIOKp(left) || SvNIOKp(right)) {
        if (PL_op->op_private & HINT_INTEGER) {
          const IV i = (USE_LEFT(left) ? SvIV_nomg(left) : 0) | SvIV_nomg(right);
@@ -2303,8 +2244,7 @@ PP(pp_negate)
     {
        dTOPss;
        const int flags = SvFLAGS(sv);
-       if (SvGMAGICAL(sv))
-           mg_get(sv);
+       SvGETMAGIC(sv);
        if ((flags & SVf_IOK) || ((flags & (SVp_IOK | SVp_NOK)) == SVp_IOK)) {
            /* It's publicly an integer, or privately an integer-not-float */
        oops_its_an_int:
@@ -2380,8 +2320,7 @@ PP(pp_complement)
     dSP; dTARGET; tryAMAGICun(compl);
     {
       dTOPss;
-      if (SvGMAGICAL(sv))
-         mg_get(sv);
+      SvGETMAGIC(sv);
       if (SvNIOKp(sv)) {
        if (PL_op->op_private & HINT_INTEGER) {
          const IV i = ~SvIV_nomg(sv);
@@ -2424,7 +2363,7 @@ PP(pp_complement)
          tmps -= len;
 
          if (nwide) {
-             Newz(0, result, targlen + 1, U8);
+             Newxz(result, targlen + 1, U8);
              while (tmps < send) {
                  const UV c = utf8n_to_uvchr(tmps, send-tmps, &l, UTF8_ALLOW_ANYUV);
                  tmps += UTF8SKIP(tmps);
@@ -2436,7 +2375,7 @@ PP(pp_complement)
              SvUTF8_on(TARG);
          }
          else {
-             Newz(0, result, nchar + 1, U8);
+             Newxz(result, nchar + 1, U8);
              while (tmps < send) {
                  const U8 c = (U8)utf8n_to_uvchr(tmps, 0, &l, UTF8_ALLOW_ANY);
                  tmps += UTF8SKIP(tmps);
@@ -2742,11 +2681,7 @@ PP(pp_rand)
 PP(pp_srand)
 {
     dSP;
-    UV anum;
-    if (MAXARG < 1)
-       anum = seed();
-    else
-       anum = POPu;
+    const UV anum = (MAXARG < 1) ? seed() : POPu;
     (void)seedDrand01((Rand_seed_t)anum);
     PL_srand_called = TRUE;
     EXTEND(SP, 1);
@@ -2861,9 +2796,9 @@ PP(pp_abs)
       } else{
        const NV value = TOPn;
        if (value < 0.0)
-         SETn(value);
-       else
          SETn(-value);
+       else
+         SETn(value);
       }
     }
     RETURN;
@@ -2945,7 +2880,7 @@ PP(pp_oct)
 PP(pp_length)
 {
     dSP; dTARGET;
-    SV *sv = TOPs;
+    SV * const sv = TOPs;
 
     if (DO_UTF8(sv))
        SETi(sv_len_utf8(sv));
@@ -3290,8 +3225,6 @@ PP(pp_sprintf)
     dSP; dMARK; dORIGMARK; dTARGET;
     do_sprintf(TARG, SP-MARK, MARK+1);
     TAINT_IF(SvTAINTED(TARG));
-    if (DO_UTF8(*(MARK+1)))
-       SvUTF8_on(TARG);
     SP = ORIGMARK;
     PUSHTARG;
     RETURN;
@@ -3429,6 +3362,7 @@ PP(pp_ucfirst)
     SV *sv = TOPs;
     const U8 *s;
     STRLEN slen;
+    const int op_type = PL_op->op_type;
 
     SvGETMAGIC(sv);
     if (DO_UTF8(sv) &&
@@ -3439,18 +3373,21 @@ PP(pp_ucfirst)
        STRLEN tculen;
 
        utf8_to_uvchr(s, &ulen);
-       toTITLE_utf8(s, tmpbuf, &tculen);
-       utf8_to_uvchr(tmpbuf, 0);
+       if (op_type == OP_UCFIRST) {
+           toTITLE_utf8(s, tmpbuf, &tculen);
+       } else {
+           toLOWER_utf8(s, tmpbuf, &tculen);
+       }
 
-       if (!SvPADTMP(sv) || SvREADONLY(sv)) {
+       if (!SvPADTMP(sv) || SvREADONLY(sv) || ulen != tculen) {
            dTARGET;
            /* slen is the byte length of the whole SV.
             * ulen is the byte length of the original Unicode character
             * stored as UTF-8 at s.
-            * tculen is the byte length of the freshly titlecased
-            * Unicode character stored as UTF-8 at tmpbuf.
-            * We first set the result to be the titlecased character,
-            * and then append the rest of the SV data. */
+            * tculen is the byte length of the freshly titlecased (or
+            * lowercased) Unicode character stored as UTF-8 at tmpbuf.
+            * We first set the result to be the titlecased (/lowercased)
+            * character, and then append the rest of the SV data. */
            sv_setpvn(TARG, (char*)tmpbuf, tculen);
            if (slen > ulen)
                sv_catpvn(TARG, (char*)(s + ulen), slen - ulen);
@@ -3476,67 +3413,11 @@ PP(pp_ucfirst)
            if (IN_LOCALE_RUNTIME) {
                TAINT;
                SvTAINTED_on(sv);
-               *s1 = toUPPER_LC(*s1);
-           }
-           else
-               *s1 = toUPPER(*s1);
-       }
-    }
-    SvSETMAGIC(sv);
-    RETURN;
-}
-
-PP(pp_lcfirst)
-{
-    dSP;
-    SV *sv = TOPs;
-    const U8 *s;
-    STRLEN slen;
-
-    SvGETMAGIC(sv);
-    if (DO_UTF8(sv) &&
-       (s = (const U8*)SvPV_nomg_const(sv, slen)) && slen &&
-       UTF8_IS_START(*s)) {
-       STRLEN ulen;
-       U8 tmpbuf[UTF8_MAXBYTES_CASE+1];
-       U8 *tend;
-       UV uv;
-
-       toLOWER_utf8(s, tmpbuf, &ulen);
-       uv = utf8_to_uvchr(tmpbuf, 0);
-       tend = uvchr_to_utf8(tmpbuf, uv);
-
-       if (!SvPADTMP(sv) || (STRLEN)(tend - tmpbuf) != ulen || SvREADONLY(sv)) {
-           dTARGET;
-           sv_setpvn(TARG, (char*)tmpbuf, tend - tmpbuf);
-           if (slen > ulen)
-               sv_catpvn(TARG, (char*)(s + ulen), slen - ulen);
-           SvUTF8_on(TARG);
-           SETs(TARG);
-       }
-       else {
-           s = (U8*)SvPV_force_nomg(sv, slen);
-           Copy(tmpbuf, s, ulen, U8);
-       }
-    }
-    else {
-       U8 *s1;
-       if (!SvPADTMP(sv) || SvREADONLY(sv)) {
-           dTARGET;
-           SvUTF8_off(TARG);                           /* decontaminate */
-           sv_setsv_nomg(TARG, sv);
-           sv = TARG;
-           SETs(sv);
-       }
-       s1 = (U8*)SvPV_force_nomg(sv, slen);
-       if (*s1) {
-           if (IN_LOCALE_RUNTIME) {
-               TAINT;
-               SvTAINTED_on(sv);
-               *s1 = toLOWER_LC(*s1);
+               *s1 = (op_type == OP_UCFIRST)
+                   ? toUPPER_LC(*s1) : toLOWER_LC(*s1);
            }
            else
-               *s1 = toLOWER(*s1);
+               *s1 = (op_type == OP_UCFIRST) ? toUPPER(*s1) : toLOWER(*s1);
        }
     }
     SvSETMAGIC(sv);
@@ -3579,7 +3460,7 @@ PP(pp_uc)
                if (ulen > u && (SvLEN(TARG) < (min += ulen - u))) {
                    /* If the eventually required minimum size outgrows
                     * the available space, we need to grow. */
-                   UV o = d - (U8*)SvPVX_const(TARG);
+                   const UV o = d - (U8*)SvPVX_const(TARG);
 
                    /* If someone uppercases one million U+03B0s we
                     * SvGROW() one million times.  Or we could try
@@ -3609,7 +3490,7 @@ PP(pp_uc)
        }
        s = (U8*)SvPV_force_nomg(sv, len);
        if (len) {
-           const register U8 *send = s + len;
+           register const U8 *send = s + len;
 
            if (IN_LOCALE_RUNTIME) {
                TAINT;
@@ -3682,7 +3563,7 @@ PP(pp_lc)
                if (ulen > u && (SvLEN(TARG) < (min += ulen - u))) {
                    /* If the eventually required minimum size outgrows
                     * the available space, we need to grow. */
-                   UV o = d - (U8*)SvPVX_const(TARG);
+                   const UV o = d - (U8*)SvPVX_const(TARG);
 
                    /* If someone lowercases one million U+0130s we
                     * SvGROW() one million times.  Or we could try
@@ -3736,7 +3617,7 @@ PP(pp_quotemeta)
     dSP; dTARGET;
     SV * const sv = TOPs;
     STRLEN len;
-    const register char *s = SvPV_const(sv,len);
+    register const char *s = SvPV_const(sv,len);
 
     SvUTF8_off(TARG);                          /* decontaminate */
     if (len) {
@@ -3860,16 +3741,6 @@ PP(pp_each)
     RETURN;
 }
 
-PP(pp_values)
-{
-    return do_kv();
-}
-
-PP(pp_keys)
-{
-    return do_kv();
-}
-
 PP(pp_delete)
 {
     dSP;
@@ -3937,7 +3808,7 @@ PP(pp_exists)
 
     if (PL_op->op_private & OPpEXISTS_SUB) {
        GV *gv;
-       SV *sv = POPs;
+       SV * const sv = POPs;
        CV * const cv = sv_2cv(sv, &hv, &gv, FALSE);
        if (cv)
            RETPUSHYES;
@@ -4199,7 +4070,7 @@ PP(pp_splice)
 
     if (diff < 0) {                            /* shrinking the area */
        if (newlen) {
-           New(451, tmparyval, newlen, SV*);   /* so remember insertion */
+           Newx(tmparyval, newlen, SV*);       /* so remember insertion */
            Copy(MARK, tmparyval, newlen, SV*);
        }
 
@@ -4259,7 +4130,7 @@ PP(pp_splice)
     }
     else {                                     /* no, expanding (or same) */
        if (length) {
-           New(452, tmparyval, length, SV*);   /* so remember deletion */
+           Newx(tmparyval, length, SV*);       /* so remember deletion */
            Copy(AvARRAY(ary)+offset, tmparyval, length, SV*);
        }
 
@@ -4341,18 +4212,19 @@ PP(pp_push)
        call_method("PUSH",G_SCALAR|G_DISCARD);
        LEAVE;
        SPAGAIN;
+       SP = ORIGMARK;
+       PUSHi( AvFILL(ary) + 1 );
     }
     else {
-       /* Why no pre-extend of ary here ? */
        for (++MARK; MARK <= SP; MARK++) {
            SV * const sv = NEWSV(51, 0);
            if (*MARK)
                sv_setsv(sv, *MARK);
-           av_push(ary, sv);
+           av_store(ary, AvFILLp(ary)+1, sv);
        }
+       SP = ORIGMARK;
+       PUSHi( AvFILLp(ary) + 1 );
     }
-    SP = ORIGMARK;
-    PUSHi( AvFILL(ary) + 1 );
     RETURN;
 }
 
@@ -4797,9 +4669,11 @@ PP(pp_lock)
     RETURN;
 }
 
-PP(pp_threadsv)
+
+PP(unimplemented_op)
 {
-    DIE(aTHX_ "tried to access per-thread data in non-threaded perl");
+    DIE(aTHX_ "panic: unimplemented op %s (#%d) called", OP_NAME(PL_op),
+       PL_op->op_type);
 }
 
 /*