Skip to content

Commit

Permalink
add rpp_replace_at_norc() to API
Browse files Browse the repository at this point in the history
It's like rpp_replace_at(), but it assumes that the SV has already had
its refcount bumped. It replaces ugly code like

        SV *nsv = newSVsv(*svp);
    #ifdef PERL_RC_STACK
        rpp_replace(svp, nsv);
        SvREFCNT_dec(nsv);
    #else
        rpp_replace(svp, sv_2mortal(nsv));
    #endif

with a simple

    rpp_replace_at_norc(svp, newSvsv(*svp));

On PERL_RC_STACK builds it's more efficient than before as it's not
unnecessarily bumping and then immediately unbumping nsv's refcount.
  • Loading branch information
iabyn committed Nov 16, 2023
1 parent c0878a0 commit 2bb1814
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 0 deletions.
3 changes: 3 additions & 0 deletions embed.fnc
Expand Up @@ -2774,6 +2774,9 @@ Adipx |void |rpp_replace_1_1|NN SV *sv
Adipx |void |rpp_replace_2_1|NN SV *sv
Adipx |void |rpp_replace_at |NN SV **sp \
|NN SV *sv
Adipx |void |rpp_replace_at_norc \
|NN SV **sp \
|NN SV *sv
Adipx |bool |rpp_stack_is_rc
Adipx |bool |rpp_try_AMAGIC_1 \
|int method \
Expand Down
1 change: 1 addition & 0 deletions embed.h
Expand Up @@ -552,6 +552,7 @@
# define rpp_replace_1_1(a) Perl_rpp_replace_1_1(aTHX_ a)
# define rpp_replace_2_1(a) Perl_rpp_replace_2_1(aTHX_ a)
# define rpp_replace_at(a,b) Perl_rpp_replace_at(aTHX_ a,b)
# define rpp_replace_at_norc(a,b) Perl_rpp_replace_at_norc(aTHX_ a,b)
# define rpp_stack_is_rc() Perl_rpp_stack_is_rc(aTHX)
# define rpp_try_AMAGIC_1(a,b) Perl_rpp_try_AMAGIC_1(aTHX_ a,b)
# define rpp_try_AMAGIC_2(a,b) Perl_rpp_try_AMAGIC_2(aTHX_ a,b)
Expand Down
33 changes: 33 additions & 0 deletions inline.h
Expand Up @@ -705,6 +705,39 @@ Perl_rpp_replace_at(pTHX_ SV **sp, SV *sv)
}


/*
=for apidoc rpp_replace_at_norc
Replace the SV at address sp within the stack with C<sv>, while suitably
adjusting the reference count of the old SV. Equivalent to C<*sp = sv>,
except with proper reference count handling.
C<sv>'s reference count doesn't get incremented. On non-C<PERL_RC_STACK>
builds, it gets mortalised too.
This is most useful where an SV has just been created and already has a
reference count of 1, but has not yet been anchored anywhere.
=cut
*/

PERL_STATIC_INLINE void
Perl_rpp_replace_at_norc(pTHX_ SV **sp, SV *sv)
{
PERL_ARGS_ASSERT_RPP_REPLACE_AT_NORC;

#ifdef PERL_RC_STACK
assert(rpp_stack_is_rc());
SV *oldsv = *sp;
*sp = sv;
SvREFCNT_dec(oldsv);
#else
*sp = sv;
sv_2mortal(sv);
#endif
}


/*
=for apidoc rpp_context
Expand Down
6 changes: 6 additions & 0 deletions pod/perlguts.pod
Expand Up @@ -4760,6 +4760,7 @@ in summary:
rpp_replace_1_1(sv) (void)POPs; PUSHs(sv);
rpp_replace_2_1(sv) (void)POPs; (void)POPs; PUSHs(sv);
rpp_replace_at(sp, sv) *sp = sv;
rpp_replace_at_norc(sp, sv) *sp = sv_2mortal(sv);

rpp_context(mark, gimme,
extra) SP -= extra;
Expand Down Expand Up @@ -4809,6 +4810,11 @@ handle edge cases such as an old and new SV being the same.
rpp_replace_at(sp, sv) is similar to rpp_replace_1_1(), except that
it replaces an SV at an address in the stack rather than at the top.

rpp_replace_at_norc(sp, sv) is similar to rpp_replace_at(), except that
it assumes that C<sv> already has a bumped reference count. So, a bit
like rpp_push_1_norc() (see below), it doesn't bother increasing C<sv>'s
reference count, or on non-RC builds it mortalises it instead.

rpp_popfree_to(svp) is designed to replace code like

PL_stack_sp = PL_stack_base + cx->blk_oldsp;
Expand Down
5 changes: 5 additions & 0 deletions proto.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 2bb1814

Please sign in to comment.