@@ -612,7 +612,10 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
612612 & Insn :: Send { cd, blockiseq : None , state, reason, .. } => gen_send_without_block ( jit, asm, cd, & function. frame_state ( state) , reason) ,
613613 & Insn :: Send { cd, blockiseq : Some ( blockiseq) , state, reason, .. } => gen_send ( jit, asm, cd, blockiseq, & function. frame_state ( state) , reason) ,
614614 & Insn :: SendForward { cd, blockiseq, state, reason, .. } => gen_send_forward ( jit, asm, cd, blockiseq, & function. frame_state ( state) , reason) ,
615- Insn :: SendDirect { cme, iseq, recv, args, kw_bits, blockiseq, state, .. } => gen_send_iseq_direct ( cb, jit, asm, * cme, * iseq, opnd ! ( recv) , opnds ! ( args) , * kw_bits, & function. frame_state ( * state) , * blockiseq) ,
615+ & Insn :: SendDirect { cme, iseq, recv, ref args, kw_bits, blockiseq, state, .. } => gen_send_iseq_direct (
616+ cb, jit, asm, cme, iseq, opnd ! ( recv) , opnds ! ( args) ,
617+ kw_bits, & function. frame_state ( state) , blockiseq,
618+ ) . ok_or ( state) ?,
616619 & Insn :: InvokeSuper { cd, blockiseq, state, reason, .. } => gen_invokesuper ( jit, asm, cd, blockiseq, & function. frame_state ( state) , reason) ,
617620 & Insn :: InvokeSuperForward { cd, blockiseq, state, reason, .. } => gen_invokesuperforward ( jit, asm, cd, blockiseq, & function. frame_state ( state) , reason) ,
618621 & Insn :: InvokeBlock { cd, state, reason, .. } => gen_invokeblock ( jit, asm, cd, & function. frame_state ( state) , reason) ,
@@ -1535,7 +1538,7 @@ fn gen_send_iseq_direct(
15351538 kw_bits: u32,
15361539 state: & FrameState ,
15371540 blockiseq: Option <IseqPtr >,
1538- ) -> lir:: Opnd {
1541+ ) -> Option < lir:: Opnd > {
15391542 gen_incr_counter ( asm, Counter :: iseq_optimized_send_count) ;
15401543
15411544 let local_size = unsafe { get_iseq_body_local_table_size ( iseq) } . to_usize ( ) ;
@@ -1651,7 +1654,7 @@ fn gen_send_iseq_direct(
16511654 } ;
16521655
16531656 // Make a method call. The target address will be rewritten once compiled.
1654- let iseq_call = IseqCall :: new ( iseq, num_optionals_passed) ;
1657+ let iseq_call = IseqCall :: new ( iseq, num_optionals_passed. try_into ( ) . ok ( ) ? , args . len ( ) . try_into ( ) . ok ( ) ? ) ;
16551658 let dummy_ptr = cb. get_write_ptr ( ) . raw_ptr ( cb) ;
16561659 jit. iseq_calls . push ( iseq_call. clone ( ) ) ;
16571660 let ret = asm. ccall_with_iseq_call ( dummy_ptr, c_args, & iseq_call) ;
@@ -1668,7 +1671,7 @@ fn gen_send_iseq_direct(
16681671 let new_sp = asm. sub ( SP , sp_offset. into ( ) ) ;
16691672 asm. mov ( SP , new_sp) ;
16701673
1671- ret
1674+ Some ( ret)
16721675}
16731676
16741677/// Compile for invokeblock
@@ -2937,22 +2940,39 @@ c_callable! {
29372940 // function_stub_hit_body() may allocate and call gc_validate_pc(), so we always set PC.
29382941 let iseq_call = unsafe { Rc :: from_raw( iseq_call_ptr as * const IseqCall ) } ;
29392942 let iseq = iseq_call. iseq. get( ) ;
2943+ let argc = iseq_call. argc;
2944+ let num_opts_filled = iseq_call. jit_entry_idx;
29402945 let entry_insn_idxs = crate :: hir:: jit_entry_insns( iseq) ;
29412946 let pc = unsafe { rb_iseq_pc_at_idx( iseq, entry_insn_idxs[ iseq_call. jit_entry_idx. to_usize( ) ] ) } ;
29422947 unsafe { rb_set_cfp_pc( cfp, pc) } ;
29432948
29442949 // JIT-to-JIT calls don't eagerly fill nils to non-parameter locals.
29452950 // If we side-exit from function_stub_hit (before JIT code runs), we need to set them here.
2946- fn prepare_for_exit( iseq: IseqPtr , cfp: CfpPtr , sp: * mut VALUE , compile_error: & CompileError ) {
2951+ fn prepare_for_exit( iseq: IseqPtr , cfp: CfpPtr , sp: * mut VALUE , argc : u16 , num_opts_filled : u16 , compile_error: & CompileError ) {
29472952 unsafe {
29482953 // Set SP which gen_push_frame() doesn't set
29492954 rb_set_cfp_sp( cfp, sp) ;
29502955
2951- // Fill nils to uninitialized (non-argument) locals
29522956 let local_size = get_iseq_body_local_table_size( iseq) . to_usize( ) ;
2953- let num_params = iseq. params( ) . size. to_usize( ) ;
2954- let base = sp. offset( -local_size_and_idx_to_bp_offset( local_size, num_params) as isize ) ;
2955- slice:: from_raw_parts_mut( base, local_size - num_params) . fill( Qnil ) ;
2957+ let params = iseq. params( ) ;
2958+ let params_size = params. size. to_usize( ) ;
2959+ let frame_base = sp. offset( -local_size_and_idx_to_bp_offset( local_size, 0 ) as isize ) ;
2960+ let locals = slice:: from_raw_parts_mut( frame_base, local_size) ;
2961+ // Fill nils to uninitialized (non-parameter) locals
2962+ locals. get_mut( params_size..) . unwrap_or_default( ) . fill( Qnil ) ;
2963+
2964+ // When there are unfilled optionals
2965+ let opt_num: usize = params. opt_num. try_into( ) . expect( "ISEQ opt_num should be non-negative" ) ;
2966+ let opts_unfilled = opt_num - num_opts_filled. to_usize( ) ;
2967+ if opts_unfilled > 0 {
2968+ let lead_num: usize = params. lead_num. try_into( ) . expect( "should be non-negative" ) ;
2969+ let after_opts = lead_num + opt_num;
2970+ let param_locals = & mut locals[ ..params_size] ;
2971+ // Right-justify params that are after the unfilled optionals
2972+ param_locals. copy_within( num_opts_filled. to_usize( ) ..argc. to_usize( ) , after_opts) ;
2973+ // Nil-fill unfilled optionals
2974+ ( & mut param_locals[ num_opts_filled. to_usize( ) ..after_opts] ) . fill( Qnil ) ;
2975+ }
29562976 }
29572977
29582978 // Increment a compile error counter for --zjit-stats
@@ -2976,7 +2996,7 @@ c_callable! {
29762996 // We'll use this Rc again, so increment the ref count decremented by from_raw.
29772997 unsafe { Rc :: increment_strong_count( iseq_call_ptr as * const IseqCall ) ; }
29782998
2979- prepare_for_exit( iseq, cfp, sp, compile_error) ;
2999+ prepare_for_exit( iseq, cfp, sp, argc , num_opts_filled , compile_error) ;
29803000 return ZJITState :: get_exit_trampoline_with_counter( ) . raw_ptr( cb) ;
29813001 }
29823002
@@ -2991,7 +3011,7 @@ c_callable! {
29913011 // We'll use this Rc again, so increment the ref count decremented by from_raw.
29923012 unsafe { Rc :: increment_strong_count( iseq_call_ptr as * const IseqCall ) ; }
29933013
2994- prepare_for_exit( iseq, cfp, sp, & compile_error) ;
3014+ prepare_for_exit( iseq, cfp, sp, argc , num_opts_filled , & compile_error) ;
29953015 ZJITState :: get_exit_trampoline_with_counter( )
29963016 } ) ;
29973017 cb. mark_all_executable( ) ;
@@ -3316,7 +3336,10 @@ pub struct IseqCall {
33163336 pub iseq : Cell < IseqPtr > ,
33173337
33183338 /// Index that corresponds to [crate::hir::jit_entry_insns]
3319- jit_entry_idx : u32 ,
3339+ jit_entry_idx : u16 ,
3340+
3341+ /// Argument count passing to the HIR function
3342+ argc : u16 ,
33203343
33213344 /// Position where the call instruction starts
33223345 start_addr : Cell < Option < CodePtr > > ,
@@ -3329,12 +3352,13 @@ pub type IseqCallRef = Rc<IseqCall>;
33293352
33303353impl IseqCall {
33313354 /// Allocate a new IseqCall
3332- fn new ( iseq : IseqPtr , jit_entry_idx : u32 ) -> IseqCallRef {
3355+ fn new ( iseq : IseqPtr , jit_entry_idx : u16 , argc : u16 ) -> IseqCallRef {
33333356 let iseq_call = IseqCall {
33343357 iseq : Cell :: new ( iseq) ,
33353358 start_addr : Cell :: new ( None ) ,
33363359 end_addr : Cell :: new ( None ) ,
33373360 jit_entry_idx,
3361+ argc,
33383362 } ;
33393363 Rc :: new ( iseq_call)
33403364 }
0 commit comments