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

ruby-changes:68997

From: John <ko1@a...>
Date: Thu, 21 Oct 2021 08:19:37 +0900 (JST)
Subject: [ruby-changes:68997] 7d252186fe (master): Simplify known class check for singletons

https://git.ruby-lang.org/ruby.git/commit/?id=7d252186fe

From 7d252186fe803aa5e1fa37c953609266a2d8ba1d Mon Sep 17 00:00:00 2001
From: John Hawthorn <john@h...>
Date: Thu, 17 Jun 2021 11:29:28 -0700
Subject: Simplify known class check for singletons

Singleton classes should only ever be attached to one object. This means
that checking for the object should be the same as checking for the
class. This should be slightly faster by avoiding one memory acccess as
well as allowing us to skip checking if the receiver is a heap object.

This will be most common for calling class methods.
---
 bootstraptest/test_yjit.rb | 31 +++++++++++++++++++++++++++++++
 yjit_codegen.c             | 35 +++++++++++++++++++----------------
 2 files changed, 50 insertions(+), 16 deletions(-)

diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb
index 129903bf9c..e15728fd98 100644
--- a/bootstraptest/test_yjit.rb
+++ b/bootstraptest/test_yjit.rb
@@ -1153,3 +1153,34 @@ assert_equal '7', %q{ https://github.com/ruby/ruby/blob/trunk/bootstraptest/test_yjit.rb#L1153
   foo(5,2)
   foo(5,2)
 }
+
+# Call to object with singleton
+assert_equal '123', %q{
+  obj = Object.new
+  def obj.foo
+    123
+  end
+
+  def foo(obj)
+    obj.foo()
+  end
+
+  foo(obj)
+  foo(obj)
+}
+
+# Call to singleton class
+assert_equal '123', %q{
+  class Foo
+    def self.foo
+      123
+    end
+  end
+
+  def foo(obj)
+    obj.foo()
+  end
+
+  foo(Foo)
+  foo(Foo)
+}
diff --git a/yjit_codegen.c b/yjit_codegen.c
index 3a6f6c5cdc..60d2338115 100644
--- a/yjit_codegen.c
+++ b/yjit_codegen.c
@@ -2172,6 +2172,7 @@ static bool https://github.com/ruby/ruby/blob/trunk/yjit_codegen.c#L2172
 jit_guard_known_klass(jitstate_t *jit, ctx_t* ctx, VALUE known_klass, insn_opnd_t insn_opnd, const int max_chain_depth, uint8_t *side_exit)
 {
     val_type_t val_type = ctx_get_opnd_type(ctx, insn_opnd);
+    bool singleton_klass = FL_TEST(known_klass, FL_SINGLETON);
 
     if (known_klass == rb_cNilClass) {
         if (val_type.type != ETYPE_NIL) {
@@ -2190,7 +2191,6 @@ jit_guard_known_klass(jitstate_t *jit, ctx_t* ctx, VALUE known_klass, insn_opnd_ https://github.com/ruby/ruby/blob/trunk/yjit_codegen.c#L2191
 
             ctx_set_opnd_type(ctx, insn_opnd, TYPE_TRUE);
         }
-
     }
     else if (known_klass == rb_cFalseClass) {
         if (val_type.type != ETYPE_FALSE) {
@@ -2202,15 +2202,26 @@ jit_guard_known_klass(jitstate_t *jit, ctx_t* ctx, VALUE known_klass, insn_opnd_ https://github.com/ruby/ruby/blob/trunk/yjit_codegen.c#L2202
             ctx_set_opnd_type(ctx, insn_opnd, TYPE_FALSE);
         }
     }
-    else {
-        // Can't guard for for these classes because some of they are sometimes immediate (special const).
-        // Can remove this by adding appropriate dynamic checks.
-        if (known_klass == rb_cInteger ||
+    else if (known_klass == rb_cInteger ||
             known_klass == rb_cSymbol ||
             known_klass == rb_cFloat) {
-            return false;
-        }
-
+        // Can't guard for for these classes because some of they are sometimes
+        // immediate (special const). Can remove this by adding appropriate
+        // dynamic checks.
+        return false;
+    }
+    else if (singleton_klass) {
+        // Singleton classes are attached to one specific object, so we can
+        // avoid one memory access (and potentially the is_heap check) by
+        // looking for the expected object directly.
+        ADD_COMMENT(cb, "guard known object with singleton class");
+        VALUE known_obj = rb_attr_get(known_klass, id__attached__);
+        // TODO: jit_mov_gc_ptr keeps a strong reference, which leaks the object.
+        jit_mov_gc_ptr(jit, cb, REG1, known_obj);
+        cmp(cb, REG0, REG1);
+        jit_chain_guard(JCC_JNE, jit, ctx, max_chain_depth, side_exit);
+    }
+    else {
         // Check that the receiver is a heap object
         // Note: if we get here, the class doesn't have immediate instances.
         if (!val_type.is_heap) {
@@ -2234,14 +2245,6 @@ jit_guard_known_klass(jitstate_t *jit, ctx_t* ctx, VALUE known_klass, insn_opnd_ https://github.com/ruby/ruby/blob/trunk/yjit_codegen.c#L2245
         jit_chain_guard(JCC_JNE, jit, ctx, max_chain_depth, side_exit);
     }
 
-    // Pointer to the klass field of the receiver &(recv->klass)
-    x86opnd_t klass_opnd = mem_opnd(64, REG0, offsetof(struct RBasic, klass));
-
-    // Bail if receiver class is different from known_klass
-    // TODO: jit_mov_gc_ptr keeps a strong reference, which leaks the class.
-    jit_mov_gc_ptr(jit, cb, REG1, known_klass);
-    cmp(cb, klass_opnd, REG1);
-    jit_chain_guard(JCC_JNE, jit, ctx, max_chain_depth, side_exit);
     return true;
 }
 
-- 
cgit v1.2.1


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

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