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;
 }