summaryrefslogtreecommitdiff
path: root/inline.h
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2012-12-02 12:59:37 +0000
committerDavid Mitchell <davem@iabyn.com>2012-12-04 11:03:38 +0000
commit75a9bf9690b77515a287eb483ea2709b73810c41 (patch)
treeb708681f8c48b94d2c2e0d4d49ac49c70783a548 /inline.h
parentb492a59ed90fecea7508c6bc9601fb08e0212721 (diff)
downloadperl-75a9bf9690b77515a287eb483ea2709b73810c41.tar.gz
make SvREFCNT_dec() more efficient
Historically, SvREFCNT_dec was just #define SvREFCNT_dec(sv) sv_free((SV*)(sv)) then in 5.10.0, for GCC, the macro was partially inlined, avoiding a function call for the refcnt > 1 case. Recently, the macro was turned into an inline function, providing the function-call avoidance to other platforms too. However, the macro/inline-function is quite big, and appears over 500 times in the core source. Its action is logically equivalent to: if (sv) { if (SvREFCNT(sv) > 1) SvREFCNT(sv)--; else if (SvREFCNT == 1) { // normal case SvREFCNT(sv)--; sv_free2(sv); } else { // exceptional case sv_free(sv); } } Where sv_free2() handles the "normal" quick cases, while sv_free() handles the odd cases (e,g. a ref count already at 0 during global destruction). This means we have to plant code that potentially calls two different subs, over 500 times. This commit changes SvREFCNT_dec and sv_free2() to look like: PERL_STATIC_INLINE void S_SvREFCNT_dec(pTHX_ SV *sv) { if (sv) { U32 rc = SvREFCNT(sv); if (rc > 1) SvREFCNT(sv) = rc - 1; else Perl_sv_free2(aTHX_ sv, rc); } } Perl_sv_free2(pTHX_ SV *const sv, const U32 rc) { if (rc == 1) { SvREFCNT(sv) = 0; ... do sv_clear, del_SV etc ... return } /* handle exceptional rc == 0 */ ... } So for the normal cases (rc > 1, rc == 1) there is the same amount of testing and function calls, but the second test has been moved inside the sv_free2() function. This makes the perl executable about 10-15K smaller, and apparently a bit faster (modulo the fact that most benchmarks are just measuring noise). The refcount is passed as a second arg to sv_free2(), as on platforms that pass the first few args in registers, it saves reading sv->sv_refcnt again.
Diffstat (limited to 'inline.h')
-rw-r--r--inline.h11
1 files changed, 5 insertions, 6 deletions
diff --git a/inline.h b/inline.h
index 0d53860da5..5e11b69122 100644
--- a/inline.h
+++ b/inline.h
@@ -55,12 +55,11 @@ PERL_STATIC_INLINE void
S_SvREFCNT_dec(pTHX_ SV *sv)
{
if (sv) {
- if (SvREFCNT(sv)) {
- if (--(SvREFCNT(sv)) == 0)
- Perl_sv_free2(aTHX_ sv);
- } else {
- sv_free(sv);
- }
+ U32 rc = SvREFCNT(sv);
+ if (rc > 1)
+ SvREFCNT(sv) = rc - 1;
+ else
+ Perl_sv_free2(aTHX_ sv, rc);
}
}