Start refactoring JIT engine
This commit is contained in:
parent
f761e9ee64
commit
f7717b1d46
|
@ -43,7 +43,7 @@ static void
|
|||
ujit_gen_exit(codeblock_t* cb, ctx_t* ctx, VALUE* exit_pc)
|
||||
{
|
||||
// Write the adjusted SP back into the CFP
|
||||
if (ctx->stack_diff != 0)
|
||||
if (ctx->stack_size != 0)
|
||||
{
|
||||
x86opnd_t stack_pointer = ctx_sp_opnd(ctx, 0);
|
||||
lea(cb, REG_SP, stack_pointer);
|
||||
|
@ -95,11 +95,10 @@ ujit_side_exit(codeblock_t* cb, ctx_t* ctx, VALUE* exit_pc)
|
|||
|
||||
/*
|
||||
Compile a sequence of bytecode instructions starting at `insn_idx`.
|
||||
Return the index to the first instruction not compiled in the sequence
|
||||
through `next_ujit_idx`. Return `NULL` in case compilation fails.
|
||||
Returns `NULL` if compilation fails.
|
||||
*/
|
||||
uint8_t *
|
||||
ujit_compile_insn(const rb_iseq_t *iseq, unsigned int insn_idx, unsigned int *next_ujit_idx)
|
||||
ujit_compile_block(const rb_iseq_t *iseq, unsigned int insn_idx)
|
||||
{
|
||||
assert (cb != NULL);
|
||||
unsigned first_insn_idx = insn_idx;
|
||||
|
@ -174,16 +173,13 @@ ujit_compile_insn(const rb_iseq_t *iseq, unsigned int insn_idx, unsigned int *ne
|
|||
}
|
||||
}
|
||||
|
||||
// Let the caller know how many instructions ujit compiled
|
||||
*next_ujit_idx = insn_idx;
|
||||
|
||||
// If no instructions were compiled
|
||||
if (num_instrs == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Generate code to exit to the interpreter
|
||||
ujit_gen_exit(cb, &ctx, &encoded[*next_ujit_idx]);
|
||||
ujit_gen_exit(cb, &ctx, &encoded[insn_idx]);
|
||||
|
||||
map_addr2insn(code_ptr, first_opcode);
|
||||
|
||||
|
@ -191,7 +187,7 @@ ujit_compile_insn(const rb_iseq_t *iseq, unsigned int insn_idx, unsigned int *ne
|
|||
// Dump list of compiled instrutions
|
||||
fprintf(stderr, "Compiled the following for iseq=%p:\n", (void *)iseq);
|
||||
VALUE *pc = &encoded[first_insn_idx];
|
||||
VALUE *end_pc = &encoded[*next_ujit_idx];
|
||||
VALUE *end_pc = &encoded[insn_idx];
|
||||
while (pc < end_pc) {
|
||||
int opcode = opcode_at_pc(iseq, pc);
|
||||
fprintf(stderr, " %04td %s\n", pc - encoded, insn_name(opcode));
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include "stddef.h"
|
||||
|
||||
uint8_t * ujit_compile_insn(const rb_iseq_t *iseq, unsigned int insn_idx, unsigned int *next_ujit_idx);
|
||||
uint8_t * ujit_compile_block(const rb_iseq_t *iseq, unsigned int insn_idx);
|
||||
|
||||
void ujit_init_codegen(void);
|
||||
|
||||
|
|
42
ujit_core.c
42
ujit_core.c
|
@ -1,7 +1,37 @@
|
|||
#include "internal.h"
|
||||
#include "ujit_asm.h"
|
||||
#include "ujit_iface.h"
|
||||
#include "ujit_core.h"
|
||||
|
||||
|
||||
|
||||
|
||||
// Table of block versions indexed by (iseq, index) tuples
|
||||
st_table * version_tbl;
|
||||
|
||||
/*
|
||||
struct st_hash_type {
|
||||
int (*compare)(st_data_t, st_data_t); // st_compare_func*
|
||||
st_index_t (*hash)(st_data_t); // st_hash_func*
|
||||
};
|
||||
|
||||
static const struct st_hash_type st_hashtype_num = {
|
||||
st_numcmp,
|
||||
st_numhash,
|
||||
};
|
||||
|
||||
strcasehash(st_data_t arg)
|
||||
{
|
||||
register const char *string = (const char *)arg;
|
||||
...
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Get the current instruction opcode from the context object
|
||||
int
|
||||
ctx_get_opcode(ctx_t *ctx)
|
||||
|
@ -23,7 +53,7 @@ Get an operand for the adjusted stack pointer address
|
|||
x86opnd_t
|
||||
ctx_sp_opnd(ctx_t* ctx, int32_t offset_bytes)
|
||||
{
|
||||
int32_t offset = (ctx->stack_diff) * 8 + offset_bytes;
|
||||
int32_t offset = (ctx->stack_size) * 8 + offset_bytes;
|
||||
return mem_opnd(64, REG_SP, offset);
|
||||
}
|
||||
|
||||
|
@ -34,10 +64,10 @@ Return a pointer to the new stack top
|
|||
x86opnd_t
|
||||
ctx_stack_push(ctx_t* ctx, size_t n)
|
||||
{
|
||||
ctx->stack_diff += n;
|
||||
ctx->stack_size += n;
|
||||
|
||||
// SP points just above the topmost value
|
||||
int32_t offset = (ctx->stack_diff - 1) * 8;
|
||||
int32_t offset = (ctx->stack_size - 1) * 8;
|
||||
return mem_opnd(64, REG_SP, offset);
|
||||
}
|
||||
|
||||
|
@ -49,10 +79,10 @@ x86opnd_t
|
|||
ctx_stack_pop(ctx_t* ctx, size_t n)
|
||||
{
|
||||
// SP points just above the topmost value
|
||||
int32_t offset = (ctx->stack_diff - 1) * 8;
|
||||
int32_t offset = (ctx->stack_size - 1) * 8;
|
||||
x86opnd_t top = mem_opnd(64, REG_SP, offset);
|
||||
|
||||
ctx->stack_diff -= n;
|
||||
ctx->stack_size -= n;
|
||||
|
||||
return top;
|
||||
}
|
||||
|
@ -61,7 +91,7 @@ x86opnd_t
|
|||
ctx_stack_opnd(ctx_t* ctx, int32_t idx)
|
||||
{
|
||||
// SP points just above the topmost value
|
||||
int32_t offset = (ctx->stack_diff - 1 - idx) * 8;
|
||||
int32_t offset = (ctx->stack_size - 1 - idx) * 8;
|
||||
x86opnd_t opnd = mem_opnd(64, REG_SP, offset);
|
||||
|
||||
return opnd;
|
||||
|
|
20
ujit_core.h
20
ujit_core.h
|
@ -17,16 +17,18 @@
|
|||
#define REG0_32 EAX
|
||||
#define REG1_32 ECX
|
||||
|
||||
// Maximum number of versions per block
|
||||
#define MAX_VERSIONS 5
|
||||
|
||||
// Code generation context
|
||||
typedef struct ctx_struct
|
||||
{
|
||||
// Current PC
|
||||
VALUE *pc;
|
||||
// TODO: we may want to remove information that is not
|
||||
// strictly necessary for versioning from this struct
|
||||
// Some of the information here is only needed during
|
||||
// code generation, eg: current pc
|
||||
|
||||
// Difference between the current stack pointer and actual stack top
|
||||
int32_t stack_diff;
|
||||
|
||||
// The iseq that owns the region that is compiling
|
||||
// Instruction sequence this is associated with
|
||||
const rb_iseq_t *iseq;
|
||||
|
||||
// Index in the iseq of the opcode we are replacing
|
||||
|
@ -35,6 +37,12 @@ typedef struct ctx_struct
|
|||
// The start of the generated code
|
||||
uint8_t *code_ptr;
|
||||
|
||||
// Current PC
|
||||
VALUE *pc;
|
||||
|
||||
// Number of values pushed on the temporary stack
|
||||
int32_t stack_size;
|
||||
|
||||
// Whether we know self is a heap object
|
||||
bool self_is_object;
|
||||
|
||||
|
|
22
ujit_iface.c
22
ujit_iface.c
|
@ -232,25 +232,13 @@ rb_ujit_compile_iseq(const rb_iseq_t *iseq)
|
|||
RB_VM_LOCK_ENTER();
|
||||
VALUE *encoded = (VALUE *)iseq->body->iseq_encoded;
|
||||
|
||||
unsigned int insn_idx;
|
||||
unsigned int next_ujit_idx = 0;
|
||||
// Compile a block version starting at the first instruction
|
||||
uint8_t* native_code_ptr = ujit_compile_block(iseq, 0);
|
||||
|
||||
for (insn_idx = 0; insn_idx < iseq->body->iseq_size; /* */) {
|
||||
int insn = opcode_at_pc(iseq, &encoded[insn_idx]);
|
||||
int len = insn_len(insn);
|
||||
|
||||
uint8_t *native_code_ptr = NULL;
|
||||
|
||||
// If ujit hasn't already compiled this instruction
|
||||
if (insn_idx >= next_ujit_idx) {
|
||||
native_code_ptr = ujit_compile_insn(iseq, insn_idx, &next_ujit_idx);
|
||||
}
|
||||
|
||||
if (native_code_ptr) {
|
||||
encoded[insn_idx] = (VALUE)native_code_ptr;
|
||||
}
|
||||
insn_idx += len;
|
||||
if (native_code_ptr) {
|
||||
encoded[0] = (VALUE)native_code_ptr;
|
||||
}
|
||||
|
||||
RB_VM_LOCK_LEAVE();
|
||||
#endif
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue