line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
|
2
|
|
|
|
|
|
|
#include "EXTERN.h" |
3
|
|
|
|
|
|
|
#include "perl.h" |
4
|
|
|
|
|
|
|
#include "XSUB.h" |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
/* *********** ppport stuff */ |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
#ifndef PERL_UNUSED_VAR |
9
|
|
|
|
|
|
|
# define PERL_UNUSED_VAR(x) ((void)x) |
10
|
|
|
|
|
|
|
#endif |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
#if defined(PERL_GCC_PEDANTIC) |
13
|
|
|
|
|
|
|
# ifndef PERL_GCC_BRACE_GROUPS_FORBIDDEN |
14
|
|
|
|
|
|
|
# define PERL_GCC_BRACE_GROUPS_FORBIDDEN |
15
|
|
|
|
|
|
|
# endif |
16
|
|
|
|
|
|
|
#endif |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
#if defined(__GNUC__) && !defined(PERL_GCC_BRACE_GROUPS_FORBIDDEN) && !defined(__cplusplus) |
19
|
|
|
|
|
|
|
# ifndef PERL_USE_GCC_BRACE_GROUPS |
20
|
|
|
|
|
|
|
# define PERL_USE_GCC_BRACE_GROUPS |
21
|
|
|
|
|
|
|
# endif |
22
|
|
|
|
|
|
|
#endif |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
#ifndef SvREFCNT_inc |
25
|
|
|
|
|
|
|
# ifdef PERL_USE_GCC_BRACE_GROUPS |
26
|
|
|
|
|
|
|
# define SvREFCNT_inc(sv) \ |
27
|
|
|
|
|
|
|
({ \ |
28
|
|
|
|
|
|
|
SV * const _sv = (SV*)(sv); \ |
29
|
|
|
|
|
|
|
if (_sv) \ |
30
|
|
|
|
|
|
|
(SvREFCNT(_sv))++; \ |
31
|
|
|
|
|
|
|
_sv; \ |
32
|
|
|
|
|
|
|
}) |
33
|
|
|
|
|
|
|
# else |
34
|
|
|
|
|
|
|
# define SvREFCNT_inc(sv) \ |
35
|
|
|
|
|
|
|
((PL_Sv=(SV*)(sv)) ? (++(SvREFCNT(PL_Sv)),PL_Sv) : NULL) |
36
|
|
|
|
|
|
|
# endif |
37
|
|
|
|
|
|
|
#endif |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
#ifndef dAX |
40
|
|
|
|
|
|
|
# define dAX I32 ax = MARK - PL_stack_base + 1 |
41
|
|
|
|
|
|
|
#endif |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
#ifndef dVAR |
44
|
|
|
|
|
|
|
# define dVAR dNOOP |
45
|
|
|
|
|
|
|
#endif |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
#ifndef packWARN |
48
|
|
|
|
|
|
|
# define packWARN(a) (a) |
49
|
|
|
|
|
|
|
#endif |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
/* *********** end ppport.h stuff */ |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
#ifndef SVfARG |
54
|
|
|
|
|
|
|
# define SVfARG(p) ((void*)(p)) |
55
|
|
|
|
|
|
|
#endif |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
/* Most of this code is backported from the bleadperl patch's |
58
|
|
|
|
|
|
|
mro.c, and then modified to work with Class::C3's |
59
|
|
|
|
|
|
|
internals. |
60
|
|
|
|
|
|
|
*/ |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
AV* |
63
|
144
|
|
|
|
|
|
__mro_linear_isa_c3(pTHX_ HV* stash, HV* cache, I32 level) |
64
|
|
|
|
|
|
|
{ |
65
|
|
|
|
|
|
|
AV* retval; |
66
|
|
|
|
|
|
|
GV** gvp; |
67
|
|
|
|
|
|
|
GV* gv; |
68
|
|
|
|
|
|
|
AV* isa; |
69
|
|
|
|
|
|
|
const char* stashname; |
70
|
|
|
|
|
|
|
STRLEN stashname_len; |
71
|
144
|
|
|
|
|
|
I32 made_mortal_cache = 0; |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
assert(stash); |
74
|
|
|
|
|
|
|
|
75
|
144
|
50
|
|
|
|
|
stashname = HvNAME(stash); |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
76
|
144
|
|
|
|
|
|
stashname_len = strlen(stashname); |
77
|
144
|
50
|
|
|
|
|
if (!stashname) |
78
|
0
|
|
|
|
|
|
Perl_croak(aTHX_ |
79
|
|
|
|
|
|
|
"Can't linearize anonymous symbol table"); |
80
|
|
|
|
|
|
|
|
81
|
144
|
50
|
|
|
|
|
if (level > 100) |
82
|
0
|
|
|
|
|
|
Perl_croak(aTHX_ "Recursive inheritance detected in package '%s'", |
83
|
|
|
|
|
|
|
stashname); |
84
|
|
|
|
|
|
|
|
85
|
144
|
100
|
|
|
|
|
if(!cache) { |
86
|
33
|
|
|
|
|
|
cache = (HV*)sv_2mortal((SV*)newHV()); |
87
|
33
|
|
|
|
|
|
made_mortal_cache = 1; |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
else { |
90
|
111
|
|
|
|
|
|
SV** cache_entry = hv_fetch(cache, stashname, stashname_len, 0); |
91
|
111
|
100
|
|
|
|
|
if(cache_entry) |
92
|
24
|
|
|
|
|
|
return (AV*)SvREFCNT_inc(*cache_entry); |
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
/* not in cache, make a new one */ |
96
|
|
|
|
|
|
|
|
97
|
120
|
|
|
|
|
|
gvp = (GV**)hv_fetch(stash, "ISA", 3, FALSE); |
98
|
120
|
100
|
|
|
|
|
isa = (gvp && (gv = *gvp) && gv != (GV*)&PL_sv_undef) ? GvAV(gv) : NULL; |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
99
|
149
|
100
|
|
|
|
|
if(isa && AvFILLp(isa) >= 0) { |
|
|
100
|
|
|
|
|
|
100
|
|
|
|
|
|
|
SV** seqs_ptr; |
101
|
|
|
|
|
|
|
I32 seqs_items; |
102
|
|
|
|
|
|
|
HV* tails; |
103
|
82
|
|
|
|
|
|
AV* const seqs = (AV*)sv_2mortal((SV*)newAV()); |
104
|
|
|
|
|
|
|
I32* heads; |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
/* This builds @seqs, which is an array of arrays. |
107
|
|
|
|
|
|
|
The members of @seqs are the MROs of |
108
|
|
|
|
|
|
|
the members of @ISA, followed by @ISA itself. |
109
|
|
|
|
|
|
|
*/ |
110
|
82
|
|
|
|
|
|
I32 items = AvFILLp(isa) + 1; |
111
|
82
|
|
|
|
|
|
SV** isa_ptr = AvARRAY(isa); |
112
|
140
|
100
|
|
|
|
|
while(items--) { |
113
|
111
|
|
|
|
|
|
SV* const isa_item = *isa_ptr++; |
114
|
111
|
|
|
|
|
|
HV* const isa_item_stash = gv_stashsv(isa_item, 0); |
115
|
111
|
50
|
|
|
|
|
if(!isa_item_stash) { |
116
|
|
|
|
|
|
|
/* if no stash, make a temporary fake MRO |
117
|
|
|
|
|
|
|
containing just itself */ |
118
|
0
|
|
|
|
|
|
AV* const isa_lin = newAV(); |
119
|
0
|
|
|
|
|
|
av_push(isa_lin, newSVsv(isa_item)); |
120
|
0
|
|
|
|
|
|
av_push(seqs, (SV*)isa_lin); |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
else { |
123
|
|
|
|
|
|
|
/* recursion */ |
124
|
111
|
|
|
|
|
|
AV* const isa_lin = __mro_linear_isa_c3(aTHX_ isa_item_stash, cache, level + 1); |
125
|
|
|
|
|
|
|
|
126
|
111
|
100
|
|
|
|
|
if(items == 0 && AvFILLp(seqs) == -1) { |
|
|
100
|
|
|
|
|
|
127
|
|
|
|
|
|
|
/* Only one parent class. For this case, the C3 |
128
|
|
|
|
|
|
|
linearisation is this class followed by the parent's |
129
|
|
|
|
|
|
|
linearisation, so don't bother with the expensive |
130
|
|
|
|
|
|
|
calculation. */ |
131
|
|
|
|
|
|
|
SV **svp; |
132
|
53
|
|
|
|
|
|
I32 subrv_items = AvFILLp(isa_lin) + 1; |
133
|
53
|
|
|
|
|
|
SV *const *subrv_p = AvARRAY(isa_lin); |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
/* Hijack the allocated but unused array seqs to be the |
136
|
|
|
|
|
|
|
return value. It's currently mortalised. */ |
137
|
|
|
|
|
|
|
|
138
|
53
|
|
|
|
|
|
retval = seqs; |
139
|
|
|
|
|
|
|
|
140
|
53
|
|
|
|
|
|
av_extend(retval, subrv_items); |
141
|
53
|
|
|
|
|
|
AvFILLp(retval) = subrv_items; |
142
|
53
|
|
|
|
|
|
svp = AvARRAY(retval); |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
/* First entry is this class. */ |
145
|
53
|
|
|
|
|
|
*svp++ = newSVpvn(stashname, stashname_len); |
146
|
|
|
|
|
|
|
|
147
|
112
|
100
|
|
|
|
|
while(subrv_items--) { |
148
|
|
|
|
|
|
|
/* These values are unlikely to be shared hash key |
149
|
|
|
|
|
|
|
scalars, so no point in adding code to optimising |
150
|
|
|
|
|
|
|
for a case that is unlikely to be true. |
151
|
|
|
|
|
|
|
(Or prove me wrong and do it.) */ |
152
|
|
|
|
|
|
|
|
153
|
59
|
|
|
|
|
|
SV *const val = *subrv_p++; |
154
|
59
|
|
|
|
|
|
*svp++ = newSVsv(val); |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
53
|
|
|
|
|
|
SvREFCNT_dec(isa_lin); |
158
|
53
|
|
|
|
|
|
SvREFCNT_inc(retval); |
159
|
|
|
|
|
|
|
|
160
|
53
|
|
|
|
|
|
goto done; |
161
|
|
|
|
|
|
|
} |
162
|
58
|
|
|
|
|
|
av_push(seqs, (SV*)isa_lin); |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
} |
165
|
29
|
|
|
|
|
|
av_push(seqs, SvREFCNT_inc((SV*)isa)); |
166
|
29
|
|
|
|
|
|
tails = (HV*)sv_2mortal((SV*)newHV()); |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
/* This builds "heads", which as an array of integer array |
169
|
|
|
|
|
|
|
indices, one per seq, which point at the virtual "head" |
170
|
|
|
|
|
|
|
of the seq (initially zero) */ |
171
|
29
|
50
|
|
|
|
|
Newz(0xdead, heads, AvFILLp(seqs)+1, I32); |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
/* This builds %tails, which has one key for every class |
174
|
|
|
|
|
|
|
mentioned in the tail of any sequence in @seqs (tail meaning |
175
|
|
|
|
|
|
|
everything after the first class, the "head"). The value |
176
|
|
|
|
|
|
|
is how many times this key appears in the tails of @seqs. |
177
|
|
|
|
|
|
|
*/ |
178
|
29
|
|
|
|
|
|
seqs_ptr = AvARRAY(seqs); |
179
|
29
|
|
|
|
|
|
seqs_items = AvFILLp(seqs) + 1; |
180
|
116
|
100
|
|
|
|
|
while(seqs_items--) { |
181
|
87
|
|
|
|
|
|
AV* const seq = (AV*)*seqs_ptr++; |
182
|
87
|
|
|
|
|
|
I32 seq_items = AvFILLp(seq); |
183
|
87
|
100
|
|
|
|
|
if(seq_items > 0) { |
184
|
77
|
|
|
|
|
|
SV** seq_ptr = AvARRAY(seq) + 1; |
185
|
168
|
100
|
|
|
|
|
while(seq_items--) { |
186
|
91
|
|
|
|
|
|
SV* const seqitem = *seq_ptr++; |
187
|
|
|
|
|
|
|
/* LVALUE fetch will create a new undefined SV if necessary |
188
|
|
|
|
|
|
|
*/ |
189
|
91
|
|
|
|
|
|
HE* const he = hv_fetch_ent(tails, seqitem, 1, 0); |
190
|
91
|
50
|
|
|
|
|
if(he) { |
191
|
91
|
|
|
|
|
|
SV* const val = HeVAL(he); |
192
|
|
|
|
|
|
|
/* For 5.8.0 and later, sv_inc() with increment undef to |
193
|
|
|
|
|
|
|
an IV of 1, which is what we want for a newly created |
194
|
|
|
|
|
|
|
entry. However, for 5.6.x it will become an NV of |
195
|
|
|
|
|
|
|
1.0, which confuses the SvIVX() checks above */ |
196
|
91
|
100
|
|
|
|
|
if(SvIOK(val)) { |
197
|
27
|
|
|
|
|
|
SvIVX(val)++; |
198
|
|
|
|
|
|
|
} else { |
199
|
91
|
|
|
|
|
|
sv_setiv(val, 1); |
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
} else { |
202
|
0
|
|
|
|
|
|
croak("failed to store value in hash"); |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
/* Initialize retval to build the return value in */ |
209
|
29
|
|
|
|
|
|
retval = newAV(); |
210
|
29
|
|
|
|
|
|
av_push(retval, newSVpvn(stashname, stashname_len)); /* us first */ |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
/* This loop won't terminate until we either finish building |
213
|
|
|
|
|
|
|
the MRO, or get an exception. */ |
214
|
|
|
|
|
|
|
while(1) { |
215
|
122
|
|
|
|
|
|
SV* cand = NULL; |
216
|
122
|
|
|
|
|
|
SV* winner = NULL; |
217
|
|
|
|
|
|
|
int s; |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
/* "foreach $seq (@seqs)" */ |
220
|
122
|
|
|
|
|
|
SV** const avptr = AvARRAY(seqs); |
221
|
488
|
100
|
|
|
|
|
for(s = 0; s <= AvFILLp(seqs); s++) { |
222
|
|
|
|
|
|
|
SV** svp; |
223
|
366
|
|
|
|
|
|
AV * const seq = (AV*)(avptr[s]); |
224
|
|
|
|
|
|
|
SV* seqhead; |
225
|
366
|
100
|
|
|
|
|
if(!seq) continue; /* skip empty seqs */ |
226
|
240
|
|
|
|
|
|
svp = av_fetch(seq, heads[s], 0); |
227
|
240
|
|
|
|
|
|
seqhead = *svp; /* seqhead = head of this seq */ |
228
|
240
|
100
|
|
|
|
|
if(!winner) { |
229
|
|
|
|
|
|
|
HE* tail_entry; |
230
|
|
|
|
|
|
|
SV* val; |
231
|
|
|
|
|
|
|
/* if we haven't found a winner for this round yet, |
232
|
|
|
|
|
|
|
and this seqhead is not in tails (or the count |
233
|
|
|
|
|
|
|
for it in tails has dropped to zero), then this |
234
|
|
|
|
|
|
|
seqhead is our new winner, and is added to the |
235
|
|
|
|
|
|
|
final MRO immediately */ |
236
|
120
|
|
|
|
|
|
cand = seqhead; |
237
|
120
|
100
|
|
|
|
|
if((tail_entry = hv_fetch_ent(tails, cand, 0, 0)) |
238
|
91
|
50
|
|
|
|
|
&& (val = HeVAL(tail_entry)) |
239
|
91
|
100
|
|
|
|
|
&& (SvIVX(val) > 0)) |
240
|
27
|
|
|
|
|
|
continue; |
241
|
93
|
|
|
|
|
|
winner = newSVsv(cand); |
242
|
93
|
|
|
|
|
|
av_push(retval, winner); |
243
|
|
|
|
|
|
|
/* note however that even when we find a winner, |
244
|
|
|
|
|
|
|
we continue looping over @seqs to do housekeeping */ |
245
|
|
|
|
|
|
|
} |
246
|
213
|
100
|
|
|
|
|
if(!sv_cmp(seqhead, winner)) { |
247
|
|
|
|
|
|
|
/* Once we have a winner (including the iteration |
248
|
|
|
|
|
|
|
where we first found him), inc the head ptr |
249
|
|
|
|
|
|
|
for any seq which had the winner as a head, |
250
|
|
|
|
|
|
|
NULL out any seq which is now empty, |
251
|
|
|
|
|
|
|
and adjust tails for consistency */ |
252
|
|
|
|
|
|
|
|
253
|
178
|
|
|
|
|
|
const int new_head = ++heads[s]; |
254
|
178
|
100
|
|
|
|
|
if(new_head > AvFILLp(seq)) { |
255
|
87
|
|
|
|
|
|
SvREFCNT_dec(avptr[s]); |
256
|
87
|
|
|
|
|
|
avptr[s] = NULL; |
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
else { |
259
|
|
|
|
|
|
|
HE* tail_entry; |
260
|
|
|
|
|
|
|
SV* val; |
261
|
|
|
|
|
|
|
/* Because we know this new seqhead used to be |
262
|
|
|
|
|
|
|
a tail, we can assume it is in tails and has |
263
|
|
|
|
|
|
|
a positive value, which we need to dec */ |
264
|
91
|
|
|
|
|
|
svp = av_fetch(seq, new_head, 0); |
265
|
91
|
|
|
|
|
|
seqhead = *svp; |
266
|
91
|
|
|
|
|
|
tail_entry = hv_fetch_ent(tails, seqhead, 0, 0); |
267
|
91
|
|
|
|
|
|
val = HeVAL(tail_entry); |
268
|
91
|
|
|
|
|
|
sv_dec(val); |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
/* if we found no candidates, we are done building the MRO. |
274
|
|
|
|
|
|
|
!cand means no seqs have any entries left to check */ |
275
|
122
|
100
|
|
|
|
|
if(!cand) { |
276
|
29
|
|
|
|
|
|
Safefree(heads); |
277
|
29
|
|
|
|
|
|
break; |
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
/* If we had candidates, but nobody won, then the @ISA |
281
|
|
|
|
|
|
|
hierarchy is not C3-incompatible */ |
282
|
93
|
50
|
|
|
|
|
if(!winner) { |
283
|
|
|
|
|
|
|
SV *errmsg; |
284
|
|
|
|
|
|
|
I32 i; |
285
|
|
|
|
|
|
|
/* we have to do some cleanup before we croak */ |
286
|
|
|
|
|
|
|
|
287
|
0
|
|
|
|
|
|
errmsg = newSVpvf("Inconsistent hierarchy during C3 merge of class '%s':\n\t" |
288
|
|
|
|
|
|
|
"current merge results [\n", stashname); |
289
|
0
|
0
|
|
|
|
|
for (i = 0; i <= av_len(retval); i++) { |
290
|
0
|
|
|
|
|
|
SV **elem = av_fetch(retval, i, 0); |
291
|
0
|
|
|
|
|
|
sv_catpvf(errmsg, "\t\t%"SVf",\n", SVfARG(*elem)); |
292
|
|
|
|
|
|
|
} |
293
|
0
|
|
|
|
|
|
sv_catpvf(errmsg, "\t]\n\tmerging failed on '%"SVf"'", SVfARG(cand)); |
294
|
|
|
|
|
|
|
|
295
|
0
|
|
|
|
|
|
SvREFCNT_dec(retval); |
296
|
0
|
|
|
|
|
|
Safefree(heads); |
297
|
|
|
|
|
|
|
|
298
|
0
|
|
|
|
|
|
croak("%"SVf, SVfARG(errmsg)); |
299
|
|
|
|
|
|
|
} |
300
|
93
|
|
|
|
|
|
} |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
else { /* @ISA was undefined or empty */ |
303
|
|
|
|
|
|
|
/* build a retval containing only ourselves */ |
304
|
38
|
|
|
|
|
|
retval = newAV(); |
305
|
38
|
|
|
|
|
|
av_push(retval, newSVpvn(stashname, stashname_len)); |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
done: |
309
|
|
|
|
|
|
|
/* we don't want anyone modifying the cache entry but us, |
310
|
|
|
|
|
|
|
and we do so by replacing it completely */ |
311
|
120
|
|
|
|
|
|
SvREADONLY_on(retval); |
312
|
|
|
|
|
|
|
|
313
|
120
|
100
|
|
|
|
|
if(!made_mortal_cache) { |
314
|
87
|
|
|
|
|
|
SvREFCNT_inc(retval); |
315
|
87
|
50
|
|
|
|
|
if(!hv_store(cache, stashname, stashname_len, (SV*)retval, 0)) { |
316
|
0
|
|
|
|
|
|
croak("failed to store value in hash"); |
317
|
|
|
|
|
|
|
} |
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
|
320
|
120
|
|
|
|
|
|
return retval; |
321
|
|
|
|
|
|
|
} |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
STATIC I32 |
324
|
115
|
|
|
|
|
|
__dopoptosub_at(const PERL_CONTEXT *cxstk, I32 startingblock) { |
325
|
|
|
|
|
|
|
I32 i; |
326
|
147
|
100
|
|
|
|
|
for (i = startingblock; i >= 0; i--) { |
327
|
124
|
100
|
|
|
|
|
if(CxTYPE((PERL_CONTEXT*)(&cxstk[i])) == CXt_SUB) return i; |
328
|
|
|
|
|
|
|
} |
329
|
23
|
|
|
|
|
|
return i; |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
XS(XS_Class_C3_XS_nextcan); |
333
|
27
|
|
|
|
|
|
XS(XS_Class_C3_XS_nextcan) |
334
|
|
|
|
|
|
|
{ |
335
|
27
|
|
|
|
|
|
dVAR; dXSARGS; |
336
|
|
|
|
|
|
|
|
337
|
27
|
|
|
|
|
|
SV* self = ST(0); |
338
|
27
|
|
|
|
|
|
const I32 throw_nomethod = SvIVX(ST(1)); |
339
|
27
|
|
|
|
|
|
register I32 cxix = cxstack_ix; |
340
|
27
|
|
|
|
|
|
register const PERL_CONTEXT *ccstack = cxstack; |
341
|
27
|
|
|
|
|
|
const PERL_SI *top_si = PL_curstackinfo; |
342
|
|
|
|
|
|
|
HV* selfstash; |
343
|
|
|
|
|
|
|
GV* cvgv; |
344
|
|
|
|
|
|
|
SV *stashname; |
345
|
|
|
|
|
|
|
const char *fq_subname; |
346
|
|
|
|
|
|
|
const char *subname; |
347
|
|
|
|
|
|
|
STRLEN fq_subname_len; |
348
|
|
|
|
|
|
|
STRLEN stashname_len; |
349
|
|
|
|
|
|
|
STRLEN subname_len; |
350
|
|
|
|
|
|
|
SV* sv; |
351
|
|
|
|
|
|
|
GV** gvp; |
352
|
|
|
|
|
|
|
AV* linear_av; |
353
|
|
|
|
|
|
|
SV** linear_svp; |
354
|
|
|
|
|
|
|
HV* cstash; |
355
|
27
|
|
|
|
|
|
GV* candidate = NULL; |
356
|
27
|
|
|
|
|
|
CV* cand_cv = NULL; |
357
|
|
|
|
|
|
|
const char *hvname; |
358
|
|
|
|
|
|
|
I32 entries; |
359
|
|
|
|
|
|
|
HV* nmcache; |
360
|
|
|
|
|
|
|
HE* cache_entry; |
361
|
|
|
|
|
|
|
SV* cachekey; |
362
|
|
|
|
|
|
|
I32 i; |
363
|
|
|
|
|
|
|
|
364
|
27
|
|
|
|
|
|
SP -= items; |
365
|
|
|
|
|
|
|
|
366
|
27
|
100
|
|
|
|
|
if(sv_isobject(self)) |
367
|
1
|
|
|
|
|
|
selfstash = SvSTASH(SvRV(self)); |
368
|
|
|
|
|
|
|
else |
369
|
26
|
|
|
|
|
|
selfstash = gv_stashsv(self, 0); |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
assert(selfstash); |
372
|
|
|
|
|
|
|
|
373
|
27
|
50
|
|
|
|
|
hvname = HvNAME(selfstash); |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
374
|
27
|
50
|
|
|
|
|
if (!hvname) |
375
|
0
|
|
|
|
|
|
Perl_croak(aTHX_ "Can't use anonymous symbol table for method lookup"); |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
/* This block finds the contextually-enclosing fully-qualified subname, |
378
|
|
|
|
|
|
|
much like looking at (caller($i))[3] until you find a real sub that |
379
|
|
|
|
|
|
|
isn't ANON, etc (also skips over pureperl next::method, etc) */ |
380
|
80
|
100
|
|
|
|
|
for(i = 0; i < 2; i++) { |
381
|
54
|
|
|
|
|
|
cxix = __dopoptosub_at(ccstack, cxix); |
382
|
|
|
|
|
|
|
for (;;) { |
383
|
|
|
|
|
|
|
/* we may be in a higher stacklevel, so dig down deeper */ |
384
|
58
|
100
|
|
|
|
|
while (cxix < 0) { |
385
|
1
|
50
|
|
|
|
|
if(top_si->si_type == PERLSI_MAIN) |
386
|
1
|
|
|
|
|
|
Perl_croak(aTHX_ "next::method/next::can/maybe::next::method must be used in method context"); |
387
|
0
|
|
|
|
|
|
top_si = top_si->si_prev; |
388
|
0
|
|
|
|
|
|
ccstack = top_si->si_cxstack; |
389
|
0
|
|
|
|
|
|
cxix = __dopoptosub_at(ccstack, top_si->si_cxix); |
390
|
|
|
|
|
|
|
} |
391
|
|
|
|
|
|
|
|
392
|
57
|
50
|
|
|
|
|
if(CxTYPE((PERL_CONTEXT*)(&ccstack[cxix])) != CXt_SUB |
393
|
57
|
50
|
|
|
|
|
|| (PL_DBsub && GvCV(PL_DBsub) && ccstack[cxix].blk_sub.cv == GvCV(PL_DBsub))) { |
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
394
|
0
|
|
|
|
|
|
cxix = __dopoptosub_at(ccstack, cxix - 1); |
395
|
0
|
|
|
|
|
|
continue; |
396
|
|
|
|
|
|
|
} |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
{ |
399
|
57
|
|
|
|
|
|
const I32 dbcxix = __dopoptosub_at(ccstack, cxix - 1); |
400
|
57
|
50
|
|
|
|
|
if (PL_DBsub && GvCV(PL_DBsub) && dbcxix >= 0 && ccstack[dbcxix].blk_sub.cv == GvCV(PL_DBsub)) { |
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
401
|
0
|
0
|
|
|
|
|
if(CxTYPE((PERL_CONTEXT*)(&ccstack[dbcxix])) != CXt_SUB) { |
402
|
0
|
|
|
|
|
|
cxix = dbcxix; |
403
|
0
|
|
|
|
|
|
continue; |
404
|
|
|
|
|
|
|
} |
405
|
|
|
|
|
|
|
} |
406
|
|
|
|
|
|
|
} |
407
|
|
|
|
|
|
|
|
408
|
57
|
|
|
|
|
|
cvgv = CvGV(ccstack[cxix].blk_sub.cv); |
409
|
|
|
|
|
|
|
|
410
|
57
|
50
|
|
|
|
|
if(!isGV(cvgv)) { |
411
|
0
|
|
|
|
|
|
cxix = __dopoptosub_at(ccstack, cxix - 1); |
412
|
0
|
|
|
|
|
|
continue; |
413
|
|
|
|
|
|
|
} |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
/* we found a real sub here */ |
416
|
57
|
|
|
|
|
|
sv = sv_newmortal(); |
417
|
|
|
|
|
|
|
|
418
|
57
|
|
|
|
|
|
gv_efullname3(sv, cvgv, NULL); |
419
|
|
|
|
|
|
|
|
420
|
57
|
50
|
|
|
|
|
if (SvPOK(sv)) { |
421
|
57
|
|
|
|
|
|
fq_subname = SvPVX(sv); |
422
|
57
|
|
|
|
|
|
fq_subname_len = SvCUR(sv); |
423
|
|
|
|
|
|
|
|
424
|
57
|
|
|
|
|
|
subname = strrchr(fq_subname, ':'); |
425
|
|
|
|
|
|
|
} else { |
426
|
0
|
|
|
|
|
|
subname = NULL; |
427
|
|
|
|
|
|
|
} |
428
|
|
|
|
|
|
|
|
429
|
57
|
|
|
|
|
|
subname = strrchr(fq_subname, ':'); |
430
|
57
|
50
|
|
|
|
|
if(!subname) |
431
|
0
|
|
|
|
|
|
Perl_croak(aTHX_ "next::method/next::can/maybe::next::method cannot find enclosing method"); |
432
|
|
|
|
|
|
|
|
433
|
57
|
|
|
|
|
|
subname++; |
434
|
57
|
|
|
|
|
|
subname_len = fq_subname_len - (subname - fq_subname); |
435
|
57
|
100
|
|
|
|
|
if(subname_len == 8 && strEQ(subname, "__ANON__")) { |
|
|
50
|
|
|
|
|
|
436
|
4
|
|
|
|
|
|
cxix = __dopoptosub_at(ccstack, cxix - 1); |
437
|
4
|
|
|
|
|
|
continue; |
438
|
|
|
|
|
|
|
} |
439
|
53
|
|
|
|
|
|
break; |
440
|
4
|
|
|
|
|
|
} |
441
|
53
|
|
|
|
|
|
cxix--; |
442
|
|
|
|
|
|
|
} |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
/* If we made it to here, we found our context */ |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
/* cachekey = "objpkg|context::method::name" */ |
447
|
26
|
|
|
|
|
|
cachekey = sv_2mortal(newSVpv(hvname, 0)); |
448
|
26
|
|
|
|
|
|
sv_catpvn(cachekey, "|", 1); |
449
|
26
|
|
|
|
|
|
sv_catsv(cachekey, sv); |
450
|
|
|
|
|
|
|
|
451
|
26
|
|
|
|
|
|
nmcache = get_hv("next::METHOD_CACHE", 1); |
452
|
26
|
100
|
|
|
|
|
if((cache_entry = hv_fetch_ent(nmcache, cachekey, 0, 0))) { |
453
|
3
|
|
|
|
|
|
SV* val = HeVAL(cache_entry); |
454
|
3
|
50
|
|
|
|
|
if(val == &PL_sv_undef) { |
455
|
0
|
0
|
|
|
|
|
if(throw_nomethod) |
456
|
0
|
|
|
|
|
|
Perl_croak(aTHX_ "No next::method '%s' found for %s", subname, hvname); |
457
|
0
|
|
|
|
|
|
XSRETURN_EMPTY; |
458
|
|
|
|
|
|
|
} |
459
|
3
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newRV_inc(val))); |
460
|
3
|
|
|
|
|
|
XSRETURN(1); |
461
|
|
|
|
|
|
|
} |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
/* beyond here is just for cache misses, so perf isn't as critical */ |
464
|
|
|
|
|
|
|
|
465
|
23
|
|
|
|
|
|
stashname_len = subname - fq_subname - 2; |
466
|
23
|
|
|
|
|
|
stashname = sv_2mortal(newSVpvn(fq_subname, stashname_len)); |
467
|
|
|
|
|
|
|
|
468
|
23
|
|
|
|
|
|
linear_av = __mro_linear_isa_c3(aTHX_ selfstash, NULL, 0); |
469
|
|
|
|
|
|
|
|
470
|
23
|
|
|
|
|
|
linear_svp = AvARRAY(linear_av); |
471
|
23
|
|
|
|
|
|
entries = AvFILLp(linear_av) + 1; |
472
|
|
|
|
|
|
|
|
473
|
30
|
50
|
|
|
|
|
while (entries--) { |
474
|
30
|
|
|
|
|
|
SV* const linear_sv = *linear_svp++; |
475
|
|
|
|
|
|
|
assert(linear_sv); |
476
|
30
|
100
|
|
|
|
|
if(sv_eq(linear_sv, stashname)) |
477
|
23
|
|
|
|
|
|
break; |
478
|
|
|
|
|
|
|
} |
479
|
|
|
|
|
|
|
|
480
|
23
|
50
|
|
|
|
|
if(entries > 0) { |
481
|
23
|
|
|
|
|
|
SV* sub_sv = sv_2mortal(newSVpv(subname, subname_len)); |
482
|
23
|
|
|
|
|
|
HV* cc3_mro = get_hv("Class::C3::MRO", 0); |
483
|
|
|
|
|
|
|
|
484
|
42
|
100
|
|
|
|
|
while (entries--) { |
485
|
38
|
|
|
|
|
|
SV* const linear_sv = *linear_svp++; |
486
|
|
|
|
|
|
|
assert(linear_sv); |
487
|
|
|
|
|
|
|
|
488
|
38
|
50
|
|
|
|
|
if(cc3_mro) { |
489
|
0
|
|
|
|
|
|
HE* he_cc3_mro_class = hv_fetch_ent(cc3_mro, linear_sv, 0, 0); |
490
|
0
|
0
|
|
|
|
|
if(he_cc3_mro_class) { |
491
|
0
|
|
|
|
|
|
SV* cc3_mro_class_sv = HeVAL(he_cc3_mro_class); |
492
|
0
|
0
|
|
|
|
|
if(SvROK(cc3_mro_class_sv)) { |
493
|
0
|
|
|
|
|
|
HV* cc3_mro_class = (HV*)SvRV(cc3_mro_class_sv); |
494
|
0
|
|
|
|
|
|
SV** svp_cc3_mro_class_methods = hv_fetch(cc3_mro_class, "methods", 7, 0); |
495
|
0
|
0
|
|
|
|
|
if(svp_cc3_mro_class_methods) { |
496
|
0
|
|
|
|
|
|
SV* cc3_mro_class_methods_sv = *svp_cc3_mro_class_methods; |
497
|
0
|
0
|
|
|
|
|
if(SvROK(cc3_mro_class_methods_sv)) { |
498
|
0
|
|
|
|
|
|
HV* cc3_mro_class_methods = (HV*)SvRV(cc3_mro_class_methods_sv); |
499
|
0
|
0
|
|
|
|
|
if(hv_exists_ent(cc3_mro_class_methods, sub_sv, 0)) |
500
|
0
|
|
|
|
|
|
continue; |
501
|
|
|
|
|
|
|
} |
502
|
|
|
|
|
|
|
} |
503
|
|
|
|
|
|
|
} |
504
|
|
|
|
|
|
|
} |
505
|
|
|
|
|
|
|
} |
506
|
|
|
|
|
|
|
|
507
|
38
|
|
|
|
|
|
cstash = gv_stashsv(linear_sv, FALSE); |
508
|
|
|
|
|
|
|
|
509
|
38
|
50
|
|
|
|
|
if (!cstash) { |
510
|
0
|
0
|
|
|
|
|
if (ckWARN(WARN_MISC)) |
511
|
0
|
|
|
|
|
|
Perl_warner(aTHX_ packWARN(WARN_MISC), "Can't locate package %"SVf" for @%s::ISA", |
512
|
|
|
|
|
|
|
(void*)linear_sv, hvname); |
513
|
0
|
|
|
|
|
|
continue; |
514
|
|
|
|
|
|
|
} |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
assert(cstash); |
517
|
|
|
|
|
|
|
|
518
|
38
|
|
|
|
|
|
gvp = (GV**)hv_fetch(cstash, subname, subname_len, 0); |
519
|
38
|
100
|
|
|
|
|
if (!gvp) continue; |
520
|
|
|
|
|
|
|
|
521
|
19
|
|
|
|
|
|
candidate = *gvp; |
522
|
|
|
|
|
|
|
assert(candidate); |
523
|
|
|
|
|
|
|
|
524
|
19
|
50
|
|
|
|
|
if (SvTYPE(candidate) != SVt_PVGV) |
525
|
0
|
|
|
|
|
|
gv_init(candidate, cstash, subname, subname_len, TRUE); |
526
|
19
|
50
|
|
|
|
|
if (SvTYPE(candidate) == SVt_PVGV && (cand_cv = GvCV(candidate)) && !GvCVGEN(candidate)) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
527
|
19
|
|
|
|
|
|
SvREFCNT_dec(linear_av); |
528
|
19
|
|
|
|
|
|
SvREFCNT_inc((SV*)cand_cv); |
529
|
19
|
50
|
|
|
|
|
if (!hv_store_ent(nmcache, cachekey, (SV*)cand_cv, 0)) { |
530
|
0
|
|
|
|
|
|
croak("failed to store value in hash"); |
531
|
|
|
|
|
|
|
} |
532
|
19
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newRV_inc((SV*)cand_cv))); |
533
|
19
|
|
|
|
|
|
XSRETURN(1); |
534
|
|
|
|
|
|
|
} |
535
|
|
|
|
|
|
|
} |
536
|
|
|
|
|
|
|
} |
537
|
|
|
|
|
|
|
|
538
|
4
|
|
|
|
|
|
SvREFCNT_dec(linear_av); |
539
|
4
|
50
|
|
|
|
|
if (!hv_store_ent(nmcache, cachekey, &PL_sv_undef, 0)) { |
540
|
0
|
|
|
|
|
|
croak("failed to store value in hash"); |
541
|
|
|
|
|
|
|
} |
542
|
4
|
100
|
|
|
|
|
if(throw_nomethod) |
543
|
1
|
|
|
|
|
|
Perl_croak(aTHX_ "No next::method '%s' found for %s", subname, hvname); |
544
|
3
|
|
|
|
|
|
XSRETURN_EMPTY; |
545
|
|
|
|
|
|
|
} |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
XS(XS_Class_C3_XS_calculateMRO); |
548
|
10
|
|
|
|
|
|
XS(XS_Class_C3_XS_calculateMRO) |
549
|
|
|
|
|
|
|
{ |
550
|
10
|
|
|
|
|
|
dVAR; dXSARGS; |
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
SV* classname; |
553
|
|
|
|
|
|
|
HV* class_stash; |
554
|
10
|
|
|
|
|
|
HV* cache = NULL; |
555
|
|
|
|
|
|
|
AV* res; |
556
|
|
|
|
|
|
|
I32 res_items; |
557
|
|
|
|
|
|
|
I32 ret_items; |
558
|
|
|
|
|
|
|
SV** res_ptr; |
559
|
|
|
|
|
|
|
|
560
|
10
|
50
|
|
|
|
|
if(items < 1 || items > 2) |
|
|
50
|
|
|
|
|
|
561
|
0
|
|
|
|
|
|
croak("Usage: calculateMRO(classname[, cache])"); |
562
|
|
|
|
|
|
|
|
563
|
10
|
|
|
|
|
|
classname = ST(0); |
564
|
10
|
50
|
|
|
|
|
if(items == 2) cache = (HV*)SvRV(ST(1)); |
565
|
|
|
|
|
|
|
|
566
|
10
|
|
|
|
|
|
class_stash = gv_stashsv(classname, 0); |
567
|
10
|
50
|
|
|
|
|
if(!class_stash) |
568
|
0
|
0
|
|
|
|
|
Perl_croak(aTHX_ "No such class: '%s'!", SvPV_nolen(classname)); |
569
|
|
|
|
|
|
|
|
570
|
10
|
|
|
|
|
|
res = __mro_linear_isa_c3(aTHX_ class_stash, cache, 0); |
571
|
|
|
|
|
|
|
|
572
|
10
|
|
|
|
|
|
res_items = ret_items = AvFILLp(res) + 1; |
573
|
10
|
|
|
|
|
|
res_ptr = AvARRAY(res); |
574
|
|
|
|
|
|
|
|
575
|
10
|
|
|
|
|
|
SP -= items; |
576
|
|
|
|
|
|
|
|
577
|
55
|
100
|
|
|
|
|
while(res_items--) { |
578
|
45
|
|
|
|
|
|
SV* res_item = *res_ptr++; |
579
|
45
|
50
|
|
|
|
|
XPUSHs(sv_2mortal(newSVsv(res_item))); |
580
|
|
|
|
|
|
|
} |
581
|
10
|
|
|
|
|
|
SvREFCNT_dec(res); |
582
|
|
|
|
|
|
|
|
583
|
10
|
|
|
|
|
|
PUTBACK; |
584
|
|
|
|
|
|
|
|
585
|
10
|
|
|
|
|
|
return; |
586
|
|
|
|
|
|
|
} |
587
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
XS(XS_Class_C3_XS_plsubgen); |
589
|
0
|
|
|
|
|
|
XS(XS_Class_C3_XS_plsubgen) |
590
|
|
|
|
|
|
|
{ |
591
|
0
|
|
|
|
|
|
dVAR; dXSARGS; |
592
|
|
|
|
|
|
|
|
593
|
0
|
|
|
|
|
|
SP -= items; |
594
|
0
|
0
|
|
|
|
|
XPUSHs(sv_2mortal(newSViv(PL_sub_generation))); |
595
|
0
|
|
|
|
|
|
PUTBACK; |
596
|
0
|
|
|
|
|
|
return; |
597
|
|
|
|
|
|
|
} |
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
XS(XS_Class_C3_XS_calc_mdt); |
600
|
0
|
|
|
|
|
|
XS(XS_Class_C3_XS_calc_mdt) |
601
|
|
|
|
|
|
|
{ |
602
|
0
|
|
|
|
|
|
dVAR; dXSARGS; |
603
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
SV* classname; |
605
|
|
|
|
|
|
|
HV* cache; |
606
|
|
|
|
|
|
|
HV* class_stash; |
607
|
|
|
|
|
|
|
AV* class_mro; |
608
|
|
|
|
|
|
|
HV* our_c3mro; /* $Class::C3::MRO{classname} */ |
609
|
0
|
|
|
|
|
|
SV* has_ovf = NULL; |
610
|
|
|
|
|
|
|
HV* methods; |
611
|
|
|
|
|
|
|
I32 mroitems; |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
/* temps */ |
614
|
|
|
|
|
|
|
HV* hv; |
615
|
|
|
|
|
|
|
HE* he; |
616
|
|
|
|
|
|
|
SV** svp; |
617
|
|
|
|
|
|
|
|
618
|
0
|
0
|
|
|
|
|
if(items < 1 || items > 2) |
|
|
0
|
|
|
|
|
|
619
|
0
|
|
|
|
|
|
croak("Usage: calculate_method_dispatch_table(classname[, cache])"); |
620
|
|
|
|
|
|
|
|
621
|
0
|
|
|
|
|
|
classname = ST(0); |
622
|
0
|
|
|
|
|
|
class_stash = gv_stashsv(classname, 0); |
623
|
0
|
0
|
|
|
|
|
if(!class_stash) |
624
|
0
|
0
|
|
|
|
|
Perl_croak(aTHX_ "No such class: '%s'!", SvPV_nolen(classname)); |
625
|
|
|
|
|
|
|
|
626
|
0
|
0
|
|
|
|
|
if(items == 2) cache = (HV*)SvRV(ST(1)); |
627
|
|
|
|
|
|
|
|
628
|
0
|
|
|
|
|
|
class_mro = __mro_linear_isa_c3(aTHX_ class_stash, cache, 0); |
629
|
|
|
|
|
|
|
|
630
|
0
|
|
|
|
|
|
our_c3mro = newHV(); |
631
|
0
|
0
|
|
|
|
|
if(!hv_store(our_c3mro, "MRO", 3, (SV*)newRV_noinc((SV*)class_mro), 0)) { |
632
|
0
|
|
|
|
|
|
croak("failed to store value in hash"); |
633
|
|
|
|
|
|
|
} |
634
|
|
|
|
|
|
|
|
635
|
0
|
|
|
|
|
|
hv = get_hv("Class::C3::MRO", 1); |
636
|
0
|
0
|
|
|
|
|
if(!hv_store_ent(hv, classname, (SV*)newRV_noinc((SV*)our_c3mro), 0)) { |
637
|
0
|
|
|
|
|
|
croak("failed to store value in hash"); |
638
|
|
|
|
|
|
|
} |
639
|
|
|
|
|
|
|
|
640
|
0
|
|
|
|
|
|
methods = newHV(); |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
/* skip first entry */ |
643
|
0
|
|
|
|
|
|
mroitems = AvFILLp(class_mro); |
644
|
0
|
|
|
|
|
|
svp = AvARRAY(class_mro) + 1; |
645
|
0
|
0
|
|
|
|
|
while(mroitems--) { |
646
|
0
|
|
|
|
|
|
SV* mro_class = *svp++; |
647
|
0
|
|
|
|
|
|
HV* mro_stash = gv_stashsv(mro_class, 0); |
648
|
|
|
|
|
|
|
|
649
|
0
|
0
|
|
|
|
|
if(!mro_stash) continue; |
650
|
|
|
|
|
|
|
|
651
|
0
|
0
|
|
|
|
|
if(!has_ovf) { |
652
|
0
|
|
|
|
|
|
SV** ovfp = hv_fetch(mro_stash, "()", 2, 0); |
653
|
0
|
0
|
|
|
|
|
if(ovfp) has_ovf = *ovfp; |
654
|
|
|
|
|
|
|
} |
655
|
|
|
|
|
|
|
|
656
|
0
|
|
|
|
|
|
hv_iterinit(mro_stash); |
657
|
0
|
0
|
|
|
|
|
while((he = hv_iternext(mro_stash))) { |
658
|
|
|
|
|
|
|
CV* code; |
659
|
|
|
|
|
|
|
SV* mskey; |
660
|
|
|
|
|
|
|
SV* msval; |
661
|
|
|
|
|
|
|
HE* ourent; |
662
|
|
|
|
|
|
|
HV* meth_hash; |
663
|
|
|
|
|
|
|
SV* orig; |
664
|
|
|
|
|
|
|
|
665
|
0
|
|
|
|
|
|
mskey = hv_iterkeysv(he); |
666
|
0
|
0
|
|
|
|
|
if(hv_exists_ent(methods, mskey, 0)) continue; |
667
|
|
|
|
|
|
|
|
668
|
0
|
|
|
|
|
|
msval = hv_iterval(mro_stash, he); |
669
|
0
|
0
|
|
|
|
|
if(SvTYPE(msval) != SVt_PVGV || !(code = GvCVu(msval))) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
670
|
0
|
|
|
|
|
|
continue; |
671
|
|
|
|
|
|
|
|
672
|
0
|
0
|
|
|
|
|
if((ourent = hv_fetch_ent(class_stash, mskey, 0, 0))) { |
673
|
0
|
|
|
|
|
|
SV* val = HeVAL(ourent); |
674
|
0
|
0
|
|
|
|
|
if(val && SvTYPE(val) == SVt_PVGV && GvCVu(val)) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
675
|
0
|
|
|
|
|
|
continue; |
676
|
|
|
|
|
|
|
} |
677
|
|
|
|
|
|
|
|
678
|
0
|
|
|
|
|
|
meth_hash = newHV(); |
679
|
0
|
|
|
|
|
|
orig = newSVsv(mro_class); |
680
|
0
|
|
|
|
|
|
sv_catpvn(orig, "::", 2); |
681
|
0
|
|
|
|
|
|
sv_catsv(orig, mskey); |
682
|
0
|
0
|
|
|
|
|
if( !hv_store(meth_hash, "orig", 4, orig, 0) |
683
|
0
|
0
|
|
|
|
|
|| !hv_store(meth_hash, "code", 4, newRV_inc((SV*)code), 0) |
684
|
0
|
0
|
|
|
|
|
|| !hv_store_ent(methods, mskey, newRV_noinc((SV*)meth_hash), 0) ) { |
685
|
0
|
|
|
|
|
|
croak("failed to store value in hash"); |
686
|
|
|
|
|
|
|
} |
687
|
|
|
|
|
|
|
} |
688
|
|
|
|
|
|
|
} |
689
|
|
|
|
|
|
|
|
690
|
0
|
0
|
|
|
|
|
if(!hv_store(our_c3mro, "methods", 7, newRV_noinc((SV*)methods), 0)) { |
691
|
0
|
|
|
|
|
|
croak("failed to store value in hash"); |
692
|
|
|
|
|
|
|
} |
693
|
0
|
0
|
|
|
|
|
if(has_ovf) { |
694
|
0
|
0
|
|
|
|
|
if(!hv_store(our_c3mro, "has_overload_fallback", 21, SvREFCNT_inc(has_ovf), 0)) { |
695
|
0
|
|
|
|
|
|
croak("failed to store value in hash"); |
696
|
|
|
|
|
|
|
} |
697
|
|
|
|
|
|
|
} |
698
|
0
|
|
|
|
|
|
XSRETURN_EMPTY; |
699
|
|
|
|
|
|
|
} |
700
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
MODULE = Class::C3::XS PACKAGE = Class::C3::XS |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
PROTOTYPES: DISABLED |
704
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
BOOT: |
706
|
12
|
|
|
|
|
|
newXS("Class::C3::XS::calculateMRO", XS_Class_C3_XS_calculateMRO, __FILE__); |
707
|
12
|
|
|
|
|
|
newXS("Class::C3::XS::_plsubgen", XS_Class_C3_XS_plsubgen, __FILE__); |
708
|
12
|
|
|
|
|
|
newXS("Class::C3::XS::_calculate_method_dispatch_table", XS_Class_C3_XS_calc_mdt, __FILE__); |
709
|
12
|
|
|
|
|
|
newXS("Class::C3::XS::_nextcan", XS_Class_C3_XS_nextcan, __FILE__); |
710
|
|
|
|
|
|
|
|