From 6c3f77255aa49b36f68c43add3864a0b7b6e84f2 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 3 Dec 2015 13:31:15 -0800 Subject: [PATCH] optimize case / when for `nil` --- compile.c | 2 ++ insns.def | 1 + object.c | 1 + test/ruby/test_case.rb | 21 +++++++++++++++++++++ vm.c | 3 ++- vm_core.h | 1 + 6 files changed, 28 insertions(+), 1 deletion(-) diff --git a/compile.c b/compile.c index bb8fe86..f494350 100644 --- a/compile.c +++ b/compile.c @@ -2893,6 +2893,8 @@ case_when_optimizable_literal(NODE * node) } break; } + case NODE_NIL: + return Qnil; case NODE_STR: return node->nd_lit = rb_fstring(node->nd_lit); } diff --git a/insns.def b/insns.def index 36a132b..facb77d 100644 --- a/insns.def +++ b/insns.def @@ -1272,6 +1272,7 @@ opt_case_dispatch SYMBOL_REDEFINED_OP_FLAG | FIXNUM_REDEFINED_OP_FLAG | BIGNUM_REDEFINED_OP_FLAG | + NIL_REDEFINED_OP_FLAG | STRING_REDEFINED_OP_FLAG)) { st_data_t val; if (st_lookup(RHASH_TBL_RAW(hash), key, &val)) { diff --git a/object.c b/object.c index ff2db0b..e2bcf74 100644 --- a/object.c +++ b/object.c @@ -3468,6 +3468,7 @@ InitVM_Object(void) rb_define_method(rb_cNilClass, "&", false_and, 1); rb_define_method(rb_cNilClass, "|", false_or, 1); rb_define_method(rb_cNilClass, "^", false_xor, 1); + rb_define_method(rb_cNilClass, "===", rb_equal, 1); rb_define_method(rb_cNilClass, "nil?", rb_true, 0); rb_undef_alloc_func(rb_cNilClass); diff --git a/test/ruby/test_case.rb b/test/ruby/test_case.rb index f20d1df..b9f8ab2 100644 --- a/test/ruby/test_case.rb +++ b/test/ruby/test_case.rb @@ -121,4 +121,25 @@ def test_nomethoderror end } end + + module NilEqq + refine NilClass do + def === other + false + end + end + end + + class NilEqqClass + using NilEqq + + def eqq(a) + case a; when nil then nil; else :not_nil; end + end + end + + + def test_deoptimize_nil + assert_equal :not_nil, NilEqqClass.new.eqq(nil) + end end diff --git a/vm.c b/vm.c index de8be50..a87b51c 100644 --- a/vm.c +++ b/vm.c @@ -1373,6 +1373,7 @@ vm_redefinition_check_flag(VALUE klass) if (klass == rb_cSymbol) return SYMBOL_REDEFINED_OP_FLAG; if (klass == rb_cTime) return TIME_REDEFINED_OP_FLAG; if (klass == rb_cRegexp) return REGEXP_REDEFINED_OP_FLAG; + if (klass == rb_cNilClass) return NIL_REDEFINED_OP_FLAG; return 0; } @@ -1437,7 +1438,7 @@ vm_init_redefined_flag(void) OP(DIV, DIV), (C(Fixnum), C(Float)); OP(MOD, MOD), (C(Fixnum), C(Float)); OP(Eq, EQ), (C(Fixnum), C(Float), C(String)); - OP(Eqq, EQQ), (C(Fixnum), C(Bignum), C(Float), C(Symbol), C(String)); + OP(Eqq, EQQ), (C(Fixnum), C(Bignum), C(Float), C(Symbol), C(String), C(NilClass)); OP(LT, LT), (C(Fixnum), C(Float)); OP(LE, LE), (C(Fixnum), C(Float)); OP(GT, GT), (C(Fixnum), C(Float)); diff --git a/vm_core.h b/vm_core.h index 2343e11..657e82e 100644 --- a/vm_core.h +++ b/vm_core.h @@ -545,6 +545,7 @@ typedef struct rb_vm_struct { #define SYMBOL_REDEFINED_OP_FLAG (1 << 6) #define TIME_REDEFINED_OP_FLAG (1 << 7) #define REGEXP_REDEFINED_OP_FLAG (1 << 8) +#define NIL_REDEFINED_OP_FLAG (1 << 9) #define BASIC_OP_UNREDEFINED_P(op, klass) (LIKELY((GET_VM()->redefined_flag[(op)]&(klass)) == 0)) -- 2.2.1