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

Restore interpreter regs in ujit hook. Implement leave bytecode.

This commit is contained in:
Maxime Chevalier-Boisvert 2021-01-28 16:58:20 -05:00 committed by Alan Wu
parent 3c7251b41b
commit 2e561ff255
7 changed files with 59 additions and 35 deletions

13
iseq.c
View file

@ -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

4
iseq.h
View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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
%

View file

@ -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);
}

View file

@ -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)