Add to the MicroJIT scraper an example that passes ec

This commit is contained in:
Alan Wu 2020-10-19 17:45:43 -04:00
Родитель 008551decb
Коммит 11c1daea17
6 изменённых файлов: 47 добавлений и 15 удалений

7
iseq.c
Просмотреть файл

@ -3495,6 +3495,13 @@ rb_ujit_empty_func(rb_control_frame_t *cfp)
return NULL; 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 void
rb_iseq_trace_set_all(rb_event_flag_t turnon_events) rb_iseq_trace_set_all(rb_event_flag_t turnon_events)
{ {

1
iseq.h
Просмотреть файл

@ -316,6 +316,7 @@ VALUE rb_iseq_defined_string(enum defined_type type);
VALUE rb_iseq_local_variables(const rb_iseq_t *iseq); 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(rb_control_frame_t *cfp));
NOINLINE(VALUE *rb_ujit_empty_func_with_ec(rb_control_frame_t *cfp, rb_execution_context_t *ec));
RUBY_SYMBOL_EXPORT_END RUBY_SYMBOL_EXPORT_END

Просмотреть файл

@ -128,20 +128,23 @@ module RubyVM::MicroJIT
raise "found an unrecognized \"#{unrecognized[1]}\" instruction in the example. List of recognized instructions: #{acceptable_mnemonics.join(', ')}" if unrecognized raise "found an unrecognized \"#{unrecognized[1]}\" instruction in the example. List of recognized instructions: #{acceptable_mnemonics.join(', ')}" if unrecognized
raise 'found multiple jmp instructions' if handler_instructions.count { |_, mnemonic, _| mnemonic == 'jmp' } > 1 raise 'found multiple jmp instructions' if handler_instructions.count { |_, mnemonic, _| mnemonic == 'jmp' } > 1
raise "the jmp instruction seems to be relative which isn't copiable" if instructions[jmp_idx][0].split.size > 4 raise "the jmp instruction seems to be relative which isn't copiable" if instructions[jmp_idx][0].split.size > 4
raise 'no call instructions found' if handler_instructions.count { |_, mnemonic, _| mnemonic == 'call' } == 0
raise 'found multiple call instructions' if handler_instructions.count { |_, mnemonic, _| mnemonic == 'call' } > 1 raise 'found multiple call instructions' if handler_instructions.count { |_, mnemonic, _| mnemonic == 'call' } > 1
call_idx = handler_instructions.find_index { |_, mnemonic, _| mnemonic == 'call' } call_idx = handler_instructions.find_index { |_, mnemonic, _| mnemonic == 'call' }
@pre_call_bytes = [] pre_call_bytes = []
@post_call_bytes = [] post_call_bytes = []
handler_instructions.take(call_idx).each do |bytes, mnemonic, _| handler_instructions.take(call_idx).each do |bytes, mnemonic, _|
@pre_call_bytes += bytes.split pre_call_bytes += bytes.split
end end
handler_instructions[call_idx + 1, handler_instructions.size].each do |bytes, _, _| handler_instructions[call_idx + 1, handler_instructions.size].each do |bytes, _, _|
@post_call_bytes += bytes.split post_call_bytes += bytes.split
end end
[pre_call_bytes, post_call_bytes]
end end
def darwin_scrape(instruction_id) def darwin_scrape(instruction_id)
@ -166,8 +169,19 @@ module RubyVM::MicroJIT
disassemble(handler_offset) disassemble(handler_offset)
end end
def scrape def make_result(success, pre_call, post_call, pre_call_with_ec, post_call_with_ec)
instruction_id = RubyVM::Instructions.find_index { |insn| insn.name == 'ujit_call_example' } [success ? 1 : 0,
[
['ujit_pre_call_bytes', comma_separated_hex_string(pre_call)],
['ujit_post_call_bytes', comma_separated_hex_string(post_call)],
['ujit_pre_call_with_ec_bytes', comma_separated_hex_string(pre_call_with_ec)],
['ujit_post_call_with_ec_bytes', comma_separated_hex_string(post_call_with_ec)]
]
]
end
def scrape_instruction(instruction_id)
raise unless instruction_id.is_a?(Integer)
case target_platform case target_platform
when :darwin when :darwin
darwin_scrape(instruction_id) darwin_scrape(instruction_id)
@ -176,10 +190,15 @@ module RubyVM::MicroJIT
else else
raise 'Unkonwn platform. Only Mach-O on macOS and ELF on Linux are supported' raise 'Unkonwn platform. Only Mach-O on macOS and ELF on Linux are supported'
end end
[true, comma_separated_hex_string(@pre_call_bytes), comma_separated_hex_string(@post_call_bytes)] end
def scrape
pre, post = scrape_instruction(RubyVM::Instructions.find_index { |insn| insn.name == 'ujit_call_example' })
pre_with_ec, post_with_ec = scrape_instruction(RubyVM::Instructions.find_index { |insn| insn.name == 'ujit_call_example_with_ec' })
make_result(true, pre, post, pre_with_ec, post_with_ec)
rescue => e rescue => e
print_warning("scrape failed: #{e.message}") print_warning("scrape failed: #{e.message}")
[false, '0xcc', '0xcc'] make_result(false, ['cc'], ['cc'], ['cc'], ['cc'])
end end
def print_warning(text) def print_warning(text)

Просмотреть файл

@ -13,10 +13,11 @@
class RubyVM::MicroJIT::ExampleInstructions class RubyVM::MicroJIT::ExampleInstructions
include RubyVM::CEscape include RubyVM::CEscape
attr_reader :name attr_reader :name, :call_line
def initialize name def initialize(name, call_line)
@name = name @name = name
@call_line = call_line
end end
def pretty_name def pretty_name
@ -63,7 +64,10 @@ class RubyVM::MicroJIT::ExampleInstructions
false false
end end
@all_examples = [new('ujit_call_example')] @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 def self.to_a
@all_examples @all_examples

Просмотреть файл

@ -12,7 +12,8 @@
edit: __FILE__, edit: __FILE__,
} -%> } -%>
% success, pre_call_bytes, post_call_bytes = RubyVM::MicroJIT.scrape % success, byte_arrays = RubyVM::MicroJIT.scrape
static const uint8_t ujit_scrape_successful = <%= success %>; static const uint8_t ujit_scrape_successful = <%= success %>;
static const uint8_t ujit_pre_call_bytes[] = { <%= pre_call_bytes %> }; % byte_arrays.each do |(name, bytes)|
static const uint8_t ujit_post_call_bytes[] = { <%= post_call_bytes %> }; static const uint8_t <%= name %>[] = { <%= bytes %> };
% end

Просмотреть файл

@ -32,7 +32,7 @@ INSN_ENTRY(<%= insn.name %>)
#if USE_MACHINE_REGS #if USE_MACHINE_REGS
// assumes USE_MACHINE_REGS, aka reg_pc setup, // assumes USE_MACHINE_REGS, aka reg_pc setup,
// aka #define SET_PC(x) (reg_cfp->pc = reg_pc = (x)) // aka #define SET_PC(x) (reg_cfp->pc = reg_pc = (x))
reg_pc = rb_ujit_empty_func(GET_CFP()); <%= insn.call_line %>
#endif #endif
END_INSN(<%= insn.name %>); END_INSN(<%= insn.name %>);
} }