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