@@ -9,6 +9,7 @@ use crate::options::*;
99use crate :: stats:: * ;
1010use InsnOpnd :: * ;
1111use TempMapping :: * ;
12+ use core:: ffi:: { c_void} ;
1213
1314// Maximum number of temp value types we keep track of
1415const MAX_TEMP_TYPES : usize = 8 ;
@@ -1219,132 +1220,142 @@ fn make_branch_entry(block: BlockRef, src_ctx: &Context, gen_fn: BranchGenFn) ->
12191220// Called by the generated code when a branch stub is executed
12201221// Triggers compilation of branches and code patching
12211222#[ no_mangle]
1222- pub extern "C" fn branch_stub_hit ( branch_ptr : * const u8 , target_idx : u32 , ec : EcPtr ) -> * const u8
1223+ pub extern "C" fn rb_yjit_rust_branch_stub_hit ( branch_ptr : * const c_void , target_idx : u32 , ec : EcPtr ) -> * const u8
12231224{
1225+ assert ! ( !branch_ptr. is_null( ) ) ;
1226+
12241227 //branch_ptr is actually:
12251228 //branch_ptr: *const RefCell<Branch>
1229+ let branch_rc = unsafe { BranchRef :: from_raw ( branch_ptr as * const RefCell < Branch > ) } ;
1230+ let mut branch = branch_rc. borrow_mut ( ) ;
12261231
1227- todo ! ( ) ;
1228-
1229- // NOTE: here we need to take the VM lock. Should we call this function from C?
1232+ let branch_size_on_entry = branch. code_size ( ) ;
12301233
1231- /*
1232- uint8_t *dst_addr = NULL;
1234+ let target_idx: usize = target_idx as usize ;
1235+ let target = branch. targets [ target_idx] ;
1236+ let target_ctx = branch. target_ctxs [ target_idx] ;
12331237
1234- // Stop other ractors since we are going to patch machine code.
1235- // This is how the GC does it.
1236- RB_VM_LOCK_ENTER();
1237- rb_vm_barrier();
1238-
1239- const ptrdiff_t branch_size_on_entry = branch_code_size(branch);
1238+ let target_branch_shape = match target_idx {
1239+ 0 => BranchShape :: Next0 ,
1240+ 1 => BranchShape :: Next1 ,
1241+ _ => unreachable ! ( "target_idx < 2 must always hold" )
1242+ } ;
12401243
1241- RUBY_ASSERT(branch != NULL);
1242- RUBY_ASSERT(target_idx < 2);
1243- blockid_t target = branch->targets[target_idx];
1244- const ctx_t *target_ctx = &branch->target_ctxs[target_idx];
1244+ let cb = CodegenGlobals :: get_inline_cb ( ) ;
1245+ let ocb = CodegenGlobals :: get_outlined_cb ( ) ;
12451246
12461247 // If this branch has already been patched, return the dst address
12471248 // Note: ractors can cause the same stub to be hit multiple times
1248- if ( branch-> blocks[target_idx]) {
1249- dst_addr = branch-> dst_addrs[target_idx];
1249+ if let Some ( _ ) = branch. blocks [ target_idx] {
1250+ return branch. dst_addrs [ target_idx] . unwrap ( ) . raw_ptr ( ) ;
12501251 }
1251- else {
1252- rb_vm_barrier();
1252+
1253+ let ( cfp, original_interp_sp) = unsafe {
1254+ let cfp = get_ec_cfp ( ec) ;
1255+ let original_interp_sp = get_cfp_sp ( cfp) ;
1256+
1257+ let reconned_pc = rb_iseq_pc_at_idx ( rb_cfp_get_iseq ( cfp) , target. idx ) ;
1258+ let reconned_sp = original_interp_sp. add ( target_ctx. sp_offset as usize ) ;
1259+
1260+ // Update the PC in the current CFP, because it may be out of sync in JITted code
1261+ rb_set_cfp_pc ( cfp, reconned_pc) ;
12531262
12541263 // :stub-sp-flush:
12551264 // Generated code do stack operations without modifying cfp->sp, while the
12561265 // cfp->sp tells the GC what values on the stack to root. Generated code
12571266 // generally takes care of updating cfp->sp when it calls runtime routines that
12581267 // could trigger GC, but it's inconvenient to do it before calling this function.
12591268 // So we do it here instead.
1260- VALUE *const original_interp_sp = ec->cfp->sp;
1261- ec->cfp->sp += target_ctx->sp_offset;
1269+ rb_set_cfp_sp ( cfp, reconned_sp) ;
12621270
1263- // Update the PC in the current CFP, because it
1264- // may be out of sync in JITted code
1265- ec->cfp->pc = yjit_iseq_pc_at_idx(target.iseq, target.idx);
1271+ ( cfp, original_interp_sp)
1272+ } ;
12661273
1267- // Try to find an existing compiled version of this block
1268- block_t *p_block = find_block_version(target, target_ctx);
12691274
1270- // If this block hasn't yet been compiled
1271- if (!p_block) {
1272- const uint8_t branch_old_shape = branch->shape;
1273- bool branch_modified = false;
1275+ // Try to find an existing compiled version of this block
1276+ let mut block = find_block_version ( target, & target_ctx) ;
12741277
1275- // If the new block can be generated right after the branch (at cb->write_pos)
1276- if (cb.get_write_ptr() == branch->end_addr) {
1277- // This branch should be terminating its block
1278- RUBY_ASSERT(branch->end_addr == branch->block->end_addr);
1278+ // If this block hasn't yet been compiled
1279+ if block. is_none ( ) {
12791280
1280- // Change the branch shape to indicate the target block will be placed next
1281- branch->shape = (uint8_t)target_idx ;
1281+ let branch_old_shape = branch. shape ;
1282+ let mut branch_modified = false ;
12821283
1283- // Rewrite the branch with the new, potentially more compact shape
1284- regenerate_branch (cb, branch);
1285- branch_modified = true ;
1284+ // If the new block can be generated right after the branch (at cb->write_pos)
1285+ if Some ( cb. get_write_ptr ( ) ) == branch. end_addr {
1286+ let branch_end_addr = branch . end_addr . unwrap ( ) ;
12861287
1287- // Ensure that the branch terminates the codeblock just like
1288- // before entering this if block. This drops bytes off the end
1289- // in case we shrank the branch when regenerating.
1290- cb_set_write_ptr(cb, branch->end_addr);
1291- }
1288+ // This branch should be terminating its block
1289+ assert ! ( branch. end_addr == branch. block. borrow( ) . end_addr) ;
12921290
1293- // Compile the new block version
1294- p_block = gen_block_series(target, target_ctx, ec) ;
1291+ // Change the branch shape to indicate the target block will be placed next
1292+ branch . shape = target_branch_shape ;
12951293
1296- if (!p_block && branch_modified) {
1297- // We couldn't generate a new block for the branch, but we modified the branch.
1298- // Restore the branch by regenerating it.
1299- branch->shape = branch_old_shape;
1300- regenerate_branch(cb, branch);
1301- }
1294+ // Rewrite the branch with the new, potentially more compact shape
1295+ regenerate_branch ( cb, & mut branch) ;
1296+ branch_modified = true ;
1297+
1298+ // Ensure that the branch terminates the codeblock just like
1299+ // before entering this if block. This drops bytes off the end
1300+ // in case we shrank the branch when regenerating.
1301+ cb. set_write_ptr ( branch_end_addr) ;
13021302 }
13031303
1304- if (p_block) {
1304+ // Compile the new block version
1305+ block = gen_block_series ( target, & target_ctx, ec, cb, ocb) ;
1306+
1307+ if block. is_none ( ) && branch_modified {
1308+ // We couldn't generate a new block for the branch, but we modified the branch.
1309+ // Restore the branch by regenerating it.
1310+ branch. shape = branch_old_shape;
1311+ regenerate_branch ( cb, & mut branch) ;
1312+ }
1313+ }
1314+
1315+ let dst_addr = match block {
1316+ Some ( block_rc) => {
1317+ let mut block = block_rc. borrow_mut ( ) ;
13051318 // Branch shape should reflect layout
1306- RUBY_ASSERT(! (branch-> shape == (uint8_t)target_idx && p_block-> start_addr != branch-> end_addr));
1319+ assert ! ( ! ( branch. shape == target_branch_shape && block . start_addr != branch. end_addr) ) ;
13071320
13081321 // Add this branch to the list of incoming branches for the target
1309- rb_darray_append(&p_block-> incoming, branch );
1322+ block . incoming . push ( branch_rc . clone ( ) ) ;
13101323
13111324 // Update the branch target address
1312- dst_addr = p_block-> start_addr;
1313- branch-> dst_addrs[target_idx] = dst_addr;
1325+ let dst_addr = block . start_addr ;
1326+ branch. dst_addrs [ target_idx] = dst_addr;
13141327
13151328 // Mark this branch target as patched (no longer a stub)
1316- branch-> blocks[target_idx] = p_block ;
1329+ branch. blocks [ target_idx] = Some ( block_rc . clone ( ) ) ;
13171330
13181331 // Rewrite the branch with the new jump target address
1319- regenerate_branch(cb, branch);
1332+ regenerate_branch ( cb, & mut branch) ;
13201333
13211334 // Restore interpreter sp, since the code hitting the stub expects the original.
1322- ec->cfp->sp = original_interp_sp;
1335+ unsafe { rb_set_cfp_sp ( cfp, original_interp_sp) } ;
1336+
1337+ block. start_addr . unwrap ( )
13231338 }
1324- else {
1339+ None => {
13251340 // Failed to service the stub by generating a new block so now we
13261341 // need to exit to the interpreter at the stubbed location. We are
13271342 // intentionally *not* restoring original_interp_sp. At the time of
13281343 // writing, reconstructing interpreter state only involves setting
13291344 // cfp->sp and cfp->pc. We set both before trying to generate the
13301345 // block. All there is left to do to exit is to pop the native
13311346 // frame. We do that in code_for_exit_from_stub.
1332- dst_addr = code_for_exit_from_stub;
1347+ todo ! ( " code_for_exit_from_stub" ) ;
13331348 }
1349+ } ;
13341350
1335- cb_mark_all_executable(ocb);
1336- cb_mark_all_executable(cb);
1337- }
1338-
1339- const ptrdiff_t new_branch_size = branch_code_size(branch);
1340- RUBY_ASSERT_ALWAYS(new_branch_size >= 0);
1341- RUBY_ASSERT_ALWAYS(new_branch_size <= branch_size_on_entry && "branch stubs should not enlarge branches");
1351+ ocb. unwrap ( ) . mark_all_executable ( ) ;
1352+ cb. mark_all_executable ( ) ;
13421353
1343- RB_VM_LOCK_LEAVE();
1354+ let new_branch_size = branch. code_size ( ) ;
1355+ assert ! ( new_branch_size <= branch_size_on_entry, "branch stubs should not enlarge branches" ) ;
13441356
13451357 // Return a pointer to the compiled block version
1346- return dst_addr;
1347- */
1358+ dst_addr. raw_ptr ( )
13481359}
13491360
13501361// Get a version or stub corresponding to a branch target
@@ -1384,7 +1395,7 @@ fn get_branch_target(
13841395 mov ( ocb, C_ARG_REGS [ 2 ] , REG_EC ) ;
13851396 mov ( ocb, C_ARG_REGS [ 1 ] , uimm_opnd ( target_idx as u64 ) ) ;
13861397 mov ( ocb, C_ARG_REGS [ 0 ] , const_ptr_opnd ( branch_ptr as * const u8 ) ) ;
1387- call_ptr ( ocb, REG0 , branch_stub_hit as * mut u8 ) ;
1398+ call_ptr ( ocb, REG0 , rb_yjit_branch_stub_hit as * mut u8 ) ;
13881399
13891400 // Jump to the address returned by the
13901401 // branch_stub_hit call
0 commit comments