/home/travis/build/MoarVM/MoarVM/src/spesh/stats.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "moar.h" |
2 | | |
3 | | /* Gets the statistics for a static frame, creating them if needed. */ |
4 | 3.38M | MVMSpeshStats * stats_for(MVMThreadContext *tc, MVMStaticFrame *sf) { |
5 | 3.38M | MVMStaticFrameSpesh *spesh = sf->body.spesh; |
6 | 3.38M | if (!spesh->body.spesh_stats) |
7 | 80.1k | spesh->body.spesh_stats = MVM_calloc(1, sizeof(MVMSpeshStats)); |
8 | 3.38M | return spesh->body.spesh_stats; |
9 | 3.38M | } |
10 | | |
11 | | /* Gets the stats by callsite, adding it if it's missing. */ |
12 | 3.38M | MVMuint32 by_callsite_idx(MVMThreadContext *tc, MVMSpeshStats *ss, MVMCallsite *cs) { |
13 | 3.38M | /* See if we already have it. */ |
14 | 3.38M | MVMuint32 found; |
15 | 3.38M | MVMuint32 n = ss->num_by_callsite; |
16 | 4.04M | for (found = 0; found < n; found++) |
17 | 3.95M | if (ss->by_callsite[found].cs == cs) |
18 | 3.29M | return found; |
19 | 3.38M | |
20 | 3.38M | /* If not, we need a new record. */ |
21 | 91.8k | found = ss->num_by_callsite; |
22 | 91.8k | ss->num_by_callsite++; |
23 | 91.8k | ss->by_callsite = MVM_realloc(ss->by_callsite, |
24 | 91.8k | ss->num_by_callsite * sizeof(MVMSpeshStatsByCallsite)); |
25 | 91.8k | memset(&(ss->by_callsite[found]), 0, sizeof(MVMSpeshStatsByCallsite)); |
26 | 91.8k | ss->by_callsite[found].cs = cs; |
27 | 91.8k | return found; |
28 | 3.38M | } |
29 | | |
30 | | /* Checks if a type tuple is incomplete (no types logged for some passed |
31 | | * objects, or no decont type logged for a container type). */ |
32 | | MVMint32 incomplete_type_tuple(MVMThreadContext *tc, MVMCallsite *cs, |
33 | 3.28M | MVMSpeshStatsType *arg_types) { |
34 | 3.28M | MVMuint32 i; |
35 | 9.04M | for (i = 0; i < cs->flag_count; i++) { |
36 | 5.90M | if (cs->arg_flags[i] & MVM_CALLSITE_ARG_OBJ) { |
37 | 4.98M | MVMObject *type = arg_types[i].type; |
38 | 4.98M | if (!type) |
39 | 149k | return 1; |
40 | 4.83M | if (arg_types[i].type_concrete && type->st->container_spec) |
41 | 0 | if (!arg_types[i].decont_type && REPR(type)->ID != MVM_REPR_ID_NativeRef) |
42 | 0 | return 1; |
43 | 4.83M | } |
44 | 5.90M | } |
45 | 3.13M | return 0; |
46 | 3.28M | } |
47 | | |
48 | | /* Returns true if the callsite has no object arguments, false otherwise. */ |
49 | 3.31M | MVMint32 cs_without_object_args(MVMThreadContext *tc, MVMCallsite *cs) { |
50 | 3.31M | MVMuint32 i; |
51 | 3.32M | for (i = 0; i < cs->flag_count; i++) |
52 | 3.30M | if (cs->arg_flags[i] & MVM_CALLSITE_ARG_OBJ) |
53 | 3.28M | return 0; |
54 | 25.2k | return 1; |
55 | 3.31M | } |
56 | | |
57 | | /* Gets the stats by type, adding it if it's missing. Frees arg_types. Returns |
58 | | * the index in the by type array, or -1 if unresolved. */ |
59 | | MVMint32 by_type(MVMThreadContext *tc, MVMSpeshStats *ss, MVMuint32 callsite_idx, |
60 | 3.31M | MVMSpeshStatsType *arg_types) { |
61 | 3.31M | /* Resolve type by callsite level info. If this is the no-callsite |
62 | 3.31M | * specialization there is nothing further to do. */ |
63 | 3.31M | MVMSpeshStatsByCallsite *css = &(ss->by_callsite[callsite_idx]); |
64 | 3.31M | MVMCallsite *cs = css->cs; |
65 | 3.31M | if (!cs) { |
66 | 0 | MVM_free(arg_types); |
67 | 0 | return -1; |
68 | 0 | } |
69 | 3.31M | |
70 | 3.31M | /* Otherwise if there's no object args, then we'll use a single "by type" |
71 | 3.31M | * specialization, so we can have data tracked by offset at least. */ |
72 | 3.31M | else if (cs_without_object_args(tc, cs)) { |
73 | 25.2k | if (css->num_by_type == 0) { |
74 | 3.82k | css->num_by_type++; |
75 | 3.82k | css->by_type = MVM_calloc(1, sizeof(MVMSpeshStatsByType)); |
76 | 3.82k | css->by_type[0].arg_types = arg_types; |
77 | 3.82k | } |
78 | 21.4k | else { |
79 | 21.4k | MVM_free(arg_types); |
80 | 21.4k | } |
81 | 25.2k | return 0; |
82 | 25.2k | } |
83 | 3.31M | |
84 | 3.31M | /* Maybe the type tuple is incomplete, maybe because the log buffer ended |
85 | 3.31M | * prior to having all the type information. Discard. */ |
86 | 3.28M | else if (incomplete_type_tuple(tc, cs, arg_types)) { |
87 | 149k | MVM_free(arg_types); |
88 | 149k | return -1; |
89 | 149k | } |
90 | 3.28M | |
91 | 3.28M | /* Can produce by-type stats. */ |
92 | 3.13M | else { |
93 | 3.13M | /* See if we already have it. */ |
94 | 3.13M | size_t args_length = cs->flag_count * sizeof(MVMSpeshStatsType); |
95 | 3.13M | MVMuint32 found; |
96 | 3.13M | MVMuint32 n = css->num_by_type; |
97 | 12.5M | for (found = 0; found < n; found++) { |
98 | 12.4M | if (memcmp(css->by_type[found].arg_types, arg_types, args_length) == 0) { |
99 | 2.99M | MVM_free(arg_types); |
100 | 2.99M | return found; |
101 | 2.99M | } |
102 | 12.4M | } |
103 | 3.13M | |
104 | 3.13M | /* If not, we need a new record. */ |
105 | 142k | found = css->num_by_type; |
106 | 142k | css->num_by_type++; |
107 | 142k | css->by_type = MVM_realloc(css->by_type, |
108 | 142k | css->num_by_type * sizeof(MVMSpeshStatsByType)); |
109 | 142k | memset(&(css->by_type[found]), 0, sizeof(MVMSpeshStatsByType)); |
110 | 142k | css->by_type[found].arg_types = arg_types; |
111 | 142k | return found; |
112 | 3.13M | } |
113 | 3.31M | } |
114 | | |
115 | | /* Get the stats by offset entry, adding it if it's missing. */ |
116 | | MVMSpeshStatsByOffset * by_offset(MVMThreadContext *tc, MVMSpeshStatsByType *tss, |
117 | 17.8M | MVMuint32 bytecode_offset) { |
118 | 17.8M | /* See if we already have it. */ |
119 | 17.8M | MVMuint32 found; |
120 | 17.8M | MVMuint32 n = tss->num_by_offset; |
121 | 113M | for (found = 0; found < n; found++) |
122 | 112M | if (tss->by_offset[found].bytecode_offset == bytecode_offset) |
123 | 17.3M | return &(tss->by_offset[found]); |
124 | 17.8M | |
125 | 17.8M | /* If not, we need a new record. */ |
126 | 446k | found = tss->num_by_offset; |
127 | 446k | tss->num_by_offset++; |
128 | 446k | tss->by_offset = MVM_realloc(tss->by_offset, |
129 | 446k | tss->num_by_offset * sizeof(MVMSpeshStatsByOffset)); |
130 | 446k | memset(&(tss->by_offset[found]), 0, sizeof(MVMSpeshStatsByOffset)); |
131 | 446k | tss->by_offset[found].bytecode_offset = bytecode_offset; |
132 | 446k | return &(tss->by_offset[found]); |
133 | 17.8M | } |
134 | | |
135 | | /* Adds/increments the count of a certain type seen at the given offset. */ |
136 | | void add_type_at_offset(MVMThreadContext *tc, MVMSpeshStatsByOffset *oss, |
137 | 10.1M | MVMStaticFrame *sf, MVMObject *type, MVMuint8 concrete) { |
138 | 10.1M | /* If we have it already, increment the count. */ |
139 | 10.1M | MVMuint32 found; |
140 | 10.1M | MVMuint32 n = oss->num_types; |
141 | 10.7M | for (found = 0; found < n; found++) { |
142 | 10.3M | if (oss->types[found].type == type && oss->types[found].type_concrete == concrete) { |
143 | 9.72M | oss->types[found].count++; |
144 | 9.72M | return; |
145 | 9.72M | } |
146 | 10.3M | } |
147 | 10.1M | |
148 | 10.1M | /* Otherwise, add it to the list. */ |
149 | 416k | found = oss->num_types; |
150 | 416k | oss->num_types++; |
151 | 416k | oss->types = MVM_realloc(oss->types, oss->num_types * sizeof(MVMSpeshStatsTypeCount)); |
152 | 416k | MVM_ASSIGN_REF(tc, &(sf->body.spesh->common.header), oss->types[found].type, type); |
153 | 416k | oss->types[found].type_concrete = concrete; |
154 | 416k | oss->types[found].count = 1; |
155 | 416k | } |
156 | | |
157 | | /* Adds/increments the count of a certain invocation target seen at the given |
158 | | * offset. */ |
159 | | void add_invoke_at_offset(MVMThreadContext *tc, MVMSpeshStatsByOffset *oss, |
160 | | MVMStaticFrame *sf, MVMStaticFrame *target_sf, |
161 | 4.98M | MVMint16 caller_is_outer, MVMint16 was_multi) { |
162 | 4.98M | /* If we have it already, increment the count. */ |
163 | 4.98M | MVMuint32 found; |
164 | 4.98M | MVMuint32 n = oss->num_invokes; |
165 | 5.27M | for (found = 0; found < n; found++) { |
166 | 5.02M | if (oss->invokes[found].sf == target_sf) { |
167 | 4.73M | oss->invokes[found].count++; |
168 | 4.73M | if (caller_is_outer) |
169 | 47.6k | oss->invokes[found].caller_is_outer_count++; |
170 | 4.73M | if (was_multi) |
171 | 40.4k | oss->invokes[found].was_multi_count++; |
172 | 4.73M | return; |
173 | 4.73M | } |
174 | 5.02M | } |
175 | 4.98M | |
176 | 4.98M | /* Otherwise, add it to the list. */ |
177 | 251k | found = oss->num_invokes; |
178 | 251k | oss->num_invokes++; |
179 | 251k | oss->invokes = MVM_realloc(oss->invokes, |
180 | 251k | oss->num_invokes * sizeof(MVMSpeshStatsInvokeCount)); |
181 | 251k | MVM_ASSIGN_REF(tc, &(sf->body.spesh->common.header), oss->invokes[found].sf, target_sf); |
182 | 251k | oss->invokes[found].count = 1; |
183 | 248k | oss->invokes[found].caller_is_outer_count = caller_is_outer ? 1 : 0; |
184 | 246k | oss->invokes[found].was_multi_count = was_multi ? 1 : 0; |
185 | 251k | } |
186 | | |
187 | | /* Adds/increments the count of a plugin guard index seen at the given offset. */ |
188 | | void add_plugin_guard_at_offset(MVMThreadContext *tc, MVMSpeshStatsByOffset *oss, |
189 | 5.35k | MVMuint32 guard_index) { |
190 | 5.35k | /* If we have it already, increment the count. */ |
191 | 5.35k | MVMuint32 found; |
192 | 5.35k | MVMuint32 n = oss->num_plugin_guards; |
193 | 5.36k | for (found = 0; found < n; found++) { |
194 | 5.33k | if (oss->plugin_guards[found].guard_index == guard_index) { |
195 | 5.33k | oss->plugin_guards[found].count++; |
196 | 5.33k | return; |
197 | 5.33k | } |
198 | 5.33k | } |
199 | 5.35k | |
200 | 5.35k | /* Otherwise, add it to the list. */ |
201 | 22 | found = oss->num_plugin_guards; |
202 | 22 | oss->num_plugin_guards++; |
203 | 22 | oss->plugin_guards = MVM_realloc(oss->plugin_guards, |
204 | 22 | oss->num_plugin_guards * sizeof(MVMSpeshStatsPluginGuardCount)); |
205 | 22 | oss->plugin_guards[found].guard_index = guard_index; |
206 | 22 | oss->plugin_guards[found].count = 1; |
207 | 22 | } |
208 | | |
209 | | /* Adds/increments the count of a type tuple seen at the given offset. */ |
210 | | void add_type_tuple_at_offset(MVMThreadContext *tc, MVMSpeshStatsByOffset *oss, |
211 | 2.67M | MVMStaticFrame *sf, MVMSpeshSimCallType *info) { |
212 | 2.67M | /* Compute type tuple size. */ |
213 | 2.67M | size_t tt_size = info->cs->flag_count * sizeof(MVMSpeshStatsType); |
214 | 2.67M | |
215 | 2.67M | /* If we have it already, increment the count. */ |
216 | 2.67M | MVMuint32 found, i; |
217 | 2.67M | MVMuint32 n = oss->num_type_tuples; |
218 | 10.0M | for (found = 0; found < n; found++) { |
219 | 9.80M | if (oss->type_tuples[found].cs == info->cs) { |
220 | 9.80M | if (memcmp(oss->type_tuples[found].arg_types, info->arg_types, tt_size) == 0) { |
221 | 2.39M | oss->type_tuples[found].count++; |
222 | 2.39M | return; |
223 | 2.39M | } |
224 | 9.80M | } |
225 | 9.80M | } |
226 | 2.67M | |
227 | 2.67M | /* Otherwise, add it to the list; copy type tuple to ease memory |
228 | 2.67M | * management, but also need to write barrier any types. */ |
229 | 272k | found = oss->num_type_tuples; |
230 | 272k | oss->num_type_tuples++; |
231 | 272k | oss->type_tuples = MVM_realloc(oss->type_tuples, |
232 | 272k | oss->num_type_tuples * sizeof(MVMSpeshStatsTypeTupleCount)); |
233 | 272k | oss->type_tuples[found].cs = info->cs; |
234 | 272k | oss->type_tuples[found].arg_types = MVM_malloc(tt_size); |
235 | 272k | memcpy(oss->type_tuples[found].arg_types, info->arg_types, tt_size); |
236 | 786k | for (i = 0; i < info->cs->flag_count; i++) { |
237 | 514k | if (info->arg_types[i].type) |
238 | 447k | MVM_gc_write_barrier(tc, &(sf->body.spesh->common.header), |
239 | 447k | &(info->arg_types[i].type->header)); |
240 | 514k | if (info->arg_types[i].decont_type) |
241 | 0 | MVM_gc_write_barrier(tc, &(sf->body.spesh->common.header), |
242 | 0 | &(info->arg_types[i].decont_type->header)); |
243 | 514k | } |
244 | 272k | oss->type_tuples[found].count = 1; |
245 | 272k | } |
246 | | |
247 | | /* Initializes the stack simulation. */ |
248 | 145 | void sim_stack_init(MVMThreadContext *tc, MVMSpeshSimStack *sims) { |
249 | 145 | sims->used = 0; |
250 | 145 | sims->limit = 32; |
251 | 145 | sims->frames = MVM_malloc(sims->limit * sizeof(MVMSpeshSimStackFrame)); |
252 | 145 | sims->depth = 0; |
253 | 145 | } |
254 | | |
255 | | /* Pushes an entry onto the stack frame model. */ |
256 | | void sim_stack_push(MVMThreadContext *tc, MVMSpeshSimStack *sims, MVMStaticFrame *sf, |
257 | 3.38M | MVMSpeshStats *ss, MVMuint32 cid, MVMuint32 callsite_idx) { |
258 | 3.38M | MVMSpeshSimStackFrame *frame; |
259 | 3.38M | MVMCallsite *cs; |
260 | 3.38M | if (sims->used == sims->limit) { |
261 | 235 | sims->limit *= 2; |
262 | 235 | sims->frames = MVM_realloc(sims->frames, sims->limit * sizeof(MVMSpeshSimStackFrame)); |
263 | 235 | } |
264 | 3.38M | frame = &(sims->frames[sims->used++]); |
265 | 3.38M | frame->sf = sf; |
266 | 3.38M | frame->ss = ss; |
267 | 3.38M | frame->cid = cid; |
268 | 3.38M | frame->callsite_idx = callsite_idx; |
269 | 3.38M | frame->type_idx = -1; |
270 | 3.38M | frame->arg_types = (cs = ss->by_callsite[callsite_idx].cs) |
271 | 3.31M | ? MVM_calloc(cs->flag_count, sizeof(MVMSpeshStatsType)) |
272 | 3.38M | : NULL; |
273 | 3.38M | frame->offset_logs = NULL; |
274 | 3.38M | frame->offset_logs_used = frame->offset_logs_limit = 0; |
275 | 3.38M | frame->osr_hits = 0; |
276 | 3.38M | frame->call_type_info = NULL; |
277 | 3.38M | frame->call_type_info_used = frame->call_type_info_limit = 0; |
278 | 3.38M | frame->last_invoke_offset = 0; |
279 | 3.38M | frame->last_invoke_sf = NULL; |
280 | 3.38M | sims->depth++; |
281 | 3.38M | } |
282 | | |
283 | | /* Adds an entry to a sim frame's callsite type info list, for later |
284 | | * inclusion in the callsite stats. */ |
285 | | void add_sim_call_type_info(MVMThreadContext *tc, MVMSpeshSimStackFrame *simf, |
286 | | MVMuint32 bytecode_offset, MVMCallsite *cs, |
287 | 2.77M | MVMSpeshStatsType *arg_types) { |
288 | 2.77M | MVMSpeshSimCallType *info; |
289 | 2.77M | if (simf->call_type_info_used == simf->call_type_info_limit) { |
290 | 1.19M | simf->call_type_info_limit += 32; |
291 | 1.19M | simf->call_type_info = MVM_realloc(simf->call_type_info, |
292 | 1.19M | simf->call_type_info_limit * sizeof(MVMSpeshSimCallType)); |
293 | 1.19M | } |
294 | 2.77M | info = &(simf->call_type_info[simf->call_type_info_used++]); |
295 | 2.77M | info->bytecode_offset = bytecode_offset; |
296 | 2.77M | info->cs = cs; |
297 | 2.77M | info->arg_types = arg_types; |
298 | 2.77M | } |
299 | | |
300 | | /* Incorporate information collected into a sim stack frame. */ |
301 | | void incorporate_stats(MVMThreadContext *tc, MVMSpeshSimStackFrame *simf, |
302 | | MVMuint32 frame_depth, MVMSpeshSimStackFrame *caller, |
303 | 3.43M | MVMObject *sf_updated) { |
304 | 3.43M | MVMSpeshStatsByType *tss; |
305 | 3.43M | MVMint32 first_type_hit = 0; |
306 | 3.43M | |
307 | 3.43M | /* Bump version if needed. */ |
308 | 3.43M | if (simf->ss->last_update != tc->instance->spesh_stats_version) { |
309 | 36.4k | simf->ss->last_update = tc->instance->spesh_stats_version; |
310 | 36.4k | MVM_repr_push_o(tc, sf_updated, (MVMObject *)simf->sf); |
311 | 36.4k | } |
312 | 3.43M | |
313 | 3.43M | /* Add OSR hits at callsite level and update depth. */ |
314 | 3.43M | if (simf->osr_hits) { |
315 | 197k | simf->ss->osr_hits += simf->osr_hits; |
316 | 197k | simf->ss->by_callsite[simf->callsite_idx].osr_hits += simf->osr_hits; |
317 | 197k | } |
318 | 3.43M | if (frame_depth > simf->ss->by_callsite[simf->callsite_idx].max_depth) |
319 | 237k | simf->ss->by_callsite[simf->callsite_idx].max_depth = frame_depth; |
320 | 3.43M | |
321 | 3.43M | /* See if there's a type tuple to attach type-based stats to. */ |
322 | 3.43M | if (simf->type_idx < 0 && simf->arg_types) { |
323 | 3.31M | simf->type_idx = by_type(tc, simf->ss, simf->callsite_idx, simf->arg_types); |
324 | 3.31M | simf->arg_types = NULL; |
325 | 3.31M | first_type_hit = 1; |
326 | 3.31M | } |
327 | 3.43M | tss = simf->type_idx >= 0 |
328 | 3.20M | ? &(simf->ss->by_callsite[simf->callsite_idx].by_type[simf->type_idx]) |
329 | 3.43M | : NULL; |
330 | 3.43M | if (tss) { |
331 | 3.20M | /* Incorporate data logged at offsets. */ |
332 | 3.20M | MVMuint32 i; |
333 | 18.3M | for (i = 0; i < simf->offset_logs_used; i++) { |
334 | 15.1M | MVMSpeshLogEntry *e = simf->offset_logs[i]; |
335 | 15.1M | switch (e->kind) { |
336 | 10.1M | case MVM_SPESH_LOG_TYPE: |
337 | 10.1M | case MVM_SPESH_LOG_RETURN: { |
338 | 10.1M | MVMSpeshStatsByOffset *oss = by_offset(tc, tss, |
339 | 10.1M | e->type.bytecode_offset); |
340 | 10.1M | add_type_at_offset(tc, oss, simf->sf, e->type.type, |
341 | 10.1M | e->type.flags & MVM_SPESH_LOG_TYPE_FLAG_CONCRETE); |
342 | 10.1M | break; |
343 | 10.1M | } |
344 | 4.98M | case MVM_SPESH_LOG_INVOKE: { |
345 | 4.98M | MVMSpeshStatsByOffset *oss = by_offset(tc, tss, |
346 | 4.98M | e->invoke.bytecode_offset); |
347 | 4.98M | add_invoke_at_offset(tc, oss, simf->sf, e->invoke.sf, |
348 | 4.98M | e->invoke.caller_is_outer, e->invoke.was_multi); |
349 | 4.98M | break; |
350 | 10.1M | } |
351 | 5.35k | case MVM_SPESH_LOG_PLUGIN_RESOLUTION: { |
352 | 5.35k | MVMSpeshStatsByOffset *oss = by_offset(tc, tss, |
353 | 5.35k | e->plugin.bytecode_offset); |
354 | 5.35k | add_plugin_guard_at_offset(tc, oss, e->plugin.guard_index); |
355 | 5.35k | break; |
356 | 10.1M | } |
357 | 15.1M | } |
358 | 15.1M | } |
359 | 3.20M | |
360 | 3.20M | /* Incorporate callsite type stats (what type tuples did we make a |
361 | 3.20M | * call with). */ |
362 | 5.87M | for (i = 0; i < simf->call_type_info_used; i++) { |
363 | 2.67M | MVMSpeshSimCallType *info = &(simf->call_type_info[i]); |
364 | 2.67M | MVMSpeshStatsByOffset *oss = by_offset(tc, tss, info->bytecode_offset); |
365 | 2.67M | add_type_tuple_at_offset(tc, oss, simf->sf, info); |
366 | 2.67M | } |
367 | 3.20M | |
368 | 3.20M | /* Incorporate OSR hits and bump max depth. */ |
369 | 3.20M | if (first_type_hit) |
370 | 3.16M | tss->hits++; |
371 | 3.20M | tss->osr_hits += simf->osr_hits; |
372 | 3.20M | if (frame_depth > tss->max_depth) |
373 | 299k | tss->max_depth = frame_depth; |
374 | 3.20M | |
375 | 3.20M | /* If the callee's last incovation matches the frame just invoked, |
376 | 3.20M | * then log the type tuple against the callsite. */ |
377 | 3.20M | if (caller && caller->last_invoke_sf == simf->sf) |
378 | 2.77M | add_sim_call_type_info(tc, caller, caller->last_invoke_offset, |
379 | 2.77M | simf->ss->by_callsite[simf->callsite_idx].cs, |
380 | 2.77M | tss->arg_types); |
381 | 3.20M | } |
382 | 3.43M | |
383 | 3.43M | /* Clear up offset logs and call type info; they're either incorproated or |
384 | 3.43M | * to be tossed. Also zero OSR hits, so we don't over-inflate them if this |
385 | 3.43M | * frame entry survives. */ |
386 | 3.43M | MVM_free(simf->offset_logs); |
387 | 3.43M | simf->offset_logs = NULL; |
388 | 3.43M | simf->offset_logs_used = simf->offset_logs_limit = 0; |
389 | 3.43M | MVM_free(simf->call_type_info); |
390 | 3.43M | simf->call_type_info = NULL; |
391 | 3.43M | simf->call_type_info_used = simf->call_type_info_limit = 0; |
392 | 3.43M | simf->osr_hits = 0; |
393 | 3.43M | } |
394 | | |
395 | | /* Pops the top frame from the sim stack. */ |
396 | 3.37M | void sim_stack_pop(MVMThreadContext *tc, MVMSpeshSimStack *sims, MVMObject *sf_updated) { |
397 | 3.37M | MVMSpeshSimStackFrame *simf; |
398 | 3.37M | MVMuint32 frame_depth; |
399 | 3.37M | |
400 | 3.37M | /* Pop off the simulated frame and incorporate logged data into the spesh |
401 | 3.37M | * stats model. */ |
402 | 3.37M | if (sims->used == 0) |
403 | 0 | MVM_panic(1, "Spesh stats: cannot pop an empty simulation stack"); |
404 | 3.37M | sims->used--; |
405 | 3.37M | simf = &(sims->frames[sims->used]); |
406 | 3.37M | frame_depth = sims->depth--; |
407 | 3.37M | |
408 | 3.37M | /* Incorporate logged data into the statistics model. */ |
409 | 3.37M | incorporate_stats(tc, simf, frame_depth, |
410 | 3.37M | sims->used > 0 ? &(sims->frames[sims->used - 1]) : NULL, |
411 | 3.37M | sf_updated); |
412 | 3.37M | } |
413 | | |
414 | | /* Gets the simulation stack frame for the specified correlation ID. If it is |
415 | | * not on the top, searches to see if it's further down. If it is, then pops |
416 | | * off the top to reach it. If it's not found at all, returns NULL and does |
417 | | * nothing to the simulation stack. */ |
418 | | MVMSpeshSimStackFrame * sim_stack_find(MVMThreadContext *tc, MVMSpeshSimStack *sims, |
419 | 22.5M | MVMuint32 cid, MVMObject *sf_updated) { |
420 | 22.5M | MVMuint32 found_at = sims->used; |
421 | 22.5M | while (found_at != 0) { |
422 | 22.5M | found_at--; |
423 | 22.5M | if (sims->frames[found_at].cid == cid) { |
424 | 22.5M | MVMint32 pop = (sims->used - found_at) - 1; |
425 | 22.5M | MVMint32 i; |
426 | 22.5M | for (i = 0; i < pop; i++) |
427 | 15.2k | sim_stack_pop(tc, sims, sf_updated); |
428 | 22.5M | return &(sims->frames[found_at]); |
429 | 22.5M | } |
430 | 22.5M | } |
431 | 0 | return NULL; |
432 | 22.5M | } |
433 | | |
434 | | /* Pops all the frames in the stack simulation and frees the frames storage. */ |
435 | 0 | void sim_stack_teardown(MVMThreadContext *tc, MVMSpeshSimStack *sims, MVMObject *sf_updated) { |
436 | 0 | while (sims->used) |
437 | 0 | sim_stack_pop(tc, sims, sf_updated); |
438 | 0 | MVM_free(sims->frames); |
439 | 0 | } |
440 | | |
441 | | /* Gets the parameter type slot from a simulation frame. */ |
442 | 5.23M | MVMSpeshStatsType * param_type(MVMThreadContext *tc, MVMSpeshSimStackFrame *simf, MVMSpeshLogEntry *e) { |
443 | 5.23M | if (simf->arg_types) { |
444 | 5.10M | MVMuint16 idx = e->param.arg_idx; |
445 | 5.10M | MVMCallsite *cs = simf->ss->by_callsite[simf->callsite_idx].cs; |
446 | 5.10M | if (cs) { |
447 | 5.10M | MVMint32 flag_idx = idx < cs->num_pos |
448 | 4.91M | ? idx |
449 | 182k | : cs->num_pos + (((idx - 1) - cs->num_pos) / 2); |
450 | 5.10M | if (flag_idx >= cs->flag_count) |
451 | 0 | MVM_panic(1, "Spesh stats: argument flag index out of bounds"); |
452 | 5.10M | if (cs->arg_flags[flag_idx] & MVM_CALLSITE_ARG_OBJ) |
453 | 4.84M | return &(simf->arg_types[flag_idx]); |
454 | 5.10M | } |
455 | 5.10M | } |
456 | 394k | return NULL; |
457 | 5.23M | } |
458 | | |
459 | | /* Records a static value for a frame, unless it's already in the log. */ |
460 | | void add_static_value(MVMThreadContext *tc, MVMSpeshSimStackFrame *simf, MVMint32 bytecode_offset, |
461 | 48.3k | MVMObject *value) { |
462 | 48.3k | MVMSpeshStats *ss = simf->ss; |
463 | 48.3k | MVMuint32 i, id; |
464 | 133k | for (i = 0; i < ss->num_static_values; i++) |
465 | 128k | if (ss->static_values[i].bytecode_offset == bytecode_offset) |
466 | 43.9k | return; |
467 | 4.41k | id = ss->num_static_values++; |
468 | 4.41k | ss->static_values = MVM_realloc(ss->static_values, |
469 | 4.41k | ss->num_static_values * sizeof(MVMSpeshStatsStatic)); |
470 | 4.41k | ss->static_values[id].bytecode_offset = bytecode_offset; |
471 | 4.41k | MVM_ASSIGN_REF(tc, &(simf->sf->body.spesh->common.header), ss->static_values[id].value, value); |
472 | 4.41k | } |
473 | | |
474 | | /* Decides whether to save or free the simulation stack. */ |
475 | | static void save_or_free_sim_stack(MVMThreadContext *tc, MVMSpeshSimStack *sims, |
476 | 1.58k | MVMThreadContext *save_on_tc, MVMObject *sf_updated) { |
477 | 1.58k | MVMint32 first_survivor = -1; |
478 | 1.58k | MVMint32 i; |
479 | 1.58k | if (save_on_tc) { |
480 | 1.58k | for (i = 0; i < sims->used; i++) { |
481 | 1.58k | MVMSpeshSimStackFrame *simf = &(sims->frames[i]); |
482 | 1.58k | MVMuint32 age = tc->instance->spesh_stats_version - simf->ss->last_update; |
483 | 1.58k | if (age < MVM_SPESH_STATS_MAX_AGE - 1) { |
484 | 1.58k | first_survivor = i; |
485 | 1.58k | break; |
486 | 1.58k | } |
487 | 1.58k | } |
488 | 1.58k | } |
489 | 1.58k | if (first_survivor >= 0) { |
490 | 1.58k | /* Move survivors to the start. */ |
491 | 1.58k | if (first_survivor > 0) { |
492 | 0 | sims->used -= first_survivor; |
493 | 0 | memmove(sims->frames, sims->frames + first_survivor, |
494 | 0 | sims->used * sizeof(MVMSpeshSimStackFrame)); |
495 | 0 | } |
496 | 1.58k | |
497 | 1.58k | /* Incorporate data from the rest into the stats model, clearing it |
498 | 1.58k | * away. */ |
499 | 1.58k | i = sims->used - 1; |
500 | 60.8k | while (i >= 0) { |
501 | 59.2k | incorporate_stats(tc, &(sims->frames[i]), first_survivor + i, |
502 | 57.6k | i > 0 ? &(sims->frames[i - 1]) : NULL, |
503 | 59.2k | sf_updated); |
504 | 59.2k | i--; |
505 | 59.2k | } |
506 | 1.58k | |
507 | 1.58k | /* Save frames for next time. */ |
508 | 1.58k | save_on_tc->spesh_sim_stack = sims; |
509 | 1.58k | } |
510 | 0 | else { |
511 | 0 | /* Everything on the simulated stack is too old; throw it away. */ |
512 | 0 | sim_stack_teardown(tc, sims, sf_updated); |
513 | 0 | MVM_free(sims); |
514 | 0 | } |
515 | 1.58k | } |
516 | | |
517 | | /* Receives a spesh log and updates static frame statistics. Each static frame |
518 | | * that is updated is pushed once into sf_updated. */ |
519 | 1.60k | void MVM_spesh_stats_update(MVMThreadContext *tc, MVMSpeshLog *sl, MVMObject *sf_updated) { |
520 | 1.60k | MVMuint32 i; |
521 | 1.60k | MVMuint32 n = sl->body.used; |
522 | 1.60k | MVMSpeshSimStack *sims; |
523 | 1.60k | MVMThreadContext *log_from_tc = sl->body.thread->body.tc; |
524 | 1.60k | #if MVM_GC_DEBUG |
525 | | tc->in_spesh = 1; |
526 | | #endif |
527 | 1.60k | /* See if we have a simulation stack left over from before; create a new |
528 | 1.60k | * one if not. */ |
529 | 1.60k | if (log_from_tc && log_from_tc->spesh_sim_stack) { |
530 | 1.45k | /* Filter out those whose stats pointer is outdated. */ |
531 | 1.45k | MVMuint32 insert_pos = 0; |
532 | 1.45k | sims = log_from_tc->spesh_sim_stack; |
533 | 55.7k | for (i = 0; i < sims->used; i++) { |
534 | 54.3k | MVMSpeshStats *cur_stats = sims->frames[i].sf->body.spesh->body.spesh_stats; |
535 | 54.3k | if (cur_stats == sims->frames[i].ss) { |
536 | 54.3k | if (i != insert_pos) |
537 | 0 | sims->frames[insert_pos] = sims->frames[i]; |
538 | 54.3k | insert_pos++; |
539 | 54.3k | } |
540 | 54.3k | } |
541 | 1.45k | sims->used = insert_pos; |
542 | 1.45k | log_from_tc->spesh_sim_stack = NULL; |
543 | 1.45k | } |
544 | 145 | else { |
545 | 145 | sims = MVM_malloc(sizeof(MVMSpeshSimStack)); |
546 | 145 | sim_stack_init(tc, sims); |
547 | 145 | } |
548 | 1.60k | |
549 | 1.60k | /* Process the log entries. */ |
550 | 25.9M | for (i = 0; i < n; i++) { |
551 | 25.9M | MVMSpeshLogEntry *e = &(sl->body.entries[i]); |
552 | 25.9M | switch (e->kind) { |
553 | 3.38M | case MVM_SPESH_LOG_ENTRY: { |
554 | 3.38M | MVMSpeshStats *ss = stats_for(tc, e->entry.sf); |
555 | 3.38M | MVMuint32 callsite_idx; |
556 | 3.38M | if (ss->last_update != tc->instance->spesh_stats_version) { |
557 | 264k | ss->last_update = tc->instance->spesh_stats_version; |
558 | 264k | MVM_repr_push_o(tc, sf_updated, (MVMObject *)e->entry.sf); |
559 | 264k | } |
560 | 3.38M | ss->hits++; |
561 | 3.38M | callsite_idx = by_callsite_idx(tc, ss, e->entry.cs); |
562 | 3.38M | ss->by_callsite[callsite_idx].hits++; |
563 | 3.38M | sim_stack_push(tc, sims, e->entry.sf, ss, e->id, callsite_idx); |
564 | 3.38M | break; |
565 | 3.38M | } |
566 | 5.23M | case MVM_SPESH_LOG_PARAMETER: { |
567 | 5.23M | MVMSpeshSimStackFrame *simf = sim_stack_find(tc, sims, e->id, sf_updated); |
568 | 5.23M | if (simf) { |
569 | 5.23M | MVMSpeshStatsType *type_slot = param_type(tc, simf, e); |
570 | 5.23M | if (type_slot) { |
571 | 4.84M | MVM_ASSIGN_REF(tc, &(simf->sf->body.spesh->common.header), |
572 | 4.84M | type_slot->type, e->param.type); |
573 | 4.84M | type_slot->type_concrete = |
574 | 4.84M | e->param.flags & MVM_SPESH_LOG_TYPE_FLAG_CONCRETE ? 1 : 0; |
575 | 4.84M | type_slot->rw_cont = |
576 | 4.84M | e->param.flags & MVM_SPESH_LOG_TYPE_FLAG_RW_CONT ? 1 : 0; |
577 | 4.84M | } |
578 | 5.23M | } |
579 | 5.23M | break; |
580 | 3.38M | } |
581 | 0 | case MVM_SPESH_LOG_PARAMETER_DECONT: { |
582 | 0 | MVMSpeshSimStackFrame *simf = sim_stack_find(tc, sims, e->id, sf_updated); |
583 | 0 | if (simf) { |
584 | 0 | MVMSpeshStatsType *type_slot = param_type(tc, simf, e); |
585 | 0 | if (type_slot) { |
586 | 0 | MVM_ASSIGN_REF(tc, &(simf->sf->body.spesh->common.header), |
587 | 0 | type_slot->decont_type, e->param.type); |
588 | 0 | type_slot->decont_type_concrete = |
589 | 0 | e->param.flags & MVM_SPESH_LOG_TYPE_FLAG_CONCRETE; |
590 | 0 | } |
591 | 0 | } |
592 | 0 | break; |
593 | 3.38M | } |
594 | 13.2M | case MVM_SPESH_LOG_TYPE: |
595 | 13.2M | case MVM_SPESH_LOG_INVOKE: |
596 | 13.2M | case MVM_SPESH_LOG_PLUGIN_RESOLUTION: { |
597 | 13.2M | /* We only incorporate these into the model later, and only |
598 | 13.2M | * then if we need to. For now, just keep references to |
599 | 13.2M | * them. */ |
600 | 13.2M | MVMSpeshSimStackFrame *simf = sim_stack_find(tc, sims, e->id, sf_updated); |
601 | 13.2M | if (simf) { |
602 | 13.2M | if (simf->offset_logs_used == simf->offset_logs_limit) { |
603 | 2.84M | simf->offset_logs_limit += 32; |
604 | 2.84M | simf->offset_logs = MVM_realloc(simf->offset_logs, |
605 | 2.84M | simf->offset_logs_limit * sizeof(MVMSpeshLogEntry *)); |
606 | 2.84M | } |
607 | 13.2M | simf->offset_logs[simf->offset_logs_used++] = e; |
608 | 13.2M | if (e->kind == MVM_SPESH_LOG_INVOKE) { |
609 | 5.19M | simf->last_invoke_offset = e->invoke.bytecode_offset; |
610 | 5.19M | simf->last_invoke_sf = e->invoke.sf; |
611 | 5.19M | } |
612 | 13.2M | } |
613 | 13.2M | break; |
614 | 13.2M | } |
615 | 594k | case MVM_SPESH_LOG_OSR: { |
616 | 594k | MVMSpeshSimStackFrame *simf = sim_stack_find(tc, sims, e->id, sf_updated); |
617 | 594k | if (simf) |
618 | 594k | simf->osr_hits++; |
619 | 594k | break; |
620 | 13.2M | } |
621 | 48.3k | case MVM_SPESH_LOG_STATIC: { |
622 | 48.3k | MVMSpeshSimStackFrame *simf = sim_stack_find(tc, sims, e->id, sf_updated); |
623 | 48.3k | if (simf) |
624 | 48.3k | add_static_value(tc, simf, e->value.bytecode_offset, e->value.value); |
625 | 48.3k | break; |
626 | 13.2M | } |
627 | 3.36M | case MVM_SPESH_LOG_RETURN: { |
628 | 3.36M | MVMSpeshSimStackFrame *simf = sim_stack_find(tc, sims, e->id, sf_updated); |
629 | 3.36M | if (simf) { |
630 | 3.36M | MVMStaticFrame *called_sf = simf->sf; |
631 | 3.36M | sim_stack_pop(tc, sims, sf_updated); |
632 | 3.36M | if (e->type.type && sims->used) { |
633 | 2.80M | MVMSpeshSimStackFrame *caller = &(sims->frames[sims->used - 1]); |
634 | 2.80M | if (called_sf == caller->last_invoke_sf) { |
635 | 2.44M | if (caller->offset_logs_used == caller->offset_logs_limit) { |
636 | 24.6k | caller->offset_logs_limit += 32; |
637 | 24.6k | caller->offset_logs = MVM_realloc(caller->offset_logs, |
638 | 24.6k | caller->offset_logs_limit * sizeof(MVMSpeshLogEntry *)); |
639 | 24.6k | } |
640 | 2.44M | e->type.bytecode_offset = caller->last_invoke_offset; |
641 | 2.44M | caller->offset_logs[caller->offset_logs_used++] = e; |
642 | 2.44M | } |
643 | 2.80M | } |
644 | 3.36M | } |
645 | 3.36M | break; |
646 | 13.2M | } |
647 | 25.9M | } |
648 | 25.9M | } |
649 | 1.58k | save_or_free_sim_stack(tc, sims, log_from_tc, sf_updated); |
650 | 1.58k | #if MVM_GC_DEBUG |
651 | | tc->in_spesh = 0; |
652 | | #endif |
653 | 1.58k | } |
654 | | |
655 | | /* Takes an array of frames we recently updated the stats in. If they weren't |
656 | | * updated in a while, clears them out. */ |
657 | 1.47k | void MVM_spesh_stats_cleanup(MVMThreadContext *tc, MVMObject *check_frames) { |
658 | 1.47k | MVMint64 elems = MVM_repr_elems(tc, check_frames); |
659 | 1.47k | MVMint64 insert_pos = 0; |
660 | 1.47k | MVMint64 i; |
661 | 1.80M | for (i = 0; i < elems; i++) { |
662 | 1.80M | MVMStaticFrame *sf = (MVMStaticFrame *)MVM_repr_at_pos_o(tc, check_frames, i); |
663 | 1.80M | MVMStaticFrameSpesh *spesh = sf->body.spesh; |
664 | 1.80M | MVMSpeshStats *ss = spesh->body.spesh_stats; |
665 | 1.80M | if (!ss) { |
666 | 51.3k | /* No stats; already destroyed, don't keep this frame under |
667 | 51.3k | * consideration. */ |
668 | 51.3k | } |
669 | 1.75M | else if (tc->instance->spesh_stats_version - ss->last_update > MVM_SPESH_STATS_MAX_AGE) { |
670 | 20.4k | MVM_spesh_stats_destroy(tc, ss); |
671 | 20.4k | MVM_free(spesh->body.spesh_stats); |
672 | 20.4k | spesh->body.spesh_stats = NULL; |
673 | 20.4k | } |
674 | 1.73M | else { |
675 | 1.73M | MVM_repr_bind_pos_o(tc, check_frames, insert_pos++, (MVMObject *)sf); |
676 | 1.73M | } |
677 | 1.80M | } |
678 | 1.47k | MVM_repr_pos_set_elems(tc, check_frames, insert_pos); |
679 | 1.47k | } |
680 | | |
681 | 11.1k | void MVM_spesh_stats_gc_mark(MVMThreadContext *tc, MVMSpeshStats *ss, MVMGCWorklist *worklist) { |
682 | 11.1k | if (ss) { |
683 | 9.57k | MVMuint32 i, j, k, l, m; |
684 | 21.8k | for (i = 0; i < ss->num_by_callsite; i++) { |
685 | 12.2k | MVMSpeshStatsByCallsite *by_cs = &(ss->by_callsite[i]); |
686 | 45.4k | for (j = 0; j < by_cs->num_by_type; j++) { |
687 | 33.1k | MVMSpeshStatsByType *by_type = &(by_cs->by_type[j]); |
688 | 33.1k | MVMuint32 num_types = by_cs->cs->flag_count; |
689 | 105k | for (k = 0; k < num_types; k++) { |
690 | 72.5k | MVM_gc_worklist_add(tc, worklist, &(by_type->arg_types[k].type)); |
691 | 72.5k | MVM_gc_worklist_add(tc, worklist, &(by_type->arg_types[k].decont_type)); |
692 | 72.5k | } |
693 | 141k | for (k = 0; k < by_type->num_by_offset; k++) { |
694 | 107k | MVMSpeshStatsByOffset *by_offset = &(by_type->by_offset[k]); |
695 | 214k | for (l = 0; l < by_offset->num_types; l++) |
696 | 106k | MVM_gc_worklist_add(tc, worklist, &(by_offset->types[l].type)); |
697 | 165k | for (l = 0; l < by_offset->num_invokes; l++) |
698 | 57.0k | MVM_gc_worklist_add(tc, worklist, &(by_offset->invokes[l].sf)); |
699 | 174k | for (l = 0; l < by_offset->num_type_tuples; l++) { |
700 | 66.2k | MVMSpeshStatsType *off_types = by_offset->type_tuples[l].arg_types; |
701 | 66.2k | MVMuint32 num_off_types = by_offset->type_tuples[l].cs->flag_count; |
702 | 198k | for (m = 0; m < num_off_types; m++) { |
703 | 132k | MVM_gc_worklist_add(tc, worklist, &(off_types[m].type)); |
704 | 132k | MVM_gc_worklist_add(tc, worklist, &(off_types[m].decont_type)); |
705 | 132k | } |
706 | 66.2k | } |
707 | 107k | } |
708 | 33.1k | } |
709 | 12.2k | } |
710 | 10.9k | for (i = 0; i < ss->num_static_values; i++) |
711 | 1.37k | MVM_gc_worklist_add(tc, worklist, &(ss->static_values[i].value)); |
712 | 9.57k | } |
713 | 11.1k | } |
714 | | |
715 | 0 | void MVM_spesh_stats_gc_describe(MVMThreadContext *tc, MVMHeapSnapshotState *snapshot, MVMSpeshStats *ss) { |
716 | 0 | if (ss) { |
717 | 0 | MVMuint32 i, j, k, l, m; |
718 | 0 | for (i = 0; i < ss->num_by_callsite; i++) { |
719 | 0 | MVMSpeshStatsByCallsite *by_cs = &(ss->by_callsite[i]); |
720 | 0 | for (j = 0; j < by_cs->num_by_type; j++) { |
721 | 0 | MVMSpeshStatsByType *by_type = &(by_cs->by_type[j]); |
722 | 0 | MVMuint32 num_types = by_cs->cs->flag_count; |
723 | 0 | for (k = 0; k < num_types; k++) { |
724 | 0 | MVM_profile_heap_add_collectable_rel_const_cstr(tc, snapshot, |
725 | 0 | (MVMCollectable*)(by_type->arg_types[k].type), "type"); |
726 | 0 | MVM_profile_heap_add_collectable_rel_const_cstr(tc, snapshot, |
727 | 0 | (MVMCollectable*)(by_type->arg_types[k].decont_type), "decont type"); |
728 | 0 | } |
729 | 0 | for (k = 0; k < by_type->num_by_offset; k++) { |
730 | 0 | MVMSpeshStatsByOffset *by_offset = &(by_type->by_offset[k]); |
731 | 0 | for (l = 0; l < by_offset->num_types; l++) |
732 | 0 | MVM_profile_heap_add_collectable_rel_const_cstr(tc, snapshot, |
733 | 0 | (MVMCollectable*)(by_offset->types[l].type), "type at offset"); |
734 | 0 | for (l = 0; l < by_offset->num_invokes; l++) |
735 | 0 | MVM_profile_heap_add_collectable_rel_const_cstr(tc, snapshot, |
736 | 0 | (MVMCollectable*)(by_offset->invokes[l].sf), "invoke"); |
737 | 0 | for (l = 0; l < by_offset->num_type_tuples; l++) { |
738 | 0 | MVMSpeshStatsType *off_types = by_offset->type_tuples[l].arg_types; |
739 | 0 | MVMuint32 num_off_types = by_offset->type_tuples[l].cs->flag_count; |
740 | 0 | for (m = 0; m < num_off_types; m++) { |
741 | 0 | MVM_profile_heap_add_collectable_rel_const_cstr(tc, snapshot, |
742 | 0 | (MVMCollectable*)(off_types[m].type), "type tuple type"); |
743 | 0 | MVM_profile_heap_add_collectable_rel_const_cstr(tc, snapshot, |
744 | 0 | (MVMCollectable*)(off_types[m].decont_type), "type tuple deconted type"); |
745 | 0 | } |
746 | 0 | } |
747 | 0 | } |
748 | 0 | } |
749 | 0 | } |
750 | 0 | for (i = 0; i < ss->num_static_values; i++) |
751 | 0 | MVM_profile_heap_add_collectable_rel_const_cstr(tc, snapshot, |
752 | 0 | (MVMCollectable*)(ss->static_values[i].value), "static value"); |
753 | 0 | } |
754 | 0 | } |
755 | | |
756 | 20.4k | void MVM_spesh_stats_destroy(MVMThreadContext *tc, MVMSpeshStats *ss) { |
757 | 20.4k | if (ss) { |
758 | 20.4k | MVMuint32 i, j, k, l; |
759 | 42.5k | for (i = 0; i < ss->num_by_callsite; i++) { |
760 | 22.0k | MVMSpeshStatsByCallsite *by_cs = &(ss->by_callsite[i]); |
761 | 50.9k | for (j = 0; j < by_cs->num_by_type; j++) { |
762 | 28.9k | MVMSpeshStatsByType *by_type = &(by_cs->by_type[j]); |
763 | 129k | for (k = 0; k < by_type->num_by_offset; k++) { |
764 | 100k | MVMSpeshStatsByOffset *by_offset = &(by_type->by_offset[k]); |
765 | 100k | MVM_free(by_offset->types); |
766 | 100k | MVM_free(by_offset->invokes); |
767 | 147k | for (l = 0; l < by_offset->num_type_tuples; l++) |
768 | 46.1k | MVM_free(by_offset->type_tuples[l].arg_types); |
769 | 100k | MVM_free(by_offset->type_tuples); |
770 | 100k | MVM_free(by_offset->plugin_guards); |
771 | 100k | } |
772 | 28.9k | MVM_free(by_type->by_offset); |
773 | 28.9k | MVM_free(by_type->arg_types); |
774 | 28.9k | } |
775 | 22.0k | MVM_free(by_cs->by_type); |
776 | 22.0k | } |
777 | 20.4k | MVM_free(ss->by_callsite); |
778 | 20.4k | MVM_free(ss->static_values); |
779 | 20.4k | } |
780 | 20.4k | } |
781 | | |
782 | | void MVM_spesh_sim_stack_gc_mark(MVMThreadContext *tc, MVMSpeshSimStack *sims, |
783 | 750 | MVMGCWorklist *worklist) { |
784 | 401 | MVMuint32 n = sims ? sims->used : 0; |
785 | 750 | MVMuint32 i; |
786 | 11.5k | for (i = 0; i < n; i++) { |
787 | 10.7k | MVMSpeshSimStackFrame *simf = &(sims->frames[i]); |
788 | 10.7k | MVM_gc_worklist_add(tc, worklist, &(simf->sf)); |
789 | 10.7k | MVM_gc_worklist_add(tc, worklist, &(simf->last_invoke_sf)); |
790 | 10.7k | } |
791 | 750 | } |
792 | | |
793 | 0 | void MVM_spesh_sim_stack_gc_describe(MVMThreadContext *tc, MVMHeapSnapshotState *ss, MVMSpeshSimStack *sims) { |
794 | 0 | MVMuint32 n = sims ? sims->used : 0; |
795 | 0 | MVMuint32 i; |
796 | 0 | for (i = 0; i < n; i++) { |
797 | 0 | MVMSpeshSimStackFrame *simf = &(sims->frames[i]); |
798 | 0 | MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss, |
799 | 0 | (MVMCollectable*)(simf->sf), "staticframe"); |
800 | 0 | MVM_profile_heap_add_collectable_rel_const_cstr(tc, ss, |
801 | 0 | (MVMCollectable*)(simf->last_invoke_sf), "last invoked staticframe"); |
802 | 0 | } |
803 | 0 | } |
804 | | |
805 | 23 | void MVM_spesh_sim_stack_destroy(MVMThreadContext *tc, MVMSpeshSimStack *sims) { |
806 | 23 | if (sims) { |
807 | 2 | MVM_free(sims->frames); |
808 | 2 | MVM_free(sims); |
809 | 2 | } |
810 | 23 | } |