-
Notifications
You must be signed in to change notification settings - Fork 575
Dedicated SV cloning code in place of Perl_sv_setsv_flags #23202
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: blead
Are you sure you want to change the base?
Conversation
S_sv_freshcopy_flags is a drop-in replacement for `Perl_sv_setsv_flags`. It is designed for use when the destination SV is being freshly created and much of the logic in `sv_setsv_flags` is irrelevant. The intended users for this new function are: * Perl_sv_mortalcopy_flags * Perl_newSVsv_flags Those functions have been modified such that: * Bodyless destination SVs are created inline * SVt_PVs also have special casing * SVt_PVMG and below use S_sv_freshcopy_flags * Anything else drops back to using Perl_sv_setsv_flags S_sv_freshcopy_POK is a helper function that concentrates on the string assignment logic: * Swipe the buffer * CoW the buffer * Copy the buffer Using perl's test harness as a guide: * 45% of Perl_newSVsv_flags / 57% of Perl_sv_mortalcopy_flags calls use the bodyless code * 32% of Perl_newSVsv_flags / 36% of Perl_sv_mortalcopy_flags calls use the SVt_PV/SVp_POK code * The S_sv_freshcopy_flags code handles the bulk of the remainder. With these changes compared with a build of blead: * `perl -e 'for (1..100_000) { my $x = [ (1) x 1000 ]; }'` runs 30% faster * `perl -e 'for (1..100_000) { my $x = [ ("Perl") x 1000 ]; }' runs: * 15% faster if `newSV_type(SVt_PV)` is NOT inlined * 30% faster if it IS inlined The overall reduction in branches when cloning SVs, and refocusing of branch prediction within Perl_sv_setsv_flags, will hopefully give a meaningful boost to realistic Perl applications.
sv_setsv_nomg(sv, *MARK); | ||
if (*MARK) { | ||
SvGETMAGIC(*MARK); | ||
sv = newSVsv_flags(*MARK, SV_DO_COW_SVSETSV); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe cache *MARK
to a auto and skip the 2nd -O1/2 deref in sv = newSVsv_flags(*MARK, SV_DO_COW_SVSETSV);
? fn call containing macro SvGETMAGIC(*MARK);
won't overwrite the SV* on the PL stack with a new SV*.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just calling newSVsv_flags(*MARK, SV_DO_COW_SVSETSV|SV_GMAGIC)
should be better
if (*MARK) {
sv = newSVsv_flags(*MARK, SV_DO_COW_SVSETSV|SV_GMAGIC);
}
else
sv = newSV_type(SVt_NULL);
does (MARK is %rbx), %rdi is the first function argument:
.loc 2 6424 13 view .LVU16810
.loc 2 6424 17 is_stmt 0 view .LVU16811
movq (%rbx), %rdi
.loc 2 6424 16 view .LVU16812
testq %rdi, %rdi
jne .L5826
.loc 2 6428 17 is_stmt 1 view .LVU16813
; the else with "sv = newSV_type(SVt_NULL);", not shown
...
.L5826:
.LBB7306:
.loc 2 6425 17 view .LVU16801
.loc 2 6425 22 is_stmt 0 view .LVU16802
movl $1538, %esi
call Perl_newSVsv_flags@PLT
Perl_newSVsv_flags() already has the GMAGIC test and mg_get() call, saving space and a duplicate test here, and the source SV goes into a register and stays there.
@@ -5357,8 +5357,7 @@ PP(pp_subst) | |||
if (dstr) { | |||
/* replacement needing upgrading? */ | |||
if (DO_UTF8(TARG) && !doutf8) { | |||
nsv = sv_newmortal(); | |||
SvSetSV(nsv, dstr); | |||
nsv = sv_mortalcopy_flags(dstr, SV_GMAGIC|SV_DO_COW_SVSETSV); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re-think this chunk, macro SvSetSV
macro has an ultra fast shortcut/bypass in it. That shortcut will be lost if this chinkgoes to production. sv_mortalcopy_flags
is a linkable extern C func. The macro's shortcut path doesn't have any fn calls in it. The shortcut branch in that macro may or may not be executable in real life at this line of code. Plz research.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That shortcut/bypass:
#define SvSetSV_and(dst,src,finally) \
STMT_START { \
SV * src_ = src; \
SV * dst_ = dst; \
if (LIKELY((dst_) != (src_))) { \
sv_setsv(dst_, src_); \
finally; \
} \
} STMT_END
...
#define SvSetSV(dst,src) \
SvSetSV_and(dst,src,/*nothing*/;)
dst_
is never equal to src_
here (unless dst_
points to freed SV, which would be a serious bug and shouldn't be optimized for).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That shortcut/bypass:
....
dst_
is never equal tosrc_
here (unlessdst_
points to freed SV, which would be a serious bug and shouldn't be optimized for).
@tonycoz you are correct, That macro's optimization branch is impossible to execute at this particular line.
&& !(SvFLAGS(dsv) & SVf_BREAK) \ | ||
) | ||
#endif | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this macro cover or need to cover SVf_STATIC COWs? Modern Perl C has a total of 4 SVPV COW types right now. COW 255, HEK COW, SVf_STATIC and SvLEN == 0.
There is a future 5th SVPV COW type that needs to get added by someone. Blead's current SVPV COW impl/logic has a very bad sore spot, that RCPV objs can't be boxed/wrapped in a SV* head. Its just a limitation from RCPV's day 1 "minimalist" design, since it was created as low-controversy new API alternative to my heavy weight new API inter-thread SHEK patch that stalled out over lack of review/input/identifier naming/final C prototypes of new macros/funcs some years earlier. RCPV objs are heavily used inside threaded Perl, since they are the backbone of the inter-ithread op-tree related "hint hash" and CopFILE subsystems. So this PR needs to have provisions, or keep it easy/clean/maintainable for someone to add SVPV COW type # 5 at a later date.
Also sv_setsv_foo(dsv, ssv, F_FOO)
all P5 versions has never propagated SvLEN == 0 SvPVX pointers AFAIK. Which makes "for speed"/"for perf" usage of RO C strings in interp versions pre-SVf_STATIC, near useless/a benchmarkable perf downgrade in production, for CPAN XS code, since SvLEN == 0 COWs almost instantly get de-COWed in the runloop. In very very rare cases, along with using dXSTARG, and a PP caller, using SvLEN == 0 COWs maybe will be a benchmark win, but I personally refuse to write "SvLEN == 0 COW" code ever again for pre-SVf_STATIC interps, and instead I keep HEKs or PVHEK SVs in my XS lib's MY_CXT struct for pre-SVf_STATIC interps.
SVf_STATIC is most used for public API req bool propagation rn, maybe in the near future, alot of authorized or P5P unauthorized CPAN XS/B::C/B::CC usage, I am addicted to that flag after it was added. SVPVHEKs are slightly slightly bouncing around the interp than SVf_STATIC SVPVs, I remember the diff being as 6 ns or 6 us for SVf_STATIC vs 9 ns or 9 us for SVPVHEK in some private benchmark I did.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SvLEN() == 0 doesn't mean that the SvPVX is freely copiable to other SVs, multiconcat for example sets PAD SVs to SvLEN()==0 that point into the OP's aux data. If these transferred the PV pointer they'd become invalid if the OP were freed.
This macro brings out the existing test, talking about new things that could be done with SV behaviour here seems off-topic to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, the SvLEN() == 0
topic is too complex and too distant from this PR to think about or care about in this PR. SvLEN() == 0
is so rarely seen IME, both PP/core and random CPAN XS libs that, for me and what I care about, it is a very low priority topic. It is a 2nd round of desert in the engine, not the main course.
Only the first 3 types, COW 255, HEK COW, SVf_STATIC, need propagation or meaningful "thinking over" in this PR.
From what I see with 5.41, the COW 255 is # 1 super highest frequency COW type to bounce around VM state in the runloop. HEK COWs are # 2 in frequency, but in my rough guess, their circulation or chance of seeing one at a random breakpoint you made, is 1/4th or 1/10th the chance of a seeing a COW 255. Mostly b/c of missed-optimization opportunities, which can be slowly fixed over time in small steps. # 3 COW type, SVf_STATIC, in real life, they are almost non-existent in the run loop. That COW type only exists for reasons involving SvIMMs, public API, and various CPAN XS JSON/JSON-like modules. Aslong as this PR doesn't break the bare minimum public API behavior of # 3, this PR is good enough to go into blead.
Deep future/long-term strategic outlook, SVf_STATIC has very high use potential and speed benefits.
As you said, SvLEN() == 0 has legacy (?) or a long time CPAN XS public API assumption, that SvLEN() == 0
+ MG*->vtbl->svt_free()
+ SvREADONLY()
is the proper way to implement your brand new Kernel MMap XS module. I definitely see how un-stable/high risk it is, to suddenly make the SvPVX() ptr from a SvLEN() == 0, randomly and uncontrollably reproduce throughout the VM when XS mods don't want their 3p/foreign RO or RW SvPVX() to reproduce.
SVf_STATIC solves alot of the "Perl 5 SUXS!!! The PHP interp and Python interp compile their code." gossip problem, on the engineering technical level, not the politics level. newSVpvs()
and either libperl.so.dll
+DynaLoader::
/XS, or libperl.so.dll
-only, enough said.
SvHEK COWs, egh, they work, they have their purpose, but on x64 CPUs, they have a 0x21 bytes long header, excluding SvCUR(), excluding libc's malloc header, excluding libc bucket round up. And I've heard this before, and agree, what if U32
HEK_HASH()
is never ever used/read, for rest of the proc's lifetime? It easy to guess for any XS dev, what CStr literal they typed WILL, CAN, and NEVER will become a HE.
Off-topic for this PR and its scope, SVf_STATIC, as designed, as intended, has a major design limitation and a tiny runtime performace problem. A 5% or 10% grey zone exists, where SVf_STATIC
is wrong, and SvPVHEK
is wrong. I ran into it with one of my unpublished experiments.
newSVpvs()
? cool, that is easy enough.
Now think, wait for it, sv_setpvs();
. Now what???!!! Not so easy.
f it is not clear, the technical problem is, what if the SV* already has a SvPVX() from Newx() with correct length? dXSTARG
, my/PAD vars, sv_catpvn
, sv_catpvf
, and more. API contract says flag SVf_STATIC SHALL propagate, not MAY propagate. It is not optional for sv_setsv()
/sv_setpvs_xtra_sss();
to ignore and drop out that flag, even if it very un-wise, and a total performance downgrade, to propagate the flag, or in other words, do the Safefree(SvPVX())
dance. So very long term strategic, and low priority, this rare 5% grey zone, needs its own SV* metadata permutation in core.
* though, which is why the code below does not try that type | ||
* simplification. Perhaps this might be worth revisiting in the future. | ||
* -- April 2025. */ | ||
assert(ssv); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea, just b/c ssv is currently type PVIV/PVNV/PVMG/PVLV, isn't a valid reason for dsv to be 1 of those 4, if there isn't any fOK
data or other metadata on ssv, to justify dsv being upgraded to a super-sized body type. ssv could've been blessed or had MAGIC *
s, or been PVLV (my ❤️ SV type), could've been a stringified IV -> PV in the past, but got a
PP =
, and by now IOK_OK and IOKp_OK, both, are ancient history. Since this C func is always forking a source SV*, its very unlikely IMO the new fork will get independently near-future get upgraded to a large exotic SV body, by the caller C code/API/module/PP or XSUB, that is creating dest SV*, if the source SV* isn't currently defined and formally data-wise blessed/overload.pm/MAGIC */PVLV/etc at the exactly moment,
/* The switch cases are in the order that gcov of make/make test suggests. */ | ||
switch(sflags & (SVp_IOK|SVp_NOK|SVf_ROK|SVp_POK|SVf_FAKE|SVppv_STATIC)) { | ||
case SVp_IOK: | ||
SvIV_set(dsv, SvIVX(ssv)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SVt_IV and some build configs SVt_NV, are bodyless, please write direct to the 4th SV head field and skip indirecting through SvANY. Grep sv.c
for ideas on how to do the fresh bodyless SV head field 4 assignment.
const char *vstr_pv; | ||
STRLEN vstr_len; | ||
if ((vstr_pv = SvVSTRING(ssv, vstr_len))) { | ||
sv_magic(dsv, NULL, PERL_MAGIC_vstring, vstr_pv, vstr_len); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't feel super comfortable with this. This if() test probably needs to be done before SV *dsv = newSV_type(stype);
executes at the very top, so sv_magic()
doesn't need to execute sv_upgrade()
to go from SVt_PV to SVt_PVMG, The right body type for SV* dsv, was picked correctly from the very start. Looking at machine code/single stepping in machine code view, or some C dbgr BP research might change my/other ppls opinion if the macro SvVSTRING(
in if ((vstr_pv = SvVSTRING(ssv, vstr_len))) {
is super expensive/inefficient, and therefore justify sv_magic()
executing sv_upgrade()
which slightly inefficient, vs slowing down 100% of all other interp wide calls with a source SV* of any type/contents.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SvVSTRING() is a macro that tests magical-ness via flags before checking the actual magic, so it should be cheap in most circumstances, the most common exception being utf8 length magic.
I don't think the upgrade is an issue, vstrings are generally rare, an extra check early on adds extra instructions (including a branch) in the hot path for every other SV type,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the upgrade is an issue, vstrings are generally rare, an extra check early on adds extra instructions (including a branch) in the hot path for every other SV type,
Same here. I am just nit picking, any thing, any flaw, I can think of. Some of the flaws I mention in this PR, are just for academic reasons or academic ritual. A certain small percent % of the flaws I mention in this PR, even I would write back with "No/decline/disagree, here is why .....". Fixing the flaw was not the intention. someone thinking it over and posting "No/decline/disagree, here is why ....." was the point :-)
Besides, I have never in my life seen a SV* VSTRING in my C debugger. I disagree with your opinion that they are generally rare
. My opinion is they don't exist
. They are some obsolete ancient grammar museum thing from 5.000 alpha or 4.0, and can get the chainsaw. VSTRING lost its SvTYPE() slot and was "sent to CPAN" in 5.9.x or 5.10.1 IIRC. It has been a humble MG* struct "from CPAN" ever since.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have a vstring:
$ perl -MDevel::Peek -e 'Dump(v1.2.3)'
SV = PVMG(0x55a6e40944c0) at 0x55a6e4051ee0
REFCNT = 1
FLAGS = (RMG,POK,IsCOW,READONLY,PROTECT,pPOK)
IV = 0
NV = 0
PV = 0x55a6e405a6f0 "\x01\x02\x03"\0
CUR = 3
LEN = 10
COW_REFCNT = 0
MAGIC = 0x55a6e405b2c0
MG_VIRTUAL = 0
MG_TYPE = PERL_MAGIC_vstring(V)
MG_LEN = 6
MG_PTR = 0x55a6e4043b60 "v1.2.3"
SvRMAGICAL_on(dsv); | ||
} | ||
} | ||
break; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see same-looking code on case:
above and case:
below this comment, maybe remove the break;
and fall through?
/* Source was SVf_IOK|SVp_IOK|SVp_POK but not SVf_POK, meaning | ||
a value set as an integer and later stringified. So mark | ||
destination the same: */ | ||
SvFLAGS(dsv) &= ~SVf_POK; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What code above in this func, already wrote to dsv SvFLAGS , in such a way that public flag not private flag, SVf_POK bit is turned on in dsv right now? Im confused.
{ | ||
const STRLEN cur = SvCUR(ssv); | ||
|
||
(void)SvPOK_only(dsv); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why would there be any ROK+public 3, FAKE + private 3, SV head flag bits, be turned on, in a fresh SV* head of any body type? I hope there isn't a secret sv_backoff()
fn call on this line.
SvNV_set(dsv, SvNVX(ssv)); | ||
SvFLAGS(dsv) |= SVf_IsCOW|SVppv_STATIC| | ||
(sflags & (SVf_IOK|SVp_IOK|SVf_IVisUV|SVf_NOK|SVp_NOK|SVf_POK|SVf_POK|SVf_UTF8)); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This case:
is getting vague and indecisive and unsure of itself own purpose, is this case:
a generic SVf_IsCOW|SVppv_STATIC
duplicator, or a highly specific "3 SvIMMORTALs()" duplicator, or a duplicator of "3 SvIMMORTALS" + any regular RCed forks/descendants of the 3 IMMs/RO SV bools? We don't need to dynamically &
mask out current contents from sflags
, if we can prove what flag bits sflags
, and use a most efficient literal integer here,
{ | ||
const char *vstr_pv; | ||
STRLEN vstr_len; | ||
if ((vstr_pv = SvVSTRING(ssv, vstr_len))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This VSTRING test is starting to look like excessive copy paste. It can't be in so many case statements.
Is this also true?
if (SvVSTRING(&PL_sv_undef, unused_len))
warn("true");
case SVf_ROK: | ||
SvRV_set(dsv, SvREFCNT_inc(SvRV(ssv))); | ||
SvFLAGS(dsv) |= sflags & SVf_ROK; | ||
break; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are weak refs??? does this func need special casing for them? I forgot their internals off the top of my head, other that 1 side or the other uses a MAGIC , or hides a void *
to the weak ref SV head, somewhere very secretive inside a HV*/AV*.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As below, I don't think we need any special handling of weak refs here.
sv_setsv_flags(dsv,ssv,flags); | ||
return dsv; | ||
case SVp_NOK: | ||
SvNV_set(dsv, SvNVX(ssv)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remember about bodyless NVs, check rest of sv.c for examples. Don't indirect through SvANY.
return dsv; | ||
case SVp_NOK: | ||
SvNV_set(dsv, SvNVX(ssv)); | ||
SvFLAGS(dsv) |= (sflags & (SVf_NOK|SVp_NOK)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why read and extract bits from sflags
? does SVp_NOK WITHOUT SVf_NOK and no other "OK" bits, does that have any meaning on a PP level? is it ever encountered at runtime in a blead/stable perl running normal production PP and CPAN XS code? do we need to consider buggy/weird/beginner CPAN XS code that would make such a SV* head or not?
|=
with a literal on the right side, is much more efficient that bit extraction from var sflags, in CC optimized C code.
} else if (SvFLAGS(old) & SVf_ROK) { | ||
SvFLAGS(dsv) |= SVf_ROK; | ||
SvRV_set(dsv, SvREFCNT_inc(SvRV(old))); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
weak ref applies here or not? Move SvRV(old)
to separate oldsv =;
line, move SvREFCNT_inc
to a separate line, and use one of the more efficient SvREFCNT_inc
macros variants here, like SvREFCNT_inc_simple_void_NN
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A copy of a weak ref isn't weak itself, I don't think there needs to be any special handling of weak references here.
@@ -9635,15 +9906,75 @@ C<L</sv_setsv_flags>>. | |||
SV * | |||
Perl_sv_mortalcopy_flags(pTHX_ SV *const oldstr, U32 flags) | |||
{ | |||
SV *sv; | |||
SV * old = (oldstr) ? oldstr : &PL_sv_undef; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this, and don't introduce it as public API. SV * Perl_sv_mortalcopy_flags(interpreter *my_perl, SV *const oldstr, unsigned int flags)
in blead/stable perl always has, and should continue to SEGV if oldstr
is NULL. The caller frame can type &PL_sv_undef
themselves if they want to. 10-25% chance a NULL SV* sitting in a C auto/C expression in the caller, is a uninitialized memory read bug and not a legit PP level undefined value. Also the interp exports Perl_sv_set_undef()
(newish) and newSV()
for CPAN XS authors if they want a RW PP undef in XS/C, and these 2 are much more efficient for their narrow scoped task vs any other Perl C API func/macro, that obviously that is more universal/dynamic in its purpose.
Note Perl_sv_set_undef()
is newish, and is not in ppport.h, IIRC. Most CPAN XS authors are uninformed, or too lazy to write an old perl polyfill and use this func (Perl_sv_set_undef()
) in private production XS code or in CPAN XS.
I personally use sv_set_undef()
sometimes and I did write that polyfill. The polyfill/fallback for old perls is sv_setpv(sv, NULL)
and/or sv_setpv_mg(sv, NULL)
for dXSTARGs. I personally type sv_setpv_mg(sv, NULL)
more often than sv_set_undef()
b/c the 4 calls, sv_set_bool
sv_set_bool
sv_set_false
sv_set_true
have no _mg
variants for dXSTARG, or returning &PL_sv_*
on PL stack is more efficient b/c I know the average caller frame, PP or XS, that is caller my XSUB, isn't going to PP =
or sv_setsv
my PL stack retval to its own private SV* for long term storage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this, and don't introduce it as public API. SV * Perl_sv_mortalcopy_flags(interpreter *my_perl, SV *const oldstr, unsigned int flags) in blead/stable perl always has, and should continue to SEGV if oldstr is NULL. The caller frame can type &PL_sv_undef themselves if they want to
I can sort of agree, but sv_mortalcopy_flags():
- only segfaults on a NULL oldsv when
SV_GMAGIC
is set in flags - the embed.fnc entry has oldsv marked as NULLOK.
That said, rather than conditionally setting old
and then going through the copy process to copy from PL_sv_undef
, it could just conditionally return sv_newmortal().
@@ -10178,20 +10509,76 @@ parameter. | |||
SV * | |||
Perl_newSVsv_flags(pTHX_ SV *const old, I32 flags) | |||
{ | |||
SV *sv; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe Perl_mortalcopy_flags
needs to be a thin wrapper around Perl_newSVsv_flags
, or a tailcall to Perl_newSVsv_flags
with a super secret or minimally secret flag in Perl_newSVsv_flags
's I32 flags
arg. Alot of duplicate looking code between mortalcopy and newSVsv.
Perl_sv_setsv_flags
is the heavyweight function for assigning the value(s) ofa source SV to a destination SV. It contains many branches for preparing the
destination SV prior to assignment. However:
This set of commits:
Perl_sv_setsv_flags
into a macro.S_sv_freshcopy_flags
andS_sv_freshcopy_POK
helper functions.Perl_newSVsv_flags
andPerl_sv_mortalcopy_flags
to use them -and optimise the hot cases in particular.
should use
Perl_newSVsv_flags
orPerl_sv_mortalcopy_flags
.Using perl's test harness as a guide:
Perl_newSVsv_flags
and57% of calls to
Perl_sv_mortalcopy_flags
.SVt_PV/SVp_POK
code handles 32% of calls toPerl_newSVsv_flags
and 36% of calls toPerl_sv_mortalcopy_flags
.S_sv_freshcopy_flags
code handles 95% of the remainder inPerl_newSVsv_flags
and 91% of the remainder in toPerl_sv_mortalcopy_flags
.With these changes compared with a build of blead:
perl -e 'for (1..100_000) { my $x = [ (1) x 1000 ]; }'
runs 30% fasterperl -e 'for (1..100_000) { my $x = [ ("Perl") x 1000 ]; }'
runs:newSV_type(SVt_PV)
is NOT inlined