File Coverage

Deep.xs
Criterion Covered Total %
statement 108 130 83.0
branch 56 94 59.5
condition n/a
subroutine n/a
pod n/a
total 164 224 73.2


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT
2             #include "EXTERN.h"
3             #include "perl.h"
4             #include "XSUB.h"
5              
6             #include "ppport.h"
7              
8             #include "const-c.inc"
9              
10             #define PERL_VERSION_DECIMAL(r,v,s) (r*1000000 + v*1000 + s)
11             #define PERL_DECIMAL_VERSION PERL_VERSION_DECIMAL(PERL_REVISION,PERL_VERSION,PERL_SUBVERSION)
12             #define PERL_VERSION_GE(r,v,s) (PERL_DECIMAL_VERSION >= PERL_VERSION_DECIMAL(r,v,s))
13              
14             #ifndef G_WANT
15             #define G_WANT (G_VOID|G_SCALAR|G_ARRAY)
16             #endif
17              
18             struct block_symbol_t {
19             CV * cv;
20             SV * symbol_SV;
21             };
22              
23             static Perl_ppaddr_t return_ppaddr;
24             static struct block_symbol_t * block_symbols;
25             static int block_symbols_capacity, block_symbols_n;
26              
27             static SV * regex_match_sv;
28              
29 5           static OP * my_pp_deep_ret(pTHX){
30 5           dSP; POPs;
31              
32 5 50         IV depth = SvIV(PL_stack_base[TOPMARK+1]);
33              
34 20 100         for(SV ** p = PL_stack_base+TOPMARK+1; p
35 15           *p = *(p+1);
36 5           POPs;
37              
38 5 100         if( depth <= 0 )
39 1           RETURN;
40              
41             OP * next_op;
42 14 100         while( depth-- )
43 10           next_op = return_ppaddr(aTHX);
44 4           RETURNOP(next_op);
45             }
46              
47 8           static OP * my_pp_sym_ret(pTHX){
48 8           dSP; POPs;
49              
50 8           SV * symbol_SV = PL_stack_base[TOPMARK+1];
51              
52 32 100         for(SV ** p = PL_stack_base+TOPMARK+1; p
53 24           *p = *(p+1);
54 8           POPs;
55              
56             while(TRUE){
57 56 50         for(PERL_CONTEXT * cx = &cxstack[cxstack_ix]; cx>=cxstack; --cx){
58 56           switch( CxTYPE(cx) ){
59             default:
60 0           continue;
61             case CXt_SUB:
62             #if PERL_VERSION_GE(5,18,0)
63 56 50         if( cx->cx_type & CXp_SUB_RE_FAKE )
64 0           continue;
65             #endif
66 193 100         for(struct block_symbol_t *p = block_symbols+block_symbols_n-1; p>=block_symbols; --p)
67 145 100         if( p->cv == cx->blk_sub.cv ){
68 24 100         if( !SvOK(p->symbol_SV) )
    50          
    50          
69 4           RETURNOP(return_ppaddr(aTHX));
70             #if PERL_VERSION_GE(5,10,0)
71 20 100         if( SvRXOK(p->symbol_SV) ){
72 7 50         PUSHMARK(SP);
73 7 50         EXTEND(SP, 2);
74 7           PUSHs(p->symbol_SV);
75 7           PUSHs(symbol_SV);
76 7           PUTBACK;
77 7           call_sv(regex_match_sv, G_SCALAR);
78 7           SPAGAIN;
79 7 50         IV match_res = POPi;
80 7           PUTBACK;
81              
82 7 100         if( match_res )
83 7           RETURNOP(return_ppaddr(aTHX));
84             }
85             else
86             #endif
87 13 100         if( sv_cmp(p->symbol_SV, symbol_SV)==0 )
88 2           RETURNOP(return_ppaddr(aTHX));
89             }
90             case CXt_EVAL:
91             case CXt_FORMAT:
92 48           goto DO_RETURN;
93             }
94             }
95             DO_RETURN:
96 48           return_ppaddr(aTHX);
97 48           }
98             }
99              
100 1           static OP * deep_ret_check(pTHX_ OP * o, GV * namegv, SV * ckobj){
101 1           o->op_ppaddr = my_pp_deep_ret;
102 1           return o;
103             }
104              
105 1           static OP * sym_ret_check(pTHX_ OP * o, GV * namegv, SV * ckobj){
106 1           o->op_ppaddr = my_pp_sym_ret;
107 1           return o;
108             }
109              
110 35           static int guard_free(pTHX_ SV * guard_SV, MAGIC * mg){
111 35 50         for(struct block_symbol_t * p=block_symbols+block_symbols_n-1; p>=block_symbols; --p)
112 35 50         if( (IV)p->cv == (IV)mg->mg_ptr ){
113 35           --block_symbols_n;
114 35           *p = block_symbols[block_symbols_n];
115 35           break;
116             }
117 35           return 0;
118             }
119              
120             static MGVTBL guard_vtbl = {
121             0, 0, 0, 0,
122             guard_free
123             };
124              
125             #if !PERL_VERSION_GE(5,14,0)
126             static CV* my_deep_ret_cv;
127             static CV* my_sym_ret_cv;
128             static OP* (*orig_entersub_check)(pTHX_ OP*);
129             static OP* my_entersub_check(pTHX_ OP* o){
130             CV *cv = NULL;
131             OP *cvop = OpSIBLING(((OpSIBLING(cUNOPo->op_first)) ? cUNOPo : ((UNOP*)cUNOPo->op_first))->op_first);
132             while( OpSIBLING(cvop) )
133             cvop = OpSIBLING(cvop);
134             if( cvop->op_type == OP_RV2CV && !(o->op_private & OPpENTERSUB_AMPER) ){
135             SVOP *tmpop = (SVOP*)((UNOP*)cvop)->op_first;
136             switch (tmpop->op_type) {
137             case OP_GV: {
138             GV *gv = cGVOPx_gv(tmpop);
139             cv = GvCVu(gv);
140             if (!cv)
141             tmpop->op_private |= OPpEARLY_CV;
142             } break;
143             case OP_CONST: {
144             SV *sv = cSVOPx_sv(tmpop);
145             if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVCV)
146             cv = (CV*)SvRV(sv);
147             } break;
148             }
149             if( cv==my_deep_ret_cv )
150             o->op_ppaddr = my_pp_deep_ret;
151             if( cv==my_sym_ret_cv )
152             o->op_ppaddr = my_pp_sym_ret;
153             }
154             return orig_entersub_check(aTHX_ o);
155             }
156             #endif
157              
158             MODULE = Return::Deep PACKAGE = Return::Deep
159              
160             INCLUDE: const-xs.inc
161              
162             void add_bound(SV * act_SV, SV * symbol_SV)
163             PPCODE:
164 35 50         if( !(SvOK(act_SV) && SvROK(act_SV) && SvTYPE(SvRV(act_SV))==SVt_PVCV) )
    0          
    0          
    50          
    50          
165 0           croak("there should be a code block");
166              
167 35           CV * act_CV = (CV*) SvRV(act_SV);
168 35           SV * guard_SV = newSV(0);
169              
170 35           sv_magicext(guard_SV, NULL, PERL_MAGIC_ext, &guard_vtbl, (char*) act_CV, 0);
171              
172 35 50         if( block_symbols_n >= block_symbols_capacity ){
173 0           block_symbols_capacity *= 2;
174 0 0         Renew(block_symbols, block_symbols_capacity, struct block_symbol_t);
175             }
176 35           block_symbols[block_symbols_n].cv = act_CV;
177 35           block_symbols[block_symbols_n].symbol_SV = symbol_SV;
178 35           ++block_symbols_n;
179              
180 35           PUSHs(sv_2mortal(newRV_noinc(guard_SV)));
181              
182             void deep_wantarray(IV depth)
183             PPCODE:
184 12 50         if( depth<1 )
185 0           croak("deep_wantarray with non-positive depth");
186              
187 12           PERL_CONTEXT * cx = &cxstack[cxstack_ix];
188 79 100         for(; cx>=cxstack; --cx)
189 77           switch( CxTYPE(cx) ){
190             default:
191 2           continue;
192             case CXt_SUB:
193             #if PERL_VERSION_GE(5,18,0)
194 75 50         if( cx->cx_type & CXp_SUB_RE_FAKE )
195 0           continue;
196             #endif
197             case CXt_EVAL:
198             case CXt_FORMAT:
199 75 100         if( --depth <= 0 )
200 10           goto FOUND;
201             }
202             FOUND:
203              
204 12 100         if( cx
205 2           PUSHs(&PL_sv_undef);
206             else
207 10           switch(cx->blk_gimme & G_WANT){
208             case G_VOID:
209 3           PUSHs(&PL_sv_undef);
210 3           break;
211             case G_SCALAR:
212 4           PUSHs(&PL_sv_no);
213 4           break;
214             case G_ARRAY:
215 3           PUSHs(&PL_sv_yes);
216 3           break;
217             default:
218 0           croak("Unknown wantarray");
219             }
220              
221             void sym_wantarray(SV * symbol_SV)
222             PPCODE:
223 4           PERL_CONTEXT * cx = &cxstack[cxstack_ix];
224 27 100         for(; cx>=cxstack; --cx){
225 26           switch( CxTYPE(cx) ){
226             default:
227 1           continue;
228             case CXt_SUB:
229             #if PERL_VERSION_GE(5,18,0)
230 25 50         if( cx->cx_type & CXp_SUB_RE_FAKE )
231 0           continue;
232             #endif
233 94 100         for(struct block_symbol_t *p = block_symbols+block_symbols_n-1; p>=block_symbols; --p)
234 72 100         if( p->cv == cx->blk_sub.cv ){
235 9 50         if( !SvOK(p->symbol_SV) )
    0          
    0          
236 0           break;
237             #if PERL_VERSION_GE(5,10,0)
238 9 50         if( SvRXOK(p->symbol_SV) ){
239 0 0         PUSHMARK(SP);
240 0 0         EXTEND(SP, 2);
241 0           PUSHs(p->symbol_SV);
242 0           PUSHs(symbol_SV);
243 0           PUTBACK;
244 0           call_sv(regex_match_sv, G_SCALAR);
245 0           SPAGAIN;
246 0 0         IV match_res = POPi;
247 0           PUTBACK;
248              
249 0 0         if( match_res )
250 0           goto FOUND;
251             }
252             else
253             #endif
254 9 100         if( sv_cmp(p->symbol_SV, symbol_SV)==0 )
255 3           goto FOUND;
256             }
257             case CXt_EVAL:
258             case CXt_FORMAT:
259 22           break;
260             }
261             }
262             FOUND:
263 4 100         if( cx
264 1           PUSHs(&PL_sv_undef);
265             else
266 3           switch(cx->blk_gimme & G_WANT){
267             case G_VOID:
268 1           PUSHs(&PL_sv_undef);
269 1           break;
270             case G_SCALAR:
271 1           PUSHs(&PL_sv_no);
272 1           break;
273             case G_ARRAY:
274 1           PUSHs(&PL_sv_yes);
275 1           break;
276             default:
277 0           croak("Unknown wantarray");
278             }
279              
280             BOOT:
281 1           block_symbols_capacity = 8;
282 1           block_symbols_n = 0;
283 1 50         Newx(block_symbols, block_symbols_capacity, struct block_symbol_t);
284              
285 1           regex_match_sv = newRV_inc((SV*)get_cv("Return::Deep::regex_match", FALSE));
286              
287 1           return_ppaddr = PL_ppaddr[OP_RETURN];
288             #if PERL_VERSION_GE(5,14,0)
289 1           cv_set_call_checker(get_cv("Return::Deep::deep_ret", TRUE), deep_ret_check, &PL_sv_undef);
290 1           cv_set_call_checker(get_cv("Return::Deep::sym_ret", TRUE), sym_ret_check, &PL_sv_undef);
291             #else
292             my_deep_ret_cv = get_cv("Return::Deep::deep_ret", TRUE);
293             my_sym_ret_cv = get_cv("Return::Deep::sym_ret", TRUE);
294             orig_entersub_check = PL_check[OP_ENTERSUB];
295             PL_check[OP_ENTERSUB] = my_entersub_check;
296             #endif