diff --git a/compile.c b/compile.c index d3b9704cc94d69..cb8554f0a17fd3 100644 --- a/compile.c +++ b/compile.c @@ -14002,7 +14002,11 @@ struct ibf_object_symbol { #define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \ ((((offset) - 1) / (align) + 1) * (align)) -#define IBF_OBJBODY(type, offset) (const type *)\ +/* No cast, since it's UB to create an unaligned pointer. + * Leave as void* for use with memcpy in those cases. + * We align the offset, but the buffer pointer is only VALUE aligned, + * so the returned pointer may be unaligned for `type` .*/ +#define IBF_OBJBODY(type, offset) \ ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset)) static const void * @@ -14097,8 +14101,10 @@ ibf_dump_object_float(struct ibf_dump *dump, VALUE obj) static VALUE ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset) { - const double *dblp = IBF_OBJBODY(double, offset); - return DBL2NUM(*dblp); + double d; + /* Avoid unaligned VFP load on ARMv7; IBF payload may be unaligned (C99 6.3.2.3 p7). */ + memcpy(&d, IBF_OBJBODY(double, offset), sizeof(d)); + return DBL2NUM(d); } static void diff --git a/depend b/depend index 5c3a03c96219d1..fa17e2ea6a43f6 100644 --- a/depend +++ b/depend @@ -5797,6 +5797,7 @@ gc.$(OBJEXT): {$(VPATH)}vm_debug.h gc.$(OBJEXT): {$(VPATH)}vm_opts.h gc.$(OBJEXT): {$(VPATH)}vm_sync.h gc.$(OBJEXT): {$(VPATH)}yjit.h +gc.$(OBJEXT): {$(VPATH)}zjit.h goruby.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h goruby.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h goruby.$(OBJEXT): $(CCAN_DIR)/list/list.h diff --git a/gc.c b/gc.c index da74c24c3f5e54..8c8887c46b7d78 100644 --- a/gc.c +++ b/gc.c @@ -127,6 +127,7 @@ #include "vm_callinfo.h" #include "ractor_core.h" #include "yjit.h" +#include "zjit.h" #include "builtin.h" #include "shape.h" @@ -4106,6 +4107,14 @@ rb_gc_update_vm_references(void *objspace) rb_yjit_root_update_references(); } #endif + +#if USE_ZJIT + void rb_zjit_root_update_references(void); // in Rust + + if (rb_zjit_enabled_p) { + rb_zjit_root_update_references(); + } +#endif } void diff --git a/iseq.c b/iseq.c index d8891353f1a365..082ea28c4ad199 100644 --- a/iseq.c +++ b/iseq.c @@ -174,6 +174,9 @@ rb_iseq_free(const rb_iseq_t *iseq) RUBY_ASSERT(rb_yjit_live_iseq_count > 0); rb_yjit_live_iseq_count--; } +#endif +#if USE_ZJIT + rb_zjit_iseq_free(iseq); #endif ruby_xfree((void *)body->iseq_encoded); ruby_xfree((void *)body->insns_info.body); diff --git a/lib/bundler/cli/exec.rb b/lib/bundler/cli/exec.rb index 9428e9db3bf8d7..2fdc4162868abe 100644 --- a/lib/bundler/cli/exec.rb +++ b/lib/bundler/cli/exec.rb @@ -19,11 +19,13 @@ def run validate_cmd! SharedHelpers.set_bundle_environment if bin_path = Bundler.which(cmd) - if !Bundler.settings[:disable_exec_load] && ruby_shebang?(bin_path) - return kernel_load(bin_path, *args) + if !Bundler.settings[:disable_exec_load] && directly_loadable?(bin_path) + bin_path.delete_suffix!(".bat") if Gem.win_platform? + kernel_load(bin_path, *args) + else + bin_path = "./" + bin_path unless File.absolute_path?(bin_path) + kernel_exec(bin_path, *args) end - bin_path = "./" + bin_path unless File.absolute_path?(bin_path) - kernel_exec(bin_path, *args) else # exec using the given command kernel_exec(cmd, *args) @@ -69,6 +71,29 @@ def process_title(file, args) "#{file} #{args.join(" ")}".strip end + def directly_loadable?(file) + if Gem.win_platform? + script_wrapper?(file) + else + ruby_shebang?(file) + end + end + + def script_wrapper?(file) + script_file = file.delete_suffix(".bat") + return false unless File.exist?(script_file) + + if File.zero?(script_file) + Bundler.ui.warn "#{script_file} is empty" + return false + end + + header = File.open(file, "r") {|f| f.read(32) } + ruby_exe = "#{RbConfig::CONFIG["RUBY_INSTALL_NAME"]}#{RbConfig::CONFIG["EXEEXT"]}" + ruby_exe = "ruby.exe" if ruby_exe.empty? + header.include?(ruby_exe) + end + def ruby_shebang?(file) possibilities = [ "#!/usr/bin/env ruby\n", diff --git a/spec/bundler/commands/exec_spec.rb b/spec/bundler/commands/exec_spec.rb index cad1ac4ba3ce83..af8bfc71f19419 100644 --- a/spec/bundler/commands/exec_spec.rb +++ b/spec/bundler/commands/exec_spec.rb @@ -661,8 +661,6 @@ describe "with gems bundled for deployment" do it "works when calling bundler from another script" do - skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? - gemfile <<-G source "https://gem.repo1" @@ -730,13 +728,16 @@ def bin_path(a,b,c) puts "EXEC: \#{caller.grep(/load/).empty? ? 'exec' : 'load'}" puts "ARGS: \#{$0} \#{ARGV.join(' ')}" puts "MYRACK: \#{MYRACK}" - process_title = `ps -o args -p \#{Process.pid}`.split("\n", 2).last.strip + if Gem.win_platform? + process_title = "ruby" + else + process_title = `ps -o args -p \#{Process.pid}`.split("\n", 2).last.strip + end puts "PROCESS: \#{process_title}" RUBY before do - bundled_app(path).open("w") {|f| f << executable } - bundled_app(path).chmod(0o755) + create_file(bundled_app(path), executable) install_gemfile <<-G source "https://gem.repo1" @@ -748,9 +749,11 @@ def bin_path(a,b,c) let(:args) { "ARGS: #{path} arg1 arg2" } let(:myrack) { "MYRACK: 1.0.0" } let(:process) do - title = "PROCESS: #{path}" - title += " arg1 arg2" - title + if Gem.win_platform? + "PROCESS: ruby" + else + "PROCESS: #{path} arg1 arg2" + end end let(:exit_code) { 0 } let(:expected) { [exec, args, myrack, process].join("\n") } @@ -759,8 +762,6 @@ def bin_path(a,b,c) subject { bundle "exec #{path} arg1 arg2", raise_on_error: false } it "runs" do - skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? - subject expect(exitstatus).to eq(exit_code) expect(err).to eq(expected_err) @@ -772,8 +773,6 @@ def bin_path(a,b,c) context "with exit 0" do it "runs" do - skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? - subject expect(exitstatus).to eq(exit_code) expect(err).to eq(expected_err) @@ -785,8 +784,6 @@ def bin_path(a,b,c) let(:exit_code) { 99 } it "runs" do - skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? - subject expect(exitstatus).to eq(exit_code) expect(err).to eq(expected_err) @@ -825,7 +822,12 @@ def bin_path(a,b,c) let(:expected) { "" } it "runs" do - skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? + # it's empty, so `create_file` won't add executable permission and bat scripts on Windows + bundled_app(path).chmod(0o755) + path.sub_ext(".bat").write <<~SCRIPT if Gem.win_platform? + @ECHO OFF + @"ruby.exe" "%~dpn0" %* + SCRIPT subject expect(exitstatus).to eq(exit_code) @@ -838,12 +840,10 @@ def bin_path(a,b,c) let(:executable) { super() << "\nraise 'ERROR'" } let(:exit_code) { 1 } let(:expected_err) do - /\Abundler: failed to load command: #{Regexp.quote(path.to_s)} \(#{Regexp.quote(path.to_s)}\)\n#{Regexp.quote(path.to_s)}:10:in [`']': ERROR \(RuntimeError\)/ + /\Abundler: failed to load command: #{Regexp.quote(path.to_s)} \(#{Regexp.quote(path.to_s)}\)\n#{Regexp.quote(path.to_s)}:[0-9]+:in [`']': ERROR \(RuntimeError\)/ end it "runs like a normally executed executable" do - skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? - subject expect(exitstatus).to eq(exit_code) expect(err).to match(expected_err) @@ -858,8 +858,6 @@ def bin_path(a,b,c) let(:expected) { super() } it "runs" do - skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? - subject expect(exitstatus).to eq(exit_code) expect(err).to eq(expected_err) @@ -871,8 +869,6 @@ def bin_path(a,b,c) let(:shebang) { "#!#{Gem.ruby}" } it "runs" do - skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? - subject expect(exitstatus).to eq(exit_code) expect(err).to eq(expected_err) @@ -903,8 +899,6 @@ def bin_path(a,b,c) EOS it "runs" do - skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? - subject expect(exitstatus).to eq(exit_code) expect(err).to eq(expected_err) @@ -927,8 +921,6 @@ def bin_path(a,b,c) let(:expected) { "" } it "prints proper suggestion" do - skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? - subject expect(exitstatus).to eq(exit_code) expect(err).to include("Run `bundle install --gemfile CustomGemfile` to install missing gems.") @@ -941,8 +933,6 @@ def bin_path(a,b,c) let(:exit_code) { 1 } it "runs" do - skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? - subject expect(exitstatus).to eq(exit_code) expect(err).to eq(expected_err) @@ -952,15 +942,19 @@ def bin_path(a,b,c) context "when disable_exec_load is set" do let(:exec) { "EXEC: exec" } - let(:process) { "PROCESS: ruby #{path} arg1 arg2" } + let(:process) do + if Gem.win_platform? + "PROCESS: ruby" + else + "PROCESS: ruby #{path} arg1 arg2" + end + end before do bundle "config set disable_exec_load true" end it "runs" do - skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? - subject expect(exitstatus).to eq(exit_code) expect(err).to eq(expected_err) @@ -983,8 +977,6 @@ def bin_path(a,b,c) EOS it "runs" do - skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? - subject expect(exitstatus).to eq(exit_code) expect(err).to eq(expected_err) @@ -1001,8 +993,6 @@ def bin_path(a,b,c) EOS it "runs" do - skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? - subject expect(exitstatus).to eq(exit_code) expect(err).to eq(expected_err) @@ -1019,8 +1009,6 @@ def bin_path(a,b,c) EOS it "runs" do - skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? - subject expect(exitstatus).to eq(exit_code) expect(err).to eq(expected_err) @@ -1161,8 +1149,6 @@ def require(path) context "when gemfile and path are configured", :ruby_repo do before do - skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? - build_repo2 do build_gem "rails", "6.1.0" do |s| s.executables = "rails" diff --git a/test/ruby/test_thread.rb b/test/ruby/test_thread.rb index 12ba1165ed8817..01a1e51025181c 100644 --- a/test/ruby/test_thread.rb +++ b/test/ruby/test_thread.rb @@ -1589,4 +1589,65 @@ def frame_for_deadlock_test_2 frame_for_deadlock_test_2 { t.join } INPUT end + + # [Bug #21342] + def test_unlock_locked_mutex_with_collected_fiber + bug21127 = '[ruby-core:120930] [Bug #21127]' + assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") + begin; + 5.times do + m = Mutex.new + Thread.new do + m.synchronize do + end + end.join + Fiber.new do + GC.start + m.lock + end.resume + end + end; + end + + def test_unlock_locked_mutex_with_collected_fiber2 + assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") + begin; + MUTEXES = [] + 5.times do + m = Mutex.new + Fiber.new do + GC.start + m.lock + end.resume + MUTEXES << m + end + 10.times do + MUTEXES.clear + GC.start + end + end; + end + + def test_mutexes_locked_in_fiber_dont_have_aba_issue_with_new_fibers + assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") + begin; + mutexes = 1000.times.map do + Mutex.new + end + + mutexes.map do |m| + Fiber.new do + m.lock + end.resume + end + + GC.start + + 1000.times.map do + Fiber.new do + raise "FAILED!" if mutexes.any?(&:owned?) + end.resume + end + end; + end end diff --git a/test/ruby/test_zjit.rb b/test/ruby/test_zjit.rb index 564e62c070698f..683d53f339f8c2 100644 --- a/test/ruby/test_zjit.rb +++ b/test/ruby/test_zjit.rb @@ -308,6 +308,39 @@ def test_setlocal_on_eval } end + def test_optional_arguments + assert_compiles '[[1, 2, 3], [10, 20, 3], [100, 200, 300]]', %q{ + def test(a, b = 2, c = 3) + [a, b, c] + end + [test(1), test(10, 20), test(100, 200, 300)] + } + end + + def test_optional_arguments_setlocal + assert_compiles '[[2, 2], [1, nil]]', %q{ + def test(a = (b = 2)) + [a, b] + end + [test, test(1)] + } + end + + def test_optional_arguments_cyclic + assert_compiles '[nil, 1]', %q{ + test = proc { |a=a| a } + [test.call, test.call(1)] + } + end + + def test_optional_arguments_side_exit + # This leads to FailedOptionalArguments, so not using assert_compiles + assert_runs '[:foo, nil, 1]', %q{ + def test(a = (def foo = nil)) = a + [test, (undef :foo), test(1)] + } + end + def test_getblockparamproxy assert_compiles '1', %q{ def test(&block) diff --git a/thread.c b/thread.c index bab615b9edb27b..55561001023dfe 100644 --- a/thread.c +++ b/thread.c @@ -442,7 +442,7 @@ rb_threadptr_unlock_all_locking_mutexes(rb_thread_t *th) th->keeping_mutexes = mutex->next_mutex; // rb_warn("mutex #<%p> was not unlocked by thread #<%p>", (void *)mutex, (void*)th); - + VM_ASSERT(mutex->fiber); const char *error_message = rb_mutex_unlock_th(mutex, th, mutex->fiber); if (error_message) rb_bug("invalid keeping_mutexes: %s", error_message); } diff --git a/thread_sync.c b/thread_sync.c index dd54e8267195cd..0fc70224ff90ed 100644 --- a/thread_sync.c +++ b/thread_sync.c @@ -8,6 +8,7 @@ static VALUE rb_eClosedQueueError; /* Mutex */ typedef struct rb_mutex_struct { rb_fiber_t *fiber; + VALUE thread; // even if the fiber is collected, we might need access to the thread in mutex_free struct rb_mutex_struct *next_mutex; struct ccan_list_head waitq; /* protected by GVL */ } rb_mutex_t; @@ -106,8 +107,6 @@ static const char* rb_mutex_unlock_th(rb_mutex_t *mutex, rb_thread_t *th, rb_fib * */ -#define mutex_mark ((void(*)(void*))0) - static size_t rb_mutex_num_waiting(rb_mutex_t *mutex) { @@ -123,13 +122,39 @@ rb_mutex_num_waiting(rb_mutex_t *mutex) rb_thread_t* rb_fiber_threadptr(const rb_fiber_t *fiber); +static bool +locked_p(rb_mutex_t *mutex) +{ + return mutex->fiber != 0; +} + +static void +mutex_mark(void *ptr) +{ + rb_mutex_t *mutex = ptr; + VALUE fiber; + if (locked_p(mutex)) { + fiber = rb_fiberptr_self(mutex->fiber); // rb_fiber_t* doesn't move along with fiber object + if (fiber) rb_gc_mark_movable(fiber); + rb_gc_mark_movable(mutex->thread); + } +} + +static void +mutex_compact(void *ptr) +{ + rb_mutex_t *mutex = ptr; + if (locked_p(mutex)) { + mutex->thread = rb_gc_location(mutex->thread); + } +} + static void mutex_free(void *ptr) { rb_mutex_t *mutex = ptr; - if (mutex->fiber) { - /* rb_warn("free locked mutex"); */ - const char *err = rb_mutex_unlock_th(mutex, rb_fiber_threadptr(mutex->fiber), mutex->fiber); + if (locked_p(mutex)) { + const char *err = rb_mutex_unlock_th(mutex, rb_thread_ptr(mutex->thread), mutex->fiber); if (err) rb_bug("%s", err); } ruby_xfree(ptr); @@ -143,7 +168,7 @@ mutex_memsize(const void *ptr) static const rb_data_type_t mutex_data_type = { "mutex", - {mutex_mark, mutex_free, mutex_memsize,}, + {mutex_mark, mutex_free, mutex_memsize, mutex_compact,}, 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY }; @@ -204,12 +229,13 @@ rb_mutex_locked_p(VALUE self) { rb_mutex_t *mutex = mutex_ptr(self); - return RBOOL(mutex->fiber); + return RBOOL(locked_p(mutex)); } static void thread_mutex_insert(rb_thread_t *thread, rb_mutex_t *mutex) { + RUBY_ASSERT(!mutex->next_mutex); if (thread->keeping_mutexes) { mutex->next_mutex = thread->keeping_mutexes; } @@ -234,10 +260,24 @@ thread_mutex_remove(rb_thread_t *thread, rb_mutex_t *mutex) } static void -mutex_locked(rb_thread_t *th, VALUE self) +mutex_set_owner(VALUE self, rb_thread_t *th, rb_fiber_t *fiber) +{ + rb_mutex_t *mutex = mutex_ptr(self); + + mutex->thread = th->self; + mutex->fiber = fiber; + RB_OBJ_WRITTEN(self, Qundef, th->self); + if (fiber) { + RB_OBJ_WRITTEN(self, Qundef, rb_fiberptr_self(fiber)); + } +} + +static void +mutex_locked(rb_thread_t *th, rb_fiber_t *fiber, VALUE self) { rb_mutex_t *mutex = mutex_ptr(self); + mutex_set_owner(self, th, fiber); thread_mutex_insert(th, mutex); } @@ -258,9 +298,8 @@ rb_mutex_trylock(VALUE self) rb_fiber_t *fiber = GET_EC()->fiber_ptr; rb_thread_t *th = GET_THREAD(); - mutex->fiber = fiber; - mutex_locked(th, self); + mutex_locked(th, fiber, self); return Qtrue; } else { @@ -328,7 +367,7 @@ do_mutex_lock(VALUE self, int interruptible_p) rb_ensure(call_rb_fiber_scheduler_block, self, delete_from_waitq, (VALUE)&sync_waiter); if (!mutex->fiber) { - mutex->fiber = fiber; + mutex_set_owner(self, th, fiber); } } else { @@ -358,6 +397,7 @@ do_mutex_lock(VALUE self, int interruptible_p) rb_ractor_sleeper_threads_inc(th->ractor); rb_check_deadlock(th->ractor); + RUBY_ASSERT(!th->locking_mutex); th->locking_mutex = self; ccan_list_add_tail(&mutex->waitq, &sync_waiter.node); @@ -368,7 +408,7 @@ do_mutex_lock(VALUE self, int interruptible_p) // unlocked by another thread while sleeping if (!mutex->fiber) { - mutex->fiber = fiber; + mutex_set_owner(self, th, fiber); } rb_ractor_sleeper_threads_dec(th->ractor); @@ -381,10 +421,13 @@ do_mutex_lock(VALUE self, int interruptible_p) if (interruptible_p) { /* release mutex before checking for interrupts...as interrupt checking * code might call rb_raise() */ - if (mutex->fiber == fiber) mutex->fiber = 0; + if (mutex->fiber == fiber) { + mutex->thread = Qfalse; + mutex->fiber = NULL; + } RUBY_VM_CHECK_INTS_BLOCKING(th->ec); /* may release mutex */ if (!mutex->fiber) { - mutex->fiber = fiber; + mutex_set_owner(self, th, fiber); } } else { @@ -403,7 +446,7 @@ do_mutex_lock(VALUE self, int interruptible_p) } if (saved_ints) th->ec->interrupt_flag = saved_ints; - if (mutex->fiber == fiber) mutex_locked(th, self); + if (mutex->fiber == fiber) mutex_locked(th, fiber, self); } RUBY_DEBUG_LOG("%p locked", mutex); diff --git a/vm_backtrace.c b/vm_backtrace.c index e81c568dda2e6b..07d2e33e321787 100644 --- a/vm_backtrace.c +++ b/vm_backtrace.c @@ -1745,14 +1745,14 @@ thread_profile_frames(rb_execution_context_t *ec, int start, int limit, VALUE *b end_cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp); for (i=0; ipc != 0) { + if (VM_FRAME_RUBYFRAME_P_UNCHECKED(cfp) && cfp->pc != 0) { if (start > 0) { start--; continue; } /* record frame info */ - cme = rb_vm_frame_method_entry(cfp); + cme = rb_vm_frame_method_entry_unchecked(cfp); if (cme && cme->def->type == VM_METHOD_TYPE_ISEQ) { buff[i] = (VALUE)cme; } @@ -1770,6 +1770,8 @@ thread_profile_frames(rb_execution_context_t *ec, int start, int limit, VALUE *b // before entering a non-leaf method (so that `caller` will work), // so only the topmost frame could possibly have an out-of-date PC. // ZJIT doesn't set `cfp->jit_return`, so it's not a reliable signal. + // TODO(zjit): lightweight frames potentially makes more than + // the top most frame invalid. // // Avoid passing invalid PC to calc_lineno() to avoid crashing. if (cfp == top && (pc < iseq_encoded || pc > pc_end)) { @@ -1783,7 +1785,7 @@ thread_profile_frames(rb_execution_context_t *ec, int start, int limit, VALUE *b i++; } else { - cme = rb_vm_frame_method_entry(cfp); + cme = rb_vm_frame_method_entry_unchecked(cfp); if (cme && cme->def->type == VM_METHOD_TYPE_CFUNC) { if (start > 0) { start--; diff --git a/vm_core.h b/vm_core.h index 2e77e1073eb959..487a4020eec5cd 100644 --- a/vm_core.h +++ b/vm_core.h @@ -1449,12 +1449,25 @@ VM_ENV_FLAGS(const VALUE *ep, long flag) return flags & flag; } +static inline unsigned long +VM_ENV_FLAGS_UNCHECKED(const VALUE *ep, long flag) +{ + VALUE flags = ep[VM_ENV_DATA_INDEX_FLAGS]; + return flags & flag; +} + static inline unsigned long VM_FRAME_TYPE(const rb_control_frame_t *cfp) { return VM_ENV_FLAGS(cfp->ep, VM_FRAME_MAGIC_MASK); } +static inline unsigned long +VM_FRAME_TYPE_UNCHECKED(const rb_control_frame_t *cfp) +{ + return VM_ENV_FLAGS_UNCHECKED(cfp->ep, VM_FRAME_MAGIC_MASK); +} + static inline int VM_FRAME_LAMBDA_P(const rb_control_frame_t *cfp) { @@ -1473,6 +1486,12 @@ VM_FRAME_FINISHED_P(const rb_control_frame_t *cfp) return VM_ENV_FLAGS(cfp->ep, VM_FRAME_FLAG_FINISH) != 0; } +static inline int +VM_FRAME_FINISHED_P_UNCHECKED(const rb_control_frame_t *cfp) +{ + return VM_ENV_FLAGS_UNCHECKED(cfp->ep, VM_FRAME_FLAG_FINISH) != 0; +} + static inline int VM_FRAME_BMETHOD_P(const rb_control_frame_t *cfp) { @@ -1498,12 +1517,24 @@ VM_FRAME_CFRAME_P(const rb_control_frame_t *cfp) return cframe_p; } +static inline int +VM_FRAME_CFRAME_P_UNCHECKED(const rb_control_frame_t *cfp) +{ + return VM_ENV_FLAGS_UNCHECKED(cfp->ep, VM_FRAME_FLAG_CFRAME) != 0; +} + static inline int VM_FRAME_RUBYFRAME_P(const rb_control_frame_t *cfp) { return !VM_FRAME_CFRAME_P(cfp); } +static inline int +VM_FRAME_RUBYFRAME_P_UNCHECKED(const rb_control_frame_t *cfp) +{ + return !VM_FRAME_CFRAME_P_UNCHECKED(cfp); +} + static inline int VM_FRAME_NS_SWITCH_P(const rb_control_frame_t *cfp) { @@ -1522,11 +1553,23 @@ VM_ENV_LOCAL_P(const VALUE *ep) return VM_ENV_FLAGS(ep, VM_ENV_FLAG_LOCAL) ? 1 : 0; } +static inline int +VM_ENV_LOCAL_P_UNCHECKED(const VALUE *ep) +{ + return VM_ENV_FLAGS_UNCHECKED(ep, VM_ENV_FLAG_LOCAL) ? 1 : 0; +} + +static inline const VALUE * +VM_ENV_PREV_EP_UNCHECKED(const VALUE *ep) +{ + return GC_GUARDED_PTR_REF(ep[VM_ENV_DATA_INDEX_SPECVAL]); +} + static inline const VALUE * VM_ENV_PREV_EP(const VALUE *ep) { VM_ASSERT(VM_ENV_LOCAL_P(ep) == 0); - return GC_GUARDED_PTR_REF(ep[VM_ENV_DATA_INDEX_SPECVAL]); + return VM_ENV_PREV_EP_UNCHECKED(ep); } static inline VALUE @@ -1934,6 +1977,7 @@ void rb_gc_mark_machine_context(const rb_execution_context_t *ec); rb_cref_t *rb_vm_rewrite_cref(rb_cref_t *node, VALUE old_klass, VALUE new_klass); const rb_callable_method_entry_t *rb_vm_frame_method_entry(const rb_control_frame_t *cfp); +const rb_callable_method_entry_t *rb_vm_frame_method_entry_unchecked(const rb_control_frame_t *cfp); #define sysstack_error GET_VM()->special_exceptions[ruby_error_sysstack] diff --git a/vm_dump.c b/vm_dump.c index 2a863ddef955a0..131844b4cc1766 100644 --- a/vm_dump.c +++ b/vm_dump.c @@ -61,14 +61,14 @@ control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *c const char *magic, *iseq_name = "-", *selfstr = "-", *biseq_name = "-"; VALUE tmp; const rb_iseq_t *iseq = NULL; - const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp); + const rb_callable_method_entry_t *me = rb_vm_frame_method_entry_unchecked(cfp); if (ep < 0 || (size_t)ep > ec->vm_stack_size) { ep = (ptrdiff_t)cfp->ep; ep_in_heap = 'p'; } - switch (VM_FRAME_TYPE(cfp)) { + switch (VM_FRAME_TYPE_UNCHECKED(cfp)) { case VM_FRAME_MAGIC_TOP: magic = "TOP"; break; @@ -128,7 +128,9 @@ control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *c iseq = cfp->iseq; pc = cfp->pc - ISEQ_BODY(iseq)->iseq_encoded; iseq_name = RSTRING_PTR(ISEQ_BODY(iseq)->location.label); - line = rb_vm_get_sourceline(cfp); + if (pc >= 0 && pc <= ISEQ_BODY(iseq)->iseq_size) { + line = rb_vm_get_sourceline(cfp); + } if (line) { snprintf(posbuf, MAX_POSBUF, "%s:%d", RSTRING_PTR(rb_iseq_path(iseq)), line); } @@ -138,7 +140,7 @@ control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *c } } } - else if (me != NULL) { + else if (me != NULL && IMEMO_TYPE_P(me, imemo_ment)) { iseq_name = rb_id2name(me->def->original_id); snprintf(posbuf, MAX_POSBUF, ":%s", iseq_name); line = -1; @@ -158,7 +160,7 @@ control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *c if (line) { kprintf(" %s", posbuf); } - if (VM_FRAME_FINISHED_P(cfp)) { + if (VM_FRAME_FINISHED_P_UNCHECKED(cfp)) { kprintf(" [FINISH]"); } if (0) { diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 8022a29a6e77e2..75339aaa5c5abd 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -761,6 +761,25 @@ check_method_entry(VALUE obj, int can_be_svar) } } +static rb_callable_method_entry_t * +env_method_entry_unchecked(VALUE obj, int can_be_svar) +{ + if (obj == Qfalse) return NULL; + + switch (imemo_type(obj)) { + case imemo_ment: + return (rb_callable_method_entry_t *)obj; + case imemo_cref: + return NULL; + case imemo_svar: + if (can_be_svar) { + return env_method_entry_unchecked(((struct vm_svar *)obj)->cref_or_me, FALSE); + } + default: + return NULL; + } +} + const rb_callable_method_entry_t * rb_vm_frame_method_entry(const rb_control_frame_t *cfp) { @@ -775,6 +794,20 @@ rb_vm_frame_method_entry(const rb_control_frame_t *cfp) return check_method_entry(ep[VM_ENV_DATA_INDEX_ME_CREF], TRUE); } +const rb_callable_method_entry_t * +rb_vm_frame_method_entry_unchecked(const rb_control_frame_t *cfp) +{ + const VALUE *ep = cfp->ep; + rb_callable_method_entry_t *me; + + while (!VM_ENV_LOCAL_P_UNCHECKED(ep)) { + if ((me = env_method_entry_unchecked(ep[VM_ENV_DATA_INDEX_ME_CREF], FALSE)) != NULL) return me; + ep = VM_ENV_PREV_EP_UNCHECKED(ep); + } + + return env_method_entry_unchecked(ep[VM_ENV_DATA_INDEX_ME_CREF], TRUE); +} + static const rb_iseq_t * method_entry_iseqptr(const rb_callable_method_entry_t *me) { diff --git a/vm_method.c b/vm_method.c index 238ad62f4b134b..16f402e893c8ed 100644 --- a/vm_method.c +++ b/vm_method.c @@ -859,6 +859,17 @@ rb_free_method_entry_vm_weak_references(const rb_method_entry_t *me) void rb_free_method_entry(const rb_method_entry_t *me) { +#if USE_ZJIT + if (METHOD_ENTRY_CACHED(me)) { + rb_zjit_cme_free((const rb_callable_method_entry_t *)me); + } +#endif + +#if USE_YJIT + // YJIT rb_yjit_root_mark() roots CMEs in `Invariants`, + // to remove from `Invariants` here. +#endif + rb_method_definition_release(me->def); } diff --git a/zjit.h b/zjit.h index 9735cab6d459d0..85f6e86d0350d4 100644 --- a/zjit.h +++ b/zjit.h @@ -18,10 +18,12 @@ void rb_zjit_profile_insn(uint32_t insn, rb_execution_context_t *ec); void rb_zjit_profile_enable(const rb_iseq_t *iseq); void rb_zjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop); void rb_zjit_cme_invalidate(const rb_callable_method_entry_t *cme); +void rb_zjit_cme_free(const rb_callable_method_entry_t *cme); void rb_zjit_invalidate_no_ep_escape(const rb_iseq_t *iseq); void rb_zjit_constant_state_changed(ID id); void rb_zjit_iseq_mark(void *payload); void rb_zjit_iseq_update_references(void *payload); +void rb_zjit_iseq_free(const rb_iseq_t *iseq); void rb_zjit_before_ractor_spawn(void); void rb_zjit_tracing_invalidate_all(void); #else diff --git a/zjit/src/backend/lir.rs b/zjit/src/backend/lir.rs index e931e14e8f24e9..21adc42cd1c753 100644 --- a/zjit/src/backend/lir.rs +++ b/zjit/src/backend/lir.rs @@ -1607,12 +1607,9 @@ impl Assembler self.store(Opnd::mem(64, SP, (-local_size_and_idx_to_ep_offset(locals.len(), idx) - 1) * SIZEOF_VALUE_I32), opnd); } - // Avoid setting cfp->pc when exiting entry_block with optional arguments - if !pc.is_null() { - asm_comment!(self, "save cfp->pc"); - self.load_into(SCRATCH_OPND, Opnd::const_ptr(pc)); - self.store(Opnd::mem(64, CFP, RUBY_OFFSET_CFP_PC), SCRATCH_OPND); - } + asm_comment!(self, "save cfp->pc"); + self.load_into(SCRATCH_OPND, Opnd::const_ptr(pc)); + self.store(Opnd::mem(64, CFP, RUBY_OFFSET_CFP_PC), SCRATCH_OPND); asm_comment!(self, "save cfp->sp"); self.lea_into(SCRATCH_OPND, Opnd::mem(64, SP, stack.len() as i32 * SIZEOF_VALUE_I32)); diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs index 682b7ea61d21bc..8230d39522504f 100644 --- a/zjit/src/codegen.rs +++ b/zjit/src/codegen.rs @@ -16,7 +16,7 @@ use crate::stats::{exit_counter_for_compile_error, incr_counter, incr_counter_by use crate::stats::{counter_ptr, with_time_stat, Counter, send_fallback_counter, Counter::{compile_time_ns, exit_compile_error}}; use crate::{asm::CodeBlock, cruby::*, options::debug, virtualmem::CodePtr}; use crate::backend::lir::{self, asm_comment, asm_ccall, Assembler, Opnd, Target, CFP, C_ARG_OPNDS, C_RET_OPND, EC, NATIVE_STACK_PTR, NATIVE_BASE_PTR, SCRATCH_OPND, SP}; -use crate::hir::{iseq_to_hir, Block, BlockId, BranchEdge, Invariant, RangeType, SideExitReason, SideExitReason::*, MethodType, SpecialObjectType, SpecialBackrefSymbol, SELF_PARAM_IDX}; +use crate::hir::{iseq_to_hir, Block, BlockId, BranchEdge, Invariant, MethodType, RangeType, SideExitReason::{self, *}, SpecialBackrefSymbol, SpecialObjectType, SELF_PARAM_IDX}; use crate::hir::{Const, FrameState, Function, Insn, InsnId}; use crate::hir_type::{types, Type}; use crate::options::get_option; @@ -34,7 +34,7 @@ struct JITState { labels: Vec>, /// JIT entry point for the `iseq` - jit_entry: Option>>, + jit_entries: Vec>>, /// ISEQ calls that need to be compiled later iseq_calls: Vec>>, @@ -50,7 +50,7 @@ impl JITState { iseq, opnds: vec![None; num_insns], labels: vec![None; num_blocks], - jit_entry: None, + jit_entries: Vec::default(), iseq_calls: Vec::default(), c_stack_slots, } @@ -228,7 +228,7 @@ fn gen_iseq_body(cb: &mut CodeBlock, iseq: IseqPtr, function: Option<&Function>, }; // Compile the High-level IR - let (start_ptr, jit_entry_ptr, gc_offsets, iseq_calls) = gen_function(cb, iseq, function)?; + let (iseq_code_ptrs, gc_offsets, iseq_calls) = gen_function(cb, iseq, function)?; // Stub callee ISEQs for JIT-to-JIT calls for iseq_call in iseq_calls.iter() { @@ -238,11 +238,11 @@ fn gen_iseq_body(cb: &mut CodeBlock, iseq: IseqPtr, function: Option<&Function>, // Prepare for GC payload.iseq_calls.extend(iseq_calls.clone()); append_gc_offsets(iseq, &gc_offsets); - Ok(IseqCodePtrs { start_ptr, jit_entry_ptr }) + Ok(iseq_code_ptrs) } /// Compile a function -fn gen_function(cb: &mut CodeBlock, iseq: IseqPtr, function: &Function) -> Result<(CodePtr, CodePtr, Vec, Vec), CompileError> { +fn gen_function(cb: &mut CodeBlock, iseq: IseqPtr, function: &Function) -> Result<(IseqCodePtrs, Vec, Vec), CompileError> { let c_stack_slots = max_num_params(function).saturating_sub(ALLOC_REGS.len()); let mut jit = JITState::new(iseq, function.num_insns(), function.num_blocks(), c_stack_slots); let mut asm = Assembler::new(); @@ -307,8 +307,13 @@ fn gen_function(cb: &mut CodeBlock, iseq: IseqPtr, function: &Function) -> Resul } } result.map(|(start_ptr, gc_offsets)| { - let jit_entry_ptr = jit.jit_entry.unwrap().borrow().start_addr.get().unwrap(); - (start_ptr, jit_entry_ptr, gc_offsets, jit.iseq_calls) + // Make sure jit_entry_ptrs can be used as a parallel vector to jit_entry_insns() + jit.jit_entries.sort_by_key(|jit_entry| jit_entry.borrow().jit_entry_idx); + + let jit_entry_ptrs = jit.jit_entries.iter().map(|jit_entry| + jit_entry.borrow().start_addr.get().expect("start_addr should have been set by pos_marker in gen_entry_point") + ).collect(); + (IseqCodePtrs { start_ptr, jit_entry_ptrs }, gc_offsets, jit.iseq_calls) }) } @@ -375,7 +380,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio // TODO remove this check when we have stack args (we can use Time.new to test it) Insn::InvokeBuiltin { bf, state, .. } if bf.argc + 2 > (C_ARG_OPNDS.len() as i32) => return Err(*state), Insn::InvokeBuiltin { bf, args, state, .. } => gen_invokebuiltin(jit, asm, &function.frame_state(*state), bf, opnds!(args)), - &Insn::EntryPoint { jit_entry } => no_output!(gen_entry_point(jit, asm, jit_entry)), + &Insn::EntryPoint { jit_entry_idx } => no_output!(gen_entry_point(jit, asm, jit_entry_idx)), Insn::Return { val } => no_output!(gen_return(asm, opnd!(val))), Insn::FixnumAdd { left, right, state } => gen_fixnum_add(jit, asm, opnd!(left), opnd!(right), &function.frame_state(*state)), Insn::FixnumSub { left, right, state } => gen_fixnum_sub(jit, asm, opnd!(left), opnd!(right), &function.frame_state(*state)), @@ -424,7 +429,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio &Insn::DefinedIvar { self_val, id, pushval, .. } => { gen_defined_ivar(asm, opnd!(self_val), id, pushval) }, &Insn::ArrayExtend { left, right, state } => { no_output!(gen_array_extend(jit, asm, opnd!(left), opnd!(right), &function.frame_state(state))) }, &Insn::GuardShape { val, shape, state } => gen_guard_shape(jit, asm, opnd!(val), shape, &function.frame_state(state)), - Insn::LoadPC => gen_load_pc(), + Insn::LoadPC => gen_load_pc(asm), &Insn::LoadIvarEmbedded { self_val, id, index } => gen_load_ivar_embedded(asm, opnd!(self_val), id, index), &Insn::LoadIvarExtended { self_val, id, index } => gen_load_ivar_extended(asm, opnd!(self_val), id, index), &Insn::ArrayMax { state, .. } @@ -825,8 +830,8 @@ fn gen_guard_shape(jit: &mut JITState, asm: &mut Assembler, val: Opnd, shape: Sh val } -fn gen_load_pc() -> Opnd { - Opnd::mem(64, CFP, RUBY_OFFSET_CFP_PC) +fn gen_load_pc(asm: &mut Assembler) -> Opnd { + asm.load(Opnd::mem(64, CFP, RUBY_OFFSET_CFP_PC)) } fn gen_load_ivar_embedded(asm: &mut Assembler, self_val: Opnd, id: ID, index: u16) -> Opnd { @@ -1313,12 +1318,11 @@ fn gen_object_alloc_class(asm: &mut Assembler, class: VALUE, state: &FrameState) } } -/// Compile a frame setup. If is_jit_entry is true, remember the address of it as a JIT entry. -fn gen_entry_point(jit: &mut JITState, asm: &mut Assembler, is_jit_entry: bool) { - if is_jit_entry { - assert!(jit.jit_entry.is_none(), "only one jit_entry is expected"); - let jit_entry = JITEntry::new(); - jit.jit_entry = Some(jit_entry.clone()); +/// Compile a frame setup. If jit_entry_idx is Some, remember the address of it as a JIT entry. +fn gen_entry_point(jit: &mut JITState, asm: &mut Assembler, jit_entry_idx: Option) { + if let Some(jit_entry_idx) = jit_entry_idx { + let jit_entry = JITEntry::new(jit_entry_idx); + jit.jit_entries.push(jit_entry.clone()); asm.pos_marker(move |code_ptr, _| { jit_entry.borrow_mut().start_addr.set(Some(code_ptr)); }); @@ -1776,8 +1780,7 @@ fn compile_iseq(iseq: IseqPtr) -> Result { let mut function = match iseq_to_hir(iseq) { Ok(function) => function, Err(err) => { - let name = crate::cruby::iseq_get_location(iseq, 0); - debug!("ZJIT: iseq_to_hir: {err:?}: {name}"); + debug!("ZJIT: iseq_to_hir: {err:?}: {}", iseq_get_location(iseq, 0)); return Err(CompileError::ParseError(err)); } }; @@ -1785,12 +1788,6 @@ fn compile_iseq(iseq: IseqPtr) -> Result { function.optimize(); } function.dump_hir(); - #[cfg(debug_assertions)] - if let Err(err) = function.validate() { - debug!("ZJIT: compile_iseq: {err:?}"); - use crate::hir::ParseError; - return Err(CompileError::ParseError(ParseError::Validation(err))); - } Ok(function) } @@ -1928,10 +1925,15 @@ c_callable! { /// Compile an ISEQ for a function stub fn function_stub_hit_body(cb: &mut CodeBlock, iseq_call: &Rc>) -> Result { // Compile the stubbed ISEQ - let IseqCodePtrs { jit_entry_ptr, .. } = gen_iseq(cb, iseq_call.borrow().iseq, None).inspect_err(|err| { + let IseqCodePtrs { jit_entry_ptrs, .. } = gen_iseq(cb, iseq_call.borrow().iseq, None).inspect_err(|err| { debug!("{err:?}: gen_iseq failed: {}", iseq_get_location(iseq_call.borrow().iseq, 0)); })?; + // We currently don't support JIT-to-JIT calls for ISEQs with optional arguments. + // So we only need to use jit_entry_ptrs[0] for now. TODO: Support optional arguments. + assert_eq!(1, jit_entry_ptrs.len()); + let jit_entry_ptr = jit_entry_ptrs[0]; + // Update the stub to call the code pointer let code_addr = jit_entry_ptr.raw_ptr(cb); let iseq = iseq_call.borrow().iseq; @@ -2131,14 +2133,17 @@ impl Assembler { /// Store info about a JIT entry point pub struct JITEntry { + /// Index that corresponds to jit_entry_insns() + jit_entry_idx: usize, /// Position where the entry point starts start_addr: Cell>, } impl JITEntry { /// Allocate a new JITEntry - fn new() -> Rc> { + fn new(jit_entry_idx: usize) -> Rc> { let jit_entry = JITEntry { + jit_entry_idx, start_addr: Cell::new(None), }; Rc::new(RefCell::new(jit_entry)) diff --git a/zjit/src/cruby.rs b/zjit/src/cruby.rs index 85aa3c0b05b435..9575c3d1993393 100644 --- a/zjit/src/cruby.rs +++ b/zjit/src/cruby.rs @@ -1105,9 +1105,14 @@ pub mod test_utils { ruby_str_to_rust_string(eval(&inspect)) } - /// Get the ISeq of a specified method + /// Get IseqPtr for a specified method pub fn get_method_iseq(recv: &str, name: &str) -> *const rb_iseq_t { - let wrapped_iseq = eval(&format!("RubyVM::InstructionSequence.of({}.method(:{}))", recv, name)); + get_proc_iseq(&format!("{}.method(:{})", recv, name)) + } + + /// Get IseqPtr for a specified Proc object + pub fn get_proc_iseq(obj: &str) -> *const rb_iseq_t { + let wrapped_iseq = eval(&format!("RubyVM::InstructionSequence.of({obj})")); unsafe { rb_iseqw_to_iseq(wrapped_iseq) } } diff --git a/zjit/src/gc.rs b/zjit/src/gc.rs index bf07f1f340f7d6..eed202ac77a378 100644 --- a/zjit/src/gc.rs +++ b/zjit/src/gc.rs @@ -40,8 +40,8 @@ impl IseqPayload { pub struct IseqCodePtrs { /// Entry for the interpreter pub start_ptr: CodePtr, - /// Entry for JIT-to-JIT calls - pub jit_entry_ptr: CodePtr, + /// Entries for JIT-to-JIT calls + pub jit_entry_ptrs: Vec, } #[derive(Debug, PartialEq)] @@ -128,6 +128,27 @@ pub extern "C" fn rb_zjit_iseq_update_references(payload: *mut c_void) { with_time_stat(gc_time_ns, || iseq_update_references(payload)); } +/// GC callback for finalizing an ISEQ +#[unsafe(no_mangle)] +pub extern "C" fn rb_zjit_iseq_free(iseq: IseqPtr) { + if !ZJITState::has_instance() { + return; + } + // TODO(Shopify/ruby#682): Free `IseqPayload` + let invariants = ZJITState::get_invariants(); + invariants.forget_iseq(iseq); +} + +/// GC callback for finalizing a CME +#[unsafe(no_mangle)] +pub extern "C" fn rb_zjit_cme_free(cme: *const rb_callable_method_entry_struct) { + if !ZJITState::has_instance() { + return; + } + let invariants = ZJITState::get_invariants(); + invariants.forget_cme(cme); +} + /// GC callback for updating object references after all object moves #[unsafe(no_mangle)] pub extern "C" fn rb_zjit_root_update_references() { diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index a23d117d7d27c5..598bcb00c4e082 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -6,10 +6,10 @@ #![allow(clippy::if_same_then_else)] #![allow(clippy::match_like_matches_macro)] use crate::{ - cast::IntoUsize, codegen::local_idx_to_ep_offset, cruby::*, gc::{get_or_create_iseq_payload, IseqPayload}, options::{get_option, DumpHIR}, state::ZJITState + cast::IntoUsize, codegen::local_idx_to_ep_offset, cruby::*, gc::{get_or_create_iseq_payload, IseqPayload}, options::{debug, get_option, DumpHIR}, state::ZJITState }; use std::{ - cell::RefCell, collections::{HashMap, HashSet, VecDeque}, ffi::{c_int, c_void, CStr}, fmt::Display, mem::{align_of, size_of}, ptr, slice::Iter + cell::RefCell, collections::{HashMap, HashSet, VecDeque}, ffi::{c_void, CStr}, fmt::Display, mem::{align_of, size_of}, ptr, slice::Iter }; use crate::hir_type::{Type, types}; use crate::bitset::BitSet; @@ -456,7 +456,6 @@ pub enum SideExitReason { BlockParamProxyModified, BlockParamProxyNotIseqOrIfunc, StackOverflow, - OptionalArgumentsSupplied, } #[derive(Debug, Clone, Copy)] @@ -661,8 +660,8 @@ pub enum Insn { return_type: Option, // None for unannotated builtins }, - /// Set up frame and remember the address as a JIT entry if jit_entry is true - EntryPoint { jit_entry: bool }, + /// Set up frame. Remember the address as the JIT entry for the insn_idx in `jit_entry_insns()[jit_entry_idx]`. + EntryPoint { jit_entry_idx: Option }, /// Control flow instructions Return { val: InsnId }, /// Non-local control flow. See the throw YARV instruction @@ -936,7 +935,8 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> { } Ok(()) } - &Insn::EntryPoint { jit_entry } => write!(f, "EntryPoint {}", if jit_entry { "JIT" } else { "interpreter" }), + &Insn::EntryPoint { jit_entry_idx: Some(idx) } => write!(f, "EntryPoint JIT({idx})"), + &Insn::EntryPoint { jit_entry_idx: None } => write!(f, "EntryPoint interpreter"), Insn::Return { val } => { write!(f, "Return {val}") } Insn::FixnumAdd { left, right, .. } => { write!(f, "FixnumAdd {left}, {right}") }, Insn::FixnumSub { left, right, .. } => { write!(f, "FixnumSub {left}, {right}") }, @@ -1221,7 +1221,8 @@ fn can_direct_send(iseq: *const rb_iseq_t) -> bool { pub struct Function { // ISEQ this function refers to iseq: *const rb_iseq_t, - // The types for the parameters of this function + /// The types for the parameters of this function. They are copied to the type + /// of entry block params after infer_types() fills Empty to all insn_types. param_types: Vec, // TODO: get method name and source location from the ISEQ @@ -1233,7 +1234,7 @@ pub struct Function { /// Entry block for the interpreter entry_block: BlockId, /// Entry block for JIT-to-JIT calls - jit_entry_block: BlockId, + jit_entry_blocks: Vec, profiles: Option, } @@ -1244,9 +1245,9 @@ impl Function { insns: vec![], insn_types: vec![], union_find: UnionFind::new().into(), - blocks: vec![Block::default(), Block::default()], + blocks: vec![Block::default()], entry_block: BlockId(0), - jit_entry_block: BlockId(1), + jit_entry_blocks: vec![], param_types: vec![], profiles: None, } @@ -1607,40 +1608,60 @@ impl Function { } } + /// Set self.param_types. They are copied to the param types of entry blocks. + fn set_param_types(&mut self) { + let iseq = self.iseq; + let param_size = unsafe { get_iseq_body_param_size(iseq) }.as_usize(); + let rest_param_idx = if !iseq.is_null() && unsafe { get_iseq_flags_has_rest(iseq) } { + let opt_num = unsafe { get_iseq_body_param_opt_num(iseq) }; + let lead_num = unsafe { get_iseq_body_param_lead_num(iseq) }; + Some(opt_num + lead_num) + } else { + None + }; + + self.param_types.push(types::BasicObject); // self + for local_idx in 0..param_size { + let param_type = if Some(local_idx as i32) == rest_param_idx { + types::ArrayExact // Rest parameters are always ArrayExact + } else { + types::BasicObject + }; + self.param_types.push(param_type); + } + } + + /// Copy self.param_types to the param types of entry blocks. + fn copy_param_types(&mut self) { + for entry_block in self.entry_blocks() { + let entry_params = self.blocks[entry_block.0].params.iter(); + let param_types = self.param_types.iter(); + assert_eq!( + entry_params.len(), + param_types.len(), + "param types should be initialized before type inference", + ); + for (param, param_type) in std::iter::zip(entry_params, param_types) { + // We know that function parameters are BasicObject or some subclass + self.insn_types[param.0] = *param_type; + } + } + } + fn infer_types(&mut self) { // Reset all types self.insn_types.fill(types::Empty); - // Fill parameter types - // TODO: Remove this when HIR incorporates parameter loads as well - let entry_params = self.blocks[self.entry_block.0].params.iter(); - let param_types = self.param_types.iter(); - assert_eq!( - entry_params.len(), - param_types.len(), - "param types should be initialized before type inference" - ); - for (param, param_type) in std::iter::zip(entry_params, param_types.clone()) { - // We know that function parameters are BasicObject or some subclass - self.insn_types[param.0] = *param_type; - } + // Fill entry parameter types + self.copy_param_types(); - // Fill JIT entry parameter types - let entry_params = self.blocks[self.jit_entry_block.0].params.iter(); - assert_eq!( - entry_params.len(), - param_types.len(), - "param types should be initialized before type inference" - ); - for (param, param_type) in std::iter::zip(entry_params, param_types) { - // We know that function parameters are BasicObject or some subclass - self.insn_types[param.0] = *param_type; + let mut reachable = BlockSet::with_capacity(self.blocks.len()); + for entry_block in self.entry_blocks() { + reachable.insert(entry_block); } - let rpo = self.rpo(); // Walk the graph, computing types until fixpoint - let mut reachable = BlockSet::with_capacity(self.blocks.len()); - reachable.insert(self.entry_block); + let rpo = self.rpo(); loop { let mut changed = false; for &block in &rpo { @@ -2623,15 +2644,21 @@ impl Function { } } + /// Return a list that has entry_block and then jit_entry_blocks + fn entry_blocks(&self) -> Vec { + let mut entry_blocks = self.jit_entry_blocks.clone(); + entry_blocks.insert(0, self.entry_block); + entry_blocks + } + /// Return a traversal of the `Function`'s `BlockId`s in reverse post-order. pub fn rpo(&self) -> Vec { - let mut result = self.po_from(self.entry_block); + let mut result = self.po_from(self.entry_blocks()); result.reverse(); - result.insert(1, self.jit_entry_block); // Put jit_entry_block after entry_block result } - fn po_from(&self, start: BlockId) -> Vec { + fn po_from(&self, starts: Vec) -> Vec { #[derive(PartialEq)] enum Action { VisitEdges, @@ -2639,7 +2666,7 @@ impl Function { } let mut result = vec![]; let mut seen = BlockSet::with_capacity(self.blocks.len()); - let mut stack = vec![(start, Action::VisitEdges)]; + let mut stack: Vec<_> = starts.iter().map(|&start| (start, Action::VisitEdges)).collect(); while let Some((block, action)) = stack.pop() { if action == Action::VisitSelf { result.push(block); @@ -3125,16 +3152,36 @@ fn insn_idx_at_offset(idx: u32, offset: i64) -> u32 { ((idx as isize) + (offset as isize)) as u32 } +/// List of insn_idx that starts a JIT entry block +fn jit_entry_insns(iseq: IseqPtr) -> Vec { + let opt_num = unsafe { get_iseq_body_param_opt_num(iseq) }; + if opt_num > 0 { + let mut result = vec![]; + + let opt_table = unsafe { get_iseq_body_param_opt_table(iseq) }; // `opt_num + 1` entries + for opt_idx in 0..=opt_num as isize { + let insn_idx = unsafe { opt_table.offset(opt_idx).read().as_u32() }; + result.push(insn_idx); + } + + // Deduplicate entries with HashSet since opt_table may have duplicated entries, e.g. proc { |a=a| a } + result.sort(); + result.dedup(); + result + } else { + vec![0] + } +} + struct BytecodeInfo { jump_targets: Vec, has_blockiseq: bool, } -fn compute_bytecode_info(iseq: *const rb_iseq_t) -> BytecodeInfo { +fn compute_bytecode_info(iseq: *const rb_iseq_t, opt_table: &Vec) -> BytecodeInfo { let iseq_size = unsafe { get_iseq_encoded_size(iseq) }; let mut insn_idx = 0; - let mut jump_targets = HashSet::new(); - jump_targets.insert(0); // entry blocks jump to the first instruction + let mut jump_targets: HashSet = opt_table.iter().copied().collect(); let mut has_blockiseq = false; while insn_idx < iseq_size { // Get the current pc and opcode @@ -3185,6 +3232,7 @@ pub enum ParseError { StackUnderflow(FrameState), MalformedIseq(u32), // insn_idx into iseq_encoded Validation(ValidationError), + FailedOptionalArguments, NotAllowed, } @@ -3258,9 +3306,16 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result { let mut fun = Function::new(iseq); // Compute a map of PC->Block by finding jump targets - let BytecodeInfo { jump_targets, has_blockiseq } = compute_bytecode_info(iseq); + let jit_entry_insns = jit_entry_insns(iseq); + let BytecodeInfo { jump_targets, has_blockiseq } = compute_bytecode_info(iseq, &jit_entry_insns); let mut insn_idx_to_block = HashMap::new(); for insn_idx in jump_targets { + // Prepend a JIT entry block if it's a jit_entry_insn. + // compile_entry_block() assumes that a JIT entry block jumps to the next block. + if jit_entry_insns.contains(&insn_idx) { + let jit_entry_block = fun.new_block(insn_idx); + fun.jit_entry_blocks.push(jit_entry_block); + } insn_idx_to_block.insert(insn_idx, fun.new_block(insn_idx)); } @@ -3268,60 +3323,34 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result { // optimizing locals in that case because they're shared with other frames. let ep_escaped = iseq_escapes_ep(iseq); - // Compile an interpreter entry to the first block - let first_block = insn_idx_to_block[&0]; - compile_entry_block(fun.entry_block, first_block, &mut fun, false); - - // Compile a JIT entry to the first block - compile_entry_block(fun.jit_entry_block, first_block, &mut fun, true); + // Compile an entry_block for the interpreter + compile_entry_block(&mut fun, &jit_entry_insns); // Iteratively fill out basic blocks using a queue // TODO(max): Basic block arguments at edges - let mut queue = std::collections::VecDeque::new(); - // Index of the rest parameter for comparison below - let rest_param_idx = if !iseq.is_null() && unsafe { get_iseq_flags_has_rest(iseq) } { - let opt_num = unsafe { get_iseq_body_param_opt_num(iseq) }; - let lead_num = unsafe { get_iseq_body_param_lead_num(iseq) }; - opt_num + lead_num - } else { - -1 - }; - // The HIR function will have the same number of parameter as the iseq so - // we properly handle calls from the interpreter. Roughly speaking, each - // item between commas in the source increase the parameter count by one, - // regardless of parameter kind. - let mut entry_state = FrameState::new(iseq); - fun.push_insn(first_block, Insn::Param { idx: SELF_PARAM_IDX }); - fun.param_types.push(types::BasicObject); // self - for local_idx in 0..num_locals(iseq) { - if local_idx < unsafe { get_iseq_body_param_size(iseq) }.as_usize() { - entry_state.locals.push(fun.push_insn(first_block, Insn::Param { idx: local_idx + 1 })); // +1 for self - - let mut param_type = types::BasicObject; - // Rest parameters are always ArrayExact - if let Ok(true) = c_int::try_from(local_idx).map(|idx| idx == rest_param_idx) { - param_type = types::ArrayExact; - } - fun.param_types.push(param_type); - } else { - entry_state.locals.push(fun.push_insn(first_block, Insn::Const { val: Const::Value(Qnil) })); - } - } - queue.push_back((entry_state.clone(), first_block, /*insn_idx=*/0_u32, /*local_inval=*/false)); + let mut queue = VecDeque::new(); + queue.push_back((FrameState::new(iseq), insn_idx_to_block[&0], /*insn_idx=*/0, /*local_inval=*/false)); + // Keep compiling blocks until the queue becomes empty let mut visited = HashSet::new(); - let iseq_size = unsafe { get_iseq_encoded_size(iseq) }; while let Some((incoming_state, block, mut insn_idx, mut local_inval)) = queue.pop_front() { + // Compile each block only once if visited.contains(&block) { continue; } visited.insert(block); - let (self_param, mut state) = if insn_idx == 0 { - (fun.blocks[block.0].params[SELF_PARAM_IDX], incoming_state.clone()) - } else { - let self_param = fun.push_insn(block, Insn::Param { idx: SELF_PARAM_IDX }); + + // Compile a JIT entry to the block if it's a jit_entry_insn + if let Some(block_idx) = jit_entry_insns.iter().position(|&idx| idx == insn_idx) { + compile_jit_entry_block(&mut fun, block_idx, block); + } + + // Load basic block params first + let self_param = fun.push_insn(block, Insn::Param { idx: SELF_PARAM_IDX }); + let mut state = { let mut result = FrameState::new(iseq); let mut idx = 1; - for _ in 0..incoming_state.locals.len() { + let local_size = if insn_idx == 0 { num_locals(iseq) } else { incoming_state.locals.len() }; + for _ in 0..local_size { result.locals.push(fun.push_insn(block, Insn::Param { idx })); idx += 1; } @@ -3329,8 +3358,9 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result { result.stack.push(fun.push_insn(block, Insn::Param { idx })); idx += 1; } - (self_param, result) + result }; + // Start the block off with a Snapshot so that if we need to insert a new Guard later on // and we don't have a Snapshot handy, we can just iterate backward (at the earliest, to // the beginning of the block). @@ -4106,6 +4136,15 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result { } } + // Bail out if there's a JIT entry block whose target block was not compiled + // due to an unsupported instruction in the middle of the ISEQ. + for jit_entry_block in fun.jit_entry_blocks.iter() { + if fun.blocks[jit_entry_block.0].insns.is_empty() { + return Err(ParseError::FailedOptionalArguments); + } + } + + fun.set_param_types(); fun.infer_types(); match get_option!(dump_hir_init) { @@ -4116,44 +4155,77 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result { } fun.profiles = Some(profiles); - if let Err(e) = fun.validate() { - return Err(ParseError::Validation(e)); + if let Err(err) = fun.validate() { + debug!("ZJIT: {err:?}: Initial HIR:\n{}", FunctionPrinter::without_snapshot(&fun)); + return Err(ParseError::Validation(err)); } Ok(fun) } -/// Compile entry_block that jumps to first_block. Add prologue for the interpreter if jit_entry is false. -fn compile_entry_block(entry_block: BlockId, first_block: BlockId, fun: &mut Function, jit_entry: bool) { - fun.push_insn(entry_block, Insn::EntryPoint { jit_entry }); +/// Compile an entry_block for the interpreter +fn compile_entry_block(fun: &mut Function, jit_entry_insns: &Vec) { + let entry_block = fun.entry_block; + fun.push_insn(entry_block, Insn::EntryPoint { jit_entry_idx: None }); // Prepare entry_state with basic block params - let iseq = fun.iseq; - let mut entry_state = FrameState::new(iseq); - let self_param = fun.push_insn(entry_block, Insn::Param { idx: SELF_PARAM_IDX }); - for local_idx in 0..unsafe { get_iseq_body_param_size(iseq) }.as_usize() { - entry_state.locals.push(fun.push_insn(entry_block, Insn::Param { idx: local_idx + 1 })); // +1 for self + let (self_param, entry_state) = compile_entry_state(fun, entry_block); + + // Jump to target blocks + let mut pc: Option = None; + let &last_entry_insn = jit_entry_insns.last().unwrap(); + for (jit_entry_block_idx, &jit_entry_insn) in jit_entry_insns.iter().enumerate() { + let jit_entry_block = fun.jit_entry_blocks[jit_entry_block_idx]; + let target_block = BlockId(jit_entry_block.0 + 1); // jit_entry_block precedes the jump target block + + if jit_entry_insn == last_entry_insn { + // If it's the last possible entry, jump to the target_block without checking PC + fun.push_insn(entry_block, Insn::Jump(BranchEdge { target: target_block, args: entry_state.as_args(self_param) })); + } else { + // Otherwise, jump to the target_block only if PC matches. + let pc = pc.unwrap_or_else(|| { + let insn_id = fun.push_insn(entry_block, Insn::LoadPC); + pc = Some(insn_id); + insn_id + }); + let expected_pc = fun.push_insn(entry_block, Insn::Const { + val: Const::CPtr(unsafe { rb_iseq_pc_at_idx(fun.iseq, jit_entry_insn) } as *const u8), + }); + let test_id = fun.push_insn(entry_block, Insn::IsBitEqual { left: pc, right: expected_pc }); + fun.push_insn(entry_block, Insn::IfTrue { + val: test_id, + target: BranchEdge { target: target_block, args: entry_state.as_args(self_param) }, + }); + } } +} - // Jump to the first_block. Conditionally side-exit for interpreter entry with optional arguments. - // TODO: Compile gen_entry_params() for !jit_entry here - let opt_num = unsafe { get_iseq_body_param_opt_num(iseq) }; - if !jit_entry && opt_num > 0 { - let pc = fun.push_insn(entry_block, Insn::LoadPC); - let no_opts_pc = fun.push_insn(entry_block, Insn::Const { val: Const::CPtr(unsafe { rb_iseq_pc_at_idx(iseq, 0) } as *const u8) }); - let test_id = fun.push_insn(entry_block, Insn::IsBitEqual { left: pc, right: no_opts_pc }); - - // Jump to the first_block if no optional arguments are supplied - fun.push_insn(entry_block, Insn::IfTrue { - val: test_id, - target: BranchEdge { target: first_block, args: entry_state.as_args(self_param) }, - }); +/// Compile a jit_entry_block +fn compile_jit_entry_block(fun: &mut Function, jit_entry_idx: usize, target_block: BlockId) { + let jit_entry_block = fun.jit_entry_blocks[jit_entry_idx]; + fun.push_insn(jit_entry_block, Insn::EntryPoint { jit_entry_idx: Some(jit_entry_idx) }); - // Side-exit if any optional argument is supplied - let state = fun.push_insn(entry_block, Insn::Snapshot { state: FrameState::new(iseq) }); // no need to spill params - fun.push_insn(entry_block, Insn::SideExit { state, reason: SideExitReason::OptionalArgumentsSupplied }); - } else { - fun.push_insn(entry_block, Insn::Jump(BranchEdge { target: first_block, args: entry_state.as_args(self_param) })); + // Prepare entry_state with basic block params + let (self_param, entry_state) = compile_entry_state(fun, jit_entry_block); + + // Jump to target_block + fun.push_insn(jit_entry_block, Insn::Jump(BranchEdge { target: target_block, args: entry_state.as_args(self_param) })); +} + +/// Compile params and initial locals for an entry block +fn compile_entry_state(fun: &mut Function, entry_block: BlockId) -> (InsnId, FrameState) { + let iseq = fun.iseq; + let param_size = unsafe { get_iseq_body_param_size(iseq) }.as_usize(); + + let self_param = fun.push_insn(entry_block, Insn::Param { idx: SELF_PARAM_IDX }); + let mut entry_state = FrameState::new(iseq); + for local_idx in 0..num_locals(iseq) { + if local_idx < param_size { + entry_state.locals.push(fun.push_insn(entry_block, Insn::Param { idx: local_idx + 1 })); // +1 for self + } else { + entry_state.locals.push(fun.push_insn(entry_block, Insn::Const { val: Const::Value(Qnil) })); + } } + (self_param, entry_state) } #[cfg(test)] @@ -4201,29 +4273,26 @@ mod rpo_tests { fn one_block() { let mut function = Function::new(std::ptr::null()); let entry = function.entry_block; - let jit_entry = function.jit_entry_block; let val = function.push_insn(entry, Insn::Const { val: Const::Value(Qnil) }); function.push_insn(entry, Insn::Return { val }); - assert_eq!(function.rpo(), vec![entry, jit_entry]); + assert_eq!(function.rpo(), vec![entry]); } #[test] fn jump() { let mut function = Function::new(std::ptr::null()); let entry = function.entry_block; - let jit_entry = function.jit_entry_block; let exit = function.new_block(0); function.push_insn(entry, Insn::Jump(BranchEdge { target: exit, args: vec![] })); let val = function.push_insn(entry, Insn::Const { val: Const::Value(Qnil) }); function.push_insn(entry, Insn::Return { val }); - assert_eq!(function.rpo(), vec![entry, jit_entry, exit]); + assert_eq!(function.rpo(), vec![entry, exit]); } #[test] fn diamond_iftrue() { let mut function = Function::new(std::ptr::null()); let entry = function.entry_block; - let jit_entry = function.jit_entry_block; let side = function.new_block(0); let exit = function.new_block(0); function.push_insn(side, Insn::Jump(BranchEdge { target: exit, args: vec![] })); @@ -4232,14 +4301,13 @@ mod rpo_tests { function.push_insn(entry, Insn::Jump(BranchEdge { target: exit, args: vec![] })); let val = function.push_insn(entry, Insn::Const { val: Const::Value(Qnil) }); function.push_insn(entry, Insn::Return { val }); - assert_eq!(function.rpo(), vec![entry, jit_entry, side, exit]); + assert_eq!(function.rpo(), vec![entry, side, exit]); } #[test] fn diamond_iffalse() { let mut function = Function::new(std::ptr::null()); let entry = function.entry_block; - let jit_entry = function.jit_entry_block; let side = function.new_block(0); let exit = function.new_block(0); function.push_insn(side, Insn::Jump(BranchEdge { target: exit, args: vec![] })); @@ -4248,16 +4316,15 @@ mod rpo_tests { function.push_insn(entry, Insn::Jump(BranchEdge { target: exit, args: vec![] })); let val = function.push_insn(entry, Insn::Const { val: Const::Value(Qnil) }); function.push_insn(entry, Insn::Return { val }); - assert_eq!(function.rpo(), vec![entry, jit_entry, side, exit]); + assert_eq!(function.rpo(), vec![entry, side, exit]); } #[test] fn a_loop() { let mut function = Function::new(std::ptr::null()); let entry = function.entry_block; - let jit_entry = function.jit_entry_block; function.push_insn(entry, Insn::Jump(BranchEdge { target: entry, args: vec![] })); - assert_eq!(function.rpo(), vec![entry, jit_entry]); + assert_eq!(function.rpo(), vec![entry]); } } @@ -4387,11 +4454,7 @@ mod validation_tests { fn instruction_appears_twice_in_same_block() { let mut function = Function::new(std::ptr::null()); let block = function.new_block(0); - - // Add jumps from entry blocks to avoid BlockHasNoterminator function.push_insn(function.entry_block, Insn::Jump(BranchEdge { target: block, args: vec![] })); - function.push_insn(function.jit_entry_block, Insn::Jump(BranchEdge { target: block, args: vec![] })); - let val = function.push_insn(block, Insn::Const { val: Const::Value(Qnil) }); function.push_insn_id(block, val); function.push_insn(block, Insn::Return { val }); @@ -4402,11 +4465,7 @@ mod validation_tests { fn instruction_appears_twice_with_different_ids() { let mut function = Function::new(std::ptr::null()); let block = function.new_block(0); - - // Add jumps from entry blocks to avoid BlockHasNoterminator function.push_insn(function.entry_block, Insn::Jump(BranchEdge { target: block, args: vec![] })); - function.push_insn(function.jit_entry_block, Insn::Jump(BranchEdge { target: block, args: vec![] })); - let val0 = function.push_insn(block, Insn::Const { val: Const::Value(Qnil) }); let val1 = function.push_insn(block, Insn::Const { val: Const::Value(Qnil) }); function.make_equal_to(val1, val0); @@ -4418,11 +4477,7 @@ mod validation_tests { fn instruction_appears_twice_in_different_blocks() { let mut function = Function::new(std::ptr::null()); let block = function.new_block(0); - - // Add jumps from entry blocks to avoid BlockHasNoterminator function.push_insn(function.entry_block, Insn::Jump(BranchEdge { target: block, args: vec![] })); - function.push_insn(function.jit_entry_block, Insn::Jump(BranchEdge { target: block, args: vec![] })); - let val = function.push_insn(block, Insn::Const { val: Const::Value(Qnil) }); let exit = function.new_block(0); function.push_insn(block, Insn::Jump(BranchEdge { target: exit, args: vec![] })); @@ -4491,7 +4546,6 @@ mod infer_tests { crate::cruby::with_rubyvm(|| { let mut function = Function::new(std::ptr::null()); let param = function.push_insn(function.entry_block, Insn::Param { idx: SELF_PARAM_IDX }); - function.push_insn(function.jit_entry_block, Insn::Param { idx: SELF_PARAM_IDX }); function.param_types.push(types::BasicObject); // self let val = function.push_insn(function.entry_block, Insn::Test { val: param }); function.infer_types(); @@ -4577,7 +4631,7 @@ mod snapshot_tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): v13:Any = Snapshot FrameState { pc: 0x1000, stack: [], locals: [a=v11, b=v12] } @@ -4634,9 +4688,23 @@ mod tests { } } + /// Combine multiple hir_string() results to match all of them at once, which allows + /// us to avoid running the set of zjit-test -> zjit-test-update multiple times. + #[macro_export] + macro_rules! hir_strings { + ($( $s:expr ),+ $(,)?) => {{ + vec![$( hir_string($s) ),+].join("\n") + }}; + } + #[track_caller] fn hir_string(method: &str) -> String { - let iseq = crate::cruby::with_rubyvm(|| get_method_iseq("self", method)); + hir_string_proc(&format!("{}.method(:{})", "self", method)) + } + + #[track_caller] + fn hir_string_proc(proc: &str) -> String { + let iseq = crate::cruby::with_rubyvm(|| get_proc_iseq(proc)); unsafe { crate::cruby::rb_zjit_profile_disable(iseq) }; let function = iseq_to_hir(iseq).unwrap(); hir_string_function(&function) @@ -4667,15 +4735,20 @@ mod tests { v4:CPtr[CPtr(0x1000)] = Const CPtr(0x1008) v5:CBool = IsBitEqual v3, v4 IfTrue v5, bb2(v1, v2) - SideExit OptionalArgumentsSupplied - bb1(v10:BasicObject, v11:BasicObject): - EntryPoint JIT - Jump bb2(v10, v11) - bb2(v13:BasicObject, v14:BasicObject): - v16:Fixnum[1] = Const Value(1) - v19:Fixnum[123] = Const Value(123) + Jump bb4(v1, v2) + bb1(v9:BasicObject, v10:BasicObject): + EntryPoint JIT(0) + Jump bb2(v9, v10) + bb2(v12:BasicObject, v13:BasicObject): + v15:Fixnum[1] = Const Value(1) + Jump bb4(v12, v15) + bb3(v18:BasicObject, v19:BasicObject): + EntryPoint JIT(1) + Jump bb4(v18, v19) + bb4(v21:BasicObject, v22:BasicObject): + v26:Fixnum[123] = Const Value(123) CheckInterrupts - Return v19 + Return v26 "); } @@ -4689,7 +4762,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[123] = Const Value(123) @@ -4708,7 +4781,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v11:ArrayExact = NewArray @@ -4727,7 +4800,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v14:ArrayExact = NewArray v9 @@ -4746,7 +4819,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): v17:ArrayExact = NewArray v11, v12 @@ -4765,7 +4838,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v13:Fixnum[10] = Const Value(10) @@ -4785,7 +4858,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): v17:RangeExact = NewRange v11 NewRangeInclusive v12 @@ -4804,7 +4877,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v13:Fixnum[10] = Const Value(10) @@ -4824,7 +4897,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): v17:RangeExact = NewRange v11 NewRangeExclusive v12 @@ -4843,7 +4916,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) @@ -4863,7 +4936,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:HashExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) @@ -4883,7 +4956,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v11:HashExact = NewHash @@ -4902,7 +4975,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): v16:StaticSymbol[:a] = Const Value(VALUE(0x1000)) @@ -4923,7 +4996,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) @@ -4943,7 +5016,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Bignum[VALUE(0x1000)] = Const Value(VALUE(0x1000)) @@ -4962,7 +5035,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Flonum[VALUE(0x1000)] = Const Value(VALUE(0x1000)) @@ -4981,7 +5054,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:HeapFloat[VALUE(0x1000)] = Const Value(VALUE(0x1000)) @@ -5000,7 +5073,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:StaticSymbol[:foo] = Const Value(VALUE(0x1000)) @@ -5019,7 +5092,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[1] = Const Value(1) @@ -5042,7 +5115,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint BOPRedefined(HASH_REDEFINED_OP_FLAG, BOP_FREEZE) @@ -5067,7 +5140,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): SideExit PatchPoint(BOPRedefined(HASH_REDEFINED_OP_FLAG, BOP_FREEZE)) @@ -5086,7 +5159,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_FREEZE) @@ -5111,7 +5184,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): SideExit PatchPoint(BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_FREEZE)) @@ -5130,7 +5203,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint BOPRedefined(STRING_REDEFINED_OP_FLAG, BOP_FREEZE) @@ -5155,7 +5228,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): SideExit PatchPoint(BOPRedefined(STRING_REDEFINED_OP_FLAG, BOP_FREEZE)) @@ -5174,7 +5247,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint BOPRedefined(STRING_REDEFINED_OP_FLAG, BOP_UMINUS) @@ -5199,7 +5272,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): SideExit PatchPoint(BOPRedefined(STRING_REDEFINED_OP_FLAG, BOP_UMINUS)) @@ -5219,15 +5292,16 @@ mod tests { fn test@:3: bb0(v1:BasicObject): EntryPoint interpreter - Jump bb2(v1) - bb1(v4:BasicObject): - EntryPoint JIT - Jump bb2(v4) - bb2(v6:BasicObject): - v7:NilClass = Const Value(nil) - v11:Fixnum[1] = Const Value(1) + v2:NilClass = Const Value(nil) + Jump bb2(v1, v2) + bb1(v5:BasicObject): + EntryPoint JIT(0) + v6:NilClass = Const Value(nil) + Jump bb2(v5, v6) + bb2(v8:BasicObject, v9:NilClass): + v13:Fixnum[1] = Const Value(1) CheckInterrupts - Return v11 + Return v13 "); } @@ -5259,7 +5333,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:BasicObject = GetLocal l2, EP@4 @@ -5278,6 +5352,77 @@ mod tests { ); } + #[test] + fn test_setlocal_in_default_args() { + eval(" + def test(a = (b = 1)) = [a, b] + "); + assert_contains_opcode("test", YARVINSN_setlocal_WC_0); + assert_snapshot!(hir_string("test"), @r" + fn test@:2: + bb0(v1:BasicObject, v2:BasicObject): + EntryPoint interpreter + v3:NilClass = Const Value(nil) + v4:CPtr = LoadPC + v5:CPtr[CPtr(0x1000)] = Const CPtr(0x1008) + v6:CBool = IsBitEqual v4, v5 + IfTrue v6, bb2(v1, v2, v3) + Jump bb4(v1, v2, v3) + bb1(v10:BasicObject, v11:BasicObject): + EntryPoint JIT(0) + v12:NilClass = Const Value(nil) + Jump bb2(v10, v11, v12) + bb2(v14:BasicObject, v15:BasicObject, v16:NilClass): + v20:Fixnum[1] = Const Value(1) + Jump bb4(v14, v20, v20) + bb3(v23:BasicObject, v24:BasicObject): + EntryPoint JIT(1) + v25:NilClass = Const Value(nil) + Jump bb4(v23, v24, v25) + bb4(v27:BasicObject, v28:BasicObject, v29:NilClass|Fixnum): + v34:ArrayExact = NewArray v28, v29 + CheckInterrupts + Return v34 + "); + } + + #[test] + fn test_setlocal_in_default_args_with_tracepoint() { + eval(" + def test(a = (b = 1)) = [a, b] + TracePoint.new(:line) {}.enable + test + "); + assert_compile_fails("test", ParseError::FailedOptionalArguments); + } + + #[test] + fn test_setlocal_in_default_args_with_side_exit() { + eval(" + def test(a = (def foo = nil)) = a + "); + assert_compile_fails("test", ParseError::FailedOptionalArguments); + } + + #[test] + fn test_setlocal_cyclic_default_args() { + eval(" + def test = proc { |a=a| a } + "); + assert_snapshot!(hir_string_proc("test"), @r" + fn block in test@:2: + bb0(v1:BasicObject, v2:BasicObject): + EntryPoint interpreter + Jump bb2(v1, v2) + bb1(v5:BasicObject, v6:BasicObject): + EntryPoint JIT(0) + Jump bb2(v5, v6) + bb2(v8:BasicObject, v9:BasicObject): + CheckInterrupts + Return v9 + "); + } + #[test] fn defined_ivar() { eval(" @@ -5290,7 +5435,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v11:StringExact|NilClass = DefinedIvar v6, :@foo @@ -5317,7 +5462,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v11:TrueClass|NilClass = DefinedIvar v6, :@foo @@ -5346,7 +5491,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:NilClass = Const Value(nil) @@ -5378,7 +5523,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): CheckInterrupts @@ -5410,27 +5555,28 @@ mod tests { fn test@:3: bb0(v1:BasicObject, v2:BasicObject): EntryPoint interpreter - Jump bb2(v1, v2) - bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT - Jump bb2(v5, v6) - bb2(v8:BasicObject, v9:BasicObject): - v10:NilClass = Const Value(nil) + v3:NilClass = Const Value(nil) + Jump bb2(v1, v2, v3) + bb1(v6:BasicObject, v7:BasicObject): + EntryPoint JIT(0) + v8:NilClass = Const Value(nil) + Jump bb2(v6, v7, v8) + bb2(v10:BasicObject, v11:BasicObject, v12:NilClass): CheckInterrupts - v16:CBool = Test v9 - IfFalse v16, bb3(v8, v9, v10) - v20:Fixnum[3] = Const Value(3) + v18:CBool = Test v11 + IfFalse v18, bb3(v10, v11, v12) + v22:Fixnum[3] = Const Value(3) PatchPoint NoEPEscape(test) CheckInterrupts - Jump bb4(v8, v9, v20) - bb3(v26:BasicObject, v27:BasicObject, v28:NilClass): - v32:Fixnum[4] = Const Value(4) + Jump bb4(v10, v11, v22) + bb3(v28:BasicObject, v29:BasicObject, v30:NilClass): + v34:Fixnum[4] = Const Value(4) PatchPoint NoEPEscape(test) - Jump bb4(v26, v27, v32) - bb4(v36:BasicObject, v37:BasicObject, v38:Fixnum): + Jump bb4(v28, v29, v34) + bb4(v38:BasicObject, v39:BasicObject, v40:Fixnum): PatchPoint NoEPEscape(test) CheckInterrupts - Return v38 + Return v40 "); } @@ -5447,7 +5593,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): v19:BasicObject = SendWithoutBlock v11, :+, v12 @@ -5469,7 +5615,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): v19:BasicObject = SendWithoutBlock v11, :-, v12 @@ -5491,7 +5637,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): v19:BasicObject = SendWithoutBlock v11, :*, v12 @@ -5513,7 +5659,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): v19:BasicObject = SendWithoutBlock v11, :/, v12 @@ -5535,7 +5681,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): v19:BasicObject = SendWithoutBlock v11, :%, v12 @@ -5557,7 +5703,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): v19:BasicObject = SendWithoutBlock v11, :==, v12 @@ -5579,7 +5725,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): v19:BasicObject = SendWithoutBlock v11, :!=, v12 @@ -5601,7 +5747,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): v19:BasicObject = SendWithoutBlock v11, :<, v12 @@ -5623,7 +5769,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): v19:BasicObject = SendWithoutBlock v11, :<=, v12 @@ -5645,7 +5791,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): v19:BasicObject = SendWithoutBlock v11, :>, v12 @@ -5672,35 +5818,37 @@ mod tests { fn test@:3: bb0(v1:BasicObject): EntryPoint interpreter - Jump bb2(v1) - bb1(v4:BasicObject): - EntryPoint JIT - Jump bb2(v4) - bb2(v6:BasicObject): + v2:NilClass = Const Value(nil) + v3:NilClass = Const Value(nil) + Jump bb2(v1, v2, v3) + bb1(v6:BasicObject): + EntryPoint JIT(0) v7:NilClass = Const Value(nil) v8:NilClass = Const Value(nil) - v12:Fixnum[0] = Const Value(0) - v15:Fixnum[10] = Const Value(10) + Jump bb2(v6, v7, v8) + bb2(v10:BasicObject, v11:NilClass, v12:NilClass): + v16:Fixnum[0] = Const Value(0) + v19:Fixnum[10] = Const Value(10) CheckInterrupts - Jump bb4(v6, v12, v15) - bb4(v21:BasicObject, v22:BasicObject, v23:BasicObject): + Jump bb4(v10, v16, v19) + bb4(v25:BasicObject, v26:BasicObject, v27:BasicObject): PatchPoint NoEPEscape(test) - v27:Fixnum[0] = Const Value(0) - v31:BasicObject = SendWithoutBlock v23, :>, v27 + v31:Fixnum[0] = Const Value(0) + v35:BasicObject = SendWithoutBlock v27, :>, v31 CheckInterrupts - v34:CBool = Test v31 - IfTrue v34, bb3(v21, v22, v23) - v36:NilClass = Const Value(nil) + v38:CBool = Test v35 + IfTrue v38, bb3(v25, v26, v27) + v40:NilClass = Const Value(nil) PatchPoint NoEPEscape(test) CheckInterrupts - Return v22 - bb3(v46:BasicObject, v47:BasicObject, v48:BasicObject): + Return v26 + bb3(v50:BasicObject, v51:BasicObject, v52:BasicObject): PatchPoint NoEPEscape(test) - v54:Fixnum[1] = Const Value(1) - v58:BasicObject = SendWithoutBlock v47, :+, v54 - v61:Fixnum[1] = Const Value(1) - v65:BasicObject = SendWithoutBlock v48, :-, v61 - Jump bb4(v46, v58, v65) + v58:Fixnum[1] = Const Value(1) + v62:BasicObject = SendWithoutBlock v51, :+, v58 + v65:Fixnum[1] = Const Value(1) + v69:BasicObject = SendWithoutBlock v52, :-, v65 + Jump bb4(v50, v62, v69) "); } @@ -5717,7 +5865,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): v19:BasicObject = SendWithoutBlock v11, :>=, v12 @@ -5742,23 +5890,24 @@ mod tests { fn test@:3: bb0(v1:BasicObject): EntryPoint interpreter - Jump bb2(v1) - bb1(v4:BasicObject): - EntryPoint JIT - Jump bb2(v4) - bb2(v6:BasicObject): - v7:NilClass = Const Value(nil) - v11:TrueClass = Const Value(true) + v2:NilClass = Const Value(nil) + Jump bb2(v1, v2) + bb1(v5:BasicObject): + EntryPoint JIT(0) + v6:NilClass = Const Value(nil) + Jump bb2(v5, v6) + bb2(v8:BasicObject, v9:NilClass): + v13:TrueClass = Const Value(true) CheckInterrupts - v16:CBool[true] = Test v11 - IfFalse v16, bb3(v6, v11) - v20:Fixnum[3] = Const Value(3) + v18:CBool[true] = Test v13 + IfFalse v18, bb3(v8, v13) + v22:Fixnum[3] = Const Value(3) CheckInterrupts - Return v20 - bb3(v26, v27): - v31 = Const Value(4) + Return v22 + bb3(v28, v29): + v33 = Const Value(4) CheckInterrupts - Return v31 + Return v33 "); } @@ -5779,7 +5928,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[2] = Const Value(2) @@ -5807,7 +5956,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v13:BasicObject = GetLocal l0, EP@3 @@ -5832,7 +5981,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) @@ -5857,7 +6006,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) @@ -5885,7 +6034,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v14:ArrayExact = ToArray v9 @@ -5904,7 +6053,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v14:BasicObject = Send v8, 0x1000, :foo, v9 @@ -5924,7 +6073,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v13:Fixnum[1] = Const Value(1) @@ -5943,7 +6092,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v14:BasicObject = SendWithoutBlock v8, :foo, v9 @@ -5965,7 +6114,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v11:BasicObject = InvokeSuper v6, 0x1000 @@ -5985,7 +6134,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v11:BasicObject = InvokeSuper v6, 0x1000 @@ -6005,7 +6154,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:NilClass = Const Value(nil) @@ -6026,7 +6175,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): SideExit UnhandledYARVInsn(invokesuperforward) @@ -6042,7 +6191,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v13:NilClass = Const Value(nil) @@ -6064,7 +6213,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v13:Class[VMFrozenCore] = Const Value(VALUE(0x1000)) @@ -6092,7 +6241,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:ArrayExact): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:ArrayExact): v14:ArrayExact = ToNewArray v9 @@ -6113,7 +6262,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v14:BasicObject = SendForward 0x1000, :foo, v9 @@ -6131,16 +6280,17 @@ mod tests { fn test@:2: bb0(v1:BasicObject, v2:BasicObject, v3:ArrayExact, v4:BasicObject, v5:BasicObject): EntryPoint interpreter - Jump bb2(v1, v2, v3, v4, v5) - bb1(v8:BasicObject, v9:BasicObject, v10:ArrayExact, v11:BasicObject, v12:BasicObject): - EntryPoint JIT - Jump bb2(v8, v9, v10, v11, v12) - bb2(v14:BasicObject, v15:BasicObject, v16:ArrayExact, v17:BasicObject, v18:BasicObject): - v19:NilClass = Const Value(nil) - v24:ArrayExact = ToArray v16 + v6:NilClass = Const Value(nil) + Jump bb2(v1, v2, v3, v4, v5, v6) + bb1(v9:BasicObject, v10:BasicObject, v11:ArrayExact, v12:BasicObject, v13:BasicObject): + EntryPoint JIT(0) + v14:NilClass = Const Value(nil) + Jump bb2(v9, v10, v11, v12, v13, v14) + bb2(v16:BasicObject, v17:BasicObject, v18:ArrayExact, v19:BasicObject, v20:BasicObject, v21:NilClass): + v26:ArrayExact = ToArray v18 PatchPoint NoEPEscape(test) GuardBlockParamProxy l0 - v29:HeapObject[BlockParamProxy] = Const Value(VALUE(0x1000)) + v31:HeapObject[BlockParamProxy] = Const Value(VALUE(0x1000)) SideExit UnhandledYARVInsn(splatkw) "); } @@ -6158,7 +6308,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v11:BasicObject = GetConstantPath 0x1000 @@ -6191,7 +6341,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_MAX) @@ -6213,7 +6363,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_MAX) @@ -6238,14 +6388,16 @@ mod tests { fn test@:3: bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): EntryPoint interpreter - Jump bb2(v1, v2, v3) - bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT - Jump bb2(v6, v7, v8) - bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): - v13:NilClass = Const Value(nil) - v14:NilClass = Const Value(nil) - v21:BasicObject = SendWithoutBlock v11, :+, v12 + v4:NilClass = Const Value(nil) + v5:NilClass = Const Value(nil) + Jump bb2(v1, v2, v3, v4, v5) + bb1(v8:BasicObject, v9:BasicObject, v10:BasicObject): + EntryPoint JIT(0) + v11:NilClass = Const Value(nil) + v12:NilClass = Const Value(nil) + Jump bb2(v8, v9, v10, v11, v12) + bb2(v14:BasicObject, v15:BasicObject, v16:BasicObject, v17:NilClass, v18:NilClass): + v25:BasicObject = SendWithoutBlock v15, :+, v16 SideExit UnknownNewarraySend(MIN) "); } @@ -6265,14 +6417,16 @@ mod tests { fn test@:3: bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): EntryPoint interpreter - Jump bb2(v1, v2, v3) - bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT - Jump bb2(v6, v7, v8) - bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): - v13:NilClass = Const Value(nil) - v14:NilClass = Const Value(nil) - v21:BasicObject = SendWithoutBlock v11, :+, v12 + v4:NilClass = Const Value(nil) + v5:NilClass = Const Value(nil) + Jump bb2(v1, v2, v3, v4, v5) + bb1(v8:BasicObject, v9:BasicObject, v10:BasicObject): + EntryPoint JIT(0) + v11:NilClass = Const Value(nil) + v12:NilClass = Const Value(nil) + Jump bb2(v8, v9, v10, v11, v12) + bb2(v14:BasicObject, v15:BasicObject, v16:BasicObject, v17:NilClass, v18:NilClass): + v25:BasicObject = SendWithoutBlock v15, :+, v16 SideExit UnknownNewarraySend(HASH) "); } @@ -6292,16 +6446,18 @@ mod tests { fn test@:3: bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): EntryPoint interpreter - Jump bb2(v1, v2, v3) - bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT - Jump bb2(v6, v7, v8) - bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): - v13:NilClass = Const Value(nil) - v14:NilClass = Const Value(nil) - v21:BasicObject = SendWithoutBlock v11, :+, v12 - v24:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) - v26:StringExact = StringCopy v24 + v4:NilClass = Const Value(nil) + v5:NilClass = Const Value(nil) + Jump bb2(v1, v2, v3, v4, v5) + bb1(v8:BasicObject, v9:BasicObject, v10:BasicObject): + EntryPoint JIT(0) + v11:NilClass = Const Value(nil) + v12:NilClass = Const Value(nil) + Jump bb2(v8, v9, v10, v11, v12) + bb2(v14:BasicObject, v15:BasicObject, v16:BasicObject, v17:NilClass, v18:NilClass): + v25:BasicObject = SendWithoutBlock v15, :+, v16 + v28:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) + v30:StringExact = StringCopy v28 SideExit UnknownNewarraySend(PACK) "); } @@ -6323,14 +6479,16 @@ mod tests { fn test@:3: bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): EntryPoint interpreter - Jump bb2(v1, v2, v3) - bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT - Jump bb2(v6, v7, v8) - bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): - v13:NilClass = Const Value(nil) - v14:NilClass = Const Value(nil) - v21:BasicObject = SendWithoutBlock v11, :+, v12 + v4:NilClass = Const Value(nil) + v5:NilClass = Const Value(nil) + Jump bb2(v1, v2, v3, v4, v5) + bb1(v8:BasicObject, v9:BasicObject, v10:BasicObject): + EntryPoint JIT(0) + v11:NilClass = Const Value(nil) + v12:NilClass = Const Value(nil) + Jump bb2(v8, v9, v10, v11, v12) + bb2(v14:BasicObject, v15:BasicObject, v16:BasicObject, v17:NilClass, v18:NilClass): + v25:BasicObject = SendWithoutBlock v15, :+, v16 SideExit UnknownNewarraySend(INCLUDE_P) "); } @@ -6347,7 +6505,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): v17:ArrayExact = NewArray v11, v12 @@ -6369,7 +6527,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): v17:ArrayExact = NewArray v11, v12 @@ -6392,7 +6550,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint SingleRactorMode @@ -6415,7 +6573,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[1] = Const Value(1) @@ -6439,7 +6597,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[1] = Const Value(1) @@ -6462,7 +6620,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v11:BasicObject = GetGlobal :$foo @@ -6483,7 +6641,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v14:ArrayExact = ToNewArray v9 @@ -6504,7 +6662,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v13:Fixnum[1] = Const Value(1) @@ -6528,7 +6686,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v14:ArrayExact = ToNewArray v9 @@ -6551,7 +6709,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v14:ArrayExact = ToNewArray v9 @@ -6578,7 +6736,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): v16:NilClass = Const Value(nil) @@ -6601,7 +6759,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): v19:BasicObject = SendWithoutBlock v11, :[], v12 @@ -6622,7 +6780,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v16:BasicObject = SendWithoutBlock v9, :empty? @@ -6643,7 +6801,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v16:BasicObject = SendWithoutBlock v9, :succ @@ -6664,7 +6822,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): v19:BasicObject = SendWithoutBlock v11, :&, v12 @@ -6685,7 +6843,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): v19:BasicObject = SendWithoutBlock v11, :|, v12 @@ -6706,7 +6864,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v16:BasicObject = SendWithoutBlock v9, :! @@ -6727,7 +6885,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): v19:BasicObject = SendWithoutBlock v11, :=~, v12 @@ -6752,7 +6910,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Class[VMFrozenCore] = Const Value(VALUE(0x1000)) @@ -6779,55 +6937,61 @@ mod tests { end "); assert_contains_opcode("reverse_odd", YARVINSN_opt_reverse); - assert_snapshot!(hir_string("reverse_odd"), @r" + assert_contains_opcode("reverse_even", YARVINSN_opt_reverse); + assert_snapshot!(hir_strings!("reverse_odd", "reverse_even"), @r" fn reverse_odd@:3: bb0(v1:BasicObject): EntryPoint interpreter - Jump bb2(v1) - bb1(v4:BasicObject): - EntryPoint JIT - Jump bb2(v4) - bb2(v6:BasicObject): - v7:NilClass = Const Value(nil) + v2:NilClass = Const Value(nil) + v3:NilClass = Const Value(nil) + v4:NilClass = Const Value(nil) + Jump bb2(v1, v2, v3, v4) + bb1(v7:BasicObject): + EntryPoint JIT(0) v8:NilClass = Const Value(nil) v9:NilClass = Const Value(nil) + v10:NilClass = Const Value(nil) + Jump bb2(v7, v8, v9, v10) + bb2(v12:BasicObject, v13:NilClass, v14:NilClass, v15:NilClass): PatchPoint SingleRactorMode - v15:BasicObject = GetIvar v6, :@a + v21:BasicObject = GetIvar v12, :@a PatchPoint SingleRactorMode - v18:BasicObject = GetIvar v6, :@b + v24:BasicObject = GetIvar v12, :@b PatchPoint SingleRactorMode - v21:BasicObject = GetIvar v6, :@c + v27:BasicObject = GetIvar v12, :@c PatchPoint NoEPEscape(reverse_odd) - v27:ArrayExact = NewArray v15, v18, v21 + v33:ArrayExact = NewArray v21, v24, v27 CheckInterrupts - Return v27 - "); - assert_contains_opcode("reverse_even", YARVINSN_opt_reverse); - assert_snapshot!(hir_string("reverse_even"), @r" + Return v33 + fn reverse_even@:8: bb0(v1:BasicObject): EntryPoint interpreter - Jump bb2(v1) - bb1(v4:BasicObject): - EntryPoint JIT - Jump bb2(v4) - bb2(v6:BasicObject): - v7:NilClass = Const Value(nil) - v8:NilClass = Const Value(nil) + v2:NilClass = Const Value(nil) + v3:NilClass = Const Value(nil) + v4:NilClass = Const Value(nil) + v5:NilClass = Const Value(nil) + Jump bb2(v1, v2, v3, v4, v5) + bb1(v8:BasicObject): + EntryPoint JIT(0) v9:NilClass = Const Value(nil) v10:NilClass = Const Value(nil) + v11:NilClass = Const Value(nil) + v12:NilClass = Const Value(nil) + Jump bb2(v8, v9, v10, v11, v12) + bb2(v14:BasicObject, v15:NilClass, v16:NilClass, v17:NilClass, v18:NilClass): PatchPoint SingleRactorMode - v16:BasicObject = GetIvar v6, :@a + v24:BasicObject = GetIvar v14, :@a PatchPoint SingleRactorMode - v19:BasicObject = GetIvar v6, :@b + v27:BasicObject = GetIvar v14, :@b PatchPoint SingleRactorMode - v22:BasicObject = GetIvar v6, :@c + v30:BasicObject = GetIvar v14, :@c PatchPoint SingleRactorMode - v25:BasicObject = GetIvar v6, :@d + v33:BasicObject = GetIvar v14, :@d PatchPoint NoEPEscape(reverse_even) - v31:ArrayExact = NewArray v16, v19, v22, v25 + v39:ArrayExact = NewArray v24, v27, v30, v33 CheckInterrupts - Return v31 + Return v39 "); } @@ -6843,7 +7007,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): CheckInterrupts @@ -6866,7 +7030,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2, v3, v4) bb1(v7:BasicObject, v8:BasicObject, v9:BasicObject, v10:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v7, v8, v9, v10) bb2(v12:BasicObject, v13:BasicObject, v14:BasicObject, v15:BasicObject): v20:Float = InvokeBuiltin rb_f_float, v12, v13, v14 @@ -6886,7 +7050,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v11:Class = InvokeBuiltin _bi20, v6 @@ -6907,28 +7071,29 @@ mod tests { fn open@: bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject, v4:BasicObject, v5:BasicObject): EntryPoint interpreter - Jump bb2(v1, v2, v3, v4, v5) - bb1(v8:BasicObject, v9:BasicObject, v10:BasicObject, v11:BasicObject, v12:BasicObject): - EntryPoint JIT - Jump bb2(v8, v9, v10, v11, v12) - bb2(v14:BasicObject, v15:BasicObject, v16:BasicObject, v17:BasicObject, v18:BasicObject): - v19:NilClass = Const Value(nil) - v24:BasicObject = InvokeBuiltin dir_s_open, v14, v15, v16 + v6:NilClass = Const Value(nil) + Jump bb2(v1, v2, v3, v4, v5, v6) + bb1(v9:BasicObject, v10:BasicObject, v11:BasicObject, v12:BasicObject, v13:BasicObject): + EntryPoint JIT(0) + v14:NilClass = Const Value(nil) + Jump bb2(v9, v10, v11, v12, v13, v14) + bb2(v16:BasicObject, v17:BasicObject, v18:BasicObject, v19:BasicObject, v20:BasicObject, v21:NilClass): + v26:BasicObject = InvokeBuiltin dir_s_open, v16, v17, v18 PatchPoint NoEPEscape(open) GuardBlockParamProxy l0 - v31:HeapObject[BlockParamProxy] = Const Value(VALUE(0x1000)) + v33:HeapObject[BlockParamProxy] = Const Value(VALUE(0x1000)) CheckInterrupts - v34:CBool[true] = Test v31 - IfFalse v34, bb3(v14, v15, v16, v17, v18, v24) + v36:CBool[true] = Test v33 + IfFalse v36, bb3(v16, v17, v18, v19, v20, v26) PatchPoint NoEPEscape(open) - v41:BasicObject = InvokeBlock, v24 - v45:BasicObject = InvokeBuiltin dir_s_close, v14, v24 + v43:BasicObject = InvokeBlock, v26 + v47:BasicObject = InvokeBuiltin dir_s_close, v16, v26 CheckInterrupts - Return v41 - bb3(v51, v52, v53, v54, v55, v56): + Return v43 + bb3(v53, v54, v55, v56, v57, v58): PatchPoint NoEPEscape(open) CheckInterrupts - Return v56 + Return v58 "); } @@ -6943,7 +7108,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v11:BasicObject = InvokeBuiltin gc_enable, v6 @@ -6965,7 +7130,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2, v3, v4, v5) bb1(v8:BasicObject, v9:BasicObject, v10:BasicObject, v11:BasicObject, v12:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v8, v9, v10, v11, v12) bb2(v14:BasicObject, v15:BasicObject, v16:BasicObject, v17:BasicObject, v18:BasicObject): v22:FalseClass = Const Value(false) @@ -6987,7 +7152,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v13:NilClass = Const Value(nil) @@ -7019,7 +7184,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) @@ -7044,7 +7209,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[1] = Const Value(1) @@ -7074,7 +7239,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) @@ -7099,7 +7264,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[1] = Const Value(1) @@ -7129,7 +7294,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[1] = Const Value(1) @@ -7151,26 +7316,25 @@ mod tests { define_method(:throw_break) { break 2 } "); assert_contains_opcode("throw_return", YARVINSN_throw); - assert_snapshot!(hir_string("throw_return"), @r" + assert_contains_opcode("throw_break", YARVINSN_throw); + assert_snapshot!(hir_strings!("throw_return", "throw_break"), @r" fn block in @:2: bb0(v1:BasicObject): EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v12:Fixnum[1] = Const Value(1) Throw TAG_RETURN, v12 - "); - assert_contains_opcode("throw_break", YARVINSN_throw); - assert_snapshot!(hir_string("throw_break"), @r" + fn block in @:3: bb0(v1:BasicObject): EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v12:Fixnum[2] = Const Value(2) @@ -7191,7 +7355,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v11:BasicObject = InvokeBlock @@ -7213,7 +7377,7 @@ mod tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): v17:BasicObject = InvokeBlock, v11, v12 @@ -7257,7 +7421,7 @@ mod graphviz_tests { bb0:v4 -> bb2:params:n; bb1 [label=< - +
bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject) 
EntryPoint JIT 
EntryPoint JIT(0) 
Jump bb2(v6, v7, v8) 
>]; bb1:v9 -> bb2:params:n; @@ -7303,7 +7467,7 @@ mod graphviz_tests { bb0:v3 -> bb2:params:n; bb1 [label=< - +
bb1(v5:BasicObject, v6:BasicObject) 
EntryPoint JIT 
EntryPoint JIT(0) 
Jump bb2(v5, v6) 
>]; bb1:v7 -> bb2:params:n; @@ -7336,7 +7500,7 @@ mod graphviz_tests { #[cfg(test)] mod opt_tests { use super::*; - use crate::options::*; + use crate::{hir_strings, options::*}; use insta::assert_snapshot; #[track_caller] @@ -7365,17 +7529,18 @@ mod opt_tests { fn test@:3: bb0(v1:BasicObject): EntryPoint interpreter - Jump bb2(v1) - bb1(v4:BasicObject): - EntryPoint JIT - Jump bb2(v4) - bb2(v6:BasicObject): - v7:NilClass = Const Value(nil) - v11:TrueClass = Const Value(true) + v2:NilClass = Const Value(nil) + Jump bb2(v1, v2) + bb1(v5:BasicObject): + EntryPoint JIT(0) + v6:NilClass = Const Value(nil) + Jump bb2(v5, v6) + bb2(v8:BasicObject, v9:NilClass): + v13:TrueClass = Const Value(true) CheckInterrupts - v20:Fixnum[3] = Const Value(3) + v22:Fixnum[3] = Const Value(3) CheckInterrupts - Return v20 + Return v22 "); } @@ -7395,17 +7560,18 @@ mod opt_tests { fn test@:3: bb0(v1:BasicObject): EntryPoint interpreter - Jump bb2(v1) - bb1(v4:BasicObject): - EntryPoint JIT - Jump bb2(v4) - bb2(v6:BasicObject): - v7:NilClass = Const Value(nil) - v11:FalseClass = Const Value(false) + v2:NilClass = Const Value(nil) + Jump bb2(v1, v2) + bb1(v5:BasicObject): + EntryPoint JIT(0) + v6:NilClass = Const Value(nil) + Jump bb2(v5, v6) + bb2(v8:BasicObject, v9:NilClass): + v13:FalseClass = Const Value(false) CheckInterrupts - v31:Fixnum[4] = Const Value(4) + v33:Fixnum[4] = Const Value(4) CheckInterrupts - Return v31 + Return v33 "); } @@ -7422,7 +7588,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[1] = Const Value(1) @@ -7450,7 +7616,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[5] = Const Value(5) @@ -7478,7 +7644,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[0] = Const Value(0) @@ -7503,7 +7669,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[6] = Const Value(6) @@ -7529,7 +7695,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v13:Fixnum[0] = Const Value(0) @@ -7564,7 +7730,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[1] = Const Value(1) @@ -7595,7 +7761,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[1] = Const Value(1) @@ -7631,7 +7797,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[2] = Const Value(2) @@ -7662,7 +7828,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[2] = Const Value(2) @@ -7698,7 +7864,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[1] = Const Value(1) @@ -7729,7 +7895,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[2] = Const Value(2) @@ -7760,7 +7926,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[1] = Const Value(1) @@ -7792,7 +7958,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[2] = Const Value(2) @@ -7821,7 +7987,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v13:Fixnum[1] = Const Value(1) @@ -7842,64 +8008,58 @@ mod opt_tests { def post(*rest, post) = post def block(&b) = nil "); - - assert_snapshot!(hir_string("rest"), @r" + assert_snapshot!(hir_strings!("rest", "kw", "kw_rest", "block", "post"), @r" fn rest@:2: bb0(v1:BasicObject, v2:ArrayExact): EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:ArrayExact): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:ArrayExact): CheckInterrupts Return v9 - "); - // extra hidden param for the set of specified keywords - assert_snapshot!(hir_string("kw"), @r" + fn kw@:3: bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): CheckInterrupts Return v11 - "); - assert_snapshot!(hir_string("kw_rest"), @r" + fn kw_rest@:4: bb0(v1:BasicObject, v2:BasicObject): EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): CheckInterrupts Return v9 - "); - assert_snapshot!(hir_string("block"), @r" + fn block@:6: bb0(v1:BasicObject, v2:BasicObject): EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v13:NilClass = Const Value(nil) CheckInterrupts Return v13 - "); - assert_snapshot!(hir_string("post"), @r" + fn post@:5: bb0(v1:BasicObject, v2:ArrayExact, v3:BasicObject): EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:ArrayExact, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:ArrayExact, v12:BasicObject): CheckInterrupts @@ -7923,7 +8083,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010) @@ -7951,7 +8111,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v11:BasicObject = SendWithoutBlock v6, :foo @@ -7977,7 +8137,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010) @@ -8002,7 +8162,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[3] = Const Value(3) @@ -8030,7 +8190,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[1] = Const Value(1) @@ -8062,7 +8222,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010) @@ -8090,7 +8250,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) @@ -8120,7 +8280,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): v19:BasicObject = SendWithoutBlock v11, :+, v12 @@ -8141,7 +8301,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, BOP_PLUS) @@ -8165,7 +8325,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v13:Fixnum[1] = Const Value(1) @@ -8189,7 +8349,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v13:Fixnum[1] = Const Value(1) @@ -8213,7 +8373,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, BOP_LT) @@ -8237,7 +8397,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v13:Fixnum[1] = Const Value(1) @@ -8261,7 +8421,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v13:Fixnum[1] = Const Value(1) @@ -8286,17 +8446,18 @@ mod opt_tests { fn test@:3: bb0(v1:BasicObject): EntryPoint interpreter - Jump bb2(v1) - bb1(v4:BasicObject): - EntryPoint JIT - Jump bb2(v4) - bb2(v6:BasicObject): - v7:NilClass = Const Value(nil) - v11:Fixnum[2] = Const Value(2) - v14:Fixnum[1] = Const Value(1) - v22:RangeExact = NewRangeFixnum v14 NewRangeInclusive v11 + v2:NilClass = Const Value(nil) + Jump bb2(v1, v2) + bb1(v5:BasicObject): + EntryPoint JIT(0) + v6:NilClass = Const Value(nil) + Jump bb2(v5, v6) + bb2(v8:BasicObject, v9:NilClass): + v13:Fixnum[2] = Const Value(2) + v16:Fixnum[1] = Const Value(1) + v24:RangeExact = NewRangeFixnum v16 NewRangeInclusive v13 CheckInterrupts - Return v22 + Return v24 "); } @@ -8314,17 +8475,18 @@ mod opt_tests { fn test@:3: bb0(v1:BasicObject): EntryPoint interpreter - Jump bb2(v1) - bb1(v4:BasicObject): - EntryPoint JIT - Jump bb2(v4) - bb2(v6:BasicObject): - v7:NilClass = Const Value(nil) - v11:Fixnum[2] = Const Value(2) - v14:Fixnum[1] = Const Value(1) - v22:RangeExact = NewRangeFixnum v14 NewRangeExclusive v11 + v2:NilClass = Const Value(nil) + Jump bb2(v1, v2) + bb1(v5:BasicObject): + EntryPoint JIT(0) + v6:NilClass = Const Value(nil) + Jump bb2(v5, v6) + bb2(v8:BasicObject, v9:NilClass): + v13:Fixnum[2] = Const Value(2) + v16:Fixnum[1] = Const Value(1) + v24:RangeExact = NewRangeFixnum v16 NewRangeExclusive v13 CheckInterrupts - Return v22 + Return v24 "); } @@ -8342,7 +8504,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v13:Fixnum[1] = Const Value(1) @@ -8367,7 +8529,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v13:Fixnum[1] = Const Value(1) @@ -8392,7 +8554,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v13:Fixnum[10] = Const Value(10) @@ -8417,7 +8579,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v13:Fixnum[10] = Const Value(10) @@ -8441,16 +8603,17 @@ mod opt_tests { fn test@:3: bb0(v1:BasicObject): EntryPoint interpreter - Jump bb2(v1) - bb1(v4:BasicObject): - EntryPoint JIT - Jump bb2(v4) - bb2(v6:BasicObject): - v7:NilClass = Const Value(nil) - v12:ArrayExact = NewArray - v15:Fixnum[5] = Const Value(5) + v2:NilClass = Const Value(nil) + Jump bb2(v1, v2) + bb1(v5:BasicObject): + EntryPoint JIT(0) + v6:NilClass = Const Value(nil) + Jump bb2(v5, v6) + bb2(v8:BasicObject, v9:NilClass): + v14:ArrayExact = NewArray + v17:Fixnum[5] = Const Value(5) CheckInterrupts - Return v15 + Return v17 "); } @@ -8467,16 +8630,17 @@ mod opt_tests { fn test@:3: bb0(v1:BasicObject): EntryPoint interpreter - Jump bb2(v1) - bb1(v4:BasicObject): - EntryPoint JIT - Jump bb2(v4) - bb2(v6:BasicObject): - v7:NilClass = Const Value(nil) - v11:RangeExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) - v14:Fixnum[5] = Const Value(5) + v2:NilClass = Const Value(nil) + Jump bb2(v1, v2) + bb1(v5:BasicObject): + EntryPoint JIT(0) + v6:NilClass = Const Value(nil) + Jump bb2(v5, v6) + bb2(v8:BasicObject, v9:NilClass): + v13:RangeExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) + v16:Fixnum[5] = Const Value(5) CheckInterrupts - Return v14 + Return v16 "); } @@ -8493,21 +8657,22 @@ mod opt_tests { fn test@:3: bb0(v1:BasicObject): EntryPoint interpreter - Jump bb2(v1) - bb1(v4:BasicObject): - EntryPoint JIT - Jump bb2(v4) - bb2(v6:BasicObject): - v7:NilClass = Const Value(nil) + v2:NilClass = Const Value(nil) + Jump bb2(v1, v2) + bb1(v5:BasicObject): + EntryPoint JIT(0) + v6:NilClass = Const Value(nil) + Jump bb2(v5, v6) + bb2(v8:BasicObject, v9:NilClass): PatchPoint BOPRedefined(STRING_REDEFINED_OP_FLAG, BOP_UMINUS) - v13:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) - v14:StringExact[VALUE(0x1008)] = Const Value(VALUE(0x1008)) - v16:StringExact = StringCopy v14 - v18:RangeExact = NewRange v13 NewRangeInclusive v16 + v15:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) + v16:StringExact[VALUE(0x1008)] = Const Value(VALUE(0x1008)) + v18:StringExact = StringCopy v16 + v20:RangeExact = NewRange v15 NewRangeInclusive v18 PatchPoint NoEPEscape(test) - v23:Fixnum[0] = Const Value(0) + v25:Fixnum[0] = Const Value(0) CheckInterrupts - Return v23 + Return v25 "); } @@ -8524,16 +8689,17 @@ mod opt_tests { fn test@:3: bb0(v1:BasicObject, v2:BasicObject): EntryPoint interpreter - Jump bb2(v1, v2) - bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT - Jump bb2(v5, v6) - bb2(v8:BasicObject, v9:BasicObject): - v10:NilClass = Const Value(nil) - v15:ArrayExact = NewArray v9 - v18:Fixnum[5] = Const Value(5) + v3:NilClass = Const Value(nil) + Jump bb2(v1, v2, v3) + bb1(v6:BasicObject, v7:BasicObject): + EntryPoint JIT(0) + v8:NilClass = Const Value(nil) + Jump bb2(v6, v7, v8) + bb2(v10:BasicObject, v11:BasicObject, v12:NilClass): + v17:ArrayExact = NewArray v11 + v20:Fixnum[5] = Const Value(5) CheckInterrupts - Return v18 + Return v20 "); } @@ -8549,17 +8715,18 @@ mod opt_tests { fn test@:3: bb0(v1:BasicObject): EntryPoint interpreter - Jump bb2(v1) - bb1(v4:BasicObject): - EntryPoint JIT - Jump bb2(v4) - bb2(v6:BasicObject): - v7:NilClass = Const Value(nil) - v12:HashExact = NewHash + v2:NilClass = Const Value(nil) + Jump bb2(v1, v2) + bb1(v5:BasicObject): + EntryPoint JIT(0) + v6:NilClass = Const Value(nil) + Jump bb2(v5, v6) + bb2(v8:BasicObject, v9:NilClass): + v14:HashExact = NewHash PatchPoint NoEPEscape(test) - v17:Fixnum[5] = Const Value(5) + v19:Fixnum[5] = Const Value(5) CheckInterrupts - Return v17 + Return v19 "); } @@ -8575,19 +8742,20 @@ mod opt_tests { fn test@:3: bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): EntryPoint interpreter - Jump bb2(v1, v2, v3) - bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT - Jump bb2(v6, v7, v8) - bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): - v13:NilClass = Const Value(nil) - v17:StaticSymbol[:a] = Const Value(VALUE(0x1000)) - v18:StaticSymbol[:b] = Const Value(VALUE(0x1008)) - v20:HashExact = NewHash v17: v11, v18: v12 + v4:NilClass = Const Value(nil) + Jump bb2(v1, v2, v3, v4) + bb1(v7:BasicObject, v8:BasicObject, v9:BasicObject): + EntryPoint JIT(0) + v10:NilClass = Const Value(nil) + Jump bb2(v7, v8, v9, v10) + bb2(v12:BasicObject, v13:BasicObject, v14:BasicObject, v15:NilClass): + v19:StaticSymbol[:a] = Const Value(VALUE(0x1000)) + v20:StaticSymbol[:b] = Const Value(VALUE(0x1008)) + v22:HashExact = NewHash v19: v13, v20: v14 PatchPoint NoEPEscape(test) - v25:Fixnum[5] = Const Value(5) + v27:Fixnum[5] = Const Value(5) CheckInterrupts - Return v25 + Return v27 "); } @@ -8604,17 +8772,18 @@ mod opt_tests { fn test@:3: bb0(v1:BasicObject): EntryPoint interpreter - Jump bb2(v1) - bb1(v4:BasicObject): - EntryPoint JIT - Jump bb2(v4) - bb2(v6:BasicObject): - v7:NilClass = Const Value(nil) - v11:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) - v13:ArrayExact = ArrayDup v11 - v16:Fixnum[5] = Const Value(5) + v2:NilClass = Const Value(nil) + Jump bb2(v1, v2) + bb1(v5:BasicObject): + EntryPoint JIT(0) + v6:NilClass = Const Value(nil) + Jump bb2(v5, v6) + bb2(v8:BasicObject, v9:NilClass): + v13:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) + v15:ArrayExact = ArrayDup v13 + v18:Fixnum[5] = Const Value(5) CheckInterrupts - Return v16 + Return v18 "); } @@ -8630,17 +8799,18 @@ mod opt_tests { fn test@:3: bb0(v1:BasicObject): EntryPoint interpreter - Jump bb2(v1) - bb1(v4:BasicObject): - EntryPoint JIT - Jump bb2(v4) - bb2(v6:BasicObject): - v7:NilClass = Const Value(nil) - v11:HashExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) - v13:HashExact = HashDup v11 - v16:Fixnum[5] = Const Value(5) + v2:NilClass = Const Value(nil) + Jump bb2(v1, v2) + bb1(v5:BasicObject): + EntryPoint JIT(0) + v6:NilClass = Const Value(nil) + Jump bb2(v5, v6) + bb2(v8:BasicObject, v9:NilClass): + v13:HashExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) + v15:HashExact = HashDup v13 + v18:Fixnum[5] = Const Value(5) CheckInterrupts - Return v16 + Return v18 "); } @@ -8657,15 +8827,16 @@ mod opt_tests { fn test@:3: bb0(v1:BasicObject): EntryPoint interpreter - Jump bb2(v1) - bb1(v4:BasicObject): - EntryPoint JIT - Jump bb2(v4) - bb2(v6:BasicObject): - v7:NilClass = Const Value(nil) - v13:Fixnum[5] = Const Value(5) + v2:NilClass = Const Value(nil) + Jump bb2(v1, v2) + bb1(v5:BasicObject): + EntryPoint JIT(0) + v6:NilClass = Const Value(nil) + Jump bb2(v5, v6) + bb2(v8:BasicObject, v9:NilClass): + v15:Fixnum[5] = Const Value(5) CheckInterrupts - Return v13 + Return v15 "); } @@ -8682,17 +8853,18 @@ mod opt_tests { fn test@:3: bb0(v1:BasicObject): EntryPoint interpreter - Jump bb2(v1) - bb1(v4:BasicObject): - EntryPoint JIT - Jump bb2(v4) - bb2(v6:BasicObject): - v7:NilClass = Const Value(nil) - v11:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) - v13:StringExact = StringCopy v11 - v16:Fixnum[5] = Const Value(5) + v2:NilClass = Const Value(nil) + Jump bb2(v1, v2) + bb1(v5:BasicObject): + EntryPoint JIT(0) + v6:NilClass = Const Value(nil) + Jump bb2(v5, v6) + bb2(v8:BasicObject, v9:NilClass): + v13:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) + v15:StringExact = StringCopy v13 + v18:Fixnum[5] = Const Value(5) CheckInterrupts - Return v16 + Return v18 "); } @@ -8711,7 +8883,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, BOP_PLUS) @@ -8738,7 +8910,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, BOP_MINUS) @@ -8765,7 +8937,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, BOP_MULT) @@ -8792,7 +8964,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, BOP_DIV) @@ -8820,7 +8992,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, BOP_MOD) @@ -8848,7 +9020,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, BOP_LT) @@ -8875,7 +9047,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, BOP_LE) @@ -8902,7 +9074,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, BOP_GT) @@ -8929,7 +9101,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, BOP_GE) @@ -8956,7 +9128,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, BOP_EQ) @@ -8983,7 +9155,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, BOP_EQ) @@ -9010,7 +9182,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v11:BasicObject = GetConstantPath 0x1000 @@ -9033,7 +9205,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): PatchPoint MethodRedefined(Integer@0x1000, itself@0x1008, cme:0x1010) @@ -9055,7 +9227,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v11:ArrayExact = NewArray @@ -9078,19 +9250,20 @@ mod opt_tests { fn test@:3: bb0(v1:BasicObject): EntryPoint interpreter - Jump bb2(v1) - bb1(v4:BasicObject): - EntryPoint JIT - Jump bb2(v4) - bb2(v6:BasicObject): - v7:NilClass = Const Value(nil) - v12:ArrayExact = NewArray + v2:NilClass = Const Value(nil) + Jump bb2(v1, v2) + bb1(v5:BasicObject): + EntryPoint JIT(0) + v6:NilClass = Const Value(nil) + Jump bb2(v5, v6) + bb2(v8:BasicObject, v9:NilClass): + v14:ArrayExact = NewArray PatchPoint MethodRedefined(Array@0x1000, itself@0x1008, cme:0x1010) - v26:BasicObject = CCall itself@0x1038, v12 + v28:BasicObject = CCall itself@0x1038, v14 PatchPoint NoEPEscape(test) - v19:Fixnum[1] = Const Value(1) + v21:Fixnum[1] = Const Value(1) CheckInterrupts - Return v19 + Return v21 "); } @@ -9108,21 +9281,22 @@ mod opt_tests { fn test@:4: bb0(v1:BasicObject): EntryPoint interpreter - Jump bb2(v1) - bb1(v4:BasicObject): - EntryPoint JIT - Jump bb2(v4) - bb2(v6:BasicObject): - v7:NilClass = Const Value(nil) + v2:NilClass = Const Value(nil) + Jump bb2(v1, v2) + bb1(v5:BasicObject): + EntryPoint JIT(0) + v6:NilClass = Const Value(nil) + Jump bb2(v5, v6) + bb2(v8:BasicObject, v9:NilClass): PatchPoint SingleRactorMode PatchPoint StableConstantNames(0x1000, M) - v27:ModuleExact[VALUE(0x1008)] = Const Value(VALUE(0x1008)) + v29:ModuleExact[VALUE(0x1008)] = Const Value(VALUE(0x1008)) PatchPoint MethodRedefined(Module@0x1010, name@0x1018, cme:0x1020) - v29:StringExact|NilClass = CCall name@0x1048, v27 + v31:StringExact|NilClass = CCall name@0x1048, v29 PatchPoint NoEPEscape(test) - v19:Fixnum[1] = Const Value(1) + v21:Fixnum[1] = Const Value(1) CheckInterrupts - Return v19 + Return v21 "); } @@ -9138,18 +9312,19 @@ mod opt_tests { fn test@:3: bb0(v1:BasicObject): EntryPoint interpreter - Jump bb2(v1) - bb1(v4:BasicObject): - EntryPoint JIT - Jump bb2(v4) - bb2(v6:BasicObject): - v7:NilClass = Const Value(nil) - v12:ArrayExact = NewArray + v2:NilClass = Const Value(nil) + Jump bb2(v1, v2) + bb1(v5:BasicObject): + EntryPoint JIT(0) + v6:NilClass = Const Value(nil) + Jump bb2(v5, v6) + bb2(v8:BasicObject, v9:NilClass): + v14:ArrayExact = NewArray PatchPoint MethodRedefined(Array@0x1000, length@0x1008, cme:0x1010) - v26:Fixnum = CCall length@0x1038, v12 - v19:Fixnum[5] = Const Value(5) + v28:Fixnum = CCall length@0x1038, v14 + v21:Fixnum[5] = Const Value(5) CheckInterrupts - Return v19 + Return v21 "); } @@ -9166,7 +9341,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint SingleRactorMode @@ -9189,7 +9364,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint SingleRactorMode @@ -9222,7 +9397,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint SingleRactorMode @@ -9251,7 +9426,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint SingleRactorMode @@ -9274,18 +9449,19 @@ mod opt_tests { fn test@:3: bb0(v1:BasicObject): EntryPoint interpreter - Jump bb2(v1) - bb1(v4:BasicObject): - EntryPoint JIT - Jump bb2(v4) - bb2(v6:BasicObject): - v7:NilClass = Const Value(nil) - v12:ArrayExact = NewArray + v2:NilClass = Const Value(nil) + Jump bb2(v1, v2) + bb1(v5:BasicObject): + EntryPoint JIT(0) + v6:NilClass = Const Value(nil) + Jump bb2(v5, v6) + bb2(v8:BasicObject, v9:NilClass): + v14:ArrayExact = NewArray PatchPoint MethodRedefined(Array@0x1000, size@0x1008, cme:0x1010) - v26:Fixnum = CCall size@0x1038, v12 - v19:Fixnum[5] = Const Value(5) + v28:Fixnum = CCall size@0x1038, v14 + v21:Fixnum[5] = Const Value(5) CheckInterrupts - Return v19 + Return v21 "); } @@ -9303,7 +9479,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[1] = Const Value(1) @@ -9325,7 +9501,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v13:Fixnum[1] = Const Value(1) @@ -9348,18 +9524,19 @@ mod opt_tests { fn test@:3: bb0(v1:BasicObject, v2:BasicObject): EntryPoint interpreter - Jump bb2(v1, v2) - bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT - Jump bb2(v5, v6) - bb2(v8:BasicObject, v9:BasicObject): - v10:NilClass = Const Value(nil) - v14:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) - v16:ArrayExact = ArrayDup v14 + v3:NilClass = Const Value(nil) + Jump bb2(v1, v2, v3) + bb1(v6:BasicObject, v7:BasicObject): + EntryPoint JIT(0) + v8:NilClass = Const Value(nil) + Jump bb2(v6, v7, v8) + bb2(v10:BasicObject, v11:BasicObject, v12:NilClass): + v16:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) + v18:ArrayExact = ArrayDup v16 PatchPoint MethodRedefined(Array@0x1008, first@0x1010, cme:0x1018) - v27:BasicObject = SendWithoutBlockDirect v16, :first (0x1040) + v29:BasicObject = SendWithoutBlockDirect v18, :first (0x1040) CheckInterrupts - Return v27 + Return v29 "); } @@ -9377,7 +9554,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint SingleRactorMode @@ -9411,7 +9588,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): PatchPoint MethodRedefined(C@0x1000, foo@0x1008, cme:0x1010) @@ -9436,7 +9613,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[1] = Const Value(1) @@ -9460,7 +9637,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v11:BasicObject = Send v6, 0x1000, :foo @@ -9485,19 +9662,20 @@ mod opt_tests { fn test@:4: bb0(v1:BasicObject): EntryPoint interpreter - Jump bb2(v1) - bb1(v4:BasicObject): - EntryPoint JIT - Jump bb2(v4) - bb2(v6:BasicObject): - v7:NilClass = Const Value(nil) - v11:Fixnum[1] = Const Value(1) - SetLocal l0, EP@3, v11 - v16:BasicObject = Send v6, 0x1000, :foo - v17:BasicObject = GetLocal l0, EP@3 - v20:BasicObject = GetLocal l0, EP@3 + v2:NilClass = Const Value(nil) + Jump bb2(v1, v2) + bb1(v5:BasicObject): + EntryPoint JIT(0) + v6:NilClass = Const Value(nil) + Jump bb2(v5, v6) + bb2(v8:BasicObject, v9:NilClass): + v13:Fixnum[1] = Const Value(1) + SetLocal l0, EP@3, v13 + v18:BasicObject = Send v8, 0x1000, :foo + v19:BasicObject = GetLocal l0, EP@3 + v22:BasicObject = GetLocal l0, EP@3 CheckInterrupts - Return v20 + Return v22 "); } @@ -9515,7 +9693,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[1] = Const Value(1) @@ -9539,7 +9717,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[1] = Const Value(1) @@ -9561,7 +9739,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[1] = Const Value(1) @@ -9582,7 +9760,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) @@ -9605,7 +9783,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v11:BasicObject = GetConstantPath 0x1000 @@ -9627,7 +9805,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v11:BasicObject = GetConstantPath 0x1000 @@ -9648,7 +9826,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint SingleRactorMode @@ -9677,7 +9855,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint SingleRactorMode @@ -9701,7 +9879,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint SingleRactorMode @@ -9735,7 +9913,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint SingleRactorMode @@ -9765,7 +9943,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint SingleRactorMode @@ -9794,7 +9972,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint SingleRactorMode @@ -9823,7 +10001,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint SingleRactorMode @@ -9852,7 +10030,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint SingleRactorMode @@ -9880,7 +10058,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint SingleRactorMode @@ -9910,7 +10088,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint SingleRactorMode @@ -9937,7 +10115,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint SingleRactorMode @@ -9967,7 +10145,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): v17:ArrayExact = NewArray v11, v12 @@ -9989,7 +10167,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): v17:ArrayExact = NewArray v11, v12 @@ -10011,7 +10189,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): GuardBlockParamProxy l0 @@ -10033,7 +10211,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint SingleRactorMode @@ -10054,7 +10232,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[1] = Const Value(1) @@ -10076,7 +10254,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint BOPRedefined(HASH_REDEFINED_OP_FLAG, BOP_FREEZE) @@ -10100,7 +10278,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): SideExit PatchPoint(BOPRedefined(HASH_REDEFINED_OP_FLAG, BOP_FREEZE)) @@ -10118,7 +10296,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint BOPRedefined(HASH_REDEFINED_OP_FLAG, BOP_FREEZE) @@ -10140,7 +10318,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v11:HashExact = NewHash @@ -10162,7 +10340,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v11:HashExact = NewHash @@ -10184,7 +10362,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_FREEZE) @@ -10205,7 +10383,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_FREEZE) @@ -10227,7 +10405,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v11:ArrayExact = NewArray @@ -10249,7 +10427,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v11:ArrayExact = NewArray @@ -10271,7 +10449,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint BOPRedefined(STRING_REDEFINED_OP_FLAG, BOP_FREEZE) @@ -10292,7 +10470,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint BOPRedefined(STRING_REDEFINED_OP_FLAG, BOP_FREEZE) @@ -10314,7 +10492,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) @@ -10337,7 +10515,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) @@ -10360,7 +10538,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint BOPRedefined(STRING_REDEFINED_OP_FLAG, BOP_UMINUS) @@ -10381,7 +10559,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint BOPRedefined(STRING_REDEFINED_OP_FLAG, BOP_FREEZE) @@ -10403,7 +10581,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) @@ -10426,7 +10604,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) @@ -10449,7 +10627,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) @@ -10477,7 +10655,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v13:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) @@ -10506,7 +10684,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v13:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) @@ -10532,7 +10710,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v13:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) @@ -10558,16 +10736,17 @@ mod opt_tests { fn test@:3: bb0(v1:BasicObject): EntryPoint interpreter - Jump bb2(v1) - bb1(v4:BasicObject): - EntryPoint JIT - Jump bb2(v4) - bb2(v6:BasicObject): - v7:NilClass = Const Value(nil) - v11:NilClass = Const Value(nil) + v2:NilClass = Const Value(nil) + Jump bb2(v1, v2) + bb1(v5:BasicObject): + EntryPoint JIT(0) + v6:NilClass = Const Value(nil) + Jump bb2(v5, v6) + bb2(v8:BasicObject, v9:NilClass): + v13:NilClass = Const Value(nil) CheckInterrupts CheckInterrupts - Return v11 + Return v13 "); } @@ -10584,18 +10763,19 @@ mod opt_tests { fn test@:3: bb0(v1:BasicObject): EntryPoint interpreter - Jump bb2(v1) - bb1(v4:BasicObject): - EntryPoint JIT - Jump bb2(v4) - bb2(v6:BasicObject): - v7:NilClass = Const Value(nil) - v11:Fixnum[1] = Const Value(1) + v2:NilClass = Const Value(nil) + Jump bb2(v1, v2) + bb1(v5:BasicObject): + EntryPoint JIT(0) + v6:NilClass = Const Value(nil) + Jump bb2(v5, v6) + bb2(v8:BasicObject, v9:NilClass): + v13:Fixnum[1] = Const Value(1) CheckInterrupts PatchPoint MethodRedefined(Integer@0x1000, itself@0x1008, cme:0x1010) - v31:BasicObject = CCall itself@0x1038, v11 + v33:BasicObject = CCall itself@0x1038, v13 CheckInterrupts - Return v31 + Return v33 "); } @@ -10610,7 +10790,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_FREEZE) @@ -10634,7 +10814,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_FREEZE) @@ -10658,7 +10838,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_FREEZE) @@ -10682,7 +10862,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_FREEZE) @@ -10709,7 +10889,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_FREEZE) @@ -10735,7 +10915,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) @@ -10763,7 +10943,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint SingleRactorMode @@ -10785,7 +10965,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:RegexpExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) @@ -10805,7 +10985,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:NilClass = Const Value(nil) @@ -10830,7 +11010,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:NilClass = Const Value(nil) @@ -10852,7 +11032,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[1] = Const Value(1) @@ -10877,7 +11057,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): v10:Fixnum[1] = Const Value(1) @@ -10901,7 +11081,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): PatchPoint MethodRedefined(NilClass@0x1000, nil?@0x1008, cme:0x1010) @@ -10925,7 +11105,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): PatchPoint MethodRedefined(FalseClass@0x1000, nil?@0x1008, cme:0x1010) @@ -10949,7 +11129,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): PatchPoint MethodRedefined(TrueClass@0x1000, nil?@0x1008, cme:0x1010) @@ -10973,7 +11153,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): PatchPoint MethodRedefined(Symbol@0x1000, nil?@0x1008, cme:0x1010) @@ -10997,7 +11177,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): PatchPoint MethodRedefined(Integer@0x1000, nil?@0x1008, cme:0x1010) @@ -11021,7 +11201,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): PatchPoint MethodRedefined(Float@0x1000, nil?@0x1008, cme:0x1010) @@ -11045,7 +11225,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): PatchPoint MethodRedefined(String@0x1000, nil?@0x1008, cme:0x1010) @@ -11069,7 +11249,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): PatchPoint MethodRedefined(Array@0x1000, !@0x1008, cme:0x1010) @@ -11093,7 +11273,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): PatchPoint MethodRedefined(Array@0x1000, empty?@0x1008, cme:0x1010) @@ -11117,7 +11297,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): PatchPoint MethodRedefined(Hash@0x1000, empty?@0x1008, cme:0x1010) @@ -11142,7 +11322,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): PatchPoint MethodRedefined(C@0x1000, ==@0x1008, cme:0x1010) @@ -11166,7 +11346,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, 28) @@ -11191,7 +11371,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v6, v7, v8) bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject): PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, 29) @@ -11218,7 +11398,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010) @@ -11250,7 +11430,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): PatchPoint MethodRedefined(C@0x1000, foo@0x1008, cme:0x1010) @@ -11283,7 +11463,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): PatchPoint MethodRedefined(C@0x1000, foo@0x1008, cme:0x1010) @@ -11327,7 +11507,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): v14:BasicObject = SendWithoutBlock v9, :foo @@ -11354,7 +11534,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint SingleRactorMode @@ -11386,7 +11566,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1) bb1(v4:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v4) bb2(v6:BasicObject): PatchPoint SingleRactorMode @@ -11417,7 +11597,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): PatchPoint MethodRedefined(C@0x1000, foo@0x1008, cme:0x1010) @@ -11446,7 +11626,7 @@ mod opt_tests { EntryPoint interpreter Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): - EntryPoint JIT + EntryPoint JIT(0) Jump bb2(v5, v6) bb2(v8:BasicObject, v9:BasicObject): PatchPoint MethodRedefined(C@0x1000, foo@0x1008, cme:0x1010) diff --git a/zjit/src/invariants.rs b/zjit/src/invariants.rs index 80948c696eb704..75f900c38dffd8 100644 --- a/zjit/src/invariants.rs +++ b/zjit/src/invariants.rs @@ -2,7 +2,7 @@ use std::{collections::{HashMap, HashSet}, mem}; -use crate::{backend::lir::{asm_comment, Assembler}, cruby::{iseq_name, rb_callable_method_entry_t, rb_gc_location, ruby_basic_operators, src_loc, with_vm_lock, IseqPtr, RedefinitionFlag, ID, VALUE}, gc::IseqPayload, hir::Invariant, options::debug, state::{zjit_enabled_p, ZJITState}, virtualmem::CodePtr}; +use crate::{backend::lir::{asm_comment, Assembler}, cruby::{iseq_name, rb_callable_method_entry_t, rb_gc_location, ruby_basic_operators, src_loc, with_vm_lock, IseqPtr, RedefinitionFlag, ID}, gc::IseqPayload, hir::Invariant, options::debug, state::{zjit_enabled_p, ZJITState}, virtualmem::CodePtr}; use crate::stats::with_time_stat; use crate::stats::Counter::invalidation_time_ns; use crate::gc::remove_gc_offsets; @@ -66,42 +66,55 @@ impl Invariants { pub fn update_references(&mut self) { self.update_ep_escape_iseqs(); self.update_no_ep_escape_iseq_patch_points(); + self.update_cme_patch_points(); } - /// Update ISEQ references in Invariants::ep_escape_iseqs - fn update_ep_escape_iseqs(&mut self) { - let mut moved: Vec = Vec::with_capacity(self.ep_escape_iseqs.len()); + /// Forget an ISEQ when freeing it. We need to because a) if the address is reused, we'd be + /// tracking the wrong object b) dead VALUEs in the table can means we risk passing invalid + /// VALUEs to `rb_gc_location()`. + pub fn forget_iseq(&mut self, iseq: IseqPtr) { + // Why not patch the patch points? If the ISEQ is dead then the GC also proved that all + // generated code referencing the ISEQ are unreachable. We mark the ISEQs baked into + // generated code. + self.ep_escape_iseqs.remove(&iseq); + self.no_ep_escape_iseq_patch_points.remove(&iseq); + } - self.ep_escape_iseqs.retain(|&old_iseq| { - let new_iseq = unsafe { rb_gc_location(VALUE(old_iseq as usize)) }.0 as IseqPtr; - if old_iseq != new_iseq { - moved.push(new_iseq); - } - old_iseq == new_iseq - }); + /// Forget a CME when freeing it. See [Self::forget_iseq] for reasoning. + pub fn forget_cme(&mut self, cme: *const rb_callable_method_entry_t) { + self.cme_patch_points.remove(&cme); + } - for new_iseq in moved { - self.ep_escape_iseqs.insert(new_iseq); - } + /// Update ISEQ references in Invariants::ep_escape_iseqs + fn update_ep_escape_iseqs(&mut self) { + let updated = std::mem::take(&mut self.ep_escape_iseqs) + .into_iter() + .map(|iseq| unsafe { rb_gc_location(iseq.into()) }.as_iseq()) + .collect(); + self.ep_escape_iseqs = updated; } /// Update ISEQ references in Invariants::no_ep_escape_iseq_patch_points fn update_no_ep_escape_iseq_patch_points(&mut self) { - let mut moved: Vec<(IseqPtr, HashSet)> = Vec::with_capacity(self.no_ep_escape_iseq_patch_points.len()); - let iseqs: Vec = self.no_ep_escape_iseq_patch_points.keys().cloned().collect(); - - for old_iseq in iseqs { - let new_iseq = unsafe { rb_gc_location(VALUE(old_iseq as usize)) }.0 as IseqPtr; - if old_iseq != new_iseq { - let patch_points = self.no_ep_escape_iseq_patch_points.remove(&old_iseq).unwrap(); - // Do not insert patch points to no_ep_escape_iseq_patch_points yet to avoid corrupting keys that had a different ISEQ - moved.push((new_iseq, patch_points)); - } - } + let updated = std::mem::take(&mut self.no_ep_escape_iseq_patch_points) + .into_iter() + .map(|(iseq, patch_points)| { + let new_iseq = unsafe { rb_gc_location(iseq.into()) }; + (new_iseq.as_iseq(), patch_points) + }) + .collect(); + self.no_ep_escape_iseq_patch_points = updated; + } - for (new_iseq, patch_points) in moved { - self.no_ep_escape_iseq_patch_points.insert(new_iseq, patch_points); - } + fn update_cme_patch_points(&mut self) { + let updated_cme_patch_points = std::mem::take(&mut self.cme_patch_points) + .into_iter() + .map(|(cme, patch_points)| { + let new_cme = unsafe { rb_gc_location(cme.into()) }; + (new_cme.as_cme(), patch_points) + }) + .collect(); + self.cme_patch_points = updated_cme_patch_points; } } diff --git a/zjit/src/stats.rs b/zjit/src/stats.rs index 3d9ce07c36cf20..6d4525084ef849 100644 --- a/zjit/src/stats.rs +++ b/zjit/src/stats.rs @@ -110,7 +110,6 @@ make_counters! { exit_obj_to_string_fallback, exit_interrupt, exit_stackoverflow, - exit_optional_arguments, exit_block_param_proxy_modified, exit_block_param_proxy_not_iseq_or_ifunc, } @@ -123,8 +122,14 @@ make_counters! { compile_error_register_spill_on_alloc, compile_error_parse_stack_underflow, compile_error_parse_malformed_iseq, - compile_error_parse_validation, + compile_error_parse_failed_optional_arguments, compile_error_parse_not_allowed, + compile_error_validation_block_has_no_terminator, + compile_error_validation_terminator_not_at_end, + compile_error_validation_mismatched_block_arity, + compile_error_validation_jump_target_not_in_rpo, + compile_error_validation_operand_not_defined, + compile_error_validation_duplicate_instruction, // The number of times YARV instructions are executed on JIT code zjit_insn_count, @@ -203,6 +208,7 @@ pub enum CompileError { /// Return a raw pointer to the exit counter for a given CompileError pub fn exit_counter_for_compile_error(compile_error: &CompileError) -> Counter { use crate::hir::ParseError::*; + use crate::hir::ValidationError::*; use crate::stats::CompileError::*; use crate::stats::Counter::*; match compile_error { @@ -212,10 +218,18 @@ pub fn exit_counter_for_compile_error(compile_error: &CompileError) -> Counter { RegisterSpillOnAlloc => compile_error_register_spill_on_alloc, RegisterSpillOnCCall => compile_error_register_spill_on_ccall, ParseError(parse_error) => match parse_error { - StackUnderflow(_) => compile_error_parse_stack_underflow, - MalformedIseq(_) => compile_error_parse_malformed_iseq, - Validation(_) => compile_error_parse_validation, - NotAllowed => compile_error_parse_not_allowed, + StackUnderflow(_) => compile_error_parse_stack_underflow, + MalformedIseq(_) => compile_error_parse_malformed_iseq, + FailedOptionalArguments => compile_error_parse_failed_optional_arguments, + NotAllowed => compile_error_parse_not_allowed, + Validation(validation) => match validation { + BlockHasNoTerminator(_) => compile_error_validation_block_has_no_terminator, + TerminatorNotAtEnd(_, _, _) => compile_error_validation_terminator_not_at_end, + MismatchedBlockArity(_, _, _) => compile_error_validation_mismatched_block_arity, + JumpTargetNotInRPO(_) => compile_error_validation_jump_target_not_in_rpo, + OperandNotDefined(_, _, _) => compile_error_validation_operand_not_defined, + DuplicateInstruction(_, _) => compile_error_validation_duplicate_instruction, + }, } } } @@ -246,7 +260,6 @@ pub fn exit_counter_ptr(reason: crate::hir::SideExitReason) -> *mut u64 { StackOverflow => exit_stackoverflow, BlockParamProxyModified => exit_block_param_proxy_modified, BlockParamProxyNotIseqOrIfunc => exit_block_param_proxy_not_iseq_or_ifunc, - OptionalArgumentsSupplied => exit_optional_arguments, }; counter_ptr(counter) }