diff options
author | Takashi Kokubun <takashikkbn@gmail.com> | 2020-07-03 09:52:35 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-03 09:52:35 -0700 |
commit | f3a0d7a2035e9f5e0c70effd55732607e3def263 (patch) | |
tree | 697ff4e3c14edb8005ea2c361f026cec557fa1c6 | |
parent | e8010c7401764f54173ffbe8c2bde38cd6d216fa (diff) |
Rewrite Kernel#tap with Ruby (#3281)
* Rewrite Kernel#tap with Ruby
This was good for VM too, but of course my intention is to unblock JIT's inlining of a block over yield
(inlining invokeyield has not been committed though).
* Fix test_settracefunc
About the :tap deletions, the :tap events are actually traced (we already have a TracePoint test for builtin methods),
but it's filtered out by tp.path == "xyzzy" (it became "<internal:kernel>"). We could trace tp.path == "<internal:kernel>"
cases too, but the lineno is impacted by kernel.rb changes and I didn't want to make it fragile for kernel.rb lineno changes.
Notes
Notes:
Merged-By: k0kubun <takashikkbn@gmail.com>
-rw-r--r-- | benchmark/kernel_tap.yml | 6 | ||||
-rw-r--r-- | kernel.rb | 22 | ||||
-rw-r--r-- | object.c | 26 | ||||
-rw-r--r-- | test/ruby/test_settracefunc.rb | 16 |
4 files changed, 32 insertions, 38 deletions
diff --git a/benchmark/kernel_tap.yml b/benchmark/kernel_tap.yml new file mode 100644 index 0000000000..4dcbb31b4d --- /dev/null +++ b/benchmark/kernel_tap.yml @@ -0,0 +1,6 @@ +prelude: | + obj = Object.new + x = nil +benchmark: + kernel_tap: obj.tap { |o| x = o } +loop_count: 20000000 @@ -48,6 +48,28 @@ module Kernel Primitive.rb_obj_clone2(freeze) end + # + # call-seq: + # obj.tap {|x| block } -> obj + # + # Yields self to the block, and then returns self. + # The primary purpose of this method is to "tap into" a method chain, + # in order to perform operations on intermediate results within the chain. + # + # (1..10) .tap {|x| puts "original: #{x}" } + # .to_a .tap {|x| puts "array: #{x}" } + # .select {|x| x.even? } .tap {|x| puts "evens: #{x}" } + # .map {|x| x*x } .tap {|x| puts "squares: #{x}" } + # + #-- + # \private + #++ + # + def tap + yield(self) + self + end + module_function # @@ -938,31 +938,6 @@ rb_class_search_ancestor(VALUE cl, VALUE c) return class_search_ancestor(cl, RCLASS_ORIGIN(c)); } -/** - * call-seq: - * obj.tap {|x| block } -> obj - * - * Yields self to the block, and then returns self. - * The primary purpose of this method is to "tap into" a method chain, - * in order to perform operations on intermediate results within the chain. - * - * (1..10) .tap {|x| puts "original: #{x}" } - * .to_a .tap {|x| puts "array: #{x}" } - * .select {|x| x.even? } .tap {|x| puts "evens: #{x}" } - * .map {|x| x*x } .tap {|x| puts "squares: #{x}" } - * - *-- - * \private - *++ - */ - -VALUE -rb_obj_tap(VALUE obj) -{ - rb_yield(obj); - return obj; -} - /* * Document-method: inherited @@ -4638,7 +4613,6 @@ InitVM_Object(void) rb_define_method(rb_mKernel, "instance_of?", rb_obj_is_instance_of, 1); rb_define_method(rb_mKernel, "kind_of?", rb_obj_is_kind_of, 1); rb_define_method(rb_mKernel, "is_a?", rb_obj_is_kind_of, 1); - rb_define_method(rb_mKernel, "tap", rb_obj_tap, 0); rb_define_global_function("sprintf", f_sprintf, -1); rb_define_global_function("format", f_sprintf, -1); diff --git a/test/ruby/test_settracefunc.rb b/test/ruby/test_settracefunc.rb index 3aaa34ff73..f688e5a9aa 100644 --- a/test/ruby/test_settracefunc.rb +++ b/test/ruby/test_settracefunc.rb @@ -485,8 +485,6 @@ class TestSetTraceFunc < Test::Unit::TestCase [:c_call, 4, 'xyzzy', Integer, :times, 1, :outer, :nothing], [:line, 4, 'xyzzy', self.class, method, self, nil, :nothing], [:line, 5, 'xyzzy', self.class, method, self, :inner, :nothing], - [:c_call, 5, 'xyzzy', Kernel, :tap, self, :inner, :nothing], - [:c_return, 5, "xyzzy", Kernel, :tap, self, :inner, self], [:c_return, 4, "xyzzy", Integer, :times, 1, :outer, 1], [:line, 7, 'xyzzy', self.class, method, self, :outer, :nothing], [:c_call, 7, "xyzzy", Class, :inherited, Object, :outer, :nothing], @@ -512,8 +510,6 @@ class TestSetTraceFunc < Test::Unit::TestCase [:call, 13, "xyzzy", xyzzy.class, :bar, xyzzy, nil, :nothing], [:line, 14, "xyzzy", xyzzy.class, :bar, xyzzy, nil, :nothing], [:line, 15, "xyzzy", xyzzy.class, :bar, xyzzy, :XYZZY_bar, :nothing], - [:c_call, 15, "xyzzy", Kernel, :tap, xyzzy, :XYZZY_bar, :nothing], - [:c_return,15, "xyzzy", Kernel, :tap, xyzzy, :XYZZY_bar, xyzzy], [:return, 16, "xyzzy", xyzzy.class, :bar, xyzzy, :XYZZY_bar, xyzzy], [:return, 12, "xyzzy", xyzzy.class, :foo, xyzzy, :XYZZY_foo, xyzzy], [:line, 20, "xyzzy", TestSetTraceFunc, method, self, :outer, :nothing], @@ -610,8 +606,6 @@ class TestSetTraceFunc < Test::Unit::TestCase [:c_call, 4, 'xyzzy', Integer, :times, 1, :outer, :nothing], [:line, 4, 'xyzzy', self.class, method, self, nil, :nothing], [:line, 5, 'xyzzy', self.class, method, self, :inner, :nothing], - [:c_call, 5, 'xyzzy', Kernel, :tap, self, :inner, :nothing], - [:c_return, 5, "xyzzy", Kernel, :tap, self, :inner, self], [:c_return, 4, "xyzzy", Integer, :times, 1, :outer, 1], [:line, 7, 'xyzzy', self.class, method, self, :outer, :nothing], [:c_call, 7, "xyzzy", Class, :inherited, Object, :outer, :nothing], @@ -637,8 +631,6 @@ class TestSetTraceFunc < Test::Unit::TestCase [:call, 13, "xyzzy", xyzzy.class, :bar, xyzzy, nil, :nothing], [:line, 14, "xyzzy", xyzzy.class, :bar, xyzzy, nil, :nothing], [:line, 15, "xyzzy", xyzzy.class, :bar, xyzzy, :XYZZY_bar, :nothing], - [:c_call, 15, "xyzzy", Kernel, :tap, xyzzy, :XYZZY_bar, :nothing], - [:c_return,15, "xyzzy", Kernel, :tap, xyzzy, :XYZZY_bar, xyzzy], [:return, 16, "xyzzy", xyzzy.class, :bar, xyzzy, :XYZZY_bar, xyzzy], [:return, 12, "xyzzy", xyzzy.class, :foo, xyzzy, :XYZZY_foo, xyzzy], [:line, 20, "xyzzy", TestSetTraceFunc, method, self, :outer, :nothing], @@ -1685,7 +1677,7 @@ class TestSetTraceFunc < Test::Unit::TestCase TracePoint.new(:return, &capture_events).enable{ o.alias_m } - assert_equal [[:return, :m, :alias_m]], events + assert_equal [[:return, :tap, :tap], [:return, :m, :alias_m]], events events.clear o = Class.new{ @@ -1709,13 +1701,13 @@ class TestSetTraceFunc < Test::Unit::TestCase events.clear o = Class.new{ - alias alias_tap tap - define_method(:m){alias_tap{return}} + alias alias_singleton_class singleton_class + define_method(:m){alias_singleton_class} }.new TracePoint.new(:c_return, &capture_events).enable{ o.m } - assert_equal [[:c_return, :tap, :alias_tap]], events + assert_equal [[:c_return, :singleton_class, :alias_singleton_class]], events events.clear c = Class.new{ |