]> git.vpit.fr Git - perl/modules/autovivification.git/blob - autovivification.xs
Use the op free hook to clean up pointer table entries when available
[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 #ifndef A_WORKAROUND_REQUIRE_PROPAGATION
25 # define A_WORKAROUND_REQUIRE_PROPAGATION !A_HAS_PERL(5, 10, 1)
26 #endif
27
28 #ifndef A_HAS_RPEEP
29 # define A_HAS_RPEEP A_HAS_PERL(5, 13, 5)
30 #endif
31
32 #ifndef A_HAS_OPFREEHOOK
33 # define A_HAS_OPFREEHOOK A_HAS_PERL(5, 12, 0)
34 #endif
35
36 /* ... Thread safety and multiplicity ...................................... */
37
38 /* Always safe when the workaround isn't needed */
39 #if !A_WORKAROUND_REQUIRE_PROPAGATION
40 # undef A_FORKSAFE
41 # define A_FORKSAFE 1
42 /* Otherwise, safe unless Makefile.PL says it's Win32 */
43 #elif !defined(A_FORKSAFE)
44 # define A_FORKSAFE 1
45 #endif
46
47 #ifndef A_MULTIPLICITY
48 # if defined(MULTIPLICITY) || defined(PERL_IMPLICIT_CONTEXT)
49 #  define A_MULTIPLICITY 1
50 # else
51 #  define A_MULTIPLICITY 0
52 # endif
53 #endif
54
55 #ifndef tTHX
56 # define tTHX PerlInterpreter*
57 #endif
58
59 #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))
60 # define A_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 A_THREADSAFE 0
70 # undef  dMY_CXT
71 # define dMY_CXT      dNOOP
72 # undef  MY_CXT
73 # define MY_CXT       a_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 defined(OP_CHECK_MUTEX_LOCK) && defined(OP_CHECK_MUTEX_UNLOCK)
83 # define A_CHECK_MUTEX_LOCK   OP_CHECK_MUTEX_LOCK
84 # define A_CHECK_MUTEX_UNLOCK OP_CHECK_MUTEX_UNLOCK
85 #else
86 # define A_CHECK_MUTEX_LOCK   OP_REFCNT_LOCK
87 # define A_CHECK_MUTEX_UNLOCK OP_REFCNT_UNLOCK
88 #endif
89
90 typedef OP *(*a_ck_t)(pTHX_ OP *);
91
92 #ifdef wrap_op_checker
93
94 # define a_ck_replace(T, NC, OCP) wrap_op_checker((T), (NC), (OCP))
95
96 #else
97
98 STATIC void a_ck_replace(pTHX_ OPCODE type, a_ck_t new_ck, a_ck_t *old_ck_p) {
99 #define a_ck_replace(T, NC, OCP) a_ck_replace(aTHX_ (T), (NC), (OCP))
100  A_CHECK_MUTEX_LOCK;
101  if (!*old_ck_p) {
102   *old_ck_p      = PL_check[type];
103   PL_check[type] = new_ck;
104  }
105  A_CHECK_MUTEX_UNLOCK;
106 }
107
108 #endif
109
110 STATIC void a_ck_restore(pTHX_ OPCODE type, a_ck_t *old_ck_p) {
111 #define a_ck_restore(T, OCP) a_ck_restore(aTHX_ (T), (OCP))
112  A_CHECK_MUTEX_LOCK;
113  if (*old_ck_p) {
114   PL_check[type] = *old_ck_p;
115   *old_ck_p      = 0;
116  }
117  A_CHECK_MUTEX_UNLOCK;
118 }
119
120 /* --- Helpers ------------------------------------------------------------- */
121
122 /* ... Thread-safe hints ................................................... */
123
124 #if A_WORKAROUND_REQUIRE_PROPAGATION
125
126 typedef struct {
127  U32 bits;
128  IV  require_tag;
129 } a_hint_t;
130
131 #define A_HINT_FREE(H) PerlMemShared_free(H)
132
133 #if A_THREADSAFE
134
135 #define PTABLE_NAME        ptable_hints
136 #define PTABLE_VAL_FREE(V) A_HINT_FREE(V)
137
138 #define pPTBL  pTHX
139 #define pPTBL_ pTHX_
140 #define aPTBL  aTHX
141 #define aPTBL_ aTHX_
142
143 #include "ptable.h"
144
145 #define ptable_hints_store(T, K, V) ptable_hints_store(aTHX_ (T), (K), (V))
146 #define ptable_hints_free(T)        ptable_hints_free(aTHX_ (T))
147
148 #endif /* A_THREADSAFE */
149
150 #endif /* A_WORKAROUND_REQUIRE_PROPAGATION */
151
152 #define PTABLE_NAME        ptable_seen
153 #define PTABLE_VAL_FREE(V) NOOP
154
155 #include "ptable.h"
156
157 /* PerlMemShared_free() needs the [ap]PTBLMS_? default values */
158 #define ptable_seen_store(T, K, V) ptable_seen_store(aPTBLMS_ (T), (K), (V))
159 #define ptable_seen_clear(T)       ptable_seen_clear(aPTBLMS_ (T))
160 #define ptable_seen_free(T)        ptable_seen_free(aPTBLMS_ (T))
161
162 #define MY_CXT_KEY __PACKAGE__ "::_guts" XS_VERSION
163
164 typedef struct {
165 #if A_THREADSAFE && A_WORKAROUND_REQUIRE_PROPAGATION
166  ptable *tbl;   /* It really is a ptable_hints */
167  tTHX    owner;
168 #endif /* A_THREADSAFE && A_WORKAROUND_REQUIRE_PROPAGATION */
169  ptable *seen;  /* It really is a ptable_seen */
170 } my_cxt_t;
171
172 START_MY_CXT
173
174 #if A_THREADSAFE
175
176 #if A_WORKAROUND_REQUIRE_PROPAGATION
177
178 typedef struct {
179  ptable       *tbl;
180 #if A_HAS_PERL(5, 13, 2)
181  CLONE_PARAMS *params;
182 #else
183  CLONE_PARAMS  params;
184 #endif
185 } a_ptable_clone_ud;
186
187 #if A_HAS_PERL(5, 13, 2)
188 # define a_ptable_clone_ud_init(U, T, O) \
189    (U).tbl    = (T); \
190    (U).params = Perl_clone_params_new((O), aTHX)
191 # define a_ptable_clone_ud_deinit(U) Perl_clone_params_del((U).params)
192 # define a_dup_inc(S, U)             SvREFCNT_inc(sv_dup((S), (U)->params))
193 #else
194 # define a_ptable_clone_ud_init(U, T, O) \
195    (U).tbl               = (T);     \
196    (U).params.stashes    = newAV(); \
197    (U).params.flags      = 0;       \
198    (U).params.proto_perl = (O)
199 # define a_ptable_clone_ud_deinit(U) SvREFCNT_dec((U).params.stashes)
200 # define a_dup_inc(S, U)             SvREFCNT_inc(sv_dup((S), &((U)->params)))
201 #endif
202
203 STATIC void a_ptable_clone(pTHX_ ptable_ent *ent, void *ud_) {
204  a_ptable_clone_ud *ud = ud_;
205  a_hint_t *h1 = ent->val;
206  a_hint_t *h2;
207
208  h2              = PerlMemShared_malloc(sizeof *h2);
209  h2->bits        = h1->bits;
210  h2->require_tag = PTR2IV(a_dup_inc(INT2PTR(SV *, h1->require_tag), ud));
211
212  ptable_hints_store(ud->tbl, ent->key, h2);
213 }
214
215 #endif /* A_WORKAROUND_REQUIRE_PROPAGATION */
216
217 #include "reap.h"
218
219 STATIC void a_thread_cleanup(pTHX_ void *ud) {
220  dMY_CXT;
221
222 #if A_WORKAROUND_REQUIRE_PROPAGATION
223  ptable_hints_free(MY_CXT.tbl);
224 #endif /* A_WORKAROUND_REQUIRE_PROPAGATION */
225  ptable_seen_free(MY_CXT.seen);
226 }
227
228 #endif /* A_THREADSAFE */
229
230 #if A_WORKAROUND_REQUIRE_PROPAGATION
231
232 STATIC IV a_require_tag(pTHX) {
233 #define a_require_tag() a_require_tag(aTHX)
234  const CV *cv, *outside;
235
236  cv = PL_compcv;
237
238  if (!cv) {
239   /* If for some reason the pragma is operational at run-time, try to discover
240    * the current cv in use. */
241   const PERL_SI *si;
242
243   for (si = PL_curstackinfo; si; si = si->si_prev) {
244    I32 cxix;
245
246    for (cxix = si->si_cxix; cxix >= 0; --cxix) {
247     const PERL_CONTEXT *cx = si->si_cxstack + cxix;
248
249     switch (CxTYPE(cx)) {
250      case CXt_SUB:
251      case CXt_FORMAT:
252       /* The propagation workaround is only needed up to 5.10.0 and at that
253        * time format and sub contexts were still identical. And even later the
254        * cv members offsets should have been kept the same. */
255       cv = cx->blk_sub.cv;
256       goto get_enclosing_cv;
257      case CXt_EVAL:
258       cv = cx->blk_eval.cv;
259       goto get_enclosing_cv;
260      default:
261       break;
262     }
263    }
264   }
265
266   cv = PL_main_cv;
267  }
268
269 get_enclosing_cv:
270  for (outside = CvOUTSIDE(cv); outside; outside = CvOUTSIDE(cv))
271   cv = outside;
272
273  return PTR2IV(cv);
274 }
275
276 STATIC SV *a_tag(pTHX_ UV bits) {
277 #define a_tag(B) a_tag(aTHX_ (B))
278  a_hint_t *h;
279
280  h              = PerlMemShared_malloc(sizeof *h);
281  h->bits        = bits;
282  h->require_tag = a_require_tag();
283
284 #if A_THREADSAFE
285  {
286   dMY_CXT;
287   /* We only need for the key to be an unique tag for looking up the value later
288    * Allocated memory provides convenient unique identifiers, so that's why we
289    * use the hint as the key itself. */
290   ptable_hints_store(MY_CXT.tbl, h, h);
291  }
292 #endif /* A_THREADSAFE */
293
294  return newSViv(PTR2IV(h));
295 }
296
297 STATIC UV a_detag(pTHX_ const SV *hint) {
298 #define a_detag(H) a_detag(aTHX_ (H))
299  a_hint_t *h;
300
301  if (!(hint && SvIOK(hint)))
302   return 0;
303
304  h = INT2PTR(a_hint_t *, SvIVX(hint));
305 #if A_THREADSAFE
306  {
307   dMY_CXT;
308   h = ptable_fetch(MY_CXT.tbl, h);
309  }
310 #endif /* A_THREADSAFE */
311
312  if (a_require_tag() != h->require_tag)
313   return 0;
314
315  return h->bits;
316 }
317
318 #else /* A_WORKAROUND_REQUIRE_PROPAGATION */
319
320 #define a_tag(B)   newSVuv(B)
321 /* PVs fetched from the hints chain have their SvLEN set to zero, so get the UV
322  * from a copy. */
323 #define a_detag(H) \
324  ((H)              \
325   ? (SvIOK(H)      \
326      ? SvUVX(H)    \
327      : (SvPOK(H)   \
328         ? sv_2uv(SvLEN(H) ? (H) : sv_mortalcopy(H)) \
329         : 0        \
330        )           \
331      )             \
332   : 0)
333
334 #endif /* !A_WORKAROUND_REQUIRE_PROPAGATION */
335
336 /* Used both for hints and op flags */
337 #define A_HINT_STRICT 1
338 #define A_HINT_WARN   2
339 #define A_HINT_FETCH  4
340 #define A_HINT_STORE  8
341 #define A_HINT_EXISTS 16
342 #define A_HINT_DELETE 32
343 #define A_HINT_NOTIFY (A_HINT_STRICT|A_HINT_WARN)
344 #define A_HINT_DO     (A_HINT_FETCH|A_HINT_STORE|A_HINT_EXISTS|A_HINT_DELETE)
345 #define A_HINT_MASK   (A_HINT_NOTIFY|A_HINT_DO)
346
347 /* Only used in op flags */
348 #define A_HINT_ROOT   64
349 #define A_HINT_DEREF  128
350
351 STATIC U32 a_hash = 0;
352
353 STATIC UV a_hint(pTHX) {
354 #define a_hint() a_hint(aTHX)
355  SV *hint;
356 #ifdef cop_hints_fetch_pvn
357  hint = cop_hints_fetch_pvn(PL_curcop, __PACKAGE__, __PACKAGE_LEN__, a_hash, 0);
358 #elif A_HAS_PERL(5, 9, 5)
359  hint = Perl_refcounted_he_fetch(aTHX_ PL_curcop->cop_hints_hash,
360                                        NULL,
361                                        __PACKAGE__, __PACKAGE_LEN__,
362                                        0,
363                                        a_hash);
364 #else
365  SV **val = hv_fetch(GvHV(PL_hintgv), __PACKAGE__, __PACKAGE_LEN__, 0);
366  if (!val)
367   return 0;
368  hint = *val;
369 #endif
370  return a_detag(hint);
371 }
372
373 /* ... op => info map ...................................................... */
374
375 typedef struct {
376  OP   *(*old_pp)(pTHX);
377  void   *next;
378  UV      flags;
379 } a_op_info;
380
381 #define PTABLE_NAME        ptable_map
382 #define PTABLE_VAL_FREE(V) PerlMemShared_free(V)
383
384 #include "ptable.h"
385
386 /* PerlMemShared_free() needs the [ap]PTBLMS_? default values */
387 #define ptable_map_store(T, K, V) ptable_map_store(aPTBLMS_ (T), (K), (V))
388 #define ptable_map_delete(T, K)   ptable_map_delete(aPTBLMS_ (T), (K))
389
390 STATIC ptable *a_op_map = NULL;
391
392 #ifdef USE_ITHREADS
393
394 #define dA_MAP_THX a_op_info a_op_map_tmp_oi
395
396 STATIC perl_mutex a_op_map_mutex;
397
398 #define A_LOCK(M)   MUTEX_LOCK(M)
399 #define A_UNLOCK(M) MUTEX_UNLOCK(M)
400
401 STATIC const a_op_info *a_map_fetch(const OP *o, a_op_info *oi) {
402  const a_op_info *val;
403
404  A_LOCK(&a_op_map_mutex);
405
406  val = ptable_fetch(a_op_map, o);
407  if (val) {
408   *oi = *val;
409   val = oi;
410  }
411
412  A_UNLOCK(&a_op_map_mutex);
413
414  return val;
415 }
416
417 #define a_map_fetch(O) a_map_fetch((O), &a_op_map_tmp_oi)
418
419 #else /* USE_ITHREADS */
420
421 #define dA_MAP_THX dNOOP
422
423 #define A_LOCK(M)   NOOP
424 #define A_UNLOCK(M) NOOP
425
426 #define a_map_fetch(O) ptable_fetch(a_op_map, (O))
427
428 #endif /* !USE_ITHREADS */
429
430 STATIC const a_op_info *a_map_store_locked(pPTBLMS_ const OP *o, OP *(*old_pp)(pTHX), void *next, UV flags) {
431 #define a_map_store_locked(O, PP, N, F) a_map_store_locked(aPTBLMS_ (O), (PP), (N), (F))
432  a_op_info *oi;
433
434  if (!(oi = ptable_fetch(a_op_map, o))) {
435   oi = PerlMemShared_malloc(sizeof *oi);
436   ptable_map_store(a_op_map, o, oi);
437  }
438
439  oi->old_pp = old_pp;
440  oi->next   = next;
441  oi->flags  = flags;
442
443  return oi;
444 }
445
446 STATIC void a_map_store(pPTBLMS_ const OP *o, OP *(*old_pp)(pTHX), void *next, UV flags) {
447 #define a_map_store(O, PP, N, F) a_map_store(aPTBLMS_ (O), (PP), (N), (F))
448  A_LOCK(&a_op_map_mutex);
449
450  a_map_store_locked(o, old_pp, next, flags);
451
452  A_UNLOCK(&a_op_map_mutex);
453 }
454
455 STATIC void a_map_delete(pTHX_ const OP *o) {
456 #define a_map_delete(O) a_map_delete(aTHX_ (O))
457  A_LOCK(&a_op_map_mutex);
458
459  ptable_map_delete(a_op_map, o);
460
461  A_UNLOCK(&a_op_map_mutex);
462 }
463
464 STATIC const OP *a_map_descend(const OP *o) {
465  switch (PL_opargs[o->op_type] & OA_CLASS_MASK) {
466   case OA_BASEOP:
467   case OA_UNOP:
468   case OA_BINOP:
469   case OA_BASEOP_OR_UNOP:
470    return cUNOPo->op_first;
471   case OA_LIST:
472   case OA_LISTOP:
473    return cLISTOPo->op_last;
474  }
475
476  return NULL;
477 }
478
479 STATIC void a_map_store_root(pPTBLMS_ const OP *root, OP *(*old_pp)(pTHX), UV flags) {
480 #define a_map_store_root(R, PP, F) a_map_store_root(aPTBLMS_ (R), (PP), (F))
481  const a_op_info *roi;
482  a_op_info *oi;
483  const OP *o = root;
484
485  A_LOCK(&a_op_map_mutex);
486
487  roi = a_map_store_locked(o, old_pp, (OP *) root, flags | A_HINT_ROOT);
488
489  while (o->op_flags & OPf_KIDS) {
490   o = a_map_descend(o);
491   if (!o)
492    break;
493   if ((oi = ptable_fetch(a_op_map, o))) {
494    oi->flags &= ~A_HINT_ROOT;
495    oi->next   = (a_op_info *) roi;
496    break;
497   }
498  }
499
500  A_UNLOCK(&a_op_map_mutex);
501
502  return;
503 }
504
505 STATIC void a_map_update_flags_topdown(const OP *root, UV flags) {
506  a_op_info *oi;
507  const OP *o = root;
508
509  A_LOCK(&a_op_map_mutex);
510
511  flags &= ~A_HINT_ROOT;
512
513  do {
514   if ((oi = ptable_fetch(a_op_map, o)))
515    oi->flags = (oi->flags & A_HINT_ROOT) | flags;
516   if (!(o->op_flags & OPf_KIDS))
517    break;
518   o = a_map_descend(o);
519  } while (o);
520
521  A_UNLOCK(&a_op_map_mutex);
522
523  return;
524 }
525
526 #define a_map_cancel(R) a_map_update_flags_topdown((R), 0)
527
528 STATIC void a_map_update_flags_bottomup(const OP *o, UV flags, UV rflags) {
529  a_op_info *oi;
530
531  A_LOCK(&a_op_map_mutex);
532
533  flags  &= ~A_HINT_ROOT;
534  rflags |=  A_HINT_ROOT;
535
536  oi = ptable_fetch(a_op_map, o);
537  while (!(oi->flags & A_HINT_ROOT)) {
538   oi->flags = flags;
539   oi        = oi->next;
540  }
541  oi->flags = rflags;
542
543  A_UNLOCK(&a_op_map_mutex);
544
545  return;
546 }
547
548 /* ... Decide whether this expression should be autovivified or not ........ */
549
550 STATIC UV a_map_resolve(const OP *o, const a_op_info *oi) {
551  UV flags = 0, rflags;
552  const OP *root;
553  const a_op_info *roi = oi;
554
555  while (!(roi->flags & A_HINT_ROOT))
556   roi = roi->next;
557  if (!roi)
558   goto cancel;
559
560  rflags = roi->flags & ~A_HINT_ROOT;
561  if (!rflags)
562   goto cancel;
563
564  root = roi->next;
565  if (root->op_flags & OPf_MOD) {
566   if (rflags & A_HINT_STORE)
567    flags = (A_HINT_STORE|A_HINT_DEREF);
568  } else if (rflags & A_HINT_FETCH)
569    flags = (A_HINT_FETCH|A_HINT_DEREF);
570
571  if (!flags) {
572 cancel:
573   a_map_update_flags_bottomup(o, 0, 0);
574   return 0;
575  }
576
577  flags |= (rflags & A_HINT_NOTIFY);
578  a_map_update_flags_bottomup(o, flags, 0);
579
580  return oi->flags & A_HINT_ROOT ? 0 : flags;
581 }
582
583 /* ... Inspired from pp_defined() .......................................... */
584
585 STATIC int a_undef(pTHX_ SV *sv) {
586 #define a_undef(S) a_undef(aTHX_ (S))
587  switch (SvTYPE(sv)) {
588   case SVt_NULL:
589    return 1;
590   case SVt_PVAV:
591    if (AvMAX(sv) >= 0 || SvGMAGICAL(sv)
592                       || (SvRMAGICAL(sv) && mg_find(sv, PERL_MAGIC_tied)))
593     return 0;
594    break;
595   case SVt_PVHV:
596    if (HvARRAY(sv) || SvGMAGICAL(sv)
597                    || (SvRMAGICAL(sv) && mg_find(sv, PERL_MAGIC_tied)))
598     return 0;
599    break;
600   default:
601    SvGETMAGIC(sv);
602    if (SvOK(sv))
603     return 0;
604  }
605
606  return 1;
607 }
608
609 /* --- PP functions -------------------------------------------------------- */
610
611 /* Be aware that we restore PL_op->op_ppaddr from the pointer table old_pp
612  * value, another extension might have saved our pp replacement as the ppaddr
613  * for this op, so this doesn't ensure that our function will never be called
614  * again. That's why we don't remove the op info from our map, so that it can
615  * still run correctly if required. */
616
617 /* ... pp_rv2av ............................................................ */
618
619 STATIC OP *a_pp_rv2av(pTHX) {
620  dA_MAP_THX;
621  const a_op_info *oi;
622  dSP;
623
624  oi = a_map_fetch(PL_op);
625
626  if (oi->flags & A_HINT_DEREF) {
627   if (a_undef(TOPs)) {
628    /* We always need to push an empty array to fool the pp_aelem() that comes
629     * later. */
630    SV *av;
631    (void) POPs;
632    av = sv_2mortal((SV *) newAV());
633    PUSHs(av);
634    RETURN;
635   }
636  }
637
638  return oi->old_pp(aTHX);
639 }
640
641 /* ... pp_rv2hv ............................................................ */
642
643 STATIC OP *a_pp_rv2hv_simple(pTHX) {
644  dA_MAP_THX;
645  const a_op_info *oi;
646  dSP;
647
648  oi = a_map_fetch(PL_op);
649
650  if (oi->flags & A_HINT_DEREF) {
651   if (a_undef(TOPs))
652    RETURN;
653  }
654
655  return oi->old_pp(aTHX);
656 }
657
658 STATIC OP *a_pp_rv2hv(pTHX) {
659  dA_MAP_THX;
660  const a_op_info *oi;
661  dSP;
662
663  oi = a_map_fetch(PL_op);
664
665  if (oi->flags & A_HINT_DEREF) {
666   if (a_undef(TOPs)) {
667    SV *hv;
668    (void) POPs;
669    hv = sv_2mortal((SV *) newHV());
670    PUSHs(hv);
671    RETURN;
672   }
673  }
674
675  return oi->old_pp(aTHX);
676 }
677
678 /* ... pp_deref (aelem,helem,rv2sv,padsv) .................................. */
679
680 STATIC OP *a_pp_deref(pTHX) {
681  dA_MAP_THX;
682  const a_op_info *oi;
683  UV flags;
684  dSP;
685
686  oi = a_map_fetch(PL_op);
687
688  flags = oi->flags;
689  if (flags & A_HINT_DEREF) {
690   OP *o;
691
692   o = oi->old_pp(aTHX);
693
694   if (flags & (A_HINT_NOTIFY|A_HINT_STORE)) {
695    SPAGAIN;
696    if (a_undef(TOPs)) {
697     if (flags & A_HINT_STRICT)
698      croak("Reference vivification forbidden");
699     else if (flags & A_HINT_WARN)
700       warn("Reference was vivified");
701     else /* A_HINT_STORE */
702      croak("Can't vivify reference");
703    }
704   }
705
706   return o;
707  }
708
709  return oi->old_pp(aTHX);
710 }
711
712 /* ... pp_root (exists,delete,keys,values) ................................. */
713
714 STATIC OP *a_pp_root_unop(pTHX) {
715  dSP;
716
717  if (a_undef(TOPs)) {
718   (void) POPs;
719   /* Can only be reached by keys or values */
720   if (GIMME_V == G_SCALAR) {
721    dTARGET;
722    PUSHi(0);
723   }
724   RETURN;
725  }
726
727  {
728   dA_MAP_THX;
729   const a_op_info *oi = a_map_fetch(PL_op);
730   return oi->old_pp(aTHX);
731  }
732 }
733
734 STATIC OP *a_pp_root_binop(pTHX) {
735  dSP;
736
737  if (a_undef(TOPm1s)) {
738   (void) POPs;
739   (void) POPs;
740   if (PL_op->op_type == OP_EXISTS)
741    RETPUSHNO;
742   else
743    RETPUSHUNDEF;
744  }
745
746  {
747   dA_MAP_THX;
748   const a_op_info *oi = a_map_fetch(PL_op);
749   return oi->old_pp(aTHX);
750  }
751 }
752
753 /* --- Check functions ----------------------------------------------------- */
754
755 STATIC void a_recheck_rv2xv(pTHX_ OP *o, OPCODE type, OP *(*new_pp)(pTHX)) {
756 #define a_recheck_rv2xv(O, T, PP) a_recheck_rv2xv(aTHX_ (O), (T), (PP))
757
758  if (o->op_type == type && o->op_ppaddr != new_pp
759                         && cUNOPo->op_first->op_type != OP_GV) {
760   dA_MAP_THX;
761   const a_op_info *oi = a_map_fetch(o);
762   if (oi) {
763    a_map_store(o, o->op_ppaddr, oi->next, oi->flags);
764    o->op_ppaddr = new_pp;
765   }
766  }
767
768  return;
769 }
770
771 /* ... ck_pad{any,sv} ...................................................... */
772
773 /* Sadly, the padsv OPs we are interested in don't trigger the padsv check
774  * function, but are instead manually mutated from a padany. So we store
775  * the op entry in the op map in the padany check function, and we set their
776  * op_ppaddr member in our peephole optimizer replacement below. */
777
778 STATIC OP *(*a_old_ck_padany)(pTHX_ OP *) = 0;
779
780 STATIC OP *a_ck_padany(pTHX_ OP *o) {
781  UV hint;
782
783  o = a_old_ck_padany(aTHX_ o);
784
785  hint = a_hint();
786  if (hint & A_HINT_DO) {
787   a_map_store_root(o, o->op_ppaddr, hint);
788 #if !A_HAS_OPFREEHOOK
789  } else {
790   a_map_delete(o);
791 #endif
792  }
793
794  return o;
795 }
796
797 STATIC OP *(*a_old_ck_padsv)(pTHX_ OP *) = 0;
798
799 STATIC OP *a_ck_padsv(pTHX_ OP *o) {
800  UV hint;
801
802  o = a_old_ck_padsv(aTHX_ o);
803
804  hint = a_hint();
805  if (hint & A_HINT_DO) {
806   a_map_store_root(o, o->op_ppaddr, hint);
807   o->op_ppaddr = a_pp_deref;
808 #if !A_HAS_OPFREEHOOK
809  } else {
810   a_map_delete(o);
811 #endif
812  }
813
814  return o;
815 }
816
817 /* ... ck_deref (aelem,helem,rv2sv) ........................................ */
818
819 /* Those ops appear both at the root and inside an expression but there's no
820  * way to distinguish both situations. Worse, we can't even know if we are in a
821  * modifying context, so the expression can't be resolved yet. It will be at the
822  * first invocation of a_pp_deref() for this expression. */
823
824 STATIC OP *(*a_old_ck_aelem)(pTHX_ OP *) = 0;
825 STATIC OP *(*a_old_ck_helem)(pTHX_ OP *) = 0;
826 STATIC OP *(*a_old_ck_rv2sv)(pTHX_ OP *) = 0;
827
828 STATIC OP *a_ck_deref(pTHX_ OP *o) {
829  OP * (*old_ck)(pTHX_ OP *o) = 0;
830  UV hint = a_hint();
831
832  switch (o->op_type) {
833   case OP_AELEM:
834    old_ck = a_old_ck_aelem;
835    if ((hint & A_HINT_DO) && !(hint & A_HINT_STRICT))
836     a_recheck_rv2xv(cUNOPo->op_first, OP_RV2AV, a_pp_rv2av);
837    break;
838   case OP_HELEM:
839    old_ck = a_old_ck_helem;
840    if ((hint & A_HINT_DO) && !(hint & A_HINT_STRICT))
841     a_recheck_rv2xv(cUNOPo->op_first, OP_RV2HV, a_pp_rv2hv_simple);
842    break;
843   case OP_RV2SV:
844    old_ck = a_old_ck_rv2sv;
845    break;
846  }
847  o = old_ck(aTHX_ o);
848
849  if (hint & A_HINT_DO) {
850   a_map_store_root(o, o->op_ppaddr, hint);
851   o->op_ppaddr = a_pp_deref;
852 #if !A_HAS_OPFREEHOOK
853  } else {
854   a_map_delete(o);
855 #endif
856  }
857
858  return o;
859 }
860
861 /* ... ck_rv2xv (rv2av,rv2hv) .............................................. */
862
863 /* Those ops also appear both inisde and at the root, hence the caveats for
864  * a_ck_deref() still apply here. Since a padsv/rv2sv must appear before a
865  * rv2[ah]v, resolution is handled by the first call to a_pp_deref() in the
866  * expression. */
867
868 STATIC OP *(*a_old_ck_rv2av)(pTHX_ OP *) = 0;
869 STATIC OP *(*a_old_ck_rv2hv)(pTHX_ OP *) = 0;
870
871 STATIC OP *a_ck_rv2xv(pTHX_ OP *o) {
872  OP * (*old_ck)(pTHX_ OP *o) = 0;
873  OP * (*new_pp)(pTHX)        = 0;
874  UV hint;
875
876  switch (o->op_type) {
877   case OP_RV2AV: old_ck = a_old_ck_rv2av; new_pp = a_pp_rv2av; break;
878   case OP_RV2HV: old_ck = a_old_ck_rv2hv; new_pp = a_pp_rv2hv_simple; break;
879  }
880  o = old_ck(aTHX_ o);
881
882  if (cUNOPo->op_first->op_type == OP_GV)
883   return o;
884
885  hint = a_hint();
886  if (hint & A_HINT_DO && !(hint & A_HINT_STRICT)) {
887   a_map_store_root(o, o->op_ppaddr, hint);
888   o->op_ppaddr = new_pp;
889 #if !A_HAS_OPFREEHOOK
890  } else {
891   a_map_delete(o);
892 #endif
893  }
894
895  return o;
896 }
897
898 /* ... ck_xslice (aslice,hslice) ........................................... */
899
900 /* I think those are only found at the root, but there's nothing that really
901  * prevent them to be inside the expression too. We only need to update the
902  * root so that the rest of the expression will see the right context when
903  * resolving. That's why we don't replace the ppaddr. */
904
905 STATIC OP *(*a_old_ck_aslice)(pTHX_ OP *) = 0;
906 STATIC OP *(*a_old_ck_hslice)(pTHX_ OP *) = 0;
907
908 STATIC OP *a_ck_xslice(pTHX_ OP *o) {
909  OP * (*old_ck)(pTHX_ OP *o) = 0;
910  UV hint = a_hint();
911
912  switch (o->op_type) {
913   case OP_ASLICE:
914    old_ck = a_old_ck_aslice;
915    break;
916   case OP_HSLICE:
917    old_ck = a_old_ck_hslice;
918    if (hint & A_HINT_DO)
919     a_recheck_rv2xv(cUNOPo->op_first->op_sibling, OP_RV2HV, a_pp_rv2hv);
920    break;
921  }
922  o = old_ck(aTHX_ o);
923
924  if (hint & A_HINT_DO) {
925   a_map_store_root(o, 0, hint);
926 #if !A_HAS_OPFREEHOOK
927  } else {
928   a_map_delete(o);
929 #endif
930  }
931
932  return o;
933 }
934
935 /* ... ck_root (exists,delete,keys,values) ................................. */
936
937 /* Those ops are only found at the root of a dereferencing expression. We can
938  * then resolve at compile time if vivification must take place or not. */
939
940 STATIC OP *(*a_old_ck_exists)(pTHX_ OP *) = 0;
941 STATIC OP *(*a_old_ck_delete)(pTHX_ OP *) = 0;
942 STATIC OP *(*a_old_ck_keys)  (pTHX_ OP *) = 0;
943 STATIC OP *(*a_old_ck_values)(pTHX_ OP *) = 0;
944
945 STATIC OP *a_ck_root(pTHX_ OP *o) {
946  OP * (*old_ck)(pTHX_ OP *o) = 0;
947  OP * (*new_pp)(pTHX)        = 0;
948  bool enabled = FALSE;
949  UV hint = a_hint();
950
951  switch (o->op_type) {
952   case OP_EXISTS:
953    old_ck  = a_old_ck_exists;
954    new_pp  = a_pp_root_binop;
955    enabled = hint & A_HINT_EXISTS;
956    break;
957   case OP_DELETE:
958    old_ck  = a_old_ck_delete;
959    new_pp  = a_pp_root_binop;
960    enabled = hint & A_HINT_DELETE;
961    break;
962   case OP_KEYS:
963    old_ck  = a_old_ck_keys;
964    new_pp  = a_pp_root_unop;
965    enabled = hint & A_HINT_FETCH;
966    break;
967   case OP_VALUES:
968    old_ck  = a_old_ck_values;
969    new_pp  = a_pp_root_unop;
970    enabled = hint & A_HINT_FETCH;
971    break;
972  }
973  o = old_ck(aTHX_ o);
974
975  if (hint & A_HINT_DO) {
976   if (enabled) {
977    a_map_update_flags_topdown(o, hint | A_HINT_DEREF);
978    a_map_store_root(o, o->op_ppaddr, hint);
979    o->op_ppaddr = new_pp;
980   } else {
981    a_map_cancel(o);
982   }
983 #if !A_HAS_OPFREEHOOK
984  } else {
985   a_map_delete(o);
986 #endif
987  }
988
989  return o;
990 }
991
992 /* ... Our peephole optimizer .............................................. */
993
994 STATIC peep_t a_old_peep = 0; /* This is actually the rpeep past 5.13.5 */
995
996 STATIC void a_peep_rec(pTHX_ OP *o, ptable *seen);
997
998 STATIC void a_peep_rec(pTHX_ OP *o, ptable *seen) {
999 #define a_peep_rec(O) a_peep_rec(aTHX_ (O), seen)
1000  for (; o; o = o->op_next) {
1001   dA_MAP_THX;
1002   const a_op_info *oi = NULL;
1003   UV flags = 0;
1004
1005   if (ptable_fetch(seen, o))
1006    break;
1007   ptable_seen_store(seen, o, o);
1008
1009   switch (o->op_type) {
1010    case OP_PADSV:
1011     if (o->op_ppaddr != a_pp_deref) {
1012      oi = a_map_fetch(o);
1013      if (oi && (oi->flags & A_HINT_DO)) {
1014       a_map_store(o, o->op_ppaddr, oi->next, oi->flags);
1015       o->op_ppaddr = a_pp_deref;
1016      }
1017     }
1018     /* FALLTHROUGH */
1019    case OP_AELEM:
1020    case OP_AELEMFAST:
1021    case OP_HELEM:
1022    case OP_RV2SV:
1023     if (o->op_ppaddr != a_pp_deref)
1024      break;
1025     oi = a_map_fetch(o);
1026     if (!oi)
1027      break;
1028     flags = oi->flags;
1029     if (!(flags & A_HINT_DEREF)
1030         && (flags & A_HINT_DO)
1031         && (o->op_private & OPpDEREF || flags & A_HINT_ROOT)) {
1032      /* Decide if the expression must autovivify or not. */
1033      flags = a_map_resolve(o, oi);
1034     }
1035     if (flags & A_HINT_DEREF)
1036      o->op_private = ((o->op_private & ~OPpDEREF) | OPpLVAL_DEFER);
1037     else
1038      o->op_ppaddr  = oi->old_pp;
1039     break;
1040    case OP_RV2AV:
1041    case OP_RV2HV:
1042     if (   o->op_ppaddr != a_pp_rv2av
1043         && o->op_ppaddr != a_pp_rv2hv
1044         && o->op_ppaddr != a_pp_rv2hv_simple)
1045      break;
1046     oi = a_map_fetch(o);
1047     if (!oi)
1048      break;
1049     if (!(oi->flags & A_HINT_DEREF))
1050      o->op_ppaddr  = oi->old_pp;
1051     break;
1052 #if !A_HAS_RPEEP
1053    case OP_MAPWHILE:
1054    case OP_GREPWHILE:
1055    case OP_AND:
1056    case OP_OR:
1057    case OP_ANDASSIGN:
1058    case OP_ORASSIGN:
1059    case OP_COND_EXPR:
1060    case OP_RANGE:
1061 # if A_HAS_PERL(5, 10, 0)
1062    case OP_ONCE:
1063    case OP_DOR:
1064    case OP_DORASSIGN:
1065 # endif
1066     a_peep_rec(cLOGOPo->op_other);
1067     break;
1068    case OP_ENTERLOOP:
1069    case OP_ENTERITER:
1070     a_peep_rec(cLOOPo->op_redoop);
1071     a_peep_rec(cLOOPo->op_nextop);
1072     a_peep_rec(cLOOPo->op_lastop);
1073     break;
1074 # if A_HAS_PERL(5, 9, 5)
1075    case OP_SUBST:
1076     a_peep_rec(cPMOPo->op_pmstashstartu.op_pmreplstart);
1077     break;
1078 # else
1079    case OP_QR:
1080    case OP_MATCH:
1081    case OP_SUBST:
1082     a_peep_rec(cPMOPo->op_pmreplstart);
1083     break;
1084 # endif
1085 #endif /* !A_HAS_RPEEP */
1086    default:
1087     break;
1088   }
1089  }
1090 }
1091
1092 STATIC void a_peep(pTHX_ OP *o) {
1093  dMY_CXT;
1094  ptable *seen = MY_CXT.seen;
1095
1096  a_old_peep(aTHX_ o);
1097
1098  ptable_seen_clear(seen);
1099  a_peep_rec(o);
1100  ptable_seen_clear(seen);
1101 }
1102
1103 /* ... Our op free hook (when available) ................................... */
1104
1105 #if A_HAS_OPFREEHOOK
1106
1107 STATIC void (*a_old_opfreehook)(pTHX_ OP *) = 0;
1108
1109 STATIC void a_opfreehook(pTHX_ OP *o) {
1110  a_map_delete(o);
1111
1112  if (a_old_opfreehook)
1113   a_old_opfreehook(aTHX_ o);
1114 }
1115
1116 #endif
1117
1118 /* --- Interpreter setup/teardown ------------------------------------------ */
1119
1120 STATIC U32 a_initialized = 0;
1121
1122 STATIC void a_teardown(pTHX_ void *root) {
1123
1124  if (!a_initialized)
1125   return;
1126
1127 #if A_MULTIPLICITY
1128  if (aTHX != root)
1129   return;
1130 #endif
1131
1132  {
1133   dMY_CXT;
1134 # if A_THREADSAFE && A_WORKAROUND_REQUIRE_PROPAGATION
1135   ptable_hints_free(MY_CXT.tbl);
1136 # endif /* A_THREADSAFE && A_WORKAROUND_REQUIRE_PROPAGATION */
1137   ptable_seen_free(MY_CXT.seen);
1138  }
1139
1140  a_ck_restore(OP_PADANY, &a_old_ck_padany);
1141  a_ck_restore(OP_PADSV,  &a_old_ck_padsv);
1142
1143  a_ck_restore(OP_AELEM,  &a_old_ck_aelem);
1144  a_ck_restore(OP_HELEM,  &a_old_ck_helem);
1145  a_ck_restore(OP_RV2SV,  &a_old_ck_rv2sv);
1146
1147  a_ck_restore(OP_RV2AV,  &a_old_ck_rv2av);
1148  a_ck_restore(OP_RV2HV,  &a_old_ck_rv2hv);
1149
1150  a_ck_restore(OP_ASLICE, &a_old_ck_aslice);
1151  a_ck_restore(OP_HSLICE, &a_old_ck_hslice);
1152
1153  a_ck_restore(OP_EXISTS, &a_old_ck_exists);
1154  a_ck_restore(OP_DELETE, &a_old_ck_delete);
1155  a_ck_restore(OP_KEYS,   &a_old_ck_keys);
1156  a_ck_restore(OP_VALUES, &a_old_ck_values);
1157
1158 #if A_HAS_RPEEP
1159  PL_rpeepp  = a_old_peep;
1160 #else
1161  PL_peepp   = a_old_peep;
1162 #endif
1163  a_old_peep = 0;
1164
1165 #if A_HAS_OPFREEHOOK
1166  PL_opfreehook    = a_old_opfreehook;
1167  a_old_opfreehook = 0;
1168 #endif
1169
1170  a_initialized = 0;
1171 }
1172
1173 STATIC void a_setup(pTHX) {
1174 #define a_setup() a_setup(aTHX)
1175  if (a_initialized)
1176   return;
1177
1178  {
1179   MY_CXT_INIT;
1180 # if A_THREADSAFE && A_WORKAROUND_REQUIRE_PROPAGATION
1181   MY_CXT.tbl   = ptable_new();
1182   MY_CXT.owner = aTHX;
1183 # endif /* A_THREADSAFE && A_WORKAROUND_REQUIRE_PROPAGATION */
1184   MY_CXT.seen  = ptable_new();
1185  }
1186
1187  a_ck_replace(OP_PADANY, a_ck_padany, &a_old_ck_padany);
1188  a_ck_replace(OP_PADSV,  a_ck_padsv,  &a_old_ck_padsv);
1189
1190  a_ck_replace(OP_AELEM,  a_ck_deref,  &a_old_ck_aelem);
1191  a_ck_replace(OP_HELEM,  a_ck_deref,  &a_old_ck_helem);
1192  a_ck_replace(OP_RV2SV,  a_ck_deref,  &a_old_ck_rv2sv);
1193
1194  a_ck_replace(OP_RV2AV,  a_ck_rv2xv,  &a_old_ck_rv2av);
1195  a_ck_replace(OP_RV2HV,  a_ck_rv2xv,  &a_old_ck_rv2hv);
1196
1197  a_ck_replace(OP_ASLICE, a_ck_xslice, &a_old_ck_aslice);
1198  a_ck_replace(OP_HSLICE, a_ck_xslice, &a_old_ck_hslice);
1199
1200  a_ck_replace(OP_EXISTS, a_ck_root,   &a_old_ck_exists);
1201  a_ck_replace(OP_DELETE, a_ck_root,   &a_old_ck_delete);
1202  a_ck_replace(OP_KEYS,   a_ck_root,   &a_old_ck_keys);
1203  a_ck_replace(OP_VALUES, a_ck_root,   &a_old_ck_values);
1204
1205 #if A_HAS_RPEEP
1206  a_old_peep = PL_rpeepp;
1207  PL_rpeepp  = a_peep;
1208 #else
1209  a_old_peep = PL_peepp;
1210  PL_peepp   = a_peep;
1211 #endif
1212
1213 #if A_HAS_OPFREEHOOK
1214  a_old_opfreehook = PL_opfreehook;
1215  PL_opfreehook    = a_opfreehook;
1216 #endif
1217
1218 #if A_MULTIPLICITY
1219  call_atexit(a_teardown, aTHX);
1220 #else
1221  call_atexit(a_teardown, NULL);
1222 #endif
1223
1224  a_initialized = 1;
1225 }
1226
1227 STATIC U32 a_booted = 0;
1228
1229 /* --- XS ------------------------------------------------------------------ */
1230
1231 MODULE = autovivification      PACKAGE = autovivification
1232
1233 PROTOTYPES: ENABLE
1234
1235 BOOT:
1236 {
1237  if (!a_booted++) {
1238   HV *stash;
1239
1240   a_op_map = ptable_new();
1241 #ifdef USE_ITHREADS
1242   MUTEX_INIT(&a_op_map_mutex);
1243 #endif
1244
1245   PERL_HASH(a_hash, __PACKAGE__, __PACKAGE_LEN__);
1246
1247   stash = gv_stashpvn(__PACKAGE__, __PACKAGE_LEN__, 1);
1248   newCONSTSUB(stash, "A_HINT_STRICT", newSVuv(A_HINT_STRICT));
1249   newCONSTSUB(stash, "A_HINT_WARN",   newSVuv(A_HINT_WARN));
1250   newCONSTSUB(stash, "A_HINT_FETCH",  newSVuv(A_HINT_FETCH));
1251   newCONSTSUB(stash, "A_HINT_STORE",  newSVuv(A_HINT_STORE));
1252   newCONSTSUB(stash, "A_HINT_EXISTS", newSVuv(A_HINT_EXISTS));
1253   newCONSTSUB(stash, "A_HINT_DELETE", newSVuv(A_HINT_DELETE));
1254   newCONSTSUB(stash, "A_HINT_MASK",   newSVuv(A_HINT_MASK));
1255   newCONSTSUB(stash, "A_THREADSAFE",  newSVuv(A_THREADSAFE));
1256   newCONSTSUB(stash, "A_FORKSAFE",    newSVuv(A_FORKSAFE));
1257  }
1258
1259  a_setup();
1260 }
1261
1262 #if A_THREADSAFE
1263
1264 void
1265 CLONE(...)
1266 PROTOTYPE: DISABLE
1267 PREINIT:
1268 #if A_WORKAROUND_REQUIRE_PROPAGATION
1269  ptable *t;
1270 #endif
1271  ptable *s;
1272 PPCODE:
1273  {
1274   dMY_CXT;
1275 #if A_WORKAROUND_REQUIRE_PROPAGATION
1276   {
1277    a_ptable_clone_ud ud;
1278
1279    t = ptable_new();
1280    a_ptable_clone_ud_init(ud, t, MY_CXT.owner);
1281    ptable_walk(MY_CXT.tbl, a_ptable_clone, &ud);
1282    a_ptable_clone_ud_deinit(ud);
1283   }
1284 #endif
1285   s = ptable_new();
1286  }
1287  {
1288   MY_CXT_CLONE;
1289 #if A_WORKAROUND_REQUIRE_PROPAGATION
1290   MY_CXT.tbl   = t;
1291   MY_CXT.owner = aTHX;
1292 #endif
1293   MY_CXT.seen  = s;
1294  }
1295  reap(3, a_thread_cleanup, NULL);
1296  XSRETURN(0);
1297
1298 #endif /* A_THREADSAFE */
1299
1300 SV *
1301 _tag(SV *hint)
1302 PROTOTYPE: $
1303 CODE:
1304  RETVAL = a_tag(SvOK(hint) ? SvUV(hint) : 0);
1305 OUTPUT:
1306  RETVAL
1307
1308 SV *
1309 _detag(SV *tag)
1310 PROTOTYPE: $
1311 CODE:
1312  if (!SvOK(tag))
1313   XSRETURN_UNDEF;
1314  RETVAL = newSVuv(a_detag(tag));
1315 OUTPUT:
1316  RETVAL