ZJIT: Disable ZJIT instructions when USE_ZJIT is 0 (#13199)

* ZJIT: Disable ZJIT instructions when USE_ZJIT is 0

* Test the order of ZJIT instructions

* Add more jobs that disable JITs

* Show instruction names in the message
This commit is contained in:
Takashi Kokubun 2025-04-29 11:03:13 -07:00 committed by GitHub
parent 0c44e5ab5e
commit 0f3d6ee578
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
Notes: git 2025-04-29 18:03:32 +00:00
Merged-By: k0kubun <takashikkbn@gmail.com>
12 changed files with 118 additions and 47 deletions

View File

@ -193,7 +193,9 @@ jobs:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
- { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
- { uses: './.github/actions/compilers', name: 'disable-jit', with: { append_configure: '--disable-yjit' } }
- { uses: './.github/actions/compilers', name: 'disable-jit', with: { append_configure: '--disable-yjit --disable-zjit' } }
- { uses: './.github/actions/compilers', name: 'disable-yjit', with: { append_configure: '--disable-yjit' } }
- { uses: './.github/actions/compilers', name: 'disable-zjit', with: { append_configure: '--disable-zjit' } }
- { uses: './.github/actions/compilers', name: 'disable-dln', with: { append_configure: '--disable-dln' } }
- { uses: './.github/actions/compilers', name: 'enable-mkmf-verbose', with: { append_configure: '--enable-mkmf-verbose' } }
- { uses: './.github/actions/compilers', name: 'disable-rubygems', with: { append_configure: '--disable-rubygems' } }

View File

@ -479,6 +479,19 @@ class TestZJIT < Test::Unit::TestCase
}, call_threshold: 5, num_profiles: 3
end
# tool/ruby_vm/views/*.erb relies on the zjit instructions a) being contiguous and
# b) being reliably ordered after all the other instructions.
def test_instruction_order
insn_names = RubyVM::INSTRUCTION_NAMES
zjit, others = insn_names.map.with_index.partition { |name, _| name.start_with?('zjit_') }
zjit_indexes = zjit.map(&:last)
other_indexes = others.map(&:last)
zjit_indexes.product(other_indexes).each do |zjit_index, other_index|
assert zjit_index > other_index, "'#{insn_names[zjit_index]}' at #{zjit_index} "\
"must be defined after '#{insn_names[other_index]}' at #{other_index}"
end
end
private
# Assert that every method call in `test_script` can be compiled by ZJIT

View File

@ -6,6 +6,16 @@
%# conditions mentioned in the file COPYING are met. Consult the file for
%# details.
%#
%
% stack_increase = proc do |i|
% if i.has_attribute?('sp_inc')
% '-127'
% else
% sprintf("%4d", i.rets.size - i.pops.size)
% end
% end
% zjit_insns, insns = RubyVM::Instructions.partition { |i| i.name.start_with?('zjit_') }
%
PUREFUNC(MAYBE_UNUSED(static int comptime_insn_stack_increase(int depth, int insn, const VALUE *opes)));
PUREFUNC(static rb_snum_t comptime_insn_stack_increase_dispatch(enum ruby_vminsn_type insn, const VALUE *opes));
@ -13,15 +23,14 @@ rb_snum_t
comptime_insn_stack_increase_dispatch(enum ruby_vminsn_type insn, const VALUE *opes)
{
static const signed char t[] = {
% RubyVM::Instructions.each_slice 8 do |a|
<%= a.map { |i|
if i.has_attribute?('sp_inc')
'-127'
else
sprintf("%4d", i.rets.size - i.pops.size)
end
}.join(', ') -%>,
% insns.each_slice(8) do |row|
<%= row.map(&stack_increase).join(', ') -%>,
% end
#if USE_ZJIT
% zjit_insns.each_slice(8) do |row|
<%= row.map(&stack_increase).join(', ') -%>,
% end
#endif
};
signed char c = t[insn];

View File

@ -5,6 +5,9 @@
%# granted, to either redistribute and/or modify this file, provided that the
%# conditions mentioned in the file COPYING are met. Consult the file for
%# details.
%
% zjit_insns, insns = RubyVM::Instructions.partition { |i| i.name.start_with?('zjit_') }
%
CONSTFUNC(MAYBE_UNUSED(static int insn_len(VALUE insn)));
RUBY_SYMBOL_EXPORT_BEGIN /* for debuggers */
@ -13,9 +16,14 @@ RUBY_SYMBOL_EXPORT_END
#ifdef RUBY_VM_INSNS_INFO
const uint8_t rb_vm_insn_len_info[] = {
% RubyVM::Instructions.each_slice 23 do |a|
<%= a.map(&:width).join(', ') -%>,
% insns.each_slice(23) do |row|
<%= row.map(&:width).join(', ') -%>,
% end
#if USE_ZJIT
% zjit_insns.each_slice(23) do |row|
<%= row.map(&:width).join(', ') -%>,
% end
#endif
};
ASSERT_VM_INSTRUCTION_SIZE(rb_vm_insn_len_info);

View File

@ -6,10 +6,14 @@
%# conditions mentioned in the file COPYING are met. Consult the file for
%# details.
%
% a = RubyVM::Instructions.map {|i| i.name }
% b = (0...a.size)
% c = a.inject([0]) {|r, i| r << (r[-1] + i.length + 1) }
% c.pop
% zjit_insns, insns = RubyVM::Instructions.partition { |i| i.name.start_with?('zjit_') }
%
% next_offset = 0
% name_offset = proc do |i|
% offset = sprintf("%4d", next_offset)
% next_offset += i.name.length + 1 # insn.name + \0
% offset
% end
%
CONSTFUNC(MAYBE_UNUSED(static const char *insn_name(VALUE insn)));
@ -20,18 +24,28 @@ extern const unsigned short rb_vm_insn_name_offset[VM_INSTRUCTION_SIZE];
RUBY_SYMBOL_EXPORT_END
#ifdef RUBY_VM_INSNS_INFO
const int rb_vm_max_insn_name_size = <%= a.map(&:size).max %>;
const int rb_vm_max_insn_name_size = <%= RubyVM::Instructions.map { |i| i.name.size }.max %>;
const char rb_vm_insn_name_base[] =
% a.each do |i|
<%=cstr i%> "\0"
% insns.each do |i|
<%= cstr i.name %> "\0"
% end
#if USE_ZJIT
% zjit_insns.each do |i|
<%= cstr i.name %> "\0"
% end
#endif
;
const unsigned short rb_vm_insn_name_offset[] = {
% c.each_slice 12 do |d|
<%= d.map {|i| sprintf("%4d", i) }.join(', ') %>,
% insns.each_slice(12) do |row|
<%= row.map(&name_offset).join(', ') %>,
% end
#if USE_ZJIT
% zjit_insns.each_slice(12) do |row|
<%= row.map(&name_offset).join(', ') %>,
% end
#endif
};
ASSERT_VM_INSTRUCTION_SIZE(rb_vm_insn_name_offset);

View File

@ -6,10 +6,16 @@
%# conditions mentioned in the file COPYING are met. Consult the file for
%# details.
%
% a = RubyVM::Instructions.map {|i| i.operands_info }
% b = (0...a.size)
% c = a.inject([0]) {|r, i| r << (r[-1] + i.length + 1) }
% c.pop
% zjit_insns, insns = RubyVM::Instructions.partition { |i| i.name.start_with?('zjit_') }
%
% operands_info = proc { |i| sprintf("%-6s", cstr(i.operands_info)) }
%
% next_offset = 0
% op_offset = proc do |i|
% offset = sprintf("%3d", next_offset)
% next_offset += i.operands_info.length + 1 # insn.operands_info + \0
% offset
% end
%
CONSTFUNC(MAYBE_UNUSED(static const char *insn_op_types(VALUE insn)));
CONSTFUNC(MAYBE_UNUSED(static int insn_op_type(VALUE insn, long pos)));
@ -21,15 +27,25 @@ RUBY_SYMBOL_EXPORT_END
#ifdef RUBY_VM_INSNS_INFO
const char rb_vm_insn_op_base[] =
% a.each_slice 5 do |d|
<%= d.map {|i| sprintf("%-6s", cstr(i)) }.join(' "\0" ') %> "\0"
% insns.each_slice(5) do |row|
<%= row.map(&operands_info).join(' "\0" ') %> "\0"
% end
#if USE_ZJIT
% zjit_insns.each_slice(5) do |row|
<%= row.map(&operands_info).join(' "\0" ') %> "\0"
% end
#endif
;
const unsigned short rb_vm_insn_op_offset[] = {
% c.each_slice 12 do |d|
<%= d.map {|i| sprintf("%3d", i) }.join(', ') %>,
% insns.each_slice(12) do |row|
<%= row.map(&op_offset).join(', ') %>,
% end
#if USE_ZJIT
% zjit_insns.each_slice(12) do |row|
<%= row.map(&op_offset).join(', ') %>,
% end
#endif
};
ASSERT_VM_INSTRUCTION_SIZE(rb_vm_insn_op_offset);

View File

@ -1,3 +1,5 @@
#if USE_ZJIT
MAYBE_UNUSED(static int vm_bare_insn_to_zjit_insn(int insn));
static int
vm_bare_insn_to_zjit_insn(int insn)
@ -25,3 +27,5 @@ vm_zjit_insn_to_bare_insn(int insn)
return insn;
}
}
#endif

View File

@ -1,3 +1,5 @@
#if USE_ZJIT
/* insn <%= insn.pretty_name %> */
INSN_ENTRY(<%= insn.name %>)
{
@ -6,3 +8,5 @@ INSN_ENTRY(<%= insn.name %>)
DISPATCH_ORIGINAL_INSN(<%= insn.jump_destination %>);
END_INSN(<%= insn.name %>);
}
#endif

View File

@ -6,6 +6,9 @@
%# granted, to either redistribute and/or modify this file, provided that the
%# conditions mentioned in the file COPYING are met. Consult the file for
%# details.
%
% zjit_insns, insns = RubyVM::Instructions.partition { |i| i.name.start_with?('zjit_') }
%
<%= render 'copyright' %>
<%= render 'notice', locals: {
this_file: 'contains YARV instruction list',
@ -19,9 +22,14 @@
#define BIN(n) YARVINSN_##n
enum ruby_vminsn_type {
% RubyVM::Instructions.each do |i|
% insns.each do |i|
<%= i.bin %>,
% end
#if USE_ZJIT
% zjit_insns.each do |i|
<%= i.bin %>,
% end
#endif
VM_INSTRUCTION_SIZE
};

View File

@ -7,7 +7,6 @@
%# conditions mentioned in the file COPYING are met. Consult the file for
%# details.
% raise ':FIXME:TBW' if RubyVM::VmOptsH['INSTRUCTIONS_UNIFICATION']
% n = RubyVM::Instructions.size
<%= render 'copyright' %>
<%= render 'notice', locals: {
this_file: 'is for threaded code',
@ -16,6 +15,4 @@
/* Let .bss section automatically initialize this variable */
/* cf. Section 6.7.8 of ISO/IEC 9899:1999 */
static const int *const *const unified_insns_data[<%= n %>];
ASSERT_VM_INSTRUCTION_SIZE(unified_insns_data);
static const int *const *const unified_insns_data[VM_INSTRUCTION_SIZE];

View File

@ -6,6 +6,9 @@
%# granted, to either redistribute and/or modify this file, provided that the
%# conditions mentioned in the file COPYING are met. Consult the file for
%# details.
%
% zjit_insns, insns = RubyVM::Instructions.partition { |i| i.name.start_with?('zjit_') }
%
<%= render 'copyright' -%>
<%= render 'notice', locals: {
this_file: 'is for threaded code',
@ -13,9 +16,14 @@
} -%>
static const void *const insns_address_table[] = {
% RubyVM::Instructions.each do |i|
% insns.each do |i|
LABEL_PTR(<%= i.name %>),
% end
#if USE_ZJIT
% zjit_insns.each do |i|
LABEL_PTR(<%= i.name %>),
% end
#endif
};
ASSERT_VM_INSTRUCTION_SIZE(insns_address_table);

View File

@ -949,19 +949,7 @@ pub const YARVINSN_trace_setlocal_WC_0: ruby_vminsn_type = 218;
pub const YARVINSN_trace_setlocal_WC_1: ruby_vminsn_type = 219;
pub const YARVINSN_trace_putobject_INT2FIX_0_: ruby_vminsn_type = 220;
pub const YARVINSN_trace_putobject_INT2FIX_1_: ruby_vminsn_type = 221;
pub const YARVINSN_zjit_opt_send_without_block: ruby_vminsn_type = 222;
pub const YARVINSN_zjit_opt_plus: ruby_vminsn_type = 223;
pub const YARVINSN_zjit_opt_minus: ruby_vminsn_type = 224;
pub const YARVINSN_zjit_opt_mult: ruby_vminsn_type = 225;
pub const YARVINSN_zjit_opt_div: ruby_vminsn_type = 226;
pub const YARVINSN_zjit_opt_mod: ruby_vminsn_type = 227;
pub const YARVINSN_zjit_opt_eq: ruby_vminsn_type = 228;
pub const YARVINSN_zjit_opt_neq: ruby_vminsn_type = 229;
pub const YARVINSN_zjit_opt_lt: ruby_vminsn_type = 230;
pub const YARVINSN_zjit_opt_le: ruby_vminsn_type = 231;
pub const YARVINSN_zjit_opt_gt: ruby_vminsn_type = 232;
pub const YARVINSN_zjit_opt_ge: ruby_vminsn_type = 233;
pub const VM_INSTRUCTION_SIZE: ruby_vminsn_type = 234;
pub const VM_INSTRUCTION_SIZE: ruby_vminsn_type = 222;
pub type ruby_vminsn_type = u32;
pub type rb_iseq_callback = ::std::option::Option<
unsafe extern "C" fn(arg1: *const rb_iseq_t, arg2: *mut ::std::os::raw::c_void),