diff --git a/ujit_codegen.c b/ujit_codegen.c index ec55600bae..01785d5fc4 100644 --- a/ujit_codegen.c +++ b/ujit_codegen.c @@ -65,7 +65,7 @@ ujit_gen_exit(codeblock_t* cb, ctx_t* ctx, VALUE* exit_pc) Generate an out-of-line exit to return to the interpreter */ static uint8_t * -ujit_side_exit(codeblock_t* cb, ctx_t* ctx, VALUE* exit_pc) +ujit_side_exit(codeblock_t* cb, ctx_t* ctx) { uint8_t* code_ptr = cb_get_ptr(cb, cb->write_pos); @@ -84,6 +84,7 @@ ujit_side_exit(codeblock_t* cb, ctx_t* ctx, VALUE* exit_pc) // Write back the old instruction at the exit PC // Otherwise the interpreter may jump right back to the // JITted code we're trying to exit + VALUE* exit_pc = &ctx->iseq->body->iseq_encoded[ctx->insn_idx]; int exit_opcode = opcode_at_pc(ctx->iseq, exit_pc); void* exit_instr = (void*)table[exit_opcode]; mov(cb, RAX, const_ptr_opnd(exit_pc)); @@ -101,10 +102,9 @@ Compile a sequence of bytecode instructions starting at `insn_idx`. Returns `NULL` if compilation fails. */ uint8_t * -ujit_compile_block(const rb_iseq_t *iseq, unsigned int insn_idx, bool gen_entry) +ujit_compile_block(const rb_iseq_t *iseq, uint32_t insn_idx, bool gen_entry) { assert (cb != NULL); - unsigned first_insn_idx = insn_idx; VALUE *encoded = iseq->body->iseq_encoded; // NOTE: if we are ever deployed in production, we @@ -136,7 +136,8 @@ ujit_compile_block(const rb_iseq_t *iseq, unsigned int insn_idx, bool gen_entry) // For each instruction to compile unsigned num_instrs = 0; for (;;) { - // Set the current PC + // Set the current instruction + ctx.insn_idx = insn_idx; ctx.pc = &encoded[insn_idx]; // Get the current opcode @@ -187,7 +188,7 @@ ujit_compile_block(const rb_iseq_t *iseq, unsigned int insn_idx, bool gen_entry) if (UJIT_DUMP_MODE >= 2) { // Dump list of compiled instrutions fprintf(stderr, "Compiled the following for iseq=%p:\n", (void *)iseq); - VALUE *pc = &encoded[first_insn_idx]; + VALUE *pc = &encoded[ctx.start_idx]; VALUE *end_pc = &encoded[insn_idx]; while (pc < end_pc) { int opcode = opcode_at_pc(iseq, pc); @@ -199,15 +200,6 @@ ujit_compile_block(const rb_iseq_t *iseq, unsigned int insn_idx, bool gen_entry) return code_ptr; } - - - - - - - - - static bool gen_dup(codeblock_t* cb, codeblock_t* ocb, ctx_t* ctx) { @@ -248,7 +240,7 @@ static bool gen_putobject(codeblock_t* cb, codeblock_t* ocb, ctx_t* ctx) { // Load the argument from the bytecode sequence. - // We need to do this as the argument can chanage due to GC compaction. + // We need to do this as the argument can change due to GC compaction. x86opnd_t pc_imm = const_ptr_opnd((void*)ctx->pc); mov(cb, RAX, pc_imm); mov(cb, RAX, mem_opnd(64, RAX, 8)); // One after the opcode @@ -330,7 +322,7 @@ gen_setlocal_wc0(codeblock_t* cb, codeblock_t* ocb, ctx_t* ctx) test(cb, flags_opnd, imm_opnd(VM_ENV_FLAG_WB_REQUIRED)); // Create a size-exit to fall back to the interpreter - uint8_t* side_exit = ujit_side_exit(ocb, ctx, ctx->pc); + uint8_t* side_exit = ujit_side_exit(ocb, ctx); // if (flags & VM_ENV_FLAG_WB_REQUIRED) != 0 jnz_ptr(cb, side_exit); @@ -386,7 +378,7 @@ gen_getinstancevariable(codeblock_t* cb, codeblock_t* ocb, ctx_t* ctx) uint32_t ivar_index = ic->entry->index; // Create a size-exit to fall back to the interpreter - uint8_t* side_exit = ujit_side_exit(ocb, ctx, ctx->pc); + uint8_t* side_exit = ujit_side_exit(ocb, ctx); // Load self from CFP mov(cb, REG0, member_opnd(REG_CFP, rb_control_frame_t, self)); @@ -448,7 +440,7 @@ gen_setinstancevariable(codeblock_t* cb, codeblock_t* ocb, ctx_t* ctx) uint32_t ivar_index = ic->entry->index; // Create a size-exit to fall back to the interpreter - uint8_t* side_exit = ujit_side_exit(ocb, ctx, ctx->pc); + uint8_t* side_exit = ujit_side_exit(ocb, ctx); // Load self from CFP mov(cb, REG0, member_opnd(REG_CFP, rb_control_frame_t, self)); @@ -501,7 +493,7 @@ gen_opt_lt(codeblock_t* cb, codeblock_t* ocb, ctx_t* ctx) { // Create a size-exit to fall back to the interpreter // Note: we generate the side-exit before popping operands from the stack - uint8_t* side_exit = ujit_side_exit(ocb, ctx, ctx->pc); + uint8_t* side_exit = ujit_side_exit(ocb, ctx); // TODO: make a helper function for guarding on op-not-redefined // Make sure that minus isn't redefined for integers @@ -542,7 +534,7 @@ gen_opt_minus(codeblock_t* cb, codeblock_t* ocb, ctx_t* ctx) { // Create a size-exit to fall back to the interpreter // Note: we generate the side-exit before popping operands from the stack - uint8_t* side_exit = ujit_side_exit(ocb, ctx, ctx->pc); + uint8_t* side_exit = ujit_side_exit(ocb, ctx); // TODO: make a helper function for guarding on op-not-redefined // Make sure that minus isn't redefined for integers @@ -582,7 +574,7 @@ gen_opt_plus(codeblock_t* cb, codeblock_t* ocb, ctx_t* ctx) { // Create a size-exit to fall back to the interpreter // Note: we generate the side-exit before popping operands from the stack - uint8_t* side_exit = ujit_side_exit(ocb, ctx, ctx->pc); + uint8_t* side_exit = ujit_side_exit(ocb, ctx); // TODO: make a helper function for guarding on op-not-redefined // Make sure that plus isn't redefined for integers @@ -711,7 +703,7 @@ gen_opt_send_without_block(codeblock_t* cb, codeblock_t* ocb, ctx_t* ctx) } // Create a size-exit to fall back to the interpreter - uint8_t* side_exit = ujit_side_exit(ocb, ctx, ctx->pc); + uint8_t* side_exit = ujit_side_exit(ocb, ctx); // Check for interrupts // RUBY_VM_CHECK_INTS(ec) diff --git a/ujit_codegen.h b/ujit_codegen.h index 5216dbb1be..3dc3d1bf47 100644 --- a/ujit_codegen.h +++ b/ujit_codegen.h @@ -3,7 +3,7 @@ #include "stddef.h" -uint8_t *ujit_compile_block(const rb_iseq_t *iseq, unsigned int insn_idx, bool gen_entry); +uint8_t *ujit_compile_block(const rb_iseq_t *iseq, uint32_t insn_idx, bool gen_entry); void ujit_init_codegen(void); diff --git a/ujit_core.c b/ujit_core.c index c981ef0e30..1119e3df91 100644 --- a/ujit_core.c +++ b/ujit_core.c @@ -18,7 +18,7 @@ st_index_t blockid_hash(st_data_t arg) { const blockid_t *blockid = (const blockid_t*)arg; st_index_t hash0 = st_numhash((st_data_t)blockid->iseq); - st_index_t hash1 = st_numhash((st_data_t)blockid->idx); + st_index_t hash1 = st_numhash((st_data_t)(uint64_t)blockid->idx); // Use XOR to combine the hashes return hash0 ^ hash1; @@ -31,7 +31,7 @@ static const struct st_hash_type hashtype_blockid = { // Retrieve a basic block version for an (iseq, idx) tuple // TODO: we need to add a versioning context here -uint8_t* get_block_version(const rb_iseq_t *iseq, unsigned int idx /*, ctx_t* ctx */) +uint8_t* get_block_version(const rb_iseq_t *iseq, uint32_t idx) { blockid_t blockid = { iseq, idx }; diff --git a/ujit_core.h b/ujit_core.h index f42ff84ace..5bcbd89f3c 100644 --- a/ujit_core.h +++ b/ujit_core.h @@ -27,7 +27,7 @@ typedef struct BlockId const rb_iseq_t *iseq; // Instruction index - const unsigned int idx; + const uint32_t idx; } blockid_t; @@ -39,26 +39,31 @@ typedef struct ctx_struct // Some of the information here is only needed during // code generation, eg: current pc + // The start of the generated code + uint8_t *code_ptr; + // Instruction sequence this is associated with const rb_iseq_t *iseq; // Index in the iseq of the opcode we are replacing - size_t start_idx; + uint32_t start_idx; - // The start of the generated code - uint8_t *code_ptr; + // Index of the current instruction being compiled + uint32_t insn_idx; // Current PC VALUE *pc; // Number of values pushed on the temporary stack - int32_t stack_size; + uint32_t stack_size; // Whether we know self is a heap object bool self_is_object; } ctx_t; +uint8_t* get_block_version(const rb_iseq_t *iseq, uint32_t idx); + // Context object methods int ctx_get_opcode(ctx_t *ctx); VALUE ctx_get_arg(ctx_t* ctx, size_t arg_idx);