]> git.vpit.fr Git - perl/modules/Variable-Magic.git/blob - Magic.xs
Always use a safe version of call_sv()
[perl/modules/Variable-Magic.git] / Magic.xs
1 /* This file is part of the Variable::Magic Perl module.
2  * See http://search.cpan.org/dist/Variable-Magic/ */
3
4 #include <stdarg.h> /* <va_list>, va_{start,arg,end}, ... */
5
6 #include <stdio.h>  /* sprintf() */
7
8 #define PERL_NO_GET_CONTEXT
9 #include "EXTERN.h"
10 #include "perl.h"
11 #include "XSUB.h"
12
13 #define __PACKAGE__ "Variable::Magic"
14
15 #ifndef VMG_PERL_PATCHLEVEL
16 # ifdef PERL_PATCHNUM
17 #  define VMG_PERL_PATCHLEVEL PERL_PATCHNUM
18 # else
19 #  define VMG_PERL_PATCHLEVEL 0
20 # endif
21 #endif
22
23 #define VMG_HAS_PERL(R, V, S) (PERL_REVISION > (R) || (PERL_REVISION == (R) && (PERL_VERSION > (V) || (PERL_VERSION == (V) && (PERL_SUBVERSION >= (S))))))
24
25 #define VMG_HAS_PERL_BRANCH(R, V, S) (PERL_REVISION == (R) && PERL_VERSION == (V) && PERL_SUBVERSION >= (S))
26
27 #define VMG_HAS_PERL_MAINT(R, V, S, P) (PERL_REVISION == (R) && PERL_VERSION == (V) && (VMG_PERL_PATCHLEVEL >= (P) || (!VMG_PERL_PATCHLEVEL && PERL_SUBVERSION >= (S))))
28
29 /* --- Threads and multiplicity -------------------------------------------- */
30
31 #ifndef NOOP
32 # define NOOP
33 #endif
34
35 #ifndef dNOOP
36 # define dNOOP
37 #endif
38
39 /* Safe unless stated otherwise in Makefile.PL */
40 #ifndef VMG_FORKSAFE
41 # define VMG_FORKSAFE 1
42 #endif
43
44 #ifndef VMG_MULTIPLICITY
45 # if defined(MULTIPLICITY) || defined(PERL_IMPLICIT_CONTEXT)
46 #  define VMG_MULTIPLICITY 1
47 # else
48 #  define VMG_MULTIPLICITY 0
49 # endif
50 #endif
51 #if VMG_MULTIPLICITY && !defined(tTHX)
52 # define tTHX PerlInterpreter*
53 #endif
54
55 #if VMG_MULTIPLICITY && defined(USE_ITHREADS) && defined(dMY_CXT) && defined(MY_CXT) && defined(START_MY_CXT) && defined(MY_CXT_INIT) && (defined(MY_CXT_CLONE) || defined(dMY_CXT_SV))
56 # define VMG_THREADSAFE 1
57 # ifndef MY_CXT_CLONE
58 #  define MY_CXT_CLONE \
59     dMY_CXT_SV;                                                      \
60     my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1)); \
61     Copy(INT2PTR(my_cxt_t*, SvUV(my_cxt_sv)), my_cxtp, 1, my_cxt_t); \
62     sv_setuv(my_cxt_sv, PTR2UV(my_cxtp))
63 # endif
64 #else
65 # define VMG_THREADSAFE 0
66 # undef  dMY_CXT
67 # define dMY_CXT      dNOOP
68 # undef  MY_CXT
69 # define MY_CXT       vmg_globaldata
70 # undef  START_MY_CXT
71 # define START_MY_CXT STATIC my_cxt_t MY_CXT;
72 # undef  MY_CXT_INIT
73 # define MY_CXT_INIT  NOOP
74 # undef  MY_CXT_CLONE
75 # define MY_CXT_CLONE NOOP
76 #endif
77
78 #if VMG_THREADSAFE
79
80 STATIC SV *vmg_clone(pTHX_ SV *sv, tTHX owner) {
81 #define vmg_clone(P, O) vmg_clone(aTHX_ (P), (O))
82  CLONE_PARAMS param;
83
84  param.stashes    = NULL; /* don't need it unless sv is a PVHV */
85  param.flags      = 0;
86  param.proto_perl = owner;
87
88  return SvREFCNT_inc(sv_dup(sv, &param));
89 }
90
91 #endif /* VMG_THREADSAFE */
92
93 /* --- Compatibility ------------------------------------------------------- */
94
95 #ifndef Newx
96 # define Newx(v, n, c) New(0, v, n, c)
97 #endif
98
99 #ifndef SvMAGIC_set
100 # define SvMAGIC_set(sv, val) (SvMAGIC(sv) = (val))
101 #endif
102
103 #ifndef SvRV_const
104 # define SvRV_const(sv) SvRV((SV *) sv)
105 #endif
106
107 #ifndef SvREFCNT_inc_simple_void
108 # define SvREFCNT_inc_simple_void(sv) SvREFCNT_inc(sv)
109 #endif
110
111 #ifndef mPUSHu
112 # define mPUSHu(U) PUSHs(sv_2mortal(newSVuv(U)))
113 #endif
114
115 #ifndef PERL_MAGIC_ext
116 # define PERL_MAGIC_ext '~'
117 #endif
118
119 #ifndef PERL_MAGIC_tied
120 # define PERL_MAGIC_tied 'P'
121 #endif
122
123 #ifndef MGf_COPY
124 # define MGf_COPY 0
125 #endif
126
127 #ifndef MGf_DUP
128 # define MGf_DUP 0
129 #endif
130
131 #ifndef MGf_LOCAL
132 # define MGf_LOCAL 0
133 #endif
134
135 #ifndef IN_PERL_COMPILETIME
136 # define IN_PERL_COMPILETIME (PL_curcop == &PL_compiling)
137 #endif
138
139 /* uvar magic and Hash::Util::FieldHash were commited with 28419, but we only
140  * enable them on 5.10 */
141 #if VMG_HAS_PERL(5, 10, 0)
142 # define VMG_UVAR 1
143 #else
144 # define VMG_UVAR 0
145 #endif
146
147 /* Applied to dev-5.9 as 25854, integrated to maint-5.8 as 28160, partially
148  * reverted to dev-5.11 as 9cdcb38b */
149 #if VMG_HAS_PERL_MAINT(5, 8, 9, 28160) || VMG_HAS_PERL_MAINT(5, 9, 3, 25854) || VMG_HAS_PERL(5, 10, 0)
150 # ifndef VMG_COMPAT_ARRAY_PUSH_NOLEN
151 /* This branch should only apply for perls before the official 5.11.0 release.
152  * Makefile.PL takes care of the higher ones. */
153 #  define VMG_COMPAT_ARRAY_PUSH_NOLEN 1
154 # endif
155 # ifndef VMG_COMPAT_ARRAY_PUSH_NOLEN_VOID
156 #  define VMG_COMPAT_ARRAY_PUSH_NOLEN_VOID 1
157 # endif
158 #else
159 # ifndef VMG_COMPAT_ARRAY_PUSH_NOLEN
160 #  define VMG_COMPAT_ARRAY_PUSH_NOLEN 0
161 # endif
162 # ifndef VMG_COMPAT_ARRAY_PUSH_NOLEN_VOID
163 #  define VMG_COMPAT_ARRAY_PUSH_NOLEN_VOID 0
164 # endif
165 #endif
166
167 /* Applied to dev-5.11 as 34908 */
168 #if VMG_HAS_PERL_MAINT(5, 11, 0, 34908) || VMG_HAS_PERL(5, 12, 0)
169 # define VMG_COMPAT_ARRAY_UNSHIFT_NOLEN_VOID 1
170 #else
171 # define VMG_COMPAT_ARRAY_UNSHIFT_NOLEN_VOID 0
172 #endif
173
174 /* Applied to dev-5.9 as 31473 (see #43357), integrated to maint-5.8 as 32542 */
175 #if VMG_HAS_PERL_MAINT(5, 8, 9, 32542) || VMG_HAS_PERL_MAINT(5, 9, 5, 31473) || VMG_HAS_PERL(5, 10, 0)
176 # define VMG_COMPAT_ARRAY_UNDEF_CLEAR 1
177 #else
178 # define VMG_COMPAT_ARRAY_UNDEF_CLEAR 0
179 #endif
180
181 #if VMG_HAS_PERL_MAINT(5, 11, 0, 32969) || VMG_HAS_PERL(5, 12, 0)
182 # define VMG_COMPAT_SCALAR_LENGTH_NOLEN 1
183 #else
184 # define VMG_COMPAT_SCALAR_LENGTH_NOLEN 0
185 #endif
186
187 /* ... Bug-free mg_magical ................................................. */
188
189 /* See the discussion at http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2008-01/msg00036.html. This version is specialized to our needs. */
190
191 #if VMG_UVAR
192
193 STATIC void vmg_sv_magicuvar(pTHX_ SV *sv, const char *uf, I32 len) {
194 #define vmg_sv_magicuvar(S, U, L) vmg_sv_magicuvar(aTHX_ (S), (U), (L))
195  const MAGIC* mg;
196  sv_magic(sv, NULL, PERL_MAGIC_uvar, uf, len);
197  /* uvar magic has set and get magic, hence this has set SVs_GMG and SVs_SMG. */
198  if ((mg = SvMAGIC(sv))) {
199   SvRMAGICAL_off(sv);
200   do {
201    const MGVTBL* const vtbl = mg->mg_virtual;
202    if (vtbl) {
203     if (vtbl->svt_clear) {
204      SvRMAGICAL_on(sv);
205      break;
206     }
207    }
208   } while ((mg = mg->mg_moremagic));
209  }
210 }
211
212 #endif /* VMG_UVAR */
213
214 /* ... Safe version of call_sv() ........................................... */
215
216 #define VMG_SAVE_LAST_CX (!VMG_HAS_PERL(5, 8, 4) || VMG_HAS_PERL(5, 9, 5))
217
218 STATIC I32 vmg_call_sv(pTHX_ SV *sv, I32 flags, I32 destructor) {
219 #define vmg_call_sv(S, F, D) vmg_call_sv(aTHX_ (S), (F), (D))
220  I32 ret, cxix = 0, in_eval = 0;
221 #if VMG_SAVE_LAST_CX
222  PERL_CONTEXT saved_cx;
223 #endif
224  SV *old_err = NULL;
225
226  if (SvTRUE(ERRSV)) {
227   old_err = ERRSV;
228   ERRSV   = newSV(0);
229  }
230
231  if (cxstack_ix < cxstack_max) {
232   cxix = cxstack_ix + 1;
233   if (destructor && CxTYPE(cxstack + cxix) == CXt_EVAL)
234    in_eval = 1;
235  }
236
237 #if VMG_SAVE_LAST_CX
238  /* The last popped context will be reused by call_sv(), but our callers may
239   * still need its previous value. Back it up so that it isn't clobbered. */
240  saved_cx = cxstack[cxix];
241 #endif
242
243  ret = call_sv(sv, flags | G_EVAL);
244
245 #if VMG_SAVE_LAST_CX
246  cxstack[cxix] = saved_cx;
247 #endif
248
249  if (SvTRUE(ERRSV)) {
250   if (old_err) {
251    sv_setsv(old_err, ERRSV);
252    SvREFCNT_dec(ERRSV);
253    ERRSV = old_err;
254   }
255   if (IN_PERL_COMPILETIME) {
256    if (!PL_in_eval) {
257     if (PL_errors)
258      sv_catsv(PL_errors, ERRSV);
259     else
260      Perl_warn(aTHX_ "%s", SvPV_nolen(ERRSV));
261     SvCUR_set(ERRSV, 0);
262    }
263 #if VMG_HAS_PERL(5, 10, 0) || defined(PL_parser)
264    if (PL_parser)
265     ++PL_parser->error_count;
266 #elif defined(PL_error_count)
267    ++PL_error_count;
268 #else
269    ++PL_Ierror_count;
270 #endif
271    } else if (!in_eval)
272     croak(NULL);
273  } else {
274   if (old_err) {
275    SvREFCNT_dec(ERRSV);
276    ERRSV = old_err;
277   }
278  }
279
280  return ret;
281 }
282
283 /* --- Stolen chunk of B --------------------------------------------------- */
284
285 typedef enum {
286  OPc_NULL   = 0,
287  OPc_BASEOP = 1,
288  OPc_UNOP   = 2,
289  OPc_BINOP  = 3,
290  OPc_LOGOP  = 4,
291  OPc_LISTOP = 5,
292  OPc_PMOP   = 6,
293  OPc_SVOP   = 7,
294  OPc_PADOP  = 8,
295  OPc_PVOP   = 9,
296  OPc_LOOP   = 10,
297  OPc_COP    = 11,
298  OPc_MAX    = 12
299 } opclass;
300
301 STATIC const char *const vmg_opclassnames[] = {
302  "B::NULL",
303  "B::OP",
304  "B::UNOP",
305  "B::BINOP",
306  "B::LOGOP",
307  "B::LISTOP",
308  "B::PMOP",
309  "B::SVOP",
310  "B::PADOP",
311  "B::PVOP",
312  "B::LOOP",
313  "B::COP"
314 };
315
316 STATIC opclass vmg_opclass(const OP *o) {
317 #if 0
318  if (!o)
319   return OPc_NULL;
320 #endif
321
322  if (o->op_type == 0)
323   return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
324
325  if (o->op_type == OP_SASSIGN)
326   return ((o->op_private & OPpASSIGN_BACKWARDS) ? OPc_UNOP : OPc_BINOP);
327
328  if (o->op_type == OP_AELEMFAST) {
329   if (o->op_flags & OPf_SPECIAL)
330    return OPc_BASEOP;
331   else
332 #ifdef USE_ITHREADS
333    return OPc_PADOP;
334 #else
335    return OPc_SVOP;
336 #endif
337  }
338
339 #ifdef USE_ITHREADS
340  if (o->op_type == OP_GV || o->op_type == OP_GVSV || o->op_type == OP_RCATLINE)
341   return OPc_PADOP;
342 #endif
343
344  switch (PL_opargs[o->op_type] & OA_CLASS_MASK) {
345   case OA_BASEOP:
346    return OPc_BASEOP;
347   case OA_UNOP:
348    return OPc_UNOP;
349   case OA_BINOP:
350    return OPc_BINOP;
351   case OA_LOGOP:
352    return OPc_LOGOP;
353   case OA_LISTOP:
354    return OPc_LISTOP;
355   case OA_PMOP:
356    return OPc_PMOP;
357   case OA_SVOP:
358    return OPc_SVOP;
359   case OA_PADOP:
360    return OPc_PADOP;
361   case OA_PVOP_OR_SVOP:
362    return (o->op_private & (OPpTRANS_TO_UTF|OPpTRANS_FROM_UTF)) ? OPc_SVOP : OPc_PVOP;
363   case OA_LOOP:
364    return OPc_LOOP;
365   case OA_COP:
366    return OPc_COP;
367   case OA_BASEOP_OR_UNOP:
368    return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
369   case OA_FILESTATOP:
370    return ((o->op_flags & OPf_KIDS) ? OPc_UNOP :
371 #ifdef USE_ITHREADS
372            (o->op_flags & OPf_REF) ? OPc_PADOP : OPc_BASEOP);
373 #else
374            (o->op_flags & OPf_REF) ? OPc_SVOP : OPc_BASEOP);
375 #endif
376   case OA_LOOPEXOP:
377    if (o->op_flags & OPf_STACKED)
378     return OPc_UNOP;
379    else if (o->op_flags & OPf_SPECIAL)
380     return OPc_BASEOP;
381    else
382     return OPc_PVOP;
383  }
384
385  return OPc_BASEOP;
386 }
387
388 /* --- Error messages ------------------------------------------------------ */
389
390 STATIC const char vmg_invalid_wiz[]    = "Invalid wizard object";
391 STATIC const char vmg_wrongargnum[]    = "Wrong number of arguments";
392 STATIC const char vmg_argstorefailed[] = "Error while storing arguments";
393
394 /* --- Signatures ---------------------------------------------------------- */
395
396 #define SIG_WZO ((U16) (0x3891))
397 #define SIG_WIZ ((U16) (0x3892))
398
399 /* --- MGWIZ structure ----------------------------------------------------- */
400
401 typedef struct {
402  MGVTBL *vtbl;
403
404  U8 opinfo;
405  U8 uvar;
406
407  SV *cb_data;
408  SV *cb_get, *cb_set, *cb_len, *cb_clear, *cb_free;
409 #if MGf_COPY
410  SV *cb_copy;
411 #endif /* MGf_COPY */
412 #if MGf_DUP
413  SV *cb_dup;
414 #endif /* MGf_DUP */
415 #if MGf_LOCAL
416  SV *cb_local;
417 #endif /* MGf_LOCAL */
418 #if VMG_UVAR
419  SV *cb_fetch, *cb_store, *cb_exists, *cb_delete;
420 #endif /* VMG_UVAR */
421
422 #if VMG_MULTIPLICITY
423  tTHX owner;
424 #endif /* VMG_MULTIPLICITY */
425 } MGWIZ;
426
427 STATIC void vmg_mgwiz_free(pTHX_ MGWIZ *w) {
428 #define vmg_mgwiz_free(W) vmg_mgwiz_free(aTHX_ (W))
429  if (!w)
430   return;
431
432  if (w->cb_data)   SvREFCNT_dec(w->cb_data);
433  if (w->cb_get)    SvREFCNT_dec(w->cb_get);
434  if (w->cb_set)    SvREFCNT_dec(w->cb_set);
435  if (w->cb_len)    SvREFCNT_dec(w->cb_len);
436  if (w->cb_clear)  SvREFCNT_dec(w->cb_clear);
437  if (w->cb_free)   SvREFCNT_dec(w->cb_free);
438 #if MGf_COPY
439  if (w->cb_copy)   SvREFCNT_dec(w->cb_copy);
440 #endif /* MGf_COPY */
441 #if 0 /* MGf_DUP */
442  if (w->cb_dup)    SvREFCNT_dec(w->cb_dup);
443 #endif /* MGf_DUP */
444 #if MGf_LOCAL
445  if (w->cb_local)  SvREFCNT_dec(w->cb_local);
446 #endif /* MGf_LOCAL */
447 #if VMG_UVAR
448  if (w->cb_fetch)  SvREFCNT_dec(w->cb_fetch);
449  if (w->cb_store)  SvREFCNT_dec(w->cb_store);
450  if (w->cb_exists) SvREFCNT_dec(w->cb_exists);
451  if (w->cb_delete) SvREFCNT_dec(w->cb_delete);
452 #endif /* VMG_UVAR */
453
454  Safefree(w->vtbl);
455  Safefree(w);
456
457  return;
458 }
459
460 #if VMG_THREADSAFE
461
462 #define VMG_CLONE_CB(N) \
463  z->cb_ ## N = (w->cb_ ## N) ? vmg_clone(w->cb_ ## N, w->owner) \
464                              : NULL;
465
466 STATIC MGWIZ *vmg_mgwiz_clone(pTHX_ const MGWIZ *w) {
467 #define vmg_mgwiz_clone(W) vmg_mgwiz_clone(aTHX_ (W))
468  MGVTBL *t;
469  MGWIZ *z;
470
471  if (!w)
472   return NULL;
473
474  Newx(t, 1, MGVTBL);
475  Copy(w->vtbl, t, 1, MGVTBL);
476
477  Newx(z, 1, MGWIZ);
478
479  z->vtbl   = t;
480  z->uvar   = w->uvar;
481  z->opinfo = w->opinfo;
482
483  VMG_CLONE_CB(data);
484  VMG_CLONE_CB(get);
485  VMG_CLONE_CB(set);
486  VMG_CLONE_CB(len);
487  VMG_CLONE_CB(clear);
488  VMG_CLONE_CB(free);
489 #if MGf_COPY
490  VMG_CLONE_CB(copy);
491 #endif /* MGf_COPY */
492 #if MGf_DUP
493  VMG_CLONE_CB(dup);
494 #endif /* MGf_DUP */
495 #if MGf_LOCAL
496  VMG_CLONE_CB(local);
497 #endif /* MGf_LOCAL */
498 #if VMG_UVAR
499  VMG_CLONE_CB(fetch);
500  VMG_CLONE_CB(store);
501  VMG_CLONE_CB(exists);
502  VMG_CLONE_CB(delete);
503 #endif /* VMG_UVAR */
504
505  z->owner = aTHX;
506
507  return z;
508 }
509
510 #endif /* VMG_THREADSAFE */
511
512 /* --- Context-safe global data -------------------------------------------- */
513
514 #if VMG_THREADSAFE
515
516 #define PTABLE_NAME        ptable
517 #define PTABLE_VAL_FREE(V) vmg_mgwiz_free(V)
518
519 #define pPTBL  pTHX
520 #define pPTBL_ pTHX_
521 #define aPTBL  aTHX
522 #define aPTBL_ aTHX_
523
524 #include "ptable.h"
525
526 #define ptable_store(T, K, V) ptable_store(aTHX_ (T), (K), (V))
527 #define ptable_clear(T)       ptable_clear(aTHX_ (T))
528 #define ptable_free(T)        ptable_free(aTHX_ (T))
529
530 #endif /* VMG_THREADSAFE */
531
532 #define MY_CXT_KEY __PACKAGE__ "::_guts" XS_VERSION
533
534 typedef struct {
535 #if VMG_THREADSAFE
536  ptable *wizards;
537  tTHX    owner;
538 #endif
539  HV     *b__op_stashes[OPc_MAX];
540 } my_cxt_t;
541
542 START_MY_CXT
543
544 #if VMG_THREADSAFE
545
546 STATIC void vmg_ptable_clone(pTHX_ ptable_ent *ent, void *ud_) {
547  my_cxt_t *ud = ud_;
548  MGWIZ *w;
549
550  if (ud->owner == aTHX)
551   return;
552
553  w = vmg_mgwiz_clone(ent->val);
554  if (w)
555   ptable_store(ud->wizards, ent->key, w);
556 }
557
558 #endif /* VMG_THREADSAFE */
559
560 /* --- Wizard objects ------------------------------------------------------ */
561
562 STATIC int vmg_wizard_free(pTHX_ SV *sv, MAGIC *mg);
563
564 STATIC MGVTBL vmg_wizard_vtbl = {
565  NULL,            /* get */
566  NULL,            /* set */
567  NULL,            /* len */
568  NULL,            /* clear */
569  vmg_wizard_free, /* free */
570 #if MGf_COPY
571  NULL,            /* copy */
572 #endif /* MGf_COPY */
573 #if MGf_DUP
574  NULL,            /* dup */
575 #endif /* MGf_DUP */
576 #if MGf_LOCAL
577  NULL,            /* local */
578 #endif /* MGf_LOCAL */
579 };
580
581 /* ... Wizard constructor .................................................. */
582
583 STATIC SV *vmg_wizard_new(pTHX_ const MGWIZ *w) {
584 #define vmg_wizard_new(W) vmg_wizard_new(aTHX_ (W))
585  SV *wiz = newSVuv(PTR2IV(w));
586
587  if (w) {
588   MAGIC *mg = sv_magicext(wiz, NULL, PERL_MAGIC_ext, &vmg_wizard_vtbl, NULL, 0);
589   mg->mg_private = SIG_WZO;
590  }
591  SvREADONLY_on(wiz);
592
593  return wiz;
594 }
595
596 STATIC const SV *vmg_wizard_validate(pTHX_ const SV *wiz) {
597 #define vmg_wizard_validate(W) vmg_wizard_validate(aTHX_ (W))
598  if (SvROK(wiz)) {
599   wiz = SvRV_const(wiz);
600   if (SvIOK(wiz))
601    return wiz;
602  }
603
604  croak(vmg_invalid_wiz);
605  /* Not reached */
606  return NULL;
607 }
608
609 #define vmg_wizard_id(W)         SvIVX((const SV *) (W))
610 #define vmg_wizard_main_mgwiz(W) INT2PTR(const MGWIZ *, vmg_wizard_id(W))
611
612 /* ... Wizard destructor ................................................... */
613
614 STATIC int vmg_wizard_free(pTHX_ SV *sv, MAGIC *mg) {
615  MGWIZ *w;
616
617  if (PL_dirty) /* During global destruction, the context is already freed */
618   return 0;
619
620  w = (MGWIZ *) vmg_wizard_main_mgwiz(sv);
621
622 #if VMG_THREADSAFE
623  {
624   dMY_CXT;
625   ptable_store(MY_CXT.wizards, w, NULL);
626  }
627 #else /* VMG_THREADSAFE */
628  vmg_mgwiz_free(w);
629 #endif /* !VMG_THREADSAFE */
630
631  return 0;
632 }
633
634 #if VMG_THREADSAFE
635
636 STATIC const MGWIZ *vmg_wizard_mgwiz(pTHX_ const SV *wiz) {
637 #define vmg_wizard_mgwiz(W) vmg_wizard_mgwiz(aTHX_ ((const SV *) (W)))
638  const MGWIZ *w;
639
640  w = vmg_wizard_main_mgwiz(wiz);
641  if (w->owner == aTHX)
642   return w;
643
644  {
645   dMY_CXT;
646   return ptable_fetch(MY_CXT.wizards, w);
647  }
648 }
649
650 #else /* VMG_THREADSAFE */
651
652 #define vmg_wizard_mgwiz(W) vmg_wizard_main_mgwiz(W)
653
654 #endif /* !VMG_THREADSAFE */
655
656 /* --- User-level functions implementation --------------------------------- */
657
658 STATIC const MAGIC *vmg_find(const SV *sv, const SV *wiz) {
659  const MAGIC *mg, *moremagic;
660  IV wid;
661
662  if (SvTYPE(sv) < SVt_PVMG)
663   return NULL;
664
665  wid = vmg_wizard_id(wiz);
666  for (mg = SvMAGIC(sv); mg; mg = moremagic) {
667   moremagic = mg->mg_moremagic;
668   if (mg->mg_type == PERL_MAGIC_ext && mg->mg_private == SIG_WIZ) {
669    IV zid = vmg_wizard_id(mg->mg_ptr);
670    if (zid == wid)
671     return mg;
672   }
673  }
674
675  return NULL;
676 }
677
678 /* ... Construct private data .............................................. */
679
680 STATIC SV *vmg_data_new(pTHX_ SV *ctor, SV *sv, SV **args, I32 items) {
681 #define vmg_data_new(C, S, A, I) vmg_data_new(aTHX_ (C), (S), (A), (I))
682  I32 i;
683  SV *nsv;
684
685  dSP;
686
687  ENTER;
688  SAVETMPS;
689
690  PUSHMARK(SP);
691  EXTEND(SP, items + 1);
692  PUSHs(sv_2mortal(newRV_inc(sv)));
693  for (i = 0; i < items; ++i)
694   PUSHs(args[i]);
695  PUTBACK;
696
697  vmg_call_sv(ctor, G_SCALAR, 0);
698
699  SPAGAIN;
700  nsv = POPs;
701 #if VMG_HAS_PERL(5, 8, 3)
702  SvREFCNT_inc_simple_void(nsv); /* Or it will be destroyed in FREETMPS */
703 #else
704  nsv = sv_newref(nsv);          /* Workaround some bug in SvREFCNT_inc() */
705 #endif
706  PUTBACK;
707
708  FREETMPS;
709  LEAVE;
710
711  return nsv;
712 }
713
714 STATIC SV *vmg_data_get(pTHX_ SV *sv, const SV *wiz) {
715 #define vmg_data_get(S, W) vmg_data_get(aTHX_ (S), (W))
716  const MAGIC *mg = vmg_find(sv, wiz);
717  return mg ? mg->mg_obj : NULL;
718
719
720 /* ... Magic cast/dispell .................................................. */
721
722 #if VMG_UVAR
723 STATIC I32 vmg_svt_val(pTHX_ IV, SV *);
724
725 STATIC void vmg_uvar_del(SV *sv, MAGIC *prevmagic, MAGIC *mg, MAGIC *moremagic) {
726  if (prevmagic) {
727   prevmagic->mg_moremagic = moremagic;
728  } else {
729   SvMAGIC_set(sv, moremagic);
730  }
731  mg->mg_moremagic = NULL;
732  Safefree(mg->mg_ptr);
733  Safefree(mg);
734 }
735 #endif /* VMG_UVAR */
736
737 STATIC UV vmg_cast(pTHX_ SV *sv, const SV *wiz, SV **args, I32 items) {
738 #define vmg_cast(S, W, A, I) vmg_cast(aTHX_ (S), (W), (A), (I))
739  MAGIC       *mg, *moremagic = NULL;
740  SV          *data;
741  const MGWIZ *w;
742  U32          oldgmg;
743
744  if (vmg_find(sv, wiz))
745   return 1;
746
747  w = vmg_wizard_mgwiz(wiz);
748  oldgmg = SvGMAGICAL(sv);
749
750  data = (w->cb_data) ? vmg_data_new(w->cb_data, sv, args, items) : NULL;
751  mg = sv_magicext(sv, data, PERL_MAGIC_ext, w->vtbl, (const char *) wiz, HEf_SVKEY);
752  SvREFCNT_dec(data);
753  mg->mg_private = SIG_WIZ;
754 #if MGf_COPY
755  if (w->cb_copy)
756   mg->mg_flags |= MGf_COPY;
757 #endif /* MGf_COPY */
758 #if 0 /* MGf_DUP */
759  if (w->cb_dup)
760   mg->mg_flags |= MGf_DUP;
761 #endif /* MGf_DUP */
762 #if MGf_LOCAL
763  if (w->cb_local)
764   mg->mg_flags |= MGf_LOCAL;
765 #endif /* MGf_LOCAL */
766
767  if (SvTYPE(sv) < SVt_PVHV)
768   goto done;
769
770  /* The GMAGICAL flag only says that a hash is tied or has uvar magic - get
771   * magic is actually never called for them. If the GMAGICAL flag was off before
772   * calling sv_magicext(), the hash isn't tied and has no uvar magic. If it's
773   * now on, then this wizard has get magic. Hence we can work around the
774   * get/clear shortcoming by turning the GMAGICAL flag off. If the current magic
775   * has uvar callbacks, it will be turned back on later. */
776  if (!oldgmg && SvGMAGICAL(sv))
777   SvGMAGICAL_off(sv);
778
779 #if VMG_UVAR
780  if (w->uvar) {
781   MAGIC *prevmagic;
782   struct ufuncs uf[2];
783
784   uf[0].uf_val   = vmg_svt_val;
785   uf[0].uf_set   = NULL;
786   uf[0].uf_index = 0;
787   uf[1].uf_val   = NULL;
788   uf[1].uf_set   = NULL;
789   uf[1].uf_index = 0;
790
791   /* One uvar magic in the chain is enough. */
792   for (prevmagic = NULL, mg = SvMAGIC(sv); mg; prevmagic = mg, mg = moremagic) {
793    moremagic = mg->mg_moremagic;
794    if (mg->mg_type == PERL_MAGIC_uvar)
795     break;
796   }
797
798   if (mg) { /* Found another uvar magic. */
799    struct ufuncs *olduf = (struct ufuncs *) mg->mg_ptr;
800    if (olduf->uf_val == vmg_svt_val) {
801     /* It's our uvar magic, nothing to do. oldgmg was true. */
802     goto done;
803    } else {
804     /* It's another uvar magic, backup it and replace it by ours. */
805     uf[1] = *olduf;
806     vmg_uvar_del(sv, prevmagic, mg, moremagic);
807    }
808   }
809
810   vmg_sv_magicuvar(sv, (const char *) &uf, sizeof(uf));
811   /* Our hash now carries uvar magic. The uvar/clear shortcoming has to be
812    * handled by our uvar callback. */
813  }
814 #endif /* VMG_UVAR */
815
816 done:
817  return 1;
818 }
819
820 STATIC UV vmg_dispell(pTHX_ SV *sv, const SV *wiz) {
821 #define vmg_dispell(S, W) vmg_dispell(aTHX_ (S), (W))
822 #if VMG_UVAR
823  U32 uvars = 0;
824 #endif /* VMG_UVAR */
825  MAGIC *mg, *prevmagic, *moremagic = NULL;
826  IV wid = vmg_wizard_id(wiz);
827
828  if (SvTYPE(sv) < SVt_PVMG)
829   return 0;
830
831  for (prevmagic = NULL, mg = SvMAGIC(sv); mg; prevmagic = mg, mg = moremagic) {
832   moremagic = mg->mg_moremagic;
833   if (mg->mg_type == PERL_MAGIC_ext && mg->mg_private == SIG_WIZ) {
834    const MGWIZ *z   = vmg_wizard_mgwiz(mg->mg_ptr);
835    IV           zid = vmg_wizard_id(mg->mg_ptr);
836    if (zid == wid) {
837 #if VMG_UVAR
838     /* If the current has no uvar, short-circuit uvar deletion. */
839     uvars = z->uvar ? (uvars + 1) : 0;
840 #endif /* VMG_UVAR */
841     break;
842 #if VMG_UVAR
843    } else if (z->uvar) {
844     ++uvars;
845     /* We can't break here since we need to find the ext magic to delete. */
846 #endif /* VMG_UVAR */
847    }
848   }
849  }
850  if (!mg)
851   return 0;
852
853  if (prevmagic) {
854   prevmagic->mg_moremagic = moremagic;
855  } else {
856   SvMAGIC_set(sv, moremagic);
857  }
858  mg->mg_moremagic = NULL;
859
860  /* Destroy private data */
861  if (mg->mg_obj != sv)
862   SvREFCNT_dec(mg->mg_obj);
863  /* Unreference the wizard */
864  SvREFCNT_dec((SV *) mg->mg_ptr);
865  Safefree(mg);
866
867 #if VMG_UVAR
868  if (uvars == 1 && SvTYPE(sv) >= SVt_PVHV) {
869   /* mg was the first ext magic in the chain that had uvar */
870
871   for (mg = moremagic; mg; mg = mg->mg_moremagic) {
872    if (mg->mg_type == PERL_MAGIC_ext && mg->mg_private == SIG_WIZ) {
873     const MGWIZ *z = vmg_wizard_mgwiz(mg->mg_ptr);
874     if (z->uvar) {
875      ++uvars;
876      break;
877     }
878    }
879   }
880
881   if (uvars == 1) {
882    struct ufuncs *uf;
883    for (prevmagic = NULL, mg = SvMAGIC(sv); mg; prevmagic = mg, mg = moremagic){
884     moremagic = mg->mg_moremagic;
885     if (mg->mg_type == PERL_MAGIC_uvar)
886      break;
887    }
888    /* assert(mg); */
889    uf = (struct ufuncs *) mg->mg_ptr;
890    /* assert(uf->uf_val == vmg_svt_val); */
891    if (uf[1].uf_val || uf[1].uf_set) {
892     /* Revert the original uvar magic. */
893     uf[0] = uf[1];
894     Renew(uf, 1, struct ufuncs);
895     mg->mg_ptr = (char *) uf;
896     mg->mg_len = sizeof(struct ufuncs);
897    } else {
898     /* Remove the uvar magic. */
899     vmg_uvar_del(sv, prevmagic, mg, moremagic);
900    }
901   }
902  }
903 #endif /* VMG_UVAR */
904
905  return 1;
906 }
907
908 /* ... OP info ............................................................. */
909
910 #define VMG_OP_INFO_NAME   1
911 #define VMG_OP_INFO_OBJECT 2
912
913 #if VMG_THREADSAFE
914 STATIC perl_mutex vmg_op_name_init_mutex;
915 #endif
916
917 STATIC U32           vmg_op_name_init      = 0;
918 STATIC unsigned char vmg_op_name_len[MAXO] = { 0 };
919
920 STATIC void vmg_op_info_init(pTHX_ unsigned int opinfo) {
921 #define vmg_op_info_init(W) vmg_op_info_init(aTHX_ (W))
922  switch (opinfo) {
923   case VMG_OP_INFO_NAME:
924 #if VMG_THREADSAFE
925    MUTEX_LOCK(&vmg_op_name_init_mutex);
926 #endif
927    if (!vmg_op_name_init) {
928     OPCODE t;
929     for (t = 0; t < OP_max; ++t)
930      vmg_op_name_len[t] = strlen(PL_op_name[t]);
931     vmg_op_name_init = 1;
932    }
933 #if VMG_THREADSAFE
934    MUTEX_UNLOCK(&vmg_op_name_init_mutex);
935 #endif
936    break;
937   case VMG_OP_INFO_OBJECT: {
938    dMY_CXT;
939    if (!MY_CXT.b__op_stashes[0]) {
940     opclass c;
941     require_pv("B.pm");
942     for (c = OPc_NULL; c < OPc_MAX; ++c)
943      MY_CXT.b__op_stashes[c] = gv_stashpv(vmg_opclassnames[c], 1);
944    }
945    break;
946   }
947   default:
948    break;
949  }
950 }
951
952 STATIC SV *vmg_op_info(pTHX_ unsigned int opinfo) {
953 #define vmg_op_info(W) vmg_op_info(aTHX_ (W))
954  if (!PL_op)
955   return &PL_sv_undef;
956
957  switch (opinfo) {
958   case VMG_OP_INFO_NAME: {
959    OPCODE t = PL_op->op_type;
960    return sv_2mortal(newSVpvn(PL_op_name[t], vmg_op_name_len[t]));
961   }
962   case VMG_OP_INFO_OBJECT: {
963    dMY_CXT;
964    return sv_bless(sv_2mortal(newRV_noinc(newSViv(PTR2IV(PL_op)))),
965                    MY_CXT.b__op_stashes[vmg_opclass(PL_op)]);
966   }
967   default:
968    break;
969  }
970
971  return &PL_sv_undef;
972 }
973
974 /* ... svt callbacks ....................................................... */
975
976 #define VMG_CB_CALL_ARGS_MASK  15
977 #define VMG_CB_CALL_ARGS_SHIFT 4
978 #define VMG_CB_CALL_OPINFO     (VMG_OP_INFO_NAME|VMG_OP_INFO_OBJECT)
979
980 STATIC int vmg_cb_call(pTHX_ SV *cb, unsigned int flags, SV *sv, ...) {
981  va_list ap;
982  int ret = 0;
983  unsigned int i, args, opinfo;
984  SV *svr;
985
986  dSP;
987
988  args    = flags & VMG_CB_CALL_ARGS_MASK;
989  flags >>= VMG_CB_CALL_ARGS_SHIFT;
990  opinfo  = flags & VMG_CB_CALL_OPINFO;
991
992  ENTER;
993  SAVETMPS;
994
995  PUSHMARK(SP);
996  EXTEND(SP, args + 1);
997  PUSHs(sv_2mortal(newRV_inc(sv)));
998  va_start(ap, sv);
999  for (i = 0; i < args; ++i) {
1000   SV *sva = va_arg(ap, SV *);
1001   PUSHs(sva ? sva : &PL_sv_undef);
1002  }
1003  va_end(ap);
1004  if (opinfo)
1005   XPUSHs(vmg_op_info(opinfo));
1006  PUTBACK;
1007
1008  vmg_call_sv(cb, G_SCALAR, 0);
1009
1010  SPAGAIN;
1011  svr = POPs;
1012  if (SvOK(svr))
1013   ret = (int) SvIV(svr);
1014  PUTBACK;
1015
1016  FREETMPS;
1017  LEAVE;
1018
1019  return ret;
1020 }
1021
1022 #define VMG_CB_FLAGS(OI, A) \
1023         ((((unsigned int) (OI)) << VMG_CB_CALL_ARGS_SHIFT) | (A))
1024
1025 #define vmg_cb_call1(I, OI, S, A1) \
1026         vmg_cb_call(aTHX_ (I), VMG_CB_FLAGS((OI), 1), (S), (A1))
1027 #define vmg_cb_call2(I, OI, S, A1, A2) \
1028         vmg_cb_call(aTHX_ (I), VMG_CB_FLAGS((OI), 2), (S), (A1), (A2))
1029 #define vmg_cb_call3(I, OI, S, A1, A2, A3) \
1030         vmg_cb_call(aTHX_ (I), VMG_CB_FLAGS((OI), 3), (S), (A1), (A2), (A3))
1031
1032 STATIC int vmg_svt_get(pTHX_ SV *sv, MAGIC *mg) {
1033  const MGWIZ *w = vmg_wizard_mgwiz(mg->mg_ptr);
1034  return vmg_cb_call1(w->cb_get, w->opinfo, sv, mg->mg_obj);
1035 }
1036
1037 STATIC int vmg_svt_set(pTHX_ SV *sv, MAGIC *mg) {
1038  const MGWIZ *w = vmg_wizard_mgwiz(mg->mg_ptr);
1039  return vmg_cb_call1(w->cb_set, w->opinfo, sv, mg->mg_obj);
1040 }
1041
1042 STATIC U32 vmg_svt_len(pTHX_ SV *sv, MAGIC *mg) {
1043  const MGWIZ *w = vmg_wizard_mgwiz(mg->mg_ptr);
1044  unsigned int opinfo = w->opinfo;
1045  U32 len, ret;
1046  SV *svr;
1047  svtype t = SvTYPE(sv);
1048
1049  dSP;
1050
1051  ENTER;
1052  SAVETMPS;
1053
1054  PUSHMARK(SP);
1055  EXTEND(SP, 3);
1056  PUSHs(sv_2mortal(newRV_inc(sv)));
1057  PUSHs(mg->mg_obj ? mg->mg_obj : &PL_sv_undef);
1058  if (t < SVt_PVAV) {
1059   STRLEN l;
1060 #if VMG_HAS_PERL(5, 9, 3)
1061   const U8 *s = SvPV_const(sv, l);
1062 #else
1063   U8 *s = SvPV(sv, l);
1064 #endif
1065   if (DO_UTF8(sv))
1066    len = utf8_length(s, s + l);
1067   else
1068    len = l;
1069   mPUSHu(len);
1070  } else if (t == SVt_PVAV) {
1071   len = av_len((AV *) sv) + 1;
1072   mPUSHu(len);
1073  } else {
1074   len = 0;
1075   PUSHs(&PL_sv_undef);
1076  }
1077  if (opinfo)
1078   XPUSHs(vmg_op_info(opinfo));
1079  PUTBACK;
1080
1081  vmg_call_sv(w->cb_len, G_SCALAR, 0);
1082
1083  SPAGAIN;
1084  svr = POPs;
1085  ret = SvOK(svr) ? (U32) SvUV(svr) : len;
1086  if (t == SVt_PVAV)
1087   --ret;
1088  PUTBACK;
1089
1090  FREETMPS;
1091  LEAVE;
1092
1093  return ret;
1094 }
1095
1096 STATIC int vmg_svt_clear(pTHX_ SV *sv, MAGIC *mg) {
1097  const MGWIZ *w = vmg_wizard_mgwiz(mg->mg_ptr);
1098  return vmg_cb_call1(w->cb_clear, w->opinfo, sv, mg->mg_obj);
1099 }
1100
1101 STATIC int vmg_svt_free(pTHX_ SV *sv, MAGIC *mg) {
1102  const MGWIZ *w;
1103  int ret = 0;
1104  SV *svr;
1105
1106  dSP;
1107
1108  /* Don't even bother if we are in global destruction - the wizard is prisoner
1109   * of circular references and we are way beyond user realm */
1110  if (PL_dirty)
1111   return 0;
1112
1113  w = vmg_wizard_mgwiz(mg->mg_ptr);
1114
1115  /* So that it survives the temp cleanup below */
1116  SvREFCNT_inc_simple_void(sv);
1117
1118 #if !(VMG_HAS_PERL_MAINT(5, 11, 0, 32686) || VMG_HAS_PERL(5, 12, 0))
1119  /* The previous magic tokens were freed but the magic chain wasn't updated, so
1120   * if you access the sv from the callback the old deleted magics will trigger
1121   * and cause memory misreads. Change 32686 solved it that way : */
1122  SvMAGIC_set(sv, mg);
1123 #endif
1124
1125  ENTER;
1126  SAVETMPS;
1127
1128  PUSHMARK(SP);
1129  EXTEND(SP, 2);
1130  PUSHs(sv_2mortal(newRV_inc(sv)));
1131  PUSHs(mg->mg_obj ? mg->mg_obj : &PL_sv_undef);
1132  if (w->opinfo)
1133   XPUSHs(vmg_op_info(w->opinfo));
1134  PUTBACK;
1135
1136  vmg_call_sv(w->cb_free, G_SCALAR, 1);
1137
1138  SPAGAIN;
1139  svr = POPs;
1140  if (SvOK(svr))
1141   ret = (int) SvIV(svr);
1142  PUTBACK;
1143
1144  FREETMPS;
1145  LEAVE;
1146
1147  /* Calling SvREFCNT_dec() will trigger destructors in an infinite loop, so
1148   * we have to rely on SvREFCNT() being a lvalue. Heck, even the core does it */
1149  --SvREFCNT(sv);
1150
1151  /* Perl_mg_free will get rid of the magic and decrement mg->mg_obj and
1152   * mg->mg_ptr reference count */
1153  return ret;
1154 }
1155
1156 #if MGf_COPY
1157 STATIC int vmg_svt_copy(pTHX_ SV *sv, MAGIC *mg, SV *nsv, const char *key,
1158 # if VMG_HAS_PERL_MAINT(5, 11, 0, 33256) || VMG_HAS_PERL(5, 12, 0)
1159   I32 keylen
1160 # else
1161   int keylen
1162 # endif
1163  ) {
1164  SV *keysv;
1165  const MGWIZ *w = vmg_wizard_mgwiz(mg->mg_ptr);
1166  int ret;
1167
1168  if (keylen == HEf_SVKEY) {
1169   keysv = (SV *) key;
1170  } else {
1171   keysv = newSVpvn(key, keylen);
1172  }
1173
1174  ret = vmg_cb_call3(w->cb_copy, w->opinfo, sv, mg->mg_obj, keysv, nsv);
1175
1176  if (keylen != HEf_SVKEY) {
1177   SvREFCNT_dec(keysv);
1178  }
1179
1180  return ret;
1181 }
1182 #endif /* MGf_COPY */
1183
1184 #if 0 /*  MGf_DUP */
1185 STATIC int vmg_svt_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *param) {
1186  return 0;
1187 }
1188 #endif /* MGf_DUP */
1189
1190 #if MGf_LOCAL
1191 STATIC int vmg_svt_local(pTHX_ SV *nsv, MAGIC *mg) {
1192  const MGWIZ *w = vmg_wizard_mgwiz(mg->mg_ptr);
1193  return vmg_cb_call1(w->cb_local, w->opinfo, nsv, mg->mg_obj);
1194 }
1195 #endif /* MGf_LOCAL */
1196
1197 #if VMG_UVAR
1198 STATIC OP *vmg_pp_resetuvar(pTHX) {
1199  SvRMAGICAL_on(cSVOP_sv);
1200  return NORMAL;
1201 }
1202
1203 STATIC I32 vmg_svt_val(pTHX_ IV action, SV *sv) {
1204  struct ufuncs *uf;
1205  MAGIC *mg, *umg;
1206  SV *key = NULL, *newkey = NULL;
1207  int tied = 0;
1208
1209  umg = mg_find(sv, PERL_MAGIC_uvar);
1210  /* umg can't be NULL or we wouldn't be there. */
1211  key = umg->mg_obj;
1212  uf  = (struct ufuncs *) umg->mg_ptr;
1213
1214  if (uf[1].uf_val)
1215   uf[1].uf_val(aTHX_ action, sv);
1216  if (uf[1].uf_set)
1217   uf[1].uf_set(aTHX_ action, sv);
1218
1219  action &= HV_FETCH_ISSTORE | HV_FETCH_ISEXISTS | HV_FETCH_LVALUE | HV_DELETE;
1220  for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) {
1221   const MGWIZ *w;
1222   switch (mg->mg_type) {
1223    case PERL_MAGIC_ext:
1224     break;
1225    case PERL_MAGIC_tied:
1226     ++tied;
1227     continue;
1228    default:
1229     continue;
1230   }
1231   if (mg->mg_private != SIG_WIZ) continue;
1232   w = vmg_wizard_mgwiz(mg->mg_ptr);
1233   switch (w->uvar) {
1234    case 0:
1235     continue;
1236    case 2:
1237     if (!newkey)
1238      newkey = key = umg->mg_obj = sv_mortalcopy(umg->mg_obj);
1239   }
1240   switch (action) {
1241    case 0:
1242     if (w->cb_fetch)
1243      vmg_cb_call2(w->cb_fetch, w->opinfo, sv, mg->mg_obj, key);
1244     break;
1245    case HV_FETCH_ISSTORE:
1246    case HV_FETCH_LVALUE:
1247    case (HV_FETCH_ISSTORE|HV_FETCH_LVALUE):
1248     if (w->cb_store)
1249      vmg_cb_call2(w->cb_store, w->opinfo, sv, mg->mg_obj, key);
1250     break;
1251    case HV_FETCH_ISEXISTS:
1252     if (w->cb_exists)
1253      vmg_cb_call2(w->cb_exists, w->opinfo, sv, mg->mg_obj, key);
1254     break;
1255    case HV_DELETE:
1256     if (w->cb_delete)
1257      vmg_cb_call2(w->cb_delete, w->opinfo, sv, mg->mg_obj, key);
1258     break;
1259   }
1260  }
1261
1262  if (SvRMAGICAL(sv) && !tied) {
1263   /* Temporarily hide the RMAGICAL flag of the hash so it isn't wrongly
1264    * mistaken for a tied hash by the rest of hv_common. It will be reset by
1265    * the op_ppaddr of a new fake op injected between the current and the next
1266    * one. */
1267   OP *o = PL_op;
1268   if (!o->op_next || o->op_next->op_ppaddr != vmg_pp_resetuvar) {
1269    SVOP *svop;
1270    NewOp(1101, svop, 1, SVOP);
1271    svop->op_type   = OP_STUB;
1272    svop->op_ppaddr = vmg_pp_resetuvar;
1273    svop->op_next   = o->op_next;
1274    svop->op_flags  = 0;
1275    svop->op_sv     = sv;
1276    o->op_next      = (OP *) svop;
1277   }
1278   SvRMAGICAL_off(sv);
1279  }
1280
1281  return 0;
1282 }
1283 #endif /* VMG_UVAR */
1284
1285 /* --- Macros for the XS section ------------------------------------------- */
1286
1287 #define VMG_SET_CB(S, N)              \
1288  cb = (S);                            \
1289  w->cb_ ## N = (SvOK(cb) && SvROK(cb)) ? SvREFCNT_inc(SvRV(cb)) : NULL;
1290
1291 #define VMG_SET_SVT_CB(S, N)          \
1292  cb = (S);                            \
1293  if (SvOK(cb) && SvROK(cb)) {         \
1294   t->svt_ ## N = vmg_svt_ ## N;       \
1295   w->cb_  ## N = SvREFCNT_inc(SvRV(cb)); \
1296  } else {                             \
1297   t->svt_ ## N = NULL;                \
1298   w->cb_  ## N = NULL;                \
1299  }
1300
1301 #if VMG_THREADSAFE
1302
1303 STATIC void vmg_cleanup(pTHX_ void *ud) {
1304  dMY_CXT;
1305
1306  ptable_free(MY_CXT.wizards);
1307  MY_CXT.wizards = NULL;
1308 }
1309
1310 #endif /* VMG_THREADSAFE */
1311
1312 /* --- XS ------------------------------------------------------------------ */
1313
1314 MODULE = Variable::Magic            PACKAGE = Variable::Magic
1315
1316 PROTOTYPES: ENABLE
1317
1318 BOOT:
1319 {
1320  HV *stash;
1321
1322  MY_CXT_INIT;
1323 #if VMG_THREADSAFE
1324  MY_CXT.wizards = ptable_new();
1325  MY_CXT.owner   = aTHX;
1326 #endif
1327  MY_CXT.b__op_stashes[0] = NULL;
1328 #if VMG_THREADSAFE
1329  MUTEX_INIT(&vmg_op_name_init_mutex);
1330  call_atexit(vmg_cleanup, NULL);
1331 #endif
1332
1333  stash = gv_stashpv(__PACKAGE__, 1);
1334  newCONSTSUB(stash, "MGf_COPY",  newSVuv(MGf_COPY));
1335  newCONSTSUB(stash, "MGf_DUP",   newSVuv(MGf_DUP));
1336  newCONSTSUB(stash, "MGf_LOCAL", newSVuv(MGf_LOCAL));
1337  newCONSTSUB(stash, "VMG_UVAR",  newSVuv(VMG_UVAR));
1338  newCONSTSUB(stash, "VMG_COMPAT_ARRAY_PUSH_NOLEN",
1339                     newSVuv(VMG_COMPAT_ARRAY_PUSH_NOLEN));
1340  newCONSTSUB(stash, "VMG_COMPAT_ARRAY_PUSH_NOLEN_VOID",
1341                     newSVuv(VMG_COMPAT_ARRAY_PUSH_NOLEN_VOID));
1342  newCONSTSUB(stash, "VMG_COMPAT_ARRAY_UNSHIFT_NOLEN_VOID",
1343                     newSVuv(VMG_COMPAT_ARRAY_UNSHIFT_NOLEN_VOID));
1344  newCONSTSUB(stash, "VMG_COMPAT_ARRAY_UNDEF_CLEAR",
1345                     newSVuv(VMG_COMPAT_ARRAY_UNDEF_CLEAR));
1346  newCONSTSUB(stash, "VMG_COMPAT_SCALAR_LENGTH_NOLEN",
1347                     newSVuv(VMG_COMPAT_SCALAR_LENGTH_NOLEN));
1348  newCONSTSUB(stash, "VMG_PERL_PATCHLEVEL", newSVuv(VMG_PERL_PATCHLEVEL));
1349  newCONSTSUB(stash, "VMG_THREADSAFE",      newSVuv(VMG_THREADSAFE));
1350  newCONSTSUB(stash, "VMG_FORKSAFE",        newSVuv(VMG_FORKSAFE));
1351  newCONSTSUB(stash, "VMG_OP_INFO_NAME",    newSVuv(VMG_OP_INFO_NAME));
1352  newCONSTSUB(stash, "VMG_OP_INFO_OBJECT",  newSVuv(VMG_OP_INFO_OBJECT));
1353 }
1354
1355 #if VMG_THREADSAFE
1356
1357 void
1358 CLONE(...)
1359 PROTOTYPE: DISABLE
1360 PREINIT:
1361  ptable *t;
1362  U32     had_b__op_stash = 0;
1363  opclass c;
1364 PPCODE:
1365  {
1366   my_cxt_t ud;
1367   dMY_CXT;
1368
1369   ud.wizards = t = ptable_new();
1370   ud.owner   = MY_CXT.owner;
1371   ptable_walk(MY_CXT.wizards, vmg_ptable_clone, &ud);
1372
1373   for (c = OPc_NULL; c < OPc_MAX; ++c) {
1374    if (MY_CXT.b__op_stashes[c])
1375     had_b__op_stash |= (((U32) 1) << c);
1376   }
1377  }
1378  {
1379   MY_CXT_CLONE;
1380   MY_CXT.wizards = t;
1381   MY_CXT.owner   = aTHX;
1382   for (c = OPc_NULL; c < OPc_MAX; ++c) {
1383    MY_CXT.b__op_stashes[c] = (had_b__op_stash & (((U32) 1) << c))
1384                               ? gv_stashpv(vmg_opclassnames[c], 1) : NULL;
1385   }
1386  }
1387  XSRETURN(0);
1388
1389 #endif /* VMG_THREADSAFE */
1390
1391 SV *_wizard(...)
1392 PROTOTYPE: DISABLE
1393 PREINIT:
1394  I32 i = 0;
1395  UV opinfo;
1396  MGWIZ *w;
1397  MGVTBL *t;
1398  SV *cb;
1399 CODE:
1400  dMY_CXT;
1401
1402  if (items != 7
1403 #if MGf_COPY
1404               + 1
1405 #endif /* MGf_COPY */
1406 #if MGf_DUP
1407               + 1
1408 #endif /* MGf_DUP */
1409 #if MGf_LOCAL
1410               + 1
1411 #endif /* MGf_LOCAL */
1412 #if VMG_UVAR
1413               + 5
1414 #endif /* VMG_UVAR */
1415               ) { croak(vmg_wrongargnum); }
1416
1417  Newx(t, 1, MGVTBL);
1418  Newx(w, 1, MGWIZ);
1419
1420  VMG_SET_CB(ST(i++), data);
1421
1422  cb = ST(i++);
1423  opinfo = SvOK(cb) ? SvUV(cb) : 0;
1424  w->opinfo = (U8) ((opinfo < 255) ? opinfo : 255);
1425  if (w->opinfo)
1426   vmg_op_info_init(w->opinfo);
1427
1428  VMG_SET_SVT_CB(ST(i++), get);
1429  VMG_SET_SVT_CB(ST(i++), set);
1430  VMG_SET_SVT_CB(ST(i++), len);
1431  VMG_SET_SVT_CB(ST(i++), clear);
1432  VMG_SET_SVT_CB(ST(i++), free);
1433 #if MGf_COPY
1434  VMG_SET_SVT_CB(ST(i++), copy);
1435 #endif /* MGf_COPY */
1436 #if MGf_DUP
1437  /* VMG_SET_SVT_CB(ST(i++), dup); */
1438  i++;
1439  t->svt_dup = NULL;
1440  w->cb_dup  = NULL;
1441 #endif /* MGf_DUP */
1442 #if MGf_LOCAL
1443  VMG_SET_SVT_CB(ST(i++), local);
1444 #endif /* MGf_LOCAL */
1445 #if VMG_UVAR
1446  VMG_SET_CB(ST(i++), fetch);
1447  VMG_SET_CB(ST(i++), store);
1448  VMG_SET_CB(ST(i++), exists);
1449  VMG_SET_CB(ST(i++), delete);
1450  cb = ST(i++);
1451  if (w->cb_fetch || w->cb_store || w->cb_exists || w->cb_delete)
1452   w->uvar = SvTRUE(cb) ? 2 : 1;
1453  else
1454   w->uvar = 0;
1455 #endif /* VMG_UVAR */
1456 #if VMG_MULTIPLICITY
1457  w->owner = aTHX;
1458 #endif /* VMG_MULTIPLICITY */
1459  w->vtbl  = t;
1460 #if VMG_THREADSAFE
1461  ptable_store(MY_CXT.wizards, w, w);
1462 #endif /* VMG_THREADSAFE */
1463
1464  RETVAL = newRV_noinc(vmg_wizard_new(w));
1465 OUTPUT:
1466  RETVAL
1467
1468 SV *cast(SV *sv, SV *wiz, ...)
1469 PROTOTYPE: \[$@%&*]$@
1470 PREINIT:
1471  SV **args = NULL;
1472  I32 i = 0;
1473 CODE:
1474  if (items > 2) {
1475   i = items - 2;
1476   args = &ST(2);
1477  }
1478  RETVAL = newSVuv(vmg_cast(SvRV(sv), vmg_wizard_validate(wiz), args, i));
1479 OUTPUT:
1480  RETVAL
1481
1482 void
1483 getdata(SV *sv, SV *wiz)
1484 PROTOTYPE: \[$@%&*]$
1485 PREINIT:
1486  SV *data;
1487 PPCODE:
1488  data = vmg_data_get(SvRV(sv), vmg_wizard_validate(wiz));
1489  if (!data)
1490   XSRETURN_EMPTY;
1491  ST(0) = data;
1492  XSRETURN(1);
1493
1494 SV *dispell(SV *sv, SV *wiz)
1495 PROTOTYPE: \[$@%&*]$
1496 CODE:
1497  RETVAL = newSVuv(vmg_dispell(SvRV(sv), vmg_wizard_validate(wiz)));
1498 OUTPUT:
1499  RETVAL