@@ -9,7 +9,7 @@ use crate::{
99 cast:: IntoUsize , codegen:: local_idx_to_ep_offset, cruby:: * , payload:: { get_or_create_iseq_payload, IseqPayload } , options:: { debug, get_option, DumpHIR } , state:: ZJITState
1010} ;
1111use std:: {
12- cell:: RefCell , collections:: { HashMap , HashSet , VecDeque } , ffi:: { c_void, c_uint, CStr } , fmt:: Display , mem:: { align_of, size_of} , ptr, slice:: Iter
12+ cell:: RefCell , collections:: { HashMap , HashSet , VecDeque } , ffi:: { c_void, c_uint, c_int , CStr } , fmt:: Display , mem:: { align_of, size_of} , ptr, slice:: Iter
1313} ;
1414use crate :: hir_type:: { Type , types} ;
1515use crate :: bitset:: BitSet ;
@@ -593,7 +593,6 @@ pub enum SendFallbackReason {
593593 SendWithoutBlockCfuncArrayVariadic ,
594594 SendWithoutBlockNotOptimizedMethodType ( MethodType ) ,
595595 SendWithoutBlockNotOptimizedMethodTypeOptimized ( OptimizedMethodType ) ,
596- SendWithoutBlockDirectTooManyArgs ,
597596 SendWithoutBlockBopRedefined ,
598597 SendWithoutBlockOperandsNotFixnum ,
599598 SendPolymorphic ,
@@ -604,8 +603,11 @@ pub enum SendFallbackReason {
604603 SendNotOptimizedMethodType ( MethodType ) ,
605604 CCallWithFrameTooManyArgs ,
606605 ObjToStringNotString ,
606+ TooManyArgsForLir ,
607607 /// The Proc object for a BMETHOD is not defined by an ISEQ. (See `enum rb_block_type`.)
608608 BmethodNonIseqProc ,
609+ /// Caller supplies too few or too many arguments than what the callee's parameters expects.
610+ ArgcParamMismatch ,
609611 /// The call has at least one feature on the caller or callee side that the optimizer does not
610612 /// support.
611613 ComplexArgPass ,
@@ -1457,7 +1459,7 @@ pub enum ValidationError {
14571459 MiscValidationError ( InsnId , String ) ,
14581460}
14591461
1460- fn can_direct_send ( function : & mut Function , block : BlockId , iseq : * const rb_iseq_t ) -> bool {
1462+ fn can_direct_send ( function : & mut Function , block : BlockId , iseq : * const rb_iseq_t , send_insn : InsnId , args : & [ InsnId ] ) -> bool {
14611463 let mut can_send = true ;
14621464 let mut count_failure = |counter| {
14631465 can_send = false ;
@@ -1472,6 +1474,24 @@ fn can_direct_send(function: &mut Function, block: BlockId, iseq: *const rb_iseq
14721474 if unsafe { rb_get_iseq_flags_has_block ( iseq) } { count_failure ( complex_arg_pass_param_block) }
14731475 if unsafe { rb_get_iseq_flags_forwardable ( iseq) } { count_failure ( complex_arg_pass_param_forwardable) }
14741476
1477+ if !can_send {
1478+ function. set_dynamic_send_reason ( send_insn, ComplexArgPass ) ;
1479+ return false ;
1480+ }
1481+
1482+ // Check argument count against callee's parameters. Note that correctness for this calculation
1483+ // relies on rejecting features above.
1484+ let lead_num = unsafe { get_iseq_body_param_lead_num ( iseq) } ;
1485+ let opt_num = unsafe { get_iseq_body_param_opt_num ( iseq) } ;
1486+ can_send = c_int:: try_from ( args. len ( ) )
1487+ . as_ref ( )
1488+ . map ( |argc| ( lead_num..=lead_num + opt_num) . contains ( argc) )
1489+ . unwrap_or ( false ) ;
1490+ if !can_send {
1491+ function. set_dynamic_send_reason ( send_insn, ArgcParamMismatch ) ;
1492+ return false
1493+ }
1494+
14751495 can_send
14761496}
14771497
@@ -2358,8 +2378,7 @@ impl Function {
23582378 // Only specialize positional-positional calls
23592379 // TODO(max): Handle other kinds of parameter passing
23602380 let iseq = unsafe { get_def_iseq_ptr ( ( * cme) . def ) } ;
2361- if !can_direct_send ( self , block, iseq) {
2362- self . set_dynamic_send_reason ( insn_id, ComplexArgPass ) ;
2381+ if !can_direct_send ( self , block, iseq, insn_id, args. as_slice ( ) ) {
23632382 self . push_insn_id ( block, insn_id) ; continue ;
23642383 }
23652384 self . push_insn ( block, Insn :: PatchPoint { invariant : Invariant :: MethodRedefined { klass, method : mid, cme } , state } ) ;
@@ -2384,8 +2403,7 @@ impl Function {
23842403 let capture = unsafe { proc_block. as_ . captured . as_ref ( ) } ;
23852404 let iseq = unsafe { * capture. code . iseq . as_ref ( ) } ;
23862405
2387- if !can_direct_send ( self , block, iseq) {
2388- self . set_dynamic_send_reason ( insn_id, ComplexArgPass ) ;
2406+ if !can_direct_send ( self , block, iseq, insn_id, args. as_slice ( ) ) {
23892407 self . push_insn_id ( block, insn_id) ; continue ;
23902408 }
23912409 // Can't pass a block to a block for now
0 commit comments