Feature #10333 » 0001-optimize-yoda-literal-string.patch
| benchmark/bm_vm2_streq2.rb | ||
|---|---|---|
|
i = 0
|
||
|
foo = "literal"
|
||
|
while i<6_000_000 # benchmark loop 2
|
||
|
i += 1
|
||
|
"literal" == foo
|
||
|
end
|
||
| compile.c | ||
|---|---|---|
|
}
|
||
|
break;
|
||
|
}
|
||
|
/* TODO: optimization shortcut
|
||
|
/* optimization shortcut
|
||
|
* "yoda" == other -> opt_streq2("yoda", other)
|
||
|
*/
|
||
|
if (node->nd_recv && nd_type(node->nd_recv) == NODE_STR) {
|
||
|
DECL_ANCHOR(args);
|
||
|
unsigned int flag = 0;
|
||
|
VALUE argc;
|
||
|
VALUE yoda = rb_fstring(node->nd_recv->nd_lit);
|
||
|
node->nd_recv->nd_lit = yoda;
|
||
|
INIT_ANCHOR(args);
|
||
|
argc = setup_args(iseq, args, node->nd_args, &flag);
|
||
|
assert(flag == 0 && argc == INT2FIX(1));
|
||
|
ADD_SEQ(ret, args);
|
||
|
ADD_INSN2(ret, line, opt_streq2,
|
||
|
new_callinfo(iseq, node->nd_mid, 1, 0, 0), yoda);
|
||
|
if (poped) {
|
||
|
ADD_INSN(ret, line, pop);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
case NODE_FCALL:
|
||
|
case NODE_VCALL:{ /* VCALL: variable or call */
|
||
| insns.def | ||
|---|---|---|
|
/**
|
||
|
@c optimize
|
||
|
@e "yoda" == other
|
||
|
*/
|
||
|
DEFINE_INSN
|
||
|
opt_streq2
|
||
|
(CALL_INFO ci, VALUE yoda)
|
||
|
(VALUE other)
|
||
|
(VALUE val)
|
||
|
{
|
||
|
if (BASIC_OP_UNREDEFINED_P(BOP_EQ, STRING_REDEFINED_OP_FLAG)) {
|
||
|
val = rb_str_equal(yoda, other);
|
||
|
}
|
||
|
else {
|
||
|
yoda = rb_str_resurrect(yoda);
|
||
|
PUSH(yoda);
|
||
|
PUSH(other);
|
||
|
CALL_SIMPLE_METHOD(yoda);
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
@c optimize
|
||
|
@e optimized length
|
||
|
@j 最適化された recv.length()。
|
||
|
*/
|
||
| test/ruby/test_string.rb | ||
|---|---|---|
|
end
|
||
|
end
|
||
|
def test_opt_streq1
|
||
|
def test_opt_streq
|
||
|
assert_separately([], <<-RUBY)
|
||
|
class String
|
||
|
undef ==
|
||
| ... | ... | |
|
:TROO
|
||
|
end
|
||
|
end
|
||
|
assert_equal(:TROO, ("foo" == "foo"))
|
||
|
foo = "foo"
|
||
|
assert_equal(:TROO, (foo == "foo"), 'opt_streq1')
|
||
|
assert_equal(:TROO, ("foo" == foo), 'opt_streq2')
|
||
|
RUBY
|
||
|
if @cls == String
|
||
| ... | ... | |
|
recv = "something"
|
||
|
res = []
|
||
|
before = GC.stat(:total_allocated_objects)
|
||
|
nr.times { res << (recv == "constant") }
|
||
|
nr.times { res << (recv == "constant") } # opt_streq1
|
||
|
nr.times { res << ("constant" == recv) } # opt_streq2
|
||
|
assert_equal before, GC.stat(:total_allocated_objects)
|
||
|
assert_equal [ false ], res.uniq!
|
||
|
res.clear
|
||
|
before = GC.stat(:total_allocated_objects)
|
||
|
nr.times { res << (recv == "something") }
|
||
|
nr.times { res << (recv == "something") } # opt_streq1
|
||
|
nr.times { res << ("something" == recv) } # opt_streq2
|
||
|
assert_equal before, GC.stat(:total_allocated_objects)
|
||
|
assert_equal [ true ], res.uniq!
|
||
|
end
|
||
|
-
|
||