Coverage Report

Created: 2018-07-03 15:31

/home/travis/build/MoarVM/MoarVM/src/jit/compile.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
#include "internal.h"
3
#include "platform/mmap.h"
4
5
6
void MVM_jit_compiler_init(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg);
7
void MVM_jit_compiler_deinit(MVMThreadContext *tc, MVMJitCompiler *compiler);
8
MVMJitCode * MVM_jit_compiler_assemble(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg);
9
void MVM_jit_compile_expr_tree(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *graph, MVMJitExprTree *tree);
10
11
12
32.1k
#define COPY_ARRAY(a, n) ((n) > 0) ? memcpy(MVM_malloc((n) * sizeof(a[0])), a, (n) * sizeof(a[0])) : NULL;
13
14
static const MVMuint16 MAGIC_BYTECODE[] = { MVM_OP_sp_jit_enter, 0 };
15
16
10.7k
void MVM_jit_compiler_init(MVMThreadContext *tc, MVMJitCompiler *cl, MVMJitGraph *jg) {
17
10.7k
    /* Create dasm state */
18
10.7k
    dasm_init(cl, 2);
19
10.7k
    dasm_setupglobal(cl, cl->dasm_globals, MVM_JIT_MAX_GLOBALS);
20
10.7k
    dasm_setup(cl, MVM_jit_actions());
21
10.7k
22
10.7k
    /* Store graph we're compiling */
23
10.7k
    cl->graph        = jg;
24
10.7k
    /* next (internal) label to assign */
25
10.7k
    cl->label_offset = jg->num_labels;
26
10.7k
    /* space for dynamic labels */
27
10.7k
    dasm_growpc(cl, jg->num_labels);
28
10.7k
29
10.7k
    /* Spill offset and free list */
30
10.7k
    cl->spills_base = jg->sg->num_locals * sizeof(MVMRegister);
31
10.7k
    memset(cl->spills_free, -1, sizeof(cl->spills_free));
32
10.7k
    MVM_VECTOR_INIT(cl->spills, 4);
33
10.7k
}
34
35
36
10.7k
void MVM_jit_compiler_deinit(MVMThreadContext *tc, MVMJitCompiler *cl) {
37
10.7k
    dasm_free(cl);
38
10.7k
    MVM_VECTOR_DESTROY(cl->spills);
39
10.7k
}
40
41
10.7k
MVMJitCode * MVM_jit_compile_graph(MVMThreadContext *tc, MVMJitGraph *jg) {
42
10.7k
    MVMJitCompiler cl;
43
10.7k
    MVMJitCode *code;
44
10.7k
    MVMJitNode *node = jg->first_node;
45
10.7k
46
10.7k
    MVM_jit_log(tc, "Starting compilation\n");
47
10.7k
    /* initialation */
48
10.7k
    MVM_jit_compiler_init(tc, &cl, jg);
49
10.7k
    /* generate code */
50
10.7k
    MVM_jit_emit_prologue(tc, &cl, jg);
51
875k
    while (node) {
52
865k
        switch(node->type) {
53
322k
        case MVM_JIT_NODE_LABEL:
54
322k
            MVM_jit_emit_label(tc, &cl, jg, node->u.label.name);
55
322k
            break;
56
135k
        case MVM_JIT_NODE_PRIMITIVE:
57
135k
            MVM_jit_emit_primitive(tc, &cl, jg, &node->u.prim);
58
135k
            break;
59
22.9k
        case MVM_JIT_NODE_BRANCH:
60
22.9k
            MVM_jit_emit_block_branch(tc, &cl, jg, &node->u.branch);
61
22.9k
            break;
62
67.2k
        case MVM_JIT_NODE_CALL_C:
63
67.2k
            MVM_jit_emit_call_c(tc, &cl, jg, &node->u.call);
64
67.2k
            break;
65
36.2k
        case MVM_JIT_NODE_GUARD:
66
36.2k
            MVM_jit_emit_guard(tc, &cl, jg, &node->u.guard);
67
36.2k
            break;
68
26.1k
        case MVM_JIT_NODE_INVOKE:
69
26.1k
            MVM_jit_emit_invoke(tc, &cl, jg, &node->u.invoke);
70
26.1k
            break;
71
713
        case MVM_JIT_NODE_JUMPLIST:
72
713
            MVM_jit_emit_jumplist(tc, &cl, jg, &node->u.jumplist);
73
713
            break;
74
0
        case MVM_JIT_NODE_CONTROL:
75
0
            MVM_jit_emit_control(tc, &cl, &node->u.control, NULL);
76
0
            break;
77
253k
        case MVM_JIT_NODE_EXPR_TREE:
78
253k
            MVM_jit_compile_expr_tree(tc, &cl, jg, node->u.tree);
79
253k
            break;
80
0
        case MVM_JIT_NODE_DATA:
81
0
            MVM_jit_emit_data(tc, &cl, &node->u.data);
82
0
            break;
83
865k
        }
84
865k
        node = node->next;
85
865k
    }
86
10.7k
    MVM_jit_emit_epilogue(tc, &cl, jg);
87
10.7k
88
10.7k
    /* Generate code */
89
10.7k
    code = MVM_jit_compiler_assemble(tc, &cl, jg);
90
10.7k
91
10.7k
    /* Clear up the compiler */
92
10.7k
    MVM_jit_compiler_deinit(tc, &cl);
93
10.7k
94
10.7k
    /* Logging for insight */
95
10.7k
    if (tc->instance->jit_bytecode_dir) {
96
0
        MVM_jit_log_bytecode(tc, code);
97
0
    }
98
10.7k
    if (tc->instance->jit_log_fh)
99
0
        fflush(tc->instance->jit_log_fh);
100
10.7k
    return code;
101
10.7k
}
102
103
10.7k
MVMJitCode * MVM_jit_compiler_assemble(MVMThreadContext *tc, MVMJitCompiler *cl, MVMJitGraph *jg) {
104
10.7k
    MVMJitCode * code;
105
10.7k
    MVMint32 i;
106
10.7k
    char * memory;
107
10.7k
    size_t codesize;
108
10.7k
109
10.7k
    MVMint32 dasm_error = 0;
110
10.7k
111
10.7k
   /* compile the function */
112
10.7k
    if ((dasm_error = dasm_link(cl, &codesize)) != 0) {
113
0
        MVM_jit_log(tc, "DynASM could not link, error: %d\n", dasm_error);
114
0
        return NULL;
115
0
    }
116
10.7k
117
10.7k
    memory = MVM_platform_alloc_pages(codesize, MVM_PAGE_READ|MVM_PAGE_WRITE);
118
10.7k
    if ((dasm_error = dasm_encode(cl, memory)) != 0) {
119
0
        MVM_jit_log(tc, "DynASM could not encode, error: %d\n", dasm_error);
120
0
        return NULL;
121
0
    }
122
10.7k
123
10.7k
    /* set memory readable + executable */
124
10.7k
    if (!MVM_platform_set_page_mode(memory, codesize, MVM_PAGE_READ|MVM_PAGE_EXEC)) {
125
0
        MVM_jit_log(tc, "Setting jit page executable failed or was denied. deactivating jit.\n");
126
0
        /* our caller allocated the compiler and our caller must clean it up */
127
0
        tc->instance->jit_enabled = 0;
128
0
        return NULL;
129
0
    }
130
10.7k
131
10.7k
    MVM_jit_log(tc, "Bytecode size: %"MVM_PRSz"\n", codesize);
132
10.7k
133
10.7k
    /* Create code segment */
134
10.7k
    code = MVM_malloc(sizeof(MVMJitCode));
135
10.7k
    code->func_ptr   = (void (*)(MVMThreadContext*,MVMCompUnit*,void*)) memory;
136
10.7k
    code->size       = codesize;
137
10.7k
    code->bytecode   = (MVMuint8*)MAGIC_BYTECODE;
138
10.7k
    code->sf         = jg->sg->sf;
139
10.7k
    code->spill_size = cl->spills_num;
140
10.7k
    if (cl->spills_num > 0) {
141
9.59k
        MVMint32 sg_num_locals = jg->sg->num_locals;
142
9.59k
        code->num_locals  = sg_num_locals + cl->spills_num;
143
9.59k
        code->local_types = MVM_malloc(code->num_locals * sizeof(MVMuint16));
144
9.59k
        if (jg->sg->local_types != NULL) {
145
4.75k
            memcpy(code->local_types, jg->sg->local_types, sizeof(MVMuint16)*sg_num_locals);
146
4.84k
        } else {
147
4.84k
            memcpy(code->local_types, code->sf->body.local_types, sizeof(MVMuint16)*sg_num_locals);
148
4.84k
        }
149
28.6k
        for (i = 0; i < cl->spills_num; i++) {
150
19.0k
            code->local_types[sg_num_locals + i] = cl->spills[i].reg_type;
151
19.0k
        }
152
1.11k
    } else {
153
1.11k
        code->local_types = NULL;
154
1.11k
        code->num_locals  = 0;
155
1.11k
    }
156
10.7k
157
10.7k
    /* Get the basic block labels */
158
10.7k
    code->num_labels = jg->num_labels;
159
10.7k
    code->labels = MVM_calloc(code->num_labels, sizeof(void*));
160
10.7k
161
338k
    for (i = 0; i < code->num_labels; i++) {
162
327k
        MVMint32 offset = dasm_getpclabel(cl, i);
163
327k
        if (offset < 0)
164
0
            MVM_jit_log(tc, "Got negative offset for dynamic label %d\n", i);
165
327k
        code->labels[i] = memory + offset;
166
327k
    }
167
10.7k
    /* We only ever use one global label, which is the exit label */
168
10.7k
    code->exit_label = cl->dasm_globals[0];
169
10.7k
170
10.7k
    /* Copy the deopts, inlines, and handlers. Because these use the
171
10.7k
     * label index rather than the direct pointer, no fixup is
172
10.7k
     * necessary */
173
10.7k
    code->num_deopts   = jg->deopts_num;
174
10.7k
    code->deopts       = COPY_ARRAY(jg->deopts, jg->deopts_num);
175
10.7k
    code->num_handlers = jg->handlers_num;
176
10.7k
    code->handlers     = COPY_ARRAY(jg->handlers, jg->handlers_alloc);
177
10.7k
    code->num_inlines  = jg->inlines_num;
178
10.7k
    code->inlines      = COPY_ARRAY(jg->inlines, jg->inlines_alloc);
179
10.7k
180
10.7k
    /* add sequence number */
181
10.7k
    code->seq_nr       = tc->instance->jit_seq_nr++;
182
10.7k
183
10.7k
    return code;
184
10.7k
}
185
186
0
void MVM_jit_code_destroy(MVMThreadContext *tc, MVMJitCode *code) {
187
0
    MVM_platform_free_pages(code->func_ptr, code->size);
188
0
    MVM_free(code->labels);
189
0
    MVM_free(code->deopts);
190
0
    MVM_free(code->handlers);
191
0
    MVM_free(code->inlines);
192
0
    MVM_free(code->local_types);
193
0
    MVM_free(code);
194
0
}
195
196
197
198
#define NYI(x) MVM_oops(tc, #x " NYI")
199
200
201
/* pseudotile emit functions */
202
void MVM_jit_compile_branch(MVMThreadContext *tc, MVMJitCompiler *compiler,
203
155k
                            MVMJitTile *tile, MVMJitExprTree *tree) {
204
155k
    MVM_jit_emit_branch(tc, compiler, tile->args[0] + compiler->label_offset);
205
155k
}
206
207
void MVM_jit_compile_conditional_branch(MVMThreadContext *tc, MVMJitCompiler *compiler,
208
392k
                                        MVMJitTile *tile, MVMJitExprTree *tree) {
209
392k
    MVM_jit_emit_conditional_branch(tc, compiler, tile->args[0], tile->args[1] + compiler->label_offset);
210
392k
}
211
212
void MVM_jit_compile_label(MVMThreadContext *tc, MVMJitCompiler *compiler,
213
400k
                           MVMJitTile *tile, MVMJitExprTree *tree) {
214
400k
    MVM_jit_emit_label(tc, compiler, tree->graph, tile->args[0] + compiler->label_offset);
215
400k
}
216
217
void MVM_jit_compile_store(MVMThreadContext *tc, MVMJitCompiler *compiler,
218
114k
                           MVMJitTile *tile, MVMJitExprTree *tree) {
219
114k
    MVM_jit_emit_store(tc, compiler, tile->args[0], tile->args[1],
220
114k
                       MVM_JIT_STORAGE_GPR, tile->values[1], sizeof(MVMRegister));
221
114k
}
222
223
void MVM_jit_compile_memory_copy(MVMThreadContext *tc, MVMJitCompiler *compiler,
224
0
                                 MVMJitTile *tile, MVMJitExprTree *tree) {
225
0
    MVM_jit_emit_load(tc, compiler, MVM_JIT_STORAGE_GPR, tile->values[1],
226
0
                      tile->args[2], tile->args[3], sizeof(MVMRegister));
227
0
    MVM_jit_emit_store(tc, compiler, tile->args[0], tile->args[1],
228
0
                       MVM_JIT_STORAGE_GPR, tile->values[1], sizeof(MVMRegister));
229
0
}
230
231
void MVM_jit_compile_move(MVMThreadContext *tc, MVMJitCompiler *compiler,
232
1.01M
                          MVMJitTile *tile, MVMJitExprTree *tree) {
233
1.01M
    MVM_jit_emit_copy(tc, compiler, MVM_JIT_STORAGE_GPR, tile->values[0],
234
1.01M
                      MVM_JIT_STORAGE_GPR, tile->values[1]);
235
1.01M
}
236
237
void MVM_jit_compile_load(MVMThreadContext *tc, MVMJitCompiler *compiler,
238
470k
                          MVMJitTile *tile, MVMJitExprTree *tree) {
239
470k
    MVM_jit_emit_load(tc, compiler,
240
470k
                      MVM_JIT_STORAGE_GPR, tile->values[0],
241
470k
                      tile->args[0], tile->args[1],
242
470k
                      sizeof(MVMRegister));
243
470k
}
244
245
void MVM_jit_compile_guard(MVMThreadContext *tc, MVMJitCompiler *compiler,
246
0
                          MVMJitTile *tile, MVMJitExprTree *tree) {
247
0
    MVM_jit_emit_control(tc, compiler, NULL, tile);
248
0
}
249
250
253k
void MVM_jit_compile_expr_tree(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg, MVMJitExprTree *tree) {
251
253k
    MVMJitTileList *list;
252
253k
    MVMJitTile *tile;
253
253k
    MVMint32 i;
254
253k
    /* First stage, tile the tree */
255
253k
    list = MVM_jit_tile_expr_tree(tc, compiler, tree);
256
253k
    MVM_jit_log_tile_list(tc, list);
257
253k
258
253k
    /* Second stage, allocate registers */
259
253k
    MVM_jit_linear_scan_allocate(tc, compiler, list);
260
253k
261
253k
    /* Allocate sufficient space for the internal labels */
262
253k
    dasm_growpc(compiler, compiler->label_offset + tree->num_labels);
263
253k
264
253k
    /* Third stage, emit the code */
265
8.65M
    for (i = 0; i < list->items_num; i++) {
266
8.40M
        tile = list->items[i];
267
8.40M
        /* definition tiles etc. have NULL emit rules */
268
8.40M
        if (tile->emit != NULL) {
269
5.84M
            tile->emit(tc, compiler, tile, tree);
270
5.84M
        }
271
8.40M
    }
272
253k
    /* Cleanup tile lits */
273
253k
    MVM_jit_tile_list_destroy(tc, list);
274
253k
275
253k
    /* Make sure no other tree reuses the same labels */
276
253k
    compiler->label_offset += tree->num_labels;
277
253k
}
278
279
133k
MVM_STATIC_INLINE MVMint32 reg_type_bucket(MVMint8 reg_type) {
280
133k
    switch (reg_type) {
281
0
    case MVM_reg_num32:
282
0
    case MVM_reg_num64:
283
0
        return 1;
284
0
        break;
285
3.59k
    case MVM_reg_str:
286
3.59k
        return 2;
287
0
        break;
288
108k
    case MVM_reg_obj:
289
108k
        return 3;
290
0
        break;
291
21.2k
    default:
292
21.2k
        break;
293
133k
    }
294
21.2k
    return 0;
295
133k
}
296
297
298
66.6k
MVMint32 MVM_jit_spill_memory_select(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMint8 reg_type) {
299
66.6k
    MVMint32 idx;
300
66.6k
    MVMint8 bucket = reg_type_bucket(reg_type);
301
66.6k
302
66.6k
    if (compiler->spills_free[bucket] >= 0) {
303
47.4k
        idx = compiler->spills_free[bucket];
304
47.4k
        compiler->spills_free[bucket] = compiler->spills[idx].next;
305
19.2k
    } else {
306
19.2k
        MVM_VECTOR_ENSURE_SPACE(compiler->spills, idx = compiler->spills_num++);
307
19.2k
        compiler->spills[idx].reg_type = reg_type;
308
19.2k
    }
309
66.6k
    return compiler->spills_base + idx * sizeof(MVMRegister);
310
66.6k
}
311
312
66.6k
void MVM_jit_spill_memory_release(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMint32 pos, MVMint8 reg_type) {
313
66.6k
    MVMint32 idx   = (pos - compiler->spills_base) / sizeof(MVMRegister);
314
66.6k
    MVMint8 bucket = reg_type_bucket(reg_type);
315
66.6k
    compiler->spills[idx].next    = compiler->spills_free[bucket];
316
66.6k
    compiler->spills_free[bucket] = idx;
317
66.6k
}