This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Make immortal SVs contiguous
authorDavid Mitchell <davem@iabyn.com>
Wed, 12 Jul 2017 13:07:16 +0000 (14:07 +0100)
committerDavid Mitchell <davem@iabyn.com>
Thu, 27 Jul 2017 10:30:22 +0000 (11:30 +0100)
Ensure that PL_sv_yes, PL_sv_undef, PL_sv_no and PL_sv_zero are allocated
adjacently in memory.

This allows the SvIMMORTAL() test to be more efficient, and will (in the
next commit) allow SvTRUE() to be more efficient.

In MULTIPLICITY builds the constraint is already met by virtue of them
being adjacent items in the interpreter struct. For non-MULTIPLICITY
builds, they were just 4 global vars with no guarantees of where
they would be allocated. For this case, PL_sv_undef are deleted
as global vars and replaced with a new global var PL_sv_immortals[4],
with

    #define PL_sv_yes   (PL_sv_immortals[0])

etc in their place.

embedvar.h
intrpvar.h
makedef.pl
perl.h
sv.c
sv.h

index 4b945f2..7d284b8 100644 (file)
 #define PL_sv_arenaroot                (vTHX->Isv_arenaroot)
 #define PL_sv_consts           (vTHX->Isv_consts)
 #define PL_sv_count            (vTHX->Isv_count)
+#define PL_sv_immortals                (vTHX->Isv_immortals)
 #define PL_sv_no               (vTHX->Isv_no)
 #define PL_sv_root             (vTHX->Isv_root)
 #define PL_sv_serial           (vTHX->Isv_serial)
index e1c96f7..e2468bf 100644 (file)
@@ -167,10 +167,16 @@ C<&PL_sv_zero>. Introduced in 5.28.
 =cut
 */
 
+#ifdef MULTIPLICITY
+PERLVAR(I, sv_yes,     SV)
 PERLVAR(I, sv_undef,   SV)
 PERLVAR(I, sv_no,      SV)
-PERLVAR(I, sv_yes,     SV)
 PERLVAR(I, sv_zero,    SV)
+#else
+/* store the immortals as an array to ensure they are contiguous in
+ * memory: makes SvIMMORTAL_INTERP(sv) possible */
+PERLVARA(I, sv_immortals, 4, SV)
+#endif
 
 PERLVAR(I, padname_undef,      PADNAME)
 PERLVAR(I, padname_const,      PADNAME)
index 9761954..6e9ea5f 100644 (file)
@@ -482,6 +482,10 @@ unless ($define{'MULTIPLICITY'}) {
     ++$skip{$_} foreach qw(
                    PL_interp_size
                    PL_interp_size_5_18_0
+                    PL_sv_yes
+                    PL_sv_undef
+                    PL_sv_no
+                    PL_sv_zero
                         );
 }
 
diff --git a/perl.h b/perl.h
index c09536b..09e77cf 100644 (file)
--- a/perl.h
+++ b/perl.h
@@ -5629,6 +5629,10 @@ struct tempsym; /* defined in pp_pack.c */
 START_EXTERN_C
 #  include "intrpvar.h"
 END_EXTERN_C
+#  define PL_sv_yes   (PL_sv_immortals[0])
+#  define PL_sv_undef (PL_sv_immortals[1])
+#  define PL_sv_no    (PL_sv_immortals[2])
+#  define PL_sv_zero  (PL_sv_immortals[3])
 #endif
 
 #ifdef PERL_CORE
diff --git a/sv.c b/sv.c
index 887c9e7..c17cb92 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -15931,6 +15931,26 @@ Perl_init_constants(pTHX)
     SvNV_set(&PL_sv_zero, 0);
 
     PadnamePV(&PL_padname_const) = (char *)PL_No;
+
+    assert(SvIMMORTAL_INTERP(&PL_sv_yes));
+    assert(SvIMMORTAL_INTERP(&PL_sv_undef));
+    assert(SvIMMORTAL_INTERP(&PL_sv_no));
+    assert(SvIMMORTAL_INTERP(&PL_sv_zero));
+
+    assert(SvIMMORTAL(&PL_sv_yes));
+    assert(SvIMMORTAL(&PL_sv_undef));
+    assert(SvIMMORTAL(&PL_sv_no));
+    assert(SvIMMORTAL(&PL_sv_zero));
+
+    assert( SvIMMORTAL_TRUE(&PL_sv_yes));
+    assert(!SvIMMORTAL_TRUE(&PL_sv_undef));
+    assert(!SvIMMORTAL_TRUE(&PL_sv_no));
+    assert(!SvIMMORTAL_TRUE(&PL_sv_zero));
+
+    assert( SvTRUE_nomg_NN(&PL_sv_yes));
+    assert(!SvTRUE_nomg_NN(&PL_sv_undef));
+    assert(!SvTRUE_nomg_NN(&PL_sv_no));
+    assert(!SvTRUE_nomg_NN(&PL_sv_zero));
 }
 
 /*
diff --git a/sv.h b/sv.h
index b7690c2..15b8547 100644 (file)
--- a/sv.h
+++ b/sv.h
@@ -2090,7 +2090,20 @@ properly null terminated. Equivalent to sv_setpvs(""), but more efficient.
 #define SvPEEK(sv) ""
 #endif
 
-#define SvIMMORTAL(sv) (SvREADONLY(sv) && ((sv)==&PL_sv_undef || (sv)==&PL_sv_yes || (sv)==&PL_sv_no || (sv)==&PL_sv_zero || (sv)==&PL_sv_placeholder))
+/* Is this a per-interpreter immortal SV (rather than global)?
+ * These should either occupy adjacent entries in the interpreter struct
+ * (MULTIPLICITY) or adjacent elements of PL_sv_immortals[] otherwise.
+ * The unsigned (Size_t) cast avoids the need for a second < 0 condition.
+ */
+#define SvIMMORTAL_INTERP(sv) ((Size_t)((sv) - &PL_sv_yes) < 4)
+
+/* Does this immortal have a true value? Currently only PL_sv_yes does. */
+#define SvIMMORTAL_TRUE(sv)   ((sv) == &PL_sv_yes)
+
+/* the SvREADONLY() test is to quickly reject most SVs */
+#define SvIMMORTAL(sv) \
+                (  SvREADONLY(sv) \
+                && (SvIMMORTAL_INTERP(sv) || (sv) == &PL_sv_placeholder))
 
 #ifdef DEBUGGING
    /* exercise the immortal resurrection code in sv_free2() */