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:
parent
3c7251b41b
commit
2e561ff255
7 changed files with 59 additions and 35 deletions
13
iseq.c
13
iseq.c
|
@ -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
4
iseq.h
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
%
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue