const and static for the const static private table.
[p5sagit/p5-mst-13.2.git] / sv.c
diff --git a/sv.c b/sv.c
index 286b2e1..e7355b7 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -1215,75 +1215,86 @@ S_new_body(pTHX_ size_t size, svtype sv_type)
 /* The following 2 arrays hide the above details in a pair of
    lookup-tables, allowing us to be body-type agnostic.
 
-   sizeof_body_by_svtype[] maps svtype to its body's allocated size.
-   offset_by_type[] maps svtype to the body-pointer adjustment needed
+   size maps svtype to its body's allocated size.
+   offset maps svtype to the body-pointer adjustment needed
 
    NB: elements in latter are 0 or <0, and are added during
    allocation, and subtracted during deallocation.  It may be clearer
    to invert the values, and call it shrinkage_by_svtype.
 */
 
-static int sizeof_body_by_svtype[] = {
-    0, /* SVt_NULLs, SVt_IVs, SVt_NVs, SVt_RVs have no body */
-    0,
-    sizeof(xpv_allocated),     /* 8 bytes on 686 */
-    0,
-    sizeof(xpv_allocated),     /* 8 bytes on 686 */
-    sizeof(xpviv_allocated),   /* 12 */
-    sizeof(XPVNV),             /* 20 */
-    sizeof(XPVMG),             /* 28 */
-    sizeof(XPVBM),             /* 36 */
-    sizeof(XPVGV),             /* 48 */
-    sizeof(XPVLV),             /* 64 */
-    sizeof(xpvav_allocated),   /* 20 */
-    sizeof(xpvhv_allocated),   /* 20 */
-    sizeof(XPVCV),             /* 76 */
-    sizeof(XPVFM),             /* 80 */
-    sizeof(XPVIO)              /* 84 */
+struct body_details {
+    size_t size;       /* Size to allocate  */
+    size_t copy;       /* Size of structure to copy (may be shorter)  */
+    int offset;
+    bool cant_upgrade; /* Can upgrade this type */
+    bool zero_nv;      /* zero the NV when upgrading from this */
 };
-#define SIZE_SVTYPES sizeof(sizeof_body_by_svtype)
-
-static int offset_by_svtype[] = {
-    0,
-    0,
-    0,
-    0,
-    STRUCT_OFFSET(xpv_allocated,   xpv_cur) - STRUCT_OFFSET(XPV,   xpv_cur),
-    STRUCT_OFFSET(xpviv_allocated, xpv_cur) - STRUCT_OFFSET(XPVIV, xpv_cur),
-    0,
-    0,
-    0,
-    0,
-    0,
-    STRUCT_OFFSET(xpvav_allocated, xav_fill) - STRUCT_OFFSET(XPVAV, xav_fill),
-    STRUCT_OFFSET(xpvhv_allocated, xhv_fill) - STRUCT_OFFSET(XPVHV, xhv_fill),
-    0,
-    0,
-    0,
-};
-#define SIZE_OFFSETS sizeof(sizeof_body_by_svtype)
-
-/* they better stay synchronized, but this doesnt do it.
-   #if SIZE_SVTYPES != SIZE_OFFSETS
-   #error "declaration problem: sizeof_body_by_svtype != sizeof(offset_by_svtype)"
-   #endif
-*/
 
+static const struct body_details bodies_by_type[] = {
+    {0, 0, 0, FALSE, TRUE},
+    /* IVs are in the head, so the allocation size is 0  */
+    {0, sizeof(IV), -STRUCT_OFFSET(XPVIV, xiv_iv), FALSE, TRUE},
+    /* 8 bytes on most ILP32 with IEEE doubles */
+    {sizeof(NV), sizeof(NV), 0, FALSE, FALSE},
+    /* RVs are in the head now */
+    {0, 0, 0, FALSE, TRUE},
+    /* 8 bytes on most ILP32 with IEEE doubles */
+    {sizeof(xpv_allocated),
+     STRUCT_OFFSET(XPV, xpv_len) + sizeof (((XPV*)SvANY((SV*)0))->xpv_len)
+     + STRUCT_OFFSET(xpv_allocated, xpv_cur) - STRUCT_OFFSET(XPV, xpv_cur),
+     + STRUCT_OFFSET(xpv_allocated, xpv_cur) - STRUCT_OFFSET(XPV, xpv_cur)
+     , FALSE, TRUE},
+    /* 12 */
+    {sizeof(xpviv_allocated),
+     STRUCT_OFFSET(XPVIV, xiv_u) + sizeof (((XPVIV*)SvANY((SV*)0))->xiv_u)
+     + STRUCT_OFFSET(xpviv_allocated, xpv_cur) - STRUCT_OFFSET(XPVIV, xpv_cur),
+     + STRUCT_OFFSET(xpviv_allocated, xpv_cur) - STRUCT_OFFSET(XPVIV, xpv_cur)
+    , FALSE, TRUE},
+    /* 20 */
+    {sizeof(XPVNV),
+     STRUCT_OFFSET(XPVNV, xiv_u) + sizeof (((XPVNV*)SvANY((SV*)0))->xiv_u),
+     0, FALSE, FALSE},
+    /* 28 */
+    {sizeof(XPVMG),
+     STRUCT_OFFSET(XPVMG, xmg_stash) + sizeof (((XPVMG*)SvANY((SV*)0))->xmg_stash),
+     0, FALSE, FALSE},
+    /* 36 */
+    {sizeof(XPVBM), 0, 0, TRUE, FALSE},
+    /* 48 */
+    {sizeof(XPVGV), 0, 0, TRUE, FALSE},
+    /* 64 */
+    {sizeof(XPVLV), 0, 0, TRUE, FALSE},
+    /* 20 */
+    {sizeof(xpvav_allocated), 0,
+     STRUCT_OFFSET(xpvav_allocated, xav_fill)
+     - STRUCT_OFFSET(XPVAV, xav_fill), TRUE, FALSE},
+    /* 20 */
+    {sizeof(xpvhv_allocated), 0, 
+     STRUCT_OFFSET(xpvhv_allocated, xhv_fill)
+     - STRUCT_OFFSET(XPVHV, xhv_fill), TRUE, FALSE},
+    /* 76 */
+    {sizeof(XPVCV), 0, 0, TRUE, FALSE},
+    /* 80 */
+    {sizeof(XPVFM), 0, 0, TRUE, FALSE},
+    /* 84 */
+    {sizeof(XPVIO), 0, 0, TRUE, FALSE}
+};
 
 #define new_body_type(sv_type)                 \
-    (void *)((char *)S_new_body(aTHX_ sizeof_body_by_svtype[sv_type], sv_type)\
-            + offset_by_svtype[sv_type])
+    (void *)((char *)S_new_body(aTHX_ bodies_by_type[sv_type].size, sv_type)\
+            + bodies_by_type[sv_type].offset)
 
 #define del_body_type(p, sv_type)      \
     del_body(p, &PL_body_roots[sv_type])
 
 
 #define new_body_allocated(sv_type)            \
-    (void *)((char *)S_new_body(aTHX_ sizeof_body_by_svtype[sv_type], sv_type)\
-            + offset_by_svtype[sv_type])
+    (void *)((char *)S_new_body(aTHX_ bodies_by_type[sv_type].size, sv_type)\
+            + bodies_by_type[sv_type].offset)
 
 #define del_body_allocated(p, sv_type)         \
-    del_body(p - offset_by_svtype[sv_type], &PL_body_roots[sv_type])
+    del_body(p - bodies_by_type[sv_type].offset, &PL_body_roots[sv_type])
 
 
 #define my_safemalloc(s)       (void*)safemalloc(s)
@@ -1381,40 +1392,31 @@ You generally want to use the C<SvUPGRADE> macro wrapper. See also C<svtype>.
 */
 
 void
-Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
+Perl_sv_upgrade(pTHX_ register SV *sv, U32 new_type)
 {
-    void**     old_body_arena;
-    size_t     old_body_offset;
-    size_t     old_body_length;        /* Well, the length to copy.  */
     void*      old_body;
-#ifndef NV_ZERO_IS_ALLBITS_ZERO
-    /* If NV 0.0 is store as all bits 0 then Zero() already creates a correct
-       0.0 for us.  */
-    bool       zero_nv = TRUE;
-#endif
     void*      new_body;
     size_t     new_body_length;
     size_t     new_body_offset;
     void**     new_body_arena;
     void**     new_body_arenaroot;
     const U32  old_type = SvTYPE(sv);
+    const struct body_details *const old_type_details
+       = bodies_by_type + old_type;
 
-    if (mt != SVt_PV && SvIsCOW(sv)) {
+    if (new_type != SVt_PV && SvIsCOW(sv)) {
        sv_force_normal_flags(sv, 0);
     }
 
-    if (old_type == mt)
+    if (old_type == new_type)
        return;
 
-    if (old_type > mt)
+    if (old_type > new_type)
        Perl_croak(aTHX_ "sv_upgrade from type %d down to type %d",
-               (int)old_type, (int)mt);
+               (int)old_type, (int)new_type);
 
 
     old_body = SvANY(sv);
-    old_body_arena = 0;
-    old_body_offset = 0;
-    old_body_length = 0;
     new_body_offset = 0;
     new_body_length = ~0;
 
@@ -1458,49 +1460,25 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
     case SVt_NULL:
        break;
     case SVt_IV:
-       if (mt == SVt_NV)
-           mt = SVt_PVNV;
-       else if (mt < SVt_PVIV)
-           mt = SVt_PVIV;
-       old_body_offset = STRUCT_OFFSET(XPVIV, xiv_iv);
-       old_body_length = sizeof(IV);
+       if (new_type == SVt_NV)
+           new_type = SVt_PVNV;
+       else if (new_type < SVt_PVIV)
+           new_type = SVt_PVIV;
        break;
     case SVt_NV:
-       old_body_arena = &PL_body_roots[SVt_NV];
-       old_body_length = sizeof(NV);
-#ifndef NV_ZERO_IS_ALLBITS_ZERO
-       zero_nv = FALSE;
-#endif
-       if (mt < SVt_PVNV)
-           mt = SVt_PVNV;
+       if (new_type < SVt_PVNV)
+           new_type = SVt_PVNV;
        break;
     case SVt_RV:
        break;
     case SVt_PV:
-       old_body_arena = &PL_body_roots[SVt_PV];
-       old_body_offset = - offset_by_svtype[SVt_PVIV];
-       old_body_length = STRUCT_OFFSET(XPV, xpv_len)
-           + sizeof (((XPV*)SvANY(sv))->xpv_len)
-           - old_body_offset;
-       if (mt <= SVt_IV)
-           mt = SVt_PVIV;
-       else if (mt == SVt_NV)
-           mt = SVt_PVNV;
+       assert(new_type > SVt_PV);
+       assert(SVt_IV < SVt_PV);
+       assert(SVt_NV < SVt_PV);
        break;
     case SVt_PVIV:
-       old_body_arena = &PL_body_roots[SVt_PVIV];
-       old_body_offset = - offset_by_svtype[SVt_PVIV];
-       old_body_length = STRUCT_OFFSET(XPVIV, xiv_u);
-       old_body_length += sizeof (((XPVIV*)SvANY(sv))->xiv_u);
-       old_body_length -= old_body_offset;
        break;
     case SVt_PVNV:
-       old_body_arena = &PL_body_roots[SVt_PVNV];
-       old_body_length = STRUCT_OFFSET(XPVNV, xiv_u)
-           + sizeof (((XPVNV*)SvANY(sv))->xiv_u);
-#ifndef NV_ZERO_IS_ALLBITS_ZERO
-       zero_nv = FALSE;
-#endif
        break;
     case SVt_PVMG:
        /* Because the XPVMG of PL_mess_sv isn't allocated from the arena,
@@ -1511,21 +1489,16 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
           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);
-       old_body_arena = &PL_body_roots[SVt_PVMG];
-       old_body_length = STRUCT_OFFSET(XPVMG, xmg_stash)
-           + sizeof (((XPVMG*)SvANY(sv))->xmg_stash);
-#ifndef NV_ZERO_IS_ALLBITS_ZERO
-       zero_nv = FALSE;
-#endif
        break;
     default:
-       Perl_croak(aTHX_ "Can't upgrade that kind of scalar");
+       if (old_type_details->cant_upgrade)
+           Perl_croak(aTHX_ "Can't upgrade that kind of scalar");
     }
 
     SvFLAGS(sv) &= ~SVTYPEMASK;
-    SvFLAGS(sv) |= mt;
+    SvFLAGS(sv) |= new_type;
 
-    switch (mt) {
+    switch (new_type) {
     case SVt_NULL:
        Perl_croak(aTHX_ "Can't upgrade to undef");
     case SVt_IV:
@@ -1595,13 +1568,13 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
     case SVt_PVLV:
     case SVt_PVMG:
     case SVt_PVNV:
-       new_body_length = sizeof_body_by_svtype[mt];
-       new_body_arena = &PL_body_roots[mt];
-       new_body_arenaroot = &PL_body_arenaroots[mt];
+       new_body_length = bodies_by_type[new_type].size;
+       new_body_arena = &PL_body_roots[new_type];
+       new_body_arenaroot = &PL_body_arenaroots[new_type];
        goto new_body;
 
     case SVt_PVIV:
-       new_body_offset = - offset_by_svtype[SVt_PVIV];
+       new_body_offset = - bodies_by_type[SVt_PVIV].offset;
        new_body_length = sizeof(XPVIV) - new_body_offset;
        new_body_arena = &PL_body_roots[SVt_PVIV];
        new_body_arenaroot = &PL_body_arenaroots[SVt_PVIV];
@@ -1612,21 +1585,18 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
        SvNOK_off(sv);
        goto new_body_no_NV; 
     case SVt_PV:
-       new_body_offset = - offset_by_svtype[SVt_PV];
+       new_body_offset = - bodies_by_type[SVt_PV].offset;
        new_body_length = sizeof(XPV) - new_body_offset;
        new_body_arena = &PL_body_roots[SVt_PV];
        new_body_arenaroot = &PL_body_arenaroots[SVt_PV];
     new_body_no_NV:
        /* PV and PVIV don't have an NV slot.  */
-#ifndef NV_ZERO_IS_ALLBITS_ZERO
-       zero_nv = FALSE;
-#endif
 
     new_body:
        assert(new_body_length);
 #ifndef PURIFY
        /* This points to the start of the allocated area.  */
-       new_body_inline(new_body, new_body_arena, new_body_length, mt);
+       new_body_inline(new_body, new_body_arena, new_body_length, new_type);
 #else
        /* We always allocated the full length item with PURIFY */
        new_body_length += new_body_offset;
@@ -1639,33 +1609,35 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
        new_body = ((char *)new_body) - new_body_offset;
        SvANY(sv) = new_body;
 
-       if (old_body_length) {
-           Copy((char *)old_body + old_body_offset,
-                (char *)new_body + old_body_offset,
-                old_body_length, char);
+       if (old_type_details->copy) {
+           Copy((char *)old_body - old_type_details->offset,
+                (char *)new_body - old_type_details->offset,
+                old_type_details->copy, char);
        }
 
 #ifndef NV_ZERO_IS_ALLBITS_ZERO
-       if (zero_nv)
+    /* If NV 0.0 is store as all bits 0 then Zero() already creates a correct
+       0.0 for us.  */
+       if (old_type_details->zero_nv)
            SvNV_set(sv, 0);
 #endif
 
-       if (mt == SVt_PVIO)
+       if (new_type == SVt_PVIO)
            IoPAGE_LEN(sv)      = 60;
        if (old_type < SVt_RV)
            SvPV_set(sv, 0);
        break;
     default:
-       Perl_croak(aTHX_ "panic: sv_upgrade to unknown type %lu", mt);
+       Perl_croak(aTHX_ "panic: sv_upgrade to unknown type %lu", new_type);
     }
 
-
-    if (old_body_arena) {
+    if (old_type_details->size) {
+       /* If the old body had an allocated size, then we need to free it.  */
 #ifdef PURIFY
        my_safefree(old_body);
 #else
-       del_body((void*)((char*)old_body + old_body_offset),
-                old_body_arena);
+       del_body((void*)((char*)old_body - old_type_details->offset),
+                &PL_body_roots[old_type]);
 #endif
     }
 }
@@ -10112,7 +10084,7 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
            case SVt_PVHV:
                new_body_arena = &PL_body_roots[SVt_PVHV];
                new_body_arenaroot = &PL_body_arenaroots[SVt_PVHV];
-               new_body_offset = - offset_by_svtype[SVt_PVHV];
+               new_body_offset = - bodies_by_type[SVt_PVHV].offset;
 
                new_body_length = STRUCT_OFFSET(XPVHV, xmg_stash)
                    + sizeof (((XPVHV*)SvANY(sstr))->xmg_stash)
@@ -10121,7 +10093,7 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
            case SVt_PVAV:
                new_body_arena = &PL_body_roots[SVt_PVAV];
                new_body_arenaroot = &PL_body_arenaroots[SVt_PVAV];
-               new_body_offset =  - offset_by_svtype[SVt_PVAV];
+               new_body_offset =  - bodies_by_type[SVt_PVAV].offset;
 
                new_body_length = STRUCT_OFFSET(XPVHV, xmg_stash)
                    + sizeof (((XPVHV*)SvANY(sstr))->xmg_stash)
@@ -10136,19 +10108,19 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
            case SVt_PVLV:
            case SVt_PVMG:
            case SVt_PVNV:
-               new_body_length = sizeof_body_by_svtype[sv_type];
+               new_body_length = bodies_by_type[sv_type].size;
                new_body_arena = &PL_body_roots[sv_type];
                new_body_arenaroot = &PL_body_arenaroots[sv_type];
                goto new_body;
 
            case SVt_PVIV:
-               new_body_offset = - offset_by_svtype[SVt_PVIV];
+               new_body_offset = - bodies_by_type[SVt_PVIV].offset;
                new_body_length = sizeof(XPVIV) - new_body_offset;
                new_body_arena = &PL_body_roots[SVt_PVIV];
                new_body_arenaroot = &PL_body_arenaroots[SVt_PVIV];
                goto new_body; 
            case SVt_PV:
-               new_body_offset = - offset_by_svtype[SVt_PV];
+               new_body_offset = - bodies_by_type[SVt_PV].offset;
                new_body_length = sizeof(XPV) - new_body_offset;
                new_body_arena = &PL_body_roots[SVt_PV];
                new_body_arenaroot = &PL_body_arenaroots[SVt_PV];