1 #ifndef XSH_PEEP_H
2 #define XSH_PEEP_H 1
3 
4 #include "caps.h" /* XSH_HAS_PERL(), XSH_THREADSAFE */
5 #include "util.h" /* XSH_ASSERT(), NOOP */
6 
7 #ifdef XSH_THREADS_H
8 # error threads.h must be loaded at the very end
9 #endif
10 
11 #ifndef XSH_HAS_RPEEP
12 # define XSH_HAS_RPEEP XSH_HAS_PERL(5, 13, 5)
13 #endif
14 
15 #define PTABLE_USE_DEFAULT 1
16 #define PTABLE_NEED_DELETE 0
17 
18 #include "ptable.h"
19 
20 #define ptable_seen_store(T, K, V) ptable_default_store(aPTBL_ (T), (K), (V))
21 #define ptable_seen_clear(T)       ptable_default_clear(aPTBL_ (T))
22 #define ptable_seen_free(T)        ptable_default_free(aPTBL_ (T))
23 
24 #define XSH_THREADS_PEEP_CONTEXT 1
25 
26 typedef struct {
27 #if XSH_HAS_RPEEP
28  peep_t  old_rpeep;
29 #else
30  peep_t  old_peep;
31 #endif
32  ptable *seen;
33 } xsh_peep_cxt_t;
34 
35 static xsh_peep_cxt_t *xsh_peep_get_cxt(pTHX);
36 
37 static void xsh_peep_rec(pTHX_ OP *o, ptable *seen);
38 
39 #if XSH_HAS_RPEEP
40 
xsh_rpeep(pTHX_ OP * o)41 static void xsh_rpeep(pTHX_ OP *o) {
42  ptable         *seen;
43  xsh_peep_cxt_t *cxt = xsh_peep_get_cxt(aTHX);
44 
45  cxt->old_rpeep(aTHX_ o);
46 
47  seen = cxt->seen;
48  XSH_ASSERT(seen);
49 
50  ptable_seen_clear(seen);
51 
52  xsh_peep_rec(aTHX_ o, seen);
53 
54  ptable_seen_clear(seen);
55 
56  return;
57 }
58 
59 #define xsh_peep_maybe_recurse(O, S) NOOP
60 
61 #else  /*  XSH_HAS_RPEEP */
62 
xsh_peep(pTHX_ OP * o)63 static void xsh_peep(pTHX_ OP *o) {
64  ptable         *seen;
65  xsh_peep_cxt_t *cxt = xsh_peep_get_cxt(aTHX);
66 
67  cxt->old_peep(aTHX_ o); /* Will call the rpeep */
68 
69  seen = cxt->seen;
70  XSH_ASSERT(seen);
71 
72  ptable_seen_clear(seen);
73 
74  xsh_peep_rec(aTHX_ o, seen);
75 
76  ptable_seen_clear(seen);
77 
78  return;
79 }
80 
xsh_peep_maybe_recurse(pTHX_ OP * o,ptable * seen)81 static void xsh_peep_maybe_recurse(pTHX_ OP *o, ptable *seen) {
82 #define xsh_peep_maybe_recurse(O, S) xsh_peep_maybe_recurse(aTHX_ (O), (S))
83  switch (o->op_type) {
84   case OP_MAPWHILE:
85   case OP_GREPWHILE:
86   case OP_AND:
87   case OP_OR:
88   case OP_ANDASSIGN:
89   case OP_ORASSIGN:
90   case OP_COND_EXPR:
91   case OP_RANGE:
92 #if XSH_HAS_PERL(5, 10, 0)
93   case OP_ONCE:
94   case OP_DOR:
95   case OP_DORASSIGN:
96 #endif
97    xsh_peep_rec(aTHX_ cLOGOPo->op_other, seen);
98    break;
99   case OP_ENTERLOOP:
100   case OP_ENTERITER:
101    xsh_peep_rec(aTHX_ cLOOPo->op_redoop, seen);
102    xsh_peep_rec(aTHX_ cLOOPo->op_nextop, seen);
103    xsh_peep_rec(aTHX_ cLOOPo->op_lastop, seen);
104    break;
105 #if XSH_HAS_PERL(5, 9, 5)
106   case OP_SUBST:
107    xsh_peep_rec(aTHX_ cPMOPo->op_pmstashstartu.op_pmreplstart, seen);
108    break;
109 #else
110   case OP_QR:
111   case OP_MATCH:
112   case OP_SUBST:
113    xsh_peep_rec(aTHX_ cPMOPo->op_pmreplstart, seen);
114    break;
115 #endif
116  }
117 
118  return;
119 }
120 
121 #endif /* !XSH_HAS_RPEEP */
122 
xsh_peep_seen(pTHX_ OP * o,ptable * seen)123 static int xsh_peep_seen(pTHX_ OP *o, ptable *seen) {
124 #define xsh_peep_seen(O, S) xsh_peep_seen(aTHX_ (O), (S))
125 #if XSH_HAS_RPEEP
126  switch (o->op_type) {
127   case OP_NEXTSTATE:
128   case OP_DBSTATE:
129   case OP_UNSTACK:
130   case OP_STUB:
131    break;
132   default:
133    return 0;
134  }
135 #endif /* XSH_HAS_RPEEP */
136 
137  if (ptable_fetch(seen, o))
138   return 1;
139 
140  ptable_seen_store(seen, o, o);
141 
142  return 0;
143 }
144 
xsh_peep_local_setup(pTHX_ xsh_peep_cxt_t * cxt)145 static void xsh_peep_local_setup(pTHX_ xsh_peep_cxt_t *cxt) {
146 #if XSH_HAS_RPEEP
147  if (PL_rpeepp != xsh_rpeep) {
148   cxt->old_rpeep = PL_rpeepp;
149   PL_rpeepp      = xsh_rpeep;
150  } else {
151   cxt->old_rpeep = 0;
152  }
153 #else
154  if (PL_peepp != xsh_peep) {
155   cxt->old_peep = PL_peepp;
156   PL_peepp      = xsh_peep;
157  } else {
158   cxt->old_peep = 0;
159  }
160 #endif
161 
162  cxt->seen = ptable_new(32);
163 }
164 
xsh_peep_local_teardown(pTHX_ xsh_peep_cxt_t * cxt)165 static void xsh_peep_local_teardown(pTHX_ xsh_peep_cxt_t *cxt) {
166  ptable_seen_free(cxt->seen);
167  cxt->seen = NULL;
168 
169 #if XSH_HAS_RPEEP
170  if (cxt->old_rpeep) {
171   PL_rpeepp      = cxt->old_rpeep;
172   cxt->old_rpeep = 0;
173  }
174 #else
175  if (cxt->old_peep) {
176   PL_peepp      = cxt->old_peep;
177   cxt->old_peep = 0;
178  }
179 #endif
180 
181  return;
182 }
183 
xsh_peep_clone(pTHX_ const xsh_peep_cxt_t * old_cxt,xsh_peep_cxt_t * new_cxt)184 static void xsh_peep_clone(pTHX_ const xsh_peep_cxt_t *old_cxt, xsh_peep_cxt_t *new_cxt) {
185  new_cxt->seen = ptable_new(32);
186 
187  return;
188 }
189 
190 #endif /* XSH_PEEP_H */
191