-
Notifications
You must be signed in to change notification settings - Fork 577
add compact vararg impl gv_stashsvpvn_cached_p, add gv_stashhek #23041
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?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -1621,7 +1621,8 @@ HV* | |||
Perl_gv_stashpv(pTHX_ const char *name, I32 create) | ||||
{ | ||||
PERL_ARGS_ASSERT_GV_STASHPV; | ||||
return gv_stashpvn(name, strlen(name), create); | ||||
return Perl_gv_stashsvpvn_cached_p(aTHX_ create | GVCf_ISPV | GVCf_HASVA_LEN, | ||||
(void*)name, strlen(name)); | ||||
} | ||||
|
||||
/* | ||||
|
@@ -1696,15 +1697,73 @@ reasons. | |||
|
||||
HV* | ||||
Perl_gv_stashsvpvn_cached(pTHX_ SV *namesv, const char *name, U32 namelen, I32 flags) | ||||
{ | ||||
PERL_ARGS_ASSERT_GV_STASHSVPVN_CACHED; | ||||
if(namesv) | ||||
return Perl_gv_stashsvpvn_cached_p(aTHX_ flags | GVCf_ISSV, (void*)namesv); | ||||
else | ||||
return Perl_gv_stashsvpvn_cached_p(aTHX_ flags | GVCf_ISPV | GVCf_HASVA_LEN, | ||||
(void*)name, namelen); | ||||
} | ||||
|
||||
/* Not public API, "..." takes exactly 1 optional arg, "U32 namelen" for the | ||||
public facing _pvn() variant. All other varieties, pv() pvs() sv() hek() | ||||
do not use the optional 3rd arg.*/ | ||||
HV* | ||||
Perl_gv_stashsvpvn_cached_p(pTHX_ I32 flags, void * namevp, ...) | ||||
{ | ||||
HV* stash; | ||||
HE* he; | ||||
SV* namesv; | ||||
const char* name; | ||||
va_list args; | ||||
U32 namelen; | ||||
U32 hash; | ||||
|
||||
PERL_ARGS_ASSERT_GV_STASHSVPVN_CACHED; | ||||
PERL_ARGS_ASSERT_GV_STASHSVPVN_CACHED_P; | ||||
va_start(args, namevp); | ||||
if(GV_CACHE_ISRC(flags)) { | ||||
if(GV_CACHE_ISHEK(flags)) { | ||||
HEK* hek = (HEK*)namevp; | ||||
I32 hek_len = HEK_LEN(hek); | ||||
if(hek_len == HEf_SVKEY) { | ||||
namesv = *(SV**)HEK_KEY(hek); | ||||
namevp = (void*)namesv; | ||||
goto have_sv; | ||||
} | ||||
namesv = NULL; | ||||
name = HEK_KEY(hek); | ||||
namelen = hek_len; | ||||
flags = (flags & ~SVf_UTF8) | (HEK_UTF8(hek) ? SVf_UTF8 : 0); | ||||
/* hv_fetchhek() isn't used here. Its a macro and doesn't currently | ||||
do the optimisation you think it is supposed to do. Using macro | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What optimization is that? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Line 849 in 49e1c32
|
||||
hv_fetchhek() in this fn, would add needless indirection through | ||||
wrapper hv_common_key_len() instead of centralized single call sites | ||||
to hv_common(). */ | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How's that? It looks like it just calls
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See link ^^^ hv_fetchhek() is writing checks that dont cash. Patches welcome. |
||||
hash = HEK_HASH(hek); | ||||
} | ||||
else { | ||||
have_sv: | ||||
assert(GV_CACHE_ISSV(flags)); | ||||
namesv = (SV*)namevp; | ||||
name = NULL; | ||||
namelen = 0; | ||||
flags = (flags & ~SVf_UTF8) | SvUTF8(namesv); | ||||
hash = 0; | ||||
} | ||||
} | ||||
else { | ||||
assert(GV_CACHE_ISPV(flags)); | ||||
namesv = NULL; | ||||
name = (const char *)namevp; | ||||
namelen = GV_CACHE_HASVA_LEN(flags) | ||||
? va_arg(args, U32) : GV_CACHE_GET_INL_LEN(flags); | ||||
hash = 0; | ||||
} | ||||
|
||||
he = (HE *)hv_common( | ||||
PL_stashcache, namesv, name, namelen, | ||||
(flags & SVf_UTF8) ? HVhek_UTF8 : 0, 0, NULL, 0 | ||||
(flags & SVf_UTF8) ? HVhek_UTF8 : 0, 0, NULL, hash | ||||
); | ||||
|
||||
if (he) { | ||||
|
@@ -1713,44 +1772,74 @@ Perl_gv_stashsvpvn_cached(pTHX_ SV *namesv, const char *name, U32 namelen, I32 f | |||
assert(SvIOK(sv)); | ||||
hv = INT2PTR(HV*, SvIVX(sv)); | ||||
assert(SvTYPE(hv) == SVt_PVHV); | ||||
return hv; | ||||
stash = hv; | ||||
goto end; | ||||
} | ||||
else if (flags & GV_CACHE_ONLY) { | ||||
stash = NULL; | ||||
goto end; | ||||
} | ||||
else if (flags & GV_CACHE_ONLY) return NULL; | ||||
|
||||
if (namesv) { | ||||
if (SvOK(namesv)) { /* prevent double uninit warning */ | ||||
STRLEN len; | ||||
name = SvPV_const(namesv, len); | ||||
namelen = len; | ||||
flags |= SvUTF8(namesv); | ||||
flags = (flags & ~SVf_UTF8) | SvUTF8(namesv); | ||||
} else { | ||||
name = ""; namelen = 0; | ||||
namesv = NULL; flags = flags & ~SVf_UTF8; | ||||
} | ||||
} | ||||
} /* Turn off bits specific to our call conv so GV_NOADD_MASK works. | ||||
Some of our call conv bits are shared with other features from | ||||
other front end gv_*() funcs. */ | ||||
flags &= ~GV_CACHE_VA_ARGS_MASK; | ||||
stash = gv_stashpvn_internal(name, namelen, flags); | ||||
|
||||
if (stash && namelen) { | ||||
SV* const ref = newSViv(PTR2IV(stash)); | ||||
(void)hv_store(PL_stashcache, name, | ||||
(flags & SVf_UTF8) ? -(I32)namelen : (I32)namelen, ref, 0); | ||||
hv_common( PL_stashcache, namesv, name, namelen, | ||||
(flags & SVf_UTF8) ? HVhek_UTF8 : 0, HV_FETCH_ISSTORE, ref, hash | ||||
); | ||||
} | ||||
|
||||
end: | ||||
va_end(args); | ||||
return stash; | ||||
} | ||||
|
||||
HV* | ||||
Perl_gv_stashpvn(pTHX_ const char *name, U32 namelen, I32 flags) | ||||
{ | ||||
PERL_ARGS_ASSERT_GV_STASHPVN; | ||||
return gv_stashsvpvn_cached(NULL, name, namelen, flags); | ||||
return Perl_gv_stashsvpvn_cached_p(aTHX_ flags | GVCf_ISPV | GVCf_HASVA_LEN, | ||||
(void*)name, namelen); | ||||
} | ||||
|
||||
HV* | ||||
Perl_gv_stashpvs_p(pTHX_ I32 flags, const char *name) | ||||
{ | ||||
PERL_ARGS_ASSERT_GV_STASHPVS_P; | ||||
return Perl_gv_stashsvpvn_cached_p(aTHX_ flags | GVCf_ISPV, (void*)name); | ||||
} | ||||
|
||||
|
||||
HV* | ||||
Perl_gv_stashsv(pTHX_ SV *sv, I32 flags) | ||||
{ | ||||
PERL_ARGS_ASSERT_GV_STASHSV; | ||||
return gv_stashsvpvn_cached(sv, NULL, 0, flags); | ||||
return Perl_gv_stashsvpvn_cached_p(aTHX_ flags | GVCf_ISSV, (void*)sv); | ||||
} | ||||
|
||||
HV* | ||||
Perl_gv_stashhek(pTHX_ HEK *hek, I32 flags) | ||||
{ | ||||
PERL_ARGS_ASSERT_GV_STASHHEK; | ||||
return Perl_gv_stashsvpvn_cached_p(aTHX_ | ||||
flags | GVCf_ISHEK, | ||||
(void*)hek); | ||||
} | ||||
|
||||
GV * | ||||
Perl_gv_fetchpv(pTHX_ const char *nambeg, I32 flags, const svtype sv_type) { | ||||
PERL_ARGS_ASSERT_GV_FETCHPV; | ||||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
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.
For consistency with the other gv_ functions, could the flags argument always be the final argument?
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.
Oh, it's to support the vararg in
Perl_gv_stashsvpvn_cached_p
?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.
Right, the machine code level C prototype is non-publically/private internals. arg flags goes on the front to communicate the va_arg details of what comes next. The va_arg is never, ever, supposed to be filled out by hand with fingers. The macros are the only way to call it, and they give protect against all the usual pitfalls..
Flags being first prevents 2-5 "push NULL" CPU ops in all callers/all call sites. Remember about my_perl var that always exists in machine code, >4 args on Win64, and the __regcall ABI expires and now you are using real C stack. On Linux its >6, and the __regcall ABI expires, and then your using C stack. C stack ops atleast for Intel CISC always will take more space vs reg to reg moves, b/c they have to write out a 1 byte U8 or 4 byte U32 offset into the C stack. Arg flags is always const folded to 1/2/4 byte CPU integer literal anyway and 1 cpu code. Multiple NULLs will be multiple cpu ops.
There is a very tiny provision I'm making here, which VA, probably helps with.
gv_*fetch*()
funcs need/should always return an var length array of HEK *s to the caller, after being given an ascii string. There are many ways to brain storm it; 5void**
s being pushed on C stack, and used as 2-way transport, turn in a const C str, get back 1 HEK * (end user must RC++ it if they want it or are capable of caching it). 5 const char *s interleved with 5 &c_autos/void **
s. Also perhaps a NULL pointer terminated var len HEK * list gets passed togv_*fetch*()
. I dont see myself doing anything this fancy any time soon. But the provision is there for futuristic not yet invented string objects/package token objects. RCPV and ref counted HEs are a recent example.