Fix profile.pl
[gitmo/Class-MOP.git] / mop.c
CommitLineData
90e2d066 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
7void
1be56175 8mop_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
1bc0cb6b 16#if PERL_BCDVERSION >= 0x5010000
d846ade3 17UV
18mop_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
53UV
54mop_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
63SV *
64mop_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
e989c0df 82SV *
83mop_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 104int
e1f52a8a 105mop_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
135void
e1f52a8a 136mop_get_package_symbols (HV *stash, type_filter_t filter, get_package_symbols_cb_t cb, void *ud)
d846ade3 137{
e989c0df 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)) ) {
9135ad30 155 GV * const gv = (GV*)HeVAL(he);
d846ade3 156 STRLEN keylen;
9135ad30 157 const char * const key = HePV(he, keylen);
158 SV *sv = NULL;
d846ade3 159
9135ad30 160 if(isGV(gv)){
161 switch (filter) {
162 case TYPE_FILTER_CODE: sv = (SV *)GvCVu(gv); break;
163 case TYPE_FILTER_ARRAY: sv = (SV *)GvAV(gv); break;
164 case TYPE_FILTER_IO: sv = (SV *)GvIO(gv); break;
165 case TYPE_FILTER_HASH: sv = (SV *)GvHV(gv); break;
166 case TYPE_FILTER_SCALAR: sv = (SV *)GvSV(gv); break;
167 default:
168 croak("Unknown type");
169 }
170 }
171 /* expand the gv into a real typeglob if it
172 * contains stub functions or constants and we
173 * were asked to return CODE references */
174 else if (filter == TYPE_FILTER_CODE) {
175 gv_init(gv, stash, key, keylen, GV_ADDMULTI);
176 sv = (SV *)GvCV(gv);
d846ade3 177 }
178
179 if (sv) {
d846ade3 180 if (!cb(key, keylen, sv, ud)) {
181 return;
182 }
183 }
184 }
185}
186
187static bool
188collect_all_symbols (const char *key, STRLEN keylen, SV *val, void *ud)
189{
e989c0df 190 dTHX;
d846ade3 191 HV *hash = (HV *)ud;
192
193 if (!hv_store (hash, key, keylen, newRV_inc(val), 0)) {
194 croak("failed to store symbol ref");
195 }
196
197 return TRUE;
198}
199
200HV *
e1f52a8a 201mop_get_all_package_symbols (HV *stash, type_filter_t filter)
d846ade3 202{
e989c0df 203 dTHX;
d846ade3 204 HV *ret = newHV ();
e1f52a8a 205 mop_get_package_symbols (stash, filter, collect_all_symbols, ret);
d846ade3 206 return ret;
207}
22932438 208
22932438 209
e989c0df 210MAGIC*
211mop_mg_find(pTHX_ SV* const sv, const MGVTBL* const vtbl, I32 const flags){
1bc0cb6b 212 MAGIC* mg;
213
214 assert(sv != NULL);
215 for(mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic){
216 if(mg->mg_virtual == vtbl){
e989c0df 217 return mg;
1bc0cb6b 218 }
22932438 219 }
7ec7b950 220
e989c0df 221 if(flags & MOPf_DIE_ON_FAIL){
222 croak("mop_mg_find: no MAGIC found for %"SVf, sv_2mortal(newRV_inc(sv)));
206860b8 223 }
224 return NULL;
225}
87cfe982 226
227#ifdef DEBUGGING
228SV**
229mop_av_at_safe(pTHX_ AV* const av, I32 const ix){
230 assert(av);
231 assert(SvTYPE(av) == SVt_PVAV);
232 assert(AvMAX(av) >= ix);
233 return &AvARRAY(av)[ix];
234}
235#endif
236
237
238/*
239 XXX: 5.8.1 does have shared hash key mechanism, but does not have the APIs,
240 so the following APIs, which are stolen from 5.8.9, are safe to use.
241*/
242#ifndef SvIsCOW_shared_hash
243#define SvIsCOW(sv) ((SvFLAGS(sv) & (SVf_FAKE | SVf_READONLY)) == \
244 (SVf_FAKE | SVf_READONLY))
245#define SvIsCOW_shared_hash(sv) (SvIsCOW(sv) && SvLEN(sv) == 0)
246#define SvSHARED_HASH(sv) (0 + SvUVX(sv))
247#endif
248
249SV*
250mop_newSVsv_share(pTHX_ SV* const sv){
251 STRLEN len;
252 const char* const pv = SvPV_const(sv, len);
253 U32 const hash = SvIsCOW_shared_hash(sv) ? SvSHARED_HASH(sv) : 0U;
254
255 return newSVpvn_share(pv, SvUTF8(sv) ? -len : len, hash);
256}
257
258SV*
259mop_class_of(pTHX_ SV* const sv){
260 SV* class_name;
261
262 if(IsObject(sv)){
263 HV* const stash = SvSTASH(SvRV(sv));
264 assert(stash);
265#ifdef HvNAME_HEK /* 5.10.0 */
266 assert(HvNAME_HEK(stash));
267 class_name = sv_2mortal(newSVhek(HvNAME_HEK(stash)));
268#else
269 assert(HvNAME_get(stash));
270 class_name = sv_2mortal(newSVpv(HvNAME_get(stash), 0));
271#endif
272 }
273 else{
274 class_name = sv;
275 }
276 return mop_call1(aTHX_ mop_Class, mop_initialize, class_name);
277}