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

ruby-changes:58576

From: =E5=8D=9C=E9=83=A8=E6=98=8C=E5=B9=B3 <ko1@a...>
Date: Tue, 5 Nov 2019 11:39:55 +0900 (JST)
Subject: [ruby-changes:58576] 6ff1250739 (master): rb_method_basic_definition_p with CC

https://git.ruby-lang.org/ruby.git/commit/?id=6ff1250739

From 6ff1250739c57ce7f234a2148d3f6214da01b7e5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=8D=9C=E9=83=A8=E6=98=8C=E5=B9=B3?=
 <shyouhei@r...>
Date: Tue, 29 Oct 2019 11:37:25 +0900
Subject: rb_method_basic_definition_p with CC

Noticed that rb_method_basic_definition_p is frequently called.
Its callers include vm_caller_setup_args_block(),
rb_hash_default_value(), rb_num_neative_int_p(), and a lot more.

It seems worth caching the method resolution part.  Majority of
rb_method_basic_definion_p() usages take fixed class and fixed
method id combinations.

Calculating -------------------------------------
                           ours       trunk
           so_matrix      2.379       2.115 i/s -       1.000 times in 0.420409s 0.472879s

Comparison:
                        so_matrix
                ours:         2.4 i/s
               trunk:         2.1 i/s - 1.12x  slower

diff --git a/internal.h b/internal.h
index 6c6e262..0c245c3 100644
--- a/internal.h
+++ b/internal.h
@@ -2389,6 +2389,8 @@ struct rb_call_data { https://github.com/ruby/ruby/blob/trunk/internal.h#L2389
 };
 RUBY_FUNC_EXPORTED
 RUBY_FUNC_NONNULL(1, VALUE rb_funcallv_with_cc(struct rb_call_data*, VALUE, ID, int, const VALUE*));
+RUBY_FUNC_EXPORTED
+RUBY_FUNC_NONNULL(1, bool rb_method_basic_definition_p_with_cc(struct rb_call_data *, VALUE, ID));
 
 #ifdef __GNUC__
 # define rb_funcallv(recv, mid, argc, argv) \
@@ -2396,6 +2398,12 @@ RUBY_FUNC_NONNULL(1, VALUE rb_funcallv_with_cc(struct rb_call_data*, VALUE, ID, https://github.com/ruby/ruby/blob/trunk/internal.h#L2398
         static struct rb_call_data rb_funcallv_data = { { 0, }, { 0, }, }; \
         rb_funcallv_with_cc(&rb_funcallv_data, recv, mid, argc, argv); \
     })
+# define rb_method_basic_definition_p(klass, mid) \
+    __extension__({ \
+        static struct rb_call_data rb_mbdp = { { 0, }, { 0, }, }; \
+        (klass == Qfalse) ? /* hidden object cannot be overridden */ true : \
+            rb_method_basic_definition_p_with_cc(&rb_mbdp, klass, mid); \
+    })
 #endif
 
 /* miniprelude.c, prelude.c */
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index a4bc276..5e1cfcc 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -1433,13 +1433,9 @@ rb_vm_search_method_slowpath(struct rb_call_data *cd, VALUE klass) https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L1433
 }
 
 static void
-vm_search_method(struct rb_call_data *cd, VALUE recv)
+vm_search_method_fastpath(struct rb_call_data *cd, VALUE klass)
 {
     struct rb_call_cache *cc = &cd->cc;
-    VALUE klass = CLASS_OF(recv);
-
-    VM_ASSERT(klass != Qfalse);
-    VM_ASSERT(RBASIC_CLASS(klass) == 0 || rb_obj_is_kind_of(klass, rb_cClass));
 
 #if OPT_INLINE_METHOD_CACHE
     if (LIKELY(RB_DEBUG_COUNTER_INC_UNLESS(mc_global_state_miss,
@@ -1456,6 +1452,16 @@ vm_search_method(struct rb_call_data *cd, VALUE recv) https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L1452
     rb_vm_search_method_slowpath(cd, klass);
 }
 
+static void
+vm_search_method(struct rb_call_data *cd, VALUE recv)
+{
+    VALUE klass = CLASS_OF(recv);
+
+    VM_ASSERT(klass != Qfalse);
+    VM_ASSERT(RBASIC_CLASS(klass) == 0 || rb_obj_is_kind_of(klass, rb_cClass));
+    vm_search_method_fastpath(cd, klass);
+}
+
 static inline int
 check_cfunc(const rb_callable_method_entry_t *me, VALUE (*func)())
 {
diff --git a/vm_method.c b/vm_method.c
index 5ee1773..311a669 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -2024,6 +2024,21 @@ rb_mod_modfunc(int argc, VALUE *argv, VALUE module) https://github.com/ruby/ruby/blob/trunk/vm_method.c#L2024
     return module;
 }
 
+bool
+rb_method_basic_definition_p_with_cc(struct rb_call_data *cd, VALUE klass, ID mid)
+{
+    if (cd->ci.mid != mid) {
+        *cd = (struct rb_call_data) /* reset */ { .ci = { .mid = mid, }, };
+    }
+
+    vm_search_method_fastpath(cd, klass);
+    return cd->cc.me && METHOD_ENTRY_BASIC(cd->cc.me);
+}
+
+#ifdef __GNUC__
+#pragma push_macro("rb_method_basic_definition_p")
+#undef rb_method_basic_definition_p
+#endif
 int
 rb_method_basic_definition_p(VALUE klass, ID id)
 {
@@ -2032,6 +2047,9 @@ rb_method_basic_definition_p(VALUE klass, ID id) https://github.com/ruby/ruby/blob/trunk/vm_method.c#L2047
     me = rb_method_entry(klass, id);
     return (me && METHOD_ENTRY_BASIC(me)) ? TRUE : FALSE;
 }
+#ifdef __GNUC__
+#pragma pop_macro("rb_method_basic_definition_p")
+#endif
 
 static VALUE
 call_method_entry(rb_execution_context_t *ec, VALUE defined_class, VALUE obj, ID id,
-- 
cgit v0.10.2


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

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