| 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
|
|
|
|
|
|
|
|