summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Kokubun <takashikkbn@gmail.com>2020-06-20 14:55:09 -0700
committerGitHub <noreply@github.com>2020-06-20 14:55:09 -0700
commit95b0fed3714b87dcb40a16f33d9e3160f9945e38 (patch)
tree100cb67619729fa2b5c306a138599eef6fb11377
parentb68ddcf30ce1dc2788d3bd3d10169726feada1f2 (diff)
Make Integer#zero? a separated method and builtin (#3226)
A prerequisite to fix https://bugs.ruby-lang.org/issues/15589 with JIT. This commit alone doesn't make a significant difference yet, but I thought this commit should be committed independently. This method override was discussed in [Misc #16961].
Notes
Notes: Merged-By: k0kubun <takashikkbn@gmail.com>
-rw-r--r--.document1
-rw-r--r--NEWS.md2
-rw-r--r--benchmark/num_zero_p.yml8
-rw-r--r--common.mk5
-rw-r--r--inits.c1
-rw-r--r--integer.rb9
-rw-r--r--numeric.c24
-rw-r--r--test/ruby/test_jit.rb2
8 files changed, 44 insertions, 8 deletions
diff --git a/.document b/.document
index b18ca80971..0e0969a6d3 100644
--- a/.document
+++ b/.document
@@ -14,6 +14,7 @@ array.rb
ast.rb
dir.rb
gc.rb
+integer.rb
io.rb
kernel.rb
pack.rb
diff --git a/NEWS.md b/NEWS.md
index c69321d507..ac6c6de58b 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -214,6 +214,8 @@ Excluding feature bug fixes.
* The issues of sdbm will handle at https://github.com/ruby/sdbm
+* `Integer#zero?` overrides `Numeric#zero?` for optimization.
+
## Stdlib compatibility issues
Excluding feature bug fixes.
diff --git a/benchmark/num_zero_p.yml b/benchmark/num_zero_p.yml
new file mode 100644
index 0000000000..2195963433
--- /dev/null
+++ b/benchmark/num_zero_p.yml
@@ -0,0 +1,8 @@
+benchmark:
+ - 0.zero?
+ - 1.zero?
+ - 0r.zero?
+ - 1r.zero?
+ - 0i.zero?
+ - 1i.zero?
+loop_count: 50000000
diff --git a/common.mk b/common.mk
index 3a54b0e9e9..7f4e026b3f 100644
--- a/common.mk
+++ b/common.mk
@@ -1008,6 +1008,7 @@ $(srcs_vpath)mjit_compile.inc: $(tooldir)/ruby_vm/views/mjit_compile.inc.erb $(i
BUILTIN_RB_SRCS = \
$(srcdir)/ast.rb \
$(srcdir)/gc.rb \
+ $(srcdir)/integer.rb \
$(srcdir)/io.rb \
$(srcdir)/dir.rb \
$(srcdir)/pack.rb \
@@ -8087,6 +8088,7 @@ miniinit.$(OBJEXT): {$(VPATH)}encoding.h
miniinit.$(OBJEXT): {$(VPATH)}gc.rb
miniinit.$(OBJEXT): {$(VPATH)}gem_prelude.rb
miniinit.$(OBJEXT): {$(VPATH)}id.h
+miniinit.$(OBJEXT): {$(VPATH)}integer.rb
miniinit.$(OBJEXT): {$(VPATH)}intern.h
miniinit.$(OBJEXT): {$(VPATH)}internal.h
miniinit.$(OBJEXT): {$(VPATH)}internal/anyargs.h
@@ -8921,12 +8923,15 @@ numeric.$(OBJEXT): {$(VPATH)}backward/2/r_cast.h
numeric.$(OBJEXT): {$(VPATH)}backward/2/rmodule.h
numeric.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
numeric.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+numeric.$(OBJEXT): {$(VPATH)}builtin.h
numeric.$(OBJEXT): {$(VPATH)}config.h
numeric.$(OBJEXT): {$(VPATH)}constant.h
numeric.$(OBJEXT): {$(VPATH)}defines.h
numeric.$(OBJEXT): {$(VPATH)}encoding.h
numeric.$(OBJEXT): {$(VPATH)}id.h
numeric.$(OBJEXT): {$(VPATH)}id_table.h
+numeric.$(OBJEXT): {$(VPATH)}integer.rb
+numeric.$(OBJEXT): {$(VPATH)}integer.rbinc
numeric.$(OBJEXT): {$(VPATH)}intern.h
numeric.$(OBJEXT): {$(VPATH)}internal.h
numeric.$(OBJEXT): {$(VPATH)}internal/anyargs.h
diff --git a/inits.c b/inits.c
index 4e5d65ab85..ad57b754a4 100644
--- a/inits.c
+++ b/inits.c
@@ -82,6 +82,7 @@ rb_call_builtin_inits(void)
{
#define BUILTIN(n) CALL(builtin_##n)
BUILTIN(gc);
+ BUILTIN(integer);
BUILTIN(io);
BUILTIN(dir);
BUILTIN(ast);
diff --git a/integer.rb b/integer.rb
new file mode 100644
index 0000000000..2fd32ea463
--- /dev/null
+++ b/integer.rb
@@ -0,0 +1,9 @@
+class Integer
+ # call-seq:
+ # int.zero? -> true or false
+ #
+ # Returns +true+ if +num+ has a zero value.
+ def zero?
+ Primitive.cexpr! 'int_zero_p(self);'
+ end
+end
diff --git a/numeric.c b/numeric.c
index 990d792245..76567f835b 100644
--- a/numeric.c
+++ b/numeric.c
@@ -39,6 +39,7 @@
#include "internal/variable.h"
#include "ruby/encoding.h"
#include "ruby/util.h"
+#include "builtin.h"
/* use IEEE 64bit values if not defined */
#ifndef FLT_RADIX
@@ -769,20 +770,27 @@ num_abs(VALUE num)
static VALUE
num_zero_p(VALUE num)
{
+ if (rb_equal(num, INT2FIX(0))) {
+ return Qtrue;
+ }
+ return Qfalse;
+}
+
+static VALUE
+int_zero_p(VALUE num)
+{
if (FIXNUM_P(num)) {
if (FIXNUM_ZERO_P(num)) {
return Qtrue;
}
}
- else if (RB_TYPE_P(num, T_BIGNUM)) {
+ else {
+ assert(RB_TYPE_P(num, T_BIGNUM));
if (rb_bigzero_p(num)) {
/* this should not happen usually */
return Qtrue;
}
}
- else if (rb_equal(num, INT2FIX(0))) {
- return Qtrue;
- }
return Qfalse;
}
@@ -3307,7 +3315,7 @@ static VALUE
int_anybits_p(VALUE num, VALUE mask)
{
mask = rb_to_int(mask);
- return num_zero_p(rb_int_and(num, mask)) ? Qfalse : Qtrue;
+ return int_zero_p(rb_int_and(num, mask)) ? Qfalse : Qtrue;
}
/*
@@ -3321,7 +3329,7 @@ static VALUE
int_nobits_p(VALUE num, VALUE mask)
{
mask = rb_to_int(mask);
- return num_zero_p(rb_int_and(num, mask));
+ return int_zero_p(rb_int_and(num, mask));
}
/*
@@ -4722,7 +4730,7 @@ int_aref1(VALUE num, VALUE arg)
if (!RTEST(num_negative_p(end))) {
if (!excl) end = rb_int_plus(end, INT2FIX(1));
VALUE mask = generate_mask(end);
- if (RTEST(num_zero_p(rb_int_and(num, mask)))) {
+ if (RTEST(int_zero_p(rb_int_and(num, mask)))) {
return INT2FIX(0);
}
else {
@@ -5844,3 +5852,5 @@ rb_float_new(double d)
{
return rb_float_new_inline(d);
}
+
+#include "integer.rbinc"
diff --git a/test/ruby/test_jit.rb b/test/ruby/test_jit.rb
index 97c287f692..0a7089375d 100644
--- a/test/ruby/test_jit.rb
+++ b/test/ruby/test_jit.rb
@@ -980,7 +980,7 @@ class TestJIT < Test::Unit::TestCase
def test_frame_omitted_inlining
assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: "true\ntrue\ntrue\n", success_count: 1, min_calls: 2)
begin;
- class Numeric
+ class Integer
remove_method :zero?
def zero?
self == 0