add PL_sv_zero
authorDavid Mitchell <davem@iabyn.com>
Mon, 3 Jul 2017 16:07:28 +0000 (17:07 +0100)
committerDavid Mitchell <davem@iabyn.com>
Thu, 27 Jul 2017 10:30:21 +0000 (11:30 +0100)
it's like PL_sv_no, except that its string value is "0" rather than "".
It can be used for example where pp function wants to push a zero return
value on the stack. The next commit will start to use it.

Also update the SvIMMORTAL() to be more efficient: it now checks whether
the SV's address is in a range rather than individually checking against
&PL_sv_undef, &PL_sv_no etc.

dump.c
embedvar.h
globvar.sym
intrpvar.h
perl.c
perl.h
sv.c
sv.h

diff --git a/dump.c b/dump.c
index c4bb3ce..fa5f0ba 100644 (file)
--- a/dump.c
+++ b/dump.c
@@ -369,7 +369,9 @@ Perl_sv_peek(pTHX_ SV *sv)
        sv_catpv(t, "WILD");
        goto finish;
     }
-    else if (sv == &PL_sv_undef || sv == &PL_sv_no || sv == &PL_sv_yes || sv == &PL_sv_placeholder) {
+    else if (  sv == &PL_sv_undef || sv == &PL_sv_no || sv == &PL_sv_yes
+            || sv == &PL_sv_zero || sv == &PL_sv_placeholder)
+    {
        if (sv == &PL_sv_undef) {
            sv_catpv(t, "SV_UNDEF");
            if (!(SvFLAGS(sv) & (SVf_OK|SVf_OOK|SVs_OBJECT|
@@ -398,6 +400,17 @@ Perl_sv_peek(pTHX_ SV *sv)
                SvNVX(sv) == 1.0)
                goto finish;
        }
+       else if (sv == &PL_sv_zero) {
+           sv_catpv(t, "SV_ZERO");
+           if (!(SvFLAGS(sv) & (SVf_ROK|SVf_OOK|SVs_OBJECT|
+                                SVs_GMG|SVs_SMG|SVs_RMG)) &&
+               !(~SvFLAGS(sv) & (SVf_POK|SVf_NOK|SVf_READONLY|
+                                 SVp_POK|SVp_NOK)) &&
+               SvCUR(sv) == 1 &&
+               SvPVX_const(sv) && *SvPVX_const(sv) == '0' &&
+               SvNVX(sv) == 0.0)
+               goto finish;
+       }
        else {
            sv_catpv(t, "SV_PLACEHOLDER");
            if (!(SvFLAGS(sv) & (SVf_OK|SVf_OOK|SVs_OBJECT|
index 1e3f9a2..4b945f2 100644 (file)
 #define PL_sv_serial           (vTHX->Isv_serial)
 #define PL_sv_undef            (vTHX->Isv_undef)
 #define PL_sv_yes              (vTHX->Isv_yes)
+#define PL_sv_zero             (vTHX->Isv_zero)
 #define PL_sys_intern          (vTHX->Isys_intern)
 #define PL_taint_warn          (vTHX->Itaint_warn)
 #define PL_tainted             (vTHX->Itainted)
index c82dc8f..a91d520 100644 (file)
@@ -3,6 +3,7 @@
 # *** Usual globals initialized at runtime should be added in *var*.h.
 
 PL_No
+PL_Zero
 PL_Yes
 PL_bincompat_options
 PL_bitcount
index c6070ea..e1c96f7 100644 (file)
@@ -158,12 +158,20 @@ C<&PL_sv_no>.
 This is the C<true> SV.  See C<L</PL_sv_no>>.  Always refer to this as
 C<&PL_sv_yes>.
 
+=for apidoc Amn|SV|PL_sv_zero
+This readonly SV has a zero numeric value and a C<"0"> string value. It's
+similar to C<L</PL_sv_no>> except for its string value. Can be used as a
+cheap alternative to C<mXPUSHi(0)> for example.  Always refer to this as
+C<&PL_sv_zero>. Introduced in 5.28.
+
 =cut
 */
 
 PERLVAR(I, sv_undef,   SV)
 PERLVAR(I, sv_no,      SV)
 PERLVAR(I, sv_yes,     SV)
+PERLVAR(I, sv_zero,    SV)
+
 PERLVAR(I, padname_undef,      PADNAME)
 PERLVAR(I, padname_const,      PADNAME)
 PERLVAR(I, Sv,         SV *)           /* used to hold temporary values */
diff --git a/perl.c b/perl.c
index 3497043..4370f48 100644 (file)
--- a/perl.c
+++ b/perl.c
@@ -1287,6 +1287,11 @@ perl_destruct(pTHXx)
     SvANY(&PL_sv_no) = NULL;
     SvFLAGS(&PL_sv_no) = 0;
 
+    SvREFCNT(&PL_sv_zero) = 0;
+    sv_clear(&PL_sv_zero);
+    SvANY(&PL_sv_zero) = NULL;
+    SvFLAGS(&PL_sv_zero) = 0;
+
     {
         int i;
         for (i=0; i<=2; i++) {
diff --git a/perl.h b/perl.h
index 01f8960..db1b5b3 100644 (file)
--- a/perl.h
+++ b/perl.h
@@ -4766,6 +4766,8 @@ EXTCONST char PL_Yes[]
   INIT("1");
 EXTCONST char PL_No[]
   INIT("");
+EXTCONST char PL_Zero[]
+  INIT("0");
 EXTCONST char PL_hexdigit[]
   INIT("0123456789abcdef0123456789ABCDEF");
 
diff --git a/sv.c b/sv.c
index cb3c1d1..5a554fe 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -15407,6 +15407,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     init_constants();
     ptr_table_store(PL_ptr_table, &proto_perl->Isv_undef, &PL_sv_undef);
     ptr_table_store(PL_ptr_table, &proto_perl->Isv_no, &PL_sv_no);
+    ptr_table_store(PL_ptr_table, &proto_perl->Isv_zero, &PL_sv_zero);
     ptr_table_store(PL_ptr_table, &proto_perl->Isv_yes, &PL_sv_yes);
     ptr_table_store(PL_ptr_table, &proto_perl->Ipadname_const,
                    &PL_padname_const);
@@ -15914,6 +15915,12 @@ Perl_init_constants(pTHX)
                                  |SVp_IOK|SVf_IOK|SVp_NOK|SVf_NOK
                                  |SVp_POK|SVf_POK;
 
+    SvANY(&PL_sv_zero)         = new_XPVNV();
+    SvREFCNT(&PL_sv_zero)      = SvREFCNT_IMMORTAL;
+    SvFLAGS(&PL_sv_zero)       = SVt_PVNV|SVf_READONLY|SVf_PROTECT
+                                 |SVp_IOK|SVf_IOK|SVp_NOK|SVf_NOK
+                                 |SVp_POK|SVf_POK;
+
     SvPV_set(&PL_sv_no, (char*)PL_No);
     SvCUR_set(&PL_sv_no, 0);
     SvLEN_set(&PL_sv_no, 0);
@@ -15926,6 +15933,12 @@ Perl_init_constants(pTHX)
     SvIV_set(&PL_sv_yes, 1);
     SvNV_set(&PL_sv_yes, 1);
 
+    SvPV_set(&PL_sv_zero, (char*)PL_Zero);
+    SvCUR_set(&PL_sv_zero, 1);
+    SvLEN_set(&PL_sv_zero, 0);
+    SvIV_set(&PL_sv_zero, 0);
+    SvNV_set(&PL_sv_zero, 0);
+
     PadnamePV(&PL_padname_const) = (char *)PL_No;
 }
 
diff --git a/sv.h b/sv.h
index 71c494b..5b11c18 100644 (file)
--- a/sv.h
+++ b/sv.h
@@ -2087,7 +2087,7 @@ 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_placeholder))
+#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))
 
 #ifdef DEBUGGING
    /* exercise the immortal resurrection code in sv_free2() */