This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Integrate:
authorNicholas Clark <nick@ccl4.org>
Fri, 10 Feb 2006 11:04:46 +0000 (11:04 +0000)
committerNicholas Clark <nick@ccl4.org>
Fri, 10 Feb 2006 11:04:46 +0000 (11:04 +0000)
[ 24878]
Replace all the new/del static functions with calls to a single pair
of functions that uproot/plant bodies
p4raw-link: @24878 on //depot/perl: aeb18a1e6ec30416322d12056d5c9acd228820fd

p4raw-id: //depot/maint-5.8/perl@27147
p4raw-edited: from //depot/perl@24878 'edit in' sv.c (@24877..)
p4raw-integrated: from //depot/perl@24878 'edit in' embed.fnc embed.h
proto.h (@24847..)

embed.fnc
embed.h
proto.h
sv.c

index 974a08b..eb54130 100644 (file)
--- a/embed.fnc
+++ b/embed.fnc
@@ -1230,32 +1230,6 @@ s        |SV*    |save_scalar_at |NN SV **sptr
 nsR    |char * |uiv_2buf       |NN char *buf|IV iv|UV uv|int is_uv|NN char **peob
 sR     |IV     |asIV           |NN SV* sv
 sR     |UV     |asUV           |NN SV* sv
-s      |XPVIV* |new_xiv
-s      |XPVNV* |new_xnv
-s      |XPV*   |new_xpv
-s      |XPVIV* |new_xpviv
-s      |XPVNV* |new_xpvnv
-s      |XPVCV* |new_xpvcv
-s      |XPVAV* |new_xpvav
-s      |XPVHV* |new_xpvhv
-s      |XPVMG* |new_xpvmg
-s      |XPVGV* |new_xpvgv
-s      |XPVLV* |new_xpvlv
-s      |XPVBM* |new_xpvbm
-s      |XRV*   |new_xrv
-s      |void   |del_xiv        |NN XPVIV* p
-s      |void   |del_xnv        |NN XPVNV* p
-s      |void   |del_xpv        |NN XPV* p
-s      |void   |del_xpviv      |NN XPVIV* p
-s      |void   |del_xpvnv      |NN XPVNV* p
-s      |void   |del_xpvcv      |NN XPVCV* p
-s      |void   |del_xpvav      |NN XPVAV* p
-s      |void   |del_xpvhv      |NN XPVHV* p
-s      |void   |del_xpvmg      |NN XPVMG* p
-s      |void   |del_xpvgv      |NN XPVGV* p
-s      |void   |del_xpvlv      |NN XPVLV* p
-s      |void   |del_xpvbm      |NN XPVBM* p
-s      |void   |del_xrv        |NN XRV* p
 s      |void   |sv_unglob      |NN SV* sv
 s      |void   |not_a_number   |NN SV *sv
 s      |I32    |visit          |NN SVFUNC_t f|U32 flags|U32 mask
diff --git a/embed.h b/embed.h
index 418d2fc..af33d6c 100644 (file)
--- a/embed.h
+++ b/embed.h
 #define uiv_2buf               S_uiv_2buf
 #define asIV                   S_asIV
 #define asUV                   S_asUV
-#define new_xiv                        S_new_xiv
-#define new_xnv                        S_new_xnv
-#define new_xpv                        S_new_xpv
-#define new_xpviv              S_new_xpviv
-#define new_xpvnv              S_new_xpvnv
-#define new_xpvcv              S_new_xpvcv
-#define new_xpvav              S_new_xpvav
-#define new_xpvhv              S_new_xpvhv
-#define new_xpvmg              S_new_xpvmg
-#define new_xpvgv              S_new_xpvgv
-#define new_xpvlv              S_new_xpvlv
-#define new_xpvbm              S_new_xpvbm
-#define new_xrv                        S_new_xrv
-#define del_xiv                        S_del_xiv
-#define del_xnv                        S_del_xnv
-#define del_xpv                        S_del_xpv
-#define del_xpviv              S_del_xpviv
-#define del_xpvnv              S_del_xpvnv
-#define del_xpvcv              S_del_xpvcv
-#define del_xpvav              S_del_xpvav
-#define del_xpvhv              S_del_xpvhv
-#define del_xpvmg              S_del_xpvmg
-#define del_xpvgv              S_del_xpvgv
-#define del_xpvlv              S_del_xpvlv
-#define del_xpvbm              S_del_xpvbm
-#define del_xrv                        S_del_xrv
 #define sv_unglob              S_sv_unglob
 #define not_a_number           S_not_a_number
 #define visit                  S_visit
 #define uiv_2buf               S_uiv_2buf
 #define asIV(a)                        S_asIV(aTHX_ a)
 #define asUV(a)                        S_asUV(aTHX_ a)
-#define new_xiv()              S_new_xiv(aTHX)
-#define new_xnv()              S_new_xnv(aTHX)
-#define new_xpv()              S_new_xpv(aTHX)
-#define new_xpviv()            S_new_xpviv(aTHX)
-#define new_xpvnv()            S_new_xpvnv(aTHX)
-#define new_xpvcv()            S_new_xpvcv(aTHX)
-#define new_xpvav()            S_new_xpvav(aTHX)
-#define new_xpvhv()            S_new_xpvhv(aTHX)
-#define new_xpvmg()            S_new_xpvmg(aTHX)
-#define new_xpvgv()            S_new_xpvgv(aTHX)
-#define new_xpvlv()            S_new_xpvlv(aTHX)
-#define new_xpvbm()            S_new_xpvbm(aTHX)
-#define new_xrv()              S_new_xrv(aTHX)
-#define del_xiv(a)             S_del_xiv(aTHX_ a)
-#define del_xnv(a)             S_del_xnv(aTHX_ a)
-#define del_xpv(a)             S_del_xpv(aTHX_ a)
-#define del_xpviv(a)           S_del_xpviv(aTHX_ a)
-#define del_xpvnv(a)           S_del_xpvnv(aTHX_ a)
-#define del_xpvcv(a)           S_del_xpvcv(aTHX_ a)
-#define del_xpvav(a)           S_del_xpvav(aTHX_ a)
-#define del_xpvhv(a)           S_del_xpvhv(aTHX_ a)
-#define del_xpvmg(a)           S_del_xpvmg(aTHX_ a)
-#define del_xpvgv(a)           S_del_xpvgv(aTHX_ a)
-#define del_xpvlv(a)           S_del_xpvlv(aTHX_ a)
-#define del_xpvbm(a)           S_del_xpvbm(aTHX_ a)
-#define del_xrv(a)             S_del_xrv(aTHX_ a)
 #define sv_unglob(a)           S_sv_unglob(aTHX_ a)
 #define not_a_number(a)                S_not_a_number(aTHX_ a)
 #define visit(a,b,c)           S_visit(aTHX_ a,b,c)
diff --git a/proto.h b/proto.h
index 19a97cb..8396fed 100644 (file)
--- a/proto.h
+++ b/proto.h
@@ -1832,32 +1832,6 @@ STATIC IV        S_asIV(pTHX_ SV* sv)
 STATIC UV      S_asUV(pTHX_ SV* sv)
                        __attribute__warn_unused_result__;
 
-STATIC XPVIV*  S_new_xiv(pTHX);
-STATIC XPVNV*  S_new_xnv(pTHX);
-STATIC XPV*    S_new_xpv(pTHX);
-STATIC XPVIV*  S_new_xpviv(pTHX);
-STATIC XPVNV*  S_new_xpvnv(pTHX);
-STATIC XPVCV*  S_new_xpvcv(pTHX);
-STATIC XPVAV*  S_new_xpvav(pTHX);
-STATIC XPVHV*  S_new_xpvhv(pTHX);
-STATIC XPVMG*  S_new_xpvmg(pTHX);
-STATIC XPVGV*  S_new_xpvgv(pTHX);
-STATIC XPVLV*  S_new_xpvlv(pTHX);
-STATIC XPVBM*  S_new_xpvbm(pTHX);
-STATIC XRV*    S_new_xrv(pTHX);
-STATIC void    S_del_xiv(pTHX_ XPVIV* p);
-STATIC void    S_del_xnv(pTHX_ XPVNV* p);
-STATIC void    S_del_xpv(pTHX_ XPV* p);
-STATIC void    S_del_xpviv(pTHX_ XPVIV* p);
-STATIC void    S_del_xpvnv(pTHX_ XPVNV* p);
-STATIC void    S_del_xpvcv(pTHX_ XPVCV* p);
-STATIC void    S_del_xpvav(pTHX_ XPVAV* p);
-STATIC void    S_del_xpvhv(pTHX_ XPVHV* p);
-STATIC void    S_del_xpvmg(pTHX_ XPVMG* p);
-STATIC void    S_del_xpvgv(pTHX_ XPVGV* p);
-STATIC void    S_del_xpvlv(pTHX_ XPVLV* p);
-STATIC void    S_del_xpvbm(pTHX_ XPVBM* p);
-STATIC void    S_del_xrv(pTHX_ XRV* p);
 STATIC void    S_sv_unglob(pTHX_ SV* sv);
 STATIC void    S_not_a_number(pTHX_ SV *sv);
 STATIC I32     S_visit(pTHX_ SVFUNC_t f, U32 flags, U32 mask);
diff --git a/sv.c b/sv.c
index 8487f60..8314a81 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -660,7 +660,6 @@ Perl_report_uninit(pTHX)
     else
        Perl_warner(aTHX_ packWARN(WARN_UNINITIALIZED), PL_warn_uninit, "", "");
 }
-/* allocate another arena's worth of struct xrv */
 
 STATIC void *
 S_more_bodies (pTHX_ void **arena_root, void **root, size_t size)
@@ -691,362 +690,82 @@ S_more_bodies (pTHX_ void **arena_root, void **root, size_t size)
     return *root;
 }
 
-#define more_thingy(TYPE,lctype)                               \
-    S_more_bodies(aTHX_ (void**)&PL_## lctype ## _arenaroot,   \
-                 (void**)&PL_ ## lctype ## _root,              \
-                 sizeof(TYPE))
+/* grab a new thing from the free list, allocating more if necessary */
 
-#define more_thingy_allocated(lctype)                          \
-    S_more_bodies(aTHX_ (void**)&PL_## lctype ## _arenaroot,   \
-                 (void**)&PL_ ## lctype ## _root,              \
-                 sizeof(lctype ## _allocated))
-
-
-#define more_xiv()     more_thingy_allocated(xiv)
-#define more_xrv()     more_thingy(XRV, xrv)
-#define more_xnv()     more_thingy_allocated(xnv)
-#define more_xpv()     more_thingy_allocated(xpv)
-#define more_xpviv()   more_thingy_allocated(xpviv)
-#define more_xpvnv()   more_thingy(XPVNV, xpvnv)
-#define more_xpvcv()   more_thingy(XPVCV, xpvcv)
-#define more_xpvav()   more_thingy_allocated(xpvav)
-#define more_xpvhv()   more_thingy_allocated(xpvhv)
-#define more_xpvgv()   more_thingy(XPVGV, xpvgv)
-#define more_xpvmg()   more_thingy(XPVMG, xpvmg)
-#define more_xpvbm()   more_thingy(XPVBM, xpvbm)
-#define more_xpvlv()   more_thingy(XPVLV, xpvlv)
-
-
-/* grab a new struct xrv from the free list, allocating more if necessary */
-
-STATIC XRV*
-S_new_xrv(pTHX)
-{
-    XRV* xrv;
-    LOCK_SV_MUTEX;
-    xrv = PL_xrv_root ? PL_xrv_root : more_xrv();
-    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)
-{
-    xiv_allocated* xiv;
-    LOCK_SV_MUTEX;
-    xiv = PL_xiv_root ? PL_xiv_root : more_xiv();
-    PL_xiv_root = *(xiv_allocated**)xiv;
-    UNLOCK_SV_MUTEX;
-    return (XPVIV*)((char*)xiv - STRUCT_OFFSET(XPVIV, xiv_iv));
-}
-
-/* return an IV body to the free list */
-
-STATIC void
-S_del_xiv(pTHX_ XPVIV *p)
-{
-    xiv_allocated * xiv = (xiv_allocated*)((char*)(p) + STRUCT_OFFSET(XPVIV, xiv_iv));
-    LOCK_SV_MUTEX;
-    *(xiv_allocated**)xiv = PL_xiv_root;
-    PL_xiv_root = xiv;
-    UNLOCK_SV_MUTEX;
-}
-
-/* grab a new NV body from the free list, allocating more if necessary */
-
-STATIC XPVNV*
-S_new_xnv(pTHX)
-{
-    xnv_allocated* xnv;
-    LOCK_SV_MUTEX;
-    xnv = PL_xnv_root ? PL_xnv_root : more_xnv();
-    PL_xnv_root = *(xnv_allocated **)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)
-{
-    xnv_allocated * xnv = (xnv_allocated*)((char*)(p) + STRUCT_OFFSET(XPVNV, xnv_nv));
-    LOCK_SV_MUTEX;
-    *(xnv_allocated**)xnv = PL_xnv_root;
-    PL_xnv_root = xnv;
-    UNLOCK_SV_MUTEX;
-}
-
-/* grab a new struct xpv from the free list, allocating more if necessary */
-
-STATIC XPV*
-S_new_xpv(pTHX)
-{
-    xpv_allocated* xpv;
-    LOCK_SV_MUTEX;
-    xpv = PL_xpv_root ? PL_xpv_root : more_xpv();
-    PL_xpv_root = *(xpv_allocated**)xpv;
-    UNLOCK_SV_MUTEX;
-    /* 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 */
-
-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;
-    *(xpv_allocated**)xpv = PL_xpv_root;
-    PL_xpv_root = xpv;
-    UNLOCK_SV_MUTEX;
-}
-
-/* grab a new struct xpviv from the free list, allocating more if necessary */
-
-STATIC XPVIV*
-S_new_xpviv(pTHX)
-{
-    XPVIV* xpviv;
-    LOCK_SV_MUTEX;
-    xpviv = PL_xpviv_root ? PL_xpviv_root : more_xpviv();
-    PL_xpviv_root = (XPVIV*)xpviv->xpv_pv;
-    UNLOCK_SV_MUTEX;
-    return xpviv;
-}
-
-/* return a struct xpviv to the free list */
-
-STATIC void
-S_del_xpviv(pTHX_ XPVIV *p)
-{
-    LOCK_SV_MUTEX;
-    p->xpv_pv = (char*)PL_xpviv_root;
-    PL_xpviv_root = p;
-    UNLOCK_SV_MUTEX;
-}
-
-/* grab a new struct xpvnv from the free list, allocating more if necessary */
-
-STATIC XPVNV*
-S_new_xpvnv(pTHX)
-{
-    XPVNV* xpvnv;
-    LOCK_SV_MUTEX;
-    xpvnv = PL_xpvnv_root ? PL_xpvnv_root : more_xpvnv();
-    PL_xpvnv_root = (XPVNV*)xpvnv->xpv_pv;
-    UNLOCK_SV_MUTEX;
-    return xpvnv;
-}
-
-/* return a struct xpvnv to the free list */
-
-STATIC void
-S_del_xpvnv(pTHX_ XPVNV *p)
-{
-    LOCK_SV_MUTEX;
-    p->xpv_pv = (char*)PL_xpvnv_root;
-    PL_xpvnv_root = p;
-    UNLOCK_SV_MUTEX;
-}
-
-/* grab a new struct xpvcv from the free list, allocating more if necessary */
-
-STATIC XPVCV*
-S_new_xpvcv(pTHX)
-{
-    XPVCV* xpvcv;
-    LOCK_SV_MUTEX;
-    xpvcv = PL_xpvcv_root ? PL_xpvcv_root : more_xpvcv();
-    PL_xpvcv_root = (XPVCV*)xpvcv->xpv_pv;
-    UNLOCK_SV_MUTEX;
-    return xpvcv;
-}
-
-/* return a struct xpvcv to the free list */
-
-STATIC void
-S_del_xpvcv(pTHX_ XPVCV *p)
-{
-    LOCK_SV_MUTEX;
-    p->xpv_pv = (char*)PL_xpvcv_root;
-    PL_xpvcv_root = p;
-    UNLOCK_SV_MUTEX;
-}
-
-/* grab a new struct xpvav from the free list, allocating more if necessary */
-
-STATIC XPVAV*
-S_new_xpvav(pTHX)
-{
-    xpvav_allocated* xpvav;
-    LOCK_SV_MUTEX;
-    xpvav = PL_xpvav_root ? PL_xpvav_root : more_xpvav();
-    PL_xpvav_root = *(xpvav_allocated**)xpvav;
-    UNLOCK_SV_MUTEX;
-    return (XPVAV*)((char*)xpvav - STRUCT_OFFSET(XPVAV, xav_fill)
-                   + STRUCT_OFFSET(xpvav_allocated, xav_fill));
-}
-
-/* return a struct xpvav to the free list */
-
-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;
-    *(xpvav_allocated**)xpvav = PL_xpvav_root;
-    PL_xpvav_root = xpvav;
-    UNLOCK_SV_MUTEX;
-}
-
-/* grab a new struct xpvhv from the free list, allocating more if necessary */
-
-STATIC XPVHV*
-S_new_xpvhv(pTHX)
-{
-    xpvhv_allocated* xpvhv;
-    LOCK_SV_MUTEX;
-    xpvhv = PL_xpvhv_root ? PL_xpvhv_root : more_xpvhv();
-    PL_xpvhv_root = *(xpvhv_allocated**)xpvhv;
-    UNLOCK_SV_MUTEX;
-    return (XPVHV*)((char*)xpvhv - STRUCT_OFFSET(XPVHV, xhv_fill)
-                   + STRUCT_OFFSET(xpvhv_allocated, xhv_fill));
-}
-
-/* return a struct xpvhv to the free list */
-
-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;
-    *(xpvhv_allocated**)xpvhv = PL_xpvhv_root;
-    PL_xpvhv_root = xpvhv;
-    UNLOCK_SV_MUTEX;
-}
-
-/* grab a new struct xpvmg from the free list, allocating more if necessary */
-
-STATIC XPVMG*
-S_new_xpvmg(pTHX)
-{
-    XPVMG* xpvmg;
-    LOCK_SV_MUTEX;
-    xpvmg = PL_xpvmg_root ? PL_xpvmg_root : more_xpvmg();
-    PL_xpvmg_root = (XPVMG*)xpvmg->xpv_pv;
-    UNLOCK_SV_MUTEX;
-    return xpvmg;
-}
-
-/* return a struct xpvmg to the free list */
-
-STATIC void
-S_del_xpvmg(pTHX_ XPVMG *p)
-{
-    LOCK_SV_MUTEX;
-    p->xpv_pv = (char*)PL_xpvmg_root;
-    PL_xpvmg_root = p;
-    UNLOCK_SV_MUTEX;
-}
-
-/* grab a new struct xpvgv from the free list, allocating more if necessary */
-
-STATIC XPVGV*
-S_new_xpvgv(pTHX)
-{
-    XPVGV* xpvgv;
-    LOCK_SV_MUTEX;
-    xpvgv = PL_xpvgv_root ? PL_xpvgv_root : more_xpvgv();
-    PL_xpvgv_root = (XPVGV*)xpvgv->xpv_pv;
-    UNLOCK_SV_MUTEX;
-    return xpvgv;
-}
-
-/* return a struct xpvgv to the free list */
-
-STATIC void
-S_del_xpvgv(pTHX_ XPVGV *p)
-{
-    LOCK_SV_MUTEX;
-    p->xpv_pv = (char*)PL_xpvgv_root;
-    PL_xpvgv_root = p;
-    UNLOCK_SV_MUTEX;
-}
-
-/* grab a new struct xpvlv from the free list, allocating more if necessary */
-
-STATIC XPVLV*
-S_new_xpvlv(pTHX)
+STATIC void *
+S_new_body(pTHX_ void **arena_root, void **root, size_t size, size_t offset)
 {
-    XPVLV* xpvlv;
+    void *xpv;
     LOCK_SV_MUTEX;
-    xpvlv = PL_xpvlv_root ? PL_xpvlv_root : more_xpvlv();
-    PL_xpvlv_root = (XPVLV*)xpvlv->xpv_pv;
+    xpv = *root ? *root : S_more_bodies(aTHX_ arena_root, root, size);
+    *root = *(void**)xpv;
     UNLOCK_SV_MUTEX;
-    return xpvlv;
+    return (void*)((char*)xpv - offset);
 }
 
-/* return a struct xpvlv to the free list */
+/* return a thing to the free list */
 
 STATIC void
-S_del_xpvlv(pTHX_ XPVLV *p)
+S_del_body(pTHX_ void *thing, void **root, size_t offset)
 {
+    void **real_thing = (void**)((char *)thing + offset);
     LOCK_SV_MUTEX;
-    p->xpv_pv = (char*)PL_xpvlv_root;
-    PL_xpvlv_root = p;
+    *real_thing = *root;
+    *root = (void*)real_thing;
     UNLOCK_SV_MUTEX;
 }
 
-/* grab a new struct xpvbm from the free list, allocating more if necessary */
+/* Conventionally we simply malloc() a big block of memory, then divide it
+   up into lots of the thing that we're allocating.
 
-STATIC XPVBM*
-S_new_xpvbm(pTHX)
-{
-    XPVBM* xpvbm;
-    LOCK_SV_MUTEX;
-    xpvbm = PL_xpvbm_root ? PL_xpvbm_root : more_xpvbm();
-    PL_xpvbm_root = (XPVBM*)xpvbm->xpv_pv;
-    UNLOCK_SV_MUTEX;
-    return xpvbm;
-}
+   This macro will expand to call to S_new_body. So for XPVBM (with ithreads),
+   it would become
 
-/* return a struct xpvbm to the free list */
+   S_new_body(my_perl, (void**)&(my_perl->Ixpvbm_arenaroot),
+             (void**)&(my_perl->Ixpvbm_root), sizeof(XPVBM), 0)
+*/
 
-STATIC void
-S_del_xpvbm(pTHX_ XPVBM *p)
-{
-    LOCK_SV_MUTEX;
-    p->xpv_pv = (char*)PL_xpvbm_root;
-    PL_xpvbm_root = p;
-    UNLOCK_SV_MUTEX;
-}
+#define new_body(TYPE,lctype)                                          \
+    S_new_body(aTHX_ (void**)&PL_ ## lctype ## _arenaroot,             \
+                (void**)&PL_ ## lctype ## _root,                       \
+                sizeof(TYPE),                                          \
+                0)
+
+/* But for some types, we cheat. The type starts with some members that are
+   never accessed. So we allocate the substructure, starting at the first used
+   member, then adjust the pointer back in memory by the size of the bit not
+   allocated, so it's as if we allocated the full structure.
+   (But things will all go boom if you write to the part that is "not there",
+   because you'll be overwriting the last members of the preceding structure
+   in memory.)
+
+   We calculate the correction using the STRUCT_OFFSET macro. For example, 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 NV actually allocated) then the net effect is to subtract the size
+   of the NV from the pointer, to return a new pointer as if an initial NV were
+   actually allocated.
+
+   This is the same trick as was used for NV and IV bodies. Ironically it
+   doesn't need to be used for NV bodies any more, because NV is now at the
+   start of the structure. IV bodies don't need it either, because they are
+   no longer allocated.  */
+
+#define new_body_allocated(TYPE,lctype,member)                         \
+    S_new_body(aTHX_ (void**)&PL_ ## lctype ## _arenaroot,             \
+              (void**)&PL_ ## lctype ## _root,                         \
+              sizeof(lctype ## _allocated),                            \
+              STRUCT_OFFSET(TYPE, member)                              \
+              - STRUCT_OFFSET(lctype ## _allocated, member))
+
+
+#define del_body(p,TYPE,lctype)                                                \
+    S_del_body(aTHX_ (void*)p, (void**)&PL_ ## lctype ## _root, 0)
+
+#define del_body_allocated(p,TYPE,lctype,member)                       \
+    S_del_body(aTHX_ (void*)p, (void**)&PL_ ## lctype ## _root,                \
+              STRUCT_OFFSET(TYPE, member)                              \
+              - STRUCT_OFFSET(lctype ## _allocated, member))
 
 #define my_safemalloc(s)       (void*)safemalloc(s)
 #define my_safefree(p) safefree((char*)p)
@@ -1094,44 +813,47 @@ S_del_xpvbm(pTHX_ XPVBM *p)
 
 #else /* !PURIFY */
 
-#define new_XIV()      (void*)new_xiv()
-#define del_XIV(p)     del_xiv((XPVIV*) p)
+typedef struct xpviv XIV;
+typedef struct xpvnv XNV;
+
+#define new_XIV()      new_body_allocated(XIV, xiv, xiv_iv)
+#define del_XIV(p)     del_body_allocated(p, XIV, xiv, xiv_iv)
 
-#define new_XNV()      (void*)new_xnv()
-#define del_XNV(p)     del_xnv((XPVNV*) p)
+#define new_XNV()      new_body_allocated(XNV, xnv, xnv_nv)
+#define del_XNV(p)     del_body_allocated(p, XNV, xnv, xnv_nv)
 
-#define new_XRV()      (void*)new_xrv()
-#define del_XRV(p)     del_xrv((XRV*) p)
+#define new_XRV()      new_body(XRV, xrv)
+#define del_XRV(p)     del_body(p, XRV, xrv)
 
-#define new_XPV()      (void*)new_xpv()
-#define del_XPV(p)     del_xpv((XPV *)p)
+#define new_XPV()      new_body_allocated(XPV, xpv, xpv_cur)
+#define del_XPV(p)     del_body_allocated(p, XPV, xpv, xpv_cur)
 
-#define new_XPVIV()    (void*)new_xpviv()
-#define del_XPVIV(p)   del_xpviv((XPVIV *)p)
+#define new_XPVIV()    new_body_allocated(XPVIV, xpviv, xpv_cur)
+#define del_XPVIV(p)   del_body_allocated(p, XPVIV, xpviv, xpv_cur)
 
-#define new_XPVNV()    (void*)new_xpvnv()
-#define del_XPVNV(p)   del_xpvnv((XPVNV *)p)
+#define new_XPVNV()    new_body(XPVNV, xpvnv)
+#define del_XPVNV(p)   del_body(p, XPVNV, xpvnv)
 
-#define new_XPVCV()    (void*)new_xpvcv()
-#define del_XPVCV(p)   del_xpvcv((XPVCV *)p)
+#define new_XPVCV()    new_body(XPVCV, xpvcv)
+#define del_XPVCV(p)   del_body(p, XPVCV, xpvcv)
 
-#define new_XPVAV()    (void*)new_xpvav()
-#define del_XPVAV(p)   del_xpvav((XPVAV *)p)
+#define new_XPVAV()    new_body_allocated(XPVAV, xpvav, xav_fill)
+#define del_XPVAV(p)   del_body_allocated(p, XPVAV, xpvav, xav_fill)
 
-#define new_XPVHV()    (void*)new_xpvhv()
-#define del_XPVHV(p)   del_xpvhv((XPVHV *)p)
+#define new_XPVHV()    new_body_allocated(XPVHV, xpvhv, xhv_fill)
+#define del_XPVHV(p)   del_body_allocated(p, XPVHV, xpvhv, xhv_fill)
 
-#define new_XPVMG()    (void*)new_xpvmg()
-#define del_XPVMG(p)   del_xpvmg((XPVMG *)p)
+#define new_XPVMG()    new_body(XPVMG, xpvmg)
+#define del_XPVMG(p)   del_body(p, XPVMG, xpvmg)
 
-#define new_XPVGV()    (void*)new_xpvgv()
-#define del_XPVGV(p)   del_xpvgv((XPVGV *)p)
+#define new_XPVGV()    new_body(XPVGV, xpvgv)
+#define del_XPVGV(p)   del_body(p, XPVGV, xpvgv)
 
-#define new_XPVLV()    (void*)new_xpvlv()
-#define del_XPVLV(p)   del_xpvlv((XPVLV *)p)
+#define new_XPVLV()    new_body(XPVLV, xpvlv)
+#define del_XPVLV(p)   del_body(p, XPVLV, xpvlv)
 
-#define new_XPVBM()    (void*)new_xpvbm()
-#define del_XPVBM(p)   del_xpvbm((XPVBM *)p)
+#define new_XPVBM()    new_body(XPVBM, xpvbm)
+#define del_XPVBM(p)   del_body(p, XPVBM, xpvbm)
 
 #endif /* PURIFY */