File Coverage

XS.xs
Criterion Covered Total %
statement 69 71 97.1
branch 239 618 38.6
condition n/a
subroutine n/a
pod n/a
total 308 689 44.7


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             #define NEED_SvRX
7             #include "ppport.h"
8              
9             #if defined(cv_set_call_checker) && defined(XopENTRY_set)
10             # define USE_CUSTOM_OPS 1
11             #else
12             # define USE_CUSTOM_OPS 0
13             #endif
14              
15             /* Boolean expression that considers an SV* named "ref" */
16             #define COND(expr) (SvROK(ref) && expr)
17              
18             #define PLAIN (!sv_isobject(ref))
19             #define REFTYPE(tail) (SvTYPE(SvRV(ref)) tail)
20             #define REFREF (SvROK( SvRV(ref) ))
21              
22             #define JUSTSCALAR ( \
23             REFTYPE(< SVt_PVAV) \
24             && REFTYPE(!= SVt_PVGV) \
25             && (SvTYPE(SvRV(ref)) != SVt_PVGV) \
26             && !REFREF \
27             && !SvRXOK(ref) \
28             )
29              
30             #if PERL_VERSION >= 7
31             #define FORMATREF REFTYPE(== SVt_PVFM)
32             #else
33             #define FORMATREF (croak("is_formatref() isn't available on Perl 5.6.x and under"), 0)
34             #endif
35              
36             #define FUNC_BODY(cond) \
37             { \
38             SV *ref = TOPs; \
39             SvGETMAGIC(ref); \
40             SETs( COND(cond) ? &PL_sv_yes : &PL_sv_no ); \
41             }
42              
43             #define DECL_RUNTIME_FUNC(x, cond) \
44             static void \
45             THX_xsfunc_ ## x (pTHX_ CV *cv) \
46             { \
47             dXSARGS; \
48             if (items != 1) \
49             Perl_croak(aTHX_ "Usage: Ref::Util::XS::" #x "(ref)"); \
50             FUNC_BODY(cond); \
51             }
52              
53             #define DECL_XOP(x) \
54             static XOP x ## _xop;
55              
56             #define DECL_MAIN_FUNC(x, cond) \
57             static OP * \
58             x ## _op(pTHX) \
59             { \
60             dSP; \
61             FUNC_BODY(cond); \
62             return NORMAL; \
63             }
64              
65             #define DECL_CALL_CHK_FUNC(x) \
66             static OP * \
67             THX_ck_entersub_args_ ## x(pTHX_ OP *entersubop, GV *namegv, SV *ckobj) \
68             { \
69             return call_checker_common(aTHX_ entersubop, namegv, ckobj, x ## _op); \
70             }
71              
72             #if !USE_CUSTOM_OPS
73              
74             #define DECL(x, cond) DECL_RUNTIME_FUNC(x, cond)
75             #define INSTALL(x, ref) \
76             newXSproto("Ref::Util::XS::" #x, THX_xsfunc_ ## x, __FILE__, "$");
77              
78             #else
79              
80             #define DECL(x, cond) \
81             DECL_RUNTIME_FUNC(x, cond) \
82             DECL_XOP(x) \
83             DECL_MAIN_FUNC(x, cond) \
84             DECL_CALL_CHK_FUNC(x)
85              
86             #define INSTALL(x, ref) \
87             { \
88             CV *cv; \
89             XopENTRY_set(& x ##_xop, xop_name, #x); \
90             XopENTRY_set(& x ##_xop, xop_desc, "'" ref "' ref check"); \
91             XopENTRY_set(& x ##_xop, xop_class, OA_UNOP); \
92             Perl_custom_op_register(aTHX_ x ##_op, & x ##_xop); \
93             cv = newXSproto_portable( \
94             "Ref::Util::XS::" #x, THX_xsfunc_ ## x, __FILE__, "$" \
95             ); \
96             cv_set_call_checker(cv, THX_ck_entersub_args_ ## x, (SV*)cv); \
97             }
98              
99             // This function extracts the args for the custom op, and deletes the remaining
100             // ops from memory, so they can then be replaced entirely by the custom op.
101             /*
102             This is how the ops will look like:
103              
104             $ perl -MO=Concise -E'is_arrayref($foo)'
105             7 <@> leave[1 ref] vKP/REFC ->(end)
106             1 <0> enter ->2
107             2 <;> nextstate(main 47 -e:1) v:%,{,469764096 ->3
108             6 <1> entersub[t4] vKS/TARG ->7
109             - <1> ex-list K ->6
110             3 <0> pushmark s ->4
111             - <1> ex-rv2sv sKM/1 ->5
112             4 <#> gvsv[*foo] s ->5
113             - <1> ex-rv2cv sK ->-
114             5 <#> gv[*is_arrayref] ->6
115             */
116             static OP *
117 118           call_checker_common(pTHX_ OP *entersubop, GV *namegv, SV *ckobj, OP* (*op_ppaddr)(pTHX))
118             {
119 118           OP *pushop = NULL;
120 118           OP *arg = NULL;
121 118           OP *newop = NULL;
122              
123             /* fix up argument structures */
124 118           entersubop = ck_entersub_args_proto(entersubop, namegv, ckobj);
125              
126             /* extract the args for the custom op, and delete the remaining ops
127             NOTE: this is the *single* arg version, multi-arg is more
128             complicated, see Hash::SharedMem's THX_ck_entersub_args_hsm */
129              
130             /* These comments will visualize how the op tree look like after
131             each operation. We usually start out with this: */
132             /* --> entersub( list( push, arg1, cv ) ) */
133             /* Though in rare cases it can also look like this: */
134             /* --> entersub( push, arg1, cv ) */
135              
136             /* first, get the real pushop, after which comes the arg list */
137              
138             /* Cast the entersub op as an op with a single child */
139             /* and get that child (the args list or pushop). */
140 118           pushop = cUNOPx( entersubop )->op_first;
141              
142             /* At this point we're still not sure if it's the right op,
143             (because it should normally be a list() with the push inside it)
144             so we check whether it has siblings or not. The list() has no
145             siblings */
146             /* Go one layer deeper to get at the real pushop. */
147 118 50         if( !OpHAS_SIBLING( pushop ) )
148             /* Fetch the actual push op from inside the list() op */
149 118           pushop = cUNOPx( pushop )->op_first;
150              
151             /* then extract the arg */
152             /* Get a pointer to the first arg op */
153             /* so we can attach it to the custom op later on. */
154             /* Notice "ex-rv2sv" calls are optimized away. */
155 118 50         arg = OpSIBLING( pushop );
156              
157             /* --> entersub( list( push, arg1, cv ) ) + ( arg1, cv ) */
158              
159             /* and prepare to delete the other ops */
160             /* Replace the first op of the arg list with the last arg op
161             (the cv op, i.e. pointer to original xs function),
162             which allows recursive deletion of all unneeded ops
163             while keeping the arg list. */
164 118 50         OpMORESIB_set( pushop, OpSIBLING( arg ) );
165             /* --> entersub( list( push, cv ) ) + ( arg1, cv ) */
166              
167             /* Remove the trailing cv op from the arg list,
168             by declaring the arg to be the last sibling in the arg list. */
169 118           OpLASTSIB_set( arg, NULL );
170             /* --> entersub( list( push, cv ) ) */
171             /* --> arg1 */
172              
173             /* Recursively free entersubop + children,
174             as it'll be replaced by the op we return. */
175 118           op_free( entersubop );
176             /* --> ( arg1 ) */
177              
178             /* create and return new op */
179 118           newop = newUNOP( OP_NULL, 0, arg );
180             /* can't do this in the new above, due to crashes pre-5.22 */
181 118           newop->op_type = OP_CUSTOM;
182 118           newop->op_ppaddr = op_ppaddr;
183             /* --> custom_op( arg1 ) */
184              
185 118           return newop;
186             }
187              
188             #endif
189              
190 108 50         DECL(is_ref, 1)
    0          
    50          
    50          
    50          
    0          
    50          
191 112 50         DECL(is_scalarref, JUSTSCALAR)
    0          
    50          
    100          
    100          
    50          
    100          
    100          
    50          
    50          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
192 157 100         DECL(is_arrayref, REFTYPE(== SVt_PVAV))
    50          
    50          
    100          
    100          
    50          
    0          
    100          
    100          
193 121 50         DECL(is_hashref, REFTYPE(== SVt_PVHV))
    0          
    50          
    100          
    100          
    50          
    0          
    50          
    0          
194 112 50         DECL(is_coderef, REFTYPE(== SVt_PVCV))
    0          
    50          
    100          
    50          
    50          
    0          
    50          
    0          
195 112 50         DECL(is_globref, REFTYPE(== SVt_PVGV))
    0          
    50          
    100          
    50          
    50          
    0          
    50          
    0          
196 112 50         DECL(is_formatref, FORMATREF)
    0          
    50          
    100          
    50          
    50          
    0          
    50          
    0          
197 50 50         DECL(is_ioref, REFTYPE(== SVt_PVIO))
    0          
    50          
    100          
    50          
    50          
    0          
    50          
    0          
198 50 50         DECL(is_regexpref, SvRXOK(ref))
    0          
    50          
    100          
    50          
    50          
    0          
    50          
    0          
199 112 50         DECL(is_refref, REFREF)
    0          
    50          
    100          
    50          
    50          
    0          
    50          
    0          
200              
201 108 50         DECL(is_plain_ref, PLAIN)
    0          
    50          
    100          
    50          
    50          
    0          
    50          
    0          
202 110 50         DECL(is_plain_scalarref, JUSTSCALAR && PLAIN)
    0          
    50          
    100          
    100          
    50          
    100          
    100          
    100          
    50          
    50          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
203 110 50         DECL(is_plain_arrayref, REFTYPE(== SVt_PVAV) && PLAIN)
    0          
    50          
    100          
    100          
    50          
    50          
    0          
    50          
    0          
    0          
204 112 50         DECL(is_plain_hashref, REFTYPE(== SVt_PVHV) && PLAIN)
    0          
    50          
    100          
    100          
    50          
    50          
    0          
    50          
    0          
    0          
205 110 50         DECL(is_plain_coderef, REFTYPE(== SVt_PVCV) && PLAIN)
    0          
    50          
    100          
    100          
    50          
    50          
    0          
    50          
    0          
    0          
206 110 50         DECL(is_plain_globref, REFTYPE(== SVt_PVGV) && PLAIN)
    0          
    50          
    100          
    100          
    50          
    50          
    0          
    50          
    0          
    0          
207 110 50         DECL(is_plain_formatref, FORMATREF && PLAIN)
    0          
    50          
    100          
    100          
    50          
    50          
    0          
    50          
    0          
    0          
208 0 0         DECL(is_plain_ioref, REFTYPE(== SVt_PVIO) && PLAIN)
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
209 110 50         DECL(is_plain_refref, REFREF && PLAIN)
    0          
    50          
    100          
    100          
    50          
    50          
    0          
    50          
    0          
    0          
210              
211 108 50         DECL(is_blessed_ref, !PLAIN)
    0          
    50          
    100          
    50          
    50          
    0          
    50          
    0          
212 110 50         DECL(is_blessed_scalarref, JUSTSCALAR && !PLAIN)
    0          
    50          
    100          
    100          
    50          
    100          
    100          
    100          
    50          
    50          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
213 110 50         DECL(is_blessed_arrayref, REFTYPE(== SVt_PVAV) && !PLAIN)
    0          
    50          
    100          
    100          
    50          
    50          
    0          
    50          
    0          
    0          
214 112 50         DECL(is_blessed_hashref, REFTYPE(== SVt_PVHV) && !PLAIN)
    0          
    50          
    100          
    100          
    50          
    50          
    0          
    50          
    0          
    0          
215 110 50         DECL(is_blessed_coderef, REFTYPE(== SVt_PVCV) && !PLAIN)
    0          
    50          
    100          
    100          
    50          
    50          
    0          
    50          
    0          
    0          
216 110 50         DECL(is_blessed_globref, REFTYPE(== SVt_PVGV) && !PLAIN)
    0          
    50          
    100          
    100          
    50          
    50          
    0          
    50          
    0          
    0          
217 110 50         DECL(is_blessed_formatref, FORMATREF && !PLAIN)
    0          
    50          
    100          
    100          
    50          
    50          
    0          
    50          
    0          
    0          
218 0 0         DECL(is_blessed_ioref, REFTYPE(== SVt_PVIO) && !PLAIN)
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
219 110 50         DECL(is_blessed_refref, REFREF && !PLAIN)
    0          
    50          
    100          
    100          
    50          
    50          
    0          
    50          
    0          
    0          
220              
221             MODULE = Ref::Util::XS PACKAGE = Ref::Util::XS
222              
223             PROTOTYPES: DISABLE
224              
225             BOOT:
226             {
227 10           INSTALL( is_ref, "" )
228 10           INSTALL( is_scalarref, "SCALAR" )
229 10           INSTALL( is_arrayref, "ARRAY" )
230 10           INSTALL( is_hashref, "HASH" )
231 10           INSTALL( is_coderef, "CODE" )
232 10           INSTALL( is_regexpref, "REGEXP" )
233 10           INSTALL( is_globref, "GLOB" )
234 10           INSTALL( is_formatref, "FORMAT" )
235 10           INSTALL( is_ioref, "IO" )
236 10           INSTALL( is_refref, "REF" )
237 10           INSTALL( is_plain_ref, "plain" )
238 10           INSTALL( is_plain_scalarref, "plain SCALAR" )
239 10           INSTALL( is_plain_arrayref, "plain ARRAY" )
240 10           INSTALL( is_plain_hashref, "plain HASH" )
241 10           INSTALL( is_plain_coderef, "plain CODE" )
242 10           INSTALL( is_plain_globref, "plain GLOB" )
243 10           INSTALL( is_plain_formatref, "plain FORMAT" )
244 10           INSTALL( is_plain_refref, "plain REF" )
245 10           INSTALL( is_blessed_ref, "blessed" )
246 10           INSTALL( is_blessed_scalarref, "blessed SCALAR" )
247 10           INSTALL( is_blessed_arrayref, "blessed ARRAY" )
248 10           INSTALL( is_blessed_hashref, "blessed HASH" )
249 10           INSTALL( is_blessed_coderef, "blessed CODE" )
250 10           INSTALL( is_blessed_globref, "blessed GLOB" )
251 10           INSTALL( is_blessed_formatref, "blessed FORMAT" )
252 10           INSTALL( is_blessed_refref, "blessed REF" )
253             }
254              
255             SV *
256             _using_custom_ops()
257             PPCODE:
258             /* This is provided for the test suite; do not use it. */
259             /* Use if-else below because ternary operator cannot build on Sun
260             Studio 11 and 12. */
261             if (USE_CUSTOM_OPS) {
262 11           XSRETURN_YES;
263             }
264             else {
265             XSRETURN_NO;
266             }