/
compile.c
232 lines (187 loc) · 8.29 KB
/
compile.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
#include "moar.h"
#include "internal.h"
#include "platform/mmap.h"
void MVM_jit_compiler_init(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg);
void MVM_jit_compiler_deinit(MVMThreadContext *tc, MVMJitCompiler *compiler);
MVMJitCode * MVM_jit_compiler_assemble(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg);
void MVM_jit_compile_expr_tree(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *graph, MVMJitExprTree *tree);
#define COPY_ARRAY(a, n) memcpy(MVM_malloc(n * sizeof(a[0])), a, n * sizeof(a[0]))
static const MVMuint16 MAGIC_BYTECODE[] = { MVM_OP_sp_jit_enter, 0 };
void MVM_jit_compiler_init(MVMThreadContext *tc, MVMJitCompiler *cl, MVMJitGraph *jg) {
MVMint32 num_globals = MVM_jit_num_globals();
/* Create dasm state */
dasm_init(cl, 1);
cl->dasm_globals = MVM_malloc(num_globals * sizeof(void*));
dasm_setupglobal(cl, cl->dasm_globals, num_globals);
dasm_setup(cl, MVM_jit_actions());
/* Store graph we're compiling */
cl->graph = jg;
/* next (internal) label to assign */
cl->label_offset = jg->num_labels;
/* space for dynamic labels */
dasm_growpc(cl, jg->num_labels);
/* Offset in temporary array in which we can spill */
cl->spill_offset = (jg->sg->num_locals + jg->sg->sf->body.cu->body.max_callsite_size) * MVM_JIT_REG_SZ;
cl->max_spill = 2*MVM_JIT_PTR_SZ;
}
void MVM_jit_compiler_deinit(MVMThreadContext *tc, MVMJitCompiler *cl) {
dasm_free(cl);
MVM_free(cl->dasm_globals);
}
MVMJitCode * MVM_jit_compile_graph(MVMThreadContext *tc, MVMJitGraph *jg) {
MVMJitCompiler cl;
MVMJitCode *code;
MVMJitNode *node = jg->first_node;
MVM_jit_log(tc, "Starting compilation\n");
/* initialation */
MVM_jit_compiler_init(tc, &cl, jg);
/* generate code */
MVM_jit_emit_prologue(tc, &cl, jg);
while (node) {
switch(node->type) {
case MVM_JIT_NODE_LABEL:
MVM_jit_emit_label(tc, &cl, jg, node->u.label.name);
break;
case MVM_JIT_NODE_PRIMITIVE:
MVM_jit_emit_primitive(tc, &cl, jg, &node->u.prim);
break;
case MVM_JIT_NODE_BRANCH:
MVM_jit_emit_block_branch(tc, &cl, jg, &node->u.branch);
break;
case MVM_JIT_NODE_CALL_C:
MVM_jit_emit_call_c(tc, &cl, jg, &node->u.call);
break;
case MVM_JIT_NODE_GUARD:
MVM_jit_emit_guard(tc, &cl, jg, &node->u.guard);
break;
case MVM_JIT_NODE_INVOKE:
MVM_jit_emit_invoke(tc, &cl, jg, &node->u.invoke);
break;
case MVM_JIT_NODE_JUMPLIST:
MVM_jit_emit_jumplist(tc, &cl, jg, &node->u.jumplist);
break;
case MVM_JIT_NODE_CONTROL:
MVM_jit_emit_control(tc, &cl, jg, &node->u.control);
break;
case MVM_JIT_NODE_EXPR_TREE:
MVM_jit_compile_expr_tree(tc, &cl, jg, node->u.tree);
break;
}
node = node->next;
}
MVM_jit_emit_epilogue(tc, &cl, jg);
/* Generate code */
code = MVM_jit_compiler_assemble(tc, &cl, jg);
/* Clear up the compiler */
MVM_jit_compiler_deinit(tc, &cl);
/* Logging for insight */
if (tc->instance->jit_bytecode_dir) {
MVM_jit_log_bytecode(tc, code);
}
if (tc->instance->jit_log_fh)
fflush(tc->instance->jit_log_fh);
return code;
}
MVMJitCode * MVM_jit_compiler_assemble(MVMThreadContext *tc, MVMJitCompiler *cl, MVMJitGraph *jg) {
MVMJitCode * code;
MVMint32 i;
char * memory;
size_t codesize;
/* compile the function */
if (dasm_link(cl, &codesize) != 0)
MVM_oops(tc, "dynasm could not link :-(");
memory = MVM_platform_alloc_pages(codesize, MVM_PAGE_READ|MVM_PAGE_WRITE);
if (dasm_encode(cl, memory) != 0)
MVM_oops(tc, "dynasm could not encode :-(");
/* set memory readable + executable */
MVM_platform_set_page_mode(memory, codesize, MVM_PAGE_READ|MVM_PAGE_EXEC);
MVM_jit_log(tc, "Bytecode size: %"MVM_PRSz"\n", codesize);
/* Create code segment */
code = MVM_malloc(sizeof(MVMJitCode));
code->func_ptr = (void (*)(MVMThreadContext*,MVMCompUnit*,void*)) memory;
code->size = codesize;
code->bytecode = (MVMuint8*)MAGIC_BYTECODE;
code->sf = jg->sg->sf;
code->spill_size = cl->max_spill;
/* Get the basic block labels */
code->num_labels = jg->num_labels;
code->labels = MVM_calloc(code->num_labels, sizeof(void*));
for (i = 0; i < code->num_labels; i++) {
MVMint32 offset = dasm_getpclabel(cl, i);
if (offset < 0)
MVM_jit_log(tc, "Got negative offset for dynamic label %d\n", i);
code->labels[i] = memory + offset;
}
/* Copy the deopts, inlines, and handlers. Because these use the
* label index rather than the direct pointer, no fixup is
* necessary */
code->num_deopts = jg->deopts_num;
code->deopts = code->num_deopts ? COPY_ARRAY(jg->deopts, jg->deopts_num) : NULL;
code->num_handlers = jg->handlers_num;
code->handlers = code->num_handlers ? COPY_ARRAY(jg->handlers, jg->handlers_alloc) : NULL;
code->num_inlines = jg->inlines_num;
code->inlines = code->num_inlines ? COPY_ARRAY(jg->inlines, jg->inlines_alloc) : NULL;
code->seq_nr = MVM_incr(&tc->instance->jit_seq_nr);
return code;
}
void MVM_jit_destroy_code(MVMThreadContext *tc, MVMJitCode *code) {
MVM_platform_free_pages(code->func_ptr, code->size);
MVM_free(code->labels);
MVM_free(code->deopts);
MVM_free(code->handlers);
MVM_free(code->inlines);
MVM_free(code);
}
#define NYI(x) MVM_oops(tc, #x " NYI")
void MVM_jit_compile_breakpoint(void) {
fprintf(stderr, "Pause here please\n");
}
/* pseudotile emit functions */
void MVM_jit_compile_branch(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitExprTree *tree,
MVMint32 node, MVMJitValueDescriptor **value, MVMJitExprNode *args) {
MVM_jit_emit_branch(tc, compiler, args[0] + compiler->label_offset);
}
void MVM_jit_compile_conditional_branch(MVMThreadContext *tc, MVMJitCompiler *compiler,
MVMJitExprTree *tree, MVMint32 node,
MVMJitValueDescriptor **values, MVMJitExprNode *args) {
MVM_jit_emit_conditional_branch(tc, compiler, args[0], args[1] + compiler->label_offset);
}
void MVM_jit_compile_label(MVMThreadContext *tc, MVMJitCompiler *compiler,
MVMJitExprTree *tree, MVMint32 node,
MVMJitValueDescriptor **values, MVMJitExprNode *args) {
MVM_jit_emit_label(tc, compiler, tree->graph, args[0] + compiler->label_offset);
}
void MVM_jit_compile_expr_tree(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg, MVMJitExprTree *tree) {
MVMJitTileList *list;
MVMJitTile *tile;
MVMint32 i;
/* First stage, tile the tree */
list = MVM_jit_tile_expr_tree(tc, tree);
/* Log the tile list for debugging purposes */
MVM_jit_log_tile_list(tc, list);
/* Second stage, allocate registers */
MVM_jit_register_allocate(tc, compiler, list);
/* Allocate sufficient space for the internal labels */
dasm_growpc(compiler, compiler->label_offset + tree->num_labels);
/* Third stage, emit the code */
for (i = 0; i < list->items_num; i++) {
tile = list->items[i];
tile->emit(tc, compiler, tree, tile->node, tile->values, tile->args);
}
/* Tile list items are kept in a malloc'ed vector */
MVM_free(list->items);
/* Make sure no other tree reuses the same labels */
compiler->label_offset += tree->num_labels;
}
/* Enter the JIT code segment. The label is a continuation point where control
* is resumed after the frame is properly setup. */
void MVM_jit_enter_code(MVMThreadContext *tc, MVMCompUnit *cu,
MVMJitCode *code) {
void *label = tc->cur_frame->jit_entry_label;
if (label < (void*)code->func_ptr || (char*)label > (((char*)code->func_ptr) + code->size))
MVM_oops(tc, "JIT entry label out of range for code!\n"
"(label %x, func_ptr %x, code size %d, offset %d, frame_nr %d, seq nr %d)",
label, code->func_ptr, code->size, ((char*)label) - ((char*)code->func_ptr),
tc->cur_frame->sequence_nr, code->seq_nr);
code->func_ptr(tc, cu, label);
}