Fast object is iclass checks
Calling rb_obj_is_kind_of with an ICLASS returns the same result as calling it with the ICLASS's original Module. Most of the time we encounter an ICLASS here checking the validity of a protected method or super call, which we expect to return true (or raise a slow exception anyways). We can take advantage of this by performing a fast class inheritance check on the ICLASS's "includer" in hopes that it returns true. If the includer class check returns false we still have to fallback to the full inheritance chain scan for the module's inclusion, but this should be less common.
This commit is contained in:
parent
9a4bddd761
commit
4d8f76286b
Notes:
git
2022-03-12 03:36:40 +09:00
36
object.c
36
object.c
|
@ -817,18 +817,38 @@ rb_obj_is_kind_of(VALUE obj, VALUE c)
|
||||||
// class without checking type and can return immediately.
|
// class without checking type and can return immediately.
|
||||||
if (cl == c) return Qtrue;
|
if (cl == c) return Qtrue;
|
||||||
|
|
||||||
// Fast path: Both are T_CLASS
|
|
||||||
if (LIKELY(RB_TYPE_P(c, T_CLASS))) {
|
|
||||||
return class_search_class_ancestor(cl, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: YJIT needs this function to never allocate and never raise when
|
// Note: YJIT needs this function to never allocate and never raise when
|
||||||
// `c` is a class or a module.
|
// `c` is a class or a module.
|
||||||
c = class_or_module_required(c);
|
|
||||||
c = RCLASS_ORIGIN(c);
|
|
||||||
|
|
||||||
|
if (LIKELY(RB_TYPE_P(c, T_CLASS))) {
|
||||||
|
// Fast path: Both are T_CLASS
|
||||||
|
return class_search_class_ancestor(cl, c);
|
||||||
|
}
|
||||||
|
else if (RB_TYPE_P(c, T_ICLASS)) {
|
||||||
|
// First check if we inherit the includer
|
||||||
|
// If we do we can return true immediately
|
||||||
|
VALUE includer = RCLASS_INCLUDER(c);
|
||||||
|
if (cl == includer) return Qtrue;
|
||||||
|
|
||||||
|
// Usually includer is a T_CLASS here, except when including into an
|
||||||
|
// already included Module.
|
||||||
|
// If it is a class, attempt the fast class-to-class check and return
|
||||||
|
// true if there is a match.
|
||||||
|
if (RB_TYPE_P(includer, T_CLASS) && class_search_class_ancestor(cl, includer))
|
||||||
|
return Qtrue;
|
||||||
|
|
||||||
|
// We don't include the ICLASS directly, so must check if we inherit
|
||||||
|
// the module via another include
|
||||||
|
return RBOOL(class_search_ancestor(cl, RCLASS_ORIGIN(c)));
|
||||||
|
}
|
||||||
|
else if (RB_TYPE_P(c, T_MODULE)) {
|
||||||
// Slow path: check each ancestor in the linked list and its method table
|
// Slow path: check each ancestor in the linked list and its method table
|
||||||
return RBOOL(class_search_ancestor(cl, c));
|
return RBOOL(class_search_ancestor(cl, RCLASS_ORIGIN(c)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rb_raise(rb_eTypeError, "class or module required");
|
||||||
|
UNREACHABLE_RETURN(Qfalse);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue