diff options
-rw-r--r-- | iseq.c | 13 | ||||
-rw-r--r-- | iseq.h | 4 | ||||
-rw-r--r-- | tool/ruby_vm/models/micro_jit.rb | 10 | ||||
-rw-r--r-- | tool/ruby_vm/models/micro_jit/example_instructions.rb | 12 | ||||
-rw-r--r-- | tool/ruby_vm/views/vm.inc.erb | 9 | ||||
-rw-r--r-- | ujit_codegen.c | 44 | ||||
-rw-r--r-- | vm_exec.h | 2 |
7 files changed, 59 insertions, 35 deletions
@@ -3485,21 +3485,12 @@ trace_set_i(void *vstart, void *vend, size_t stride, void *data) return 0; } -VALUE * -rb_ujit_empty_func(rb_control_frame_t *cfp) +void +rb_ujit_empty_func_with_ec(rb_control_frame_t *cfp, rb_execution_context_t *ec) { - // okay, not really empty, so maybe think of another name. // it's put in this file instead of say, compile.c to dodge long C compile time. // it just needs to be in a different unit from vm.o so the compiler can't see the definition // and is forced to emit a call that respects the calling convention. - return NULL; -} - -VALUE * -rb_ujit_empty_func_with_ec(rb_control_frame_t *cfp, rb_execution_context_t *ec) -{ - // see rb_ujit_empty_func - return NULL; } void @@ -315,9 +315,7 @@ VALUE rb_iseq_defined_string(enum defined_type type); /* vm.c */ VALUE rb_iseq_local_variables(const rb_iseq_t *iseq); -NOINLINE(VALUE *rb_ujit_empty_func(rb_control_frame_t *cfp)); -NOINLINE(VALUE *rb_ujit_empty_func_with_ec(rb_control_frame_t *cfp, rb_execution_context_t *ec)); - +NOINLINE(void rb_ujit_empty_func_with_ec(rb_control_frame_t *cfp, rb_execution_context_t *ec)); RUBY_SYMBOL_EXPORT_END diff --git a/tool/ruby_vm/models/micro_jit.rb b/tool/ruby_vm/models/micro_jit.rb index 9bbce73150..5e376ebb3a 100644 --- a/tool/ruby_vm/models/micro_jit.rb +++ b/tool/ruby_vm/models/micro_jit.rb @@ -176,10 +176,9 @@ module RubyVM::MicroJIT disassemble(handler_offset) end - def make_result(success, without_pc, with_pc) + def make_result(success, with_pc) [success ? 1 : 0, [ - ['ujit_without_ec', without_pc], ['ujit_with_ec', with_pc], ] ] @@ -193,19 +192,18 @@ module RubyVM::MicroJIT when :linux linux_scrape(instruction_id) else - raise 'Unkonwn platform. Only Mach-O on macOS and ELF on Linux are supported' + raise 'Unknown platform. Only Mach-O on macOS and ELF on Linux are supported' end end def scrape - without_ec = scrape_instruction(RubyVM::Instructions.find_index { |insn| insn.name == 'ujit_call_example' }) with_ec = scrape_instruction(RubyVM::Instructions.find_index { |insn| insn.name == 'ujit_call_example_with_ec' }) - make_result(true, without_ec, with_ec) + make_result(true, with_ec) rescue => e print_warning("scrape failed: #{e.message}") int3 = '0xcc' failure_result = ScrapeResult.new(int3, int3, ['int3']) - make_result(false, failure_result, failure_result) + make_result(false, failure_result) end def print_warning(text) diff --git a/tool/ruby_vm/models/micro_jit/example_instructions.rb b/tool/ruby_vm/models/micro_jit/example_instructions.rb index 111346f6e9..23ecf72a3b 100644 --- a/tool/ruby_vm/models/micro_jit/example_instructions.rb +++ b/tool/ruby_vm/models/micro_jit/example_instructions.rb @@ -13,11 +13,10 @@ class RubyVM::MicroJIT::ExampleInstructions include RubyVM::CEscape - attr_reader :name, :call_line + attr_reader :name - def initialize(name, call_line) + def initialize(name) @name = name - @call_line = call_line end def pretty_name @@ -64,12 +63,7 @@ class RubyVM::MicroJIT::ExampleInstructions false end - @all_examples = [ - new('ujit_call_example', 'reg_pc = rb_ujit_empty_func(GET_CFP());'), - new('ujit_call_example_with_ec', 'reg_pc = rb_ujit_empty_func_with_ec(GET_CFP(), ec);') - ] - def self.to_a - @all_examples + [new('ujit_call_example_with_ec')] end end diff --git a/tool/ruby_vm/views/vm.inc.erb b/tool/ruby_vm/views/vm.inc.erb index 235eb30b11..57a860efcf 100644 --- a/tool/ruby_vm/views/vm.inc.erb +++ b/tool/ruby_vm/views/vm.inc.erb @@ -26,15 +26,16 @@ % end % % RubyVM::MicroJIT::ExampleInstructions.to_a.each do |insn| -INSN_ENTRY(<%= insn.name %>) +INSN_ENTRY(ujit_call_example_with_ec) { - START_OF_ORIGINAL_INSN(<%= insn.name %>); + START_OF_ORIGINAL_INSN(ujit_call_example_with_ec); #if USE_MACHINE_REGS // assumes USE_MACHINE_REGS, aka reg_pc setup, // aka #define SET_PC(x) (reg_cfp->pc = reg_pc = (x)) - <%= insn.call_line %> + rb_ujit_empty_func_with_ec(GET_CFP(), ec); + RESTORE_REGS(); #endif - END_INSN(<%= insn.name %>); + END_INSN(ujit_call_example_with_ec); } % end % diff --git a/ujit_codegen.c b/ujit_codegen.c index 43da3e6473..7c7457aea3 100644 --- a/ujit_codegen.c +++ b/ujit_codegen.c @@ -371,7 +371,7 @@ gen_setlocal_wc0(jitstate_t* jit, ctx_t* ctx) mov(cb, REG0, member_opnd(REG_CFP, rb_control_frame_t, ep)); // flags & VM_ENV_FLAG_WB_REQUIRED - x86opnd_t flags_opnd = mem_opnd(64, REG0, 8 * VM_ENV_DATA_INDEX_FLAGS); + x86opnd_t flags_opnd = mem_opnd(64, REG0, sizeof(VALUE) * VM_ENV_DATA_INDEX_FLAGS); test(cb, flags_opnd, imm_opnd(VM_ENV_FLAG_WB_REQUIRED)); // Create a size-exit to fall back to the interpreter @@ -1062,6 +1062,47 @@ gen_opt_send_without_block(jitstate_t* jit, ctx_t* ctx) return true; } +static bool +gen_leave(jitstate_t* jit, ctx_t* ctx) +{ + // Only the return value should be on the stack + RUBY_ASSERT(ctx->stack_size == 1); + + // Create a size-exit to fall back to the interpreter + uint8_t* side_exit = ujit_side_exit(jit, ctx); + + // Load environment pointer EP from CFP + mov(cb, REG0, member_opnd(REG_CFP, rb_control_frame_t, ep)); + + // flags & VM_FRAME_FLAG_FINISH + x86opnd_t flags_opnd = mem_opnd(64, REG0, sizeof(VALUE) * VM_ENV_DATA_INDEX_FLAGS); + test(cb, flags_opnd, imm_opnd(VM_FRAME_FLAG_FINISH)); + + // if (flags & VM_FRAME_FLAG_FINISH) != 0 + jnz_ptr(cb, side_exit); + + // TODO: + // RUBY_VM_CHECK_INTS(ec); + + // Load the return value + mov(cb, REG0, ctx_stack_pop(ctx, 1)); + + // Pop the current CFP (ec->cfp++) + // Note: the return PC is already in the previous CFP + add(cb, REG_CFP, imm_opnd(sizeof(rb_control_frame_t))); + mov(cb, member_opnd(REG_EC, rb_execution_context_t, cfp), REG_CFP); + + // Push the return value on the caller frame + mov(cb, REG1, member_opnd(REG_CFP, rb_control_frame_t, sp)); + mov(cb, mem_opnd(64, REG1, 0), REG0); + add(cb, member_opnd(REG_CFP, rb_control_frame_t, sp), imm_opnd(SIZEOF_VALUE)); + + // Write the post call bytes + cb_write_post_call_bytes(cb); + + return true; +} + void ujit_reg_op(int opcode, codegen_fn gen_fn, bool is_branch) { // Check that the op wasn't previously registered @@ -1111,4 +1152,5 @@ ujit_init_codegen(void) ujit_reg_op(BIN(branchunless), gen_branchunless, true); ujit_reg_op(BIN(jump), gen_jump, true); ujit_reg_op(BIN(opt_send_without_block), gen_opt_send_without_block, true); + ujit_reg_op(BIN(leave), gen_leave, true); } @@ -81,7 +81,7 @@ error ! RSTRING_PTR(rb_iseq_path(reg_cfp->iseq)), \ rb_iseq_line_no(reg_cfp->iseq, reg_pc - reg_cfp->iseq->body->iseq_encoded)); \ } \ - if (USE_INSNS_COUNTER && BIN(insn) != BIN(ujit_call_example)) vm_insns_counter_count_insn(BIN(insn)); + if (USE_INSNS_COUNTER && BIN(insn) != BIN(ujit_call_example_with_ec)) vm_insns_counter_count_insn(BIN(insn)); #define INSN_DISPATCH_SIG(insn) |