@@ -28,18 +28,74 @@ These functions are related to the method resolution order of perl classes
28
28
#include "perl.h"
29
29
30
30
struct mro_alg {
31
- const char * name ;
32
31
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 */
33
36
};
34
37
35
38
/* First one is the default */
36
39
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 }
39
42
};
40
43
41
44
#define NUMBER_OF_MROS (sizeof(mros)/sizeof(struct mro_alg))
42
45
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
+
43
99
static const struct mro_alg *
44
100
S_get_mro_from_name (pTHX_ const char * const name ) {
45
101
const struct mro_alg * algo = mros ;
@@ -85,9 +141,7 @@ Perl_mro_meta_dup(pTHX_ struct mro_meta* smeta, CLONE_PARAMS* param)
85
141
if (newmeta -> mro_linear_dfs )
86
142
newmeta -> mro_linear_dfs
87
143
= 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 ;
91
145
if (newmeta -> mro_nextmethod )
92
146
newmeta -> mro_nextmethod
93
147
= 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)
177
231
meta = HvMROMETA (stash );
178
232
179
233
/* 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 )) )) {
181
235
return retval ;
182
236
}
183
237
@@ -283,8 +337,8 @@ S_mro_get_linear_isa_dfs(pTHX_ HV *stash, U32 level)
283
337
and we do so by replacing it completely */
284
338
SvREADONLY_on (retval );
285
339
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 ))) ;
288
342
}
289
343
290
344
/*
@@ -328,7 +382,7 @@ S_mro_get_linear_isa_c3(pTHX_ HV* stash, U32 level)
328
382
meta = HvMROMETA (stash );
329
383
330
384
/* 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 )) )) {
332
386
return retval ;
333
387
}
334
388
@@ -501,7 +555,8 @@ S_mro_get_linear_isa_c3(pTHX_ HV* stash, U32 level)
501
555
and we do so by replacing it completely */
502
556
SvREADONLY_on (retval );
503
557
504
- meta -> mro_linear_c3 = retval ;
558
+ return MUTABLE_AV (Perl_mro_set_private_data (aTHX_ meta , c3_alg ,
559
+ MUTABLE_SV (retval )));
505
560
return retval ;
506
561
}
507
562
@@ -569,7 +624,6 @@ Perl_mro_isa_changed_in(pTHX_ HV* stash)
569
624
/* wipe out the cached linearizations for this stash */
570
625
meta = HvMROMETA (stash );
571
626
SvREFCNT_dec (MUTABLE_SV (meta -> mro_linear_dfs ));
572
- SvREFCNT_dec (MUTABLE_SV (meta -> mro_linear_c3 ));
573
627
meta -> mro_linear_dfs = NULL ;
574
628
meta -> mro_linear_c3 = NULL ;
575
629
if (meta -> isa ) {
@@ -612,7 +666,6 @@ Perl_mro_isa_changed_in(pTHX_ HV* stash)
612
666
if (!revstash ) continue ;
613
667
revmeta = HvMROMETA (revstash );
614
668
SvREFCNT_dec (MUTABLE_SV (revmeta -> mro_linear_dfs ));
615
- SvREFCNT_dec (MUTABLE_SV (revmeta -> mro_linear_c3 ));
616
669
revmeta -> mro_linear_dfs = NULL ;
617
670
revmeta -> mro_linear_c3 = NULL ;
618
671
if (!is_universal )
@@ -845,6 +898,8 @@ XS(XS_mro_set_mro)
845
898
846
899
if (meta -> mro_which != which ) {
847
900
meta -> mro_which = which ;
901
+ /* Scrub our cached pointer to the private data. */
902
+ meta -> mro_linear_c3 = NULL ;
848
903
/* Only affects local method cache, not
849
904
even child classes */
850
905
meta -> cache_gen ++ ;
0 commit comments