1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Complete refactoring to codegen functions

This commit is contained in:
Maxime Chevalier-Boisvert 2020-09-16 10:33:34 -04:00 committed by Alan Wu
parent b0b7d0a87e
commit 16ddb422eb

View file

@ -14,6 +14,9 @@
// Code generation context // Code generation context
typedef struct ctx_struct typedef struct ctx_struct
{ {
// Current PC
VALUE* pc;
// TODO: virtual stack pointer handling // TODO: virtual stack pointer handling
} ctx_t; } ctx_t;
@ -65,11 +68,26 @@ addr2insn_bookkeeping(void *code_ptr, int insn)
} }
} }
// Generate a chunk of machine code for one individual bytecode instruction // Get the current instruction opcode from the context object
// Eventually, this will handle multiple instructions in a sequence int ctx_get_opcode(ctx_t* ctx)
// {
// MicroJIT code gets a pointer to the cfp as the first argument in RSI return (int)(*ctx->pc);
// See rb_ujit_empty_func(rb_control_frame_t *cfp) in iseq.c }
// Get an instruction argument from the context object
VALUE ctx_get_arg(ctx_t* ctx, size_t arg_idx)
{
assert (arg_idx + 1 < insn_len(ctx_get_opcode(ctx)));
return *(ctx->pc + arg_idx + 1);
}
/*
Generate a chunk of machine code for one individual bytecode instruction
Eventually, this will handle multiple instructions in a sequence
MicroJIT code gets a pointer to the cfp as the first argument in RSI
See rb_ujit_empty_func(rb_control_frame_t *cfp) in iseq.c
*/
uint8_t * uint8_t *
ujit_compile_insn(rb_iseq_t *iseq, size_t insn_idx) ujit_compile_insn(rb_iseq_t *iseq, size_t insn_idx)
{ {
@ -84,9 +102,12 @@ ujit_compile_insn(rb_iseq_t *iseq, size_t insn_idx)
rb_bug("out of executable memory"); rb_bug("out of executable memory");
} }
// 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);
int insn = (int)iseq->body->iseq_encoded[insn_idx]; int insn = (int)iseq->body->iseq_encoded[insn_idx];
int len = insn_len(insn); int len = insn_len(insn);
//const char* name = insn_name(insn); //const char* name = insn_name(insn);
//printf("%s\n", name); //printf("%s\n", name);
@ -99,22 +120,20 @@ ujit_compile_insn(rb_iseq_t *iseq, size_t insn_idx)
codegen_fn gen_fn = (codegen_fn)st_gen_fn; codegen_fn gen_fn = (codegen_fn)st_gen_fn;
// Compute the address of the next instruction
void *next_pc = &iseq->body->iseq_encoded[insn_idx + len];
// 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);
// Write the pre call bytes // Write the pre call bytes
ujit_instr_entry(cb); ujit_instr_entry(cb);
// TODO: create codegen context // Create codegen context
ctx_t ctx;
// Set the current PC
ctx.pc = &iseq->body->iseq_encoded[insn_idx];
// Call the code generation function // Call the code generation function
gen_fn(cb, NULL); gen_fn(cb, &ctx);
// Directly return the next PC, which is a constant // Directly return the next PC, which is a constant
void *next_pc = &iseq->body->iseq_encoded[insn_idx + len];
mov(cb, RAX, const_ptr_opnd(next_pc)); mov(cb, RAX, const_ptr_opnd(next_pc));
// Write the post call bytes // Write the post call bytes
@ -123,92 +142,6 @@ ujit_compile_insn(rb_iseq_t *iseq, size_t insn_idx)
addr2insn_bookkeeping(code_ptr, insn); addr2insn_bookkeeping(code_ptr, insn);
return code_ptr; return code_ptr;
/*
if (insn == BIN(putobject_INT2FIX_0_) || insn == BIN(putobject_INT2FIX_1_))
{
// Load current SP into RAX
mov(cb, RAX, mem_opnd(64, RDI, 8));
// Write constant at SP
int cst_val = (insn == BIN(putobject_INT2FIX_0_))? 0:1;
mov(cb, mem_opnd(64, RAX, 0), imm_opnd(INT2FIX(cst_val)));
// Load incremented SP into RCX
lea(cb, RCX, mem_opnd(64, RAX, 8));
// Write back incremented SP
mov(cb, mem_opnd(64, RDI, 8), RCX);
// Directly return the next PC, which is a constant
mov(cb, RAX, const_ptr_opnd(next_pc));
// Write the post call bytes
ujit_instr_exit(cb);
addr2insn_bookkeeping(code_ptr, insn);
return code_ptr;
}
*/
// TODO: implement putself
/*
if (insn == BIN(putself))
{
}
*/
// TODO: implement putobject
/*
if (insn == BIN(putobject))
{
}
*/
/*
if (insn == BIN(getlocal_WC_0))
{
//printf("compiling getlocal_WC_0\n");
// Load current SP from CFP
mov(cb, RAX, mem_opnd(64, RDI, 8));
// Load block pointer from CFP
mov(cb, RDX, mem_opnd(64, RDI, 32));
// TODO: we may want a macro or helper function to get insn operands
// Compute the offset from BP to the local
int32_t opnd0 = (int)iseq->body->iseq_encoded[insn_idx+1];
const int32_t offs = -8 * opnd0;
// Load the local from the block
mov(cb, RCX, mem_opnd(64, RDX, offs));
// Write the local at SP
mov(cb, mem_opnd(64, RAX, 0), RCX);
// Compute address of incremented SP
lea(cb, RCX, mem_opnd(64, RAX, 8));
// Write back incremented SP
mov(cb, mem_opnd(64, RDI, 8), RCX);
// Directly return the next PC, which is a constant
mov(cb, RAX, const_ptr_opnd(next_pc));
// Write the post call bytes
ujit_instr_exit(cb);
addr2insn_bookkeeping(code_ptr, insn);
}
*/
} }
void gen_nop(codeblock_t* cb, ctx_t* ctx) void gen_nop(codeblock_t* cb, ctx_t* ctx)
@ -221,6 +154,56 @@ void gen_pop(codeblock_t* cb, ctx_t* ctx)
sub(cb, mem_opnd(64, RDI, 8), imm_opnd(8)); sub(cb, mem_opnd(64, RDI, 8), imm_opnd(8));
} }
void gen_putobject_int2fix(codeblock_t* cb, ctx_t* ctx)
{
// Load current SP into RAX
mov(cb, RAX, mem_opnd(64, RDI, 8));
// Write constant at SP
int opcode = ctx_get_opcode(ctx);
int cst_val = (opcode == BIN(putobject_INT2FIX_0_))? 0:1;
mov(cb, mem_opnd(64, RAX, 0), imm_opnd(INT2FIX(cst_val)));
// Load incremented SP into RCX
lea(cb, RCX, mem_opnd(64, RAX, 8));
// Write back incremented SP
mov(cb, mem_opnd(64, RDI, 8), RCX);
}
// TODO: putnil
// could we reuse code from putobject_int2fix here?
// TODO: implement putself
// TODO: implement putobject
void gen_getlocal_wc0(codeblock_t* cb, ctx_t* ctx)
{
// Load current SP from CFP
mov(cb, RAX, mem_opnd(64, RDI, 8));
// Load block pointer from CFP
mov(cb, RDX, mem_opnd(64, RDI, 32));
// TODO: we may want a macro or helper function to get insn operands
// Compute the offset from BP to the local
int32_t local_idx = (int32_t)ctx_get_arg(ctx, 0);
const int32_t offs = -8 * local_idx;
// Load the local from the block
mov(cb, RCX, mem_opnd(64, RDX, offs));
// Write the local at SP
mov(cb, mem_opnd(64, RAX, 0), RCX);
// Compute address of incremented SP
lea(cb, RCX, mem_opnd(64, RAX, 8));
// Write back incremented SP
mov(cb, mem_opnd(64, RDI, 8), RCX);
}
static void ujit_init() static void ujit_init()
{ {
// 4MB ought to be enough for anybody // 4MB ought to be enough for anybody
@ -233,4 +216,7 @@ static void ujit_init()
// Map YARV opcodes to the corresponding codegen functions // Map YARV opcodes to the corresponding codegen functions
st_insert(gen_fns, (st_data_t)BIN(nop), (st_data_t)&gen_nop); st_insert(gen_fns, (st_data_t)BIN(nop), (st_data_t)&gen_nop);
st_insert(gen_fns, (st_data_t)BIN(pop), (st_data_t)&gen_pop); st_insert(gen_fns, (st_data_t)BIN(pop), (st_data_t)&gen_pop);
st_insert(gen_fns, (st_data_t)BIN(putobject_INT2FIX_0_), (st_data_t)&gen_putobject_int2fix);
st_insert(gen_fns, (st_data_t)BIN(putobject_INT2FIX_1_), (st_data_t)&gen_putobject_int2fix);
st_insert(gen_fns, (st_data_t)BIN(getlocal_WC_0), (st_data_t)&gen_getlocal_wc0);
} }