Commit | Line | Data |
739d9a8d |
1 | #define NEED_newRV_noinc_GLOBAL |
2 | #define NEED_sv_2pv_flags_GLOBAL |
3 | #define NEED_sv_2pv_nolen_GLOBAL |
4 | #define NEED_newSVpvn_flags_GLOBAL |
d846ade3 |
5 | #include "mop.h" |
6 | |
7 | void |
1be56175 |
8 | mop_call_xs (pTHX_ XSPROTO(subaddr), CV *cv, SV **mark) |
d846ade3 |
9 | { |
e3dcef7f |
10 | dSP; |
11 | PUSHMARK(mark); |
12 | (*subaddr)(aTHX_ cv); |
13 | PUTBACK; |
d846ade3 |
14 | } |
15 | |
8a2e4cdb |
16 | #if PERL_BCDVERSION >= 0x5010000 |
d846ade3 |
17 | UV |
18 | mop_check_package_cache_flag (pTHX_ HV *stash) |
19 | { |
20 | assert(SvTYPE(stash) == SVt_PVHV); |
21 | |
22 | /* here we're trying to implement a c version of mro::get_pkg_gen($stash), |
23 | * however the perl core doesn't make it easy for us. It doesn't provide an |
24 | * api that just does what we want. |
25 | * |
26 | * However, we know that the information we want is, inside the core, |
27 | * available using HvMROMETA(stash)->pkg_gen. Unfortunately, although the |
28 | * HvMROMETA macro is public, it is implemented using Perl_mro_meta_init, |
29 | * which is not public and only available inside the core, as the mro |
30 | * interface as well as the structure returned by mro_meta_init isn't |
31 | * considered to be stable yet. |
32 | * |
33 | * Perl_mro_meta_init isn't declared static, so we could just define it |
34 | * ourselfs if perls headers don't do that for us, except that won't work |
35 | * on platforms where symbols need to be explicitly exported when linking |
36 | * shared libraries. |
37 | * |
38 | * So our, hopefully temporary, solution is to be even more evil and |
39 | * basically reimplement HvMROMETA in a very fragile way that'll blow up |
40 | * when the relevant parts of the mro implementation in core change. |
41 | * |
42 | * :-( |
43 | * |
44 | */ |
45 | |
46 | return HvAUX(stash)->xhv_mro_meta |
47 | ? HvAUX(stash)->xhv_mro_meta->pkg_gen |
48 | : 0; |
49 | } |
50 | |
51 | #else /* pre 5.10.0 */ |
52 | |
53 | UV |
54 | mop_check_package_cache_flag (pTHX_ HV *stash) |
55 | { |
56 | PERL_UNUSED_ARG(stash); |
57 | assert(SvTYPE(stash) == SVt_PVHV); |
58 | |
59 | return PL_sub_generation; |
60 | } |
61 | #endif |
62 | |
63 | SV * |
64 | mop_call0 (pTHX_ SV *const self, SV *const method) |
65 | { |
66 | dSP; |
67 | SV *ret; |
68 | |
69 | PUSHMARK(SP); |
70 | XPUSHs(self); |
71 | PUTBACK; |
72 | |
73 | call_sv(method, G_SCALAR | G_METHOD); |
74 | |
75 | SPAGAIN; |
76 | ret = POPs; |
77 | PUTBACK; |
78 | |
79 | return ret; |
80 | } |
81 | |
353c6152 |
82 | SV * |
83 | mop_call1 (pTHX_ SV *const self, SV *const method, SV* const arg1) |
84 | { |
85 | dSP; |
86 | SV *ret; |
87 | |
88 | PUSHMARK(SP); |
89 | EXTEND(SP, 2); |
90 | PUSHs(self); |
91 | PUSHs(arg1); |
92 | PUTBACK; |
93 | |
94 | call_sv(method, G_SCALAR | G_METHOD); |
95 | |
96 | SPAGAIN; |
97 | ret = POPs; |
98 | PUTBACK; |
99 | |
100 | return ret; |
101 | } |
102 | |
103 | |
d846ade3 |
104 | int |
e1f52a8a |
105 | mop_get_code_info (SV *coderef, char **pkg, char **name) |
d846ade3 |
106 | { |
107 | if (!SvOK(coderef) || !SvROK(coderef) || SvTYPE(SvRV(coderef)) != SVt_PVCV) { |
108 | return 0; |
109 | } |
110 | |
111 | coderef = SvRV(coderef); |
caa6b5cd |
112 | |
113 | /* sub is still being compiled */ |
114 | if (!CvGV(coderef)) { |
115 | return 0; |
116 | } |
117 | |
d846ade3 |
118 | /* I think this only gets triggered with a mangled coderef, but if |
119 | we hit it without the guard, we segfault. The slightly odd return |
120 | value strikes me as an improvement (mst) |
121 | */ |
9b52bbf1 |
122 | |
d846ade3 |
123 | if ( isGV_with_GP(CvGV(coderef)) ) { |
2087a201 |
124 | GV *gv = CvGV(coderef); |
125 | *pkg = HvNAME( GvSTASH(gv) ? GvSTASH(gv) : CvSTASH(coderef) ); |
d846ade3 |
126 | *name = GvNAME( CvGV(coderef) ); |
d846ade3 |
127 | } else { |
128 | *pkg = "__UNKNOWN__"; |
129 | *name = "__ANON__"; |
130 | } |
d846ade3 |
131 | |
132 | return 1; |
133 | } |
134 | |
135 | void |
e1f52a8a |
136 | mop_get_package_symbols (HV *stash, type_filter_t filter, get_package_symbols_cb_t cb, void *ud) |
d846ade3 |
137 | { |
353c6152 |
138 | dTHX; |
d846ade3 |
139 | HE *he; |
140 | |
141 | (void)hv_iterinit(stash); |
142 | |
143 | if (filter == TYPE_FILTER_NONE) { |
144 | while ( (he = hv_iternext(stash)) ) { |
145 | STRLEN keylen; |
146 | const char *key = HePV(he, keylen); |
147 | if (!cb(key, keylen, HeVAL(he), ud)) { |
148 | return; |
149 | } |
150 | } |
151 | return; |
152 | } |
153 | |
154 | while ( (he = hv_iternext(stash)) ) { |
155 | SV *const gv = HeVAL(he); |
156 | SV *sv = NULL; |
157 | char *key; |
158 | STRLEN keylen; |
159 | char *package; |
d846ade3 |
160 | |
161 | switch( SvTYPE(gv) ) { |
162 | #ifndef SVt_RV |
163 | case SVt_RV: |
164 | #endif |
165 | case SVt_PV: |
166 | case SVt_IV: |
167 | /* expand the gv into a real typeglob if it |
168 | * contains stub functions and we were asked to |
169 | * return CODE symbols */ |
170 | if (filter == TYPE_FILTER_CODE) { |
171 | if (SvROK(gv)) { |
8a2e4cdb |
172 | SV* fq; |
d846ade3 |
173 | /* we don't really care about the length, |
174 | but that's the API */ |
175 | key = HePV(he, keylen); |
176 | package = HvNAME(stash); |
efc98200 |
177 | fq = sv_2mortal(newSVpvf("%s::%s", package, key)); |
d846ade3 |
178 | sv = (SV *)get_cv(SvPV_nolen(fq), 0); |
179 | break; |
180 | } |
181 | |
182 | key = HePV(he, keylen); |
183 | gv_init((GV *)gv, stash, key, keylen, GV_ADDMULTI); |
184 | } |
185 | /* fall through */ |
186 | case SVt_PVGV: |
187 | switch (filter) { |
188 | case TYPE_FILTER_CODE: sv = (SV *)GvCVu(gv); break; |
189 | case TYPE_FILTER_ARRAY: sv = (SV *)GvAV(gv); break; |
190 | case TYPE_FILTER_IO: sv = (SV *)GvIO(gv); break; |
191 | case TYPE_FILTER_HASH: sv = (SV *)GvHV(gv); break; |
192 | case TYPE_FILTER_SCALAR: sv = (SV *)GvSV(gv); break; |
193 | default: |
194 | croak("Unknown type"); |
195 | } |
196 | break; |
197 | default: |
198 | continue; |
199 | } |
200 | |
201 | if (sv) { |
202 | const char *key = HePV(he, keylen); |
203 | if (!cb(key, keylen, sv, ud)) { |
204 | return; |
205 | } |
206 | } |
207 | } |
208 | } |
209 | |
210 | static bool |
211 | collect_all_symbols (const char *key, STRLEN keylen, SV *val, void *ud) |
212 | { |
353c6152 |
213 | dTHX; |
d846ade3 |
214 | HV *hash = (HV *)ud; |
215 | |
216 | if (!hv_store (hash, key, keylen, newRV_inc(val), 0)) { |
217 | croak("failed to store symbol ref"); |
218 | } |
219 | |
220 | return TRUE; |
221 | } |
222 | |
223 | HV * |
e1f52a8a |
224 | mop_get_all_package_symbols (HV *stash, type_filter_t filter) |
d846ade3 |
225 | { |
353c6152 |
226 | dTHX; |
d846ade3 |
227 | HV *ret = newHV (); |
e1f52a8a |
228 | mop_get_package_symbols (stash, filter, collect_all_symbols, ret); |
d846ade3 |
229 | return ret; |
230 | } |
22932438 |
231 | |
22932438 |
232 | |
353c6152 |
233 | MAGIC* |
234 | mop_mg_find(pTHX_ SV* const sv, const MGVTBL* const vtbl, I32 const flags){ |
8a2e4cdb |
235 | MAGIC* mg; |
236 | |
237 | assert(sv != NULL); |
238 | for(mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic){ |
239 | if(mg->mg_virtual == vtbl){ |
353c6152 |
240 | return mg; |
8a2e4cdb |
241 | } |
22932438 |
242 | } |
22932438 |
243 | |
353c6152 |
244 | if(flags & MOPf_DIE_ON_FAIL){ |
245 | croak("mop_mg_find: no MAGIC found for %"SVf, sv_2mortal(newRV_inc(sv))); |
a69b9501 |
246 | } |
247 | return NULL; |
248 | } |