diff --git a/compile.c b/compile.c index 7a5f869b6d3fe4..b82a7f4ab7aa50 100644 --- a/compile.c +++ b/compile.c @@ -13080,7 +13080,8 @@ inline_iseqs(VALUE *code, size_t pos, iseq_value_itr_t * func, void *_ctx, rb_vm const struct rb_iseq_constant_body *const body = callee_iseq->body; // Is the cache still valid? - ADD_INSN1(code_list_root, &dummy_line_node, jump_if_cache_miss, cd); + LABEL * cache_miss_label = NEW_LABEL(0); + ADD_INSN2(code_list_root, &dummy_line_node, jump_if_cache_miss, cd, cache_miss_label); size_t size = body->iseq_size; VALUE * callee_code = body->iseq_encoded; @@ -13109,6 +13110,10 @@ inline_iseqs(VALUE *code, size_t pos, iseq_value_itr_t * func, void *_ctx, rb_vm n += inline_iseqs(callee_code, n, NULL, _ctx, translator); } + ADD_LABEL(code_list_root, cache_miss_label); + iseq->body->ci_size++; + ADD_INSN1(code_list_root, &dummy_line_node, opt_send_without_block, cd->ci); + ADD_LABEL(code_list_root, leave_label); st_free_table(ctx->labels); @@ -13311,6 +13316,8 @@ rb_inline_callee_iseqs(const rb_iseq_t * original_iseq) } fprintf(stderr, "original size: %d new size %d\n", original_iseq->body->local_table_size, info.max_locals); + iseq->body->original_iseq = original_iseq; + RB_OBJ_WRITTEN(iseq, Qundef, original_iseq); CHECK(iseq_setup_insn(iseq, code_list_root)); iseq_setup(iseq, code_list_root); @@ -13333,4 +13340,3 @@ rb_inline_callee_iseqs(const rb_iseq_t * original_iseq) return iseq; } - diff --git a/insns.def b/insns.def index 4fa4405e3eb767..65c902e642009d 100644 --- a/insns.def +++ b/insns.def @@ -786,24 +786,24 @@ opt_send_without_block /* Invoke method without block */ DEFINE_INSN jump_if_cache_miss -(CALL_DATA cd) +(CALL_DATA cd, OFFSET dst) () () { VALUE recv = TOPN(vm_ci_argc(cd->ci)); - if (LIKELY(vm_cc_class_check(cd->cc, CLASS_OF(recv)))) { if (LIKELY(!METHOD_ENTRY_INVALIDATED(vm_cc_cme(cd->cc)))) { RB_DEBUG_COUNTER_INC(mc_inline_hit); - fprintf(stderr, "hit!\n"); } else { - rb_bug("guard miss 1!\n"); + rb_bug("guard miss 1!\n"); + JUMP(dst); } } else { - rb_bug("guard miss 2!\n"); + printf("cache miss!\n"); RB_DEBUG_COUNTER_INC(mc_inline_miss_klass); + JUMP(dst); } } diff --git a/iseq.c b/iseq.c index 3b803b1db785c1..a66834555bd964 100644 --- a/iseq.c +++ b/iseq.c @@ -349,7 +349,9 @@ rb_iseq_mark(const rb_iseq_t *iseq) if (FL_TEST((VALUE)iseq, ISEQ_MARKABLE_ISEQ)) { rb_iseq_each_value(iseq, each_insn_value, NULL); } - + if (body->param.flags.inlined_iseq) { + rb_gc_mark(body->original_iseq); + } rb_gc_mark_movable(body->variable.coverage); rb_gc_mark_movable(body->variable.pc2branchindex); rb_gc_mark_movable(body->variable.script_lines); diff --git a/test/inlining/test_inlining.rb b/test/inlining/test_inlining.rb new file mode 100644 index 00000000000000..b90aa3729871ac --- /dev/null +++ b/test/inlining/test_inlining.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: false +require 'test/unit' + +class TestInlining < Test::Unit::TestCase + def foo(a); a + 1; end + def bar; foo(9); end + + def test_enable_inlining + reader, writer = IO.pipe + Process.waitpid fork { + reader.close + RubyVM.enable_inlining! + + 3.times do + bar + end + + disasm = RubyVM::InstructionSequence.disasm(method(:bar)) + writer.write(Marshal.dump(disasm)) + } + + writer.close + disasm = Marshal.load(reader.read) + + expected_disasm = <<~HEREDOC + 0000 putself + 0001 putobject 9 + 0003 jump_if_cache_miss , 16 + 0006 setlocal_WC_0 ?@0 + 0008 pop + 0009 getlocal_WC_0 ?@0 + 0011 putobject_INT2FIX_1_ + 0012 opt_plus + 0014 jump 18 + 0016 opt_send_without_block + 0018 leave + HEREDOC + + assert_match(expected_disasm, disasm) + end + + def test_disable_inlining + reader, writer = IO.pipe + Process.waitpid fork { + reader.close + RubyVM.disable_inlining! + + 3.times do + bar + end + + disasm = RubyVM::InstructionSequence.disasm(method(:bar)) + writer.write(Marshal.dump(disasm)) + } + + writer.close + disasm = Marshal.load(reader.read) + + expected_disasm = <<~HEREDOC + 0000 putself ( 6)[LiCa] + 0001 putobject 9 + 0003 opt_send_without_block + 0005 leave [Re] + HEREDOC + + assert_match(expected_disasm, disasm) + end +end diff --git a/test3.rb b/test3.rb new file mode 100644 index 00000000000000..00188eef898b97 --- /dev/null +++ b/test3.rb @@ -0,0 +1,16 @@ +class A + def foo + self.class + end +end + +def bar(a) + a.foo +end + +a = A.new +p bar(a) +bar(a) + +puts RubyVM::InstructionSequence.disasm(method(:bar)) +p bar(a) diff --git a/vm_core.h b/vm_core.h index e06788238eaa2e..bfee8b641ddbfd 100644 --- a/vm_core.h +++ b/vm_core.h @@ -498,6 +498,7 @@ struct rb_iseq_constant_body { #endif rb_yjit_block_array_array_t yjit_blocks; // empty, or has a size equal to iseq_size + rb_iseq_t *original_iseq; }; /* T_IMEMO/iseq */