Class: Furnace::AVM2::Transform::CFGBuild

Inherits:
Object
  • Object
show all
Includes:
Visitor
Defined in:
lib/furnace-avm2/transform/cfg_build.rb

Instance Method Summary collapse

Instance Method Details

#cutoff(cti, targets) ⇒ Object



82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/furnace-avm2/transform/cfg_build.rb', line 82

def cutoff(cti, targets)
  node = CFG::Node.new(@cfg, @pending_label, @pending_queue, cti, targets)

  if @cfg.nodes.empty?
    @cfg.entry = node
  end

  @cfg.nodes.add node

  @pending_label = nil
  @pending_queue = []
end

#on_any(node) ⇒ Object

propagate labels



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/furnace-avm2/transform/cfg_build.rb', line 64

def on_any(node)
  return if node == @ast

  label = nil

  node.children.each do |child|
    if child.is_a?(AST::Node) && child.[:label]
      if label.nil? || child.[:label] < label
        label = child.[:label]
      end

      child..delete :label
    end
  end

  node.[:label] = label if label
end

#transform(ast) ⇒ Object



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/furnace-avm2/transform/cfg_build.rb', line 6

def transform(ast)
  @ast = ast

  @jumps = Set.new

  visit @ast

  @cfg = CFG::Graph.new

  @pending_label = nil
  @pending_queue = []

  @ast.children.each_with_index do |node, index|
    @pending_label ||= node.[:label]
    @pending_queue << node if ![:nop, :jump].include? node.type

    next_node  = @ast.children[index + 1]
    next_label = next_node.[:label] if next_node

    case node.type
    when :label
      @jumps.add node.children.first
      node.update :nop

    when :return_value, :return_void
      cutoff(nil, [nil])

    when :jump
      @jumps.add(node.children[0])
      cutoff(nil, [ node.children.delete_at(0) ])

    when :jump_if
      @jumps.add(node.children[1])
      cutoff(node, [ node.children.delete_at(1), next_label ])

    when :lookup_switch
      jumps_to = [ node.children[0] ] + node.children[1]
      @jumps.merge(jumps_to)
      cutoff(node, jumps_to)

    else
      if @jumps.include? next_label
        cutoff(nil, [next_label])
      end
    end
  end

  exit_node = CFG::Node.new(@cfg)
  @cfg.nodes.add exit_node
  @cfg.exit = exit_node

  @cfg.eliminate_unreachable!
  @cfg.merge_redundant!

  @cfg
end