X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=XS.xs;h=4ced6b89dc389ae99d75de5c7278365b613e8767;hb=a2051bf948cf922e8b2f80580cb86ce56dc36e45;hp=94ba2d84d2523d43f0aea4c5494287a3626c8c7f;hpb=b6bdbb4cd4eabccfea0b721257dffee4ca74adbc;p=gitmo%2FClass-C3-XS.git diff --git a/XS.xs b/XS.xs index 94ba2d8..4ced6b8 100644 --- a/XS.xs +++ b/XS.xs @@ -50,6 +50,10 @@ /* *********** end ppport.h stuff */ +#ifndef SVfARG +# define SVfARG(p) ((void*)(p)) +#endif + /* Most of this code is backported from the bleadperl patch's mro.c, and then modified to work with Class::C3's internals. @@ -95,7 +99,7 @@ __mro_linear_isa_c3(pTHX_ HV* stash, HV* cache, I32 level) if(isa && AvFILLp(isa) >= 0) { SV** seqs_ptr; I32 seqs_items; - HV* const tails = (HV*)sv_2mortal((SV*)newHV()); + HV* tails; AV* const seqs = (AV*)sv_2mortal((SV*)newAV()); I32* heads; @@ -118,10 +122,48 @@ __mro_linear_isa_c3(pTHX_ HV* stash, HV* cache, I32 level) else { /* recursion */ AV* const isa_lin = __mro_linear_isa_c3(aTHX_ isa_item_stash, cache, level + 1); + + if(items == 0 && AvFILLp(seqs) == -1) { + /* Only one parent class. For this case, the C3 + linearisation is this class followed by the parent's + linearisation, so don't bother with the expensive + calculation. */ + SV **svp; + I32 subrv_items = AvFILLp(isa_lin) + 1; + SV *const *subrv_p = AvARRAY(isa_lin); + + /* Hijack the allocated but unused array seqs to be the + return value. It's currently mortalised. */ + + retval = seqs; + + av_extend(retval, subrv_items); + AvFILLp(retval) = subrv_items; + svp = AvARRAY(retval); + + /* First entry is this class. */ + *svp++ = newSVpvn(stashname, stashname_len); + + while(subrv_items--) { + /* These values are unlikely to be shared hash key + scalars, so no point in adding code to optimising + for a case that is unlikely to be true. + (Or prove me wrong and do it.) */ + + SV *const val = *subrv_p++; + *svp++ = newSVsv(val); + } + + SvREFCNT_dec(isa_lin); + SvREFCNT_inc(retval); + + goto done; + } av_push(seqs, (SV*)isa_lin); } } av_push(seqs, SvREFCNT_inc((SV*)isa)); + tails = (HV*)sv_2mortal((SV*)newHV()); /* This builds "heads", which as an array of integer array indices, one per seq, which point at the virtual "head" @@ -142,15 +184,16 @@ __mro_linear_isa_c3(pTHX_ HV* stash, HV* cache, I32 level) SV** seq_ptr = AvARRAY(seq) + 1; while(seq_items--) { SV* const seqitem = *seq_ptr++; - HE* const he = hv_fetch_ent(tails, seqitem, 0, 0); - if(!he) { - if(!hv_store_ent(tails, seqitem, newSViv(1), 0)) { - croak("failed to store value in hash"); - } - } - else { + /* LVALUE fetch will create a new undefined SV if necessary + */ + HE* const he = hv_fetch_ent(tails, seqitem, 1, 0); + if(he) { SV* const val = HeVAL(he); + /* This will increment undef to 1, which is what we + want for a newly created entry. */ sv_inc(val); + } else { + croak("failed to store value in hash"); } } } @@ -256,6 +299,7 @@ __mro_linear_isa_c3(pTHX_ HV* stash, HV* cache, I32 level) av_push(retval, newSVpvn(stashname, stashname_len)); } +done: /* we don't want anyone modifying the cache entry but us, and we do so by replacing it completely */ SvREADONLY_on(retval); @@ -363,12 +407,18 @@ XS(XS_Class_C3_XS_nextcan) } /* we found a real sub here */ - sv = sv_2mortal(newSV(0)); + sv = sv_newmortal(); gv_efullname3(sv, cvgv, NULL); - fq_subname = SvPVX(sv); - fq_subname_len = SvCUR(sv); + if (SvPOK(sv)) { + fq_subname = SvPVX(sv); + fq_subname_len = SvCUR(sv); + + subname = strrchr(fq_subname, ':'); + } else { + subname = NULL; + } subname = strrchr(fq_subname, ':'); if(!subname) @@ -470,7 +520,7 @@ XS(XS_Class_C3_XS_nextcan) if (SvTYPE(candidate) == SVt_PVGV && (cand_cv = GvCV(candidate)) && !GvCVGEN(candidate)) { SvREFCNT_dec(linear_av); SvREFCNT_inc((SV*)cand_cv); - if (!hv_store_ent(nmcache, newSVsv(cachekey), (SV*)cand_cv, 0)) { + if (!hv_store_ent(nmcache, cachekey, (SV*)cand_cv, 0)) { croak("failed to store value in hash"); } XPUSHs(sv_2mortal(newRV_inc((SV*)cand_cv))); @@ -480,7 +530,7 @@ XS(XS_Class_C3_XS_nextcan) } SvREFCNT_dec(linear_av); - if (!hv_store_ent(nmcache, newSVsv(cachekey), &PL_sv_undef, 0)) { + if (!hv_store_ent(nmcache, cachekey, &PL_sv_undef, 0)) { croak("failed to store value in hash"); } if(throw_nomethod)