summaryrefslogtreecommitdiff
path: root/vm_method.c
diff options
context:
space:
mode:
authorJohn Hawthorn <john@hawthorn.email>2019-12-11 13:10:39 -0800
committerAaron Patterson <tenderlove@github.com>2019-12-17 09:19:00 -0800
commitd7a50a5cc694ab28608a9d5a2e39c2766330ffe6 (patch)
treeb07ca44076f0b641f32cddd1a71d3a72d3871a99 /vm_method.c
parent8a40dce0ff2964df22e06ae9a08f50592d17caf0 (diff)
Avoid revisiting seen nodes clearing method cache
rb_clear_method_cache_by_class calls rb_class_clear_method_cache recursively on subclasses, where it will bump the class serial and clear some other data (callable_m_tbl, and some mjit data). Previously this could end up taking a long time to clear all the classes if the module was included a few levels deep and especially if there were multiple paths to it in the dependency tree (ie. a class includes two modules which both include the same other module) as we end up revisiting class/iclass/module objects multiple times. This commit avoids revisiting the same object, by short circuiting when revisit the same object. We can check this efficiently by comparing the class serial of each object we visit with the next class serial at the start. We know that any objects with a higher class serial have already been visited.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/2752
Diffstat (limited to 'vm_method.c')
-rw-r--r--vm_method.c8
1 files changed, 7 insertions, 1 deletions
diff --git a/vm_method.c b/vm_method.c
index 1a6b1cfeaf..2e948144d6 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -62,6 +62,11 @@ static struct {
static void
rb_class_clear_method_cache(VALUE klass, VALUE arg)
{
+ VALUE old_serial = *(rb_serial_t *)arg;
+ if (RCLASS_SERIAL(klass) > old_serial) {
+ return;
+ }
+
mjit_remove_class_serial(RCLASS_SERIAL(klass));
RCLASS_SERIAL(klass) = rb_next_class_serial();
@@ -99,7 +104,8 @@ rb_clear_method_cache_by_class(VALUE klass)
INC_GLOBAL_METHOD_STATE();
}
else {
- rb_class_clear_method_cache(klass, Qnil);
+ rb_serial_t old_serial = rb_next_class_serial();
+ rb_class_clear_method_cache(klass, (VALUE)&old_serial);
}
}