mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
compile.c: optimize method chain
* compile.c (iseq_peephole_optimize): optimize lengthy safe navigation method chain. [Feature #11537] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52237 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
4f9ded5cdd
commit
ae8f8fddb0
3 changed files with 49 additions and 30 deletions
|
@ -1,3 +1,8 @@
|
||||||
|
Fri Oct 23 11:58:21 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
|
* compile.c (iseq_peephole_optimize): optimize lengthy safe
|
||||||
|
navigation method chain. [Feature #11537]
|
||||||
|
|
||||||
Fri Oct 23 10:58:41 2015 Shugo Maeda <shugo@ruby-lang.org>
|
Fri Oct 23 10:58:41 2015 Shugo Maeda <shugo@ruby-lang.org>
|
||||||
|
|
||||||
* lib/matrix/eigenvalue_decomposition.rb (tridiagonalize): fix
|
* lib/matrix/eigenvalue_decomposition.rb (tridiagonalize): fix
|
||||||
|
|
51
compile.c
51
compile.c
|
@ -1967,33 +1967,36 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
|
||||||
* if L2
|
* if L2
|
||||||
*/
|
*/
|
||||||
INSN *nobj = (INSN *)get_destination_insn(iobj);
|
INSN *nobj = (INSN *)get_destination_insn(iobj);
|
||||||
if (nobj->insn_id == BIN(jump)) {
|
INSN *pobj = (INSN *)iobj->link.prev;
|
||||||
OPERAND_AT(iobj, 0) = OPERAND_AT(nobj, 0);
|
int prev_dup = (pobj && pobj->insn_id == BIN(dup));
|
||||||
}
|
|
||||||
|
|
||||||
if (nobj->insn_id == BIN(dup)) {
|
for (;;) {
|
||||||
/*
|
if (nobj->insn_id == BIN(jump)) {
|
||||||
* dup
|
|
||||||
* if L1
|
|
||||||
* ...
|
|
||||||
* L1:
|
|
||||||
* dup
|
|
||||||
* if L2
|
|
||||||
* =>
|
|
||||||
* dup
|
|
||||||
* if L2
|
|
||||||
* ...
|
|
||||||
* L1:
|
|
||||||
* dup
|
|
||||||
* if L2
|
|
||||||
*/
|
|
||||||
INSN *pobj = (INSN *)iobj->link.prev;
|
|
||||||
nobj = (INSN *)nobj->link.next;
|
|
||||||
/* basic blocks, with no labels in the middle */
|
|
||||||
if ((pobj && pobj->insn_id == BIN(dup)) &&
|
|
||||||
(nobj && nobj->insn_id == iobj->insn_id)) {
|
|
||||||
OPERAND_AT(iobj, 0) = OPERAND_AT(nobj, 0);
|
OPERAND_AT(iobj, 0) = OPERAND_AT(nobj, 0);
|
||||||
}
|
}
|
||||||
|
else if (prev_dup && nobj->insn_id == BIN(dup) &&
|
||||||
|
!!(nobj = (INSN *)nobj->link.next) &&
|
||||||
|
/* basic blocks, with no labels in the middle */
|
||||||
|
nobj->insn_id == iobj->insn_id) {
|
||||||
|
/*
|
||||||
|
* dup
|
||||||
|
* if L1
|
||||||
|
* ...
|
||||||
|
* L1:
|
||||||
|
* dup
|
||||||
|
* if L2
|
||||||
|
* =>
|
||||||
|
* dup
|
||||||
|
* if L2
|
||||||
|
* ...
|
||||||
|
* L1:
|
||||||
|
* dup
|
||||||
|
* if L2
|
||||||
|
*/
|
||||||
|
OPERAND_AT(iobj, 0) = OPERAND_AT(nobj, 0);
|
||||||
|
}
|
||||||
|
else break;
|
||||||
|
nobj = (INSN *)get_destination_insn(nobj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,12 @@ class TestISeq < Test::Unit::TestCase
|
||||||
assert_normal_exit('p RubyVM::InstructionSequence.compile("1", "mac", "", 0).to_a', bug5894)
|
assert_normal_exit('p RubyVM::InstructionSequence.compile("1", "mac", "", 0).to_a', bug5894)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def compile(src, line = nil, opt = nil)
|
||||||
|
RubyVM::InstructionSequence.new(src, __FILE__, __FILE__, line, opt)
|
||||||
|
end
|
||||||
|
|
||||||
def lines src
|
def lines src
|
||||||
body = RubyVM::InstructionSequence.new(src).to_a[13]
|
body = compile(src).to_a[13]
|
||||||
body.find_all{|e| e.kind_of? Fixnum}
|
body.find_all{|e| e.kind_of? Fixnum}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -52,7 +56,7 @@ class TestISeq < Test::Unit::TestCase
|
||||||
end if defined?(RubyVM::InstructionSequence.load)
|
end if defined?(RubyVM::InstructionSequence.load)
|
||||||
|
|
||||||
def test_loaded_cdhash_mark
|
def test_loaded_cdhash_mark
|
||||||
iseq = RubyVM::InstructionSequence.compile(<<-'end;', __FILE__, __FILE__, __LINE__+1)
|
iseq = compile(<<-'end;', __LINE__+1)
|
||||||
def bug(kw)
|
def bug(kw)
|
||||||
case kw
|
case kw
|
||||||
when "false" then false
|
when "false" then false
|
||||||
|
@ -73,11 +77,11 @@ class TestISeq < Test::Unit::TestCase
|
||||||
|
|
||||||
def test_disasm_encoding
|
def test_disasm_encoding
|
||||||
src = "\u{3042} = 1; \u{3042}; \u{3043}"
|
src = "\u{3042} = 1; \u{3042}; \u{3043}"
|
||||||
asm = RubyVM::InstructionSequence.compile(src).disasm
|
asm = compile(src).disasm
|
||||||
assert_equal(src.encoding, asm.encoding)
|
assert_equal(src.encoding, asm.encoding)
|
||||||
assert_predicate(asm, :valid_encoding?)
|
assert_predicate(asm, :valid_encoding?)
|
||||||
src.encode!(Encoding::Shift_JIS)
|
src.encode!(Encoding::Shift_JIS)
|
||||||
asm = RubyVM::InstructionSequence.compile(src).disasm
|
asm = compile(src).disasm
|
||||||
assert_equal(src.encoding, asm.encoding)
|
assert_equal(src.encoding, asm.encoding)
|
||||||
assert_predicate(asm, :valid_encoding?)
|
assert_predicate(asm, :valid_encoding?)
|
||||||
end
|
end
|
||||||
|
@ -147,7 +151,7 @@ class TestISeq < Test::Unit::TestCase
|
||||||
|
|
||||||
def test_disable_opt
|
def test_disable_opt
|
||||||
src = "a['foo'] = a['bar']; 'a'.freeze"
|
src = "a['foo'] = a['bar']; 'a'.freeze"
|
||||||
_,_,_,_,_,_,_,_,_,_,_,_,_,body= RubyVM::InstructionSequence.compile(src, __FILE__, __FILE__, __LINE__, false).to_a
|
body= compile(src, __LINE__, false).to_a[13]
|
||||||
body.each{|insn|
|
body.each{|insn|
|
||||||
next unless Array === insn
|
next unless Array === insn
|
||||||
op = insn.first
|
op = insn.first
|
||||||
|
@ -168,11 +172,18 @@ class TestISeq < Test::Unit::TestCase
|
||||||
code = <<-'EOS'
|
code = <<-'EOS'
|
||||||
['foo', 'foo', "#{$f}foo", "#{'foo'}"]
|
['foo', 'foo', "#{$f}foo", "#{'foo'}"]
|
||||||
EOS
|
EOS
|
||||||
s1, s2, s3, s4 = RubyVM::InstructionSequence.compile(code, __FILE__, __FILE__, line, {frozen_string_literal: true}).eval
|
s1, s2, s3, s4 = compile(code, line, {frozen_string_literal: true}).eval
|
||||||
assert_predicate(s1, :frozen?)
|
assert_predicate(s1, :frozen?)
|
||||||
assert_predicate(s2, :frozen?)
|
assert_predicate(s2, :frozen?)
|
||||||
assert_not_predicate(s3, :frozen?)
|
assert_not_predicate(s3, :frozen?)
|
||||||
assert_predicate(s4, :frozen?)
|
assert_predicate(s4, :frozen?)
|
||||||
assert_same(s1, s2)
|
assert_same(s1, s2)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_safe_call_chain
|
||||||
|
src = "a.?a.?a.?a.?a.?a"
|
||||||
|
body = compile(src, __LINE__, {peephole_optimization: true}).to_a[13]
|
||||||
|
labels = body.select {|op, arg| op == :branchnil}.map {|op, arg| arg}
|
||||||
|
assert_equal(1, labels.uniq.size)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue