Add some comments
[gitmo/Class-MOP.git] / mop.c
CommitLineData
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 12UV
13mop_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
48UV
49mop_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
58SV *
59mop_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 77SV *
78mop_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 99int
e1f52a8a 100mop_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
130void
e1f52a8a 131mop_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
182static bool
183collect_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
195HV *
e1f52a8a 196mop_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 205MAGIC*
206mop_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
223SV**
224mop_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
244SV*
245mop_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
253SV*
254mop_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}