Skip to content

Commit fa60396

Browse files
committed
Repurpose struct mro_meta to allow it to store cached linear ISA for arbitary
method resolution orders. mro_linear_dfs becomes a hash holding the different MROs' private data. mro_linear_c3 becomes a shortcut pointer to the current MRO's private data.
1 parent 4e7245b commit fa60396

File tree

6 files changed

+90
-14
lines changed

6 files changed

+90
-14
lines changed

embed.fnc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2184,6 +2184,11 @@ XEMop |void |emulate_cop_io |NN const COP *const c|NN SV *const sv
21842184
: Used by SvRX and SvRXOK
21852185
XEMop |REGEXP *|get_re_arg|NULLOK SV *sv
21862186

2187+
Aop |SV* |mro_get_private_data|NN struct mro_meta *const smeta \
2188+
|NN const struct mro_alg *const which
2189+
Aop |SV* |mro_set_private_data|NN struct mro_meta *const smeta \
2190+
|NN const struct mro_alg *const which \
2191+
|NN SV *const data
21872192
: Used in HvMROMETA() in gv.c, pp_hot.c, universal.c
21882193
p |struct mro_meta* |mro_meta_init |NN HV* stash
21892194
#if defined(USE_ITHREADS)

global.sym

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,8 @@ Perl_my_strlcpy
769769
Perl_signbit
770770
Perl_emulate_cop_io
771771
Perl_get_re_arg
772+
Perl_mro_get_private_data
773+
Perl_mro_set_private_data
772774
Perl_mro_get_linear_isa
773775
Perl_mro_method_changed_in
774776
Perl_sys_init

hv.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1695,7 +1695,6 @@ S_hfreeentries(pTHX_ HV *hv)
16951695

16961696
if((meta = iter->xhv_mro_meta)) {
16971697
if(meta->mro_linear_dfs) SvREFCNT_dec(meta->mro_linear_dfs);
1698-
if(meta->mro_linear_c3) SvREFCNT_dec(meta->mro_linear_c3);
16991698
if(meta->mro_nextmethod) SvREFCNT_dec(meta->mro_nextmethod);
17001699
SvREFCNT_dec(meta->isa);
17011700
Safefree(meta);

hv.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ struct shared_he {
4646
struct mro_alg;
4747

4848
struct mro_meta {
49+
/* repurposed as a hash holding the different MROs private data. */
4950
AV *mro_linear_dfs; /* cached dfs @ISA linearization */
51+
/* repurposed as a pointer directly to the current MROs private data. */
5052
AV *mro_linear_c3; /* cached c3 @ISA linearization */
5153
HV *mro_nextmethod; /* next::method caching */
5254
U32 cache_gen; /* Bumping this invalidates our method cache */

mro.c

Lines changed: 68 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,74 @@ These functions are related to the method resolution order of perl classes
2828
#include "perl.h"
2929

3030
struct mro_alg {
31-
const char *name;
3231
AV *(*resolve)(pTHX_ HV* stash, U32 level);
32+
const char *name;
33+
U16 length;
34+
U16 kflags; /* For the hash API - set HVhek_UTF8 if name is UTF-8 */
35+
U32 hash; /* or 0 */
3336
};
3437

3538
/* First one is the default */
3639
static struct mro_alg mros[] = {
37-
{"dfs", S_mro_get_linear_isa_dfs},
38-
{"c3", S_mro_get_linear_isa_c3}
40+
{S_mro_get_linear_isa_dfs, "dfs", 3, 0, 0},
41+
{S_mro_get_linear_isa_c3, "c3", 2, 0, 0}
3942
};
4043

4144
#define NUMBER_OF_MROS (sizeof(mros)/sizeof(struct mro_alg))
4245

46+
#define dfs_alg (&mros[0])
47+
#define c3_alg (&mros[1])
48+
49+
SV *
50+
Perl_mro_get_private_data(pTHX_ struct mro_meta *const smeta,
51+
const struct mro_alg *const which)
52+
{
53+
SV **data;
54+
PERL_ARGS_ASSERT_MRO_GET_PRIVATE_DATA;
55+
56+
data = Perl_hv_common(aTHX_ MUTABLE_HV(smeta->mro_linear_dfs), NULL,
57+
which->name, which->length, which->kflags,
58+
HV_FETCH_JUST_SV, NULL, which->hash);
59+
if (!data)
60+
return NULL;
61+
62+
/* If we've been asked to look up the private data for the current MRO, then
63+
cache it. */
64+
if (smeta->mro_which == which)
65+
smeta->mro_linear_c3 = MUTABLE_AV(*data);
66+
67+
return *data;
68+
}
69+
70+
SV *
71+
Perl_mro_set_private_data(pTHX_ struct mro_meta *const smeta,
72+
const struct mro_alg *const which, SV *const data)
73+
{
74+
PERL_ARGS_ASSERT_MRO_SET_PRIVATE_DATA;
75+
76+
/* If we've been asked to look up the private data for the current MRO, then
77+
cache it. */
78+
if (smeta->mro_which == which)
79+
smeta->mro_linear_c3 = MUTABLE_AV(data);
80+
81+
if (!smeta->mro_linear_dfs) {
82+
HV *const hv = newHV();
83+
HvMAX(hv) = 0; /* Start with 1 bucket. It's unlikely we'll need more.
84+
*/
85+
smeta->mro_linear_dfs = MUTABLE_AV(hv);
86+
}
87+
88+
if (!Perl_hv_common(aTHX_ MUTABLE_HV(smeta->mro_linear_dfs), NULL,
89+
which->name, which->length, which->kflags,
90+
HV_FETCH_ISSTORE, data, which->hash)) {
91+
Perl_croak(aTHX_ "panic: hv_store() failed in set_mro_private_data() "
92+
"for '%.*s' %d", (int) which->length, which->name,
93+
which->kflags);
94+
}
95+
96+
return data;
97+
}
98+
4399
static const struct mro_alg *
44100
S_get_mro_from_name(pTHX_ const char *const name) {
45101
const struct mro_alg *algo = mros;
@@ -85,9 +141,7 @@ Perl_mro_meta_dup(pTHX_ struct mro_meta* smeta, CLONE_PARAMS* param)
85141
if (newmeta->mro_linear_dfs)
86142
newmeta->mro_linear_dfs
87143
= MUTABLE_AV(SvREFCNT_inc(sv_dup((const SV *)newmeta->mro_linear_dfs, param)));
88-
if (newmeta->mro_linear_c3)
89-
newmeta->mro_linear_c3
90-
= MUTABLE_AV(SvREFCNT_inc(sv_dup((const SV *)newmeta->mro_linear_c3, param)));
144+
newmeta->mro_linear_c3 = NULL;
91145
if (newmeta->mro_nextmethod)
92146
newmeta->mro_nextmethod
93147
= MUTABLE_HV(SvREFCNT_inc(sv_dup((const SV *)newmeta->mro_nextmethod, param)));
@@ -177,7 +231,7 @@ S_mro_get_linear_isa_dfs(pTHX_ HV *stash, U32 level)
177231
meta = HvMROMETA(stash);
178232

179233
/* return cache if valid */
180-
if((retval = meta->mro_linear_dfs)) {
234+
if((retval = MUTABLE_AV(Perl_mro_get_private_data(aTHX_ meta, dfs_alg)))) {
181235
return retval;
182236
}
183237

@@ -283,8 +337,8 @@ S_mro_get_linear_isa_dfs(pTHX_ HV *stash, U32 level)
283337
and we do so by replacing it completely */
284338
SvREADONLY_on(retval);
285339

286-
meta->mro_linear_dfs = retval;
287-
return retval;
340+
return MUTABLE_AV(Perl_mro_set_private_data(aTHX_ meta, dfs_alg,
341+
MUTABLE_SV(retval)));
288342
}
289343

290344
/*
@@ -328,7 +382,7 @@ S_mro_get_linear_isa_c3(pTHX_ HV* stash, U32 level)
328382
meta = HvMROMETA(stash);
329383

330384
/* return cache if valid */
331-
if((retval = meta->mro_linear_c3)) {
385+
if((retval = MUTABLE_AV(Perl_mro_get_private_data(aTHX_ meta, c3_alg)))) {
332386
return retval;
333387
}
334388

@@ -501,7 +555,8 @@ S_mro_get_linear_isa_c3(pTHX_ HV* stash, U32 level)
501555
and we do so by replacing it completely */
502556
SvREADONLY_on(retval);
503557

504-
meta->mro_linear_c3 = retval;
558+
return MUTABLE_AV(Perl_mro_set_private_data(aTHX_ meta, c3_alg,
559+
MUTABLE_SV(retval)));
505560
return retval;
506561
}
507562

@@ -569,7 +624,6 @@ Perl_mro_isa_changed_in(pTHX_ HV* stash)
569624
/* wipe out the cached linearizations for this stash */
570625
meta = HvMROMETA(stash);
571626
SvREFCNT_dec(MUTABLE_SV(meta->mro_linear_dfs));
572-
SvREFCNT_dec(MUTABLE_SV(meta->mro_linear_c3));
573627
meta->mro_linear_dfs = NULL;
574628
meta->mro_linear_c3 = NULL;
575629
if (meta->isa) {
@@ -612,7 +666,6 @@ Perl_mro_isa_changed_in(pTHX_ HV* stash)
612666
if(!revstash) continue;
613667
revmeta = HvMROMETA(revstash);
614668
SvREFCNT_dec(MUTABLE_SV(revmeta->mro_linear_dfs));
615-
SvREFCNT_dec(MUTABLE_SV(revmeta->mro_linear_c3));
616669
revmeta->mro_linear_dfs = NULL;
617670
revmeta->mro_linear_c3 = NULL;
618671
if(!is_universal)
@@ -845,6 +898,8 @@ XS(XS_mro_set_mro)
845898

846899
if(meta->mro_which != which) {
847900
meta->mro_which = which;
901+
/* Scrub our cached pointer to the private data. */
902+
meta->mro_linear_c3 = NULL;
848903
/* Only affects local method cache, not
849904
even child classes */
850905
meta->cache_gen++;

proto.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6554,6 +6554,19 @@ PERL_CALLCONV void Perl_emulate_cop_io(pTHX_ const COP *const c, SV *const sv)
65546554

65556555
PERL_CALLCONV REGEXP * Perl_get_re_arg(pTHX_ SV *sv);
65566556

6557+
PERL_CALLCONV SV* Perl_mro_get_private_data(pTHX_ struct mro_meta *const smeta, const struct mro_alg *const which)
6558+
__attribute__nonnull__(pTHX_1)
6559+
__attribute__nonnull__(pTHX_2);
6560+
#define PERL_ARGS_ASSERT_MRO_GET_PRIVATE_DATA \
6561+
assert(smeta); assert(which)
6562+
6563+
PERL_CALLCONV SV* Perl_mro_set_private_data(pTHX_ struct mro_meta *const smeta, const struct mro_alg *const which, SV *const data)
6564+
__attribute__nonnull__(pTHX_1)
6565+
__attribute__nonnull__(pTHX_2)
6566+
__attribute__nonnull__(pTHX_3);
6567+
#define PERL_ARGS_ASSERT_MRO_SET_PRIVATE_DATA \
6568+
assert(smeta); assert(which); assert(data)
6569+
65576570
PERL_CALLCONV struct mro_meta* Perl_mro_meta_init(pTHX_ HV* stash)
65586571
__attribute__nonnull__(pTHX_1);
65596572
#define PERL_ARGS_ASSERT_MRO_META_INIT \

0 commit comments

Comments
 (0)