compiler awareness week
[p5sagit/p5-mst-13.2.git] / sv.c
diff --git a/sv.c b/sv.c
index 9dfbadb..e8c47f5 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -165,6 +165,7 @@ Public API:
  * "A time to plant, and a time to uproot what was planted..."
  */
 
+
 #ifdef DEBUG_LEAKING_SCALARS
 #  ifdef NETWARE
 #    define FREE_SV_DEBUG_FILE(sv) PerlMemfree((sv)->sv_debug_file)
@@ -193,6 +194,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 */
+       New(704,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
@@ -206,7 +229,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;
@@ -233,7 +256,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;                                \
@@ -261,12 +284,10 @@ 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)];
+           SV *sv = sva + 1;
+           SV *svend = &sva[SvREFCNT(sva)];
            if (p >= sv && p < svend) {
                ok = 1;
                break;
@@ -335,28 +356,6 @@ Perl_sv_add_arena(pTHX_ char *ptr, U32 size, U32 flags)
     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. */
 
@@ -364,12 +363,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 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
@@ -525,7 +523,7 @@ Perl_sv_free_arenas(pTHX)
 {
     SV* sva;
     SV* svanext;
-    XPV *arena, *arenanext;
+    void *arena, *arenanext;
 
     /* Free arenas here, but be careful about fake ones.  (We assume
        contiguity of the fake ones with the corresponding real ones.) */
@@ -539,85 +537,78 @@ Perl_sv_free_arenas(pTHX)
            Safefree((void *)sva);
     }
 
-    for (arena = PL_xiv_arenaroot; arena; arena = arenanext) {
-       arenanext = (XPV*)arena->xpv_pv;
-       Safefree(arena);
-    }
-    PL_xiv_arenaroot = 0;
-    PL_xiv_root = 0;
-
     for (arena = PL_xnv_arenaroot; arena; arena = arenanext) {
-       arenanext = (XPV*)arena->xpv_pv;
+       arenanext = *(void **)arena;
        Safefree(arena);
     }
     PL_xnv_arenaroot = 0;
     PL_xnv_root = 0;
 
-    for (arena = PL_xrv_arenaroot; arena; arena = arenanext) {
-       arenanext = (XPV*)arena->xpv_pv;
-       Safefree(arena);
-    }
-    PL_xrv_arenaroot = 0;
-    PL_xrv_root = 0;
-
     for (arena = PL_xpv_arenaroot; arena; arena = arenanext) {
-       arenanext = (XPV*)arena->xpv_pv;
+       arenanext = *(void **)arena;
        Safefree(arena);
     }
     PL_xpv_arenaroot = 0;
     PL_xpv_root = 0;
 
-    for (arena = (XPV*)PL_xpviv_arenaroot; arena; arena = arenanext) {
-       arenanext = (XPV*)arena->xpv_pv;
+    for (arena = PL_xpviv_arenaroot; arena; arena = arenanext) {
+       arenanext = *(void **)arena;
        Safefree(arena);
     }
     PL_xpviv_arenaroot = 0;
     PL_xpviv_root = 0;
 
-    for (arena = (XPV*)PL_xpvnv_arenaroot; arena; arena = arenanext) {
-       arenanext = (XPV*)arena->xpv_pv;
+    for (arena = PL_xpvnv_arenaroot; arena; arena = arenanext) {
+       arenanext = *(void **)arena;
        Safefree(arena);
     }
     PL_xpvnv_arenaroot = 0;
     PL_xpvnv_root = 0;
 
-    for (arena = (XPV*)PL_xpvcv_arenaroot; arena; arena = arenanext) {
-       arenanext = (XPV*)arena->xpv_pv;
+    for (arena = PL_xpvcv_arenaroot; arena; arena = arenanext) {
+       arenanext = *(void **)arena;
        Safefree(arena);
     }
     PL_xpvcv_arenaroot = 0;
     PL_xpvcv_root = 0;
 
-    for (arena = (XPV*)PL_xpvav_arenaroot; arena; arena = arenanext) {
-       arenanext = (XPV*)arena->xpv_pv;
+    for (arena = PL_xpvav_arenaroot; arena; arena = arenanext) {
+       arenanext = *(void **)arena;
        Safefree(arena);
     }
     PL_xpvav_arenaroot = 0;
     PL_xpvav_root = 0;
 
-    for (arena = (XPV*)PL_xpvhv_arenaroot; arena; arena = arenanext) {
-       arenanext = (XPV*)arena->xpv_pv;
+    for (arena = PL_xpvhv_arenaroot; arena; arena = arenanext) {
+       arenanext = *(void **)arena;
        Safefree(arena);
     }
     PL_xpvhv_arenaroot = 0;
     PL_xpvhv_root = 0;
 
-    for (arena = (XPV*)PL_xpvmg_arenaroot; arena; arena = arenanext) {
-       arenanext = (XPV*)arena->xpv_pv;
+    for (arena = PL_xpvmg_arenaroot; arena; arena = arenanext) {
+       arenanext = *(void **)arena;
        Safefree(arena);
     }
     PL_xpvmg_arenaroot = 0;
     PL_xpvmg_root = 0;
 
-    for (arena = (XPV*)PL_xpvlv_arenaroot; arena; arena = arenanext) {
-       arenanext = (XPV*)arena->xpv_pv;
+    for (arena = PL_xpvgv_arenaroot; arena; arena = arenanext) {
+       arenanext = *(void **)arena;
+       Safefree(arena);
+    }
+    PL_xpvgv_arenaroot = 0;
+    PL_xpvgv_root = 0;
+
+    for (arena = PL_xpvlv_arenaroot; arena; arena = arenanext) {
+       arenanext = *(void **)arena;
        Safefree(arena);
     }
     PL_xpvlv_arenaroot = 0;
     PL_xpvlv_root = 0;
 
-    for (arena = (XPV*)PL_xpvbm_arenaroot; arena; arena = arenanext) {
-       arenanext = (XPV*)arena->xpv_pv;
+    for (arena = PL_xpvbm_arenaroot; arena; arena = arenanext) {
+       arenanext = *(void **)arena;
        Safefree(arena);
     }
     PL_xpvbm_arenaroot = 0;
@@ -735,10 +726,9 @@ S_varname(pTHX_ GV *gv, const char *gvtype, PADOFFSET targ,
        SV* keyname, I32 aindex, int subscript_type)
 {
     AV *av;
+    SV *sv;
 
-    SV *sv, *name;
-
-    name = sv_newmortal();
+    SV * const name = sv_newmortal();
     if (gv) {
 
        /* simulate gv_fullname4(), but add literal '^' for $^FOO names
@@ -750,7 +740,7 @@ S_varname(pTHX_ GV *gv, const char *gvtype, PADOFFSET targ,
        sv_setpv(name, gvtype);
        if (!hv)
            p = "???";
-       else if (!(p=HvNAME(hv)))
+       else if (!(p=HvNAME_get(hv)))
            p = "__ANON__";
        if (strNE(p, "main")) {
            sv_catpv(name,p);
@@ -1135,156 +1125,256 @@ Perl_report_uninit(pTHX_ SV* uninit_sv)
                    "", "", "");
 }
 
-/* grab a new IV body from the free list, allocating more if necessary */
+/* allocate another arena's worth of NV bodies */
 
-STATIC XPVIV*
-S_new_xiv(pTHX)
+STATIC void
+S_more_xnv(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));
+    NV* xnv;
+    NV* xnvend;
+    void *ptr;
+    New(711, ptr, PERL_ARENA_SIZE/sizeof(NV), NV);
+    *((void **) ptr) = (void *)PL_xnv_arenaroot;
+    PL_xnv_arenaroot = ptr;
+
+    xnv = (NV*) ptr;
+    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) {
+       *(NV**)xnv = (NV*)(xnv + 1);
+       xnv++;
+    }
+    *(NV**)xnv = 0;
 }
 
-/* return an IV body to the free list */
+/* allocate another arena's worth of struct xpv */
 
 STATIC void
-S_del_xiv(pTHX_ XPVIV *p)
+S_more_xpv(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;
+    xpv_allocated* xpv;
+    xpv_allocated* xpvend;
+    New(713, xpv, PERL_ARENA_SIZE/sizeof(xpv_allocated), xpv_allocated);
+    *((xpv_allocated**)xpv) = PL_xpv_arenaroot;
+    PL_xpv_arenaroot = xpv;
+
+    xpvend = &xpv[PERL_ARENA_SIZE / sizeof(xpv_allocated) - 1];
+    PL_xpv_root = ++xpv;
+    while (xpv < xpvend) {
+       *((xpv_allocated**)xpv) = xpv + 1;
+       xpv++;
+    }
+    *((xpv_allocated**)xpv) = 0;
 }
 
-/* allocate another arena's worth of IV bodies */
+/* allocate another arena's worth of struct xpviv */
 
 STATIC void
-S_more_xiv(pTHX)
+S_more_xpviv(pTHX)
 {
-    register IV* xiv;
-    register IV* xivend;
-    XPV* ptr;
-    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 */
+    xpviv_allocated* xpviv;
+    xpviv_allocated* xpvivend;
+    New(713, xpviv, PERL_ARENA_SIZE/sizeof(xpviv_allocated), xpviv_allocated);
+    *((xpviv_allocated**)xpviv) = PL_xpviv_arenaroot;
+    PL_xpviv_arenaroot = xpviv;
 
-    xiv = (IV*) ptr;
-    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) {
-       *(IV**)xiv = (IV *)(xiv + 1);
-       xiv++;
+    xpvivend = &xpviv[PERL_ARENA_SIZE / sizeof(xpviv_allocated) - 1];
+    PL_xpviv_root = ++xpviv;
+    while (xpviv < xpvivend) {
+       *((xpviv_allocated**)xpviv) = xpviv + 1;
+       xpviv++;
     }
-    *(IV**)xiv = 0;
+    *((xpviv_allocated**)xpviv) = 0;
 }
 
-/* grab a new NV body from the free list, allocating more if necessary */
+/* allocate another arena's worth of struct xpvnv */
 
-STATIC XPVNV*
-S_new_xnv(pTHX)
+STATIC void
+S_more_xpvnv(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));
+    XPVNV* xpvnv;
+    XPVNV* xpvnvend;
+    New(715, xpvnv, PERL_ARENA_SIZE/sizeof(XPVNV), XPVNV);
+    *((XPVNV**)xpvnv) = PL_xpvnv_arenaroot;
+    PL_xpvnv_arenaroot = xpvnv;
+
+    xpvnvend = &xpvnv[PERL_ARENA_SIZE / sizeof(XPVNV) - 1];
+    PL_xpvnv_root = ++xpvnv;
+    while (xpvnv < xpvnvend) {
+       *((XPVNV**)xpvnv) = xpvnv + 1;
+       xpvnv++;
+    }
+    *((XPVNV**)xpvnv) = 0;
 }
 
-/* return an NV body to the free list */
+/* allocate another arena's worth of struct xpvcv */
 
 STATIC void
-S_del_xnv(pTHX_ XPVNV *p)
+S_more_xpvcv(pTHX)
 {
-    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;
+    XPVCV* xpvcv;
+    XPVCV* xpvcvend;
+    New(716, xpvcv, PERL_ARENA_SIZE/sizeof(XPVCV), XPVCV);
+    *((XPVCV**)xpvcv) = PL_xpvcv_arenaroot;
+    PL_xpvcv_arenaroot = xpvcv;
+
+    xpvcvend = &xpvcv[PERL_ARENA_SIZE / sizeof(XPVCV) - 1];
+    PL_xpvcv_root = ++xpvcv;
+    while (xpvcv < xpvcvend) {
+       *((XPVCV**)xpvcv) = xpvcv + 1;
+       xpvcv++;
+    }
+    *((XPVCV**)xpvcv) = 0;
 }
 
-/* allocate another arena's worth of NV bodies */
+/* allocate another arena's worth of struct xpvav */
 
 STATIC void
-S_more_xnv(pTHX)
+S_more_xpvav(pTHX)
 {
-    register NV* xnv;
-    register NV* xnvend;
-    XPV *ptr;
-    New(711, ptr, PERL_ARENA_SIZE/sizeof(XPV), XPV);
-    ptr->xpv_pv = (char*)PL_xnv_arenaroot;
-    PL_xnv_arenaroot = ptr;
+    xpvav_allocated* xpvav;
+     xpvav_allocated* xpvavend;
+    New(717, xpvav, PERL_ARENA_SIZE/sizeof(xpvav_allocated),
+       xpvav_allocated);
+    *((xpvav_allocated**)xpvav) = PL_xpvav_arenaroot;
+    PL_xpvav_arenaroot = xpvav;
 
-    xnv = (NV*) ptr;
-    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) {
-       *(NV**)xnv = (NV*)(xnv + 1);
-       xnv++;
+    xpvavend = &xpvav[PERL_ARENA_SIZE / sizeof(xpvav_allocated) - 1];
+    PL_xpvav_root = ++xpvav;
+    while (xpvav < xpvavend) {
+       *((xpvav_allocated**)xpvav) = xpvav + 1;
+       xpvav++;
     }
-    *(NV**)xnv = 0;
+    *((xpvav_allocated**)xpvav) = 0;
 }
 
-/* grab a new struct xrv from the free list, allocating more if necessary */
+/* allocate another arena's worth of struct xpvhv */
 
-STATIC XRV*
-S_new_xrv(pTHX)
+STATIC void
+S_more_xpvhv(pTHX)
 {
-    XRV* xrv;
-    LOCK_SV_MUTEX;
-    if (!PL_xrv_root)
-       more_xrv();
-    xrv = PL_xrv_root;
-    PL_xrv_root = (XRV*)xrv->xrv_rv;
-    UNLOCK_SV_MUTEX;
-    return xrv;
+    xpvhv_allocated* xpvhv;
+    xpvhv_allocated* xpvhvend;
+    New(718, xpvhv, PERL_ARENA_SIZE/sizeof(xpvhv_allocated),
+       xpvhv_allocated);
+    *((xpvhv_allocated**)xpvhv) = PL_xpvhv_arenaroot;
+    PL_xpvhv_arenaroot = xpvhv;
+
+    xpvhvend = &xpvhv[PERL_ARENA_SIZE / sizeof(xpvhv_allocated) - 1];
+    PL_xpvhv_root = ++xpvhv;
+    while (xpvhv < xpvhvend) {
+       *((xpvhv_allocated**)xpvhv) = xpvhv + 1;
+       xpvhv++;
+    }
+    *((xpvhv_allocated**)xpvhv) = 0;
 }
 
-/* return a struct xrv to the free list */
+/* allocate another arena's worth of struct xpvmg */
 
 STATIC void
-S_del_xrv(pTHX_ XRV *p)
+S_more_xpvmg(pTHX)
 {
-    LOCK_SV_MUTEX;
-    p->xrv_rv = (SV*)PL_xrv_root;
-    PL_xrv_root = p;
-    UNLOCK_SV_MUTEX;
+    XPVMG* xpvmg;
+    XPVMG* xpvmgend;
+    New(719, xpvmg, PERL_ARENA_SIZE/sizeof(XPVMG), XPVMG);
+    *((XPVMG**)xpvmg) = PL_xpvmg_arenaroot;
+    PL_xpvmg_arenaroot = xpvmg;
+
+    xpvmgend = &xpvmg[PERL_ARENA_SIZE / sizeof(XPVMG) - 1];
+    PL_xpvmg_root = ++xpvmg;
+    while (xpvmg < xpvmgend) {
+       *((XPVMG**)xpvmg) = xpvmg + 1;
+       xpvmg++;
+    }
+    *((XPVMG**)xpvmg) = 0;
 }
 
-/* allocate another arena's worth of struct xrv */
+/* allocate another arena's worth of struct xpvgv */
 
 STATIC void
-S_more_xrv(pTHX)
+S_more_xpvgv(pTHX)
 {
-    register XRV* xrv;
-    register XRV* xrvend;
-    XPV *ptr;
-    New(712, ptr, PERL_ARENA_SIZE/sizeof(XPV), XPV);
-    ptr->xpv_pv = (char*)PL_xrv_arenaroot;
-    PL_xrv_arenaroot = ptr;
+    XPVGV* xpvgv;
+    XPVGV* xpvgvend;
+    New(720, xpvgv, PERL_ARENA_SIZE/sizeof(XPVGV), XPVGV);
+    *((XPVGV**)xpvgv) = PL_xpvgv_arenaroot;
+    PL_xpvgv_arenaroot = xpvgv;
 
-    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++;
+    xpvgvend = &xpvgv[PERL_ARENA_SIZE / sizeof(XPVGV) - 1];
+    PL_xpvgv_root = ++xpvgv;
+    while (xpvgv < xpvgvend) {
+       *((XPVGV**)xpvgv) = xpvgv + 1;
+       xpvgv++;
     }
-    xrv->xrv_rv = 0;
+    *((XPVGV**)xpvgv) = 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**)xpvlv) = PL_xpvlv_arenaroot;
+    PL_xpvlv_arenaroot = xpvlv;
+
+    xpvlvend = &xpvlv[PERL_ARENA_SIZE / sizeof(XPVLV) - 1];
+    PL_xpvlv_root = ++xpvlv;
+    while (xpvlv < xpvlvend) {
+       *((XPVLV**)xpvlv) = xpvlv + 1;
+       xpvlv++;
+    }
+    *((XPVLV**)xpvlv) = 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**)xpvbm) = PL_xpvbm_arenaroot;
+    PL_xpvbm_arenaroot = xpvbm;
+
+    xpvbmend = &xpvbm[PERL_ARENA_SIZE / sizeof(XPVBM) - 1];
+    PL_xpvbm_root = ++xpvbm;
+    while (xpvbm < xpvbmend) {
+       *((XPVBM**)xpvbm) = xpvbm + 1;
+       xpvbm++;
+    }
+    *((XPVBM**)xpvbm) = 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)
+       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));
+}
+
+/* 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;
 }
 
 /* grab a new struct xpv from the free list, allocating more if necessary */
@@ -1292,14 +1382,20 @@ S_more_xrv(pTHX)
 STATIC XPV*
 S_new_xpv(pTHX)
 {
-    XPV* xpv;
+    xpv_allocated* 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;
+    PL_xpv_root = *(xpv_allocated**)xpv;
     UNLOCK_SV_MUTEX;
-    return xpv;
+    /* If xpv_allocated is the same structure as XPV then the two OFFSETs
+       sum to zero, and the pointer is unchanged. If the allocated structure
+       is smaller (no initial IV actually allocated) then the net effect is
+       to subtract the size of the IV from the pointer, to return a new pointer
+       as if an initial IV were actually allocated.  */
+    return (XPV*)((char*)xpv - STRUCT_OFFSET(XPV, xpv_cur)
+                 + STRUCT_OFFSET(xpv_allocated, xpv_cur));
 }
 
 /* return a struct xpv to the free list */
@@ -1307,45 +1403,34 @@ S_new_xpv(pTHX)
 STATIC void
 S_del_xpv(pTHX_ XPV *p)
 {
+    xpv_allocated* xpv
+       = (xpv_allocated*)((char*)(p) + STRUCT_OFFSET(XPV, xpv_cur)
+                          - STRUCT_OFFSET(xpv_allocated, xpv_cur));
     LOCK_SV_MUTEX;
-    p->xpv_pv = (char*)PL_xpv_root;
-    PL_xpv_root = p;
+    *(xpv_allocated**)xpv = PL_xpv_root;
+    PL_xpv_root = xpv;
     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, 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;
-}
-
 /* grab a new struct xpviv from the free list, allocating more if necessary */
 
 STATIC XPVIV*
 S_new_xpviv(pTHX)
 {
-    XPVIV* xpviv;
+    xpviv_allocated* 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;
+    PL_xpviv_root = *(xpviv_allocated**)xpviv;
     UNLOCK_SV_MUTEX;
-    return xpviv;
+    /* If xpviv_allocated is the same structure as XPVIV then the two OFFSETs
+       sum to zero, and the pointer is unchanged. If the allocated structure
+       is smaller (no initial IV actually allocated) then the net effect is
+       to subtract the size of the IV from the pointer, to return a new pointer
+       as if an initial IV were actually allocated.  */
+    return (XPVIV*)((char*)xpviv - STRUCT_OFFSET(XPVIV, xpv_cur)
+                 + STRUCT_OFFSET(xpviv_allocated, xpv_cur));
 }
 
 /* return a struct xpviv to the free list */
@@ -1353,32 +1438,15 @@ S_new_xpviv(pTHX)
 STATIC void
 S_del_xpviv(pTHX_ XPVIV *p)
 {
+    xpviv_allocated* xpviv
+       = (xpviv_allocated*)((char*)(p) + STRUCT_OFFSET(XPVIV, xpv_cur)
+                          - STRUCT_OFFSET(xpviv_allocated, xpv_cur));
     LOCK_SV_MUTEX;
-    p->xpv_pv = (char*)PL_xpviv_root;
-    PL_xpviv_root = p;
+    *(xpviv_allocated**)xpviv = PL_xpviv_root;
+    PL_xpviv_root = xpviv;
     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, 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;
-}
-
 /* grab a new struct xpvnv from the free list, allocating more if necessary */
 
 STATIC XPVNV*
@@ -1387,9 +1455,9 @@ 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;
+    PL_xpvnv_root = *(XPVNV**)xpvnv;
     UNLOCK_SV_MUTEX;
     return xpvnv;
 }
@@ -1400,31 +1468,11 @@ STATIC void
 S_del_xpvnv(pTHX_ XPVNV *p)
 {
     LOCK_SV_MUTEX;
-    p->xpv_pv = (char*)PL_xpvnv_root;
+    *(XPVNV**)p = PL_xpvnv_root;
     PL_xpvnv_root = 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, 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;
-}
-
 /* grab a new struct xpvcv from the free list, allocating more if necessary */
 
 STATIC XPVCV*
@@ -1433,9 +1481,9 @@ 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;
+    PL_xpvcv_root = *(XPVCV**)xpvcv;
     UNLOCK_SV_MUTEX;
     return xpvcv;
 }
@@ -1446,44 +1494,25 @@ STATIC void
 S_del_xpvcv(pTHX_ XPVCV *p)
 {
     LOCK_SV_MUTEX;
-    p->xpv_pv = (char*)PL_xpvcv_root;
+    *(XPVCV**)p = PL_xpvcv_root;
     PL_xpvcv_root = 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, 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;
-}
-
 /* grab a new struct xpvav from the free list, allocating more if necessary */
 
 STATIC XPVAV*
 S_new_xpvav(pTHX)
 {
-    XPVAV* xpvav;
+    xpvav_allocated* 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;
+    PL_xpvav_root = *(xpvav_allocated**)xpvav;
     UNLOCK_SV_MUTEX;
-    return xpvav;
+    return (XPVAV*)((char*)xpvav - STRUCT_OFFSET(XPVAV, xav_fill)
+                   + STRUCT_OFFSET(xpvav_allocated, xav_fill));
 }
 
 /* return a struct xpvav to the free list */
@@ -1491,45 +1520,29 @@ S_new_xpvav(pTHX)
 STATIC void
 S_del_xpvav(pTHX_ XPVAV *p)
 {
+    xpvav_allocated* xpvav
+       = (xpvav_allocated*)((char*)(p) + STRUCT_OFFSET(XPVAV, xav_fill)
+                            - STRUCT_OFFSET(xpvav_allocated, xav_fill));
     LOCK_SV_MUTEX;
-    p->xav_array = (char*)PL_xpvav_root;
-    PL_xpvav_root = p;
+    *(xpvav_allocated**)xpvav = PL_xpvav_root;
+    PL_xpvav_root = xpvav;
     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, 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;
-}
-
 /* grab a new struct xpvhv from the free list, allocating more if necessary */
 
 STATIC XPVHV*
 S_new_xpvhv(pTHX)
 {
-    XPVHV* xpvhv;
+    xpvhv_allocated* 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;
+    PL_xpvhv_root = *(xpvhv_allocated**)xpvhv;
     UNLOCK_SV_MUTEX;
-    return xpvhv;
+    return (XPVHV*)((char*)xpvhv - STRUCT_OFFSET(XPVHV, xhv_fill)
+                   + STRUCT_OFFSET(xpvhv_allocated, xhv_fill));
 }
 
 /* return a struct xpvhv to the free list */
@@ -1537,32 +1550,15 @@ S_new_xpvhv(pTHX)
 STATIC void
 S_del_xpvhv(pTHX_ XPVHV *p)
 {
+    xpvhv_allocated* xpvhv
+       = (xpvhv_allocated*)((char*)(p) + STRUCT_OFFSET(XPVHV, xhv_fill)
+                            - STRUCT_OFFSET(xpvhv_allocated, xhv_fill));
     LOCK_SV_MUTEX;
-    p->xhv_array = (char*)PL_xpvhv_root;
-    PL_xpvhv_root = p;
+    *(xpvhv_allocated**)xpvhv = PL_xpvhv_root;
+    PL_xpvhv_root = xpvhv;
     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, 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;
-}
-
 /* grab a new struct xpvmg from the free list, allocating more if necessary */
 
 STATIC XPVMG*
@@ -1571,9 +1567,9 @@ 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;
+    PL_xpvmg_root = *(XPVMG**)xpvmg;
     UNLOCK_SV_MUTEX;
     return xpvmg;
 }
@@ -1584,29 +1580,35 @@ STATIC void
 S_del_xpvmg(pTHX_ XPVMG *p)
 {
     LOCK_SV_MUTEX;
-    p->xpv_pv = (char*)PL_xpvmg_root;
+    *(XPVMG**)p = PL_xpvmg_root;
     PL_xpvmg_root = p;
     UNLOCK_SV_MUTEX;
 }
 
-/* allocate another arena's worth of struct xpvmg */
+/* grab a new struct xpvgv from the free list, allocating more if necessary */
 
-STATIC void
-S_more_xpvmg(pTHX)
+STATIC XPVGV*
+S_new_xpvgv(pTHX)
 {
-    register XPVMG* xpvmg;
-    register XPVMG* xpvmgend;
-    New(719, xpvmg, PERL_ARENA_SIZE/sizeof(XPVMG), XPVMG);
-    xpvmg->xpv_pv = (char*)PL_xpvmg_arenaroot;
-    PL_xpvmg_arenaroot = xpvmg;
+    XPVGV* xpvgv;
+    LOCK_SV_MUTEX;
+    if (!PL_xpvgv_root)
+       S_more_xpvgv(aTHX);
+    xpvgv = PL_xpvgv_root;
+    PL_xpvgv_root = *(XPVGV**)xpvgv;
+    UNLOCK_SV_MUTEX;
+    return xpvgv;
+}
 
-    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;
+/* return a struct xpvgv to the free list */
+
+STATIC void
+S_del_xpvgv(pTHX_ XPVGV *p)
+{
+    LOCK_SV_MUTEX;
+    *(XPVGV**)p = PL_xpvgv_root;
+    PL_xpvgv_root = p;
+    UNLOCK_SV_MUTEX;
 }
 
 /* grab a new struct xpvlv from the free list, allocating more if necessary */
@@ -1617,9 +1619,9 @@ 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;
+    PL_xpvlv_root = *(XPVLV**)xpvlv;
     UNLOCK_SV_MUTEX;
     return xpvlv;
 }
@@ -1630,31 +1632,11 @@ STATIC void
 S_del_xpvlv(pTHX_ XPVLV *p)
 {
     LOCK_SV_MUTEX;
-    p->xpv_pv = (char*)PL_xpvlv_root;
+    *(XPVLV**)p = PL_xpvlv_root;
     PL_xpvlv_root = 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, 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;
-}
-
 /* grab a new struct xpvbm from the free list, allocating more if necessary */
 
 STATIC XPVBM*
@@ -1663,9 +1645,9 @@ 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;
+    PL_xpvbm_root = *(XPVBM**)xpvbm;
     UNLOCK_SV_MUTEX;
     return xpvbm;
 }
@@ -1676,45 +1658,19 @@ STATIC void
 S_del_xpvbm(pTHX_ XPVBM *p)
 {
     LOCK_SV_MUTEX;
-    p->xpv_pv = (char*)PL_xpvbm_root;
+    *(XPVBM**)p = PL_xpvbm_root;
     PL_xpvbm_root = 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, 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;
-}
-
 #define my_safemalloc(s)       (void*)safemalloc(s)
 #define my_safefree(p) safefree((char*)p)
 
 #ifdef PURIFY
 
-#define new_XIV()      my_safemalloc(sizeof(XPVIV))
-#define del_XIV(p)     my_safefree(p)
-
 #define new_XNV()      my_safemalloc(sizeof(XPVNV))
 #define del_XNV(p)     my_safefree(p)
 
-#define new_XRV()      my_safemalloc(sizeof(XRV))
-#define del_XRV(p)     my_safefree(p)
-
 #define new_XPV()      my_safemalloc(sizeof(XPV))
 #define del_XPV(p)     my_safefree(p)
 
@@ -1736,6 +1692,9 @@ S_more_xpvbm(pTHX)
 #define new_XPVMG()    my_safemalloc(sizeof(XPVMG))
 #define del_XPVMG(p)   my_safefree(p)
 
+#define new_XPVGV()    my_safemalloc(sizeof(XPVGV))
+#define del_XPVGV(p)   my_safefree(p)
+
 #define new_XPVLV()    my_safemalloc(sizeof(XPVLV))
 #define del_XPVLV(p)   my_safefree(p)
 
@@ -1744,15 +1703,9 @@ S_more_xpvbm(pTHX)
 
 #else /* !PURIFY */
 
-#define new_XIV()      (void*)new_xiv()
-#define del_XIV(p)     del_xiv((XPVIV*) p)
-
 #define new_XNV()      (void*)new_xnv()
 #define del_XNV(p)     del_xnv((XPVNV*) p)
 
-#define new_XRV()      (void*)new_xrv()
-#define del_XRV(p)     del_xrv((XRV*) p)
-
 #define new_XPV()      (void*)new_xpv()
 #define del_XPV(p)     del_xpv((XPV *)p)
 
@@ -1774,6 +1727,9 @@ S_more_xpvbm(pTHX)
 #define new_XPVMG()    (void*)new_xpvmg()
 #define del_XPVMG(p)   del_xpvmg((XPVMG *)p)
 
+#define new_XPVGV()    (void*)new_xpvgv()
+#define del_XPVGV(p)   del_xpvgv((XPVGV *)p)
+
 #define new_XPVLV()    (void*)new_xpvlv()
 #define del_XPVLV(p)   del_xpvlv((XPVLV *)p)
 
@@ -1782,9 +1738,6 @@ S_more_xpvbm(pTHX)
 
 #endif /* PURIFY */
 
-#define new_XPVGV()    my_safemalloc(sizeof(XPVGV))
-#define del_XPVGV(p)   my_safefree(p)
-
 #define new_XPVFM()    my_safemalloc(sizeof(XPVFM))
 #define del_XPVFM(p)   my_safefree(p)
 
@@ -1833,7 +1786,6 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
        break;
     case SVt_IV:
        iv      = SvIVX(sv);
-       del_XIV(SvANY(sv));
        if (mt == SVt_NV)
            mt = SVt_PVNV;
        else if (mt < SVt_PVIV)
@@ -1847,7 +1799,6 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
        break;
     case SVt_RV:
        pv      = (char*)SvRV(sv);
-       del_XRV(SvANY(sv));
        break;
     case SVt_PV:
        pv      = SvPVX(sv);
@@ -1879,6 +1830,10 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
           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(sv);
        cur     = SvCUR(sv);
        len     = SvLEN(sv);
@@ -1899,7 +1854,7 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
     case SVt_NULL:
        Perl_croak(aTHX_ "Can't upgrade to undef");
     case SVt_IV:
-       SvANY(sv) = new_XIV();
+       SvANY(sv) = (XPVIV*)((char*)&(sv->sv_u.svu_iv) - STRUCT_OFFSET(XPVIV, xiv_iv));
        SvIV_set(sv, iv);
        break;
     case SVt_NV:
@@ -1907,19 +1862,15 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
        SvNV_set(sv, nv);
        break;
     case SVt_RV:
-       SvANY(sv) = new_XRV();
+       SvANY(sv) = &sv->sv_u.svu_rv;
        SvRV_set(sv, (SV*)pv);
        break;
     case SVt_PVHV:
        SvANY(sv) = new_XPVHV();
-       HvRITER(sv)     = 0;
-       HvEITER(sv)     = 0;
-       HvPMROOT(sv)    = 0;
-       HvNAME(sv)      = 0;
+       ((XPVHV*) SvANY(sv))->xhv_aux = 0;
        HvFILL(sv)      = 0;
        HvMAX(sv)       = 0;
        HvTOTALKEYS(sv) = 0;
-       HvPLACEHOLDERS(sv) = 0;
 
        /* Fall through...  */
        if (0) {
@@ -1929,9 +1880,7 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
            AvFILLp(sv) = -1;
            AvALLOC(sv) = 0;
            AvARYLEN(sv)= 0;
-           AvFLAGS(sv) = AVf_REAL;
-           SvIV_set(sv, 0);
-           SvNV_set(sv, 0.0);
+           AvREAL_only(sv);
        }
        /* to here.  */
        /* XXX? Only SVt_NULL is ever upgraded to AV or HV?  */
@@ -2090,7 +2039,7 @@ Perl_sv_grow(pTHX_ register SV *sv, register STRLEN newlen)
     if (newlen > SvLEN(sv)) {          /* need more room? */
        if (SvLEN(sv) && s) {
 #ifdef MYMALLOC
-           STRLEN l = malloced_size((void*)SvPVX(sv));
+           const STRLEN l = malloced_size((void*)SvPVX(sv));
            if (newlen <= l) {
                SvLEN_set(sv, l);
                return s;
@@ -2361,7 +2310,7 @@ 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)) {
@@ -2652,7 +2601,7 @@ Perl_sv_2iv_flags(pTHX_ register SV *sv, I32 flags)
     }
     else if (SvPOKp(sv) && SvLEN(sv)) {
        UV value;
-       const 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
@@ -2955,7 +2904,7 @@ Perl_sv_2uv_flags(pTHX_ register SV *sv, I32 flags)
     }
     else if (SvPOKp(sv) && SvLEN(sv)) {
        UV value;
-       const 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
@@ -3127,7 +3076,7 @@ Perl_sv_2nv(pTHX_ register SV *sv)
            return SvNVX(sv);
        if (SvPOKp(sv) && SvLEN(sv)) {
            if (ckWARN(WARN_NUMERIC) && !SvIOKp(sv) &&
-               !grok_number(SvPVX(sv), SvCUR(sv), NULL))
+               !grok_number(SvPVX_const(sv), SvCUR(sv), NULL))
                not_a_number(sv);
            return Atof(SvPVX(sv));
        }
@@ -3349,7 +3298,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) {
@@ -3603,7 +3552,7 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
                }
                tsv = NEWSV(0,0);
                if (SvOBJECT(sv)) {
-                   const char *name = HvNAME(SvSTASH(sv));
+                   const char *name = HvNAME_get(SvSTASH(sv));
                    Perl_sv_setpvf(aTHX_ tsv, "%s=%s(0x%"UVxf")",
                                   name ? name : "__ANON__" , typestr, PTR2UV(sv));
                }
@@ -3857,9 +3806,9 @@ Perl_sv_2bool(pTHX_ register SV *sv)
     if (SvPOKp(sv)) {
        register XPV* Xpvtmp;
        if ((Xpvtmp = (XPV*)SvANY(sv)) &&
-               (*Xpvtmp->xpv_pv > '0' ||
+               (*sv->sv_u.svu_pv > '0' ||
                Xpvtmp->xpv_cur > 1 ||
-               (Xpvtmp->xpv_cur && *Xpvtmp->xpv_pv != '0')))
+               (Xpvtmp->xpv_cur && *sv->sv_u.svu_pv != '0')))
            return 1;
        else
            return 0;
@@ -4245,19 +4194,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);
                /* don't upgrade SVt_PVLV: it can hold a glob */
                if (dtype != SVt_PVLV)
                    sv_upgrade(dstr, SVt_PVGV);
@@ -4317,7 +4268,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)) {
@@ -4393,7 +4344,7 @@ 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));
                                }
                            }
@@ -4767,7 +4718,7 @@ 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");
     }
@@ -5331,6 +5282,7 @@ Perl_sv_magicext(pTHX_ SV* sv, SV* obj, int how, const MGVTBL *vtable,
     if (!obj || obj == sv ||
        how == PERL_MAGIC_arylen ||
        how == PERL_MAGIC_qr ||
+       how == PERL_MAGIC_symtab ||
        (SvTYPE(obj) == SVt_PVGV &&
            (GvSV(obj) == sv || GvHV(obj) == (HV*)sv || GvAV(obj) == (AV*)sv ||
            GvCV(obj) == (CV*)sv || GvIOp(obj) == (IO*)sv ||
@@ -5502,6 +5454,8 @@ Perl_sv_magic(pTHX_ register SV *sv, SV *obj, int how, const char *name, I32 nam
     case PERL_MAGIC_vec:
        vtable = &PL_vtbl_vec;
        break;
+    case PERL_MAGIC_rhash:
+    case PERL_MAGIC_symtab:
     case PERL_MAGIC_vstring:
        vtable = 0;
        break;
@@ -5787,7 +5741,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_COW_DROP(sv);
     if (SvREFCNT(nsv) != 1 && ckWARN_d(WARN_INTERNAL))
        Perl_warner(aTHX_ packWARN(WARN_INTERNAL), "Reference miscount in sv_replace()");
@@ -5811,6 +5765,15 @@ Perl_sv_replace(pTHX_ register SV *sv, register SV *nsv)
 #else
     StructCopy(nsv,sv,SV);
 #endif
+    /* Currently could join these into one piece of pointer arithmetic, but
+       it would be unclear.  */
+    if(SvTYPE(sv) == SVt_IV)
+       SvANY(sv)
+           = (XPVIV*)((char*)&(sv->sv_u.svu_iv) - STRUCT_OFFSET(XPVIV, xiv_iv));
+    else if (SvTYPE(sv) == SVt_RV) {
+       SvANY(sv) = &sv->sv_u.svu_rv;
+    }
+       
 
 #ifdef PERL_COPY_ON_WRITE
     if (SvIsCOW_normal(nsv)) {
@@ -5901,7 +5864,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;
            }
@@ -5917,7 +5880,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;
@@ -6025,13 +5988,11 @@ Perl_sv_clear(pTHX_ register SV *sv)
     case SVt_NULL:
        break;
     case SVt_IV:
-       del_XIV(SvANY(sv));
        break;
     case SVt_NV:
        del_XNV(SvANY(sv));
        break;
     case SVt_RV:
-       del_XRV(SvANY(sv));
        break;
     case SVt_PV:
        del_XPV(SvANY(sv));
@@ -6211,7 +6172,7 @@ Perl_sv_len_utf8(pTHX_ register SV *sv)
     else
     {
        STRLEN len, ulen;
-       U8 *s = (U8*)SvPV(sv, len);
+       const U8 *s = (U8*)SvPV(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)) {
@@ -6245,7 +6206,7 @@ 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, U8 *s, U8 *start)
 {
     bool found = FALSE;
 
@@ -6262,7 +6223,7 @@ S_utf8_mg_pos_init(pTHX_ SV *sv, MAGIC **mgp, STRLEN **cachep, I32 i, I32 *offse
        }
        assert(*cachep);
 
-       (*cachep)[i]   = *offsetp;
+       (*cachep)[i]   = offsetp;
        (*cachep)[i+1] = s - start;
        found = TRUE;
     }
@@ -6293,7 +6254,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
@@ -6312,7 +6273,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];
@@ -6433,7 +6394,7 @@ 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;
         }
@@ -6451,7 +6412,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;
         }
@@ -7333,7 +7294,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.
@@ -7481,7 +7442,7 @@ Perl_sv_dec(pTHX_ register SV *sv)
     }
 #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.
@@ -7866,7 +7827,6 @@ Perl_sv_reset(pTHX_ register const char *s, HV *stash)
     register GV *gv;
     register SV *sv;
     register I32 i;
-    register PMOP *pm;
     register I32 max;
     char todo[PERL_UCHAR_MAX+1];
 
@@ -7874,8 +7834,13 @@ Perl_sv_reset(pTHX_ register const char *s, HV *stash)
        return;
 
     if (!*s) {         /* reset ?? searches */
-       for (pm = HvPMROOT(stash); pm; pm = pm->op_pmnext) {
-           pm->op_pmdynflags &= ~PMdf_USED;
+       MAGIC *mg = mg_find((SV *)stash, PERL_MAGIC_symtab);
+       if (mg) {
+           PMOP *pm = (PMOP *) mg->mg_obj;
+           while (pm) {
+               pm->op_pmdynflags &= ~PMdf_USED;
+               pm = pm->op_pmnext;
+           }
        }
        return;
     }
@@ -7919,7 +7884,7 @@ Perl_sv_reset(pTHX_ register const char *s, HV *stash)
                if (GvAV(gv)) {
                    av_clear(GvAV(gv));
                }
-               if (GvHV(gv) && !HvNAME(GvHV(gv))) {
+               if (GvHV(gv) && !HvNAME_get(GvHV(gv))) {
                    hv_clear(GvHV(gv));
 #ifndef PERL_MICRO
 #ifdef USE_ENVIRON_ARRAY
@@ -8083,7 +8048,7 @@ Perl_sv_true(pTHX_ register SV *sv)
        const register XPV* tXpv;
        if ((tXpv = (XPV*)SvANY(sv)) &&
                (tXpv->xpv_cur > 1 ||
-               (tXpv->xpv_cur && *tXpv->xpv_pv != '0')))
+               (tXpv->xpv_cur && *sv->sv_u.svu_pv != '0')))
            return 1;
        else
            return 0;
@@ -8238,7 +8203,6 @@ 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_flags(sv, 0);
@@ -8247,6 +8211,7 @@ Perl_sv_pvn_force_flags(pTHX_ SV *sv, STRLEN *lp, I32 flags)
        *lp = SvCUR(sv);
     }
     else {
+       char *s;
        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));
@@ -8254,7 +8219,7 @@ Perl_sv_pvn_force_flags(pTHX_ SV *sv, STRLEN *lp, I32 flags)
        else
            s = sv_2pv_flags(sv, lp, flags);
        if (s != SvPVX(sv)) {   /* Almost, but not quite, sv_setpvn() */
-           STRLEN len = *lp;
+           const STRLEN len = *lp;
        
            if (SvROK(sv))
                sv_unref(sv);
@@ -8390,7 +8355,7 @@ Perl_sv_reftype(pTHX_ const 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)) {
-       char *name = HvNAME(SvSTASH(sv));
+       char *name = HvNAME_get(SvSTASH(sv));
        return name ? name : (char *) "__ANON__";
     }
     else {
@@ -8465,6 +8430,7 @@ an inheritance relationship.
 int
 Perl_sv_isa(pTHX_ SV *sv, const char *name)
 {
+    const char *hvname;
     if (!sv)
        return 0;
     if (SvGMAGICAL(sv))
@@ -8474,10 +8440,11 @@ Perl_sv_isa(pTHX_ SV *sv, const char *name)
     sv = (SV*)SvRV(sv);
     if (!SvOBJECT(sv))
        return 0;
-    if (!HvNAME(SvSTASH(sv)))
+    hvname = HvNAME_get(SvSTASH(sv));
+    if (!hvname)
        return 0;
 
-    return strEQ(HvNAME(SvSTASH(sv)), name);
+    return strEQ(hvname, name);
 }
 
 /*
@@ -8502,7 +8469,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;
@@ -9097,7 +9064,7 @@ 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;
 
@@ -9109,7 +9076,7 @@ F0convert(NV nv, char *endbuf, STRLEN *len)
        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)
@@ -9142,7 +9109,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
 {
     char *p;
     char *q;
-    char *patend;
+    const char *patend;
     STRLEN origlen;
     I32 svix = 0;
     static const char nullstr[] = "(null)";
@@ -9162,12 +9129,10 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
     /* no matter what, this is a string now */
     (void)SvPV_force(sv, origlen);
 
-    /* special-case "", "%s", and "%_" */
+    /* special-case "", "%s", and "%-p" (SVf) */
     if (patlen == 0)
        return;
-    if (patlen == 2 && pat[0] == '%') {
-       switch (pat[1]) {
-       case 's':
+    if (patlen == 2 && pat[0] == '%' && pat[1] == 's') {
            if (args) {
                 const char *s = va_arg(*args, char*);
                sv_catpv(sv, s ? s : nullstr);
@@ -9178,7 +9143,9 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                    SvUTF8_on(sv);
            }
            return;
-       case '_':
+    }
+    if (patlen == 3 && pat[0] == '%' &&
+       pat[1] == '-' && pat[2] == 'p') {
            if (args) {
                argsv = va_arg(*args, SV*);
                sv_catsv(sv, argsv);
@@ -9186,9 +9153,6 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                    SvUTF8_on(sv);
                return;
            }
-           /* See comment on '_' below */
-           break;
-       }
     }
 
 #ifndef USE_LONG_DOUBLE
@@ -9566,23 +9530,6 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                    is_utf8 = TRUE;
                }
            }
-           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.
-            * So we keep it hidden from users' code.
-            */
-           if (!args || vectorize)
-               goto unknown;
-           argsv = va_arg(*args, SV*);
-           eptr = SvPVx(argsv, elen);
-           if (DO_UTF8(argsv))
-               is_utf8 = TRUE;
 
        string:
            vectorize = FALSE;
@@ -9593,17 +9540,21 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            /* INTEGERS */
 
        case 'p':
-#ifdef CHECK_FORMAT
-           if (left) {
+           if (left && args) {         /* SVf */
                left = FALSE;
-               if (!width)
-                   goto format_sv;     /* %-p  -> %_   */
-               precis = width;
-               has_precis = TRUE;
-               width = 0;
-               goto format_sv;         /* %-Np -> %.N_ */      
+               if (width) {
+                   precis = width;
+                   has_precis = TRUE;
+                   width = 0;
+               }
+               if (vectorize)
+                   goto unknown;
+               argsv = va_arg(*args, SV*);
+               eptr = SvPVx(argsv, elen);
+               if (DO_UTF8(argsv))
+                   is_utf8 = TRUE;
+               goto string;
            }
-#endif
            if (alt || vectorize)
                goto unknown;
            uv = PTR2UV(args ? va_arg(*args, void*) : argsv);
@@ -10386,6 +10337,9 @@ Perl_mg_dup(pTHX_ MAGIC *mg, CLONE_PARAMS* param)
                av_push((AV*)nmg->mg_obj,sv_dup(svp[i],param));
            }
        }
+       else if (mg->mg_type == PERL_MAGIC_symtab) {
+           nmg->mg_obj = mg->mg_obj;
+       }
        else {
            nmg->mg_obj = (mg->mg_flags & MGf_REFCOUNTED)
                              ? sv_dup_inc(mg->mg_obj, param)
@@ -10442,8 +10396,8 @@ Perl_ptr_table_new(pTHX)
 STATIC void
 S_more_pte(pTHX)
 {
-    register struct ptr_tbl_ent* pte;
-    register struct ptr_tbl_ent* pteend;
+    struct ptr_tbl_ent* pte;
+    struct ptr_tbl_ent* pteend;
     New(0, pte, PERL_ARENA_SIZE/sizeof(struct ptr_tbl_ent), struct ptr_tbl_ent);
     pte->next = PL_pte_arenaroot;
     PL_pte_arenaroot = pte;
@@ -10625,7 +10579,7 @@ S_gv_share(pTHX_ SV *sstr, CLONE_PARAMS *param)
     if (!GvUNIQUE(gv)) {
 #if 0
         PerlIO_printf(Perl_debug_log, "gv_share: unable to share %s::%s\n",
-                      HvNAME(GvSTASH(gv)), GvNAME(gv));
+                      HvNAME_get(GvSTASH(gv)), GvNAME(gv));
 #endif
         return Nullsv;
     }
@@ -10731,11 +10685,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;
         }
     }
@@ -10780,7 +10735,7 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
        SvANY(dstr)     = NULL;
        break;
     case SVt_IV:
-       SvANY(dstr)     = new_XIV();
+       SvANY(dstr)     = (XPVIV*)((char*)&(dstr->sv_u.svu_iv) - STRUCT_OFFSET(XPVIV, xiv_iv));
        SvIV_set(dstr, SvIVX(sstr));
        break;
     case SVt_NV:
@@ -10788,7 +10743,7 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
        SvNV_set(dstr, SvNVX(sstr));
        break;
     case SVt_RV:
-       SvANY(dstr)     = new_XRV();
+       SvANY(dstr)     = &(dstr->sv_u.svu_rv);
        Perl_rvpv_dup(aTHX_ dstr, sstr, param);
        break;
     case SVt_PV:
@@ -10863,7 +10818,7 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
                 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));
+                              HvNAME_get(GvSTASH(share)), GvNAME(share));
 #endif
                 break;
             }
@@ -10929,12 +10884,9 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
        SvANY(dstr)     = new_XPVAV();
        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)) {
            SV **dst_ary, **src_ary;
            SSize_t items = AvFILLp((AV*)sstr) + 1;
@@ -10966,35 +10918,60 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
        SvANY(dstr)     = new_XPVHV();
        SvCUR_set(dstr, SvCUR(sstr));
        SvLEN_set(dstr, SvLEN(sstr));
-       SvIV_set(dstr, SvIVX(sstr));
-       SvNV_set(dstr, SvNVX(sstr));
+       HvTOTALKEYS(dstr) = HvTOTALKEYS(sstr);
        SvMAGIC_set(dstr, mg_dup(SvMAGIC(sstr), param));
        SvSTASH_set(dstr, hv_dup_inc(SvSTASH(sstr), param));
-       HvRITER((HV*)dstr)      = HvRITER((HV*)sstr);
-       if (HvARRAY((HV*)sstr)) {
-           STRLEN i = 0;
-           XPVHV *dxhv = (XPVHV*)SvANY(dstr);
-           XPVHV *sxhv = (XPVHV*)SvANY(sstr);
-           Newz(0, 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);
-               ++i;
+       {
+           struct xpvhv_aux *aux = ((XPVHV *)SvANY(sstr))->xhv_aux;
+           HEK *hvname = 0;
+
+           if (aux) {
+               I32 riter = aux->xhv_riter;
+
+               hvname = aux->xhv_name;
+               if (hvname || riter != -1) {
+                   struct xpvhv_aux *d_aux;
+
+                   New(0, d_aux, 1, struct xpvhv_aux);
+
+                   d_aux->xhv_riter = riter;
+                   d_aux->xhv_eiter = 0;
+                   d_aux->xhv_name = hvname ? hek_dup(hvname, param) : hvname;
+
+                   ((XPVHV *)SvANY(dstr))->xhv_aux = d_aux;
+               } else {
+                   ((XPVHV *)SvANY(dstr))->xhv_aux = 0;
+               }
            }
-           dxhv->xhv_eiter = he_dup(sxhv->xhv_eiter,
-                                    (bool)!!HvSHAREKEYS(sstr), param);
-       }
-       else {
-           SvPV_set(dstr, Nullch);
-           HvEITER((HV*)dstr)  = (HE*)NULL;
+           else {
+               ((XPVHV *)SvANY(dstr))->xhv_aux = 0;
+           }
+           if (HvARRAY((HV*)sstr)) {
+               STRLEN i = 0;
+               XPVHV *dxhv = (XPVHV*)SvANY(dstr);
+               XPVHV *sxhv = (XPVHV*)SvANY(sstr);
+               char *darray;
+               /* FIXME - surely this doesn't need to be zeroed?  */
+               Newz(0, darray,
+                    PERL_HV_ARRAY_ALLOC_BYTES(dxhv->xhv_max+1), char);
+               HvARRAY(dstr) = (HE**)darray;
+               while (i <= sxhv->xhv_max) {
+                   HvARRAY(dstr)[i]
+                       = he_dup(HvARRAY(sstr)[i],
+                                (bool)!!HvSHAREKEYS(sstr), param);
+                   ++i;
+               }
+               HvEITER_set(dstr, he_dup(HvEITER_get(sstr),
+                                        (bool)!!HvSHAREKEYS(sstr), param));
+           }
+           else {
+               SvPV_set(dstr, Nullch);
+               HvEITER_set((HV*)dstr, (HE*)NULL);
+           }
+           /* Record stashes for possible cloning in Perl_clone(). */
+           if(hvname)
+               av_push(param->stashes, dstr);
        }
-       HvPMROOT((HV*)dstr)     = HvPMROOT((HV*)sstr);          /* XXX */
-       HvNAME((HV*)dstr)       = SAVEPV(HvNAME((HV*)sstr));
-    /* Record stashes for possible cloning in Perl_clone(). */
-       if(HvNAME((HV*)dstr))
-           av_push(param->stashes, dstr);
        break;
     case SVt_PVFM:
        SvANY(dstr)     = new_XPVFM();
@@ -11498,8 +11475,10 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
 static void
 do_mark_cloneable_stash(pTHX_ SV *sv)
 {
-    if (HvNAME((HV*)sv)) {
+    const char *hvname = HvNAME_get((HV*)sv);
+    if (hvname) {
        GV* cloner = gv_fetchmethod_autoload((HV*)sv, "CLONE_SKIP", 0);
+       STRLEN len = HvNAMELEN_get((HV*)sv);
        SvFLAGS(sv) |= SVphv_CLONEABLE; /* clone objects by default */
        if (cloner && GvCV(cloner)) {
            dSP;
@@ -11508,7 +11487,7 @@ do_mark_cloneable_stash(pTHX_ SV *sv)
            ENTER;
            SAVETMPS;
            PUSHMARK(SP);
-           XPUSHs(sv_2mortal(newSVpv(HvNAME((HV*)sv), 0)));
+           XPUSHs(sv_2mortal(newSVpvn(hvname, len)));
            PUTBACK;
            call_sv((SV*)GvCV(cloner), G_SCALAR);
            SPAGAIN;
@@ -11663,12 +11642,8 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     param->proto_perl = proto_perl;
 
     /* arena roots */
-    PL_xiv_arenaroot   = NULL;
-    PL_xiv_root                = NULL;
     PL_xnv_arenaroot   = NULL;
     PL_xnv_root                = NULL;
-    PL_xrv_arenaroot   = NULL;
-    PL_xrv_root                = NULL;
     PL_xpv_arenaroot   = NULL;
     PL_xpv_root                = NULL;
     PL_xpviv_arenaroot = NULL;
@@ -11683,6 +11658,8 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_xpvhv_root      = NULL;
     PL_xpvmg_arenaroot = NULL;
     PL_xpvmg_root      = NULL;
+    PL_xpvgv_arenaroot = NULL;
+    PL_xpvgv_root      = NULL;
     PL_xpvlv_arenaroot = NULL;
     PL_xpvlv_root      = NULL;
     PL_xpvbm_arenaroot = NULL;
@@ -11702,6 +11679,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);
@@ -11712,6 +11692,8 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 
     /* create SV map for pointer relocation */
     PL_ptr_table = ptr_table_new();
+    /* and one for finding shared hash keys quickly */
+    PL_shared_hek_table = ptr_table_new();
 
     /* initialize these special pointers as early as possible */
     SvANY(&PL_sv_undef)                = NULL;
@@ -11744,7 +11726,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     /* 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;
@@ -11823,7 +11805,7 @@ 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);
+       const I32 len = av_len((AV*)proto_perl->Iregex_padav);
        SV** regexen = AvARRAY((AV*)proto_perl->Iregex_padav);
        av_push(PL_regex_padav,
                sv_dup_inc(regexen[0],param));
@@ -12142,8 +12124,6 @@ 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 */
 
@@ -12342,6 +12322,8 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     if (!(flags & CLONEf_KEEP_PTR_TABLE)) {
         ptr_table_free(PL_ptr_table);
         PL_ptr_table = NULL;
+        ptr_table_free(PL_shared_hek_table);
+        PL_shared_hek_table = NULL;
     }
 
     /* Call the ->CLONE method, if it exists, for each of the stashes
@@ -12355,7 +12337,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
            ENTER;
            SAVETMPS;
            PUSHMARK(SP);
-           XPUSHs(sv_2mortal(newSVpv(HvNAME(stash), 0)));
+           XPUSHs(sv_2mortal(newSVpvn(HvNAME_get(stash), HvNAMELEN_get(stash))));
            PUTBACK;
            call_sv((SV*)GvCV(cloner), G_DISCARD);
            FREETMPS;
@@ -12365,6 +12347,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;
 }
 
@@ -12489,5 +12477,5 @@ Perl_sv_cat_decode(pTHX_ SV *dsv, SV *encoding,
  * indent-tabs-mode: t
  * End:
  *
- * vim: shiftwidth=4:
-*/
+ * ex: set ts=8 sts=4 sw=4 noet:
+ */