Skip to content

Commit

Permalink
Perl_newSV_type_mortal - new inline function introduced and used
Browse files Browse the repository at this point in the history
There's no efficient way to create a mortal SV of any type other than
SVt_NULL (via sv_newmortal). The options are either to do:

* SV* sv = sv_newmortal; sv_upgrade(sv, SVt_SOMETYPE);
  but sv_upgrade is needlessly inefficient on new SVs.

* SV* sv = sv_2mortal(newSV_type(SVt_SOMETYPE)
  but this will perform runtime checks to see if (sv) and if (SvIMMORTAL(sv),
  and for a new SV we know that those answers will always be yes and no.

This commit adds a new inline function which is basically a mortalizing
wrapper around the now-inlined newSV_type.
  • Loading branch information
richardleach committed Mar 2, 2022
1 parent 83babae commit 8a82591
Show file tree
Hide file tree
Showing 16 changed files with 113 additions and 58 deletions.
3 changes: 1 addition & 2 deletions av.c
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,7 @@ Perl_av_fetch(pTHX_ AV *av, SSize_t key, I32 lval)
return NULL;
}

sv = sv_newmortal();
sv_upgrade(sv, SVt_PVLV);
sv = newSV_type_mortal(SVt_PVLV);
mg_copy(MUTABLE_SV(av), sv, 0, key);
if (!tied_magic) /* for regdata, force leavesub to make copies */
SvTEMP_off(sv);
Expand Down
2 changes: 1 addition & 1 deletion doop.c
Original file line number Diff line number Diff line change
Expand Up @@ -1176,7 +1176,7 @@ Perl_do_kv(pTHX)

if (gimme == G_SCALAR) {
if (PL_op->op_flags & OPf_MOD || LVRET) { /* lvalue */
SV * const ret = sv_2mortal(newSV_type(SVt_PVLV)); /* Not TARG RT#67838 */
SV * const ret = newSV_type_mortal(SVt_PVLV); /* Not TARG RT#67838 */
sv_magic(ret, NULL, PERL_MAGIC_nkeys, NULL, 0);
LvTYPE(ret) = 'k';
LvTARG(ret) = SvREFCNT_inc_simple(keys);
Expand Down
1 change: 1 addition & 0 deletions embed.fnc
Original file line number Diff line number Diff line change
Expand Up @@ -1520,6 +1520,7 @@ ApMbdR |SV* |newSVsv |NULLOK SV *const old
AmdR |SV* |newSVsv_nomg |NULLOK SV *const old
AdpR |SV* |newSVsv_flags |NULLOK SV *const old|I32 flags
ApdiR |SV* |newSV_type |const svtype type
ApdIR |SV* |newSV_type_mortal|const svtype type
ApdR |OP* |newUNOP |I32 type|I32 flags|NULLOK OP* first
ApdR |OP* |newUNOP_AUX |I32 type|I32 flags|NULLOK OP* first \
|NULLOK UNOP_AUX_item *aux
Expand Down
1 change: 1 addition & 0 deletions embed.h
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@
#define newSVOP(a,b,c) Perl_newSVOP(aTHX_ a,b,c)
#define newSVREF(a) Perl_newSVREF(aTHX_ a)
#define newSV_type(a) Perl_newSV_type(aTHX_ a)
#define newSV_type_mortal(a) Perl_newSV_type_mortal(aTHX_ a)
#define newSVhek(a) Perl_newSVhek(aTHX_ a)
#define newSViv(a) Perl_newSViv(aTHX_ a)
#define newSVnv(a) Perl_newSVnv(aTHX_ a)
Expand Down
2 changes: 1 addition & 1 deletion gv.c
Original file line number Diff line number Diff line change
Expand Up @@ -3801,7 +3801,7 @@ Perl_amagic_call(pTHX_ SV *left, SV *right, int method, int flags)
break;
case G_LIST:
if (flags & AMGf_want_list) {
res = sv_2mortal((SV *)newAV());
res = newSV_type_mortal(SVt_PVAV);
av_extend((AV *)res, nret);
while (nret--)
av_store((AV *)res, nret, POPs);
Expand Down
24 changes: 19 additions & 5 deletions hv.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,12 +200,12 @@ static void
S_hv_notallowed(pTHX_ int flags, const char *key, I32 klen,
const char *msg)
{
SV * const sv = sv_newmortal();
/* Straight to SVt_PVN here, as needed by sv_setpvn_fresh and
* sv_usepvn would otherwise call it */
SV * const sv = newSV_type_mortal(SVt_PV);

PERL_ARGS_ASSERT_HV_NOTALLOWED;

sv_upgrade(sv, SVt_PV); /* Needed by sv_setpvn_fresh and
* sv_usepvn would otherwise call it */
if (!(flags & HVhek_FREEKEY)) {
sv_setpvn_fresh(sv, key, klen);
}
Expand Down Expand Up @@ -968,6 +968,7 @@ SV *
Perl_hv_scalar(pTHX_ HV *hv)
{
SV *sv;
UV u;

PERL_ARGS_ASSERT_HV_SCALAR;

Expand All @@ -977,8 +978,21 @@ Perl_hv_scalar(pTHX_ HV *hv)
return magic_scalarpack(hv, mg);
}

sv = sv_newmortal();
sv_setuv(sv, HvUSEDKEYS(hv));
sv = newSV_type_mortal(SVt_IV);

/* Inlined sv_setuv(sv, HvUSEDKEYS(hv)) follows:*/
u = HvUSEDKEYS(hv);

if (u <= (UV)IV_MAX) {
SvIV_set(sv, (IV)u);
(void)SvIOK_only(sv);
SvTAINT(sv);
} else {
SvIV_set(sv, 0);
SvUV_set(sv, u);
(void)SvIOK_only_UV(sv);
SvTAINT(sv);
}

return sv;
}
Expand Down
2 changes: 1 addition & 1 deletion mg.c
Original file line number Diff line number Diff line change
Expand Up @@ -877,7 +877,7 @@ Perl_sv_string_from_errnum(pTHX_ int errnum, SV *tgtsv)
{
char const *errstr;
if(!tgtsv)
tgtsv = sv_newmortal();
tgtsv = newSV_type_mortal(SVt_PV);
errstr = my_strerror(errnum);
if(errstr) {
sv_setpv(tgtsv, errstr);
Expand Down
22 changes: 11 additions & 11 deletions mro_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ S_mro_get_linear_isa_dfs(pTHX_ HV *stash, U32 level)

/* not in cache, make a new one */

retval = MUTABLE_AV(sv_2mortal(MUTABLE_SV(newAV())));
retval = MUTABLE_AV(newSV_type_mortal(SVt_PVAV));
/* We use this later in this function, but don't need a reference to it
beyond the end of this function, so reference count is fine. */
our_name = newSVhek(stashhek);
Expand Down Expand Up @@ -347,7 +347,7 @@ S_mro_get_linear_isa_dfs(pTHX_ HV *stash, U32 level)
} else {
/* They have no stash. So create ourselves an ->isa cache
as if we'd copied it from what theirs should be. */
stored = MUTABLE_HV(sv_2mortal(MUTABLE_SV(newHV())));
stored = MUTABLE_HV(newSV_type_mortal(SVt_PVHV));
(void) hv_stores(stored, "UNIVERSAL", &PL_sv_undef);
av_push(retval,
newSVhek(HeKEY_hek(hv_store_ent(stored, sv,
Expand All @@ -357,7 +357,7 @@ S_mro_get_linear_isa_dfs(pTHX_ HV *stash, U32 level)
}
} else {
/* We have no parents. */
stored = MUTABLE_HV(sv_2mortal(MUTABLE_SV(newHV())));
stored = MUTABLE_HV(newSV_type_mortal(SVt_PVHV));
(void) hv_stores(stored, "UNIVERSAL", &PL_sv_undef);
}

Expand Down Expand Up @@ -428,7 +428,7 @@ Perl_mro_get_linear_isa(pTHX_ HV *stash)
SV **svp;
SV **ovp = AvARRAY(old);
SV * const * const oend = ovp + AvFILLp(old) + 1;
isa = (AV *)sv_2mortal((SV *)newAV());
isa = (AV *)newSV_type_mortal(SVt_PVAV);
av_extend(isa, AvFILLp(isa) = AvFILLp(old)+1);
*AvARRAY(isa) = namesv;
svp = AvARRAY(isa)+1;
Expand Down Expand Up @@ -570,7 +570,7 @@ Perl_mro_isa_changed_in(pTHX_ HV* stash)
if(hv_iterinit(isarev)) {
/* Only create the hash if we need it; i.e., if isarev has
any elements. */
isa_hashes = (HV *)sv_2mortal((SV *)newHV());
isa_hashes = (HV *)newSV_type_mortal(SVt_PVHV);
}
while((iter = hv_iternext(isarev))) {
HV* revstash = gv_stashsv(hv_iterkeysv(iter), 0);
Expand Down Expand Up @@ -817,7 +817,7 @@ Perl_mro_package_moved(pTHX_ HV * const stash, HV * const oldstash,
}
else {
SV *aname;
namesv = sv_2mortal((SV *)newAV());
namesv = newSV_type_mortal(SVt_PVAV);
while (name_count--) {
if(memEQs(HEK_KEY(*namep), HEK_LEN(*namep), "main")){
aname = GvNAMELEN(gv) == 1
Expand Down Expand Up @@ -854,9 +854,9 @@ Perl_mro_package_moved(pTHX_ HV * const stash, HV * const oldstash,
wrong name. The names must be set on *all* affected stashes before
we do anything else. (And linearisations must be cleared, too.)
*/
stashes = (HV *) sv_2mortal((SV *)newHV());
stashes = (HV *) newSV_type_mortal(SVt_PVHV);
mro_gather_and_rename(
stashes, (HV *) sv_2mortal((SV *)newHV()),
stashes, (HV *) newSV_type_mortal(SVt_PVHV),
stash, oldstash, namesv
);

Expand Down Expand Up @@ -1119,7 +1119,7 @@ S_mro_gather_and_rename(pTHX_ HV * const stashes, HV * const seen_stashes,
/* Skip the entire loop if the hash is empty. */
if(oldstash && HvTOTALKEYS(oldstash)) {
xhv = (XPVHV*)SvANY(oldstash);
seen = (HV *) sv_2mortal((SV *)newHV());
seen = (HV *) newSV_type_mortal(SVt_PVHV);

/* Iterate through entries in the oldstash, adding them to the
list, meanwhile doing the equivalent of $seen{$key} = 1.
Expand Down Expand Up @@ -1164,7 +1164,7 @@ S_mro_gather_and_rename(pTHX_ HV * const stashes, HV * const seen_stashes,
SV *aname;
items = AvFILLp((AV *)namesv) + 1;
svp = AvARRAY((AV *)namesv);
subname = sv_2mortal((SV *)newAV());
subname = newSV_type_mortal(SVt_PVAV);
while (items--) {
aname = newSVsv(*svp++);
if (len == 1)
Expand Down Expand Up @@ -1247,7 +1247,7 @@ S_mro_gather_and_rename(pTHX_ HV * const stashes, HV * const seen_stashes,
SV *aname;
items = AvFILLp((AV *)namesv) + 1;
svp = AvARRAY((AV *)namesv);
subname = sv_2mortal((SV *)newAV());
subname = newSV_type_mortal(SVt_PVAV);
while (items--) {
aname = newSVsv(*svp++);
if (len == 1)
Expand Down
10 changes: 5 additions & 5 deletions pad.c
Original file line number Diff line number Diff line change
Expand Up @@ -1252,13 +1252,13 @@ S_pad_findlex(pTHX_ const char *namepv, STRLEN namelen, U32 flags, const CV* cv,
}
if (!*out_capture) {
if (namelen != 0 && *namepv == '@')
*out_capture = sv_2mortal(MUTABLE_SV(newAV()));
*out_capture = newSV_type_mortal(SVt_PVAV);
else if (namelen != 0 && *namepv == '%')
*out_capture = sv_2mortal(MUTABLE_SV(newHV()));
*out_capture = newSV_type_mortal(SVt_PVHV);
else if (namelen != 0 && *namepv == '&')
*out_capture = sv_2mortal(newSV_type(SVt_PVCV));
*out_capture = newSV_type_mortal(SVt_PVCV);
else
*out_capture = sv_newmortal();
*out_capture = newSV_type_mortal(SVt_NULL);
}
}

Expand Down Expand Up @@ -2063,7 +2063,7 @@ S_cv_clone_pad(pTHX_ CV *proto, CV *cv, CV *outside, HV *cloned,
*/
bool cloned_in_this_pass;
if (!cloned)
cloned = (HV *)sv_2mortal((SV *)newHV());
cloned = (HV *)newSV_type_mortal(SVt_PVHV);
do {
cloned_in_this_pass = FALSE;
for (ix = fpad; ix > 0; ix--) {
Expand Down
12 changes: 6 additions & 6 deletions pp.c
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ PP(pp_pos)
dSP; dTOPss;

if (PL_op->op_flags & OPf_MOD || LVRET) {
SV * const ret = sv_2mortal(newSV_type(SVt_PVLV));/* Not TARG RT#67838 */
SV * const ret = newSV_type_mortal(SVt_PVLV);/* Not TARG RT#67838 */
sv_magic(ret, NULL, PERL_MAGIC_pos, NULL, 0);
LvTYPE(ret) = '.';
LvTARG(ret) = SvREFCNT_inc_simple(sv);
Expand Down Expand Up @@ -467,7 +467,7 @@ S_refto(pTHX_ SV *sv)
SvTEMP_off(sv);
SvREFCNT_inc_void_NN(sv);
}
rv = sv_newmortal();
rv = newSV_type_mortal(SVt_IV);
sv_setrv_noinc(rv, sv);
return rv;
}
Expand Down Expand Up @@ -3300,7 +3300,7 @@ PP(pp_substr)
}
if (lvalue && !repl_sv) {
SV * ret;
ret = sv_2mortal(newSV_type(SVt_PVLV)); /* Not TARG RT#67838 */
ret = newSV_type_mortal(SVt_PVLV); /* Not TARG RT#67838 */
sv_magic(ret, NULL, PERL_MAGIC_substr, NULL, 0);
LvTYPE(ret) = 'x';
LvTARG(ret) = SvREFCNT_inc_simple(sv);
Expand Down Expand Up @@ -3432,7 +3432,7 @@ PP(pp_vec)
retuv = errflags ? 0 : do_vecget(src, offset, size);

if (lvalue) { /* it's an lvalue! */
ret = sv_2mortal(newSV_type(SVt_PVLV)); /* Not TARG RT#67838 */
ret = newSV_type_mortal(SVt_PVLV); /* Not TARG RT#67838 */
sv_magic(ret, NULL, PERL_MAGIC_vec, NULL, 0);
LvTYPE(ret) = 'v';
LvTARG(ret) = SvREFCNT_inc_simple(src);
Expand Down Expand Up @@ -6830,7 +6830,7 @@ PP(pp_refassign)
PP(pp_lvref)
{
dSP;
SV * const ret = sv_2mortal(newSV_type(SVt_PVMG));
SV * const ret = newSV_type_mortal(SVt_PVMG);
SV * const elem = PL_op->op_private & OPpLVREF_ELEM ? POPs : NULL;
SV * const arg = PL_op->op_flags & OPf_STACKED ? POPs : NULL;
MAGIC * const mg = sv_magicext(ret, arg, PERL_MAGIC_lvref,
Expand Down Expand Up @@ -6898,7 +6898,7 @@ PP(pp_lvrefslice)
else
S_localise_helem_lval(aTHX_ (HV *)av, elemsv, can_preserve);
}
*MARK = sv_2mortal(newSV_type(SVt_PVMG));
*MARK = newSV_type_mortal(SVt_PVMG);
sv_magic(*MARK,(SV *)av,PERL_MAGIC_lvref,(char *)elemsv,HEf_SVKEY);
}
RETURN;
Expand Down
8 changes: 3 additions & 5 deletions pp_ctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -5169,12 +5169,10 @@ S_do_smartmatch(pTHX_ HV *seen_this, HV *seen_other, const bool copied)
const Size_t other_len = av_count(other_av);

if (NULL == seen_this) {
seen_this = newHV();
(void) sv_2mortal(MUTABLE_SV(seen_this));
seen_this = (HV*)newSV_type_mortal(SVt_PVHV);
}
if (NULL == seen_other) {
seen_other = newHV();
(void) sv_2mortal(MUTABLE_SV(seen_other));
seen_other = (HV*)newSV_type_mortal(SVt_PVHV);
}
for(i = 0; i < other_len; ++i) {
SV * const * const this_elem = av_fetch(MUTABLE_AV(SvRV(e)), i, FALSE);
Expand Down Expand Up @@ -5882,7 +5880,7 @@ S_run_user_filter(pTHX_ int idx, SV *buf_sv, int maxlen)
don't want to pass it in a second time.
I'm going to use a mortal in case the upstream filter croaks. */
upstream = ((SvOK(buf_sv) && sv_len(buf_sv)) || SvGMAGICAL(buf_sv))
? sv_newmortal() : buf_sv;
? newSV_type_mortal(SVt_PV) : buf_sv;
SvUPGRADE(upstream, SVt_PV);

if (filter_has_file) {
Expand Down
10 changes: 4 additions & 6 deletions pp_hot.c
Original file line number Diff line number Diff line change
Expand Up @@ -991,7 +991,7 @@ PP(pp_multiconcat)
)
)
{
SV *tmp = sv_newmortal();
SV *tmp = newSV_type_mortal(SVt_PV);
sv_copypv(tmp, left);
SvSETMAGIC(tmp);
left = tmp;
Expand Down Expand Up @@ -2868,7 +2868,7 @@ PP(pp_qr)
REGEXP * rx = PM_GETRE(pm);
regexp *prog = ReANY(rx);
SV * const pkg = RXp_ENGINE(prog)->qr_package(aTHX_ (rx));
SV * const rv = sv_newmortal();
SV * const rv = newSV_type_mortal(SVt_IV);
CV **cvp;
CV *cv;

Expand Down Expand Up @@ -3406,8 +3406,7 @@ PP(pp_helem)
if (!defer) {
DIE(aTHX_ PL_no_helem_sv, SVfARG(keysv));
}
lv = sv_newmortal();
sv_upgrade(lv, SVt_PVLV);
lv = newSV_type_mortal(SVt_PVLV);
LvTYPE(lv) = 'y';
sv_magic(lv, key2 = newSVsv(keysv), PERL_MAGIC_defelem, NULL, 0);
SvREFCNT_dec_NN(key2); /* sv_magic() increments refcount */
Expand Down Expand Up @@ -3846,8 +3845,7 @@ PP(pp_multideref)
SV* key2;
if (!defer)
DIE(aTHX_ PL_no_helem_sv, SVfARG(keysv));
lv = sv_newmortal();
sv_upgrade(lv, SVt_PVLV);
lv = newSV_type_mortal(SVt_PVLV);
LvTYPE(lv) = 'y';
sv_magic(lv, key2 = newSVsv(keysv),
PERL_MAGIC_defelem, NULL, 0);
Expand Down
7 changes: 7 additions & 0 deletions proto.h
Original file line number Diff line number Diff line change
Expand Up @@ -2488,6 +2488,13 @@ PERL_STATIC_INLINE SV* Perl_newSV_type(pTHX_ const svtype type)
#define PERL_ARGS_ASSERT_NEWSV_TYPE
#endif

#ifndef PERL_NO_INLINE_FUNCTIONS
PERL_STATIC_FORCE_INLINE SV* Perl_newSV_type_mortal(pTHX_ const svtype type)
__attribute__warn_unused_result__
__attribute__always_inline__;
#define PERL_ARGS_ASSERT_NEWSV_TYPE_MORTAL
#endif

PERL_CALLCONV SV* Perl_newSVavdefelem(pTHX_ AV *av, SSize_t ix, bool extendible)
__attribute__warn_unused_result__;
#define PERL_ARGS_ASSERT_NEWSVAVDEFELEM \
Expand Down
4 changes: 2 additions & 2 deletions regcomp.c
Original file line number Diff line number Diff line change
Expand Up @@ -16673,8 +16673,8 @@ S_handle_regex_sets(pTHX_ RExC_state_t *pRExC_state, SV** return_invlist,
* so that everything gets evaluated down to a single operand, which is the
* result */

sv_2mortal((SV *)(stack = newAV()));
sv_2mortal((SV *)(fence_stack = newAV()));
stack = (AV*)newSV_type_mortal(SVt_PVAV);
fence_stack = (AV*)newSV_type_mortal(SVt_PVAV);

while (RExC_parse < RExC_end) {
I32 top_index; /* Index of top-most element in 'stack' */
Expand Down
Loading

0 comments on commit 8a82591

Please sign in to comment.