File Coverage

autovivification.xs
Criterion Covered Total %
statement 355 556 63.8
branch 156 310 50.3
condition n/a
subroutine n/a
pod n/a
total 511 866 59.0


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