Commit | Line | Data |
38bf2a25 |
1 | #include "mop.h" |
2 | |
3 | void |
4 | mop_call_xs (pTHX_ XSPROTO(subaddr), CV *cv, SV **mark) |
5 | { |
6 | dSP; |
7 | PUSHMARK(mark); |
8 | (*subaddr)(aTHX_ cv); |
9 | PUTBACK; |
10 | } |
11 | |
12 | #if PERL_VERSION >= 10 |
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 |
79 | mop_get_code_info (SV *coderef, char **pkg, char **name) |
80 | { |
81 | if (!SvOK(coderef) || !SvROK(coderef) || SvTYPE(SvRV(coderef)) != SVt_PVCV) { |
82 | return 0; |
83 | } |
84 | |
85 | coderef = SvRV(coderef); |
86 | |
87 | /* sub is still being compiled */ |
88 | if (!CvGV(coderef)) { |
89 | return 0; |
90 | } |
91 | |
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 | */ |
96 | |
97 | if ( isGV_with_GP(CvGV(coderef)) ) { |
9b2ef039 |
98 | GV *gv = CvGV(coderef); |
99 | HV *stash = GvSTASH(gv) ? GvSTASH(gv) : CvSTASH(coderef); |
100 | |
101 | *pkg = stash ? HvNAME(stash) : "__UNKNOWN__"; |
102 | *name = GvNAME( CvGV(coderef) ); |
38bf2a25 |
103 | } else { |
9b2ef039 |
104 | *pkg = "__UNKNOWN__"; |
105 | *name = "__ANON__"; |
38bf2a25 |
106 | } |
107 | |
108 | return 1; |
109 | } |
110 | |
111 | /* XXX: eventually this should just use the implementation in Package::Stash */ |
112 | void |
113 | mop_get_package_symbols (HV *stash, type_filter_t filter, get_package_symbols_cb_t cb, void *ud) |
114 | { |
115 | HE *he; |
116 | |
117 | (void)hv_iterinit(stash); |
118 | |
119 | if (filter == TYPE_FILTER_NONE) { |
120 | while ( (he = hv_iternext(stash)) ) { |
121 | STRLEN keylen; |
122 | const char *key = HePV(he, keylen); |
123 | if (!cb(key, keylen, HeVAL(he), ud)) { |
124 | return; |
125 | } |
126 | } |
127 | return; |
128 | } |
129 | |
130 | while ( (he = hv_iternext(stash)) ) { |
131 | GV * const gv = (GV*)HeVAL(he); |
132 | STRLEN keylen; |
133 | const char * const key = HePV(he, keylen); |
134 | SV *sv = NULL; |
135 | |
136 | if(isGV(gv)){ |
137 | switch (filter) { |
138 | case TYPE_FILTER_CODE: sv = (SV *)GvCVu(gv); break; |
139 | case TYPE_FILTER_ARRAY: sv = (SV *)GvAV(gv); break; |
140 | case TYPE_FILTER_IO: sv = (SV *)GvIO(gv); break; |
141 | case TYPE_FILTER_HASH: sv = (SV *)GvHV(gv); break; |
142 | case TYPE_FILTER_SCALAR: sv = (SV *)GvSV(gv); break; |
143 | default: |
144 | croak("Unknown type"); |
145 | } |
146 | } |
147 | /* expand the gv into a real typeglob if it |
148 | * contains stub functions or constants and we |
149 | * were asked to return CODE references */ |
150 | else if (filter == TYPE_FILTER_CODE) { |
151 | gv_init(gv, stash, key, keylen, GV_ADDMULTI); |
152 | sv = (SV *)GvCV(gv); |
153 | } |
154 | |
155 | if (sv) { |
156 | if (!cb(key, keylen, sv, ud)) { |
157 | return; |
158 | } |
159 | } |
160 | } |
161 | } |
162 | |
163 | static bool |
164 | collect_all_symbols (const char *key, STRLEN keylen, SV *val, void *ud) |
165 | { |
166 | HV *hash = (HV *)ud; |
167 | |
168 | if (!hv_store (hash, key, keylen, newRV_inc(val), 0)) { |
169 | croak("failed to store symbol ref"); |
170 | } |
171 | |
172 | return TRUE; |
173 | } |
174 | |
175 | HV * |
176 | mop_get_all_package_symbols (HV *stash, type_filter_t filter) |
177 | { |
178 | HV *ret = newHV (); |
179 | mop_get_package_symbols (stash, filter, collect_all_symbols, ret); |
180 | return ret; |
181 | } |
182 | |
183 | #define DECLARE_KEY(name) { #name, #name, NULL, 0 } |
184 | #define DECLARE_KEY_WITH_VALUE(name, value) { #name, value, NULL, 0 } |
185 | |
186 | /* the order of these has to match with those in mop.h */ |
187 | static struct { |
188 | const char *name; |
189 | const char *value; |
190 | SV *key; |
191 | U32 hash; |
192 | } prehashed_keys[key_last] = { |
193 | DECLARE_KEY(_expected_method_class), |
194 | DECLARE_KEY(ISA), |
195 | DECLARE_KEY(VERSION), |
196 | DECLARE_KEY(accessor), |
197 | DECLARE_KEY(associated_class), |
198 | DECLARE_KEY(associated_metaclass), |
199 | DECLARE_KEY(associated_methods), |
200 | DECLARE_KEY(attribute_metaclass), |
201 | DECLARE_KEY(attributes), |
202 | DECLARE_KEY(body), |
203 | DECLARE_KEY(builder), |
204 | DECLARE_KEY(clearer), |
205 | DECLARE_KEY(constructor_class), |
206 | DECLARE_KEY(constructor_name), |
207 | DECLARE_KEY(definition_context), |
208 | DECLARE_KEY(destructor_class), |
209 | DECLARE_KEY(immutable_trait), |
210 | DECLARE_KEY(init_arg), |
211 | DECLARE_KEY(initializer), |
212 | DECLARE_KEY(insertion_order), |
213 | DECLARE_KEY(instance_metaclass), |
214 | DECLARE_KEY(is_inline), |
215 | DECLARE_KEY(method_metaclass), |
216 | DECLARE_KEY(methods), |
217 | DECLARE_KEY(name), |
218 | DECLARE_KEY(package), |
219 | DECLARE_KEY(package_name), |
220 | DECLARE_KEY(predicate), |
221 | DECLARE_KEY(reader), |
222 | DECLARE_KEY(wrapped_method_metaclass), |
223 | DECLARE_KEY(writer), |
224 | DECLARE_KEY_WITH_VALUE(package_cache_flag, "_package_cache_flag"), |
2683d371 |
225 | DECLARE_KEY_WITH_VALUE(_version, "-version"), |
644d6eaa |
226 | DECLARE_KEY(operator) |
38bf2a25 |
227 | }; |
228 | |
229 | SV * |
230 | mop_prehashed_key_for (mop_prehashed_key_t key) |
231 | { |
232 | return prehashed_keys[key].key; |
233 | } |
234 | |
235 | U32 |
236 | mop_prehashed_hash_for (mop_prehashed_key_t key) |
237 | { |
238 | return prehashed_keys[key].hash; |
239 | } |
240 | |
241 | void |
242 | mop_prehash_keys () |
243 | { |
244 | int i; |
245 | for (i = 0; i < key_last; i++) { |
246 | const char *value = prehashed_keys[i].value; |
247 | prehashed_keys[i].key = newSVpv(value, strlen(value)); |
248 | PERL_HASH(prehashed_keys[i].hash, value, strlen(value)); |
249 | } |
250 | } |
251 | |
cdcadcbe |
252 | XS_EXTERNAL(mop_xs_simple_reader) |
38bf2a25 |
253 | { |
254 | #ifdef dVAR |
255 | dVAR; dXSARGS; |
256 | #else |
257 | dXSARGS; |
258 | #endif |
259 | register HE *he; |
260 | mop_prehashed_key_t key = (mop_prehashed_key_t)CvXSUBANY(cv).any_i32; |
261 | SV *self; |
262 | |
263 | if (items != 1) { |
264 | croak("expected exactly one argument"); |
265 | } |
266 | |
267 | self = ST(0); |
268 | |
269 | if (!SvROK(self)) { |
270 | croak("can't call %s as a class method", prehashed_keys[key].name); |
271 | } |
272 | |
273 | if (SvTYPE(SvRV(self)) != SVt_PVHV) { |
274 | croak("object is not a hashref"); |
275 | } |
276 | |
277 | if ((he = hv_fetch_ent((HV *)SvRV(self), prehashed_keys[key].key, 0, prehashed_keys[key].hash))) { |
278 | ST(0) = HeVAL(he); |
279 | } |
280 | else { |
281 | ST(0) = &PL_sv_undef; |
282 | } |
283 | |
284 | XSRETURN(1); |
285 | } |
286 | |