#include "perl.h"
struct mro_alg {
- const char *name;
AV *(*resolve)(pTHX_ HV* stash, U32 level);
+ const char *name;
+ U16 length;
+ U16 kflags; /* For the hash API - set HVhek_UTF8 if name is UTF-8 */
+ U32 hash; /* or 0 */
};
/* First one is the default */
static struct mro_alg mros[] = {
- {"dfs", S_mro_get_linear_isa_dfs},
- {"c3", S_mro_get_linear_isa_c3}
+ {S_mro_get_linear_isa_dfs, "dfs", 3, 0, 0},
+ {S_mro_get_linear_isa_c3, "c3", 2, 0, 0}
};
#define NUMBER_OF_MROS (sizeof(mros)/sizeof(struct mro_alg))
+#define dfs_alg (&mros[0])
+#define c3_alg (&mros[1])
+
+SV *
+Perl_mro_get_private_data(pTHX_ struct mro_meta *const smeta,
+ const struct mro_alg *const which)
+{
+ SV **data;
+ PERL_ARGS_ASSERT_MRO_GET_PRIVATE_DATA;
+
+ data = Perl_hv_common(aTHX_ MUTABLE_HV(smeta->mro_linear_dfs), NULL,
+ which->name, which->length, which->kflags,
+ HV_FETCH_JUST_SV, NULL, which->hash);
+ if (!data)
+ return NULL;
+
+ /* If we've been asked to look up the private data for the current MRO, then
+ cache it. */
+ if (smeta->mro_which == which)
+ smeta->mro_linear_c3 = MUTABLE_AV(*data);
+
+ return *data;
+}
+
+SV *
+Perl_mro_set_private_data(pTHX_ struct mro_meta *const smeta,
+ const struct mro_alg *const which, SV *const data)
+{
+ PERL_ARGS_ASSERT_MRO_SET_PRIVATE_DATA;
+
+ /* If we've been asked to look up the private data for the current MRO, then
+ cache it. */
+ if (smeta->mro_which == which)
+ smeta->mro_linear_c3 = MUTABLE_AV(data);
+
+ if (!smeta->mro_linear_dfs) {
+ HV *const hv = newHV();
+ HvMAX(hv) = 0; /* Start with 1 bucket. It's unlikely we'll need more.
+ */
+ smeta->mro_linear_dfs = MUTABLE_AV(hv);
+ }
+
+ if (!Perl_hv_common(aTHX_ MUTABLE_HV(smeta->mro_linear_dfs), NULL,
+ which->name, which->length, which->kflags,
+ HV_FETCH_ISSTORE, data, which->hash)) {
+ Perl_croak(aTHX_ "panic: hv_store() failed in set_mro_private_data() "
+ "for '%.*s' %d", (int) which->length, which->name,
+ which->kflags);
+ }
+
+ return data;
+}
+
static const struct mro_alg *
S_get_mro_from_name(pTHX_ const char *const name) {
const struct mro_alg *algo = mros;
if (newmeta->mro_linear_dfs)
newmeta->mro_linear_dfs
= MUTABLE_AV(SvREFCNT_inc(sv_dup((const SV *)newmeta->mro_linear_dfs, param)));
- if (newmeta->mro_linear_c3)
- newmeta->mro_linear_c3
- = MUTABLE_AV(SvREFCNT_inc(sv_dup((const SV *)newmeta->mro_linear_c3, param)));
+ newmeta->mro_linear_c3 = NULL;
if (newmeta->mro_nextmethod)
newmeta->mro_nextmethod
= MUTABLE_HV(SvREFCNT_inc(sv_dup((const SV *)newmeta->mro_nextmethod, param)));
meta = HvMROMETA(stash);
/* return cache if valid */
- if((retval = meta->mro_linear_dfs)) {
+ if((retval = MUTABLE_AV(Perl_mro_get_private_data(aTHX_ meta, dfs_alg)))) {
return retval;
}
and we do so by replacing it completely */
SvREADONLY_on(retval);
- meta->mro_linear_dfs = retval;
- return retval;
+ return MUTABLE_AV(Perl_mro_set_private_data(aTHX_ meta, dfs_alg,
+ MUTABLE_SV(retval)));
}
/*
meta = HvMROMETA(stash);
/* return cache if valid */
- if((retval = meta->mro_linear_c3)) {
+ if((retval = MUTABLE_AV(Perl_mro_get_private_data(aTHX_ meta, c3_alg)))) {
return retval;
}
and we do so by replacing it completely */
SvREADONLY_on(retval);
- meta->mro_linear_c3 = retval;
+ return MUTABLE_AV(Perl_mro_set_private_data(aTHX_ meta, c3_alg,
+ MUTABLE_SV(retval)));
return retval;
}
/* wipe out the cached linearizations for this stash */
meta = HvMROMETA(stash);
SvREFCNT_dec(MUTABLE_SV(meta->mro_linear_dfs));
- SvREFCNT_dec(MUTABLE_SV(meta->mro_linear_c3));
meta->mro_linear_dfs = NULL;
meta->mro_linear_c3 = NULL;
if (meta->isa) {
if(!revstash) continue;
revmeta = HvMROMETA(revstash);
SvREFCNT_dec(MUTABLE_SV(revmeta->mro_linear_dfs));
- SvREFCNT_dec(MUTABLE_SV(revmeta->mro_linear_c3));
revmeta->mro_linear_dfs = NULL;
revmeta->mro_linear_c3 = NULL;
if(!is_universal)
if(meta->mro_which != which) {
meta->mro_which = which;
+ /* Scrub our cached pointer to the private data. */
+ meta->mro_linear_c3 = NULL;
/* Only affects local method cache, not
even child classes */
meta->cache_gen++;
PERL_CALLCONV REGEXP * Perl_get_re_arg(pTHX_ SV *sv);
+PERL_CALLCONV SV* Perl_mro_get_private_data(pTHX_ struct mro_meta *const smeta, const struct mro_alg *const which)
+ __attribute__nonnull__(pTHX_1)
+ __attribute__nonnull__(pTHX_2);
+#define PERL_ARGS_ASSERT_MRO_GET_PRIVATE_DATA \
+ assert(smeta); assert(which)
+
+PERL_CALLCONV SV* Perl_mro_set_private_data(pTHX_ struct mro_meta *const smeta, const struct mro_alg *const which, SV *const data)
+ __attribute__nonnull__(pTHX_1)
+ __attribute__nonnull__(pTHX_2)
+ __attribute__nonnull__(pTHX_3);
+#define PERL_ARGS_ASSERT_MRO_SET_PRIVATE_DATA \
+ assert(smeta); assert(which); assert(data)
+
PERL_CALLCONV struct mro_meta* Perl_mro_meta_init(pTHX_ HV* stash)
__attribute__nonnull__(pTHX_1);
#define PERL_ARGS_ASSERT_MRO_META_INIT \