mirror of
https://github.com/ruby/ruby.git
synced 2025-08-15 13:39:04 +02:00
ZJIT: Avoid compiling and direct sends to forwardable ISEQs
These `...` ISEQs have a special calling convention in the interpreter and our stubs and JIT calling convention don't deal well. Reject for now. Debugged with help from `@tekknolagi` and `tool/zjit_bisect.rb`. Merely avoiding direct sends is enough to pass the attached test, but also avoid compiling ISEQs with `...` parameter to limit exposure for now. `SendWithoutBlock`, which does dynamic dispatch using interpreter code, seems to handle calling into forwardable ISEQs correctly, so they are fine -- we can't predict where these dynamic sends land anyways.
This commit is contained in:
parent
eb931a09c5
commit
0ba488d7f5
2 changed files with 22 additions and 17 deletions
|
@ -969,6 +969,7 @@ fn can_direct_send(iseq: *const rb_iseq_t) -> bool {
|
|||
else if unsafe { rb_get_iseq_flags_has_kw(iseq) } { false }
|
||||
else if unsafe { rb_get_iseq_flags_has_kwrest(iseq) } { false }
|
||||
else if unsafe { rb_get_iseq_flags_has_block(iseq) } { false }
|
||||
else if unsafe { rb_get_iseq_flags_forwardable(iseq) } { false }
|
||||
else { true }
|
||||
}
|
||||
|
||||
|
@ -2581,6 +2582,9 @@ pub enum CallType {
|
|||
#[derive(Debug, PartialEq)]
|
||||
pub enum ParameterType {
|
||||
Optional,
|
||||
/// For example, `foo(...)`. Interaction of JIT
|
||||
/// calling convention and side exits currently unsolved.
|
||||
Forwardable,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
|
@ -2650,6 +2654,7 @@ pub const SELF_PARAM_IDX: usize = 0;
|
|||
|
||||
fn filter_unknown_parameter_type(iseq: *const rb_iseq_t) -> Result<(), ParseError> {
|
||||
if unsafe { rb_get_iseq_body_param_opt_num(iseq) } != 0 { return Err(ParseError::UnknownParameterType(ParameterType::Optional)); }
|
||||
if unsafe { rb_get_iseq_flags_forwardable(iseq) } { return Err(ParseError::UnknownParameterType(ParameterType::Forwardable)); }
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -4583,11 +4588,13 @@ mod tests {
|
|||
eval("
|
||||
def test(...) = super(...)
|
||||
");
|
||||
assert_method_hir("test", expect![[r#"
|
||||
fn test@<compiled>:2:
|
||||
bb0(v0:BasicObject, v1:BasicObject):
|
||||
SideExit UnknownOpcode(invokesuperforward)
|
||||
"#]]);
|
||||
assert_compile_fails("test", ParseError::UnknownParameterType(ParameterType::Forwardable));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cant_compile_forwardable() {
|
||||
eval("def forwardable(...) = nil");
|
||||
assert_compile_fails("forwardable", ParseError::UnknownParameterType(ParameterType::Forwardable));
|
||||
}
|
||||
|
||||
// TODO(max): Figure out how to generate a call with OPT_SEND flag
|
||||
|
@ -4631,11 +4638,7 @@ mod tests {
|
|||
eval("
|
||||
def test(...) = foo(...)
|
||||
");
|
||||
assert_method_hir("test", expect![[r#"
|
||||
fn test@<compiled>:2:
|
||||
bb0(v0:BasicObject, v1:BasicObject):
|
||||
SideExit UnknownOpcode(sendforward)
|
||||
"#]]);
|
||||
assert_compile_fails("test", ParseError::UnknownParameterType(ParameterType::Forwardable));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -5691,7 +5694,6 @@ mod opt_tests {
|
|||
def kw_rest(**k) = k
|
||||
def post(*rest, post) = post
|
||||
def block(&b) = nil
|
||||
def forwardable(...) = nil
|
||||
");
|
||||
|
||||
assert_optimized_method_hir("rest", expect![[r#"
|
||||
|
@ -5721,12 +5723,6 @@ mod opt_tests {
|
|||
bb0(v0:BasicObject, v1:ArrayExact, v2:BasicObject):
|
||||
Return v2
|
||||
"#]]);
|
||||
assert_optimized_method_hir("forwardable", expect![[r#"
|
||||
fn forwardable@<compiled>:7:
|
||||
bb0(v0:BasicObject, v1:BasicObject):
|
||||
v3:NilClass = Const Value(nil)
|
||||
Return v3
|
||||
"#]]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue