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

ruby-changes:71361

From: John <ko1@a...>
Date: Fri, 11 Mar 2022 02:34:29 +0900 (JST)
Subject: [ruby-changes:71361] 1b15756d24 (master): Fast object is iclass checks

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

From 1b15756d24c11ed6bfddb5ae53402a071a20ea97 Mon Sep 17 00:00:00 2001
From: John Hawthorn <john@h...>
Date: Fri, 18 Feb 2022 23:05:23 -0800
Subject: 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.
---
 object.c | 32 +++++++++++++++++++++++---------
 1 file changed, 23 insertions(+), 9 deletions(-)

diff --git a/object.c b/object.c
index 84acf0aada..2ed056b6b9 100644
--- a/object.c
+++ b/object.c
@@ -817,18 +817,32 @@ rb_obj_is_kind_of(VALUE obj, VALUE c) https://github.com/ruby/ruby/blob/trunk/object.c#L817
     // class without checking type and can return immediately.
     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
     // `c` is a class or a module.
-    c = class_or_module_required(c);
-    c = RCLASS_ORIGIN(c);
 
-    // Slow path: check each ancestor in the linked list and its method table
-    return RBOOL(class_search_ancestor(cl, 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);
+        RUBY_ASSERT(RB_TYPE_P(includer, T_CLASS));
+        if (cl == includer) return Qtrue;
+
+        if(class_search_class_ancestor(cl, includer))
+            return Qtrue;
+
+        // We don't include the ICLASS directly, but 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
+        return RBOOL(class_search_ancestor(cl, RCLASS_ORIGIN(c)));
+    } else {
+        rb_raise(rb_eTypeError, "class or module required");
+        UNREACHABLE_RETURN(Qfalse);
+    }
 }
 
 
-- 
cgit v1.2.1


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

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