uninline panic branch from POPSTACK
authorDaniel Dragan <bulk88@hotmail.com>
Sun, 16 Dec 2012 22:26:49 +0000 (17:26 -0500)
committerFather Chrysostomos <sprout@cpan.org>
Mon, 24 Dec 2012 00:36:38 +0000 (16:36 -0800)
This commit saves machine instructions by preventing inlining, and keeps
the error handling code for an extremely rare panic out of hot code. This
should make the interp smaller and faster.

Perl_error_log is a macro that has a very large expansion on threaded
perls, 4 branches and possibly a call to Perl_PerlIO_stderr. POPSTACK
18 times, by asm, on my non DEBUGGING threaded Win32 32 bit Perl 5.17
-O1 compiled with VC 2003. POPSTACK is also used in some core XS modules,
for example List::Util and PerlIO::encoding. The .text section of
perl517.dll dropped from 0xc05ff bytes of x86 instructions to 0xc00ff
after applying this for me.

Perl_croak_popstack was made contextless to save a push/move instruction
at each caller (less instructions in the instruction cache) and for more
opportunity for the compiler to optimize. Since Perl_croak_popstack is a
noreturn, some compilers may optimize it to just a conditional jump
instruction. VC 2003 32 bit did this inside perl517.dll and from XS
modules using POPSTACK.  Perl_croak_popstack measures at 0x48 bytes of
instructions under -O1 for me, so previously, those 0x48 minus the
dTHX overhead would have been sitting in the caller because of macro
expansion.

cop.h
embed.fnc
embed.h
proto.h
util.c

diff --git a/cop.h b/cop.h
index 0a682f1..8acdec8 100644 (file)
--- a/cop.h
+++ b/cop.h
@@ -1134,8 +1134,7 @@ typedef struct stackinfo PERL_SI;
            Perl_deb(aTHX_ "pop  STACKINFO %d at %s:%d\n",              \
                         i, __FILE__, __LINE__);})                      \
        if (!prev) {                                                    \
-           PerlIO_printf(Perl_error_log, "panic: POPSTACK\n");         \
-           my_exit(1);                                                 \
+           Perl_croak_popstack();                                      \
        }                                                               \
        SWITCHSTACK(PL_curstack,prev->si_stack);                        \
        /* don't free prev here, free them all at the END{} */          \
index 61934fb..75688fb 100644 (file)
--- a/embed.fnc
+++ b/embed.fnc
@@ -262,6 +262,7 @@ Anprd       |void   |croak_no_modify
 Anprd  |void   |croak_xs_usage |NN const CV *const cv \
                                |NN const char *const params
 npr    |void   |croak_no_mem
+nprX   |void   |croak_popstack
 #if defined(WIN32)
 norx   |void   |win32_croak_not_implemented|NN const char * fname
 #endif
diff --git a/embed.h b/embed.h
index 2aae592..1136f60 100644 (file)
--- a/embed.h
+++ b/embed.h
 #define coresub_op(a,b,c)      Perl_coresub_op(aTHX_ a,b,c)
 #define create_eval_scope(a)   Perl_create_eval_scope(aTHX_ a)
 #define croak_no_mem           Perl_croak_no_mem
+#define croak_popstack         Perl_croak_popstack
 #define cv_ckproto_len_flags(a,b,c,d,e)        Perl_cv_ckproto_len_flags(aTHX_ a,b,c,d,e)
 #define cv_clone_into(a,b)     Perl_cv_clone_into(aTHX_ a,b)
 #define cv_forget_slab(a)      Perl_cv_forget_slab(aTHX_ a)
diff --git a/proto.h b/proto.h
index e8af3c8..ee2b14e 100644 (file)
--- a/proto.h
+++ b/proto.h
@@ -676,6 +676,9 @@ PERL_CALLCONV_NO_RET void   Perl_croak_no_mem(void)
 PERL_CALLCONV_NO_RET void      Perl_croak_no_modify(void)
                        __attribute__noreturn__;
 
+PERL_CALLCONV_NO_RET void      Perl_croak_popstack(void)
+                       __attribute__noreturn__;
+
 PERL_CALLCONV_NO_RET void      Perl_croak_sv(pTHX_ SV *baseex)
                        __attribute__noreturn__
                        __attribute__nonnull__(pTHX_1);
diff --git a/util.c b/util.c
index 12a6bf4..987e41e 100644 (file)
--- a/util.c
+++ b/util.c
@@ -1634,6 +1634,15 @@ Perl_croak_no_mem()
     my_exit(1);
 }
 
+/* does not return, used only in POPSTACK */
+void
+Perl_croak_popstack(void)
+{
+    dTHX;
+    PerlIO_printf(Perl_error_log, "panic: POPSTACK\n");
+    my_exit(1);
+}
+
 /*
 =for apidoc Am|void|warn_sv|SV *baseex