Coverage Report

Created: 2017-04-15 07:07

/home/travis/build/MoarVM/MoarVM/src/spesh/dump.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
3
/* Auto-growing buffer. */
4
typedef struct {
5
    char   *buffer;
6
    size_t  alloc;
7
    size_t  pos;
8
} DumpStr;
9
0
static void append(DumpStr *ds, char *to_add) {
10
0
    size_t len = strlen(to_add);
11
0
    if (ds->pos + len >= ds->alloc) {
12
0
        ds->alloc *= 4;
13
0
        if (ds->pos + len >= ds->alloc)
14
0
            ds->alloc += len;
15
0
        ds->buffer = MVM_realloc(ds->buffer, ds->alloc);
16
0
    }
17
0
    memcpy(ds->buffer + ds->pos, to_add, len);
18
0
    ds->pos += len;
19
0
}
20
21
0
static size_t tell_ds(DumpStr *ds) {
22
0
    return ds->pos;
23
0
}
24
25
0
static void rewind_ds(DumpStr *ds, size_t target) {
26
0
    if (ds->pos > target) {
27
0
        ds->pos = target;
28
0
        ds->buffer[ds->pos + 1] = '\0';
29
0
    }
30
0
}
31
32
/* Formats a string and then appends it. */
33
MVM_FORMAT(printf, 2, 3)
34
0
static void appendf(DumpStr *ds, const char *fmt, ...) {
35
0
    char *c_message = MVM_malloc(1024);
36
0
    va_list args;
37
0
    va_start(args, fmt);
38
0
    c_message[vsnprintf(c_message, 1023, fmt, args)] = 0;
39
0
    append(ds, c_message);
40
0
    MVM_free(c_message);
41
0
    va_end(args);
42
0
}
43
44
/* Turns a MoarVM string into a C string and appends it. */
45
0
static void append_str(MVMThreadContext *tc, DumpStr *ds, MVMString *s) {
46
0
    char *cs = MVM_string_utf8_encode_C_string(tc, s);
47
0
    append(ds, cs);
48
0
    MVM_free(cs);
49
0
}
50
51
/* Appends a null at the end. */
52
0
static void append_null(DumpStr *ds) {
53
0
    append(ds, " "); /* Delegate realloc if we're really unlucky. */
54
0
    ds->buffer[ds->pos - 1] = '\0';
55
0
}
56
57
/* Dumps a basic block. */
58
0
static void dump_bb(MVMThreadContext *tc, DumpStr *ds, MVMSpeshGraph *g, MVMSpeshBB *bb) {
59
0
    MVMSpeshIns *cur_ins;
60
0
    MVMint64     i;
61
0
62
0
    /* Heading. */
63
0
    appendf(ds, "  BB %d (%p):\n", bb->idx, bb);
64
0
65
0
    if (bb->inlined) {
66
0
        append(ds, "    Inlined\n");
67
0
    }
68
0
69
0
    {
70
0
        /* Also, we have a line number */
71
0
        MVMBytecodeAnnotation *bbba = MVM_bytecode_resolve_annotation(tc, &g->sf->body, bb->initial_pc);
72
0
        MVMuint32 line_number;
73
0
        if (bbba) {
74
0
            line_number = bbba->line_number;
75
0
            MVM_free(bbba);
76
0
        } else {
77
0
            line_number = -1;
78
0
        }
79
0
        appendf(ds, "    line: %d (pc %d)\n", line_number, bb->initial_pc);
80
0
    }
81
0
82
0
    /* Instructions. */
83
0
    append(ds, "    Instructions:\n");
84
0
    cur_ins = bb->first_ins;
85
0
    while (cur_ins) {
86
0
        MVMSpeshAnn *ann = cur_ins->annotations;
87
0
        MVMuint32 line_number;
88
0
89
0
        while (ann) {
90
0
            /* These four annotations carry a deopt index that we can find a
91
0
             * corresponding line number for */
92
0
            if (ann->type == MVM_SPESH_ANN_DEOPT_ONE_INS
93
0
                || ann->type == MVM_SPESH_ANN_DEOPT_ALL_INS
94
0
                || ann->type == MVM_SPESH_ANN_DEOPT_INLINE
95
0
                || ann->type == MVM_SPESH_ANN_DEOPT_OSR) {
96
0
                MVMBytecodeAnnotation *ba = MVM_bytecode_resolve_annotation(tc, &g->sf->body, g->deopt_addrs[2 * ann->data.deopt_idx]);
97
0
                if (ba) {
98
0
                    line_number = ba->line_number;
99
0
                    MVM_free(ba);
100
0
                } else {
101
0
                    line_number = -1;
102
0
                }
103
0
            }
104
0
            switch (ann->type) {
105
0
                case MVM_SPESH_ANN_FH_START:
106
0
                    appendf(ds, "      [Annotation: FH Start (%d)]\n",
107
0
                        ann->data.frame_handler_index);
108
0
                    break;
109
0
                case MVM_SPESH_ANN_FH_END:
110
0
                    appendf(ds, "      [Annotation: FH End (%d)]\n",
111
0
                        ann->data.frame_handler_index);
112
0
                    break;
113
0
                case MVM_SPESH_ANN_FH_GOTO:
114
0
                    appendf(ds, "      [Annotation: FH Goto (%d)]\n",
115
0
                        ann->data.frame_handler_index);
116
0
                    break;
117
0
                case MVM_SPESH_ANN_DEOPT_ONE_INS:
118
0
                    appendf(ds, "      [Annotation: INS Deopt One (idx %d -> pc %d; line %d)]\n",
119
0
                        ann->data.deopt_idx, g->deopt_addrs[2 * ann->data.deopt_idx], line_number);
120
0
                    break;
121
0
                case MVM_SPESH_ANN_DEOPT_ALL_INS:
122
0
                    appendf(ds, "      [Annotation: INS Deopt All (idx %d -> pc %d; line %d)]\n",
123
0
                        ann->data.deopt_idx, g->deopt_addrs[2 * ann->data.deopt_idx], line_number);
124
0
                    break;
125
0
                case MVM_SPESH_ANN_INLINE_START:
126
0
                    appendf(ds, "      [Annotation: Inline Start (%d)]\n",
127
0
                        ann->data.inline_idx);
128
0
                    break;
129
0
                case MVM_SPESH_ANN_INLINE_END:
130
0
                    appendf(ds, "      [Annotation: Inline End (%d)]\n",
131
0
                        ann->data.inline_idx);
132
0
                    break;
133
0
                case MVM_SPESH_ANN_DEOPT_INLINE:
134
0
                    appendf(ds, "      [Annotation: INS Deopt Inline (idx %d -> pc %d; line %d)]\n",
135
0
                        ann->data.deopt_idx, g->deopt_addrs[2 * ann->data.deopt_idx], line_number);
136
0
                    break;
137
0
                case MVM_SPESH_ANN_DEOPT_OSR:
138
0
                    appendf(ds, "      [Annotation: INS Deopt OSR (idx %d -> pc %d); line %d]\n",
139
0
                        ann->data.deopt_idx, g->deopt_addrs[2 * ann->data.deopt_idx], line_number);
140
0
                    break;
141
0
                default:
142
0
                    appendf(ds, "      [Annotation: %d (unknown)]\n", ann->type);
143
0
            }
144
0
            ann = ann->next;
145
0
        }
146
0
147
0
        appendf(ds, "      %-15s ", cur_ins->info->name);
148
0
        if (cur_ins->info->opcode == MVM_SSA_PHI) {
149
0
            for (i = 0; i < cur_ins->info->num_operands; i++) {
150
0
                MVMint16 orig = cur_ins->operands[i].reg.orig;
151
0
                MVMint16 regi = cur_ins->operands[i].reg.i;
152
0
                if (i)
153
0
                    append(ds, ", ");
154
0
                if (orig < 10) append(ds, " ");
155
0
                if (regi < 10) append(ds, " ");
156
0
                appendf(ds, "r%d(%d)", orig, regi);
157
0
            }
158
0
        }
159
0
        else {
160
0
            for (i = 0; i < cur_ins->info->num_operands; i++) {
161
0
                if (i)
162
0
                    append(ds, ", ");
163
0
                switch (cur_ins->info->operands[i] & MVM_operand_rw_mask) {
164
0
                    case MVM_operand_read_reg:
165
0
                    case MVM_operand_write_reg: {
166
0
                        MVMint16 orig = cur_ins->operands[i].reg.orig;
167
0
                        MVMint16 regi = cur_ins->operands[i].reg.i;
168
0
                        if (orig < 10) append(ds, " ");
169
0
                        if (regi < 10) append(ds, " ");
170
0
                        appendf(ds, "r%d(%d)", orig, regi);
171
0
                        break;
172
0
                    }
173
0
                    case MVM_operand_read_lex:
174
0
                    case MVM_operand_write_lex: {
175
0
                        MVMStaticFrameBody *cursor = &g->sf->body;
176
0
                        MVMuint32 ascension;
177
0
                        appendf(ds, "lex(idx=%d,outers=%d", cur_ins->operands[i].lex.idx,
178
0
                            cur_ins->operands[i].lex.outers);
179
0
                        for (ascension = 0;
180
0
                                ascension < cur_ins->operands[i].lex.outers;
181
0
                                ascension++, cursor = &cursor->outer->body) { };
182
0
                        if (cursor->fully_deserialized) {
183
0
                            if (cur_ins->operands[i].lex.idx < cursor->num_lexicals) {
184
0
                                char *cstr = MVM_string_utf8_encode_C_string(tc, cursor->lexical_names_list[cur_ins->operands[i].lex.idx]->key);
185
0
                                appendf(ds, ",%s)", cstr);
186
0
                                MVM_free(cstr);
187
0
                            } else {
188
0
                                append(ds, ",<out of bounds>)");
189
0
                            }
190
0
                        } else {
191
0
                            append(ds, ",<pending deserialization>)");
192
0
                        }
193
0
                        break;
194
0
                    }
195
0
                    case MVM_operand_literal: {
196
0
                        MVMuint32 type = cur_ins->info->operands[i] & MVM_operand_type_mask;
197
0
                        switch (type) {
198
0
                        case MVM_operand_ins: {
199
0
                            MVMint32 bb_idx = cur_ins->operands[i].ins_bb->idx;
200
0
                            if (bb_idx < 100) append(ds, " ");
201
0
                            if (bb_idx < 10)  append(ds, " ");
202
0
                            appendf(ds, "BB(%d)", bb_idx);
203
0
                            break;
204
0
                        }
205
0
                        case MVM_operand_int8:
206
0
                            appendf(ds, "liti8(%"PRId8")", cur_ins->operands[i].lit_i8);
207
0
                            break;
208
0
                        case MVM_operand_int16:
209
0
                            appendf(ds, "liti16(%"PRId16")", cur_ins->operands[i].lit_i16);
210
0
                            break;
211
0
                        case MVM_operand_int32:
212
0
                            appendf(ds, "liti32(%"PRId32")", cur_ins->operands[i].lit_i32);
213
0
                            break;
214
0
                        case MVM_operand_int64:
215
0
                            appendf(ds, "liti64(%"PRId64")", cur_ins->operands[i].lit_i64);
216
0
                            break;
217
0
                        case MVM_operand_num32:
218
0
                            appendf(ds, "litn32(%f)", cur_ins->operands[i].lit_n32);
219
0
                            break;
220
0
                        case MVM_operand_num64:
221
0
                            appendf(ds, "litn64(%g)", cur_ins->operands[i].lit_n64);
222
0
                            break;
223
0
                        case MVM_operand_str: {
224
0
                            char *cstr = MVM_string_utf8_encode_C_string(tc,
225
0
                                MVM_cu_string(tc, g->sf->body.cu, cur_ins->operands[i].lit_str_idx));
226
0
                            appendf(ds, "lits(%s)", cstr);
227
0
                            MVM_free(cstr);
228
0
                            break;
229
0
                        }
230
0
                        case MVM_operand_callsite: {
231
0
                            MVMCallsite *callsite = g->sf->body.cu->body.callsites[cur_ins->operands[i].callsite_idx];
232
0
                            appendf(ds, "callsite(%p, %d arg, %d pos, %s, %s)",
233
0
                                    callsite,
234
0
                                    callsite->arg_count, callsite->num_pos,
235
0
                                    callsite->has_flattening ? "flattening" : "nonflattening",
236
0
                                    callsite->is_interned ? "interned" : "noninterned");
237
0
                            break;
238
0
239
0
                        }
240
0
                        case MVM_operand_spesh_slot:
241
0
                            appendf(ds, "sslot(%"PRId16")", cur_ins->operands[i].lit_i16);
242
0
                            break;
243
0
                        case MVM_operand_coderef: {
244
0
                            MVMCodeBody *body = &((MVMCode*)g->sf->body.cu->body.coderefs[cur_ins->operands[i].coderef_idx])->body;
245
0
                            MVMBytecodeAnnotation *anno = MVM_bytecode_resolve_annotation(tc, &body->sf->body, 0);
246
0
247
0
                            append(ds, "coderef(");
248
0
249
0
                            if (anno) {
250
0
                                char *filestr = MVM_string_utf8_encode_C_string(tc,
251
0
                                    MVM_cu_string(tc, g->sf->body.cu, anno->filename_string_heap_index));
252
0
                                appendf(ds, "%s:%d%s)", filestr, anno->line_number, body->outer ? " (closure)" : "");
253
0
                                MVM_free(filestr);
254
0
                            } else {
255
0
                                append(ds, "??\?)");
256
0
                            }
257
0
258
0
                            MVM_free(anno);
259
0
                            break;
260
0
                        }
261
0
                        default:
262
0
                            append(ds, "<nyi(lit)>");
263
0
                        }
264
0
                        break;
265
0
                    }
266
0
                    default:
267
0
                        append(ds, "<nyi>");
268
0
                }
269
0
            }
270
0
            if (cur_ins->info->opcode == MVM_OP_wval || cur_ins->info->opcode == MVM_OP_wval_wide) {
271
0
                /* We can try to find out what the debug_name of this thing is. */
272
0
                MVMint16 dep = cur_ins->operands[1].lit_i16;
273
0
                MVMint64 idx;
274
0
                MVMCollectable *result = NULL;
275
0
                MVMSerializationContext *sc;
276
0
                char *debug_name = NULL;
277
0
                const char *repr_name = NULL;
278
0
                if (cur_ins->info->opcode == MVM_OP_wval) {
279
0
                    idx = cur_ins->operands[2].lit_i16;
280
0
                } else {
281
0
                    idx = cur_ins->operands[2].lit_i64;
282
0
                }
283
0
                sc = MVM_sc_get_sc(tc, g->sf->body.cu, dep);
284
0
                if (sc)
285
0
                    result = (MVMCollectable *)MVM_sc_try_get_object(tc, sc, idx);
286
0
                if (result) {
287
0
                    if (result->flags & MVM_CF_STABLE) {
288
0
                        debug_name = ((MVMSTable *)result)->debug_name;
289
0
                        repr_name  = ((MVMSTable *)result)->REPR->name;
290
0
                    } else {
291
0
                        debug_name = STABLE(result)->debug_name;
292
0
                        repr_name  = REPR(result)->name;
293
0
                    }
294
0
                    if (debug_name) {
295
0
                        appendf(ds, " (%s: %s)", repr_name, debug_name);
296
0
                    } else {
297
0
                        appendf(ds, " (%s: ?)", repr_name);
298
0
                    }
299
0
                } else {
300
0
                    appendf(ds, " (not deserialized)");
301
0
                }
302
0
            }
303
0
        }
304
0
        append(ds, "\n");
305
0
        cur_ins = cur_ins->next;
306
0
    }
307
0
308
0
    /* Predecessors and successors. */
309
0
    append(ds, "    Successors: ");
310
0
    for (i = 0; i < bb->num_succ; i++)
311
0
        appendf(ds, (i == 0 ? "%d" : ", %d"), bb->succ[i]->idx);
312
0
    append(ds, "\n    Predeccessors: ");
313
0
    for (i = 0; i < bb->num_pred; i++)
314
0
        appendf(ds, (i == 0 ? "%d" : ", %d"), bb->pred[i]->idx);
315
0
    append(ds, "\n    Dominance children: ");
316
0
    for (i = 0; i < bb->num_children; i++)
317
0
        appendf(ds, (i == 0 ? "%d" : ", %d"), bb->children[i]->idx);
318
0
    append(ds, "\n\n");
319
0
}
320
321
/* Dumps the facts table. */
322
0
static void dump_facts(MVMThreadContext *tc, DumpStr *ds, MVMSpeshGraph *g) {
323
0
    MVMuint16 i, j, num_locals, num_facts;
324
0
    num_locals = g->num_locals;
325
0
    for (i = 0; i < num_locals; i++) {
326
0
        num_facts = g->fact_counts[i];
327
0
        for (j = 0; j < num_facts; j++) {
328
0
            MVMint32 usages = g->facts[i][j].usages;
329
0
            MVMint32 flags  = g->facts[i][j].flags;
330
0
            if (i < 10) append(ds, " ");
331
0
            if (j < 10) append(ds, " ");
332
0
            appendf(ds, "    r%d(%d): usages=%d, flags=%-5d", i, j, usages, flags);
333
0
            if (flags & 1) {
334
0
                append(ds, " KnTyp");
335
0
            }
336
0
            if (flags & 2) {
337
0
                append(ds, " KnVal");
338
0
            }
339
0
            if (flags & 4) {
340
0
                append(ds, " Dcntd");
341
0
            }
342
0
            if (flags & 8) {
343
0
                append(ds, " Concr");
344
0
            }
345
0
            if (flags & 16) {
346
0
                append(ds, " TyObj");
347
0
            }
348
0
            if (flags & 32) {
349
0
                append(ds, " KnDcT");
350
0
            }
351
0
            if (flags & 64) {
352
0
                append(ds, " DCncr");
353
0
            }
354
0
            if (flags & 128) {
355
0
                append(ds, " DcTyO");
356
0
            }
357
0
            if (flags & 256) {
358
0
                append(ds, " LogGd");
359
0
            }
360
0
            if (flags & 512) {
361
0
                append(ds, " HashI");
362
0
            }
363
0
            if (flags & 1024) {
364
0
                append(ds, " ArrIt");
365
0
            }
366
0
            if (flags & 2048) {
367
0
                append(ds, " KBxSr");
368
0
            }
369
0
            if (flags & 4096) {
370
0
                append(ds, " MgWLG");
371
0
            }
372
0
            if (flags & 8192) {
373
0
                append(ds, " KRWCn");
374
0
            }
375
0
            if (g->facts[i][j].writer && g->facts[i][j].writer->info->opcode == MVM_SSA_PHI) {
376
0
                appendf(ds, " (merged from %d regs)", g->facts[i][j].writer->info->num_operands - 1);
377
0
            }
378
0
            append(ds, "\n");
379
0
        }
380
0
    }
381
0
}
382
383
/* Dumps a table of all logged values */
384
0
static void dump_log_values(MVMThreadContext *tc, DumpStr *ds, MVMSpeshGraph *g) {
385
0
    MVMint16 log_index;
386
0
    MVMint16 seen_table_size =  g->num_log_slots * MVM_SPESH_LOG_RUNS;
387
0
    size_t   ds_pos_before = tell_ds(ds);
388
0
    MVMint16 interesting = 0;
389
0
390
0
    MVMCollectable **seen_table = alloca(sizeof(MVMCollectable *) *seen_table_size);
391
0
    memset(seen_table, 0, sizeof(MVMCollectable *) * seen_table_size);
392
0
393
0
    append(ds, "Logged values:\n");
394
0
395
0
    for (log_index = 0; log_index < g->num_log_slots; log_index++) {
396
0
        MVMint16 run_index;
397
0
398
0
        appendf(ds, "    % 3d ", log_index);
399
0
400
0
        for (run_index = 0; run_index < MVM_SPESH_LOG_RUNS; run_index++) {
401
0
            MVMuint16       log_slot = log_index * MVM_SPESH_LOG_RUNS + run_index;
402
0
            MVMCollectable *log_obj  = g->log_slots[log_slot];
403
0
            MVMint16        log_obj_idx;
404
0
405
0
            if (log_obj) {
406
0
                for (log_obj_idx = 0; log_obj_idx < seen_table_size; log_obj_idx++) {
407
0
                    if (seen_table[log_obj_idx] == log_obj) {
408
0
                        break;
409
0
                    } else if (seen_table[log_obj_idx] == 0) {
410
0
                        seen_table[log_obj_idx] = log_obj;
411
0
                        break;
412
0
                    }
413
0
                }
414
0
415
0
                appendf(ds, "% 4d  ", log_obj_idx + 1);
416
0
                interesting = 1;
417
0
            } else {
418
0
                appendf(ds, "%4s  ", "_");
419
0
            }
420
0
421
0
        }
422
0
423
0
        append(ds, "\n");
424
0
    }
425
0
    append(ds, "\n");
426
0
427
0
    for (log_index = 0; log_index < seen_table_size && seen_table[log_index]; log_index++) {
428
0
        appendf(ds, "    %d: %p", log_index + 1, seen_table[log_index]);
429
0
        if (STABLE(seen_table[log_index])->REPR->ID == MVM_REPR_ID_P6int) {
430
0
            if (IS_CONCRETE(seen_table[log_index]))
431
0
                appendf(ds, " P6int(%"PRId64")", MVM_repr_get_int(tc, (MVMObject*)seen_table[log_index]));
432
0
            else
433
0
                append(ds, " P6int(type object)");
434
0
        } else {
435
0
            append(ds, " ");
436
0
            append(ds, (char *)STABLE(seen_table[log_index])->REPR->name);
437
0
            if (!IS_CONCRETE(seen_table[log_index]))
438
0
                append(ds, "(type object)");
439
0
            if (STABLE(seen_table[log_index])->debug_name) {
440
0
                appendf(ds, " debugname: %s", STABLE(seen_table[log_index])->debug_name);
441
0
            }
442
0
        }
443
0
        append(ds, "\n");
444
0
    }
445
0
446
0
    append(ds, "\n");
447
0
448
0
    if (!interesting) {
449
0
        rewind_ds(ds, ds_pos_before);
450
0
    }
451
0
}
452
453
0
static void dump_callsite(MVMThreadContext *tc, DumpStr *ds, MVMSpeshGraph *g) {
454
0
    MVMuint16 i;
455
0
    appendf(ds, "Callsite %p (%d args, %d pos)\n", g->cs, g->cs->arg_count, g->cs->num_pos);
456
0
    for (i = 0; i < (g->cs->arg_count - g->cs->num_pos) / 2; i++) {
457
0
        if (g->cs->arg_names[i]) {
458
0
            char * argname_utf8 = MVM_string_utf8_encode_C_string(tc, g->cs->arg_names[i]);
459
0
            appendf(ds, "  - %s\n", argname_utf8);
460
0
            MVM_free(argname_utf8);
461
0
        }
462
0
    }
463
0
    if (g->cs->num_pos)
464
0
        append(ds, "Positional flags: ");
465
0
    for (i = 0; i < g->cs->num_pos; i++) {
466
0
        MVMCallsiteEntry arg_flag = g->cs->arg_flags[i];
467
0
468
0
        if (i)
469
0
            append(ds, ", ");
470
0
471
0
        if (arg_flag == MVM_CALLSITE_ARG_OBJ) {
472
0
            append(ds, "obj");
473
0
        } else if (arg_flag == MVM_CALLSITE_ARG_INT) {
474
0
            append(ds, "int");
475
0
        } else if (arg_flag == MVM_CALLSITE_ARG_NUM) {
476
0
            append(ds, "num");
477
0
        } else if (arg_flag == MVM_CALLSITE_ARG_STR) {
478
0
            append(ds, "str");
479
0
        }
480
0
    }
481
0
    if (g->cs->num_pos)
482
0
        append(ds, "\n");
483
0
    append(ds, "\n");
484
0
}
485
486
0
static void dump_arg_guards(MVMThreadContext *tc, DumpStr *ds, MVMSpeshGraph *g) {
487
0
    MVMuint16 i;
488
0
    appendf(ds, "%d argument guards\n", g->num_arg_guards);
489
0
490
0
    for (i = 0; i < g->num_arg_guards; i++) {
491
0
        MVMSpeshGuard *guard = &g->arg_guards[i];
492
0
        switch (guard->kind) {
493
0
        case MVM_SPESH_GUARD_CONC:
494
0
            appendf(ds, "  concrete(%d)\n", guard->slot);
495
0
            break;
496
0
        case MVM_SPESH_GUARD_TYPE:
497
0
            appendf(ds, "  type(%d, %p)", guard->slot, guard->match);
498
0
            if (((MVMSTable*)(guard->match))->debug_name) {
499
0
                appendf(ds, " debugname: %s", ((MVMSTable*)(guard->match))->debug_name);
500
0
            }
501
0
            append(ds, "\n");
502
0
            break;
503
0
        case MVM_SPESH_GUARD_DC_CONC:
504
0
            appendf(ds, "  deconted_concrete(%d)\n", guard->slot);
505
0
            break;
506
0
        case MVM_SPESH_GUARD_DC_TYPE:
507
0
            appendf(ds, "  deconted_type(%d, %p)", guard->slot, guard->match);
508
0
            if (((MVMSTable*)(guard->match))->debug_name) {
509
0
                appendf(ds, " debugname: %s", ((MVMSTable*)(guard->match))->debug_name);
510
0
            }
511
0
            append(ds, "\n");
512
0
            break;
513
0
        case MVM_SPESH_GUARD_DC_CONC_RW:
514
0
            appendf(ds, "  deconted_concrete_rw(%d)\n", guard->slot);
515
0
            break;
516
0
        case MVM_SPESH_GUARD_DC_TYPE_RW:
517
0
            appendf(ds, "  deconted_type_rw(%d, %p)", guard->slot, guard->match);
518
0
            if (((MVMSTable*)(guard->match))->debug_name) {
519
0
                appendf(ds, " debugname: %s", ((MVMSTable*)(guard->match))->debug_name);
520
0
            }
521
0
            append(ds, "\n");
522
0
            break;
523
0
        }
524
0
    }
525
0
    append(ds, "\n");
526
0
}
527
528
0
static void dump_fileinfo(MVMThreadContext *tc, DumpStr *ds, MVMSpeshGraph *g) {
529
0
    MVMBytecodeAnnotation *ann = MVM_bytecode_resolve_annotation(tc, &g->sf->body, 0);
530
0
    MVMCompUnit            *cu = g->sf->body.cu;
531
0
    MVMint32           str_idx = ann ? ann->filename_string_heap_index : 0;
532
0
    MVMint32           line_nr = ann ? ann->line_number : 1;
533
0
    MVMString        *filename = cu->body.filename;
534
0
    char        *filename_utf8 = "<unknown>";
535
0
    if (ann && str_idx < cu->body.num_strings) {
536
0
        filename = MVM_cu_string(tc, cu, str_idx);
537
0
    }
538
0
    if (filename)
539
0
        filename_utf8 = MVM_string_utf8_encode_C_string(tc, filename);
540
0
    appendf(ds, "%s:%d", filename_utf8, line_nr);
541
0
    if (filename)
542
0
        MVM_free(filename_utf8);
543
0
    MVM_free(ann);
544
0
}
545
546
/* Dump a spesh graph into string form, for debugging purposes. */
547
0
char * MVM_spesh_dump(MVMThreadContext *tc, MVMSpeshGraph *g) {
548
0
    MVMSpeshBB *cur_bb;
549
0
550
0
    /* Allocate buffer. */
551
0
    DumpStr ds;
552
0
    ds.alloc  = 8192;
553
0
    ds.buffer = MVM_malloc(ds.alloc);
554
0
    ds.pos    = 0;
555
0
556
0
    /* Dump name and CUID. */
557
0
    append(&ds, "Spesh of '");
558
0
    append_str(tc, &ds, g->sf->body.name);
559
0
    append(&ds, "' (cuid: ");
560
0
    append_str(tc, &ds, g->sf->body.cuuid);
561
0
    append(&ds, ", file: ");
562
0
    dump_fileinfo(tc, &ds, g);
563
0
    append(&ds, ")\n");
564
0
    if (g->cs)
565
0
        dump_callsite(tc, &ds, g);
566
0
    if (g->num_arg_guards)
567
0
        dump_arg_guards(tc, &ds, g);
568
0
    if (!g->cs && !g->num_arg_guards)
569
0
        append(&ds, "\n");
570
0
571
0
    /* Go over all the basic blocks and dump them. */
572
0
    cur_bb = g->entry;
573
0
    while (cur_bb) {
574
0
        dump_bb(tc, &ds, g, cur_bb);
575
0
        cur_bb = cur_bb->linear_next;
576
0
    }
577
0
578
0
    /* Dump facts. */
579
0
    append(&ds, "\nFacts:\n");
580
0
    dump_facts(tc, &ds, g);
581
0
582
0
    if (g->num_spesh_slots || g->num_log_slots) {
583
0
        append(&ds, "\nStats:\n");
584
0
        appendf(&ds, "    %d spesh slots\n", g->num_spesh_slots);
585
0
        appendf(&ds, "    %d log slots\n", g->num_log_slots);
586
0
    }
587
0
588
0
    if (g->num_log_slots) {
589
0
        dump_log_values(tc, &ds, g);
590
0
    }
591
0
592
0
    append(&ds, "\n");
593
0
    append_null(&ds);
594
0
    return ds.buffer;
595
0
}