]> git.vpit.fr Git - perl/modules/Variable-Magic.git/blob - Magic.xs
Add support for copy magic on code prototype clone
[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 #undef VOID2
16 #ifdef __cplusplus
17 # define VOID2(T, P) static_cast<T>(P)
18 #else
19 # define VOID2(T, P) (P)
20 #endif
21
22 #ifndef VMG_PERL_PATCHLEVEL
23 # ifdef PERL_PATCHNUM
24 #  define VMG_PERL_PATCHLEVEL PERL_PATCHNUM
25 # else
26 #  define VMG_PERL_PATCHLEVEL 0
27 # endif
28 #endif
29
30 #define VMG_HAS_PERL(R, V, S) (PERL_REVISION > (R) || (PERL_REVISION == (R) && (PERL_VERSION > (V) || (PERL_VERSION == (V) && (PERL_SUBVERSION >= (S))))))
31
32 #define VMG_HAS_PERL_BRANCH(R, V, S) (PERL_REVISION == (R) && PERL_VERSION == (V) && PERL_SUBVERSION >= (S))
33
34 #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))))
35
36 /* --- Threads and multiplicity -------------------------------------------- */
37
38 #ifndef NOOP
39 # define NOOP
40 #endif
41
42 #ifndef dNOOP
43 # define dNOOP
44 #endif
45
46 /* Safe unless stated otherwise in Makefile.PL */
47 #ifndef VMG_FORKSAFE
48 # define VMG_FORKSAFE 1
49 #endif
50
51 #ifndef VMG_MULTIPLICITY
52 # if defined(MULTIPLICITY) || defined(PERL_IMPLICIT_CONTEXT)
53 #  define VMG_MULTIPLICITY 1
54 # else
55 #  define VMG_MULTIPLICITY 0
56 # endif
57 #endif
58
59 #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))
60 # define VMG_THREADSAFE 1
61 # ifndef MY_CXT_CLONE
62 #  define MY_CXT_CLONE \
63     dMY_CXT_SV;                                                      \
64     my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1)); \
65     Copy(INT2PTR(my_cxt_t*, SvUV(my_cxt_sv)), my_cxtp, 1, my_cxt_t); \
66     sv_setuv(my_cxt_sv, PTR2UV(my_cxtp))
67 # endif
68 #else
69 # define VMG_THREADSAFE 0
70 # undef  dMY_CXT
71 # define dMY_CXT      dNOOP
72 # undef  MY_CXT
73 # define MY_CXT       vmg_globaldata
74 # undef  START_MY_CXT
75 # define START_MY_CXT STATIC my_cxt_t MY_CXT;
76 # undef  MY_CXT_INIT
77 # define MY_CXT_INIT  NOOP
78 # undef  MY_CXT_CLONE
79 # define MY_CXT_CLONE NOOP
80 #endif
81
82 #if VMG_THREADSAFE
83 # define VMG_LOCK(M)   MUTEX_LOCK(M)
84 # define VMG_UNLOCK(M) MUTEX_UNLOCK(M)
85 #else
86 # define VMG_LOCK(M)
87 # define VMG_UNLOCK(M)
88 #endif
89
90 /* --- Compatibility ------------------------------------------------------- */
91
92 #ifndef Newx
93 # define Newx(v, n, c) New(0, v, n, c)
94 #endif
95
96 #ifndef SvMAGIC_set
97 # define SvMAGIC_set(sv, val) (SvMAGIC(sv) = (val))
98 #endif
99
100 #ifndef SvRV_const
101 # define SvRV_const(sv) SvRV((SV *) sv)
102 #endif
103
104 #ifndef SvREFCNT_inc_simple_void
105 # define SvREFCNT_inc_simple_void(sv) ((void) SvREFCNT_inc(sv))
106 #endif
107
108 #ifndef mPUSHu
109 # define mPUSHu(U) PUSHs(sv_2mortal(newSVuv(U)))
110 #endif
111
112 #ifndef PERL_MAGIC_ext
113 # define PERL_MAGIC_ext '~'
114 #endif
115
116 #ifndef PERL_MAGIC_tied
117 # define PERL_MAGIC_tied 'P'
118 #endif
119
120 #ifndef MGf_LOCAL
121 # define MGf_LOCAL 0
122 #endif
123
124 #ifndef IN_PERL_COMPILETIME
125 # define IN_PERL_COMPILETIME (PL_curcop == &PL_compiling)
126 #endif
127
128 /* uvar magic and Hash::Util::FieldHash were commited with 28419, but we only
129  * enable them on 5.10 */
130 #if VMG_HAS_PERL(5, 10, 0)
131 # define VMG_UVAR 1
132 #else
133 # define VMG_UVAR 0
134 #endif
135
136 #if VMG_HAS_PERL_MAINT(5, 11, 0, 32969) || VMG_HAS_PERL(5, 12, 0)
137 # define VMG_COMPAT_SCALAR_LENGTH_NOLEN 1
138 #else
139 # define VMG_COMPAT_SCALAR_LENGTH_NOLEN 0
140 #endif
141
142 #if VMG_HAS_PERL(5, 17, 4)
143 # define VMG_COMPAT_SCALAR_NOLEN 1
144 #else
145 # define VMG_COMPAT_SCALAR_NOLEN 0
146 #endif
147
148 /* Applied to dev-5.9 as 25854, integrated to maint-5.8 as 28160, partially
149  * reverted to dev-5.11 as 9cdcb38b */
150 #if VMG_HAS_PERL_MAINT(5, 8, 9, 28160) || VMG_HAS_PERL_MAINT(5, 9, 3, 25854) || VMG_HAS_PERL(5, 10, 0)
151 # ifndef VMG_COMPAT_ARRAY_PUSH_NOLEN
152 #  if VMG_HAS_PERL(5, 11, 0)
153 #   define VMG_COMPAT_ARRAY_PUSH_NOLEN 0
154 #  else
155 #   define VMG_COMPAT_ARRAY_PUSH_NOLEN 1
156 #  endif
157 # endif
158 # ifndef VMG_COMPAT_ARRAY_PUSH_NOLEN_VOID
159 #  define VMG_COMPAT_ARRAY_PUSH_NOLEN_VOID 1
160 # endif
161 #else
162 # ifndef VMG_COMPAT_ARRAY_PUSH_NOLEN
163 #  define VMG_COMPAT_ARRAY_PUSH_NOLEN 0
164 # endif
165 # ifndef VMG_COMPAT_ARRAY_PUSH_NOLEN_VOID
166 #  define VMG_COMPAT_ARRAY_PUSH_NOLEN_VOID 0
167 # endif
168 #endif
169
170 /* Applied to dev-5.11 as 34908 */
171 #if VMG_HAS_PERL_MAINT(5, 11, 0, 34908) || VMG_HAS_PERL(5, 12, 0)
172 # define VMG_COMPAT_ARRAY_UNSHIFT_NOLEN_VOID 1
173 #else
174 # define VMG_COMPAT_ARRAY_UNSHIFT_NOLEN_VOID 0
175 #endif
176
177 /* Applied to dev-5.9 as 31473 (see #43357), integrated to maint-5.8 as 32542 */
178 #if VMG_HAS_PERL_MAINT(5, 8, 9, 32542) || VMG_HAS_PERL_MAINT(5, 9, 5, 31473) || VMG_HAS_PERL(5, 10, 0)
179 # define VMG_COMPAT_ARRAY_UNDEF_CLEAR 1
180 #else
181 # define VMG_COMPAT_ARRAY_UNDEF_CLEAR 0
182 #endif
183
184 #if VMG_HAS_PERL(5, 11, 0)
185 # define VMG_COMPAT_HASH_DELETE_NOUVAR_VOID 1
186 #else
187 # define VMG_COMPAT_HASH_DELETE_NOUVAR_VOID 0
188 #endif
189
190 #if VMG_HAS_PERL(5, 17, 0)
191 # define VMG_COMPAT_CODE_COPY_CLONE 1
192 #else
193 # define VMG_COMPAT_CODE_COPY_CLONE 0
194 #endif
195
196 #if VMG_HAS_PERL(5, 13, 2)
197 # define VMG_COMPAT_GLOB_GET 1
198 #else
199 # define VMG_COMPAT_GLOB_GET 0
200 #endif
201
202 #define VMG_PROPAGATE_ERRSV_NEEDS_TRAMPOLINE (VMG_HAS_PERL(5, 10, 0) && !VMG_HAS_PERL(5, 10, 1))
203
204 /* NewOp() isn't public in perl 5.8.0. */
205 #define VMG_RESET_RMG_NEEDS_TRAMPOLINE (VMG_UVAR && (VMG_THREADSAFE || !VMG_HAS_PERL(5, 8, 1)))
206
207 /* ... Bug-free mg_magical ................................................. */
208
209 /* See the discussion at http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2008-01/msg00036.html */
210
211 #if VMG_HAS_PERL(5, 11, 3)
212
213 #define vmg_mg_magical(S) mg_magical(S)
214
215 #else
216
217 STATIC void vmg_mg_magical(SV *sv) {
218  const MAGIC *mg;
219
220  SvMAGICAL_off(sv);
221  if ((mg = SvMAGIC(sv))) {
222   do {
223    const MGVTBL* const vtbl = mg->mg_virtual;
224    if (vtbl) {
225     if (vtbl->svt_get && !(mg->mg_flags & MGf_GSKIP))
226      SvGMAGICAL_on(sv);
227     if (vtbl->svt_set)
228      SvSMAGICAL_on(sv);
229     if (vtbl->svt_clear)
230      SvRMAGICAL_on(sv);
231    }
232   } while ((mg = mg->mg_moremagic));
233   if (!(SvFLAGS(sv) & (SVs_GMG|SVs_SMG)))
234    SvRMAGICAL_on(sv);
235  }
236 }
237
238 #endif
239
240 /* --- Trampoline ops ------------------------------------------------------ */
241
242 #define VMG_NEEDS_TRAMPOLINE VMG_PROPAGATE_ERRSV_NEEDS_TRAMPOLINE || VMG_RESET_RMG_NEEDS_TRAMPOLINE
243
244 #if VMG_NEEDS_TRAMPOLINE
245
246 typedef struct {
247  OP   temp;
248  SVOP target;
249 } vmg_trampoline;
250
251 STATIC void vmg_trampoline_init(vmg_trampoline *t, OP *(*cb)(pTHX)) {
252  t->temp.op_type    = OP_STUB;
253  t->temp.op_ppaddr  = 0;
254  t->temp.op_next    = (OP *) &t->target;
255  t->temp.op_flags   = 0;
256  t->temp.op_private = 0;
257
258  t->target.op_type    = OP_STUB;
259  t->target.op_ppaddr  = cb;
260  t->target.op_next    = NULL;
261  t->target.op_flags   = 0;
262  t->target.op_private = 0;
263  t->target.op_sv      = NULL;
264 }
265
266 STATIC OP *vmg_trampoline_bump(pTHX_ vmg_trampoline *t, SV *sv, OP *o) {
267 #define vmg_trampoline_bump(T, S, O) vmg_trampoline_bump(aTHX_ (T), (S), (O))
268  t->temp         = *o;
269  t->temp.op_next = (OP *) &t->target;
270
271  t->target.op_sv   = sv;
272  t->target.op_next = o->op_next;
273
274  return &t->temp;
275 }
276
277 #endif /* VMG_NEEDS_TRAMPOLINE */
278
279 /* --- Safe version of call_sv() ------------------------------------------- */
280
281 STATIC I32 vmg_call_sv(pTHX_ SV *sv, I32 flags, int (*cleanup)(pTHX_ void *), void *ud) {
282 #define vmg_call_sv(S, F, C, U) vmg_call_sv(aTHX_ (S), (F), (C), (U))
283  I32 ret, cxix;
284  PERL_CONTEXT saved_cx;
285  SV *old_err = NULL;
286
287  if (SvTRUE(ERRSV)) {
288   old_err = ERRSV;
289   ERRSV   = newSV(0);
290  }
291
292  cxix     = (cxstack_ix < cxstack_max) ? (cxstack_ix + 1) : Perl_cxinc(aTHX);
293  /* The last popped context will be reused by call_sv(), but our callers may
294   * still need its previous value. Back it up so that it isn't clobbered. */
295  saved_cx = cxstack[cxix];
296
297  ret = call_sv(sv, flags | G_EVAL);
298
299  cxstack[cxix] = saved_cx;
300
301  if (SvTRUE(ERRSV)) {
302   if (old_err) {
303    sv_setsv(old_err, ERRSV);
304    SvREFCNT_dec(ERRSV);
305    ERRSV = old_err;
306   }
307   if (IN_PERL_COMPILETIME) {
308    if (!PL_in_eval) {
309     if (PL_errors)
310      sv_catsv(PL_errors, ERRSV);
311     else
312      Perl_warn(aTHX_ "%s", SvPV_nolen(ERRSV));
313     SvCUR_set(ERRSV, 0);
314    }
315 #if VMG_HAS_PERL(5, 10, 0) || defined(PL_parser)
316    if (PL_parser)
317     ++PL_parser->error_count;
318 #elif defined(PL_error_count)
319    ++PL_error_count;
320 #else
321    ++PL_Ierror_count;
322 #endif
323   } else {
324    if (!cleanup || cleanup(aTHX_ ud))
325     croak(NULL);
326   }
327  } else {
328   if (old_err) {
329    SvREFCNT_dec(ERRSV);
330    ERRSV = old_err;
331   }
332  }
333
334  return ret;
335 }
336
337 /* --- Stolen chunk of B --------------------------------------------------- */
338
339 typedef enum {
340  OPc_NULL   = 0,
341  OPc_BASEOP = 1,
342  OPc_UNOP   = 2,
343  OPc_BINOP  = 3,
344  OPc_LOGOP  = 4,
345  OPc_LISTOP = 5,
346  OPc_PMOP   = 6,
347  OPc_SVOP   = 7,
348  OPc_PADOP  = 8,
349  OPc_PVOP   = 9,
350  OPc_LOOP   = 10,
351  OPc_COP    = 11,
352  OPc_MAX    = 12
353 } opclass;
354
355 STATIC const char *const vmg_opclassnames[] = {
356  "B::NULL",
357  "B::OP",
358  "B::UNOP",
359  "B::BINOP",
360  "B::LOGOP",
361  "B::LISTOP",
362  "B::PMOP",
363  "B::SVOP",
364  "B::PADOP",
365  "B::PVOP",
366  "B::LOOP",
367  "B::COP"
368 };
369
370 STATIC opclass vmg_opclass(const OP *o) {
371 #if 0
372  if (!o)
373   return OPc_NULL;
374 #endif
375
376  if (o->op_type == 0)
377   return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
378
379  if (o->op_type == OP_SASSIGN)
380   return ((o->op_private & OPpASSIGN_BACKWARDS) ? OPc_UNOP : OPc_BINOP);
381
382  if (o->op_type == OP_AELEMFAST) {
383 #if PERL_VERSION <= 14
384   if (o->op_flags & OPf_SPECIAL)
385    return OPc_BASEOP;
386   else
387 #endif
388 #ifdef USE_ITHREADS
389    return OPc_PADOP;
390 #else
391    return OPc_SVOP;
392 #endif
393  }
394
395 #ifdef USE_ITHREADS
396  if (o->op_type == OP_GV || o->op_type == OP_GVSV || o->op_type == OP_RCATLINE)
397   return OPc_PADOP;
398 #endif
399
400  switch (PL_opargs[o->op_type] & OA_CLASS_MASK) {
401   case OA_BASEOP:
402    return OPc_BASEOP;
403   case OA_UNOP:
404    return OPc_UNOP;
405   case OA_BINOP:
406    return OPc_BINOP;
407   case OA_LOGOP:
408    return OPc_LOGOP;
409   case OA_LISTOP:
410    return OPc_LISTOP;
411   case OA_PMOP:
412    return OPc_PMOP;
413   case OA_SVOP:
414    return OPc_SVOP;
415   case OA_PADOP:
416    return OPc_PADOP;
417   case OA_PVOP_OR_SVOP:
418    return (o->op_private & (OPpTRANS_TO_UTF|OPpTRANS_FROM_UTF)) ? OPc_SVOP : OPc_PVOP;
419   case OA_LOOP:
420    return OPc_LOOP;
421   case OA_COP:
422    return OPc_COP;
423   case OA_BASEOP_OR_UNOP:
424    return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
425   case OA_FILESTATOP:
426    return ((o->op_flags & OPf_KIDS) ? OPc_UNOP :
427 #ifdef USE_ITHREADS
428            (o->op_flags & OPf_REF) ? OPc_PADOP : OPc_BASEOP);
429 #else
430            (o->op_flags & OPf_REF) ? OPc_SVOP : OPc_BASEOP);
431 #endif
432   case OA_LOOPEXOP:
433    if (o->op_flags & OPf_STACKED)
434     return OPc_UNOP;
435    else if (o->op_flags & OPf_SPECIAL)
436     return OPc_BASEOP;
437    else
438     return OPc_PVOP;
439  }
440
441  return OPc_BASEOP;
442 }
443
444 /* --- Error messages ------------------------------------------------------ */
445
446 STATIC const char vmg_invalid_wiz[]    = "Invalid wizard object";
447 STATIC const char vmg_wrongargnum[]    = "Wrong number of arguments";
448 STATIC const char vmg_argstorefailed[] = "Error while storing arguments";
449
450 /* --- Context-safe global data -------------------------------------------- */
451
452 #define MY_CXT_KEY __PACKAGE__ "::_guts" XS_VERSION
453
454 typedef struct {
455  HV             *b__op_stashes[OPc_MAX];
456  I32             depth;
457  MAGIC          *freed_tokens;
458 #if VMG_PROPAGATE_ERRSV_NEEDS_TRAMPOLINE
459  vmg_trampoline  propagate_errsv;
460 #endif
461 #if VMG_RESET_RMG_NEEDS_TRAMPOLINE
462  vmg_trampoline  reset_rmg;
463 #endif
464 } my_cxt_t;
465
466 START_MY_CXT
467
468 /* --- <vmg_vtable> structure ---------------------------------------------- */
469
470 #if VMG_THREADSAFE
471
472 typedef struct {
473  MGVTBL *vtbl;
474  U32     refcount;
475 } vmg_vtable;
476
477 STATIC vmg_vtable *vmg_vtable_alloc(pTHX) {
478 #define vmg_vtable_alloc() vmg_vtable_alloc(aTHX)
479  vmg_vtable *t;
480
481  t = VOID2(vmg_vtable *, PerlMemShared_malloc(sizeof *t));
482
483  t->vtbl     = VOID2(MGVTBL *, PerlMemShared_malloc(sizeof *t->vtbl));
484  t->refcount = 1;
485
486  return t;
487 }
488
489 #define vmg_vtable_vtbl(T) (T)->vtbl
490
491 STATIC perl_mutex vmg_vtable_refcount_mutex;
492
493 STATIC vmg_vtable *vmg_vtable_dup(pTHX_ vmg_vtable *t) {
494 #define vmg_vtable_dup(T) vmg_vtable_dup(aTHX_ (T))
495  VMG_LOCK(&vmg_vtable_refcount_mutex);
496  ++t->refcount;
497  VMG_UNLOCK(&vmg_vtable_refcount_mutex);
498
499  return t;
500 }
501
502 STATIC void vmg_vtable_free(pTHX_ vmg_vtable *t) {
503 #define vmg_vtable_free(T) vmg_vtable_free(aTHX_ (T))
504  U32 refcount;
505
506  VMG_LOCK(&vmg_vtable_refcount_mutex);
507  refcount = --t->refcount;
508  VMG_UNLOCK(&vmg_vtable_refcount_mutex);
509
510  if (!refcount) {
511   PerlMemShared_free(t->vtbl);
512   PerlMemShared_free(t);
513  }
514 }
515
516 #else /* VMG_THREADSAFE */
517
518 typedef MGVTBL vmg_vtable;
519
520 STATIC vmg_vtable *vmg_vtable_alloc(pTHX) {
521 #define vmg_vtable_alloc() vmg_vtable_alloc(aTHX)
522  vmg_vtable *t;
523
524  Newx(t, 1, vmg_vtable);
525
526  return t;
527 }
528
529 #define vmg_vtable_vtbl(T) ((MGVTBL *) (T))
530
531 #define vmg_vtable_free(T) Safefree(T)
532
533 #endif /* !VMG_THREADSAFE */
534
535 /* --- <vmg_wizard> structure ---------------------------------------------- */
536
537 typedef struct {
538  vmg_vtable *vtable;
539
540  U8 opinfo;
541  U8 uvar;
542
543  SV *cb_data;
544  SV *cb_get, *cb_set, *cb_len, *cb_clear, *cb_free;
545  SV *cb_copy;
546  SV *cb_dup;
547 #if MGf_LOCAL
548  SV *cb_local;
549 #endif /* MGf_LOCAL */
550 #if VMG_UVAR
551  SV *cb_fetch, *cb_store, *cb_exists, *cb_delete;
552 #endif /* VMG_UVAR */
553 } vmg_wizard;
554
555 STATIC void vmg_op_info_init(pTHX_ unsigned int opinfo);
556
557 STATIC vmg_wizard *vmg_wizard_alloc(pTHX_ UV opinfo) {
558 #define vmg_wizard_alloc(O) vmg_wizard_alloc(aTHX_ (O))
559  vmg_wizard *w;
560
561  Newx(w, 1, vmg_wizard);
562
563  w->uvar   = 0;
564  w->opinfo = (U8) ((opinfo < 255) ? opinfo : 255);
565  if (w->opinfo)
566   vmg_op_info_init(aTHX_ w->opinfo);
567
568  w->vtable = vmg_vtable_alloc();
569
570  return w;
571 }
572
573 STATIC void vmg_wizard_free(pTHX_ vmg_wizard *w) {
574 #define vmg_wizard_free(W) vmg_wizard_free(aTHX_ (W))
575  if (!w)
576   return;
577
578  /* During global destruction, any of the callbacks may already have been
579   * freed, so we can't rely on still being able to access them. */
580  if (!PL_dirty) {
581   SvREFCNT_dec(w->cb_data);
582   SvREFCNT_dec(w->cb_get);
583   SvREFCNT_dec(w->cb_set);
584   SvREFCNT_dec(w->cb_len);
585   SvREFCNT_dec(w->cb_clear);
586   SvREFCNT_dec(w->cb_free);
587   SvREFCNT_dec(w->cb_copy);
588 #if 0
589   SvREFCNT_dec(w->cb_dup);
590 #endif
591 #if MGf_LOCAL
592   SvREFCNT_dec(w->cb_local);
593 #endif /* MGf_LOCAL */
594 #if VMG_UVAR
595   SvREFCNT_dec(w->cb_fetch);
596   SvREFCNT_dec(w->cb_store);
597   SvREFCNT_dec(w->cb_exists);
598   SvREFCNT_dec(w->cb_delete);
599 #endif /* VMG_UVAR */
600  }
601
602  /* PerlMemShared_free() and Safefree() are still fine during global
603   * destruction though. */
604  vmg_vtable_free(w->vtable);
605  Safefree(w);
606
607  return;
608 }
609
610 #if VMG_THREADSAFE
611
612 #define VMG_CLONE_CB(N) \
613  z->cb_ ## N = (w->cb_ ## N) ? SvREFCNT_inc(sv_dup(w->cb_ ## N, params)) \
614                              : NULL;
615
616 STATIC const vmg_wizard *vmg_wizard_dup(pTHX_ const vmg_wizard *w, CLONE_PARAMS *params) {
617 #define vmg_wizard_dup(W, P) vmg_wizard_dup(aTHX_ (W), (P))
618  vmg_wizard *z;
619
620  if (!w)
621   return NULL;
622
623  Newx(z, 1, vmg_wizard);
624
625  z->vtable = vmg_vtable_dup(w->vtable);
626  z->uvar   = w->uvar;
627  z->opinfo = w->opinfo;
628
629  VMG_CLONE_CB(data);
630  VMG_CLONE_CB(get);
631  VMG_CLONE_CB(set);
632  VMG_CLONE_CB(len);
633  VMG_CLONE_CB(clear);
634  VMG_CLONE_CB(free);
635  VMG_CLONE_CB(copy);
636  VMG_CLONE_CB(dup);
637 #if MGf_LOCAL
638  VMG_CLONE_CB(local);
639 #endif /* MGf_LOCAL */
640 #if VMG_UVAR
641  VMG_CLONE_CB(fetch);
642  VMG_CLONE_CB(store);
643  VMG_CLONE_CB(exists);
644  VMG_CLONE_CB(delete);
645 #endif /* VMG_UVAR */
646
647  return z;
648 }
649
650 #endif /* VMG_THREADSAFE */
651
652 #define vmg_wizard_id(W) PTR2IV(vmg_vtable_vtbl((W)->vtable))
653
654 /* --- Wizard SV objects --------------------------------------------------- */
655
656 STATIC int vmg_wizard_sv_free(pTHX_ SV *sv, MAGIC *mg) {
657  vmg_wizard_free((vmg_wizard *) mg->mg_ptr);
658
659  return 0;
660 }
661
662 #if VMG_THREADSAFE
663
664 STATIC int vmg_wizard_sv_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *params) {
665  mg->mg_ptr = (char *) vmg_wizard_dup((const vmg_wizard *) mg->mg_ptr, params);
666
667  return 0;
668 }
669
670 #endif /* VMG_THREADSAFE */
671
672 STATIC MGVTBL vmg_wizard_sv_vtbl = {
673  NULL,               /* get */
674  NULL,               /* set */
675  NULL,               /* len */
676  NULL,               /* clear */
677  vmg_wizard_sv_free, /* free */
678  NULL,               /* copy */
679 #if VMG_THREADSAFE
680  vmg_wizard_sv_dup,  /* dup */
681 #else
682  NULL,               /* dup */
683 #endif
684 #if MGf_LOCAL
685  NULL,               /* local */
686 #endif /* MGf_LOCAL */
687 };
688
689 STATIC SV *vmg_wizard_sv_new(pTHX_ const vmg_wizard *w) {
690 #define vmg_wizard_sv_new(W) vmg_wizard_sv_new(aTHX_ (W))
691  SV *wiz;
692
693 #if VMG_THREADSAFE
694  wiz = newSV(0);
695 #else
696  wiz = newSViv(PTR2IV(w));
697 #endif
698
699  if (w) {
700   MAGIC *mg = sv_magicext(wiz, NULL, PERL_MAGIC_ext, &vmg_wizard_sv_vtbl,
701                                      (const char *) w, 0);
702   mg->mg_private = 0;
703 #if VMG_THREADSAFE
704   mg->mg_flags  |= MGf_DUP;
705 #endif
706  }
707  SvREADONLY_on(wiz);
708
709  return wiz;
710 }
711
712 #if VMG_THREADSAFE
713
714 #define vmg_sv_has_wizard_type(S) (SvTYPE(S) >= SVt_PVMG)
715
716 STATIC const vmg_wizard *vmg_wizard_from_sv_nocheck(const SV *wiz) {
717  MAGIC *mg;
718
719  for (mg = SvMAGIC(wiz); mg; mg = mg->mg_moremagic) {
720   if (mg->mg_type == PERL_MAGIC_ext && mg->mg_virtual == &vmg_wizard_sv_vtbl)
721    return (const vmg_wizard *) mg->mg_ptr;
722  }
723
724  return NULL;
725 }
726
727 #else /* VMG_THREADSAFE */
728
729 #define vmg_sv_has_wizard_type(S) SvIOK(S)
730
731 #define vmg_wizard_from_sv_nocheck(W) INT2PTR(const vmg_wizard *, SvIVX(W))
732
733 #endif /* !VMG_THREADSAFE */
734
735 #define vmg_wizard_from_sv(W) (vmg_sv_has_wizard_type(W) ? vmg_wizard_from_sv_nocheck(W) : NULL)
736
737 STATIC const vmg_wizard *vmg_wizard_from_mg(const MAGIC *mg) {
738  if (mg->mg_type == PERL_MAGIC_ext && mg->mg_len == HEf_SVKEY) {
739   SV *sv = (SV *) mg->mg_ptr;
740
741   if (vmg_sv_has_wizard_type(sv))
742    return vmg_wizard_from_sv_nocheck(sv);
743  }
744
745  return NULL;
746 }
747
748 #define vmg_wizard_from_mg_nocheck(M) vmg_wizard_from_sv_nocheck((const SV *) (M)->mg_ptr)
749
750 /* --- User-level functions implementation --------------------------------- */
751
752 STATIC const MAGIC *vmg_find(const SV *sv, const vmg_wizard *w) {
753  const MAGIC *mg;
754  IV wid;
755
756  if (SvTYPE(sv) < SVt_PVMG)
757   return NULL;
758
759  wid = vmg_wizard_id(w);
760
761  for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) {
762   const vmg_wizard *z = vmg_wizard_from_mg(mg);
763
764   if (z && vmg_wizard_id(z) == wid)
765    return mg;
766  }
767
768  return NULL;
769 }
770
771 /* ... Construct private data .............................................. */
772
773 STATIC SV *vmg_data_new(pTHX_ SV *ctor, SV *sv, SV **args, I32 items) {
774 #define vmg_data_new(C, S, A, I) vmg_data_new(aTHX_ (C), (S), (A), (I))
775  I32 i;
776  SV *nsv;
777
778  dSP;
779
780  ENTER;
781  SAVETMPS;
782
783  PUSHMARK(SP);
784  EXTEND(SP, items + 1);
785  PUSHs(sv_2mortal(newRV_inc(sv)));
786  for (i = 0; i < items; ++i)
787   PUSHs(args[i]);
788  PUTBACK;
789
790  vmg_call_sv(ctor, G_SCALAR, 0, NULL);
791
792  SPAGAIN;
793  nsv = POPs;
794 #if VMG_HAS_PERL(5, 8, 3)
795  SvREFCNT_inc_simple_void(nsv); /* Or it will be destroyed in FREETMPS */
796 #else
797  nsv = sv_newref(nsv);          /* Workaround some bug in SvREFCNT_inc() */
798 #endif
799  PUTBACK;
800
801  FREETMPS;
802  LEAVE;
803
804  return nsv;
805 }
806
807 STATIC SV *vmg_data_get(pTHX_ SV *sv, const vmg_wizard *w) {
808 #define vmg_data_get(S, W) vmg_data_get(aTHX_ (S), (W))
809  const MAGIC *mg = vmg_find(sv, w);
810
811  return mg ? mg->mg_obj : NULL;
812 }
813
814 /* ... Magic cast/dispell .................................................. */
815
816 #if VMG_UVAR
817
818 STATIC I32 vmg_svt_val(pTHX_ IV, SV *);
819
820 typedef struct {
821  struct ufuncs new_uf;
822  struct ufuncs old_uf;
823 } vmg_uvar_ud;
824
825 #endif /* VMG_UVAR */
826
827 STATIC void vmg_mg_del(pTHX_ SV *sv, MAGIC *prevmagic, MAGIC *mg, MAGIC *moremagic) {
828 #define vmg_mg_del(S, P, M, N) vmg_mg_del(aTHX_ (S), (P), (M), (N))
829  dMY_CXT;
830
831  if (prevmagic)
832   prevmagic->mg_moremagic = moremagic;
833  else
834   SvMAGIC_set(sv, moremagic);
835
836  /* Destroy private data */
837 #if VMG_UVAR
838  if (mg->mg_type == PERL_MAGIC_uvar) {
839   Safefree(mg->mg_ptr);
840  } else {
841 #endif /* VMG_UVAR */
842   if (mg->mg_obj != sv) {
843    SvREFCNT_dec(mg->mg_obj);
844    mg->mg_obj = NULL;
845   }
846   /* Unreference the wizard */
847   SvREFCNT_dec((SV *) mg->mg_ptr);
848   mg->mg_ptr = NULL;
849 #if VMG_UVAR
850  }
851 #endif /* VMG_UVAR */
852
853  if (MY_CXT.depth) {
854   mg->mg_moremagic    = MY_CXT.freed_tokens;
855   MY_CXT.freed_tokens = mg;
856  } else {
857   mg->mg_moremagic = NULL;
858   Safefree(mg);
859  }
860 }
861
862 STATIC int vmg_magic_chain_free(pTHX_ MAGIC *mg, MAGIC *skip) {
863 #define vmg_magic_chain_free(M, S) vmg_magic_chain_free(aTHX_ (M), (S))
864  int skipped = 0;
865
866  while (mg) {
867   MAGIC *moremagic = mg->mg_moremagic;
868
869   if (mg == skip)
870    ++skipped;
871   else
872    Safefree(mg);
873
874   mg = moremagic;
875  }
876
877  return skipped;
878 }
879
880 STATIC UV vmg_cast(pTHX_ SV *sv, const vmg_wizard *w, const SV *wiz, SV **args, I32 items) {
881 #define vmg_cast(S, W, WIZ, A, I) vmg_cast(aTHX_ (S), (W), (WIZ), (A), (I))
882  MAGIC  *mg;
883  MGVTBL *t;
884  SV     *data;
885  U32     oldgmg;
886
887  if (vmg_find(sv, w))
888   return 1;
889
890  oldgmg = SvGMAGICAL(sv);
891
892  data = (w->cb_data) ? vmg_data_new(w->cb_data, sv, args, items) : NULL;
893
894  t  = vmg_vtable_vtbl(w->vtable);
895  mg = sv_magicext(sv, data, PERL_MAGIC_ext, t, (const char *) wiz, HEf_SVKEY);
896  mg->mg_private = 0;
897
898  /* sv_magicext() calls mg_magical and increments data's refcount */
899  SvREFCNT_dec(data);
900
901  if (t->svt_copy)
902   mg->mg_flags |= MGf_COPY;
903 #if 0
904  if (t->svt_dup)
905   mg->mg_flags |= MGf_DUP;
906 #endif
907 #if MGf_LOCAL
908  if (t->svt_local)
909   mg->mg_flags |= MGf_LOCAL;
910 #endif /* MGf_LOCAL */
911
912  if (SvTYPE(sv) < SVt_PVHV)
913   goto done;
914
915  /* The GMAGICAL flag only says that a hash is tied or has uvar magic - get
916   * magic is actually never called for them. If the GMAGICAL flag was off before
917   * calling sv_magicext(), the hash isn't tied and has no uvar magic. If it's
918   * now on, then this wizard has get magic. Hence we can work around the
919   * get/clear shortcoming by turning the GMAGICAL flag off. If the current magic
920   * has uvar callbacks, it will be turned back on later. */
921  if (!oldgmg && SvGMAGICAL(sv))
922   SvGMAGICAL_off(sv);
923
924 #if VMG_UVAR
925  if (w->uvar) {
926   MAGIC *prevmagic, *moremagic = NULL;
927   vmg_uvar_ud ud;
928
929   ud.new_uf.uf_val   = vmg_svt_val;
930   ud.new_uf.uf_set   = NULL;
931   ud.new_uf.uf_index = 0;
932   ud.old_uf.uf_val   = NULL;
933   ud.old_uf.uf_set   = NULL;
934   ud.old_uf.uf_index = 0;
935
936   /* One uvar magic in the chain is enough. */
937   for (prevmagic = NULL, mg = SvMAGIC(sv); mg; prevmagic = mg, mg = moremagic) {
938    moremagic = mg->mg_moremagic;
939    if (mg->mg_type == PERL_MAGIC_uvar)
940     break;
941   }
942
943   if (mg) { /* Found another uvar magic. */
944    struct ufuncs *uf = (struct ufuncs *) mg->mg_ptr;
945    if (uf->uf_val == vmg_svt_val) {
946     /* It's our uvar magic, nothing to do. oldgmg was true. */
947     goto done;
948    } else {
949     /* It's another uvar magic, backup it and replace it by ours. */
950     ud.old_uf = *uf;
951     vmg_mg_del(sv, prevmagic, mg, moremagic);
952    }
953   }
954
955   sv_magic(sv, NULL, PERL_MAGIC_uvar, (const char *) &ud, sizeof(ud));
956   vmg_mg_magical(sv);
957   /* Our hash now carries uvar magic. The uvar/clear shortcoming has to be
958    * handled by our uvar callback. */
959  }
960 #endif /* VMG_UVAR */
961
962 done:
963  return 1;
964 }
965
966 STATIC UV vmg_dispell(pTHX_ SV *sv, const vmg_wizard *w) {
967 #define vmg_dispell(S, W) vmg_dispell(aTHX_ (S), (W))
968 #if VMG_UVAR
969  U32 uvars = 0;
970 #endif /* VMG_UVAR */
971  MAGIC *mg, *prevmagic, *moremagic = NULL;
972  IV wid = vmg_wizard_id(w);
973
974  if (SvTYPE(sv) < SVt_PVMG)
975   return 0;
976
977  for (prevmagic = NULL, mg = SvMAGIC(sv); mg; prevmagic = mg, mg = moremagic) {
978   const vmg_wizard *z;
979
980   moremagic = mg->mg_moremagic;
981
982   z = vmg_wizard_from_mg(mg);
983   if (z) {
984    IV zid = vmg_wizard_id(z);
985
986 #if VMG_UVAR
987    if (zid == wid) {
988     /* If the current has no uvar, short-circuit uvar deletion. */
989     uvars = z->uvar ? (uvars + 1) : 0;
990     break;
991    } else if (z->uvar) {
992     ++uvars;
993     /* We can't break here since we need to find the ext magic to delete. */
994    }
995 #else /* VMG_UVAR */
996    if (zid == wid)
997     break;
998 #endif /* !VMG_UVAR */
999   }
1000  }
1001  if (!mg)
1002   return 0;
1003
1004  vmg_mg_del(sv, prevmagic, mg, moremagic);
1005
1006 #if VMG_UVAR
1007  if (uvars == 1 && SvTYPE(sv) >= SVt_PVHV) {
1008   /* mg was the first ext magic in the chain that had uvar */
1009
1010   for (mg = moremagic; mg; mg = mg->mg_moremagic) {
1011    const vmg_wizard *z = vmg_wizard_from_mg(mg);
1012
1013    if (z && z->uvar) {
1014     ++uvars;
1015     break;
1016    }
1017   }
1018
1019   if (uvars == 1) {
1020    vmg_uvar_ud *ud;
1021
1022    for (prevmagic = NULL, mg = SvMAGIC(sv); mg; prevmagic = mg, mg = moremagic){
1023     moremagic = mg->mg_moremagic;
1024     if (mg->mg_type == PERL_MAGIC_uvar)
1025      break;
1026    }
1027
1028    ud = (vmg_uvar_ud *) mg->mg_ptr;
1029    if (ud->old_uf.uf_val || ud->old_uf.uf_set) {
1030     /* Revert the original uvar magic. */
1031     struct ufuncs *uf;
1032     Newx(uf, 1, struct ufuncs);
1033     *uf = ud->old_uf;
1034     Safefree(ud);
1035     mg->mg_ptr = (char *) uf;
1036     mg->mg_len = sizeof(*uf);
1037    } else {
1038     /* Remove the uvar magic. */
1039     vmg_mg_del(sv, prevmagic, mg, moremagic);
1040    }
1041   }
1042  }
1043 #endif /* VMG_UVAR */
1044
1045  vmg_mg_magical(sv);
1046
1047  return 1;
1048 }
1049
1050 /* ... OP info ............................................................. */
1051
1052 #define VMG_OP_INFO_NAME   1
1053 #define VMG_OP_INFO_OBJECT 2
1054
1055 #if VMG_THREADSAFE
1056 STATIC perl_mutex vmg_op_name_init_mutex;
1057 #endif
1058
1059 STATIC U32           vmg_op_name_init      = 0;
1060 STATIC unsigned char vmg_op_name_len[MAXO] = { 0 };
1061
1062 STATIC void vmg_op_info_init(pTHX_ unsigned int opinfo) {
1063 #define vmg_op_info_init(W) vmg_op_info_init(aTHX_ (W))
1064  switch (opinfo) {
1065   case VMG_OP_INFO_NAME:
1066    VMG_LOCK(&vmg_op_name_init_mutex);
1067    if (!vmg_op_name_init) {
1068     OPCODE t;
1069     for (t = 0; t < OP_max; ++t)
1070      vmg_op_name_len[t] = strlen(PL_op_name[t]);
1071     vmg_op_name_init = 1;
1072    }
1073    VMG_UNLOCK(&vmg_op_name_init_mutex);
1074    break;
1075   case VMG_OP_INFO_OBJECT: {
1076    dMY_CXT;
1077    if (!MY_CXT.b__op_stashes[0]) {
1078     int c;
1079     require_pv("B.pm");
1080     for (c = OPc_NULL; c < OPc_MAX; ++c)
1081      MY_CXT.b__op_stashes[c] = gv_stashpv(vmg_opclassnames[c], 1);
1082    }
1083    break;
1084   }
1085   default:
1086    break;
1087  }
1088 }
1089
1090 STATIC SV *vmg_op_info(pTHX_ unsigned int opinfo) {
1091 #define vmg_op_info(W) vmg_op_info(aTHX_ (W))
1092  if (!PL_op)
1093   return &PL_sv_undef;
1094
1095  switch (opinfo) {
1096   case VMG_OP_INFO_NAME: {
1097    OPCODE t = PL_op->op_type;
1098    return sv_2mortal(newSVpvn(PL_op_name[t], vmg_op_name_len[t]));
1099   }
1100   case VMG_OP_INFO_OBJECT: {
1101    dMY_CXT;
1102    return sv_bless(sv_2mortal(newRV_noinc(newSViv(PTR2IV(PL_op)))),
1103                    MY_CXT.b__op_stashes[vmg_opclass(PL_op)]);
1104   }
1105   default:
1106    break;
1107  }
1108
1109  return &PL_sv_undef;
1110 }
1111
1112 /* --- svt callbacks ------------------------------------------------------- */
1113
1114 #define VMG_CB_CALL_ARGS_MASK  15
1115 #define VMG_CB_CALL_ARGS_SHIFT 4
1116 #define VMG_CB_CALL_OPINFO     (VMG_OP_INFO_NAME|VMG_OP_INFO_OBJECT) /* 1|2 */
1117 #define VMG_CB_CALL_GUARD      4
1118
1119 STATIC int vmg_dispell_guard_oncroak(pTHX_ void *ud) {
1120  dMY_CXT;
1121
1122  MY_CXT.depth--;
1123
1124  /* If we're at the upmost magic call and we're about to die, we can just free
1125   * the tokens right now, since we will jump past the problematic part of our
1126   * caller. */
1127  if (MY_CXT.depth == 0 && MY_CXT.freed_tokens) {
1128   vmg_magic_chain_free(MY_CXT.freed_tokens, NULL);
1129   MY_CXT.freed_tokens = NULL;
1130  }
1131
1132  return 1;
1133 }
1134
1135 STATIC int vmg_dispell_guard_free(pTHX_ SV *sv, MAGIC *mg) {
1136  vmg_magic_chain_free((MAGIC *) mg->mg_ptr, NULL);
1137
1138  return 0;
1139 }
1140
1141 #if VMG_THREADSAFE
1142
1143 STATIC int vmg_dispell_guard_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *params) {
1144  /* The freed magic tokens aren't cloned by perl because it cannot reach them
1145   * (they have been detached from their parent SV when they were enqueued).
1146   * Hence there's nothing to purge in the new thread. */
1147  mg->mg_ptr = NULL;
1148
1149  return 0;
1150 }
1151
1152 #endif /* VMG_THREADSAFE */
1153
1154 STATIC MGVTBL vmg_dispell_guard_vtbl = {
1155  NULL,                   /* get */
1156  NULL,                   /* set */
1157  NULL,                   /* len */
1158  NULL,                   /* clear */
1159  vmg_dispell_guard_free, /* free */
1160  NULL,                   /* copy */
1161 #if VMG_THREADSAFE
1162  vmg_dispell_guard_dup,  /* dup */
1163 #else
1164  NULL,                   /* dup */
1165 #endif
1166 #if MGf_LOCAL
1167  NULL,                   /* local */
1168 #endif /* MGf_LOCAL */
1169 };
1170
1171 STATIC SV *vmg_dispell_guard_new(pTHX_ MAGIC *root) {
1172 #define vmg_dispell_guard_new(R) vmg_dispell_guard_new(aTHX_ (R))
1173  SV *guard;
1174
1175  guard = sv_newmortal();
1176  sv_magicext(guard, NULL, PERL_MAGIC_ext, &vmg_dispell_guard_vtbl,
1177                           (char *) root, 0);
1178
1179  return guard;
1180 }
1181
1182 STATIC int vmg_cb_call(pTHX_ SV *cb, unsigned int flags, SV *sv, ...) {
1183  va_list ap;
1184  int ret = 0;
1185  unsigned int i, args, opinfo;
1186  MAGIC **chain = NULL;
1187  SV *svr;
1188
1189  dSP;
1190
1191  args    = flags & VMG_CB_CALL_ARGS_MASK;
1192  flags >>= VMG_CB_CALL_ARGS_SHIFT;
1193  opinfo  = flags & VMG_CB_CALL_OPINFO;
1194
1195  ENTER;
1196  SAVETMPS;
1197
1198  PUSHMARK(SP);
1199  EXTEND(SP, args + 1);
1200  PUSHs(sv_2mortal(newRV_inc(sv)));
1201  va_start(ap, sv);
1202  for (i = 0; i < args; ++i) {
1203   SV *sva = va_arg(ap, SV *);
1204   PUSHs(sva ? sva : &PL_sv_undef);
1205  }
1206  va_end(ap);
1207  if (opinfo)
1208   XPUSHs(vmg_op_info(opinfo));
1209  PUTBACK;
1210
1211  if (flags & VMG_CB_CALL_GUARD) {
1212   dMY_CXT;
1213   MY_CXT.depth++;
1214   vmg_call_sv(cb, G_SCALAR, vmg_dispell_guard_oncroak, NULL);
1215   MY_CXT.depth--;
1216   if (MY_CXT.depth == 0 && MY_CXT.freed_tokens)
1217    chain = &MY_CXT.freed_tokens;
1218  } else {
1219   vmg_call_sv(cb, G_SCALAR, 0, NULL);
1220  }
1221
1222  SPAGAIN;
1223  svr = POPs;
1224  if (SvOK(svr))
1225   ret = (int) SvIV(svr);
1226  PUTBACK;
1227
1228  FREETMPS;
1229  LEAVE;
1230
1231  if (chain) {
1232   vmg_dispell_guard_new(*chain);
1233   *chain = NULL;
1234  }
1235
1236  return ret;
1237 }
1238
1239 #define VMG_CB_FLAGS(OI, A) \
1240         ((((unsigned int) (OI)) << VMG_CB_CALL_ARGS_SHIFT) | (A))
1241
1242 #define vmg_cb_call1(I, OI, S, A1) \
1243         vmg_cb_call(aTHX_ (I), VMG_CB_FLAGS((OI), 1), (S), (A1))
1244 #define vmg_cb_call2(I, OI, S, A1, A2) \
1245         vmg_cb_call(aTHX_ (I), VMG_CB_FLAGS((OI), 2), (S), (A1), (A2))
1246 #define vmg_cb_call3(I, OI, S, A1, A2, A3) \
1247         vmg_cb_call(aTHX_ (I), VMG_CB_FLAGS((OI), 3), (S), (A1), (A2), (A3))
1248
1249 /* ... Default no-op magic callback ........................................ */
1250
1251 STATIC int vmg_svt_default_noop(pTHX_ SV *sv, MAGIC *mg) {
1252  return 0;
1253 }
1254
1255 /* ... get magic ........................................................... */
1256
1257 STATIC int vmg_svt_get(pTHX_ SV *sv, MAGIC *mg) {
1258  const vmg_wizard *w = vmg_wizard_from_mg_nocheck(mg);
1259
1260  return vmg_cb_call1(w->cb_get, w->opinfo, sv, mg->mg_obj);
1261 }
1262
1263 #define vmg_svt_get_noop vmg_svt_default_noop
1264
1265 /* ... set magic ........................................................... */
1266
1267 STATIC int vmg_svt_set(pTHX_ SV *sv, MAGIC *mg) {
1268  const vmg_wizard *w = vmg_wizard_from_mg_nocheck(mg);
1269
1270  return vmg_cb_call1(w->cb_set, w->opinfo, sv, mg->mg_obj);
1271 }
1272
1273 #define vmg_svt_set_noop vmg_svt_default_noop
1274
1275 /* ... len magic ........................................................... */
1276
1277 STATIC U32 vmg_sv_len(pTHX_ SV *sv) {
1278 #define vmg_sv_len(S) vmg_sv_len(aTHX_ (S))
1279  STRLEN len;
1280 #if VMG_HAS_PERL(5, 9, 3)
1281  const U8 *s = VOID2(const U8 *, VOID2(const void *, SvPV_const(sv, len)));
1282 #else
1283  U8 *s = SvPV(sv, len);
1284 #endif
1285
1286  return DO_UTF8(sv) ? utf8_length(s, s + len) : len;
1287 }
1288
1289 STATIC U32 vmg_svt_len(pTHX_ SV *sv, MAGIC *mg) {
1290  const vmg_wizard *w = vmg_wizard_from_mg_nocheck(mg);
1291  unsigned int opinfo = w->opinfo;
1292  U32 len, ret;
1293  SV *svr;
1294  svtype t = SvTYPE(sv);
1295
1296  dSP;
1297
1298  ENTER;
1299  SAVETMPS;
1300
1301  PUSHMARK(SP);
1302  EXTEND(SP, 3);
1303  PUSHs(sv_2mortal(newRV_inc(sv)));
1304  PUSHs(mg->mg_obj ? mg->mg_obj : &PL_sv_undef);
1305  if (t < SVt_PVAV) {
1306   len = vmg_sv_len(sv);
1307   mPUSHu(len);
1308  } else if (t == SVt_PVAV) {
1309   len = av_len((AV *) sv) + 1;
1310   mPUSHu(len);
1311  } else {
1312   len = 0;
1313   PUSHs(&PL_sv_undef);
1314  }
1315  if (opinfo)
1316   XPUSHs(vmg_op_info(opinfo));
1317  PUTBACK;
1318
1319  vmg_call_sv(w->cb_len, G_SCALAR, 0, NULL);
1320
1321  SPAGAIN;
1322  svr = POPs;
1323  ret = SvOK(svr) ? (U32) SvUV(svr) : len;
1324  if (t == SVt_PVAV)
1325   --ret;
1326  PUTBACK;
1327
1328  FREETMPS;
1329  LEAVE;
1330
1331  return ret;
1332 }
1333
1334 STATIC U32 vmg_svt_len_noop(pTHX_ SV *sv, MAGIC *mg) {
1335  U32    len = 0;
1336  svtype t   = SvTYPE(sv);
1337
1338  if (t < SVt_PVAV) {
1339   len = vmg_sv_len(sv);
1340  } else if (t == SVt_PVAV) {
1341   len = (U32) av_len((AV *) sv);
1342  }
1343
1344  return len;
1345 }
1346
1347 /* ... clear magic ......................................................... */
1348
1349 STATIC int vmg_svt_clear(pTHX_ SV *sv, MAGIC *mg) {
1350  const vmg_wizard *w = vmg_wizard_from_mg_nocheck(mg);
1351  unsigned int flags  = w->opinfo;
1352
1353 #if !VMG_HAS_PERL(5, 12, 0)
1354  flags |= VMG_CB_CALL_GUARD;
1355 #endif
1356
1357  return vmg_cb_call1(w->cb_clear, flags, sv, mg->mg_obj);
1358 }
1359
1360 #define vmg_svt_clear_noop vmg_svt_default_noop
1361
1362 /* ... free magic .......................................................... */
1363
1364 #if VMG_PROPAGATE_ERRSV_NEEDS_TRAMPOLINE
1365
1366 STATIC OP *vmg_pp_propagate_errsv(pTHX) {
1367  SVOP *o = cSVOPx(PL_op);
1368
1369  if (o->op_sv) {
1370   SvREFCNT_dec(ERRSV);
1371   ERRSV    = o->op_sv;
1372   o->op_sv = NULL;
1373  }
1374
1375  return NORMAL;
1376 }
1377
1378 #endif /* VMG_PROPAGATE_ERRSV_NEEDS_TRAMPOLINE */
1379
1380 STATIC int vmg_propagate_errsv_free(pTHX_ SV *sv, MAGIC *mg) {
1381  if (mg->mg_obj) {
1382   ERRSV         = mg->mg_obj;
1383   mg->mg_obj    = NULL;
1384   mg->mg_flags &= ~MGf_REFCOUNTED;
1385  }
1386
1387  return 0;
1388 }
1389
1390 /* perl is already kind enough to handle the cloning of the mg_obj member,
1391    hence we don't need to define a dup magic callback. */
1392
1393 STATIC MGVTBL vmg_propagate_errsv_vtbl = {
1394  0,                        /* get */
1395  0,                        /* set */
1396  0,                        /* len */
1397  0,                        /* clear */
1398  vmg_propagate_errsv_free, /* free */
1399  0,                        /* copy */
1400  0,                        /* dup */
1401 #if MGf_LOCAL
1402  0,                        /* local */
1403 #endif /* MGf_LOCAL */
1404 };
1405
1406 typedef struct {
1407  SV  *sv;
1408  int  in_eval;
1409  I32  base;
1410 } vmg_svt_free_cleanup_ud;
1411
1412 STATIC int vmg_svt_free_cleanup(pTHX_ void *ud_) {
1413  vmg_svt_free_cleanup_ud *ud = VOID2(vmg_svt_free_cleanup_ud *, ud_);
1414
1415  if (ud->in_eval) {
1416   U32 optype = PL_op ? PL_op->op_type : OP_NULL;
1417
1418   if (optype == OP_LEAVETRY || optype == OP_LEAVEEVAL) {
1419    SV *errsv = newSVsv(ERRSV);
1420
1421    FREETMPS;
1422    LEAVE_SCOPE(ud->base);
1423
1424 #if VMG_PROPAGATE_ERRSV_NEEDS_TRAMPOLINE
1425    if (optype == OP_LEAVETRY) {
1426     dMY_CXT;
1427     PL_op = vmg_trampoline_bump(&MY_CXT.propagate_errsv, errsv, PL_op);
1428    } else if (optype == OP_LEAVEEVAL) {
1429     SV *guard = sv_newmortal();
1430     sv_magicext(guard, errsv, PERL_MAGIC_ext, &vmg_propagate_errsv_vtbl,
1431                               NULL, 0);
1432    }
1433 #else /* !VMG_PROPAGATE_ERRSV_NEEDS_TRAMPOLINE */
1434 # if !VMG_HAS_PERL(5, 8, 9)
1435    {
1436     SV *guard = sv_newmortal();
1437     sv_magicext(guard, errsv, PERL_MAGIC_ext, &vmg_propagate_errsv_vtbl,
1438                               NULL, 0);
1439    }
1440 # else
1441    sv_magicext(ERRSV, errsv, PERL_MAGIC_ext, &vmg_propagate_errsv_vtbl,
1442                              NULL, 0);
1443    SvREFCNT_dec(errsv);
1444 # endif
1445 #endif /* VMG_PROPAGATE_ERRSV_NEEDS_TRAMPOLINE */
1446
1447    SAVETMPS;
1448   }
1449
1450   /* Don't propagate */
1451   return 0;
1452  } else {
1453   SV    *sv = ud->sv;
1454   MAGIC *mg;
1455
1456   /* We are about to croak() while sv is being destroyed. Try to clean up
1457    * things a bit. */
1458   mg = SvMAGIC(sv);
1459   if (mg) {
1460    vmg_mg_del(sv, NULL, mg, mg->mg_moremagic);
1461    mg_magical(sv);
1462   }
1463   SvREFCNT_dec(sv);
1464
1465   vmg_dispell_guard_oncroak(aTHX_ NULL);
1466
1467   /* After that, propagate the error upwards. */
1468   return 1;
1469  }
1470 }
1471
1472 STATIC int vmg_svt_free(pTHX_ SV *sv, MAGIC *mg) {
1473  vmg_svt_free_cleanup_ud ud;
1474  const vmg_wizard *w;
1475  int ret = 0;
1476  SV *svr;
1477
1478  dSP;
1479
1480  /* During global destruction, we cannot be sure that the wizard and its free
1481   * callback are still alive. */
1482  if (PL_dirty)
1483   return 0;
1484
1485  w = vmg_wizard_from_mg_nocheck(mg);
1486
1487  /* So that it survives the temp cleanup below */
1488  SvREFCNT_inc_simple_void(sv);
1489
1490 #if !(VMG_HAS_PERL_MAINT(5, 11, 0, 32686) || VMG_HAS_PERL(5, 12, 0))
1491  /* The previous magic tokens were freed but the magic chain wasn't updated, so
1492   * if you access the sv from the callback the old deleted magics will trigger
1493   * and cause memory misreads. Change 32686 solved it that way : */
1494  SvMAGIC_set(sv, mg);
1495 #endif
1496
1497  ud.sv = sv;
1498  if (cxstack_ix < cxstack_max) {
1499   ud.in_eval = (CxTYPE(cxstack + cxstack_ix + 1) == CXt_EVAL);
1500   ud.base    = ud.in_eval ? PL_scopestack[PL_scopestack_ix] : 0;
1501  } else {
1502   ud.in_eval = 0;
1503   ud.base    = 0;
1504  }
1505
1506  ENTER;
1507  SAVETMPS;
1508
1509  PUSHMARK(SP);
1510  EXTEND(SP, 2);
1511  PUSHs(sv_2mortal(newRV_inc(sv)));
1512  PUSHs(mg->mg_obj ? mg->mg_obj : &PL_sv_undef);
1513  if (w->opinfo)
1514   XPUSHs(vmg_op_info(w->opinfo));
1515  PUTBACK;
1516
1517  {
1518   dMY_CXT;
1519   MY_CXT.depth++;
1520   vmg_call_sv(w->cb_free, G_SCALAR, vmg_svt_free_cleanup, &ud);
1521   MY_CXT.depth--;
1522   if (MY_CXT.depth == 0 && MY_CXT.freed_tokens) {
1523    /* Free all the tokens in the chain but the current one (if it's present).
1524     * It will be taken care of by our caller, Perl_mg_free(). */
1525    vmg_magic_chain_free(MY_CXT.freed_tokens, mg);
1526    MY_CXT.freed_tokens = NULL;
1527   }
1528  }
1529
1530  SPAGAIN;
1531  svr = POPs;
1532  if (SvOK(svr))
1533   ret = (int) SvIV(svr);
1534  PUTBACK;
1535
1536  FREETMPS;
1537  LEAVE;
1538
1539  /* Calling SvREFCNT_dec() will trigger destructors in an infinite loop, so
1540   * we have to rely on SvREFCNT() being a lvalue. Heck, even the core does it */
1541  --SvREFCNT(sv);
1542
1543  /* Perl_mg_free will get rid of the magic and decrement mg->mg_obj and
1544   * mg->mg_ptr reference count */
1545  return ret;
1546 }
1547
1548 #define vmg_svt_free_noop vmg_svt_default_noop
1549
1550 #if VMG_HAS_PERL_MAINT(5, 11, 0, 33256) || VMG_HAS_PERL(5, 12, 0)
1551 # define VMG_SVT_COPY_KEYLEN_TYPE I32
1552 #else
1553 # define VMG_SVT_COPY_KEYLEN_TYPE int
1554 #endif
1555
1556 /* ... copy magic .......................................................... */
1557
1558 STATIC int vmg_svt_copy(pTHX_ SV *sv, MAGIC *mg, SV *nsv, const char *key, VMG_SVT_COPY_KEYLEN_TYPE keylen) {
1559  const vmg_wizard *w = vmg_wizard_from_mg_nocheck(mg);
1560  SV *keysv;
1561  int ret;
1562
1563  if (keylen == HEf_SVKEY) {
1564   keysv = (SV *) key;
1565  } else {
1566   keysv = newSVpvn(key, keylen);
1567  }
1568
1569  if (SvTYPE(sv) >= SVt_PVCV)
1570   nsv = sv_2mortal(newRV_inc(nsv));
1571
1572  ret = vmg_cb_call3(w->cb_copy, w->opinfo, sv, mg->mg_obj, keysv, nsv);
1573
1574  if (keylen != HEf_SVKEY) {
1575   SvREFCNT_dec(keysv);
1576  }
1577
1578  return ret;
1579 }
1580
1581 STATIC int vmg_svt_copy_noop(pTHX_ SV *sv, MAGIC *mg, SV *nsv, const char *key, VMG_SVT_COPY_KEYLEN_TYPE keylen) {
1582  return 0;
1583 }
1584
1585 /* ... dup magic ........................................................... */
1586
1587 #if 0
1588 STATIC int vmg_svt_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *param) {
1589  return 0;
1590 }
1591 #define vmg_svt_dup_noop vmg_svt_dup
1592 #endif
1593
1594 /* ... local magic ......................................................... */
1595
1596 #if MGf_LOCAL
1597
1598 STATIC int vmg_svt_local(pTHX_ SV *nsv, MAGIC *mg) {
1599  const vmg_wizard *w = vmg_wizard_from_mg_nocheck(mg);
1600
1601  return vmg_cb_call1(w->cb_local, w->opinfo, nsv, mg->mg_obj);
1602 }
1603
1604 #define vmg_svt_local_noop vmg_svt_default_noop
1605
1606 #endif /* MGf_LOCAL */
1607
1608 /* ... uvar magic .......................................................... */
1609
1610 #if VMG_UVAR
1611
1612 STATIC OP *vmg_pp_reset_rmg(pTHX) {
1613  SVOP *o = cSVOPx(PL_op);
1614
1615  SvRMAGICAL_on(o->op_sv);
1616  o->op_sv = NULL;
1617
1618  return NORMAL;
1619 }
1620
1621 STATIC I32 vmg_svt_val(pTHX_ IV action, SV *sv) {
1622  vmg_uvar_ud *ud;
1623  MAGIC *mg, *umg, *moremagic;
1624  SV *key = NULL, *newkey = NULL;
1625  int tied = 0;
1626
1627  umg = mg_find(sv, PERL_MAGIC_uvar);
1628  /* umg can't be NULL or we wouldn't be there. */
1629  key = umg->mg_obj;
1630  ud  = (vmg_uvar_ud *) umg->mg_ptr;
1631
1632  if (ud->old_uf.uf_val)
1633   ud->old_uf.uf_val(aTHX_ action, sv);
1634  if (ud->old_uf.uf_set)
1635   ud->old_uf.uf_set(aTHX_ action, sv);
1636
1637  for (mg = SvMAGIC(sv); mg; mg = moremagic) {
1638   const vmg_wizard *w;
1639
1640   /* mg may be freed later by the uvar call, so we need to fetch the next
1641    * token before reaching that fateful point. */
1642   moremagic = mg->mg_moremagic;
1643
1644   switch (mg->mg_type) {
1645    case PERL_MAGIC_ext:
1646     break;
1647    case PERL_MAGIC_tied:
1648     ++tied;
1649     continue;
1650    default:
1651     continue;
1652   }
1653
1654   w = vmg_wizard_from_mg(mg);
1655   if (!w)
1656    continue;
1657
1658   switch (w->uvar) {
1659    case 0:
1660     continue;
1661    case 2:
1662     if (!newkey)
1663      newkey = key = umg->mg_obj = sv_mortalcopy(umg->mg_obj);
1664   }
1665
1666   switch (action
1667              & (HV_FETCH_ISSTORE|HV_FETCH_ISEXISTS|HV_FETCH_LVALUE|HV_DELETE)) {
1668    case 0:
1669     if (w->cb_fetch)
1670      vmg_cb_call2(w->cb_fetch, w->opinfo | VMG_CB_CALL_GUARD, sv,
1671                                mg->mg_obj, key);
1672     break;
1673    case HV_FETCH_ISSTORE:
1674    case HV_FETCH_LVALUE:
1675    case (HV_FETCH_ISSTORE|HV_FETCH_LVALUE):
1676     if (w->cb_store)
1677      vmg_cb_call2(w->cb_store, w->opinfo | VMG_CB_CALL_GUARD, sv,
1678                                mg->mg_obj, key);
1679     break;
1680    case HV_FETCH_ISEXISTS:
1681     if (w->cb_exists)
1682      vmg_cb_call2(w->cb_exists, w->opinfo | VMG_CB_CALL_GUARD, sv,
1683                                 mg->mg_obj, key);
1684     break;
1685    case HV_DELETE:
1686     if (w->cb_delete)
1687      vmg_cb_call2(w->cb_delete, w->opinfo | VMG_CB_CALL_GUARD, sv,
1688                                 mg->mg_obj, key);
1689     break;
1690   }
1691  }
1692
1693  if (SvRMAGICAL(sv) && !tied && !(action & (HV_FETCH_ISSTORE|HV_DELETE))) {
1694   /* Temporarily hide the RMAGICAL flag of the hash so it isn't wrongly
1695    * mistaken for a tied hash by the rest of hv_common. It will be reset by
1696    * the op_ppaddr of a new fake op injected between the current and the next
1697    * one. */
1698
1699 #if VMG_RESET_RMG_NEEDS_TRAMPOLINE
1700
1701   dMY_CXT;
1702
1703   PL_op = vmg_trampoline_bump(&MY_CXT.reset_rmg, sv, PL_op);
1704
1705 #else /* !VMG_RESET_RMG_NEEDS_TRAMPOLINE */
1706
1707   OP   *nop  = PL_op->op_next;
1708   SVOP *svop = NULL;
1709
1710   if (nop && nop->op_ppaddr == vmg_pp_reset_rmg) {
1711    svop = (SVOP *) nop;
1712   } else {
1713    NewOp(1101, svop, 1, SVOP);
1714    svop->op_type    = OP_STUB;
1715    svop->op_ppaddr  = vmg_pp_reset_rmg;
1716    svop->op_next    = nop;
1717    svop->op_flags   = 0;
1718    svop->op_private = 0;
1719
1720    PL_op->op_next = (OP *) svop;
1721   }
1722
1723   svop->op_sv = sv;
1724
1725 #endif /* VMG_RESET_RMG_NEEDS_TRAMPOLINE */
1726
1727   SvRMAGICAL_off(sv);
1728  }
1729
1730  return 0;
1731 }
1732
1733 #endif /* VMG_UVAR */
1734
1735 /* --- Macros for the XS section ------------------------------------------- */
1736
1737 #ifdef CvISXSUB
1738 # define VMG_CVOK(C) \
1739    ((CvISXSUB(C) ? (void *) CvXSUB(C) : (void *) CvROOT(C)) ? 1 : 0)
1740 #else
1741 # define VMG_CVOK(C) (CvROOT(C) || CvXSUB(C))
1742 #endif
1743
1744 #define VMG_CBOK(S) ((SvTYPE(S) == SVt_PVCV) ? VMG_CVOK(S) : SvOK(S))
1745
1746 #define VMG_SET_CB(S, N) {       \
1747  SV *cb = (S);                   \
1748  if (SvOK(cb) && SvROK(cb)) {    \
1749   cb = SvRV(cb);                 \
1750   if (VMG_CBOK(cb))              \
1751    SvREFCNT_inc_simple_void(cb); \
1752   else                           \
1753    cb = NULL;                    \
1754  } else {                        \
1755   cb = NULL;                     \
1756  }                               \
1757  w->cb_ ## N = cb;               \
1758 }
1759
1760 #define VMG_SET_SVT_CB(S, N) {   \
1761  SV *cb = (S);                   \
1762  if (SvOK(cb) && SvROK(cb)) {    \
1763   cb = SvRV(cb);                 \
1764   if (VMG_CBOK(cb)) {            \
1765    t->svt_ ## N = vmg_svt_ ## N; \
1766    SvREFCNT_inc_simple_void(cb); \
1767   } else {                       \
1768    t->svt_ ## N = vmg_svt_ ## N ## _noop; \
1769    cb           = NULL;          \
1770   }                              \
1771  } else {                        \
1772   t->svt_ ## N = NULL;           \
1773   cb           = NULL;           \
1774  }                               \
1775  w->cb_ ## N = cb;               \
1776 }
1777
1778 /* --- XS ------------------------------------------------------------------ */
1779
1780 MODULE = Variable::Magic            PACKAGE = Variable::Magic
1781
1782 PROTOTYPES: ENABLE
1783
1784 BOOT:
1785 {
1786  HV *stash;
1787  int c;
1788
1789  MY_CXT_INIT;
1790  for (c = OPc_NULL; c < OPc_MAX; ++c)
1791   MY_CXT.b__op_stashes[c] = NULL;
1792
1793  MY_CXT.depth        = 0;
1794  MY_CXT.freed_tokens = NULL;
1795
1796  /* XS doesn't like a blank line here */
1797 #if VMG_PROPAGATE_ERRSV_NEEDS_TRAMPOLINE
1798  vmg_trampoline_init(&MY_CXT.propagate_errsv, vmg_pp_propagate_errsv);
1799 #endif
1800 #if VMG_RESET_RMG_NEEDS_TRAMPOLINE
1801  vmg_trampoline_init(&MY_CXT.reset_rmg, vmg_pp_reset_rmg);
1802 #endif
1803
1804  /* XS doesn't like a blank line here */
1805 #if VMG_THREADSAFE
1806  MUTEX_INIT(&vmg_vtable_refcount_mutex);
1807  MUTEX_INIT(&vmg_op_name_init_mutex);
1808 #endif
1809
1810  stash = gv_stashpv(__PACKAGE__, 1);
1811  newCONSTSUB(stash, "MGf_COPY",  newSVuv(MGf_COPY));
1812  newCONSTSUB(stash, "MGf_DUP",   newSVuv(MGf_DUP));
1813  newCONSTSUB(stash, "MGf_LOCAL", newSVuv(MGf_LOCAL));
1814  newCONSTSUB(stash, "VMG_UVAR",  newSVuv(VMG_UVAR));
1815  newCONSTSUB(stash, "VMG_COMPAT_SCALAR_LENGTH_NOLEN",
1816                     newSVuv(VMG_COMPAT_SCALAR_LENGTH_NOLEN));
1817  newCONSTSUB(stash, "VMG_COMPAT_SCALAR_NOLEN",
1818                     newSVuv(VMG_COMPAT_SCALAR_NOLEN));
1819  newCONSTSUB(stash, "VMG_COMPAT_ARRAY_PUSH_NOLEN",
1820                     newSVuv(VMG_COMPAT_ARRAY_PUSH_NOLEN));
1821  newCONSTSUB(stash, "VMG_COMPAT_ARRAY_PUSH_NOLEN_VOID",
1822                     newSVuv(VMG_COMPAT_ARRAY_PUSH_NOLEN_VOID));
1823  newCONSTSUB(stash, "VMG_COMPAT_ARRAY_UNSHIFT_NOLEN_VOID",
1824                     newSVuv(VMG_COMPAT_ARRAY_UNSHIFT_NOLEN_VOID));
1825  newCONSTSUB(stash, "VMG_COMPAT_ARRAY_UNDEF_CLEAR",
1826                     newSVuv(VMG_COMPAT_ARRAY_UNDEF_CLEAR));
1827  newCONSTSUB(stash, "VMG_COMPAT_HASH_DELETE_NOUVAR_VOID",
1828                     newSVuv(VMG_COMPAT_HASH_DELETE_NOUVAR_VOID));
1829  newCONSTSUB(stash, "VMG_COMPAT_CODE_COPY_CLONE",
1830                     newSVuv(VMG_COMPAT_CODE_COPY_CLONE));
1831  newCONSTSUB(stash, "VMG_COMPAT_GLOB_GET", newSVuv(VMG_COMPAT_GLOB_GET));
1832  newCONSTSUB(stash, "VMG_PERL_PATCHLEVEL", newSVuv(VMG_PERL_PATCHLEVEL));
1833  newCONSTSUB(stash, "VMG_THREADSAFE",      newSVuv(VMG_THREADSAFE));
1834  newCONSTSUB(stash, "VMG_FORKSAFE",        newSVuv(VMG_FORKSAFE));
1835  newCONSTSUB(stash, "VMG_OP_INFO_NAME",    newSVuv(VMG_OP_INFO_NAME));
1836  newCONSTSUB(stash, "VMG_OP_INFO_OBJECT",  newSVuv(VMG_OP_INFO_OBJECT));
1837 }
1838
1839 #if VMG_THREADSAFE
1840
1841 void
1842 CLONE(...)
1843 PROTOTYPE: DISABLE
1844 PREINIT:
1845  U32 had_b__op_stash = 0;
1846  I32 old_depth;
1847  int c;
1848 PPCODE:
1849  {
1850   dMY_CXT;
1851   for (c = OPc_NULL; c < OPc_MAX; ++c) {
1852    if (MY_CXT.b__op_stashes[c])
1853     had_b__op_stash |= (((U32) 1) << c);
1854   }
1855   old_depth = MY_CXT.depth;
1856  }
1857  {
1858   MY_CXT_CLONE;
1859   for (c = OPc_NULL; c < OPc_MAX; ++c) {
1860    MY_CXT.b__op_stashes[c] = (had_b__op_stash & (((U32) 1) << c))
1861                               ? gv_stashpv(vmg_opclassnames[c], 1) : NULL;
1862   }
1863   MY_CXT.depth        = old_depth;
1864   MY_CXT.freed_tokens = NULL;
1865  }
1866  XSRETURN(0);
1867
1868 #endif /* VMG_THREADSAFE */
1869
1870 SV *_wizard(...)
1871 PROTOTYPE: DISABLE
1872 PREINIT:
1873  vmg_wizard *w;
1874  MGVTBL *t;
1875  SV *op_info, *copy_key;
1876  I32 i = 0;
1877 CODE:
1878  if (items != 9
1879 #if MGf_LOCAL
1880               + 1
1881 #endif /* MGf_LOCAL */
1882 #if VMG_UVAR
1883               + 5
1884 #endif /* VMG_UVAR */
1885               ) { croak(vmg_wrongargnum); }
1886
1887  op_info = ST(i++);
1888  w = vmg_wizard_alloc(SvOK(op_info) ? SvUV(op_info) : 0);
1889  t = vmg_vtable_vtbl(w->vtable);
1890
1891  VMG_SET_CB(ST(i++), data);
1892
1893  VMG_SET_SVT_CB(ST(i++), get);
1894  VMG_SET_SVT_CB(ST(i++), set);
1895  VMG_SET_SVT_CB(ST(i++), len);
1896  VMG_SET_SVT_CB(ST(i++), clear);
1897  VMG_SET_SVT_CB(ST(i++), free);
1898  VMG_SET_SVT_CB(ST(i++), copy);
1899  /* VMG_SET_SVT_CB(ST(i++), dup); */
1900  i++;
1901  t->svt_dup = NULL;
1902  w->cb_dup  = NULL;
1903 #if MGf_LOCAL
1904  VMG_SET_SVT_CB(ST(i++), local);
1905 #endif /* MGf_LOCAL */
1906 #if VMG_UVAR
1907  VMG_SET_CB(ST(i++), fetch);
1908  VMG_SET_CB(ST(i++), store);
1909  VMG_SET_CB(ST(i++), exists);
1910  VMG_SET_CB(ST(i++), delete);
1911
1912  copy_key = ST(i++);
1913  if (w->cb_fetch || w->cb_store || w->cb_exists || w->cb_delete)
1914   w->uvar = SvTRUE(copy_key) ? 2 : 1;
1915 #endif /* VMG_UVAR */
1916
1917  RETVAL = newRV_noinc(vmg_wizard_sv_new(w));
1918 OUTPUT:
1919  RETVAL
1920
1921 SV *cast(SV *sv, SV *wiz, ...)
1922 PROTOTYPE: \[$@%&*]$@
1923 PREINIT:
1924  const vmg_wizard *w = NULL;
1925  SV **args = NULL;
1926  I32 i = 0;
1927 CODE:
1928  if (items > 2) {
1929   i = items - 2;
1930   args = &ST(2);
1931  }
1932  if (SvROK(wiz)) {
1933   wiz = SvRV_const(wiz);
1934   w   = vmg_wizard_from_sv(wiz);
1935  }
1936  if (!w)
1937   croak(vmg_invalid_wiz);
1938  RETVAL = newSVuv(vmg_cast(SvRV(sv), w, wiz, args, i));
1939 OUTPUT:
1940  RETVAL
1941
1942 void
1943 getdata(SV *sv, SV *wiz)
1944 PROTOTYPE: \[$@%&*]$
1945 PREINIT:
1946  const vmg_wizard *w = NULL;
1947  SV *data;
1948 PPCODE:
1949  if (SvROK(wiz))
1950   w = vmg_wizard_from_sv(SvRV_const(wiz));
1951  if (!w)
1952   croak(vmg_invalid_wiz);
1953  data = vmg_data_get(SvRV(sv), w);
1954  if (!data)
1955   XSRETURN_EMPTY;
1956  ST(0) = data;
1957  XSRETURN(1);
1958
1959 SV *dispell(SV *sv, SV *wiz)
1960 PROTOTYPE: \[$@%&*]$
1961 PREINIT:
1962  const vmg_wizard *w = NULL;
1963 CODE:
1964  if (SvROK(wiz))
1965   w = vmg_wizard_from_sv(SvRV_const(wiz));
1966  if (!w)
1967   croak(vmg_invalid_wiz);
1968  RETVAL = newSVuv(vmg_dispell(SvRV(sv), w));
1969 OUTPUT:
1970  RETVAL