Skip to content

Commit

Permalink
de-mathom Perl_sv_taint() part 4 add SvTAINTTC() tailcall API
Browse files Browse the repository at this point in the history
Perl_newSVnv/Perl_newSViv/Perl_newSVuv, currently have to save the fresh
SV *, either on C stack, or in non volatile registers, around the
possible Perl_sv_taint() fn call inside SvTAINT(). If Perl_sv_taint()
returns its SV * argument, and assigns it back to the same C var, now
these 3 performance critical SV allocator functions, after plucking
the SV head from the arena, these 3 function never ever have to
store the fresh SV * back to C stack for any reason during their execution.

This optimization removes pop/push pairs of the C compiler saving
non-volatile registers and restoring them at function entry and exit since
after SvTAINTTC() change, NO variables AT ALL, have to be saved around
any function calls in Perl_newSVnv/Perl_newSViv/Perl_newSVuv. Also the
SV head *, after being delinked/removed from an areana, can now be
stored through the whole function, in the x86 EAX/x64 RAX register, and
pass through to the caller, without a final (non vol) reg to
(vol retval reg) mov/copy cpu op.

Remember eax/rax/retval registers, are always wiped after each fn call,
but the refactoring of SvTAINTTC() conviently returns the
SV * back to us, in the ABI return register, and we let the fresh
SV * glide through on the "heavy" Perl_sv_taint() branch, from
Perl_sv_taint() to Perl_newSViv()'s caller, without touching it, 0
machine code ops.

Few code sites were changed from SvTAINT() to SvTAINTTC(), to keep this
patch smaller, and the Perl_sv_set*vXXX() category of functions, all have
void return types and can't be chained. Also the Perl_sv_taint() branch
can be tail called or converted to a JMP insted of CALL, if the CC/OS/ABI
wants to now.

This is the final part of speeding up
Perl_newSVnv/Perl_newSViv/Perl_newSVuv there is nothing else to remove or
optimze.
  • Loading branch information
bulk88 committed Oct 17, 2024
1 parent 7f29878 commit c77e852
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 6 deletions.
4 changes: 2 additions & 2 deletions hv.c
Original file line number Diff line number Diff line change
Expand Up @@ -1130,12 +1130,12 @@ Perl_hv_scalar(pTHX_ HV *hv)
if (u <= (UV)IV_MAX) {
SvIV_set(sv, (IV)u);
(void)SvIOK_only(sv);
SvTAINT(sv);
sv = SvTAINTTC(sv);
} else {
SvIV_set(sv, 0);
SvUV_set(sv, u);
(void)SvIOK_only_UV(sv);
SvTAINT(sv);
sv = SvTAINTTC(sv);
}

return sv;
Expand Down
6 changes: 3 additions & 3 deletions sv.c
Original file line number Diff line number Diff line change
Expand Up @@ -10037,7 +10037,7 @@ Perl_newSVnv(pTHX_ const NV n)
SvNV_set(sv, n);
#endif

SvTAINT(sv);
sv = SvTAINTTC(sv);

return sv;
}
Expand Down Expand Up @@ -10073,7 +10073,7 @@ Perl_newSViv(pTHX_ const IV i)
SET_SVANY_FOR_BODYLESS_IV(sv);
sv->sv_u.svu_iv = i;

SvTAINT(sv);
sv = SvTAINTTC(sv);

return sv;
}
Expand Down Expand Up @@ -10175,7 +10175,7 @@ Perl_newSVuv(pTHX_ const UV u)
SET_SVANY_FOR_BODYLESS_IV(sv);
sv->sv_u.svu_uv = u;

SvTAINT(sv);
sv = SvTAINTTC(sv);

return sv;
}
Expand Down
18 changes: 18 additions & 0 deletions sv.h
Original file line number Diff line number Diff line change
Expand Up @@ -1721,6 +1721,21 @@ inputs such as locale settings. C<SvTAINT> propagates that taintedness to
the outputs of an expression in a pessimistic fashion; i.e., without paying
attention to precisely which outputs are influenced by which inputs.
=cut
=for apidoc Cm|SV* sv|SvTAINTTC|SV* sv
Identical to C<SvTAINT>, except optimized for for C compilers to do tail calls.
Incoming arg I<sv> will be returned as the retval of I<SvTAINTTC>.
The return value I<SV *> pointer will be identical to the incoming
argument I<SV *> pointer. Ex. I<sv = sv;>). This way if I<TAINT> is on, and
the slow path branch executes, which has an internal helper function, that
helper function returns the argument passed in, and C compilers can optimize
the slowpath branch to a tail call, or use less registers. This macro is mostly
intended to be used if C<SvTAINTTC> is the last or almost last statement
in the caller function, and the caller has a I<SV *> return type, and will
return C<SvTAINTTC>'s arg I<sv>, to its caller as a return value. Similar idea
to C<sv_2mortal>.
=cut
*/

Expand All @@ -1739,6 +1754,9 @@ attention to precisely which outputs are influenced by which inputs.
sv_taint(sv); \
} STMT_END

#define SvTAINTTC(sv) ((assert(TAINTING_get || !TAINT_get), \
TAINT_AND_TAINTING_get) ? sv_taint((sv)) : (sv))

/*
=for apidoc_section $SV
=for apidoc Am|char*|SvPV_force |SV* sv|STRLEN len
Expand Down
2 changes: 1 addition & 1 deletion sv_inline.h
Original file line number Diff line number Diff line change
Expand Up @@ -985,7 +985,7 @@ Perl_sv_setpv_freshbuf(pTHX_ SV *const sv)
(void)SvPOK_only_UTF8(sv); /* UTF-8 flag will be 0; This is used instead
of 'SvPOK_only' because the other sv_setpv
functions use it */
SvTAINT(sv);
SvTAINTTC(sv);
return SvPVX(sv);
}

Expand Down

0 comments on commit c77e852

Please sign in to comment.