mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
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
This commit is contained in:
parent
a8dcab7233
commit
adcf0316d1
Notes:
git
2020-02-29 16:58:55 +09:00
Merged-By: k0kubun <takashikkbn@gmail.com>
5 changed files with 52 additions and 8 deletions
|
@ -2907,6 +2907,7 @@ mjit.$(OBJEXT): $(hdrdir)/ruby/ruby.h
|
||||||
mjit.$(OBJEXT): $(top_srcdir)/internal/array.h
|
mjit.$(OBJEXT): $(top_srcdir)/internal/array.h
|
||||||
mjit.$(OBJEXT): $(top_srcdir)/internal/class.h
|
mjit.$(OBJEXT): $(top_srcdir)/internal/class.h
|
||||||
mjit.$(OBJEXT): $(top_srcdir)/internal/compilers.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/file.h
|
||||||
mjit.$(OBJEXT): $(top_srcdir)/internal/gc.h
|
mjit.$(OBJEXT): $(top_srcdir)/internal/gc.h
|
||||||
mjit.$(OBJEXT): $(top_srcdir)/internal/hash.h
|
mjit.$(OBJEXT): $(top_srcdir)/internal/hash.h
|
||||||
|
|
21
cont.c
21
cont.c
|
@ -1103,6 +1103,15 @@ cont_save_thread(rb_context_t *cont, rb_thread_t *th)
|
||||||
sec->machine.stack_end = NULL;
|
sec->machine.stack_end = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
static void
|
||||||
cont_init(rb_context_t *cont, rb_thread_t *th)
|
cont_init(rb_context_t *cont, rb_thread_t *th)
|
||||||
{
|
{
|
||||||
|
@ -1112,9 +1121,7 @@ cont_init(rb_context_t *cont, rb_thread_t *th)
|
||||||
cont->saved_ec.local_storage = NULL;
|
cont->saved_ec.local_storage = NULL;
|
||||||
cont->saved_ec.local_storage_recursive_hash = Qnil;
|
cont->saved_ec.local_storage_recursive_hash = Qnil;
|
||||||
cont->saved_ec.local_storage_recursive_hash_for_trace = Qnil;
|
cont->saved_ec.local_storage_recursive_hash_for_trace = Qnil;
|
||||||
if (mjit_enabled) {
|
cont_init_mjit_cont(cont);
|
||||||
cont->mjit_cont = mjit_cont_new(&cont->saved_ec);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static rb_context_t *
|
static rb_context_t *
|
||||||
|
@ -1131,6 +1138,14 @@ cont_new(VALUE klass)
|
||||||
return cont;
|
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
|
#if 0
|
||||||
void
|
void
|
||||||
show_vm_stack(const rb_execution_context_t *ec)
|
show_vm_stack(const rb_execution_context_t *ec)
|
||||||
|
|
|
@ -12,10 +12,12 @@
|
||||||
#include "ruby/ruby.h" /* for VALUE */
|
#include "ruby/ruby.h" /* for VALUE */
|
||||||
|
|
||||||
struct rb_thread_struct; /* in vm_core.h */
|
struct rb_thread_struct; /* in vm_core.h */
|
||||||
|
struct rb_fiber_struct; /* in cont.c */
|
||||||
|
|
||||||
/* cont.c */
|
/* cont.c */
|
||||||
VALUE rb_obj_is_fiber(VALUE);
|
VALUE rb_obj_is_fiber(VALUE);
|
||||||
void rb_fiber_reset_root_local_storage(struct rb_thread_struct *);
|
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 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 */
|
#endif /* INTERNAL_CONT_H */
|
||||||
|
|
4
mjit.c
4
mjit.c
|
@ -19,6 +19,7 @@
|
||||||
#include "id_table.h"
|
#include "id_table.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "internal/class.h"
|
#include "internal/class.h"
|
||||||
|
#include "internal/cont.h"
|
||||||
#include "internal/file.h"
|
#include "internal/file.h"
|
||||||
#include "internal/hash.h"
|
#include "internal/hash.h"
|
||||||
#include "internal/mjit.h"
|
#include "internal/mjit.h"
|
||||||
|
@ -811,6 +812,9 @@ mjit_init(const struct mjit_options *opts)
|
||||||
rb_native_cond_initialize(&mjit_worker_wakeup);
|
rb_native_cond_initialize(&mjit_worker_wakeup);
|
||||||
rb_native_cond_initialize(&mjit_gc_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
|
// Initialize class_serials cache for compilation
|
||||||
valid_class_serials = rb_hash_new();
|
valid_class_serials = rb_hash_new();
|
||||||
rb_obj_hide(valid_class_serials);
|
rb_obj_hide(valid_class_serials);
|
||||||
|
|
|
@ -12,6 +12,10 @@ class TestJIT < Test::Unit::TestCase
|
||||||
/\AJIT inline: .+\n\z/,
|
/\AJIT inline: .+\n\z/,
|
||||||
/\ASuccessful MJIT finish\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...
|
# trace_* insns are not compiled for now...
|
||||||
TEST_PENDING_INSNS = RubyVM::INSTRUCTION_NAMES.select { |n| n.start_with?('trace_') }.map(&:to_sym) + [
|
TEST_PENDING_INSNS = RubyVM::INSTRUCTION_NAMES.select { |n| n.start_with?('trace_') }.map(&:to_sym) + [
|
||||||
|
@ -611,11 +615,7 @@ class TestJIT < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_nothing_to_unload_with_jit_wait
|
def test_nothing_to_unload_with_jit_wait
|
||||||
ignorable_patterns = [
|
assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: 'hello', success_count: 11, max_cache: 10, ignorable_patterns: MAX_CACHE_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)
|
|
||||||
begin;
|
begin;
|
||||||
def a1() a2() end
|
def a1() a2() end
|
||||||
def a2() a3() end
|
def a2() a3() end
|
||||||
|
@ -632,6 +632,28 @@ class TestJIT < Test::Unit::TestCase
|
||||||
end;
|
end;
|
||||||
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
|
def test_unload_units_and_compaction
|
||||||
Dir.mktmpdir("jit_test_unload_units_") do |dir|
|
Dir.mktmpdir("jit_test_unload_units_") do |dir|
|
||||||
# MIN_CACHE_SIZE is 10
|
# MIN_CACHE_SIZE is 10
|
||||||
|
|
Loading…
Reference in a new issue