remove PL_patchlevel from S_minus_v
authorDaniel Dragan <bulk88@hotmail.com>
Wed, 13 Nov 2013 04:07:16 +0000 (23:07 -0500)
committerTony Cook <tony@develop-help.com>
Wed, 20 Nov 2013 02:47:16 +0000 (13:47 +1100)
|SvPVX(vstringify(PL_patchlevel))| is the same string as
|"v" PERL_VERSION_STRING|. No need to go through the overhead of using a
version object. Instead of creating a SV, then further manipulating it.
Create and manipulate it at the same time with Perl_newSVpvf_nocontext or
newSVpvn. "num_len >= level_len " will be folded away by the compiler,
previously, since both lengths came from SVs, they were not const
technically. A very smart compiler might see strncmp/strnEQ takes all
const arguments, and will optimize that away also. VC 2003 didnt do that.
Change SvREFCNT_dec to SvREFCNT_dec_NN for obvious reasons.

There should not be any user visible changes to -v with this patch.
switches.t contains a regexp for -v already so no further tests were added.

This patch is part of #116296.

perl.c

diff --git a/perl.c b/perl.c
index 2892a87..e4310cd 100644 (file)
--- a/perl.c
+++ b/perl.c
@@ -3443,30 +3443,35 @@ STATIC void
 S_minus_v(pTHX)
 {
        PerlIO * PIO_stdout;
-       if (!sv_derived_from(PL_patchlevel, "version"))
-           upg_version(PL_patchlevel, TRUE);
        {
-           SV* level= vstringify(PL_patchlevel);
+           const char * const level_str = "v" PERL_VERSION_STRING;
+           const STRLEN level_len = sizeof("v" PERL_VERSION_STRING)-1;
 #ifdef PERL_PATCHNUM
+           SV* level;
 #  ifdef PERL_GIT_UNCOMMITTED_CHANGES
-           SV *num = newSVpvs(PERL_PATCHNUM "*");
+           static const char num [] = PERL_PATCHNUM "*";
 #  else
-           SV *num = newSVpvs(PERL_PATCHNUM);
+           static const char num [] = PERL_PATCHNUM;
 #  endif
            {
-               STRLEN level_len, num_len;
-               char * level_str, * num_str;
-               num_str = SvPV(num, num_len);
-               level_str = SvPV(level, level_len);
-               if (num_len>=level_len && strnEQ(num_str,level_str,level_len)) {
-                   SvREFCNT_dec(level);
-                   level= num;
+               const STRLEN num_len = sizeof(num)-1;
+               /* A very advanced compiler would fold away the strnEQ
+                  and this whole conditional, but most (all?) won't do it.
+                  SV level could also be replaced by with preprocessor
+                  catenation.
+               */
+               if (num_len >= level_len && strnEQ(num,level_str,level_len)) {
+                   /* per 46807d8e80, PERL_PATCHNUM is outside of the control
+                      of the interp so it might contain format characters
+                   */
+                   level = newSVpvn(num, num_len);
                } else {
-                   Perl_sv_catpvf(aTHX_ level, " (%"SVf")", num);
-                   SvREFCNT_dec(num);
+                   level = Perl_newSVpvf_nocontext("%s (%s)", level_str, num);
                }
            }
- #endif
+#else
+       SV* level = newSVpvn(level_str, level_len);
+#endif /* #ifdef PERL_PATCHNUM */
        PIO_stdout =  PerlIO_stdout();
            PerlIO_printf(PIO_stdout,
                "\nThis is perl "       STRINGIFY(PERL_REVISION)
@@ -3474,7 +3479,7 @@ S_minus_v(pTHX)
                ", subversion "         STRINGIFY(PERL_SUBVERSION)
                " (%"SVf") built for "  ARCHNAME, level
                );
-           SvREFCNT_dec(level);
+           SvREFCNT_dec_NN(level);
        }
 #if defined(LOCAL_PATCH_COUNT)
        if (LOCAL_PATCH_COUNT > 0)