@@ -26,6 +26,9 @@ codeblock_t* cb = NULL;
2626static codeblock_t outline_block ;
2727codeblock_t * ocb = NULL ;
2828
29+ // Code for exiting back to the interpreter
30+ static void * interp_exit ;
31+
2932// Print the current source location for debugging purposes
3033RBIMPL_ATTR_MAYBE_UNUSED ()
3134static void
@@ -136,7 +139,7 @@ yjit_load_regs(codeblock_t* cb)
136139static uint8_t *
137140yjit_gen_exit (jitstate_t * jit , ctx_t * ctx , codeblock_t * cb )
138141{
139- uint8_t * code_ptr = cb_get_ptr (ocb , ocb -> write_pos );
142+ uint8_t * code_ptr = cb_get_ptr (cb , cb -> write_pos );
140143
141144 VALUE * exit_pc = jit -> pc ;
142145
@@ -183,6 +186,26 @@ yjit_gen_exit(jitstate_t *jit, ctx_t *ctx, codeblock_t *cb)
183186 return code_ptr ;
184187}
185188
189+ // Generate an interpreter to REG_CFP->pc.
190+ static uint8_t *
191+ yjit_gen_context_free_exit (codeblock_t * cb )
192+ {
193+ uint8_t * code_ptr = cb_get_ptr (cb , cb -> write_pos );
194+
195+ // Update the CFP on the EC
196+ mov (cb , member_opnd (REG_EC , rb_execution_context_t , cfp ), REG_CFP );
197+
198+ // Put PC into the return register, which the post call bytes dispatches to
199+ mov (cb , RAX , member_opnd (REG_CFP , rb_control_frame_t , pc ));
200+
201+ cb_write_post_call_bytes (cb );
202+
203+ // Note, not incrementing stats here since this exit is the natural end to
204+ // executing output code.
205+
206+ return code_ptr ;
207+ }
208+
186209
187210// A shorthand for generating an exit in the outline block
188211static uint8_t *
@@ -250,7 +273,7 @@ yjit_comment_array_t yjit_code_comments;
250273Compile an interpreter entry block to be inserted into an iseq
251274Returns `NULL` if compilation fails.
252275*/
253- uint8_t *
276+ uint8_t *
254277yjit_entry_prologue (void )
255278{
256279 RUBY_ASSERT (cb != NULL );
@@ -270,6 +293,11 @@ yjit_entry_prologue(void)
270293 // Load the current SP from the CFP into REG_SP
271294 mov (cb , REG_SP , member_opnd (REG_CFP , rb_control_frame_t , sp ));
272295
296+ // Setup cfp->jit_return
297+ // TODO: this could use a IP relative LEA instead of an 8 byte immediate
298+ mov (cb , REG0 , const_ptr_opnd (interp_exit ));
299+ mov (cb , member_opnd (REG_CFP , rb_control_frame_t , jit_return ), REG0 );
300+
273301 return code_ptr ;
274302}
275303
@@ -2005,21 +2033,9 @@ gen_leave(jitstate_t* jit, ctx_t* ctx)
20052033 mov (cb , REG_SP , member_opnd (REG_CFP , rb_control_frame_t , sp ));
20062034 mov (cb , mem_opnd (64 , REG_SP , - SIZEOF_VALUE ), REG0 );
20072035
2008- // If the return address is NULL, fall back to the interpreter
2009- ADD_COMMENT (cb , "check for jit return" );
2010- int FALLBACK_LABEL = cb_new_label (cb , "FALLBACK" );
2011- test (cb , REG1 , REG1 );
2012- jz_label (cb , FALLBACK_LABEL );
2013-
20142036 // Jump to the JIT return address
20152037 jmp_rm (cb , REG1 );
20162038
2017- // Fall back to the interpreter
2018- cb_write_label (cb , FALLBACK_LABEL );
2019- cb_link_labels (cb );
2020- GEN_COUNTER_INC (cb , leave_interp_return );
2021- cb_write_post_call_bytes (cb );
2022-
20232039 return YJIT_END_BLOCK ;
20242040}
20252041
@@ -2080,12 +2096,17 @@ yjit_init_codegen(void)
20802096{
20812097 // Initialize the code blocks
20822098 uint32_t mem_size = 128 * 1024 * 1024 ;
2083- uint8_t * mem_block = alloc_exec_mem (mem_size );
2099+ uint8_t * mem_block = alloc_exec_mem (mem_size );
2100+
20842101 cb = & block ;
20852102 cb_init (cb , mem_block , mem_size /2 );
2103+
20862104 ocb = & outline_block ;
20872105 cb_init (ocb , mem_block + mem_size /2 , mem_size /2 );
20882106
2107+ // Generate interp_exit
2108+ interp_exit = yjit_gen_context_free_exit (cb );
2109+
20892110 // Map YARV opcodes to the corresponding codegen functions
20902111 yjit_reg_op (BIN (dup ), gen_dup );
20912112 yjit_reg_op (BIN (nop ), gen_nop );
0 commit comments