зеркало из https://github.com/github/ruby.git
merge revision(s) 015b0e2e1d312e2be60551587389c8da5c585e6f,ac1e9e443a0d6a4d4c0801c26d1d8bd33d9eb431: [Backport #20195]
YJIT: Fix unused warnings
```
warning: unused import: `condition::Condition`
--> src/asm/arm64/arg/mod.rs:13:9
|
13 | pub use condition::Condition;
| ^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(unused_imports)]` on by default
warning: unused import: `rb_yjit_fix_mul_fix as rb_fix_mul_fix`
--> src/cruby.rs:188:9
|
188 | pub use rb_yjit_fix_mul_fix as rb_fix_mul_fix;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused import: `rb_insn_len as raw_insn_len`
--> src/cruby.rs:142:9
|
142 | pub use rb_insn_len as raw_insn_len;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(unused_imports)]` on by default
```
Make asm public so it stops warning about unused public stuff in there.
YJIT: Fix ruby2_keywords splat+rest and drop bogus checks
YJIT didn't guard for ruby2_keywords hash in case of splat calls that
land in methods with a rest parameter, creating incorrect results.
The compile-time checks didn't correspond to any actual effects of
ruby2_keywords, so it was masking this bug and YJIT was needlessly
refusing to compile some code. About 16% of fallback reasons in
`lobsters` was due to the ISeq check.
We already handle the tagging part with
exit_if_supplying_kw_and_has_no_kw() and should now have a dynamic guard
for all splat cases.
Note for backporting: You also need 7f51959ff1
.
[Bug #20195]
This commit is contained in:
Родитель
d7ad603739
Коммит
6383d0afac
|
@ -4423,3 +4423,34 @@ assert_equal '0', %q{
|
||||||
|
|
||||||
entry
|
entry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Integer succ and overflow
|
||||||
|
assert_equal '[2, 4611686018427387904]', %q{
|
||||||
|
[1.succ, 4611686018427387903.succ]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Integer right shift
|
||||||
|
assert_equal '[0, 1, -4]', %q{
|
||||||
|
[0 >> 1, 2 >> 1, -7 >> 1]
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal '[nil, "yield"]', %q{
|
||||||
|
def defined_yield = defined?(yield)
|
||||||
|
[defined_yield, defined_yield {}]
|
||||||
|
}
|
||||||
|
|
||||||
|
# splat with ruby2_keywords into rest parameter
|
||||||
|
assert_equal '[[{:a=>1}], {}]', %q{
|
||||||
|
ruby2_keywords def foo(*args) = args
|
||||||
|
|
||||||
|
def bar(*args, **kw) = [args, kw]
|
||||||
|
|
||||||
|
def pass_bar(*args) = bar(*args)
|
||||||
|
|
||||||
|
def body
|
||||||
|
args = foo(a: 1)
|
||||||
|
pass_bar(*args)
|
||||||
|
end
|
||||||
|
|
||||||
|
body
|
||||||
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
# define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
|
# define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
|
||||||
#define RUBY_VERSION_TEENY 1
|
#define RUBY_VERSION_TEENY 1
|
||||||
#define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
|
#define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
|
||||||
#define RUBY_PATCHLEVEL 58
|
#define RUBY_PATCHLEVEL 59
|
||||||
|
|
||||||
#include "ruby/version.h"
|
#include "ruby/version.h"
|
||||||
#include "ruby/internal/abi.h"
|
#include "ruby/internal/abi.h"
|
||||||
|
|
13
yjit.c
13
yjit.c
|
@ -871,10 +871,17 @@ rb_yjit_fix_mod_fix(VALUE recv, VALUE obj)
|
||||||
return rb_fix_mod_fix(recv, obj);
|
return rb_fix_mod_fix(recv, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE
|
// Return non-zero when `obj` is an array and its last item is a
|
||||||
rb_yjit_fix_mul_fix(VALUE recv, VALUE obj)
|
// `ruby2_keywords` hash. We don't support this kind of splat.
|
||||||
|
size_t
|
||||||
|
rb_yjit_ruby2_keywords_splat_p(VALUE obj)
|
||||||
{
|
{
|
||||||
return rb_fix_mul_fix(recv, obj);
|
if (!RB_TYPE_P(obj, T_ARRAY)) return 0;
|
||||||
|
long len = RARRAY_LEN(obj);
|
||||||
|
if (len == 0) return 0;
|
||||||
|
VALUE last = RARRAY_AREF(obj, len - 1);
|
||||||
|
if (!RB_TYPE_P(last, T_HASH)) return 0;
|
||||||
|
return FL_TEST_RAW(last, RHASH_PASS_AS_KEYWORDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print the Ruby source location of some ISEQ for debugging purposes
|
// Print the Ruby source location of some ISEQ for debugging purposes
|
||||||
|
|
|
@ -426,9 +426,9 @@ fn main() {
|
||||||
.allowlist_function("rb_yarv_str_eql_internal")
|
.allowlist_function("rb_yarv_str_eql_internal")
|
||||||
.allowlist_function("rb_str_neq_internal")
|
.allowlist_function("rb_str_neq_internal")
|
||||||
.allowlist_function("rb_yarv_ary_entry_internal")
|
.allowlist_function("rb_yarv_ary_entry_internal")
|
||||||
|
.allowlist_function("rb_yjit_ruby2_keywords_splat_p")
|
||||||
.allowlist_function("rb_yjit_fix_div_fix")
|
.allowlist_function("rb_yjit_fix_div_fix")
|
||||||
.allowlist_function("rb_yjit_fix_mod_fix")
|
.allowlist_function("rb_yjit_fix_mod_fix")
|
||||||
.allowlist_function("rb_yjit_fix_mul_fix")
|
|
||||||
.allowlist_function("rb_FL_TEST")
|
.allowlist_function("rb_FL_TEST")
|
||||||
.allowlist_function("rb_FL_TEST_RAW")
|
.allowlist_function("rb_FL_TEST_RAW")
|
||||||
.allowlist_function("rb_RB_TYPE_P")
|
.allowlist_function("rb_RB_TYPE_P")
|
||||||
|
|
|
@ -5413,18 +5413,6 @@ fn gen_send_cfunc(
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// In order to handle backwards compatibility between ruby 3 and 2
|
|
||||||
// ruby2_keywords was introduced. It is called only on methods
|
|
||||||
// with splat and changes they way they handle them.
|
|
||||||
// We are just going to not compile these.
|
|
||||||
// https://docs.ruby-lang.org/en/3.2/Module.html#method-i-ruby2_keywords
|
|
||||||
if unsafe {
|
|
||||||
get_iseq_flags_ruby2_keywords(jit.iseq) && flags & VM_CALL_ARGS_SPLAT != 0
|
|
||||||
} {
|
|
||||||
gen_counter_incr(asm, Counter::send_args_splat_cfunc_ruby2_keywords);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let kw_arg = unsafe { vm_ci_kwarg(ci) };
|
let kw_arg = unsafe { vm_ci_kwarg(ci) };
|
||||||
let kw_arg_num = if kw_arg.is_null() {
|
let kw_arg_num = if kw_arg.is_null() {
|
||||||
0
|
0
|
||||||
|
@ -6004,7 +5992,6 @@ fn gen_send_iseq(
|
||||||
exit_if_has_post(asm, iseq)?;
|
exit_if_has_post(asm, iseq)?;
|
||||||
exit_if_has_kwrest(asm, iseq)?;
|
exit_if_has_kwrest(asm, iseq)?;
|
||||||
exit_if_kw_splat(asm, flags)?;
|
exit_if_kw_splat(asm, flags)?;
|
||||||
exit_if_splat_and_ruby2_keywords(asm, jit, flags)?;
|
|
||||||
exit_if_has_rest_and_captured(asm, iseq_has_rest, captured_opnd)?;
|
exit_if_has_rest_and_captured(asm, iseq_has_rest, captured_opnd)?;
|
||||||
exit_if_has_rest_and_supplying_kws(asm, iseq_has_rest, iseq, supplying_kws)?;
|
exit_if_has_rest_and_supplying_kws(asm, iseq_has_rest, iseq, supplying_kws)?;
|
||||||
exit_if_supplying_kw_and_has_no_kw(asm, supplying_kws, iseq)?;
|
exit_if_supplying_kw_and_has_no_kw(asm, supplying_kws, iseq)?;
|
||||||
|
@ -6282,6 +6269,8 @@ fn gen_send_iseq(
|
||||||
asm.jbe(Target::side_exit(Counter::guard_send_se_cf_overflow));
|
asm.jbe(Target::side_exit(Counter::guard_send_se_cf_overflow));
|
||||||
|
|
||||||
if iseq_has_rest && flags & VM_CALL_ARGS_SPLAT != 0 {
|
if iseq_has_rest && flags & VM_CALL_ARGS_SPLAT != 0 {
|
||||||
|
let splat_pos = i32::from(block_arg) + kw_arg_num;
|
||||||
|
|
||||||
// Insert length guard for a call to copy_splat_args_for_rest_callee()
|
// Insert length guard for a call to copy_splat_args_for_rest_callee()
|
||||||
// that will come later. We will have made changes to
|
// that will come later. We will have made changes to
|
||||||
// the stack by spilling or handling __send__ shifting
|
// the stack by spilling or handling __send__ shifting
|
||||||
|
@ -6295,12 +6284,19 @@ fn gen_send_iseq(
|
||||||
if take_count > 0 {
|
if take_count > 0 {
|
||||||
asm_comment!(asm, "guard splat_array_length >= {take_count}");
|
asm_comment!(asm, "guard splat_array_length >= {take_count}");
|
||||||
|
|
||||||
let splat_array = asm.stack_opnd(i32::from(block_arg) + kw_arg_num);
|
let splat_array = asm.stack_opnd(splat_pos);
|
||||||
let array_len_opnd = get_array_len(asm, splat_array);
|
let array_len_opnd = get_array_len(asm, splat_array);
|
||||||
asm.cmp(array_len_opnd, take_count.into());
|
asm.cmp(array_len_opnd, take_count.into());
|
||||||
asm.jl(Target::side_exit(Counter::guard_send_iseq_has_rest_and_splat_too_few));
|
asm.jl(Target::side_exit(Counter::guard_send_iseq_has_rest_and_splat_too_few));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// All splats need to guard for ruby2_keywords hash. Check with a function call when
|
||||||
|
// splatting into a rest param since the index for the last item in the array is dynamic.
|
||||||
|
asm_comment!(asm, "guard no ruby2_keywords hash in splat");
|
||||||
|
let bad_splat = asm.ccall(rb_yjit_ruby2_keywords_splat_p as _, vec![asm.stack_opnd(splat_pos)]);
|
||||||
|
asm.cmp(bad_splat, 0.into());
|
||||||
|
asm.jnz(Target::side_exit(Counter::guard_send_splatarray_last_ruby_2_keywords));
|
||||||
}
|
}
|
||||||
|
|
||||||
match block_arg_type {
|
match block_arg_type {
|
||||||
|
@ -6845,20 +6841,6 @@ fn exit_if_kw_splat(asm: &mut Assembler, flags: u32) -> Option<()> {
|
||||||
exit_if(asm, flags & VM_CALL_KW_SPLAT != 0, Counter::send_iseq_kw_splat)
|
exit_if(asm, flags & VM_CALL_KW_SPLAT != 0, Counter::send_iseq_kw_splat)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
fn exit_if_splat_and_ruby2_keywords(asm: &mut Assembler, jit: &mut JITState, flags: u32) -> Option<()> {
|
|
||||||
// In order to handle backwards compatibility between ruby 3 and 2
|
|
||||||
// ruby2_keywords was introduced. It is called only on methods
|
|
||||||
// with splat and changes they way they handle them.
|
|
||||||
// We are just going to not compile these.
|
|
||||||
// https://www.rubydoc.info/stdlib/core/Proc:ruby2_keywords
|
|
||||||
exit_if(
|
|
||||||
asm,
|
|
||||||
unsafe { get_iseq_flags_ruby2_keywords(jit.iseq) } && flags & VM_CALL_ARGS_SPLAT != 0,
|
|
||||||
Counter::send_iseq_ruby2_keywords,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn exit_if_has_rest_and_captured(asm: &mut Assembler, iseq_has_rest: bool, captured_opnd: Option<Opnd>) -> Option<()> {
|
fn exit_if_has_rest_and_captured(asm: &mut Assembler, iseq_has_rest: bool, captured_opnd: Option<Opnd>) -> Option<()> {
|
||||||
exit_if(asm, iseq_has_rest && captured_opnd.is_some(), Counter::send_iseq_has_rest_and_captured)
|
exit_if(asm, iseq_has_rest && captured_opnd.is_some(), Counter::send_iseq_has_rest_and_captured)
|
||||||
|
|
|
@ -139,7 +139,6 @@ extern "C" {
|
||||||
|
|
||||||
// Renames
|
// Renames
|
||||||
pub use rb_insn_name as raw_insn_name;
|
pub use rb_insn_name as raw_insn_name;
|
||||||
pub use rb_insn_len as raw_insn_len;
|
|
||||||
pub use rb_get_ec_cfp as get_ec_cfp;
|
pub use rb_get_ec_cfp as get_ec_cfp;
|
||||||
pub use rb_get_cfp_iseq as get_cfp_iseq;
|
pub use rb_get_cfp_iseq as get_cfp_iseq;
|
||||||
pub use rb_get_cfp_pc as get_cfp_pc;
|
pub use rb_get_cfp_pc as get_cfp_pc;
|
||||||
|
@ -166,7 +165,6 @@ pub use rb_get_iseq_flags_has_lead as get_iseq_flags_has_lead;
|
||||||
pub use rb_get_iseq_flags_has_opt as get_iseq_flags_has_opt;
|
pub use rb_get_iseq_flags_has_opt as get_iseq_flags_has_opt;
|
||||||
pub use rb_get_iseq_flags_has_kw as get_iseq_flags_has_kw;
|
pub use rb_get_iseq_flags_has_kw as get_iseq_flags_has_kw;
|
||||||
pub use rb_get_iseq_flags_has_rest as get_iseq_flags_has_rest;
|
pub use rb_get_iseq_flags_has_rest as get_iseq_flags_has_rest;
|
||||||
pub use rb_get_iseq_flags_ruby2_keywords as get_iseq_flags_ruby2_keywords;
|
|
||||||
pub use rb_get_iseq_flags_has_post as get_iseq_flags_has_post;
|
pub use rb_get_iseq_flags_has_post as get_iseq_flags_has_post;
|
||||||
pub use rb_get_iseq_flags_has_kwrest as get_iseq_flags_has_kwrest;
|
pub use rb_get_iseq_flags_has_kwrest as get_iseq_flags_has_kwrest;
|
||||||
pub use rb_get_iseq_flags_has_block as get_iseq_flags_has_block;
|
pub use rb_get_iseq_flags_has_block as get_iseq_flags_has_block;
|
||||||
|
@ -185,7 +183,6 @@ pub use rb_yarv_str_eql_internal as rb_str_eql_internal;
|
||||||
pub use rb_yarv_ary_entry_internal as rb_ary_entry_internal;
|
pub use rb_yarv_ary_entry_internal as rb_ary_entry_internal;
|
||||||
pub use rb_yjit_fix_div_fix as rb_fix_div_fix;
|
pub use rb_yjit_fix_div_fix as rb_fix_div_fix;
|
||||||
pub use rb_yjit_fix_mod_fix as rb_fix_mod_fix;
|
pub use rb_yjit_fix_mod_fix as rb_fix_mod_fix;
|
||||||
pub use rb_yjit_fix_mul_fix as rb_fix_mul_fix;
|
|
||||||
pub use rb_FL_TEST as FL_TEST;
|
pub use rb_FL_TEST as FL_TEST;
|
||||||
pub use rb_FL_TEST_RAW as FL_TEST_RAW;
|
pub use rb_FL_TEST_RAW as FL_TEST_RAW;
|
||||||
pub use rb_RB_TYPE_P as RB_TYPE_P;
|
pub use rb_RB_TYPE_P as RB_TYPE_P;
|
||||||
|
@ -222,7 +219,7 @@ pub fn insn_len(opcode: usize) -> u32 {
|
||||||
|
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
unsafe {
|
unsafe {
|
||||||
raw_insn_len(VALUE(opcode)).try_into().unwrap()
|
rb_insn_len(VALUE(opcode)).try_into().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1123,7 +1123,7 @@ extern "C" {
|
||||||
pub fn rb_yjit_rb_ary_subseq_length(ary: VALUE, beg: ::std::os::raw::c_long) -> VALUE;
|
pub fn rb_yjit_rb_ary_subseq_length(ary: VALUE, beg: ::std::os::raw::c_long) -> VALUE;
|
||||||
pub fn rb_yjit_fix_div_fix(recv: VALUE, obj: VALUE) -> VALUE;
|
pub fn rb_yjit_fix_div_fix(recv: VALUE, obj: VALUE) -> VALUE;
|
||||||
pub fn rb_yjit_fix_mod_fix(recv: VALUE, obj: VALUE) -> VALUE;
|
pub fn rb_yjit_fix_mod_fix(recv: VALUE, obj: VALUE) -> VALUE;
|
||||||
pub fn rb_yjit_fix_mul_fix(recv: VALUE, obj: VALUE) -> VALUE;
|
pub fn rb_yjit_ruby2_keywords_splat_p(obj: VALUE) -> usize;
|
||||||
pub fn rb_yjit_dump_iseq_loc(iseq: *const rb_iseq_t, insn_idx: u32);
|
pub fn rb_yjit_dump_iseq_loc(iseq: *const rb_iseq_t, insn_idx: u32);
|
||||||
pub fn rb_FL_TEST(obj: VALUE, flags: VALUE) -> VALUE;
|
pub fn rb_FL_TEST(obj: VALUE, flags: VALUE) -> VALUE;
|
||||||
pub fn rb_FL_TEST_RAW(obj: VALUE, flags: VALUE) -> VALUE;
|
pub fn rb_FL_TEST_RAW(obj: VALUE, flags: VALUE) -> VALUE;
|
||||||
|
|
|
@ -3,8 +3,7 @@
|
||||||
#![allow(clippy::too_many_arguments)] // :shrug:
|
#![allow(clippy::too_many_arguments)] // :shrug:
|
||||||
#![allow(clippy::identity_op)] // Sometimes we do it for style
|
#![allow(clippy::identity_op)] // Sometimes we do it for style
|
||||||
|
|
||||||
|
pub mod asm;
|
||||||
mod asm;
|
|
||||||
mod backend;
|
mod backend;
|
||||||
mod codegen;
|
mod codegen;
|
||||||
mod core;
|
mod core;
|
||||||
|
|
|
@ -355,10 +355,8 @@ make_counters! {
|
||||||
send_args_splat_opt_call,
|
send_args_splat_opt_call,
|
||||||
send_args_splat_cfunc_var_args,
|
send_args_splat_cfunc_var_args,
|
||||||
send_args_splat_cfunc_zuper,
|
send_args_splat_cfunc_zuper,
|
||||||
send_args_splat_cfunc_ruby2_keywords,
|
|
||||||
send_iseq_splat_arity_error,
|
send_iseq_splat_arity_error,
|
||||||
send_splat_too_long,
|
send_splat_too_long,
|
||||||
send_iseq_ruby2_keywords,
|
|
||||||
send_send_not_imm,
|
send_send_not_imm,
|
||||||
send_send_wrong_args,
|
send_send_wrong_args,
|
||||||
send_send_null_mid,
|
send_send_null_mid,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче