Continue 4-arg substr() UTF-8 fixage.
[p5sagit/p5-mst-13.2.git] / pp.c
diff --git a/pp.c b/pp.c
index d79c170..a2ca097 100644 (file)
--- a/pp.c
+++ b/pp.c
@@ -92,7 +92,7 @@ extern Pid_t getpid (void);
 
 PP(pp_stub)
 {
-    djSP;
+    dSP;
     if (GIMME_V == G_SCALAR)
        XPUSHs(&PL_sv_undef);
     RETURN;
@@ -107,13 +107,18 @@ PP(pp_scalar)
 
 PP(pp_padav)
 {
-    djSP; dTARGET;
+    dSP; dTARGET;
     if (PL_op->op_private & OPpLVAL_INTRO)
        SAVECLEARSV(PL_curpad[PL_op->op_targ]);
     EXTEND(SP, 1);
     if (PL_op->op_flags & OPf_REF) {
        PUSHs(TARG);
        RETURN;
+    } else if (LVRET) {
+       if (GIMME == G_SCALAR)
+           Perl_croak(aTHX_ "Can't return array to lvalue scalar context");
+       PUSHs(TARG);
+       RETURN;
     }
     if (GIMME == G_ARRAY) {
        I32 maxarg = AvFILL((AV*)TARG) + 1;
@@ -141,7 +146,7 @@ PP(pp_padav)
 
 PP(pp_padhv)
 {
-    djSP; dTARGET;
+    dSP; dTARGET;
     I32 gimme;
 
     XPUSHs(TARG);
@@ -149,6 +154,11 @@ PP(pp_padhv)
        SAVECLEARSV(PL_curpad[PL_op->op_targ]);
     if (PL_op->op_flags & OPf_REF)
        RETURN;
+    else if (LVRET) {
+       if (GIMME == G_SCALAR)
+           Perl_croak(aTHX_ "Can't return hash to lvalue scalar context");
+       RETURN;
+    }
     gimme = GIMME_V;
     if (gimme == G_ARRAY) {
        RETURNOP(do_kv());
@@ -174,7 +184,7 @@ PP(pp_padany)
 
 PP(pp_rv2gv)
 {
-    djSP; dTOPss;
+    dSP; dTOPss;
 
     if (SvROK(sv)) {
       wasref:
@@ -260,7 +270,7 @@ PP(pp_rv2gv)
 
 PP(pp_rv2sv)
 {
-    djSP; dTOPss;
+    dSP; dTOPss;
 
     if (SvROK(sv)) {
       wasref:
@@ -325,7 +335,7 @@ PP(pp_rv2sv)
 
 PP(pp_av2arylen)
 {
-    djSP;
+    dSP;
     AV *av = (AV*)TOPs;
     SV *sv = AvARYLEN(av);
     if (!sv) {
@@ -339,9 +349,9 @@ PP(pp_av2arylen)
 
 PP(pp_pos)
 {
-    djSP; dTARGET; dPOPss;
+    dSP; dTARGET; dPOPss;
 
-    if (PL_op->op_flags & OPf_MOD) {
+    if (PL_op->op_flags & OPf_MOD || LVRET) {
        if (SvTYPE(TARG) < SVt_PVLV) {
            sv_upgrade(TARG, SVt_PVLV);
            sv_magic(TARG, Nullsv, '.', Nullch, 0);
@@ -375,7 +385,7 @@ PP(pp_pos)
 
 PP(pp_rv2cv)
 {
-    djSP;
+    dSP;
     GV *gv;
     HV *stash;
 
@@ -400,7 +410,7 @@ PP(pp_rv2cv)
 
 PP(pp_prototype)
 {
-    djSP;
+    dSP;
     CV *cv;
     HV *stash;
     GV *gv;
@@ -466,7 +476,7 @@ PP(pp_prototype)
 
 PP(pp_anoncode)
 {
-    djSP;
+    dSP;
     CV* cv = (CV*)PL_curpad[PL_op->op_targ];
     if (CvCLONE(cv))
        cv = (CV*)sv_2mortal((SV*)cv_clone(cv));
@@ -477,14 +487,14 @@ PP(pp_anoncode)
 
 PP(pp_srefgen)
 {
-    djSP;
+    dSP;
     *SP = refto(*SP);
     RETURN;
 }
 
 PP(pp_refgen)
 {
-    djSP; dMARK;
+    dSP; dMARK;
     if (GIMME != G_ARRAY) {
        if (++MARK <= SP)
            *MARK = *SP;
@@ -534,7 +544,7 @@ S_refto(pTHX_ SV *sv)
 
 PP(pp_ref)
 {
-    djSP; dTARGET;
+    dSP; dTARGET;
     SV *sv;
     char *pv;
 
@@ -554,7 +564,7 @@ PP(pp_ref)
 
 PP(pp_bless)
 {
-    djSP;
+    dSP;
     HV *stash;
 
     if (MAXARG == 1)
@@ -583,7 +593,7 @@ PP(pp_gelem)
     SV *sv;
     SV *tmpRef;
     char *elem;
-    djSP;
+    dSP;
     STRLEN n_a;
 
     sv = POPs;
@@ -647,7 +657,7 @@ PP(pp_gelem)
 
 PP(pp_study)
 {
-    djSP; dPOPss;
+    dSP; dPOPss;
     register unsigned char *s;
     register I32 pos;
     register I32 ch;
@@ -709,7 +719,7 @@ PP(pp_study)
 
 PP(pp_trans)
 {
-    djSP; dTARG;
+    dSP; dTARG;
     SV *sv;
 
     if (PL_op->op_flags & OPf_STACKED)
@@ -727,7 +737,7 @@ PP(pp_trans)
 
 PP(pp_schop)
 {
-    djSP; dTARGET;
+    dSP; dTARGET;
     do_chop(TARG, TOPs);
     SETTARG;
     RETURN;
@@ -735,23 +745,24 @@ PP(pp_schop)
 
 PP(pp_chop)
 {
-    djSP; dMARK; dTARGET;
-    while (SP > MARK)
-       do_chop(TARG, POPs);
+    dSP; dMARK; dTARGET; dORIGMARK;
+    while (MARK < SP)
+       do_chop(TARG, *++MARK);
+    SP = ORIGMARK;
     PUSHTARG;
     RETURN;
 }
 
 PP(pp_schomp)
 {
-    djSP; dTARGET;
+    dSP; dTARGET;
     SETi(do_chomp(TOPs));
     RETURN;
 }
 
 PP(pp_chomp)
 {
-    djSP; dMARK; dTARGET;
+    dSP; dMARK; dTARGET;
     register I32 count = 0;
 
     while (SP > MARK)
@@ -762,7 +773,7 @@ PP(pp_chomp)
 
 PP(pp_defined)
 {
-    djSP;
+    dSP;
     register SV* sv;
 
     sv = POPs;
@@ -792,7 +803,7 @@ PP(pp_defined)
 
 PP(pp_undef)
 {
-    djSP;
+    dSP;
     SV *sv;
 
     if (!PL_op->op_private) {
@@ -824,7 +835,7 @@ PP(pp_undef)
     case SVt_PVFM:
        {
            /* let user-undef'd sub keep its identity */
-           GV* gv = (GV*)SvREFCNT_inc(CvGV((CV*)sv));
+           GV* gv = CvGV((CV*)sv);
            cv_undef((CV*)sv);
            CvGV((CV*)sv) = gv;
        }
@@ -859,7 +870,7 @@ PP(pp_undef)
 
 PP(pp_predec)
 {
-    djSP;
+    dSP;
     if (SvREADONLY(TOPs) || SvTYPE(TOPs) > SVt_PVLV)
        DIE(aTHX_ PL_no_modify);
     if (SvIOK_notUV(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs) &&
@@ -876,7 +887,7 @@ PP(pp_predec)
 
 PP(pp_postinc)
 {
-    djSP; dTARGET;
+    dSP; dTARGET;
     if (SvREADONLY(TOPs) || SvTYPE(TOPs) > SVt_PVLV)
        DIE(aTHX_ PL_no_modify);
     sv_setsv(TARG, TOPs);
@@ -897,7 +908,7 @@ PP(pp_postinc)
 
 PP(pp_postdec)
 {
-    djSP; dTARGET;
+    dSP; dTARGET;
     if (SvREADONLY(TOPs) || SvTYPE(TOPs) > SVt_PVLV)
        DIE(aTHX_ PL_no_modify);
     sv_setsv(TARG, TOPs);
@@ -918,7 +929,7 @@ PP(pp_postdec)
 
 PP(pp_pow)
 {
-    djSP; dATARGET; tryAMAGICbin(pow,opASSIGN);
+    dSP; dATARGET; tryAMAGICbin(pow,opASSIGN);
     {
       dPOPTOPnnrl;
       SETn( Perl_pow( left, right) );
@@ -928,7 +939,7 @@ PP(pp_pow)
 
 PP(pp_multiply)
 {
-    djSP; dATARGET; tryAMAGICbin(mult,opASSIGN);
+    dSP; dATARGET; tryAMAGICbin(mult,opASSIGN);
 #ifdef PERL_PRESERVE_IVUV
     SvIV_please(TOPs);
     if (SvIOK(TOPs)) {
@@ -1046,7 +1057,7 @@ PP(pp_multiply)
 
 PP(pp_divide)
 {
-    djSP; dATARGET; tryAMAGICbin(div,opASSIGN);
+    dSP; dATARGET; tryAMAGICbin(div,opASSIGN);
     {
       dPOPPOPnnrl;
       NV value;
@@ -1075,7 +1086,7 @@ PP(pp_divide)
 
 PP(pp_modulo)
 {
-    djSP; dATARGET; tryAMAGICbin(modulo,opASSIGN);
+    dSP; dATARGET; tryAMAGICbin(modulo,opASSIGN);
     {
        UV left;
        UV right;
@@ -1175,7 +1186,7 @@ PP(pp_modulo)
 
 PP(pp_repeat)
 {
-  djSP; dATARGET; tryAMAGICbin(repeat,opASSIGN);
+  dSP; dATARGET; tryAMAGICbin(repeat,opASSIGN);
   {
     register IV count = POPi;
     if (GIMME == G_ARRAY && PL_op->op_private & OPpREPEAT_DOLIST) {
@@ -1202,10 +1213,11 @@ PP(pp_repeat)
     else {     /* Note: mark already snarfed by pp_list */
        SV *tmpstr = POPs;
        STRLEN len;
-       bool isutf = DO_UTF8(tmpstr);
+       bool isutf;
 
        SvSetSV(TARG, tmpstr);
        SvPV_force(TARG, len);
+       isutf = DO_UTF8(TARG);
        if (count != 1) {
            if (count < 1)
                SvCUR_set(TARG, 0);
@@ -1228,137 +1240,109 @@ PP(pp_repeat)
 
 PP(pp_subtract)
 {
-    djSP; dATARGET; bool useleft; tryAMAGICbin(subtr,opASSIGN);
+    dSP; dATARGET; bool useleft; tryAMAGICbin(subtr,opASSIGN);
     useleft = USE_LEFT(TOPm1s);
 #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.
-       If either argument hasn't had a numeric conversion yet attempt to get
-       the IV. It's important to do this now, rather than just assuming that
-       it's not IOK as a PV of "9223372036854775806" may not take well to NV
-       addition, and an SV which is NOK, NV=6.0 ought to be coerced to
-       integer in case the second argument is IV=9223372036854775806
-       We can (now) rely on sv_2iv to do the right thing, only setting the
-       public IOK flag if the value in the NV (or PV) slot is truly integer.
-
-       A side effect is that this also aggressively prefers integer maths over
-       fp maths for integer values.  */
+    /* 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)) {
        /* 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.  */
+       register UV auv;
+       bool auvok;
+       bool a_valid = 0;
+
        if (!useleft) {
-           /* left operand is undef, treat as zero. + 0 is identity. */
-           if (SvUOK(TOPs)) {
-               dPOPuv; /* Scary macros. Lets put a sequence point (;) here */
-               if (value <= (UV)IV_MIN) {
-                   /* 2s complement assumption.  */
-                   SETi(-(IV)value);
-                   RETURN;
-               } /* else drop through into NVs below */
-           } else {
-               dPOPiv;
-               SETu((UV)-value);
-               RETURN;
-           }
+           auv = 0;
+           a_valid = auvok = 1;
+           /* left operand is undef, treat as zero.  */
        } else {
            /* Left operand is defined, so is it IV? */
            SvIV_please(TOPm1s);
            if (SvIOK(TOPm1s)) {
-               bool auvok = SvUOK(TOPm1s);
-               bool buvok = SvUOK(TOPs);
-           
-               if (!auvok && !buvok) { /* ## IV - IV ## */
-                   IV aiv = SvIVX(TOPm1s);
-                   IV biv = SvIVX(TOPs);
-                   IV result = aiv - biv;
-               
-                   if (biv >= 0 ? (result < aiv) : (result >= aiv)) {
-                       SP--;
-                       SETi( result );
-                       RETURN;
-                   }
-                   /* +ve - +ve can't overflow. (worst case 0 - IV_MAX) */
-                   /* -ve - -ve can't overflow. (worst case -1 - IV_MIN) */
-                   /* -ve - +ve can only overflow too negative. */
-                   /* leaving +ve - -ve, which will go UV */
-                   if (aiv >= 0 && biv < 0) { /* assert don't need biv <0 */
-                       /* 2s complement assumption for IV_MIN */
-                       UV result = (UV)aiv + (UV)-biv;
-                       /* UV + UV must get bigger. +ve IV + +ve IV +1 can't
-                          overflow UV (2s complement assumption */
-                       assert (result >= (UV) aiv);
-                       SP--;
-                       SETu( result );
-                       RETURN;
-                   }
-                   /* Overflow, drop through to NVs */
-               } else if (auvok && buvok) {    /* ## UV - UV ## */
-                   UV auv = SvUVX(TOPm1s);
-                   UV buv = SvUVX(TOPs);
-                   IV result;
-                   
-                   if (auv >= buv) {
-                       SP--;
-                       SETu( auv - buv );
-                       RETURN;
-                   }
-                   /* Blatant 2s complement assumption.  */
-                   result = (IV)(auv - buv);
-                   if (result < 0) {
-                       SP--;
-                       SETi( result );
-                       RETURN;
+               if ((auvok = SvUOK(TOPm1s)))
+                   auv = SvUVX(TOPm1s);
+               else {
+                   register IV aiv = SvIVX(TOPm1s);
+                   if (aiv >= 0) {
+                       auv = aiv;
+                       auvok = 1;      /* Now acting as a sign flag.  */
+                   } else { /* 2s complement assumption for IV_MIN */
+                       auv = (UV)-aiv;
                    }
-                   /* Overflow on IV - IV, drop through to NVs */
-               } else if (auvok) {     /* ## Mixed UV - IV ## */
-                   UV auv = SvUVX(TOPm1s);
-                   IV biv = SvIVX(TOPs);
-
-                   if (biv < 0) {
-                       /* 2s complement assumptions for IV_MIN */
-                       UV result = auv + ((UV)-biv);
-                       /* UV + UV can only get bigger... */
-                       if (result >= auv) {
-                           SP--;
-                           SETu( result );
-                           RETURN;
-                       }
-                       /* and if it gets too big for UV then it's NV time.  */
-                   } else if (auv > (UV)IV_MAX) {
-                       /* I think I'm making an implicit 2s complement
-                          assumption that IV_MIN == -IV_MAX - 1 */
-                       /* biv is >= 0 */
-                       UV result = auv - (UV)biv;
-                       assert (result <= auv);
-                       SP--;
-                       SETu( result );
-                       RETURN;
-                   } else {
-                       /* biv is >= 0 */
-                       IV result = (IV)auv - biv;
-                       assert (result <= (IV)auv);
-                       SP--;
-                       SETi( result );
-                       RETURN;
+               }
+               a_valid = 1;
+           }
+       }
+       if (a_valid) {
+           bool result_good = 0;
+           UV result;
+           register UV buv;
+           bool buvok = SvUOK(TOPs);
+       
+           if (buvok)
+               buv = SvUVX(TOPs);
+           else {
+               register IV biv = SvIVX(TOPs);
+               if (biv >= 0) {
+                   buv = biv;
+                   buvok = 1;
+               } else
+                   buv = (UV)-biv;
+           }
+           /* ?uvok if value is >= 0. basically, flagged as UV if it's +ve,
+              else "IV" now, independant of how it came in.
+              if a, b represents positive, A, B negative, a maps to -A etc
+              a - b =>  (a - b)
+              A - b => -(a + b)
+              a - B =>  (a + b)
+              A - B => -(a - b)
+              all UV maths. negate result if A negative.
+              subtract if signs same, add if signs differ. */
+
+           if (auvok ^ buvok) {
+               /* Signs differ.  */
+               result = auv + buv;
+               if (result >= auv)
+                   result_good = 1;
+           } else {
+               /* Signs same */
+               if (auv >= buv) {
+                   result = auv - buv;
+                   /* Must get smaller */
+                   if (result <= auv)
+                       result_good = 1;
+               } else {
+                   result = buv - auv;
+                   if (result <= buv) {
+                       /* result really should be -(auv-buv). as its negation
+                          of true value, need to swap our result flag  */
+                       auvok = !auvok;
+                       result_good = 1;
                    }
-               } else {                /* ## Mixed IV - UV ## */
-                   IV aiv = SvIVX(TOPm1s);
-                   UV buv = SvUVX(TOPs);
-                   IV result = aiv - (IV)buv; /* 2s complement assumption. */
-               
-                   /* result must not get larger. */
-                   if (result <= aiv) {
-                       SP--;
-                       SETi( result );
-                       RETURN;
-                   } /* end of IV-IV / UV-UV / UV-IV / IV-UV */
                }
            }
+           if (result_good) {
+               SP--;
+               if (auvok)
+                   SETu( result );
+               else {
+                   /* Negate result */
+                   if (result <= (UV)IV_MIN)
+                       SETi( -(IV)result );
+                   else {
+                       /* result valid, but out of range for IV.  */
+                       SETn( -(NV)result );
+                   }
+               }
+               RETURN;
+           } /* Overflow, drop through to NVs.  */
        }
     }
 #endif
+    useleft = USE_LEFT(TOPm1s);
     {
        dPOPnv;
        if (!useleft) {
@@ -1373,7 +1357,7 @@ PP(pp_subtract)
 
 PP(pp_left_shift)
 {
-    djSP; dATARGET; tryAMAGICbin(lshift,opASSIGN);
+    dSP; dATARGET; tryAMAGICbin(lshift,opASSIGN);
     {
       IV shift = POPi;
       if (PL_op->op_private & HINT_INTEGER) {
@@ -1390,7 +1374,7 @@ PP(pp_left_shift)
 
 PP(pp_right_shift)
 {
-    djSP; dATARGET; tryAMAGICbin(rshift,opASSIGN);
+    dSP; dATARGET; tryAMAGICbin(rshift,opASSIGN);
     {
       IV shift = POPi;
       if (PL_op->op_private & HINT_INTEGER) {
@@ -1407,7 +1391,7 @@ PP(pp_right_shift)
 
 PP(pp_lt)
 {
-    djSP; tryAMAGICbinSET(lt,0);
+    dSP; tryAMAGICbinSET(lt,0);
 #ifdef PERL_PRESERVE_IVUV
     SvIV_please(TOPs);
     if (SvIOK(TOPs)) {
@@ -1415,7 +1399,7 @@ PP(pp_lt)
        if (SvIOK(TOPm1s)) {
            bool auvok = SvUOK(TOPm1s);
            bool buvok = SvUOK(TOPs);
-           
+       
            if (!auvok && !buvok) { /* ## IV < IV ## */
                IV aiv = SvIVX(TOPm1s);
                IV biv = SvIVX(TOPs);
@@ -1485,7 +1469,7 @@ PP(pp_lt)
 
 PP(pp_gt)
 {
-    djSP; tryAMAGICbinSET(gt,0);
+    dSP; tryAMAGICbinSET(gt,0);
 #ifdef PERL_PRESERVE_IVUV
     SvIV_please(TOPs);
     if (SvIOK(TOPs)) {
@@ -1493,7 +1477,7 @@ PP(pp_gt)
        if (SvIOK(TOPm1s)) {
            bool auvok = SvUOK(TOPm1s);
            bool buvok = SvUOK(TOPs);
-           
+       
            if (!auvok && !buvok) { /* ## IV > IV ## */
                IV aiv = SvIVX(TOPm1s);
                IV biv = SvIVX(TOPs);
@@ -1563,7 +1547,7 @@ PP(pp_gt)
 
 PP(pp_le)
 {
-    djSP; tryAMAGICbinSET(le,0);
+    dSP; tryAMAGICbinSET(le,0);
 #ifdef PERL_PRESERVE_IVUV
     SvIV_please(TOPs);
     if (SvIOK(TOPs)) {
@@ -1571,7 +1555,7 @@ PP(pp_le)
        if (SvIOK(TOPm1s)) {
            bool auvok = SvUOK(TOPm1s);
            bool buvok = SvUOK(TOPs);
-           
+       
            if (!auvok && !buvok) { /* ## IV <= IV ## */
                IV aiv = SvIVX(TOPm1s);
                IV biv = SvIVX(TOPs);
@@ -1641,7 +1625,7 @@ PP(pp_le)
 
 PP(pp_ge)
 {
-    djSP; tryAMAGICbinSET(ge,0);
+    dSP; tryAMAGICbinSET(ge,0);
 #ifdef PERL_PRESERVE_IVUV
     SvIV_please(TOPs);
     if (SvIOK(TOPs)) {
@@ -1649,7 +1633,7 @@ PP(pp_ge)
        if (SvIOK(TOPm1s)) {
            bool auvok = SvUOK(TOPm1s);
            bool buvok = SvUOK(TOPs);
-           
+       
            if (!auvok && !buvok) { /* ## IV >= IV ## */
                IV aiv = SvIVX(TOPm1s);
                IV biv = SvIVX(TOPs);
@@ -1719,7 +1703,7 @@ PP(pp_ge)
 
 PP(pp_ne)
 {
-    djSP; tryAMAGICbinSET(ne,0);
+    dSP; tryAMAGICbinSET(ne,0);
 #ifdef PERL_PRESERVE_IVUV
     SvIV_please(TOPs);
     if (SvIOK(TOPs)) {
@@ -1727,7 +1711,7 @@ PP(pp_ne)
        if (SvIOK(TOPm1s)) {
            bool auvok = SvUOK(TOPm1s);
            bool buvok = SvUOK(TOPs);
-           
+       
            if (!auvok && !buvok) { /* ## IV <=> IV ## */
                IV aiv = SvIVX(TOPm1s);
                IV biv = SvIVX(TOPs);
@@ -1789,7 +1773,7 @@ PP(pp_ne)
 
 PP(pp_ncmp)
 {
-    djSP; dTARGET; tryAMAGICbin(ncmp,0);
+    dSP; dTARGET; tryAMAGICbin(ncmp,0);
 #ifdef PERL_PRESERVE_IVUV
     /* Fortunately it seems NaN isn't IOK */
     SvIV_please(TOPs);
@@ -1897,7 +1881,7 @@ PP(pp_ncmp)
 
 PP(pp_slt)
 {
-    djSP; tryAMAGICbinSET(slt,0);
+    dSP; tryAMAGICbinSET(slt,0);
     {
       dPOPTOPssrl;
       int cmp = ((PL_op->op_private & OPpLOCALE)
@@ -1910,7 +1894,7 @@ PP(pp_slt)
 
 PP(pp_sgt)
 {
-    djSP; tryAMAGICbinSET(sgt,0);
+    dSP; tryAMAGICbinSET(sgt,0);
     {
       dPOPTOPssrl;
       int cmp = ((PL_op->op_private & OPpLOCALE)
@@ -1923,7 +1907,7 @@ PP(pp_sgt)
 
 PP(pp_sle)
 {
-    djSP; tryAMAGICbinSET(sle,0);
+    dSP; tryAMAGICbinSET(sle,0);
     {
       dPOPTOPssrl;
       int cmp = ((PL_op->op_private & OPpLOCALE)
@@ -1936,7 +1920,7 @@ PP(pp_sle)
 
 PP(pp_sge)
 {
-    djSP; tryAMAGICbinSET(sge,0);
+    dSP; tryAMAGICbinSET(sge,0);
     {
       dPOPTOPssrl;
       int cmp = ((PL_op->op_private & OPpLOCALE)
@@ -1949,7 +1933,7 @@ PP(pp_sge)
 
 PP(pp_seq)
 {
-    djSP; tryAMAGICbinSET(seq,0);
+    dSP; tryAMAGICbinSET(seq,0);
     {
       dPOPTOPssrl;
       SETs(boolSV(sv_eq(left, right)));
@@ -1959,7 +1943,7 @@ PP(pp_seq)
 
 PP(pp_sne)
 {
-    djSP; tryAMAGICbinSET(sne,0);
+    dSP; tryAMAGICbinSET(sne,0);
     {
       dPOPTOPssrl;
       SETs(boolSV(!sv_eq(left, right)));
@@ -1969,7 +1953,7 @@ PP(pp_sne)
 
 PP(pp_scmp)
 {
-    djSP; dTARGET;  tryAMAGICbin(scmp,0);
+    dSP; dTARGET;  tryAMAGICbin(scmp,0);
     {
       dPOPTOPssrl;
       int cmp = ((PL_op->op_private & OPpLOCALE)
@@ -1982,7 +1966,7 @@ PP(pp_scmp)
 
 PP(pp_bit_and)
 {
-    djSP; dATARGET; tryAMAGICbin(band,opASSIGN);
+    dSP; dATARGET; tryAMAGICbin(band,opASSIGN);
     {
       dPOPTOPssrl;
       if (SvNIOKp(left) || SvNIOKp(right)) {
@@ -2005,7 +1989,7 @@ PP(pp_bit_and)
 
 PP(pp_bit_xor)
 {
-    djSP; dATARGET; tryAMAGICbin(bxor,opASSIGN);
+    dSP; dATARGET; tryAMAGICbin(bxor,opASSIGN);
     {
       dPOPTOPssrl;
       if (SvNIOKp(left) || SvNIOKp(right)) {
@@ -2028,7 +2012,7 @@ PP(pp_bit_xor)
 
 PP(pp_bit_or)
 {
-    djSP; dATARGET; tryAMAGICbin(bor,opASSIGN);
+    dSP; dATARGET; tryAMAGICbin(bor,opASSIGN);
     {
       dPOPTOPssrl;
       if (SvNIOKp(left) || SvNIOKp(right)) {
@@ -2051,7 +2035,7 @@ PP(pp_bit_or)
 
 PP(pp_negate)
 {
-    djSP; dTARGET; tryAMAGICun(neg);
+    dSP; dTARGET; tryAMAGICun(neg);
     {
        dTOPss;
        int flags = SvFLAGS(sv);
@@ -2095,7 +2079,7 @@ PP(pp_negate)
                sv_setsv(TARG, sv);
                *SvPV_force(TARG, len) = *s == '-' ? '+' : '-';
            }
-           else if (DO_UTF8(sv) && *(U8*)s >= 0xc0 && isIDFIRST_utf8((U8*)s)) {
+           else if (DO_UTF8(sv) && UTF8_IS_START(*s) && isIDFIRST_utf8((U8*)s)) {
                sv_setpvn(TARG, "-", 1);
                sv_catsv(TARG, sv);
            }
@@ -2115,14 +2099,14 @@ PP(pp_negate)
 
 PP(pp_not)
 {
-    djSP; tryAMAGICunSET(not);
+    dSP; tryAMAGICunSET(not);
     *PL_stack_sp = boolSV(!SvTRUE(*PL_stack_sp));
     return NORMAL;
 }
 
 PP(pp_complement)
 {
-    djSP; dTARGET; tryAMAGICun(compl);
+    dSP; dTARGET; tryAMAGICun(compl);
     {
       dTOPss;
       if (SvNIOKp(sv)) {
@@ -2154,7 +2138,7 @@ PP(pp_complement)
 
          send = tmps + len;
          while (tmps < send) {
-           UV c = utf8_to_uv(tmps, send-tmps, &l, UTF8_ALLOW_ANYUV);
+           UV c = utf8n_to_uvchr(tmps, send-tmps, &l, UTF8_ALLOW_ANYUV);
            tmps += UTF8SKIP(tmps);
            targlen += UNISKIP(~c);
            nchar++;
@@ -2168,9 +2152,9 @@ PP(pp_complement)
          if (nwide) {
              Newz(0, result, targlen + 1, U8);
              while (tmps < send) {
-                 UV c = utf8_to_uv(tmps, send-tmps, &l, UTF8_ALLOW_ANYUV);
+                 UV c = utf8n_to_uvchr(tmps, send-tmps, &l, UTF8_ALLOW_ANYUV);
                  tmps += UTF8SKIP(tmps);
-                 result = uv_to_utf8(result, ~c);
+                 result = uvchr_to_utf8(result, ~c);
              }
              *result = '\0';
              result -= targlen;
@@ -2180,7 +2164,7 @@ PP(pp_complement)
          else {
              Newz(0, result, nchar + 1, U8);
              while (tmps < send) {
-                 U8 c = (U8)utf8_to_uv(tmps, 0, &l, UTF8_ALLOW_ANY);
+                 U8 c = (U8)utf8n_to_uvchr(tmps, 0, &l, UTF8_ALLOW_ANY);
                  tmps += UTF8SKIP(tmps);
                  *result++ = ~c;
              }
@@ -2216,7 +2200,7 @@ PP(pp_complement)
 
 PP(pp_i_multiply)
 {
-    djSP; dATARGET; tryAMAGICbin(mult,opASSIGN);
+    dSP; dATARGET; tryAMAGICbin(mult,opASSIGN);
     {
       dPOPTOPiirl;
       SETi( left * right );
@@ -2226,7 +2210,7 @@ PP(pp_i_multiply)
 
 PP(pp_i_divide)
 {
-    djSP; dATARGET; tryAMAGICbin(div,opASSIGN);
+    dSP; dATARGET; tryAMAGICbin(div,opASSIGN);
     {
       dPOPiv;
       if (value == 0)
@@ -2239,7 +2223,7 @@ PP(pp_i_divide)
 
 PP(pp_i_modulo)
 {
-    djSP; dATARGET; tryAMAGICbin(modulo,opASSIGN);
+    dSP; dATARGET; tryAMAGICbin(modulo,opASSIGN);
     {
       dPOPTOPiirl;
       if (!right)
@@ -2251,7 +2235,7 @@ PP(pp_i_modulo)
 
 PP(pp_i_add)
 {
-    djSP; dATARGET; tryAMAGICbin(add,opASSIGN);
+    dSP; dATARGET; tryAMAGICbin(add,opASSIGN);
     {
       dPOPTOPiirl_ul;
       SETi( left + right );
@@ -2261,7 +2245,7 @@ PP(pp_i_add)
 
 PP(pp_i_subtract)
 {
-    djSP; dATARGET; tryAMAGICbin(subtr,opASSIGN);
+    dSP; dATARGET; tryAMAGICbin(subtr,opASSIGN);
     {
       dPOPTOPiirl_ul;
       SETi( left - right );
@@ -2271,7 +2255,7 @@ PP(pp_i_subtract)
 
 PP(pp_i_lt)
 {
-    djSP; tryAMAGICbinSET(lt,0);
+    dSP; tryAMAGICbinSET(lt,0);
     {
       dPOPTOPiirl;
       SETs(boolSV(left < right));
@@ -2281,7 +2265,7 @@ PP(pp_i_lt)
 
 PP(pp_i_gt)
 {
-    djSP; tryAMAGICbinSET(gt,0);
+    dSP; tryAMAGICbinSET(gt,0);
     {
       dPOPTOPiirl;
       SETs(boolSV(left > right));
@@ -2291,7 +2275,7 @@ PP(pp_i_gt)
 
 PP(pp_i_le)
 {
-    djSP; tryAMAGICbinSET(le,0);
+    dSP; tryAMAGICbinSET(le,0);
     {
       dPOPTOPiirl;
       SETs(boolSV(left <= right));
@@ -2301,7 +2285,7 @@ PP(pp_i_le)
 
 PP(pp_i_ge)
 {
-    djSP; tryAMAGICbinSET(ge,0);
+    dSP; tryAMAGICbinSET(ge,0);
     {
       dPOPTOPiirl;
       SETs(boolSV(left >= right));
@@ -2311,7 +2295,7 @@ PP(pp_i_ge)
 
 PP(pp_i_eq)
 {
-    djSP; tryAMAGICbinSET(eq,0);
+    dSP; tryAMAGICbinSET(eq,0);
     {
       dPOPTOPiirl;
       SETs(boolSV(left == right));
@@ -2321,7 +2305,7 @@ PP(pp_i_eq)
 
 PP(pp_i_ne)
 {
-    djSP; tryAMAGICbinSET(ne,0);
+    dSP; tryAMAGICbinSET(ne,0);
     {
       dPOPTOPiirl;
       SETs(boolSV(left != right));
@@ -2331,7 +2315,7 @@ PP(pp_i_ne)
 
 PP(pp_i_ncmp)
 {
-    djSP; dTARGET; tryAMAGICbin(ncmp,0);
+    dSP; dTARGET; tryAMAGICbin(ncmp,0);
     {
       dPOPTOPiirl;
       I32 value;
@@ -2349,7 +2333,7 @@ PP(pp_i_ncmp)
 
 PP(pp_i_negate)
 {
-    djSP; dTARGET; tryAMAGICun(neg);
+    dSP; dTARGET; tryAMAGICun(neg);
     SETi(-TOPi);
     RETURN;
 }
@@ -2358,7 +2342,7 @@ PP(pp_i_negate)
 
 PP(pp_atan2)
 {
-    djSP; dTARGET; tryAMAGICbin(atan2,0);
+    dSP; dTARGET; tryAMAGICbin(atan2,0);
     {
       dPOPTOPnnrl;
       SETn(Perl_atan2(left, right));
@@ -2368,7 +2352,7 @@ PP(pp_atan2)
 
 PP(pp_sin)
 {
-    djSP; dTARGET; tryAMAGICun(sin);
+    dSP; dTARGET; tryAMAGICun(sin);
     {
       NV value;
       value = POPn;
@@ -2380,7 +2364,7 @@ PP(pp_sin)
 
 PP(pp_cos)
 {
-    djSP; dTARGET; tryAMAGICun(cos);
+    dSP; dTARGET; tryAMAGICun(cos);
     {
       NV value;
       value = POPn;
@@ -2407,7 +2391,7 @@ extern double drand48 (void);
 
 PP(pp_rand)
 {
-    djSP; dTARGET;
+    dSP; dTARGET;
     NV value;
     if (MAXARG < 1)
        value = 1.0;
@@ -2426,7 +2410,7 @@ PP(pp_rand)
 
 PP(pp_srand)
 {
-    djSP;
+    dSP;
     UV anum;
     if (MAXARG < 1)
        anum = seed();
@@ -2521,7 +2505,7 @@ S_seed(pTHX)
 
 PP(pp_exp)
 {
-    djSP; dTARGET; tryAMAGICun(exp);
+    dSP; dTARGET; tryAMAGICun(exp);
     {
       NV value;
       value = POPn;
@@ -2533,7 +2517,7 @@ PP(pp_exp)
 
 PP(pp_log)
 {
-    djSP; dTARGET; tryAMAGICun(log);
+    dSP; dTARGET; tryAMAGICun(log);
     {
       NV value;
       value = POPn;
@@ -2549,7 +2533,7 @@ PP(pp_log)
 
 PP(pp_sqrt)
 {
-    djSP; dTARGET; tryAMAGICun(sqrt);
+    dSP; dTARGET; tryAMAGICun(sqrt);
     {
       NV value;
       value = POPn;
@@ -2565,7 +2549,7 @@ PP(pp_sqrt)
 
 PP(pp_int)
 {
-    djSP; dTARGET;
+    dSP; dTARGET; tryAMAGICun(int);
     {
       NV value;
       IV iv = TOPi; /* attempt to convert to IV if possible. */
@@ -2593,6 +2577,7 @@ PP(pp_int)
                  (void)Perl_modf(tmp, &tmp);
                  value = (NV)tmp;
 #endif
+                 SETn(value);
              }
          }
          else {
@@ -2617,11 +2602,11 @@ PP(pp_int)
 
 PP(pp_abs)
 {
-    djSP; dTARGET; tryAMAGICun(abs);
+    dSP; dTARGET; tryAMAGICun(abs);
     {
       /* This will cache the NV value if string isn't actually integer  */
       IV iv = TOPi;
-      
+
       if (SvIOK(TOPs)) {
        /* IVX is precise  */
        if (SvIsUV(TOPs)) {
@@ -2637,7 +2622,7 @@ PP(pp_abs)
                 IV_MIN and -IV_MIN should both be %100...00 and NV-able  */
              SETu(IV_MIN);
            }
-         } 
+         }
        }
       } else{
        NV value = TOPn;
@@ -2651,7 +2636,7 @@ PP(pp_abs)
 
 PP(pp_hex)
 {
-    djSP; dTARGET;
+    dSP; dTARGET;
     char *tmps;
     STRLEN argtype;
     STRLEN n_a;
@@ -2664,7 +2649,7 @@ PP(pp_hex)
 
 PP(pp_oct)
 {
-    djSP; dTARGET;
+    dSP; dTARGET;
     NV value;
     STRLEN argtype;
     char *tmps;
@@ -2690,7 +2675,7 @@ PP(pp_oct)
 
 PP(pp_length)
 {
-    djSP; dTARGET;
+    dSP; dTARGET;
     SV *sv = TOPs;
 
     if (DO_UTF8(sv))
@@ -2702,48 +2687,65 @@ PP(pp_length)
 
 PP(pp_substr)
 {
-    djSP; dTARGET;
+    dSP; dTARGET;
     SV *sv;
     I32 len;
     STRLEN curlen;
-    STRLEN utfcurlen;
+    STRLEN utf8_curlen;
     I32 pos;
     I32 rem;
     I32 fail;
-    I32 lvalue = PL_op->op_flags & OPf_MOD;
+    I32 lvalue = PL_op->op_flags & OPf_MOD || LVRET;
     char *tmps;
     I32 arybase = PL_curcop->cop_arybase;
+    SV *repl_sv = NULL;
+    SV *repl_sv_copy = NULL;
     char *repl = 0;
     STRLEN repl_len;
+    int num_args = PL_op->op_private & 7;
+    bool repl_is_utf8 = FALSE;
 
     SvTAINTED_off(TARG);                       /* decontaminate */
     SvUTF8_off(TARG);                          /* decontaminate */
-    if (MAXARG > 2) {
-       if (MAXARG > 3) {
-           sv = POPs;
-           repl = SvPV(sv, repl_len);
+    if (num_args > 2) {
+       if (num_args > 3) {
+           repl_sv = POPs;
+           repl = SvPV(repl_sv, repl_len);
+           repl_is_utf8 = DO_UTF8(repl_sv) && SvCUR(repl_sv);
        }
        len = POPi;
     }
     pos = POPi;
     sv = POPs;
     PUTBACK;
+    if (repl_sv) {
+       if (repl_is_utf8) {
+           if (!DO_UTF8(sv))
+               sv_utf8_upgrade(sv);
+       }
+       else if (DO_UTF8(sv)) {
+           repl_sv_copy = newSVsv(repl_sv);
+           sv_utf8_upgrade(repl_sv_copy);
+           repl = SvPV(repl_sv_copy, repl_len);
+           repl_is_utf8 = DO_UTF8(repl_sv_copy) && SvCUR(sv);
+       }
+    }
     tmps = SvPV(sv, curlen);
     if (DO_UTF8(sv)) {
-        utfcurlen = sv_len_utf8(sv);
-       if (utfcurlen == curlen)
-           utfcurlen = 0;
+        utf8_curlen = sv_len_utf8(sv);
+       if (utf8_curlen == curlen)
+           utf8_curlen = 0;
        else
-           curlen = utfcurlen;
+           curlen = utf8_curlen;
     }
     else
-       utfcurlen = 0;
+       utf8_curlen = 0;
 
     if (pos >= arybase) {
        pos -= arybase;
        rem = curlen-pos;
        fail = rem;
-       if (MAXARG > 2) {
+       if (num_args > 2) {
            if (len < 0) {
                rem += len;
                if (rem < 0)
@@ -2755,7 +2757,7 @@ PP(pp_substr)
     }
     else {
        pos += curlen;
-       if (MAXARG < 3)
+       if (num_args < 3)
            rem = curlen;
        else if (len >= 0) {
            rem = pos+len;
@@ -2780,14 +2782,21 @@ PP(pp_substr)
        RETPUSHUNDEF;
     }
     else {
-       if (utfcurlen)
+       I32 upos = pos;
+       I32 urem = rem;
+       if (utf8_curlen)
            sv_pos_u2b(sv, &pos, &rem);
        tmps += pos;
        sv_setpvn(TARG, tmps, rem);
-       if (utfcurlen)
+       if (utf8_curlen)
            SvUTF8_on(TARG);
-       if (repl)
+       if (repl) {
            sv_insert(sv, pos, rem, repl, repl_len);
+           if (repl_is_utf8)
+               SvUTF8_on(sv);
+           if (repl_sv_copy)
+               SvREFCNT_dec(repl_sv_copy);
+       }
        else if (lvalue) {              /* it's an lvalue! */
            if (!SvGMAGICAL(sv)) {
                if (SvROK(sv)) {
@@ -2814,8 +2823,8 @@ PP(pp_substr)
                    SvREFCNT_dec(LvTARG(TARG));
                LvTARG(TARG) = SvREFCNT_inc(sv);
            }
-           LvTARGOFF(TARG) = pos;
-           LvTARGLEN(TARG) = rem;
+           LvTARGOFF(TARG) = upos;
+           LvTARGLEN(TARG) = urem;
        }
     }
     SPAGAIN;
@@ -2825,11 +2834,11 @@ PP(pp_substr)
 
 PP(pp_vec)
 {
-    djSP; dTARGET;
+    dSP; dTARGET;
     register IV size   = POPi;
     register IV offset = POPi;
     register SV *src = POPs;
-    I32 lvalue = PL_op->op_flags & OPf_MOD;
+    I32 lvalue = PL_op->op_flags & OPf_MOD || LVRET;
 
     SvTAINTED_off(TARG);               /* decontaminate */
     if (lvalue) {                      /* it's an lvalue! */
@@ -2854,7 +2863,7 @@ PP(pp_vec)
 
 PP(pp_index)
 {
-    djSP; dTARGET;
+    dSP; dTARGET;
     SV *big;
     SV *little;
     I32 offset;
@@ -2890,7 +2899,7 @@ PP(pp_index)
 
 PP(pp_rindex)
 {
-    djSP; dTARGET;
+    dSP; dTARGET;
     SV *big;
     SV *little;
     STRLEN blen;
@@ -2931,7 +2940,7 @@ PP(pp_rindex)
 
 PP(pp_sprintf)
 {
-    djSP; dMARK; dORIGMARK; dTARGET;
+    dSP; dMARK; dORIGMARK; dTARGET;
     do_sprintf(TARG, SP-MARK, MARK+1);
     TAINT_IF(SvTAINTED(TARG));
     SP = ORIGMARK;
@@ -2941,27 +2950,26 @@ PP(pp_sprintf)
 
 PP(pp_ord)
 {
-    djSP; dTARGET;
+    dSP; dTARGET;
     SV *argsv = POPs;
     STRLEN len;
     U8 *s = (U8*)SvPVx(argsv, len);
 
-    XPUSHu(DO_UTF8(argsv) ? utf8_to_uv_simple(s, 0) : (*s & 0xff));
+    XPUSHu(DO_UTF8(argsv) ? utf8_to_uvchr(s, 0) : (*s & 0xff));
     RETURN;
 }
 
 PP(pp_chr)
 {
-    djSP; dTARGET;
+    dSP; dTARGET;
     char *tmps;
     UV value = POPu;
 
     (void)SvUPGRADE(TARG,SVt_PV);
 
-    if ((value > 255 && !IN_BYTE) || (value & 0x80 && PL_hints & HINT_UTF8) ) {
-       SvGROW(TARG, UTF8_MAXLEN+1);
-       tmps = SvPVX(TARG);
-       tmps = (char*)uv_to_utf8((U8*)tmps, (UV)value);
+    if (value > 255 && !IN_BYTE) {
+       SvGROW(TARG, UNISKIP(value)+1);
+       tmps = (char*)uvchr_to_utf8((U8*)SvPVX(TARG), value);
        SvCUR_set(TARG, tmps - SvPVX(TARG));
        *tmps = '\0';
        (void)SvPOK_only(TARG);
@@ -2982,7 +2990,7 @@ PP(pp_chr)
 
 PP(pp_crypt)
 {
-    djSP; dTARGET; dPOPTOPssrl;
+    dSP; dTARGET; dPOPTOPssrl;
     STRLEN n_a;
 #ifdef HAS_CRYPT
     char *tmps = SvPV(left, n_a);
@@ -3001,26 +3009,26 @@ PP(pp_crypt)
 
 PP(pp_ucfirst)
 {
-    djSP;
+    dSP;
     SV *sv = TOPs;
     register U8 *s;
     STRLEN slen;
 
-    if (DO_UTF8(sv) && (s = (U8*)SvPV(sv, slen)) && slen && (*s & 0xc0) == 0xc0) {
+    if (DO_UTF8(sv) && (s = (U8*)SvPV(sv, slen)) && slen && UTF8_IS_START(*s)) {
        STRLEN ulen;
        U8 tmpbuf[UTF8_MAXLEN+1];
        U8 *tend;
-       UV uv = utf8_to_uv(s, slen, &ulen, 0);
+       UV uv;
 
        if (PL_op->op_private & OPpLOCALE) {
            TAINT;
            SvTAINTED_on(sv);
-           uv = toTITLE_LC_uni(uv);
+           uv = toTITLE_LC_uvchr(utf8n_to_uvchr(s, slen, &ulen, 0));
        }
        else
            uv = toTITLE_utf8(s);
        
-       tend = uv_to_utf8(tmpbuf, uv);
+       tend = uvchr_to_utf8(tmpbuf, uv);
 
        if (!SvPADTMP(sv) || tend - tmpbuf != ulen || SvREADONLY(sv)) {
            dTARGET;
@@ -3060,26 +3068,26 @@ PP(pp_ucfirst)
 
 PP(pp_lcfirst)
 {
-    djSP;
+    dSP;
     SV *sv = TOPs;
     register U8 *s;
     STRLEN slen;
 
-    if (DO_UTF8(sv) && (s = (U8*)SvPV(sv, slen)) && slen && (*s & 0xc0) == 0xc0) {
+    if (DO_UTF8(sv) && (s = (U8*)SvPV(sv, slen)) && slen && UTF8_IS_START(*s)) {
        STRLEN ulen;
        U8 tmpbuf[UTF8_MAXLEN+1];
        U8 *tend;
-       UV uv = utf8_to_uv(s, slen, &ulen, 0);
+       UV uv;
 
        if (PL_op->op_private & OPpLOCALE) {
            TAINT;
            SvTAINTED_on(sv);
-           uv = toLOWER_LC_uni(uv);
+           uv = toLOWER_LC_uvchr(utf8n_to_uvchr(s, slen, &ulen, 0));
        }
        else
            uv = toLOWER_utf8(s);
        
-       tend = uv_to_utf8(tmpbuf, uv);
+       tend = uvchr_to_utf8(tmpbuf, uv);
 
        if (!SvPADTMP(sv) || tend - tmpbuf != ulen || SvREADONLY(sv)) {
            dTARGET;
@@ -3119,7 +3127,7 @@ PP(pp_lcfirst)
 
 PP(pp_uc)
 {
-    djSP;
+    dSP;
     SV *sv = TOPs;
     register U8 *s;
     STRLEN len;
@@ -3146,13 +3154,13 @@ PP(pp_uc)
                TAINT;
                SvTAINTED_on(TARG);
                while (s < send) {
-                   d = uv_to_utf8(d, toUPPER_LC_uni( utf8_to_uv(s, len, &ulen, 0)));
+                   d = uvchr_to_utf8(d, toUPPER_LC_uvchr( utf8n_to_uvchr(s, len, &ulen, 0)));
                    s += ulen;
                }
            }
            else {
                while (s < send) {
-                   d = uv_to_utf8(d, toUPPER_utf8( s ));
+                   d = uvchr_to_utf8(d, toUPPER_utf8( s ));
                    s += UTF8SKIP(s);
                }
            }
@@ -3193,7 +3201,7 @@ PP(pp_uc)
 
 PP(pp_lc)
 {
-    djSP;
+    dSP;
     SV *sv = TOPs;
     register U8 *s;
     STRLEN len;
@@ -3220,13 +3228,13 @@ PP(pp_lc)
                TAINT;
                SvTAINTED_on(TARG);
                while (s < send) {
-                   d = uv_to_utf8(d, toLOWER_LC_uni( utf8_to_uv(s, len, &ulen, 0)));
+                   d = uvchr_to_utf8(d, toLOWER_LC_uvchr( utf8n_to_uvchr(s, len, &ulen, 0)));
                    s += ulen;
                }
            }
            else {
                while (s < send) {
-                   d = uv_to_utf8(d, toLOWER_utf8(s));
+                   d = uvchr_to_utf8(d, toLOWER_utf8(s));
                    s += UTF8SKIP(s);
                }
            }
@@ -3268,7 +3276,7 @@ PP(pp_lc)
 
 PP(pp_quotemeta)
 {
-    djSP; dTARGET;
+    dSP; dTARGET;
     SV *sv = TOPs;
     STRLEN len;
     register char *s = SvPV(sv,len);
@@ -3281,7 +3289,7 @@ PP(pp_quotemeta)
        d = SvPVX(TARG);
        if (DO_UTF8(sv)) {
            while (len) {
-               if (*s & 0x80) {
+               if (UTF8_IS_CONTINUED(*s)) {
                    STRLEN ulen = UTF8SKIP(s);
                    if (ulen > len)
                        ulen = len;
@@ -3321,10 +3329,10 @@ PP(pp_quotemeta)
 
 PP(pp_aslice)
 {
-    djSP; dMARK; dORIGMARK;
+    dSP; dMARK; dORIGMARK;
     register SV** svp;
     register AV* av = (AV*)POPs;
-    register I32 lval = PL_op->op_flags & OPf_MOD;
+    register I32 lval = (PL_op->op_flags & OPf_MOD || LVRET);
     I32 arybase = PL_curcop->cop_arybase;
     I32 elem;
 
@@ -3366,7 +3374,7 @@ PP(pp_aslice)
 
 PP(pp_each)
 {
-    djSP;
+    dSP;
     HV *hash = (HV*)POPs;
     HE *entry;
     I32 gimme = GIMME_V;
@@ -3408,7 +3416,7 @@ PP(pp_keys)
 
 PP(pp_delete)
 {
-    djSP;
+    dSP;
     I32 gimme = GIMME_V;
     I32 discard = (gimme == G_VOID) ? G_DISCARD : 0;
     SV *sv;
@@ -3472,7 +3480,7 @@ PP(pp_delete)
 
 PP(pp_exists)
 {
-    djSP;
+    dSP;
     SV *tmpsv;
     HV *hv;
 
@@ -3509,9 +3517,9 @@ PP(pp_exists)
 
 PP(pp_hslice)
 {
-    djSP; dMARK; dORIGMARK;
+    dSP; dMARK; dORIGMARK;
     register HV *hv = (HV*)POPs;
-    register I32 lval = PL_op->op_flags & OPf_MOD;
+    register I32 lval = (PL_op->op_flags & OPf_MOD || LVRET);
     I32 realhv = (SvTYPE(hv) == SVt_PVHV);
 
     if (!realhv && PL_op->op_private & OPpLVAL_INTRO)
@@ -3535,12 +3543,12 @@ PP(pp_hslice)
                    DIE(aTHX_ PL_no_helem, SvPV(keysv, n_a));
                }
                if (PL_op->op_private & OPpLVAL_INTRO) {
-                   if (preeminent) 
+                   if (preeminent)
                        save_helem(hv, keysv, svp);
                    else {
                        STRLEN keylen;
                        char *key = SvPV(keysv, keylen);
-                       save_delete(hv, key, keylen);
+                       SAVEDELETE(hv, savepvn(key,keylen), keylen);
                    }
                 }
            }
@@ -3559,7 +3567,7 @@ PP(pp_hslice)
 
 PP(pp_list)
 {
-    djSP; dMARK;
+    dSP; dMARK;
     if (GIMME != G_ARRAY) {
        if (++MARK <= SP)
            *MARK = *SP;                /* unwanted list, return last item */
@@ -3572,7 +3580,7 @@ PP(pp_list)
 
 PP(pp_lslice)
 {
-    djSP;
+    dSP;
     SV **lastrelem = PL_stack_sp;
     SV **lastlelem = PL_stack_base + POPMARK;
     SV **firstlelem = PL_stack_base + POPMARK + 1;
@@ -3627,7 +3635,7 @@ PP(pp_lslice)
 
 PP(pp_anonlist)
 {
-    djSP; dMARK; dORIGMARK;
+    dSP; dMARK; dORIGMARK;
     I32 items = SP - MARK;
     SV *av = sv_2mortal((SV*)av_make(items, MARK+1));
     SP = ORIGMARK;             /* av_make() might realloc stack_sp */
@@ -3637,7 +3645,7 @@ PP(pp_anonlist)
 
 PP(pp_anonhash)
 {
-    djSP; dMARK; dORIGMARK;
+    dSP; dMARK; dORIGMARK;
     HV* hv = (HV*)sv_2mortal((SV*)newHV());
 
     while (MARK < SP) {
@@ -3656,7 +3664,7 @@ PP(pp_anonhash)
 
 PP(pp_splice)
 {
-    djSP; dMARK; dORIGMARK;
+    dSP; dMARK; dORIGMARK;
     register AV *ary = (AV*)*++MARK;
     register SV **src;
     register SV **dst;
@@ -3858,7 +3866,7 @@ PP(pp_splice)
 
 PP(pp_push)
 {
-    djSP; dMARK; dORIGMARK; dTARGET;
+    dSP; dMARK; dORIGMARK; dTARGET;
     register AV *ary = (AV*)*++MARK;
     register SV *sv = &PL_sv_undef;
     MAGIC *mg;
@@ -3888,7 +3896,7 @@ PP(pp_push)
 
 PP(pp_pop)
 {
-    djSP;
+    dSP;
     AV *av = (AV*)POPs;
     SV *sv = av_pop(av);
     if (AvREAL(av))
@@ -3899,7 +3907,7 @@ PP(pp_pop)
 
 PP(pp_shift)
 {
-    djSP;
+    dSP;
     AV *av = (AV*)POPs;
     SV *sv = av_shift(av);
     EXTEND(SP, 1);
@@ -3913,7 +3921,7 @@ PP(pp_shift)
 
 PP(pp_unshift)
 {
-    djSP; dMARK; dORIGMARK; dTARGET;
+    dSP; dMARK; dORIGMARK; dTARGET;
     register AV *ary = (AV*)*++MARK;
     register SV *sv;
     register I32 i = 0;
@@ -3943,7 +3951,7 @@ PP(pp_unshift)
 
 PP(pp_reverse)
 {
-    djSP; dMARK;
+    dSP; dMARK;
     register SV *tmp;
     SV **oldsp = SP;
 
@@ -3975,20 +3983,17 @@ PP(pp_reverse)
                U8* s = (U8*)SvPVX(TARG);
                U8* send = (U8*)(s + len);
                while (s < send) {
-                   if (*s < 0x80) {
+                   if (UTF8_IS_INVARIANT(*s)) {
                        s++;
                        continue;
                    }
                    else {
+                       if (!utf8_to_uvchr(s, 0))
+                           break;
                        up = (char*)s;
                        s += UTF8SKIP(s);
                        down = (char*)(s - 1);
-                       if (s > send || !((*down & 0xc0) == 0x80)) {
-                           if (ckWARN_d(WARN_UTF8))
-                               Perl_warner(aTHX_ WARN_UTF8,
-                                           "Malformed UTF-8 character");
-                           break;
-                       }
+                       /* reverse this character */
                        while (down > up) {
                            tmp = *up;
                            *up++ = *down;
@@ -4052,9 +4057,10 @@ S_mul128(pTHX_ SV *sv, U8 m)
 #define ISUUCHAR(ch)    (memchr(PL_uuemap, (ch), sizeof(PL_uuemap)-1) || (ch) == ' ')
 #endif
 
+
 PP(pp_unpack)
 {
-    djSP;
+    dSP;
     dPOPPOPssrl;
     I32 start_sp_offset = SP - PL_stack_base;
     I32 gimme = GIMME_V;
@@ -4062,7 +4068,14 @@ PP(pp_unpack)
     STRLEN llen;
     STRLEN rlen;
     register char *pat = SvPV(left, llen);
+#ifdef PACKED_IS_OCTETS
+    /* Packed side is assumed to be octets - so force downgrade if it
+       has been UTF-8 encoded by accident
+     */
+    register char *s = SvPVbyte(right, rlen);
+#else
     register char *s = SvPV(right, rlen);
+#endif
     char *strend = s + rlen;
     char *strbeg = s;
     register char *patend = pat + llen;
@@ -4371,7 +4384,7 @@ PP(pp_unpack)
            if (checksum) {
                while (len-- > 0 && s < strend) {
                    STRLEN alen;
-                   auint = utf8_to_uv((U8*)s, strend - s, &alen, 0);
+                   auint = utf8n_to_uvchr((U8*)s, strend - s, &alen, 0);
                    along = alen;
                    s += along;
                    if (checksum > 32)
@@ -4385,7 +4398,7 @@ PP(pp_unpack)
                EXTEND_MORTAL(len);
                while (len-- > 0 && s < strend) {
                    STRLEN alen;
-                   auint = utf8_to_uv((U8*)s, strend - s, &alen, 0);
+                   auint = utf8n_to_uvchr((U8*)s, strend - s, &alen, 0);
                    along = alen;
                    s += along;
                    sv = NEWSV(37, 0);
@@ -4797,7 +4810,8 @@ PP(pp_unpack)
                
                while ((len > 0) && (s < strend)) {
                    auv = (auv << 7) | (*s & 0x7f);
-                   if (!(*s++ & 0x80)) {
+                   /* UTF8_IS_XXXXX not right here - using constant 0x80 */
+                   if ((U8)(*s++) < 0x80) {
                        bytes = 0;
                        sv = NEWSV(40, 0);
                        sv_setuv(sv, auv);
@@ -5141,7 +5155,7 @@ S_div128(pTHX_ SV *pnum, bool *done)
 
 PP(pp_pack)
 {
-    djSP; dMARK; dORIGMARK; dTARGET;
+    dSP; dMARK; dORIGMARK; dTARGET;
     register SV *cat = TARG;
     register I32 items;
     STRLEN fromlen;
@@ -5189,8 +5203,10 @@ PP(pp_pack)
            patcopy++;
            continue;
         }
+#ifndef PACKED_IS_OCTETS
        if (datumtype == 'U' && pat == patcopy+1)
            SvUTF8_on(cat);
+#endif
        if (datumtype == '#') {
            while (pat < patend && *pat != '\n')
                pat++;
@@ -5423,7 +5439,7 @@ PP(pp_pack)
                fromstr = NEXTFROM;
                auint = SvUV(fromstr);
                SvGROW(cat, SvCUR(cat) + UTF8_MAXLEN + 1);
-               SvCUR_set(cat, (char*)uv_to_utf8((U8*)SvEND(cat),auint)
+               SvCUR_set(cat, (char*)uvchr_to_utf8((U8*)SvEND(cat),auint)
                               - SvPVX(cat));
            }
            *SvEND(cat) = '\0';
@@ -5735,7 +5751,7 @@ PP(pp_pack)
 
 PP(pp_split)
 {
-    djSP; dTARG;
+    dSP; dTARG;
     AV *ary;
     register IV limit = POPi;                  /* note, negative is forever */
     SV *sv = POPs;
@@ -5871,7 +5887,8 @@ PP(pp_split)
            s = m;
        }
     }
-    else if ((rx->reganch & RE_USE_INTUIT) && !rx->nparens
+    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)) {
        int tail = (rx->reganch & RE_INTUIT_TAIL);
@@ -6057,7 +6074,7 @@ Perl_unlock_condpair(pTHX_ void *svv)
 
 PP(pp_lock)
 {
-    djSP;
+    dSP;
     dTOPss;
     SV *retsv = sv;
 #ifdef USE_THREADS
@@ -6074,7 +6091,7 @@ PP(pp_lock)
 PP(pp_threadsv)
 {
 #ifdef USE_THREADS
-    djSP;
+    dSP;
     EXTEND(SP, 1);
     if (PL_op->op_private & OPpLVAL_INTRO)
        PUSHs(*save_threadsv(PL_op->op_targ));