summaryrefslogtreecommitdiff
path: root/proc.c
diff options
context:
space:
mode:
authorJean Boussier <jean.boussier@gmail.com>2021-02-12 17:31:19 +0100
committerAaron Patterson <aaron.patterson@gmail.com>2021-03-10 13:43:22 -0800
commita03653d386bd64256932ea7eead3c28f03de1bac (patch)
treef781523dd309618615d615c40371d64710c61417 /proc.c
parentd9fea496afed5a35d2f79ea3cac35176966dd471 (diff)
proc.c: make bind_call use existing callable method entry when possible
The most common use case for `bind_call` is to protect from core methods being redefined, for instance a typical use: ```ruby UNBOUND_METHOD_MODULE_NAME = Module.instance_method(:name) def real_mod_name(mod) UNBOUND_METHOD_MODULE_NAME.bind_call(mod) end ``` But it's extremely common that the method wasn't actually redefined. In such case we can avoid creating a new callable method entry, and simply delegate to the receiver. This result in a 1.5-2X speed-up for the fast path, and little to no impact on the slowpath: ``` compare-ruby: ruby 3.1.0dev (2021-02-05T06:33:00Z master b2674c1fd7) [x86_64-darwin19] built-ruby: ruby 3.1.0dev (2021-02-15T10:35:17Z bind-call-fastpath d687e06615) [x86_64-darwin19] | |compare-ruby|built-ruby| |:---------|-----------:|---------:| |fastpath | 11.325M| 16.393M| | | -| 1.45x| |slowpath | 10.488M| 10.242M| | | 1.02x| -| ```
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/4188
Diffstat (limited to 'proc.c')
-rw-r--r--proc.c34
1 files changed, 21 insertions, 13 deletions
diff --git a/proc.c b/proc.c
index d1e8358bea..b266365f40 100644
--- a/proc.c
+++ b/proc.c
@@ -18,6 +18,7 @@
#include "internal/object.h"
#include "internal/proc.h"
#include "internal/symbol.h"
+#include "method.h"
#include "iseq.h"
#include "vm_core.h"
@@ -2512,12 +2513,8 @@ rb_method_call_with_block(int argc, const VALUE *argv, VALUE method, VALUE passe
*/
static void
-convert_umethod_to_method_components(VALUE method, VALUE recv, VALUE *methclass_out, VALUE *klass_out, VALUE *iclass_out, const rb_method_entry_t **me_out)
+convert_umethod_to_method_components(const struct METHOD *data, VALUE recv, VALUE *methclass_out, VALUE *klass_out, VALUE *iclass_out, const rb_method_entry_t **me_out)
{
- struct METHOD *data;
-
- TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
-
VALUE methclass = data->me->owner;
VALUE iclass = data->me->defined_class;
VALUE klass = CLASS_OF(recv);
@@ -2598,7 +2595,9 @@ umethod_bind(VALUE method, VALUE recv)
{
VALUE methclass, klass, iclass;
const rb_method_entry_t *me;
- convert_umethod_to_method_components(method, recv, &methclass, &klass, &iclass, &me);
+ const struct METHOD *data;
+ TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
+ convert_umethod_to_method_components(data, recv, &methclass, &klass, &iclass, &me);
struct METHOD *bound;
method = TypedData_Make_Struct(rb_cMethod, struct METHOD, &method_data_type, bound);
@@ -2626,15 +2625,24 @@ umethod_bind_call(int argc, VALUE *argv, VALUE method)
argc--;
argv++;
- VALUE methclass, klass, iclass;
- const rb_method_entry_t *me;
- convert_umethod_to_method_components(method, recv, &methclass, &klass, &iclass, &me);
- struct METHOD bound = { recv, klass, 0, me };
-
VALUE passed_procval = rb_block_given_p() ? rb_block_proc() : Qnil;
-
rb_execution_context_t *ec = GET_EC();
- return call_method_data(ec, &bound, argc, argv, passed_procval, RB_PASS_CALLED_KEYWORDS);
+
+ const struct METHOD *data;
+ TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
+
+ const rb_callable_method_entry_t *cme = rb_callable_method_entry(CLASS_OF(recv), data->me->called_id);
+ if (data->me == (const rb_method_entry_t *)cme) {
+ vm_passed_block_handler_set(ec, proc_to_block_handler(passed_procval));
+ return rb_vm_call_kw(ec, recv, cme->called_id, argc, argv, cme, RB_PASS_CALLED_KEYWORDS);
+ } else {
+ VALUE methclass, klass, iclass;
+ const rb_method_entry_t *me;
+ convert_umethod_to_method_components(data, recv, &methclass, &klass, &iclass, &me);
+ struct METHOD bound = { recv, klass, 0, me };
+
+ return call_method_data(ec, &bound, argc, argv, passed_procval, RB_PASS_CALLED_KEYWORDS);
+ }
}
/*