File Coverage

xs/op.h
Criterion Covered Total %
statement 83 83 100.0
branch 358 2816 12.7
condition n/a
subroutine n/a
pod n/a
total 441 2899 15.2


line stmt bran cond sub pod time code
1             #ifndef __INHERITED_XS_OP_H_
2             #define __INHERITED_XS_OP_H_
3              
4             #ifdef CAIX_OPTIMIZE_OPMETHOD
5             #include
6              
7             typedef void (*ACCESSOR_t)(pTHX_ SV**, CV*, HV*);
8             typedef std::pair accessor_cb_pair_t;
9             #endif
10              
11             #define OP_UNSTEAL(name) STMT_START { \
12             ++unstolen; \
13             PL_op->op_ppaddr = PL_ppaddr[name]; \
14             return PL_ppaddr[name](aTHX); \
15             } STMT_END \
16              
17             template static
18 299           XSPROTO(CAIXS_entersub_wrapper) {
19 299           dSP;
20              
21 299           CAIXS_accessor(aTHX_ SP, cv, NULL);
22              
23 279           return;
24             }
25              
26             #ifdef CAIX_OPTIMIZE_OPMETHOD
27              
28             #define AMAP_ENTRY(type, opts) \
29             accessor_cb_pair_t(&CAIXS_entersub_wrapper, &CAIXS_accessor)
30              
31             /* catchy place, don't forget to add new types here */
32             #define ACCESSOR_MAP_SIZE 16
33 38           static accessor_cb_pair_t accessor_map[ACCESSOR_MAP_SIZE] = {
34             AMAP_ENTRY(Inherited, IsReadonly),
35             AMAP_ENTRY(Inherited, IsWeak),
36             AMAP_ENTRY(Inherited, None),
37             AMAP_ENTRY(InheritedCb, None),
38             AMAP_ENTRY(InheritedCbNamed, None),
39             AMAP_ENTRY(PrivateClass, IsReadonly),
40             AMAP_ENTRY(PrivateClass, IsWeak),
41             AMAP_ENTRY(PrivateClass,None),
42             AMAP_ENTRY(LazyClass, IsReadonly),
43             AMAP_ENTRY(LazyClass, IsWeak),
44             AMAP_ENTRY(LazyClass, None),
45             AMAP_ENTRY(ObjectOnly, IsReadonly),
46             AMAP_ENTRY(ObjectOnly, IsWeak),
47             AMAP_ENTRY(ObjectOnly, None),
48             AMAP_ENTRY(Constructor, None),
49             accessor_cb_pair_t(NULL, NULL), /* sentinel */
50 38           };
51              
52             static int
53 1634           CAIXS_map_compare(const void* a, const void* b) {
54 1634 100         return ((const accessor_cb_pair_t*)a)->first > ((const accessor_cb_pair_t*)b)->first ? -1 : 1;
55             }
56              
57             template static
58             OP *
59 125           CAIXS_opmethod_wrapper(pTHX) {
60 125           dSP;
61              
62 125 0         SV* self = PL_stack_base + TOPMARK == SP ? (SV*)NULL : *(PL_stack_base + TOPMARK + 1);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
63 125           HV* stash = NULL;
64              
65             /*
66             This block isn't required for the 'goto gotcv' case, but skipping it
67             (or swapping those blocks) makes unstealing inside 'goto gotcv' block impossible,
68             thus requiring additional check in the fast case, which is to be avoided.
69             */
70             #ifndef GV_CACHE_ONLY
71             if (LIKELY(self != NULL)) {
72             SvGETMAGIC(self);
73             #else
74 125 0         if (LIKELY(self && !SvGMAGICAL(self))) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
75             /* SvIsCOW_shared_hash is incompatible with SvGMAGICAL, so skip it completely */
76 125 0         if (SvIsCOW_shared_hash(self)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
    50          
    0          
    50          
    0          
    100          
    50          
    100          
    50          
    100          
    100          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
77 21           stash = gv_stashsv(self, GV_CACHE_ONLY);
78             } else
79             #endif
80 104 0         if (SvROK(self)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    100          
    100          
    0          
    0          
    0          
    0          
81 93           SV* ob = SvRV(self);
82 93 0         if (SvOBJECT(ob)) stash = SvSTASH(ob);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    100          
    100          
    0          
    0          
    0          
    0          
83              
84 11 0         } else if (SvPOK(self)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
85 10           const char* packname = SvPVX_const(self);
86 10           const STRLEN packlen = SvCUR(self);
87 10           const int is_utf8 = SvUTF8(self);
88              
89             #ifndef GV_CACHE_ONLY
90             const HE* const he = (const HE *)hv_common(PL_stashcache, NULL, packname, packlen, is_utf8, 0, NULL, 0);
91             if (he) stash = INT2PTR(HV*, SvIV(HeVAL(he)));
92             else
93             #endif
94 125           stash = gv_stashpvn(packname, packlen, is_utf8);
95             }
96             }
97              
98             SV* meth;
99 125           CV* cv = NULL;
100             U32 hash;
101              
102             if (optype == OP_METHOD) {
103 60           meth = TOPs;
104 60 0         if (SvROK(meth)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    50          
    100          
    0          
    0          
105 5           SV* const rmeth = SvRV(meth);
106 5 0         if (SvTYPE(rmeth) == SVt_PVCV) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
107 5           cv = (CV*)rmeth;
108 5           goto gotcv; /* We don't care about the 'stash' var here */
109             }
110             }
111              
112 55           hash = 0;
113              
114             } else if (optype == OP_METHOD_NAMED) {
115 65           meth = cSVOPx_sv(PL_op);
116              
117             #ifndef GV_CACHE_ONLY
118             hash = SvSHARED_HASH(meth);
119             #else
120 65           hash = 0;
121             #endif
122             }
123              
124             /* SvTYPE check appeared only since 5.22, but execute it for all perls nevertheless */
125 120 0         if (UNLIKELY(!stash || SvTYPE(stash) != SVt_PVHV)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    100          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
126 2           OP_UNSTEAL(optype);
127             }
128              
129             HE* he; /* To allow 'goto' to jump over this */
130 118 0         if ((he = hv_fetch_ent(stash, meth, 0, hash))) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    100          
    0          
    0          
    0          
    0          
131 117           GV* gv = (GV*)(HeVAL(he));
132 117 0         if (isGV(gv) && GvCV(gv) && (!GvCVGEN(gv) || GvCVGEN(gv) == (PL_sub_generation + HvMROMETA(stash)->cache_gen))) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    50          
    100          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
133 117           cv = GvCV(gv);
134             }
135             }
136              
137 118 0         if (UNLIKELY(!cv)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    100          
    0          
    0          
    0          
    0          
138 1           GV* gv = gv_fetchmethod_sv_flags(stash, meth, GV_AUTOLOAD|GV_CROAK);
139             assert(gv);
140              
141 1 0         cv = isGV(gv) ? GvCV(gv) : (CV*)gv;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
142             assert(cv);
143             }
144              
145             gotcv:
146 123           ACCESSOR_t accessor = NULL;
147 123           XSUBADDR_t xsub = CvXSUB(cv);
148              
149 123 0         if (LIKELY((xsub == (XSUBADDR_t)&CAIXS_entersub_wrapper))) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    50          
    50          
    100          
    50          
    100          
    100          
    0          
    0          
    0          
    0          
150 86           accessor = &CAIXS_accessor;
151              
152             } else {
153             /*
154             Check whether this is an iterator over another friendly accessor.
155             This is much faster then a permanent optimization lift, even if we guess
156             base type only once.
157             */
158              
159 37           const accessor_cb_pair_t* iter = accessor_map;
160 434 0         while (iter->first > xsub) { ++iter; }
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    0          
    100          
    100          
    0          
    0          
    0          
    0          
161 37 0         if (iter->first == xsub) accessor = iter->second;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    100          
    100          
    0          
    0          
    0          
    0          
162             }
163              
164 123 0         if (LIKELY(accessor != NULL)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    100          
    100          
    0          
    0          
    0          
    0          
165             assert(CvISXSUB(cv));
166 56           if (optype == OP_METHOD) {--SP; PUTBACK; }
167              
168 118           accessor(aTHX_ SP, cv, stash);
169 102           return PL_op->op_next->op_next;
170              
171             } else {
172             /*
173             We could also lift off CAIXS_entersub optimization here, but that's a one-time action,
174             so let it fail on it's own
175             */
176 5           OP_UNSTEAL(optype);
177             }
178             }
179              
180             #endif /* CAIX_OPTIMIZE_OPMETHOD */
181              
182             template static
183             OP *
184 20           CAIXS_entersub(pTHX) {
185 20           dSP;
186              
187 20           CV* sv = (CV*)TOPs;
188              
189 20 0         if (LIKELY(sv != NULL)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
190 20 0         if (UNLIKELY(SvTYPE(sv) != SVt_PVCV)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    0          
    0          
191             /* can('acc')->() or (\&acc)->() */
192              
193 13 0         if ((SvFLAGS(sv) & (SVf_ROK|SVs_GMG)) == SVf_ROK) sv = (CV*)SvRV(sv);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
194 13 0         if (UNLIKELY((SvTYPE(sv) != SVt_PVCV) || SvOBJECT(sv))) OP_UNSTEAL(OP_ENTERSUB);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
195             }
196              
197             /* Some older gcc's can't deduce correct function - have to add explicit cast */
198 20 0         if (LIKELY((CvXSUB(sv) == (XSUBADDR_t)&CAIXS_entersub_wrapper))) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    0          
    0          
199             /*
200             Assert against future XPVCV layout change - as for now, xcv_xsub shares space with xcv_root
201             which are both pointers, so address check is enough, and there's no need to look into op_flags for CvISXSUB.
202             */
203             assert(CvISXSUB(sv));
204              
205 13           POPs; PUTBACK;
206 13           CAIXS_accessor(aTHX_ SP, sv, NULL);
207              
208 20           return NORMAL;
209             }
210              
211             }
212              
213 7           OP_UNSTEAL(OP_ENTERSUB);
214             }
215              
216             template inline
217             void
218 420           CAIXS_install_entersub(pTHX) {
219             /*
220             Check whether we can replace opcode executor with our own variant. Unfortunatelly, this guards
221             only against local changes, not when someone steals PL_ppaddr[OP_ENTERSUB] globally.
222             Sorry, Devel::NYTProf.
223             */
224              
225 420           OP* op = PL_op;
226              
227 420 0         if (
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    100          
    50          
    50          
    50          
    100          
    100          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
228 420           (op->op_spare & 1) != 1
229             &&
230             op->op_type == OP_ENTERSUB
231             &&
232 275           (op->op_flags & OPf_STACKED) /* avoid stealing &sub calls, as we don't want to unpack @_ */
233             &&
234 272           op->op_ppaddr == PL_ppaddr[OP_ENTERSUB]
235             &&
236             optimize_entersub
237             ) {
238 272           op->op_spare |= 1;
239 272           op->op_ppaddr = &CAIXS_entersub;
240              
241             #ifdef CAIX_OPTIMIZE_OPMETHOD
242 272           OP* methop = cUNOPx(op)->op_first;
243 272 0         if (LIKELY(methop != NULL)) { /* Such op can be created by call_sv(G_METHOD_NAMED) */
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    100          
    50          
    0          
244 897 0         while (OpHAS_SIBLING(methop)) { methop = OpSIBLING(methop); }
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    50          
    100          
    50          
    100          
    50          
    100          
    50          
    100          
    50          
    100          
    50          
    100          
    50          
    100          
    50          
    100          
    50          
    100          
    50          
    100          
    50          
    0          
    0          
245              
246 271 0         if (methop->op_next == op) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
247 271 0         if (methop->op_type == OP_METHOD_NAMED && methop->op_ppaddr == PL_ppaddr[OP_METHOD_NAMED]) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    100          
    50          
    50          
    50          
    50          
    50          
    100          
    50          
    100          
    50          
    100          
    50          
    50          
    50          
    0          
    0          
248 231           methop->op_ppaddr = &CAIXS_opmethod_wrapper;
249              
250 40 0         } else if (methop->op_type == OP_METHOD && methop->op_ppaddr == PL_ppaddr[OP_METHOD]) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
251 272           methop->op_ppaddr = &CAIXS_opmethod_wrapper;
252             }
253             }
254             }
255             #endif /* CAIX_OPTIMIZE_OPMETHOD */
256             }
257 420           }
258              
259             #endif /* __INHERITED_XS_OP_H_ */