ruby-changes:68755
From: Maxime <ko1@a...>
Date: Thu, 21 Oct 2021 08:13:26 +0900 (JST)
Subject: [ruby-changes:68755] 8357e8e514 (master): Fixed two bugs in JIT-to-JIT calls (thanks Alan!)
https://git.ruby-lang.org/ruby.git/commit/?id=8357e8e514 From 8357e8e5142b97c452929aade0c24f59c7a34833 Mon Sep 17 00:00:00 2001 From: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@s...> Date: Fri, 5 Feb 2021 12:18:55 -0500 Subject: Fixed two bugs in JIT-to-JIT calls (thanks Alan!) --- bootstraptest/test_ujit.rb | 48 +++++++++++++++++++++++++++++++++++++++++++- ujit_codegen.c | 50 ++++++++++++++++++++++++++++++++-------------- 2 files changed, 82 insertions(+), 16 deletions(-) diff --git a/bootstraptest/test_ujit.rb b/bootstraptest/test_ujit.rb index 9d26aec347..dda9e89559 100644 --- a/bootstraptest/test_ujit.rb +++ b/bootstraptest/test_ujit.rb @@ -27,4 +27,50 @@ assert_equal '1', %q{ https://github.com/ruby/ruby/blob/trunk/bootstraptest/test_ujit.rb#L27 end retval -} \ No newline at end of file +} + +# foo leaves a temp on the stack before the call +assert_equal '6', %q{ + def bar + return 5 + end + + def foo + return 1 + bar + end + + foo() + retval = foo() +} + +# Ruby-to-Ruby call and C call +assert_normal_exit %q{ + def bar + puts('hi!') + end + + def foo + bar + end + + foo() + foo() +} + +# Test for GC safety. Don't invalidate dead iseqs. +assert_normal_exit %q{ + Class.new do + def foo + itself + end + + new.foo + UJIT.install_entry(RubyVM::InstructionSequence.of(instance_method(:foo))) + new.foo + end + + 4.times { GC.start } + def itself + self + end +} diff --git a/ujit_codegen.c b/ujit_codegen.c index 30d38b5d77..bb5c336d6d 100644 --- a/ujit_codegen.c +++ b/ujit_codegen.c @@ -62,6 +62,9 @@ ujit_gen_exit(jitstate_t* jit, ctx_t* ctx, codeblock_t* cb, VALUE* exit_pc) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L62 mov(cb, member_opnd(REG_CFP, rb_control_frame_t, sp), REG_SP); } + // Update the CFP on the EC + mov(cb, member_opnd(REG_EC, rb_execution_context_t, cfp), REG_CFP); + // Directly return the next PC, which is a constant mov(cb, RAX, const_ptr_opnd(exit_pc)); mov(cb, member_opnd(REG_CFP, rb_control_frame_t, pc), RAX); @@ -1250,7 +1253,7 @@ gen_opt_swb_iseq(jitstate_t* jit, ctx_t* ctx, struct rb_call_data * cd, const rb https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L1253 mov(cb, REG0, const_ptr_opnd(jit->pc + insn_len(BIN(opt_send_without_block)))); mov(cb, mem_opnd(64, REG_CFP, offsetof(rb_control_frame_t, pc)), REG0); - // Store the updated SP on the CFP (pop arguments and self) + // Store the updated SP on the CFP (pop arguments and receiver) lea(cb, REG0, ctx_sp_opnd(ctx, sizeof(VALUE) * -(argc + 1))); mov(cb, member_opnd(REG_CFP, rb_control_frame_t, sp), REG0); @@ -1285,11 +1288,8 @@ gen_opt_swb_iseq(jitstate_t* jit, ctx_t* ctx, struct rb_call_data * cd, const rb https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L1288 mov(cb, mem_opnd(64, REG0, 8 * -1), imm_opnd(frame_type)); // Allocate a new CFP (ec->cfp--) - sub( - cb, - member_opnd(REG_EC, rb_execution_context_t, cfp), - imm_opnd(sizeof(rb_control_frame_t)) - ); + sub(cb, REG_CFP, imm_opnd(sizeof(rb_control_frame_t))); + mov(cb, member_opnd(REG_EC, rb_execution_context_t, cfp), REG_CFP); // Setup the new frame // *cfp = (const struct rb_control_frame_struct) { @@ -1315,10 +1315,31 @@ gen_opt_swb_iseq(jitstate_t* jit, ctx_t* ctx, struct rb_call_data * cd, const rb https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L1315 mov(cb, member_opnd(REG1, rb_control_frame_t, pc), REG0); //print_str(cb, "calling Ruby func:"); - //print_str(cb, rb_id2name(mid)); + //print_str(cb, rb_id2name(vm_ci_mid(cd->ci))); + + // Load the updated SP + mov(cb, REG_SP, member_opnd(REG_CFP, rb_control_frame_t, sp)); + + // Directly jump to the entry point of the callee + gen_direct_jump( + &DEFAULT_CTX, + (blockid_t){ iseq, 0 } + ); + + + + // TODO: create stub for call continuation + + // TODO: need to pop args in the caller ctx + + // TODO: stub so we can return to JITted code + //blockid_t cont_block = { jit->iseq, jit_next_insn_idx(jit) }; + + + + + - // Write the post call bytes, exit to the interpreter - cb_write_post_call_bytes(cb); return true; } @@ -1387,11 +1408,9 @@ gen_leave(jitstate_t* jit, ctx_t* ctx) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L1408 // Load environment pointer EP from CFP mov(cb, REG0, member_opnd(REG_CFP, rb_control_frame_t, ep)); - // flags & VM_FRAME_FLAG_FINISH + // if (flags & VM_FRAME_FLAG_FINISH) != 0 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: @@ -1400,15 +1419,16 @@ gen_leave(jitstate_t* jit, ctx_t* ctx) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L1419 // Load the return value mov(cb, REG0, ctx_stack_pop(ctx, 1)); - // Pop the current CFP (ec->cfp++) + // Pop the current frame (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); + // The SP points one above the topmost value add(cb, member_opnd(REG_CFP, rb_control_frame_t, sp), imm_opnd(SIZEOF_VALUE)); + mov(cb, REG_SP, member_opnd(REG_CFP, rb_control_frame_t, sp)); + mov(cb, mem_opnd(64, REG_SP, -SIZEOF_VALUE), REG0); // Write the post call bytes cb_write_post_call_bytes(cb); -- cgit v1.2.1 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/