#include "perl.h"
#include "XSUB.h"
-/* Most of this code is backported from bleadperl's
+/* Most of this code is backported from the bleadperl patch's
mro.c, and then modified to work with Class::C3's
internals.
*/
+/* This is %next::METHOD_CACHE */
+STATIC HV* nmcache;
+
AV*
__mro_linear_isa_c3(pTHX_ HV* stash, HV* cache, I32 level)
{
stashname);
if(!cache) {
- cache = newHV();
+ cache = (HV*)sv_2mortal((SV*)newHV());
}
else {
- /* XXX return cached entry for stashname if available */
+ SV** cache_entry = hv_fetch(cache, stashname, stashname_len, 0);
+ if(cache_entry)
+ return (AV*)SvREFCNT_inc(*cache_entry);
}
/* not in cache, make a new one */
av_push(isa_lin, newSVsv(isa_item));
}
else {
- isa_lin = (AV*)sv_2mortal((SV*)__mro_linear_isa_c3(isa_item_stash, cache, level + 1)); /* recursion */
+ isa_lin = (AV*)sv_2mortal((SV*)__mro_linear_isa_c3(aTHX_ isa_item_stash, cache, level + 1)); /* recursion */
}
av_push(seqs, (SV*)av_make(AvFILLp(isa_lin)+1, AvARRAY(isa_lin)));
}
SvREADONLY_on(retval);
SvREFCNT_inc(retval); /* for cache storage */
- SvREFCNT_inc(retval); /* for return to caller */
- /* XXX store in cache storage */
+ SvREFCNT_inc(retval); /* for return */
+ hv_store(cache, stashname, stashname_len, (SV*)retval, 0);
return retval;
}
CV* cand_cv = NULL;
const char *hvname;
I32 items;
- struct mro_meta* selfmeta;
- HV* nmcache;
HE* cache_entry;
+ SV* cachekey;
if(sv_isobject(self))
selfstash = SvSTASH(SvRV(self));
/* If we made it to here, we found our context */
- /*
- XXX check %next::METHOD_CACHE
-
- selfmeta = HvMROMETA(selfstash);
- if(!(nmcache = selfmeta->mro_nextmethod)) {
- nmcache = selfmeta->mro_nextmethod = newHV();
- }
+ /* cachekey = "objpkg|context::method::name" */
+ cachekey = sv_2mortal(newSVpv(hvname, 0));
+ sv_catpvn(cachekey, "|", 1);
+ sv_catsv(cachekey, sv);
- if((cache_entry = hv_fetch_ent(nmcache, sv, 0, 0))) {
+ if((cache_entry = hv_fetch_ent(nmcache, cachekey, 0, 0))) {
SV* val = HeVAL(cache_entry);
if(val == &PL_sv_undef) {
if(throw_nomethod)
}
return SvREFCNT_inc(val);
}
- */
/* beyond here is just for cache misses, so perf isn't as critical */
stashname_len = subname - fq_subname - 2;
stashname = sv_2mortal(newSVpvn(fq_subname, stashname_len));
- linear_av = __mro_linear_isa_c3(selfstash, NULL, 0); /* has ourselves at the top of the list */
- sv_2mortal((SV*)linear_av);
+ linear_av = (AV*)sv_2mortal((SV*)__mro_linear_isa_c3(aTHX_ selfstash, NULL, 0));
linear_svp = AvARRAY(linear_av);
items = AvFILLp(linear_av) + 1;
}
if(items > 0) {
+ SV* sub_sv = sv_2mortal(newSVpv(subname, subname_len));
+ HV* cc3_mro = get_hv("Class::C3::MRO", 0);
+
while (items--) {
linear_sv = *linear_svp++;
assert(linear_sv);
+
+ if(cc3_mro) {
+ HE* he_cc3_mro_class = hv_fetch_ent(cc3_mro, linear_sv, 0, 0);
+ if(he_cc3_mro_class) {
+ HV* cc3_mro_class = (HV*)SvRV(HeVAL(he_cc3_mro_class));
+ SV** svp_cc3_mro_class_methods = hv_fetch(cc3_mro_class, "methods", 7, 0);
+ if(svp_cc3_mro_class_methods) {
+ HV* cc3_mro_class_methods = (HV*)SvRV(*svp_cc3_mro_class_methods);
+ if(hv_exists_ent(cc3_mro_class_methods, sub_sv, 0))
+ continue;
+ }
+ }
+ }
+
cstash = gv_stashsv(linear_sv, FALSE);
if (!cstash) {
assert(cstash);
-/* XXX we need to fetch from %Class::C3::MRO, not the real stash table */
-
gvp = (GV**)hv_fetch(cstash, subname, subname_len, 0);
if (!gvp) continue;
gv_init(candidate, cstash, subname, subname_len, TRUE);
if (SvTYPE(candidate) == SVt_PVGV && (cand_cv = GvCV(candidate)) && !GvCVGEN(candidate)) {
SvREFCNT_inc((SV*)cand_cv);
- /* XXX store result in cache */
- /* hv_store_ent(nmcache, newSVsv(sv), (SV*)cand_cv, 0); */
+ hv_store_ent(nmcache, newSVsv(cachekey), (SV*)cand_cv, 0);
return (SV*)cand_cv;
}
}
}
- /* XXX store undef in cache */
- /* hv_store_ent(nmcache, newSVsv(sv), &PL_sv_undef, 0); */
+ hv_store_ent(nmcache, newSVsv(cachekey), &PL_sv_undef, 0);
if(throw_nomethod)
croak("No next::method '%s' found for %s", subname, hvname);
return &PL_sv_undef;
croak("Usage: calculateMRO(classname[, cache])");
classname = ST(0);
- if(items == 2) cache = (HV*)ST(1);
+ if(items == 2) cache = (HV*)SvRV(ST(1));
class_stash = gv_stashsv(classname, 0);
if(!class_stash) croak("No such class: '%s'!", SvPV_nolen(classname));
- res = (AV*)sv_2mortal((SV*)__mro_linear_isa_c3(class_stash, cache, 0));
-
+ res = (AV*)sv_2mortal((SV*)__mro_linear_isa_c3(aTHX_ class_stash, cache, 0));
res_items = ret_items = AvFILLp(res) + 1;
res_ptr = AvARRAY(res);
#endif
SV* self = ST(0);
- SV* methcv = __nextcan(self, 0);
+ SV* methcv = __nextcan(aTHX_ self, 0);
PERL_UNUSED_VAR(items);
dMARK;
dAX;
SV* self = ST(0);
- SV* methcv = __nextcan(self, 1);
+ SV* methcv = __nextcan(aTHX_ self, 1);
PL_markstack_ptr++;
call_sv(methcv, GIMME_V);
dMARK;
dAX;
SV* self = ST(0);
- SV* methcv = __nextcan(self, 0);
+ SV* methcv = __nextcan(aTHX_ self, 0);
if(methcv == &PL_sv_undef) {
ST(0) = &PL_sv_undef;
MODULE = Class::C3::XS PACKAGE = Class::C3::XS
BOOT:
+ nmcache = get_hv("next::METHOD_CACHE", 1);
newXS("Class::C3::XS::calculateMRO", XS_Class_C3_XS_calculateMRO, __FILE__);
newXS("next::can", XS_next_can, __FILE__);
newXS("next::method", XS_next_method, __FILE__);