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