class SyntaxTree::YARV::ControlFlowGraph
cfg = SyntaxTree::YARV::ControlFlowGraph.compile(iseq)
iseq = SyntaxTree::YARV::InstructionSequence.from(iseq.to_a)
iseq = RubyVM::InstructionSequence.compile(“1 + 2”)
YARV instruction sequence. It will return a control flow graph object.
You can use this class by calling the ::compile method and passing it a
instructions from the instruction sequence.
It constructs a graph of basic blocks that hold subsets of the list of
This class represents a control flow graph of a YARV instruction sequence.
def self.compile(iseq)
def self.compile(iseq) Compiler.new(iseq).compile end
def disasm
def disasm fmt = Disassembler.new(iseq) fmt.puts("== cfg: #{iseq.inspect}") blocks.each do |block| fmt.puts(block.id) fmt.with_prefix(" ") do |prefix| unless block.incoming_blocks.empty? from = block.incoming_blocks.map(&:id) fmt.puts("#{prefix}== from: #{from.join(", ")}") end fmt.format_insns!(block.insns, block.block_start) to = block.outgoing_blocks.map(&:id) to << "leaves" if block.insns.last.leaves? fmt.puts("#{prefix}== to: #{to.join(", ")}") end end fmt.string end
def initialize(iseq, insns, blocks)
def initialize(iseq, insns, blocks) @iseq = iseq @insns = insns @blocks = blocks end
def to_dfg
def to_dfg DataFlowGraph.compile(self) end
def to_mermaid
def to_mermaid Mermaid.flowchart do |flowchart| disasm = Disassembler::Squished.new blocks.each do |block| flowchart.subgraph(block.id) do previous = nil block.each_with_length do |insn, length| node = flowchart.node( "node_#{length}", "%04d %s" % [length, insn.disasm(disasm)] ) flowchart.link(previous, node) if previous previous = node end end end blocks.each do |block| block.outgoing_blocks.each do |outgoing| offset = block.block_start + block.insns.sum(&:length) - block.insns.last.length from = flowchart.fetch("node_#{offset}") to = flowchart.fetch("node_#{outgoing.block_start}") flowchart.link(from, to) end end end end
def to_son
def to_son to_dfg.to_son end
def verify
formed. It does this by checking that each basic block is itself well
This method is used to verify that the control flow graph is well
def verify blocks.each(&:verify) end