Coverage Report

Created: 2018-07-03 15:31

/home/travis/build/MoarVM/MoarVM/src/core/bytecodedump.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
3
0
#define line_length 1024
4
MVM_FORMAT(printf, 4, 5)
5
static void append_string(char **out, MVMuint32 *size,
6
0
        MVMuint32 *length, char *str, ...) {
7
0
    char string[line_length];
8
0
    MVMuint32 len;
9
0
    va_list args;
10
0
    va_start(args, str);
11
0
12
0
    vsnprintf(string, line_length, str, args);
13
0
    va_end(args);
14
0
15
0
    len = strlen(string);
16
0
    if (*length + len > *size) {
17
0
        while (*length + len > *size)
18
0
            *size = *size * 2;
19
0
        *out = MVM_realloc(*out, *size);
20
0
    }
21
0
22
0
    memcpy(*out + *length, string, len);
23
0
    *length = *length + len;
24
0
}
25
26
0
static const char * get_typename(MVMuint16 type) {
27
0
    switch(type) {
28
0
        case MVM_reg_int8 : return "int8";
29
0
        case MVM_reg_int16: return "int16";
30
0
        case MVM_reg_int32: return "int32";
31
0
        case MVM_reg_int64: return "int";
32
0
        case MVM_reg_num32: return "num32";
33
0
        case MVM_reg_num64: return "num";
34
0
        case MVM_reg_str  : return "str";
35
0
        case MVM_reg_obj  : return "obj";
36
0
        case MVM_reg_uint8 : return "uint8";
37
0
        case MVM_reg_uint16: return "uint16";
38
0
        case MVM_reg_uint32: return "uint32";
39
0
        case MVM_reg_uint64: return "uint";
40
0
        default           : fprintf(stderr, "unknown type %d\n", type);
41
0
                             return "UNKNOWN";
42
0
    }
43
0
}
44
45
0
#define a(...) append_string(&o,&s,&l, __VA_ARGS__)
46
/* Macros for getting things from the bytecode stream. */
47
/* GET_REG is defined differently here from interp.c */
48
#define GET_I8(pc, idx)     *((MVMint8 *)((pc) + (idx)))
49
#define GET_REG(pc, idx)    *((MVMuint16 *)((pc) + (idx)))
50
#define GET_I16(pc, idx)    *((MVMint16 *)((pc) + (idx)))
51
0
#define GET_UI16(pc, idx)   *((MVMuint16 *)((pc) + (idx)))
52
#define GET_I32(pc, idx)    *((MVMint32 *)((pc) + (idx)))
53
0
#define GET_UI32(pc, idx)   *((MVMuint32 *)((pc) + (idx)))
54
#define GET_N32(pc, idx)    *((MVMnum32 *)((pc) + (idx)))
55
56
enum {
57
    MVM_val_branch_target = 1,
58
    MVM_val_op_boundary   = 2
59
};
60
61
0
static MVMStaticFrame * get_frame(MVMThreadContext *tc, MVMCompUnit *cu, int idx) {
62
0
    return ((MVMCode *)cu->body.coderefs[idx])->body.sf;
63
0
}
64
65
0
static void bytecode_dump_frame_internal(MVMThreadContext *tc, MVMStaticFrame *frame, MVMSpeshCandidate *maybe_candidate, MVMuint8 *frame_cur_op, char ***frame_lexicals, char **oo, MVMuint32 *os, MVMuint32 *ol) {
66
0
    /* since "references" are not a thing in C, keep a local copy of these
67
0
     * and update the passed-in pointers at the end of the function */
68
0
    char *o = *oo;
69
0
    MVMuint32 s = *os;
70
0
    MVMuint32 l = *ol;
71
0
72
0
    MVMuint32 i, j, k;
73
0
74
0
    /* mostly stolen from validation.c */
75
0
    MVMStaticFrame *static_frame = frame;
76
0
    MVMuint32 bytecode_size = maybe_candidate ? maybe_candidate->bytecode_size : static_frame->body.bytecode_size;
77
0
    MVMuint8 *bytecode_start = maybe_candidate ? maybe_candidate->bytecode : static_frame->body.bytecode;
78
0
    MVMuint8 *bytecode_end = bytecode_start + bytecode_size;
79
0
    /* current position in the bytestream */
80
0
    MVMuint8 *cur_op = bytecode_start;
81
0
    /* positions in the bytestream that are starts of ops and goto targets */
82
0
    MVMuint8 *labels = MVM_calloc(1, bytecode_size);
83
0
    MVMuint32 *jumps = MVM_calloc(1, sizeof(MVMuint32) * bytecode_size);
84
0
    char **lines = MVM_malloc(sizeof(char *) * bytecode_size);
85
0
    MVMuint32 *linelocs = MVM_malloc(sizeof(MVMuint32) * bytecode_size);
86
0
    MVMuint32 lineno = 0;
87
0
    MVMuint32 lineloc;
88
0
    MVMuint16 op_num;
89
0
    const MVMOpInfo *op_info;
90
0
    MVMuint32 operand_size = 0;
91
0
    unsigned char op_rw;
92
0
    unsigned char op_type;
93
0
    unsigned char op_flags;
94
0
    MVMOpInfo tmp_extop_info;
95
0
    /* stash the outer output buffer */
96
0
    MVMuint32 sP = s;
97
0
    MVMuint32 lP = l;
98
0
    char *oP = o;
99
0
    char *tmpstr;
100
0
    char mark_this_line = 0;
101
0
    MVMCompUnit *cu = static_frame->body.cu;
102
0
103
0
    while (cur_op < bytecode_end - 1) {
104
0
105
0
        /* allocate a line buffer */
106
0
        s = 200;
107
0
        l = 0;
108
0
        o = MVM_calloc(s, sizeof(char));
109
0
110
0
        lineloc = cur_op - bytecode_start;
111
0
        /* mark that this line starts at this point in the bytestream */
112
0
        linelocs[lineno] = lineloc;
113
0
        /* mark that this point in the bytestream is an op boundary */
114
0
        labels[lineloc] |= MVM_val_op_boundary;
115
0
116
0
117
0
        mark_this_line = 0;
118
0
        if (frame_cur_op) {
119
0
            if (frame_cur_op == cur_op || frame_cur_op == cur_op + 2) {
120
0
                mark_this_line = 1;
121
0
            }
122
0
        }
123
0
124
0
        if (mark_this_line) {
125
0
            a("-> ");
126
0
        } else {
127
0
            a("   ");
128
0
        }
129
0
130
0
        op_num = *((MVMint16 *)cur_op);
131
0
        cur_op += 2;
132
0
        if (op_num < MVM_OP_EXT_BASE) {
133
0
            op_info = MVM_op_get_op(op_num);
134
0
            a("%-18s ", op_info->name);
135
0
        }
136
0
        else {
137
0
            MVMint16 ext_op_num = op_num - MVM_OP_EXT_BASE;
138
0
            if (ext_op_num < cu->body.num_extops) {
139
0
                MVMExtOpRecord r = cu->body.extops[ext_op_num];
140
0
                MVMuint8 j;
141
0
                memset(&tmp_extop_info, 0, sizeof(MVMOpInfo));
142
0
                tmp_extop_info.name = MVM_string_utf8_encode_C_string(tc, r.name);
143
0
                memcpy(tmp_extop_info.operands, r.operand_descriptor, 8);
144
0
                for (j = 0; j < 8; j++)
145
0
                    if (tmp_extop_info.operands[j])
146
0
                        tmp_extop_info.num_operands++;
147
0
                    else
148
0
                        break;
149
0
                op_info = &tmp_extop_info;
150
0
                a("%-12s ", tmp_extop_info.name);
151
0
                MVM_free((void *)tmp_extop_info.name);
152
0
                tmp_extop_info.name = NULL;
153
0
            }
154
0
            else {
155
0
                MVM_exception_throw_adhoc(tc, "Extension op %d out of range", (int)op_num);
156
0
            }
157
0
        }
158
0
159
0
        for (i = 0; i < op_info->num_operands; i++) {
160
0
            if (i) a(", ");
161
0
            op_flags = op_info->operands[i];
162
0
            op_rw   = op_flags & MVM_operand_rw_mask;
163
0
            op_type = op_flags & MVM_operand_type_mask;
164
0
165
0
            if (op_rw == MVM_operand_literal) {
166
0
                switch (op_type) {
167
0
                    case MVM_operand_int8:
168
0
                        operand_size = 1;
169
0
                        a("%"PRId8, GET_I8(cur_op, 0));
170
0
                        break;
171
0
                    case MVM_operand_int16:
172
0
                        operand_size = 2;
173
0
                        a("%"PRId16, GET_I16(cur_op, 0));
174
0
                        break;
175
0
                    case MVM_operand_int32:
176
0
                        operand_size = 4;
177
0
                        a("%"PRId32, GET_I32(cur_op, 0));
178
0
                        break;
179
0
                    case MVM_operand_int64:
180
0
                        operand_size = 8;
181
0
                        a("%"PRId64, MVM_BC_get_I64(cur_op, 0));
182
0
                        break;
183
0
                    case MVM_operand_uint8:
184
0
                        operand_size = 1;
185
0
                        a("%"PRIu8, GET_I8(cur_op, 0));
186
0
                        break;
187
0
                    case MVM_operand_uint16:
188
0
                        operand_size = 2;
189
0
                        a("%"PRIu16, GET_I16(cur_op, 0));
190
0
                        break;
191
0
                    case MVM_operand_uint32:
192
0
                        operand_size = 4;
193
0
                        a("%"PRIu32, GET_I32(cur_op, 0));
194
0
                        break;
195
0
                    case MVM_operand_uint64:
196
0
                        operand_size = 8;
197
0
                        a("%"PRIu64, MVM_BC_get_I64(cur_op, 0));
198
0
                        break;
199
0
                    case MVM_operand_num32:
200
0
                        operand_size = 4;
201
0
                        a("%f", GET_N32(cur_op, 0));
202
0
                        break;
203
0
                    case MVM_operand_num64:
204
0
                        operand_size = 8;
205
0
                        a("%f", MVM_BC_get_N64(cur_op, 0));
206
0
                        break;
207
0
                    case MVM_operand_callsite:
208
0
                        operand_size = 2;
209
0
                        a("Callsite_%"PRIu16, GET_UI16(cur_op, 0));
210
0
                        break;
211
0
                    case MVM_operand_coderef:
212
0
                        operand_size = 2;
213
0
                        a("Frame_%"PRIu16, GET_UI16(cur_op, 0));
214
0
                        break;
215
0
                    case MVM_operand_str:
216
0
                        operand_size = 4;
217
0
                        tmpstr = MVM_string_utf8_encode_C_string(
218
0
                            tc, MVM_cu_string(tc, cu, GET_UI32(cur_op, 0)));
219
0
                        /* XXX C-string-literal escape the \ and '
220
0
                            and line breaks and non-ascii someday */
221
0
                        a("'%s'", tmpstr);
222
0
                        MVM_free(tmpstr);
223
0
                        break;
224
0
                    case MVM_operand_ins:
225
0
                        operand_size = 4;
226
0
                        /* luckily all the ins operands are at the end
227
0
                        of op operands, so I can wait to resolve the label
228
0
                        to the end. */
229
0
                        labels[GET_UI32(cur_op, 0)] |= MVM_val_branch_target;
230
0
                        jumps[lineno] = GET_UI32(cur_op, 0);
231
0
                        break;
232
0
                    case MVM_operand_obj:
233
0
                        /* not sure what a literal object is */
234
0
                        operand_size = 4;
235
0
                        break;
236
0
                    case MVM_operand_spesh_slot:
237
0
                        operand_size = 2;
238
0
                        a("sslot(%d)", GET_UI16(cur_op, 0));
239
0
                        break;
240
0
                    default:
241
0
                        fprintf(stderr, "what is an operand of type %d??\n", op_type);
242
0
                        abort(); /* never reached, silence compiler warnings */
243
0
                }
244
0
            }
245
0
            else if (op_rw == MVM_operand_read_reg || op_rw == MVM_operand_write_reg) {
246
0
                /* register operand */
247
0
                MVMuint8 frame_has_inlines = maybe_candidate && maybe_candidate->num_inlines ? 1 : 0;
248
0
                MVMuint16 *local_types = frame_has_inlines ? maybe_candidate->local_types : frame->body.local_types;
249
0
                MVMuint16 num_locals   = frame_has_inlines ? maybe_candidate->num_locals : frame->body.num_locals;
250
0
                operand_size = 2;
251
0
                a("loc_%u_%s", GET_REG(cur_op, 0),
252
0
                    get_typename(local_types[GET_REG(cur_op, 0)]));
253
0
            }
254
0
            else if (op_rw == MVM_operand_read_lex || op_rw == MVM_operand_write_lex) {
255
0
                /* lexical operand */
256
0
                MVMuint16 idx, frames, m;
257
0
                MVMStaticFrame *applicable_frame = static_frame;
258
0
259
0
                operand_size = 4;
260
0
                idx = GET_UI16(cur_op, 0);
261
0
                frames = GET_UI16(cur_op, 2);
262
0
263
0
                m = frames;
264
0
                while (m > 0) {
265
0
                    applicable_frame = applicable_frame->body.outer;
266
0
                    m--;
267
0
                }
268
0
                /* inefficient, I know. should use a hash. */
269
0
                for (m = 0; m < cu->body.num_frames; m++) {
270
0
                    if (get_frame(tc, cu, m) == applicable_frame) {
271
0
                        char *lexname = frame_lexicals ? frame_lexicals[m][idx] : "lex??";
272
0
                        a("lex_Frame_%u_%s_%s", m, lexname,
273
0
                            get_typename(applicable_frame->body.lexical_types[idx]));
274
0
                    }
275
0
                }
276
0
            }
277
0
            cur_op += operand_size;
278
0
        }
279
0
280
0
        lines[lineno++] = o;
281
0
    }
282
0
    {
283
0
        MVMuint32 *linelabels = MVM_calloc(lineno, sizeof(MVMuint32));
284
0
        MVMuint32 byte_offset = 0;
285
0
        MVMuint32 line_number = 0;
286
0
        MVMuint32 label_number = 1;
287
0
        MVMuint32 *annotations = MVM_calloc(lineno, sizeof(MVMuint32));
288
0
289
0
        for (; byte_offset < bytecode_size; byte_offset++) {
290
0
            if (labels[byte_offset] & MVM_val_branch_target) {
291
0
                /* found a byte_offset where a label should be.
292
0
                 now crawl up through the lines to find which line starts there */
293
0
                while (linelocs[line_number] != byte_offset) line_number++;
294
0
                linelabels[line_number] = label_number++;
295
0
            }
296
0
        }
297
0
        o = oP;
298
0
        l = lP;
299
0
        s = sP;
300
0
301
0
        i = 0;
302
0
        /* resolve annotation line numbers */
303
0
        for (j = 0; j < frame->body.num_annotations; j++) {
304
0
            MVMuint32 ann_offset = GET_UI32(frame->body.annotations_data, j*12);
305
0
            for (; i < lineno; i++) {
306
0
                if (linelocs[i] == ann_offset) {
307
0
                    annotations[i] = j + 1;
308
0
                    break;
309
0
                }
310
0
            }
311
0
        }
312
0
313
0
        for (j = 0; j < lineno; j++) {
314
0
            if (annotations[j]) {
315
0
                MVMuint16 shi = GET_UI16(frame->body.annotations_data + 4, (annotations[j] - 1)*12);
316
0
                tmpstr = MVM_string_utf8_encode_C_string(
317
0
                    tc, MVM_cu_string(tc, cu, shi < cu->body.num_strings ? shi : 0));
318
0
                a("     annotation: %s:%u\n", tmpstr, GET_UI32(frame->body.annotations_data, (annotations[j] - 1)*12 + 8));
319
0
                MVM_free(tmpstr);
320
0
            }
321
0
            if (linelabels[j])
322
0
                a("     label_%u:\n", linelabels[j]);
323
0
            a("%05d   %s", j, lines[j]);
324
0
            MVM_free(lines[j]);
325
0
            if (jumps[j]) {
326
0
                /* horribly inefficient for large frames.  again, should use a hash */
327
0
                line_number = 0;
328
0
                while (linelocs[line_number] != jumps[j]) line_number++;
329
0
                a("label_%u(%05u)", linelabels[line_number], line_number);
330
0
            }
331
0
            a("\n");
332
0
        }
333
0
        MVM_free(lines);
334
0
        MVM_free(jumps);
335
0
        MVM_free(linelocs);
336
0
        MVM_free(linelabels);
337
0
        MVM_free(labels);
338
0
        MVM_free(annotations);
339
0
    }
340
0
341
0
    *oo = o;
342
0
    *os = s;
343
0
    *ol = l;
344
0
}
345
346
347
0
char * MVM_bytecode_dump(MVMThreadContext *tc, MVMCompUnit *cu) {
348
0
    MVMuint32 s = 1024;
349
0
    MVMuint32 l = 0;
350
0
    MVMuint32 i, j, k;
351
0
    char *o = MVM_calloc(s, sizeof(char));
352
0
    char ***frame_lexicals = MVM_malloc(sizeof(char **) * cu->body.num_frames);
353
0
    MVMString *name = MVM_string_utf8_decode(tc, tc->instance->VMString, "", 0);
354
0
355
0
    a("\nMoarVM dump of binary compilation unit:\n\n");
356
0
357
0
    for (k = 0; k < cu->body.num_scs; k++) {
358
0
        char *tmpstr = MVM_string_utf8_encode_C_string(
359
0
            tc, MVM_cu_string(tc, cu, cu->body.sc_handle_idxs[k]));
360
0
        a("  SC_%u : %s\n", k, tmpstr);
361
0
        MVM_free(tmpstr);
362
0
    }
363
0
364
0
    for (k = 0; k < cu->body.num_callsites; k++) {
365
0
        MVMCallsite *callsite  = cu->body.callsites[k];
366
0
        MVMuint16 arg_count    = callsite->arg_count;
367
0
        MVMuint16 nameds_count = 0;
368
0
369
0
        a("  Callsite_%u :\n", k);
370
0
        a("    num_pos: %d\n", callsite->num_pos);
371
0
        a("    arg_count: %u\n", arg_count);
372
0
        for (j = 0, i = 0; j < arg_count; j++) {
373
0
            MVMCallsiteEntry csitee = callsite->arg_flags[i++];
374
0
            a("    Arg %u :", i);
375
0
            if (csitee & MVM_CALLSITE_ARG_NAMED) {
376
0
                if (callsite->arg_names) {
377
0
                    char *arg_name = MVM_string_utf8_encode_C_string(tc,
378
0
                        callsite->arg_names[nameds_count++]);
379
0
                    a(" named(%s)", arg_name);
380
0
                    MVM_free(arg_name);
381
0
                }
382
0
                else {
383
0
                    a(" named");
384
0
                }
385
0
                j++;
386
0
            }
387
0
            else if (csitee & MVM_CALLSITE_ARG_FLAT_NAMED) {
388
0
                a(" flatnamed");
389
0
            }
390
0
            else if (csitee & MVM_CALLSITE_ARG_FLAT) {
391
0
                a(" flat");
392
0
            }
393
0
            else a(" positional");
394
0
            if (csitee & MVM_CALLSITE_ARG_OBJ) a(" obj");
395
0
            else if (csitee & MVM_CALLSITE_ARG_INT) a(" int");
396
0
            else if (csitee & MVM_CALLSITE_ARG_NUM) a(" num");
397
0
            else if (csitee & MVM_CALLSITE_ARG_STR) a(" str");
398
0
            if (csitee & MVM_CALLSITE_ARG_FLAT) a(" flat");
399
0
            a("\n");
400
0
        }
401
0
    }
402
0
    for (k = 0; k < cu->body.num_frames; k++)
403
0
        MVM_bytecode_finish_frame(tc, cu, get_frame(tc, cu, k), 1);
404
0
405
0
    for (k = 0; k < cu->body.num_frames; k++) {
406
0
        MVMStaticFrame *frame = get_frame(tc, cu, k);
407
0
        MVMLexicalRegistry *current, *tmp;
408
0
        unsigned bucket_tmp;
409
0
        char **lexicals;
410
0
411
0
        if (!frame->body.fully_deserialized) {
412
0
            MVM_bytecode_finish_frame(tc, cu, frame, 1);
413
0
        }
414
0
415
0
        lexicals = (char **)MVM_malloc(sizeof(char *) * frame->body.num_lexicals);
416
0
        frame_lexicals[k] = lexicals;
417
0
418
0
        HASH_ITER(hash_handle, frame->body.lexical_names, current, tmp, bucket_tmp) {
419
0
            name->body.storage.blob_32 = (MVMint32 *)current->hash_handle.key;
420
0
            name->body.num_graphs      = (MVMuint32)current->hash_handle.keylen / sizeof(MVMGrapheme32);
421
0
            lexicals[current->value]   = MVM_string_utf8_encode_C_string(tc, name);
422
0
        }
423
0
    }
424
0
    for (k = 0; k < cu->body.num_frames; k++) {
425
0
        MVMStaticFrame *frame = get_frame(tc, cu, k);
426
0
        char *cuuid;
427
0
        char *fname;
428
0
        cuuid = MVM_string_utf8_encode_C_string(tc, frame->body.cuuid);
429
0
        fname = MVM_string_utf8_encode_C_string(tc, frame->body.name);
430
0
        a("  Frame_%u :\n", k);
431
0
        a("    cuuid : %s\n", cuuid);
432
0
        MVM_free(cuuid);
433
0
        a("    name : %s\n", fname);
434
0
        MVM_free(fname);
435
0
        for (j = 0; j < cu->body.num_frames; j++) {
436
0
            if (get_frame(tc, cu, j) == frame->body.outer)
437
0
                a("    outer : Frame_%u\n", j);
438
0
        }
439
0
440
0
        for (j = 0; j < frame->body.num_locals; j++) {
441
0
            if (!j)
442
0
                a("    Locals :\n");
443
0
            a("  %6u: loc_%u_%s\n", j, j, get_typename(frame->body.local_types[j]));
444
0
        }
445
0
446
0
        for (j = 0; j < frame->body.num_lexicals; j++) {
447
0
            if (!j)
448
0
                a("    Lexicals :\n");
449
0
            a("  %6u: lex_Frame_%u_%s_%s\n", j, k, frame_lexicals[k][j], get_typename(frame->body.lexical_types[j]));
450
0
        }
451
0
        a("    Instructions :\n");
452
0
        {
453
0
            bytecode_dump_frame_internal(tc, frame, NULL, NULL, frame_lexicals, &o, &s, &l);
454
0
        }
455
0
    }
456
0
457
0
    o[l] = '\0';
458
0
459
0
    for (k = 0; k < cu->body.num_frames; k++) {
460
0
        for (j = 0; j < get_frame(tc, cu, k)->body.num_lexicals; j++) {
461
0
            MVM_free(frame_lexicals[k][j]);
462
0
        }
463
0
        MVM_free(frame_lexicals[k]);
464
0
    }
465
0
    MVM_free(frame_lexicals);
466
0
    return o;
467
0
}
468
469
#ifdef DEBUG_HELPERS
470
0
void MVM_dump_bytecode_of(MVMThreadContext *tc, MVMFrame *frame, MVMSpeshCandidate *maybe_candidate) {
471
0
    MVMuint32 s = 1024;
472
0
    MVMuint32 l = 0;
473
0
    char *o = MVM_calloc(s, sizeof(char));
474
0
    MVMuint8 *addr;
475
0
476
0
    if (!frame) {
477
0
        frame = tc->cur_frame;
478
0
        addr = *tc->interp_cur_op;
479
0
    } else {
480
0
        addr = frame->return_address;
481
0
        if (!addr) {
482
0
            addr = *tc->interp_cur_op;
483
0
        }
484
0
    }
485
0
486
0
    bytecode_dump_frame_internal(tc, frame->static_info, maybe_candidate, addr, NULL, &o, &s, &l);
487
0
488
0
    o[l] = 0;
489
0
490
0
    fprintf(stderr, "%s", o);
491
0
}
492
493
0
void MVM_dump_bytecode_staticframe(MVMThreadContext *tc, MVMStaticFrame *frame) {
494
0
    MVMuint32 s = 1024;
495
0
    MVMuint32 l = 0;
496
0
    char *o = MVM_calloc(s, sizeof(char));
497
0
498
0
    bytecode_dump_frame_internal(tc, frame, NULL, NULL, NULL, &o, &s, &l);
499
0
500
0
    o[l] = 0;
501
0
502
0
    fprintf(stderr, "%s", o);
503
0
}
504
505
0
void MVM_dump_bytecode(MVMThreadContext *tc) {
506
0
    MVMStaticFrame *sf = tc->cur_frame->static_info;
507
0
    MVMuint8 *effective_bytecode = MVM_frame_effective_bytecode(tc->cur_frame);
508
0
    if (effective_bytecode == sf->body.bytecode) {
509
0
        MVM_dump_bytecode_of(tc, tc->cur_frame, NULL);
510
0
    } else {
511
0
        MVM_dump_bytecode_of(tc, tc->cur_frame, tc->cur_frame->spesh_cand);
512
0
        /*MVMint32 spesh_cand_idx;*/
513
0
        /*MVMuint8 found = 0;*/
514
0
        /*for (spesh_cand_idx = 0; spesh_cand_idx < sf->body.num_spesh_candidates; spesh_cand_idx++) {*/
515
0
            /*MVMSpeshCandidate *cand = sf->body.spesh_candidates[spesh_cand_idx];*/
516
0
            /*if (cand->bytecode == effective_bytecode) {*/
517
0
                /*MVM_dump_bytecode_of(tc, tc->cur_frame, cand);*/
518
0
                /*found = 1;*/
519
0
            /*}*/
520
0
        /*}*/
521
0
        /*if (!found) {*/
522
0
            /* It's likely the MAGIC_BYTECODE from the jit?
523
0
             * in that case we just grab tc->cur_frame->spesh_cand apparently */
524
0
        /*}*/
525
0
    }
526
0
}
527
528
0
void MVM_dump_bytecode_stackframe(MVMThreadContext *tc, MVMint32 depth) {
529
0
    MVMStaticFrame *sf;
530
0
    MVMuint8 *effective_bytecode;
531
0
    MVMFrame *frame = tc->cur_frame;
532
0
    for (;depth > 0; depth--) {
533
0
        frame = frame->caller;
534
0
    }
535
0
    sf = frame->static_info;
536
0
    effective_bytecode = MVM_frame_effective_bytecode(frame);
537
0
    if (effective_bytecode == sf->body.bytecode) {
538
0
        MVM_dump_bytecode_of(tc, frame, NULL);
539
0
    } else {
540
0
        MVMint32 spesh_cand_idx;
541
0
        MVMStaticFrameSpesh *spesh = sf->body.spesh;
542
0
        for (spesh_cand_idx = 0; spesh_cand_idx < spesh->body.num_spesh_candidates; spesh_cand_idx++) {
543
0
            MVMSpeshCandidate *cand = spesh->body.spesh_candidates[spesh_cand_idx];
544
0
            if (cand->bytecode == effective_bytecode) {
545
0
                MVM_dump_bytecode_of(tc, frame, cand);
546
0
            }
547
0
        }
548
0
    }
549
0
}
550
#endif