ruby-changes:73282
From: Takashi <ko1@a...>
Date: Tue, 30 Aug 2022 01:07:33 +0900 (JST)
Subject: [ruby-changes:73282] df84832c75 (master): Port getblockparamproxy and getblockparam (https://github.com/Shopify/ruby/pull/394)
https://git.ruby-lang.org/ruby.git/commit/?id=df84832c75 From df84832c758e3dcb360f18335c2c93dcc90344aa Mon Sep 17 00:00:00 2001 From: Takashi Kokubun <takashikkbn@g...> Date: Wed, 10 Aug 2022 13:29:01 -0700 Subject: Port getblockparamproxy and getblockparam (https://github.com/Shopify/ruby/pull/394) --- bootstraptest/test_yjit.rb | 16 ++++++ yjit/src/codegen.rs | 132 +++++++++++++++++++-------------------------- 2 files changed, 70 insertions(+), 78 deletions(-) diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb index 7aed5ac43c..d44fe25800 100644 --- a/bootstraptest/test_yjit.rb +++ b/bootstraptest/test_yjit.rb @@ -3220,3 +3220,19 @@ assert_equal 'foo', %q{ https://github.com/ruby/ruby/blob/trunk/bootstraptest/test_yjit.rb#L3220 Foo = Struct.new(:bar) Foo.new("foo").bar } + +# getblockparamproxy +assert_equal 'foo', %q{ + def foo(&block) + block.call + end + foo { "foo" } +} + +# getblockparam +assert_equal 'foo', %q{ + def foo(&block) + block + end + foo { "foo" }.call +} diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index 1ac4f54952..b5b145790c 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -5556,6 +5556,7 @@ fn gen_opt_getinlinecache( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L5556 ); EndBlock } +*/ // Push the explicit block parameter onto the temporary stack. Part of the // interpreter's scheme for avoiding Proc allocations when delegating @@ -5563,11 +5564,11 @@ fn gen_opt_getinlinecache( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L5564 fn gen_getblockparamproxy( jit: &mut JITState, ctx: &mut Context, - cb: &mut CodeBlock, + asm: &mut Assembler, ocb: &mut OutlinedCb, ) -> CodegenStatus { if !jit_at_current_insn(jit) { - defer_compilation(jit, ctx, cb, ocb); + defer_compilation(jit, ctx, asm, ocb); return EndBlock; } @@ -5590,79 +5591,64 @@ fn gen_getblockparamproxy( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L5591 } // Load environment pointer EP from CFP - gen_get_ep(cb, REG0, level); + let ep_opnd = gen_get_ep(asm, level); // Bail when VM_ENV_FLAGS(ep, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM) is non zero - let flag_check = mem_opnd( + let flag_check = Opnd::mem( 64, - REG0, + ep_opnd, (SIZEOF_VALUE as i32) * (VM_ENV_DATA_INDEX_FLAGS as i32), ); - test( - cb, - flag_check, - uimm_opnd(VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM.into()), - ); - jnz_ptr(cb, counted_exit!(ocb, side_exit, gbpp_block_param_modified)); + asm.test(flag_check, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM.into()); + asm.jnz(counted_exit!(ocb, side_exit, gbpp_block_param_modified).into()); // Load the block handler for the current frame // note, VM_ASSERT(VM_ENV_LOCAL_P(ep)) - mov( - cb, - REG0, - mem_opnd( - 64, - REG0, - (SIZEOF_VALUE as i32) * (VM_ENV_DATA_INDEX_SPECVAL as i32), - ), + let block_handler = asm.load( + Opnd::mem(64, ep_opnd, (SIZEOF_VALUE as i32) * (VM_ENV_DATA_INDEX_SPECVAL as i32)) ); // Specialize compilation for the case where no block handler is present if comptime_handler.as_u64() == 0 { // Bail if there is a block handler - cmp(cb, REG0, uimm_opnd(0)); + asm.cmp(block_handler, Opnd::UImm(0)); jit_chain_guard( JCC_JNZ, jit, &starting_context, - cb, + asm, ocb, SEND_MAX_DEPTH, side_exit, ); - jit_putobject(jit, ctx, cb, Qnil); + jit_putobject(jit, ctx, asm, Qnil); } else { // Block handler is a tagged pointer. Look at the tag. 0x03 is from VM_BH_ISEQ_BLOCK_P(). - and(cb, REG0_8, imm_opnd(0x3)); + let block_handler = asm.and(block_handler, 0x3.into()); // Bail unless VM_BH_ISEQ_BLOCK_P(bh). This also checks for null. - cmp(cb, REG0_8, imm_opnd(0x1)); + asm.cmp(block_handler, 0x1.into()); jit_chain_guard( JCC_JNZ, jit, &starting_context, - cb, + asm, ocb, SEND_MAX_DEPTH, side_exit, ); // Push rb_block_param_proxy. It's a root, so no need to use jit_mov_gc_ptr. - mov( - cb, - REG0, - const_ptr_opnd(unsafe { rb_block_param_proxy }.as_ptr()), - ); assert!(!unsafe { rb_block_param_proxy }.special_const_p()); let top = ctx.stack_push(Type::Unknown); - mov(cb, top, REG0); + asm.mov(top, Opnd::const_ptr(unsafe { rb_block_param_proxy }.as_ptr())); } - jump_to_next_insn(jit, ctx, cb, ocb); + jump_to_next_insn(jit, ctx, asm, ocb); EndBlock } @@ -5670,95 +5656,85 @@ fn gen_getblockparamproxy( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L5656 fn gen_getblockparam( jit: &mut JITState, ctx: &mut Context, - cb: &mut CodeBlock, + asm: &mut Assembler, ocb: &mut OutlinedCb, ) -> CodegenStatus { // EP level let level = jit_get_arg(jit, 1).as_u32(); // Save the PC and SP because we might allocate - jit_prepare_routine_call(jit, ctx, cb, REG0); + jit_prepare_routine_call(jit, ctx, asm); // A mirror of the interpreter code. Checking for the case // where it's pushing rb_block_param_proxy. let side_exit = get_side_exit(jit, ocb, ctx); // Load environment pointer EP from CFP - gen_get_ep(cb, REG1, level); + let ep_opnd = gen_get_ep(asm, level); // Bail when VM_ENV_FLAGS(ep, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM) is non zero - let flag_check = mem_opnd( - 64, - REG1, - (SIZEOF_VALUE as i32) * (VM_ENV_DATA_INDEX_FLAGS as i32), - ); + let flag_check = Opnd::mem(64, ep_opnd, (SIZEOF_VALUE as i32) * (VM_ENV_DATA_INDEX_FLAGS as i32)); // FIXME: This is testing bits in the same place that the WB check is testing. // We should combine these at some point - test( - cb, - flag_check, - uimm_opnd(VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM.into()), - ); + asm.test(flag_check, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM.into()); // If the frame flag has been modified, then the actual proc value is // already in the EP and we should just use the value. - let frame_flag_modified = cb.new_label("frame_flag_modified".to_string()); - jnz_label(cb, frame_flag_modified); + let frame_flag_modified = asm.new_label("frame_flag_modified"); + asm.jnz(frame_flag_modified); // This instruction writes the block handler to the EP. If we need to // fire a write barrier for the write, then exit (we'll let the // interpreter handle it so it can fire the write barrier). // flags & VM_ENV_FLAG_WB_REQUIRED - let flags_opnd = mem_opnd( + let flags_opnd = Opnd::mem( 64, - REG1, + ep_opnd, SIZEOF_VALUE as i32 * VM_ENV_DATA_INDEX_FLAGS as i32, ); - test(cb, flags_opnd, imm_opnd(VM_ENV_FLAG_WB_REQUIRED.into())); + asm.test(flags_opnd, VM_ENV_FLAG_WB_REQUIRED.into()); // if (flags & VM_ENV_FLAG_WB_REQUIRED) != 0 - jnz_ptr(cb, side_exit); - - // Load the block handler for the current frame - // note, VM_ASSERT(VM_ENV_LOCAL_P(ep)) - mov( - cb, - C_ARG_REGS[1], - mem_opnd( - 64, - REG1, - (SIZEOF_VALUE as i32) * (VM_ENV_DATA_INDEX_SPECVAL as i32), - ), - ); + asm.jnz(side_exit.into()); // Convert the block handler in to a proc // call rb_vm_bh_to_procval(const rb_execution_context_t *ec, VALUE block_handler) - mov(cb, C_ARG_REGS[0], REG_EC); - call_ptr(cb, REG0, rb_vm_bh_to_procval as *const u8); + let proc = asm.ccall( + rb_vm_bh_to_procval as *const u8, + vec![ + EC, + // The block handler for the current frame + // note, VM_ASSERT(VM_ENV_LOCAL_P(ep)) + Opnd::mem( + 64, + ep_opnd, + (SIZEOF_VALUE as i32) * (VM_ENV_DATA_INDEX_SPECVAL as i32), + ), + ] + ); // Load environment pointer EP from CFP (again) - gen_get_ep(cb, REG1, level); - - // Set the frame modified flag - or(cb, flag_check, uimm_opnd(VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM.into())); + let ep_opnd = gen_get_ep(asm, level); // Write the value at the environment pointer let idx = jit_get_arg(jit, 0).as_i32(); let offs = -(SIZEOF_VALUE as i32 * idx); - mov(cb, mem_opnd(64, REG1, offs), RAX); + asm.mov(Opnd::mem(64, ep_opnd, offs), proc); + + // Set the frame modified flag + let flag_check = Opnd::mem(64, ep_opnd, (SIZEOF_VALUE as i32) * (VM_ENV_DATA_INDEX_FLAGS as i32)); + let modified_flag = asm.or(flag_check, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM.into()); + asm.store(flag_check, modified_flag); - cb.write_label(frame_flag_modified); + asm.write_label(frame_flag_modified); // Push the proc on the stack let stack_ret = ctx.stack_push(Type::Unknown); - mov(cb, RAX, mem_opnd(64, REG1, offs)); - mov(cb, stack_ret, RAX); - - cb.link_labels(); + let ep_opnd = gen_get_ep(asm, level); + asm.mov(stack_ret, Opnd::mem(64, ep_opnd, offs)); KeepCompiling } -*/ fn gen_invokebuiltin( jit: &mut JITState, @@ -5919,8 +5895,8 @@ fn get_gen_fn(opcode: VALUE) -> Option<InsnGenFn> { https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L5895 YARVINSN_branchnil => Some(gen_branchnil), YARVINSN_jump => Some(gen_jump), - //YARVINSN_getblockparamproxy => Some(gen_getblockparamproxy), - //YARVINSN_getblockparam => Some(gen_getblockparam), + YARVINSN_getblockparamproxy => Some(gen_getblockparamproxy), + YARVINSN_getblockparam => Some(gen_getblockparam), (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/