ruby-changes:73174
From: Maxime <ko1@a...>
Date: Tue, 30 Aug 2022 00:58:00 +0900 (JST)
Subject: [ruby-changes:73174] 65019ed60c (master): Get codegen for deferred compilation working
https://git.ruby-lang.org/ruby.git/commit/?id=65019ed60c From 65019ed60c635b34337ea35978e931d09ab0181b Mon Sep 17 00:00:00 2001 From: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@s...> Date: Thu, 7 Jul 2022 10:49:59 -0400 Subject: Get codegen for deferred compilation working --- yjit/src/codegen.rs | 42 +++++++++++++++++++++++------------ yjit/src/core.rs | 63 +++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 72 insertions(+), 33 deletions(-) diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index 656fc63c0c..6c8fd950a6 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -34,9 +34,10 @@ pub use crate::virtualmem::CodePtr; https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L34 /// Status returned by code generation functions #[derive(PartialEq, Debug)] enum CodegenStatus { - EndBlock, KeepCompiling, CantCompile, + EndBlock, + DeferCompilation, } /// Code generation function signature @@ -734,6 +735,9 @@ pub fn gen_single_block( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L735 // Create a backend assembler instance let mut asm = Assembler::new(); + // Codegen status for the last instruction compiled + let mut status = CantCompile; + // For each instruction to compile // NOTE: could rewrite this loop with a std::iter::Iterator while insn_idx < iseq_size { @@ -759,16 +763,12 @@ pub fn gen_single_block( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L763 // If previous instruction requested to record the boundary if jit.record_boundary_patch_point { - // FIXME: is this sound with the new assembler? // Generate an exit to this instruction and record it let exit_pos = gen_outlined_exit(jit.pc, &ctx, ocb); record_global_inval_patch(cb, exit_pos); jit.record_boundary_patch_point = false; - - - } // In debug mode, verify our existing assumption @@ -777,7 +777,7 @@ pub fn gen_single_block( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L777 } // Lookup the codegen function for this instruction - let mut status = CantCompile; + status = CantCompile; if let Some(gen_fn) = get_gen_fn(VALUE(opcode)) { // :count-placement: // Count bytecode instructions that execute in generated code. @@ -820,6 +820,11 @@ pub fn gen_single_block( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L820 break; } + // If we are deferring compilation for this instruction + if status == DeferCompilation { + break; + } + // For now, reset the chain depth after each instruction as only the // first instruction in the block can concern itself with the depth. ctx.reset_chain_depth(); @@ -850,10 +855,25 @@ pub fn gen_single_block( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L855 block.set_end_idx(insn_idx); } + // If we are deferring compilation for the current instruction + if status == DeferCompilation { + defer_compilation(&jit.block, insn_idx, &ctx, cb, ocb); + + // Mark the end position of the block + let mut block = jit.block.borrow_mut(); + block.set_end_addr(cb.get_write_ptr()); + } + + + // We currently can't handle cases where the request is for a block that // doesn't go to the next instruction. //assert!(!jit.record_boundary_patch_point); + + + + // If code for the block doesn't fit, fail if cb.has_dropped_bytes() || ocb.unwrap().has_dropped_bytes() { return Err(()); @@ -1100,8 +1120,6 @@ fn gen_adjuststack( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L1120 KeepCompiling } - -/* fn gen_opt_plus( jit: &mut JITState, ctx: &mut Context, @@ -1109,8 +1127,7 @@ fn gen_opt_plus( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L1127 ocb: &mut OutlinedCb, ) -> CodegenStatus { if !jit_at_current_insn(jit) { - defer_compilation(jit, ctx, cb, ocb); - return EndBlock; + return DeferCompilation; } let comptime_a = jit_peek_at_stack(jit, ctx, 1); @@ -1147,9 +1164,6 @@ fn gen_opt_plus( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L1164 //gen_opt_send_without_block(jit, ctx, cb, ocb) } } -*/ - - // new array initialized from top N values fn gen_newarray( @@ -5969,7 +5983,7 @@ fn get_gen_fn(opcode: VALUE) -> Option<InsnGenFn> { https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L5983 //YARVINSN_setlocal => Some(gen_setlocal), //YARVINSN_setlocal_WC_0 => Some(gen_setlocal_wc0), //YARVINSN_setlocal_WC_1 => Some(gen_setlocal_wc1), - //YARVINSN_opt_plus => Some(gen_opt_plus), + YARVINSN_opt_plus => Some(gen_opt_plus), /* YARVINSN_opt_minus => Some(gen_opt_minus), YARVINSN_opt_and => Some(gen_opt_and), diff --git a/yjit/src/core.rs b/yjit/src/core.rs index a2659b55fd..1b90260248 100644 --- a/yjit/src/core.rs +++ b/yjit/src/core.rs @@ -255,7 +255,7 @@ pub enum InsnOpnd { https://github.com/ruby/ruby/blob/trunk/yjit/src/core.rs#L255 /// Code generation context /// Contains information we can use to specialize/optimize code /// There are a lot of context objects so we try to keep the size small. -#[derive(Copy, Clone, Default, Debug)] +#[derive(Copy, Clone, Default, PartialEq, Debug)] pub struct Context { // Number of values currently on the temporary stack stack_size: u16, @@ -301,7 +301,7 @@ pub enum BranchShape { https://github.com/ruby/ruby/blob/trunk/yjit/src/core.rs#L301 // Branch code generation function signature type BranchGenFn = - fn(cb: &mut CodeBlock, target0: CodePtr, target1: Option<CodePtr>, shape: BranchShape) -> (); + fn(cb: &mut Assembler, target0: CodePtr, target1: Option<CodePtr>, shape: BranchShape) -> (); /// Store info about an outgoing branch in a code segment /// Note: care must be taken to minimize the size of branch objects @@ -1511,12 +1511,18 @@ fn regenerate_branch(cb: &mut CodeBlock, branch: &mut Branch) { https://github.com/ruby/ruby/blob/trunk/yjit/src/core.rs#L1511 // Rewrite the branch assert!(branch.dst_addrs[0].is_some()); cb.set_write_ptr(branch.start_addr.unwrap()); + + let mut asm = Assembler::new(); + (branch.gen_fn)( - cb, + &mut asm, branch.dst_addrs[0].unwrap(), branch.dst_addrs[1], branch.shape, ); + + asm.compile(cb); + branch.end_addr = Some(cb.get_write_ptr()); // The block may have shrunk after the branch is rewritten @@ -1542,7 +1548,7 @@ fn regenerate_branch(cb: &mut CodeBlock, branch: &mut Branch) { https://github.com/ruby/ruby/blob/trunk/yjit/src/core.rs#L1548 } /// Create a new outgoing branch entry for a block -fn make_branch_entry(block: BlockRef, src_ctx: &Context, gen_fn: BranchGenFn) -> BranchRef { +fn make_branch_entry(block: &BlockRef, src_ctx: &Context, gen_fn: BranchGenFn) -> BranchRef { let branch = Branch { // Block this is attached to block: block.clone(), @@ -1591,6 +1597,10 @@ extern "sysv64" fn branch_stub_hit( https://github.com/ruby/ruby/blob/trunk/yjit/src/core.rs#L1597 /// Called by the generated code when a branch stub is executed /// Triggers compilation of branches and code patching fn branch_stub_hit_body(branch_ptr: *const c_void, target_idx: u32, ec: EcPtr) -> *const u8 { + if get_option!(dump_insns) { + println!("branch_stub_hit"); + } + assert!(!branch_ptr.is_null()); //branch_ptr is actually: @@ -1770,13 +1780,13 @@ fn get_branch_target( https://github.com/ruby/ruby/blob/trunk/yjit/src/core.rs#L1780 let mut asm = Assembler::new(); - // Call branch_stub_hit(branch_idx, target_idx, ec) + // Call branch_stub_hit(branch_ptr, target_idx, ec) let jump_addr = asm.ccall( branch_stub_hit as *mut u8, vec![ - EC, + Opnd::const_ptr(branch_ptr as *const u8), Opnd::UImm(target_idx as u64), - Opnd::const_ptr(branch_ptr as *const u8) + EC, ] ); @@ -1804,7 +1814,7 @@ pub fn gen_branch( https://github.com/ruby/ruby/blob/trunk/yjit/src/core.rs#L1814 ctx1: Option<&Context>, gen_fn: BranchGenFn, ) { - let branchref = make_branch_entry(jit.get_block(), src_ctx, gen_fn); + let branchref = make_branch_entry(&jit.get_block(), src_ctx, gen_fn); // Get the branch targets or stubs let dst_addr0 = get_branch_target(target0, ctx0, &branchref, 0, ocb); @@ -1835,7 +1845,7 @@ pub fn gen_branch( https://github.com/ruby/ruby/blob/trunk/yjit/src/core.rs#L1845 } fn gen_jump_branch( - cb: &mut CodeBlock, + asm: &mut Assembler, target0: CodePtr, _target1: Option<CodePtr>, shape: BranchShape, @@ -1845,13 +1855,12 @@ fn gen_jump_branch( https://github.com/ruby/ruby/blob/trunk/yjit/src/core.rs#L1855 } if shape == BranchShape::Default { - //jmp_ptr(cb, target0); - todo!("jmp_ptr with new assembler"); + asm.jmp(target0.into()); } } pub fn gen_direct_jump(jit: &JITState, ctx: &Context, target0: BlockId, cb: &mut CodeBlock) { - let branchref = make_branch_entry(jit.get_block(), ctx, gen_jump_branch); + let branchref = make_branch_entry(&jit.get_block(), ctx, gen_jump_branch); let mut branch = branchref.borrow_mut(); branch.targets[0] = Some(target0); @@ -1869,10 +1878,25 @@ pub fn gen_direct_jump(jit: &JITState, ctx: &Context, target0: BlockId, cb: &mut https://github.com/ruby/ruby/blob/trunk/yjit/src/core.rs#L1878 branch.blocks[0] = Some(blockref.clone()); branch.shape = BranchShape::Default; + + + todo!("convert gen_direct_jump to using new asm"); + + + // TODO: could we use regenerate_branch logic here? + + /* // Call t (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/