Commit 3ba9d2634f for perl
commit 3ba9d2634f6ec3c24d1e1f762801ef04af65dc99
Author: Richard Leach <rich+perl@hyphen-dash-hyphen.info>
Date: Thu Sep 10 17:34:09 2026 +0000
Perl_newSV_type: only hot SV types are created inline
`SVt_PV` and below are handled by this function, with every other case
being passed to `Perl_newSV_type_generic`.
These types were largely selected as a result of a _gcov_ build, but it
might be that some other types should come back in. (e.g. `SVt_PVCV` for
things like _Future::AsyncAwait_?)
The function has also been microoptimized to keep its size low,
maximising the opportunities for inlining.
diff --git a/sv_inline.h b/sv_inline.h
index 5e4640cb5a..7b2656b0af 100644
--- a/sv_inline.h
+++ b/sv_inline.h
@@ -373,31 +373,50 @@ Perl_newSV_type(pTHX_ const svtype type)
{
PERL_ARGS_ASSERT_NEWSV_TYPE;
- SV *sv;
- void* new_body;
- const struct body_details *type_details;
+ /* Hot types will be handled inline. */
+ switch (type) {
+ case SVt_NULL:
+ case SVt_IV:
+ case SVt_NV:
+ case SVt_PVHV:
+ case SVt_PVAV:
+ case SVt_PVOBJ:
+ case SVt_PV:
+ break;
+ default:
+ return newSV_type_generic(type);
+ }
+ SV *sv;
new_SV(sv);
+ SvFLAGS(sv) = type;
+ assert(!SvOK(sv));
+ /* Clear the sv_u slot, regardless of what
+ * might actually be stored inside it. */
+ sv->sv_u.svu_rv = NULL;
+ void* new_body;
+ const struct body_details *type_details;
+ PERL_UNUSED_VAR(type_details);
+#if defined(PURIFY) || defined(DEBUGGING)
type_details = bodies_by_type + type;
-
- SvFLAGS(sv) &= ~SVTYPEMASK;
- SvFLAGS(sv) |= type;
+#endif
switch (type) {
case SVt_NULL:
break;
case SVt_IV:
SET_SVANY_FOR_BODYLESS_IV(sv);
- SvIV_set(sv, 0);
+ assert(SvIVX(sv) == 0);
break;
case SVt_NV:
#if NVSIZE <= IVSIZE
SET_SVANY_FOR_BODYLESS_NV(sv);
+ assert(SvNVX(sv) == 0.0);
#else
SvANY(sv) = new_XNV();
-#endif
SvNV_set(sv, 0);
+#endif
break;
case SVt_PVHV:
case SVt_PVAV:
@@ -409,7 +428,7 @@ Perl_newSV_type(pTHX_ const svtype type)
assert(type_details->arena_size);
/* This points to the start of the allocated area. */
new_body = S_new_body(aTHX_ type);
- /* xpvav and xpvhv have no offset, so no need to adjust new_body */
+ /* xpvav, xpvhv, xobject have no offset, no need to adjust new_body */
assert(!(type_details->offset));
#else
/* We always allocated the full length item with PURIFY. To do this
@@ -418,88 +437,56 @@ Perl_newSV_type(pTHX_ const svtype type)
#endif
SvANY(sv) = new_body;
- SvSTASH_set(sv, NULL);
- SvMAGIC_set(sv, NULL);
+ ((XPVMG*)new_body)->xmg_u.xmg_magic = NULL;
+ ((XPVMG*)new_body)->xmg_stash = NULL;
switch(type) {
case SVt_PVAV:
- AvFILLp(sv) = -1;
- AvMAX(sv) = -1;
- AvALLOC(sv) = NULL;
+ ((XPVAV*)new_body)->xav_fill = -1;
+ ((XPVAV*)new_body)->xav_max = -1;
+ ((XPVAV*)new_body)->xav_alloc = NULL;
- AvREAL_only(sv);
+ assert(!AvREIFY(sv));
+ AvREAL_on(sv);
+ assert(!sv->sv_u.svu_array);
break;
case SVt_PVHV:
- HvTOTALKEYS(sv) = 0;
+ ((XPVHV*)new_body)->xhv_keys = 0;
/* start with PERL_HASH_DEFAULT_HvMAX+1 buckets: */
- HvMAX(sv) = PERL_HASH_DEFAULT_HvMAX;
+ ((XPVHV*)new_body)->xhv_max = PERL_HASH_DEFAULT_HvMAX;
assert(!SvOK(sv));
- SvOK_off(sv);
#ifndef NODEFAULT_SHAREKEYS
HvSHAREKEYS_on(sv); /* key-sharing on by default */
#endif
- /* start with PERL_HASH_DEFAULT_HvMAX+1 buckets: */
- HvMAX(sv) = PERL_HASH_DEFAULT_HvMAX;
+ assert(!sv->sv_u.svu_hash);
break;
case SVt_PVOBJ:
- ObjectMAXFIELD(sv) = -1;
- ObjectFIELDS(sv) = NULL;
+ ((XPVOBJ*)new_body)->xobject_maxfield = -1;
+ assert(!sv->sv_u.svu_fields);
break;
default:
NOT_REACHED;
}
-
- sv->sv_u.svu_array = NULL; /* or svu_hash */
break;
- case SVt_PVIV:
- case SVt_PVIO:
- case SVt_PVGV:
- case SVt_PVCV:
- case SVt_PVLV:
- case SVt_INVLIST:
- case SVt_REGEXP:
- case SVt_PVMG:
- case SVt_PVNV:
case SVt_PV:
- case SVt_PVFM:
- assert(type_details->body_size);
- /* We always allocated the full length item with PURIFY. To do this
- we fake things so that arena is false for all 16 types.. */
#ifndef PURIFY
assert(type_details->arena);
assert(type_details->arena_size);
-
/* This points to the start of the allocated area. */
new_body = S_new_body(aTHX_ type);
- Zero(new_body, type_details->body_size, char);
- new_body = ((char *)new_body) - type_details->offset;
+ Zero(new_body, sizeof(XPV) - STRUCT_OFFSET(XPV, xpv_cur), char);
+ new_body = ((char *)new_body) - STRUCT_OFFSET(XPV, xpv_cur);
#else
new_body = new_NOARENAZ(type_details);
#endif
SvANY(sv) = new_body;
-
- if (UNLIKELY(type == SVt_PVIO)) {
- IO * const io = MUTABLE_IO(sv);
- GV *iogv = gv_fetchpvs("IO::File::", GV_ADD, SVt_PVHV);
-
- SvOBJECT_on(io);
- /* Clear the stashcache because a new IO could overrule a package
- name */
- DEBUG_o(deb("sv_upgrade clearing PL_stashcache\n"));
- hv_clear(PL_stashcache);
-
- SvSTASH_set(io, MUTABLE_HV(SvREFCNT_inc(GvHV(iogv))));
- IoPAGE_LEN(sv) = 60;
- }
-
- sv->sv_u.svu_rv = NULL;
+ assert(!sv->sv_u.svu_rv);
break;
default:
- croak("panic: newSV_type() unknown type %lu", (unsigned long)type);
+ NOT_REACHED;
}
-
return sv;
}