class Rubinius::Coverage::CFG
Attributes
basic_blocks[RW]
call_sites[RW]
code[RW]
enter[RW]
exit[RW]
Public Class Methods
new(code, call_sites)
click to toggle source
# File lib/rubinius/coverage.rb, line 8 def initialize(code, call_sites) @code = code @call_sites = call_sites @basic_blocks = Hash.new { |h, k| h[k] = BasicBlock.new k } end
Public Instance Methods
graph()
click to toggle source
# File lib/rubinius/coverage.rb, line 14 def graph iseq = @code.iseq total = iseq.size i = 0 @enter = BasicBlock.new 0 @enter.left = bb = @basic_blocks[0] @exit = @basic_blocks[total] while i < total opcode = InstructionSet[iseq[i]] if @basic_blocks.has_key? i bb.exit_ip = i-1 bb = bb.left = @basic_blocks[i] else bb.exit_ip = i+opcode.width-1 case opcode.control_flow when :branch bb.left = @basic_blocks[iseq[i+1]] bb.left.exit_ip = total next_bb = @basic_blocks[i+opcode.width] bb.right = next_bb if opcode.name != :goto bb = next_bb when :raise, :return bb.left = @exit bb = @basic_blocks[i+opcode.width] end end i += opcode.width end @basic_blocks.values.each do |bb| # Split if a jump target intersects our range i = bb.enter_ip while i < bb.exit_ip opcode = InstructionSet[iseq[i]] i += opcode.width if @basic_blocks.has_key? i bb.exit_ip = i-1 if opcode.control_flow != :branch bb.left = @basic_blocks[i] bb.right = nil end break end end bb.coverage @code, @call_sites end stack = [@enter] cycles = {} until stack.empty? bb = stack.shift if left = bb.left left.count = bb.count if bb.count > left.count unless cycles.has_key? left stack << left cycles[left] = true end end if right = bb.right right.count = bb.count if bb.count > right.count unless cycles.has_key? right stack << right cycles[right] = true end end end # Flow coverage counts backwards @basic_blocks.values.each do |bb| if bb.count == 0 if (bb.left and bb.left.count > 0) or (bb.right and bb.right.count > 0) bb.count = 1 end end end end