Use Newxc instead of casting by hand
[p5sagit/p5-mst-13.2.git] / mro.c
CommitLineData
e1a479c5 1/* mro.c
2 *
3 * Copyright (c) 2007 Brandon L Black
4 *
5 * You may distribute under the terms of either the GNU General Public
6 * License or the Artistic License, as specified in the README file.
7 *
8 */
9
10/*
cac98860 11 * "Which order shall we go in?" said Frodo. "Eldest first, or quickest first?
12 * You'll be last either way, Master Peregrin."
13 */
14
15/*
e1a479c5 16=head1 MRO Functions
17
18These functions are related to the method resolution order of perl classes
19
20=cut
21*/
22
23#include "EXTERN.h"
24#include "perl.h"
25
26struct mro_meta*
27Perl_mro_meta_init(pTHX_ HV* stash)
28{
9fe4aecf 29 struct mro_meta* newmeta;
e1a479c5 30
31 assert(stash);
32 assert(HvAUX(stash));
33 assert(!(HvAUX(stash)->xhv_mro_meta));
9fe4aecf 34 Newxc(newmeta, sizeof(struct mro_meta), char, struct mro_meta);
35 HvAUX(stash)->xhv_mro_meta = newmeta;
36 newmeta->sub_generation = 1;
e1a479c5 37
38 /* Manually flag UNIVERSAL as being universal.
39 This happens early in perl booting (when universal.c
40 does the newXS calls for UNIVERSAL::*), and infects
41 other packages as they are added to UNIVERSAL's MRO
42 */
43 if(HvNAMELEN_get(stash) == 9
44 && strEQ(HEK_KEY(HvAUX(stash)->xhv_name), "UNIVERSAL")) {
45 HvMROMETA(stash)->is_universal = 1;
46 }
47
48 return newmeta;
49}
50
51#if defined(USE_ITHREADS)
52
53/* for sv_dup on new threads */
54struct mro_meta*
55Perl_mro_meta_dup(pTHX_ struct mro_meta* smeta, CLONE_PARAMS* param)
56{
e1a479c5 57 struct mro_meta* newmeta;
58
59 assert(smeta);
60
9fe4aecf 61 Newxc(newmeta, sizeof(struct mro_meta), char, struct mro_meta);
e1a479c5 62
63 newmeta->mro_which = smeta->mro_which;
64 newmeta->sub_generation = smeta->sub_generation;
65 newmeta->is_universal = smeta->is_universal;
66 newmeta->fake = smeta->fake;
67 newmeta->mro_linear_dfs = smeta->mro_linear_dfs
68 ? (AV*) SvREFCNT_inc(sv_dup((SV*)smeta->mro_linear_dfs, param))
69 : 0;
70 newmeta->mro_linear_c3 = smeta->mro_linear_c3
71 ? (AV*) SvREFCNT_inc(sv_dup((SV*)smeta->mro_linear_c3, param))
72 : 0;
73 newmeta->mro_isarev = smeta->mro_isarev
74 ? (HV*) SvREFCNT_inc(sv_dup((SV*)smeta->mro_isarev, param))
75 : 0;
76 newmeta->mro_nextmethod = smeta->mro_nextmethod
77 ? (HV*) SvREFCNT_inc(sv_dup((SV*)smeta->mro_nextmethod, param))
78 : 0;
79
80 return newmeta;
81}
82
83#endif /* USE_ITHREADS */
84
85/*
86=for apidoc mro_get_linear_isa_dfs
87
88Returns the Depth-First Search linearization of @ISA
89the given stash. The return value is a read-only AV*.
90C<level> should be 0 (it is used internally in this
91function's recursion).
92
93=cut
94*/
95AV*
96Perl_mro_get_linear_isa_dfs(pTHX_ HV *stash, I32 level)
97{
98 AV* retval;
99 GV** gvp;
100 GV* gv;
101 AV* av;
102 SV** svp;
103 I32 items;
104 AV* subrv;
105 SV** subrv_p;
106 I32 subrv_items;
107 const char* stashname;
108 struct mro_meta* meta;
109
110 assert(stash);
111 assert(HvAUX(stash));
112
113 stashname = HvNAME_get(stash);
114 if (!stashname)
115 Perl_croak(aTHX_
116 "Can't linearize anonymous symbol table");
117
118 if (level > 100)
119 Perl_croak(aTHX_ "Recursive inheritance detected in package '%s'",
120 stashname);
121
122 meta = HvMROMETA(stash);
123 if((retval = meta->mro_linear_dfs)) {
124 /* return cache if valid */
125 return retval;
126 }
127
128 /* not in cache, make a new one */
129 retval = newAV();
130 av_push(retval, newSVpv(stashname, 0)); /* add ourselves at the top */
131
132 gvp = (GV**)hv_fetchs(stash, "ISA", FALSE);
133 av = (gvp && (gv = *gvp) && isGV_with_GP(gv)) ? GvAV(gv) : NULL;
134
135 if(av) {
136 HV* stored = (HV*)sv_2mortal((SV*)newHV());
137 svp = AvARRAY(av);
138 items = AvFILLp(av) + 1;
139 while (items--) {
140 SV* const sv = *svp++;
141 HV* const basestash = gv_stashsv(sv, 0);
142
143 if (!basestash) {
144 if(!hv_exists_ent(stored, sv, 0)) {
145 av_push(retval, newSVsv(sv));
146 hv_store_ent(stored, sv, &PL_sv_undef, 0);
147 }
148 }
149 else {
150 subrv = mro_get_linear_isa_dfs(basestash, level + 1);
151 subrv_p = AvARRAY(subrv);
152 subrv_items = AvFILLp(subrv) + 1;
153 while(subrv_items--) {
154 SV* subsv = *subrv_p++;
155 if(!hv_exists_ent(stored, subsv, 0)) {
156 av_push(retval, newSVsv(subsv));
157 hv_store_ent(stored, subsv, &PL_sv_undef, 0);
158 }
159 }
160 }
161 }
162 }
163
164 SvREADONLY_on(retval);
165 meta->mro_linear_dfs = retval;
166 return retval;
167}
168
169/*
170=for apidoc mro_get_linear_isa_c3
171
172Returns the C3 linearization of @ISA
173the given stash. The return value is a read-only AV*.
174C<level> should be 0 (it is used internally in this
175function's recursion).
176
177=cut
178*/
179
180AV*
181Perl_mro_get_linear_isa_c3(pTHX_ HV* stash, I32 level)
182{
183 AV* retval;
184 GV** gvp;
185 GV* gv;
186 AV* isa;
187 const char* stashname;
188 STRLEN stashname_len;
189 struct mro_meta* meta;
190
191 assert(stash);
192 assert(HvAUX(stash));
193
194 stashname = HvNAME_get(stash);
195 stashname_len = HvNAMELEN_get(stash);
196 if (!stashname)
197 Perl_croak(aTHX_
198 "Can't linearize anonymous symbol table");
199
200 if (level > 100)
201 Perl_croak(aTHX_ "Recursive inheritance detected in package '%s'",
202 stashname);
203
204 meta = HvMROMETA(stash);
205 if((retval = meta->mro_linear_c3)) {
206 /* return cache if valid */
207 return retval;
208 }
209
210 /* not in cache, make a new one */
211
212 retval = newAV();
213 av_push(retval, newSVpvn(stashname, stashname_len)); /* us first */
214
215 gvp = (GV**)hv_fetchs(stash, "ISA", FALSE);
216 isa = (gvp && (gv = *gvp) && isGV_with_GP(gv)) ? GvAV(gv) : NULL;
217
218 if(isa && AvFILLp(isa) >= 0) {
219 SV** seqs_ptr;
220 I32 seqs_items;
221 HV* tails = (HV*)sv_2mortal((SV*)newHV());
222 AV* seqs = (AV*)sv_2mortal((SV*)newAV());
223 I32 items = AvFILLp(isa) + 1;
224 SV** isa_ptr = AvARRAY(isa);
225 while(items--) {
226 AV* isa_lin;
227 SV* isa_item = *isa_ptr++;
228 HV* isa_item_stash = gv_stashsv(isa_item, 0);
229 if(!isa_item_stash) {
230 isa_lin = newAV();
231 av_push(isa_lin, newSVsv(isa_item));
232 }
233 else {
234 isa_lin = mro_get_linear_isa_c3(isa_item_stash, level + 1); /* recursion */
235 }
236 av_push(seqs, (SV*)av_make(AvFILLp(isa_lin)+1, AvARRAY(isa_lin)));
237 }
238 av_push(seqs, (SV*)av_make(AvFILLp(isa)+1, AvARRAY(isa)));
239
240 seqs_ptr = AvARRAY(seqs);
241 seqs_items = AvFILLp(seqs) + 1;
242 while(seqs_items--) {
243 AV* seq = (AV*)*seqs_ptr++;
244 I32 seq_items = AvFILLp(seq);
245 if(seq_items > 0) {
246 SV** seq_ptr = AvARRAY(seq) + 1;
247 while(seq_items--) {
248 SV* seqitem = *seq_ptr++;
249 HE* he = hv_fetch_ent(tails, seqitem, 0, 0);
250 if(!he) {
251 hv_store_ent(tails, seqitem, newSViv(1), 0);
252 }
253 else {
254 SV* val = HeVAL(he);
255 sv_inc(val);
256 }
257 }
258 }
259 }
260
261 while(1) {
262 SV* seqhead = NULL;
263 SV* cand = NULL;
264 SV* winner = NULL;
265 SV* val;
266 HE* tail_entry;
267 AV* seq;
268 SV** avptr = AvARRAY(seqs);
269 items = AvFILLp(seqs)+1;
270 while(items--) {
271 SV** svp;
272 seq = (AV*)*avptr++;
273 if(AvFILLp(seq) < 0) continue;
274 svp = av_fetch(seq, 0, 0);
275 seqhead = *svp;
276 if(!winner) {
277 cand = seqhead;
278 if((tail_entry = hv_fetch_ent(tails, cand, 0, 0))
279 && (val = HeVAL(tail_entry))
280 && (SvIVx(val) > 0))
281 continue;
282 winner = newSVsv(cand);
283 av_push(retval, winner);
284 }
285 if(!sv_cmp(seqhead, winner)) {
286
287 /* this is basically shift(@seq) in void context */
288 SvREFCNT_dec(*AvARRAY(seq));
289 *AvARRAY(seq) = &PL_sv_undef;
290 AvARRAY(seq) = AvARRAY(seq) + 1;
291 AvMAX(seq)--;
292 AvFILLp(seq)--;
293
294 if(AvFILLp(seq) < 0) continue;
295 svp = av_fetch(seq, 0, 0);
296 seqhead = *svp;
297 tail_entry = hv_fetch_ent(tails, seqhead, 0, 0);
298 val = HeVAL(tail_entry);
299 sv_dec(val);
300 }
301 }
302 if(!cand) break;
303 if(!winner) {
304 SvREFCNT_dec(retval);
305 Perl_croak(aTHX_ "Inconsistent hierarchy during C3 merge of class '%s': "
306 "merging failed on parent '%"SVf"'", stashname, SVfARG(cand));
307 }
308 }
309 }
310
311 SvREADONLY_on(retval);
312 meta->mro_linear_c3 = retval;
313 return retval;
314}
315
316/*
317=for apidoc mro_get_linear_isa
318
319Returns either C<mro_get_linear_isa_c3> or
320C<mro_get_linear_isa_dfs> for the given stash,
321dependant upon which MRO is in effect
322for that stash. The return value is a
323read-only AV*.
324
325=cut
326*/
327AV*
328Perl_mro_get_linear_isa(pTHX_ HV *stash)
329{
330 struct mro_meta* meta;
331 assert(stash);
332 assert(HvAUX(stash));
333
334 meta = HvMROMETA(stash);
335 if(meta->mro_which == MRO_DFS) {
336 return mro_get_linear_isa_dfs(stash, 0);
337 } else if(meta->mro_which == MRO_C3) {
338 return mro_get_linear_isa_c3(stash, 0);
339 } else {
14f97ce6 340 Perl_croak(aTHX_ "panic: invalid MRO!");
e1a479c5 341 }
342}
343
344/*
345=for apidoc mro_isa_changed_in
346
347Takes the neccesary steps (cache invalidations, mostly)
348when the @ISA of the given package has changed. Invoked
349by the C<setisa> magic, should not need to invoke directly.
350
351=cut
352*/
353void
354Perl_mro_isa_changed_in(pTHX_ HV* stash)
355{
356 dVAR;
357 HV* isarev;
358 AV* linear_mro;
359 HE* iter;
360 SV** svp;
361 I32 items;
362 struct mro_meta* meta;
363 char* stashname;
364
365 stashname = HvNAME_get(stash);
366
367 /* wipe out the cached linearizations for this stash */
368 meta = HvMROMETA(stash);
369 SvREFCNT_dec((SV*)meta->mro_linear_dfs);
370 SvREFCNT_dec((SV*)meta->mro_linear_c3);
371 meta->mro_linear_dfs = NULL;
372 meta->mro_linear_c3 = NULL;
373
374 /* Wipe the global method cache if this package
375 is UNIVERSAL or one of its parents */
376 if(meta->is_universal)
377 PL_sub_generation++;
378
379 /* Wipe the local method cache otherwise */
380 else
381 meta->sub_generation++;
382
383 /* wipe next::method cache too */
384 if(meta->mro_nextmethod) hv_clear(meta->mro_nextmethod);
385
386 /* Iterate the isarev (classes that are our children),
387 wiping out their linearization and method caches */
388 if((isarev = meta->mro_isarev)) {
389 hv_iterinit(isarev);
390 while((iter = hv_iternext(isarev))) {
391 SV* revkey = hv_iterkeysv(iter);
392 HV* revstash = gv_stashsv(revkey, 0);
393 struct mro_meta* revmeta = HvMROMETA(revstash);
394 SvREFCNT_dec((SV*)revmeta->mro_linear_dfs);
395 SvREFCNT_dec((SV*)revmeta->mro_linear_c3);
396 revmeta->mro_linear_dfs = NULL;
397 revmeta->mro_linear_c3 = NULL;
398 if(!meta->is_universal)
399 revmeta->sub_generation++;
400 if(revmeta->mro_nextmethod)
401 hv_clear(revmeta->mro_nextmethod);
402 }
403 }
404
405 /* we're starting at the 2nd element, skipping ourselves here */
406 linear_mro = mro_get_linear_isa(stash);
407 svp = AvARRAY(linear_mro) + 1;
408 items = AvFILLp(linear_mro);
409 while (items--) {
410 SV* const sv = *svp++;
411 struct mro_meta* mrometa;
412 HV* mroisarev;
413
414 HV* mrostash = gv_stashsv(sv, 0);
415 if(!mrostash) {
416 mrostash = gv_stashsv(sv, GV_ADD);
417 /*
418 We created the package on the fly, so
419 that we could store isarev information.
420 This flag lets gv_fetchmeth know about it,
421 so that it can still generate the very useful
422 "Can't locate package Foo for @Bar::ISA" warning.
423 */
424 HvMROMETA(mrostash)->fake = 1;
425 }
426
427 mrometa = HvMROMETA(mrostash);
428 mroisarev = mrometa->mro_isarev;
429
430 /* is_universal is viral */
431 if(meta->is_universal)
432 mrometa->is_universal = 1;
433
434 if(!mroisarev)
435 mroisarev = mrometa->mro_isarev = newHV();
436
437 if(!hv_exists(mroisarev, stashname, strlen(stashname)))
438 hv_store(mroisarev, stashname, strlen(stashname), &PL_sv_yes, 0);
439
440 if(isarev) {
441 hv_iterinit(isarev);
442 while((iter = hv_iternext(isarev))) {
443 SV* revkey = hv_iterkeysv(iter);
444 if(!hv_exists_ent(mroisarev, revkey, 0))
445 hv_store_ent(mroisarev, revkey, &PL_sv_yes, 0);
446 }
447 }
448 }
449}
450
451/*
452=for apidoc mro_method_changed_in
453
454Like C<mro_isa_changed_in>, but invalidates method
455caching on any child classes of the given stash, so
456that they might notice the changes in this one.
457
458Ideally, all instances of C<PL_sub_generation++> in
459the perl source should be replaced by calls to this.
460Some already are, but some are more difficult to
461replace.
462
463Perl has always had problems with method caches
464getting out of sync when one directly manipulates
465stashes via things like C<%{Foo::} = %{Bar::}> or
466C<${Foo::}{bar} = ...> or the equivalent. If
467you do this in core or XS code, call this afterwards
468on the destination stash to get things back in sync.
469
470If you're doing such a thing from pure perl, use
471C<mro::method_changed_in(classname)>, which
472just calls this.
473
474=cut
475*/
476void
477Perl_mro_method_changed_in(pTHX_ HV *stash)
478{
479 struct mro_meta* meta = HvMROMETA(stash);
480 HV* isarev;
481 HE* iter;
482
483 /* If stash is UNIVERSAL, or one of UNIVERSAL's parents,
484 invalidate all method caches globally */
485 if(meta->is_universal) {
486 PL_sub_generation++;
487 return;
488 }
489
490 /* else, invalidate the method caches of all child classes,
491 but not itself */
492 if((isarev = meta->mro_isarev)) {
493 hv_iterinit(isarev);
494 while((iter = hv_iternext(isarev))) {
495 SV* revkey = hv_iterkeysv(iter);
496 HV* revstash = gv_stashsv(revkey, 0);
497 struct mro_meta* mrometa = HvMROMETA(revstash);
498 mrometa->sub_generation++;
499 if(mrometa->mro_nextmethod)
500 hv_clear(mrometa->mro_nextmethod);
501 }
502 }
503}
504
505/* These two are static helpers for next::method and friends,
506 and re-implement a bunch of the code from pp_caller() in
507 a more efficient manner for this particular usage.
508*/
509
510STATIC I32
511__dopoptosub_at(const PERL_CONTEXT *cxstk, I32 startingblock) {
512 I32 i;
513 for (i = startingblock; i >= 0; i--) {
514 if(CxTYPE((PERL_CONTEXT*)(&cxstk[i])) == CXt_SUB) return i;
515 }
516 return i;
517}
518
519STATIC SV*
520__nextcan(pTHX_ SV* self, I32 throw_nomethod)
521{
522 register I32 cxix;
523 register const PERL_CONTEXT *ccstack = cxstack;
524 const PERL_SI *top_si = PL_curstackinfo;
525 HV* selfstash;
526 GV* cvgv;
527 SV *stashname;
528 const char *fq_subname;
529 const char *subname;
530 STRLEN fq_subname_len;
531 STRLEN stashname_len;
532 STRLEN subname_len;
533 SV* sv;
534 GV** gvp;
535 AV* linear_av;
536 SV** linear_svp;
537 SV* linear_sv;
538 HV* curstash;
539 GV* candidate = NULL;
540 CV* cand_cv = NULL;
541 const char *hvname;
542 I32 items;
543 struct mro_meta* selfmeta;
544 HV* nmcache;
545 HE* cache_entry;
546
547 if(sv_isobject(self))
548 selfstash = SvSTASH(SvRV(self));
549 else
550 selfstash = gv_stashsv(self, 0);
551
552 assert(selfstash);
553
554 hvname = HvNAME_get(selfstash);
555 if (!hvname)
556 Perl_croak(aTHX_ "Can't use anonymous symbol table for method lookup");
557
558 cxix = __dopoptosub_at(cxstack, cxstack_ix);
559
560 /* This block finds the contextually-enclosing fully-qualified subname,
561 much like looking at (caller($i))[3] until you find a real sub that
562 isn't ANON, etc */
563 for (;;) {
564 /* we may be in a higher stacklevel, so dig down deeper */
565 while (cxix < 0) {
566 if(top_si->si_type == PERLSI_MAIN)
567 Perl_croak(aTHX_ "next::method/next::can/maybe::next::method must be used in method context");
568 top_si = top_si->si_prev;
569 ccstack = top_si->si_cxstack;
570 cxix = __dopoptosub_at(ccstack, top_si->si_cxix);
571 }
572
573 if(CxTYPE((PERL_CONTEXT*)(&ccstack[cxix])) != CXt_SUB
574 || (PL_DBsub && GvCV(PL_DBsub) && ccstack[cxix].blk_sub.cv == GvCV(PL_DBsub))) {
575 cxix = __dopoptosub_at(ccstack, cxix - 1);
576 continue;
577 }
578
579 {
580 const I32 dbcxix = __dopoptosub_at(ccstack, cxix - 1);
581 if (PL_DBsub && GvCV(PL_DBsub) && dbcxix >= 0 && ccstack[dbcxix].blk_sub.cv == GvCV(PL_DBsub)) {
582 if(CxTYPE((PERL_CONTEXT*)(&ccstack[dbcxix])) != CXt_SUB) {
583 cxix = dbcxix;
584 continue;
585 }
586 }
587 }
588
589 cvgv = CvGV(ccstack[cxix].blk_sub.cv);
590
591 if(!isGV(cvgv)) {
592 cxix = __dopoptosub_at(ccstack, cxix - 1);
593 continue;
594 }
595
596 /* we found a real sub here */
597 sv = sv_2mortal(newSV(0));
598
599 gv_efullname3(sv, cvgv, NULL);
600
601 fq_subname = SvPVX(sv);
602 fq_subname_len = SvCUR(sv);
603
604 subname = strrchr(fq_subname, ':');
605 if(!subname)
606 Perl_croak(aTHX_ "next::method/next::can/maybe::next::method cannot find enclosing method");
607
608 subname++;
609 subname_len = fq_subname_len - (subname - fq_subname);
610 if(subname_len == 8 && strEQ(subname, "__ANON__")) {
611 cxix = __dopoptosub_at(ccstack, cxix - 1);
612 continue;
613 }
614 break;
615 }
616
617 /* If we made it to here, we found our context */
618
619 selfmeta = HvMROMETA(selfstash);
620 if(!(nmcache = selfmeta->mro_nextmethod)) {
621 nmcache = selfmeta->mro_nextmethod = newHV();
622 }
623
624 if((cache_entry = hv_fetch_ent(nmcache, sv, 0, 0))) {
625 SV* val = HeVAL(cache_entry);
626 if(val == &PL_sv_undef) {
627 if(throw_nomethod)
628 Perl_croak(aTHX_ "No next::method '%s' found for %s", subname, hvname);
629 }
630 return val;
631 }
632
633 /* beyond here is just for cache misses, so perf isn't as critical */
634
635 stashname_len = subname - fq_subname - 2;
636 stashname = sv_2mortal(newSVpvn(fq_subname, stashname_len));
637
638 linear_av = mro_get_linear_isa_c3(selfstash, 0); /* has ourselves at the top of the list */
639
640 linear_svp = AvARRAY(linear_av);
641 items = AvFILLp(linear_av) + 1;
642
643 while (items--) {
644 linear_sv = *linear_svp++;
645 assert(linear_sv);
646 if(sv_eq(linear_sv, stashname))
647 break;
648 }
649
650 if(items > 0) {
651 while (items--) {
652 linear_sv = *linear_svp++;
653 assert(linear_sv);
654 curstash = gv_stashsv(linear_sv, FALSE);
655
656 if (!curstash || (HvMROMETA(curstash)->fake && !HvFILL(curstash))) {
b0c482e3 657 if (ckWARN(WARN_SYNTAX))
658 Perl_warner(aTHX_ packWARN(WARN_SYNTAX), "Can't locate package %"SVf" for @%s::ISA",
e1a479c5 659 (void*)linear_sv, hvname);
660 continue;
661 }
662
663 assert(curstash);
664
665 gvp = (GV**)hv_fetch(curstash, subname, subname_len, 0);
666 if (!gvp) continue;
667
668 candidate = *gvp;
669 assert(candidate);
670
671 if (SvTYPE(candidate) != SVt_PVGV)
672 gv_init(candidate, curstash, subname, subname_len, TRUE);
673 if (SvTYPE(candidate) == SVt_PVGV && (cand_cv = GvCV(candidate)) && !GvCVGEN(candidate)) {
674 SvREFCNT_inc_simple_void_NN((SV*)cand_cv);
675 hv_store_ent(nmcache, newSVsv(sv), (SV*)cand_cv, 0);
676 return (SV*)cand_cv;
677 }
678 }
679 }
680
681 hv_store_ent(nmcache, newSVsv(sv), &PL_sv_undef, 0);
682 if(throw_nomethod)
683 Perl_croak(aTHX_ "No next::method '%s' found for %s", subname, hvname);
684 return &PL_sv_undef;
685}
686
687#include "XSUB.h"
688
689XS(XS_mro_get_linear_isa);
690XS(XS_mro_set_mro);
691XS(XS_mro_get_mro);
692XS(XS_mro_get_isarev);
693XS(XS_mro_is_universal);
694XS(XS_mro_get_global_sub_generation);
695XS(XS_mro_invalidate_all_method_caches);
696XS(XS_mro_get_sub_generation);
697XS(XS_mro_method_changed_in);
698XS(XS_next_can);
699XS(XS_next_method);
700XS(XS_maybe_next_method);
701
702void
703Perl_boot_core_mro(pTHX)
704{
705 dVAR;
706 static const char file[] = __FILE__;
707
708 newXSproto("mro::get_linear_isa", XS_mro_get_linear_isa, file, "$;$");
709 newXSproto("mro::set_mro", XS_mro_set_mro, file, "$$");
710 newXSproto("mro::get_mro", XS_mro_get_mro, file, "$");
711 newXSproto("mro::get_isarev", XS_mro_get_isarev, file, "$");
712 newXSproto("mro::is_universal", XS_mro_is_universal, file, "$");
713 newXSproto("mro::get_global_sub_generation", XS_mro_get_global_sub_generation, file, "");
714 newXSproto("mro::invalidate_all_method_caches", XS_mro_invalidate_all_method_caches, file, "");
715 newXSproto("mro::get_sub_generation", XS_mro_get_sub_generation, file, "$");
716 newXSproto("mro::method_changed_in", XS_mro_method_changed_in, file, "$");
717 newXS("next::can", XS_next_can, file);
718 newXS("next::method", XS_next_method, file);
719 newXS("maybe::next::method", XS_maybe_next_method, file);
720}
721
722XS(XS_mro_get_linear_isa) {
723 dVAR;
724 dXSARGS;
725 AV* RETVAL;
726 HV* class_stash;
727 SV* classname;
728
729 PERL_UNUSED_ARG(cv);
730
731 if(items < 1 || items > 2)
732 Perl_croak(aTHX_ "Usage: mro::get_linear_isa(classname [, type ])");
733
734 classname = ST(0);
735 class_stash = gv_stashsv(classname, 0);
736 if(!class_stash) Perl_croak(aTHX_ "No such class: '%"SVf"'!", SVfARG(classname));
737
738 if(items > 1) {
739 char* which = SvPV_nolen(ST(1));
740 if(strEQ(which, "dfs"))
741 RETVAL = mro_get_linear_isa_dfs(class_stash, 0);
742 else if(strEQ(which, "c3"))
743 RETVAL = mro_get_linear_isa_c3(class_stash, 0);
744 else
745 Perl_croak(aTHX_ "Invalid mro name: '%s'", which);
746 }
747 else {
748 RETVAL = mro_get_linear_isa(class_stash);
749 }
750
751 ST(0) = newRV_inc((SV*)RETVAL);
752 sv_2mortal(ST(0));
753 XSRETURN(1);
754}
755
756XS(XS_mro_set_mro)
757{
758 dVAR;
759 dXSARGS;
760 SV* classname;
761 char* whichstr;
762 mro_alg which;
763 HV* class_stash;
764 struct mro_meta* meta;
765
766 PERL_UNUSED_ARG(cv);
767
768 if (items != 2)
769 Perl_croak(aTHX_ "Usage: mro::set_mro(classname, type)");
770
771 classname = ST(0);
772 whichstr = SvPV_nolen(ST(1));
773 class_stash = gv_stashsv(classname, GV_ADD);
774 if(!class_stash) Perl_croak(aTHX_ "Cannot create class: '%"SVf"'!", SVfARG(classname));
775 meta = HvMROMETA(class_stash);
776
777 if(strEQ(whichstr, "dfs"))
778 which = MRO_DFS;
779 else if(strEQ(whichstr, "c3"))
780 which = MRO_C3;
781 else
782 Perl_croak(aTHX_ "Invalid mro name: '%s'", whichstr);
783
784 if(meta->mro_which != which) {
785 meta->mro_which = which;
786 /* Only affects local method cache, not
787 even child classes */
788 meta->sub_generation++;
789 if(meta->mro_nextmethod)
790 hv_clear(meta->mro_nextmethod);
791 }
792
793 XSRETURN_EMPTY;
794}
795
796
797XS(XS_mro_get_mro)
798{
799 dVAR;
800 dXSARGS;
801 SV* classname;
802 HV* class_stash;
803 struct mro_meta* meta;
804
805 PERL_UNUSED_ARG(cv);
806
807 if (items != 1)
808 Perl_croak(aTHX_ "Usage: mro::get_mro(classname)");
809
810 classname = ST(0);
811 class_stash = gv_stashsv(classname, 0);
812 if(!class_stash) Perl_croak(aTHX_ "No such class: '%"SVf"'!", SVfARG(classname));
813 meta = HvMROMETA(class_stash);
814
815 if(meta->mro_which == MRO_DFS)
816 ST(0) = sv_2mortal(newSVpvn("dfs", 3));
817 else
818 ST(0) = sv_2mortal(newSVpvn("c3", 2));
819
820 XSRETURN(1);
821}
822
823XS(XS_mro_get_isarev)
824{
825 dVAR;
826 dXSARGS;
827 SV* classname;
828 HV* class_stash;
829 HV* isarev;
830
831 PERL_UNUSED_ARG(cv);
832
833 if (items != 1)
834 Perl_croak(aTHX_ "Usage: mro::get_isarev(classname)");
835
836 classname = ST(0);
837
838 class_stash = gv_stashsv(classname, 0);
839 if(!class_stash) Perl_croak(aTHX_ "No such class: '%"SVf"'!", SVfARG(classname));
840
841 SP -= items;
842
843 if((isarev = HvMROMETA(class_stash)->mro_isarev)) {
844 HE* iter;
845 hv_iterinit(isarev);
846 while((iter = hv_iternext(isarev)))
847 XPUSHs(hv_iterkeysv(iter));
848 }
849
850 PUTBACK;
851 return;
852}
853
854XS(XS_mro_is_universal)
855{
856 dVAR;
857 dXSARGS;
858 SV* classname;
859 HV* class_stash;
860
861 PERL_UNUSED_ARG(cv);
862
863 if (items != 1)
864 Perl_croak(aTHX_ "Usage: mro::get_mro(classname)");
865
866 classname = ST(0);
867 class_stash = gv_stashsv(classname, 0);
868 if(!class_stash) Perl_croak(aTHX_ "No such class: '%"SVf"'!", SVfARG(classname));
869
9edc5bb8 870 if (HvMROMETA(class_stash)->is_universal)
871 XSRETURN_YES;
872 else
873 XSRETURN_NO;
e1a479c5 874}
875
876XS(XS_mro_get_global_sub_generation)
877{
878 dVAR;
879 dXSARGS;
880
881 PERL_UNUSED_ARG(cv);
882
883 if (items != 0)
884 Perl_croak(aTHX_ "Usage: mro::get_global_sub_generation()");
885
886 ST(0) = sv_2mortal(newSViv(PL_sub_generation));
887 XSRETURN(1);
888}
889
890XS(XS_mro_invalidate_all_method_caches)
891{
892 dVAR;
893 dXSARGS;
894
895 PERL_UNUSED_ARG(cv);
896
897 if (items != 0)
898 Perl_croak(aTHX_ "Usage: mro::invalidate_all_method_caches()");
899
900 PL_sub_generation++;
901
902 XSRETURN_EMPTY;
903}
904
905XS(XS_mro_get_sub_generation)
906{
907 dVAR;
908 dXSARGS;
909 SV* classname;
910 HV* class_stash;
911
912 PERL_UNUSED_ARG(cv);
913
914 if(items != 1)
915 Perl_croak(aTHX_ "Usage: mro::get_sub_generation(classname)");
916
917 classname = ST(0);
918 class_stash = gv_stashsv(classname, 0);
919 if(!class_stash) Perl_croak(aTHX_ "No such class: '%"SVf"'!", SVfARG(classname));
920
921 ST(0) = sv_2mortal(newSViv(HvMROMETA(class_stash)->sub_generation));
922 XSRETURN(1);
923}
924
925XS(XS_mro_method_changed_in)
926{
927 dVAR;
928 dXSARGS;
929 SV* classname;
930 HV* class_stash;
931
932 PERL_UNUSED_ARG(cv);
933
934 if(items != 1)
935 Perl_croak(aTHX_ "Usage: mro::method_changed_in(classname)");
936
937 classname = ST(0);
938
939 class_stash = gv_stashsv(classname, 0);
940 if(!class_stash) Perl_croak(aTHX_ "No such class: '%"SVf"'!", SVfARG(classname));
941
942 mro_method_changed_in(class_stash);
943
944 XSRETURN_EMPTY;
945}
946
947XS(XS_next_can)
948{
949 dVAR;
950 dXSARGS;
951 SV* self = ST(0);
952 SV* methcv = __nextcan(aTHX_ self, 0);
953
954 PERL_UNUSED_ARG(cv);
955 PERL_UNUSED_VAR(items);
956
957 if(methcv == &PL_sv_undef) {
958 ST(0) = &PL_sv_undef;
959 }
960 else {
961 ST(0) = sv_2mortal(newRV_inc(methcv));
962 }
963
964 XSRETURN(1);
965}
966
967XS(XS_next_method)
968{
969 dMARK;
970 dAX;
971 SV* self = ST(0);
972 SV* methcv = __nextcan(aTHX_ self, 1);
973
974 PERL_UNUSED_ARG(cv);
975
976 PL_markstack_ptr++;
977 call_sv(methcv, GIMME_V);
978}
979
980XS(XS_maybe_next_method)
981{
982 dMARK;
983 dAX;
984 SV* self = ST(0);
985 SV* methcv = __nextcan(aTHX_ self, 0);
986
987 PERL_UNUSED_ARG(cv);
988
989 if(methcv == &PL_sv_undef) {
990 ST(0) = &PL_sv_undef;
991 XSRETURN(1);
992 }
993
994 PL_markstack_ptr++;
995 call_sv(methcv, GIMME_V);
996}
997
998/*
999 * Local variables:
1000 * c-indentation-style: bsd
1001 * c-basic-offset: 4
1002 * indent-tabs-mode: t
1003 * End:
1004 *
1005 * ex: set ts=8 sts=4 sw=4 noet:
1006 */