X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FClass%2FC3%2FXS.xs;h=2b3f59d44b78de42b55c31d66168e4b00c685aac;hb=b36f79e1df41c2538dfd15bd924284648ace99fa;hp=8e004cfbe68fd56adb0826938f060978c9f9cf38;hpb=b23e9cb9ccfb3d470c72b95818ce57c9b891381b;p=gitmo%2FClass-C3-XS.git diff --git a/lib/Class/C3/XS.xs b/lib/Class/C3/XS.xs index 8e004cf..2b3f59d 100644 --- a/lib/Class/C3/XS.xs +++ b/lib/Class/C3/XS.xs @@ -3,11 +3,14 @@ #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) { @@ -32,10 +35,12 @@ __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 */ @@ -62,7 +67,7 @@ __mro_linear_isa_c3(pTHX_ HV* stash, HV* cache, I32 level) 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))); } @@ -139,8 +144,8 @@ __mro_linear_isa_c3(pTHX_ HV* stash, HV* cache, I32 level) 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; } @@ -177,9 +182,8 @@ __nextcan(pTHX_ SV* self, I32 throw_nomethod) 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)); @@ -253,15 +257,12 @@ __nextcan(pTHX_ SV* self, I32 throw_nomethod) /* 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) @@ -270,15 +271,13 @@ __nextcan(pTHX_ SV* self, I32 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; @@ -291,9 +290,26 @@ __nextcan(pTHX_ SV* self, I32 throw_nomethod) } 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) { @@ -305,8 +321,6 @@ __nextcan(pTHX_ SV* self, I32 throw_nomethod) 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; @@ -317,15 +331,13 @@ __nextcan(pTHX_ SV* self, I32 throw_nomethod) 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; @@ -352,13 +364,12 @@ XS(XS_Class_C3_XS_calculateMRO) 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); @@ -385,7 +396,7 @@ XS(XS_next_can) #endif SV* self = ST(0); - SV* methcv = __nextcan(self, 0); + SV* methcv = __nextcan(aTHX_ self, 0); PERL_UNUSED_VAR(items); @@ -405,7 +416,7 @@ XS(XS_next_method) 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); @@ -417,7 +428,7 @@ XS(XS_maybe_next_method) 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; @@ -431,6 +442,7 @@ XS(XS_maybe_next_method) 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__);