Feature #10326 » 0001-optimize-recv-literal-string.patch
| benchmark/bm_vm2_strcat.rb | ||
|---|---|---|
|
i = 0
|
||
|
str = ""
|
||
|
while i<6_000_000 # benchmark loop 2
|
||
|
i += 1
|
||
|
str << "const"
|
||
|
str.clear
|
||
|
end
|
||
| compile.c | ||
|---|---|---|
|
}
|
||
|
break;
|
||
|
}
|
||
|
/* optimization shortcut
|
||
|
* obj << "literal" -> opt_strcat_with(obj, "literal")
|
||
|
*/
|
||
|
if (node->nd_mid == idLTLT && !private_recv_p(node) && node->nd_args &&
|
||
|
nd_type(node->nd_args) == NODE_ARRAY &&
|
||
|
node->nd_args->nd_alen == 1 &&
|
||
|
nd_type(node->nd_args->nd_head) == NODE_STR)
|
||
|
{
|
||
|
VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit);
|
||
|
node->nd_args->nd_head->nd_lit = str;
|
||
|
COMPILE(ret, "recv", node->nd_recv);
|
||
|
ADD_INSN2(ret, line, opt_strcat_with,
|
||
|
new_callinfo(iseq, idLTLT, 1, 0, 0), str);
|
||
|
if (poped) {
|
||
|
ADD_INSN(ret, line, pop);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case NODE_FCALL:
|
||
|
case NODE_VCALL:{ /* VCALL: variable or call */
|
||
|
/*
|
||
| insns.def | ||
|---|---|---|
|
/**
|
||
|
@c optimize
|
||
|
@e recv << "literal string"
|
||
|
*/
|
||
|
DEFINE_INSN
|
||
|
opt_strcat_with
|
||
|
(CALL_INFO ci, VALUE lit)
|
||
|
(VALUE recv)
|
||
|
(VALUE val)
|
||
|
{
|
||
|
if (!SPECIAL_CONST_P(recv) && RBASIC_CLASS(recv) == rb_cString &&
|
||
|
BASIC_OP_UNREDEFINED_P(BOP_LTLT, STRING_REDEFINED_OP_FLAG)) {
|
||
|
val = rb_str_concat(recv, lit);
|
||
|
}
|
||
|
else {
|
||
|
PUSH(recv);
|
||
|
PUSH(rb_str_resurrect(lit));
|
||
|
CALL_SIMPLE_METHOD(recv);
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
@c optimize
|
||
|
@e optimized length
|
||
|
@j 最適化された recv.length()。
|
||
|
*/
|
||
| test/ruby/test_string.rb | ||
|---|---|---|
|
end
|
||
|
end;
|
||
|
end
|
||
|
def test_opt_strcat_with
|
||
|
assert_separately([], <<-RUBY)
|
||
|
class String
|
||
|
undef <<
|
||
|
def <<(str)
|
||
|
"overridden"
|
||
|
end
|
||
|
end
|
||
|
assert_equal("overridden", "" << "foo")
|
||
|
foo = "foo"
|
||
|
assert_equal("overridden", foo << "bar")
|
||
|
RUBY
|
||
|
if @cls == String
|
||
|
nr = 10
|
||
|
recv = ""
|
||
|
before = GC.stat(:total_allocated_objects)
|
||
|
nr.times { recv << "constant" }
|
||
|
assert_equal before, GC.stat(:total_allocated_objects)
|
||
|
assert_equal "constant" * nr, recv
|
||
|
before = GC.stat(:total_allocated_objects)
|
||
|
nr.times { "recv" << "constant" }
|
||
|
assert_equal before + nr, GC.stat(:total_allocated_objects)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
class TestString2 < TestString
|
||
|
-
|
||