This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Integrate:
[perl5.git] / sv.c
diff --git a/sv.c b/sv.c
index 046b98e..80ee63c 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -1,7 +1,7 @@
 /*    sv.c
  *
  *    Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- *    2000, 2001, 2002, 2003, 2004, by Larry Wall and others
+ *    2000, 2001, 2002, 2003, 2004, 2005, 2006, by Larry Wall and others
  *
  *    You may distribute under the terms of either the GNU General Public
  *    License or the Artistic License, as specified in the README file.
@@ -56,14 +56,13 @@ av, hv...) contains type and reference count information, as well as a
 pointer to the body (struct xrv, xpv, xpviv...), which contains fields
 specific to each type.
 
-Normally, this allocation is done using arenas, which are approximately
-1K chunks of memory parcelled up into N heads or bodies. The first slot
-in each arena is reserved, and is used to hold a link to the next arena.
-In the case of heads, the unused first slot also contains some flags and
-a note of the number of slots.  Snaked through each arena chain is a
+Normally, this allocation is done using arenas, which by default are
+approximately 4K chunks of memory parcelled up into N heads or bodies.  The
+first slot in each arena is reserved, and is used to hold a link to the next
+arena.  In the case of heads, the unused first slot also contains some flags
+and a note of the number of slots.  Snaked through each arena chain is a
 linked list of free items; when this becomes empty, an extra arena is
-allocated and divided up into N items which are threaded into the free
-list.
+allocated and divided up into N items which are threaded into the free list.
 
 The following global variables are associated with arenas:
 
@@ -79,7 +78,8 @@ are not allocated using arenas, but are instead just malloc()/free()ed as
 required. Also, if PURIFY is defined, arenas are abandoned altogether,
 with all items individually malloc()ed. In addition, a few SV heads are
 not allocated from an arena, but are instead directly created as static
-or auto variables, eg PL_sv_undef.
+or auto variables, eg PL_sv_undef.  The size of arenas can be changed from
+the default by setting PERL_ARENA_SIZE appropriately at compile time.
 
 The SV arena serves the secondary purpose of allowing still-live SVs
 to be located and destroyed during final cleanup.
@@ -158,6 +158,28 @@ Public API:
  * "A time to plant, and a time to uproot what was planted..."
  */
 
+/*
+ * nice_chunk and nice_chunk size need to be set
+ * and queried under the protection of sv_mutex
+ */
+void
+Perl_offer_nice_chunk(pTHX_ void *chunk, U32 chunk_size)
+{
+    void *new_chunk;
+    U32 new_chunk_size;
+    LOCK_SV_MUTEX;
+    new_chunk = (void *)(chunk);
+    new_chunk_size = (chunk_size);
+    if (new_chunk_size > PL_nice_chunk_size) {
+       Safefree(PL_nice_chunk);
+       PL_nice_chunk = (char *) new_chunk;
+       PL_nice_chunk_size = new_chunk_size;
+    } else {
+       Safefree(chunk);
+    }
+    UNLOCK_SV_MUTEX;
+}
+
 #define plant_SV(p) \
     STMT_START {                                       \
        SvANY(p) = (void *)PL_sv_root;                  \
@@ -175,6 +197,28 @@ Public API:
     } STMT_END
 
 
+/* make some more SVs by adding another arena */
+
+/* sv_mutex must be held while calling more_sv() */
+STATIC SV*
+S_more_sv(pTHX)
+{
+    SV* sv;
+
+    if (PL_nice_chunk) {
+       sv_add_arena(PL_nice_chunk, PL_nice_chunk_size, 0);
+       PL_nice_chunk = Nullch;
+        PL_nice_chunk_size = 0;
+    }
+    else {
+       char *chunk;                /* must use New here to match call to */
+       Newx(chunk,PERL_ARENA_SIZE,char);   /* Safefree() in sv_free_arenas()     */
+       sv_add_arena(chunk, PERL_ARENA_SIZE, 0);
+    }
+    uproot_SV(sv);
+    return sv;
+}
+
 /* new_SV(): return a new, empty SV head */
 
 #ifdef DEBUG_LEAKING_SCALARS
@@ -188,7 +232,7 @@ S_new_SV(pTHX)
     if (PL_sv_root)
        uproot_SV(sv);
     else
-       sv = more_sv();
+       sv = S_more_sv(aTHX);
     UNLOCK_SV_MUTEX;
     SvANY(sv) = 0;
     SvREFCNT(sv) = 1;
@@ -204,7 +248,7 @@ S_new_SV(pTHX)
        if (PL_sv_root)                                 \
            uproot_SV(p);                               \
        else                                            \
-           (p) = more_sv();                            \
+           (p) = S_more_sv(aTHX);                      \
        UNLOCK_SV_MUTEX;                                \
        SvANY(p) = 0;                                   \
        SvREFCNT(p) = 1;                                \
@@ -232,14 +276,14 @@ S_del_sv(pTHX_ SV *p)
 {
     if (DEBUG_D_TEST) {
        SV* sva;
-       SV* sv;
-       SV* svend;
-       int ok = 0;
+       bool ok = 0;
        for (sva = PL_sv_arenaroot; sva; sva = (SV *) SvANY(sva)) {
-           sv = sva + 1;
-           svend = &sva[SvREFCNT(sva)];
-           if (p >= sv && p < svend)
+           const SV * const sv = sva + 1;
+           const SV * const svend = &sva[SvREFCNT(sva)];
+           if (p >= sv && p < svend) {
                ok = 1;
+               break;
+           }
        }
        if (!ok) {
            if (ckWARN_d(WARN_INTERNAL))        
@@ -289,36 +333,21 @@ Perl_sv_add_arena(pTHX_ char *ptr, U32 size, U32 flags)
     sv = sva + 1;
     while (sv < svend) {
        SvANY(sv) = (void *)(SV*)(sv + 1);
+#ifdef DEBUGGING
        SvREFCNT(sv) = 0;
+#endif
+       /* Must always set typemask because it's awlays checked in on cleanup
+          when the arenas are walked looking for objects.  */
        SvFLAGS(sv) = SVTYPEMASK;
        sv++;
     }
     SvANY(sv) = 0;
+#ifdef DEBUGGING
+    SvREFCNT(sv) = 0;
+#endif
     SvFLAGS(sv) = SVTYPEMASK;
 }
 
-/* make some more SVs by adding another arena */
-
-/* sv_mutex must be held while calling more_sv() */
-STATIC SV*
-S_more_sv(pTHX)
-{
-    register SV* sv;
-
-    if (PL_nice_chunk) {
-       sv_add_arena(PL_nice_chunk, PL_nice_chunk_size, 0);
-       PL_nice_chunk = Nullch;
-        PL_nice_chunk_size = 0;
-    }
-    else {
-       char *chunk;                /* must use New here to match call to */
-       New(704,chunk,1008,char);   /* Safefree() in sv_free_arenas()     */
-       sv_add_arena(chunk, 1008, 0);
-    }
-    uproot_SV(sv);
-    return sv;
-}
-
 /* visit(): call the named function for each non-free SV in the arenas
  * whose flags field matches the flags/mask args. */
 
@@ -326,12 +355,11 @@ STATIC I32
 S_visit(pTHX_ SVFUNC_t f, U32 flags, U32 mask)
 {
     SV* sva;
-    SV* sv;
-    register SV* svend;
     I32 visited = 0;
 
     for (sva = PL_sv_arenaroot; sva; sva = (SV*)SvANY(sva)) {
-       svend = &sva[SvREFCNT(sva)];
+       register const SV * const svend = &sva[SvREFCNT(sva)];
+       register SV* sv;
        for (sv = sva + 1; sv < svend; ++sv) {
            if (SvTYPE(sv) != SVTYPEMASK
                    && (sv->sv_flags & mask) == flags
@@ -387,10 +415,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);
        }
     }
@@ -405,7 +433,11 @@ static void
 do_clean_named_objs(pTHX_ SV *sv)
 {
     if (SvTYPE(sv) == SVt_PVGV && GvGP(sv)) {
-       if ( SvOBJECT(GvSV(sv)) ||
+       if ((
+#ifdef PERL_DONT_CREATE_GVSV
+            GvSV(sv) &&
+#endif
+            SvOBJECT(GvSV(sv))) ||
             (GvAV(sv) && SvOBJECT(GvAV(sv))) ||
             (GvHV(sv) && SvOBJECT(GvHV(sv))) ||
             (GvIO(sv) && SvOBJECT(GvIO(sv))) ||
@@ -494,7 +526,7 @@ Perl_sv_free_arenas(pTHX)
            svanext = (SV*) SvANY(svanext);
 
        if (!SvFAKE(sva))
-           Safefree((void *)sva);
+           Safefree(sva);
     }
 
     for (arena = PL_xiv_arenaroot; arena; arena = arenanext) {
@@ -588,8 +620,16 @@ Perl_sv_free_arenas(pTHX)
     PL_he_arenaroot = 0;
     PL_he_root = 0;
 
-    if (PL_nice_chunk)
-       Safefree(PL_nice_chunk);
+#if defined(USE_ITHREADS)
+    for (arena = (XPV*)PL_pte_arenaroot; arena; arena = arenanext) {
+       arenanext = (XPV*)arena->xpv_pv;
+       Safefree(arena);
+    }
+    PL_pte_arenaroot = 0;
+    PL_pte_root = 0;
+#endif
+
+    Safefree(PL_nice_chunk);
     PL_nice_chunk = Nullch;
     PL_nice_chunk_size = 0;
     PL_sv_arenaroot = 0;
@@ -614,34 +654,27 @@ Perl_report_uninit(pTHX)
        Perl_warner(aTHX_ packWARN(WARN_UNINITIALIZED), PL_warn_uninit, "", "");
 }
 
-/* grab a new IV body from the free list, allocating more if necessary */
-
-STATIC XPVIV*
-S_new_xiv(pTHX)
-{
-    IV* xiv;
-    LOCK_SV_MUTEX;
-    if (!PL_xiv_root)
-       more_xiv();
-    xiv = PL_xiv_root;
-    /*
-     * See comment in more_xiv() -- RAM.
-     */
-    PL_xiv_root = *(IV**)xiv;
-    UNLOCK_SV_MUTEX;
-    return (XPVIV*)((char*)xiv - STRUCT_OFFSET(XPVIV, xiv_iv));
-}
-
-/* return an IV body to the free list */
+/* allocate another arena's worth of struct xrv */
 
 STATIC void
-S_del_xiv(pTHX_ XPVIV *p)
+S_more_xrv(pTHX)
 {
-    IV* xiv = (IV*)((char*)(p) + STRUCT_OFFSET(XPVIV, xiv_iv));
-    LOCK_SV_MUTEX;
-    *(IV**)xiv = PL_xiv_root;
-    PL_xiv_root = xiv;
-    UNLOCK_SV_MUTEX;
+    XRV* xrv;
+    XRV* xrvend;
+    XPV *ptr;
+    New(712, ptr, PERL_ARENA_SIZE/sizeof(XPV), XPV);
+    ptr->xpv_pv = (char*)PL_xrv_arenaroot;
+    PL_xrv_arenaroot = ptr;
+
+    xrv = (XRV*) ptr;
+    xrvend = &xrv[PERL_ARENA_SIZE / sizeof(XRV) - 1];
+    xrv += (sizeof(XPV) - 1) / sizeof(XRV) + 1;
+    PL_xrv_root = xrv;
+    while (xrv < xrvend) {
+       xrv->xrv_rv = (SV*)(xrv + 1);
+       xrv++;
+    }
+    xrv->xrv_rv = 0;
 }
 
 /* allocate another arena's worth of IV bodies */
@@ -649,15 +682,15 @@ S_del_xiv(pTHX_ XPVIV *p)
 STATIC void
 S_more_xiv(pTHX)
 {
-    register IV* xiv;
-    register IV* xivend;
+    IV* xiv;
+    IV* xivend;
     XPV* ptr;
-    New(705, ptr, 1008/sizeof(XPV), XPV);
+    New(705, ptr, PERL_ARENA_SIZE/sizeof(XPV), XPV);
     ptr->xpv_pv = (char*)PL_xiv_arenaroot;     /* linked list of xiv arenas */
     PL_xiv_arenaroot = ptr;                    /* to keep Purify happy */
 
     xiv = (IV*) ptr;
-    xivend = &xiv[1008 / sizeof(IV) - 1];
+    xivend = &xiv[PERL_ARENA_SIZE / sizeof(IV) - 1];
     xiv += (sizeof(XPV) - 1) / sizeof(IV) + 1; /* fudge by size of XPV */
     PL_xiv_root = xiv;
     while (xiv < xivend) {
@@ -667,47 +700,20 @@ S_more_xiv(pTHX)
     *(IV**)xiv = 0;
 }
 
-/* grab a new NV body from the free list, allocating more if necessary */
-
-STATIC XPVNV*
-S_new_xnv(pTHX)
-{
-    NV* xnv;
-    LOCK_SV_MUTEX;
-    if (!PL_xnv_root)
-       more_xnv();
-    xnv = PL_xnv_root;
-    PL_xnv_root = *(NV**)xnv;
-    UNLOCK_SV_MUTEX;
-    return (XPVNV*)((char*)xnv - STRUCT_OFFSET(XPVNV, xnv_nv));
-}
-
-/* return an NV body to the free list */
-
-STATIC void
-S_del_xnv(pTHX_ XPVNV *p)
-{
-    NV* xnv = (NV*)((char*)(p) + STRUCT_OFFSET(XPVNV, xnv_nv));
-    LOCK_SV_MUTEX;
-    *(NV**)xnv = PL_xnv_root;
-    PL_xnv_root = xnv;
-    UNLOCK_SV_MUTEX;
-}
-
 /* allocate another arena's worth of NV bodies */
 
 STATIC void
 S_more_xnv(pTHX)
 {
-    register NV* xnv;
-    register NV* xnvend;
+    NV* xnv;
+    NV* xnvend;
     XPV *ptr;
-    New(711, ptr, 1008/sizeof(XPV), XPV);
+    New(711, ptr, PERL_ARENA_SIZE/sizeof(XPV), XPV);
     ptr->xpv_pv = (char*)PL_xnv_arenaroot;
     PL_xnv_arenaroot = ptr;
 
     xnv = (NV*) ptr;
-    xnvend = &xnv[1008 / sizeof(NV) - 1];
+    xnvend = &xnv[PERL_ARENA_SIZE / sizeof(NV) - 1];
     xnv += (sizeof(XPVIV) - 1) / sizeof(NV) + 1; /* fudge by sizeof XPVIV */
     PL_xnv_root = xnv;
     while (xnv < xnvend) {
@@ -717,53 +723,266 @@ S_more_xnv(pTHX)
     *(NV**)xnv = 0;
 }
 
-/* grab a new struct xrv from the free list, allocating more if necessary */
+/* allocate another arena's worth of struct xpv */
+
+STATIC void
+S_more_xpv(pTHX)
+{
+    XPV* xpv;
+    XPV* xpvend;
+    New(713, xpv, PERL_ARENA_SIZE/sizeof(XPV), XPV);
+    xpv->xpv_pv = (char*)PL_xpv_arenaroot;
+    PL_xpv_arenaroot = xpv;
+
+    xpvend = &xpv[PERL_ARENA_SIZE / sizeof(XPV) - 1];
+    PL_xpv_root = ++xpv;
+    while (xpv < xpvend) {
+       xpv->xpv_pv = (char*)(xpv + 1);
+       xpv++;
+    }
+    xpv->xpv_pv = 0;
+}
+
+/* allocate another arena's worth of struct xpviv */
+
+STATIC void
+S_more_xpviv(pTHX)
+{
+    XPVIV* xpviv;
+    XPVIV* xpvivend;
+    New(714, xpviv, PERL_ARENA_SIZE/sizeof(XPVIV), XPVIV);
+    xpviv->xpv_pv = (char*)PL_xpviv_arenaroot;
+    PL_xpviv_arenaroot = xpviv;
+
+    xpvivend = &xpviv[PERL_ARENA_SIZE / sizeof(XPVIV) - 1];
+    PL_xpviv_root = ++xpviv;
+    while (xpviv < xpvivend) {
+       xpviv->xpv_pv = (char*)(xpviv + 1);
+       xpviv++;
+    }
+    xpviv->xpv_pv = 0;
+}
+
+/* allocate another arena's worth of struct xpvnv */
+
+STATIC void
+S_more_xpvnv(pTHX) {
+    XPVNV* xpvnv;
+    XPVNV* xpvnvend;
+    New(715, xpvnv, PERL_ARENA_SIZE/sizeof(XPVNV), XPVNV);
+    xpvnv->xpv_pv = (char*)PL_xpvnv_arenaroot;
+    PL_xpvnv_arenaroot = xpvnv;
+
+    xpvnvend = &xpvnv[PERL_ARENA_SIZE / sizeof(XPVNV) - 1];
+    PL_xpvnv_root = ++xpvnv;
+    while (xpvnv < xpvnvend) {
+       xpvnv->xpv_pv = (char*)(xpvnv + 1);
+       xpvnv++;
+    }
+    xpvnv->xpv_pv = 0;
+}
+
+/* allocate another arena's worth of struct xpvcv */
+
+STATIC void
+S_more_xpvcv(pTHX)
+{
+    XPVCV* xpvcv;
+    XPVCV* xpvcvend;
+    New(716, xpvcv, PERL_ARENA_SIZE/sizeof(XPVCV), XPVCV);
+    xpvcv->xpv_pv = (char*)PL_xpvcv_arenaroot;
+    PL_xpvcv_arenaroot = xpvcv;
+
+    xpvcvend = &xpvcv[PERL_ARENA_SIZE / sizeof(XPVCV) - 1];
+    PL_xpvcv_root = ++xpvcv;
+    while (xpvcv < xpvcvend) {
+       xpvcv->xpv_pv = (char*)(xpvcv + 1);
+       xpvcv++;
+    }
+    xpvcv->xpv_pv = 0;
+}
+
+/* allocate another arena's worth of struct xpvav */
+
+STATIC void
+S_more_xpvav(pTHX)
+{
+    XPVAV* xpvav;
+    XPVAV* xpvavend;
+    New(717, xpvav, PERL_ARENA_SIZE/sizeof(XPVAV), XPVAV);
+    xpvav->xav_array = (char*)PL_xpvav_arenaroot;
+    PL_xpvav_arenaroot = xpvav;
+
+    xpvavend = &xpvav[PERL_ARENA_SIZE / sizeof(XPVAV) - 1];
+    PL_xpvav_root = ++xpvav;
+    while (xpvav < xpvavend) {
+       xpvav->xav_array = (char*)(xpvav + 1);
+       xpvav++;
+    }
+    xpvav->xav_array = 0;
+}
+
+/* allocate another arena's worth of struct xpvhv */
+
+STATIC void
+S_more_xpvhv(pTHX)
+{
+    XPVHV* xpvhv;
+    XPVHV* xpvhvend;
+    New(718, xpvhv, PERL_ARENA_SIZE/sizeof(XPVHV), XPVHV);
+    xpvhv->xhv_array = (char*)PL_xpvhv_arenaroot;
+    PL_xpvhv_arenaroot = xpvhv;
+
+    xpvhvend = &xpvhv[PERL_ARENA_SIZE / sizeof(XPVHV) - 1];
+    PL_xpvhv_root = ++xpvhv;
+    while (xpvhv < xpvhvend) {
+       xpvhv->xhv_array = (char*)(xpvhv + 1);
+       xpvhv++;
+    }
+    xpvhv->xhv_array = 0;
+}
+
+/* allocate another arena's worth of struct xpvmg */
+
+STATIC void
+S_more_xpvmg(pTHX)
+{
+    XPVMG* xpvmg;
+    XPVMG* xpvmgend;
+    New(719, xpvmg, PERL_ARENA_SIZE/sizeof(XPVMG), XPVMG);
+    xpvmg->xpv_pv = (char*)PL_xpvmg_arenaroot;
+    PL_xpvmg_arenaroot = xpvmg;
+
+    xpvmgend = &xpvmg[PERL_ARENA_SIZE / sizeof(XPVMG) - 1];
+    PL_xpvmg_root = ++xpvmg;
+    while (xpvmg < xpvmgend) {
+       xpvmg->xpv_pv = (char*)(xpvmg + 1);
+       xpvmg++;
+    }
+    xpvmg->xpv_pv = 0;
+}
+
+/* allocate another arena's worth of struct xpvlv */
+
+STATIC void
+S_more_xpvlv(pTHX)
+{
+    XPVLV* xpvlv;
+    XPVLV* xpvlvend;
+    New(720, xpvlv, PERL_ARENA_SIZE/sizeof(XPVLV), XPVLV);
+    xpvlv->xpv_pv = (char*)PL_xpvlv_arenaroot;
+    PL_xpvlv_arenaroot = xpvlv;
+
+    xpvlvend = &xpvlv[PERL_ARENA_SIZE / sizeof(XPVLV) - 1];
+    PL_xpvlv_root = ++xpvlv;
+    while (xpvlv < xpvlvend) {
+       xpvlv->xpv_pv = (char*)(xpvlv + 1);
+       xpvlv++;
+    }
+    xpvlv->xpv_pv = 0;
+}
+
+/* allocate another arena's worth of struct xpvbm */
+
+STATIC void
+S_more_xpvbm(pTHX)
+{
+    XPVBM* xpvbm;
+    XPVBM* xpvbmend;
+    New(721, xpvbm, PERL_ARENA_SIZE/sizeof(XPVBM), XPVBM);
+    xpvbm->xpv_pv = (char*)PL_xpvbm_arenaroot;
+    PL_xpvbm_arenaroot = xpvbm;
+
+    xpvbmend = &xpvbm[PERL_ARENA_SIZE / sizeof(XPVBM) - 1];
+    PL_xpvbm_root = ++xpvbm;
+    while (xpvbm < xpvbmend) {
+       xpvbm->xpv_pv = (char*)(xpvbm + 1);
+       xpvbm++;
+    }
+    xpvbm->xpv_pv = 0;
+}
+
+/* grab a new struct xrv from the free list, allocating more if necessary */
+
+STATIC XRV*
+S_new_xrv(pTHX)
+{
+    XRV* xrv;
+    LOCK_SV_MUTEX;
+    if (!PL_xrv_root)
+       S_more_xrv(aTHX);
+    xrv = PL_xrv_root;
+    PL_xrv_root = (XRV*)xrv->xrv_rv;
+    UNLOCK_SV_MUTEX;
+    return xrv;
+}
+
+/* return a struct xrv to the free list */
+
+STATIC void
+S_del_xrv(pTHX_ XRV *p)
+{
+    LOCK_SV_MUTEX;
+    p->xrv_rv = (SV*)PL_xrv_root;
+    PL_xrv_root = p;
+    UNLOCK_SV_MUTEX;
+}
+
+/* grab a new IV body from the free list, allocating more if necessary */
+
+STATIC XPVIV*
+S_new_xiv(pTHX)
+{
+    IV* xiv;
+    LOCK_SV_MUTEX;
+    if (!PL_xiv_root)
+       S_more_xiv(aTHX);
+    xiv = PL_xiv_root;
+    /*
+     * See comment in more_xiv() -- RAM.
+     */
+    PL_xiv_root = *(IV**)xiv;
+    UNLOCK_SV_MUTEX;
+    return (XPVIV*)((char*)xiv - STRUCT_OFFSET(XPVIV, xiv_iv));
+}
+
+/* return an IV body to the free list */
 
-STATIC XRV*
-S_new_xrv(pTHX)
+STATIC void
+S_del_xiv(pTHX_ XPVIV *p)
 {
-    XRV* xrv;
+    IV* xiv = (IV*)((char*)(p) + STRUCT_OFFSET(XPVIV, xiv_iv));
     LOCK_SV_MUTEX;
-    if (!PL_xrv_root)
-       more_xrv();
-    xrv = PL_xrv_root;
-    PL_xrv_root = (XRV*)xrv->xrv_rv;
+    *(IV**)xiv = PL_xiv_root;
+    PL_xiv_root = xiv;
     UNLOCK_SV_MUTEX;
-    return xrv;
 }
 
-/* return a struct xrv to the free list */
+/* grab a new NV body from the free list, allocating more if necessary */
 
-STATIC void
-S_del_xrv(pTHX_ XRV *p)
+STATIC XPVNV*
+S_new_xnv(pTHX)
 {
+    NV* xnv;
     LOCK_SV_MUTEX;
-    p->xrv_rv = (SV*)PL_xrv_root;
-    PL_xrv_root = p;
+    if (!PL_xnv_root)
+       S_more_xnv(aTHX);
+    xnv = PL_xnv_root;
+    PL_xnv_root = *(NV**)xnv;
     UNLOCK_SV_MUTEX;
+    return (XPVNV*)((char*)xnv - STRUCT_OFFSET(XPVNV, xnv_nv));
 }
 
-/* allocate another arena's worth of struct xrv */
+/* return an NV body to the free list */
 
 STATIC void
-S_more_xrv(pTHX)
+S_del_xnv(pTHX_ XPVNV *p)
 {
-    register XRV* xrv;
-    register XRV* xrvend;
-    XPV *ptr;
-    New(712, ptr, 1008/sizeof(XPV), XPV);
-    ptr->xpv_pv = (char*)PL_xrv_arenaroot;
-    PL_xrv_arenaroot = ptr;
-
-    xrv = (XRV*) ptr;
-    xrvend = &xrv[1008 / sizeof(XRV) - 1];
-    xrv += (sizeof(XPV) - 1) / sizeof(XRV) + 1;
-    PL_xrv_root = xrv;
-    while (xrv < xrvend) {
-       xrv->xrv_rv = (SV*)(xrv + 1);
-       xrv++;
-    }
-    xrv->xrv_rv = 0;
+    NV* xnv = (NV*)((char*)(p) + STRUCT_OFFSET(XPVNV, xnv_nv));
+    LOCK_SV_MUTEX;
+    *(NV**)xnv = PL_xnv_root;
+    PL_xnv_root = xnv;
+    UNLOCK_SV_MUTEX;
 }
 
 /* grab a new struct xpv from the free list, allocating more if necessary */
@@ -774,7 +993,7 @@ S_new_xpv(pTHX)
     XPV* xpv;
     LOCK_SV_MUTEX;
     if (!PL_xpv_root)
-       more_xpv();
+       S_more_xpv(aTHX);
     xpv = PL_xpv_root;
     PL_xpv_root = (XPV*)xpv->xpv_pv;
     UNLOCK_SV_MUTEX;
@@ -792,26 +1011,6 @@ S_del_xpv(pTHX_ XPV *p)
     UNLOCK_SV_MUTEX;
 }
 
-/* allocate another arena's worth of struct xpv */
-
-STATIC void
-S_more_xpv(pTHX)
-{
-    register XPV* xpv;
-    register XPV* xpvend;
-    New(713, xpv, 1008/sizeof(XPV), XPV);
-    xpv->xpv_pv = (char*)PL_xpv_arenaroot;
-    PL_xpv_arenaroot = xpv;
-
-    xpvend = &xpv[1008 / sizeof(XPV) - 1];
-    PL_xpv_root = ++xpv;
-    while (xpv < xpvend) {
-       xpv->xpv_pv = (char*)(xpv + 1);
-       xpv++;
-    }
-    xpv->xpv_pv = 0;
-}
-
 /* grab a new struct xpviv from the free list, allocating more if necessary */
 
 STATIC XPVIV*
@@ -820,7 +1019,7 @@ S_new_xpviv(pTHX)
     XPVIV* xpviv;
     LOCK_SV_MUTEX;
     if (!PL_xpviv_root)
-       more_xpviv();
+       S_more_xpviv(aTHX);
     xpviv = PL_xpviv_root;
     PL_xpviv_root = (XPVIV*)xpviv->xpv_pv;
     UNLOCK_SV_MUTEX;
@@ -838,26 +1037,6 @@ S_del_xpviv(pTHX_ XPVIV *p)
     UNLOCK_SV_MUTEX;
 }
 
-/* allocate another arena's worth of struct xpviv */
-
-STATIC void
-S_more_xpviv(pTHX)
-{
-    register XPVIV* xpviv;
-    register XPVIV* xpvivend;
-    New(714, xpviv, 1008/sizeof(XPVIV), XPVIV);
-    xpviv->xpv_pv = (char*)PL_xpviv_arenaroot;
-    PL_xpviv_arenaroot = xpviv;
-
-    xpvivend = &xpviv[1008 / sizeof(XPVIV) - 1];
-    PL_xpviv_root = ++xpviv;
-    while (xpviv < xpvivend) {
-       xpviv->xpv_pv = (char*)(xpviv + 1);
-       xpviv++;
-    }
-    xpviv->xpv_pv = 0;
-}
-
 /* grab a new struct xpvnv from the free list, allocating more if necessary */
 
 STATIC XPVNV*
@@ -866,7 +1045,7 @@ S_new_xpvnv(pTHX)
     XPVNV* xpvnv;
     LOCK_SV_MUTEX;
     if (!PL_xpvnv_root)
-       more_xpvnv();
+       S_more_xpvnv(aTHX);
     xpvnv = PL_xpvnv_root;
     PL_xpvnv_root = (XPVNV*)xpvnv->xpv_pv;
     UNLOCK_SV_MUTEX;
@@ -884,26 +1063,6 @@ S_del_xpvnv(pTHX_ XPVNV *p)
     UNLOCK_SV_MUTEX;
 }
 
-/* allocate another arena's worth of struct xpvnv */
-
-STATIC void
-S_more_xpvnv(pTHX)
-{
-    register XPVNV* xpvnv;
-    register XPVNV* xpvnvend;
-    New(715, xpvnv, 1008/sizeof(XPVNV), XPVNV);
-    xpvnv->xpv_pv = (char*)PL_xpvnv_arenaroot;
-    PL_xpvnv_arenaroot = xpvnv;
-
-    xpvnvend = &xpvnv[1008 / sizeof(XPVNV) - 1];
-    PL_xpvnv_root = ++xpvnv;
-    while (xpvnv < xpvnvend) {
-       xpvnv->xpv_pv = (char*)(xpvnv + 1);
-       xpvnv++;
-    }
-    xpvnv->xpv_pv = 0;
-}
-
 /* grab a new struct xpvcv from the free list, allocating more if necessary */
 
 STATIC XPVCV*
@@ -912,7 +1071,7 @@ S_new_xpvcv(pTHX)
     XPVCV* xpvcv;
     LOCK_SV_MUTEX;
     if (!PL_xpvcv_root)
-       more_xpvcv();
+       S_more_xpvcv(aTHX);
     xpvcv = PL_xpvcv_root;
     PL_xpvcv_root = (XPVCV*)xpvcv->xpv_pv;
     UNLOCK_SV_MUTEX;
@@ -930,26 +1089,6 @@ S_del_xpvcv(pTHX_ XPVCV *p)
     UNLOCK_SV_MUTEX;
 }
 
-/* allocate another arena's worth of struct xpvcv */
-
-STATIC void
-S_more_xpvcv(pTHX)
-{
-    register XPVCV* xpvcv;
-    register XPVCV* xpvcvend;
-    New(716, xpvcv, 1008/sizeof(XPVCV), XPVCV);
-    xpvcv->xpv_pv = (char*)PL_xpvcv_arenaroot;
-    PL_xpvcv_arenaroot = xpvcv;
-
-    xpvcvend = &xpvcv[1008 / sizeof(XPVCV) - 1];
-    PL_xpvcv_root = ++xpvcv;
-    while (xpvcv < xpvcvend) {
-       xpvcv->xpv_pv = (char*)(xpvcv + 1);
-       xpvcv++;
-    }
-    xpvcv->xpv_pv = 0;
-}
-
 /* grab a new struct xpvav from the free list, allocating more if necessary */
 
 STATIC XPVAV*
@@ -958,7 +1097,7 @@ S_new_xpvav(pTHX)
     XPVAV* xpvav;
     LOCK_SV_MUTEX;
     if (!PL_xpvav_root)
-       more_xpvav();
+       S_more_xpvav(aTHX);
     xpvav = PL_xpvav_root;
     PL_xpvav_root = (XPVAV*)xpvav->xav_array;
     UNLOCK_SV_MUTEX;
@@ -976,26 +1115,6 @@ S_del_xpvav(pTHX_ XPVAV *p)
     UNLOCK_SV_MUTEX;
 }
 
-/* allocate another arena's worth of struct xpvav */
-
-STATIC void
-S_more_xpvav(pTHX)
-{
-    register XPVAV* xpvav;
-    register XPVAV* xpvavend;
-    New(717, xpvav, 1008/sizeof(XPVAV), XPVAV);
-    xpvav->xav_array = (char*)PL_xpvav_arenaroot;
-    PL_xpvav_arenaroot = xpvav;
-
-    xpvavend = &xpvav[1008 / sizeof(XPVAV) - 1];
-    PL_xpvav_root = ++xpvav;
-    while (xpvav < xpvavend) {
-       xpvav->xav_array = (char*)(xpvav + 1);
-       xpvav++;
-    }
-    xpvav->xav_array = 0;
-}
-
 /* grab a new struct xpvhv from the free list, allocating more if necessary */
 
 STATIC XPVHV*
@@ -1004,7 +1123,7 @@ S_new_xpvhv(pTHX)
     XPVHV* xpvhv;
     LOCK_SV_MUTEX;
     if (!PL_xpvhv_root)
-       more_xpvhv();
+       S_more_xpvhv(aTHX);
     xpvhv = PL_xpvhv_root;
     PL_xpvhv_root = (XPVHV*)xpvhv->xhv_array;
     UNLOCK_SV_MUTEX;
@@ -1022,26 +1141,6 @@ S_del_xpvhv(pTHX_ XPVHV *p)
     UNLOCK_SV_MUTEX;
 }
 
-/* allocate another arena's worth of struct xpvhv */
-
-STATIC void
-S_more_xpvhv(pTHX)
-{
-    register XPVHV* xpvhv;
-    register XPVHV* xpvhvend;
-    New(718, xpvhv, 1008/sizeof(XPVHV), XPVHV);
-    xpvhv->xhv_array = (char*)PL_xpvhv_arenaroot;
-    PL_xpvhv_arenaroot = xpvhv;
-
-    xpvhvend = &xpvhv[1008 / sizeof(XPVHV) - 1];
-    PL_xpvhv_root = ++xpvhv;
-    while (xpvhv < xpvhvend) {
-       xpvhv->xhv_array = (char*)(xpvhv + 1);
-       xpvhv++;
-    }
-    xpvhv->xhv_array = 0;
-}
-
 /* grab a new struct xpvmg from the free list, allocating more if necessary */
 
 STATIC XPVMG*
@@ -1050,7 +1149,7 @@ S_new_xpvmg(pTHX)
     XPVMG* xpvmg;
     LOCK_SV_MUTEX;
     if (!PL_xpvmg_root)
-       more_xpvmg();
+       S_more_xpvmg(aTHX);
     xpvmg = PL_xpvmg_root;
     PL_xpvmg_root = (XPVMG*)xpvmg->xpv_pv;
     UNLOCK_SV_MUTEX;
@@ -1068,26 +1167,6 @@ S_del_xpvmg(pTHX_ XPVMG *p)
     UNLOCK_SV_MUTEX;
 }
 
-/* allocate another arena's worth of struct xpvmg */
-
-STATIC void
-S_more_xpvmg(pTHX)
-{
-    register XPVMG* xpvmg;
-    register XPVMG* xpvmgend;
-    New(719, xpvmg, 1008/sizeof(XPVMG), XPVMG);
-    xpvmg->xpv_pv = (char*)PL_xpvmg_arenaroot;
-    PL_xpvmg_arenaroot = xpvmg;
-
-    xpvmgend = &xpvmg[1008 / sizeof(XPVMG) - 1];
-    PL_xpvmg_root = ++xpvmg;
-    while (xpvmg < xpvmgend) {
-       xpvmg->xpv_pv = (char*)(xpvmg + 1);
-       xpvmg++;
-    }
-    xpvmg->xpv_pv = 0;
-}
-
 /* grab a new struct xpvlv from the free list, allocating more if necessary */
 
 STATIC XPVLV*
@@ -1096,7 +1175,7 @@ S_new_xpvlv(pTHX)
     XPVLV* xpvlv;
     LOCK_SV_MUTEX;
     if (!PL_xpvlv_root)
-       more_xpvlv();
+       S_more_xpvlv(aTHX);
     xpvlv = PL_xpvlv_root;
     PL_xpvlv_root = (XPVLV*)xpvlv->xpv_pv;
     UNLOCK_SV_MUTEX;
@@ -1114,26 +1193,6 @@ S_del_xpvlv(pTHX_ XPVLV *p)
     UNLOCK_SV_MUTEX;
 }
 
-/* allocate another arena's worth of struct xpvlv */
-
-STATIC void
-S_more_xpvlv(pTHX)
-{
-    register XPVLV* xpvlv;
-    register XPVLV* xpvlvend;
-    New(720, xpvlv, 1008/sizeof(XPVLV), XPVLV);
-    xpvlv->xpv_pv = (char*)PL_xpvlv_arenaroot;
-    PL_xpvlv_arenaroot = xpvlv;
-
-    xpvlvend = &xpvlv[1008 / sizeof(XPVLV) - 1];
-    PL_xpvlv_root = ++xpvlv;
-    while (xpvlv < xpvlvend) {
-       xpvlv->xpv_pv = (char*)(xpvlv + 1);
-       xpvlv++;
-    }
-    xpvlv->xpv_pv = 0;
-}
-
 /* grab a new struct xpvbm from the free list, allocating more if necessary */
 
 STATIC XPVBM*
@@ -1142,7 +1201,7 @@ S_new_xpvbm(pTHX)
     XPVBM* xpvbm;
     LOCK_SV_MUTEX;
     if (!PL_xpvbm_root)
-       more_xpvbm();
+       S_more_xpvbm(aTHX);
     xpvbm = PL_xpvbm_root;
     PL_xpvbm_root = (XPVBM*)xpvbm->xpv_pv;
     UNLOCK_SV_MUTEX;
@@ -1160,26 +1219,6 @@ S_del_xpvbm(pTHX_ XPVBM *p)
     UNLOCK_SV_MUTEX;
 }
 
-/* allocate another arena's worth of struct xpvbm */
-
-STATIC void
-S_more_xpvbm(pTHX)
-{
-    register XPVBM* xpvbm;
-    register XPVBM* xpvbmend;
-    New(721, xpvbm, 1008/sizeof(XPVBM), XPVBM);
-    xpvbm->xpv_pv = (char*)PL_xpvbm_arenaroot;
-    PL_xpvbm_arenaroot = xpvbm;
-
-    xpvbmend = &xpvbm[1008 / sizeof(XPVBM) - 1];
-    PL_xpvbm_root = ++xpvbm;
-    while (xpvbm < xpvbmend) {
-       xpvbm->xpv_pv = (char*)(xpvbm + 1);
-       xpvbm++;
-    }
-    xpvbm->xpv_pv = 0;
-}
-
 #define my_safemalloc(s)       (void*)safemalloc(s)
 #define my_safefree(p) safefree((char*)p)
 
@@ -1284,13 +1323,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 && SvREADONLY(sv) && SvFAKE(sv)) {
        sv_force_normal(sv);
@@ -1302,61 +1341,39 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
     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);
+       pv      = SvPVX_mutable(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;
@@ -1364,27 +1381,30 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
            mt = SVt_PVNV;
        break;
     case SVt_PVIV:
-       pv      = SvPVX(sv);
+       pv      = SvPVX_mutable(sv);
        cur     = SvCUR(sv);
        len     = SvLEN(sv);
        iv      = SvIVX(sv);
-       nv      = 0.0;
-       magic   = 0;
-       stash   = 0;
        del_XPVIV(SvANY(sv));
        break;
     case SVt_PVNV:
-       pv      = SvPVX(sv);
+       pv      = SvPVX_mutable(sv);
        cur     = SvCUR(sv);
        len     = SvLEN(sv);
        iv      = SvIVX(sv);
        nv      = SvNVX(sv);
-       magic   = 0;
-       stash   = 0;
        del_XPVNV(SvANY(sv));
        break;
     case SVt_PVMG:
-       pv      = SvPVX(sv);
+       /* Because the XPVMG of PL_mess_sv isn't allocated from the arena,
+          there's no way that it can be safely upgraded, because perl.c
+          expects to Safefree(SvANY(PL_mess_sv))  */
+       assert(sv != PL_mess_sv);
+       /* This flag bit is used to mean other things in other scalar types.
+          Given that it only has meaning inside the pad, it shouldn't be set
+          on anything that can get upgraded.  */
+       assert((SvFLAGS(sv) & SVpad_TYPED) == 0);
+       pv      = SvPVX_mutable(sv);
        cur     = SvCUR(sv);
        len     = SvLEN(sv);
        iv      = SvIVX(sv);
@@ -1397,64 +1417,67 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
        Perl_croak(aTHX_ "Can't upgrade that kind of scalar");
     }
 
+    SvFLAGS(sv) &= ~SVTYPEMASK;
+    SvFLAGS(sv) |= mt;
+
     switch (mt) {
     case SVt_NULL:
        Perl_croak(aTHX_ "Can't upgrade to undef");
     case SVt_IV:
        SvANY(sv) = new_XIV();
-       SvIVX(sv)       = iv;
+       SvIV_set(sv, iv);
        break;
     case SVt_NV:
        SvANY(sv) = new_XNV();
-       SvNVX(sv)       = nv;
+       SvNV_set(sv, nv);
        break;
     case SVt_RV:
        SvANY(sv) = new_XRV();
-       SvRV(sv) = (SV*)pv;
+       SvRV_set(sv, (SV*)pv);
        break;
     case SVt_PV:
        SvANY(sv) = new_XPV();
-       SvPVX(sv)       = pv;
-       SvCUR(sv)       = cur;
-       SvLEN(sv)       = len;
+       SvPV_set(sv, pv);
+       SvCUR_set(sv, cur);
+       SvLEN_set(sv, len);
        break;
     case SVt_PVIV:
        SvANY(sv) = new_XPVIV();
-       SvPVX(sv)       = pv;
-       SvCUR(sv)       = cur;
-       SvLEN(sv)       = len;
-       SvIVX(sv)       = iv;
+       SvPV_set(sv, pv);
+       SvCUR_set(sv, cur);
+       SvLEN_set(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;
-       SvIVX(sv)       = iv;
-       SvNVX(sv)       = nv;
+       SvPV_set(sv, pv);
+       SvCUR_set(sv, cur);
+       SvLEN_set(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;
-       SvIVX(sv)       = iv;
-       SvNVX(sv)       = nv;
-       SvMAGIC(sv)     = magic;
-       SvSTASH(sv)     = stash;
+       SvPV_set(sv, pv);
+       SvCUR_set(sv, cur);
+       SvLEN_set(sv, len);
+       SvIV_set(sv, iv);
+       SvNV_set(sv, nv);
+       SvMAGIC_set(sv, magic);
+       SvSTASH_set(sv, stash);
        break;
     case SVt_PVLV:
        SvANY(sv) = new_XPVLV();
-       SvPVX(sv)       = pv;
-       SvCUR(sv)       = cur;
-       SvLEN(sv)       = len;
-       SvIVX(sv)       = iv;
-       SvNVX(sv)       = nv;
-       SvMAGIC(sv)     = magic;
-       SvSTASH(sv)     = stash;
+       SvPV_set(sv, pv);
+       SvCUR_set(sv, cur);
+       SvLEN_set(sv, len);
+       SvIV_set(sv, iv);
+       SvNV_set(sv, nv);
+       SvMAGIC_set(sv, magic);
+       SvSTASH_set(sv, stash);
        LvTARGOFF(sv)   = 0;
        LvTARGLEN(sv)   = 0;
        LvTARG(sv)      = 0;
@@ -1464,13 +1487,13 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
        SvANY(sv) = new_XPVAV();
        if (pv)
            Safefree(pv);
-       SvPVX(sv)       = 0;
+       SvPV_set(sv, (char*)0);
        AvMAX(sv)       = -1;
        AvFILLp(sv)     = -1;
-       SvIVX(sv)       = 0;
-       SvNVX(sv)       = 0.0;
-       SvMAGIC(sv)     = magic;
-       SvSTASH(sv)     = stash;
+       SvIV_set(sv, 0);
+       SvNV_set(sv, 0.0);
+       SvMAGIC_set(sv, magic);
+       SvSTASH_set(sv, stash);
        AvALLOC(sv)     = 0;
        AvARYLEN(sv)    = 0;
        AvFLAGS(sv)     = AVf_REAL;
@@ -1479,13 +1502,13 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
        SvANY(sv) = new_XPVHV();
        if (pv)
            Safefree(pv);
-       SvPVX(sv)       = 0;
+       SvPV_set(sv, (char*)0);
        HvFILL(sv)      = 0;
        HvMAX(sv)       = 0;
        HvTOTALKEYS(sv) = 0;
-       HvPLACEHOLDERS(sv) = 0;
-       SvMAGIC(sv)     = magic;
-       SvSTASH(sv)     = stash;
+       HvPLACEHOLDERS_set(sv, 0);
+       SvMAGIC_set(sv, magic);
+       SvSTASH_set(sv, stash);
        HvRITER(sv)     = 0;
        HvEITER(sv)     = 0;
        HvPMROOT(sv)    = 0;
@@ -1494,23 +1517,23 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
     case SVt_PVCV:
        SvANY(sv) = new_XPVCV();
        Zero(SvANY(sv), 1, XPVCV);
-       SvPVX(sv)       = pv;
-       SvCUR(sv)       = cur;
-       SvLEN(sv)       = len;
-       SvIVX(sv)       = iv;
-       SvNVX(sv)       = nv;
-       SvMAGIC(sv)     = magic;
-       SvSTASH(sv)     = stash;
+       SvPV_set(sv, pv);
+       SvCUR_set(sv, cur);
+       SvLEN_set(sv, len);
+       SvIV_set(sv, iv);
+       SvNV_set(sv, nv);
+       SvMAGIC_set(sv, magic);
+       SvSTASH_set(sv, stash);
        break;
     case SVt_PVGV:
        SvANY(sv) = new_XPVGV();
-       SvPVX(sv)       = pv;
-       SvCUR(sv)       = cur;
-       SvLEN(sv)       = len;
-       SvIVX(sv)       = iv;
-       SvNVX(sv)       = nv;
-       SvMAGIC(sv)     = magic;
-       SvSTASH(sv)     = stash;
+       SvPV_set(sv, pv);
+       SvCUR_set(sv, cur);
+       SvLEN_set(sv, len);
+       SvIV_set(sv, iv);
+       SvNV_set(sv, nv);
+       SvMAGIC_set(sv, magic);
+       SvSTASH_set(sv, stash);
        GvGP(sv)        = 0;
        GvNAME(sv)      = 0;
        GvNAMELEN(sv)   = 0;
@@ -1519,13 +1542,13 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
        break;
     case SVt_PVBM:
        SvANY(sv) = new_XPVBM();
-       SvPVX(sv)       = pv;
-       SvCUR(sv)       = cur;
-       SvLEN(sv)       = len;
-       SvIVX(sv)       = iv;
-       SvNVX(sv)       = nv;
-       SvMAGIC(sv)     = magic;
-       SvSTASH(sv)     = stash;
+       SvPV_set(sv, pv);
+       SvCUR_set(sv, cur);
+       SvLEN_set(sv, len);
+       SvIV_set(sv, iv);
+       SvNV_set(sv, nv);
+       SvMAGIC_set(sv, magic);
+       SvSTASH_set(sv, stash);
        BmRARE(sv)      = 0;
        BmUSEFUL(sv)    = 0;
        BmPREVIOUS(sv)  = 0;
@@ -1533,29 +1556,27 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
     case SVt_PVFM:
        SvANY(sv) = new_XPVFM();
        Zero(SvANY(sv), 1, XPVFM);
-       SvPVX(sv)       = pv;
-       SvCUR(sv)       = cur;
-       SvLEN(sv)       = len;
-       SvIVX(sv)       = iv;
-       SvNVX(sv)       = nv;
-       SvMAGIC(sv)     = magic;
-       SvSTASH(sv)     = stash;
+       SvPV_set(sv, pv);
+       SvCUR_set(sv, cur);
+       SvLEN_set(sv, len);
+       SvIV_set(sv, iv);
+       SvNV_set(sv, nv);
+       SvMAGIC_set(sv, magic);
+       SvSTASH_set(sv, stash);
        break;
     case SVt_PVIO:
        SvANY(sv) = new_XPVIO();
        Zero(SvANY(sv), 1, XPVIO);
-       SvPVX(sv)       = pv;
-       SvCUR(sv)       = cur;
-       SvLEN(sv)       = len;
-       SvIVX(sv)       = iv;
-       SvNVX(sv)       = nv;
-       SvMAGIC(sv)     = magic;
-       SvSTASH(sv)     = stash;
+       SvPV_set(sv, pv);
+       SvCUR_set(sv, cur);
+       SvLEN_set(sv, len);
+       SvIV_set(sv, iv);
+       SvNV_set(sv, nv);
+       SvMAGIC_set(sv, magic);
+       SvSTASH_set(sv, stash);
        IoPAGE_LEN(sv)  = 60;
        break;
     }
-    SvFLAGS(sv) &= ~SVTYPEMASK;
-    SvFLAGS(sv) |= mt;
     return TRUE;
 }
 
@@ -1573,9 +1594,9 @@ 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);
+       const char * const s = SvPVX_const(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);
     }
@@ -1611,11 +1632,11 @@ Perl_sv_grow(pTHX_ register SV *sv, register STRLEN newlen)
        sv_unref(sv);
     if (SvTYPE(sv) < SVt_PV) {
        sv_upgrade(sv, SVt_PV);
-       s = SvPVX(sv);
+       s = SvPVX_mutable(sv);
     }
     else if (SvOOK(sv)) {      /* pv is offset? */
        sv_backoff(sv);
-       s = SvPVX(sv);
+       s = SvPVX_mutable(sv);
        if (newlen > SvLEN(sv))
            newlen += 10 * (newlen - SvCUR(sv)); /* avoid copy each time */
 #ifdef HAS_64K_LIMIT
@@ -1624,29 +1645,30 @@ Perl_sv_grow(pTHX_ register SV *sv, register STRLEN newlen)
 #endif
     }
     else
-       s = SvPVX(sv);
+       s = SvPVX_mutable(sv);
 
     if (newlen > SvLEN(sv)) {          /* need more room? */
+       newlen = PERL_STRLEN_ROUNDUP(newlen);
        if (SvLEN(sv) && s) {
 #ifdef MYMALLOC
-           STRLEN l = malloced_size((void*)SvPVX(sv));
+           const STRLEN l = malloced_size((void*)SvPVX_const(sv));
            if (newlen <= l) {
                SvLEN_set(sv, l);
                return s;
            } else
 #endif
-           Renew(s,newlen,char);
+           s = saferealloc(s, newlen);
        }
-        else {
+       else {
            /* sv_force_normal_flags() must not try to unshare the new
               PVX we allocate below. AMS 20010713 */
            if (SvREADONLY(sv) && SvFAKE(sv)) {
                SvFAKE_off(sv);
                SvREADONLY_off(sv);
            }
-           New(703, s, newlen, char);
-           if (SvPVX(sv) && SvCUR(sv)) {
-               Move(SvPVX(sv), s, (newlen < SvCUR(sv)) ? newlen : SvCUR(sv), char);
+           s = safemalloc(newlen);
+           if (SvPVX_const(sv) && SvCUR(sv)) {
+               Move(SvPVX_const(sv), s, (newlen < SvCUR(sv)) ? newlen : SvCUR(sv), char);
            }
        }
        SvPV_set(sv, s);
@@ -1690,7 +1712,7 @@ Perl_sv_setiv(pTHX_ register SV *sv, IV i)
                   OP_DESC(PL_op));
     }
     (void)SvIOK_only(sv);                      /* validate number */
-    SvIVX(sv) = i;
+    SvIV_set(sv, i);
     SvTAINT(sv);
 }
 
@@ -1735,7 +1757,7 @@ Perl_sv_setuv(pTHX_ register SV *sv, UV u)
     }
     sv_setiv(sv, 0);
     SvIsUV_on(sv);
-    SvUVX(sv) = u;
+    SvUV_set(sv, u);
 }
 
 /*
@@ -1749,21 +1771,9 @@ Like C<sv_setuv>, but also handles 'set' magic.
 void
 Perl_sv_setuv_mg(pTHX_ register SV *sv, UV u)
 {
-    /* With these two if statements:
-       u=1.49  s=0.52  cu=72.49  cs=10.64  scripts=270  tests=20865
-
-       without
-       u=1.35  s=0.47  cu=73.45  cs=11.43  scripts=270  tests=20865
-
-       If you wish to remove them, please benchmark to see what the effect is
-    */
-    if (u <= (UV)IV_MAX) {
-       sv_setiv(sv, (IV)u);
-    } else {
-       sv_setiv(sv, 0);
-       SvIsUV_on(sv);
-       sv_setuv(sv,u);
-    }
+    sv_setiv(sv, 0);
+    SvIsUV_on(sv);
+    sv_setuv(sv,u);
     SvSETMAGIC(sv);
 }
 
@@ -1800,7 +1810,7 @@ Perl_sv_setnv(pTHX_ register SV *sv, NV num)
        Perl_croak(aTHX_ "Can't coerce %s to number in %s", sv_reftype(sv,0),
                   OP_NAME(PL_op));
     }
-    SvNVX(sv) = num;
+    SvNV_set(sv, num);
     (void)SvNOK_only(sv);                      /* validate number */
     SvTAINT(sv);
 }
@@ -1829,10 +1839,10 @@ S_not_a_number(pTHX_ SV *sv)
 {
      SV *dsv;
      char tmpbuf[64];
-     char *pv;
+     const char *pv;
 
      if (DO_UTF8(sv)) {
-          dsv = sv_2mortal(newSVpv("", 0));
+          dsv = sv_2mortal(newSVpvn("", 0));
           pv = sv_uni_display(dsv, sv, 10, 0);
      } else {
          char *d = tmpbuf;
@@ -1840,8 +1850,9 @@ S_not_a_number(pTHX_ SV *sv)
          /* each *s can expand to 4 chars + "...\0",
             i.e. need room for 8 chars */
        
-         char *s, *end;
-         for (s = SvPVX(sv), end = s + SvCUR(sv); s < end && d < limit; s++) {
+         const char *s, *end;
+         for (s = SvPVX_const(sv), end = s + SvCUR(sv); s < end && d < limit;
+              s++) {
               int ch = *s & 0xFF;
               if (ch & 128 && !isPRINT_LC(ch)) {
                    *d++ = 'M';
@@ -1906,15 +1917,15 @@ non-numeric warning), even if your atof() doesn't grok them.
 I32
 Perl_looks_like_number(pTHX_ SV *sv)
 {
-    register char *sbegin;
+    register const char *sbegin;
     STRLEN len;
 
     if (SvPOK(sv)) {
-       sbegin = SvPVX(sv);
+       sbegin = SvPVX_const(sv);
        len = SvCUR(sv);
     }
     else if (SvPOKp(sv))
-       sbegin = SvPV(sv, len);
+       sbegin = SvPV_const(sv, len);
     else
        return SvFLAGS(sv) & (SVf_NOK|SVp_NOK|SVf_IOK|SVp_IOK);
     return grok_number(sbegin, len, NULL);
@@ -2007,18 +2018,18 @@ Perl_looks_like_number(pTHX_ SV *sv)
 STATIC int
 S_sv_2iuv_non_preserve(pTHX_ register SV *sv, I32 numtype)
 {
-    DEBUG_c(PerlIO_printf(Perl_debug_log,"sv_2iuv_non '%s', IV=0x%"UVxf" NV=%"NVgf" inttype=%"UVXf"\n", SvPVX(sv), SvIVX(sv), SvNVX(sv), (UV)numtype));
+    DEBUG_c(PerlIO_printf(Perl_debug_log,"sv_2iuv_non '%s', IV=0x%"UVxf" NV=%"NVgf" inttype=%"UVXf"\n", SvPVX_const(sv), SvIVX(sv), SvNVX(sv), (UV)numtype));
     if (SvNVX(sv) < (NV)IV_MIN) {
        (void)SvIOKp_on(sv);
        (void)SvNOK_on(sv);
-       SvIVX(sv) = IV_MIN;
+       SvIV_set(sv, IV_MIN);
        return IS_NUMBER_UNDERFLOW_IV;
     }
     if (SvNVX(sv) > (NV)UV_MAX) {
        (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);
@@ -2026,7 +2037,7 @@ S_sv_2iuv_non_preserve(pTHX_ register SV *sv, I32 numtype)
     /* Can't use strtol etc to convert this string.  (See truth table in
        sv_2iv  */
     if (SvNVX(sv) <= (UV)IV_MAX) {
-        SvIVX(sv) = I_V(SvNVX(sv));
+        SvIV_set(sv, I_V(SvNVX(sv)));
         if ((NV)(SvIVX(sv)) == SvNVX(sv)) {
             SvIOK_on(sv); /* Integer is precise. NOK, IOK */
         } else {
@@ -2035,7 +2046,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
@@ -2076,7 +2087,7 @@ Perl_sv_2iv(pTHX_ register SV *sv)
            return asIV(sv);
        if (!SvROK(sv)) {
            if (!(SvFLAGS(sv) & SVs_PADTMP)) {
-               if (ckWARN(WARN_UNINITIALIZED) && !PL_localizing)
+               if (!PL_localizing && ckWARN(WARN_UNINITIALIZED))
                    report_uninit();
            }
            return 0;
@@ -2122,7 +2133,7 @@ Perl_sv_2iv(pTHX_ register SV *sv)
           answer is the UV IV_MAX +1. Hence < ensures that dodgy boundary
           cases go to UV */
        if (SvNVX(sv) < (NV)IV_MAX + 0.5) {
-           SvIVX(sv) = I_V(SvNVX(sv));
+           SvIV_set(sv, I_V(SvNVX(sv)));
            if (SvNVX(sv) == (NV) SvIVX(sv)
 #ifndef NV_PRESERVES_UV
                && (((UV)1 << NV_PRESERVES_UV_BITS) >
@@ -2160,7 +2171,7 @@ Perl_sv_2iv(pTHX_ register SV *sv)
               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
@@ -2185,7 +2196,7 @@ Perl_sv_2iv(pTHX_ register SV *sv)
     }
     else if (SvPOKp(sv) && SvLEN(sv)) {
        UV value;
-       int numtype = grok_number(SvPVX(sv), SvCUR(sv), &value);
+       const int numtype = grok_number(SvPVX_const(sv), SvCUR(sv), &value);
        /* We want to avoid a possible problem when we cache an IV which
           may be later translated to an NV, and the resulting NV is not
           the same as the direct translation of the initial string
@@ -2223,15 +2234,15 @@ Perl_sv_2iv(pTHX_ register SV *sv)
            if (!(numtype & IS_NUMBER_NEG)) {
                /* positive */;
                if (value <= (UV)IV_MAX) {
-                   SvIVX(sv) = (IV)value;
+                   SvIV_set(sv, (IV)value);
                } else {
-                   SvUVX(sv) = value;
+                   SvUV_set(sv, value);
                    SvIsUV_on(sv);
                }
            } else {
                /* 2s complement assumption  */
                if (value <= (UV)IV_MIN) {
-                   SvIVX(sv) = -(IV)value;
+                   SvIV_set(sv, -(IV)value);
                } else {
                    /* Too negative for an IV.  This is a double upgrade, but
                       I'm assuming it will be rare.  */
@@ -2240,8 +2251,8 @@ Perl_sv_2iv(pTHX_ register SV *sv)
                    SvNOK_on(sv);
                    SvIOK_off(sv);
                    SvIOKp_on(sv);
-                   SvNVX(sv) = -(NV)value;
-                   SvIVX(sv) = IV_MIN;
+                   SvNV_set(sv, -(NV)value);
+                   SvIV_set(sv, IV_MIN);
                }
            }
        }
@@ -2252,7 +2263,7 @@ Perl_sv_2iv(pTHX_ register SV *sv)
        if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
            != IS_NUMBER_IN_UV) {
            /* It wasn't an (integer that doesn't overflow the UV). */
-           SvNVX(sv) = Atof(SvPVX(sv));
+           SvNV_set(sv, Atof(SvPVX_const(sv)));
 
            if (! numtype && ckWARN(WARN_NUMERIC))
                not_a_number(sv);
@@ -2270,7 +2281,7 @@ Perl_sv_2iv(pTHX_ register SV *sv)
            (void)SvIOKp_on(sv);
            (void)SvNOK_on(sv);
            if (SvNVX(sv) < (NV)IV_MAX + 0.5) {
-               SvIVX(sv) = I_V(SvNVX(sv));
+               SvIV_set(sv, I_V(SvNVX(sv)));
                if ((NV)(SvIVX(sv)) == SvNVX(sv)) {
                    SvIOK_on(sv);
                } else {
@@ -2281,10 +2292,10 @@ Perl_sv_2iv(pTHX_ register SV *sv)
                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);
@@ -2310,7 +2321,7 @@ Perl_sv_2iv(pTHX_ register SV *sv)
                     /* Small enough to preserve all bits. */
                     (void)SvIOKp_on(sv);
                     SvNOK_on(sv);
-                    SvIVX(sv) = I_V(SvNVX(sv));
+                    SvIV_set(sv, I_V(SvNVX(sv)));
                     if ((NV)(SvIVX(sv)) == SvNVX(sv))
                         SvIOK_on(sv);
                     /* Assumption: first non-preserved integer is < IV_MAX,
@@ -2336,7 +2347,7 @@ Perl_sv_2iv(pTHX_ register SV *sv)
 #endif /* NV_PRESERVES_UV */
        }
     } else  {
-       if (ckWARN(WARN_UNINITIALIZED) && !PL_localizing && !(SvFLAGS(sv) & SVs_PADTMP))
+       if (!PL_localizing && !(SvFLAGS(sv) & SVs_PADTMP) && ckWARN(WARN_UNINITIALIZED))
            report_uninit();
        if (SvTYPE(sv) < SVt_IV)
            /* Typically the caller expects that sv_any is not NULL now.  */
@@ -2373,7 +2384,7 @@ Perl_sv_2uv(pTHX_ register SV *sv)
            return asUV(sv);
        if (!SvROK(sv)) {
            if (!(SvFLAGS(sv) & SVs_PADTMP)) {
-               if (ckWARN(WARN_UNINITIALIZED) && !PL_localizing)
+               if (!PL_localizing && ckWARN(WARN_UNINITIALIZED))
                    report_uninit();
            }
            return 0;
@@ -2416,7 +2427,7 @@ Perl_sv_2uv(pTHX_ register SV *sv)
 
        (void)SvIOKp_on(sv);    /* Must do this first, to clear any SvOOK */
        if (SvNVX(sv) < (NV)IV_MAX + 0.5) {
-           SvIVX(sv) = I_V(SvNVX(sv));
+           SvIV_set(sv, I_V(SvNVX(sv)));
            if (SvNVX(sv) == (NV) SvIVX(sv)
 #ifndef NV_PRESERVES_UV
                && (((UV)1 << NV_PRESERVES_UV_BITS) >
@@ -2454,7 +2465,7 @@ Perl_sv_2uv(pTHX_ register SV *sv)
               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
@@ -2477,7 +2488,7 @@ Perl_sv_2uv(pTHX_ register SV *sv)
     }
     else if (SvPOKp(sv) && SvLEN(sv)) {
        UV value;
-       int numtype = grok_number(SvPVX(sv), SvCUR(sv), &value);
+       const int numtype = grok_number(SvPVX_const(sv), SvCUR(sv), &value);
 
        /* We want to avoid a possible problem when we cache a UV which
           may be later translated to an NV, and the resulting NV is not
@@ -2513,16 +2524,16 @@ Perl_sv_2uv(pTHX_ register SV *sv)
            if (!(numtype & IS_NUMBER_NEG)) {
                /* positive */;
                if (value <= (UV)IV_MAX) {
-                   SvIVX(sv) = (IV)value;
+                   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 {
                /* 2s complement assumption  */
                if (value <= (UV)IV_MIN) {
-                   SvIVX(sv) = -(IV)value;
+                   SvIV_set(sv, -(IV)value);
                } else {
                    /* Too negative for an IV.  This is a double upgrade, but
                       I'm assuming it will be rare.  */
@@ -2531,8 +2542,8 @@ Perl_sv_2uv(pTHX_ register SV *sv)
                    SvNOK_on(sv);
                    SvIOK_off(sv);
                    SvIOKp_on(sv);
-                   SvNVX(sv) = -(NV)value;
-                   SvIVX(sv) = IV_MIN;
+                   SvNV_set(sv, -(NV)value);
+                   SvIV_set(sv, IV_MIN);
                }
            }
        }
@@ -2540,7 +2551,7 @@ Perl_sv_2uv(pTHX_ register SV *sv)
        if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
            != IS_NUMBER_IN_UV) {
            /* It wasn't an integer, or it overflowed the UV. */
-           SvNVX(sv) = Atof(SvPVX(sv));
+           SvNV_set(sv, Atof(SvPVX_const(sv)));
 
             if (! numtype && ckWARN(WARN_NUMERIC))
                    not_a_number(sv);
@@ -2557,7 +2568,7 @@ Perl_sv_2uv(pTHX_ register SV *sv)
             (void)SvIOKp_on(sv);
             (void)SvNOK_on(sv);
             if (SvNVX(sv) < (NV)IV_MAX + 0.5) {
-                SvIVX(sv) = I_V(SvNVX(sv));
+                SvIV_set(sv, I_V(SvNVX(sv)));
                 if ((NV)(SvIVX(sv)) == SvNVX(sv)) {
                     SvIOK_on(sv);
                 } else {
@@ -2568,10 +2579,10 @@ Perl_sv_2uv(pTHX_ register SV *sv)
                 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)) {
@@ -2597,7 +2608,7 @@ Perl_sv_2uv(pTHX_ register SV *sv)
                     /* Small enough to preserve all bits. */
                     (void)SvIOKp_on(sv);
                     SvNOK_on(sv);
-                    SvIVX(sv) = I_V(SvNVX(sv));
+                    SvIV_set(sv, I_V(SvNVX(sv)));
                     if ((NV)(SvIVX(sv)) == SvNVX(sv))
                         SvIOK_on(sv);
                     /* Assumption: first non-preserved integer is < IV_MAX,
@@ -2614,7 +2625,7 @@ Perl_sv_2uv(pTHX_ register SV *sv)
     }
     else  {
        if (!(SvFLAGS(sv) & SVs_PADTMP)) {
-           if (ckWARN(WARN_UNINITIALIZED) && !PL_localizing)
+           if (!PL_localizing && ckWARN(WARN_UNINITIALIZED))
                report_uninit();
        }
        if (SvTYPE(sv) < SVt_IV)
@@ -2648,10 +2659,10 @@ Perl_sv_2nv(pTHX_ register SV *sv)
        if (SvNOKp(sv))
            return SvNVX(sv);
        if (SvPOKp(sv) && SvLEN(sv)) {
-           if (ckWARN(WARN_NUMERIC) && !SvIOKp(sv) &&
-               !grok_number(SvPVX(sv), SvCUR(sv), NULL))
+           if (!SvIOKp(sv) && ckWARN(WARN_NUMERIC) &&
+               !grok_number(SvPVX_const(sv), SvCUR(sv), NULL))
                not_a_number(sv);
-           return Atof(SvPVX(sv));
+           return Atof(SvPVX_const(sv));
        }
        if (SvIOKp(sv)) {
            if (SvIsUV(sv))
@@ -2661,10 +2672,10 @@ Perl_sv_2nv(pTHX_ register SV *sv)
        }       
         if (!SvROK(sv)) {
            if (!(SvFLAGS(sv) & SVs_PADTMP)) {
-               if (ckWARN(WARN_UNINITIALIZED) && !PL_localizing)
+               if (!PL_localizing && ckWARN(WARN_UNINITIALIZED))
                    report_uninit();
            }
-            return 0;
+            return (NV)0;
         }
     }
     if (SvTHINKFIRST(sv)) {
@@ -2712,7 +2723,7 @@ Perl_sv_2nv(pTHX_ register SV *sv)
         return SvNVX(sv);
     }
     if (SvIOKp(sv)) {
-       SvNVX(sv) = SvIsUV(sv) ? (NV)SvUVX(sv) : (NV)SvIVX(sv);
+       SvNV_set(sv, SvIsUV(sv) ? (NV)SvUVX(sv) : (NV)SvIVX(sv));
 #ifdef NV_PRESERVES_UV
        SvNOK_on(sv);
 #else
@@ -2727,19 +2738,19 @@ Perl_sv_2nv(pTHX_ register SV *sv)
     }
     else if (SvPOKp(sv) && SvLEN(sv)) {
        UV value;
-       int numtype = grok_number(SvPVX(sv), SvCUR(sv), &value);
-       if (ckWARN(WARN_NUMERIC) && !SvIOKp(sv) && !numtype)
+       const int numtype = grok_number(SvPVX_const(sv), SvCUR(sv), &value);
+       if (!SvIOKp(sv) && !numtype && ckWARN(WARN_NUMERIC))
            not_a_number(sv);
 #ifdef NV_PRESERVES_UV
        if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
            == IS_NUMBER_IN_UV) {
            /* It's definitely an integer */
-           SvNVX(sv) = (numtype & IS_NUMBER_NEG) ? -(NV)value : (NV)value;
+           SvNV_set(sv, (numtype & IS_NUMBER_NEG) ? -(NV)value : (NV)value);
        } else
-           SvNVX(sv) = Atof(SvPVX(sv));
+           SvNV_set(sv, Atof(SvPVX_const(sv)));
        SvNOK_on(sv);
 #else
-       SvNVX(sv) = Atof(SvPVX(sv));
+       SvNV_set(sv, Atof(SvPVX_const(sv)));
        /* Only set the public NV OK flag if this NV preserves the value in
           the PV at least as well as an IV/UV would.
           Not sure how to do this 100% reliably. */
@@ -2763,11 +2774,11 @@ Perl_sv_2nv(pTHX_ register SV *sv)
                 SvIOKp_on(sv);
 
                 if (numtype & IS_NUMBER_NEG) {
-                    SvIVX(sv) = -(IV)value;
+                    SvIV_set(sv, -(IV)value);
                 } else if (value <= (UV)IV_MAX) {
-                   SvIVX(sv) = (IV)value;
+                   SvIV_set(sv, (IV)value);
                } else {
-                   SvUVX(sv) = value;
+                   SvUV_set(sv, value);
                    SvIsUV_on(sv);
                }
 
@@ -2778,7 +2789,7 @@ Perl_sv_2nv(pTHX_ register SV *sv)
                        flags.  NWC, 2000/11/25 */
                     /* Both already have p flags, so do nothing */
                 } else {
-                    NV nv = SvNVX(sv);
+                   const NV nv = SvNVX(sv);
                     if (SvNVX(sv) < (NV)IV_MAX + 0.5) {
                         if (SvIVX(sv) == I_V(nv)) {
                             SvNOK_on(sv);
@@ -2794,7 +2805,7 @@ Perl_sv_2nv(pTHX_ register SV *sv)
                         if (numtype & IS_NUMBER_NOT_INT) {
                             /* UV and NV both imprecise.  */
                         } else {
-                            UV nv_as_uv = U_V(nv);
+                           const UV nv_as_uv = U_V(nv);
 
                             if (value == nv_as_uv && SvUVX(sv) != UV_MAX) {
                                 SvNOK_on(sv);
@@ -2810,7 +2821,7 @@ Perl_sv_2nv(pTHX_ register SV *sv)
 #endif /* NV_PRESERVES_UV */
     }
     else  {
-       if (ckWARN(WARN_UNINITIALIZED) && !PL_localizing && !(SvFLAGS(sv) & SVs_PADTMP))
+       if (!PL_localizing && !(SvFLAGS(sv) & SVs_PADTMP) && ckWARN(WARN_UNINITIALIZED))
            report_uninit();
        if (SvTYPE(sv) < SVt_NV)
            /* Typically the caller expects that sv_any is not NULL now.  */
@@ -2844,7 +2855,7 @@ STATIC IV
 S_asIV(pTHX_ SV *sv)
 {
     UV value;
-    int numtype = grok_number(SvPVX(sv), SvCUR(sv), &value);
+    const int numtype = grok_number(SvPVX_const(sv), SvCUR(sv), &value);
 
     if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
        == IS_NUMBER_IN_UV) {
@@ -2861,7 +2872,7 @@ S_asIV(pTHX_ SV *sv)
        if (ckWARN(WARN_NUMERIC))
            not_a_number(sv);
     }
-    return I_V(Atof(SvPVX(sv)));
+    return I_V(Atof(SvPVX_const(sv)));
 }
 
 /* asUV(): extract an unsigned integer from the string value of an SV
@@ -2871,7 +2882,7 @@ STATIC UV
 S_asUV(pTHX_ SV *sv)
 {
     UV value;
-    int numtype = grok_number(SvPVX(sv), SvCUR(sv), &value);
+    const int numtype = grok_number(SvPVX_const(sv), SvCUR(sv), &value);
 
     if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
        == IS_NUMBER_IN_UV) {
@@ -2883,7 +2894,7 @@ S_asUV(pTHX_ SV *sv)
        if (ckWARN(WARN_NUMERIC))
            not_a_number(sv);
     }
-    return U_V(Atof(SvPVX(sv)));
+    return U_V(Atof(SvPVX_const(sv)));
 }
 
 /*
@@ -2897,8 +2908,7 @@ use the macro wrapper C<SvPV_nolen(sv)> instead.
 char *
 Perl_sv_2pv_nolen(pTHX_ register SV *sv)
 {
-    STRLEN n_a;
-    return sv_2pv(sv, &n_a);
+    return sv_2pv(sv, 0);
 }
 
 /* uiv_2buf(): private routine for use by sv_2pv_flags(): print an IV or
@@ -2909,7 +2919,7 @@ Perl_sv_2pv_nolen(pTHX_ register SV *sv)
  */
 
 static char *
-uiv_2buf(char *buf, IV iv, UV uv, int is_uv, char **peob)
+S_uiv_2buf(char *buf, IV iv, UV uv, int is_uv, char **peob)
 {
     char *ptr = buf + TYPE_CHARS(UV);
     char *ebuf = ptr;
@@ -2965,14 +2975,20 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
     char *tmpbuf = tbuf;
 
     if (!sv) {
-       *lp = 0;
-       return "";
+       if (lp)
+           *lp = 0;
+       return (char *)"";
     }
     if (SvGMAGICAL(sv)) {
        if (flags & SV_GMAGIC)
            mg_get(sv);
        if (SvPOKp(sv)) {
-           *lp = SvCUR(sv);
+           if (lp)
+               *lp = SvCUR(sv);
+           if (flags & SV_MUTABLE_RETURN)
+               return SvPVX_mutable(sv);
+           if (flags & SV_CONST_RETURN)
+               return (char *)SvPVX_const(sv);
            return SvPVX(sv);
        }
        if (SvIOKp(sv)) {
@@ -2990,19 +3006,36 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
        }
         if (!SvROK(sv)) {
            if (!(SvFLAGS(sv) & SVs_PADTMP)) {
-               if (ckWARN(WARN_UNINITIALIZED) && !PL_localizing)
+               if (!PL_localizing && ckWARN(WARN_UNINITIALIZED))
                    report_uninit();
            }
-            *lp = 0;
-            return "";
+           if (lp)
+               *lp = 0;
+            return (char *)"";
         }
     }
     if (SvTHINKFIRST(sv)) {
        if (SvROK(sv)) {
            SV* tmpstr;
+            register const char *typestr;
             if (SvAMAGIC(sv) && (tmpstr=AMG_CALLun(sv,string)) &&
                 (!SvROK(tmpstr) || (SvRV(tmpstr) != SvRV(sv)))) {
-                char *pv = SvPV(tmpstr, *lp);
+               /* Unwrap this:  */
+               /* char *pv = lp ? SvPV(tmpstr, *lp) : SvPV_nolen(tmpstr); */
+
+                char *pv;
+               if ((SvFLAGS(tmpstr) & (SVf_POK)) == SVf_POK) {
+                   if (flags & SV_CONST_RETURN) {
+                       pv = (char *) SvPVX_const(tmpstr);
+                   } else {
+                       pv = (flags & SV_MUTABLE_RETURN)
+                           ? SvPVX_mutable(tmpstr) : SvPVX(tmpstr);
+                   }
+                   if (lp)
+                       *lp = SvCUR(tmpstr);
+               } else {
+                   pv = sv_2pv_flags(tmpstr, lp, flags);
+               }
                 if (SvUTF8(tmpstr))
                     SvUTF8_on(sv);
                 else
@@ -3012,7 +3045,7 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
            origsv = sv;
            sv = (SV*)SvRV(sv);
            if (!sv)
-               s = "NULLREF";
+               typestr = "NULLREF";
            else {
                MAGIC *mg;
                
@@ -3022,10 +3055,10 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
                           (SVs_OBJECT|SVf_OK|SVs_GMG|SVs_SMG|SVs_RMG))
                          == (SVs_OBJECT|SVs_SMG))
                         && (mg = mg_find(sv, PERL_MAGIC_qr))) {
-                       regexp *re = (regexp *)mg->mg_obj;
+                        const regexp *re = (regexp *)mg->mg_obj;
 
                        if (!mg->mg_ptr) {
-                           char *fptr = "msix";
+                            const char *fptr = "msix";
                            char reflags[6];
                            char ch;
                            int left = 0;
@@ -3065,10 +3098,10 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
                              */
                             if (PMf_EXTENDED & re->reganch)
                             {
-                                char *endptr = re->precomp + re->prelen;
+                                const char *endptr = re->precomp + re->prelen;
                                 while (endptr >= re->precomp)
                                 {
-                                    char c = *(endptr--);
+                                    const char c = *(endptr--);
                                     if (c == '\n')
                                         break; /* don't need another */
                                     if (c == '#') {
@@ -3081,7 +3114,7 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
                                 }
                             }
 
-                           New(616, mg->mg_ptr, mg->mg_len + 1 + left, char);
+                           Newx(mg->mg_ptr, mg->mg_len + 1 + left, char);
                            Copy("(?", mg->mg_ptr, 2, char);
                            Copy(reflags, mg->mg_ptr+2, left, char);
                            Copy(":", mg->mg_ptr+left+2, 1, char);
@@ -3097,7 +3130,8 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
                            SvUTF8_on(origsv);
                        else
                            SvUTF8_off(origsv);
-                       *lp = mg->mg_len;
+                       if (lp)
+                           *lp = mg->mg_len;
                        return mg->mg_ptr;
                    }
                                        /* Fall through */
@@ -3108,53 +3142,47 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
                case SVt_PV:
                case SVt_PVIV:
                case SVt_PVNV:
-               case SVt_PVBM:  if (SvROK(sv))
-                                   s = "REF";
-                               else
-                                   s = "SCALAR";               break;
-               case SVt_PVLV:  s = SvROK(sv) ? "REF"
+               case SVt_PVBM:  typestr = SvROK(sv) ? "REF" : "SCALAR"; break;
+               case SVt_PVLV:  typestr = SvROK(sv) ? "REF"
                                /* tied lvalues should appear to be
                                 * scalars for backwards compatitbility */
                                : (LvTYPE(sv) == 't' || LvTYPE(sv) == 'T')
                                    ? "SCALAR" : "LVALUE";      break;
-               case SVt_PVAV:  s = "ARRAY";                    break;
-               case SVt_PVHV:  s = "HASH";                     break;
-               case SVt_PVCV:  s = "CODE";                     break;
-               case SVt_PVGV:  s = "GLOB";                     break;
-               case SVt_PVFM:  s = "FORMAT";                   break;
-               case SVt_PVIO:  s = "IO";                       break;
-               default:        s = "UNKNOWN";                  break;
+               case SVt_PVAV:  typestr = "ARRAY";      break;
+               case SVt_PVHV:  typestr = "HASH";       break;
+               case SVt_PVCV:  typestr = "CODE";       break;
+               case SVt_PVGV:  typestr = "GLOB";       break;
+               case SVt_PVFM:  typestr = "FORMAT";     break;
+               case SVt_PVIO:  typestr = "IO";         break;
+               default:        typestr = "UNKNOWN";    break;
                }
                tsv = NEWSV(0,0);
                if (SvOBJECT(sv)) {
-                    HV *svs = SvSTASH(sv);
-                   Perl_sv_setpvf(
-                        aTHX_ tsv, "%s=%s",
-                        /* [20011101.072] This bandaid for C<package;>
-                           should eventually be removed. AMS 20011103 */
-                        (svs ? HvNAME(svs) : "<none>"), s
-                    );
-                }
+                   const char *name = HvNAME_get(SvSTASH(sv));
+                   Perl_sv_setpvf(aTHX_ tsv, "%s=%s(0x%"UVxf")",
+                                  name ? name : "__ANON__" , typestr, PTR2UV(sv));
+               }
                else
-                   sv_setpv(tsv, s);
-               Perl_sv_catpvf(aTHX_ tsv, "(0x%"UVxf")", PTR2UV(sv));
+                   Perl_sv_setpvf(aTHX_ tsv, "%s(0x%"UVxf")", typestr, PTR2UV(sv));
                goto tokensaveref;
            }
-           *lp = strlen(s);
-           return s;
+           if (lp)
+               *lp = strlen(typestr);
+           return (char *)typestr;
        }
        if (SvREADONLY(sv) && !SvOK(sv)) {
            if (ckWARN(WARN_UNINITIALIZED))
                report_uninit();
-           *lp = 0;
-           return "";
+           if (lp)
+               *lp = 0;
+           return (char *)"";
        }
     }
     if (SvIOK(sv) || ((SvIOKp(sv) && !SvNOKp(sv)))) {
        /* I'm assuming that if both IV and NV are equally valid then
           converting the IV is going to be more efficient */
-       U32 isIOK = SvIOK(sv);
-       U32 isUIOK = SvIsUV(sv);
+       const U32 isIOK = SvIOK(sv);
+       const U32 isUIOK = SvIsUV(sv);
        char buf[TYPE_CHARS(UV)];
        char *ebuf, *ptr;
 
@@ -3164,8 +3192,9 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
            ptr = uiv_2buf(buf, 0, SvUVX(sv), 1, &ebuf);
        else
            ptr = uiv_2buf(buf, SvIVX(sv), 0, 0, &ebuf);
-       SvGROW(sv, (STRLEN)(ebuf - ptr + 1));   /* inlined from sv_setpvn */
-       Move(ptr,SvPVX(sv),ebuf - ptr,char);
+       /* inlined from sv_setpvn */
+       SvGROW_mutable(sv, (STRLEN)(ebuf - ptr + 1));
+       Move(ptr,SvPVX_mutable(sv),ebuf - ptr,char);
        SvCUR_set(sv, ebuf - ptr);
        s = SvEND(sv);
        *s = '\0';
@@ -3180,8 +3209,7 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
        if (SvTYPE(sv) < SVt_PVNV)
            sv_upgrade(sv, SVt_PVNV);
        /* The +20 is pure guesswork.  Configure test needed. --jhi */
-       SvGROW(sv, NV_DIG + 20);
-       s = SvPVX(sv);
+       s = SvGROW_mutable(sv, NV_DIG + 20);
        olderrno = errno;       /* some Xenix systems wipe out errno here */
 #ifdef apollo
        if (SvNVX(sv) == 0.0)
@@ -3203,20 +3231,28 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
 #endif
     }
     else {
-       if (ckWARN(WARN_UNINITIALIZED)
-           && !PL_localizing && !(SvFLAGS(sv) & SVs_PADTMP))
+       if (!PL_localizing && !(SvFLAGS(sv) & SVs_PADTMP) && ckWARN(WARN_UNINITIALIZED))
            report_uninit();
+       if (lp)
        *lp = 0;
        if (SvTYPE(sv) < SVt_PV)
            /* Typically the caller expects that sv_any is not NULL now.  */
            sv_upgrade(sv, SVt_PV);
-       return "";
+       return (char *)"";
+    }
+    {
+       STRLEN len = s - SvPVX_const(sv);
+       if (lp) 
+           *lp = len;
+       SvCUR_set(sv, len);
     }
-    *lp = s - SvPVX(sv);
-    SvCUR_set(sv, *lp);
     SvPOK_on(sv);
     DEBUG_c(PerlIO_printf(Perl_debug_log, "0x%"UVxf" 2pv(%s)\n",
-                         PTR2UV(sv),SvPVX(sv)));
+                         PTR2UV(sv),SvPVX_const(sv)));
+    if (flags & SV_CONST_RETURN)
+       return (char *)SvPVX_const(sv);
+    if (flags & SV_MUTABLE_RETURN)
+       return SvPVX_mutable(sv);
     return SvPVX(sv);
 
   tokensave:
@@ -3227,16 +3263,17 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
        if (!tsv)
            tsv = newSVpv(tmpbuf, 0);
        sv_2mortal(tsv);
-       *lp = SvCUR(tsv);
+       if (lp)
+           *lp = SvCUR(tsv);
        return SvPVX(tsv);
     }
     else {
-       STRLEN len;
-       char *t;
+       STRLEN len;
+        const char *t;
 
        if (tsv) {
            sv_2mortal(tsv);
-           t = SvPVX(tsv);
+           t = SvPVX_const(tsv);
            len = SvCUR(tsv);
        }
        else {
@@ -3250,11 +3287,12 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
        }
 #endif
        (void)SvUPGRADE(sv, SVt_PV);
-       *lp = len;
-       s = SvGROW(sv, len + 1);
+       if (lp)
+           *lp = len;
+       s = SvGROW_mutable(sv, len + 1);
        SvCUR_set(sv, len);
        SvPOKp_on(sv);
-       return strcpy(s, t);
+       return memcpy(s, t, len + 1);
     }
 }
 
@@ -3276,8 +3314,7 @@ void
 Perl_sv_copypv(pTHX_ SV *dsv, register SV *ssv)
 {
     STRLEN len;
-    char *s;
-    s = SvPV(ssv,len);
+    const char * const s = SvPV_const(ssv,len);
     sv_setpvn(dsv,s,len);
     if (SvUTF8(ssv))
        SvUTF8_on(dsv);
@@ -3299,8 +3336,7 @@ Usually accessed via the C<SvPVbyte_nolen> macro.
 char *
 Perl_sv_2pvbyte_nolen(pTHX_ register SV *sv)
 {
-    STRLEN n_a;
-    return sv_2pvbyte(sv, &n_a);
+    return sv_2pvbyte(sv, 0);
 }
 
 /*
@@ -3319,7 +3355,7 @@ char *
 Perl_sv_2pvbyte(pTHX_ register SV *sv, STRLEN *lp)
 {
     sv_utf8_downgrade(sv,0);
-    return SvPV(sv,*lp);
+    return lp ? SvPV(sv,*lp) : SvPV_nolen(sv);
 }
 
 /*
@@ -3336,8 +3372,7 @@ Usually accessed via the C<SvPVutf8_nolen> macro.
 char *
 Perl_sv_2pvutf8_nolen(pTHX_ register SV *sv)
 {
-    STRLEN n_a;
-    return sv_2pvutf8(sv, &n_a);
+    return sv_2pvutf8(sv, 0);
 }
 
 /*
@@ -3355,7 +3390,7 @@ char *
 Perl_sv_2pvutf8(pTHX_ register SV *sv, STRLEN *lp)
 {
     sv_utf8_upgrade(sv);
-    return SvPV(sv,*lp);
+    return lp ? SvPV(sv,*lp) : SvPV_nolen(sv);
 }
 
 /*
@@ -3383,8 +3418,8 @@ Perl_sv_2bool(pTHX_ register SV *sv)
       return SvRV(sv) != 0;
     }
     if (SvPOKp(sv)) {
-       register XPV* Xpvtmp;
-       if ((Xpvtmp = (XPV*)SvANY(sv)) &&
+       register XPV* const Xpvtmp = (XPV*)SvANY(sv);
+       if (Xpvtmp &&
                (*Xpvtmp->xpv_pv > '0' ||
                Xpvtmp->xpv_cur > 1 ||
                (Xpvtmp->xpv_cur && *Xpvtmp->xpv_pv != '0')))
@@ -3444,9 +3479,6 @@ use the Encode extension for that.
 STRLEN
 Perl_sv_utf8_upgrade_flags(pTHX_ register SV *sv, I32 flags)
 {
-    U8 *s, *t, *e;
-    int  hibit = 0;
-
     if (sv == &PL_sv_undef)
        return 0;
     if (!SvPOK(sv)) {
@@ -3471,31 +3503,32 @@ Perl_sv_utf8_upgrade_flags(pTHX_ register SV *sv, I32 flags)
     if (PL_encoding && !(flags & SV_UTF8_NO_ENCODING))
         sv_recode_to_utf8(sv, PL_encoding);
     else { /* Assume Latin-1/EBCDIC */
-        /* This function could be much more efficient if we
-         * had a FLAG in SVs to signal if there are any hibit
-         * chars in the PV.  Given that there isn't such a flag
-         * make the loop as fast as possible. */
-        s = (U8 *) SvPVX(sv);
-        e = (U8 *) SvEND(sv);
-        t = s;
-        while (t < e) {
-             U8 ch = *t++;
-             if ((hibit = !NATIVE_IS_INVARIANT(ch)))
-                  break;
-        }
-        if (hibit) {
-             STRLEN len;
-             (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;
-             if (SvLEN(sv) != 0)
-                  Safefree(s); /* No longer using what was there before. */
-             SvLEN(sv) = len; /* No longer know the real size. */
-        }
-        /* Mark as UTF-8 even if no hibit - saves scanning loop */
-        SvUTF8_on(sv);
+       /* This function could be much more efficient if we
+        * had a FLAG in SVs to signal if there are any hibit
+        * chars in the PV.  Given that there isn't such a flag
+        * make the loop as fast as possible. */
+       const U8 *s = (U8 *) SvPVX_const(sv);
+       const U8 *e = (U8 *) SvEND(sv);
+       const U8 *t = s;
+       int hibit = 0;
+       
+       while (t < e) {
+           const U8 ch = *t++;
+           if ((hibit = !NATIVE_IS_INVARIANT(ch)))
+               break;
+       }
+       if (hibit) {
+           STRLEN len = SvCUR(sv) + 1; /* Plus the \0 */
+           U8 * const recoded = bytes_to_utf8((U8*)s, &len);
+
+           SvPV_free(sv); /* No longer using what was there before. */
+
+           SvPV_set(sv, (char*)recoded);
+           SvCUR_set(sv, len - 1);
+           SvLEN_set(sv, len); /* No longer know the real size. */
+       }
+       /* Mark as UTF-8 even if no hibit - saves scanning loop */
+       SvUTF8_on(sv);
     }
     return SvCUR(sv);
 }
@@ -3536,7 +3569,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);
@@ -3581,8 +3614,8 @@ bool
 Perl_sv_utf8_decode(pTHX_ register SV *sv)
 {
     if (SvPOKp(sv)) {
-        U8 *c;
-        U8 *e;
+        const U8 *c;
+        const U8 *e;
 
        /* The octets may have got themselves encoded - get them back as
         * bytes
@@ -3593,12 +3626,12 @@ Perl_sv_utf8_decode(pTHX_ register SV *sv)
         /* it is actually just a matter of turning the utf8 flag on, but
          * we want to make sure everything inside is valid utf8 first.
          */
-        c = (U8 *) SvPVX(sv);
-       if (!is_utf8_string(c, SvCUR(sv)+1))
+        c = (const U8 *) SvPVX_const(sv);
+       if (!is_utf8_string((U8 *)c, SvCUR(sv)+1))
            return FALSE;
-        e = (U8 *) SvEND(sv);
+        e = (const U8 *) SvEND(sv);
         while (c < e) {
-           U8 ch = *c++;
+           const U8 ch = *c++;
             if (!UTF8_IS_INVARIANT(ch)) {
                SvUTF8_on(sv);
                break;
@@ -3701,7 +3734,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
                break;
            }
            (void)SvIOK_only(dstr);
-           SvIVX(dstr) = SvIVX(sstr);
+           SvIV_set(dstr,  SvIVX(sstr));
            if (SvIsUV(sstr))
                SvIsUV_on(dstr);
            if (SvTAINTED(sstr))
@@ -3723,7 +3756,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
                sv_upgrade(dstr, SVt_PVNV);
                break;
            }
-           SvNVX(dstr) = SvNVX(sstr);
+           SvNV_set(dstr, SvNVX(sstr));
            (void)SvNOK_only(dstr);
            if (SvTAINTED(sstr))
                SvTAINT(dstr);
@@ -3766,19 +3799,21 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
     case SVt_PVHV:
     case SVt_PVCV:
     case SVt_PVIO:
+       {
+       const char * const type = sv_reftype(sstr,0);
        if (PL_op)
-           Perl_croak(aTHX_ "Bizarre copy of %s in %s", sv_reftype(sstr, 0),
-               OP_NAME(PL_op));
+           Perl_croak(aTHX_ "Bizarre copy of %s in %s", type, OP_NAME(PL_op));
        else
-           Perl_croak(aTHX_ "Bizarre copy of %s", sv_reftype(sstr, 0));
+           Perl_croak(aTHX_ "Bizarre copy of %s", type);
+       }
        break;
 
     case SVt_PVGV:
        if (dtype <= SVt_PVGV) {
   glob_assign:
            if (dtype != SVt_PVGV) {
-               char *name = GvNAME(sstr);
-               STRLEN len = GvNAMELEN(sstr);
+               const char * const name = GvNAME(sstr);
+               const STRLEN len = GvNAMELEN(sstr);
                sv_upgrade(dstr, SVt_PVGV);
                sv_magic(dstr, dstr, PERL_MAGIC_glob, Nullch, 0);
                GvSTASH(dstr) = (HV*)SvREFCNT_inc(GvSTASH(sstr));
@@ -3836,7 +3871,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
            if (dtype == SVt_PVGV) {
                SV *sref = SvREFCNT_inc(SvRV(sstr));
                SV *dref = 0;
-               int intro = GvINTRO(dstr);
+               const int intro = GvINTRO(dstr);
 
 #ifdef GV_UNIQUE_CHECK
                 if (GvUNIQUE((GV*)dstr)) {
@@ -3912,13 +3947,15 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
                                        CvCONST(cv)
                                        ? "Constant subroutine %s::%s redefined"
                                        : "Subroutine %s::%s redefined",
-                                       HvNAME(GvSTASH((GV*)dstr)),
+                                       HvNAME_get(GvSTASH((GV*)dstr)),
                                        GvENAME((GV*)dstr));
                                }
                            }
                            if (!intro)
                                cv_ckproto(cv, (GV*)dstr,
-                                       SvPOK(sref) ? SvPVX(sref) : Nullch);
+                                          SvPOK(sref)
+                                          ? (char *)SvPVX_const(sref)
+                                          : Nullch);
                        }
                        GvCV(dstr) = (CV*)sref;
                        GvCVGEN(dstr) = 0; /* Switch off cacheness. */
@@ -3964,22 +4001,21 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
                    SvTAINT(dstr);
                return;
            }
-           if (SvPVX(dstr)) {
-               (void)SvOOK_off(dstr);          /* backoff */
-               if (SvLEN(dstr))
-                   Safefree(SvPVX(dstr));
-               SvLEN(dstr)=SvCUR(dstr)=0;
+           if (SvPVX_const(dstr)) {
+               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);
            /* Only set the public OK flag if the source has public OK.  */
            if (sflags & SVf_NOK)
                SvFLAGS(dstr) |= SVf_NOK;
-           SvNVX(dstr) = SvNVX(sstr);
+           SvNV_set(dstr, SvNVX(sstr));
        }
        if (sflags & SVp_IOK) {
            (void)SvIOKp_on(dstr);
@@ -3987,7 +4023,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
                SvFLAGS(dstr) |= SVf_IOK;
            if (sflags & SVf_IVisUV)
                SvIsUV_on(dstr);
-           SvIVX(dstr) = SvIVX(sstr);
+           SvIV_set(dstr, SvIVX(sstr));
        }
        if (SvAMAGIC(sstr)) {
            SvAMAGIC_on(dstr);
@@ -3998,8 +4034,8 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
        /*
         * Check to see if we can just swipe the string.  If so, it's a
         * possible small lose on short strings, but a big win on long ones.
-        * It might even be a win on short strings if SvPVX(dstr)
-        * has to be allocated and SvPVX(sstr) has to be freed.
+        * It might even be a win on short strings if SvPVX_const(dstr)
+        * has to be allocated and SvPVX_const(sstr) has to be freed.
         */
 
        if (SvTEMP(sstr) &&             /* slated for free anyway? */
@@ -4010,13 +4046,8 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
                                /* and won't be needed again, potentially */
            !(PL_op && PL_op->op_type == OP_AASSIGN))
        {
-           if (SvPVX(dstr)) {          /* we know that dtype >= SVt_PV */
-               if (SvOOK(dstr)) {
-                   SvFLAGS(dstr) &= ~SVf_OOK;
-                   Safefree(SvPVX(dstr) - SvIVX(dstr));
-               }
-               else if (SvLEN(dstr))
-                   Safefree(SvPVX(dstr));
+           if (SvPVX_const(dstr)) {    /* we know that dtype >= SVt_PV */
+               SvPV_free(dstr);
            }
            (void)SvPOK_only(dstr);
            SvPV_set(dstr, SvPVX(sstr));
@@ -4033,19 +4064,18 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
        else {                          /* have to copy actual string */
            STRLEN len = SvCUR(sstr);
            SvGROW(dstr, len + 1);      /* inlined from sv_setpvn */
-           Move(SvPVX(sstr),SvPVX(dstr),len,char);
+           Move(SvPVX_const(sstr),SvPVX(dstr),len,char);
            SvCUR_set(dstr, len);
            *SvEND(dstr) = '\0';
            (void)SvPOK_only(dstr);
        }
        if (sflags & SVf_UTF8)
            SvUTF8_on(dstr);
-       /*SUPPRESS 560*/
        if (sflags & SVp_NOK) {
            SvNOKp_on(dstr);
            if (sflags & SVf_NOK)
                SvFLAGS(dstr) |= SVf_NOK;
-           SvNVX(dstr) = SvNVX(sstr);
+           SvNV_set(dstr, SvNVX(sstr));
        }
        if (sflags & SVp_IOK) {
            (void)SvIOKp_on(dstr);
@@ -4053,7 +4083,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
                SvFLAGS(dstr) |= SVf_IOK;
            if (sflags & SVf_IVisUV)
                SvIsUV_on(dstr);
-           SvIVX(dstr) = SvIVX(sstr);
+           SvIV_set(dstr, SvIVX(sstr));
        }
        if ( SvVOK(sstr) ) {
            MAGIC *smg = mg_find(sstr,PERL_MAGIC_vstring);
@@ -4072,13 +4102,13 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
        /* XXXX Do we want to set IsUV for IV(ROK)?  Be extra safe... */
        if (sflags & SVf_IVisUV)
            SvIsUV_on(dstr);
-       SvIVX(dstr) = SvIVX(sstr);
+       SvIV_set(dstr, SvIVX(sstr));
        if (sflags & SVp_NOK) {
            if (sflags & SVf_NOK)
                (void)SvNOK_on(dstr);
            else
                (void)SvNOKp_on(dstr);
-           SvNVX(dstr) = SvNVX(sstr);
+           SvNV_set(dstr, SvNVX(sstr));
        }
     }
     else if (sflags & SVp_NOK) {
@@ -4088,7 +4118,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
            (void)SvOK_off(dstr);
            SvNOKp_on(dstr);
        }
-       SvNVX(dstr) = SvNVX(sstr);
+       SvNV_set(dstr, SvNVX(sstr));
     }
     else {
        if (dtype == SVt_PVGV) {
@@ -4139,14 +4169,13 @@ Perl_sv_setpvn(pTHX_ register SV *sv, register const char *ptr, register STRLEN
     }
     else {
         /* len is STRLEN which is unsigned, need to copy to signed */
-       IV iv = len;
+       const IV iv = len;
        if (iv < 0)
            Perl_croak(aTHX_ "panic: sv_setpvn called with negative strlen");
     }
     (void)SvUPGRADE(sv, SVt_PV);
 
-    SvGROW(sv, len + 1);
-    dptr = SvPVX(sv);
+    dptr = SvGROW(sv, len + 1);
     Move(ptr,dptr,len,char);
     dptr[len] = '\0';
     SvCUR_set(sv, len);
@@ -4230,19 +4259,21 @@ See C<sv_usepvn_mg>.
 void
 Perl_sv_usepvn(pTHX_ register SV *sv, register char *ptr, register STRLEN len)
 {
+    STRLEN allocate;
     SV_CHECK_THINKFIRST(sv);
     (void)SvUPGRADE(sv, SVt_PV);
     if (!ptr) {
        (void)SvOK_off(sv);
        return;
     }
-    (void)SvOOK_off(sv);
-    if (SvPVX(sv) && SvLEN(sv))
-       Safefree(SvPVX(sv));
-    Renew(ptr, len+1, char);
-    SvPVX(sv) = ptr;
+    if (SvPVX_const(sv))
+       SvPV_free(sv);
+
+    allocate = PERL_STRLEN_ROUNDUP(len + 1);
+    ptr = saferealloc (ptr, allocate);
+    SvPV_set(sv, ptr);
     SvCUR_set(sv, len);
-    SvLEN_set(sv, len+1);
+    SvLEN_set(sv, allocate);
     *SvEND(sv) = '\0';
     (void)SvPOK_only_UTF8(sv);         /* validate pointer */
     SvTAINT(sv);
@@ -4279,9 +4310,9 @@ Perl_sv_force_normal_flags(pTHX_ register SV *sv, U32 flags)
 {
     if (SvREADONLY(sv)) {
        if (SvFAKE(sv)) {
-           char *pvx = SvPVX(sv);
-           STRLEN len = SvCUR(sv);
-            U32 hash   = SvUVX(sv);
+           const char * const pvx = SvPVX_const(sv);
+           const STRLEN len = SvCUR(sv);
+           const U32 hash = SvSHARED_HASH(sv);
            SvFAKE_off(sv);
            SvREADONLY_off(sv);
            SvGROW(sv, len + 1);
@@ -4321,7 +4352,7 @@ Efficient removal of characters from the beginning of the string buffer.
 SvPOK(sv) must be true and the C<ptr> must be a pointer to somewhere inside
 the string buffer.  The C<ptr> becomes the first character of the adjusted
 string. Uses the "OOK hack".
-Beware: after this function returns, C<ptr> and SvPVX(sv) may no longer
+Beware: after this function returns, C<ptr> and SvPVX_const(sv) may no longer
 refer to the same chunk of data.
 
 =cut
@@ -4333,30 +4364,30 @@ Perl_sv_chop(pTHX_ register SV *sv, register char *ptr)
     register STRLEN delta;
     if (!ptr || !SvPOKp(sv))
        return;
-    delta = ptr - SvPVX(sv);
+    delta = ptr - SvPVX_const(sv);
     SV_CHECK_THINKFIRST(sv);
     if (SvTYPE(sv) < SVt_PVIV)
        sv_upgrade(sv,SVt_PVIV);
 
     if (!SvOOK(sv)) {
        if (!SvLEN(sv)) { /* make copy of shared string */
-           char *pvx = SvPVX(sv);
-           STRLEN len = SvCUR(sv);
+           const char *pvx = SvPVX_const(sv);
+           const STRLEN len = SvCUR(sv);
            SvGROW(sv, len + 1);
            Move(pvx,SvPVX(sv),len,char);
            *SvEND(sv) = '\0';
        }
-       SvIVX(sv) = 0;
+       SvIV_set(sv, 0);
        /* Same SvOOK_on but SvOOK_on does a SvIOK_off
           and we do that anyway inside the SvNIOK_off
        */
        SvFLAGS(sv) |= SVf_OOK; 
     }
     SvNIOK_off(sv);
-    SvLEN(sv) -= delta;
-    SvCUR(sv) -= delta;
-    SvPVX(sv) += delta;
-    SvIVX(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);
 }
 
 /* sv_catpvn() is now a macro using Perl_sv_catpvn_flags();
@@ -4393,14 +4424,13 @@ void
 Perl_sv_catpvn_flags(pTHX_ register SV *dsv, register const char *sstr, register STRLEN slen, I32 flags)
 {
     STRLEN dlen;
-    char *dstr;
+    const char *dstr = SvPV_force_flags(dsv, dlen, flags);
 
-    dstr = SvPV_force_flags(dsv, dlen, flags);
     SvGROW(dsv, dlen + slen + 1);
     if (sstr == dstr)
-       sstr = SvPVX(dsv);
+       sstr = SvPVX_const(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);
@@ -4450,11 +4480,11 @@ and C<sv_catsv_nomg> are implemented in terms of this function.
 void
 Perl_sv_catsv_flags(pTHX_ SV *dsv, register SV *ssv, I32 flags)
 {
-    char *spv;
+    const char *spv;
     STRLEN slen;
     if (!ssv)
        return;
-    if ((spv = SvPV(ssv, slen))) {
+    if ((spv = SvPV_const(ssv, slen))) {
        /*  sutf8 and dutf8 were type bool, but under USE_ITHREADS,
            gcc version 2.95.2 20000220 (Debian GNU/Linux) for
            Linux xxx 2.2.17 on sparc64 with gcc -O2, we erroneously
@@ -4462,7 +4492,7 @@ Perl_sv_catsv_flags(pTHX_ SV *dsv, register SV *ssv, I32 flags)
            dsv->sv_flags doesn't have that bit set.
                Andy Dougherty  12 Oct 2001
        */
-       I32 sutf8 = DO_UTF8(ssv);
+       const I32 sutf8 = DO_UTF8(ssv);
        I32 dutf8;
 
        if (SvGMAGICAL(dsv) && (flags & SV_GMAGIC))
@@ -4475,7 +4505,7 @@ Perl_sv_catsv_flags(pTHX_ SV *dsv, register SV *ssv, I32 flags)
                SV* csv = sv_2mortal(newSVpvn(spv, slen));
 
                sv_utf8_upgrade(csv);
-               spv = SvPV(csv, slen);
+               spv = SvPV_const(csv, slen);
            }
            else
                sv_utf8_upgrade_nomg(dsv);
@@ -4521,9 +4551,9 @@ Perl_sv_catpv(pTHX_ register SV *sv, register const char *ptr)
     len = strlen(ptr);
     SvGROW(sv, tlen + len + 1);
     if (ptr == junk)
-       ptr = SvPVX(sv);
+       ptr = SvPVX_const(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);
 }
@@ -4569,18 +4599,18 @@ Perl_newSV(pTHX_ STRLEN len)
 =for apidoc sv_magicext
 
 Adds magic to an SV, upgrading it if necessary. Applies the
-supplied vtable and returns pointer to the magic added.
+supplied vtable and returns pointer to the magic added.
 
-Note that sv_magicext will allow things that sv_magic will not.
-In particular you can add magic to SvREADONLY SVs and and more than
-one instance of the same 'how'
+Note that C<sv_magicext> will allow things that C<sv_magic> will not.
+In particular, you can add magic to SvREADONLY SVs, and add more than
+one instance of the same 'how'.
 
-I C<namelen> is greater then zero then a savepvn() I<copy> of C<name> is stored,
-if C<namelen> is zero then C<name> is stored as-is and - as another special
-case - if C<(name && namelen == HEf_SVKEY)> then C<name> is assumed to contain
-an C<SV*> and has its REFCNT incremented
+If C<namlen> is greater than zero then a C<savepvn> I<copy> of C<name> is
+stored, if C<namlen> is zero then C<name> is stored as-is and - as another
+special case - if C<(name && namlen == HEf_SVKEY)> then C<name> is assumed
+to contain an C<SV*> and is stored as-is with its REFCNT incremented.
 
-(This is now used as a subroutine by sv_magic.)
+(This is now used as a subroutine by C<sv_magic>.)
 
 =cut
 */
@@ -4593,14 +4623,14 @@ Perl_sv_magicext(pTHX_ SV* sv, SV* obj, int how, MGVTBL *vtable,
     if (SvTYPE(sv) < SVt_PVMG) {
        (void)SvUPGRADE(sv, SVt_PVMG);
     }
-    Newz(702,mg, 1, MAGIC);
+    Newxz(mg, 1, MAGIC);
     mg->mg_moremagic = SvMAGIC(sv);
-    SvMAGIC(sv) = mg;
+    SvMAGIC_set(sv, mg);
 
-    /* Some magic sontains a reference loop, where the sv and object refer to
-       each other.  To prevent a reference loop that would prevent such
-       objects being freed, we look for such loops and if we find one we
-       avoid incrementing the object refcount.
+    /* Sometimes a magic contains a reference loop, where the sv and
+       object refer to each other.  To prevent a reference loop that
+       would prevent such objects being freed, we look for such loops
+       and if we find one we avoid incrementing the object refcount.
 
        Note we cannot do this to avoid self-tie loops as intervening RV must
        have its REFCNT incremented to keep it in existence.
@@ -4659,17 +4689,28 @@ Perl_sv_magicext(pTHX_ SV* sv, SV* obj, int how, MGVTBL *vtable,
 Adds magic to an SV. First upgrades C<sv> to type C<SVt_PVMG> if necessary,
 then adds a new magic item of type C<how> to the head of the magic list.
 
+See C<sv_magicext> (which C<sv_magic> now calls) for a description of the
+handling of the C<name> and C<namlen> arguments.
+
+You need to use C<sv_magicext> to add magic to SvREADONLY SVs and also
+to add more than one instance of the same 'how'.
+
 =cut
 */
 
 void
 Perl_sv_magic(pTHX_ register SV *sv, SV *obj, int how, const char *name, I32 namlen)
 {
+    const MGVTBL *vtable;
     MAGIC* mg;
-    MGVTBL *vtable = 0;
 
     if (SvREADONLY(sv)) {
-       if (IN_PERL_RUNTIME
+       if (
+           /* its okay to attach magic to shared strings; the subsequent
+            * upgrade to PVMG will unshare the string */
+           !(SvFAKE(sv) && SvTYPE(sv) < SVt_PVMG)
+
+           && IN_PERL_RUNTIME
            && how != PERL_MAGIC_regex_global
            && how != PERL_MAGIC_bm
            && how != PERL_MAGIC_fm
@@ -4735,7 +4776,7 @@ Perl_sv_magic(pTHX_ register SV *sv, SV *obj, int how, const char *name, I32 nam
        vtable = &PL_vtbl_nkeys;
        break;
     case PERL_MAGIC_dbfile:
-       vtable = 0;
+       vtable = NULL;
        break;
     case PERL_MAGIC_dbline:
        vtable = &PL_vtbl_dbline;
@@ -4776,7 +4817,7 @@ Perl_sv_magic(pTHX_ register SV *sv, SV *obj, int how, const char *name, I32 nam
        vtable = &PL_vtbl_vec;
        break;
     case PERL_MAGIC_vstring:
-       vtable = 0;
+       vtable = NULL;
        break;
     case PERL_MAGIC_utf8:
         vtable = &PL_vtbl_utf8;
@@ -4804,13 +4845,14 @@ Perl_sv_magic(pTHX_ register SV *sv, SV *obj, int how, const char *name, I32 nam
        /* Useful for attaching extension internal data to perl vars.   */
        /* Note that multiple extensions may clash if magical scalars   */
        /* etc holding private data from one are passed to another.     */
+       vtable = NULL;
        break;
     default:
        Perl_croak(aTHX_ "Don't know how to handle magic of type \\%o", how);
     }
 
     /* 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:
@@ -4841,7 +4883,7 @@ Perl_sv_unmagic(pTHX_ SV *sv, int type)
     mgp = &SvMAGIC(sv);
     for (mg = *mgp; mg; mg = *mgp) {
        if (mg->mg_type == type) {
-           MGVTBL* vtbl = mg->mg_virtual;
+            const MGVTBL* const vtbl = mg->mg_virtual;
            *mgp = mg->mg_moremagic;
            if (vtbl && vtbl->svt_free)
                CALL_FPTR(vtbl->svt_free)(aTHX_ sv, mg);
@@ -4918,13 +4960,6 @@ S_sv_add_backref(pTHX_ SV *tsv, SV *sv)
         * by magic_killbackrefs() when tsv is being freed */
     }
     if (AvFILLp(av) >= AvMAX(av)) {
-        I32 i;
-        SV **svp = AvARRAY(av);
-        for (i = AvFILLp(av); i >= 0; i--)
-            if (!svp[i]) {
-                svp[i] = sv;        /* reuse the slot */
-                return;
-            }
         av_extend(av, AvFILLp(av)+1);
     }
     AvARRAY(av)[++AvFILLp(av)] = sv; /* av_push() */
@@ -4940,14 +4975,29 @@ S_sv_del_backref(pTHX_ SV *sv)
     AV *av;
     SV **svp;
     I32 i;
-    SV *tsv = SvRV(sv);
+    SV * const tsv = SvRV(sv);
     MAGIC *mg = NULL;
     if (!SvMAGICAL(tsv) || !(mg = mg_find(tsv, PERL_MAGIC_backref)))
        Perl_croak(aTHX_ "panic: del_backref");
     av = (AV *)mg->mg_obj;
     svp = AvARRAY(av);
-    for (i = AvFILLp(av); i >= 0; i--)
-       if (svp[i] == sv) svp[i] = Nullsv;
+    /* We shouldn't be in here more than once, but for paranoia reasons lets
+       not assume this.  */
+    for (i = AvFILLp(av); i >= 0; i--) {
+       if (svp[i] == sv) {
+           const SSize_t fill = AvFILLp(av);
+           if (i != fill) {
+               /* We weren't the last entry.
+                  An unordered list has this property that you can take the
+                  last element off the end to fill the hole, and it's still
+                  an unordered list :-)
+               */
+               svp[i] = svp[fill];
+           }
+           svp[fill] = Nullsv;
+           AvFILLp(av) = fill - 1;
+       }
+    }
 }
 
 /*
@@ -4991,7 +5041,7 @@ Perl_sv_insert(pTHX_ SV *bigstr, STRLEN offset, STRLEN len, char *little, STRLEN
        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;
     }
@@ -5022,7 +5072,6 @@ Perl_sv_insert(pTHX_ SV *bigstr, STRLEN offset, STRLEN len, char *little, STRLEN
        *mid = '\0';
        SvCUR_set(bigstr, mid - big);
     }
-    /*SUPPRESS 560*/
     else if ((i = mid - big)) {        /* faster from front */
        midend -= littlelen;
        mid = midend;
@@ -5060,7 +5109,7 @@ time you'll want to use C<sv_setsv> or one of its many macro front-ends.
 void
 Perl_sv_replace(pTHX_ register SV *sv, register SV *nsv)
 {
-    U32 refcnt = SvREFCNT(sv);
+    const U32 refcnt = SvREFCNT(sv);
     SV_CHECK_THINKFIRST(sv);
     if (SvREFCNT(nsv) != 1 && ckWARN_d(WARN_INTERNAL))
        Perl_warner(aTHX_ packWARN(WARN_INTERNAL), "Reference miscount in sv_replace()");
@@ -5069,10 +5118,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);
@@ -5108,15 +5157,12 @@ Perl_sv_clear(pTHX_ register SV *sv)
     if (SvOBJECT(sv)) {
        if (PL_defstash) {              /* Still have a symbol table? */
            dSP;
-           CV* destructor;
-
-
-
            do {        
+               CV* destructor;
                stash = SvSTASH(sv);
                destructor = StashHANDLER(stash,DESTROY);
                if (destructor) {
-                   SV* tmpref = newRV(sv);
+                   SV* const tmpref = newRV(sv);
                    SvREADONLY_on(tmpref);   /* DESTROY() could be naughty */
                    ENTER;
                    PUSHSTACKi(PERLSI_DESTROY);
@@ -5133,7 +5179,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);
@@ -5144,7 +5190,7 @@ Perl_sv_clear(pTHX_ register SV *sv)
            if (SvREFCNT(sv)) {
                if (PL_in_clean_objs)
                    Perl_croak(aTHX_ "DESTROY created new reference to dead object '%s'",
-                         HvNAME(stash));
+                         HvNAME_get(stash));
                /* DESTROY gave object new lease on life */
                return;
            }
@@ -5160,7 +5206,7 @@ Perl_sv_clear(pTHX_ register SV *sv)
     if (SvTYPE(sv) >= SVt_PVMG) {
        if (SvMAGIC(sv))
            mg_free(sv);
-       if (SvFLAGS(sv) & SVpad_TYPED)
+       if (SvTYPE(sv) == SVt_PVMG && SvFLAGS(sv) & SVpad_TYPED)
            SvREFCNT_dec(SvSTASH(sv));
     }
     stash = NULL;
@@ -5214,7 +5260,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_mutable(sv) - SvIVX(sv));
+           /* Don't even bother with turning off the OOK flag.  */
+       }
        /* FALL THROUGH */
     case SVt_PV:
     case SVt_RV:
@@ -5224,10 +5274,10 @@ Perl_sv_clear(pTHX_ register SV *sv)
            else
                SvREFCNT_dec(SvRV(sv));
        }
-       else if (SvPVX(sv) && SvLEN(sv))
-           Safefree(SvPVX(sv));
-       else if (SvPVX(sv) && SvREADONLY(sv) && SvFAKE(sv)) {
-           unsharepvn(SvPVX(sv),
+       else if (SvPVX_const(sv) && SvLEN(sv))
+           Safefree(SvPVX_mutable(sv));
+       else if (SvPVX_const(sv) && SvREADONLY(sv) && SvFAKE(sv)) {
+           unsharepvn(SvPVX_const(sv),
                       SvUTF8(sv) ? -(I32)SvCUR(sv) : SvCUR(sv),
                       SvUVX(sv));
            SvFAKE_off(sv);
@@ -5347,10 +5397,14 @@ Perl_sv_free(pTHX_ SV *sv)
            SvREFCNT(sv) = (~(U32)0)/2;
            return;
        }
-       if (ckWARN_d(WARN_INTERNAL))
+       if (ckWARN_d(WARN_INTERNAL)) {
            Perl_warner(aTHX_ packWARN(WARN_INTERNAL),
                         "Attempt to free unreferenced scalar: SV 0x%"UVxf
                         pTHX__FORMAT, PTR2UV(sv) pTHX__VALUE);
+#ifdef DEBUG_LEAKING_SCALARS_FORK_DUMP
+           Perl_dump_sv_child(aTHX_ sv);
+#endif
+       }
        return;
     }
     ATOMIC_DEC_AND_TEST(refcount_is_zero, SvREFCNT(sv));
@@ -5395,7 +5449,7 @@ Perl_sv_len(pTHX_ register SV *sv)
     if (SvGMAGICAL(sv))
        len = mg_length(sv);
     else
-        (void)SvPV(sv, len);
+        (void)SvPV_const(sv, len);
     return len;
 }
 
@@ -5426,7 +5480,7 @@ Perl_sv_len_utf8(pTHX_ register SV *sv)
     else
     {
        STRLEN len, ulen;
-       U8 *s = (U8*)SvPV(sv, len);
+       const U8 *s = (U8*)SvPV_const(sv, len);
        MAGIC *mg = SvMAGICAL(sv) ? mg_find(sv, PERL_MAGIC_utf8) : 0;
 
        if (mg && mg->mg_len != -1 && (mg->mg_len > 0 || len == 0)) {
@@ -5436,7 +5490,7 @@ Perl_sv_len_utf8(pTHX_ register SV *sv)
 #endif
         }
        else {
-            ulen = Perl_utf8_length(aTHX_ s, s + len);
+            ulen = Perl_utf8_length(aTHX_ (U8 *)s, (U8 *)s + len);
             if (!mg && !SvREADONLY(sv)) {
                  sv_magic(sv, 0, PERL_MAGIC_utf8, 0, 0);
                  mg = mg_find(sv, PERL_MAGIC_utf8);
@@ -5460,26 +5514,27 @@ Perl_sv_len_utf8(pTHX_ register SV *sv)
  *
  */
 STATIC bool
-S_utf8_mg_pos_init(pTHX_ SV *sv, MAGIC **mgp, STRLEN **cachep, I32 i, I32 *offsetp, U8 *s, U8 *start)
+S_utf8_mg_pos_init(pTHX_ SV *sv, MAGIC **mgp, STRLEN **cachep, I32 i,
+                  I32 offsetp, const U8 *s, const U8 *start)
 {
     bool found = FALSE; 
 
     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)
-            *cachep = (STRLEN *) (*mgp)->mg_ptr;
-        else {
-            Newz(0, *cachep, PERL_MAGIC_UTF8_CACHESIZE * 2, STRLEN);
-            (*mgp)->mg_ptr = (char *) *cachep;
-        }
-        assert(*cachep);
+       if ((*mgp)->mg_ptr)
+           *cachep = (STRLEN *) (*mgp)->mg_ptr;
+       else {
+           Newxz(*cachep, PERL_MAGIC_UTF8_CACHESIZE * 2, STRLEN);
+           (*mgp)->mg_ptr = (char *) *cachep;
+       }
+       assert(*cachep);
 
-        (*cachep)[i]   = *offsetp;
-        (*cachep)[i+1] = s - start;
-        found = TRUE;
+       (*cachep)[i]   = offsetp;
+       (*cachep)[i+1] = s - start;
+       found = TRUE;
     }
 
     return found;
@@ -5493,7 +5548,7 @@ S_utf8_mg_pos_init(pTHX_ SV *sv, MAGIC **mgp, STRLEN **cachep, I32 i, I32 *offse
  *
  */
 STATIC bool
-S_utf8_mg_pos(pTHX_ SV *sv, MAGIC **mgp, STRLEN **cachep, I32 i, I32 *offsetp, I32 uoff, U8 **sp, U8 *start, U8 *send)
+S_utf8_mg_pos(pTHX_ SV *sv, MAGIC **mgp, STRLEN **cachep, I32 i, I32 *offsetp, I32 uoff, const U8 **sp, const U8 *start, const U8 *send)
 {
     bool found = FALSE;
 
@@ -5508,7 +5563,7 @@ S_utf8_mg_pos(pTHX_ SV *sv, MAGIC **mgp, STRLEN **cachep, I32 i, I32 *offsetp, I
            else {                      /* We will skip to the right spot. */
                 STRLEN forw  = 0;
                 STRLEN backw = 0;
-                U8* p = NULL;
+                const U8* p = NULL;
 
                 /* The assumption is that going backward is half
                  * the speed of going forward (that's where the
@@ -5527,7 +5582,7 @@ S_utf8_mg_pos(pTHX_ SV *sv, MAGIC **mgp, STRLEN **cachep, I32 i, I32 *offsetp, I
                 /* Try this only for the substr offset (i == 0),
                  * not for the substr length (i == 2). */
                 else if (i == 0) { /* (*cachep)[i] < uoff */
-                     STRLEN ulen = sv_len_utf8(sv);
+                     const STRLEN ulen = sv_len_utf8(sv);
 
                      if ((STRLEN)uoff < ulen) {
                           forw  = (STRLEN)uoff - (*cachep)[i];
@@ -5625,21 +5680,21 @@ type coercion.
 void
 Perl_sv_pos_u2b(pTHX_ register SV *sv, I32* offsetp, I32* lenp)
 {
-    U8 *start;
-    U8 *s;
+    const U8 *start;
     STRLEN len;
-    STRLEN *cache = 0;
-    STRLEN boffset = 0;
 
     if (!sv)
        return;
 
-    start = s = (U8*)SvPV(sv, len);
+    start = (U8*)SvPV_const(sv, len);
     if (len) {
-        I32 uoffset = *offsetp;
-        U8 *send = s + len;
-        MAGIC *mg = 0;
-        bool found = FALSE;
+       STRLEN boffset = 0;
+       STRLEN *cache = 0;
+       const U8 *s = start;
+       I32 uoffset = *offsetp;
+       const U8 * const send = s + len;
+       MAGIC *mg = 0;
+       bool found = FALSE;
 
          if (utf8_mg_pos(sv, &mg, &cache, 0, offsetp, *offsetp, &s, start, send))
              found = TRUE;
@@ -5648,14 +5703,14 @@ Perl_sv_pos_u2b(pTHX_ register SV *sv, I32* offsetp, I32* lenp)
                   s += UTF8SKIP(s);
              if (s >= send)
                   s = send;
-              if (utf8_mg_pos_init(sv, &mg, &cache, 0, offsetp, s, start))
+              if (utf8_mg_pos_init(sv, &mg, &cache, 0, *offsetp, s, start))
                   boffset = cache[1];
              *offsetp = s - start;
         }
         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;
               }
@@ -5666,7 +5721,7 @@ Perl_sv_pos_u2b(pTHX_ register SV *sv, I32* offsetp, I32* lenp)
                             s += UTF8SKIP(s);
                   if (s >= send)
                        s = send;
-                   utf8_mg_pos_init(sv, &mg, &cache, 2, lenp, s, start);
+                   utf8_mg_pos_init(sv, &mg, &cache, 2, *lenp, s, start);
              }
              *lenp = s - start;
         }
@@ -5701,17 +5756,17 @@ Handles magic and type coercion.
 void
 Perl_sv_pos_b2u(pTHX_ register SV* sv, I32* offsetp)
 {
-    U8* s;
+    const U8* s;
     STRLEN len;
 
     if (!sv)
        return;
 
-    s = (U8*)SvPV(sv, len);
+    s = (const U8*)SvPV_const(sv, len);
     if ((I32)len < *offsetp)
        Perl_croak(aTHX_ "panic: sv_pos_b2u: bad byte offset");
     else {
-       U8* send = s + *offsetp;
+       const U8* send = s + *offsetp;
        MAGIC* mg = NULL;
        STRLEN *cache = NULL;
       
@@ -5739,11 +5794,11 @@ Perl_sv_pos_b2u(pTHX_ register SV* sv, I32* offsetp)
                     * is made as in S_utf8_mg_pos(), namely that
                     * walking backward is twice slower than
                     * walking forward. */
-                   STRLEN forw  = *offsetp;
+                   const STRLEN forw  = *offsetp;
                    STRLEN backw = cache[1] - *offsetp;
 
                    if (!(forw < 2 * backw)) {
-                       U8 *p = s + cache[1];
+                       const U8 *p = s + cache[1];
                        STRLEN ubackw = 0;
                             
                        cache[1] -= backw;
@@ -5777,7 +5832,7 @@ Perl_sv_pos_b2u(pTHX_ register SV* sv, I32* offsetp)
            /* Call utf8n_to_uvchr() to validate the sequence
             * (unless a simple non-UTF character) */
            if (!UTF8_IS_INVARIANT(*s))
-               utf8n_to_uvchr(s, UTF8SKIP(s), &n, 0);
+               utf8n_to_uvchr((U8 *)s, UTF8SKIP(s), &n, 0);
            if (n > 0) {
                s += n;
                len++;
@@ -5794,7 +5849,7 @@ Perl_sv_pos_b2u(pTHX_ register SV* sv, I32* offsetp)
            assert(mg);
 
            if (!mg->mg_ptr) {
-               Newz(0, cache, PERL_MAGIC_UTF8_CACHESIZE * 2, STRLEN);
+               Newxz(cache, PERL_MAGIC_UTF8_CACHESIZE * 2, STRLEN);
                mg->mg_ptr = (char *) cache;
            }
            assert(cache);
@@ -5825,9 +5880,9 @@ coerce its args to strings if necessary.
 I32
 Perl_sv_eq(pTHX_ register SV *sv1, register SV *sv2)
 {
-    char *pv1;
+    const char *pv1;
     STRLEN cur1;
-    char *pv2;
+    const char *pv2;
     STRLEN cur2;
     I32  eq     = 0;
     char *tpv   = Nullch;
@@ -5838,14 +5893,14 @@ Perl_sv_eq(pTHX_ register SV *sv1, register SV *sv2)
        cur1 = 0;
     }
     else
-       pv1 = SvPV(sv1, cur1);
+       pv1 = SvPV_const(sv1, cur1);
 
     if (!sv2){
        pv2 = "";
        cur2 = 0;
     }
     else
-       pv2 = SvPV(sv2, cur2);
+       pv2 = SvPV_const(sv2, cur2);
 
     if (cur1 && cur2 && SvUTF8(sv1) != SvUTF8(sv2) && !IN_BYTES) {
         /* Differing utf8ness.
@@ -5854,12 +5909,12 @@ Perl_sv_eq(pTHX_ register SV *sv1, register SV *sv2)
              if (SvUTF8(sv1)) {
                   svrecode = newSVpvn(pv2, cur2);
                   sv_recode_to_utf8(svrecode, PL_encoding);
-                  pv2 = SvPV(svrecode, cur2);
+                  pv2 = SvPV_const(svrecode, cur2);
              }
              else {
                   svrecode = newSVpvn(pv1, cur1);
                   sv_recode_to_utf8(svrecode, PL_encoding);
-                  pv1 = SvPV(svrecode, cur1);
+                  pv1 = SvPV_const(svrecode, cur1);
              }
              /* Now both are in UTF-8. */
              if (cur1 != cur2) {
@@ -5873,7 +5928,7 @@ Perl_sv_eq(pTHX_ register SV *sv1, register SV *sv2)
              if (SvUTF8(sv1)) {
                   /* sv1 is the UTF-8 one,
                    * if is equal it must be downgrade-able */
-                  char *pv = (char*)bytes_from_utf8((U8*)pv1,
+                  char * const pv = (char*)bytes_from_utf8((U8*)pv1,
                                                     &cur1, &is_utf8);
                   if (pv != pv1)
                        pv1 = tpv = pv;
@@ -5881,7 +5936,7 @@ Perl_sv_eq(pTHX_ register SV *sv1, register SV *sv2)
              else {
                   /* sv2 is the UTF-8 one,
                    * if is equal it must be downgrade-able */
-                  char *pv = (char *)bytes_from_utf8((U8*)pv2,
+                  char * const pv = (char *)bytes_from_utf8((U8*)pv2,
                                                      &cur2, &is_utf8);
                   if (pv != pv2)
                        pv2 = tpv = pv;
@@ -5920,7 +5975,8 @@ I32
 Perl_sv_cmp(pTHX_ register SV *sv1, register SV *sv2)
 {
     STRLEN cur1, cur2;
-    char *pv1, *pv2, *tpv = Nullch;
+    const char *pv1, *pv2;
+    char *tpv = Nullch;
     I32  cmp;
     SV *svrecode = Nullsv;
 
@@ -5929,14 +5985,14 @@ Perl_sv_cmp(pTHX_ register SV *sv1, register SV *sv2)
        cur1 = 0;
     }
     else
-       pv1 = SvPV(sv1, cur1);
+       pv1 = SvPV_const(sv1, cur1);
 
     if (!sv2) {
        pv2 = "";
        cur2 = 0;
     }
     else
-       pv2 = SvPV(sv2, cur2);
+       pv2 = SvPV_const(sv2, cur2);
 
     if (cur1 && cur2 && SvUTF8(sv1) != SvUTF8(sv2) && !IN_BYTES) {
         /* Differing utf8ness.
@@ -5945,7 +6001,7 @@ Perl_sv_cmp(pTHX_ register SV *sv1, register SV *sv2)
            if (PL_encoding) {
                 svrecode = newSVpvn(pv2, cur2);
                 sv_recode_to_utf8(svrecode, PL_encoding);
-                pv2 = SvPV(svrecode, cur2);
+                pv2 = SvPV_const(svrecode, cur2);
            }
            else {
                 pv2 = tpv = (char*)bytes_to_utf8((U8*)pv2, &cur2);
@@ -5955,7 +6011,7 @@ Perl_sv_cmp(pTHX_ register SV *sv1, register SV *sv2)
            if (PL_encoding) {
                 svrecode = newSVpvn(pv1, cur1);
                 sv_recode_to_utf8(svrecode, PL_encoding);
-                pv1 = SvPV(svrecode, cur1);
+                pv1 = SvPV_const(svrecode, cur1);
            }
            else {
                 pv1 = tpv = (char*)bytes_to_utf8((U8*)pv1, &cur1);
@@ -5968,7 +6024,7 @@ Perl_sv_cmp(pTHX_ register SV *sv1, register SV *sv2)
     } else if (!cur2) {
        cmp = 1;
     } else {
-       I32 retval = memcmp((void*)pv1, (void*)pv2, cur1 < cur2 ? cur1 : cur2);
+        const I32 retval = memcmp((const void*)pv1, (const void*)pv2, cur1 < cur2 ? cur1 : cur2);
 
        if (retval) {
            cmp = retval < 0 ? -1 : 1;
@@ -6069,12 +6125,13 @@ Perl_sv_collxfrm(pTHX_ SV *sv, STRLEN *nxp)
 
     mg = SvMAGICAL(sv) ? mg_find(sv, PERL_MAGIC_collxfrm) : (MAGIC *) NULL;
     if (!mg || !mg->mg_ptr || *(U32*)mg->mg_ptr != PL_collation_ix) {
-       char *s, *xf;
+       const char *s;
+       char *xf;
        STRLEN len, xlen;
 
        if (mg)
            Safefree(mg->mg_ptr);
-       s = SvPV(sv, len);
+       s = SvPV_const(sv, len);
        if ((xf = mem_collxfrm(s, len, &xlen))) {
            if (SvREADONLY(sv)) {
                SAVEFREEPV(xf);
@@ -6120,7 +6177,7 @@ appending to the currently-stored string.
 char *
 Perl_sv_gets(pTHX_ register SV *sv, register PerlIO *fp, I32 append)
 {
-    char *rsptr;
+    const char *rsptr;
     STRLEN rslen;
     register STDCHAR rslast;
     register STDCHAR *bp;
@@ -6147,7 +6204,7 @@ Perl_sv_gets(pTHX_ register SV *sv, register PerlIO *fp, I32 append)
                sv_pos_u2b(sv,&append,0);
            }
        } else if (SvUTF8(sv)) {
-           SV *tsv = NEWSV(0,0);
+           SV * const tsv = NEWSV(0,0);
            sv_gets(tsv, fp, 0);
            sv_utf8_upgrade_nomg(tsv);
            SvCUR_set(sv,append);
@@ -6174,7 +6231,7 @@ Perl_sv_gets(pTHX_ register SV *sv, register PerlIO *fp, I32 append)
         */
        Stat_t st;
        if (!PerlLIO_fstat(PerlIO_fileno(fp), &st) && S_ISREG(st.st_mode))  {
-           Off_t offset = PerlIO_tell(fp);
+           const Off_t offset = PerlIO_tell(fp);
            if (offset != (Off_t) -1 && st.st_size + append > offset) {
                (void) SvGROW(sv, (STRLEN)((st.st_size - offset) + append + 1));
            }
@@ -6222,7 +6279,7 @@ Perl_sv_gets(pTHX_ register SV *sv, register PerlIO *fp, I32 append)
                    Perl_croak(aTHX_ "Wide character in $/");
                }
            }
-           rsptr = SvPV(PL_rs, rslen);
+           rsptr = SvPV_const(PL_rs, rslen);
        }
     }
 
@@ -6291,7 +6348,7 @@ Perl_sv_gets(pTHX_ register SV *sv, register PerlIO *fp, I32 append)
     }
     else 
        shortbuffered = 0;
-    bp = (STDCHAR*)SvPVX(sv) + append;  /* move these two too to registers */
+    bp = (STDCHAR*)SvPVX_const(sv) + append;  /* move these two too to registers */
     ptr = (STDCHAR*)PerlIO_get_ptr(fp);
     DEBUG_P(PerlIO_printf(Perl_debug_log,
        "Screamer: entering, ptr=%"UVuf", cnt=%ld\n",PTR2UV(ptr),(long)cnt));
@@ -6320,10 +6377,10 @@ Perl_sv_gets(pTHX_ register SV *sv, register PerlIO *fp, I32 append)
        if (shortbuffered) {            /* oh well, must extend */
            cnt = shortbuffered;
            shortbuffered = 0;
-           bpx = bp - (STDCHAR*)SvPVX(sv); /* box up before relocation */
+           bpx = bp - (STDCHAR*)SvPVX_const(sv); /* box up before relocation */
            SvCUR_set(sv, bpx);
            SvGROW(sv, SvLEN(sv) + append + cnt + 2);
-           bp = (STDCHAR*)SvPVX(sv) + bpx; /* unbox after relocation */
+           bp = (STDCHAR*)SvPVX_const(sv) + bpx; /* unbox after relocation */
            continue;
        }
 
@@ -6355,10 +6412,10 @@ Perl_sv_gets(pTHX_ register SV *sv, register PerlIO *fp, I32 append)
        if (i == EOF)                   /* all done for ever? */
            goto thats_really_all_folks;
 
-       bpx = bp - (STDCHAR*)SvPVX(sv); /* box up before relocation */
+       bpx = bp - (STDCHAR*)SvPVX_const(sv);   /* box up before relocation */
        SvCUR_set(sv, bpx);
        SvGROW(sv, bpx + cnt + 2);
-       bp = (STDCHAR*)SvPVX(sv) + bpx; /* unbox after relocation */
+       bp = (STDCHAR*)SvPVX_const(sv) + bpx;   /* unbox after relocation */
 
        *bp++ = (STDCHAR)i;             /* store character from PerlIO_getc */
 
@@ -6367,7 +6424,7 @@ Perl_sv_gets(pTHX_ register SV *sv, register PerlIO *fp, I32 append)
     }
 
 thats_all_folks:
-    if ((rslen > 1 && (STRLEN)(bp - (STDCHAR*)SvPVX(sv)) < rslen) ||
+    if ((rslen > 1 && (STRLEN)(bp - (STDCHAR*)SvPVX_const(sv)) < rslen) ||
          memNE((char*)bp - rslen, rsptr, rslen))
        goto screamer;                          /* go back to the fray */
 thats_really_all_folks:
@@ -6381,27 +6438,17 @@ thats_really_all_folks:
        PTR2UV(PerlIO_get_ptr(fp)), (long)PerlIO_get_cnt(fp),
        PTR2UV(PerlIO_has_base (fp) ? PerlIO_get_base(fp) : 0)));
     *bp = '\0';
-    SvCUR_set(sv, bp - (STDCHAR*)SvPVX(sv));   /* set length */
+    SvCUR_set(sv, bp - (STDCHAR*)SvPVX_const(sv));     /* set length */
     DEBUG_P(PerlIO_printf(Perl_debug_log,
        "Screamer: done, len=%ld, string=|%.*s|\n",
-       (long)SvCUR(sv),(int)SvCUR(sv),SvPVX(sv)));
+       (long)SvCUR(sv),(int)SvCUR(sv),SvPVX_const(sv)));
     }
    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);
+       Newx(buf, 8192, STDCHAR);
        assert(buf);
 #else
        STDCHAR buf[8192];
@@ -6409,7 +6456,7 @@ thats_really_all_folks:
 
 screamer2:
        if (rslen) {
-           register STDCHAR *bpe = buf + sizeof(buf);
+            const register STDCHAR *bpe = buf + sizeof(buf);
            bp = buf;
            while ((i = PerlIO_getc(fp)) != EOF && (*bp++ = (STDCHAR)i) != rslast && bp < bpe)
                ; /* keep reading */
@@ -6436,7 +6483,7 @@ screamer2:
        if (i != EOF &&                 /* joy */
            (!rslen ||
             SvCUR(sv) < rslen ||
-            memNE(SvPVX(sv) + SvCUR(sv) - rslen, rsptr, rslen)))
+            memNE(SvPVX_const(sv) + SvCUR(sv) - rslen, rsptr, rslen)))
        {
            append = -1;
            /*
@@ -6454,7 +6501,7 @@ screamer2:
                goto screamer2;
        }
 
-#ifdef USEHEAPINSTEADOFSTACK
+#ifdef USE_HEAP_INSTEAD_OF_STACK
        Safefree(buf);
 #endif
     }
@@ -6525,28 +6572,28 @@ 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);
            else {
                (void)SvIOK_only(sv);
-               ++SvIVX(sv);
+               SvIV_set(sv, SvIVX(sv) + 1);
            }   
        }
        return;
     }
     if (flags & SVp_NOK) {
        (void)SvNOK_only(sv);
-       SvNVX(sv) += 1.0;
+        SvNV_set(sv, SvNVX(sv) + 1.0);
        return;
     }
 
-    if (!(flags & SVp_POK) || !*SvPVX(sv)) {
+    if (!(flags & SVp_POK) || !*SvPVX_const(sv)) {
        if ((flags & SVTYPEMASK) < SVt_PVIV)
            sv_upgrade(sv, SVt_IV);
        (void)SvIOK_only(sv);
-       SvIVX(sv) = 1;
+       SvIV_set(sv, 1);
        return;
     }
     d = SvPVX(sv);
@@ -6557,7 +6604,7 @@ Perl_sv_inc(pTHX_ register SV *sv)
        /* Got to punt this as an integer if needs be, but we don't issue
           warnings. Probably ought to make the sv_iv_please() that does
           the conversion if possible, and silently.  */
-       int numtype = grok_number(SvPVX(sv), SvCUR(sv), NULL);
+       const int numtype = grok_number(SvPVX_const(sv), SvCUR(sv), NULL);
        if (numtype && !(numtype & IS_NUMBER_INFINITY)) {
            /* Need to try really hard to see if it's an integer.
               9.22337203685478e+18 is an integer.
@@ -6573,7 +6620,7 @@ Perl_sv_inc(pTHX_ register SV *sv)
            /* sv_2iv *should* have made this an NV */
            if (flags & SVp_NOK) {
                (void)SvNOK_only(sv);
-               SvNVX(sv) += 1.0;
+                SvNV_set(sv, SvNVX(sv) + 1.0);
                return;
            }
            /* I don't think we can get here. Maybe I should assert this
@@ -6581,18 +6628,18 @@ Perl_sv_inc(pTHX_ register SV *sv)
               Fall through. */
 #if defined(USE_LONG_DOUBLE)
            DEBUG_c(PerlIO_printf(Perl_debug_log,"sv_inc punt failed to convert '%s' to IOK or NOKp, UV=0x%"UVxf" NV=%"PERL_PRIgldbl"\n",
-                                 SvPVX(sv), SvIVX(sv), SvNVX(sv)));
+                                 SvPVX_const(sv), SvIVX(sv), SvNVX(sv)));
 #else
            DEBUG_c(PerlIO_printf(Perl_debug_log,"sv_inc punt failed to convert '%s' to IOK or NOKp, UV=0x%"UVxf" NV=%"NVgf"\n",
-                                 SvPVX(sv), SvIVX(sv), SvNVX(sv)));
+                                 SvPVX_const(sv), SvIVX(sv), SvNVX(sv)));
 #endif
        }
 #endif /* PERL_PRESERVE_IVUV */
-       sv_setnv(sv,Atof(SvPVX(sv)) + 1.0);
+       sv_setnv(sv,Atof(SvPVX_const(sv)) + 1.0);
        return;
     }
     d--;
-    while (d >= SvPVX(sv)) {
+    while (d >= SvPVX_const(sv)) {
        if (isDIGIT(*d)) {
            if (++*d <= '9')
                return;
@@ -6621,8 +6668,8 @@ Perl_sv_inc(pTHX_ register SV *sv)
     }
     /* oh,oh, the number grew */
     SvGROW(sv, SvCUR(sv) + 2);
-    SvCUR(sv)++;
-    for (d = SvPVX(sv) + SvCUR(sv); d > SvPVX(sv); d--)
+    SvCUR_set(sv, SvCUR(sv) + 1);
+    for (d = SvPVX(sv) + SvCUR(sv); d > SvPVX_const(sv); d--)
        *d = d[-1];
     if (isDIGIT(d[1]))
        *d = '1';
@@ -6675,37 +6722,37 @@ Perl_sv_dec(pTHX_ register SV *sv)
        if (SvIsUV(sv)) {
            if (SvUVX(sv) == 0) {
                (void)SvIOK_only(sv);
-               SvIVX(sv) = -1;
+               SvIV_set(sv, -1);
            }
            else {
                (void)SvIOK_only_UV(sv);
-               --SvUVX(sv);
+               SvUV_set(sv, SvUVX(sv) - 1);
            }   
        } else {
            if (SvIVX(sv) == IV_MIN)
                sv_setnv(sv, (NV)IV_MIN - 1.0);
            else {
                (void)SvIOK_only(sv);
-               --SvIVX(sv);
+               SvIV_set(sv, SvIVX(sv) - 1);
            }   
        }
        return;
     }
     if (flags & SVp_NOK) {
-       SvNVX(sv) -= 1.0;
+        SvNV_set(sv, SvNVX(sv) - 1.0);
        (void)SvNOK_only(sv);
        return;
     }
     if (!(flags & SVp_POK)) {
-       if ((flags & SVTYPEMASK) < SVt_PVNV)
-           sv_upgrade(sv, SVt_NV);
-       SvNVX(sv) = -1.0;
-       (void)SvNOK_only(sv);
+       if ((flags & SVTYPEMASK) < SVt_PVIV)
+           sv_upgrade(sv, ((flags & SVTYPEMASK) > SVt_IV) ? SVt_PVIV : SVt_IV);
+       SvIV_set(sv, -1);
+       (void)SvIOK_only(sv);
        return;
     }
 #ifdef PERL_PRESERVE_IVUV
     {
-       int numtype = grok_number(SvPVX(sv), SvCUR(sv), NULL);
+       const int numtype = grok_number(SvPVX_const(sv), SvCUR(sv), NULL);
        if (numtype && !(numtype & IS_NUMBER_INFINITY)) {
            /* Need to try really hard to see if it's an integer.
               9.22337203685478e+18 is an integer.
@@ -6721,7 +6768,7 @@ Perl_sv_dec(pTHX_ register SV *sv)
            /* sv_2iv *should* have made this an NV */
            if (flags & SVp_NOK) {
                (void)SvNOK_only(sv);
-               SvNVX(sv) -= 1.0;
+                SvNV_set(sv, SvNVX(sv) - 1.0);
                return;
            }
            /* I don't think we can get here. Maybe I should assert this
@@ -6729,15 +6776,15 @@ Perl_sv_dec(pTHX_ register SV *sv)
               Fall through. */
 #if defined(USE_LONG_DOUBLE)
            DEBUG_c(PerlIO_printf(Perl_debug_log,"sv_dec punt failed to convert '%s' to IOK or NOKp, UV=0x%"UVxf" NV=%"PERL_PRIgldbl"\n",
-                                 SvPVX(sv), SvIVX(sv), SvNVX(sv)));
+                                 SvPVX_const(sv), SvIVX(sv), SvNVX(sv)));
 #else
            DEBUG_c(PerlIO_printf(Perl_debug_log,"sv_dec punt failed to convert '%s' to IOK or NOKp, UV=0x%"UVxf" NV=%"NVgf"\n",
-                                 SvPVX(sv), SvIVX(sv), SvNVX(sv)));
+                                 SvPVX_const(sv), SvIVX(sv), SvNVX(sv)));
 #endif
        }
     }
 #endif /* PERL_PRESERVE_IVUV */
-    sv_setnv(sv,Atof(SvPVX(sv)) - 1.0);        /* punt */
+    sv_setnv(sv,Atof(SvPVX_const(sv)) - 1.0);  /* punt */
 }
 
 /*
@@ -6833,9 +6880,7 @@ Perl_newSVpv(pTHX_ const char *s, STRLEN len)
     register SV *sv;
 
     new_SV(sv);
-    if (!len)
-       len = strlen(s);
-    sv_setpvn(sv,s,len);
+    sv_setpvn(sv,s,len ? len : strlen(s));
     return sv;
 }
 
@@ -6860,15 +6905,70 @@ Perl_newSVpvn(pTHX_ const char *s, STRLEN len)
     return sv;
 }
 
+
+/*
+=for apidoc newSVhek
+
+Creates a new SV from the hash key structure.  It will generate scalars that
+point to the shared string table where possible. Returns a new (undefined)
+SV if the hek is NULL.
+
+=cut
+*/
+
+SV *
+Perl_newSVhek(pTHX_ const HEK *hek)
+{
+    if (!hek) {
+       SV *sv;
+
+       new_SV(sv);
+       return sv;
+    }
+
+    if (HEK_LEN(hek) == HEf_SVKEY) {
+       return newSVsv(*(SV**)HEK_KEY(hek));
+    } else {
+       const int flags = HEK_FLAGS(hek);
+       if (flags & HVhek_WASUTF8) {
+           /* Trouble :-)
+              Andreas would like keys he put in as utf8 to come back as utf8
+           */
+           STRLEN utf8_len = HEK_LEN(hek);
+           const U8 *as_utf8 = bytes_to_utf8 ((U8*)HEK_KEY(hek), &utf8_len);
+           SV * const sv = newSVpvn ((const char*)as_utf8, utf8_len);
+
+           SvUTF8_on (sv);
+           Safefree (as_utf8); /* bytes_to_utf8() allocates a new string */
+           return sv;
+       } else if (flags & HVhek_REHASH) {
+           /* We don't have a pointer to the hv, so we have to replicate the
+              flag into every HEK. This hv is using custom a hasing
+              algorithm. Hence we can't return a shared string scalar, as
+              that would contain the (wrong) hash value, and might get passed
+              into an hv routine with a regular hash  */
+
+           SV * const sv = newSVpvn (HEK_KEY(hek), HEK_LEN(hek));
+           if (HEK_UTF8(hek))
+               SvUTF8_on (sv);
+           return sv;
+       }
+       /* This will be overwhelminly the most common case.  */
+       return newSVpvn_share(HEK_KEY(hek),
+                             (HEK_UTF8(hek) ? -HEK_LEN(hek) : HEK_LEN(hek)),
+                             HEK_HASH(hek));
+    }
+}
+
 /*
 =for apidoc newSVpvn_share
 
-Creates a new SV with its SvPVX pointing to a shared string in the string
+Creates a new SV with its SvPVX_const pointing to a shared string in the string
 table. If the string does not already exist in the table, it is created
 first.  Turns on READONLY and FAKE.  The string's hash is stored in the UV
 slot of the SV; if the C<hash> parameter is non-zero, that value is used;
 otherwise the hash is computed.  The idea here is that as the string table
-is used for shared hash keys these strings will have SvPVX == HeKEY and
+is used for shared hash keys these strings will have SvPVX_const == HeKEY and
 hash lookup will avoid string compare.
 
 =cut
@@ -6890,10 +6990,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);
@@ -7028,7 +7128,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;
 }
@@ -7065,13 +7165,10 @@ Perl_newSVsv(pTHX_ register SV *old)
        return Nullsv;
     }
     new_SV(sv);
-    if (SvTEMP(old)) {
-       SvTEMP_off(old);
-       sv_setsv(sv,old);
-       SvTEMP_on(old);
-    }
-    else
-       sv_setsv(sv,old);
+    /* SV_GMAGIC is the default for sv_setv()
+       SV_NOSTEAL prevents TEMP buffers being, well, stolen, and saves games
+       with SvTEMP_off and SvTEMP_on round a call to sv_setsv.  */
+    sv_setsv_flags(sv, old, SV_GMAGIC | SV_NOSTEAL);
     return sv;
 }
 
@@ -7087,12 +7184,7 @@ Note that the perl-level function is vaguely deprecated.
 void
 Perl_sv_reset(pTHX_ register char *s, HV *stash)
 {
-    register HE *entry;
-    register GV *gv;
-    register SV *sv;
-    register I32 i;
     register PMOP *pm;
-    register I32 max;
     char todo[PERL_UCHAR_MAX+1];
 
     if (!stash)
@@ -7112,7 +7204,8 @@ Perl_sv_reset(pTHX_ register char *s, HV *stash)
 
     Zero(todo, 256, char);
     while (*s) {
-       i = (unsigned char)*s;
+       I32 max;
+       I32 i = (unsigned char)*s;
        if (s[1] == '-') {
            s += 2;
        }
@@ -7121,43 +7214,47 @@ Perl_sv_reset(pTHX_ register char *s, HV *stash)
            todo[i] = 1;
        }
        for (i = 0; i <= (I32) HvMAX(stash); i++) {
+           HE *entry;
            for (entry = HvARRAY(stash)[i];
                 entry;
                 entry = HeNEXT(entry))
            {
+               register GV *gv;
+               register SV *sv;
+
                if (!todo[(U8)*HeKEY(entry)])
                    continue;
                gv = (GV*)HeVAL(entry);
                sv = GvSV(gv);
-               if (SvTHINKFIRST(sv)) {
-                   if (!SvREADONLY(sv) && SvROK(sv))
-                       sv_unref(sv);
-                   continue;
-               }
-               SvOK_off(sv);
-               if (SvTYPE(sv) >= SVt_PV) {
-                   SvCUR_set(sv, 0);
-                   if (SvPVX(sv) != Nullch)
-                       *SvPVX(sv) = '\0';
-                   SvTAINT(sv);
+               if (sv) {
+                   if (SvTHINKFIRST(sv)) {
+                       if (!SvREADONLY(sv) && SvROK(sv))
+                           sv_unref(sv);
+                       /* XXX Is this continue a bug? Why should THINKFIRST
+                          exempt us from resetting arrays and hashes?  */
+                       continue;
+                   }
+                   SvOK_off(sv);
+                   if (SvTYPE(sv) >= SVt_PV) {
+                       SvCUR_set(sv, 0);
+                       if (SvPVX_const(sv) != Nullch)
+                           *SvPVX(sv) = '\0';
+                       SvTAINT(sv);
+                   }
                }
                if (GvAV(gv)) {
                    av_clear(GvAV(gv));
                }
-               if (GvHV(gv) && !HvNAME(GvHV(gv))) {
+               if (GvHV(gv) && !HvNAME_get(GvHV(gv))) {
+#if defined(VMS)
+                   Perl_die(aTHX_ "Can't reset %%ENV on this system");
+#else /* ! VMS */
                    hv_clear(GvHV(gv));
-#ifndef PERL_MICRO
-#ifdef USE_ENVIRON_ARRAY
-                   if (gv == PL_envgv
-#  ifdef USE_ITHREADS
-                       && PL_curinterp == aTHX
-#  endif
-                   )
-                   {
-                       environ[0] = Nullch;
-                   }
-#endif
-#endif /* !PERL_MICRO */
+#  if defined(USE_ENVIRON_ARRAY)
+                   if (gv == PL_envgv)
+                       my_clearenv();
+#  endif /* USE_ENVIRON_ARRAY */
+#endif /* VMS */
                }
            }
        }
@@ -7306,7 +7403,7 @@ Perl_sv_true(pTHX_ register SV *sv)
     if (!sv)
        return 0;
     if (SvPOK(sv)) {
-       register XPV* tXpv;
+       const register XPV* tXpv;
        if ((tXpv = (XPV*)SvANY(sv)) &&
                (tXpv->xpv_cur > 1 ||
                (tXpv->xpv_cur && *tXpv->xpv_pv != '0')))
@@ -7390,12 +7487,10 @@ Perl_sv_nv(pTHX_ register SV *sv)
 char *
 Perl_sv_pv(pTHX_ SV *sv)
 {
-    STRLEN n_a;
-
     if (SvPOK(sv))
        return SvPVX(sv);
 
-    return sv_2pv(sv, &n_a);
+    return sv_2pv(sv, 0);
 }
 
 /*
@@ -7464,24 +7559,34 @@ C<SvPV_force> and C<SvPV_force_nomg>
 char *
 Perl_sv_pvn_force_flags(pTHX_ SV *sv, STRLEN *lp, I32 flags)
 {
-    char *s = NULL;
 
     if (SvTHINKFIRST(sv) && !SvROK(sv))
        sv_force_normal(sv);
 
     if (SvPOK(sv)) {
-       *lp = SvCUR(sv);
+       if (lp)
+           *lp = SvCUR(sv);
     }
     else {
-       if (SvTYPE(sv) > SVt_PVLV && SvTYPE(sv) != SVt_PVFM) {
+       char *s;
+       STRLEN len;
+       if (SvREADONLY(sv) && !(flags & SV_MUTABLE_RETURN)) {
+           const char * const ref = sv_reftype(sv,0);
+           if (PL_op)
+               Perl_croak(aTHX_ "Can't coerce readonly %s to string in %s",
+                          ref, OP_NAME(PL_op));
+           else
+               Perl_croak(aTHX_ "Can't coerce readonly %s to string", ref);
+       }
+       if (SvTYPE(sv) > SVt_PVLV && SvTYPE(sv) != SVt_PVFM)
            Perl_croak(aTHX_ "Can't coerce %s to string in %s", sv_reftype(sv,0),
                OP_NAME(PL_op));
-       }
-       else
-           s = sv_2pv_flags(sv, lp, flags);
-       if (s != SvPVX(sv)) {   /* Almost, but not quite, sv_setpvn() */
-           STRLEN len = *lp;
-       
+       s = sv_2pv_flags(sv, &len, flags);
+       if (lp)
+           *lp = len;
+
+       if (s != SvPVX_const(sv)) {     /* Almost, but not quite, sv_setpvn() */
            if (SvROK(sv))
                sv_unref(sv);
            (void)SvUPGRADE(sv, SVt_PV);                /* Never FALSE */
@@ -7494,10 +7599,10 @@ Perl_sv_pvn_force_flags(pTHX_ SV *sv, STRLEN *lp, I32 flags)
            SvPOK_on(sv);               /* validate pointer */
            SvTAINT(sv);
            DEBUG_c(PerlIO_printf(Perl_debug_log, "0x%"UVxf" 2pv(%s)\n",
-                                 PTR2UV(sv),SvPVX(sv)));
+                                 PTR2UV(sv),SvPVX_const(sv)));
        }
     }
-    return SvPVX(sv);
+    return SvPVX_mutable(sv);
 }
 
 /* sv_pvbyte () is now a macro using Perl_sv_2pv_flags();
@@ -7613,11 +7718,11 @@ Returns a string describing what the SV is a reference to.
 char *
 Perl_sv_reftype(pTHX_ SV *sv, int ob)
 {
+    /* The fact that I don't need to downcast to char * everywhere, only in ?:
+       inside return suggests a const propagation bug in g++.  */
     if (ob && SvOBJECT(sv)) {
-        HV *svs = SvSTASH(sv);
-        /* [20011101.072] This bandaid for C<package;> should eventually
-           be removed. AMS 20011103 */
-        return (svs ? HvNAME(svs) : "<none>");
+       char * const name = HvNAME_get(SvSTASH(sv));
+       return name ? name : (char *) "__ANON__";
     }
     else {
        switch (SvTYPE(sv)) {
@@ -7634,12 +7739,12 @@ Perl_sv_reftype(pTHX_ SV *sv, int ob)
                                    return "REF";
                                else
                                    return "SCALAR";
-                               
-       case SVt_PVLV:          return SvROK(sv) ? "REF"
+
+       case SVt_PVLV:          return (char *)  (SvROK(sv) ? "REF"
                                /* tied lvalues should appear to be
                                 * scalars for backwards compatitbility */
                                : (LvTYPE(sv) == 't' || LvTYPE(sv) == 'T')
-                                   ? "SCALAR" : "LVALUE";
+                                   ? "SCALAR" : "LVALUE");
        case SVt_PVAV:          return "ARRAY";
        case SVt_PVHV:          return "HASH";
        case SVt_PVCV:          return "CODE";
@@ -7689,6 +7794,7 @@ an inheritance relationship.
 int
 Perl_sv_isa(pTHX_ SV *sv, const char *name)
 {
+    const char *hvname;
     if (!sv)
        return 0;
     if (SvGMAGICAL(sv))
@@ -7698,8 +7804,11 @@ Perl_sv_isa(pTHX_ SV *sv, const char *name)
     sv = (SV*)SvRV(sv);
     if (!SvOBJECT(sv))
        return 0;
+    hvname = HvNAME_get(SvSTASH(sv));
+    if (!hvname)
+       return 0;
 
-    return strEQ(HvNAME(SvSTASH(sv)), name);
+    return strEQ(hvname, name);
 }
 
 /*
@@ -7724,7 +7833,7 @@ Perl_newSVrv(pTHX_ SV *rv, const char *classname)
     SvAMAGIC_off(rv);
 
     if (SvTYPE(rv) >= SVt_PVMG) {
-       U32 refcnt = SvREFCNT(rv);
+       const U32 refcnt = SvREFCNT(rv);
        SvREFCNT(rv) = 0;
        sv_clear(rv);
        SvFLAGS(rv) = 0;
@@ -7734,19 +7843,17 @@ 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) {
-       HV* stash = gv_stashpv(classname, TRUE);
+       HV* const stash = gv_stashpv(classname, TRUE);
        (void)sv_bless(rv, stash);
     }
     return sv;
@@ -7891,7 +7998,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);
@@ -7954,22 +8061,22 @@ See C<SvROK_off>.
 void
 Perl_sv_unref_flags(pTHX_ SV *sv, U32 flags)
 {
-    SV* rv = SvRV(sv);
+    SV const * rv = SvRV(sv);
 
     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.  */
     if (SvREFCNT(rv) != 1 || (flags & SV_IMMEDIATE_UNREF))
        SvREFCNT_dec(rv);
     else /* XXX Hack, but hard to make $a=$a->[1] work otherwise */
-       sv_2mortal(rv);         /* Schedule for freeing later */
+       sv_2mortal((SV *)rv);           /* Schedule for freeing later */
 }
 
 /*
@@ -8013,7 +8120,7 @@ void
 Perl_sv_untaint(pTHX_ SV *sv)
 {
     if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv)) {
-       MAGIC *mg = mg_find(sv, PERL_MAGIC_taint);
+       MAGIC * const mg = mg_find(sv, PERL_MAGIC_taint);
        if (mg)
            mg->mg_len &= ~1;
     }
@@ -8030,7 +8137,7 @@ bool
 Perl_sv_tainted(pTHX_ SV *sv)
 {
     if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv)) {
-       MAGIC *mg = mg_find(sv, PERL_MAGIC_taint);
+       MAGIC * const mg = mg_find(sv, PERL_MAGIC_taint);
        if (mg && ((mg->mg_len & 1) || ((mg->mg_len & 2) && mg->mg_obj == sv)))
            return TRUE;
     }
@@ -8051,7 +8158,7 @@ Perl_sv_setpviv(pTHX_ SV *sv, IV iv)
 {
     char buf[TYPE_CHARS(UV)];
     char *ebuf;
-    char *ptr = uiv_2buf(buf, iv, 0, 0, &ebuf);
+    char * const ptr = uiv_2buf(buf, iv, 0, 0, &ebuf);
 
     sv_setpvn(sv, ptr, ebuf - ptr);
 }
@@ -8069,7 +8176,7 @@ Perl_sv_setpviv_mg(pTHX_ SV *sv, IV iv)
 {
     char buf[TYPE_CHARS(UV)];
     char *ebuf;
-    char *ptr = uiv_2buf(buf, iv, 0, 0, &ebuf);
+    char * const ptr = uiv_2buf(buf, iv, 0, 0, &ebuf);
 
     sv_setpvn(sv, ptr, ebuf - ptr);
     SvSETMAGIC(sv);
@@ -8111,8 +8218,8 @@ Perl_sv_setpvf_mg_nocontext(SV *sv, const char* pat, ...)
 /*
 =for apidoc sv_setpvf
 
-Processes its arguments like C<sprintf> and sets an SV to the formatted
-output.  Does not handle 'set' magic.  See C<sv_setpvf_mg>.
+Works like C<sv_catpvf> but copies the text into the SV instead of
+appending it.  Does not handle 'set' magic.  See C<sv_setpvf_mg>.
 
 =cut
 */
@@ -8126,7 +8233,16 @@ Perl_sv_setpvf(pTHX_ SV *sv, const char* pat, ...)
     va_end(args);
 }
 
-/* backend for C<sv_setpvf> and C<sv_setpvf_nocontext> */
+/*
+=for apidoc sv_vsetpvf
+
+Works like C<sv_vcatpvf> but copies the text into the SV instead of
+appending it.  Does not handle 'set' magic.  See C<sv_vsetpvf_mg>.
+
+Usually used via its frontend C<sv_setpvf>.
+
+=cut
+*/
 
 void
 Perl_sv_vsetpvf(pTHX_ SV *sv, const char* pat, va_list* args)
@@ -8151,7 +8267,15 @@ Perl_sv_setpvf_mg(pTHX_ SV *sv, const char* pat, ...)
     va_end(args);
 }
 
-/* backend for C<sv_setpvf_mg> C<setpvf_mg_nocontext> */
+/*
+=for apidoc sv_vsetpvf_mg
+
+Like C<sv_vsetpvf>, but also handles 'set' magic.
+
+Usually used via its frontend C<sv_setpvf_mg>.
+
+=cut
+*/
 
 void
 Perl_sv_vsetpvf_mg(pTHX_ SV *sv, const char* pat, va_list* args)
@@ -8200,9 +8324,9 @@ Processes its arguments like C<sprintf> and appends the formatted
 output to an SV.  If the appended data contains "wide" characters
 (including, but not limited to, SVs with a UTF-8 PV formatted with %s,
 and characters >255 formatted with %c), the original SV might get
-upgraded to UTF-8.  Handles 'get' magic, but not 'set' magic.
-C<SvSETMAGIC()> must typically be called after calling this function
-to handle 'set' magic.
+upgraded to UTF-8.  Handles 'get' magic, but not 'set' magic.  See
+C<sv_catpvf_mg>. If the original SV was UTF-8, the pattern should be
+valid UTF-8; if the original SV was bytes, the pattern should be too.
 
 =cut */
 
@@ -8215,7 +8339,16 @@ Perl_sv_catpvf(pTHX_ SV *sv, const char* pat, ...)
     va_end(args);
 }
 
-/* backend for C<sv_catpvf> and C<catpvf_mg_nocontext> */
+/*
+=for apidoc sv_vcatpvf
+
+Processes its arguments like C<vsprintf> and appends the formatted output
+to an SV.  Does not handle 'set' magic.  See C<sv_vcatpvf_mg>.
+
+Usually used via its frontend C<sv_catpvf>.
+
+=cut
+*/
 
 void
 Perl_sv_vcatpvf(pTHX_ SV *sv, const char* pat, va_list* args)
@@ -8240,7 +8373,15 @@ Perl_sv_catpvf_mg(pTHX_ SV *sv, const char* pat, ...)
     va_end(args);
 }
 
-/* backend for C<catpvf_mg> and C<catpvf_mg_nocontext> */
+/*
+=for apidoc sv_vcatpvf_mg
+
+Like C<sv_vcatpvf>, but also handles 'set' magic.
+
+Usually used via its frontend C<sv_catpvf_mg>.
+
+=cut
+*/
 
 void
 Perl_sv_vcatpvf_mg(pTHX_ SV *sv, const char* pat, va_list* args)
@@ -8252,10 +8393,10 @@ Perl_sv_vcatpvf_mg(pTHX_ SV *sv, const char* pat, va_list* args)
 /*
 =for apidoc sv_vsetpvfn
 
-Works like C<vcatpvfn> but copies the text into the SV instead of
+Works like C<sv_vcatpvfn> but copies the text into the SV instead of
 appending it.
 
-Usually used via one of its frontends C<sv_setpvf> and C<sv_setpvf_mg>.
+Usually used via one of its frontends C<sv_vsetpvf> and C<sv_vsetpvf_mg>.
 
 =cut
 */
@@ -8287,19 +8428,19 @@ S_expect_number(pTHX_ char** pattern)
 static char *
 F0convert(NV nv, char *endbuf, STRLEN *len)
 {
-    int neg = nv < 0;
+    const int neg = nv < 0;
     UV uv;
-    char *p = endbuf;
 
     if (neg)
        nv = -nv;
     if (nv < UV_MAX) {
+       char *p = endbuf;
        nv += 0.5;
        uv = (UV)nv;
        if (uv & 1 && uv == nv)
            uv--;                       /* Round to even */
        do {
-           unsigned dig = uv % 10;
+           const unsigned dig = uv % 10;
            *--p = '0' + dig;
        } while (uv /= 10);
        if (neg)
@@ -8320,23 +8461,27 @@ missing (NULL).  When running with taint checks enabled, indicates via
 C<maybe_tainted> if results are untrustworthy (often due to the use of
 locales).
 
-Usually used via one of its frontends C<sv_catpvf> and C<sv_catpvf_mg>.
+XXX Except that it maybe_tainted is never assigned to.
+
+Usually used via one of its frontends C<sv_vcatpvf> and C<sv_vcatpvf_mg>.
 
 =cut
 */
 
+/* XXX maybe_tainted is never assigned to, so the doc above is lying. */
+
 void
 Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV **svargs, I32 svmax, bool *maybe_tainted)
 {
     char *p;
     char *q;
-    char *patend;
+    const 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? */
+    bool has_utf8 = DO_UTF8(sv);    /* has the result utf8? */
+    const bool pat_utf8 = has_utf8; /* the pattern is in utf8? */
     SV *nsv = Nullsv;
     /* Times 4: a decimal digit takes more than 3 binary digits.
      * NV_DIG: mantissa takes than many decimal digits.
@@ -8345,7 +8490,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
     /* large enough for "%#.#f" --chip */
     /* what about long double NVs? --jhi */
 
-    has_utf8 = pat_utf8 = DO_UTF8(sv);
+    PERL_UNUSED_ARG(maybe_tainted);
 
     /* no matter what, this is a string now */
     (void)SvPV_force(sv, origlen);
@@ -8356,16 +8501,16 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
     if (patlen == 2 && pat[0] == '%') {
        switch (pat[1]) {
        case 's':
-           if (args) {
-               char *s = va_arg(*args, char*);
-               sv_catpv(sv, s ? s : nullstr);
-           }
-           else if (svix < svmax) {
-               sv_catsv(sv, *svargs);
-               if (DO_UTF8(*svargs))
-                   SvUTF8_on(sv);
-           }
-           return;
+       if (args) {
+           const char * const s = va_arg(*args, char*);
+           sv_catpv(sv, s ? s : nullstr);
+       }
+       else if (svix < svmax) {
+           sv_catsv(sv, *svargs);
+           if (DO_UTF8(*svargs))
+               SvUTF8_on(sv);
+       }
+       return;
        case '_':
            if (args) {
                argsv = va_arg(*args, SV*);
@@ -8381,7 +8526,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
 
 #ifndef USE_LONG_DOUBLE
     /* special-case "%.<number>[gf]" */
-    if ( patlen <= 5 && pat[0] == '%' && pat[1] == '.'
+    if ( !args && patlen <= 5 && pat[0] == '%' && pat[1] == '.'
         && (pat[patlen-1] == 'g' || pat[patlen-1] == 'f') ) {
        unsigned digits = 0;
        const char *pp;
@@ -8392,9 +8537,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
        if (pp - pat == (int)patlen - 1) {
            NV nv;
 
-           if (args)
-               nv = (NV)va_arg(*args, double);
-           else if (svix < svmax)
+           if (svix < svmax)
                nv = SvNV(*svargs);
            else
                return;
@@ -8447,13 +8590,13 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
 #endif
 
        char esignbuf[4];
-       U8 utf8buf[UTF8_MAXLEN+1];
+       U8 utf8buf[UTF8_MAXBYTES+1];
        STRLEN esignlen = 0;
 
-       char *eptr = Nullch;
+       const char *eptr = Nullch;
        STRLEN elen = 0;
        SV *vecsv = Nullsv;
-       U8 *vecstr = Null(U8*);
+       const U8 *vecstr = Null(U8*);
        STRLEN veclen = 0;
        char c = 0;
        int i;
@@ -8471,7 +8614,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
        STRLEN have;
        STRLEN need;
        STRLEN gap;
-       char *dotstr = ".";
+       const char *dotstr = ".";
        STRLEN dotstrlen = 1;
        I32 efix = 0; /* explicit format parameter index */
        I32 ewix = 0; /* explicit width index */
@@ -8562,32 +8705,43 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
        }
 
        if (!asterisk)
+       {
            if( *q == '0' ) 
                fill = *q++;
            EXPECT_NUMBER(q, width);
+       }
 
+#ifdef CHECK_FORMAT
+       if ((*q == 'p') && left) {
+            vectorize = (width == 1);
+       }
+#endif
        if (vectorize) {
            if (vectorarg) {
                if (args)
                    vecsv = va_arg(*args, SV*);
-               else
-                   vecsv = (evix ? evix <= svmax : svix < svmax) ?
-                       svargs[evix ? evix-1 : svix++] : &PL_sv_undef;
-               dotstr = SvPVx(vecsv, dotstrlen);
+               else if (evix) {
+                   vecsv = (evix > 0 && evix <= svmax)
+                       ? svargs[evix-1] : &PL_sv_undef;
+               } else {
+                   vecsv = svix < svmax ? svargs[svix++] : &PL_sv_undef;
+               }
+               dotstr = SvPV_const(vecsv, dotstrlen);
                if (DO_UTF8(vecsv))
                    is_utf8 = TRUE;
            }
            if (args) {
                vecsv = va_arg(*args, SV*);
-               vecstr = (U8*)SvPVx(vecsv,veclen);
+               vecstr = (U8*)SvPV_const(vecsv,veclen);
                vec_utf8 = DO_UTF8(vecsv);
            }
-           else if (efix ? efix <= svmax : svix < svmax) {
+           else if (efix ? (efix > 0 && efix <= svmax) : svix < svmax) {
                vecsv = svargs[efix ? efix-1 : svix++];
-               vecstr = (U8*)SvPVx(vecsv,veclen);
+               vecstr = (U8*)SvPV_const(vecsv,veclen);
                vec_utf8 = DO_UTF8(vecsv);
            }
            else {
+               vecsv = &PL_sv_undef;
                vecstr = (U8*)"";
                veclen = 0;
            }
@@ -8688,9 +8842,15 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
 
        if (vectorize)
            argsv = vecsv;
-       else if (!args)
-           argsv = (efix ? efix <= svmax : svix < svmax) ?
-                   svargs[efix ? efix-1 : svix++] : &PL_sv_undef;
+       else if (!args) {
+           if (efix) {
+               const I32 i = efix-1;
+               argsv = (i >= 0 && i < svmax) ? svargs[i] : &PL_sv_undef;
+           } else {
+               argsv = (svix >= 0 && svix < svmax)
+                   ? svargs[svix++] : &PL_sv_undef;
+           }
+       }
 
        switch (c = *q++) {
 
@@ -8724,12 +8884,12 @@ 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;
                }
            }
            else {
-               eptr = SvPVx(argsv, elen);
+               eptr = SvPVx_const(argsv, elen);
                if (DO_UTF8(argsv)) {
                    if (has_precis && precis < elen) {
                        I32 p = precis;
@@ -8745,6 +8905,9 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            goto string;
 
        case '_':
+#ifdef CHECK_FORMAT
+       format_sv:
+#endif
            /*
             * The "%_" hack might have to be changed someday,
             * if ISO or ANSI decide to use '_' for something.
@@ -8766,6 +8929,21 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            /* INTEGERS */
 
        case 'p':
+#ifdef CHECK_FORMAT
+           if (left) {
+               left = FALSE;
+               if (!width)
+                   goto format_sv;     /* %-p  -> %_   */
+               if (vectorize) {
+                   width = 0;
+                   goto format_vd;     /* %-1p -> %vd  */      
+               }
+               precis = width;
+               has_precis = TRUE;
+               width = 0;
+               goto format_sv;         /* %-Np -> %.N_ */      
+           }
+#endif
            if (alt || vectorize)
                goto unknown;
            uv = PTR2UV(args ? va_arg(*args, void*) : argsv);
@@ -8781,12 +8959,15 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            /* FALL THROUGH */
        case 'd':
        case 'i':
+#ifdef CHECK_FORMAT
+       format_vd:
+#endif
            if (vectorize) {
                STRLEN ulen;
                if (!veclen)
                    continue;
                if (vec_utf8)
-                   uv = utf8n_to_uvchr(vecstr, veclen, &ulen,
+                   uv = utf8n_to_uvchr((U8 *)vecstr, veclen, &ulen,
                                        UTF8_ALLOW_ANYUV);
                else {
                    uv = *vecstr;
@@ -8872,7 +9053,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                if (!veclen)
                    continue;
                if (vec_utf8)
-                   uv = utf8n_to_uvchr(vecstr, veclen, &ulen,
+                   uv = utf8n_to_uvchr((U8 *)vecstr, veclen, &ulen,
                                        UTF8_ALLOW_ANYUV);
                else {
                    uv = *vecstr;
@@ -8906,67 +9087,72 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            }
 
        integer:
-           eptr = ebuf + sizeof ebuf;
-           switch (base) {
-               unsigned dig;
-           case 16:
-               if (!uv)
-                   alt = FALSE;
-               p = (char*)((c == 'X')
-                           ? "0123456789ABCDEF" : "0123456789abcdef");
-               do {
-                   dig = uv & 15;
-                   *--eptr = p[dig];
-               } while (uv >>= 4);
-               if (alt) {
-                   esignbuf[esignlen++] = '0';
-                   esignbuf[esignlen++] = c;  /* 'x' or 'X' */
-               }
-               break;
-           case 8:
-               do {
-                   dig = uv & 7;
-                   *--eptr = '0' + dig;
-               } while (uv >>= 3);
-               if (alt && *eptr != '0')
-                   *--eptr = '0';
-               break;
-           case 2:
-               do {
-                   dig = uv & 1;
-                   *--eptr = '0' + dig;
-               } while (uv >>= 1);
-               if (alt) {
-                   esignbuf[esignlen++] = '0';
-                   esignbuf[esignlen++] = 'b';
-               }
-               break;
-           default:            /* it had better be ten or less */
+           {
+               char *ptr = ebuf + sizeof ebuf;
+               switch (base) {
+                   unsigned dig;
+               case 16:
+                   if (!uv)
+                       alt = FALSE;
+                   p = (char*)((c == 'X')
+                               ? "0123456789ABCDEF" : "0123456789abcdef");
+                   do {
+                       dig = uv & 15;
+                       *--ptr = p[dig];
+                   } while (uv >>= 4);
+                   if (alt) {
+                       esignbuf[esignlen++] = '0';
+                       esignbuf[esignlen++] = c;  /* 'x' or 'X' */
+                   }
+                   break;
+               case 8:
+                   do {
+                       dig = uv & 7;
+                       *--ptr = '0' + dig;
+                   } while (uv >>= 3);
+                   if (alt && *ptr != '0')
+                       *--ptr = '0';
+                   break;
+               case 2:
+                   if (!uv)
+                       alt = FALSE;
+                   do {
+                       dig = uv & 1;
+                       *--ptr = '0' + dig;
+                   } while (uv >>= 1);
+                   if (alt) {
+                       esignbuf[esignlen++] = '0';
+                       esignbuf[esignlen++] = 'b';
+                   }
+                   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'");
+                   if (ckWARN(WARN_Y2K)) {
+                       STRLEN n;
+                       const char *const s = SvPV_const(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;
-               } while (uv /= base);
-               break;
-           }
-           elen = (ebuf + sizeof ebuf) - eptr;
-           if (has_precis) {
-               if (precis > elen)
-                   zeros = precis - elen;
-               else if (precis == 0 && elen == 1 && *eptr == '0')
-                   elen = 0;
+                   do {
+                       dig = uv % base;
+                       *--ptr = '0' + dig;
+                   } while (uv /= base);
+                   break;
+               }
+               elen = (ebuf + sizeof ebuf) - ptr;
+               eptr = ptr;
+               if (has_precis) {
+                   if (precis > elen)
+                       zeros = precis - elen;
+                   else if (precis == 0 && elen == 1 && *ptr == '0')
+                       elen = 0;
+               }
            }
            break;
 
@@ -9107,7 +9293,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            if (PL_efloatsize < need) {
                Safefree(PL_efloatbuf);
                PL_efloatsize = need + 20; /* more fudge */
-               New(906, PL_efloatbuf, PL_efloatsize, char);
+               Newx(PL_efloatbuf, PL_efloatsize, char);
                PL_efloatbuf[0] = '\0';
            }
 
@@ -9124,50 +9310,52 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                        break;
                }
            }
-           eptr = ebuf + sizeof ebuf;
-           *--eptr = '\0';
-           *--eptr = c;
-           /* FIXME: what to do if HAS_LONG_DOUBLE but not PERL_PRIfldbl? */
+           {
+               char *ptr = ebuf + sizeof ebuf;
+               *--ptr = '\0';
+               *--ptr = c;
+               /* FIXME: what to do if HAS_LONG_DOUBLE but not PERL_PRIfldbl? */
 #if defined(HAS_LONG_DOUBLE) && defined(PERL_PRIfldbl)
-           if (intsize == 'q') {
-               /* Copy the one or more characters in a long double
-                * format before the 'base' ([efgEFG]) character to
-                * the format string. */
-               static char const prifldbl[] = PERL_PRIfldbl;
-               char const *p = prifldbl + sizeof(prifldbl) - 3;
-               while (p >= prifldbl) { *--eptr = *p--; }
-           }
+               if (intsize == 'q') {
+                   /* Copy the one or more characters in a long double
+                    * format before the 'base' ([efgEFG]) character to
+                    * the format string. */
+                   static char const prifldbl[] = PERL_PRIfldbl;
+                   char const *p = prifldbl + sizeof(prifldbl) - 3;
+                   while (p >= prifldbl) { *--ptr = *p--; }
+               }
 #endif
-           if (has_precis) {
-               base = precis;
-               do { *--eptr = '0' + (base % 10); } while (base /= 10);
-               *--eptr = '.';
-           }
-           if (width) {
-               base = width;
-               do { *--eptr = '0' + (base % 10); } while (base /= 10);
-           }
-           if (fill == '0')
-               *--eptr = fill;
-           if (left)
-               *--eptr = '-';
-           if (plus)
-               *--eptr = plus;
-           if (alt)
-               *--eptr = '#';
-           *--eptr = '%';
-
-           /* No taint.  Otherwise we are in the strange situation
-            * where printf() taints but print($float) doesn't.
-            * --jhi */
+               if (has_precis) {
+                   base = precis;
+                   do { *--ptr = '0' + (base % 10); } while (base /= 10);
+                   *--ptr = '.';
+               }
+               if (width) {
+                   base = width;
+                   do { *--ptr = '0' + (base % 10); } while (base /= 10);
+               }
+               if (fill == '0')
+                   *--ptr = fill;
+               if (left)
+                   *--ptr = '-';
+               if (plus)
+                   *--ptr = plus;
+               if (alt)
+                   *--ptr = '#';
+               *--ptr = '%';
+
+               /* No taint.  Otherwise we are in the strange situation
+                * where printf() taints but print($float) doesn't.
+                * --jhi */
 #if defined(HAS_LONG_DOUBLE)
-           if (intsize == 'q')
-               (void)sprintf(PL_efloatbuf, eptr, nv);
-           else
-               (void)sprintf(PL_efloatbuf, eptr, (double)nv);
+               if (intsize == 'q')
+                   (void)sprintf(PL_efloatbuf, ptr, nv);
+               else
+                   (void)sprintf(PL_efloatbuf, ptr, (double)nv);
 #else
-           (void)sprintf(PL_efloatbuf, eptr, nv);
+               (void)sprintf(PL_efloatbuf, ptr, nv);
 #endif
+           }
        float_converted:
            eptr = PL_efloatbuf;
            elen = strlen(PL_efloatbuf);
@@ -9197,8 +9385,10 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
 
        default:
       unknown:
-           if (!args && ckWARN(WARN_PRINTF) &&
-                 (PL_op->op_type == OP_PRTF || PL_op->op_type == OP_SPRINTF)) {
+           if (!args
+               && (PL_op->op_type == OP_PRTF || PL_op->op_type == OP_SPRINTF)
+               && ckWARN(WARN_PRINTF))
+           {
                SV *msg = sv_newmortal();
                Perl_sv_setpvf(aTHX_ msg, "Invalid conversion in %sprintf: ",
                          (PL_op->op_type == OP_PRTF) ? "" : "s");
@@ -9227,13 +9417,15 @@ 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_const(sv));
            svix = osvix;
            continue;   /* not "break" */
        }
 
        /* calculate width before utf8_upgrade changes it */
        have = esignlen + zeros + elen;
+       if (have < zeros)
+           Perl_croak_nocontext(PL_memory_wrap);
 
        if (is_utf8 != has_utf8) {
             if (is_utf8) {
@@ -9241,9 +9433,9 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                       sv_utf8_upgrade(sv);
             }
             else {
-                 SV *nsv = sv_2mortal(newSVpvn(eptr, elen));
+                 SV * const nsv = sv_2mortal(newSVpvn(eptr, elen));
                  sv_utf8_upgrade(nsv);
-                 eptr = SvPVX(nsv);
+                 eptr = SvPVX_const(nsv);
                  elen = SvCUR(nsv);
             }
             SvGROW(sv, SvCUR(sv) + elen + 1);
@@ -9261,9 +9453,12 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
        need = (have > width ? have : width);
        gap = need - have;
 
+       if (need >= (((STRLEN)~0) - SvCUR(sv) - dotstrlen - 1))
+           Perl_croak_nocontext(PL_memory_wrap);
        SvGROW(sv, SvCUR(sv) + need + dotstrlen + 1);
        p = SvEND(sv);
        if (esignlen && fill == '0') {
+           int i;
            for (i = 0; i < (int)esignlen; i++)
                *p++ = esignbuf[i];
        }
@@ -9272,10 +9467,12 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            p += gap;
        }
        if (esignlen && fill != '0') {
+           int i;
            for (i = 0; i < (int)esignlen; i++)
                *p++ = esignbuf[i];
        }
        if (zeros) {
+           int i;
            for (i = zeros; i; i--)
                *p++ = '0';
        }
@@ -9300,7 +9497,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_const(sv));
        if (vectorize) {
            esignlen = 0;
            goto vector;
@@ -9370,15 +9567,15 @@ Perl_re_dup(pTHX_ REGEXP *r, CLONE_PARAMS *param)
     len = r->offsets[0];
     npar = r->nparens+1;
 
-    Newc(0, ret, sizeof(regexp) + (len+1)*sizeof(regnode), char, regexp);
+    Newxc(ret, sizeof(regexp) + (len+1)*sizeof(regnode), char, regexp);
     Copy(r->program, ret->program, len+1, regnode);
 
-    New(0, ret->startp, npar, I32);
+    Newx(ret->startp, npar, I32);
     Copy(r->startp, ret->startp, npar, I32);
-    New(0, ret->endp, npar, I32);
+    Newx(ret->endp, npar, I32);
     Copy(r->startp, ret->startp, npar, I32);
 
-    New(0, ret->substrs, 1, struct reg_substr_data);
+    Newx(ret->substrs, 1, struct reg_substr_data);
     for (s = ret->substrs->data, i = 0; i < 3; i++, s++) {
        s->min_offset = r->substrs->data[i].min_offset;
        s->max_offset = r->substrs->data[i].max_offset;
@@ -9389,11 +9586,12 @@ Perl_re_dup(pTHX_ REGEXP *r, CLONE_PARAMS *param)
     ret->regstclass = NULL;
     if (r->data) {
        struct reg_data *d;
-       int count = r->data->count;
+        const int count = r->data->count;
+       int i;
 
-       Newc(0, d, sizeof(struct reg_data) + count*sizeof(void *),
+       Newxc(d, sizeof(struct reg_data) + count*sizeof(void *),
                char, struct reg_data);
-       New(0, d->what, count, U8);
+       Newx(d->what, count, U8);
 
        d->count = count;
        for (i = 0; i < count; i++) {
@@ -9407,7 +9605,7 @@ Perl_re_dup(pTHX_ REGEXP *r, CLONE_PARAMS *param)
                break;
            case 'f':
                /* This is cheating. */
-               New(0, d->data[i], 1, struct regnode_charclass_class);
+               Newx(d->data[i], 1, struct regnode_charclass_class);
                StructCopy(r->data->data[i], d->data[i],
                            struct regnode_charclass_class);
                ret->regstclass = (regnode*)d->data[i];
@@ -9415,7 +9613,9 @@ Perl_re_dup(pTHX_ REGEXP *r, CLONE_PARAMS *param)
            case 'o':
                /* Compiled op trees are readonly, and can thus be
                   shared without duplication. */
+               OP_REFCNT_LOCK;
                d->data[i] = (void*)OpREFCNT_inc((OP*)r->data->data[i]);
+               OP_REFCNT_UNLOCK;
                break;
            case 'n':
                d->data[i] = r->data->data[i];
@@ -9428,7 +9628,7 @@ Perl_re_dup(pTHX_ REGEXP *r, CLONE_PARAMS *param)
     else
        ret->data = NULL;
 
-    New(0, ret->offsets, 2*len+1, U32);
+    Newx(ret->offsets, 2*len+1, U32);
     Copy(r->offsets, ret->offsets, 2*len+1, U32);
 
     ret->precomp        = SAVEPVN(r->precomp, r->prelen);
@@ -9457,6 +9657,9 @@ PerlIO *
 Perl_fp_dup(pTHX_ PerlIO *fp, char type, CLONE_PARAMS *param)
 {
     PerlIO *ret;
+
+    PERL_UNUSED_ARG(type);
+
     if (!fp)
        return (PerlIO*)NULL;
 
@@ -9496,7 +9699,7 @@ Perl_gp_dup(pTHX_ GP *gp, CLONE_PARAMS* param)
        return ret;
 
     /* create anew and remember what it is */
-    Newz(0, ret, 1, GP);
+    Newxz(ret, 1, GP);
     ptr_table_store(PL_ptr_table, gp, ret);
 
     /* clone */
@@ -9531,7 +9734,7 @@ Perl_mg_dup(pTHX_ MAGIC *mg, CLONE_PARAMS* param)
 
     for (; mg; mg = mg->mg_moremagic) {
        MAGIC *nmg;
-       Newz(0, nmg, 1, MAGIC);
+       Newxz(nmg, 1, MAGIC);
        if (mgprev)
            mgprev->mg_moremagic = nmg;
        else
@@ -9544,10 +9747,10 @@ Perl_mg_dup(pTHX_ MAGIC *mg, CLONE_PARAMS* param)
            nmg->mg_obj = (SV*)re_dup((REGEXP*)mg->mg_obj, param);
        }
        else if(mg->mg_type == PERL_MAGIC_backref) {
-           AV *av = (AV*) mg->mg_obj;
+           const AV * const av = (AV*) mg->mg_obj;
            SV **svp;
            I32 i;
-           SvREFCNT_inc(nmg->mg_obj = (SV*)newAV());
+           (void)SvREFCNT_inc(nmg->mg_obj = (SV*)newAV());
            svp = AvARRAY(av);
            for (i = AvFILLp(av); i >= 0; i--) {
                if (!svp[i]) continue;
@@ -9592,10 +9795,10 @@ PTR_TBL_t *
 Perl_ptr_table_new(pTHX)
 {
     PTR_TBL_t *tbl;
-    Newz(0, tbl, 1, PTR_TBL_t);
+    Newxz(tbl, 1, PTR_TBL_t);
     tbl->tbl_max       = 511;
     tbl->tbl_items     = 0;
-    Newz(0, tbl->tbl_ary, tbl->tbl_max + 1, PTR_TBL_ENT_t*);
+    Newxz(tbl->tbl_ary, tbl->tbl_max + 1, PTR_TBL_ENT_t*);
     return tbl;
 }
 
@@ -9605,13 +9808,53 @@ Perl_ptr_table_new(pTHX)
 #  define PTR_TABLE_HASH(ptr) (PTR2UV(ptr) >> 2)
 #endif
 
+
+
+STATIC void
+S_more_pte(pTHX)
+{
+    struct ptr_tbl_ent* pte;
+    struct ptr_tbl_ent* pteend;
+    XPV *ptr;
+    New(54, ptr, PERL_ARENA_SIZE/sizeof(XPV), XPV);
+    ptr->xpv_pv = (char*)PL_pte_arenaroot;
+    PL_pte_arenaroot = ptr;
+
+    pte = (struct ptr_tbl_ent*)ptr;
+    pteend = &pte[PERL_ARENA_SIZE / sizeof(struct ptr_tbl_ent) - 1];
+    PL_pte_root = ++pte;
+    while (pte < pteend) {
+       pte->next = pte + 1;
+       pte++;
+    }
+    pte->next = 0;
+}
+
+STATIC struct ptr_tbl_ent*
+S_new_pte(pTHX)
+{
+    struct ptr_tbl_ent* pte;
+    if (!PL_pte_root)
+       S_more_pte(aTHX);
+    pte = PL_pte_root;
+    PL_pte_root = pte->next;
+    return pte;
+}
+
+STATIC void
+S_del_pte(pTHX_ struct ptr_tbl_ent*p)
+{
+    p->next = PL_pte_root;
+    PL_pte_root = p;
+}
+
 /* map an existing pointer using a table */
 
 void *
 Perl_ptr_table_fetch(pTHX_ PTR_TBL_t *tbl, void *sv)
 {
     PTR_TBL_ENT_t *tblent;
-    UV hash = PTR_TABLE_HASH(sv);
+    const UV hash = PTR_TABLE_HASH(sv);
     assert(tbl);
     tblent = tbl->tbl_ary[hash & tbl->tbl_max];
     for (; tblent; tblent = tblent->next) {
@@ -9624,26 +9867,26 @@ Perl_ptr_table_fetch(pTHX_ PTR_TBL_t *tbl, void *sv)
 /* add a new entry to a pointer-mapping table */
 
 void
-Perl_ptr_table_store(pTHX_ PTR_TBL_t *tbl, void *oldv, void *newv)
+Perl_ptr_table_store(pTHX_ PTR_TBL_t *tbl, void *oldsv, void *newsv)
 {
     PTR_TBL_ENT_t *tblent, **otblent;
     /* XXX this may be pessimal on platforms where pointers aren't good
      * hash values e.g. if they grow faster in the most significant
      * bits */
-    UV hash = PTR_TABLE_HASH(oldv);
+    const UV hash = PTR_TABLE_HASH(oldsv);
     bool empty = 1;
 
     assert(tbl);
     otblent = &tbl->tbl_ary[hash & tbl->tbl_max];
     for (tblent = *otblent; tblent; empty=0, tblent = tblent->next) {
-       if (tblent->oldval == oldv) {
-           tblent->newval = newv;
+       if (tblent->oldval == oldsv) {
+           tblent->newval = newsv;
            return;
        }
     }
-    Newz(0, tblent, 1, PTR_TBL_ENT_t);
-    tblent->oldval = oldv;
-    tblent->newval = newv;
+    tblent = S_new_pte(aTHX);
+    tblent->oldval = oldsv;
+    tblent->newval = newsv;
     tblent->next = *otblent;
     *otblent = tblent;
     tbl->tbl_items++;
@@ -9657,7 +9900,7 @@ void
 Perl_ptr_table_split(pTHX_ PTR_TBL_t *tbl)
 {
     PTR_TBL_ENT_t **ary = tbl->tbl_ary;
-    UV oldsize = tbl->tbl_max + 1;
+    const UV oldsize = tbl->tbl_max + 1;
     UV newsize = oldsize * 2;
     UV i;
 
@@ -9690,7 +9933,6 @@ Perl_ptr_table_clear(pTHX_ PTR_TBL_t *tbl)
 {
     register PTR_TBL_ENT_t **array;
     register PTR_TBL_ENT_t *entry;
-    register PTR_TBL_ENT_t *oentry = Null(PTR_TBL_ENT_t*);
     UV riter = 0;
     UV max;
 
@@ -9704,9 +9946,9 @@ Perl_ptr_table_clear(pTHX_ PTR_TBL_t *tbl)
 
     for (;;) {
         if (entry) {
-            oentry = entry;
+            PTR_TBL_ENT_t *oentry = entry;
             entry = entry->next;
-            Safefree(oentry);
+            S_del_pte(aTHX_ oentry);
         }
         if (!entry) {
             if (++riter > max) {
@@ -9736,62 +9978,6 @@ Perl_ptr_table_free(pTHX_ PTR_TBL_t *tbl)
 char *PL_watch_pvx;
 #endif
 
-/* attempt to make everything in the typeglob readonly */
-
-STATIC SV *
-S_gv_share(pTHX_ SV *sstr, CLONE_PARAMS *param)
-{
-    GV *gv = (GV*)sstr;
-    SV *sv = &param->proto_perl->Isv_no; /* just need SvREADONLY-ness */
-
-    if (GvIO(gv) || GvFORM(gv)) {
-        GvUNIQUE_off(gv); /* GvIOs cannot be shared. nor can GvFORMs */
-    }
-    else if (!GvCV(gv)) {
-        GvCV(gv) = (CV*)sv;
-    }
-    else {
-        /* CvPADLISTs cannot be shared */
-        if (!SvREADONLY(GvCV(gv)) && !CvXSUB(GvCV(gv))) {
-            GvUNIQUE_off(gv);
-        }
-    }
-
-    if (!GvUNIQUE(gv)) {
-#if 0
-        PerlIO_printf(Perl_debug_log, "gv_share: unable to share %s::%s\n",
-                      HvNAME(GvSTASH(gv)), GvNAME(gv));
-#endif
-        return Nullsv;
-    }
-
-    /*
-     * write attempts will die with
-     * "Modification of a read-only value attempted"
-     */
-    if (!GvSV(gv)) {
-        GvSV(gv) = sv;
-    }
-    else {
-        SvREADONLY_on(GvSV(gv));
-    }
-
-    if (!GvAV(gv)) {
-        GvAV(gv) = (AV*)sv;
-    }
-    else {
-        SvREADONLY_on(GvAV(gv));
-    }
-
-    if (!GvHV(gv)) {
-        GvHV(gv) = (HV*)sv;
-    }
-    else {
-        SvREADONLY_on(GvHV(gv));
-    }
-
-    return sstr; /* he_dup() will SvREFCNT_inc() */
-}
 
 /* duplicate an SV of any type (including AV, HV etc) */
 
@@ -9799,15 +9985,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)) {
+    else if (SvPVX_const(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_const(sstr), SvLEN(sstr)-1));
        }
        else {
            /* Special case - not normally malloced for some reason */
@@ -9818,25 +10005,28 @@ 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_const(sstr), SvCUR(sstr),
+                                           SvUVX(sstr)));
+                    SvUV_set(dstr, SvUVX(sstr));
                 } else {
 
-                    SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvCUR(sstr));
+                    SvPV_set(dstr, SAVEPVN(SvPVX_const(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);
     }
 }
 
@@ -9855,11 +10045,12 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
     if(param->flags & CLONEf_JOIN_IN) {
         /** We are joining here so we don't want do clone
            something that is bad **/
+       const char *hvname;
 
         if(SvTYPE(sstr) == SVt_PVHV &&
-          HvNAME(sstr)) {
+          (hvname = HvNAME_get(sstr))) {
            /** don't clone stashes if they already exist **/
-           HV* old_stash = gv_stashpv(HvNAME(sstr),0);
+           HV* old_stash = gv_stashpv(hvname,0);
            return (SV*) old_stash;
         }
     }
@@ -9874,22 +10065,29 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
     SvREFCNT(dstr)     = 0;                    /* must be before any other dups! */
 
 #ifdef DEBUGGING
-    if (SvANY(sstr) && PL_watch_pvx && SvPVX(sstr) == PL_watch_pvx)
+    if (SvANY(sstr) && PL_watch_pvx && SvPVX_const(sstr) == PL_watch_pvx)
        PerlIO_printf(Perl_debug_log, "watch at %p hit, found string \"%s\"\n",
-                     PL_watch_pvx, SvPVX(sstr));
+                     PL_watch_pvx, SvPVX_const(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;
        break;
     case SVt_IV:
        SvANY(dstr)     = new_XIV();
-       SvIVX(dstr)     = SvIVX(sstr);
+       SvIV_set(dstr, SvIVX(sstr));
        break;
     case SVt_NV:
        SvANY(dstr)     = new_XNV();
-       SvNVX(dstr)     = SvNVX(sstr);
+       SvNV_set(dstr, SvNVX(sstr));
        break;
     case SVt_RV:
        SvANY(dstr)     = new_XRV();
@@ -9897,43 +10095,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);
-       SvIVX(dstr)     = SvIVX(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);
-       SvIVX(dstr)     = SvIVX(sstr);
-       SvNVX(dstr)     = SvNVX(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);
-       SvIVX(dstr)     = SvIVX(sstr);
-       SvNVX(dstr)     = SvNVX(sstr);
-       SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr), param);
-       SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr), param);
+       SvCUR_set(dstr, SvCUR(sstr));
+       SvLEN_set(dstr, SvLEN(sstr));
+       SvIV_set(dstr, SvIVX(sstr));
+       SvNV_set(dstr, SvNVX(sstr));
+       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);
-       SvIVX(dstr)     = SvIVX(sstr);
-       SvNVX(dstr)     = SvNVX(sstr);
-       SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr), param);
-       SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr), param);
+       SvCUR_set(dstr, SvCUR(sstr));
+       SvLEN_set(dstr, SvLEN(sstr));
+       SvIV_set(dstr, SvIVX(sstr));
+       SvNV_set(dstr, SvNVX(sstr));
+       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);
@@ -9941,12 +10139,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);
-       SvIVX(dstr)     = SvIVX(sstr);
-       SvNVX(dstr)     = SvNVX(sstr);
-       SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr), param);
-       SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr), param);
+       SvCUR_set(dstr, SvCUR(sstr));
+       SvLEN_set(dstr, SvLEN(sstr));
+       SvIV_set(dstr, SvIVX(sstr));
+       SvNV_set(dstr, SvNVX(sstr));
+       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);
@@ -9960,25 +10158,15 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
        break;
     case SVt_PVGV:
        if (GvUNIQUE((GV*)sstr)) {
-            SV *share;
-            if ((share = gv_share(sstr, param))) {
-                del_SV(dstr);
-                dstr = share;
-                ptr_table_store(PL_ptr_table, sstr, dstr);
-#if 0
-                PerlIO_printf(Perl_debug_log, "sv_dup: sharing %s::%s\n",
-                              HvNAME(GvSTASH(share)), GvNAME(share));
-#endif
-                break;
-            }
+           /* Do sharing here.  */
        }
        SvANY(dstr)     = new_XPVGV();
-       SvCUR(dstr)     = SvCUR(sstr);
-       SvLEN(dstr)     = SvLEN(sstr);
-       SvIVX(dstr)     = SvIVX(sstr);
-       SvNVX(dstr)     = SvNVX(sstr);
-       SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr), param);
-       SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr), param);
+       SvCUR_set(dstr, SvCUR(sstr));
+       SvLEN_set(dstr, SvLEN(sstr));
+       SvIV_set(dstr, SvIVX(sstr));
+       SvNV_set(dstr, SvNVX(sstr));
+       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));
@@ -9989,12 +10177,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);
-       SvIVX(dstr)     = SvIVX(sstr);
-       SvNVX(dstr)     = SvNVX(sstr);
-       SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr), param);
-       SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr), param);
+       SvCUR_set(dstr, SvCUR(sstr));
+       SvLEN_set(dstr, SvLEN(sstr));
+       SvIV_set(dstr, SvIVX(sstr));
+       SvNV_set(dstr, SvNVX(sstr));
+       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))
@@ -10031,12 +10219,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);
-       SvIVX(dstr)     = SvIVX(sstr);
-       SvNVX(dstr)     = SvNVX(sstr);
-       SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr), param);
-       SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr), param);
+       SvCUR_set(dstr, SvCUR(sstr));
+       SvLEN_set(dstr, SvLEN(sstr));
+       SvIV_set(dstr, SvIVX(sstr));
+       SvNV_set(dstr, SvNVX(sstr));
+       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)) {
@@ -10046,7 +10234,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)
@@ -10062,41 +10250,42 @@ 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);
-       SvIVX(dstr)     = SvIVX(sstr);
-       SvNVX(dstr)     = SvNVX(sstr);
-       SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr), param);
-       SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr), param);
-       HvRITER((HV*)dstr)      = HvRITER((HV*)sstr);
+       SvCUR_set(dstr, SvCUR(sstr));
+       SvLEN_set(dstr, SvLEN(sstr));
+       HvTOTALKEYS(dstr) = HvTOTALKEYS(sstr);
+       SvNV_set(dstr, SvNVX(sstr));
+       SvMAGIC_set(dstr, mg_dup(SvMAGIC(sstr), param));
+       SvSTASH_set(dstr, hv_dup_inc(SvSTASH(sstr), param));
+       HvRITER_set((HV*)dstr, HvRITER_get((HV*)sstr));
        if (HvARRAY((HV*)sstr)) {
+           bool sharekeys = !!HvSHAREKEYS(sstr);
            STRLEN i = 0;
            XPVHV *dxhv = (XPVHV*)SvANY(dstr);
            XPVHV *sxhv = (XPVHV*)SvANY(sstr);
-           Newz(0, dxhv->xhv_array,
+           Newx(dxhv->xhv_array,
                 PERL_HV_ARRAY_ALLOC_BYTES(dxhv->xhv_max+1), char);
            while (i <= sxhv->xhv_max) {
-               ((HE**)dxhv->xhv_array)[i] = he_dup(((HE**)sxhv->xhv_array)[i],
-                                                   (bool)!!HvSHAREKEYS(sstr),
-                                                   param);
+               HE *source = HvARRAY(sstr)[i];
+               HvARRAY(dstr)[i]
+                       = source ? he_dup(source, sharekeys, param) : 0;
                ++i;
            }
            dxhv->xhv_eiter = he_dup(sxhv->xhv_eiter,
                                     (bool)!!HvSHAREKEYS(sstr), param);
        }
        else {
-           SvPVX(dstr)         = Nullch;
-           HvEITER((HV*)dstr)  = (HE*)NULL;
+           SvPV_set(dstr, Nullch);
+           HvEITER_set((HV*)dstr, (HE*)NULL);
        }
        HvPMROOT((HV*)dstr)     = HvPMROOT((HV*)sstr);          /* XXX */
        HvNAME((HV*)dstr)       = SAVEPV(HvNAME((HV*)sstr));
-    /* Record stashes for possible cloning in Perl_clone(). */
+       /* Record stashes for possible cloning in Perl_clone(). */
        if(HvNAME((HV*)dstr))
            av_push(param->stashes, dstr);
        break;
@@ -10108,16 +10297,18 @@ 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);
-       SvIVX(dstr)     = SvIVX(sstr);
-       SvNVX(dstr)     = SvNVX(sstr);
-       SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr), param);
-       SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr), param);
+       SvCUR_set(dstr, SvCUR(sstr));
+       SvLEN_set(dstr, SvLEN(sstr));
+       SvIV_set(dstr, SvIVX(sstr));
+       SvNV_set(dstr, SvNVX(sstr));
+       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);
+       OP_REFCNT_LOCK;
        CvROOT(dstr)    = OpREFCNT_inc(CvROOT(sstr));
+       OP_REFCNT_UNLOCK;
        CvXSUB(dstr)    = CvXSUB(sstr);
        CvXSUBANY(dstr) = CvXSUBANY(sstr);
        if (CvCONST(sstr)) {
@@ -10170,7 +10361,7 @@ Perl_cx_dup(pTHX_ PERL_CONTEXT *cxs, I32 ix, I32 max, CLONE_PARAMS* param)
        return ncxs;
 
     /* create anew and remember what it is */
-    Newz(56, ncxs, max + 1, PERL_CONTEXT);
+    Newxz(ncxs, max + 1, PERL_CONTEXT);
     ptr_table_store(PL_ptr_table, cxs, ncxs);
 
     while (ix >= 0) {
@@ -10258,7 +10449,7 @@ Perl_si_dup(pTHX_ PERL_SI *si, CLONE_PARAMS* param)
        return nsi;
 
     /* create anew and remember what it is */
-    Newz(56, nsi, 1, PERL_SI);
+    Newxz(nsi, 1, PERL_SI);
     ptr_table_store(PL_ptr_table, si, nsi);
 
     nsi->si_stack      = av_dup_inc(si->si_stack, param);
@@ -10325,9 +10516,9 @@ Perl_any_dup(pTHX_ void *v, PerlInterpreter *proto_perl)
 ANY *
 Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
 {
-    ANY *ss    = proto_perl->Tsavestack;
-    I32 ix     = proto_perl->Tsavestack_ix;
-    I32 max    = proto_perl->Tsavestack_max;
+    ANY * const ss     = proto_perl->Tsavestack;
+    const I32 max      = proto_perl->Tsavestack_max;
+    I32 ix             = proto_perl->Tsavestack_ix;
     ANY *nss;
     SV *sv;
     GV *gv;
@@ -10338,16 +10529,14 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
     long longval;
     GP *gp;
     IV iv;
-    I32 i;
     char *c = NULL;
     void (*dptr) (void*);
     void (*dxptr) (pTHX_ void*);
-    OP *o;
 
-    Newz(54, nss, max, ANY);
+    Newxz(nss, max, ANY);
 
     while (ix > 0) {
-       i = POPINT(ss,ix);
+       I32 i = POPINT(ss,ix);
        TOPINT(nss,ix) = i;
        switch (i) {
        case SAVEt_ITEM:                        /* normal string */
@@ -10475,6 +10664,7 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
            ptr = POPPTR(ss,ix);
            if (ptr && (((OP*)ptr)->op_private & OPpREFCOUNTED)) {
                /* these are assumed to be refcounted properly */
+               OP *o;
                switch (((OP*)ptr)->op_type) {
                case OP_LEAVESUB:
                case OP_LEAVESUBLV:
@@ -10514,13 +10704,17 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
            ptr = POPPTR(ss,ix);
            TOPPTR(nss,ix) = any_dup(ptr, proto_perl);  /* XXX quite arbitrary */
            dptr = POPDPTR(ss,ix);
-           TOPDPTR(nss,ix) = (void (*)(void*))any_dup((void *)dptr, proto_perl);
+           TOPDPTR(nss,ix) = DPTR2FPTR(void (*)(void*),
+                                       any_dup(FPTR2DPTR(void *, dptr),
+                                               proto_perl));
            break;
        case SAVEt_DESTRUCTOR_X:
            ptr = POPPTR(ss,ix);
            TOPPTR(nss,ix) = any_dup(ptr, proto_perl);  /* XXX quite arbitrary */
            dxptr = POPDXPTR(ss,ix);
-           TOPDXPTR(nss,ix) = (void (*)(pTHX_ void*))any_dup((void *)dxptr, proto_perl);
+           TOPDXPTR(nss,ix) = DPTR2FPTR(void (*)(pTHX_ void*),
+                                        any_dup(FPTR2DPTR(void *, dxptr),
+                                                proto_perl));
            break;
        case SAVEt_REGCONTEXT:
        case SAVEt_ALLOC:
@@ -10582,6 +10776,41 @@ 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)
+{
+    const char *const hvname = HvNAME_get((HV*)sv);
+    if (hvname) {
+       GV* const 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, 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
 
@@ -10663,10 +10892,14 @@ 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
     Poison(my_perl, 1, PerlInterpreter);
+    PL_op = Nullop;
+    PL_curcop = (COP *)Nullop;
     PL_markstack = 0;
     PL_scopestack = 0;
     PL_savestack = 0;
@@ -10694,12 +10927,14 @@ 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;
+    PL_curcop = (COP *)Nullop;
     PL_markstack = 0;
     PL_scopestack = 0;
     PL_savestack = 0;
@@ -10742,6 +10977,10 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_xpvbm_root      = NULL;
     PL_he_arenaroot    = NULL;
     PL_he_root         = NULL;
+#if defined(USE_ITHREADS)
+    PL_pte_arenaroot   = NULL;
+    PL_pte_root                = NULL;
+#endif
     PL_nice_chunk      = NULL;
     PL_nice_chunk_size = 0;
     PL_sv_count                = 0;
@@ -10751,6 +10990,9 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 
     PL_debug           = proto_perl->Idebug;
 
+    PL_hash_seed       = proto_perl->Ihash_seed;
+    PL_rehash_seed     = proto_perl->Irehash_seed;
+
 #ifdef USE_REENTRANT_API
     /* XXX: things like -Dm will segfault here in perlio, but doing
      *  PERL_SET_CONTEXT(proto_perl);
@@ -10770,26 +11012,30 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 
     SvANY(&PL_sv_no)           = new_XPVNV();
     SvREFCNT(&PL_sv_no)                = (~(U32)0)/2;
-    SvFLAGS(&PL_sv_no)         = 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;
-    SvNVX(&PL_sv_no)           = 0;
+    SvFLAGS(&PL_sv_no)         = SVp_IOK|SVf_IOK|SVp_NOK|SVf_NOK
+                                 |SVp_POK|SVf_POK|SVf_READONLY|SVt_PVNV;
+    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);
 
     SvANY(&PL_sv_yes)          = new_XPVNV();
     SvREFCNT(&PL_sv_yes)       = (~(U32)0)/2;
-    SvFLAGS(&PL_sv_yes)                = 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;
-    SvNVX(&PL_sv_yes)          = 1;
+    SvFLAGS(&PL_sv_yes)                = SVp_IOK|SVf_IOK|SVp_NOK|SVf_NOK
+                                 |SVp_POK|SVf_POK|SVf_READONLY|SVt_PVNV;
+    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);
 
     /* create (a non-shared!) shared string table */
     PL_strtab          = newHV();
     HvSHAREKEYS_off(PL_strtab);
-    hv_ksplit(PL_strtab, 512);
+    hv_ksplit(PL_strtab, HvTOTALKEYS(proto_perl->Istrtab));
     ptr_table_store(PL_ptr_table, proto_perl->Istrtab, PL_strtab);
 
     PL_compiling = proto_perl->Icompiling;
@@ -10868,8 +11114,9 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     /* Clone the regex array */
     PL_regex_padav = newAV();
     {
-       I32 len = av_len((AV*)proto_perl->Iregex_padav);
-       SV** regexen = AvARRAY((AV*)proto_perl->Iregex_padav);
+       const I32 len = av_len((AV*)proto_perl->Iregex_padav);
+       SV** const regexen = AvARRAY((AV*)proto_perl->Iregex_padav);
+       IV i;
        av_push(PL_regex_padav,
                sv_dup_inc(regexen[0],param));
        for(i = 1; i <= len; i++) {
@@ -10971,7 +11218,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     /* interpreter atexit processing */
     PL_exitlistlen     = proto_perl->Iexitlistlen;
     if (PL_exitlistlen) {
-       New(0, PL_exitlist, PL_exitlistlen, PerlExitListEntry);
+       Newx(PL_exitlist, PL_exitlistlen, PerlExitListEntry);
        Copy(proto_perl->Iexitlist, PL_exitlist, PL_exitlistlen, PerlExitListEntry);
     }
     else
@@ -11054,13 +11301,13 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
      */
     if (SvANY(proto_perl->Ilinestr)) {
        PL_linestr              = sv_dup_inc(proto_perl->Ilinestr, param);
-       i = proto_perl->Ibufptr - SvPVX(proto_perl->Ilinestr);
+       i = proto_perl->Ibufptr - SvPVX_const(proto_perl->Ilinestr);
        PL_bufptr               = SvPVX(PL_linestr) + (i < 0 ? 0 : i);
-       i = proto_perl->Ioldbufptr - SvPVX(proto_perl->Ilinestr);
+       i = proto_perl->Ioldbufptr - SvPVX_const(proto_perl->Ilinestr);
        PL_oldbufptr    = SvPVX(PL_linestr) + (i < 0 ? 0 : i);
-       i = proto_perl->Ioldoldbufptr - SvPVX(proto_perl->Ilinestr);
+       i = proto_perl->Ioldoldbufptr - SvPVX_const(proto_perl->Ilinestr);
        PL_oldoldbufptr = SvPVX(PL_linestr) + (i < 0 ? 0 : i);
-       i = proto_perl->Ilinestart - SvPVX(proto_perl->Ilinestr);
+       i = proto_perl->Ilinestart - SvPVX_const(proto_perl->Ilinestr);
        PL_linestart    = SvPVX(PL_linestr) + (i < 0 ? 0 : i);
     }
     else {
@@ -11086,9 +11333,9 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 
     /* XXX See comment on SvANY(proto_perl->Ilinestr) above */
     if (SvANY(proto_perl->Ilinestr)) {
-       i = proto_perl->Ilast_uni - SvPVX(proto_perl->Ilinestr);
+       i = proto_perl->Ilast_uni - SvPVX_const(proto_perl->Ilinestr);
        PL_last_uni             = SvPVX(PL_linestr) + (i < 0 ? 0 : i);
-       i = proto_perl->Ilast_lop - SvPVX(proto_perl->Ilinestr);
+       i = proto_perl->Ilast_lop - SvPVX_const(proto_perl->Ilinestr);
        PL_last_lop             = SvPVX(PL_linestr) + (i < 0 ? 0 : i);
        PL_last_lop_op  = proto_perl->Ilast_lop_op;
     }
@@ -11195,21 +11442,19 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 
     PL_glob_index      = proto_perl->Iglob_index;
     PL_srand_called    = proto_perl->Isrand_called;
-    PL_hash_seed       = proto_perl->Ihash_seed;
-    PL_rehash_seed     = proto_perl->Irehash_seed;
     PL_uudmap['M']     = 0;            /* reinits on demand */
     PL_bitcount                = Nullch;       /* reinits on demand */
 
     if (proto_perl->Ipsig_pend) {
-       Newz(0, PL_psig_pend, SIG_SIZE, int);
+       Newxz(PL_psig_pend, SIG_SIZE, int);
     }
     else {
        PL_psig_pend    = (int*)NULL;
     }
 
     if (proto_perl->Ipsig_ptr) {
-       Newz(0, PL_psig_ptr,  SIG_SIZE, SV*);
-       Newz(0, PL_psig_name, SIG_SIZE, SV*);
+       Newxz(PL_psig_ptr,  SIG_SIZE, SV*);
+       Newxz(PL_psig_name, SIG_SIZE, SV*);
        for (i = 1; i < SIG_SIZE; i++) {
            PL_psig_ptr[i]  = sv_dup_inc(proto_perl->Ipsig_ptr[i], param);
            PL_psig_name[i] = sv_dup_inc(proto_perl->Ipsig_name[i], param);
@@ -11227,7 +11472,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
        PL_tmps_ix              = proto_perl->Ttmps_ix;
        PL_tmps_max             = proto_perl->Ttmps_max;
        PL_tmps_floor           = proto_perl->Ttmps_floor;
-       Newz(50, PL_tmps_stack, PL_tmps_max, SV*);
+       Newxz(PL_tmps_stack, PL_tmps_max, SV*);
        i = 0;
        while (i <= PL_tmps_ix) {
            PL_tmps_stack[i]    = sv_dup_inc(proto_perl->Ttmps_stack[i], param);
@@ -11236,7 +11481,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 
        /* next PUSHMARK() sets *(PL_markstack_ptr+1) */
        i = proto_perl->Tmarkstack_max - proto_perl->Tmarkstack;
-       Newz(54, PL_markstack, i, I32);
+       Newxz(PL_markstack, i, I32);
        PL_markstack_max        = PL_markstack + (proto_perl->Tmarkstack_max
                                                  - proto_perl->Tmarkstack);
        PL_markstack_ptr        = PL_markstack + (proto_perl->Tmarkstack_ptr
@@ -11248,7 +11493,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
         * NOTE: unlike the others! */
        PL_scopestack_ix        = proto_perl->Tscopestack_ix;
        PL_scopestack_max       = proto_perl->Tscopestack_max;
-       Newz(54, PL_scopestack, PL_scopestack_max, I32);
+       Newxz(PL_scopestack, PL_scopestack_max, I32);
        Copy(proto_perl->Tscopestack, PL_scopestack, PL_scopestack_ix, I32);
 
        /* next push_return() sets PL_retstack[PL_retstack_ix]
@@ -11275,7 +11520,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
         * NOTE: unlike the others! */
        PL_savestack_ix         = proto_perl->Tsavestack_ix;
        PL_savestack_max        = proto_perl->Tsavestack_max;
-       /*Newz(54, PL_savestack, PL_savestack_max, ANY);*/
+       /*Newxz(PL_savestack, PL_savestack_max, ANY);*/
        PL_savestack            = ss_dup(proto_perl, param);
     }
     else {
@@ -11420,14 +11665,14 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
        identified by sv_dup() above.
     */
     while(av_len(param->stashes) != -1) {
-        HV* stash = (HV*) av_shift(param->stashes);
-       GV* cloner = gv_fetchmethod_autoload(stash, "CLONE", 0);
+       HV* const stash = (HV*) av_shift(param->stashes);
+       GV* const cloner = gv_fetchmethod_autoload(stash, "CLONE", 0);
        if (cloner && GvCV(cloner)) {
            dSP;
            ENTER;
            SAVETMPS;
            PUSHMARK(SP);
-           XPUSHs(sv_2mortal(newSVpv(HvNAME(stash), 0)));
+           XPUSHs(sv_2mortal(newSVpv(HvNAME_get(stash), 0)));
            PUTBACK;
            call_sv((SV*)GvCV(cloner), G_DISCARD);
            FREETMPS;
@@ -11437,6 +11682,12 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 
     SvREFCNT_dec(param->stashes);
 
+    /* orphaned? eg threads->new inside BEGIN or use */
+    if (PL_compcv && ! SvREFCNT(PL_compcv)) {
+       (void)SvREFCNT_inc(PL_compcv);
+       SAVEFREESV(PL_compcv);
+    }
+
     return my_perl;
 }
 
@@ -11466,7 +11717,7 @@ Perl_sv_recode_to_utf8(pTHX_ SV *sv, SV *encoding)
     if (SvPOK(sv) && !SvUTF8(sv) && !IN_BYTES && SvROK(encoding)) {
        SV *uni;
        STRLEN len;
-       char *s;
+       const char *s;
        dSP;
        ENTER;
        SAVETMPS;
@@ -11490,12 +11741,11 @@ Perl_sv_recode_to_utf8(pTHX_ SV *sv, SV *encoding)
        SPAGAIN;
        uni = POPs;
        PUTBACK;
-       s = SvPV(uni, len);
-       if (s != SvPVX(sv)) {
+       s = SvPV_const(uni, len);
+       if (s != SvPVX_const(sv)) {
            SvGROW(sv, len + 1);
-           Move(s, SvPVX(sv), len, char);
+           Move(s, SvPVX(sv), len + 1, char);
            SvCUR_set(sv, len);
-           SvPVX(sv)[len] = 0; 
        }
        FREETMPS;
        LEAVE;
@@ -11552,3 +11802,12 @@ Perl_sv_cat_decode(pTHX_ SV *dsv, SV *encoding,
     return ret;
 }
 
+/*
+ * Local variables:
+ * c-indentation-style: bsd
+ * c-basic-offset: 4
+ * indent-tabs-mode: t
+ * End:
+ *
+ * ex: set ts=8 sts=4 sw=4 noet:
+ */