Skip to content

Commit e6820ad

Browse files
committed
A silly optimization attempt
* Hard-coding some methods specific to `nil`, to see how far we can push performance * Add a benchmark yml file to test against, and a new spec verifying `==` is correctly returning true for `nil.respond_to?(:==)`
1 parent 5688434 commit e6820ad

File tree

4 files changed

+65
-6
lines changed

4 files changed

+65
-6
lines changed

benchmark/object_respond_to.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
prelude: |
2+
class Base; def foo; end end
3+
class OneTwentyEight < Base
4+
128.times { include(Module.new) }
5+
end
6+
obj = OneTwentyEight.new
7+
benchmark:
8+
respond_to_false: obj.respond_to?(:bar)
9+
respond_to_true: obj.respond_to?(:foo)
10+
respond_to_nil_false: nil.respond_to?(:bar)
11+
loop_count: 1_000_000
12+

insns.def

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -956,7 +956,9 @@ opt_respond_to
956956
(VALUE val)
957957
{
958958
val = vm_opt_respond_to(recv, mid);
959-
CALL_SIMPLE_METHOD();
959+
if (UNDEF_P(val)) {
960+
CALL_SIMPLE_METHOD();
961+
}
960962
}
961963

962964
DEFINE_INSN

spec/ruby/core/kernel/respond_to_spec.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
@a = KernelSpecs::A.new
77
end
88

9+
it "returns true for checking for `==` on nil" do
10+
nil.respond_to?(:==).should == true
11+
end
12+
913
it "is a public method" do
1014
Kernel.should have_public_instance_method(:respond_to?, false)
1115
end

vm_insnhelper.c

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6133,18 +6133,59 @@ vm_opt_ary_freeze(VALUE ary, int bop, ID id)
61336133
}
61346134
}
61356135

6136+
static struct rb_id_table *method_id_table = NULL;
6137+
61366138
static VALUE
61376139
vm_opt_respond_to(VALUE recv, VALUE mid)
61386140
{
6139-
if (SYMBOL_P(mid)) {
6140-
printf("symbol:");
6141-
} else if (STRING_P(mid)) {
6142-
printf("string:");
6141+
if (method_id_table == NULL) {
6142+
const char *method_names[] = {
6143+
"rationalize", "&", "===", "inspect", "=~", "to_a", "to_s", "to_i", "to_f", "to_r",
6144+
"to_c", "nil?", "pretty_print_cycle", "|", "to_h", "^", "to_json", "to_yaml",
6145+
"pretty_print", "pretty_print_instance_variables", "pretty_print_inspect", "singleton_class",
6146+
"dup", "itself", "methods", "singleton_methods", "protected_methods", "private_methods",
6147+
"public_methods", "instance_variables", "instance_variable_get", "instance_variable_set",
6148+
"instance_variable_defined?", "remove_instance_variable", "instance_of?", "kind_of?",
6149+
"is_a?", "display", "frozen?", "class", "then", "yield_self", "tap", "TypeName",
6150+
"public_send", "extend", "clone", "<=>", "pretty_inspect", "!~", "method", "eql?",
6151+
"respond_to?", "public_method", "singleton_method", "define_singleton_method", "hash",
6152+
"freeze", "object_id", "Namespace", "send", "to_enum", "enum_for", "equal?", "!",
6153+
"__send__", "==", "!=", "__id__", "instance_eval", "instance_exec"
6154+
};
6155+
6156+
size_t method_names_size = sizeof(method_names) / sizeof(method_names[0]);
6157+
method_id_table = rb_id_table_create(method_names_size);
6158+
6159+
for (size_t i = 0; i < method_names_size; i++) {
6160+
ID id = rb_intern(method_names[i]);
6161+
rb_id_table_insert(method_id_table, id, Qtrue);
6162+
}
6163+
}
6164+
if (NIL_P(recv)) {
6165+
ID id = rb_check_id(&mid);
6166+
if (!id) return Qfalse;
6167+
6168+
VALUE val;
6169+
if (rb_id_table_lookup(method_id_table, id, &val)) {
6170+
return Qtrue;
6171+
} else {
6172+
return Qfalse;
6173+
}
61436174
}
6144-
printf("%s\n", rb_builtin_type_name(TYPE(recv)));
6175+
61456176
return Qundef;
61466177
}
61476178

6179+
// static VALUE
6180+
// vm_opt_respond_to(VALUE recv, VALUE mid)
6181+
// {
6182+
// if (NIL_P(recv)) {
6183+
// return Qfalse;
6184+
// }
6185+
6186+
// return Qundef;
6187+
// }
6188+
61486189
static VALUE
61496190
vm_opt_hash_freeze(VALUE hash, int bop, ID id)
61506191
{

0 commit comments

Comments
 (0)