@@ -38,17 +38,21 @@ struct JITState {
3838
3939 /// The number of bytes allocated for basic block arguments spilled onto the C stack
4040 c_stack_slots : usize ,
41+
42+ /// Execution context
43+ ec : EcPtr ,
4144}
4245
4346impl JITState {
4447 /// Create a new JITState instance
45- fn new ( iseq : IseqPtr , num_insns : usize , num_blocks : usize , c_stack_slots : usize ) -> Self {
48+ fn new ( iseq : IseqPtr , num_insns : usize , num_blocks : usize , c_stack_slots : usize , ec : EcPtr ) -> Self {
4649 JITState {
4750 iseq,
4851 opnds : vec ! [ None ; num_insns] ,
4952 labels : vec ! [ None ; num_blocks] ,
5053 iseq_calls : Vec :: default ( ) ,
5154 c_stack_slots,
55+ ec,
5256 }
5357 }
5458
@@ -74,7 +78,7 @@ impl JITState {
7478/// If jit_exception is true, compile JIT code for handling exceptions.
7579/// See jit_compile_exception() for details.
7680#[ unsafe( no_mangle) ]
77- pub extern "C" fn rb_zjit_iseq_gen_entry_point ( iseq : IseqPtr , jit_exception : bool ) -> * const u8 {
81+ pub extern "C" fn rb_zjit_iseq_gen_entry_point ( iseq : IseqPtr , ec : EcPtr , jit_exception : bool ) -> * const u8 {
7882 // Do not test the JIT code in HIR tests
7983 if cfg ! ( test) {
8084 return std:: ptr:: null ( ) ;
@@ -84,7 +88,7 @@ pub extern "C" fn rb_zjit_iseq_gen_entry_point(iseq: IseqPtr, jit_exception: boo
8488 // with_vm_lock() does nothing if the program doesn't use Ractors.
8589 with_vm_lock ( src_loc ! ( ) , || {
8690 let cb = ZJITState :: get_code_block ( ) ;
87- let mut code_ptr = with_time_stat ( compile_time_ns, || gen_iseq_entry_point ( cb, iseq, jit_exception) ) ;
91+ let mut code_ptr = with_time_stat ( compile_time_ns, || gen_iseq_entry_point ( cb, iseq, ec , jit_exception) ) ;
8892
8993 if let Err ( err) = & code_ptr {
9094 // Assert that the ISEQ compiles if RubyVM::ZJIT.assert_compiles is enabled.
@@ -110,7 +114,7 @@ pub extern "C" fn rb_zjit_iseq_gen_entry_point(iseq: IseqPtr, jit_exception: boo
110114}
111115
112116/// Compile an entry point for a given ISEQ
113- fn gen_iseq_entry_point ( cb : & mut CodeBlock , iseq : IseqPtr , jit_exception : bool ) -> Result < CodePtr , CompileError > {
117+ fn gen_iseq_entry_point ( cb : & mut CodeBlock , iseq : IseqPtr , ec : EcPtr , jit_exception : bool ) -> Result < CodePtr , CompileError > {
114118 // We don't support exception handlers yet
115119 if jit_exception {
116120 return Err ( CompileError :: ExceptionHandler ) ;
@@ -122,7 +126,7 @@ fn gen_iseq_entry_point(cb: &mut CodeBlock, iseq: IseqPtr, jit_exception: bool)
122126 } ) ?;
123127
124128 // Compile the High-level IR
125- let start_ptr = gen_iseq ( cb, iseq, Some ( & function) ) . inspect_err ( |err| {
129+ let start_ptr = gen_iseq ( cb, iseq, ec , Some ( & function) ) . inspect_err ( |err| {
126130 debug ! ( "{err:?}: gen_iseq failed: {}" , iseq_get_location( iseq, 0 ) ) ;
127131 } ) ?;
128132
@@ -196,7 +200,7 @@ fn gen_entry(cb: &mut CodeBlock, iseq: IseqPtr, function: &Function, function_pt
196200}
197201
198202/// Compile an ISEQ into machine code if not compiled yet
199- fn gen_iseq ( cb : & mut CodeBlock , iseq : IseqPtr , function : Option < & Function > ) -> Result < CodePtr , CompileError > {
203+ fn gen_iseq ( cb : & mut CodeBlock , iseq : IseqPtr , ec : EcPtr , function : Option < & Function > ) -> Result < CodePtr , CompileError > {
200204 // Return an existing pointer if it's already compiled
201205 let payload = get_or_create_iseq_payload ( iseq) ;
202206 match & payload. status {
@@ -206,7 +210,7 @@ fn gen_iseq(cb: &mut CodeBlock, iseq: IseqPtr, function: Option<&Function>) -> R
206210 }
207211
208212 // Compile the ISEQ
209- let code_ptr = gen_iseq_body ( cb, iseq, function, payload) ;
213+ let code_ptr = gen_iseq_body ( cb, iseq, ec , function, payload) ;
210214 match & code_ptr {
211215 Ok ( start_ptr) => {
212216 payload. status = IseqStatus :: Compiled ( * start_ptr) ;
@@ -221,15 +225,15 @@ fn gen_iseq(cb: &mut CodeBlock, iseq: IseqPtr, function: Option<&Function>) -> R
221225}
222226
223227/// Compile an ISEQ into machine code
224- fn gen_iseq_body ( cb : & mut CodeBlock , iseq : IseqPtr , function : Option < & Function > , payload : & mut IseqPayload ) -> Result < CodePtr , CompileError > {
228+ fn gen_iseq_body ( cb : & mut CodeBlock , iseq : IseqPtr , ec : EcPtr , function : Option < & Function > , payload : & mut IseqPayload ) -> Result < CodePtr , CompileError > {
225229 // Convert ISEQ into optimized High-level IR if not given
226230 let function = match function {
227231 Some ( function) => function,
228232 None => & compile_iseq ( iseq) ?,
229233 } ;
230234
231235 // Compile the High-level IR
232- let ( start_ptr, gc_offsets, iseq_calls) = gen_function ( cb, iseq, function) ?;
236+ let ( start_ptr, gc_offsets, iseq_calls) = gen_function ( cb, iseq, ec , function) ?;
233237
234238 // Stub callee ISEQs for JIT-to-JIT calls
235239 for iseq_call in iseq_calls. iter ( ) {
@@ -243,9 +247,9 @@ fn gen_iseq_body(cb: &mut CodeBlock, iseq: IseqPtr, function: Option<&Function>,
243247}
244248
245249/// Compile a function
246- fn gen_function ( cb : & mut CodeBlock , iseq : IseqPtr , function : & Function ) -> Result < ( CodePtr , Vec < CodePtr > , Vec < IseqCallRef > ) , CompileError > {
250+ fn gen_function ( cb : & mut CodeBlock , iseq : IseqPtr , ec : EcPtr , function : & Function ) -> Result < ( CodePtr , Vec < CodePtr > , Vec < IseqCallRef > ) , CompileError > {
247251 let c_stack_slots = max_num_params ( function) . saturating_sub ( ALLOC_REGS . len ( ) ) ;
248- let mut jit = JITState :: new ( iseq, function. num_insns ( ) , function. num_blocks ( ) , c_stack_slots) ;
252+ let mut jit = JITState :: new ( iseq, function. num_insns ( ) , function. num_blocks ( ) , c_stack_slots, ec ) ;
249253 let mut asm = Assembler :: new ( ) ;
250254
251255 // Compile each basic block
@@ -342,6 +346,10 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
342346 asm_comment ! ( asm, "Insn: {insn_id} {insn}" ) ;
343347 }
344348
349+ unsafe extern "C" {
350+ fn rb_c_method_tracing_currently_enabled ( ec : EcPtr ) -> bool ;
351+ }
352+
345353 let out_opnd = match insn {
346354 Insn :: Const { val : Const :: Value ( val) } => gen_const ( * val) ,
347355 Insn :: Const { .. } => panic ! ( "Unexpected Const in gen_insn: {insn}" ) ,
@@ -397,6 +405,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
397405 & Insn :: GuardBlockParamProxy { level, state } => no_output ! ( gen_guard_block_param_proxy( jit, asm, level, & function. frame_state( state) ) ) ,
398406 Insn :: PatchPoint { invariant, state } => no_output ! ( gen_patch_point( jit, asm, invariant, & function. frame_state( * state) ) ) ,
399407 Insn :: CCall { cfun, args, name : _, return_type : _, elidable : _ } => gen_ccall ( asm, * cfun, opnds ! ( args) ) ,
408+ Insn :: CCallVariadic { state, .. } if unsafe { rb_c_method_tracing_currently_enabled ( jit. ec ) } => return Err ( * state) ,
400409 Insn :: CCallVariadic { cfun, recv, args, name : _, cme, state } => {
401410 gen_ccall_variadic ( jit, asm, * cfun, opnd ! ( recv) , opnds ! ( args) , * cme, & function. frame_state ( * state) )
402411 }
@@ -1816,7 +1825,7 @@ c_callable! {
18161825 /// This function is expected to be called repeatedly when ZJIT fails to compile the stub.
18171826 /// We should be able to compile most (if not all) function stubs by side-exiting at unsupported
18181827 /// instructions, so this should be used primarily for cb.has_dropped_bytes() situations.
1819- fn function_stub_hit( iseq_call_ptr: * const c_void, cfp: CfpPtr , sp: * mut VALUE ) -> * const u8 {
1828+ fn function_stub_hit( iseq_call_ptr: * const c_void, cfp: CfpPtr , sp: * mut VALUE , ec : EcPtr ) -> * const u8 {
18201829 with_vm_lock( src_loc!( ) , || {
18211830 // gen_push_frame() doesn't set PC, so we need to set them before exit.
18221831 // function_stub_hit_body() may allocate and call gc_validate_pc(), so we always set PC.
@@ -1864,7 +1873,7 @@ c_callable! {
18641873 }
18651874
18661875 // Otherwise, attempt to compile the ISEQ. We have to mark_all_executable() beyond this point.
1867- let code_ptr = with_time_stat( compile_time_ns, || function_stub_hit_body( cb, & iseq_call) ) ;
1876+ let code_ptr = with_time_stat( compile_time_ns, || function_stub_hit_body( cb, & iseq_call, ec ) ) ;
18681877 let code_ptr = code_ptr. unwrap_or_else( |compile_error| {
18691878 prepare_for_exit( iseq, cfp, sp, & compile_error) ;
18701879 ZJITState :: get_exit_trampoline_with_counter( )
@@ -1876,9 +1885,9 @@ c_callable! {
18761885}
18771886
18781887/// Compile an ISEQ for a function stub
1879- fn function_stub_hit_body ( cb : & mut CodeBlock , iseq_call : & Rc < RefCell < IseqCall > > ) -> Result < CodePtr , CompileError > {
1888+ fn function_stub_hit_body ( cb : & mut CodeBlock , iseq_call : & Rc < RefCell < IseqCall > > , ec : EcPtr ) -> Result < CodePtr , CompileError > {
18801889 // Compile the stubbed ISEQ
1881- let code_ptr = gen_iseq ( cb, iseq_call. borrow ( ) . iseq , None ) . inspect_err ( |err| {
1890+ let code_ptr = gen_iseq ( cb, iseq_call. borrow ( ) . iseq , ec , None ) . inspect_err ( |err| {
18821891 debug ! ( "{err:?}: gen_iseq failed: {}" , iseq_get_location( iseq_call. borrow( ) . iseq, 0 ) ) ;
18831892 } ) ?;
18841893
@@ -1924,7 +1933,7 @@ pub fn gen_function_stub_hit_trampoline(cb: &mut CodeBlock) -> Result<CodePtr, C
19241933 const { assert ! ( ALLOC_REGS . len( ) % 2 == 0 , "x86_64 would need to push one more if we push an odd number of regs" ) ; }
19251934
19261935 // Compile the stubbed ISEQ
1927- let jump_addr = asm_ccall ! ( asm, function_stub_hit, SCRATCH_OPND , CFP , SP ) ;
1936+ let jump_addr = asm_ccall ! ( asm, function_stub_hit, SCRATCH_OPND , CFP , SP , EC ) ;
19281937 asm. mov ( SCRATCH_OPND , jump_addr) ;
19291938
19301939 asm_comment ! ( asm, "restore argument registers" ) ;
0 commit comments