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