ruby-changes:73136
From: Maxime <ko1@a...>
Date: Tue, 30 Aug 2022 00:55:20 +0900 (JST)
Subject: [ruby-changes:73136] 27fcab995e (master): Get side exits working, get miniruby to boot with threshold=1
https://git.ruby-lang.org/ruby.git/commit/?id=27fcab995e From 27fcab995e6dde19deb91dc6e291bdb72100af68 Mon Sep 17 00:00:00 2001 From: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@s...> Date: Tue, 14 Jun 2022 13:41:53 -0400 Subject: Get side exits working, get miniruby to boot with threshold=1 --- yjit/src/codegen.rs | 110 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 65 insertions(+), 45 deletions(-) diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index 4d5e73686d..3589aaf579 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -397,74 +397,86 @@ fn verify_ctx(jit: &JITState, ctx: &Context) { https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L397 } } -/// Generate an exit to return to the interpreter -fn gen_exit(exit_pc: *mut VALUE, ctx: &Context, cb: &mut CodeBlock) -> CodePtr { - let code_ptr = cb.get_write_ptr(); +// Fill code_for_exit_from_stub. This is used by branch_stub_hit() to exit +// to the interpreter when it cannot service a stub by generating new code. +// Before coming here, branch_stub_hit() takes care of fully reconstructing +// interpreter state. +fn gen_code_for_exit_from_stub(ocb: &mut OutlinedCb) -> CodePtr { + let ocb = ocb.unwrap(); + let code_ptr = ocb.get_write_ptr(); todo!(); /* - add_comment(cb, "exit to interpreter"); + gen_counter_incr!(ocb, exit_from_branch_stub); + + cpop(ocb, REG_SP); + cpop(ocb, REG_EC); + cpop(ocb, REG_CFP); + + mov(ocb, RAX, uimm_opnd(Qundef.into())); + ret(ocb); + + return code_ptr; + */ +} + +/// Generate an exit to return to the interpreter +fn gen_exit(exit_pc: *mut VALUE, ctx: &Context, asm: &mut Assembler) { + asm.comment("exit to interpreter"); // Generate the code to exit to the interpreters // Write the adjusted SP back into the CFP if ctx.get_sp_offset() != 0 { - let stack_pointer = ctx.sp_opnd(0); - lea(cb, REG_SP, stack_pointer.into()); - mov(cb, mem_opnd(64, REG_CFP, RUBY_OFFSET_CFP_SP), REG_SP); + let sp_opnd = asm.lea(ctx.sp_opnd(0)); + asm.mov( + Opnd::mem(64, CFP, RUBY_OFFSET_CFP_SP), + sp_opnd + ); } // Update CFP->PC - mov(cb, RAX, const_ptr_opnd(exit_pc as *const u8)); - mov(cb, mem_opnd(64, REG_CFP, RUBY_OFFSET_CFP_PC), RAX); + asm.mov( + Opnd::mem(64, CFP, RUBY_OFFSET_CFP_PC), + Opnd::const_ptr(exit_pc as *const u8) + ); // Accumulate stats about interpreter exits #[cfg(feature = "stats")] if get_option!(gen_stats) { - mov(cb, RDI, const_ptr_opnd(exit_pc as *const u8)); - call_ptr(cb, RSI, rb_yjit_count_side_exit_op as *const u8); + asm.ccall( + rb_yjit_count_side_exit_op as *const u8, + vec![Opnd::const_ptr(exit_pc as *const u8)] + ); // If --yjit-trace-exits option is enabled, record the exit stack // while recording the side exits. if get_option!(gen_trace_exits) { - mov(cb, C_ARG_REGS[0], const_ptr_opnd(exit_pc as *const u8)); - call_ptr(cb, REG0, rb_yjit_record_exit_stack as *const u8); + asm.ccall( + rb_yjit_record_exit_stack as *const u8, + vec![Opnd::const_ptr(exit_pc as *const u8)] + ); } } - pop(cb, REG_SP); - pop(cb, REG_EC); - pop(cb, REG_CFP); - - mov(cb, RAX, uimm_opnd(Qundef.into())); - ret(cb); + asm.cpop(SP); + asm.cpop(EC); + asm.cpop(CFP); - return code_ptr; - */ + asm.cret(Qundef.into()); } -// Fill code_for_exit_from_stub. This is used by branch_stub_hit() to exit -// to the interpreter when it cannot service a stub by generating new code. -// Before coming here, branch_stub_hit() takes care of fully reconstructing -// interpreter state. -fn gen_code_for_exit_from_stub(ocb: &mut OutlinedCb) -> CodePtr { - let ocb = ocb.unwrap(); - let code_ptr = ocb.get_write_ptr(); - - todo!(); - - /* - gen_counter_incr!(ocb, exit_from_branch_stub); +/// Generate an exit to the interpreter in the outlined code block +fn gen_outlined_exit(exit_pc: *mut VALUE, ctx: &Context, ocb: &mut OutlinedCb) -> CodePtr { + let mut cb = ocb.unwrap(); + let exit_code = cb.get_write_ptr(); + let mut asm = Assembler::new(); - cpop(ocb, REG_SP); - cpop(ocb, REG_EC); - cpop(ocb, REG_CFP); + gen_exit(exit_pc, ctx, &mut asm); - mov(ocb, RAX, uimm_opnd(Qundef.into())); - ret(ocb); + asm.compile(&mut cb); - return code_ptr; - */ + exit_code } // :side-exit: @@ -482,7 +494,7 @@ fn gen_code_for_exit_from_stub(ocb: &mut OutlinedCb) -> CodePtr { https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L494 fn get_side_exit(jit: &mut JITState, ocb: &mut OutlinedCb, ctx: &Context) -> CodePtr { match jit.side_exit_for_pc { None => { - let exit_code = gen_exit(jit.pc, ctx, ocb.unwrap()); + let exit_code = gen_outlined_exit(jit.pc, ctx, ocb); jit.side_exit_for_pc = Some(exit_code); exit_code } @@ -502,13 +514,13 @@ pub fn jit_ensure_block_entry_exit(jit: &mut JITState, ocb: &mut OutlinedCb) { https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L514 return; } + // If we're compiling the first instruction in the block. if jit.insn_idx == blockid.idx { - // We are compiling the first instruction in the block. // Generate the exit with the cache in jitstate. block.entry_exit = Some(get_side_exit(jit, ocb, &block_ctx)); } else { let pc = unsafe { rb_iseq_pc_at_idx(blockid.iseq, blockid.idx) }; - block.entry_exit = Some(gen_exit(pc, &block_ctx, ocb.unwrap())); + block.entry_exit = Some(gen_outlined_exit(jit.pc, &block_ctx, ocb)); } } @@ -705,10 +717,14 @@ fn jump_to_next_insn( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L717 // We are at the end of the current instruction. Record the boundary. if jit.record_boundary_patch_point { + todo!(); + + /* let next_insn = unsafe { jit.pc.offset(insn_len(jit.opcode).try_into().unwrap()) }; let exit_pos = gen_exit(next_insn, &reset_depth, ocb.unwrap()); record_global_inval_patch(cb, exit_pos); jit.record_boundary_patch_point = false; + */ } // Generate the jump instruction @@ -777,10 +793,14 @@ pub fn gen_single_block( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L793 // If previous instruction requested to record the boundary if jit.record_boundary_patch_point { + todo!("record_boundary_patch_point"); + + /* // Generate an exit to this instruction and record it let exit_pos = gen_exit(jit.pc, &ctx, ocb.unwrap()); record_global_inval_patch(cb, exit_pos); jit.record_boundary_patch_point = false; + */ } // In debug mode, verify our existing assumption @@ -817,12 +837,12 @@ pub fn gen_single_block( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L837 // TODO: if the codegen function makes changes to ctx and then return YJIT_CANT_COMPILE, // the exit this generates would be wrong. We could save a copy of the entry context // and assert that ctx is the same here. - let exit = gen_exit(jit.pc, &ctx, cb); + gen_exit(jit.pc, &ctx, &mut asm); // If this is the first instruction in the block, then we can use // the exit for block->entry_exit. if insn_idx == block.get_blockid().idx { - block.entry_exit = Some(exit); + block.entry_exit = block.get_start_addr(); } break; -- cgit v1.2.1 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/