File Coverage

XS.xs
Criterion Covered Total %
statement 205 314 65.2
branch 117 252 46.4
condition n/a
subroutine n/a
pod n/a
total 322 566 56.8


line stmt bran cond sub pod time code
1              
2             #include "EXTERN.h"
3             #include "perl.h"
4             #include "XSUB.h"
5              
6             /* *********** ppport stuff */
7              
8             #ifndef PERL_UNUSED_VAR
9             # define PERL_UNUSED_VAR(x) ((void)x)
10             #endif
11              
12             #if defined(PERL_GCC_PEDANTIC)
13             # ifndef PERL_GCC_BRACE_GROUPS_FORBIDDEN
14             # define PERL_GCC_BRACE_GROUPS_FORBIDDEN
15             # endif
16             #endif
17              
18             #if defined(__GNUC__) && !defined(PERL_GCC_BRACE_GROUPS_FORBIDDEN) && !defined(__cplusplus)
19             # ifndef PERL_USE_GCC_BRACE_GROUPS
20             # define PERL_USE_GCC_BRACE_GROUPS
21             # endif
22             #endif
23              
24             #ifndef SvREFCNT_inc
25             # ifdef PERL_USE_GCC_BRACE_GROUPS
26             # define SvREFCNT_inc(sv) \
27             ({ \
28             SV * const _sv = (SV*)(sv); \
29             if (_sv) \
30             (SvREFCNT(_sv))++; \
31             _sv; \
32             })
33             # else
34             # define SvREFCNT_inc(sv) \
35             ((PL_Sv=(SV*)(sv)) ? (++(SvREFCNT(PL_Sv)),PL_Sv) : NULL)
36             # endif
37             #endif
38              
39             #ifndef dAX
40             # define dAX I32 ax = MARK - PL_stack_base + 1
41             #endif
42              
43             #ifndef dVAR
44             # define dVAR dNOOP
45             #endif
46              
47             #ifndef packWARN
48             # define packWARN(a) (a)
49             #endif
50              
51             /* *********** end ppport.h stuff */
52              
53             #ifndef SVfARG
54             # define SVfARG(p) ((void*)(p))
55             #endif
56              
57             /* Most of this code is backported from the bleadperl patch's
58             mro.c, and then modified to work with Class::C3's
59             internals.
60             */
61              
62             AV*
63 144           __mro_linear_isa_c3(pTHX_ HV* stash, HV* cache, I32 level)
64             {
65             AV* retval;
66             GV** gvp;
67             GV* gv;
68             AV* isa;
69             const char* stashname;
70             STRLEN stashname_len;
71 144           I32 made_mortal_cache = 0;
72              
73             assert(stash);
74              
75 144 50         stashname = HvNAME(stash);
    50          
    50          
    0          
    50          
    50          
76 144           stashname_len = strlen(stashname);
77 144 50         if (!stashname)
78 0           Perl_croak(aTHX_
79             "Can't linearize anonymous symbol table");
80              
81 144 50         if (level > 100)
82 0           Perl_croak(aTHX_ "Recursive inheritance detected in package '%s'",
83             stashname);
84              
85 144 100         if(!cache) {
86 33           cache = (HV*)sv_2mortal((SV*)newHV());
87 33           made_mortal_cache = 1;
88             }
89             else {
90 111           SV** cache_entry = hv_fetch(cache, stashname, stashname_len, 0);
91 111 100         if(cache_entry)
92 24           return (AV*)SvREFCNT_inc(*cache_entry);
93             }
94              
95             /* not in cache, make a new one */
96              
97 120           gvp = (GV**)hv_fetch(stash, "ISA", 3, FALSE);
98 120 100         isa = (gvp && (gv = *gvp) && gv != (GV*)&PL_sv_undef) ? GvAV(gv) : NULL;
    50          
    50          
99 149 100         if(isa && AvFILLp(isa) >= 0) {
    100          
100             SV** seqs_ptr;
101             I32 seqs_items;
102             HV* tails;
103 82           AV* const seqs = (AV*)sv_2mortal((SV*)newAV());
104             I32* heads;
105              
106             /* This builds @seqs, which is an array of arrays.
107             The members of @seqs are the MROs of
108             the members of @ISA, followed by @ISA itself.
109             */
110 82           I32 items = AvFILLp(isa) + 1;
111 82           SV** isa_ptr = AvARRAY(isa);
112 140 100         while(items--) {
113 111           SV* const isa_item = *isa_ptr++;
114 111           HV* const isa_item_stash = gv_stashsv(isa_item, 0);
115 111 50         if(!isa_item_stash) {
116             /* if no stash, make a temporary fake MRO
117             containing just itself */
118 0           AV* const isa_lin = newAV();
119 0           av_push(isa_lin, newSVsv(isa_item));
120 0           av_push(seqs, (SV*)isa_lin);
121             }
122             else {
123             /* recursion */
124 111           AV* const isa_lin = __mro_linear_isa_c3(aTHX_ isa_item_stash, cache, level + 1);
125              
126 111 100         if(items == 0 && AvFILLp(seqs) == -1) {
    100          
127             /* Only one parent class. For this case, the C3
128             linearisation is this class followed by the parent's
129             linearisation, so don't bother with the expensive
130             calculation. */
131             SV **svp;
132 53           I32 subrv_items = AvFILLp(isa_lin) + 1;
133 53           SV *const *subrv_p = AvARRAY(isa_lin);
134              
135             /* Hijack the allocated but unused array seqs to be the
136             return value. It's currently mortalised. */
137              
138 53           retval = seqs;
139              
140 53           av_extend(retval, subrv_items);
141 53           AvFILLp(retval) = subrv_items;
142 53           svp = AvARRAY(retval);
143              
144             /* First entry is this class. */
145 53           *svp++ = newSVpvn(stashname, stashname_len);
146              
147 112 100         while(subrv_items--) {
148             /* These values are unlikely to be shared hash key
149             scalars, so no point in adding code to optimising
150             for a case that is unlikely to be true.
151             (Or prove me wrong and do it.) */
152              
153 59           SV *const val = *subrv_p++;
154 59           *svp++ = newSVsv(val);
155             }
156              
157 53           SvREFCNT_dec(isa_lin);
158 53           SvREFCNT_inc(retval);
159              
160 53           goto done;
161             }
162 58           av_push(seqs, (SV*)isa_lin);
163             }
164             }
165 29           av_push(seqs, SvREFCNT_inc((SV*)isa));
166 29           tails = (HV*)sv_2mortal((SV*)newHV());
167              
168             /* This builds "heads", which as an array of integer array
169             indices, one per seq, which point at the virtual "head"
170             of the seq (initially zero) */
171 29 50         Newz(0xdead, heads, AvFILLp(seqs)+1, I32);
172              
173             /* This builds %tails, which has one key for every class
174             mentioned in the tail of any sequence in @seqs (tail meaning
175             everything after the first class, the "head"). The value
176             is how many times this key appears in the tails of @seqs.
177             */
178 29           seqs_ptr = AvARRAY(seqs);
179 29           seqs_items = AvFILLp(seqs) + 1;
180 116 100         while(seqs_items--) {
181 87           AV* const seq = (AV*)*seqs_ptr++;
182 87           I32 seq_items = AvFILLp(seq);
183 87 100         if(seq_items > 0) {
184 77           SV** seq_ptr = AvARRAY(seq) + 1;
185 168 100         while(seq_items--) {
186 91           SV* const seqitem = *seq_ptr++;
187             /* LVALUE fetch will create a new undefined SV if necessary
188             */
189 91           HE* const he = hv_fetch_ent(tails, seqitem, 1, 0);
190 91 50         if(he) {
191 91           SV* const val = HeVAL(he);
192             /* For 5.8.0 and later, sv_inc() with increment undef to
193             an IV of 1, which is what we want for a newly created
194             entry. However, for 5.6.x it will become an NV of
195             1.0, which confuses the SvIVX() checks above */
196 91 100         if(SvIOK(val)) {
197 27           SvIVX(val)++;
198             } else {
199 91           sv_setiv(val, 1);
200             }
201             } else {
202 0           croak("failed to store value in hash");
203             }
204             }
205             }
206             }
207              
208             /* Initialize retval to build the return value in */
209 29           retval = newAV();
210 29           av_push(retval, newSVpvn(stashname, stashname_len)); /* us first */
211              
212             /* This loop won't terminate until we either finish building
213             the MRO, or get an exception. */
214             while(1) {
215 122           SV* cand = NULL;
216 122           SV* winner = NULL;
217             int s;
218              
219             /* "foreach $seq (@seqs)" */
220 122           SV** const avptr = AvARRAY(seqs);
221 488 100         for(s = 0; s <= AvFILLp(seqs); s++) {
222             SV** svp;
223 366           AV * const seq = (AV*)(avptr[s]);
224             SV* seqhead;
225 366 100         if(!seq) continue; /* skip empty seqs */
226 240           svp = av_fetch(seq, heads[s], 0);
227 240           seqhead = *svp; /* seqhead = head of this seq */
228 240 100         if(!winner) {
229             HE* tail_entry;
230             SV* val;
231             /* if we haven't found a winner for this round yet,
232             and this seqhead is not in tails (or the count
233             for it in tails has dropped to zero), then this
234             seqhead is our new winner, and is added to the
235             final MRO immediately */
236 120           cand = seqhead;
237 120 100         if((tail_entry = hv_fetch_ent(tails, cand, 0, 0))
238 91 50         && (val = HeVAL(tail_entry))
239 91 100         && (SvIVX(val) > 0))
240 27           continue;
241 93           winner = newSVsv(cand);
242 93           av_push(retval, winner);
243             /* note however that even when we find a winner,
244             we continue looping over @seqs to do housekeeping */
245             }
246 213 100         if(!sv_cmp(seqhead, winner)) {
247             /* Once we have a winner (including the iteration
248             where we first found him), inc the head ptr
249             for any seq which had the winner as a head,
250             NULL out any seq which is now empty,
251             and adjust tails for consistency */
252              
253 178           const int new_head = ++heads[s];
254 178 100         if(new_head > AvFILLp(seq)) {
255 87           SvREFCNT_dec(avptr[s]);
256 87           avptr[s] = NULL;
257             }
258             else {
259             HE* tail_entry;
260             SV* val;
261             /* Because we know this new seqhead used to be
262             a tail, we can assume it is in tails and has
263             a positive value, which we need to dec */
264 91           svp = av_fetch(seq, new_head, 0);
265 91           seqhead = *svp;
266 91           tail_entry = hv_fetch_ent(tails, seqhead, 0, 0);
267 91           val = HeVAL(tail_entry);
268 91           sv_dec(val);
269             }
270             }
271             }
272              
273             /* if we found no candidates, we are done building the MRO.
274             !cand means no seqs have any entries left to check */
275 122 100         if(!cand) {
276 29           Safefree(heads);
277 29           break;
278             }
279              
280             /* If we had candidates, but nobody won, then the @ISA
281             hierarchy is not C3-incompatible */
282 93 50         if(!winner) {
283             SV *errmsg;
284             I32 i;
285             /* we have to do some cleanup before we croak */
286              
287 0           errmsg = newSVpvf("Inconsistent hierarchy during C3 merge of class '%s':\n\t"
288             "current merge results [\n", stashname);
289 0 0         for (i = 0; i <= av_len(retval); i++) {
290 0           SV **elem = av_fetch(retval, i, 0);
291 0           sv_catpvf(errmsg, "\t\t%"SVf",\n", SVfARG(*elem));
292             }
293 0           sv_catpvf(errmsg, "\t]\n\tmerging failed on '%"SVf"'", SVfARG(cand));
294              
295 0           SvREFCNT_dec(retval);
296 0           Safefree(heads);
297              
298 0           croak("%"SVf, SVfARG(errmsg));
299             }
300 93           }
301             }
302             else { /* @ISA was undefined or empty */
303             /* build a retval containing only ourselves */
304 38           retval = newAV();
305 38           av_push(retval, newSVpvn(stashname, stashname_len));
306             }
307              
308             done:
309             /* we don't want anyone modifying the cache entry but us,
310             and we do so by replacing it completely */
311 120           SvREADONLY_on(retval);
312              
313 120 100         if(!made_mortal_cache) {
314 87           SvREFCNT_inc(retval);
315 87 50         if(!hv_store(cache, stashname, stashname_len, (SV*)retval, 0)) {
316 0           croak("failed to store value in hash");
317             }
318             }
319              
320 120           return retval;
321             }
322              
323             STATIC I32
324 115           __dopoptosub_at(const PERL_CONTEXT *cxstk, I32 startingblock) {
325             I32 i;
326 147 100         for (i = startingblock; i >= 0; i--) {
327 124 100         if(CxTYPE((PERL_CONTEXT*)(&cxstk[i])) == CXt_SUB) return i;
328             }
329 23           return i;
330             }
331              
332             XS(XS_Class_C3_XS_nextcan);
333 27           XS(XS_Class_C3_XS_nextcan)
334             {
335 27           dVAR; dXSARGS;
336              
337 27           SV* self = ST(0);
338 27           const I32 throw_nomethod = SvIVX(ST(1));
339 27           register I32 cxix = cxstack_ix;
340 27           register const PERL_CONTEXT *ccstack = cxstack;
341 27           const PERL_SI *top_si = PL_curstackinfo;
342             HV* selfstash;
343             GV* cvgv;
344             SV *stashname;
345             const char *fq_subname;
346             const char *subname;
347             STRLEN fq_subname_len;
348             STRLEN stashname_len;
349             STRLEN subname_len;
350             SV* sv;
351             GV** gvp;
352             AV* linear_av;
353             SV** linear_svp;
354             HV* cstash;
355 27           GV* candidate = NULL;
356 27           CV* cand_cv = NULL;
357             const char *hvname;
358             I32 entries;
359             HV* nmcache;
360             HE* cache_entry;
361             SV* cachekey;
362             I32 i;
363              
364 27           SP -= items;
365              
366 27 100         if(sv_isobject(self))
367 1           selfstash = SvSTASH(SvRV(self));
368             else
369 26           selfstash = gv_stashsv(self, 0);
370              
371             assert(selfstash);
372              
373 27 50         hvname = HvNAME(selfstash);
    50          
    50          
    0          
    50          
    50          
374 27 50         if (!hvname)
375 0           Perl_croak(aTHX_ "Can't use anonymous symbol table for method lookup");
376              
377             /* This block finds the contextually-enclosing fully-qualified subname,
378             much like looking at (caller($i))[3] until you find a real sub that
379             isn't ANON, etc (also skips over pureperl next::method, etc) */
380 80 100         for(i = 0; i < 2; i++) {
381 54           cxix = __dopoptosub_at(ccstack, cxix);
382             for (;;) {
383             /* we may be in a higher stacklevel, so dig down deeper */
384 58 100         while (cxix < 0) {
385 1 50         if(top_si->si_type == PERLSI_MAIN)
386 1           Perl_croak(aTHX_ "next::method/next::can/maybe::next::method must be used in method context");
387 0           top_si = top_si->si_prev;
388 0           ccstack = top_si->si_cxstack;
389 0           cxix = __dopoptosub_at(ccstack, top_si->si_cxix);
390             }
391              
392 57 50         if(CxTYPE((PERL_CONTEXT*)(&ccstack[cxix])) != CXt_SUB
393 57 50         || (PL_DBsub && GvCV(PL_DBsub) && ccstack[cxix].blk_sub.cv == GvCV(PL_DBsub))) {
    50          
    0          
394 0           cxix = __dopoptosub_at(ccstack, cxix - 1);
395 0           continue;
396             }
397              
398             {
399 57           const I32 dbcxix = __dopoptosub_at(ccstack, cxix - 1);
400 57 50         if (PL_DBsub && GvCV(PL_DBsub) && dbcxix >= 0 && ccstack[dbcxix].blk_sub.cv == GvCV(PL_DBsub)) {
    50          
    0          
    0          
401 0 0         if(CxTYPE((PERL_CONTEXT*)(&ccstack[dbcxix])) != CXt_SUB) {
402 0           cxix = dbcxix;
403 0           continue;
404             }
405             }
406             }
407              
408 57           cvgv = CvGV(ccstack[cxix].blk_sub.cv);
409              
410 57 50         if(!isGV(cvgv)) {
411 0           cxix = __dopoptosub_at(ccstack, cxix - 1);
412 0           continue;
413             }
414              
415             /* we found a real sub here */
416 57           sv = sv_newmortal();
417              
418 57           gv_efullname3(sv, cvgv, NULL);
419              
420 57 50         if (SvPOK(sv)) {
421 57           fq_subname = SvPVX(sv);
422 57           fq_subname_len = SvCUR(sv);
423              
424 57           subname = strrchr(fq_subname, ':');
425             } else {
426 0           subname = NULL;
427             }
428              
429 57           subname = strrchr(fq_subname, ':');
430 57 50         if(!subname)
431 0           Perl_croak(aTHX_ "next::method/next::can/maybe::next::method cannot find enclosing method");
432              
433 57           subname++;
434 57           subname_len = fq_subname_len - (subname - fq_subname);
435 57 100         if(subname_len == 8 && strEQ(subname, "__ANON__")) {
    50          
436 4           cxix = __dopoptosub_at(ccstack, cxix - 1);
437 4           continue;
438             }
439 53           break;
440 4           }
441 53           cxix--;
442             }
443              
444             /* If we made it to here, we found our context */
445              
446             /* cachekey = "objpkg|context::method::name" */
447 26           cachekey = sv_2mortal(newSVpv(hvname, 0));
448 26           sv_catpvn(cachekey, "|", 1);
449 26           sv_catsv(cachekey, sv);
450              
451 26           nmcache = get_hv("next::METHOD_CACHE", 1);
452 26 100         if((cache_entry = hv_fetch_ent(nmcache, cachekey, 0, 0))) {
453 3           SV* val = HeVAL(cache_entry);
454 3 50         if(val == &PL_sv_undef) {
455 0 0         if(throw_nomethod)
456 0           Perl_croak(aTHX_ "No next::method '%s' found for %s", subname, hvname);
457 0           XSRETURN_EMPTY;
458             }
459 3 50         XPUSHs(sv_2mortal(newRV_inc(val)));
460 3           XSRETURN(1);
461             }
462              
463             /* beyond here is just for cache misses, so perf isn't as critical */
464              
465 23           stashname_len = subname - fq_subname - 2;
466 23           stashname = sv_2mortal(newSVpvn(fq_subname, stashname_len));
467              
468 23           linear_av = __mro_linear_isa_c3(aTHX_ selfstash, NULL, 0);
469              
470 23           linear_svp = AvARRAY(linear_av);
471 23           entries = AvFILLp(linear_av) + 1;
472              
473 30 50         while (entries--) {
474 30           SV* const linear_sv = *linear_svp++;
475             assert(linear_sv);
476 30 100         if(sv_eq(linear_sv, stashname))
477 23           break;
478             }
479              
480 23 50         if(entries > 0) {
481 23           SV* sub_sv = sv_2mortal(newSVpv(subname, subname_len));
482 23           HV* cc3_mro = get_hv("Class::C3::MRO", 0);
483              
484 42 100         while (entries--) {
485 38           SV* const linear_sv = *linear_svp++;
486             assert(linear_sv);
487              
488 38 50         if(cc3_mro) {
489 0           HE* he_cc3_mro_class = hv_fetch_ent(cc3_mro, linear_sv, 0, 0);
490 0 0         if(he_cc3_mro_class) {
491 0           SV* cc3_mro_class_sv = HeVAL(he_cc3_mro_class);
492 0 0         if(SvROK(cc3_mro_class_sv)) {
493 0           HV* cc3_mro_class = (HV*)SvRV(cc3_mro_class_sv);
494 0           SV** svp_cc3_mro_class_methods = hv_fetch(cc3_mro_class, "methods", 7, 0);
495 0 0         if(svp_cc3_mro_class_methods) {
496 0           SV* cc3_mro_class_methods_sv = *svp_cc3_mro_class_methods;
497 0 0         if(SvROK(cc3_mro_class_methods_sv)) {
498 0           HV* cc3_mro_class_methods = (HV*)SvRV(cc3_mro_class_methods_sv);
499 0 0         if(hv_exists_ent(cc3_mro_class_methods, sub_sv, 0))
500 0           continue;
501             }
502             }
503             }
504             }
505             }
506              
507 38           cstash = gv_stashsv(linear_sv, FALSE);
508              
509 38 50         if (!cstash) {
510 0 0         if (ckWARN(WARN_MISC))
511 0           Perl_warner(aTHX_ packWARN(WARN_MISC), "Can't locate package %"SVf" for @%s::ISA",
512             (void*)linear_sv, hvname);
513 0           continue;
514             }
515              
516             assert(cstash);
517              
518 38           gvp = (GV**)hv_fetch(cstash, subname, subname_len, 0);
519 38 100         if (!gvp) continue;
520              
521 19           candidate = *gvp;
522             assert(candidate);
523              
524 19 50         if (SvTYPE(candidate) != SVt_PVGV)
525 0           gv_init(candidate, cstash, subname, subname_len, TRUE);
526 19 50         if (SvTYPE(candidate) == SVt_PVGV && (cand_cv = GvCV(candidate)) && !GvCVGEN(candidate)) {
    50          
    50          
527 19           SvREFCNT_dec(linear_av);
528 19           SvREFCNT_inc((SV*)cand_cv);
529 19 50         if (!hv_store_ent(nmcache, cachekey, (SV*)cand_cv, 0)) {
530 0           croak("failed to store value in hash");
531             }
532 19 50         XPUSHs(sv_2mortal(newRV_inc((SV*)cand_cv)));
533 19           XSRETURN(1);
534             }
535             }
536             }
537              
538 4           SvREFCNT_dec(linear_av);
539 4 50         if (!hv_store_ent(nmcache, cachekey, &PL_sv_undef, 0)) {
540 0           croak("failed to store value in hash");
541             }
542 4 100         if(throw_nomethod)
543 1           Perl_croak(aTHX_ "No next::method '%s' found for %s", subname, hvname);
544 3           XSRETURN_EMPTY;
545             }
546              
547             XS(XS_Class_C3_XS_calculateMRO);
548 10           XS(XS_Class_C3_XS_calculateMRO)
549             {
550 10           dVAR; dXSARGS;
551              
552             SV* classname;
553             HV* class_stash;
554 10           HV* cache = NULL;
555             AV* res;
556             I32 res_items;
557             I32 ret_items;
558             SV** res_ptr;
559              
560 10 50         if(items < 1 || items > 2)
    50          
561 0           croak("Usage: calculateMRO(classname[, cache])");
562              
563 10           classname = ST(0);
564 10 50         if(items == 2) cache = (HV*)SvRV(ST(1));
565              
566 10           class_stash = gv_stashsv(classname, 0);
567 10 50         if(!class_stash)
568 0 0         Perl_croak(aTHX_ "No such class: '%s'!", SvPV_nolen(classname));
569              
570 10           res = __mro_linear_isa_c3(aTHX_ class_stash, cache, 0);
571              
572 10           res_items = ret_items = AvFILLp(res) + 1;
573 10           res_ptr = AvARRAY(res);
574              
575 10           SP -= items;
576              
577 55 100         while(res_items--) {
578 45           SV* res_item = *res_ptr++;
579 45 50         XPUSHs(sv_2mortal(newSVsv(res_item)));
580             }
581 10           SvREFCNT_dec(res);
582              
583 10           PUTBACK;
584              
585 10           return;
586             }
587              
588             XS(XS_Class_C3_XS_plsubgen);
589 0           XS(XS_Class_C3_XS_plsubgen)
590             {
591 0           dVAR; dXSARGS;
592              
593 0           SP -= items;
594 0 0         XPUSHs(sv_2mortal(newSViv(PL_sub_generation)));
595 0           PUTBACK;
596 0           return;
597             }
598              
599             XS(XS_Class_C3_XS_calc_mdt);
600 0           XS(XS_Class_C3_XS_calc_mdt)
601             {
602 0           dVAR; dXSARGS;
603              
604             SV* classname;
605             HV* cache;
606             HV* class_stash;
607             AV* class_mro;
608             HV* our_c3mro; /* $Class::C3::MRO{classname} */
609 0           SV* has_ovf = NULL;
610             HV* methods;
611             I32 mroitems;
612              
613             /* temps */
614             HV* hv;
615             HE* he;
616             SV** svp;
617              
618 0 0         if(items < 1 || items > 2)
    0          
619 0           croak("Usage: calculate_method_dispatch_table(classname[, cache])");
620              
621 0           classname = ST(0);
622 0           class_stash = gv_stashsv(classname, 0);
623 0 0         if(!class_stash)
624 0 0         Perl_croak(aTHX_ "No such class: '%s'!", SvPV_nolen(classname));
625              
626 0 0         if(items == 2) cache = (HV*)SvRV(ST(1));
627              
628 0           class_mro = __mro_linear_isa_c3(aTHX_ class_stash, cache, 0);
629              
630 0           our_c3mro = newHV();
631 0 0         if(!hv_store(our_c3mro, "MRO", 3, (SV*)newRV_noinc((SV*)class_mro), 0)) {
632 0           croak("failed to store value in hash");
633             }
634              
635 0           hv = get_hv("Class::C3::MRO", 1);
636 0 0         if(!hv_store_ent(hv, classname, (SV*)newRV_noinc((SV*)our_c3mro), 0)) {
637 0           croak("failed to store value in hash");
638             }
639              
640 0           methods = newHV();
641              
642             /* skip first entry */
643 0           mroitems = AvFILLp(class_mro);
644 0           svp = AvARRAY(class_mro) + 1;
645 0 0         while(mroitems--) {
646 0           SV* mro_class = *svp++;
647 0           HV* mro_stash = gv_stashsv(mro_class, 0);
648              
649 0 0         if(!mro_stash) continue;
650              
651 0 0         if(!has_ovf) {
652 0           SV** ovfp = hv_fetch(mro_stash, "()", 2, 0);
653 0 0         if(ovfp) has_ovf = *ovfp;
654             }
655              
656 0           hv_iterinit(mro_stash);
657 0 0         while((he = hv_iternext(mro_stash))) {
658             CV* code;
659             SV* mskey;
660             SV* msval;
661             HE* ourent;
662             HV* meth_hash;
663             SV* orig;
664              
665 0           mskey = hv_iterkeysv(he);
666 0 0         if(hv_exists_ent(methods, mskey, 0)) continue;
667              
668 0           msval = hv_iterval(mro_stash, he);
669 0 0         if(SvTYPE(msval) != SVt_PVGV || !(code = GvCVu(msval)))
    0          
    0          
670 0           continue;
671              
672 0 0         if((ourent = hv_fetch_ent(class_stash, mskey, 0, 0))) {
673 0           SV* val = HeVAL(ourent);
674 0 0         if(val && SvTYPE(val) == SVt_PVGV && GvCVu(val))
    0          
    0          
    0          
675 0           continue;
676             }
677              
678 0           meth_hash = newHV();
679 0           orig = newSVsv(mro_class);
680 0           sv_catpvn(orig, "::", 2);
681 0           sv_catsv(orig, mskey);
682 0 0         if( !hv_store(meth_hash, "orig", 4, orig, 0)
683 0 0         || !hv_store(meth_hash, "code", 4, newRV_inc((SV*)code), 0)
684 0 0         || !hv_store_ent(methods, mskey, newRV_noinc((SV*)meth_hash), 0) ) {
685 0           croak("failed to store value in hash");
686             }
687             }
688             }
689              
690 0 0         if(!hv_store(our_c3mro, "methods", 7, newRV_noinc((SV*)methods), 0)) {
691 0           croak("failed to store value in hash");
692             }
693 0 0         if(has_ovf) {
694 0 0         if(!hv_store(our_c3mro, "has_overload_fallback", 21, SvREFCNT_inc(has_ovf), 0)) {
695 0           croak("failed to store value in hash");
696             }
697             }
698 0           XSRETURN_EMPTY;
699             }
700              
701             MODULE = Class::C3::XS PACKAGE = Class::C3::XS
702              
703             PROTOTYPES: DISABLED
704              
705             BOOT:
706 12           newXS("Class::C3::XS::calculateMRO", XS_Class_C3_XS_calculateMRO, __FILE__);
707 12           newXS("Class::C3::XS::_plsubgen", XS_Class_C3_XS_plsubgen, __FILE__);
708 12           newXS("Class::C3::XS::_calculate_method_dispatch_table", XS_Class_C3_XS_calc_mdt, __FILE__);
709 12           newXS("Class::C3::XS::_nextcan", XS_Class_C3_XS_nextcan, __FILE__);
710