This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Add a new macro SvPV_free() which undoes OOK and free()s the PVX(),
[perl5.git] / sv.c
diff --git a/sv.c b/sv.c
index dff1b89..f2e6206 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -49,7 +49,7 @@
 
 #ifdef PERL_COPY_ON_WRITE
 #define SV_COW_NEXT_SV(sv)     INT2PTR(SV *,SvUVX(sv))
-#define SV_COW_NEXT_SV_SET(current,next)       SvUVX(current) = PTR2UV(next)
+#define SV_COW_NEXT_SV_SET(current,next)       SvUV_set(current, PTR2UV(next))
 /* This is a pessimistic view. Scalar must be purely a read-write PV to copy-
    on-write.  */
 #endif
@@ -416,10 +416,10 @@ do_clean_objs(pTHX_ SV *sv)
        if (SvWEAKREF(sv)) {
            sv_del_backref(sv);
            SvWEAKREF_off(sv);
-           SvRV(sv) = 0;
+           SvRV_set(sv, NULL);
        } else {
            SvROK_off(sv);
-           SvRV(sv) = 0;
+           SvRV_set(sv, NULL);
            SvREFCNT_dec(rv);
        }
     }
@@ -645,6 +645,7 @@ Perl_sv_free_arenas(pTHX)
 STATIC SV*
 S_find_hash_subscript(pTHX_ HV *hv, SV* val)
 {
+    dVAR;
     register HE **array;
     register HE *entry;
     I32 i;
@@ -790,6 +791,7 @@ PL_comppad/PL_curpad points to the currently executing pad.
 STATIC SV *
 S_find_uninit_var(pTHX_ OP* obase, SV* uninit_sv, bool match)
 {
+    dVAR;
     SV *sv;
     AV *av;
     SV **svp;
@@ -1777,13 +1779,13 @@ bool
 Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
 {
 
-    char*      pv = NULL;
-    U32                cur = 0;
-    U32                len = 0;
-    IV         iv = 0;
-    NV         nv = 0.0;
-    MAGIC*     magic = NULL;
-    HV*                stash = Nullhv;
+    char*      pv;
+    U32                cur;
+    U32                len;
+    IV         iv;
+    NV         nv;
+    MAGIC*     magic;
+    HV*                stash;
 
     if (mt != SVt_PV && SvIsCOW(sv)) {
        sv_force_normal_flags(sv, 0);
@@ -1792,64 +1794,39 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
     if (SvTYPE(sv) == mt)
        return TRUE;
 
-    if (mt < SVt_PVIV)
-       (void)SvOOK_off(sv);
+    pv = NULL;
+    cur = 0;
+    len = 0;
+    iv = 0;
+    nv = 0.0;
+    magic = NULL;
+    stash = Nullhv;
 
     switch (SvTYPE(sv)) {
     case SVt_NULL:
-       pv      = 0;
-       cur     = 0;
-       len     = 0;
-       iv      = 0;
-       nv      = 0.0;
-       magic   = 0;
-       stash   = 0;
        break;
     case SVt_IV:
-       pv      = 0;
-       cur     = 0;
-       len     = 0;
        iv      = SvIVX(sv);
-       nv      = (NV)SvIVX(sv);
        del_XIV(SvANY(sv));
-       magic   = 0;
-       stash   = 0;
        if (mt == SVt_NV)
            mt = SVt_PVNV;
        else if (mt < SVt_PVIV)
            mt = SVt_PVIV;
        break;
     case SVt_NV:
-       pv      = 0;
-       cur     = 0;
-       len     = 0;
        nv      = SvNVX(sv);
-       iv      = I_V(nv);
-       magic   = 0;
-       stash   = 0;
        del_XNV(SvANY(sv));
-       SvANY(sv) = 0;
        if (mt < SVt_PVNV)
            mt = SVt_PVNV;
        break;
     case SVt_RV:
        pv      = (char*)SvRV(sv);
-       cur     = 0;
-       len     = 0;
-       iv      = PTR2IV(pv);
-       nv      = PTR2NV(pv);
        del_XRV(SvANY(sv));
-       magic   = 0;
-       stash   = 0;
        break;
     case SVt_PV:
        pv      = SvPVX(sv);
        cur     = SvCUR(sv);
        len     = SvLEN(sv);
-       iv      = 0;
-       nv      = 0.0;
-       magic   = 0;
-       stash   = 0;
        del_XPV(SvANY(sv));
        if (mt <= SVt_IV)
            mt = SVt_PVIV;
@@ -1861,9 +1838,6 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
        cur     = SvCUR(sv);
        len     = SvLEN(sv);
        iv      = SvIVX(sv);
-       nv      = 0.0;
-       magic   = 0;
-       stash   = 0;
        del_XPVIV(SvANY(sv));
        break;
     case SVt_PVNV:
@@ -1872,8 +1846,6 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
        len     = SvLEN(sv);
        iv      = SvIVX(sv);
        nv      = SvNVX(sv);
-       magic   = 0;
-       stash   = 0;
        del_XPVNV(SvANY(sv));
        break;
     case SVt_PVMG:
@@ -1906,153 +1878,115 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
        break;
     case SVt_RV:
        SvANY(sv) = new_XRV();
-       SvRV(sv) = (SV*)pv;
-       break;
-    case SVt_PV:
-       SvANY(sv) = new_XPV();
-       SvPVX(sv)       = pv;
-       SvCUR(sv)       = cur;
-       SvLEN(sv)       = len;
-       break;
-    case SVt_PVIV:
-       SvANY(sv) = new_XPVIV();
-       SvPVX(sv)       = pv;
-       SvCUR(sv)       = cur;
-       SvLEN(sv)       = len;
-       SvIV_set(sv, iv);
-       if (SvNIOK(sv))
-           (void)SvIOK_on(sv);
-       SvNOK_off(sv);
-       break;
-    case SVt_PVNV:
-       SvANY(sv) = new_XPVNV();
-       SvPVX(sv)       = pv;
-       SvCUR(sv)       = cur;
-       SvLEN(sv)       = len;
-       SvIV_set(sv, iv);
-       SvNV_set(sv, nv);
-       break;
-    case SVt_PVMG:
-       SvANY(sv) = new_XPVMG();
-       SvPVX(sv)       = pv;
-       SvCUR(sv)       = cur;
-       SvLEN(sv)       = len;
-       SvIV_set(sv, iv);
-       SvNV_set(sv, nv);
-       SvMAGIC(sv)     = magic;
-       SvSTASH(sv)     = stash;
-       break;
-    case SVt_PVLV:
-       SvANY(sv) = new_XPVLV();
-       SvPVX(sv)       = pv;
-       SvCUR(sv)       = cur;
-       SvLEN(sv)       = len;
-       SvIV_set(sv, iv);
-       SvNV_set(sv, nv);
-       SvMAGIC(sv)     = magic;
-       SvSTASH(sv)     = stash;
-       LvTARGOFF(sv)   = 0;
-       LvTARGLEN(sv)   = 0;
-       LvTARG(sv)      = 0;
-       LvTYPE(sv)      = 0;
-       GvGP(sv)        = 0;
-       GvNAME(sv)      = 0;
-       GvNAMELEN(sv)   = 0;
-       GvSTASH(sv)     = 0;
-       GvFLAGS(sv)     = 0;
-       break;
-    case SVt_PVAV:
-       SvANY(sv) = new_XPVAV();
-       if (pv)
-           Safefree(pv);
-       SvPVX(sv)       = 0;
-       AvMAX(sv)       = -1;
-       AvFILLp(sv)     = -1;
-       SvIV_set(sv, 0);
-       SvNV_set(sv, 0.0);
-       SvMAGIC(sv)     = magic;
-       SvSTASH(sv)     = stash;
-       AvALLOC(sv)     = 0;
-       AvARYLEN(sv)    = 0;
-       AvFLAGS(sv)     = AVf_REAL;
+       SvRV_set(sv, (SV*)pv);
        break;
     case SVt_PVHV:
        SvANY(sv) = new_XPVHV();
-       if (pv)
-           Safefree(pv);
-       SvPVX(sv)       = 0;
-       HvFILL(sv)      = 0;
-       HvMAX(sv)       = 0;
-       HvTOTALKEYS(sv) = 0;
-       HvPLACEHOLDERS(sv) = 0;
-       SvMAGIC(sv)     = magic;
-       SvSTASH(sv)     = stash;
        HvRITER(sv)     = 0;
        HvEITER(sv)     = 0;
        HvPMROOT(sv)    = 0;
        HvNAME(sv)      = 0;
+       HvFILL(sv)      = 0;
+       HvMAX(sv)       = 0;
+       HvTOTALKEYS(sv) = 0;
+       HvPLACEHOLDERS(sv) = 0;
+
+       /* Fall through...  */
+       if (0) {
+       case SVt_PVAV:
+           SvANY(sv) = new_XPVAV();
+           AvMAX(sv)   = -1;
+           AvFILLp(sv) = -1;
+           AvALLOC(sv) = 0;
+           AvARYLEN(sv)= 0;
+           AvFLAGS(sv) = AVf_REAL;
+           SvIV_set(sv, 0);
+           SvNV_set(sv, 0.0);
+       }
+       /* to here.  */
+       /* XXX? Only SVt_NULL is ever upgraded to AV or HV?  */
+       assert(!pv);
+       /* FIXME. Should be able to remove all this if()... if the above
+          assertion is genuinely always true.  */
+       if(SvOOK(sv)) {
+           pv -= iv;
+           SvFLAGS(sv) &= ~SVf_OOK;
+       }
+       Safefree(pv);
+       SvPV_set(sv, (char*)0);
+       SvMAGIC_set(sv, magic);
+       SvSTASH_set(sv, stash);
        break;
+
+    case SVt_PVIO:
+       SvANY(sv) = new_XPVIO();
+       Zero(SvANY(sv), 1, XPVIO);
+       IoPAGE_LEN(sv)  = 60;
+       goto set_magic_common;
+    case SVt_PVFM:
+       SvANY(sv) = new_XPVFM();
+       Zero(SvANY(sv), 1, XPVFM);
+       goto set_magic_common;
+    case SVt_PVBM:
+       SvANY(sv) = new_XPVBM();
+       BmRARE(sv)      = 0;
+       BmUSEFUL(sv)    = 0;
+       BmPREVIOUS(sv)  = 0;
+       goto set_magic_common;
+    case SVt_PVGV:
+       SvANY(sv) = new_XPVGV();
+       GvGP(sv)        = 0;
+       GvNAME(sv)      = 0;
+       GvNAMELEN(sv)   = 0;
+       GvSTASH(sv)     = 0;
+       GvFLAGS(sv)     = 0;
+       goto set_magic_common;
     case SVt_PVCV:
        SvANY(sv) = new_XPVCV();
        Zero(SvANY(sv), 1, XPVCV);
-       SvPVX(sv)       = pv;
-       SvCUR(sv)       = cur;
-       SvLEN(sv)       = len;
-       SvIV_set(sv, iv);
-       SvNV_set(sv, nv);
-       SvMAGIC(sv)     = magic;
-       SvSTASH(sv)     = stash;
-       break;
-    case SVt_PVGV:
-       SvANY(sv) = new_XPVGV();
-       SvPVX(sv)       = pv;
-       SvCUR(sv)       = cur;
-       SvLEN(sv)       = len;
-       SvIV_set(sv, iv);
-       SvNV_set(sv, nv);
-       SvMAGIC(sv)     = magic;
-       SvSTASH(sv)     = stash;
+       goto set_magic_common;
+    case SVt_PVLV:
+       SvANY(sv) = new_XPVLV();
+       LvTARGOFF(sv)   = 0;
+       LvTARGLEN(sv)   = 0;
+       LvTARG(sv)      = 0;
+       LvTYPE(sv)      = 0;
        GvGP(sv)        = 0;
        GvNAME(sv)      = 0;
        GvNAMELEN(sv)   = 0;
        GvSTASH(sv)     = 0;
        GvFLAGS(sv)     = 0;
-       break;
-    case SVt_PVBM:
-       SvANY(sv) = new_XPVBM();
-       SvPVX(sv)       = pv;
-       SvCUR(sv)       = cur;
-       SvLEN(sv)       = len;
-       SvIV_set(sv, iv);
-       SvNV_set(sv, nv);
-       SvMAGIC(sv)     = magic;
-       SvSTASH(sv)     = stash;
-       BmRARE(sv)      = 0;
-       BmUSEFUL(sv)    = 0;
-       BmPREVIOUS(sv)  = 0;
-       break;
-    case SVt_PVFM:
-       SvANY(sv) = new_XPVFM();
-       Zero(SvANY(sv), 1, XPVFM);
-       SvPVX(sv)       = pv;
-       SvCUR(sv)       = cur;
-       SvLEN(sv)       = len;
-       SvIV_set(sv, iv);
+       /* Fall through.  */
+       if (0) {
+       case SVt_PVMG:
+           SvANY(sv) = new_XPVMG();
+       }
+    set_magic_common:
+       SvMAGIC_set(sv, magic);
+       SvSTASH_set(sv, stash);
+       /* Fall through.  */
+       if (0) {
+       case SVt_PVNV:
+           SvANY(sv) = new_XPVNV();
+       }
        SvNV_set(sv, nv);
-       SvMAGIC(sv)     = magic;
-       SvSTASH(sv)     = stash;
-       break;
-    case SVt_PVIO:
-       SvANY(sv) = new_XPVIO();
-       Zero(SvANY(sv), 1, XPVIO);
-       SvPVX(sv)       = pv;
-       SvCUR(sv)       = cur;
-       SvLEN(sv)       = len;
+       /* Fall through.  */
+       if (0) {
+       case SVt_PVIV:
+           SvANY(sv) = new_XPVIV();
+           if (SvNIOK(sv))
+               (void)SvIOK_on(sv);
+           SvNOK_off(sv);
+       }
        SvIV_set(sv, iv);
-       SvNV_set(sv, nv);
-       SvMAGIC(sv)     = magic;
-       SvSTASH(sv)     = stash;
-       IoPAGE_LEN(sv)  = 60;
+       /* Fall through.  */
+       if (0) {
+       case SVt_PV:
+           SvANY(sv) = new_XPV();
+       }
+       SvPV_set(sv, pv);
+       SvCUR_set(sv, cur);
+       SvLEN_set(sv, len);
        break;
     }
     return TRUE;
@@ -2073,8 +2007,8 @@ Perl_sv_backoff(pTHX_ register SV *sv)
     assert(SvOOK(sv));
     if (SvIVX(sv)) {
        char *s = SvPVX(sv);
-       SvLEN(sv) += SvIVX(sv);
-       SvPVX(sv) -= SvIVX(sv);
+       SvLEN_set(sv, SvLEN(sv) + SvIVX(sv));
+       SvPV_set(sv, SvPVX(sv) - SvIVX(sv));
        SvIV_set(sv, 0);
        Move(s, SvPVX(sv), SvCUR(sv)+1, char);
     }
@@ -2226,7 +2160,7 @@ Perl_sv_setuv(pTHX_ register SV *sv, UV u)
     }
     sv_setiv(sv, 0);
     SvIsUV_on(sv);
-    SvUVX(sv) = u;
+    SvUV_set(sv, u);
 }
 
 /*
@@ -2509,7 +2443,7 @@ S_sv_2iuv_non_preserve(pTHX_ register SV *sv, I32 numtype)
        (void)SvIOKp_on(sv);
        (void)SvNOK_on(sv);
        SvIsUV_on(sv);
-       SvUVX(sv) = UV_MAX;
+       SvUV_set(sv, UV_MAX);
        return IS_NUMBER_OVERFLOW_UV;
     }
     (void)SvIOKp_on(sv);
@@ -2526,7 +2460,7 @@ S_sv_2iuv_non_preserve(pTHX_ register SV *sv, I32 numtype)
         return SvNVX(sv) < 0 ? IS_NUMBER_UNDERFLOW_UV : IS_NUMBER_IV_AND_UV;
     }
     SvIsUV_on(sv);
-    SvUVX(sv) = U_V(SvNVX(sv));
+    SvUV_set(sv, U_V(SvNVX(sv)));
     if ((NV)(SvUVX(sv)) == SvNVX(sv)) {
         if (SvUVX(sv) == UV_MAX) {
             /* As we know that NVs don't preserve UVs, UV_MAX cannot
@@ -2663,7 +2597,7 @@ Perl_sv_2iv_flags(pTHX_ register SV *sv, I32 flags)
               0x8000000000000000 which will be exact. NWC */
        }
        else {
-           SvUVX(sv) = U_V(SvNVX(sv));
+           SvUV_set(sv, U_V(SvNVX(sv)));
            if (
                (SvNVX(sv) == (NV) SvUVX(sv))
 #ifndef  NV_PRESERVES_UV
@@ -2728,7 +2662,7 @@ Perl_sv_2iv_flags(pTHX_ register SV *sv, I32 flags)
                if (value <= (UV)IV_MAX) {
                    SvIV_set(sv, (IV)value);
                } else {
-                   SvUVX(sv) = value;
+                   SvUV_set(sv, value);
                    SvIsUV_on(sv);
                }
            } else {
@@ -2784,10 +2718,10 @@ Perl_sv_2iv_flags(pTHX_ register SV *sv, I32 flags)
                if (SvNVX(sv) > (NV)UV_MAX) {
                    SvIsUV_on(sv);
                    /* Integer is inaccurate. NOK, IOKp, is UV */
-                   SvUVX(sv) = UV_MAX;
+                   SvUV_set(sv, UV_MAX);
                    SvIsUV_on(sv);
                } else {
-                   SvUVX(sv) = U_V(SvNVX(sv));
+                   SvUV_set(sv, U_V(SvNVX(sv)));
                    /* 0xFFFFFFFFFFFFFFFF not an issue in here */
                    if ((NV)(SvUVX(sv)) == SvNVX(sv)) {
                        SvIOK_on(sv);
@@ -2968,7 +2902,7 @@ Perl_sv_2uv_flags(pTHX_ register SV *sv, I32 flags)
               0x8000000000000000 which will be exact. NWC */
        }
        else {
-           SvUVX(sv) = U_V(SvNVX(sv));
+           SvUV_set(sv, U_V(SvNVX(sv)));
            if (
                (SvNVX(sv) == (NV) SvUVX(sv))
 #ifndef  NV_PRESERVES_UV
@@ -3030,7 +2964,7 @@ Perl_sv_2uv_flags(pTHX_ register SV *sv, I32 flags)
                    SvIV_set(sv, (IV)value);
                } else {
                    /* it didn't overflow, and it was positive. */
-                   SvUVX(sv) = value;
+                   SvUV_set(sv, value);
                    SvIsUV_on(sv);
                }
            } else {
@@ -3082,10 +3016,10 @@ Perl_sv_2uv_flags(pTHX_ register SV *sv, I32 flags)
                 if (SvNVX(sv) > (NV)UV_MAX) {
                     SvIsUV_on(sv);
                     /* Integer is inaccurate. NOK, IOKp, is UV */
-                    SvUVX(sv) = UV_MAX;
+                    SvUV_set(sv, UV_MAX);
                     SvIsUV_on(sv);
                 } else {
-                    SvUVX(sv) = U_V(SvNVX(sv));
+                    SvUV_set(sv, U_V(SvNVX(sv)));
                     /* 0xFFFFFFFFFFFFFFFF not an issue in here, NVs
                        NV preservse UV so can do correct comparison.  */
                     if ((NV)(SvUVX(sv)) == SvNVX(sv)) {
@@ -3281,7 +3215,7 @@ Perl_sv_2nv(pTHX_ register SV *sv)
                 } else if (value <= (UV)IV_MAX) {
                    SvIV_set(sv, (IV)value);
                } else {
-                   SvUVX(sv) = value;
+                   SvUV_set(sv, value);
                    SvIsUV_on(sv);
                }
 
@@ -3738,6 +3672,7 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
        return SvPVX(tsv);
     }
     else {
+        dVAR;
        STRLEN len;
         const char *t;
 
@@ -3995,11 +3930,11 @@ Perl_sv_utf8_upgrade_flags(pTHX_ register SV *sv, I32 flags)
              (void)SvOOK_off(sv);
              s = (U8*)SvPVX(sv);
              len = SvCUR(sv) + 1; /* Plus the \0 */
-             SvPVX(sv) = (char*)bytes_to_utf8((U8*)s, &len);
-             SvCUR(sv) = len - 1;
+             SvPV_set(sv, (char*)bytes_to_utf8((U8*)s, &len));
+             SvCUR_set(sv, len - 1);
              if (SvLEN(sv) != 0)
                   Safefree(s); /* No longer using what was there before. */
-             SvLEN(sv) = len; /* No longer know the real size. */
+             SvLEN_set(sv, len); /* No longer know the real size. */
         }
         /* Mark as UTF-8 even if no hibit - saves scanning loop */
         SvUTF8_on(sv);
@@ -4044,7 +3979,7 @@ Perl_sv_utf8_downgrade(pTHX_ register SV* sv, bool fail_ok)
                        Perl_croak(aTHX_ "Wide character");
                }
            }
-           SvCUR(sv) = len;
+           SvCUR_set(sv, len);
        }
     }
     SvUTF8_off(sv);
@@ -4483,14 +4418,13 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
                return;
            }
            if (SvPVX(dstr)) {
-               (void)SvOOK_off(dstr);          /* backoff */
-               if (SvLEN(dstr))
-                   Safefree(SvPVX(dstr));
-               SvLEN(dstr)=SvCUR(dstr)=0;
+               SvPV_free(dstr);
+               SvLEN_set(dstr, 0);
+                SvCUR_set(dstr, 0);
            }
        }
        (void)SvOK_off(dstr);
-       SvRV(dstr) = SvREFCNT_inc(SvRV(sstr));
+       SvRV_set(dstr, SvREFCNT_inc(SvRV(sstr)));
        SvROK_on(dstr);
        if (sflags & SVp_NOK) {
            SvNOKp_on(dstr);
@@ -4610,10 +4544,10 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
                     SvPV_set(dstr,
                              sharepvn(SvPVX(sstr),
                                       (sflags & SVf_UTF8?-cur:cur), hash));
-                    SvUVX(dstr) = hash;
+                    SvUV_set(dstr, hash);
                 }
-                SvLEN(dstr) = len;
-                SvCUR(dstr) = cur;
+                SvLEN_set(dstr, len);
+                SvCUR_set(dstr, cur);
                 SvREADONLY_on(dstr);
                 SvFAKE_on(dstr);
                 /* Relesase a global SV mutex.  */
@@ -4752,7 +4686,7 @@ Perl_sv_setsv_cow(pTHX_ SV *dstr, SV *sstr)
            UV hash = SvUVX(sstr);
            DEBUG_C(PerlIO_printf(Perl_debug_log,
                                  "Fast copy on write: Sharing hash\n"));
-           SvUVX(dstr) = hash;
+           SvUV_set(dstr, hash);
            new_pv = sharepvn(SvPVX(sstr), (SvUTF8(sstr)?-cur:cur), hash);
            goto common_exit;
        }
@@ -4774,8 +4708,8 @@ Perl_sv_setsv_cow(pTHX_ SV *dstr, SV *sstr)
     SvFLAGS(dstr) = (SVt_PVIV|SVf_POK|SVp_POK|SVf_FAKE|SVf_READONLY);
     if (SvUTF8(sstr))
        SvUTF8_on(dstr);
-    SvLEN(dstr) = len;
-    SvCUR(dstr) = cur;
+    SvLEN_set(dstr, len);
+    SvCUR_set(dstr, cur);
     if (DEBUG_C_TEST) {
        sv_dump(dstr);
     }
@@ -4902,11 +4836,10 @@ Perl_sv_usepvn(pTHX_ register SV *sv, register char *ptr, register STRLEN len)
        (void)SvOK_off(sv);
        return;
     }
-    (void)SvOOK_off(sv);
-    if (SvPVX(sv) && SvLEN(sv))
-       Safefree(SvPVX(sv));
+    if (SvPVX(sv))
+       SvPV_free(sv);
     Renew(ptr, len+1, char);
-    SvPVX(sv) = ptr;
+    SvPV_set(sv, ptr);
     SvCUR_set(sv, len);
     SvLEN_set(sv, len+1);
     *SvEND(sv) = '\0';
@@ -5014,15 +4947,15 @@ Perl_sv_force_normal_flags(pTHX_ register SV *sv, U32 flags)
             SvFAKE_off(sv);
             SvREADONLY_off(sv);
             /* This SV doesn't own the buffer, so need to New() a new one:  */
-            SvPVX(sv) = 0;
-            SvLEN(sv) = 0;
+            SvPV_set(sv, (char*)0);
+            SvLEN_set(sv, 0);
             if (flags & SV_COW_DROP_PV) {
                 /* OK, so we don't need to copy our buffer.  */
                 SvPOK_off(sv);
             } else {
                 SvGROW(sv, cur + 1);
                 Move(pvx,SvPVX(sv),cur,char);
-                SvCUR(sv) = cur;
+                SvCUR_set(sv, cur);
                 *SvEND(sv) = '\0';
             }
             sv_release_COW(sv, pvx, cur, len, hash, next);
@@ -5043,8 +4976,8 @@ Perl_sv_force_normal_flags(pTHX_ register SV *sv, U32 flags)
             U32 hash   = SvUVX(sv);
            SvFAKE_off(sv);
            SvREADONLY_off(sv);
-            SvPVX(sv) = 0;
-            SvLEN(sv) = 0;
+            SvPV_set(sv, (char*)0);
+            SvLEN_set(sv, 0);
            SvGROW(sv, len + 1);
            Move(pvx,SvPVX(sv),len,char);
            *SvEND(sv) = '\0';
@@ -5115,9 +5048,9 @@ Perl_sv_chop(pTHX_ register SV *sv, register char *ptr)
        SvFLAGS(sv) |= SVf_OOK;
     }
     SvNIOK_off(sv);
-    SvLEN(sv) -= delta;
-    SvCUR(sv) -= delta;
-    SvPVX(sv) += delta;
+    SvLEN_set(sv, SvLEN(sv) - delta);
+    SvCUR_set(sv, SvCUR(sv) - delta);
+    SvPV_set(sv, SvPVX(sv) + delta);
     SvIV_set(sv, SvIVX(sv) + delta);
 }
 
@@ -5162,7 +5095,7 @@ Perl_sv_catpvn_flags(pTHX_ register SV *dsv, register const char *sstr, register
     if (sstr == dstr)
        sstr = SvPVX(dsv);
     Move(sstr, SvPVX(dsv) + dlen, slen, char);
-    SvCUR(dsv) += slen;
+    SvCUR_set(dsv, SvCUR(dsv) + slen);
     *SvEND(dsv) = '\0';
     (void)SvPOK_only_UTF8(dsv);                /* validate pointer */
     SvTAINT(dsv);
@@ -5285,7 +5218,7 @@ Perl_sv_catpv(pTHX_ register SV *sv, register const char *ptr)
     if (ptr == junk)
        ptr = SvPVX(sv);
     Move(ptr,SvPVX(sv)+tlen,len+1,char);
-    SvCUR(sv) += len;
+    SvCUR_set(sv, SvCUR(sv) + len);
     (void)SvPOK_only_UTF8(sv);         /* validate pointer */
     SvTAINT(sv);
 }
@@ -5357,7 +5290,7 @@ Perl_sv_magicext(pTHX_ SV* sv, SV* obj, int how, const MGVTBL *vtable,
     }
     Newz(702,mg, 1, MAGIC);
     mg->mg_moremagic = SvMAGIC(sv);
-    SvMAGIC(sv) = mg;
+    SvMAGIC_set(sv, mg);
 
     /* Sometimes a magic contains a reference loop, where the sv and
        object refer to each other.  To prevent a reference loop that
@@ -5577,7 +5510,7 @@ Perl_sv_magic(pTHX_ register SV *sv, SV *obj, int how, const char *name, I32 nam
     }
 
     /* Rest of work is done else where */
-    mg = sv_magicext(sv,obj,how,vtable,name,namlen);
+    mg = sv_magicext(sv,obj,how,(MGVTBL*)vtable,name,namlen);
 
     switch (how) {
     case PERL_MAGIC_taint:
@@ -5758,7 +5691,7 @@ Perl_sv_insert(pTHX_ SV *bigstr, STRLEN offset, STRLEN len, const char *little,
        while (midend > mid)            /* shove everything down */
            *--bigend = *--midend;
        Move(little,big+offset,littlelen,char);
-       SvCUR(bigstr) += i;
+       SvCUR_set(bigstr, SvCUR(bigstr) + i);
        SvSETMAGIC(bigstr);
        return;
     }
@@ -5836,10 +5769,10 @@ Perl_sv_replace(pTHX_ register SV *sv, register SV *nsv)
            mg_free(nsv);
        else
            sv_upgrade(nsv, SVt_PVMG);
-       SvMAGIC(nsv) = SvMAGIC(sv);
+       SvMAGIC_set(nsv, SvMAGIC(sv));
        SvFLAGS(nsv) |= SvMAGICAL(sv);
        SvMAGICAL_off(sv);
-       SvMAGIC(sv) = 0;
+       SvMAGIC_set(sv, NULL);
     }
     SvREFCNT(sv) = 0;
     sv_clear(sv);
@@ -5897,6 +5830,7 @@ instead.
 void
 Perl_sv_clear(pTHX_ register SV *sv)
 {
+    dVAR;
     HV* stash;
     assert(sv);
     assert(SvREFCNT(sv) == 0);
@@ -5929,7 +5863,7 @@ Perl_sv_clear(pTHX_ register SV *sv)
                    if(SvREFCNT(tmpref) < 2) {
                        /* tmpref is not kept alive! */
                        SvREFCNT(sv)--;
-                       SvRV(tmpref) = 0;
+                       SvRV_set(tmpref, NULL);
                        SvROK_off(tmpref);
                    }
                    SvREFCNT_dec(tmpref);
@@ -6010,7 +5944,11 @@ Perl_sv_clear(pTHX_ register SV *sv)
     case SVt_PVNV:
     case SVt_PVIV:
       freescalar:
-       SvOOK_off(sv);
+       /* Don't bother with SvOOK_off(sv); as we're only going to free it.  */
+       if (SvOOK(sv)) {
+           SvPV_set(sv, SvPVX(sv) - SvIVX(sv));
+           /* Don't even bother with turning off the OOK flag.  */
+       }
        /* FALL THROUGH */
     case SVt_PV:
     case SVt_RV:
@@ -6146,6 +6084,7 @@ Normally called via a wrapper macro C<SvREFCNT_dec>.
 void
 Perl_sv_free(pTHX_ SV *sv)
 {
+    dVAR;
     if (!sv)
        return;
     if (SvREFCNT(sv) == 0) {
@@ -6174,6 +6113,7 @@ Perl_sv_free(pTHX_ SV *sv)
 void
 Perl_sv_free2(pTHX_ SV *sv)
 {
+    dVAR;
 #ifdef DEBUGGING
     if (SvTEMP(sv)) {
        if (ckWARN_d(WARN_DEBUGGING))
@@ -6284,7 +6224,7 @@ S_utf8_mg_pos_init(pTHX_ SV *sv, MAGIC **mgp, STRLEN **cachep, I32 i, I32 *offse
 
     if (SvMAGICAL(sv) && !SvREADONLY(sv)) {
        if (!*mgp)
-           *mgp = sv_magicext(sv, 0, PERL_MAGIC_utf8, &PL_vtbl_utf8, 0, 0);
+           *mgp = sv_magicext(sv, 0, PERL_MAGIC_utf8, (MGVTBL*)&PL_vtbl_utf8, 0, 0);
        assert(*mgp);
 
        if ((*mgp)->mg_ptr)
@@ -6473,7 +6413,7 @@ Perl_sv_pos_u2b(pTHX_ register SV *sv, I32* offsetp, I32* lenp)
         if (lenp) {
              found = FALSE;
              start = s;
-              if (utf8_mg_pos(sv, &mg, &cache, 2, lenp, *lenp + *offsetp, &s, start, send)) {
+              if (utf8_mg_pos(sv, &mg, &cache, 2, lenp, *lenp, &s, start, send)) {
                   *lenp -= boffset;
                   found = TRUE;
               }
@@ -7208,17 +7148,7 @@ thats_really_all_folks:
    else
     {
        /*The big, slow, and stupid way. */
-
-      /* Any stack-challenged places. */
-#if defined(EPOC)
-      /* EPOC: need to work around SDK features.         *
-       * On WINS: MS VC5 generates calls to _chkstk,     *
-       * if a "large" stack frame is allocated.          *
-       * gcc on MARM does not generate calls like these. */
-#   define USEHEAPINSTEADOFSTACK
-#endif
-
-#ifdef USEHEAPINSTEADOFSTACK
+#ifdef USE_HEAP_INSTEAD_OF_STACK       /* Even slower way. */
        STDCHAR *buf = 0;
        New(0, buf, 8192, STDCHAR);
        assert(buf);
@@ -7273,7 +7203,7 @@ screamer2:
                goto screamer2;
        }
 
-#ifdef USEHEAPINSTEADOFSTACK
+#ifdef USE_HEAP_INSTEAD_OF_STACK
        Safefree(buf);
 #endif
     }
@@ -7344,7 +7274,7 @@ Perl_sv_inc(pTHX_ register SV *sv)
                sv_setnv(sv, UV_MAX_P1);
            else
                (void)SvIOK_only_UV(sv);
-               ++SvUVX(sv);
+               SvUV_set(sv, SvUVX(sv) + 1);
        } else {
            if (SvIVX(sv) == IV_MAX)
                sv_setuv(sv, (UV)IV_MAX + 1);
@@ -7440,7 +7370,7 @@ Perl_sv_inc(pTHX_ register SV *sv)
     }
     /* oh,oh, the number grew */
     SvGROW(sv, SvCUR(sv) + 2);
-    SvCUR(sv)++;
+    SvCUR_set(sv, SvCUR(sv) + 1);
     for (d = SvPVX(sv) + SvCUR(sv); d > SvPVX(sv); d--)
        *d = d[-1];
     if (isDIGIT(d[1]))
@@ -7498,7 +7428,7 @@ Perl_sv_dec(pTHX_ register SV *sv)
            }
            else {
                (void)SvIOK_only_UV(sv);
-               --SvUVX(sv);
+               SvUV_set(sv, SvUVX(sv) + 1);
            }   
        } else {
            if (SvIVX(sv) == IV_MIN)
@@ -7626,6 +7556,7 @@ and C<sv_mortalcopy>.
 SV *
 Perl_sv_2mortal(pTHX_ register SV *sv)
 {
+    dVAR;
     if (!sv)
        return sv;
     if (SvREADONLY(sv) && SvIMMORTAL(sv))
@@ -7709,10 +7640,10 @@ Perl_newSVpvn_share(pTHX_ const char *src, I32 len, U32 hash)
        PERL_HASH(hash, src, len);
     new_SV(sv);
     sv_upgrade(sv, SVt_PVIV);
-    SvPVX(sv) = sharepvn(src, is_utf8?-len:len, hash);
-    SvCUR(sv) = len;
-    SvUVX(sv) = hash;
-    SvLEN(sv) = 0;
+    SvPV_set(sv, sharepvn(src, is_utf8?-len:len, hash));
+    SvCUR_set(sv, len);
+    SvUV_set(sv, hash);
+    SvLEN_set(sv, 0);
     SvREADONLY_on(sv);
     SvFAKE_on(sv);
     SvPOK_on(sv);
@@ -7847,7 +7778,7 @@ Perl_newRV_noinc(pTHX_ SV *tmpRef)
     new_SV(sv);
     sv_upgrade(sv, SVt_RV);
     SvTEMP_off(tmpRef);
-    SvRV(sv) = tmpRef;
+    SvRV_set(sv, tmpRef);
     SvROK_on(sv);
     return sv;
 }
@@ -7903,6 +7834,7 @@ Note that the perl-level function is vaguely deprecated.
 void
 Perl_sv_reset(pTHX_ register const char *s, HV *stash)
 {
+    dVAR;
     register HE *entry;
     register GV *gv;
     register SV *sv;
@@ -8035,6 +7967,7 @@ possible to set C<*st> and C<*gvp> to the stash and GV associated with it.
 CV *
 Perl_sv_2cv(pTHX_ SV *sv, HV **st, GV **gvp, I32 lref)
 {
+    dVAR;
     GV *gv = Nullgv;
     CV *cv = Nullcv;
 
@@ -8552,15 +8485,13 @@ Perl_newSVrv(pTHX_ SV *rv, const char *classname)
     if (SvTYPE(rv) < SVt_RV)
        sv_upgrade(rv, SVt_RV);
     else if (SvTYPE(rv) > SVt_RV) {
-       SvOOK_off(rv);
-       if (SvPVX(rv) && SvLEN(rv))
-           Safefree(SvPVX(rv));
+       SvPV_free(rv);
        SvCUR_set(rv, 0);
        SvLEN_set(rv, 0);
     }
 
     SvOK_off(rv);
-    SvRV(rv) = sv;
+    SvRV_set(rv, sv);
     SvROK_on(rv);
 
     if (classname) {
@@ -8709,7 +8640,7 @@ Perl_sv_bless(pTHX_ SV *sv, HV *stash)
     if (SvTYPE(tmpRef) != SVt_PVIO)
        ++PL_sv_objcount;
     (void)SvUPGRADE(tmpRef, SVt_PVMG);
-    SvSTASH(tmpRef) = (HV*)SvREFCNT_inc(stash);
+    SvSTASH_set(tmpRef, (HV*)SvREFCNT_inc(stash));
 
     if (Gv_AMG(stash))
        SvAMAGIC_on(sv);
@@ -8777,10 +8708,10 @@ Perl_sv_unref_flags(pTHX_ SV *sv, U32 flags)
     if (SvWEAKREF(sv)) {
        sv_del_backref(sv);
        SvWEAKREF_off(sv);
-       SvRV(sv) = 0;
+       SvRV_set(sv, NULL);
        return;
     }
-    SvRV(sv) = 0;
+    SvRV_set(sv, NULL);
     SvROK_off(sv);
     /* You can't have a || SvREADONLY(rv) here, as $a = $$a, where $a was
        assigned to as BEGIN {$a = \"Foo"} will fail.  */
@@ -9187,7 +9118,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
     char *patend;
     STRLEN origlen;
     I32 svix = 0;
-    static char nullstr[] = "(null)";
+    static const char nullstr[] = "(null)";
     SV *argsv = Nullsv;
     bool has_utf8; /* has the result utf8? */
     bool pat_utf8; /* the pattern is in utf8? */
@@ -9590,7 +9521,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
 #endif
                    elen = strlen(eptr);
                else {
-                   eptr = nullstr;
+                   eptr = (char *)nullstr;
                    elen = sizeof nullstr - 1;
                }
            }
@@ -9822,19 +9753,6 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                }
                break;
            default:            /* it had better be ten or less */
-#if defined(PERL_Y2KWARN)
-               if (ckWARN(WARN_Y2K)) {
-                   STRLEN n;
-                   char *s = SvPV(sv,n);
-                   if (n >= 2 && s[n-2] == '1' && s[n-1] == '9'
-                       && (n == 2 || !isDIGIT(s[n-3])))
-                   {
-                       Perl_warner(aTHX_ packWARN(WARN_Y2K),
-                                   "Possible Y2K bug: %%%c %s",
-                                   c, "format string following '19'");
-                   }
-               }
-#endif
                do {
                    dig = uv % base;
                    *--eptr = '0' + dig;
@@ -10107,7 +10025,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            Copy(eptr, p, elen, char);
            p += elen;
            *p = '\0';
-           SvCUR(sv) = p - SvPVX(sv);
+           SvCUR_set(sv, p - SvPVX(sv));
            svix = osvix;
            continue;   /* not "break" */
        }
@@ -10173,7 +10091,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
        if (has_utf8)
            SvUTF8_on(sv);
        *p = '\0';
-       SvCUR(sv) = p - SvPVX(sv);
+       SvCUR_set(sv, p - SvPVX(sv));
        if (vectorize) {
            esignlen = 0;
            goto vector;
@@ -10226,6 +10144,7 @@ ptr_table_* functions.
 REGEXP *
 Perl_re_dup(pTHX_ REGEXP *r, CLONE_PARAMS *param)
 {
+    dVAR;
     REGEXP *ret;
     int i, len, npar;
     struct reg_substr_datum *s;
@@ -10618,10 +10537,6 @@ Perl_ptr_table_free(pTHX_ PTR_TBL_t *tbl)
     Safefree(tbl);
 }
 
-#ifdef DEBUGGING
-char *PL_watch_pvx;
-#endif
-
 /* attempt to make everything in the typeglob readonly */
 
 STATIC SV *
@@ -10685,15 +10600,16 @@ void
 Perl_rvpv_dup(pTHX_ SV *dstr, SV *sstr, CLONE_PARAMS* param)
 {
     if (SvROK(sstr)) {
-       SvRV(dstr) = SvWEAKREF(sstr)
-                    ? sv_dup(SvRV(sstr), param)
-                    : sv_dup_inc(SvRV(sstr), param);
+       SvRV_set(dstr, SvWEAKREF(sstr)
+                      ? sv_dup(SvRV(sstr), param)
+                      : sv_dup_inc(SvRV(sstr), param));
+
     }
     else if (SvPVX(sstr)) {
        /* Has something there */
        if (SvLEN(sstr)) {
            /* Normal PV - clone whole allocated space */
-           SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1);
+           SvPV_set(dstr, SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1));
            if (SvREADONLY(sstr) && SvFAKE(sstr)) {
                /* Not that normal - actually sstr is copy on write.
                   But we are a true, independant SV, so:  */
@@ -10710,31 +10626,35 @@ Perl_rvpv_dup(pTHX_ SV *dstr, SV *sstr, CLONE_PARAMS* param)
                        and they should not have these flags
                        turned off */
 
-                    SvPVX(dstr) = sharepvn(SvPVX(sstr), SvCUR(sstr),
-                                           SvUVX(sstr));
-                    SvUVX(dstr) = SvUVX(sstr);
+                    SvPV_set(dstr, sharepvn(SvPVX(sstr), SvCUR(sstr),
+                                           SvUVX(sstr)));
+                    SvUV_set(dstr, SvUVX(sstr));
                 } else {
 
-                    SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvCUR(sstr));
+                    SvPV_set(dstr, SAVEPVN(SvPVX(sstr), SvCUR(sstr)));
                     SvFAKE_off(dstr);
                     SvREADONLY_off(dstr);
                 }
            }
            else {
                /* Some other special case - random pointer */
-               SvPVX(dstr) = SvPVX(sstr);              
+               SvPV_set(dstr, SvPVX(sstr));            
            }
        }
     }
     else {
        /* Copy the Null */
-       SvPVX(dstr) = SvPVX(sstr);
+       if (SvTYPE(dstr) == SVt_RV)
+           SvRV_set(dstr, NULL);
+       else
+           SvPV_set(dstr, 0);
     }
 }
 
 SV *
 Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
 {
+    dVAR;
     SV *dstr;
 
     if (!sstr || SvTYPE(sstr) == SVTYPEMASK)
@@ -10784,6 +10704,13 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
                      PL_watch_pvx, SvPVX(sstr));
 #endif
 
+    /* don't clone objects whose class has asked us not to */
+    if (SvOBJECT(sstr) && ! (SvFLAGS(SvSTASH(sstr)) & SVphv_CLONEABLE)) {
+       SvFLAGS(dstr) &= ~SVTYPEMASK;
+       SvOBJECT_off(dstr);
+       return dstr;
+    }
+
     switch (SvTYPE(sstr)) {
     case SVt_NULL:
        SvANY(dstr)     = NULL;
@@ -10802,43 +10729,43 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
        break;
     case SVt_PV:
        SvANY(dstr)     = new_XPV();
-       SvCUR(dstr)     = SvCUR(sstr);
-       SvLEN(dstr)     = SvLEN(sstr);
+       SvCUR_set(dstr, SvCUR(sstr));
+       SvLEN_set(dstr, SvLEN(sstr));
        Perl_rvpv_dup(aTHX_ dstr, sstr, param);
        break;
     case SVt_PVIV:
        SvANY(dstr)     = new_XPVIV();
-       SvCUR(dstr)     = SvCUR(sstr);
-       SvLEN(dstr)     = SvLEN(sstr);
+       SvCUR_set(dstr, SvCUR(sstr));
+       SvLEN_set(dstr, SvLEN(sstr));
        SvIV_set(dstr, SvIVX(sstr));
        Perl_rvpv_dup(aTHX_ dstr, sstr, param);
        break;
     case SVt_PVNV:
        SvANY(dstr)     = new_XPVNV();
-       SvCUR(dstr)     = SvCUR(sstr);
-       SvLEN(dstr)     = SvLEN(sstr);
+       SvCUR_set(dstr, SvCUR(sstr));
+       SvLEN_set(dstr, SvLEN(sstr));
        SvIV_set(dstr, SvIVX(sstr));
        SvNV_set(dstr, SvNVX(sstr));
        Perl_rvpv_dup(aTHX_ dstr, sstr, param);
        break;
     case SVt_PVMG:
        SvANY(dstr)     = new_XPVMG();
-       SvCUR(dstr)     = SvCUR(sstr);
-       SvLEN(dstr)     = SvLEN(sstr);
+       SvCUR_set(dstr, SvCUR(sstr));
+       SvLEN_set(dstr, SvLEN(sstr));
        SvIV_set(dstr, SvIVX(sstr));
        SvNV_set(dstr, SvNVX(sstr));
-       SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr), param);
-       SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr), param);
+       SvMAGIC_set(dstr, mg_dup(SvMAGIC(sstr), param));
+       SvSTASH_set(dstr, hv_dup_inc(SvSTASH(sstr), param));
        Perl_rvpv_dup(aTHX_ dstr, sstr, param);
        break;
     case SVt_PVBM:
        SvANY(dstr)     = new_XPVBM();
-       SvCUR(dstr)     = SvCUR(sstr);
-       SvLEN(dstr)     = SvLEN(sstr);
+       SvCUR_set(dstr, SvCUR(sstr));
+       SvLEN_set(dstr, SvLEN(sstr));
        SvIV_set(dstr, SvIVX(sstr));
        SvNV_set(dstr, SvNVX(sstr));
-       SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr), param);
-       SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr), param);
+       SvMAGIC_set(dstr, mg_dup(SvMAGIC(sstr), param));
+       SvSTASH_set(dstr, hv_dup_inc(SvSTASH(sstr), param));
        Perl_rvpv_dup(aTHX_ dstr, sstr, param);
        BmRARE(dstr)    = BmRARE(sstr);
        BmUSEFUL(dstr)  = BmUSEFUL(sstr);
@@ -10846,12 +10773,12 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
        break;
     case SVt_PVLV:
        SvANY(dstr)     = new_XPVLV();
-       SvCUR(dstr)     = SvCUR(sstr);
-       SvLEN(dstr)     = SvLEN(sstr);
+       SvCUR_set(dstr, SvCUR(sstr));
+       SvLEN_set(dstr, SvLEN(sstr));
        SvIV_set(dstr, SvIVX(sstr));
        SvNV_set(dstr, SvNVX(sstr));
-       SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr), param);
-       SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr), param);
+       SvMAGIC_set(dstr, mg_dup(SvMAGIC(sstr), param));
+       SvSTASH_set(dstr, hv_dup_inc(SvSTASH(sstr), param));
        Perl_rvpv_dup(aTHX_ dstr, sstr, param);
        LvTARGOFF(dstr) = LvTARGOFF(sstr);      /* XXX sometimes holds PMOP* when DEBUGGING */
        LvTARGLEN(dstr) = LvTARGLEN(sstr);
@@ -10878,12 +10805,12 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
             }
        }
        SvANY(dstr)     = new_XPVGV();
-       SvCUR(dstr)     = SvCUR(sstr);
-       SvLEN(dstr)     = SvLEN(sstr);
+       SvCUR_set(dstr, SvCUR(sstr));
+       SvLEN_set(dstr, SvLEN(sstr));
        SvIV_set(dstr, SvIVX(sstr));
        SvNV_set(dstr, SvNVX(sstr));
-       SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr), param);
-       SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr), param);
+       SvMAGIC_set(dstr, mg_dup(SvMAGIC(sstr), param));
+       SvSTASH_set(dstr, hv_dup_inc(SvSTASH(sstr), param));
        Perl_rvpv_dup(aTHX_ dstr, sstr, param);
        GvNAMELEN(dstr) = GvNAMELEN(sstr);
        GvNAME(dstr)    = SAVEPVN(GvNAME(sstr), GvNAMELEN(sstr));
@@ -10894,12 +10821,12 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
        break;
     case SVt_PVIO:
        SvANY(dstr)     = new_XPVIO();
-       SvCUR(dstr)     = SvCUR(sstr);
-       SvLEN(dstr)     = SvLEN(sstr);
+       SvCUR_set(dstr, SvCUR(sstr));
+       SvLEN_set(dstr, SvLEN(sstr));
        SvIV_set(dstr, SvIVX(sstr));
        SvNV_set(dstr, SvNVX(sstr));
-       SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr), param);
-       SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr), param);
+       SvMAGIC_set(dstr, mg_dup(SvMAGIC(sstr), param));
+       SvSTASH_set(dstr, hv_dup_inc(SvSTASH(sstr), param));
        Perl_rvpv_dup(aTHX_ dstr, sstr, param);
        IoIFP(dstr)     = fp_dup(IoIFP(sstr), IoTYPE(sstr), param);
        if (IoOFP(sstr) == IoIFP(sstr))
@@ -10936,12 +10863,12 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
        break;
     case SVt_PVAV:
        SvANY(dstr)     = new_XPVAV();
-       SvCUR(dstr)     = SvCUR(sstr);
-       SvLEN(dstr)     = SvLEN(sstr);
+       SvCUR_set(dstr, SvCUR(sstr));
+       SvLEN_set(dstr, SvLEN(sstr));
        SvIV_set(dstr, SvIVX(sstr));
        SvNV_set(dstr, SvNVX(sstr));
-       SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr), param);
-       SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr), param);
+       SvMAGIC_set(dstr, mg_dup(SvMAGIC(sstr), param));
+       SvSTASH_set(dstr, hv_dup_inc(SvSTASH(sstr), param));
        AvARYLEN((AV*)dstr) = sv_dup_inc(AvARYLEN((AV*)sstr), param);
        AvFLAGS((AV*)dstr) = AvFLAGS((AV*)sstr);
        if (AvARRAY((AV*)sstr)) {
@@ -10951,7 +10878,7 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
            src_ary = AvARRAY((AV*)sstr);
            Newz(0, dst_ary, AvMAX((AV*)sstr)+1, SV*);
            ptr_table_store(PL_ptr_table, src_ary, dst_ary);
-           SvPVX(dstr) = (char*)dst_ary;
+           SvPV_set(dstr, (char*)dst_ary);
            AvALLOC((AV*)dstr) = dst_ary;
            if (AvREAL((AV*)sstr)) {
                while (items-- > 0)
@@ -10967,18 +10894,18 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
            }
        }
        else {
-           SvPVX(dstr)         = Nullch;
+           SvPV_set(dstr, Nullch);
            AvALLOC((AV*)dstr)  = (SV**)NULL;
        }
        break;
     case SVt_PVHV:
        SvANY(dstr)     = new_XPVHV();
-       SvCUR(dstr)     = SvCUR(sstr);
-       SvLEN(dstr)     = SvLEN(sstr);
+       SvCUR_set(dstr, SvCUR(sstr));
+       SvLEN_set(dstr, SvLEN(sstr));
        SvIV_set(dstr, SvIVX(sstr));
        SvNV_set(dstr, SvNVX(sstr));
-       SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr), param);
-       SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr), param);
+       SvMAGIC_set(dstr, mg_dup(SvMAGIC(sstr), param));
+       SvSTASH_set(dstr, hv_dup_inc(SvSTASH(sstr), param));
        HvRITER((HV*)dstr)      = HvRITER((HV*)sstr);
        if (HvARRAY((HV*)sstr)) {
            STRLEN i = 0;
@@ -10996,7 +10923,7 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
                                     (bool)!!HvSHAREKEYS(sstr), param);
        }
        else {
-           SvPVX(dstr)         = Nullch;
+           SvPV_set(dstr, Nullch);
            HvEITER((HV*)dstr)  = (HE*)NULL;
        }
        HvPMROOT((HV*)dstr)     = HvPMROOT((HV*)sstr);          /* XXX */
@@ -11013,12 +10940,12 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
     case SVt_PVCV:
        SvANY(dstr)     = new_XPVCV();
         dup_pvcv:
-       SvCUR(dstr)     = SvCUR(sstr);
-       SvLEN(dstr)     = SvLEN(sstr);
+       SvCUR_set(dstr, SvCUR(sstr));
+       SvLEN_set(dstr, SvLEN(sstr));
        SvIV_set(dstr, SvIVX(sstr));
        SvNV_set(dstr, SvNVX(sstr));
-       SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr), param);
-       SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr), param);
+       SvMAGIC_set(dstr, mg_dup(SvMAGIC(sstr), param));
+       SvSTASH_set(dstr, hv_dup_inc(SvSTASH(sstr), param));
        Perl_rvpv_dup(aTHX_ dstr, sstr, param);
        CvSTASH(dstr)   = hv_dup(CvSTASH(sstr), param); /* NOTE: not refcounted */
        CvSTART(dstr)   = CvSTART(sstr);
@@ -11499,6 +11426,40 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
     return nss;
 }
 
+
+/* if sv is a stash, call $class->CLONE_SKIP(), and set the SVphv_CLONEABLE
+ * flag to the result. This is done for each stash before cloning starts,
+ * so we know which stashes want their objects cloned */
+
+static void
+do_mark_cloneable_stash(pTHX_ SV *sv)
+{
+    if (HvNAME((HV*)sv)) {
+       GV* cloner = gv_fetchmethod_autoload((HV*)sv, "CLONE_SKIP", 0);
+       SvFLAGS(sv) |= SVphv_CLONEABLE; /* clone objects by default */
+       if (cloner && GvCV(cloner)) {
+           dSP;
+           UV status;
+
+           ENTER;
+           SAVETMPS;
+           PUSHMARK(SP);
+           XPUSHs(sv_2mortal(newSVpv(HvNAME((HV*)sv), 0)));
+           PUTBACK;
+           call_sv((SV*)GvCV(cloner), G_SCALAR);
+           SPAGAIN;
+           status = POPu;
+           PUTBACK;
+           FREETMPS;
+           LEAVE;
+           if (status)
+               SvFLAGS(sv) &= ~SVphv_CLONEABLE;
+       }
+    }
+}
+
+
+
 /*
 =for apidoc perl_clone
 
@@ -11543,6 +11504,7 @@ perl_clone_host(PerlInterpreter* proto_perl, UV flags);
 PerlInterpreter *
 perl_clone(PerlInterpreter *proto_perl, UV flags)
 {
+   dVAR;
 #ifdef PERL_IMPLICIT_SYS
 
    /* perlhost.h so we need to call into it
@@ -11580,6 +11542,8 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     CLONE_PARAMS* param = &clone_params;
 
     PerlInterpreter *my_perl = (PerlInterpreter*)(*ipM->pMalloc)(ipM, sizeof(PerlInterpreter));
+    /* for each stash, determine whether its objects should be cloned */
+    S_visit(proto_perl, do_mark_cloneable_stash, SVt_PVHV, SVTYPEMASK);
     PERL_SET_THX(my_perl);
 
 #  ifdef DEBUGGING
@@ -11612,10 +11576,10 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     CLONE_PARAMS clone_params;
     CLONE_PARAMS* param = &clone_params;
     PerlInterpreter *my_perl = (PerlInterpreter*)PerlMem_malloc(sizeof(PerlInterpreter));
+    /* for each stash, determine whether its objects should be cloned */
+    S_visit(proto_perl, do_mark_cloneable_stash, SVt_PVHV, SVTYPEMASK);
     PERL_SET_THX(my_perl);
 
-
-
 #    ifdef DEBUGGING
     Poison(my_perl, 1, PerlInterpreter);
     PL_op = Nullop;
@@ -11691,9 +11655,9 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     SvREFCNT(&PL_sv_no)                = (~(U32)0)/2;
     SvFLAGS(&PL_sv_no)         = SVp_IOK|SVf_IOK|SVp_NOK|SVf_NOK
                                  |SVp_POK|SVf_POK|SVf_READONLY|SVt_PVNV;
-    SvPVX(&PL_sv_no)           = SAVEPVN(PL_No, 0);
-    SvCUR(&PL_sv_no)           = 0;
-    SvLEN(&PL_sv_no)           = 1;
+    SvPV_set(&PL_sv_no, SAVEPVN(PL_No, 0));
+    SvCUR_set(&PL_sv_no, 0);
+    SvLEN_set(&PL_sv_no, 1);
     SvIV_set(&PL_sv_no, 0);
     SvNV_set(&PL_sv_no, 0);
     ptr_table_store(PL_ptr_table, &proto_perl->Isv_no, &PL_sv_no);
@@ -11702,9 +11666,9 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     SvREFCNT(&PL_sv_yes)       = (~(U32)0)/2;
     SvFLAGS(&PL_sv_yes)                = SVp_IOK|SVf_IOK|SVp_NOK|SVf_NOK
                                  |SVp_POK|SVf_POK|SVf_READONLY|SVt_PVNV;
-    SvPVX(&PL_sv_yes)          = SAVEPVN(PL_Yes, 1);
-    SvCUR(&PL_sv_yes)          = 1;
-    SvLEN(&PL_sv_yes)          = 2;
+    SvPV_set(&PL_sv_yes, SAVEPVN(PL_Yes, 1));
+    SvCUR_set(&PL_sv_yes, 1);
+    SvLEN_set(&PL_sv_yes, 2);
     SvIV_set(&PL_sv_yes, 1);
     SvNV_set(&PL_sv_yes, 1);
     ptr_table_store(PL_ptr_table, &proto_perl->Isv_yes, &PL_sv_yes);
@@ -12323,7 +12287,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
            ENTER;
            SAVETMPS;
            PUSHMARK(SP);
-           XPUSHs(sv_2mortal(newSVpv(HvNAME(stash), 0)));
+           XPUSHs(sv_2mortal(newSVpv(HvNAME(stash), 0)));
            PUTBACK;
            call_sv((SV*)GvCV(cloner), G_DISCARD);
            FREETMPS;
@@ -12359,6 +12323,7 @@ The PV of the sv is returned.
 char *
 Perl_sv_recode_to_utf8(pTHX_ SV *sv, SV *encoding)
 {
+    dVAR;
     if (SvPOK(sv) && !SvUTF8(sv) && !IN_BYTES && SvROK(encoding)) {
        SV *uni;
        STRLEN len;
@@ -12420,6 +12385,7 @@ bool
 Perl_sv_cat_decode(pTHX_ SV *dsv, SV *encoding,
                   SV *ssv, int *offset, char *tstr, int tlen)
 {
+    dVAR;
     bool ret = FALSE;
     if (SvPOK(ssv) && SvPOK(dsv) && SvROK(encoding) && offset) {
        SV *offsv;