Skip to content

Commit

Permalink
Skip optimized method check for most method IDs
Browse files Browse the repository at this point in the history
Previously every time a method was defined on a module, we would
recursively walk all subclasses to see if the module was included in a
class which the VM optimizes for (such as Integer#+).

For most method definitions we can tell immediately that this won't be
the case based on the method's name. To do this we just keep a hash with
method IDs of optimized methods and if our new method isn't in that list
we don't need to check subclasses at all.
  • Loading branch information
jhawthorn authored and tenderlove committed Dec 17, 2019
1 parent 9245462 commit 2544772
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 2 deletions.
1 change: 1 addition & 0 deletions internal.h
Expand Up @@ -2282,6 +2282,7 @@ const char *rb_source_location_cstr(int *pline);
MJIT_STATIC void rb_vm_pop_cfunc_frame(void);
int rb_vm_add_root_module(ID id, VALUE module);
void rb_vm_check_redefinition_by_prepend(VALUE klass);
int rb_vm_check_optimizable_mid(VALUE mid);
VALUE rb_yield_refine_block(VALUE refinement, VALUE refinements);
MJIT_STATIC VALUE ruby_vm_special_exception_copy(VALUE);
PUREFUNC(st_table *rb_vm_fstring_table(void));
Expand Down
13 changes: 13 additions & 0 deletions vm.c
Expand Up @@ -1557,6 +1557,7 @@ rb_iter_break_value(VALUE val)
/* optimization: redefine management */

static st_table *vm_opt_method_table = 0;
static st_table *vm_opt_mid_table = 0;

static int
vm_redefinition_check_flag(VALUE klass)
Expand All @@ -1576,6 +1577,16 @@ vm_redefinition_check_flag(VALUE klass)
return 0;
}

int
rb_vm_check_optimizable_mid(VALUE mid)
{
if (!vm_opt_mid_table) {
return FALSE;
}

return st_lookup(vm_opt_mid_table, mid, NULL);
}

static int
vm_redefinition_check_method_type(const rb_method_definition_t *def)
{
Expand Down Expand Up @@ -1630,6 +1641,7 @@ add_opt_method(VALUE klass, ID mid, VALUE bop)

if (me && vm_redefinition_check_method_type(me->def)) {
st_insert(vm_opt_method_table, (st_data_t)me, (st_data_t)bop);
st_insert(vm_opt_mid_table, (st_data_t)mid, (st_data_t)Qtrue);
}
else {
rb_bug("undefined optimized method: %s", rb_id2name(mid));
Expand All @@ -1643,6 +1655,7 @@ vm_init_redefined_flag(void)
VALUE bop;

vm_opt_method_table = st_init_numtable();
vm_opt_mid_table = st_init_numtable();

#define OP(mid_, bop_) (mid = id##mid_, bop = BOP_##bop_, ruby_vm_redefined_flag[bop] = 0)
#define C(k) add_opt_method(rb_c##k, mid, bop)
Expand Down
12 changes: 10 additions & 2 deletions vm_method.c
Expand Up @@ -500,7 +500,7 @@ rb_add_refined_method_entry(VALUE refined_class, ID mid)
}

static void
check_override_opt_method(VALUE klass, VALUE arg)
check_override_opt_method_i(VALUE klass, VALUE arg)
{
ID mid = (ID)arg;
const rb_method_entry_t *me, *newme;
Expand All @@ -512,7 +512,15 @@ check_override_opt_method(VALUE klass, VALUE arg)
if (newme != me) rb_vm_check_redefinition_opt_method(me, me->owner);
}
}
rb_class_foreach_subclass(klass, check_override_opt_method, (VALUE)mid);
rb_class_foreach_subclass(klass, check_override_opt_method_i, (VALUE)mid);
}

static void
check_override_opt_method(VALUE klass, VALUE mid)
{
if (rb_vm_check_optimizable_mid(mid)) {
check_override_opt_method_i(klass, mid);
}
}

/*
Expand Down

0 comments on commit 2544772

Please sign in to comment.