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