Move all mro:: XS functions from mro.c to ext/mro/mro.xs, except for
[p5sagit/p5-mst-13.2.git] / ext / mro / mro.xs
CommitLineData
b2685f0c 1#include "EXTERN.h"
2#include "perl.h"
3#include "XSUB.h"
4
5static AV*
6S_mro_get_linear_isa_c3(pTHX_ HV* stash, U32 level);
7
8static const struct mro_alg c3_alg =
9 {S_mro_get_linear_isa_c3, "c3", 2, 0, 0};
10
11/*
12=for apidoc mro_get_linear_isa_c3
13
14Returns the C3 linearization of @ISA
15the given stash. The return value is a read-only AV*.
16C<level> should be 0 (it is used internally in this
17function's recursion).
18
19You are responsible for C<SvREFCNT_inc()> on the
20return value if you plan to store it anywhere
21semi-permanently (otherwise it might be deleted
22out from under you the next time the cache is
23invalidated).
24
25=cut
26*/
27
28static AV*
29S_mro_get_linear_isa_c3(pTHX_ HV* stash, U32 level)
30{
31 AV* retval;
32 GV** gvp;
33 GV* gv;
34 AV* isa;
35 const HEK* stashhek;
36 struct mro_meta* meta;
37
38 assert(HvAUX(stash));
39
40 stashhek = HvNAME_HEK(stash);
41 if (!stashhek)
42 Perl_croak(aTHX_ "Can't linearize anonymous symbol table");
43
44 if (level > 100)
45 Perl_croak(aTHX_ "Recursive inheritance detected in package '%s'",
46 HEK_KEY(stashhek));
47
48 meta = HvMROMETA(stash);
49
50 /* return cache if valid */
51 if((retval = MUTABLE_AV(MRO_GET_PRIVATE_DATA(meta, &c3_alg)))) {
52 return retval;
53 }
54
55 /* not in cache, make a new one */
56
57 gvp = (GV**)hv_fetchs(stash, "ISA", FALSE);
58 isa = (gvp && (gv = *gvp) && isGV_with_GP(gv)) ? GvAV(gv) : NULL;
59
60 /* For a better idea how the rest of this works, see the much clearer
61 pure perl version in Algorithm::C3 0.01:
62 http://search.cpan.org/src/STEVAN/Algorithm-C3-0.01/lib/Algorithm/C3.pm
63 (later versions go about it differently than this code for speed reasons)
64 */
65
66 if(isa && AvFILLp(isa) >= 0) {
67 SV** seqs_ptr;
68 I32 seqs_items;
69 HV* const tails = MUTABLE_HV(sv_2mortal(MUTABLE_SV(newHV())));
70 AV *const seqs = MUTABLE_AV(sv_2mortal(MUTABLE_SV(newAV())));
71 I32* heads;
72
73 /* This builds @seqs, which is an array of arrays.
74 The members of @seqs are the MROs of
75 the members of @ISA, followed by @ISA itself.
76 */
77 I32 items = AvFILLp(isa) + 1;
78 SV** isa_ptr = AvARRAY(isa);
79 while(items--) {
80 SV* const isa_item = *isa_ptr++;
81 HV* const isa_item_stash = gv_stashsv(isa_item, 0);
82 if(!isa_item_stash) {
83 /* if no stash, make a temporary fake MRO
84 containing just itself */
85 AV* const isa_lin = newAV();
86 av_push(isa_lin, newSVsv(isa_item));
87 av_push(seqs, MUTABLE_SV(isa_lin));
88 }
89 else {
90 /* recursion */
91 AV* const isa_lin
92 = S_mro_get_linear_isa_c3(aTHX_ isa_item_stash, level + 1);
93 av_push(seqs, SvREFCNT_inc_simple_NN(MUTABLE_SV(isa_lin)));
94 }
95 }
96 av_push(seqs, SvREFCNT_inc_simple_NN(MUTABLE_SV(isa)));
97
98 /* This builds "heads", which as an array of integer array
99 indices, one per seq, which point at the virtual "head"
100 of the seq (initially zero) */
101 Newxz(heads, AvFILLp(seqs)+1, I32);
102
103 /* This builds %tails, which has one key for every class
104 mentioned in the tail of any sequence in @seqs (tail meaning
105 everything after the first class, the "head"). The value
106 is how many times this key appears in the tails of @seqs.
107 */
108 seqs_ptr = AvARRAY(seqs);
109 seqs_items = AvFILLp(seqs) + 1;
110 while(seqs_items--) {
111 AV *const seq = MUTABLE_AV(*seqs_ptr++);
112 I32 seq_items = AvFILLp(seq);
113 if(seq_items > 0) {
114 SV** seq_ptr = AvARRAY(seq) + 1;
115 while(seq_items--) {
116 SV* const seqitem = *seq_ptr++;
117 /* LVALUE fetch will create a new undefined SV if necessary
118 */
119 HE* const he = hv_fetch_ent(tails, seqitem, 1, 0);
120 if(he) {
121 SV* const val = HeVAL(he);
122 /* This will increment undef to 1, which is what we
123 want for a newly created entry. */
124 sv_inc(val);
125 }
126 }
127 }
128 }
129
130 /* Initialize retval to build the return value in */
131 retval = newAV();
132 av_push(retval, newSVhek(stashhek)); /* us first */
133
134 /* This loop won't terminate until we either finish building
135 the MRO, or get an exception. */
136 while(1) {
137 SV* cand = NULL;
138 SV* winner = NULL;
139 int s;
140
141 /* "foreach $seq (@seqs)" */
142 SV** const avptr = AvARRAY(seqs);
143 for(s = 0; s <= AvFILLp(seqs); s++) {
144 SV** svp;
145 AV * const seq = MUTABLE_AV(avptr[s]);
146 SV* seqhead;
147 if(!seq) continue; /* skip empty seqs */
148 svp = av_fetch(seq, heads[s], 0);
149 seqhead = *svp; /* seqhead = head of this seq */
150 if(!winner) {
151 HE* tail_entry;
152 SV* val;
153 /* if we haven't found a winner for this round yet,
154 and this seqhead is not in tails (or the count
155 for it in tails has dropped to zero), then this
156 seqhead is our new winner, and is added to the
157 final MRO immediately */
158 cand = seqhead;
159 if((tail_entry = hv_fetch_ent(tails, cand, 0, 0))
160 && (val = HeVAL(tail_entry))
161 && (SvIVX(val) > 0))
162 continue;
163 winner = newSVsv(cand);
164 av_push(retval, winner);
165 /* note however that even when we find a winner,
166 we continue looping over @seqs to do housekeeping */
167 }
168 if(!sv_cmp(seqhead, winner)) {
169 /* Once we have a winner (including the iteration
170 where we first found him), inc the head ptr
171 for any seq which had the winner as a head,
172 NULL out any seq which is now empty,
173 and adjust tails for consistency */
174
175 const int new_head = ++heads[s];
176 if(new_head > AvFILLp(seq)) {
177 SvREFCNT_dec(avptr[s]);
178 avptr[s] = NULL;
179 }
180 else {
181 HE* tail_entry;
182 SV* val;
183 /* Because we know this new seqhead used to be
184 a tail, we can assume it is in tails and has
185 a positive value, which we need to dec */
186 svp = av_fetch(seq, new_head, 0);
187 seqhead = *svp;
188 tail_entry = hv_fetch_ent(tails, seqhead, 0, 0);
189 val = HeVAL(tail_entry);
190 sv_dec(val);
191 }
192 }
193 }
194
195 /* if we found no candidates, we are done building the MRO.
196 !cand means no seqs have any entries left to check */
197 if(!cand) {
198 Safefree(heads);
199 break;
200 }
201
202 /* If we had candidates, but nobody won, then the @ISA
203 hierarchy is not C3-incompatible */
204 if(!winner) {
205 /* we have to do some cleanup before we croak */
206
207 SvREFCNT_dec(retval);
208 Safefree(heads);
209
210 Perl_croak(aTHX_ "Inconsistent hierarchy during C3 merge of class '%s': "
211 "merging failed on parent '%"SVf"'", HEK_KEY(stashhek), SVfARG(cand));
212 }
213 }
214 }
215 else { /* @ISA was undefined or empty */
216 /* build a retval containing only ourselves */
217 retval = newAV();
218 av_push(retval, newSVhek(stashhek));
219 }
220
221 /* we don't want anyone modifying the cache entry but us,
222 and we do so by replacing it completely */
223 SvREADONLY_on(retval);
224
225 return MUTABLE_AV(Perl_mro_set_private_data(aTHX_ meta, &c3_alg,
226 MUTABLE_SV(retval)));
227 return retval;
228}
229
230
231/* These two are static helpers for next::method and friends,
232 and re-implement a bunch of the code from pp_caller() in
233 a more efficient manner for this particular usage.
234*/
235
236static I32
237__dopoptosub_at(const PERL_CONTEXT *cxstk, I32 startingblock) {
238 I32 i;
239 for (i = startingblock; i >= 0; i--) {
240 if(CxTYPE((PERL_CONTEXT*)(&cxstk[i])) == CXt_SUB) return i;
241 }
242 return i;
243}
244
1e9bd118 245MODULE = mro PACKAGE = mro PREFIX = mro_
b2685f0c 246
247void
1e9bd118 248mro_get_linear_isa(...)
249 PROTOTYPE: $;$
250 PREINIT:
251 AV* RETVAL;
252 HV* class_stash;
253 SV* classname;
254 PPCODE:
255 if(items < 1 || items > 2)
256 croak_xs_usage(cv, "classname [, type ]");
257
258 classname = ST(0);
259 class_stash = gv_stashsv(classname, 0);
260
261 if(!class_stash) {
262 /* No stash exists yet, give them just the classname */
263 AV* isalin = newAV();
264 av_push(isalin, newSVsv(classname));
265 ST(0) = sv_2mortal(newRV_noinc(MUTABLE_SV(isalin)));
266 XSRETURN(1);
267 }
268 else if(items > 1) {
269 const struct mro_alg *const algo = Perl_mro_get_from_name(aTHX_ ST(1));
270 if (!algo)
271 Perl_croak(aTHX_ "Invalid mro name: '%"SVf"'", ST(1));
272 RETVAL = algo->resolve(aTHX_ class_stash, 0);
273 }
274 else {
275 RETVAL = mro_get_linear_isa(class_stash);
276 }
277 ST(0) = newRV_inc(MUTABLE_SV(RETVAL));
278 sv_2mortal(ST(0));
279 XSRETURN(1);
280
281void
282mro_set_mro(...)
283 PROTOTYPE: $$
284 PREINIT:
285 SV* classname;
286 const struct mro_alg *which;
287 HV* class_stash;
288 struct mro_meta* meta;
289 PPCODE:
290 if (items != 2)
291 croak_xs_usage(cv, "classname, type");
292
293 classname = ST(0);
294 class_stash = gv_stashsv(classname, GV_ADD);
295 if(!class_stash) Perl_croak(aTHX_ "Cannot create class: '%"SVf"'!", SVfARG(classname));
296 meta = HvMROMETA(class_stash);
297
298 Perl_mro_set_mro(aTHX_ meta, ST(1));
299
300 XSRETURN_EMPTY;
301
302void
303mro_get_mro(...)
304 PROTOTYPE: $
305 PREINIT:
306 SV* classname;
307 HV* class_stash;
308 PPCODE:
309 if (items != 1)
310 croak_xs_usage(cv, "classname");
311
312 classname = ST(0);
313 class_stash = gv_stashsv(classname, 0);
314
315 ST(0) = sv_2mortal(newSVpv(class_stash
316 ? HvMROMETA(class_stash)->mro_which->name
317 : "dfs", 0));
318 XSRETURN(1);
319
320void
321mro_get_isarev(...)
322 PROTOTYPE: $
323 PREINIT:
324 SV* classname;
325 HE* he;
326 HV* isarev;
327 AV* ret_array;
328 PPCODE:
329 if (items != 1)
330 croak_xs_usage(cv, "classname");
331
332 classname = ST(0);
333
334 he = hv_fetch_ent(PL_isarev, classname, 0, 0);
335 isarev = he ? MUTABLE_HV(HeVAL(he)) : NULL;
336
337 ret_array = newAV();
338 if(isarev) {
339 HE* iter;
340 hv_iterinit(isarev);
341 while((iter = hv_iternext(isarev)))
342 av_push(ret_array, newSVsv(hv_iterkeysv(iter)));
343 }
344 mXPUSHs(newRV_noinc(MUTABLE_SV(ret_array)));
345
346 PUTBACK;
347
348void
349mro_is_universal(...)
350 PROTOTYPE: $
351 PREINIT:
352 SV* classname;
353 HV* isarev;
354 char* classname_pv;
355 STRLEN classname_len;
356 HE* he;
357 PPCODE:
358 if (items != 1)
359 croak_xs_usage(cv, "classname");
360
361 classname = ST(0);
362
363 classname_pv = SvPV(classname,classname_len);
364
365 he = hv_fetch_ent(PL_isarev, classname, 0, 0);
366 isarev = he ? MUTABLE_HV(HeVAL(he)) : NULL;
367
368 if((classname_len == 9 && strEQ(classname_pv, "UNIVERSAL"))
369 || (isarev && hv_exists(isarev, "UNIVERSAL", 9)))
370 XSRETURN_YES;
371 else
372 XSRETURN_NO;
373
374
375void
376mro_invalidate_method_caches(...)
377 PROTOTYPE:
378 PPCODE:
379 if (items != 0)
380 croak_xs_usage(cv, "");
381
382 PL_sub_generation++;
383
384 XSRETURN_EMPTY;
385
386void
387mro_get_pkg_gen(...)
388 PROTOTYPE: $
389 PREINIT:
390 SV* classname;
391 HV* class_stash;
392 PPCODE:
393 if(items != 1)
394 croak_xs_usage(cv, "classname");
395
396 classname = ST(0);
397
398 class_stash = gv_stashsv(classname, 0);
399
400 mXPUSHi(class_stash ? HvMROMETA(class_stash)->pkg_gen : 0);
401
402 PUTBACK;
403
404void
405mro__nextcan(...)
b2685f0c 406 PREINIT:
407 SV* self = ST(0);
408 const I32 throw_nomethod = SvIVX(ST(1));
409 register I32 cxix = cxstack_ix;
410 register const PERL_CONTEXT *ccstack = cxstack;
411 const PERL_SI *top_si = PL_curstackinfo;
412 HV* selfstash;
413 SV *stashname;
414 const char *fq_subname;
415 const char *subname;
416 STRLEN stashname_len;
417 STRLEN subname_len;
418 SV* sv;
419 GV** gvp;
420 AV* linear_av;
421 SV** linear_svp;
422 const char *hvname;
423 I32 entries;
424 struct mro_meta* selfmeta;
425 HV* nmcache;
426 I32 i;
427 PPCODE:
428 PERL_UNUSED_ARG(cv);
429
430 if(sv_isobject(self))
431 selfstash = SvSTASH(SvRV(self));
432 else
433 selfstash = gv_stashsv(self, GV_ADD);
434
435 assert(selfstash);
436
437 hvname = HvNAME_get(selfstash);
438 if (!hvname)
439 Perl_croak(aTHX_ "Can't use anonymous symbol table for method lookup");
440
441 /* This block finds the contextually-enclosing fully-qualified subname,
442 much like looking at (caller($i))[3] until you find a real sub that
443 isn't ANON, etc (also skips over pureperl next::method, etc) */
444 for(i = 0; i < 2; i++) {
445 cxix = __dopoptosub_at(ccstack, cxix);
446 for (;;) {
447 GV* cvgv;
448 STRLEN fq_subname_len;
449
450 /* we may be in a higher stacklevel, so dig down deeper */
451 while (cxix < 0) {
452 if(top_si->si_type == PERLSI_MAIN)
453 Perl_croak(aTHX_ "next::method/next::can/maybe::next::method must be used in method context");
454 top_si = top_si->si_prev;
455 ccstack = top_si->si_cxstack;
456 cxix = __dopoptosub_at(ccstack, top_si->si_cxix);
457 }
458
459 if(CxTYPE((PERL_CONTEXT*)(&ccstack[cxix])) != CXt_SUB
460 || (PL_DBsub && GvCV(PL_DBsub) && ccstack[cxix].blk_sub.cv == GvCV(PL_DBsub))) {
461 cxix = __dopoptosub_at(ccstack, cxix - 1);
462 continue;
463 }
464
465 {
466 const I32 dbcxix = __dopoptosub_at(ccstack, cxix - 1);
467 if (PL_DBsub && GvCV(PL_DBsub) && dbcxix >= 0 && ccstack[dbcxix].blk_sub.cv == GvCV(PL_DBsub)) {
468 if(CxTYPE((PERL_CONTEXT*)(&ccstack[dbcxix])) != CXt_SUB) {
469 cxix = dbcxix;
470 continue;
471 }
472 }
473 }
474
475 cvgv = CvGV(ccstack[cxix].blk_sub.cv);
476
477 if(!isGV(cvgv)) {
478 cxix = __dopoptosub_at(ccstack, cxix - 1);
479 continue;
480 }
481
482 /* we found a real sub here */
483 sv = sv_2mortal(newSV(0));
484
485 gv_efullname3(sv, cvgv, NULL);
486
487 fq_subname = SvPVX(sv);
488 fq_subname_len = SvCUR(sv);
489
490 subname = strrchr(fq_subname, ':');
491 if(!subname)
492 Perl_croak(aTHX_ "next::method/next::can/maybe::next::method cannot find enclosing method");
493
494 subname++;
495 subname_len = fq_subname_len - (subname - fq_subname);
496 if(subname_len == 8 && strEQ(subname, "__ANON__")) {
497 cxix = __dopoptosub_at(ccstack, cxix - 1);
498 continue;
499 }
500 break;
501 }
502 cxix--;
503 }
504
505 /* If we made it to here, we found our context */
506
507 /* Initialize the next::method cache for this stash
508 if necessary */
509 selfmeta = HvMROMETA(selfstash);
510 if(!(nmcache = selfmeta->mro_nextmethod)) {
511 nmcache = selfmeta->mro_nextmethod = newHV();
512 }
513 else { /* Use the cached coderef if it exists */
514 HE* cache_entry = hv_fetch_ent(nmcache, sv, 0, 0);
515 if (cache_entry) {
516 SV* const val = HeVAL(cache_entry);
517 if(val == &PL_sv_undef) {
518 if(throw_nomethod)
519 Perl_croak(aTHX_ "No next::method '%s' found for %s", subname, hvname);
520 XSRETURN_EMPTY;
521 }
522 mXPUSHs(newRV_inc(val));
523 XSRETURN(1);
524 }
525 }
526
527 /* beyond here is just for cache misses, so perf isn't as critical */
528
529 stashname_len = subname - fq_subname - 2;
530 stashname = newSVpvn_flags(fq_subname, stashname_len, SVs_TEMP);
531
532 /* has ourselves at the top of the list */
533 linear_av = S_mro_get_linear_isa_c3(aTHX_ selfstash, 0);
534
535 linear_svp = AvARRAY(linear_av);
536 entries = AvFILLp(linear_av) + 1;
537
538 /* Walk down our MRO, skipping everything up
539 to the contextually enclosing class */
540 while (entries--) {
541 SV * const linear_sv = *linear_svp++;
542 assert(linear_sv);
543 if(sv_eq(linear_sv, stashname))
544 break;
545 }
546
547 /* Now search the remainder of the MRO for the
548 same method name as the contextually enclosing
549 method */
550 if(entries > 0) {
551 while (entries--) {
552 SV * const linear_sv = *linear_svp++;
553 HV* curstash;
554 GV* candidate;
555 CV* cand_cv;
556
557 assert(linear_sv);
558 curstash = gv_stashsv(linear_sv, FALSE);
559
560 if (!curstash) {
561 if (ckWARN(WARN_SYNTAX))
562 Perl_warner(aTHX_ packWARN(WARN_SYNTAX), "Can't locate package %"SVf" for @%s::ISA",
563 (void*)linear_sv, hvname);
564 continue;
565 }
566
567 assert(curstash);
568
569 gvp = (GV**)hv_fetch(curstash, subname, subname_len, 0);
570 if (!gvp) continue;
571
572 candidate = *gvp;
573 assert(candidate);
574
575 if (SvTYPE(candidate) != SVt_PVGV)
576 gv_init(candidate, curstash, subname, subname_len, TRUE);
577
578 /* Notably, we only look for real entries, not method cache
579 entries, because in C3 the method cache of a parent is not
580 valid for the child */
581 if (SvTYPE(candidate) == SVt_PVGV && (cand_cv = GvCV(candidate)) && !GvCVGEN(candidate)) {
582 SvREFCNT_inc_simple_void_NN(MUTABLE_SV(cand_cv));
583 (void)hv_store_ent(nmcache, newSVsv(sv), MUTABLE_SV(cand_cv), 0);
584 mXPUSHs(newRV_inc(MUTABLE_SV(cand_cv)));
585 XSRETURN(1);
586 }
587 }
588 }
589
590 (void)hv_store_ent(nmcache, newSVsv(sv), &PL_sv_undef, 0);
591 if(throw_nomethod)
592 Perl_croak(aTHX_ "No next::method '%s' found for %s", subname, hvname);
593 XSRETURN_EMPTY;
594
595BOOT:
596 Perl_mro_register(aTHX_ &c3_alg);