of the unused body-slots for PTEs, then use it in those (2) PTE
contexts below (line ~10k)
*/
-#define PTE_SVSLOT SVt_IV
STATIC void *
S_more_bodies (pTHX_ size_t size, svtype sv_type)
/* now use the inline version in the proper function */
+#ifndef PURIFY
+
+/* This isn't being used with -DPURIFY, so don't declare it. Otherwise
+ compilers issue warnings. */
+
STATIC void *
S_new_body(pTHX_ size_t size, svtype sv_type)
{
return xpv;
}
+#endif
+
/* return a thing to the free list */
#define del_body(thing, root) \
/* 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 */
-};
-#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,
+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_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)
*/
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 (SvTYPE(sv) == mt)
+ if (old_type == new_type)
return;
- if (SvTYPE(sv) > mt)
+ if (old_type > new_type)
Perl_croak(aTHX_ "sv_upgrade from type %d down to type %d",
- (int)SvTYPE(sv), (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;
So we are careful and work out the size of used parts of all the
structures. */
- switch (SvTYPE(sv)) {
+ switch (old_type) {
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,
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:
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];
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;
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
}
}
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)
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)
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];