@@ -14,6 +14,64 @@ module YARV
14
14
# cfg = SyntaxTree::YARV::ControlFlowGraph.compile(iseq)
15
15
#
16
16
class ControlFlowGraph
17
+ # This is the instruction sequence that this control flow graph
18
+ # corresponds to.
19
+ attr_reader :iseq
20
+
21
+ # This is the list of instructions that this control flow graph contains.
22
+ # It is effectively the same as the list of instructions in the
23
+ # instruction sequence but with line numbers and events filtered out.
24
+ attr_reader :insns
25
+
26
+ # This is the set of basic blocks that this control-flow graph contains.
27
+ attr_reader :blocks
28
+
29
+ def initialize ( iseq , insns , blocks )
30
+ @iseq = iseq
31
+ @insns = insns
32
+ @blocks = blocks
33
+ end
34
+
35
+ def disasm
36
+ fmt = Disassembler . new
37
+ output = StringIO . new
38
+ output . puts "== cfg #{ iseq . name } "
39
+
40
+ blocks . each do |block |
41
+ output . print ( block . id )
42
+
43
+ unless block . predecessors . empty?
44
+ output . print ( " # from: #{ block . predecessors . map ( &:id ) . join ( ", " ) } " )
45
+ end
46
+
47
+ output . puts
48
+
49
+ block . insns . each do |insn |
50
+ output . print ( " " )
51
+ output . puts ( insn . disasm ( fmt ) )
52
+ end
53
+
54
+ successors = block . successors . map ( &:id )
55
+ successors << "leaves" if block . last . leaves?
56
+ output . print ( " # to: #{ successors . join ( ", " ) } " ) unless successors . empty?
57
+
58
+ output . puts
59
+ end
60
+
61
+ output . string
62
+ end
63
+
64
+ # This method is used to verify that the control flow graph is well
65
+ # formed. It does this by checking that each basic block is itself well
66
+ # formed.
67
+ def verify
68
+ blocks . each ( &:verify )
69
+ end
70
+
71
+ def self . compile ( iseq )
72
+ Compiler . new ( iseq ) . compile
73
+ end
74
+
17
75
# This object represents a single basic block, wherein all contained
18
76
# instructions do not branch except for the last one.
19
77
class BasicBlock
@@ -28,19 +86,19 @@ class BasicBlock
28
86
attr_reader :insns
29
87
30
88
# This is an array of basic blocks that are predecessors to this block.
31
- attr_reader :preds
89
+ attr_reader :predecessors
32
90
33
91
# This is an array of basic blocks that are successors to this block.
34
- attr_reader :succs
92
+ attr_reader :successors
35
93
36
94
def initialize ( block_start , insns )
37
95
@id = "block_#{ block_start } "
38
96
39
97
@block_start = block_start
40
98
@insns = insns
41
99
42
- @preds = [ ]
43
- @succs = [ ]
100
+ @predecessors = [ ]
101
+ @successors = [ ]
44
102
end
45
103
46
104
# This method is used to verify that the basic block is well formed. It
@@ -122,81 +180,25 @@ def build_basic_blocks
122
180
end
123
181
end
124
182
125
- # Now we need to connect the blocks by letting them know which blocks
126
- # precede them and which blocks follow them.
183
+ # Connect the blocks by letting them know which blocks precede them and
184
+ # which blocks succeed them.
127
185
def connect_basic_blocks ( blocks )
128
186
blocks . each do |block_start , block |
129
187
insn = block . last
130
188
131
189
if insn . branches? && insn . respond_to? ( :label )
132
- block . succs << blocks . fetch ( labels [ insn . label ] )
190
+ block . successors << blocks . fetch ( labels [ insn . label ] )
133
191
end
134
192
135
193
if ( !insn . branches? && !insn . leaves? ) || insn . falls_through?
136
- block . succs << blocks . fetch ( block_start + block . insns . length )
194
+ block . successors << blocks . fetch ( block_start + block . insns . length )
137
195
end
138
196
139
- block . succs . each { |succ | succ . preds << block }
140
- end
141
- end
142
- end
143
-
144
- # This is the instruction sequence that this control flow graph
145
- # corresponds to.
146
- attr_reader :iseq
147
-
148
- # This is the list of instructions that this control flow graph contains.
149
- # It is effectively the same as the list of instructions in the
150
- # instruction sequence but with line numbers and events filtered out.
151
- attr_reader :insns
152
-
153
- # This is the set of basic blocks that this control-flow graph contains.
154
- attr_reader :blocks
155
-
156
- def initialize ( iseq , insns , blocks )
157
- @iseq = iseq
158
- @insns = insns
159
- @blocks = blocks
160
- end
161
-
162
- def disasm
163
- fmt = Disassembler . new
164
- output = StringIO . new
165
- output . puts "== cfg #{ iseq . name } "
166
-
167
- blocks . each do |block |
168
- output . print ( block . id )
169
-
170
- unless block . preds . empty?
171
- output . print ( " # from: #{ block . preds . map ( &:id ) . join ( ", " ) } " )
172
- end
173
-
174
- output . puts
175
-
176
- block . insns . each do |insn |
177
- output . print ( " " )
178
- output . puts ( insn . disasm ( fmt ) )
197
+ block . successors . each do |successor |
198
+ successor . predecessors << block
199
+ end
179
200
end
180
-
181
- succs = block . succs . map ( &:id )
182
- succs << "leaves" if block . last . leaves?
183
- output . print ( " # to: #{ succs . join ( ", " ) } " ) unless succs . empty?
184
-
185
- output . puts
186
201
end
187
-
188
- output . string
189
- end
190
-
191
- # This method is used to verify that the control flow graph is well
192
- # formed. It does this by checking that each basic block is itself well
193
- # formed.
194
- def verify
195
- blocks . each ( &:verify )
196
- end
197
-
198
- def self . compile ( iseq )
199
- Compiler . new ( iseq ) . compile
200
202
end
201
203
end
202
204
end
0 commit comments