]> git.vpit.fr Git - perl/modules/autovivification.git/blob - autovivification.xs
Improve the require propagation workaround
[perl/modules/autovivification.git] / autovivification.xs
1 /* This file is part of the autovivification Perl module.
2  * See http://search.cpan.org/dist/autovivification/ */
3
4 #define PERL_NO_GET_CONTEXT
5 #include "EXTERN.h"
6 #include "perl.h"
7 #include "XSUB.h"
8
9 #define __PACKAGE__     "autovivification"
10 #define __PACKAGE_LEN__ (sizeof(__PACKAGE__)-1)
11
12 /* --- Compatibility wrappers ---------------------------------------------- */
13
14 #ifndef HvNAME_get
15 # define HvNAME_get(H) HvNAME(H)
16 #endif
17
18 #ifndef HvNAMELEN_get
19 # define HvNAMELEN_get(H) strlen(HvNAME_get(H))
20 #endif
21
22 #define A_HAS_PERL(R, V, S) (PERL_REVISION > (R) || (PERL_REVISION == (R) && (PERL_VERSION > (V) || (PERL_VERSION == (V) && (PERL_SUBVERSION >= (S))))))
23
24 #undef ENTERn
25 #if defined(ENTER_with_name) && !A_HAS_PERL(5, 11, 4)
26 # define ENTERn(N) ENTER_with_name(N)
27 #else
28 # define ENTERn(N) ENTER
29 #endif
30
31 #undef LEAVEn
32 #if defined(LEAVE_with_name) && !A_HAS_PERL(5, 11, 4)
33 # define LEAVEn(N) LEAVE_with_name(N)
34 #else
35 # define LEAVEn(N) LEAVE
36 #endif
37
38 #ifndef A_WORKAROUND_REQUIRE_PROPAGATION
39 # define A_WORKAROUND_REQUIRE_PROPAGATION !A_HAS_PERL(5, 10, 1)
40 #endif
41
42 /* ... Thread safety and multiplicity ...................................... */
43
44 #ifndef A_MULTIPLICITY
45 # if defined(MULTIPLICITY) || defined(PERL_IMPLICIT_CONTEXT)
46 #  define A_MULTIPLICITY 1
47 # else
48 #  define A_MULTIPLICITY 0
49 # endif
50 #endif
51 #if A_MULTIPLICITY && !defined(tTHX)
52 # define tTHX PerlInterpreter*
53 #endif
54
55 #if A_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 A_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 A_THREADSAFE 0
66 # undef  dMY_CXT
67 # define dMY_CXT      dNOOP
68 # undef  MY_CXT
69 # define MY_CXT       a_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 /* --- Helpers ------------------------------------------------------------- */
79
80 /* ... Thread-safe hints ................................................... */
81
82 #if A_WORKAROUND_REQUIRE_PROPAGATION
83
84 typedef struct {
85  U32 bits;
86  IV  require_tag;
87 } a_hint_t;
88
89 #define A_HINT_BITS(H) ((H)->bits)
90
91 #define A_HINT_FREE(H) PerlMemShared_free(H)
92
93 #if A_THREADSAFE
94
95 #define PTABLE_NAME        ptable_hints
96 #define PTABLE_VAL_FREE(V) A_HINT_FREE(V)
97
98 #define pPTBL  pTHX
99 #define pPTBL_ pTHX_
100 #define aPTBL  aTHX
101 #define aPTBL_ aTHX_
102
103 #include "ptable.h"
104
105 #define ptable_hints_store(T, K, V) ptable_hints_store(aTHX_ (T), (K), (V))
106 #define ptable_hints_free(T)        ptable_hints_free(aTHX_ (T))
107
108 #define MY_CXT_KEY __PACKAGE__ "::_guts" XS_VERSION
109
110 typedef struct {
111  ptable *tbl;   /* It really is a ptable_hints */
112  tTHX    owner;
113 } my_cxt_t;
114
115 START_MY_CXT
116
117 STATIC SV *a_clone(pTHX_ SV *sv, tTHX owner) {
118 #define a_clone(S, O) a_clone(aTHX_ (S), (O))
119  CLONE_PARAMS  param;
120  AV           *stashes = NULL;
121  SV           *dupsv;
122
123  if (SvTYPE(sv) == SVt_PVHV && HvNAME_get(sv))
124   stashes = newAV();
125
126  param.stashes    = stashes;
127  param.flags      = 0;
128  param.proto_perl = owner;
129
130  dupsv = sv_dup(sv, &param);
131
132  if (stashes) {
133   av_undef(stashes);
134   SvREFCNT_dec(stashes);
135  }
136
137  return SvREFCNT_inc(dupsv);
138 }
139
140 STATIC void a_ptable_clone(pTHX_ ptable_ent *ent, void *ud_) {
141  my_cxt_t *ud = ud_;
142  a_hint_t *h1 = ent->val;
143  a_hint_t *h2;
144
145  if (ud->owner == aTHX)
146   return;
147
148  h2              = PerlMemShared_malloc(sizeof *h2);
149  h2->require_tag = PTR2IV(a_clone(INT2PTR(SV *, h1->require_tag), ud->owner));
150
151  ptable_hints_store(ud->tbl, ent->key, h2);
152 }
153
154 STATIC void a_thread_cleanup(pTHX_ void *);
155
156 STATIC void a_thread_cleanup(pTHX_ void *ud) {
157  int *level = ud;
158
159  if (*level) {
160   *level = 0;
161   LEAVE;
162   SAVEDESTRUCTOR_X(a_thread_cleanup, level);
163   ENTER;
164  } else {
165   dMY_CXT;
166   PerlMemShared_free(level);
167   ptable_hints_free(MY_CXT.tbl);
168  }
169 }
170
171 #endif /* A_THREADSAFE */
172
173 STATIC IV a_require_tag(pTHX) {
174 #define a_require_tag() a_require_tag(aTHX)
175  const CV *cv, *outside;
176
177  cv = PL_compcv;
178
179  if (!cv) {
180   /* If for some reason the pragma is operational at run-time, try to discover
181    * the current cv in use. */
182   const PERL_SI *si;
183
184   for (si = PL_curstackinfo; si; si = si->si_prev) {
185    I32 cxix;
186
187    for (cxix = si->si_cxix; cxix >= 0; --cxix) {
188     const PERL_CONTEXT *cx = si->si_cxstack + cxix;
189
190     switch (CxTYPE(cx)) {
191      case CXt_SUB:
192      case CXt_FORMAT:
193       /* The propagation workaround is only needed up to 5.10.0 and at that
194        * time format and sub contexts were still identical. And even later the
195        * cv members offsets should have been kept the same. */
196       cv = cx->blk_sub.cv;
197       goto get_enclosing_cv;
198      case CXt_EVAL:
199       cv = cx->blk_eval.cv;
200       goto get_enclosing_cv;
201      default:
202       break;
203     }
204    }
205   }
206
207   cv = PL_main_cv;
208  }
209
210 get_enclosing_cv:
211  for (outside = CvOUTSIDE(cv); outside; outside = CvOUTSIDE(cv))
212   cv = outside;
213
214  return PTR2IV(cv);
215 }
216
217 STATIC SV *a_tag(pTHX_ UV bits) {
218 #define a_tag(B) a_tag(aTHX_ (B))
219  a_hint_t *h;
220  dMY_CXT;
221
222  h              = PerlMemShared_malloc(sizeof *h);
223  h->bits        = bits;
224  h->require_tag = a_require_tag();
225
226 #if A_THREADSAFE
227  /* We only need for the key to be an unique tag for looking up the value later.
228   * Allocated memory provides convenient unique identifiers, so that's why we
229   * use the hint as the key itself. */
230  ptable_hints_store(MY_CXT.tbl, h, h);
231 #endif /* A_THREADSAFE */
232
233  return newSViv(PTR2IV(h));
234 }
235
236 STATIC UV a_detag(pTHX_ const SV *hint) {
237 #define a_detag(H) a_detag(aTHX_ (H))
238  a_hint_t *h;
239  dMY_CXT;
240
241  if (!(hint && SvIOK(hint)))
242   return 0;
243
244  h = INT2PTR(a_hint_t *, SvIVX(hint));
245 #if A_THREADSAFE
246  h = ptable_fetch(MY_CXT.tbl, h);
247 #endif /* A_THREADSAFE */
248
249  if (a_require_tag() != h->require_tag)
250   return 0;
251
252  return A_HINT_BITS(h);
253 }
254
255 #else /* A_WORKAROUND_REQUIRE_PROPAGATION */
256
257 #define a_tag(B)   newSVuv(B)
258 /* PVs fetched from the hints chain have their SvLEN set to zero, so get the UV
259  * from a copy. */
260 #define a_detag(H) \
261  ((H)              \
262   ? (SvIOK(H)      \
263      ? SvUVX(H)    \
264      : (SvPOK(H)   \
265         ? sv_2uv(SvLEN(H) ? (H) : sv_mortalcopy(H)) \
266         : 0        \
267        )           \
268      )             \
269   : 0)
270
271 #endif /* !A_WORKAROUND_REQUIRE_PROPAGATION */
272
273 /* Used both for hints and op flags */
274 #define A_HINT_STRICT 1
275 #define A_HINT_WARN   2
276 #define A_HINT_FETCH  4
277 #define A_HINT_STORE  8
278 #define A_HINT_EXISTS 16
279 #define A_HINT_DELETE 32
280 #define A_HINT_NOTIFY (A_HINT_STRICT|A_HINT_WARN)
281 #define A_HINT_DO     (A_HINT_FETCH|A_HINT_STORE|A_HINT_EXISTS|A_HINT_DELETE)
282 #define A_HINT_MASK   (A_HINT_NOTIFY|A_HINT_DO)
283
284 /* Only used in op flags */
285 #define A_HINT_ROOT   64
286 #define A_HINT_DEREF  128
287
288 STATIC U32 a_hash = 0;
289
290 STATIC UV a_hint(pTHX) {
291 #define a_hint() a_hint(aTHX)
292  SV *hint;
293 #if A_HAS_PERL(5, 9, 5)
294  hint = Perl_refcounted_he_fetch(aTHX_ PL_curcop->cop_hints_hash,
295                                        NULL,
296                                        __PACKAGE__, __PACKAGE_LEN__,
297                                        0,
298                                        a_hash);
299 #else
300  SV **val = hv_fetch(GvHV(PL_hintgv), __PACKAGE__, __PACKAGE_LEN__, a_hash);
301  if (!val)
302   return 0;
303  hint = *val;
304 #endif
305  return a_detag(hint);
306 }
307
308 /* ... op => info map ...................................................... */
309
310 typedef struct {
311  OP *(*old_pp)(pTHX);
312  UV flags;
313  void *next;
314 } a_op_info;
315
316 #define PTABLE_NAME        ptable_map
317 #define PTABLE_VAL_FREE(V) PerlMemShared_free(V)
318
319 #include "ptable.h"
320
321 /* PerlMemShared_free() needs the [ap]PTBLMS_? default values */
322 #define ptable_map_store(T, K, V) ptable_map_store(aPTBLMS_ (T), (K), (V))
323
324 STATIC ptable *a_op_map = NULL;
325
326 #ifdef USE_ITHREADS
327 STATIC perl_mutex a_op_map_mutex;
328 #endif
329
330 STATIC const a_op_info *a_map_fetch(const OP *o, a_op_info *oi) {
331  const a_op_info *val;
332
333 #ifdef USE_ITHREADS
334  MUTEX_LOCK(&a_op_map_mutex);
335 #endif
336
337  val = ptable_fetch(a_op_map, o);
338  if (val) {
339   *oi = *val;
340   val = oi;
341  }
342
343 #ifdef USE_ITHREADS
344  MUTEX_UNLOCK(&a_op_map_mutex);
345 #endif
346
347  return val;
348 }
349
350 STATIC const a_op_info *a_map_store_locked(pPTBLMS_ const OP *o, OP *(*old_pp)(pTHX), void *next, UV flags) {
351 #define a_map_store_locked(O, PP, N, F) a_map_store_locked(aPTBLMS_ (O), (PP), (N), (F))
352  a_op_info *oi;
353
354  if (!(oi = ptable_fetch(a_op_map, o))) {
355   oi = PerlMemShared_malloc(sizeof *oi);
356   ptable_map_store(a_op_map, o, oi);
357  }
358
359  oi->old_pp = old_pp;
360  oi->next   = next;
361  oi->flags  = flags;
362
363  return oi;
364 }
365
366 STATIC void a_map_store(pPTBLMS_ const OP *o, OP *(*old_pp)(pTHX), void *next, UV flags) {
367 #define a_map_store(O, PP, N, F) a_map_store(aPTBLMS_ (O), (PP), (N), (F))
368
369 #ifdef USE_ITHREADS
370  MUTEX_LOCK(&a_op_map_mutex);
371 #endif
372
373  a_map_store_locked(o, old_pp, next, flags);
374
375 #ifdef USE_ITHREADS
376  MUTEX_UNLOCK(&a_op_map_mutex);
377 #endif
378 }
379
380 STATIC void a_map_delete(pTHX_ const OP *o) {
381 #define a_map_delete(O) a_map_delete(aTHX_ (O))
382 #ifdef USE_ITHREADS
383  MUTEX_LOCK(&a_op_map_mutex);
384 #endif
385
386  ptable_map_store(a_op_map, o, NULL);
387
388 #ifdef USE_ITHREADS
389  MUTEX_UNLOCK(&a_op_map_mutex);
390 #endif
391 }
392
393 STATIC const OP *a_map_descend(const OP *o) {
394  switch (PL_opargs[o->op_type] & OA_CLASS_MASK) {
395   case OA_BASEOP:
396   case OA_UNOP:
397   case OA_BINOP:
398   case OA_BASEOP_OR_UNOP:
399    return cUNOPo->op_first;
400   case OA_LIST:
401   case OA_LISTOP:
402    return cLISTOPo->op_last;
403  }
404
405  return NULL;
406 }
407
408 STATIC void a_map_store_root(pPTBLMS_ const OP *root, OP *(*old_pp)(pTHX), UV flags) {
409 #define a_map_store_root(R, PP, F) a_map_store_root(aPTBLMS_ (R), (PP), (F))
410  const a_op_info *roi;
411  a_op_info *oi;
412  const OP *o = root;
413
414 #ifdef USE_ITHREADS
415  MUTEX_LOCK(&a_op_map_mutex);
416 #endif
417
418  roi = a_map_store_locked(o, old_pp, (OP *) root, flags | A_HINT_ROOT);
419
420  while (o->op_flags & OPf_KIDS) {
421   o = a_map_descend(o);
422   if (!o)
423    break;
424   if ((oi = ptable_fetch(a_op_map, o))) {
425    oi->flags &= ~A_HINT_ROOT;
426    oi->next   = (a_op_info *) roi;
427    break;
428   }
429  }
430
431 #ifdef USE_ITHREADS
432  MUTEX_UNLOCK(&a_op_map_mutex);
433 #endif
434
435  return;
436 }
437
438 STATIC void a_map_update_flags_topdown(const OP *root, UV flags) {
439  a_op_info *oi;
440  const OP *o = root;
441
442 #ifdef USE_ITHREADS
443  MUTEX_LOCK(&a_op_map_mutex);
444 #endif
445
446  flags &= ~A_HINT_ROOT;
447
448  do {
449   if ((oi = ptable_fetch(a_op_map, o)))
450    oi->flags = (oi->flags & A_HINT_ROOT) | flags;
451   if (!(o->op_flags & OPf_KIDS))
452    break;
453   o = a_map_descend(o);
454  } while (o);
455
456 #ifdef USE_ITHREADS
457  MUTEX_UNLOCK(&a_op_map_mutex);
458 #endif
459
460  return;
461 }
462
463 #define a_map_cancel(R) a_map_update_flags_topdown((R), 0)
464
465 STATIC void a_map_update_flags_bottomup(const OP *o, UV flags, UV rflags) {
466  a_op_info *oi;
467
468 #ifdef USE_ITHREADS
469  MUTEX_LOCK(&a_op_map_mutex);
470 #endif
471
472  flags  &= ~A_HINT_ROOT;
473  rflags |=  A_HINT_ROOT;
474
475  oi = ptable_fetch(a_op_map, o);
476  while (!(oi->flags & A_HINT_ROOT)) {
477   oi->flags = flags;
478   oi        = oi->next;
479  }
480  oi->flags = rflags;
481
482 #ifdef USE_ITHREADS
483  MUTEX_UNLOCK(&a_op_map_mutex);
484 #endif
485
486  return;
487 }
488
489 /* ... Decide whether this expression should be autovivified or not ........ */
490
491 STATIC UV a_map_resolve(const OP *o, a_op_info *oi) {
492  UV flags = 0, rflags;
493  const OP *root;
494  a_op_info *roi = oi;
495
496  while (!(roi->flags & A_HINT_ROOT))
497   roi = roi->next;
498  if (!roi)
499   goto cancel;
500
501  rflags = roi->flags & ~A_HINT_ROOT;
502  if (!rflags)
503   goto cancel;
504
505  root = roi->next;
506  if (root->op_flags & OPf_MOD) {
507   if (rflags & A_HINT_STORE)
508    flags = (A_HINT_STORE|A_HINT_DEREF);
509  } else if (rflags & A_HINT_FETCH)
510    flags = (A_HINT_FETCH|A_HINT_DEREF);
511
512  if (!flags) {
513 cancel:
514   a_map_update_flags_bottomup(o, 0, 0);
515   return 0;
516  }
517
518  flags |= (rflags & A_HINT_NOTIFY);
519  a_map_update_flags_bottomup(o, flags, 0);
520
521  return oi->flags & A_HINT_ROOT ? 0 : flags;
522 }
523
524 /* ... Lightweight pp_defined() ............................................ */
525
526 STATIC bool a_defined(pTHX_ SV *sv) {
527 #define a_defined(S) a_defined(aTHX_ (S))
528  bool defined = FALSE;
529
530  switch (SvTYPE(sv)) {
531   case SVt_PVAV:
532    if (AvMAX(sv) >= 0 || SvGMAGICAL(sv)
533                       || (SvRMAGICAL(sv) && mg_find(sv, PERL_MAGIC_tied)))
534     defined = TRUE;
535    break;
536   case SVt_PVHV:
537    if (HvARRAY(sv) || SvGMAGICAL(sv)
538                    || (SvRMAGICAL(sv) && mg_find(sv, PERL_MAGIC_tied)))
539     defined = TRUE;
540    break;
541   default:
542    SvGETMAGIC(sv);
543    if (SvOK(sv))
544     defined = TRUE;
545  }
546
547  return defined;
548 }
549
550 /* --- PP functions -------------------------------------------------------- */
551
552 /* Be aware that we restore PL_op->op_ppaddr from the pointer table old_pp
553  * value, another extension might have saved our pp replacement as the ppaddr
554  * for this op, so this doesn't ensure that our function will never be called
555  * again. That's why we don't remove the op info from our map, so that it can
556  * still run correctly if required. */
557
558 /* ... pp_rv2av ............................................................ */
559
560 STATIC OP *a_pp_rv2av(pTHX) {
561  a_op_info oi;
562  UV flags;
563  dSP;
564
565  a_map_fetch(PL_op, &oi);
566  flags = oi.flags;
567
568  if (flags & A_HINT_DEREF) {
569   if (!a_defined(TOPs)) {
570    /* We always need to push an empty array to fool the pp_aelem() that comes
571     * later. */
572    SV *av;
573    POPs;
574    av = sv_2mortal((SV *) newAV());
575    PUSHs(av);
576    RETURN;
577   }
578  } else {
579   PL_op->op_ppaddr = oi.old_pp;
580  }
581
582  return CALL_FPTR(oi.old_pp)(aTHX);
583 }
584
585 /* ... pp_rv2hv ............................................................ */
586
587 STATIC OP *a_pp_rv2hv_simple(pTHX) {
588  a_op_info oi;
589  UV flags;
590  dSP;
591
592  a_map_fetch(PL_op, &oi);
593  flags = oi.flags;
594
595  if (flags & A_HINT_DEREF) {
596   if (!a_defined(TOPs))
597    RETURN;
598  } else {
599   PL_op->op_ppaddr = oi.old_pp;
600  }
601
602  return CALL_FPTR(oi.old_pp)(aTHX);
603 }
604
605 STATIC OP *a_pp_rv2hv(pTHX) {
606  a_op_info oi;
607  UV flags;
608  dSP;
609
610  a_map_fetch(PL_op, &oi);
611  flags = oi.flags;
612
613  if (flags & A_HINT_DEREF) {
614   if (!a_defined(TOPs)) {
615    SV *hv;
616    POPs;
617    hv = sv_2mortal((SV *) newHV());
618    PUSHs(hv);
619    RETURN;
620   }
621  } else {
622   PL_op->op_ppaddr = oi.old_pp;
623  }
624
625  return CALL_FPTR(oi.old_pp)(aTHX);
626 }
627
628 /* ... pp_deref (aelem,helem,rv2sv,padsv) .................................. */
629
630 STATIC OP *a_pp_deref(pTHX) {
631  a_op_info oi;
632  UV flags;
633  dSP;
634
635  a_map_fetch(PL_op, &oi);
636  flags = oi.flags;
637
638  if (flags & A_HINT_DEREF) {
639   OP *o;
640   U8 old_private;
641
642 deref:
643   old_private       = PL_op->op_private;
644   PL_op->op_private = ((old_private & ~OPpDEREF) | OPpLVAL_DEFER);
645   o = CALL_FPTR(oi.old_pp)(aTHX);
646   PL_op->op_private = old_private;
647
648   if (flags & (A_HINT_NOTIFY|A_HINT_STORE)) {
649    SPAGAIN;
650    if (!a_defined(TOPs)) {
651     if (flags & A_HINT_STRICT)
652      croak("Reference vivification forbidden");
653     else if (flags & A_HINT_WARN)
654       warn("Reference was vivified");
655     else /* A_HINT_STORE */
656      croak("Can't vivify reference");
657    }
658   }
659
660   return o;
661  } else if ((flags & ~A_HINT_ROOT)
662                     && (PL_op->op_private & OPpDEREF || flags & A_HINT_ROOT)) {
663   /* Decide if the expression must autovivify or not.
664    * This branch should be called only once by expression. */
665   flags = a_map_resolve(PL_op, &oi);
666
667   /* We need the updated flags value in the deref branch. */
668   if (flags & A_HINT_DEREF)
669    goto deref;
670  }
671
672  /* This op doesn't need to skip autovivification, so restore the original
673   * state. */
674  PL_op->op_ppaddr = oi.old_pp;
675
676  return CALL_FPTR(oi.old_pp)(aTHX);
677 }
678
679 /* ... pp_root (exists,delete,keys,values) ................................. */
680
681 STATIC OP *a_pp_root_unop(pTHX) {
682  a_op_info oi;
683  dSP;
684
685  if (!a_defined(TOPs)) {
686   POPs;
687   /* Can only be reached by keys or values */
688   if (GIMME_V == G_SCALAR) {
689    dTARGET;
690    PUSHi(0);
691   }
692   RETURN;
693  }
694
695  a_map_fetch(PL_op, &oi);
696
697  return CALL_FPTR(oi.old_pp)(aTHX);
698 }
699
700 STATIC OP *a_pp_root_binop(pTHX) {
701  a_op_info oi;
702  dSP;
703
704  if (!a_defined(TOPm1s)) {
705   POPs;
706   POPs;
707   if (PL_op->op_type == OP_EXISTS)
708    RETPUSHNO;
709   else
710    RETPUSHUNDEF;
711  }
712
713  a_map_fetch(PL_op, &oi);
714
715  return CALL_FPTR(oi.old_pp)(aTHX);
716 }
717
718 /* --- Check functions ----------------------------------------------------- */
719
720 STATIC void a_recheck_rv2xv(pTHX_ OP *o, OPCODE type, OP *(*new_pp)(pTHX)) {
721 #define a_recheck_rv2xv(O, T, PP) a_recheck_rv2xv(aTHX_ (O), (T), (PP))
722  a_op_info oi;
723
724  if (o->op_type == type && o->op_ppaddr != new_pp
725                         && cUNOPo->op_first->op_type != OP_GV
726                         && a_map_fetch(o, &oi)) {
727   a_map_store(o, o->op_ppaddr, oi.next, oi.flags);
728   o->op_ppaddr = new_pp;
729  }
730
731  return;
732 }
733
734 /* ... ck_pad{any,sv} ...................................................... */
735
736 /* Sadly, the PADSV OPs we are interested in don't trigger the padsv check
737  * function, but are instead manually mutated from a PADANY. This is why we set
738  * PL_ppaddr[OP_PADSV] in the padany check function so that PADSV OPs will have
739  * their op_ppaddr set to our pp_padsv. PL_ppaddr[OP_PADSV] is then reset at the
740  * beginning of every ck_pad{any,sv}. Some unwanted OPs can still call our
741  * pp_padsv, but much less than if we would have set PL_ppaddr[OP_PADSV]
742  * globally. */
743
744 STATIC OP *(*a_pp_padsv_saved)(pTHX) = 0;
745
746 STATIC void a_pp_padsv_save(void) {
747  if (a_pp_padsv_saved)
748   return;
749
750  a_pp_padsv_saved    = PL_ppaddr[OP_PADSV];
751  PL_ppaddr[OP_PADSV] = a_pp_deref;
752 }
753
754 STATIC void a_pp_padsv_restore(OP *o) {
755  if (!a_pp_padsv_saved)
756   return;
757
758  if (o->op_ppaddr == a_pp_deref)
759   o->op_ppaddr = a_pp_padsv_saved;
760
761  PL_ppaddr[OP_PADSV] = a_pp_padsv_saved;
762  a_pp_padsv_saved    = 0;
763 }
764
765 STATIC OP *(*a_old_ck_padany)(pTHX_ OP *) = 0;
766
767 STATIC OP *a_ck_padany(pTHX_ OP *o) {
768  UV hint;
769
770  a_pp_padsv_restore(o);
771
772  o = CALL_FPTR(a_old_ck_padany)(aTHX_ o);
773
774  hint = a_hint();
775  if (hint & A_HINT_DO) {
776   a_pp_padsv_save();
777   a_map_store_root(o, a_pp_padsv_saved, hint);
778  } else
779   a_map_delete(o);
780
781  return o;
782 }
783
784 STATIC OP *(*a_old_ck_padsv)(pTHX_ OP *) = 0;
785
786 STATIC OP *a_ck_padsv(pTHX_ OP *o) {
787  UV hint;
788
789  a_pp_padsv_restore(o);
790
791  o = CALL_FPTR(a_old_ck_padsv)(aTHX_ o);
792
793  hint = a_hint();
794  if (hint & A_HINT_DO) {
795   a_map_store_root(o, o->op_ppaddr, hint);
796   o->op_ppaddr = a_pp_deref;
797  } else
798   a_map_delete(o);
799
800  return o;
801 }
802
803 /* ... ck_deref (aelem,helem,rv2sv) ........................................ */
804
805 /* Those ops appear both at the root and inside an expression but there's no
806  * way to distinguish both situations. Worse, we can't even know if we are in a
807  * modifying context, so the expression can't be resolved yet. It will be at the
808  * first invocation of a_pp_deref() for this expression. */
809
810 STATIC OP *(*a_old_ck_aelem)(pTHX_ OP *) = 0;
811 STATIC OP *(*a_old_ck_helem)(pTHX_ OP *) = 0;
812 STATIC OP *(*a_old_ck_rv2sv)(pTHX_ OP *) = 0;
813
814 STATIC OP *a_ck_deref(pTHX_ OP *o) {
815  OP * (*old_ck)(pTHX_ OP *o) = 0;
816  UV hint = a_hint();
817
818  switch (o->op_type) {
819   case OP_AELEM:
820    old_ck = a_old_ck_aelem;
821    if ((hint & A_HINT_DO) && !(hint & A_HINT_STRICT))
822     a_recheck_rv2xv(cUNOPo->op_first, OP_RV2AV, a_pp_rv2av);
823    break;
824   case OP_HELEM:
825    old_ck = a_old_ck_helem;
826    if ((hint & A_HINT_DO) && !(hint & A_HINT_STRICT))
827     a_recheck_rv2xv(cUNOPo->op_first, OP_RV2HV, a_pp_rv2hv_simple);
828    break;
829   case OP_RV2SV:
830    old_ck = a_old_ck_rv2sv;
831    break;
832  }
833  o = CALL_FPTR(old_ck)(aTHX_ o);
834
835  if (hint & A_HINT_DO) {
836   a_map_store_root(o, o->op_ppaddr, hint);
837   o->op_ppaddr = a_pp_deref;
838  } else
839   a_map_delete(o);
840
841  return o;
842 }
843
844 /* ... ck_rv2xv (rv2av,rv2hv) .............................................. */
845
846 /* Those ops also appear both inisde and at the root, hence the caveats for
847  * a_ck_deref() still apply here. Since a padsv/rv2sv must appear before a
848  * rv2[ah]v, resolution is handled by the first call to a_pp_deref() in the
849  * expression. */
850
851 STATIC OP *(*a_old_ck_rv2av)(pTHX_ OP *) = 0;
852 STATIC OP *(*a_old_ck_rv2hv)(pTHX_ OP *) = 0;
853
854 STATIC OP *a_ck_rv2xv(pTHX_ OP *o) {
855  OP * (*old_ck)(pTHX_ OP *o) = 0;
856  OP * (*new_pp)(pTHX)        = 0;
857  UV hint;
858
859  switch (o->op_type) {
860   case OP_RV2AV: old_ck = a_old_ck_rv2av; new_pp = a_pp_rv2av; break;
861   case OP_RV2HV: old_ck = a_old_ck_rv2hv; new_pp = a_pp_rv2hv_simple; break;
862  }
863  o = CALL_FPTR(old_ck)(aTHX_ o);
864
865  if (cUNOPo->op_first->op_type == OP_GV)
866   return o;
867
868  hint = a_hint();
869  if (hint & A_HINT_DO && !(hint & A_HINT_STRICT)) {
870   a_map_store_root(o, o->op_ppaddr, hint);
871   o->op_ppaddr = new_pp;
872  } else
873   a_map_delete(o);
874
875  return o;
876 }
877
878 /* ... ck_xslice (aslice,hslice) ........................................... */
879
880 /* I think those are only found at the root, but there's nothing that really
881  * prevent them to be inside the expression too. We only need to update the
882  * root so that the rest of the expression will see the right context when
883  * resolving. That's why we don't replace the ppaddr. */
884
885 STATIC OP *(*a_old_ck_aslice)(pTHX_ OP *) = 0;
886 STATIC OP *(*a_old_ck_hslice)(pTHX_ OP *) = 0;
887
888 STATIC OP *a_ck_xslice(pTHX_ OP *o) {
889  OP * (*old_ck)(pTHX_ OP *o) = 0;
890  UV hint = a_hint();
891
892  switch (o->op_type) {
893   case OP_ASLICE:
894    old_ck = a_old_ck_aslice;
895    break;
896   case OP_HSLICE:
897    old_ck = a_old_ck_hslice;
898    if (hint & A_HINT_DO)
899     a_recheck_rv2xv(cUNOPo->op_first->op_sibling, OP_RV2HV, a_pp_rv2hv);
900    break;
901  }
902  o = CALL_FPTR(old_ck)(aTHX_ o);
903
904  if (hint & A_HINT_DO) {
905   a_map_store_root(o, 0, hint);
906  } else
907   a_map_delete(o);
908
909  return o;
910 }
911
912 /* ... ck_root (exists,delete,keys,values) ................................. */
913
914 /* Those ops are only found at the root of a dereferencing expression. We can
915  * then resolve at compile time if vivification must take place or not. */
916
917 STATIC OP *(*a_old_ck_exists)(pTHX_ OP *) = 0;
918 STATIC OP *(*a_old_ck_delete)(pTHX_ OP *) = 0;
919 STATIC OP *(*a_old_ck_keys)  (pTHX_ OP *) = 0;
920 STATIC OP *(*a_old_ck_values)(pTHX_ OP *) = 0;
921
922 STATIC OP *a_ck_root(pTHX_ OP *o) {
923  OP * (*old_ck)(pTHX_ OP *o) = 0;
924  OP * (*new_pp)(pTHX)        = 0;
925  bool enabled = FALSE;
926  UV hint = a_hint();
927
928  switch (o->op_type) {
929   case OP_EXISTS:
930    old_ck  = a_old_ck_exists;
931    new_pp  = a_pp_root_binop;
932    enabled = hint & A_HINT_EXISTS;
933    break;
934   case OP_DELETE:
935    old_ck  = a_old_ck_delete;
936    new_pp  = a_pp_root_binop;
937    enabled = hint & A_HINT_DELETE;
938    break;
939   case OP_KEYS:
940    old_ck  = a_old_ck_keys;
941    new_pp  = a_pp_root_unop;
942    enabled = hint & A_HINT_FETCH;
943    break;
944   case OP_VALUES:
945    old_ck  = a_old_ck_values;
946    new_pp  = a_pp_root_unop;
947    enabled = hint & A_HINT_FETCH;
948    break;
949  }
950  o = CALL_FPTR(old_ck)(aTHX_ o);
951
952  if (hint & A_HINT_DO) {
953   if (enabled) {
954    a_map_update_flags_topdown(o, hint | A_HINT_DEREF);
955    a_map_store_root(o, o->op_ppaddr, hint);
956    o->op_ppaddr = new_pp;
957   } else {
958    a_map_cancel(o);
959   }
960  } else
961   a_map_delete(o);
962
963  return o;
964 }
965
966 STATIC U32 a_initialized = 0;
967
968 /* --- XS ------------------------------------------------------------------ */
969
970 MODULE = autovivification      PACKAGE = autovivification
971
972 PROTOTYPES: ENABLE
973
974 BOOT: 
975 {                                    
976  if (!a_initialized++) {
977   HV *stash;
978 #if A_THREADSAFE && A_WORKAROUND_REQUIRE_PROPAGATION
979   MY_CXT_INIT;
980   MY_CXT.tbl   = ptable_new();
981   MY_CXT.owner = aTHX;
982 #endif
983
984   a_op_map = ptable_new();
985 #ifdef USE_ITHREADS
986   MUTEX_INIT(&a_op_map_mutex);
987 #endif
988
989   PERL_HASH(a_hash, __PACKAGE__, __PACKAGE_LEN__);
990
991   a_old_ck_padany     = PL_check[OP_PADANY];
992   PL_check[OP_PADANY] = MEMBER_TO_FPTR(a_ck_padany);
993   a_old_ck_padsv      = PL_check[OP_PADSV];
994   PL_check[OP_PADSV]  = MEMBER_TO_FPTR(a_ck_padsv);
995
996   a_old_ck_aelem      = PL_check[OP_AELEM];
997   PL_check[OP_AELEM]  = MEMBER_TO_FPTR(a_ck_deref);
998   a_old_ck_helem      = PL_check[OP_HELEM];
999   PL_check[OP_HELEM]  = MEMBER_TO_FPTR(a_ck_deref);
1000   a_old_ck_rv2sv      = PL_check[OP_RV2SV];
1001   PL_check[OP_RV2SV]  = MEMBER_TO_FPTR(a_ck_deref);
1002
1003   a_old_ck_rv2av      = PL_check[OP_RV2AV];
1004   PL_check[OP_RV2AV]  = MEMBER_TO_FPTR(a_ck_rv2xv);
1005   a_old_ck_rv2hv      = PL_check[OP_RV2HV];
1006   PL_check[OP_RV2HV]  = MEMBER_TO_FPTR(a_ck_rv2xv);
1007
1008   a_old_ck_aslice     = PL_check[OP_ASLICE];
1009   PL_check[OP_ASLICE] = MEMBER_TO_FPTR(a_ck_xslice);
1010   a_old_ck_hslice     = PL_check[OP_HSLICE];
1011   PL_check[OP_HSLICE] = MEMBER_TO_FPTR(a_ck_xslice);
1012
1013   a_old_ck_exists     = PL_check[OP_EXISTS];
1014   PL_check[OP_EXISTS] = MEMBER_TO_FPTR(a_ck_root);
1015   a_old_ck_delete     = PL_check[OP_DELETE];
1016   PL_check[OP_DELETE] = MEMBER_TO_FPTR(a_ck_root);
1017   a_old_ck_keys       = PL_check[OP_KEYS];
1018   PL_check[OP_KEYS]   = MEMBER_TO_FPTR(a_ck_root);
1019   a_old_ck_values     = PL_check[OP_VALUES];
1020   PL_check[OP_VALUES] = MEMBER_TO_FPTR(a_ck_root);
1021
1022   stash = gv_stashpvn(__PACKAGE__, __PACKAGE_LEN__, 1);
1023   newCONSTSUB(stash, "A_HINT_STRICT", newSVuv(A_HINT_STRICT));
1024   newCONSTSUB(stash, "A_HINT_WARN",   newSVuv(A_HINT_WARN));
1025   newCONSTSUB(stash, "A_HINT_FETCH",  newSVuv(A_HINT_FETCH));
1026   newCONSTSUB(stash, "A_HINT_STORE",  newSVuv(A_HINT_STORE));
1027   newCONSTSUB(stash, "A_HINT_EXISTS", newSVuv(A_HINT_EXISTS));
1028   newCONSTSUB(stash, "A_HINT_DELETE", newSVuv(A_HINT_DELETE));
1029   newCONSTSUB(stash, "A_HINT_MASK",   newSVuv(A_HINT_MASK));
1030  }
1031 }
1032
1033 #if A_THREADSAFE && A_WORKAROUND_REQUIRE_PROPAGATION
1034
1035 void
1036 CLONE(...)
1037 PROTOTYPE: DISABLE
1038 PREINIT:
1039  ptable *t;
1040  int    *level;
1041 CODE:
1042  {
1043   my_cxt_t ud;
1044   dMY_CXT;
1045   ud.tbl   = t = ptable_new();
1046   ud.owner = MY_CXT.owner;
1047   ptable_walk(MY_CXT.tbl, a_ptable_clone, &ud);
1048  }
1049  {
1050   MY_CXT_CLONE;
1051   MY_CXT.tbl   = t;
1052   MY_CXT.owner = aTHX;
1053  }
1054  {
1055   level = PerlMemShared_malloc(sizeof *level);
1056   *level = 1;
1057   LEAVEn("sub");
1058   SAVEDESTRUCTOR_X(a_thread_cleanup, level);
1059   ENTERn("sub");
1060  }
1061
1062 #endif
1063
1064 SV *
1065 _tag(SV *hint)
1066 PROTOTYPE: $
1067 CODE:
1068  RETVAL = a_tag(SvOK(hint) ? SvUV(hint) : 0);
1069 OUTPUT:
1070  RETVAL
1071
1072 SV *
1073 _detag(SV *tag)
1074 PROTOTYPE: $
1075 CODE:
1076  if (!SvOK(tag))
1077   XSRETURN_UNDEF;
1078  RETVAL = newSVuv(a_detag(tag));
1079 OUTPUT:
1080  RETVAL