Coverage Report

Created: 2017-04-15 07:07

/home/travis/build/MoarVM/MoarVM/src/instrument/line_coverage.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
3
0
static void instrument_graph(MVMThreadContext *tc, MVMSpeshGraph *g) {
4
0
    MVMSpeshBB *bb = g->entry->linear_next;
5
0
    MVMuint16 array_slot = 0;
6
0
7
0
    MVMint32 last_line_number;
8
0
    MVMint32 last_filename;
9
0
10
0
    char *line_report_store = MVM_calloc(g->num_bbs, sizeof(char));
11
0
    MVMuint16 allocd_slots = g->num_bbs;
12
0
13
0
    while (bb) {
14
0
        MVMSpeshIns *ins = bb->first_ins;
15
0
        MVMSpeshIns *log_ins;
16
0
17
0
        MVMBytecodeAnnotation *bbba = MVM_bytecode_resolve_annotation(tc, &g->sf->body, bb->initial_pc);
18
0
        MVMuint32 line_number;
19
0
        MVMuint32 filename_string_index;
20
0
        if (bbba) {
21
0
            line_number = bbba->line_number;
22
0
            filename_string_index = bbba->filename_string_heap_index;
23
0
            MVM_free(bbba);
24
0
        } else {
25
0
            line_number = -1;
26
0
            bb = bb->linear_next;
27
0
            continue;
28
0
        }
29
0
30
0
        /* skip PHI instructions, to make sure PHI only occur uninterrupted after start-of-bb */
31
0
        while (ins && ins->info->opcode == MVM_SSA_PHI) {
32
0
            ins = ins->next;
33
0
        }
34
0
        if (!ins) ins = bb->last_ins;
35
0
36
0
        /* Jumplists require the target BB to start in the goto op.
37
0
         * We must not break this, or we cause the interpreter to derail */
38
0
        if (bb->last_ins->info->opcode == MVM_OP_jumplist) {
39
0
            MVMint16 to_skip = bb->num_succ;
40
0
            for (; to_skip > 0; to_skip--) {
41
0
                bb = bb->linear_next;
42
0
            }
43
0
            continue;
44
0
        }
45
0
46
0
        log_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
47
0
        log_ins->info        = MVM_op_get_op(MVM_OP_coverage_log);
48
0
        log_ins->operands    = MVM_spesh_alloc(tc, g, 4 * sizeof(MVMSpeshOperand));
49
0
50
0
        log_ins->operands[0].lit_str_idx = filename_string_index;
51
0
        log_ins->operands[1].lit_i32 = line_number;
52
0
53
0
        if (last_line_number == line_number && last_filename == filename_string_index) {
54
0
            /* Consecutive BBs with the same line number and filename should
55
0
             * share one "already reported" slot. */
56
0
            log_ins->operands[2].lit_i32 = array_slot;
57
0
        } else {
58
0
            log_ins->operands[2].lit_i32 = array_slot++;
59
0
            last_line_number = line_number;
60
0
            last_filename = filename_string_index;
61
0
        }
62
0
63
0
        log_ins->operands[3].lit_i64 = (MVMint64)line_report_store;
64
0
65
0
        MVM_spesh_manipulate_insert_ins(tc, bb, ins, log_ins);
66
0
67
0
        bb = bb->linear_next;
68
0
    }
69
0
70
0
    if (array_slot == 0) {
71
0
        MVM_free(line_report_store);
72
0
    } else if (array_slot > g->num_bbs) {
73
0
        MVM_panic(99, "we've allocated %d slots for coverage reporting, but we've used up to %d!", g->num_bbs, array_slot);
74
0
    }
75
0
}
76
77
/* Adds instrumented version of the unspecialized bytecode. */
78
0
static void add_instrumentation(MVMThreadContext *tc, MVMStaticFrame *sf) {
79
0
    MVMSpeshCode  *sc;
80
0
    MVMStaticFrameInstrumentation *ins;
81
0
    MVMSpeshGraph *sg = MVM_spesh_graph_create(tc, sf, 1, 0);
82
0
    instrument_graph(tc, sg);
83
0
    sc = MVM_spesh_codegen(tc, sg);
84
0
    ins = MVM_calloc(1, sizeof(MVMStaticFrameInstrumentation));
85
0
    ins->instrumented_bytecode        = sc->bytecode;
86
0
    ins->instrumented_handlers        = sc->handlers;
87
0
    ins->instrumented_bytecode_size   = sc->bytecode_size;
88
0
    ins->uninstrumented_bytecode      = sf->body.bytecode;
89
0
    ins->uninstrumented_handlers      = sf->body.handlers;
90
0
    ins->uninstrumented_bytecode_size = sf->body.bytecode_size;
91
0
    sf->body.instrumentation = ins;
92
0
    MVM_spesh_graph_destroy(tc, sg);
93
0
    MVM_free(sc);
94
0
}
95
96
97
/* Instruments code with per-line logging of code coverage */
98
0
void MVM_line_coverage_instrument(MVMThreadContext *tc, MVMStaticFrame *sf) {
99
0
    if (!sf->body.instrumentation || sf->body.bytecode != sf->body.instrumentation->instrumented_bytecode) {
100
0
        /* Handle main, non-specialized, bytecode. */
101
0
        if (!sf->body.instrumentation)
102
0
            add_instrumentation(tc, sf);
103
0
        sf->body.bytecode      = sf->body.instrumentation->instrumented_bytecode;
104
0
        sf->body.handlers      = sf->body.instrumentation->instrumented_handlers;
105
0
        sf->body.bytecode_size = sf->body.instrumentation->instrumented_bytecode_size;
106
0
107
0
        /* Throw away any specializations; we'll need to reproduce them as
108
0
         * instrumented versions. */
109
0
        sf->body.num_spesh_candidates = 0;
110
0
        sf->body.spesh_candidates     = NULL;
111
0
    }
112
0
}
113
114
0
void MVM_line_coverage_report(MVMThreadContext *tc, MVMString *filename, MVMuint32 line_number, MVMuint16 cache_slot, char *cache) {
115
0
    if (cache[cache_slot] == 0) {
116
0
        char *encoded_filename;
117
0
        char composed_line[256];
118
0
        size_t length;
119
0
120
0
        cache[cache_slot] = 1;
121
0
122
0
        encoded_filename = MVM_string_utf8_encode_C_string(tc, filename);
123
0
        if ((length = snprintf(composed_line, 255, "HIT  %s  %d\n", encoded_filename, line_number)) > 0) {
124
0
            fputs(composed_line, tc->instance->coverage_log_fh);
125
0
        }
126
0
        MVM_free(encoded_filename);
127
0
    }
128
0
}