ruby-changes:73135
From: Maxime <ko1@a...>
Date: Tue, 30 Aug 2022 00:55:20 +0900 (JST)
Subject: [ruby-changes:73135] e72dab304e (master): Add atomic counter increment instruction
https://git.ruby-lang.org/ruby.git/commit/?id=e72dab304e From e72dab304e423ad8c98656c146d52f6a8fa4a2c2 Mon Sep 17 00:00:00 2001 From: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@s...> Date: Tue, 14 Jun 2022 15:45:41 -0400 Subject: Add atomic counter increment instruction --- yjit/src/backend/ir.rs | 4 ++++ yjit/src/backend/x86_64/mod.rs | 7 +++++++ yjit/src/codegen.rs | 29 +++++++---------------------- 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/yjit/src/backend/ir.rs b/yjit/src/backend/ir.rs index a077eb1945..10e04c8e2b 100644 --- a/yjit/src/backend/ir.rs +++ b/yjit/src/backend/ir.rs @@ -98,6 +98,9 @@ pub enum Op https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L98 // C function return CRet, + // Atomically increment a counter + IncrCounter, + // Trigger a debugger breakpoint Breakpoint, } @@ -688,6 +691,7 @@ def_push_2_opnd_no_out!(mov, Op::Mov); https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L691 def_push_2_opnd_no_out!(cmp, Op::Cmp); def_push_2_opnd_no_out!(test, Op::Test); def_push_0_opnd_no_out!(breakpoint, Op::Breakpoint); +def_push_2_opnd_no_out!(incr_counter, Op::IncrCounter); // NOTE: these methods are temporary and will likely move // to context.rs later diff --git a/yjit/src/backend/x86_64/mod.rs b/yjit/src/backend/x86_64/mod.rs index 748bf5aea0..17571dd45b 100644 --- a/yjit/src/backend/x86_64/mod.rs +++ b/yjit/src/backend/x86_64/mod.rs @@ -183,6 +183,13 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/x86_64/mod.rs#L183 Op::Je => je_label(cb, insn.target.unwrap().unwrap_label_idx()), + // Atomically increment a counter at a given memory location + Op::IncrCounter => { + assert!(matches!(insn.opnds[0], Opnd::Mem(_))); + write_lock_prefix(cb); + add(cb, insn.opnds[0].into(), insn.opnds[1].into()); + }, + Op::Breakpoint => int3(cb), _ => panic!("unsupported instruction passed to x86 backend: {:?}", insn.op) diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index 3589aaf579..580595d499 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -223,12 +223,8 @@ macro_rules! gen_counter_incr { https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L223 let ptr_reg = $asm.load(Opnd::const_ptr(ptr as *const u8)); let counter_opnd = Opnd::mem(64, ptr_reg, 0); - // FIXME: do we want an atomic add, or an atomic store or swap for arm? - //write_lock_prefix($cb); // for ractors. - // Increment and store the updated value - let incr_opnd = $asm.add(counter_opnd, 1.into()); - $asm.store(counter_opnd, incr_opnd); + $asm.incr_counter(counter_opnd, 1.into() ); } }; } @@ -408,7 +404,7 @@ fn gen_code_for_exit_from_stub(ocb: &mut OutlinedCb) -> CodePtr { https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L404 todo!(); /* - gen_counter_incr!(ocb, exit_from_branch_stub); + gen_counter_incr!(asm, exit_from_branch_stub); cpop(ocb, REG_SP); cpop(ocb, REG_EC); @@ -541,7 +537,7 @@ fn gen_full_cfunc_return(ocb: &mut OutlinedCb) -> CodePtr { https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L537 call_ptr(cb, REG0, rb_full_cfunc_return as *const u8); // Count the exit - gen_counter_incr!(cb, traced_cfunc_return); + gen_counter_incr!(asm, traced_cfunc_return); // Return to the interpreter pop(cb, REG_SP); @@ -562,26 +558,16 @@ fn gen_leave_exit(ocb: &mut OutlinedCb) -> CodePtr { https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L558 let code_ptr = ocb.get_write_ptr(); let mut asm = Assembler::new(); - // Note, gen_leave() fully reconstructs interpreter state and leaves the - // return value in RAX before coming here. + // NOTE: gen_leave() fully reconstructs interpreter state and leaves the + // return value in C_RET_OPND before coming here. - // FIXME // Every exit to the interpreter should be counted - //gen_counter_incr!(ocb, leave_interp_return); + gen_counter_incr!(asm, leave_interp_return); asm.cpop(SP); asm.cpop(EC); asm.cpop(CFP); - // FIXME: we're currently assuming that the return value is in RAX, - // left there by gen_leave() ... - // - // What are our options? - // We could put the return value in C_RET_REG? - // Then call asm.ret with C_RET_REG? - - - asm.cret(C_RET_OPND); asm.compile(ocb); @@ -604,9 +590,8 @@ fn gen_pc_guard(asm: &mut Assembler, iseq: IseqPtr, insn_idx: u32) { https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L590 let pc_match = asm.new_label("pc_match"); asm.je(pc_match); - // FIXME // We're not starting at the first PC, so we need to exit. - //gen_counter_incr!(cb, leave_start_pc_non_zero); + gen_counter_incr!(asm, leave_start_pc_non_zero); asm.cpop(SP); asm.cpop(EC); -- cgit v1.2.1 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/