[前][次][番号順一覧][スレッド一覧]

ruby-changes:60239

From: Takashi <ko1@a...>
Date: Sat, 29 Feb 2020 16:58:50 +0900 (JST)
Subject: [ruby-changes:60239] adcf0316d1 (master): Prevent unloading methods used in root_fiber while calling another Fiber (#2939)

https://git.ruby-lang.org/ruby.git/commit/?id=adcf0316d1

From adcf0316d1ecedae2a9157ad941550e0c0fb510b Mon Sep 17 00:00:00 2001
From: Takashi Kokubun <takashikkbn@g...>
Date: Fri, 28 Feb 2020 23:58:33 -0800
Subject: Prevent unloading methods used in root_fiber while calling another
 Fiber (#2939)

Fixing SEGVs like:
http://ci.rvm.jp/results/trunk-mjit-wait@silicon-docker/2744905
http://ci.rvm.jp/results/trunk-mjit-wait@silicon-docker/2744420
http://ci.rvm.jp/results/trunk-mjit-wait@silicon-docker/2741400

diff --git a/common.mk b/common.mk
index 57e11ab..b2cb7da 100644
--- a/common.mk
+++ b/common.mk
@@ -2907,6 +2907,7 @@ mjit.$(OBJEXT): $(hdrdir)/ruby/ruby.h https://github.com/ruby/ruby/blob/trunk/common.mk#L2907
 mjit.$(OBJEXT): $(top_srcdir)/internal/array.h
 mjit.$(OBJEXT): $(top_srcdir)/internal/class.h
 mjit.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/cont.h
 mjit.$(OBJEXT): $(top_srcdir)/internal/file.h
 mjit.$(OBJEXT): $(top_srcdir)/internal/gc.h
 mjit.$(OBJEXT): $(top_srcdir)/internal/hash.h
diff --git a/cont.c b/cont.c
index df197a7..7a32573 100644
--- a/cont.c
+++ b/cont.c
@@ -1104,6 +1104,15 @@ cont_save_thread(rb_context_t *cont, rb_thread_t *th) https://github.com/ruby/ruby/blob/trunk/cont.c#L1104
 }
 
 static void
+cont_init_mjit_cont(rb_context_t *cont)
+{
+    VM_ASSERT(cont->mjit_cont == NULL);
+    if (mjit_enabled) {
+        cont->mjit_cont = mjit_cont_new(&(cont->saved_ec));
+    }
+}
+
+static void
 cont_init(rb_context_t *cont, rb_thread_t *th)
 {
     /* save thread context */
@@ -1112,9 +1121,7 @@ cont_init(rb_context_t *cont, rb_thread_t *th) https://github.com/ruby/ruby/blob/trunk/cont.c#L1121
     cont->saved_ec.local_storage = NULL;
     cont->saved_ec.local_storage_recursive_hash = Qnil;
     cont->saved_ec.local_storage_recursive_hash_for_trace = Qnil;
-    if (mjit_enabled) {
-        cont->mjit_cont = mjit_cont_new(&cont->saved_ec);
-    }
+    cont_init_mjit_cont(cont);
 }
 
 static rb_context_t *
@@ -1131,6 +1138,14 @@ cont_new(VALUE klass) https://github.com/ruby/ruby/blob/trunk/cont.c#L1138
     return cont;
 }
 
+void
+rb_fiber_init_mjit_cont(struct rb_fiber_struct *fiber)
+{
+    // Currently this function is meant for root_fiber. Others go through cont_new.
+    // XXX: Is this mjit_cont `mjit_cont_free`d?
+    cont_init_mjit_cont(&fiber->cont);
+}
+
 #if 0
 void
 show_vm_stack(const rb_execution_context_t *ec)
diff --git a/internal/cont.h b/internal/cont.h
index 5aaf095..f77fb20 100644
--- a/internal/cont.h
+++ b/internal/cont.h
@@ -12,10 +12,12 @@ https://github.com/ruby/ruby/blob/trunk/internal/cont.h#L12
 #include "ruby/ruby.h"          /* for VALUE */
 
 struct rb_thread_struct;        /* in vm_core.h */
+struct rb_fiber_struct;         /* in cont.c */
 
 /* cont.c */
 VALUE rb_obj_is_fiber(VALUE);
 void rb_fiber_reset_root_local_storage(struct rb_thread_struct *);
 void ruby_register_rollback_func_for_ensure(VALUE (*ensure_func)(VALUE), VALUE (*rollback_func)(VALUE));
+void rb_fiber_init_mjit_cont(struct rb_fiber_struct *fiber);
 
 #endif /* INTERNAL_CONT_H */
diff --git a/mjit.c b/mjit.c
index b5fcffa..a546141 100644
--- a/mjit.c
+++ b/mjit.c
@@ -19,6 +19,7 @@ https://github.com/ruby/ruby/blob/trunk/mjit.c#L19
 #include "id_table.h"
 #include "internal.h"
 #include "internal/class.h"
+#include "internal/cont.h"
 #include "internal/file.h"
 #include "internal/hash.h"
 #include "internal/mjit.h"
@@ -811,6 +812,9 @@ mjit_init(const struct mjit_options *opts) https://github.com/ruby/ruby/blob/trunk/mjit.c#L812
     rb_native_cond_initialize(&mjit_worker_wakeup);
     rb_native_cond_initialize(&mjit_gc_wakeup);
 
+    // Make sure root_fiber's saved_ec is scanned by mark_ec_units
+    rb_fiber_init_mjit_cont(GET_EC()->fiber_ptr);
+
     // Initialize class_serials cache for compilation
     valid_class_serials = rb_hash_new();
     rb_obj_hide(valid_class_serials);
diff --git a/test/ruby/test_jit.rb b/test/ruby/test_jit.rb
index adb6603..e3d8f9c 100644
--- a/test/ruby/test_jit.rb
+++ b/test/ruby/test_jit.rb
@@ -12,6 +12,10 @@ class TestJIT < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_jit.rb#L12
     /\AJIT inline: .+\n\z/,
     /\ASuccessful MJIT finish\n\z/,
   ]
+  MAX_CACHE_PATTERNS = [
+    /\AJIT compaction \([^)]+\): .+\n\z/,
+    /\ANo units can be unloaded -- .+\n\z/,
+  ]
 
   # trace_* insns are not compiled for now...
   TEST_PENDING_INSNS = RubyVM::INSTRUCTION_NAMES.select { |n| n.start_with?('trace_') }.map(&:to_sym) + [
@@ -611,11 +615,7 @@ class TestJIT < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_jit.rb#L615
   end
 
   def test_nothing_to_unload_with_jit_wait
-    ignorable_patterns = [
-      /\AJIT compaction \([^)]+\): .+\n\z/,
-      /\ANo units can be unloaded -- .+\n\z/,
-    ]
-    assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: 'hello', success_count: 11, max_cache: 10, ignorable_patterns: ignorable_patterns)
+    assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: 'hello', success_count: 11, max_cache: 10, ignorable_patterns: MAX_CACHE_PATTERNS)
     begin;
       def a1() a2() end
       def a2() a3() end
@@ -632,6 +632,28 @@ class TestJIT < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_jit.rb#L632
     end;
   end
 
+  def test_unload_units_on_fiber
+    assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: 'hello', success_count: 12, max_cache: 10, ignorable_patterns: MAX_CACHE_PATTERNS)
+    begin;
+      def a1() a2(false); a2(true) end
+      def a2(a) a3(a) end
+      def a3(a) a4(a) end
+      def a4(a) a5(a) end
+      def a5(a) a6(a) end
+      def a6(a) a7(a) end
+      def a7(a) a8(a) end
+      def a8(a) a9(a) end
+      def a9(a) a10(a) end
+      def a10(a)
+        if a
+          Fiber.new { a11 }.resume
+        end
+      end
+      def a11() print('hello') end
+      a1
+    end;
+  end
+
   def test_unload_units_and_compaction
     Dir.mktmpdir("jit_test_unload_units_") do |dir|
       # MIN_CACHE_SIZE is 10
-- 
cgit v0.10.2


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]