Commit | Line | Data |
d846ade3 |
1 | #include "mop.h" |
2 | |
3 | void |
1be56175 |
4 | mop_call_xs (pTHX_ XSPROTO(subaddr), CV *cv, SV **mark) |
d846ade3 |
5 | { |
e3dcef7f |
6 | dSP; |
7 | PUSHMARK(mark); |
8 | (*subaddr)(aTHX_ cv); |
9 | PUTBACK; |
d846ade3 |
10 | } |
11 | |
1bc0cb6b |
12 | #if PERL_BCDVERSION >= 0x5010000 |
d846ade3 |
13 | UV |
14 | mop_check_package_cache_flag (pTHX_ HV *stash) |
15 | { |
16 | assert(SvTYPE(stash) == SVt_PVHV); |
17 | |
18 | /* here we're trying to implement a c version of mro::get_pkg_gen($stash), |
19 | * however the perl core doesn't make it easy for us. It doesn't provide an |
20 | * api that just does what we want. |
21 | * |
22 | * However, we know that the information we want is, inside the core, |
23 | * available using HvMROMETA(stash)->pkg_gen. Unfortunately, although the |
24 | * HvMROMETA macro is public, it is implemented using Perl_mro_meta_init, |
25 | * which is not public and only available inside the core, as the mro |
26 | * interface as well as the structure returned by mro_meta_init isn't |
27 | * considered to be stable yet. |
28 | * |
29 | * Perl_mro_meta_init isn't declared static, so we could just define it |
30 | * ourselfs if perls headers don't do that for us, except that won't work |
31 | * on platforms where symbols need to be explicitly exported when linking |
32 | * shared libraries. |
33 | * |
34 | * So our, hopefully temporary, solution is to be even more evil and |
35 | * basically reimplement HvMROMETA in a very fragile way that'll blow up |
36 | * when the relevant parts of the mro implementation in core change. |
37 | * |
38 | * :-( |
39 | * |
40 | */ |
41 | |
42 | return HvAUX(stash)->xhv_mro_meta |
43 | ? HvAUX(stash)->xhv_mro_meta->pkg_gen |
44 | : 0; |
45 | } |
46 | |
47 | #else /* pre 5.10.0 */ |
48 | |
49 | UV |
50 | mop_check_package_cache_flag (pTHX_ HV *stash) |
51 | { |
52 | PERL_UNUSED_ARG(stash); |
53 | assert(SvTYPE(stash) == SVt_PVHV); |
54 | |
55 | return PL_sub_generation; |
56 | } |
57 | #endif |
58 | |
59 | SV * |
60 | mop_call0 (pTHX_ SV *const self, SV *const method) |
61 | { |
62 | dSP; |
63 | SV *ret; |
64 | |
65 | PUSHMARK(SP); |
66 | XPUSHs(self); |
67 | PUTBACK; |
68 | |
69 | call_sv(method, G_SCALAR | G_METHOD); |
70 | |
71 | SPAGAIN; |
72 | ret = POPs; |
73 | PUTBACK; |
74 | |
75 | return ret; |
76 | } |
77 | |
78 | int |
e1f52a8a |
79 | mop_get_code_info (SV *coderef, char **pkg, char **name) |
d846ade3 |
80 | { |
81 | if (!SvOK(coderef) || !SvROK(coderef) || SvTYPE(SvRV(coderef)) != SVt_PVCV) { |
82 | return 0; |
83 | } |
84 | |
85 | coderef = SvRV(coderef); |
caa6b5cd |
86 | |
87 | /* sub is still being compiled */ |
88 | if (!CvGV(coderef)) { |
89 | return 0; |
90 | } |
91 | |
d846ade3 |
92 | /* I think this only gets triggered with a mangled coderef, but if |
93 | we hit it without the guard, we segfault. The slightly odd return |
94 | value strikes me as an improvement (mst) |
95 | */ |
9b52bbf1 |
96 | |
d846ade3 |
97 | if ( isGV_with_GP(CvGV(coderef)) ) { |
2087a201 |
98 | GV *gv = CvGV(coderef); |
99 | *pkg = HvNAME( GvSTASH(gv) ? GvSTASH(gv) : CvSTASH(coderef) ); |
d846ade3 |
100 | *name = GvNAME( CvGV(coderef) ); |
d846ade3 |
101 | } else { |
102 | *pkg = "__UNKNOWN__"; |
103 | *name = "__ANON__"; |
104 | } |
d846ade3 |
105 | |
106 | return 1; |
107 | } |
108 | |
109 | void |
e1f52a8a |
110 | mop_get_package_symbols (HV *stash, type_filter_t filter, get_package_symbols_cb_t cb, void *ud) |
d846ade3 |
111 | { |
112 | HE *he; |
113 | |
114 | (void)hv_iterinit(stash); |
115 | |
116 | if (filter == TYPE_FILTER_NONE) { |
117 | while ( (he = hv_iternext(stash)) ) { |
118 | STRLEN keylen; |
119 | const char *key = HePV(he, keylen); |
120 | if (!cb(key, keylen, HeVAL(he), ud)) { |
121 | return; |
122 | } |
123 | } |
124 | return; |
125 | } |
126 | |
127 | while ( (he = hv_iternext(stash)) ) { |
9135ad30 |
128 | GV * const gv = (GV*)HeVAL(he); |
d846ade3 |
129 | STRLEN keylen; |
9135ad30 |
130 | const char * const key = HePV(he, keylen); |
131 | SV *sv = NULL; |
d846ade3 |
132 | |
9135ad30 |
133 | if(isGV(gv)){ |
134 | switch (filter) { |
135 | case TYPE_FILTER_CODE: sv = (SV *)GvCVu(gv); break; |
136 | case TYPE_FILTER_ARRAY: sv = (SV *)GvAV(gv); break; |
137 | case TYPE_FILTER_IO: sv = (SV *)GvIO(gv); break; |
138 | case TYPE_FILTER_HASH: sv = (SV *)GvHV(gv); break; |
139 | case TYPE_FILTER_SCALAR: sv = (SV *)GvSV(gv); break; |
140 | default: |
141 | croak("Unknown type"); |
142 | } |
143 | } |
144 | /* expand the gv into a real typeglob if it |
145 | * contains stub functions or constants and we |
146 | * were asked to return CODE references */ |
147 | else if (filter == TYPE_FILTER_CODE) { |
148 | gv_init(gv, stash, key, keylen, GV_ADDMULTI); |
149 | sv = (SV *)GvCV(gv); |
d846ade3 |
150 | } |
151 | |
152 | if (sv) { |
d846ade3 |
153 | if (!cb(key, keylen, sv, ud)) { |
154 | return; |
155 | } |
156 | } |
157 | } |
158 | } |
159 | |
160 | static bool |
161 | collect_all_symbols (const char *key, STRLEN keylen, SV *val, void *ud) |
162 | { |
163 | HV *hash = (HV *)ud; |
164 | |
165 | if (!hv_store (hash, key, keylen, newRV_inc(val), 0)) { |
166 | croak("failed to store symbol ref"); |
167 | } |
168 | |
169 | return TRUE; |
170 | } |
171 | |
172 | HV * |
e1f52a8a |
173 | mop_get_all_package_symbols (HV *stash, type_filter_t filter) |
d846ade3 |
174 | { |
175 | HV *ret = newHV (); |
e1f52a8a |
176 | mop_get_package_symbols (stash, filter, collect_all_symbols, ret); |
d846ade3 |
177 | return ret; |
178 | } |
22932438 |
179 | |
1bc0cb6b |
180 | static MGVTBL mop_accessor_vtbl; /* the MAGIC identity */ |
22932438 |
181 | |
206860b8 |
182 | CV* |
183 | mop_install_simple_accessor(pTHX_ const char* const fq_name, const char* const key, I32 const keylen, XSPROTO(accessor_impl)){ |
184 | CV* const xsub = newXS((char*)fq_name, accessor_impl, __FILE__); |
185 | SV* const keysv = newSVpvn_share(key, keylen, 0U); |
22932438 |
186 | |
1bc0cb6b |
187 | sv_magicext((SV*)xsub, keysv, PERL_MAGIC_ext, &mop_accessor_vtbl, NULL, 0); |
188 | SvREFCNT_dec(keysv); /* sv_magicext() increases refcnt in mg_obj */ |
206860b8 |
189 | return xsub; |
22932438 |
190 | } |
191 | |
1bc0cb6b |
192 | static MAGIC* |
206860b8 |
193 | mop_mg_find_by_vtbl(pTHX_ SV* const sv, const MGVTBL* const vtbl){ |
1bc0cb6b |
194 | MAGIC* mg; |
195 | |
196 | assert(sv != NULL); |
197 | for(mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic){ |
198 | if(mg->mg_virtual == vtbl){ |
199 | break; |
200 | } |
22932438 |
201 | } |
1bc0cb6b |
202 | return mg; |
22932438 |
203 | } |
7ec7b950 |
204 | |
206860b8 |
205 | static SV* |
206 | mop_fetch_attr(pTHX_ SV* const self, SV* const key, I32 const create, CV* const cv){ |
207 | HE* he; |
208 | if (!SvROK(self)) { |
209 | croak("can't call %s as a class method", GvNAME(CvGV(cv))); |
210 | } |
211 | if (SvTYPE(SvRV(self)) != SVt_PVHV) { |
212 | croak("object is not a hashref"); |
213 | } |
214 | if((he = hv_fetch_ent((HV*)SvRV(self), key, create, 0U))){ |
215 | return HeVAL(he); |
216 | } |
217 | return NULL; |
218 | } |
219 | static SV* |
220 | mop_delete_attr(pTHX_ SV* const self, SV* const key, CV* const cv){ |
221 | SV* sv; |
222 | if (!SvROK(self)) { |
223 | croak("can't call %s as a class method", GvNAME(CvGV(cv))); |
224 | } |
225 | if (SvTYPE(SvRV(self)) != SVt_PVHV) { |
226 | croak("object is not a hashref"); |
227 | } |
228 | if((sv = hv_delete_ent((HV*)SvRV(self), key, 0, 0U))){ |
229 | return sv; |
230 | } |
231 | return NULL; |
232 | } |
233 | |
234 | XS(mop_xs_simple_accessor) |
235 | { |
236 | dVAR; dXSARGS; |
237 | MAGIC* const mg = mop_mg_find_by_vtbl(aTHX_ (SV*)cv, &mop_accessor_vtbl); |
238 | SV* const key = mg->mg_obj; |
239 | SV* attr; |
240 | if(items == 1){ /* reader */ |
241 | attr = mop_fetch_attr(aTHX_ ST(0), key, FALSE, cv); |
242 | } |
243 | else if (items == 2){ /* writer */ |
244 | attr = mop_fetch_attr(aTHX_ ST(0), key, TRUE, cv); |
245 | sv_setsv(attr, ST(1)); |
246 | } |
247 | else{ |
248 | croak("expected exactly one or two argument"); |
249 | } |
250 | ST(0) = attr ? attr : &PL_sv_undef; |
251 | XSRETURN(1); |
252 | } |
253 | |
254 | |
384bb6c9 |
255 | XS(mop_xs_simple_reader) |
7ec7b950 |
256 | { |
384bb6c9 |
257 | dVAR; dXSARGS; |
206860b8 |
258 | MAGIC* const mg = mop_mg_find_by_vtbl(aTHX_ (SV*)cv, &mop_accessor_vtbl); |
1bc0cb6b |
259 | SV* const key = mg->mg_obj; |
206860b8 |
260 | SV* attr; |
384bb6c9 |
261 | |
262 | if (items != 1) { |
263 | croak("expected exactly one argument"); |
264 | } |
265 | |
206860b8 |
266 | attr = mop_fetch_attr(aTHX_ ST(0), key, FALSE, cv); |
267 | ST(0) = attr ? attr : &PL_sv_undef; |
268 | XSRETURN(1); |
269 | } |
7ec7b950 |
270 | |
206860b8 |
271 | XS(mop_xs_simple_writer) |
272 | { |
273 | dVAR; dXSARGS; |
274 | MAGIC* const mg = mop_mg_find_by_vtbl(aTHX_ (SV*)cv, &mop_accessor_vtbl); |
275 | SV* const key = mg->mg_obj; |
276 | SV* attr; |
277 | |
278 | if (items != 2) { |
279 | croak("expected exactly two argument"); |
7ec7b950 |
280 | } |
281 | |
206860b8 |
282 | attr = mop_fetch_attr(aTHX_ ST(0), key, TRUE, cv); |
283 | sv_setsv(attr, ST(1)); |
284 | ST(0) = attr; |
285 | XSRETURN(1); |
286 | } |
287 | |
288 | XS(mop_xs_simple_clearer) |
289 | { |
290 | dVAR; dXSARGS; |
291 | MAGIC* const mg = mop_mg_find_by_vtbl(aTHX_ (SV*)cv, &mop_accessor_vtbl); |
292 | SV* const key = mg->mg_obj; |
293 | SV* attr; |
294 | |
295 | if (items != 1) { |
296 | croak("expected exactly one argument"); |
7ec7b950 |
297 | } |
298 | |
206860b8 |
299 | attr = mop_delete_attr(aTHX_ ST(0), key, cv); |
300 | ST(0) = attr ? attr : &PL_sv_undef; |
301 | XSRETURN(1); |
302 | } |
303 | |
304 | |
305 | XS(mop_xs_simple_predicate) |
306 | { |
307 | dVAR; dXSARGS; |
308 | MAGIC* const mg = mop_mg_find_by_vtbl(aTHX_ (SV*)cv, &mop_accessor_vtbl); |
309 | SV* const key = mg->mg_obj; |
310 | SV* attr; |
311 | |
312 | if (items != 1) { |
313 | croak("expected exactly one argument"); |
7ec7b950 |
314 | } |
206860b8 |
315 | |
316 | attr = mop_fetch_attr(aTHX_ ST(0), key, FALSE, cv); |
317 | ST(0) = boolSV(attr); /* exists */ |
318 | XSRETURN(1); |
319 | } |
320 | |
321 | |
322 | XS(mop_xs_simple_predicate_for_metaclass) |
323 | { |
324 | dVAR; dXSARGS; |
325 | MAGIC* const mg = mop_mg_find_by_vtbl(aTHX_ (SV*)cv, &mop_accessor_vtbl); |
326 | SV* const key = mg->mg_obj; |
327 | SV* attr; |
328 | |
329 | if (items != 1) { |
330 | croak("expected exactly one argument"); |
7ec7b950 |
331 | } |
332 | |
206860b8 |
333 | attr = mop_fetch_attr(aTHX_ ST(0), key, FALSE, cv); |
334 | ST(0) = boolSV(attr && SvOK(attr)); /* defined */ |
7ec7b950 |
335 | XSRETURN(1); |
336 | } |