mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Split out compile_entry() from compile_block()
This commit is contained in:
parent
4592ef9d76
commit
5e39d83fbd
5 changed files with 61 additions and 35 deletions
|
@ -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.
|
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 *
|
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);
|
assert (cb != NULL);
|
||||||
VALUE *encoded = iseq->body->iseq_encoded;
|
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)");
|
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
|
// Get a pointer to the current write position in the code block
|
||||||
uint8_t *code_ptr = &cb->mem_block[cb->write_pos];
|
uint8_t *code_ptr = cb_get_ptr(cb, 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]);
|
|
||||||
|
|
||||||
// Create codegen context
|
// Create codegen context
|
||||||
ctx_t ctx = { 0 };
|
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;
|
ctx.start_idx = insn_idx;
|
||||||
|
|
||||||
// For each instruction to compile
|
// For each instruction to compile
|
||||||
unsigned num_instrs = 0;
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// Set the current instruction
|
// Set the current instruction
|
||||||
ctx.insn_idx = insn_idx;
|
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;
|
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));
|
//fprintf(stderr, "compiling %s\n", insn_name(opcode));
|
||||||
//print_str(cb, 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
|
// Move to the next instruction
|
||||||
insn_idx += insn_len(opcode);
|
insn_idx += insn_len(opcode);
|
||||||
num_instrs++;
|
(*num_instrs)++;
|
||||||
|
|
||||||
// Ensure we only have one send per region. Our code invalidation mechanism can't
|
// 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
|
// 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");
|
//print_str(cb, "exiting to interpreter\n");
|
||||||
|
|
||||||
// FIXME: only generate exit if no instructions were compiled?
|
// FIXME: we only need to generate an exit if an instruction fails to compile
|
||||||
// or simply don't allow instructions to fail to compile anymore?
|
//
|
||||||
// Generate code to exit to the interpreter
|
// Generate code to exit to the interpreter
|
||||||
ujit_gen_exit(cb, &ctx, &encoded[insn_idx]);
|
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) {
|
if (UJIT_DUMP_MODE >= 2) {
|
||||||
// Dump list of compiled instrutions
|
// Dump list of compiled instrutions
|
||||||
fprintf(stderr, "Compiled the following for iseq=%p:\n", (void *)iseq);
|
fprintf(stderr, "Compiled the following for iseq=%p:\n", (void *)iseq);
|
||||||
|
|
|
@ -10,7 +10,9 @@ codeblock_t* ocb;
|
||||||
// Code generation function signature
|
// Code generation function signature
|
||||||
typedef bool (*codegen_fn)(codeblock_t* cb, codeblock_t* ocb, ctx_t* ctx);
|
typedef bool (*codegen_fn)(codeblock_t* cb, codeblock_t* ocb, ctx_t* ctx);
|
||||||
|
|
||||||
uint8_t *ujit_compile_block(const rb_iseq_t *iseq, uint32_t insn_idx, bool gen_entry);
|
uint8_t* ujit_compile_entry(const rb_iseq_t *iseq, uint32_t insn_idx);
|
||||||
|
|
||||||
|
uint8_t *ujit_compile_block(const rb_iseq_t *iseq, uint32_t insn_idx, uint32_t* num_instrs);
|
||||||
|
|
||||||
void ujit_init_codegen(void);
|
void ujit_init_codegen(void);
|
||||||
|
|
||||||
|
|
|
@ -155,7 +155,8 @@ uint8_t* branch_stub_hit(uint32_t branch_idx, uint32_t target_idx)
|
||||||
{
|
{
|
||||||
//fprintf(stderr, "compiling block\n");
|
//fprintf(stderr, "compiling block\n");
|
||||||
|
|
||||||
block_ptr = ujit_compile_block(target.iseq, target.idx, false);
|
uint32_t num_instrs = 0;
|
||||||
|
block_ptr = ujit_compile_block(target.iseq, target.idx, &num_instrs);
|
||||||
st_insert(version_tbl, (st_data_t)&target, (st_data_t)block_ptr);
|
st_insert(version_tbl, (st_data_t)&target, (st_data_t)block_ptr);
|
||||||
branch->dst_addrs[target_idx] = block_ptr;
|
branch->dst_addrs[target_idx] = block_ptr;
|
||||||
}
|
}
|
||||||
|
|
12
ujit_core.h
12
ujit_core.h
|
@ -20,8 +20,18 @@
|
||||||
// Maximum number of versions per block
|
// Maximum number of versions per block
|
||||||
#define MAX_VERSIONS 5
|
#define MAX_VERSIONS 5
|
||||||
|
|
||||||
|
// Code generation state
|
||||||
|
typedef struct JITState
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} jitstate_t;
|
||||||
|
|
||||||
// Code generation context
|
// Code generation context
|
||||||
typedef struct ctx_struct
|
typedef struct CtxStruct
|
||||||
{
|
{
|
||||||
// TODO: we may want to remove information that is not
|
// TODO: we may want to remove information that is not
|
||||||
// strictly necessary for versioning from this struct
|
// strictly necessary for versioning from this struct
|
||||||
|
|
|
@ -233,7 +233,7 @@ rb_ujit_compile_iseq(const rb_iseq_t *iseq)
|
||||||
VALUE *encoded = (VALUE *)iseq->body->iseq_encoded;
|
VALUE *encoded = (VALUE *)iseq->body->iseq_encoded;
|
||||||
|
|
||||||
// Compile a block version starting at the first instruction
|
// Compile a block version starting at the first instruction
|
||||||
uint8_t* native_code_ptr = ujit_compile_block(iseq, 0, true);
|
uint8_t* native_code_ptr = ujit_compile_entry(iseq, 0);
|
||||||
|
|
||||||
if (native_code_ptr) {
|
if (native_code_ptr) {
|
||||||
encoded[0] = (VALUE)native_code_ptr;
|
encoded[0] = (VALUE)native_code_ptr;
|
||||||
|
|
Loading…
Reference in a new issue