]> git.vpit.fr Git - perl/modules/autovivification.git/blob - autovivification.xs
Add separate hint values for keys/values
[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 /* --- XS helpers ---------------------------------------------------------- */
10
11 #define XSH_PACKAGE "autovivification"
12
13 #include "xsh/caps.h"
14 #include "xsh/util.h"
15 #include "xsh/ops.h"
16 #include "xsh/peep.h"
17
18 /* ... Lexical hints ....................................................... */
19
20 /* Used both for hints and op flags */
21 #define A_HINT_STRICT 1
22 #define A_HINT_WARN   2
23 #define A_HINT_FETCH  4
24 #define A_HINT_STORE  8
25 #define A_HINT_KEYS   16
26 #define A_HINT_VALUES 32
27 #define A_HINT_EXISTS 64
28 #define A_HINT_DELETE 128
29 #define A_HINT_NOTIFY (A_HINT_STRICT|A_HINT_WARN)
30 #define A_HINT_DO     (A_HINT_FETCH|A_HINT_STORE|A_HINT_KEYS|A_HINT_VALUES|A_HINT_EXISTS|A_HINT_DELETE)
31 #define A_HINT_MASK   (A_HINT_NOTIFY|A_HINT_DO)
32
33 /* Only used in op flags */
34 #define A_HINT_ROOT   256
35 #define A_HINT_DEREF  512
36
37 #define XSH_HINTS_TYPE_UV 1
38
39 #include "xsh/hints.h"
40
41 #define a_hint() xsh_hints_detag(xsh_hints_fetch())
42
43 /* ... Thread-local storage ................................................ */
44
45 #define XSH_THREADS_COMPILE_TIME_PROTECTION 1
46 #define XSH_THREADS_USER_CONTEXT            0
47
48 #include "xsh/threads.h"
49
50 /* --- Compatibility wrappers ---------------------------------------------- */
51
52 #ifndef HvNAME_get
53 # define HvNAME_get(H) HvNAME(H)
54 #endif
55
56 #ifndef HvNAMELEN_get
57 # define HvNAMELEN_get(H) strlen(HvNAME_get(H))
58 #endif
59
60 #ifndef A_HAS_MULTIDEREF
61 # define A_HAS_MULTIDEREF XSH_HAS_PERL(5, 21, 7)
62 #endif
63
64 /* ... Our vivify_ref() .................................................... */
65
66 /* Perl_vivify_ref() is not exported, so we have to reimplement it. */
67
68 #if A_HAS_MULTIDEREF
69
70 static SV *a_vivify_ref(pTHX_ SV *sv, int to_hash) {
71 #define a_vivify_ref(S, TH) a_vivify_ref(aTHX_ (S), (TH))
72  SvGETMAGIC(sv);
73
74  if (!SvOK(sv)) {
75   SV *val;
76
77   if (SvREADONLY(sv))
78    Perl_croak_no_modify();
79
80   /* Inlined prepare_SV_for_RV() */
81   if (SvTYPE(sv) < SVt_PV && SvTYPE(sv) != SVt_IV) {
82    sv_upgrade(sv, SVt_IV);
83   } else if (SvTYPE(sv) >= SVt_PV) {
84    SvPV_free(sv);
85    SvLEN_set(sv, 0);
86    SvCUR_set(sv, 0);
87   }
88
89   val = to_hash ? MUTABLE_SV(newHV()) : MUTABLE_SV(newAV());
90   SvRV_set(sv, val);
91   SvROK_on(sv);
92   SvSETMAGIC(sv);
93   SvGETMAGIC(sv);
94  }
95
96  if (SvGMAGICAL(sv)) {
97   SV *msv = sv_newmortal();
98   sv_setsv_nomg(msv, sv);
99   return msv;
100  }
101
102  return sv;
103 }
104
105 #endif /* A_HAS_MULTIDEREF */
106
107 /* --- op => info map ------------------------------------------------------ */
108
109 typedef struct {
110  OP   *(*old_pp)(pTHX);
111  void   *next;
112  UV      flags;
113 } a_op_info;
114
115 #define PTABLE_NAME             ptable_map
116 #define PTABLE_VAL_FREE(V)      PerlMemShared_free(V)
117 #define PTABLE_VAL_NEED_CONTEXT 0
118 #define PTABLE_NEED_DELETE      1
119 #define PTABLE_NEED_WALK        0
120
121 #include "xsh/ptable.h"
122
123 #define ptable_map_store(T, K, V) ptable_map_store(aPMS_ (T), (K), (V))
124 #define ptable_map_delete(T, K)   ptable_map_delete(aPMS_ (T), (K))
125 #define ptable_map_free(T)        ptable_map_free(aPMS_ (T))
126
127 static ptable *a_op_map = NULL;
128
129 #ifdef USE_ITHREADS
130
131 #define dA_MAP_THX a_op_info a_op_map_tmp_oi
132
133 static perl_mutex a_op_map_mutex;
134
135 static const a_op_info *a_map_fetch(const OP *o, a_op_info *oi) {
136  const a_op_info *val;
137
138  XSH_LOCK(&a_op_map_mutex);
139
140  val = ptable_fetch(a_op_map, o);
141  if (val) {
142   *oi = *val;
143   val = oi;
144  }
145
146  XSH_UNLOCK(&a_op_map_mutex);
147
148  return val;
149 }
150
151 #define a_map_fetch(O) a_map_fetch((O), &a_op_map_tmp_oi)
152
153 #else /* USE_ITHREADS */
154
155 #define dA_MAP_THX dNOOP
156
157 #define a_map_fetch(O) ptable_fetch(a_op_map, (O))
158
159 #endif /* !USE_ITHREADS */
160
161 static const a_op_info *a_map_store_locked(pPMS_ const OP *o, OP *(*old_pp)(pTHX), void *next, UV flags) {
162 #define a_map_store_locked(O, PP, N, F) a_map_store_locked(aPMS_ (O), (PP), (N), (F))
163  a_op_info *oi;
164
165  if (!(oi = ptable_fetch(a_op_map, o))) {
166   oi = PerlMemShared_malloc(sizeof *oi);
167   ptable_map_store(a_op_map, o, oi);
168  }
169
170  oi->old_pp = old_pp;
171  oi->next   = next;
172  oi->flags  = flags;
173
174  return oi;
175 }
176
177 static void a_map_store(pTHX_ const OP *o, OP *(*old_pp)(pTHX), void *next, UV flags) {
178 #define a_map_store(O, PP, N, F) a_map_store(aTHX_ (O), (PP), (N), (F))
179  XSH_LOCK(&a_op_map_mutex);
180
181  a_map_store_locked(o, old_pp, next, flags);
182
183  XSH_UNLOCK(&a_op_map_mutex);
184 }
185
186 static void a_map_delete(pTHX_ const OP *o) {
187 #define a_map_delete(O) a_map_delete(aTHX_ (O))
188  XSH_LOCK(&a_op_map_mutex);
189
190  ptable_map_delete(a_op_map, o);
191
192  XSH_UNLOCK(&a_op_map_mutex);
193 }
194
195 static const OP *a_map_descend(const OP *o) {
196  switch (PL_opargs[o->op_type] & OA_CLASS_MASK) {
197   case OA_BASEOP:
198   case OA_UNOP:
199   case OA_BINOP:
200   case OA_BASEOP_OR_UNOP:
201    return cUNOPo->op_first;
202   case OA_LIST:
203   case OA_LISTOP:
204    return cLISTOPo->op_last;
205  }
206
207  return NULL;
208 }
209
210 static void a_map_store_root(pTHX_ const OP *root, OP *(*old_pp)(pTHX), UV flags) {
211 #define a_map_store_root(R, PP, F) a_map_store_root(aTHX_ (R), (PP), (F))
212  const a_op_info *roi;
213  a_op_info *oi;
214  const OP *o = root;
215
216  XSH_LOCK(&a_op_map_mutex);
217
218  roi = a_map_store_locked(o, old_pp, (OP *) root, flags | A_HINT_ROOT);
219
220  while (o->op_flags & OPf_KIDS) {
221   o = a_map_descend(o);
222   if (!o)
223    break;
224   if ((oi = ptable_fetch(a_op_map, o))) {
225    oi->flags &= ~A_HINT_ROOT;
226    oi->next   = (a_op_info *) roi;
227    break;
228   }
229  }
230
231  XSH_UNLOCK(&a_op_map_mutex);
232
233  return;
234 }
235
236 static void a_map_update_flags_topdown(const OP *root, UV flags) {
237  a_op_info *oi;
238  const OP *o = root;
239
240  XSH_LOCK(&a_op_map_mutex);
241
242  flags &= ~A_HINT_ROOT;
243
244  do {
245   if ((oi = ptable_fetch(a_op_map, o)))
246    oi->flags = (oi->flags & A_HINT_ROOT) | flags;
247   if (!(o->op_flags & OPf_KIDS))
248    break;
249   o = a_map_descend(o);
250  } while (o);
251
252  XSH_UNLOCK(&a_op_map_mutex);
253
254  return;
255 }
256
257 #define a_map_cancel(R) a_map_update_flags_topdown((R), 0)
258
259 static void a_map_update_flags_bottomup(const OP *o, UV flags, UV rflags) {
260  a_op_info *oi;
261
262  XSH_LOCK(&a_op_map_mutex);
263
264  flags  &= ~A_HINT_ROOT;
265  rflags |=  A_HINT_ROOT;
266
267  oi = ptable_fetch(a_op_map, o);
268  while (!(oi->flags & A_HINT_ROOT)) {
269   oi->flags = flags;
270   oi        = oi->next;
271  }
272  oi->flags = rflags;
273
274  XSH_UNLOCK(&a_op_map_mutex);
275
276  return;
277 }
278
279 /* ... Decide whether this expression should be autovivified or not ........ */
280
281 static UV a_map_resolve(const OP *o, const a_op_info *oi) {
282  UV flags = 0, rflags;
283  const OP *root;
284  const a_op_info *roi = oi;
285
286  while (!(roi->flags & A_HINT_ROOT))
287   roi = roi->next;
288  if (!roi)
289   goto cancel;
290
291  rflags = roi->flags & ~A_HINT_ROOT;
292  if (!rflags)
293   goto cancel;
294
295  root = roi->next;
296  if (root->op_flags & OPf_MOD) {
297   if (rflags & A_HINT_STORE)
298    flags = (A_HINT_STORE|A_HINT_DEREF);
299  } else {
300   if (rflags & (A_HINT_FETCH|A_HINT_KEYS|A_HINT_VALUES))
301    flags = (rflags|A_HINT_DEREF);
302  }
303
304  if (!flags) {
305 cancel:
306   a_map_update_flags_bottomup(o, 0, 0);
307   return 0;
308  }
309
310  flags |= (rflags & A_HINT_NOTIFY);
311  a_map_update_flags_bottomup(o, flags, 0);
312
313  return oi->flags & A_HINT_ROOT ? 0 : flags;
314 }
315
316 /* ... Inspired from pp_defined() .......................................... */
317
318 static int a_undef(pTHX_ SV *sv) {
319 #define a_undef(S) a_undef(aTHX_ (S))
320  switch (SvTYPE(sv)) {
321   case SVt_NULL:
322    return 1;
323   case SVt_PVAV:
324    if (AvMAX(sv) >= 0 || SvGMAGICAL(sv)
325                       || (SvRMAGICAL(sv) && mg_find(sv, PERL_MAGIC_tied)))
326     return 0;
327    break;
328   case SVt_PVHV:
329    if (HvARRAY(sv) || SvGMAGICAL(sv)
330                    || (SvRMAGICAL(sv) && mg_find(sv, PERL_MAGIC_tied)))
331     return 0;
332    break;
333   default:
334    SvGETMAGIC(sv);
335    if (SvOK(sv))
336     return 0;
337  }
338
339  return 1;
340 }
341
342 /* --- PP functions -------------------------------------------------------- */
343
344 /* Be aware that we restore PL_op->op_ppaddr from the pointer table old_pp
345  * value, another extension might have saved our pp replacement as the ppaddr
346  * for this op, so this doesn't ensure that our function will never be called
347  * again. That's why we don't remove the op info from our map, so that it can
348  * still run correctly if required. */
349
350 /* ... pp_rv2av ............................................................ */
351
352 static OP *a_pp_rv2av(pTHX) {
353  dA_MAP_THX;
354  const a_op_info *oi;
355  dSP;
356
357  oi = a_map_fetch(PL_op);
358
359  if (oi->flags & A_HINT_DEREF) {
360   if (a_undef(TOPs)) {
361    /* We always need to push an empty array to fool the pp_aelem() that comes
362     * later. */
363    SV *av;
364    (void) POPs;
365    av = sv_2mortal((SV *) newAV());
366    PUSHs(av);
367    RETURN;
368   }
369  }
370
371  return oi->old_pp(aTHX);
372 }
373
374 /* ... pp_rv2hv ............................................................ */
375
376 static OP *a_pp_rv2hv_simple(pTHX) {
377  dA_MAP_THX;
378  const a_op_info *oi;
379  dSP;
380
381  oi = a_map_fetch(PL_op);
382
383  if (oi->flags & A_HINT_DEREF) {
384   if (a_undef(TOPs))
385    RETURN;
386  }
387
388  return oi->old_pp(aTHX);
389 }
390
391 static OP *a_pp_rv2hv(pTHX) {
392  dA_MAP_THX;
393  const a_op_info *oi;
394  dSP;
395
396  oi = a_map_fetch(PL_op);
397
398  if (oi->flags & A_HINT_DEREF) {
399   if (a_undef(TOPs)) {
400    SV *hv;
401    (void) POPs;
402    hv = sv_2mortal((SV *) newHV());
403    PUSHs(hv);
404    RETURN;
405   }
406  }
407
408  return oi->old_pp(aTHX);
409 }
410
411 /* ... pp_deref (aelem,helem,rv2sv,padsv) .................................. */
412
413 static void a_cannot_vivify(pTHX_ UV flags) {
414 #define a_cannot_vivify(F) a_cannot_vivify(aTHX_ (F))
415  if (flags & A_HINT_STRICT)
416   croak("Reference vivification forbidden");
417  else if (flags & A_HINT_WARN)
418   warn("Reference was vivified");
419  else /* A_HINT_STORE */
420   croak("Can't vivify reference");
421 }
422
423 static OP *a_pp_deref(pTHX) {
424  dA_MAP_THX;
425  const a_op_info *oi;
426  UV flags;
427  dSP;
428
429  oi = a_map_fetch(PL_op);
430
431  flags = oi->flags;
432  if (flags & A_HINT_DEREF) {
433   OP *o;
434
435   o = oi->old_pp(aTHX);
436
437   if (flags & (A_HINT_NOTIFY|A_HINT_STORE)) {
438    SPAGAIN;
439    if (a_undef(TOPs))
440     a_cannot_vivify(flags);
441   }
442
443   return o;
444  }
445
446  return oi->old_pp(aTHX);
447 }
448
449 /* ... pp_root (exists,delete,keys,values) ................................. */
450
451 static OP *a_pp_root_unop(pTHX) {
452  dSP;
453
454  if (a_undef(TOPs)) {
455   (void) POPs;
456   /* Can only be reached by keys or values */
457   if (GIMME_V == G_SCALAR) {
458    dTARGET;
459    PUSHi(0);
460   }
461   RETURN;
462  }
463
464  {
465   dA_MAP_THX;
466   const a_op_info *oi = a_map_fetch(PL_op);
467   return oi->old_pp(aTHX);
468  }
469 }
470
471 static OP *a_pp_root_binop(pTHX) {
472  dSP;
473
474  if (a_undef(TOPm1s)) {
475   (void) POPs;
476   (void) POPs;
477   if (PL_op->op_type == OP_EXISTS)
478    RETPUSHNO;
479   else
480    RETPUSHUNDEF;
481  }
482
483  {
484   dA_MAP_THX;
485   const a_op_info *oi = a_map_fetch(PL_op);
486   return oi->old_pp(aTHX);
487  }
488 }
489
490 #if A_HAS_MULTIDEREF
491
492 /* ... pp_multideref ....................................................... */
493
494 /* This pp replacement is actually only called for topmost exists/delete ops,
495  * because we hijack the [ah]elem check functions and this disables the
496  * optimization for lvalue and rvalue dereferencing. In particular, the
497  * OPf_MOD branches should never be covered. In the future, the multideref
498  * optimization might also be disabled for custom exists/delete check functions,
499  * which will make this section unnecessary. However, the code tries to be as
500  * general as possible in case I think of a way to reenable the multideref
501  * optimization even when this module is in use. */
502
503 static UV a_do_multideref(const OP *o, UV flags) {
504  UV isexdel, other_flags;
505
506  XSH_ASSERT(o->op_type == OP_MULTIDEREF);
507
508  other_flags = flags & ~A_HINT_DO;
509
510  isexdel = o->op_private & (OPpMULTIDEREF_EXISTS|OPpMULTIDEREF_DELETE);
511  if (isexdel) {
512   if (isexdel & OPpMULTIDEREF_EXISTS) {
513    flags &= A_HINT_EXISTS;
514   } else {
515    flags &= A_HINT_DELETE;
516   }
517  } else {
518   if (o->op_flags & OPf_MOD) {
519    flags &= A_HINT_STORE;
520   } else {
521    flags &= A_HINT_FETCH;
522   }
523  }
524
525  return flags ? (flags | other_flags) : 0;
526 }
527
528 static SV *a_do_fake_pp(pTHX_ OP *op) {
529 #define a_do_fake_pp(O) a_do_fake_pp(aTHX_ (O))
530  {
531   OP *o = PL_op;
532   ENTER;
533   SAVEOP();
534   PL_op = op;
535   PL_op->op_ppaddr(aTHX);
536   PL_op = o;
537   LEAVE;
538  }
539
540  {
541   SV *ret;
542   dSP;
543   ret = POPs;
544   PUTBACK;
545   return ret;
546  }
547 }
548
549 static void a_do_fake_pp_unop_init(pTHX_ UNOP *unop, U32 type, U32 flags) {
550 #define a_do_fake_pp_unop_init(O, T, F) a_do_fake_pp_unop_init(aTHX_ (O), (T), (F))
551  unop->op_type    = type;
552  unop->op_flags   = OPf_WANT_SCALAR | (~OPf_WANT & flags);
553  unop->op_private = 0;
554  unop->op_first   = NULL;
555  unop->op_ppaddr  = PL_ppaddr[type];
556 }
557
558 static SV *a_do_fake_pp_unop_arg1(pTHX_ U32 type, U32 flags, SV *arg) {
559 #define a_do_fake_pp_unop_arg1(T, F, A) a_do_fake_pp_unop_arg1(aTHX_ (T), (F), (A))
560  UNOP unop;
561  dSP;
562
563  a_do_fake_pp_unop_init(&unop, type, flags);
564
565  EXTEND(SP, 1);
566  PUSHs(arg);
567  PUTBACK;
568
569  return a_do_fake_pp((OP *) &unop);
570 }
571
572 static SV *a_do_fake_pp_unop_arg2(pTHX_ U32 type, U32 flags, SV *arg1, SV *arg2) {
573 #define a_do_fake_pp_unop_arg2(T, F, A1, A2) a_do_fake_pp_unop_arg2(aTHX_ (T), (F), (A1), (A2))
574  UNOP unop;
575  dSP;
576
577  a_do_fake_pp_unop_init(&unop, type, flags);
578
579  EXTEND(SP, 2);
580  PUSHs(arg1);
581  PUSHs(arg2);
582  PUTBACK;
583
584  return a_do_fake_pp((OP *) &unop);
585 }
586
587 #define a_do_pp_rv2av(R)        a_do_fake_pp_unop_arg1(OP_RV2AV,  OPf_REF,     (R))
588 #define a_do_pp_afetch(A, I)    a_do_fake_pp_unop_arg2(OP_AELEM,  0,           (A), (I))
589 #define a_do_pp_afetch_lv(A, I) a_do_fake_pp_unop_arg2(OP_AELEM,  OPf_MOD,     (A), (I))
590 #define a_do_pp_aexists(A, I)   a_do_fake_pp_unop_arg2(OP_EXISTS, OPf_SPECIAL, (A), (I))
591 #define a_do_pp_adelete(A, I)   a_do_fake_pp_unop_arg2(OP_DELETE, OPf_SPECIAL, (A), (I))
592
593 #define a_do_pp_rv2hv(R)        a_do_fake_pp_unop_arg1(OP_RV2HV,  OPf_REF, (R))
594 #define a_do_pp_hfetch(H, K)    a_do_fake_pp_unop_arg2(OP_HELEM,  0,       (H), (K))
595 #define a_do_pp_hfetch_lv(H, K) a_do_fake_pp_unop_arg2(OP_HELEM,  OPf_MOD, (H), (K))
596 #define a_do_pp_hexists(H, K)   a_do_fake_pp_unop_arg2(OP_EXISTS, 0,  (H), (K))
597 #define a_do_pp_hdelete(H, K)   a_do_fake_pp_unop_arg2(OP_DELETE, 0,  (H), (K))
598
599 static OP *a_pp_multideref(pTHX) {
600  UNOP_AUX_item *items;
601  UV  actions;
602  UV  flags = 0;
603  SV *sv    = NULL;
604  dSP;
605
606  {
607   dA_MAP_THX;
608   const a_op_info *oi = a_map_fetch(PL_op);
609   XSH_ASSERT(oi);
610   flags = a_do_multideref(PL_op, oi->flags);
611   if (!flags)
612    return oi->old_pp(aTHX);
613  }
614
615  items   = cUNOP_AUXx(PL_op)->op_aux;
616  actions = items->uv;
617
618  PL_multideref_pc = items;
619
620  while (1) {
621   switch (actions & MDEREF_ACTION_MASK) {
622    case MDEREF_reload:
623     actions = (++items)->uv;
624     continue;
625    case MDEREF_AV_padav_aelem: /* $lex[...] */
626     sv = PAD_SVl((++items)->pad_offset);
627     if (a_undef(sv))
628      goto ret_undef;
629     goto do_AV_aelem;
630    case MDEREF_AV_gvav_aelem: /* $pkg[...] */
631     sv = UNOP_AUX_item_sv(++items);
632     XSH_ASSERT(isGV_with_GP(sv));
633     sv = (SV *) GvAVn((GV *) sv);
634     if (a_undef(sv))
635      goto ret_undef;
636     goto do_AV_aelem;
637    case MDEREF_AV_pop_rv2av_aelem: /* expr->[...] */
638     sv = POPs;
639     if (a_undef(sv))
640      goto ret_undef;
641     goto do_AV_rv2av_aelem;
642    case MDEREF_AV_gvsv_vivify_rv2av_aelem: /* $pkg->[...] */
643     sv = UNOP_AUX_item_sv(++items);
644     XSH_ASSERT(isGV_with_GP(sv));
645     sv = GvSVn((GV *) sv);
646     if (a_undef(sv))
647      goto ret_undef;
648     goto do_AV_vivify_rv2av_aelem;
649    case MDEREF_AV_padsv_vivify_rv2av_aelem: /* $lex->[...] */
650     sv = PAD_SVl((++items)->pad_offset);
651     /* FALLTHROUGH */
652    case MDEREF_AV_vivify_rv2av_aelem: /* vivify, ->[...] */
653     if (a_undef(sv))
654      goto ret_undef;
655 do_AV_vivify_rv2av_aelem:
656     sv = a_vivify_ref(sv, 0);
657 do_AV_rv2av_aelem:
658     sv = a_do_pp_rv2av(sv);
659 do_AV_aelem:
660     {
661      SV *esv;
662      XSH_ASSERT(SvTYPE(sv) == SVt_PVAV);
663      switch (actions & MDEREF_INDEX_MASK) {
664       case MDEREF_INDEX_none:
665        goto finish;
666       case MDEREF_INDEX_const:
667        esv = sv_2mortal(newSViv((++items)->iv));
668        break;
669       case MDEREF_INDEX_padsv:
670        esv = PAD_SVl((++items)->pad_offset);
671        goto check_elem;
672       case MDEREF_INDEX_gvsv:
673        esv = UNOP_AUX_item_sv(++items);
674        XSH_ASSERT(isGV_with_GP(esv));
675        esv = GvSVn((GV *) esv);
676 check_elem:
677        if (UNLIKELY(SvROK(esv) && !SvGAMAGIC(esv) && ckWARN(WARN_MISC)))
678         Perl_warner(aTHX_ packWARN(WARN_MISC),
679                           "Use of reference \"%"SVf"\" as array index",
680                           SVfARG(esv));
681        break;
682      }
683      PL_multideref_pc = items;
684      if (actions & MDEREF_FLAG_last) {
685       switch (flags & A_HINT_DO) {
686        case A_HINT_FETCH:
687         sv = a_do_pp_afetch(sv, esv);
688         break;
689        case A_HINT_STORE:
690         sv = a_do_pp_afetch_lv(sv, esv);
691         break;
692        case A_HINT_EXISTS:
693         sv = a_do_pp_aexists(sv, esv);
694         break;
695        case A_HINT_DELETE:
696         sv = a_do_pp_adelete(sv, esv);
697         break;
698       }
699       goto finish;
700      }
701      sv = a_do_pp_afetch(sv, esv);
702      break;
703     }
704    case MDEREF_HV_padhv_helem: /* $lex{...} */
705     sv = PAD_SVl((++items)->pad_offset);
706     if (a_undef(sv))
707      goto ret_undef;
708     goto do_HV_helem;
709    case MDEREF_HV_gvhv_helem: /* $pkg{...} */
710     sv = UNOP_AUX_item_sv(++items);
711     XSH_ASSERT(isGV_with_GP(sv));
712     sv = (SV *) GvHVn((GV *) sv);
713     if (a_undef(sv))
714      goto ret_undef;
715     goto do_HV_helem;
716    case MDEREF_HV_pop_rv2hv_helem: /* expr->{...} */
717     sv = POPs;
718     if (a_undef(sv))
719      goto ret_undef;
720     goto do_HV_rv2hv_helem;
721    case MDEREF_HV_gvsv_vivify_rv2hv_helem: /* $pkg->{...} */
722     sv = UNOP_AUX_item_sv(++items);
723     XSH_ASSERT(isGV_with_GP(sv));
724     sv = GvSVn((GV *) sv);
725     if (a_undef(sv))
726      goto ret_undef;
727     goto do_HV_vivify_rv2hv_helem;
728    case MDEREF_HV_padsv_vivify_rv2hv_helem: /* $lex->{...} */
729     sv = PAD_SVl((++items)->pad_offset);
730     /* FALLTHROUGH */
731    case MDEREF_HV_vivify_rv2hv_helem: /* vivify, ->{...} */
732     if (a_undef(sv))
733      goto ret_undef;
734 do_HV_vivify_rv2hv_helem:
735     sv = a_vivify_ref(sv, 1);
736 do_HV_rv2hv_helem:
737     sv = a_do_pp_rv2hv(sv);
738 do_HV_helem:
739     {
740      SV *key;
741      XSH_ASSERT(SvTYPE(sv) == SVt_PVHV);
742      switch (actions & MDEREF_INDEX_MASK) {
743       case MDEREF_INDEX_none:
744        goto finish;
745       case MDEREF_INDEX_const:
746        key = UNOP_AUX_item_sv(++items);
747        break;
748       case MDEREF_INDEX_padsv:
749        key = PAD_SVl((++items)->pad_offset);
750        break;
751       case MDEREF_INDEX_gvsv:
752        key = UNOP_AUX_item_sv(++items);
753        XSH_ASSERT(isGV_with_GP(key));
754        key = GvSVn((GV *) key);
755        break;
756      }
757      PL_multideref_pc = items;
758      if (actions & MDEREF_FLAG_last) {
759       switch (flags & A_HINT_DO) {
760        case A_HINT_FETCH:
761         sv = a_do_pp_hfetch(sv, key);
762         break;
763        case A_HINT_STORE:
764         sv = a_do_pp_hfetch_lv(sv, key);
765         break;
766        case A_HINT_EXISTS:
767         sv = a_do_pp_hexists(sv, key);
768         break;
769        case A_HINT_DELETE:
770         sv = a_do_pp_hdelete(sv, key);
771         break;
772        default:
773         break;
774       }
775       goto finish;
776      }
777      sv = a_do_pp_hfetch(sv, key);
778      break;
779     }
780   }
781
782   actions >>= MDEREF_SHIFT;
783  }
784
785 ret_undef:
786  if (flags & (A_HINT_NOTIFY|A_HINT_STORE))
787   a_cannot_vivify(flags);
788  if (flags & A_HINT_EXISTS)
789   sv = &PL_sv_no;
790  else
791   sv = &PL_sv_undef;
792 finish:
793  XPUSHs(sv);
794  RETURN;
795 }
796
797 #endif /* A_HAS_MULTIDEREF */
798
799 /* --- Check functions ----------------------------------------------------- */
800
801 static void a_recheck_rv2xv(pTHX_ OP *o, OPCODE type, OP *(*new_pp)(pTHX)) {
802 #define a_recheck_rv2xv(O, T, PP) a_recheck_rv2xv(aTHX_ (O), (T), (PP))
803
804  if (o->op_type == type && o->op_ppaddr != new_pp
805                         && cUNOPo->op_first->op_type != OP_GV) {
806   dA_MAP_THX;
807   const a_op_info *oi = a_map_fetch(o);
808   if (oi) {
809    a_map_store(o, o->op_ppaddr, oi->next, oi->flags);
810    o->op_ppaddr = new_pp;
811   }
812  }
813
814  return;
815 }
816
817 /* ... ck_pad{any,sv} ...................................................... */
818
819 /* Sadly, the padsv OPs we are interested in don't trigger the padsv check
820  * function, but are instead manually mutated from a padany. So we store
821  * the op entry in the op map in the padany check function, and we set their
822  * op_ppaddr member in our peephole optimizer replacement below. */
823
824 static OP *(*a_old_ck_padany)(pTHX_ OP *) = 0;
825
826 static OP *a_ck_padany(pTHX_ OP *o) {
827  UV hint;
828
829  o = a_old_ck_padany(aTHX_ o);
830
831  hint = a_hint();
832  if (hint & A_HINT_DO)
833   a_map_store_root(o, o->op_ppaddr, hint);
834  else
835   a_map_delete(o);
836
837  return o;
838 }
839
840 static OP *(*a_old_ck_padsv)(pTHX_ OP *) = 0;
841
842 static OP *a_ck_padsv(pTHX_ OP *o) {
843  UV hint;
844
845  o = a_old_ck_padsv(aTHX_ o);
846
847  hint = a_hint();
848  if (hint & A_HINT_DO) {
849   a_map_store_root(o, o->op_ppaddr, hint);
850   o->op_ppaddr = a_pp_deref;
851  } else
852   a_map_delete(o);
853
854  return o;
855 }
856
857 /* ... ck_deref (aelem,helem,rv2sv) ........................................ */
858
859 /* Those ops appear both at the root and inside an expression but there's no
860  * way to distinguish both situations. Worse, we can't even know if we are in a
861  * modifying context, so the expression can't be resolved yet. It will be at the
862  * first invocation of a_pp_deref() for this expression. */
863
864 static OP *(*a_old_ck_aelem)(pTHX_ OP *) = 0;
865 static OP *(*a_old_ck_helem)(pTHX_ OP *) = 0;
866 static OP *(*a_old_ck_rv2sv)(pTHX_ OP *) = 0;
867
868 static OP *a_ck_deref(pTHX_ OP *o) {
869  OP * (*old_ck)(pTHX_ OP *o) = 0;
870  UV hint = a_hint();
871
872  switch (o->op_type) {
873   case OP_AELEM:
874    old_ck = a_old_ck_aelem;
875    if ((hint & A_HINT_DO) && !(hint & A_HINT_STRICT))
876     a_recheck_rv2xv(cUNOPo->op_first, OP_RV2AV, a_pp_rv2av);
877    break;
878   case OP_HELEM:
879    old_ck = a_old_ck_helem;
880    if ((hint & A_HINT_DO) && !(hint & A_HINT_STRICT))
881     a_recheck_rv2xv(cUNOPo->op_first, OP_RV2HV, a_pp_rv2hv_simple);
882    break;
883   case OP_RV2SV:
884    old_ck = a_old_ck_rv2sv;
885    break;
886  }
887  o = old_ck(aTHX_ o);
888
889 #if A_HAS_MULTIDEREF
890  if (old_ck == a_old_ck_rv2sv && o->op_flags & OPf_KIDS) {
891   OP *kid = cUNOPo->op_first;
892   if (kid && kid->op_type == OP_GV) {
893    if (hint & A_HINT_DO)
894     a_map_store(kid, kid->op_ppaddr, NULL, hint);
895    else
896     a_map_delete(kid);
897   }
898  }
899 #endif
900
901  if (hint & A_HINT_DO) {
902   a_map_store_root(o, o->op_ppaddr, hint);
903   o->op_ppaddr = a_pp_deref;
904  } else
905   a_map_delete(o);
906
907  return o;
908 }
909
910 /* ... ck_rv2xv (rv2av,rv2hv) .............................................. */
911
912 /* Those ops also appear both inisde and at the root, hence the caveats for
913  * a_ck_deref() still apply here. Since a padsv/rv2sv must appear before a
914  * rv2[ah]v, resolution is handled by the first call to a_pp_deref() in the
915  * expression. */
916
917 static OP *(*a_old_ck_rv2av)(pTHX_ OP *) = 0;
918 static OP *(*a_old_ck_rv2hv)(pTHX_ OP *) = 0;
919
920 static OP *a_ck_rv2xv(pTHX_ OP *o) {
921  OP * (*old_ck)(pTHX_ OP *o) = 0;
922  OP * (*new_pp)(pTHX)        = 0;
923  UV hint;
924
925  switch (o->op_type) {
926   case OP_RV2AV: old_ck = a_old_ck_rv2av; new_pp = a_pp_rv2av; break;
927   case OP_RV2HV: old_ck = a_old_ck_rv2hv; new_pp = a_pp_rv2hv_simple; break;
928  }
929  o = old_ck(aTHX_ o);
930
931  if (cUNOPo->op_first->op_type == OP_GV)
932   return o;
933
934  hint = a_hint();
935  if (hint & A_HINT_DO && !(hint & A_HINT_STRICT)) {
936   a_map_store_root(o, o->op_ppaddr, hint);
937   o->op_ppaddr = new_pp;
938  } else
939   a_map_delete(o);
940
941  return o;
942 }
943
944 /* ... ck_xslice (aslice,hslice) ........................................... */
945
946 /* I think those are only found at the root, but there's nothing that really
947  * prevent them to be inside the expression too. We only need to update the
948  * root so that the rest of the expression will see the right context when
949  * resolving. That's why we don't replace the ppaddr. */
950
951 static OP *(*a_old_ck_aslice)(pTHX_ OP *) = 0;
952 static OP *(*a_old_ck_hslice)(pTHX_ OP *) = 0;
953
954 static OP *a_ck_xslice(pTHX_ OP *o) {
955  OP * (*old_ck)(pTHX_ OP *o) = 0;
956  UV hint = a_hint();
957
958  switch (o->op_type) {
959   case OP_ASLICE:
960    old_ck = a_old_ck_aslice;
961    break;
962   case OP_HSLICE:
963    old_ck = a_old_ck_hslice;
964    if (hint & A_HINT_DO)
965     a_recheck_rv2xv(OpSIBLING(cUNOPo->op_first), OP_RV2HV, a_pp_rv2hv);
966    break;
967  }
968  o = old_ck(aTHX_ o);
969
970  if (hint & A_HINT_DO) {
971   a_map_store_root(o, 0, hint);
972  } else
973   a_map_delete(o);
974
975  return o;
976 }
977
978 /* ... ck_root (exists,delete,keys,values) ................................. */
979
980 /* Those ops are only found at the root of a dereferencing expression. We can
981  * then resolve at compile time if vivification must take place or not. */
982
983 static OP *(*a_old_ck_exists)(pTHX_ OP *) = 0;
984 static OP *(*a_old_ck_delete)(pTHX_ OP *) = 0;
985 static OP *(*a_old_ck_keys)  (pTHX_ OP *) = 0;
986 static OP *(*a_old_ck_values)(pTHX_ OP *) = 0;
987
988 static OP *a_ck_root(pTHX_ OP *o) {
989  OP * (*old_ck)(pTHX_ OP *o) = 0;
990  OP * (*new_pp)(pTHX)        = 0;
991  int enabled = 0;
992  UV hint = a_hint();
993
994  switch (o->op_type) {
995   case OP_EXISTS:
996    old_ck  = a_old_ck_exists;
997    new_pp  = a_pp_root_binop;
998    enabled = hint & A_HINT_EXISTS;
999    break;
1000   case OP_DELETE:
1001    old_ck  = a_old_ck_delete;
1002    new_pp  = a_pp_root_binop;
1003    enabled = hint & A_HINT_DELETE;
1004    break;
1005   case OP_KEYS:
1006    old_ck  = a_old_ck_keys;
1007    new_pp  = a_pp_root_unop;
1008    enabled = hint & A_HINT_KEYS;
1009    break;
1010   case OP_VALUES:
1011    old_ck  = a_old_ck_values;
1012    new_pp  = a_pp_root_unop;
1013    enabled = hint & A_HINT_VALUES;
1014    break;
1015  }
1016  o = old_ck(aTHX_ o);
1017
1018  if (hint & A_HINT_DO) {
1019   if (enabled) {
1020    a_map_update_flags_topdown(o, hint | A_HINT_DEREF);
1021    a_map_store_root(o, o->op_ppaddr, hint);
1022    o->op_ppaddr = new_pp;
1023   } else {
1024    a_map_cancel(o);
1025   }
1026  } else
1027   a_map_delete(o);
1028
1029  return o;
1030 }
1031
1032 /* --- Our peephole optimizer ---------------------------------------------- */
1033
1034 static void xsh_peep_rec(pTHX_ OP *o, ptable *seen) {
1035  for (; o; o = o->op_next) {
1036   dA_MAP_THX;
1037   const a_op_info *oi = NULL;
1038   UV flags = 0;
1039
1040   if (xsh_peep_seen(o, seen))
1041    break;
1042
1043   switch (o->op_type) {
1044    case OP_PADSV:
1045     if (o->op_ppaddr != a_pp_deref) {
1046      oi = a_map_fetch(o);
1047      if (oi && (oi->flags & A_HINT_DO)) {
1048       a_map_store(o, o->op_ppaddr, oi->next, oi->flags);
1049       o->op_ppaddr = a_pp_deref;
1050      }
1051     }
1052     /* FALLTHROUGH */
1053    case OP_AELEM:
1054    case OP_AELEMFAST:
1055    case OP_HELEM:
1056    case OP_RV2SV:
1057     if (o->op_ppaddr != a_pp_deref)
1058      break;
1059     oi = a_map_fetch(o);
1060     if (!oi)
1061      break;
1062     flags = oi->flags;
1063     if (!(flags & A_HINT_DEREF)
1064         && (flags & A_HINT_DO)
1065         && (o->op_private & OPpDEREF || flags & A_HINT_ROOT)) {
1066      /* Decide if the expression must autovivify or not. */
1067      flags = a_map_resolve(o, oi);
1068     }
1069     if (flags & A_HINT_DEREF)
1070      o->op_private = ((o->op_private & ~OPpDEREF) | OPpLVAL_DEFER);
1071     else
1072      o->op_ppaddr  = oi->old_pp;
1073     break;
1074    case OP_RV2AV:
1075    case OP_RV2HV:
1076     if (   o->op_ppaddr != a_pp_rv2av
1077         && o->op_ppaddr != a_pp_rv2hv
1078         && o->op_ppaddr != a_pp_rv2hv_simple)
1079      break;
1080     oi = a_map_fetch(o);
1081     if (!oi)
1082      break;
1083     if (!(oi->flags & A_HINT_DEREF))
1084      o->op_ppaddr  = oi->old_pp;
1085     break;
1086 #if A_HAS_MULTIDEREF
1087    case OP_MULTIDEREF:
1088     if (o->op_ppaddr != a_pp_multideref) {
1089      oi = a_map_fetch(cUNOPo->op_first);
1090      if (!oi)
1091       break;
1092      flags = oi->flags;
1093      if (a_do_multideref(o, flags)) {
1094       a_map_store_root(o, o->op_ppaddr, flags & ~A_HINT_DEREF);
1095       o->op_ppaddr = a_pp_multideref;
1096      }
1097     }
1098     break;
1099 #endif
1100    default:
1101     xsh_peep_maybe_recurse(o, seen);
1102     break;
1103   }
1104  }
1105 }
1106
1107 /* --- Module setup/teardown ----------------------------------------------- */
1108
1109 static void xsh_user_global_setup(pTHX) {
1110  a_op_map = ptable_new(32);
1111
1112 #ifdef USE_ITHREADS
1113  MUTEX_INIT(&a_op_map_mutex);
1114 #endif
1115
1116  xsh_ck_replace(OP_PADANY, a_ck_padany, &a_old_ck_padany);
1117  xsh_ck_replace(OP_PADSV,  a_ck_padsv,  &a_old_ck_padsv);
1118
1119  xsh_ck_replace(OP_AELEM,  a_ck_deref,  &a_old_ck_aelem);
1120  xsh_ck_replace(OP_HELEM,  a_ck_deref,  &a_old_ck_helem);
1121  xsh_ck_replace(OP_RV2SV,  a_ck_deref,  &a_old_ck_rv2sv);
1122
1123  xsh_ck_replace(OP_RV2AV,  a_ck_rv2xv,  &a_old_ck_rv2av);
1124  xsh_ck_replace(OP_RV2HV,  a_ck_rv2xv,  &a_old_ck_rv2hv);
1125
1126  xsh_ck_replace(OP_ASLICE, a_ck_xslice, &a_old_ck_aslice);
1127  xsh_ck_replace(OP_HSLICE, a_ck_xslice, &a_old_ck_hslice);
1128
1129  xsh_ck_replace(OP_EXISTS, a_ck_root,   &a_old_ck_exists);
1130  xsh_ck_replace(OP_DELETE, a_ck_root,   &a_old_ck_delete);
1131  xsh_ck_replace(OP_KEYS,   a_ck_root,   &a_old_ck_keys);
1132  xsh_ck_replace(OP_VALUES, a_ck_root,   &a_old_ck_values);
1133
1134  return;
1135 }
1136
1137 static void xsh_user_local_setup(pTHX) {
1138  HV *stash;
1139
1140  stash = gv_stashpvn(XSH_PACKAGE, XSH_PACKAGE_LEN, 1);
1141  newCONSTSUB(stash, "A_HINT_STRICT", newSVuv(A_HINT_STRICT));
1142  newCONSTSUB(stash, "A_HINT_WARN",   newSVuv(A_HINT_WARN));
1143  newCONSTSUB(stash, "A_HINT_FETCH",  newSVuv(A_HINT_FETCH));
1144  newCONSTSUB(stash, "A_HINT_STORE",  newSVuv(A_HINT_STORE));
1145  newCONSTSUB(stash, "A_HINT_KEYS",   newSVuv(A_HINT_KEYS));
1146  newCONSTSUB(stash, "A_HINT_VALUES", newSVuv(A_HINT_VALUES));
1147  newCONSTSUB(stash, "A_HINT_EXISTS", newSVuv(A_HINT_EXISTS));
1148  newCONSTSUB(stash, "A_HINT_DELETE", newSVuv(A_HINT_DELETE));
1149  newCONSTSUB(stash, "A_HINT_MASK",   newSVuv(A_HINT_MASK));
1150  newCONSTSUB(stash, "A_THREADSAFE",  newSVuv(XSH_THREADSAFE));
1151  newCONSTSUB(stash, "A_FORKSAFE",    newSVuv(XSH_FORKSAFE));
1152
1153  return;
1154 }
1155
1156 static void xsh_user_local_teardown(pTHX) {
1157  return;
1158 }
1159
1160 static void xsh_user_global_teardown(pTHX) {
1161  xsh_ck_restore(OP_PADANY, &a_old_ck_padany);
1162  xsh_ck_restore(OP_PADSV,  &a_old_ck_padsv);
1163
1164  xsh_ck_restore(OP_AELEM,  &a_old_ck_aelem);
1165  xsh_ck_restore(OP_HELEM,  &a_old_ck_helem);
1166  xsh_ck_restore(OP_RV2SV,  &a_old_ck_rv2sv);
1167
1168  xsh_ck_restore(OP_RV2AV,  &a_old_ck_rv2av);
1169  xsh_ck_restore(OP_RV2HV,  &a_old_ck_rv2hv);
1170
1171  xsh_ck_restore(OP_ASLICE, &a_old_ck_aslice);
1172  xsh_ck_restore(OP_HSLICE, &a_old_ck_hslice);
1173
1174  xsh_ck_restore(OP_EXISTS, &a_old_ck_exists);
1175  xsh_ck_restore(OP_DELETE, &a_old_ck_delete);
1176  xsh_ck_restore(OP_KEYS,   &a_old_ck_keys);
1177  xsh_ck_restore(OP_VALUES, &a_old_ck_values);
1178
1179  ptable_map_free(a_op_map);
1180  a_op_map = NULL;
1181
1182 #ifdef USE_ITHREADS
1183  MUTEX_DESTROY(&a_op_map_mutex);
1184 #endif
1185
1186  return;
1187 }
1188
1189 /* --- XS ------------------------------------------------------------------ */
1190
1191 MODULE = autovivification      PACKAGE = autovivification
1192
1193 PROTOTYPES: ENABLE
1194
1195 BOOT:
1196 {
1197  xsh_setup();
1198 }
1199
1200 #if XSH_THREADSAFE
1201
1202 void
1203 CLONE(...)
1204 PROTOTYPE: DISABLE
1205 PPCODE:
1206  xsh_clone();
1207  XSRETURN(0);
1208
1209 #endif /* XSH_THREADSAFE */
1210
1211 SV *
1212 _tag(SV *hint)
1213 PROTOTYPE: $
1214 CODE:
1215  RETVAL = xsh_hints_tag(SvOK(hint) ? SvUV(hint) : 0);
1216 OUTPUT:
1217  RETVAL
1218
1219 SV *
1220 _detag(SV *tag)
1221 PROTOTYPE: $
1222 CODE:
1223  if (!SvOK(tag))
1224   XSRETURN_UNDEF;
1225  RETVAL = newSVuv(xsh_hints_detag(tag));
1226 OUTPUT:
1227  RETVAL