File Coverage

autobox.xs
Criterion Covered Total %
statement 140 163 85.8
branch 107 156 68.5
condition n/a
subroutine n/a
pod n/a
total 247 319 77.4


line stmt bran cond sub pod time code
1             #define PERL_CORE
2              
3             #include "EXTERN.h"
4             #include "perl.h"
5             #include "XSUB.h"
6             #define NEED_sv_2pv_flags
7             #include "ppport.h"
8              
9             #include "ptable.h"
10              
11             static PTABLE_t *AUTOBOX_OP_MAP = NULL;
12             static U32 AUTOBOX_SCOPE_DEPTH = 0;
13             static OP *(*autobox_old_check_entersub)(pTHX_ OP *op) = NULL;
14              
15             static SV * autobox_method_common(pTHX_ SV *method, U32 *hashp);
16             static const char * autobox_type(pTHX_ SV * const sv, STRLEN *len);
17             static void autobox_cleanup(pTHX_ void * unused);
18              
19             OP * autobox_check_entersub(pTHX_ OP *o);
20             OP * autobox_method_named(pTHX);
21             OP * autobox_method(pTHX);
22              
23             void auto_ref(pTHX_ OP *invocant, UNOP *parent, OP *prev);
24              
25             #ifndef MUTABLE_GV /* XXX missing from ppport.h */
26             #define MUTABLE_GV(p) ((GV *)MUTABLE_PTR(p))
27             #endif
28              
29             #define AUTOBOX_TYPE_RETURN(type) STMT_START { \
30             *len = (sizeof(type) - 1); return type; \
31             } STMT_END
32              
33 526           static const char *autobox_type(pTHX_ SV * const sv, STRLEN *len) {
34 526           switch (SvTYPE(sv)) {
35             case SVt_NULL:
36 0           AUTOBOX_TYPE_RETURN("UNDEF");
37             case SVt_IV:
38 123           AUTOBOX_TYPE_RETURN("INTEGER");
39             case SVt_PVIV:
40 19 100         if (SvIOK(sv)) {
41 16           AUTOBOX_TYPE_RETURN("INTEGER");
42             } else {
43 3           AUTOBOX_TYPE_RETURN("STRING");
44             }
45             case SVt_NV:
46 71 50         if (SvIOK(sv)) {
47 0           AUTOBOX_TYPE_RETURN("INTEGER");
48             } else {
49 71           AUTOBOX_TYPE_RETURN("FLOAT");
50             }
51             case SVt_PVNV:
52             /*
53             * integer before float:
54             * https://rt.cpan.org/Ticket/Display.html?id=46814
55             */
56 24 100         if (SvIOK(sv)) {
57 4           AUTOBOX_TYPE_RETURN("INTEGER");
58 20 100         } else if (SvNOK(sv)) {
59 17           AUTOBOX_TYPE_RETURN("FLOAT");
60             } else {
61 3           AUTOBOX_TYPE_RETURN("STRING");
62             }
63              
64             #ifdef SVt_RV /* no longer defined by default if PERL_CORE is defined */
65             case SVt_RV:
66             #endif
67              
68             case SVt_PV:
69             case SVt_PVMG:
70              
71             #ifdef SvVOK
72 118 50         if (SvVOK(sv)) {
    0          
73 0           AUTOBOX_TYPE_RETURN("VSTRING");
74             }
75             #endif
76              
77 118 50         if (SvROK(sv)) {
78 0           AUTOBOX_TYPE_RETURN("REF");
79             } else {
80 118           AUTOBOX_TYPE_RETURN("STRING");
81             }
82             case SVt_PVLV:
83 0 0         if (SvROK(sv)) {
84 0           AUTOBOX_TYPE_RETURN("REF");
85 0 0         } else if (LvTYPE(sv) == 't' || LvTYPE(sv) == 'T') { /* tied lvalue */
    0          
86 0 0         if (SvIOK(sv)) {
87 0           AUTOBOX_TYPE_RETURN("INTEGER");
88 0 0         } else if (SvNOK(sv)) {
89 0           AUTOBOX_TYPE_RETURN("FLOAT");
90             } else {
91 0           AUTOBOX_TYPE_RETURN("STRING");
92             }
93             } else {
94 0           AUTOBOX_TYPE_RETURN("LVALUE");
95             }
96             case SVt_PVAV:
97 63           AUTOBOX_TYPE_RETURN("ARRAY");
98             case SVt_PVHV:
99 51           AUTOBOX_TYPE_RETURN("HASH");
100             case SVt_PVCV:
101 57           AUTOBOX_TYPE_RETURN("CODE");
102             case SVt_PVGV:
103 0           AUTOBOX_TYPE_RETURN("GLOB");
104             case SVt_PVFM:
105 0           AUTOBOX_TYPE_RETURN("FORMAT");
106             case SVt_PVIO:
107 0           AUTOBOX_TYPE_RETURN("IO");
108              
109             #ifdef SVt_BIND
110             case SVt_BIND:
111             AUTOBOX_TYPE_RETURN("BIND");
112             #endif
113              
114             #ifdef SVt_REGEXP
115             case SVt_REGEXP:
116             AUTOBOX_TYPE_RETURN("REGEXP");
117             #endif
118              
119             default:
120 0           AUTOBOX_TYPE_RETURN("UNKNOWN");
121             }
122             }
123              
124             /*
125             * convert array/hash invocants to arrayref/hashref e.g.:
126             *
127             * @foo->bar -> (\@foo)->bar
128             */
129 25           void auto_ref(pTHX_ OP *invocant, UNOP *parent, OP *prev) {
130             #ifndef op_sibling_splice
131             OP *refgen;
132             #endif
133              
134             /*
135             * perlref:
136             *
137             * As a special case, "\(@foo)" returns a list of references to the
138             * contents of @foo, not a reference to @foo itself. Likewise for %foo,
139             * except that the key references are to copies (since the keys are just
140             * strings rather than full-fledged scalars).
141             *
142             * we don't want that (it results in the invocant being a reference to the
143             * last element in the list), so we toggle the parentheses off while creating
144             * the reference then toggle them back on in case they're needed elsewhere
145             *
146             */
147 25           bool toggled = FALSE;
148              
149 25 100         if (invocant->op_flags & OPf_PARENS) {
150 8           invocant->op_flags &= ~OPf_PARENS;
151 8           toggled = TRUE;
152             }
153              
154             #ifdef op_sibling_splice
155 25           op_sibling_splice(
156             (OP *)parent,
157             prev,
158             0,
159             newUNOP(
160             OP_REFGEN,
161             0,
162             op_sibling_splice(
163             (OP *)parent,
164             prev,
165             1,
166             NULL
167             )
168             )
169             );
170             #else
171             /* XXX if this (old?) way works, why do we need both? */
172             PERL_UNUSED_ARG(parent); /* silence warning on perl v5.8 */
173             refgen = newUNOP(OP_REFGEN, 0, invocant);
174             prev->op_sibling = refgen;
175             refgen->op_sibling = invocant->op_sibling;
176             invocant->op_sibling = NULL;
177             #endif
178              
179             /* Restore the parentheses in case something else expects them */
180 25 100         if (toggled) {
181 8           invocant->op_flags |= OPf_PARENS;
182             }
183 25           }
184              
185 2658           OP * autobox_check_entersub(pTHX_ OP *o) {
186             UNOP *parent;
187             OP *prev, *invocant, *cvop;
188             SV **svp;
189             HV *hh;
190 2658           bool has_bindings = FALSE;
191              
192             /*
193             * XXX note: perl adopts a convention of calling the OP `o` and has shortcut
194             * macros based on this convention like cUNOPo, among others. if the name
195             * changes, the macro will need to change as well e.g. to cUNOPx(op)
196             */
197              
198             /*
199             * work around a %^H scoping bug by checking that PL_hints (which is
200             * properly scoped) & an unused PL_hints bit (0x100000) is true
201             *
202             * XXX this is fixed in #33311:
203             *
204             * http://www.nntp.perl.org/group/perl.perl5.porters/2008/02/msg134131.html
205             */
206 2658 100         if ((PL_hints & 0x80020000) != 0x80020000) {
207 1245           goto done;
208             }
209              
210             /*
211             * the OP which yields the CV is the last OP in the ENTERSUB OP's list of
212             * children. navigate to it by following the `op_sibling` pointers from the
213             * first child in the list (the invocant)
214             */
215 1413 100         parent = OpHAS_SIBLING(cUNOPo->op_first) ? cUNOPo : ((UNOP *)cUNOPo->op_first);
216 1413           prev = parent->op_first;
217 1413 50         invocant = OpSIBLING(prev);
218              
219 3970 50         for (cvop = invocant; OpHAS_SIBLING(cvop); cvop = OpSIBLING(cvop));
    100          
220              
221             /*
222             * now we have the CV OP, we can check if it's a method lookup.
223             * bail out if it's not
224             */
225 1413 100         if ((cvop->op_type != OP_METHOD) && (cvop->op_type != OP_METHOD_NAMED)) {
    100          
226 672           goto done;
227             }
228              
229             /* bail out if the invocant is a bareword e.g. Foo->bar or Foo->$bar */
230 741 100         if ((invocant->op_type == OP_CONST) && (invocant->op_private & OPpCONST_BARE)) {
    100          
231 20           goto done;
232             }
233              
234             /*
235             * the bareword flag is not set on the invocants of the `import`, `unimport`
236             * and `VERSION` methods faked up by `use` and `no` [1]. we have no other way
237             * to detect if an OP_CONST invocant is a bareword for these methods,
238             * so we have no choice but to assume it is and bail out so that we don't
239             * break `use`, `no` etc.
240             *
241             * (this is documented: the solution/workaround is to use
242             * $native->autobox_class instead.)
243             *
244             * note: we exempt all invocant types from these methods rather than just
245             * the invocants we can't be sure about (i.e. OP_CONST). we *could* allow
246             * e.g. []->VERSION or {}->import, but we don't, for consistency. even if
247             * OP_CONST invocants had the correct bareword flags, it's far more likely
248             * to be a bug for e.g. []->VERSION to differ from ARRAY->VERSION than
249             * a deliberate feature. [2]
250             *
251             * likewise, we also exempt $native->can and $native->isa here, neither
252             * of which are well-defined as instance methods.
253             *
254             * [1] XXX this is a bug (in perl)
255             *
256             * [2] although if these barewords did have the correct flag, we could
257             * forward (non-bareword) calls to these methods to autobox_class
258             * automatically rather than requiring the user to do it manually
259             */
260 721 100         if (cvop->op_type == OP_METHOD_NAMED) {
261             /* SvPVX_const should be sane for the method name */
262 702           const char * method_name = SvPVX_const(((SVOP *)cvop)->op_sv);
263              
264 702 100         if (
265 639 50         strEQ(method_name, "can") ||
266 639 100         strEQ(method_name, "DOES") ||
267 606 100         strEQ(method_name, "import") ||
268 525 100         strEQ(method_name, "isa") ||
269 504 100         strEQ(method_name, "unimport") ||
270 504           strEQ(method_name, "VERSION")
271             ) {
272             goto done;
273             }
274             }
275              
276 516           hh = GvHV(PL_hintgv); /* the hints hash (%^H) */
277              
278             /* is there a bindings hashref for this scope? */
279 516           has_bindings = hh
280 516 50         && (svp = hv_fetch(hh, "autobox", 7, FALSE))
281 516 50         && *svp
282 1032 50         && SvROK(*svp);
    50          
283              
284 516 50         if (!has_bindings) {
285 0           goto done;
286             }
287              
288             /*
289             * if the invocant is an @array, %hash, @{ ... } or %{ ... }, then
290             * "auto-ref" it i.e. the optree equivalent of inserting a backslash
291             * before it:
292             *
293             * @foo->bar -> (\@foo)->bar
294             */
295 516 100         switch (invocant->op_type) {
296             case OP_PADAV:
297             case OP_PADHV:
298             case OP_RV2AV:
299             case OP_RV2HV:
300 25           auto_ref(aTHX_ invocant, parent, prev);
301             }
302              
303 516           cvop->op_flags |= OPf_SPECIAL;
304 1032           cvop->op_ppaddr = cvop->op_type == OP_METHOD
305             ? autobox_method
306 516 100         : autobox_method_named;
307              
308 516           PTABLE_store(AUTOBOX_OP_MAP, cvop, SvRV(*svp));
309              
310             done:
311 2658           return autobox_old_check_entersub(aTHX_ o);
312             }
313              
314             /* returns either the method, or NULL, meaning delegate to the original op */
315 508           static SV * autobox_method_common(pTHX_ SV * method, U32* hashp) {
316 508           SV * const invocant = *(PL_stack_base + TOPMARK + 1);
317             SV * packsv;
318             HV * autobox_bindings;
319             HV * stash;
320             const char * reftype; /* autobox_bindings key */
321             SV **svp; /* pointer to autobox_bindings value */
322 508           STRLEN typelen = 0, packlen = 0;
323             const char * packname;
324             GV * gv;
325              
326             /* if autobox isn't enabled (in scope) for this op, bail out */
327 508 50         if (!(PL_op->op_flags & OPf_SPECIAL)) {
328 0           return NULL;
329             }
330              
331             // bail out if the invocant is NULL (not to be confused with undef) e.g.
332             // from a buggy XS module
333 508 50         if (!invocant) {
334 0           return NULL;
335             }
336              
337             /*
338             * if the invocant's an object (blessed reference), bail out.
339             *
340             * XXX don't use sv_isobject - we don't want to call SvGETMAGIC twice
341             */
342 508 100         if (SvROK(invocant) && SvOBJECT(SvRV(invocant))) {
    100          
343 10           return NULL;
344             }
345              
346             /* XXX do non-objects have magic attached? */
347 498 50         SvGETMAGIC(invocant);
    0          
348              
349             /* the "bindings hash", which maps datatypes to package names */
350 498           autobox_bindings = (HV *)(PTABLE_fetch(AUTOBOX_OP_MAP, PL_op));
351              
352 498 50         if (!autobox_bindings) {
353 0           return NULL;
354             }
355              
356             /*
357             * the type is either the invocant's reftype(), a subtype of
358             * SCALAR if it's not a ref, or UNDEF if it's not defined
359             */
360 498 100         if (SvOK(invocant)) {
    50          
    50          
361 474 100         reftype = autobox_type(
362 474           aTHX_ (SvROK(invocant) ? SvRV(invocant) : invocant),
363             &typelen
364             );
365             } else {
366 24           reftype = "UNDEF";
367 24           typelen = sizeof("UNDEF") - 1;
368             }
369              
370 498           svp = hv_fetch(autobox_bindings, reftype, typelen, 0);
371              
372 498 100         if (!(svp && SvOK(*svp))) {
    50          
    0          
    0          
373 60           return NULL;
374             }
375              
376 438           packsv = *svp;
377 438 50         packname = SvPV_const(packsv, packlen);
378 438           stash = gv_stashpvn(packname, packlen, FALSE);
379              
380 438 100         if (hashp) { /* shortcut for simple names */
381 427           const HE * const he = hv_fetch_ent(stash, method, 0, *hashp);
382              
383 427 100         if (he) {
384             U32 cvgen;
385              
386             #ifdef HvMROMETA /* introduced in v5.10 */
387 422 50         cvgen = PL_sub_generation + HvMROMETA(stash)->cache_gen;
388             #else
389             cvgen = PL_sub_generation;
390             #endif
391              
392 422           gv = MUTABLE_GV(HeVAL(he));
393              
394             /*
395             * GvCVGEN(gv) is almost always 0, so the global and local cache
396             * invalidation (above) seldom comes into play
397             */
398 422 100         if (isGV(gv) && GvCV(gv) && (!GvCVGEN(gv) || GvCVGEN(gv) == cvgen)) {
    50          
    100          
    50          
399 419           return MUTABLE_SV(GvCV(gv));
400             }
401             }
402             }
403              
404             /*
405             * SvPV_nolen_const returns the method name as a const char *,
406             * stringifying names that are not strings (e.g. undef, SvIV,
407             * SvNV &c.) - see name.t
408             */
409 19 100         gv = gv_fetchmethod(
    50          
410             stash ? stash : (HV*)packsv,
411             SvPV_nolen_const(method)
412             );
413              
414 19 100         if (gv) {
415 16 50         return isGV(gv) ? MUTABLE_SV(GvCV(gv)) : MUTABLE_SV(gv);
416             }
417              
418 508           return NULL;
419             }
420              
421 19           OP* autobox_method(pTHX) {
422 19           dVAR; dSP;
423 19           SV * const sv = TOPs;
424             SV * cv;
425              
426 19 100         if (SvROK(sv)) {
427 8           cv = SvRV(sv);
428              
429 8 50         if (SvTYPE(cv) == SVt_PVCV) {
430 8           SETs(cv);
431 8           RETURN;
432             }
433             }
434              
435 11           cv = autobox_method_common(aTHX_ sv, NULL);
436              
437 11 100         if (cv) {
438 8           SETs(cv);
439 8           RETURN;
440             } else {
441 3           return PL_ppaddr[OP_METHOD](aTHXR);
442             }
443             }
444              
445 497           OP* autobox_method_named(pTHX) {
446 497           dVAR; dSP;
447 497           SV * const sv = cSVOP_sv;
448 497           U32 hash = SvSHARED_HASH(sv);
449             SV * cv;
450              
451 497           cv = autobox_method_common(aTHX_ sv, &hash);
452              
453 497 100         if (cv) {
454 427 50         XPUSHs(cv);
455 427           RETURN;
456             } else {
457 497           return PL_ppaddr[OP_METHOD_NAMED](aTHXR);
458             }
459             }
460              
461 22           static void autobox_cleanup(pTHX_ void * unused) {
462             PERL_UNUSED_ARG(unused); /* silence warning on perl v5.8 */
463              
464 22 50         if (AUTOBOX_OP_MAP) {
465 22           PTABLE_free(AUTOBOX_OP_MAP);
466 22           AUTOBOX_OP_MAP = NULL;
467             }
468 22           }
469              
470             MODULE = autobox PACKAGE = autobox
471              
472             PROTOTYPES: ENABLE
473              
474             BOOT:
475             /*
476             * XXX the BOOT section extends to the next blank line, so don't add one
477             * for readability
478             */
479             PERL_UNUSED_ARG(cv); /* silence warning on perl v5.8 */
480 22           AUTOBOX_OP_MAP = PTABLE_new();
481 22 50         if (AUTOBOX_OP_MAP) {
482 22           Perl_call_atexit(aTHX_ autobox_cleanup, NULL);
483             } else {
484 0           Perl_croak(aTHX_ "Can't initialize OP map");
485             }
486              
487             void
488             _enter()
489             PROTOTYPE:
490             CODE:
491             PERL_UNUSED_ARG(cv); /* silence warning on perl v5.8 */
492              
493 82 100         if (AUTOBOX_SCOPE_DEPTH > 0) {
494 9           ++AUTOBOX_SCOPE_DEPTH;
495             } else {
496 73           AUTOBOX_SCOPE_DEPTH = 1;
497             /*
498             * capture the check routine in scope when autobox is used.
499             * usually, this will be Perl_ck_subr, though, in principle,
500             * it could be a bespoke checker spliced in by another module.
501             */
502 73           autobox_old_check_entersub = PL_check[OP_ENTERSUB];
503 73           PL_check[OP_ENTERSUB] = autobox_check_entersub;
504             }
505              
506             void
507             _leave()
508             PROTOTYPE:
509             CODE:
510             PERL_UNUSED_ARG(cv); /* silence warning on perl v5.8 */
511              
512 82 50         if (AUTOBOX_SCOPE_DEPTH == 0) {
513 0           Perl_warn(aTHX_ "scope underflow");
514             }
515              
516 82 100         if (AUTOBOX_SCOPE_DEPTH > 1) {
517 9           --AUTOBOX_SCOPE_DEPTH;
518             } else {
519 73           AUTOBOX_SCOPE_DEPTH = 0;
520 73           PL_check[OP_ENTERSUB] = autobox_old_check_entersub;
521             }
522              
523             void
524             _scope()
525             PROTOTYPE:
526             CODE:
527             PERL_UNUSED_ARG(cv); /* silence warning on perl v5.8 */
528 107           XSRETURN_UV(PTR2UV(GvHV(PL_hintgv)));
529              
530             MODULE = autobox PACKAGE = autobox::universal
531              
532             SV *
533             type(SV * sv)
534             PROTOTYPE:$
535             PREINIT:
536 60           STRLEN len = 0;
537             const char *type;
538             CODE:
539             PERL_UNUSED_ARG(cv); /* silence warning on perl v5.8 */
540              
541 60 100         if (SvOK(sv)) {
    50          
    50          
542 52 100         type = autobox_type(aTHX_ (SvROK(sv) ? SvRV(sv) : sv), &len);
543 52           RETVAL = newSVpv(type, len);
544             } else {
545 8           RETVAL = newSVpv("UNDEF", sizeof("UNDEF") - 1);
546             }
547             OUTPUT:
548             RETVAL