summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Kokubun <takashikkbn@gmail.com>2020-07-03 18:02:43 -0700
committerGitHub <noreply@github.com>2020-07-03 18:02:43 -0700
commit24fa37d87a24dc932c1d778bcaf91204f5c12a76 (patch)
tree19c661338ecc6b8d5974b80a1ef77a738931cade
parenta69dd699ee630dd1086627dbca15a218a8538b6f (diff)
Make Kernel#then, #yield_self, #frozen? builtin (#3283)
* Make Kernel#then, #yield_self, #frozen? builtin * Fix test_jit
Notes
Notes: Merged-By: k0kubun <takashikkbn@gmail.com>
-rw-r--r--benchmark/kernel_then.yml6
-rw-r--r--benchmark/mjit_kernel.yml (renamed from benchmark/mjit_class.yml)9
-rw-r--r--kernel.rb78
-rw-r--r--object.c55
-rw-r--r--test/ruby/test_jit.rb2
5 files changed, 96 insertions, 54 deletions
diff --git a/benchmark/kernel_then.yml b/benchmark/kernel_then.yml
new file mode 100644
index 0000000000..85f7341e33
--- /dev/null
+++ b/benchmark/kernel_then.yml
@@ -0,0 +1,6 @@
+benchmark:
+ kernel_then: 1.then { |i| i + 1 }
+ kernel_then_enum: 1.then
+ kernel_yield_self: 1.yield_self { |i| i + 1 }
+ kernel_yield_self_enum: 1.yield_self
+loop_count: 20000000
diff --git a/benchmark/mjit_class.yml b/benchmark/mjit_kernel.yml
index 22f95c2d4d..7720e65c2c 100644
--- a/benchmark/mjit_class.yml
+++ b/benchmark/mjit_kernel.yml
@@ -4,8 +4,17 @@ prelude: |
obj.class
end
+ def mjit_frozen?(obj)
+ obj.frozen?
+ end
+
+ str = ""
+ fstr = "".freeze
+
benchmark:
- mjit_class(self)
- mjit_class(1)
+ - mjit_frozen?(str)
+ - mjit_frozen?(fstr)
loop_count: 40000000
diff --git a/kernel.rb b/kernel.rb
index 3404053d84..04a371a7c8 100644
--- a/kernel.rb
+++ b/kernel.rb
@@ -50,6 +50,27 @@ module Kernel
#
# call-seq:
+ # obj.frozen? -> true or false
+ #
+ # Returns the freeze status of <i>obj</i>.
+ #
+ # a = [ "a", "b", "c" ]
+ # a.freeze #=> ["a", "b", "c"]
+ # a.frozen? #=> true
+ #--
+ # Determines if the object is frozen. Equivalent to \c Object\#frozen? in Ruby.
+ # \param[in] obj the object to be determines
+ # \retval Qtrue if frozen
+ # \retval Qfalse if not frozen
+ #++
+ #
+ def frozen?
+ Primitive.attr! 'inline'
+ Primitive.cexpr! 'rb_obj_frozen_p(self)'
+ end
+
+ #
+ # call-seq:
# obj.tap {|x| block } -> obj
#
# Yields self to the block, and then returns self.
@@ -70,6 +91,63 @@ module Kernel
self
end
+ #
+ # call-seq:
+ # obj.then {|x| block } -> an_object
+ #
+ # Yields self to the block and returns the result of the block.
+ #
+ # 3.next.then {|x| x**x }.to_s #=> "256"
+ #
+ # Good usage for +then+ is value piping in method chains:
+ #
+ # require 'open-uri'
+ # require 'json'
+ #
+ # construct_url(arguments).
+ # then {|url| open(url).read }.
+ # then {|response| JSON.parse(response) }
+ #
+ # When called without block, the method returns +Enumerator+,
+ # which can be used, for example, for conditional
+ # circuit-breaking:
+ #
+ # # meets condition, no-op
+ # 1.then.detect(&:odd?) # => 1
+ # # does not meet condition, drop value
+ # 2.then.detect(&:odd?) # => nil
+ #
+ def then
+ unless Primitive.block_given_p
+ return Primitive.cexpr! 'SIZED_ENUMERATOR(self, 0, 0, rb_obj_size)'
+ end
+ yield(self)
+ end
+
+ #
+ # call-seq:
+ # obj.yield_self {|x| block } -> an_object
+ #
+ # Yields self to the block and returns the result of the block.
+ #
+ # "my string".yield_self {|s| s.upcase } #=> "MY STRING"
+ #
+ # Good usage for +then+ is value piping in method chains:
+ #
+ # require 'open-uri'
+ # require 'json'
+ #
+ # construct_url(arguments).
+ # then {|url| open(url).read }.
+ # then {|response| JSON.parse(response) }
+ #
+ def yield_self
+ unless Primitive.block_given_p
+ return Primitive.cexpr! 'SIZED_ENUMERATOR(self, 0, 0, rb_obj_size)'
+ end
+ yield(self)
+ end
+
module_function
#
diff --git a/object.c b/object.c
index 4718fad66f..a684927d10 100644
--- a/object.c
+++ b/object.c
@@ -597,41 +597,10 @@ rb_obj_size(VALUE self, VALUE args, VALUE obj)
return LONG2FIX(1);
}
-/*
- * call-seq:
- * obj.then {|x| block } -> an_object
- * obj.yield_self {|x| block } -> an_object
- *
- * Yields self to the block and returns the result of the block.
- *
- * 3.next.then {|x| x**x }.to_s #=> "256"
- * "my string".yield_self {|s| s.upcase } #=> "MY STRING"
- *
- * Good usage for +then+ is value piping in method chains:
- *
- * require 'open-uri'
- * require 'json'
- *
- * construct_url(arguments).
- * then {|url| open(url).read }.
- * then {|response| JSON.parse(response) }
- *
- * When called without block, the method returns +Enumerator+,
- * which can be used, for example, for conditional
- * circuit-breaking:
- *
- * # meets condition, no-op
- * 1.then.detect(&:odd?) # => 1
- * # does not meet condition, drop value
- * 2.then.detect(&:odd?) # => nil
- *
- */
-
static VALUE
-rb_obj_yield_self(VALUE obj)
+block_given_p(rb_execution_context_t *ec, VALUE self)
{
- RETURN_SIZED_ENUMERATOR(obj, 0, 0, rb_obj_size);
- return rb_yield_values2(1, &obj);
+ return rb_block_given_p() ? Qtrue : Qfalse;
}
/**
@@ -1321,23 +1290,6 @@ rb_obj_freeze(VALUE obj)
return obj;
}
-/**
- * call-seq:
- * obj.frozen? -> true or false
- *
- * Returns the freeze status of <i>obj</i>.
- *
- * a = [ "a", "b", "c" ]
- * a.freeze #=> ["a", "b", "c"]
- * a.frozen? #=> true
- *--
- * Determines if the object is frozen. Equivalent to \c Object\#frozen? in Ruby.
- * \param[in] obj the object to be determines
- * \retval Qtrue if frozen
- * \retval Qfalse if not frozen
- *++
- */
-
VALUE
rb_obj_frozen_p(VALUE obj)
{
@@ -4581,8 +4533,6 @@ InitVM_Object(void)
rb_define_method(rb_mKernel, "singleton_class", rb_obj_singleton_class, 0);
rb_define_method(rb_mKernel, "dup", rb_obj_dup, 0);
rb_define_method(rb_mKernel, "itself", rb_obj_itself, 0);
- rb_define_method(rb_mKernel, "yield_self", rb_obj_yield_self, 0);
- rb_define_method(rb_mKernel, "then", rb_obj_yield_self, 0);
rb_define_method(rb_mKernel, "initialize_copy", rb_obj_init_copy, 1);
rb_define_method(rb_mKernel, "initialize_dup", rb_obj_init_dup_clone, 1);
rb_define_method(rb_mKernel, "initialize_clone", rb_obj_init_clone, -1);
@@ -4594,7 +4544,6 @@ InitVM_Object(void)
rb_define_method(rb_mKernel, "untrusted?", rb_obj_untrusted, 0);
rb_define_method(rb_mKernel, "trust", rb_obj_trust, 0);
rb_define_method(rb_mKernel, "freeze", rb_obj_freeze, 0);
- rb_define_method(rb_mKernel, "frozen?", rb_obj_frozen_p, 0);
rb_define_method(rb_mKernel, "to_s", rb_any_to_s, 0);
rb_define_method(rb_mKernel, "inspect", rb_obj_inspect, 0);
diff --git a/test/ruby/test_jit.rb b/test/ruby/test_jit.rb
index 339bfa2193..f929a8c851 100644
--- a/test/ruby/test_jit.rb
+++ b/test/ruby/test_jit.rb
@@ -372,7 +372,7 @@ class TestJIT < Test::Unit::TestCase
end
def test_compile_insn_send
- assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: '1', success_count: 2, insns: %i[send])
+ assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: '1', success_count: 3, insns: %i[send])
begin;
print proc { yield_self { 1 } }.call
end;