Fixed two bugs in JIT-to-JIT calls (thanks Alan!)

This commit is contained in:
Maxime Chevalier-Boisvert 2021-02-05 12:18:55 -05:00 committed by Alan Wu
parent 0f53c216d2
commit 8357e8e514
2 changed files with 82 additions and 16 deletions

View File

@ -27,4 +27,50 @@ assert_equal '1', %q{
end
retval
}
}
# 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
}

View File

@ -62,6 +62,9 @@ ujit_gen_exit(jitstate_t* jit, ctx_t* ctx, codeblock_t* cb, VALUE* exit_pc)
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
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
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
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)
// 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)
// 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);