ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Devel-FindRef/FindRef.xs
Revision: 1.20
Committed: Tue Sep 8 18:12:07 2009 UTC (14 years, 8 months ago) by root
Branch: MAIN
Changes since 1.19: +1 -1 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 #include "EXTERN.h"
2     #include "perl.h"
3     #include "XSUB.h"
4    
5 root 1.4 #define PERL_VERSION_ATLEAST(a,b,c) \
6     (PERL_REVISION > (a) \
7     || (PERL_REVISION == (a) \
8     && (PERL_VERSION > (b) \
9     || (PERL_VERSION == (b) && PERLSUBVERSION >= (c)))))
10    
11     #if !PERL_VERSION_ATLEAST (5,8,9)
12     # define SVt_LAST 16
13     #endif
14    
15 root 1.9 #if !PERL_VERSION_ATLEAST (5,10,0)
16     # define SvPAD_OUR(dummy) 0
17     #endif
18    
19 root 1.17 /* pre-5.10 perls always succeed, with 5.10, we have to check first apparently */
20     #ifndef GvNAME_HEK
21     # define GvNAME_HEK(sv) 1
22     #endif
23    
24 root 1.6 #define res_pair(text) \
25 root 1.8 do { \
26 root 1.6 AV *av = newAV (); \
27     av_push (av, newSVpv (text, 0)); \
28 root 1.7 if (rmagical) SvRMAGICAL_on (sv); \
29 root 1.6 av_push (av, sv_rvweaken (newRV_inc (sv))); \
30 root 1.7 if (rmagical) SvRMAGICAL_off (sv); \
31 root 1.6 av_push (about, newRV_noinc ((SV *)av)); \
32 root 1.8 } while (0)
33 root 1.1
34 root 1.11 #define res_text(text) \
35 root 1.8 do { \
36 root 1.6 AV *av = newAV (); \
37 root 1.11 av_push (av, newSVpv (text, 0)); \
38 root 1.6 av_push (about, newRV_noinc ((SV *)av)); \
39 root 1.8 } while (0)
40 root 1.1
41 root 1.11 #define res_gv(sigil) \
42 root 1.19 res_text (form ("the global %c%s::%.*s", sigil, \
43 root 1.11 HvNAME (GvSTASH (sv)), \
44 root 1.17 GvNAME_HEK (sv) ? GvNAMELEN (sv) : 11, \
45     GvNAME_HEK (sv) ? GvNAME (sv) : "<anonymous>"))
46 root 1.11
47 root 1.1 MODULE = Devel::FindRef PACKAGE = Devel::FindRef
48    
49     PROTOTYPES: ENABLE
50    
51     void
52 root 1.15 find_ (SV *target_ref)
53 root 1.1 PPCODE:
54     {
55     SV *arena, *targ;
56 root 1.9 U32 rmagical;
57     int i;
58 root 1.1 AV *about = newAV ();
59     AV *excl = newAV ();
60    
61 root 1.15 if (!SvROK (target_ref))
62 root 1.3 croak ("find expects a reference to a perl value");
63 root 1.1
64 root 1.15 targ = SvRV (target_ref);
65 root 1.1
66 root 1.16 if (SvIMMORTAL (targ))
67 root 1.1 {
68 root 1.16 if (targ == &PL_sv_undef)
69     res_text ("the immortal 'undef' value");
70     else if (targ == &PL_sv_yes)
71     res_text ("the immortal 'yes' value");
72     else if (targ == &PL_sv_no)
73     res_text ("the immortal 'no' value");
74     else if (targ == &PL_sv_placeholder)
75     res_text ("the immortal placeholder value");
76     else
77     res_text ("some unknown immortal");
78     }
79     else
80     {
81     for (arena = PL_sv_arenaroot; arena; arena = SvANY (arena))
82     {
83     UV idx = SvREFCNT (arena);
84 root 1.1
85 root 1.16 /* Remember that the zeroth slot is used as the pointer onwards, so don't
86     include it. */
87     while (--idx > 0)
88     {
89     SV *sv = &arena [idx];
90 root 1.2
91 root 1.16 if (SvTYPE (sv) >= SVt_LAST)
92     continue;
93 root 1.2
94 root 1.16 /* temporarily disable RMAGICAL, it can easily interfere with us */
95     if ((rmagical = SvRMAGICAL (sv)))
96     SvRMAGICAL_off (sv);
97 root 1.1
98 root 1.16 if (SvTYPE (sv) >= SVt_PVMG)
99 root 1.10 {
100 root 1.16 if (SvTYPE (sv) == SVt_PVMG && SvPAD_OUR (sv))
101     {
102     /* I have no clue what this is */
103     /* maybe some placeholder for our variables for eval? */
104     /* it doesn't seem to reference anything, so we should be able to ignore it */
105     }
106     else
107 root 1.9 {
108 root 1.16 MAGIC *mg = SvMAGIC (sv);
109 root 1.2
110 root 1.16 while (mg)
111     {
112     if (mg->mg_obj == targ && mg->mg_flags & MGf_REFCOUNTED)
113     res_pair (form ("referenced (in mg_obj) by '%c' type magic attached to", mg->mg_type));
114    
115     if ((SV *)mg->mg_ptr == targ)
116     res_pair (form ("%sreferenced (in mg_ptr) by '%c' type magic attached to",
117     mg->mg_len == HEf_SVKEY ? "" : "possibly ",
118     mg->mg_type));
119 root 1.9
120 root 1.16 mg = mg->mg_moremagic;
121     }
122 root 1.9 }
123 root 1.2 }
124 root 1.1
125 root 1.16 if (SvROK (sv))
126     {
127     if (SvRV (sv) == targ && !SvWEAKREF (sv) && sv != target_ref)
128     res_pair ("referenced by");
129     }
130     else
131     switch (SvTYPE (sv))
132 root 1.2 {
133 root 1.16 case SVt_PVAV:
134     if (AvREAL (sv))
135     for (i = AvFILLp (sv) + 1; i--; )
136     if (AvARRAY (sv)[i] == targ)
137 root 1.19 res_pair (form ("the array element %d of", i));
138 root 1.16
139     break;
140    
141     case SVt_PVHV:
142     if (hv_iterinit ((HV *)sv))
143     {
144     HE *he;
145    
146     while ((he = hv_iternext ((HV *)sv)))
147     if (HeVAL (he) == targ)
148 root 1.19 res_pair (form ("the member '%.*s' of", HeKLEN (he), HeKEY (he)));
149 root 1.16 }
150 root 1.6
151 root 1.16 break;
152 root 1.7
153 root 1.16 case SVt_PVCV:
154 root 1.6 {
155 root 1.16 int depth = CvDEPTH (sv);
156 root 1.6
157 root 1.16 /* Anonymous subs have a padlist but zero depth */
158     if (CvANON (sv) && !depth && CvPADLIST (sv))
159     depth = 1;
160    
161     if (depth)
162 root 1.6 {
163 root 1.16 AV *padlist = CvPADLIST (sv);
164 root 1.6
165 root 1.16 while (depth)
166     {
167     AV *pad = (AV *)AvARRAY (padlist)[depth];
168    
169     av_push (excl, newSVuv (PTR2UV (pad))); /* exclude pads themselves from being found */
170    
171     /* The 0th pad slot is @_ */
172     if (AvARRAY (pad)[0] == targ)
173     res_pair ("the argument array for");
174    
175     for (i = AvFILLp (pad) + 1; --i; )
176     if (AvARRAY (pad)[i] == targ)
177     {
178     /* Values from constant functions are stored in the pad without any name */
179     SV *name_sv = AvARRAY (AvARRAY (padlist)[0])[i];
180    
181     if (name_sv && SvPOK (name_sv))
182 root 1.18 res_pair (form ("the lexical '%s' in", SvPVX (name_sv)));
183 root 1.16 else
184 root 1.18 res_pair ("an unnamed lexical in");
185 root 1.16 }
186 root 1.6
187 root 1.16 --depth;
188     }
189 root 1.6 }
190 root 1.7
191 root 1.16 if (CvCONST (sv) && (SV*)CvXSUBANY (sv).any_ptr == targ)
192     res_pair ("the constant value of");
193 root 1.8
194 root 1.16 if (!CvWEAKOUTSIDE (sv) && (SV*)CvOUTSIDE (sv) == targ)
195     res_pair ("the containing scope for");
196 root 1.11
197 root 1.16 if (sv == targ && CvANON (sv))
198     if (CvSTART (sv)
199     && CvSTART (sv)->op_type == OP_NEXTSTATE
200     && CopLINE ((COP *)CvSTART (sv)))
201     res_text (form ("the closure created at %s:%d",
202     CopFILE ((COP *)CvSTART (sv)) ? CopFILE ((COP *)CvSTART (sv)) : "<unknown>",
203     CopLINE ((COP *)CvSTART (sv))));
204     else
205     res_text (form ("the closure created somewhere in file %s (PLEASE REPORT!)",
206     CvFILE (sv) ? CvFILE (sv) : "<unknown>"));
207     }
208 root 1.6
209 root 1.16 break;
210 root 1.6
211 root 1.16 case SVt_PVGV:
212     if (GvGP (sv))
213     {
214     if (GvSV (sv) == (SV *)targ) res_gv ('$');
215     if (GvAV (sv) == (AV *)targ) res_gv ('@');
216     if (GvHV (sv) == (HV *)targ) res_gv ('%');
217     if (GvCV (sv) == (CV *)targ) res_gv ('&');
218     }
219    
220     break;
221    
222     case SVt_PVLV:
223     if (LvTARG (sv) == targ)
224     {
225     if (LvTYPE (sv) == 'y')
226     {
227     MAGIC *mg = mg_find (sv, PERL_MAGIC_defelem);
228    
229     if (mg && mg->mg_obj)
230     res_pair (form ("the target for the lvalue hash element '%.*s',",
231 root 1.20 (int)SvCUR (mg->mg_obj), SvPV_nolen (mg->mg_obj)));
232 root 1.16 else
233     res_pair (form ("the target for the lvalue array element #%d,", LvTARGOFF (sv)));
234     }
235     else
236     res_pair (form ("an lvalue reference target (type '%c', ofs %d, len %d),",
237     LvTYPE (sv), LvTARGOFF (sv), LvTARGLEN (sv)));
238     }
239 root 1.6
240 root 1.16 break;
241     }
242 root 1.1
243 root 1.16 if (rmagical)
244     SvRMAGICAL_on (sv);
245     }
246 root 1.1 }
247    
248 root 1.16 /* look at the mortalise stack of the current coroutine */
249     for (i = 0; i <= PL_tmps_ix; ++i)
250     if (PL_tmps_stack [i] == targ)
251     res_text ("a temporary on the stack");
252 root 1.15
253 root 1.16 if (targ == (SV*)PL_main_cv)
254     res_text ("the main body of the program");
255     }
256 root 1.13
257 root 1.1 EXTEND (SP, 2);
258     PUSHs (sv_2mortal (newRV_noinc ((SV *)about)));
259     PUSHs (sv_2mortal (newRV_noinc ((SV *)excl)));
260     }
261    
262 root 1.14 SV *
263     ptr2ref (UV ptr)
264     CODE:
265     RETVAL = newRV_inc (INT2PTR (SV *, ptr));
266     OUTPUT:
267     RETVAL
268    
269     UV
270     ref2ptr (SV *rv)
271     CODE:
272 root 1.16 if (!SvROK (rv))
273     croak ("argument to Devel::FindRef::ref2ptr must be a reference");
274 root 1.14 RETVAL = PTR2UV (SvRV (rv));
275     OUTPUT:
276     RETVAL
277    
278     U32
279     _refcnt (SV *rv)
280     CODE:
281 root 1.16 if (!SvROK (rv))
282     croak ("argument to Devel::FindRef::_refcnt must be a reference");
283 root 1.14 RETVAL = SvREFCNT (SvRV (rv));
284     OUTPUT:
285     RETVAL