File Coverage

src/xs/xs.cc
Criterion Covered Total %
statement 2 164 1.2
branch 2 214 0.9
condition n/a
subroutine n/a
pod n/a
total 4 378 1.0


line stmt bran cond sub pod time code
1             #include
2             #include
3             #include
4             #include
5             #include
6             #include
7              
8             namespace xs {
9              
10             my_perl_auto_t my_perl;
11              
12             payload_marker_t sv_payload_default_marker;
13 22           std::map sv_class_markers;
14              
15             const int CVf_NEXT_WRAPPER_CREATED = 0x10000000;
16              
17 0           payload_marker_t* sv_payload_marker (const char* class_name, on_svdup_t dup_callback) {
18 0 0         if (!class_name[0]) return &sv_payload_default_marker;
19 0 0         payload_marker_t* marker = &sv_class_markers[class_name];
    0          
20 0 0         if (!marker->svt_dup && dup_callback) marker->svt_dup = dup_callback;
    0          
21 0           return marker;
22             }
23              
24 0           static SV* _next_create_wrapper (pTHX_ CV* cv, next_t type) {
25 0           CvFLAGS(cv) |= CVf_NEXT_WRAPPER_CREATED;
26 0 0         GV* gv = CvGV(cv);
27 0           HV* stash = GvSTASH(gv);
28 0 0         std::string name = GvNAME(gv);
29 0 0         std::string stashname = HvNAME(stash);
    0          
    0          
    0          
    0          
    0          
    0          
30 0 0         std::string origxs = "_xs_orig_" + name;
31 0           std::string next_code;
32 0           switch (type) {
33 0 0         case NEXT_SUPER: next_code = "shift->SUPER::" + name; break;
    0          
34 0 0         case NEXT_METHOD: next_code = "next::method"; break;
35 0 0         case NEXT_MAYBE: next_code = "maybe::next::method"; break;
36             }
37 0 0         if (!next_code.length()) throw std::invalid_argument("type");
    0          
38             std::string code =
39 0 0         "package " + stashname + ";\n" +
    0          
    0          
40 0 0         "use feature 'state';\n" +
41 0 0         "no warnings 'redefine';\n" +
42 0 0         "BEGIN { *" + origxs + " = \\&" + name + "; }\n" +
    0          
    0          
    0          
    0          
43 0 0         "sub " + name + " {\n" +
    0          
    0          
44 0 0         " eval q!sub " + name + " { " + origxs + "(@_) } !;\n" +
    0          
    0          
    0          
    0          
45 0 0         " " + next_code + "(@_);\n" +
    0          
    0          
46 0 0         "}\n" +
47 0 0         "\\&" + name;
48 0 0         return eval_pv(code.c_str(), 1);
49             }
50              
51 0           SV* call_next (pTHX_ CV* cv, SV** args, I32 items, next_t type, I32 flags) {
52 0           SV* ret = NULL;
53 0 0         if (CvFLAGS(cv) & CVf_NEXT_WRAPPER_CREATED) { // ensure module has a perl wrapper for cv
54 0           dSP; ENTER; SAVETMPS;
55 0 0         PUSHMARK(SP);
56 0 0         for (I32 i = 0; i < items; ++i) XPUSHs(*args++);
    0          
57 0           PUTBACK;
58             int count;
59 0 0         if (type == NEXT_SUPER) {
60 0           GV* gv = CvGV(cv);
61 0 0         GV* supergv = gv_fetchmethod_pvn_flags(
62             GvSTASH(gv), GvNAME(gv), GvNAMELEN(gv), GV_CROAK|GV_SUPER|(GvNAMEUTF8(gv) ? SVf_UTF8 : 0)
63             );
64 0           count = call_sv((SV*)GvCV(supergv), flags|G_SCALAR);
65             } else {
66 0 0         count = call_method(type == NEXT_METHOD ? "next::method" : "maybe::next::method", flags|G_SCALAR);
67             }
68 0           SPAGAIN;
69 0 0         while (count--) ret = POPs;
70 0           SvREFCNT_inc_simple(ret);
71 0           PUTBACK;
72 0 0         FREETMPS; LEAVE;
73             }
74             else {
75 0           SV* wrapper = _next_create_wrapper(aTHX_ cv, type);
76 0           dSP; ENTER; SAVETMPS;
77 0 0         PUSHMARK(SP);
78 0 0         for (I32 i = 0; i < items; ++i) XPUSHs(*args++);
    0          
79 0           PUTBACK;
80 0           int count = call_sv(wrapper, flags|G_SCALAR);
81 0           SPAGAIN;
82 0 0         while (count--) ret = POPs;
83 0 0         SvREFCNT_inc_simple_void(ret);
84 0           PUTBACK;
85 0 0         FREETMPS; LEAVE;
86             }
87              
88 0           return ret;
89             }
90              
91 0           I32 _call_sub (pTHX_ CV* cv, I32 flags, SV** ret, I32 maxret, AV** aref, SV* first_arg, SV** rest_args, I32 rest_items) {
92 0           dSP; ENTER; SAVETMPS;
93 0 0         PUSHMARK(SP);
94 0 0         if (first_arg) XPUSHs(first_arg);
    0          
95 0 0         for (I32 i = 0; i < rest_items; ++i) XPUSHs(*rest_args++);
    0          
96 0           PUTBACK;
97 0 0         if (maxret <= 0 && !aref) { flags |= G_DISCARD; maxret = 0; }
    0          
98 0           I32 count = call_sv((SV*)cv, flags);
99 0 0         I32 nret = count > maxret ? maxret : count;
100 0           SPAGAIN;
101              
102 0 0         if (!aref) {
103 0 0         while (count > maxret) { POPs; --count; }
104 0 0         while (count > 0) ret[--count] = SvREFCNT_inc_NN(POPs);
105             }
106 0 0         else if (count) {
107 0           AV* arr = *aref = newAV();
108 0           av_extend(arr, count-1);
109 0           AvFILLp(arr) = count-1;
110 0           SV** svlist = AvARRAY(arr);
111 0 0         while (count--) svlist[count] = SvREFCNT_inc_NN(POPs);
112             }
113 0           else *aref = NULL;
114              
115 0           PUTBACK;
116 0 0         FREETMPS; LEAVE;
117              
118 0 0         if (aref && *aref) sv_2mortal((SV*)*aref);
    0          
119 0 0         else for (I32 i = 0; i < nret; ++i) sv_2mortal(ret[i]);
120              
121 0           return nret;
122             }
123              
124 0           I32 _call_method (pTHX_ SV* obj, I32 flags, const char* name, STRLEN len, SV** ret, I32 maxret, AV** aref, SV** args, I32 items) {
125 0           HV* stash = NULL;
126 0 0         if (SvROK(obj)) {
127 0           SV* sv = SvRV(obj);
128 0 0         if (SvOBJECT(sv)) stash = SvSTASH(sv);
129             }
130 0 0         if (!stash) stash = gv_stashsv(obj, GV_ADD);
131              
132 0           GV* methgv = gv_fetchmethod_pvn_flags(stash, name, len, GV_CROAK);
133              
134 0           return _call_sub(aTHX_ GvCV(methgv), flags, ret, maxret, aref, obj, args, items);
135             }
136              
137              
138             /* should be called when interpreter is cloned. If we get here then our perl_object is cloned, that is it is present in PL_ptr_table
139             * So we only need to get the new pointer instead of the old one */
140 0           void XSBackref::on_perl_dup (pTHX_ int32_t refcnt) {
141 0 0         if (perl_object) {
142 0           perl_object = MUTABLE_SV(ptr_table_fetch(PL_ptr_table, perl_object));
143             assert(perl_object); assert(refcnt);
144 0           SvREFCNT(perl_object) = refcnt;
145             }
146 0           }
147              
148 0           static size_t module2path (const char* module, char* path) {
149 0           char* pathptr = path;
150 0 0         while (*module) {
151 0 0         if (*module == ':') {
152 0           *pathptr = '/';
153 0           ++module;
154             }
155 0           else *pathptr = *module;
156 0           ++pathptr;
157 0           ++module;
158             }
159 0           *pathptr++ = '.';
160 0           *pathptr++ = 'p';
161 0           *pathptr++ = 'm';
162 0           *pathptr = 0;
163 0           return pathptr-path;
164             }
165              
166 0           bool register_package (pTHX_ const char* module, const char* source_module) {
167 0           char source_module_path[strlen(source_module)+4];
168 0           size_t source_module_path_len = module2path(source_module, source_module_path);
169              
170 0 0         HV* inc = get_hv("INC", GV_ADD);
171 0 0         SV** ref = hv_fetch(inc, source_module_path, source_module_path_len, 0);
172 0 0         if (!ref) return false;
173              
174 0           char module_path[strlen(module)+4];
175 0           size_t module_path_len = module2path(module, module_path);
176 0 0         hv_store(inc, module_path, module_path_len, SvREFCNT_inc(*ref), 0);
177 0           return true;
178             }
179              
180 0           void inherit_package (pTHX_ const char* module, const char* parent) {
181 0           size_t mlen = strlen(module);
182 0           char module_isa[mlen + 6];
183 0           memcpy(module_isa, module, mlen);
184 0           module_isa[mlen] = ':';
185 0           module_isa[mlen+1] = ':';
186 0           module_isa[mlen+2] = 'I';
187 0           module_isa[mlen+3] = 'S';
188 0           module_isa[mlen+4] = 'A';
189 0           module_isa[mlen+5] = 0;
190 0 0         av_push(get_av(module_isa, GV_ADD), newSVpv_share(parent, 0));
    0          
    0          
191 0           }
192              
193 0           SV* error_sv (const std::exception& err) {
194             dTHX;
195              
196             int status;
197 0 0         char* class_name = abi::__cxa_demangle(typeid(err).name(), NULL, NULL, &status);
198 0 0         if (status != 0) croak("[error_sv] !critical! abi::__cxa_demangle error");
199 0 0         SV* errsv = newSVpvs("[");
200 0 0         sv_catpv(errsv, class_name);
201 0 0         sv_catpv(errsv, "] ");
202 0 0         sv_catpv(errsv, err.what());
203 0           free(class_name);
204              
205 0           return errsv;
206             }
207              
208             namespace _tm {
209              
210 0           static inline HV* _get_stash (pTHX_ HV* stash) { return stash; }
211 0           static inline HV* _get_stash (pTHX_ SV* CLASS) { return gv_stashsv(CLASS, GV_ADD); }
212 0           static inline HV* _get_stash (pTHX_ const char* CLASS) { return gv_stashpvn(CLASS, strlen(CLASS), GV_ADD); }
213              
214             template
215 0           static inline SV* _out_oext_ (pTHX_ SV* obase, void* var, C CLASS, payload_marker_t* marker) {
216 0 0         if (!var) return &PL_sv_undef;
    0          
    0          
217             SV* objrv;
218 0 0         if (obase) {
    0          
    0          
219 0 0         if (SvROK(obase)) {
    0          
    0          
220 0           objrv = obase;
221 0           obase = SvRV(obase);
222             }
223             else {
224 0           objrv = newRV_noinc(obase);
225 0           sv_bless(objrv, _get_stash(aTHX_ CLASS));
226             }
227             } else {
228 0           obase = newSV(0);
229 0           objrv = newRV_noinc(obase);
230 0           sv_bless(objrv, _get_stash(aTHX_ CLASS));
231             }
232 0           sv_payload_attach(aTHX_ obase, var, marker);
233 0           return objrv;
234             }
235              
236 0           SV* _out_oext (pTHX_ SV* obase, void* var, HV* CLASS, payload_marker_t* marker) {
237 0           return _out_oext_(aTHX_ obase, var, CLASS, marker);
238             }
239              
240 0           SV* _out_oext (pTHX_ SV* obase, void* var, SV* CLASS, payload_marker_t* marker) {
241 0           return _out_oext_(aTHX_ obase, var, CLASS, marker);
242             }
243              
244 0           SV* _out_oext (pTHX_ SV* obase, void* var, const char* CLASS, payload_marker_t* marker) {
245 0           return _out_oext_(aTHX_ obase, var, CLASS, marker);
246             }
247             }
248              
249 88 50         };
    50