Commit | Line | Data |
d846ade3 |
1 | #include "mop.h" |
2 | |
3 | void |
4 | mop_call_xs (pTHX_ void (*subaddr) (pTHX_ CV *), 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 | 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 | /* I think this only gets triggered with a mangled coderef, but if |
87 | we hit it without the guard, we segfault. The slightly odd return |
88 | value strikes me as an improvement (mst) |
89 | */ |
90 | #ifdef isGV_with_GP |
91 | if ( isGV_with_GP(CvGV(coderef)) ) { |
92 | #endif |
93 | *pkg = HvNAME( GvSTASH(CvGV(coderef)) ); |
94 | *name = GvNAME( CvGV(coderef) ); |
95 | #ifdef isGV_with_GP |
96 | } else { |
97 | *pkg = "__UNKNOWN__"; |
98 | *name = "__ANON__"; |
99 | } |
100 | #endif |
101 | |
102 | return 1; |
103 | } |
104 | |
105 | void |
106 | get_package_symbols (HV *stash, type_filter_t filter, get_package_symbols_cb_t cb, void *ud) |
107 | { |
108 | HE *he; |
109 | |
110 | (void)hv_iterinit(stash); |
111 | |
112 | if (filter == TYPE_FILTER_NONE) { |
113 | while ( (he = hv_iternext(stash)) ) { |
114 | STRLEN keylen; |
115 | const char *key = HePV(he, keylen); |
116 | if (!cb(key, keylen, HeVAL(he), ud)) { |
117 | return; |
118 | } |
119 | } |
120 | return; |
121 | } |
122 | |
123 | while ( (he = hv_iternext(stash)) ) { |
124 | SV *const gv = HeVAL(he); |
125 | SV *sv = NULL; |
126 | char *key; |
127 | STRLEN keylen; |
128 | char *package; |
129 | SV *fq; |
130 | |
131 | switch( SvTYPE(gv) ) { |
132 | #ifndef SVt_RV |
133 | case SVt_RV: |
134 | #endif |
135 | case SVt_PV: |
136 | case SVt_IV: |
137 | /* expand the gv into a real typeglob if it |
138 | * contains stub functions and we were asked to |
139 | * return CODE symbols */ |
140 | if (filter == TYPE_FILTER_CODE) { |
141 | if (SvROK(gv)) { |
142 | /* we don't really care about the length, |
143 | but that's the API */ |
144 | key = HePV(he, keylen); |
145 | package = HvNAME(stash); |
146 | fq = newSVpvf("%s::%s", package, key); |
147 | sv = (SV *)get_cv(SvPV_nolen(fq), 0); |
148 | break; |
149 | } |
150 | |
151 | key = HePV(he, keylen); |
152 | gv_init((GV *)gv, stash, key, keylen, GV_ADDMULTI); |
153 | } |
154 | /* fall through */ |
155 | case SVt_PVGV: |
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 | break; |
166 | default: |
167 | continue; |
168 | } |
169 | |
170 | if (sv) { |
171 | const char *key = HePV(he, keylen); |
172 | if (!cb(key, keylen, sv, ud)) { |
173 | return; |
174 | } |
175 | } |
176 | } |
177 | } |
178 | |
179 | static bool |
180 | collect_all_symbols (const char *key, STRLEN keylen, SV *val, void *ud) |
181 | { |
182 | HV *hash = (HV *)ud; |
183 | |
184 | if (!hv_store (hash, key, keylen, newRV_inc(val), 0)) { |
185 | croak("failed to store symbol ref"); |
186 | } |
187 | |
188 | return TRUE; |
189 | } |
190 | |
191 | HV * |
192 | get_all_package_symbols (HV *stash, type_filter_t filter) |
193 | { |
194 | HV *ret = newHV (); |
195 | get_package_symbols (stash, filter, collect_all_symbols, ret); |
196 | return ret; |
197 | } |