summaryrefslogtreecommitdiff
path: root/ujit_codegen.c
diff options
context:
space:
mode:
authorMaxime Chevalier-Boisvert <maxime.chevalierboisvert@shopify.com>2020-12-18 13:49:53 -0500
committerAlan Wu <XrXr@users.noreply.github.com>2021-10-20 18:19:26 -0400
commit5e39d83fbd560a5151facba10e95889aff84c93e (patch)
tree90da97ad80b303e805b0c1fe2c8423d3932c394d /ujit_codegen.c
parent4592ef9d76c5ef1bf7f99119a126a1b700c88f1f (diff)
Split out compile_entry() from compile_block()
Diffstat (limited to 'ujit_codegen.c')
-rw-r--r--ujit_codegen.c75
1 files changed, 44 insertions, 31 deletions
diff --git a/ujit_codegen.c b/ujit_codegen.c
index ebffef424a..09b61a9bea 100644
--- a/ujit_codegen.c
+++ b/ujit_codegen.c
@@ -86,11 +86,49 @@ ujit_side_exit(codeblock_t* cb, ctx_t* ctx)
}
/*
-Compile a sequence of bytecode instructions starting at `insn_idx`.
+Compile an interpreter entry point to be inserted into an iseq
Returns `NULL` if compilation fails.
*/
+uint8_t* ujit_compile_entry(const rb_iseq_t *iseq, uint32_t insn_idx)
+{
+ assert (cb != NULL);
+
+ if (cb->write_pos + 1024 >= cb->mem_size) {
+ rb_bug("out of executable memory");
+ }
+
+ // Align the current write positon to cache line boundaries
+ cb_align_pos(cb, 64);
+
+ uint8_t *code_ptr = cb_get_ptr(cb, cb->write_pos);
+
+ // Write the interpreter entry prologue
+ ujit_gen_entry(cb);
+
+ // Compile the block starting at this instruction
+ uint32_t num_instrs = 0;
+ ujit_compile_block(iseq, insn_idx, &num_instrs);
+
+ // If no instructions were compiled
+ if (num_instrs == 0) {
+ return NULL;
+ }
+
+ // Get the first opcode in the sequence
+ VALUE *encoded = iseq->body->iseq_encoded;
+ int first_opcode = opcode_at_pc(iseq, &encoded[insn_idx]);
+
+ // Map the code address to the corresponding opcode
+ map_addr2insn(code_ptr, first_opcode);
+
+ return code_ptr;
+}
+
+/*
+Compile a sequence of bytecode instructions starting at `insn_idx`.
+*/
uint8_t *
-ujit_compile_block(const rb_iseq_t *iseq, uint32_t insn_idx, bool entry_point)
+ujit_compile_block(const rb_iseq_t *iseq, uint32_t insn_idx, uint32_t* num_instrs)
{
assert (cb != NULL);
VALUE *encoded = iseq->body->iseq_encoded;
@@ -105,15 +143,8 @@ ujit_compile_block(const rb_iseq_t *iseq, uint32_t insn_idx, bool entry_point)
rb_bug("out of executable memory (outlined block)");
}
- // Align the current write positon to cache line boundaries
- cb_align_pos(cb, 64);
-
// Get a pointer to the current write position in the code block
- uint8_t *code_ptr = &cb->mem_block[cb->write_pos];
- //printf("write pos: %ld\n", cb->write_pos);
-
- // Get the first opcode in the sequence
- int first_opcode = opcode_at_pc(iseq, &encoded[insn_idx]);
+ uint8_t *code_ptr = cb_get_ptr(cb, cb->write_pos);
// Create codegen context
ctx_t ctx = { 0 };
@@ -122,7 +153,6 @@ ujit_compile_block(const rb_iseq_t *iseq, uint32_t insn_idx, bool entry_point)
ctx.start_idx = insn_idx;
// For each instruction to compile
- unsigned num_instrs = 0;
for (;;) {
// Set the current instruction
ctx.insn_idx = insn_idx;
@@ -139,12 +169,6 @@ ujit_compile_block(const rb_iseq_t *iseq, uint32_t insn_idx, bool entry_point)
break;
}
- // If this is an interpreter entry point, write the interpreter
- // entry prologue before the first instruction
- if (entry_point && num_instrs == 0) {
- ujit_gen_entry(cb);
- }
-
//fprintf(stderr, "compiling %s\n", insn_name(opcode));
//print_str(cb, insn_name(opcode));
@@ -156,7 +180,7 @@ ujit_compile_block(const rb_iseq_t *iseq, uint32_t insn_idx, bool entry_point)
// Move to the next instruction
insn_idx += insn_len(opcode);
- num_instrs++;
+ (*num_instrs)++;
// Ensure we only have one send per region. Our code invalidation mechanism can't
// invalidate running code and one send could invalidate the other if we had
@@ -166,24 +190,13 @@ ujit_compile_block(const rb_iseq_t *iseq, uint32_t insn_idx, bool entry_point)
}
}
- // FIXME: maybe we want a separate function to compile entry points?
- // If this is an entry point and no instructions were compiled
- if (entry_point && num_instrs == 0) {
- return NULL;
- }
-
//print_str(cb, "exiting to interpreter\n");
- // FIXME: only generate exit if no instructions were compiled?
- // or simply don't allow instructions to fail to compile anymore?
+ // FIXME: we only need to generate an exit if an instruction fails to compile
+ //
// Generate code to exit to the interpreter
ujit_gen_exit(cb, &ctx, &encoded[insn_idx]);
- // If this is an interpreter entry point
- if (entry_point) {
- map_addr2insn(code_ptr, first_opcode);
- }
-
if (UJIT_DUMP_MODE >= 2) {
// Dump list of compiled instrutions
fprintf(stderr, "Compiled the following for iseq=%p:\n", (void *)iseq);