Fix the Perl_call_sv() problem again, and tests for it
[gitmo/Mouse.git] / xs-src / MouseUtil.xs
1 #include "mouse.h"
2
3 #define MY_CXT_KEY "Mouse::Util::_guts" XS_VERSION
4 typedef struct {
5     HV* metas;
6 } my_cxt_t;
7 START_MY_CXT
8
9 #define ISA_CACHE "::LINEALIZED_ISA_CACHE::"
10
11 #ifdef no_mro_get_linear_isa
12 AV*
13 mouse_mro_get_linear_isa(pTHX_ HV* const stash){
14     GV* const cachegv = *(GV**)hv_fetchs(stash, ISA_CACHE, TRUE);
15     AV* isa;
16     SV* gen;
17     CV* get_linear_isa;
18
19     if(!isGV(cachegv))
20         gv_init(cachegv, stash, ISA_CACHE, sizeof(ISA_CACHE)-1, TRUE);
21
22     isa = GvAVn(cachegv);
23     gen = GvSVn(cachegv);
24
25
26     if(SvIOK(gen) && SvIVX(gen) == (IV)mro_get_pkg_gen(stash)){
27         return isa; /* returns the cache if available */
28     }
29     else{
30         SvREFCNT_dec(isa);
31         GvAV(cachegv) = isa = newAV();
32     }
33
34     get_linear_isa = get_cv("Mouse::Util::get_linear_isa", TRUE);
35
36     {
37         SV* avref;
38         dSP;
39
40         ENTER;
41         SAVETMPS;
42
43         PUSHMARK(SP);
44         mXPUSHp(HvNAME_get(stash), HvNAMELEN_get(stash));
45         PUTBACK;
46
47         call_sv((SV*)get_linear_isa, G_SCALAR);
48
49         SPAGAIN;
50         avref = POPs;
51         PUTBACK;
52
53         if(IsArrayRef(avref)){
54             AV* const av  = (AV*)SvRV(avref);
55             I32 const len = AvFILLp(av) + 1;
56             I32 i;
57
58             for(i = 0; i < len; i++){
59                 HV* const stash = gv_stashsv(AvARRAY(av)[i], FALSE);
60                 if(stash)
61                     av_push(isa, newSVpv(HvNAME(stash), 0));
62             }
63             SvREADONLY_on(isa);
64         }
65         else{
66             Perl_croak(aTHX_ "Mouse:Util::get_linear_isa() didn't return an ARRAY reference");
67         }
68
69         FREETMPS;
70         LEAVE;
71     }
72
73     sv_setiv(gen, (IV)mro_get_pkg_gen(stash));
74     return isa;
75 }
76 #endif /* !no_mor_get_linear_isa */
77
78 #ifdef DEBUGGING
79 SV**
80 mouse_av_at_safe(pTHX_ AV* const av, I32 const ix){
81     assert(av);
82     assert(SvTYPE(av) == SVt_PVAV);
83     assert(AvMAX(av) >= ix);
84     return &AvARRAY(av)[ix];
85 }
86 #endif
87
88 void
89 mouse_throw_error(SV* const metaobject, SV* const data /* not used */, const char* const fmt, ...){
90     dTHX;
91     va_list args;
92     SV* message;
93
94     assert(metaobject);
95     assert(fmt);
96
97     va_start(args, fmt);
98     message = vnewSVpvf(fmt, &args);
99     va_end(args);
100
101     {
102         dSP;
103         PUSHMARK(SP);
104         EXTEND(SP, 6);
105
106         PUSHs(metaobject);
107         mPUSHs(message);
108
109         if(data){ /* extra arg, might be useful for debugging */
110             mPUSHs(newSVpvs("data"));
111             PUSHs(data);
112             mPUSHs(newSVpvs("depth"));
113             mPUSHi(-1);
114         }
115
116         PUTBACK;
117
118         call_method("throw_error", G_VOID);
119         croak("throw_error() did not throw the error (%"SVf")", message);
120     }
121 }
122
123 /* workaround Perl-RT #69939 */
124 I32
125 mouse_call_sv_safe(pTHX_ SV* const sv, I32 const flags) {
126     I32 count;
127     ENTER;
128     /* Don't do SAVETMPS */
129
130     SAVESPTR(ERRSV);
131     ERRSV = sv_newmortal();
132
133     count = Perl_call_sv(aTHX_ sv, flags | G_EVAL);
134
135     if(sv_true(ERRSV)){
136         SV* const err = sv_mortalcopy(ERRSV);
137         LEAVE;
138         sv_setsv(ERRSV, err);
139         croak(NULL); /* rethrow */
140     }
141
142     LEAVE;
143
144     return count;
145 }
146
147 void
148 mouse_must_defined(pTHX_ SV* const value, const char* const name) {
149     assert(value);
150     assert(name);
151
152     SvGETMAGIC(value);
153     if(!SvOK(value)){
154         croak("You must define %s", name);
155     }
156 }
157
158 void
159 mouse_must_ref(pTHX_ SV* const value, const char* const name, svtype const t) {
160     assert(value);
161     assert(name);
162
163     SvGETMAGIC(value);
164     if(!(SvROK(value) && (t == SVt_NULL || SvTYPE(SvRV(value)) == t))) {
165         croak("You must pass %s, not %s",
166             name, SvOK(value) ? SvPV_nolen(value) : "undef");
167     }
168 }
169
170
171 bool
172 mouse_is_class_loaded(pTHX_ SV * const klass){
173     HV *stash;
174     GV** gvp;
175     HE* he;
176
177     if (!(SvPOKp(klass) && SvCUR(klass))) { /* XXX: SvPOK does not work with magical scalars */
178         return FALSE;
179     }
180
181     stash = gv_stashsv(klass, FALSE);
182     if (!stash) {
183         return FALSE;
184     }
185
186     if (( gvp = (GV**)hv_fetchs(stash, "VERSION", FALSE) )) {
187         if(isGV(*gvp) && GvSV(*gvp) && SvOK(GvSV(*gvp))){
188             return TRUE;
189         }
190     }
191
192     if (( gvp = (GV**)hv_fetchs(stash, "ISA", FALSE) )) {
193         if(isGV(*gvp) && GvAV(*gvp) && av_len(GvAV(*gvp)) != -1){
194             return TRUE;
195         }
196     }
197
198     hv_iterinit(stash);
199     while(( he = hv_iternext(stash) )){
200         GV* const gv = (GV*)HeVAL(he);
201
202         if(isGV(gv)){
203             if(GvCVu(gv)){ /* is GV and has CV */
204                 hv_iterinit(stash); /* reset */
205                 return TRUE;
206             }
207         }
208         else if(SvOK(gv)){ /* is a stub or constant */
209             hv_iterinit(stash); /* reset */
210             return TRUE;
211         }
212     }
213     return FALSE;
214 }
215
216
217 SV*
218 mouse_call0 (pTHX_ SV* const self, SV* const method) {
219     dSP;
220     SV *ret;
221
222     PUSHMARK(SP);
223     XPUSHs(self);
224     PUTBACK;
225
226     call_sv_safe(method, G_SCALAR | G_METHOD);
227
228     SPAGAIN;
229     ret = POPs;
230     PUTBACK;
231
232     return ret;
233 }
234
235 SV*
236 mouse_call1 (pTHX_ SV* const self, SV* const method, SV* const arg1) {
237     dSP;
238     SV *ret;
239
240     PUSHMARK(SP);
241     EXTEND(SP, 2);
242     PUSHs(self);
243     PUSHs(arg1);
244     PUTBACK;
245
246     call_sv_safe(method, G_SCALAR | G_METHOD);
247
248     SPAGAIN;
249     ret = POPs;
250     PUTBACK;
251
252     return ret;
253 }
254
255 int
256 mouse_predicate_call(pTHX_ SV* const self, SV* const method) {
257     return sv_true( mcall0(self, method) );
258 }
259
260 SV*
261 mouse_get_metaclass(pTHX_ SV* metaclass_name){
262     dMY_CXT;
263     HE* he;
264
265     assert(metaclass_name);
266     assert(MY_CXT.metas);
267
268     if(IsObject(metaclass_name)){
269         HV* const stash = SvSTASH(SvRV(metaclass_name));
270
271         metaclass_name = newSVpvn_share(HvNAME_get(stash), HvNAMELEN_get(stash), 0U);
272         sv_2mortal(metaclass_name);
273     }
274
275     he = hv_fetch_ent(MY_CXT.metas, metaclass_name, FALSE, 0U);
276
277     return he ? HeVAL(he) : &PL_sv_undef;
278 }
279
280 MAGIC*
281 mouse_mg_find(pTHX_ SV* const sv, const MGVTBL* const vtbl, I32 const flags){
282     MAGIC* mg;
283
284     assert(sv != NULL);
285     for(mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic){
286         if(mg->mg_virtual == vtbl){
287             return mg;
288         }
289     }
290
291     if(flags & MOUSEf_DIE_ON_FAIL){
292         croak("mouse_mg_find: no MAGIC found for %"SVf, sv_2mortal(newRV_inc(sv)));
293     }
294     return NULL;
295 }
296
297 GV*
298 mouse_stash_fetch(pTHX_ HV* const stash, const char* const name, I32 const namelen, I32 const create) {
299     GV** const gvp = (GV**)hv_fetch(stash, name, namelen, create);
300
301     if(gvp){
302         if(!isGV(*gvp)){
303             gv_init(*gvp, stash, name, namelen, GV_ADDMULTI);
304         }
305         return *gvp;
306     }
307     else{
308         return NULL;
309     }
310 }
311
312 void
313 mouse_install_sub(pTHX_ GV* const gv, SV* const code_ref) {
314     CV* cv;
315
316     assert(gv != NULL);
317     assert(code_ref != NULL);
318     assert(isGV(gv));
319     assert(IsCodeRef(code_ref));
320
321     if(GvCVu(gv)){ /* delete *slot{gv} to work around "redefine" warning */
322         SvREFCNT_dec(GvCV(gv));
323         GvCV(gv) = NULL;
324     }
325
326     sv_setsv_mg((SV*)gv, code_ref); /* *gv = $code_ref */
327
328     /* name the CODE ref if it's anonymous */
329     cv = (CV*)SvRV(code_ref);
330     if(CvANON(cv)
331         && CvGV(cv) /* a cv under construction has no gv */ ){
332         HV* dbsub;
333
334         /* update %DB::sub to make NYTProf happy */
335         if((PL_perldb & (PERLDBf_SUBLINE|PERLDB_NAMEANON))
336             && PL_DBsub && (dbsub = GvHV(PL_DBsub))
337         ){
338             /* see Perl_newATTRSUB() in op.c */
339             SV* const subname = sv_newmortal();
340             HE* orig;
341
342             gv_efullname3(subname, CvGV(cv), NULL);
343             orig = hv_fetch_ent(dbsub, subname, FALSE, 0U);
344             if(orig){
345                 gv_efullname3(subname, gv, NULL);
346                 (void)hv_store_ent(dbsub, subname, HeVAL(orig), 0U);
347                 SvREFCNT_inc_simple_void_NN(HeVAL(orig));
348             }
349         }
350
351         CvGV(cv) = gv;
352         CvANON_off(cv);
353     }
354 }
355
356 MODULE = Mouse::Util  PACKAGE = Mouse::Util
357
358 PROTOTYPES:   DISABLE
359 VERSIONCHECK: DISABLE
360
361 BOOT:
362 {
363     MY_CXT_INIT;
364     MY_CXT.metas = NULL;
365 }
366
367 void
368 __register_metaclass_storage(HV* metas, bool cloning)
369 CODE:
370 {
371     if(cloning){
372         MY_CXT_CLONE;
373         MY_CXT.metas = NULL;
374     }
375     {
376         dMY_CXT;
377         if(MY_CXT.metas && ckWARN(WARN_REDEFINE)){
378             Perl_warner(aTHX_ packWARN(WARN_REDEFINE), "Metaclass storage more than once");
379         }
380         MY_CXT.metas = metas;
381         SvREFCNT_inc_simple_void_NN(metas);
382     }
383 }
384
385 bool
386 is_valid_class_name(SV* sv)
387 CODE:
388 {
389     SvGETMAGIC(sv);
390     if(SvPOKp(sv) && SvCUR(sv) > 0){
391         UV i;
392         RETVAL = TRUE;
393         for(i = 0; i < SvCUR(sv); i++){
394             char const c = SvPVX(sv)[i];
395             if(!(isALNUM(c) || c == ':')){
396                 RETVAL = FALSE;
397                 break;
398             }
399         }
400     }
401     else{
402         RETVAL = SvNIOKp(sv) ? TRUE : FALSE;
403     }
404 }
405 OUTPUT:
406     RETVAL
407
408 bool
409 is_class_loaded(SV* sv)
410
411 void
412 get_code_info(CV* code)
413 PREINIT:
414     GV* gv;
415     HV* stash;
416 PPCODE:
417     if((gv = CvGV(code)) && isGV(gv) && (stash = GvSTASH(gv))){
418         EXTEND(SP, 2);
419         mPUSHs(newSVpvn_share(HvNAME_get(stash), HvNAMELEN_get(stash), 0U));
420         mPUSHs(newSVpvn_share(GvNAME_get(gv), GvNAMELEN_get(gv), 0U));
421     }
422
423 SV*
424 get_code_package(CV* code)
425 PREINIT:
426     HV* stash;
427 CODE:
428     if(CvGV(code) && isGV(CvGV(code)) && (stash = GvSTASH(CvGV(code)))){
429         RETVAL = newSVpvn_share(HvNAME_get(stash), HvNAMELEN_get(stash), 0U);
430     }
431     else{
432         RETVAL = &PL_sv_no;
433     }
434 OUTPUT:
435     RETVAL
436
437 CV*
438 get_code_ref(SV* package, SV* name)
439 CODE:
440 {
441     HV* stash;
442     STRLEN name_len;
443     const char* name_pv;
444     GV* gv;
445
446     must_defined(package, "a package name");
447     must_defined(name,    "a subroutine name");
448
449     stash = gv_stashsv(package, FALSE);
450     if(!stash){
451         XSRETURN_UNDEF;
452     }
453
454     name_pv = SvPV_const(name, name_len);
455     gv = stash_fetch(stash, name_pv, name_len, FALSE);
456     RETVAL = gv ? GvCVu(gv) : NULL;
457
458     if(!RETVAL){
459         XSRETURN_UNDEF;
460     }
461 }
462 OUTPUT:
463     RETVAL
464
465 void
466 generate_isa_predicate_for(SV* arg, SV* predicate_name = NULL)
467 ALIAS:
468     generate_isa_predicate_for = 0
469     generate_can_predicate_for = 1
470 PPCODE:
471 {
472     const char* name_pv = NULL;
473     CV* xsub;
474
475     must_defined(arg, ix == 0 ? "a class_name" : "method names");
476
477     if(predicate_name){
478         must_defined(predicate_name, "a predicate name");
479         name_pv = SvPV_nolen_const(predicate_name);
480     }
481
482     if(ix == 0){
483         xsub = mouse_generate_isa_predicate_for(aTHX_ arg, name_pv);
484     }
485     else{
486         xsub = mouse_generate_can_predicate_for(aTHX_ arg, name_pv);
487     }
488
489     if(predicate_name == NULL){ /* anonymous predicate */
490         mXPUSHs( newRV_inc((SV*)xsub) );
491     }
492 }
493
494 # This xsub will redefine &Mouse::Util::install_subroutines()
495 void
496 install_subroutines(SV* into, ...)
497 CODE:
498 {
499     HV* stash;
500     I32 i;
501
502     must_defined(into, "a package name");
503     stash = gv_stashsv(into, TRUE);
504
505     if( ((items-1) % 2) != 0 ){
506         croak_xs_usage(cv, "into, name => coderef [, other_name, other_coderef ...]");
507     }
508
509     for(i = 1; i < items; i += 2) {
510         SV* const name = ST(i);
511         SV* const code = ST(i+1);
512         STRLEN len;
513         const char* pv;
514         GV* gv;
515
516         must_defined(name, "a subroutine name");
517         must_ref(code, "a CODE reference", SVt_PVCV);
518
519         pv = SvPV_const(name, len);
520         gv = stash_fetch(stash, pv, len, TRUE);
521
522         mouse_install_sub(aTHX_ gv, code);
523     }
524 }