@@ -27,6 +27,9 @@ codeblock_t* cb = NULL;
27
27
static codeblock_t outline_block ;
28
28
codeblock_t * ocb = NULL ;
29
29
30
+ // Code for exiting back to the interpreter
31
+ static void * interp_exit ;
32
+
30
33
// Print the current source location for debugging purposes
31
34
RBIMPL_ATTR_MAYBE_UNUSED ()
32
35
static void
@@ -137,7 +140,7 @@ yjit_load_regs(codeblock_t* cb)
137
140
static uint8_t *
138
141
yjit_gen_exit (jitstate_t * jit , ctx_t * ctx , codeblock_t * cb )
139
142
{
140
- uint8_t * code_ptr = cb_get_ptr (ocb , ocb -> write_pos );
143
+ uint8_t * code_ptr = cb_get_ptr (cb , cb -> write_pos );
141
144
142
145
VALUE * exit_pc = jit -> pc ;
143
146
@@ -184,6 +187,26 @@ yjit_gen_exit(jitstate_t *jit, ctx_t *ctx, codeblock_t *cb)
184
187
return code_ptr ;
185
188
}
186
189
190
+ // Generate an interpreter to REG_CFP->pc.
191
+ static uint8_t *
192
+ yjit_gen_context_free_exit (codeblock_t * cb )
193
+ {
194
+ uint8_t * code_ptr = cb_get_ptr (cb , cb -> write_pos );
195
+
196
+ // Update the CFP on the EC
197
+ mov (cb , member_opnd (REG_EC , rb_execution_context_t , cfp ), REG_CFP );
198
+
199
+ // Put PC into the return register, which the post call bytes dispatches to
200
+ mov (cb , RAX , member_opnd (REG_CFP , rb_control_frame_t , pc ));
201
+
202
+ cb_write_post_call_bytes (cb );
203
+
204
+ // Note, not incrementing stats here since this exit is the natural end to
205
+ // executing output code.
206
+
207
+ return code_ptr ;
208
+ }
209
+
187
210
188
211
// A shorthand for generating an exit in the outline block
189
212
static uint8_t *
@@ -251,7 +274,7 @@ yjit_comment_array_t yjit_code_comments;
251
274
Compile an interpreter entry block to be inserted into an iseq
252
275
Returns `NULL` if compilation fails.
253
276
*/
254
- uint8_t *
277
+ uint8_t *
255
278
yjit_entry_prologue (void )
256
279
{
257
280
RUBY_ASSERT (cb != NULL );
@@ -271,6 +294,11 @@ yjit_entry_prologue(void)
271
294
// Load the current SP from the CFP into REG_SP
272
295
mov (cb , REG_SP , member_opnd (REG_CFP , rb_control_frame_t , sp ));
273
296
297
+ // Setup cfp->jit_return
298
+ // TODO: this could use a IP relative LEA instead of an 8 byte immediate
299
+ mov (cb , REG0 , const_ptr_opnd (interp_exit ));
300
+ mov (cb , member_opnd (REG_CFP , rb_control_frame_t , jit_return ), REG0 );
301
+
274
302
return code_ptr ;
275
303
}
276
304
@@ -2076,21 +2104,9 @@ gen_leave(jitstate_t* jit, ctx_t* ctx)
2076
2104
mov (cb , REG_SP , member_opnd (REG_CFP , rb_control_frame_t , sp ));
2077
2105
mov (cb , mem_opnd (64 , REG_SP , - SIZEOF_VALUE ), REG0 );
2078
2106
2079
- // If the return address is NULL, fall back to the interpreter
2080
- ADD_COMMENT (cb , "check for jit return" );
2081
- int FALLBACK_LABEL = cb_new_label (cb , "FALLBACK" );
2082
- test (cb , REG1 , REG1 );
2083
- jz_label (cb , FALLBACK_LABEL );
2084
-
2085
2107
// Jump to the JIT return address
2086
2108
jmp_rm (cb , REG1 );
2087
2109
2088
- // Fall back to the interpreter
2089
- cb_write_label (cb , FALLBACK_LABEL );
2090
- cb_link_labels (cb );
2091
- GEN_COUNTER_INC (cb , leave_interp_return );
2092
- cb_write_post_call_bytes (cb );
2093
-
2094
2110
return YJIT_END_BLOCK ;
2095
2111
}
2096
2112
@@ -2151,12 +2167,17 @@ yjit_init_codegen(void)
2151
2167
{
2152
2168
// Initialize the code blocks
2153
2169
uint32_t mem_size = 128 * 1024 * 1024 ;
2154
- uint8_t * mem_block = alloc_exec_mem (mem_size );
2170
+ uint8_t * mem_block = alloc_exec_mem (mem_size );
2171
+
2155
2172
cb = & block ;
2156
2173
cb_init (cb , mem_block , mem_size /2 );
2174
+
2157
2175
ocb = & outline_block ;
2158
2176
cb_init (ocb , mem_block + mem_size /2 , mem_size /2 );
2159
2177
2178
+ // Generate interp_exit
2179
+ interp_exit = yjit_gen_context_free_exit (cb );
2180
+
2160
2181
// Map YARV opcodes to the corresponding codegen functions
2161
2182
yjit_reg_op (BIN (dup ), gen_dup );
2162
2183
yjit_reg_op (BIN (nop ), gen_nop );
0 commit comments