seafoam 0.13 → 0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/bgv2isabelle +3 -2
- data/bin/bgv2json +3 -2
- data/bin/seafoam +3 -2
- data/lib/seafoam/bgv/bgv_parser.rb +58 -50
- data/lib/seafoam/binary/io_binary_reader.rb +19 -17
- data/lib/seafoam/colors.rb +17 -11
- data/lib/seafoam/commands.rb +177 -153
- data/lib/seafoam/formatters/base.rb +2 -0
- data/lib/seafoam/formatters/formatters.rb +5 -3
- data/lib/seafoam/formatters/json.rb +8 -5
- data/lib/seafoam/formatters/text.rb +7 -4
- data/lib/seafoam/graal/graph_description.rb +9 -1
- data/lib/seafoam/graal/pi.rb +10 -6
- data/lib/seafoam/graal/source.rb +13 -9
- data/lib/seafoam/graph.rb +15 -9
- data/lib/seafoam/graphviz_writer.rb +129 -99
- data/lib/seafoam/isabelle_writer.rb +9 -7
- data/lib/seafoam/json_writer.rb +17 -13
- data/lib/seafoam/markdown_writer.rb +5 -3
- data/lib/seafoam/mermaid_writer.rb +36 -24
- data/lib/seafoam/passes/fallback.rb +10 -6
- data/lib/seafoam/passes/graal.rb +189 -161
- data/lib/seafoam/passes/truffle.rb +120 -22
- data/lib/seafoam/passes.rb +36 -29
- data/lib/seafoam/spotlight.rb +4 -2
- data/lib/seafoam/version.rb +3 -1
- data/lib/seafoam.rb +22 -20
- metadata +12 -12
data/lib/seafoam/passes/graal.rb
CHANGED
@@ -1,22 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Seafoam
|
2
4
|
module Passes
|
3
5
|
# The Graal pass applies if it looks like it was compiled by Graal or
|
4
6
|
# Truffle.
|
5
7
|
class GraalPass < Pass
|
6
|
-
|
7
|
-
graph
|
8
|
-
|
8
|
+
class << self
|
9
|
+
def applies?(graph)
|
10
|
+
graph.props.values.any? do |v|
|
11
|
+
TRIGGERS.any? { |t| v.to_s.include?(t) }
|
12
|
+
end
|
9
13
|
end
|
10
14
|
end
|
11
15
|
|
12
16
|
def apply(graph)
|
13
|
-
apply_nodes
|
14
|
-
apply_edges
|
15
|
-
hide_frame_state
|
16
|
-
hide_pi
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
apply_nodes(graph)
|
18
|
+
apply_edges(graph)
|
19
|
+
hide_frame_state(graph) if @options[:hide_frame_state]
|
20
|
+
hide_pi(graph) if @options[:hide_pi]
|
21
|
+
hide_begin_end(graph) if @options[:hide_begin_end]
|
22
|
+
hide_floating(graph) if @options[:hide_floating]
|
23
|
+
reduce_edges(graph) if @options[:reduce_edges]
|
24
|
+
hide_unused_nodes(graph)
|
20
25
|
end
|
21
26
|
|
22
27
|
private
|
@@ -27,7 +32,7 @@ module Seafoam
|
|
27
32
|
next if node.props[:label]
|
28
33
|
|
29
34
|
# The Java class of the node.
|
30
|
-
node_class = node.
|
35
|
+
node_class = node.node_class
|
31
36
|
|
32
37
|
# IGV renders labels using a template, with parts that are replaced
|
33
38
|
# with other properties. We will modify these templates in some
|
@@ -37,90 +42,88 @@ module Seafoam
|
|
37
42
|
# For constant nodes, the rawvalue is a truncated version of the
|
38
43
|
# actual value, which is fully qualified. Instead, produce a simple
|
39
44
|
# version of the value and don't truncate it.
|
40
|
-
if node_class ==
|
41
|
-
if node.props[
|
42
|
-
node.props[
|
45
|
+
if node_class == "org.graalvm.compiler.nodes.ConstantNode"
|
46
|
+
if node.props["value"] =~ /Object\[Instance<(\w+\.)+(\w*)>\]/
|
47
|
+
node.props["rawvalue"] = "instance:#{Regexp.last_match(2)}"
|
43
48
|
end
|
44
|
-
name_template =
|
49
|
+
name_template = "C({p#rawvalue})"
|
45
50
|
end
|
46
51
|
|
47
52
|
# The template for FixedGuardNode could be simpler.
|
48
|
-
if
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
else
|
55
|
-
'Guard, else {p#reason/s}'
|
56
|
-
end
|
53
|
+
if ["org.graalvm.compiler.nodes.FixedGuardNode", "org.graalvm.compiler.nodes.GuardNode"].include?(node_class)
|
54
|
+
name_template = if node.props["negated"]
|
55
|
+
"Guard not, else {p#reason/s}"
|
56
|
+
else
|
57
|
+
"Guard, else {p#reason/s}"
|
58
|
+
end
|
57
59
|
end
|
58
60
|
|
59
61
|
# The template for InvokeNode could be simpler.
|
60
|
-
if node_class ==
|
61
|
-
name_template =
|
62
|
+
if node_class == "org.graalvm.compiler.nodes.InvokeNode"
|
63
|
+
name_template = "Call {p#targetMethod/s}"
|
62
64
|
end
|
63
65
|
|
64
66
|
# The template for InvokeWithExceptionNode could be simpler.
|
65
|
-
if node_class ==
|
66
|
-
name_template =
|
67
|
+
if node_class == "org.graalvm.compiler.nodes.InvokeWithExceptionNode"
|
68
|
+
name_template = "Call {p#targetMethod/s} !"
|
67
69
|
end
|
68
70
|
|
69
71
|
# The template for CommitAllocationNode could be simpler.
|
70
|
-
if node_class ==
|
71
|
-
name_template =
|
72
|
+
if node_class == "org.graalvm.compiler.nodes.virtual.CommitAllocationNode"
|
73
|
+
name_template = "Alloc"
|
72
74
|
end
|
73
75
|
|
74
|
-
# The template for org.graalvm.compiler.nodes.virtual.VirtualArrayNode
|
75
|
-
|
76
|
-
|
76
|
+
# The template for org.graalvm.compiler.nodes.virtual.VirtualArrayNode
|
77
|
+
# includes an ID that we don't normally need.
|
78
|
+
if node_class == "org.graalvm.compiler.nodes.virtual.VirtualArrayNode"
|
79
|
+
name_template = "VirtualArray {p#componentType/s}[{p#length}]"
|
77
80
|
end
|
78
81
|
|
79
82
|
# The template for LoadField could be simpler.
|
80
|
-
if node_class ==
|
81
|
-
name_template =
|
83
|
+
if node_class == "org.graalvm.compiler.nodes.java.LoadFieldNode"
|
84
|
+
name_template = "LoadField {x#field}"
|
82
85
|
end
|
83
86
|
|
84
87
|
# The template for StoreField could be simpler.
|
85
|
-
if node_class ==
|
86
|
-
name_template =
|
88
|
+
if node_class == "org.graalvm.compiler.nodes.java.StoreFieldNode"
|
89
|
+
name_template = "StoreField {x#field}"
|
87
90
|
end
|
88
91
|
|
89
92
|
# We want to see keys for IntegerSwitchNode.
|
90
|
-
if node_class ==
|
91
|
-
name_template =
|
93
|
+
if node_class == "org.graalvm.compiler.nodes.extended.IntegerSwitchNode"
|
94
|
+
name_template = "IntegerSwitch {p#keys}"
|
92
95
|
end
|
93
96
|
|
94
97
|
# Use a symbol for PiNode.
|
95
|
-
if node_class ==
|
96
|
-
name_template =
|
98
|
+
if node_class == "org.graalvm.compiler.nodes.PiNode"
|
99
|
+
name_template = "π"
|
97
100
|
end
|
98
101
|
|
99
102
|
# Use a symbol for PiArrayNode.
|
100
|
-
if node_class ==
|
101
|
-
name_template =
|
103
|
+
if node_class == "org.graalvm.compiler.nodes.PiArrayNode"
|
104
|
+
name_template = "[π]"
|
102
105
|
end
|
103
106
|
|
104
107
|
# Use a symbol for PhiNode.
|
105
|
-
if node_class ==
|
106
|
-
name_template =
|
108
|
+
if node_class == "org.graalvm.compiler.nodes.ValuePhiNode"
|
109
|
+
name_template = "ϕ"
|
107
110
|
end
|
108
111
|
|
109
112
|
# Better template for frame states.
|
110
|
-
if node_class ==
|
111
|
-
name_template =
|
113
|
+
if node_class == "org.graalvm.compiler.nodes.FrameState"
|
114
|
+
name_template = "FrameState {x#state}"
|
112
115
|
end
|
113
116
|
|
114
117
|
# Show the stamp in an InstanceOfNode.
|
115
|
-
if node_class ==
|
116
|
-
name_template =
|
118
|
+
if node_class == "org.graalvm.compiler.nodes.java.InstanceOfNode"
|
119
|
+
name_template = "InstanceOf {x#simpleStamp}"
|
117
120
|
end
|
118
121
|
|
119
122
|
if name_template.empty?
|
120
123
|
# If there is no template, then the label is the short name of the
|
121
124
|
# Java class, without '...Node' because that's redundant.
|
122
|
-
short_name = node_class.split(
|
123
|
-
short_name = short_name.slice(0, short_name.size -
|
125
|
+
short_name = node_class.split(".").last
|
126
|
+
short_name = short_name.slice(0, short_name.size - "Node".size) if short_name.end_with?("Node")
|
124
127
|
label = short_name
|
125
128
|
else
|
126
129
|
# Render the template.
|
@@ -128,7 +131,7 @@ module Seafoam
|
|
128
131
|
end
|
129
132
|
|
130
133
|
# Annotate interesting stamps.
|
131
|
-
if node.props[
|
134
|
+
if node.props["stamp"] =~ /(\[\d+ \- \d+\])/
|
132
135
|
node.props[:out_annotation] = Regexp.last_match(1)
|
133
136
|
end
|
134
137
|
|
@@ -136,11 +139,11 @@ module Seafoam
|
|
136
139
|
node.props[:label] = label
|
137
140
|
|
138
141
|
# Set the :kind property.
|
139
|
-
if node_class.start_with?(
|
140
|
-
|
141
|
-
|
142
|
+
kind = if node_class.start_with?("org.graalvm.compiler.nodes.calc.") ||
|
143
|
+
node_class.start_with?("org.graalvm.compiler.replacements.nodes.arithmetic.")
|
144
|
+
"calc"
|
142
145
|
else
|
143
|
-
|
146
|
+
NODE_KIND_MAP[node_class] || "other"
|
144
147
|
end
|
145
148
|
node.props[:kind] = kind
|
146
149
|
end
|
@@ -148,50 +151,49 @@ module Seafoam
|
|
148
151
|
|
149
152
|
# Map of node classes to their kind.
|
150
153
|
NODE_KIND_MAP = {
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
# org.graalvm.compiler.word.WordCastNode is not an effect even though it is fixed.
|
154
|
+
"org.graalvm.compiler.nodes.BeginNode" => "control",
|
155
|
+
"org.graalvm.compiler.nodes.ConstantNode" => "input",
|
156
|
+
"org.graalvm.compiler.nodes.DeoptimizeNode" => "control",
|
157
|
+
"org.graalvm.compiler.nodes.EndNode" => "control",
|
158
|
+
"org.graalvm.compiler.nodes.extended.IntegerSwitchNode" => "control",
|
159
|
+
"org.graalvm.compiler.nodes.extended.UnsafeMemoryLoadNode" => "memory",
|
160
|
+
"org.graalvm.compiler.nodes.extended.UnsafeMemoryStoreNode" => "memory",
|
161
|
+
"org.graalvm.compiler.nodes.FixedGuardNode" => "guard",
|
162
|
+
"org.graalvm.compiler.nodes.FrameState" => "info",
|
163
|
+
"org.graalvm.compiler.nodes.GuardNode" => "guard",
|
164
|
+
"org.graalvm.compiler.nodes.IfNode" => "control",
|
165
|
+
"org.graalvm.compiler.nodes.InvokeNode" => "call",
|
166
|
+
"org.graalvm.compiler.nodes.InvokeWithExceptionNode" => "call",
|
167
|
+
"org.graalvm.compiler.nodes.java.ArrayLengthNode" => "memory",
|
168
|
+
"org.graalvm.compiler.nodes.java.LoadFieldNode" => "memory",
|
169
|
+
"org.graalvm.compiler.nodes.java.LoadIndexedNode" => "memory",
|
170
|
+
"org.graalvm.compiler.nodes.java.MonitorEnterNode" => "sync",
|
171
|
+
"org.graalvm.compiler.nodes.java.MonitorExitNode" => "sync",
|
172
|
+
"org.graalvm.compiler.nodes.java.NewArrayNode" => "alloc",
|
173
|
+
"org.graalvm.compiler.nodes.java.NewInstanceNode" => "alloc",
|
174
|
+
"org.graalvm.compiler.nodes.java.RawMonitorEnterNode" => "sync",
|
175
|
+
"org.graalvm.compiler.nodes.java.StoreFieldNode" => "memory",
|
176
|
+
"org.graalvm.compiler.nodes.java.StoreIndexedNode" => "memory",
|
177
|
+
"org.graalvm.compiler.nodes.KillingBeginNode" => "control",
|
178
|
+
"org.graalvm.compiler.nodes.LoopBeginNode" => "control",
|
179
|
+
"org.graalvm.compiler.nodes.LoopEndNode" => "control",
|
180
|
+
"org.graalvm.compiler.nodes.LoopExitNode" => "control",
|
181
|
+
"org.graalvm.compiler.nodes.memory.ReadNode" => "memory",
|
182
|
+
"org.graalvm.compiler.nodes.memory.WriteNode" => "memory",
|
183
|
+
"org.graalvm.compiler.nodes.MergeNode" => "control",
|
184
|
+
"org.graalvm.compiler.nodes.ParameterNode" => "input",
|
185
|
+
"org.graalvm.compiler.nodes.PrefetchAllocateNode" => "alloc",
|
186
|
+
"org.graalvm.compiler.nodes.ReturnNode" => "control",
|
187
|
+
"org.graalvm.compiler.nodes.StartNode" => "control",
|
188
|
+
"org.graalvm.compiler.nodes.UnwindNode" => "control",
|
189
|
+
"org.graalvm.compiler.nodes.virtual.AllocatedObjectNode" => "virtual",
|
190
|
+
"org.graalvm.compiler.nodes.virtual.CommitAllocationNode" => "alloc",
|
191
|
+
"org.graalvm.compiler.nodes.virtual.VirtualArrayNode" => "virtual",
|
192
|
+
"org.graalvm.compiler.nodes.VirtualObjectState" => "info",
|
193
|
+
"org.graalvm.compiler.replacements.nodes.ArrayEqualsNode" => "memory",
|
194
|
+
"org.graalvm.compiler.replacements.nodes.ReadRegisterNode" => "memory",
|
195
|
+
"org.graalvm.compiler.replacements.nodes.WriteRegisterNode" => "memory",
|
196
|
+
"org.graalvm.compiler.word.WordCastNode" => "memory",
|
195
197
|
}
|
196
198
|
|
197
199
|
# Render a Graal 'name template'.
|
@@ -201,11 +203,21 @@ module Seafoam
|
|
201
203
|
# probably need to do these replacements in one pass...
|
202
204
|
string = template
|
203
205
|
string = string.gsub(%r{\{p#(\w+)(/s)?\}}) { |_| node.props[Regexp.last_match(1)] }
|
204
|
-
string = string.gsub(%r{\{i#(\w+)(/s)?\}})
|
205
|
-
|
206
|
-
|
206
|
+
string = string.gsub(%r{\{i#(\w+)(/s)?\}}) do |_|
|
207
|
+
node.inputs.select do |e|
|
208
|
+
e.props[:name] == Regexp.last_match(1)
|
209
|
+
end.map { |e| e.from.id }.join(", ")
|
210
|
+
end
|
211
|
+
string = string.gsub(/\{x#field\}/) do |_|
|
212
|
+
"#{node.props.dig("field", :field_class).split(".").last}.#{node.props.dig("field", :name)}"
|
213
|
+
end
|
214
|
+
string = string.gsub(/\{x#state\}/) do |_|
|
215
|
+
"#{node.props.dig("code",
|
216
|
+
:declaring_class)}##{node.props.dig("code",
|
217
|
+
:method_name)} #{node.props["sourceFile"]}:#{node.props["sourceLine"]}"
|
218
|
+
end
|
207
219
|
string = string.gsub(/\{x#simpleStamp\}/) do |_|
|
208
|
-
stamp = node.props.dig(
|
220
|
+
stamp = node.props.dig("checkedStamp")
|
209
221
|
if stamp =~ /a!?# L(.*);/
|
210
222
|
Regexp.last_match(1)
|
211
223
|
else
|
@@ -218,14 +230,17 @@ module Seafoam
|
|
218
230
|
# Annotate edges with their label and kind.
|
219
231
|
def apply_edges(graph)
|
220
232
|
graph.edges.each do |edge|
|
221
|
-
if edge.to.
|
222
|
-
merge_node = edge.to.edges.find { |e| e.props[:name] ==
|
223
|
-
control_into_merge =
|
224
|
-
merge_node_control_edges_in = merge_node.edges.select
|
233
|
+
if edge.to.node_class == "org.graalvm.compiler.nodes.ValuePhiNode" && edge.props[:name] == "values"
|
234
|
+
merge_node = edge.to.edges.find { |e| e.props[:name] == "merge" }.from
|
235
|
+
control_into_merge = ["ends", "loopBegin"]
|
236
|
+
merge_node_control_edges_in = merge_node.edges.select do |e|
|
237
|
+
exit_node = "org.graalvm.compiler.nodes.LoopExitNode"
|
238
|
+
control_into_merge.include?(e.props[:name]) && e.to.node_class != exit_node
|
239
|
+
end
|
225
240
|
matching_control_edge = merge_node_control_edges_in[edge.props[:index]]
|
226
241
|
control_in_node = matching_control_edge.nodes.find { |n| n != merge_node }
|
227
242
|
edge.props[:label] = "from #{control_in_node.id}"
|
228
|
-
edge.props[:kind] =
|
243
|
+
edge.props[:kind] = "data"
|
229
244
|
next
|
230
245
|
end
|
231
246
|
|
@@ -233,74 +248,74 @@ module Seafoam
|
|
233
248
|
case edge.props[:name]
|
234
249
|
|
235
250
|
# Control edges.
|
236
|
-
when
|
237
|
-
edge.props[:kind] =
|
251
|
+
when "ends", "next", "trueSuccessor", "falseSuccessor", "exceptionEdge"
|
252
|
+
edge.props[:kind] = "control"
|
238
253
|
case edge.props[:name]
|
239
|
-
when
|
254
|
+
when "trueSuccessor"
|
240
255
|
# Simplify trueSuccessor to T
|
241
|
-
edge.props[:label] =
|
242
|
-
when
|
256
|
+
edge.props[:label] = "T"
|
257
|
+
when "falseSuccessor"
|
243
258
|
# Simplify falseSuccessor to F
|
244
|
-
edge.props[:label] =
|
245
|
-
when
|
259
|
+
edge.props[:label] = "F"
|
260
|
+
when "exceptionEdge"
|
246
261
|
# Simplify exceptionEdge to unwind
|
247
|
-
edge.props[:label] =
|
262
|
+
edge.props[:label] = "unwind"
|
248
263
|
end
|
249
264
|
|
250
265
|
# Info edges, which are drawn reversed as they point from the user
|
251
266
|
# to the info.
|
252
|
-
when
|
267
|
+
when "frameState", "callTarget", "stateAfter"
|
253
268
|
edge.props[:label] = nil
|
254
|
-
edge.props[:kind] =
|
269
|
+
edge.props[:kind] = "info"
|
255
270
|
edge.props[:reverse] = true
|
256
271
|
|
257
272
|
# Condition for branches, which we label as ?.
|
258
|
-
when
|
259
|
-
edge.props[:kind] =
|
260
|
-
edge.props[:label] =
|
273
|
+
when "condition"
|
274
|
+
edge.props[:kind] = "data"
|
275
|
+
edge.props[:label] = "?"
|
261
276
|
|
262
277
|
# loopBegin edges point from LoopEndNode (continue) and LoopExitNode
|
263
278
|
# (break) to the LoopBeginNode. Both are drawn reversed.
|
264
|
-
when
|
265
|
-
case edge.to.
|
266
|
-
when
|
279
|
+
when "loopBegin"
|
280
|
+
case edge.to.node_class
|
281
|
+
when "org.graalvm.compiler.nodes.LoopEndNode"
|
267
282
|
# If it's from the LoopEnd then it's the control edge to follow.
|
268
|
-
edge.props[:kind] =
|
283
|
+
edge.props[:kind] = "loop"
|
269
284
|
edge.props[:reverse] = true
|
270
|
-
when
|
285
|
+
when "org.graalvm.compiler.nodes.LoopExitNode"
|
271
286
|
# If it's from the LoopExit then it's just for information - it's
|
272
287
|
# not control flow to follow.
|
273
|
-
edge.props[:kind] =
|
288
|
+
edge.props[:kind] = "info"
|
274
289
|
edge.props[:reverse] = true
|
275
290
|
else
|
276
|
-
raise EncodingError,
|
291
|
+
raise EncodingError, "loopBegin edge not to LoopEnd or LoopExit"
|
277
292
|
end
|
278
293
|
|
279
294
|
# Merges are info.
|
280
|
-
when
|
281
|
-
edge.props[:kind] =
|
295
|
+
when "merge"
|
296
|
+
edge.props[:kind] = "info"
|
282
297
|
edge.props[:reverse] = true
|
283
298
|
|
284
299
|
# Successors are control from a switch.
|
285
|
-
when
|
300
|
+
when "successors"
|
286
301
|
# We want to label the edges with the corresponding index of the key.
|
287
|
-
if edge.props[:index] == edge.from.props[
|
288
|
-
|
302
|
+
label = if edge.props[:index] == edge.from.props["keys"].size
|
303
|
+
"default"
|
289
304
|
else
|
290
|
-
|
305
|
+
"k[#{edge.props[:index]}]"
|
291
306
|
end
|
292
307
|
edge.props[:label] = label
|
293
|
-
edge.props[:kind] =
|
308
|
+
edge.props[:kind] = "control"
|
294
309
|
|
295
310
|
# Successors are control from a switch.
|
296
|
-
when
|
311
|
+
when "arguments"
|
297
312
|
# We want to label the edges with their corresponding argument index.
|
298
313
|
edge.props[:label] = "arg[#{edge.props[:index]}]"
|
299
|
-
edge.props[:kind] =
|
314
|
+
edge.props[:kind] = "data"
|
300
315
|
|
301
316
|
# Everything else is data.
|
302
317
|
else
|
303
|
-
edge.props[:kind] =
|
318
|
+
edge.props[:kind] = "data"
|
304
319
|
edge.props[:label] = edge.props[:name]
|
305
320
|
|
306
321
|
end
|
@@ -311,7 +326,7 @@ module Seafoam
|
|
311
326
|
# useful to look at, and severely clutter the graph.
|
312
327
|
def hide_frame_state(graph)
|
313
328
|
graph.nodes.each_value do |node|
|
314
|
-
if FRAME_STATE_NODES.include?(node.
|
329
|
+
if FRAME_STATE_NODES.include?(node.node_class)
|
315
330
|
node.props[:hidden] = true
|
316
331
|
end
|
317
332
|
end
|
@@ -324,21 +339,41 @@ module Seafoam
|
|
324
339
|
loop do
|
325
340
|
umodified = true
|
326
341
|
graph.edges.each do |edge|
|
327
|
-
next unless Graal::Pi::PI_NODES.include?(edge.from.
|
342
|
+
next unless Graal::Pi::PI_NODES.include?(edge.from.node_class)
|
328
343
|
|
329
344
|
object = Graal::Pi.follow_pi_object(edge.from)
|
330
|
-
graph.create_edge
|
331
|
-
graph.remove_edge
|
345
|
+
graph.create_edge(object, edge.to, edge.props.merge({ synthetic: true }))
|
346
|
+
graph.remove_edge(edge)
|
332
347
|
umodified = false
|
333
348
|
end
|
334
349
|
break if umodified
|
335
350
|
end
|
336
351
|
end
|
337
352
|
|
353
|
+
def hide_begin_end(graph)
|
354
|
+
graph.nodes.each_value do |node|
|
355
|
+
node_class = node.node_class
|
356
|
+
next unless BEGIN_END_NODES.include?(node_class)
|
357
|
+
|
358
|
+
# In mid tier, a BeginNode can have multiple input edges, leave those in the graph
|
359
|
+
next unless (node.inputs.size == 1) && (node.outputs.size == 1)
|
360
|
+
|
361
|
+
input_edge = node.inputs[0]
|
362
|
+
output_edge = node.outputs[0]
|
363
|
+
# The edge above the BeginNode is the interesting one, the edges
|
364
|
+
# after the Begin or before/after the EndNode are pure control flow
|
365
|
+
# and have no extra information
|
366
|
+
preserved_props = input_edge.props
|
367
|
+
graph.create_edge(input_edge.from, output_edge.to, preserved_props)
|
368
|
+
graph.remove_edge(input_edge)
|
369
|
+
graph.remove_edge(output_edge)
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
338
373
|
# Hide floating nodes. This highlights just the control flow backbone.
|
339
374
|
def hide_floating(graph)
|
340
375
|
graph.nodes.each_value do |node|
|
341
|
-
if node.edges.none? { |e| e.props[:kind] ==
|
376
|
+
if node.edges.none? { |e| e.props[:kind] == "control" }
|
342
377
|
node.props[:hidden] = true
|
343
378
|
end
|
344
379
|
end
|
@@ -350,7 +385,7 @@ module Seafoam
|
|
350
385
|
# nodes that are 'simple', like parameters and constants.
|
351
386
|
def reduce_edges(graph)
|
352
387
|
graph.nodes.each_value do |node|
|
353
|
-
if SIMPLE_INPUTS.include?(node.
|
388
|
+
if SIMPLE_INPUTS.include?(node.node_class)
|
354
389
|
node.props[:inlined] = true
|
355
390
|
end
|
356
391
|
end
|
@@ -366,11 +401,11 @@ module Seafoam
|
|
366
401
|
graph.nodes.each_value do |node|
|
367
402
|
# Call trees are like Graal graphs but don't have these edges -
|
368
403
|
# don't hide them.
|
369
|
-
next if node.props[
|
404
|
+
next if node.props["truffleCallees"]
|
370
405
|
|
371
406
|
next unless node.outputs.all? { |edge| edge.to.props[:hidden] || edge.props[:hidden] } &&
|
372
|
-
|
373
|
-
|
407
|
+
node.inputs.none? { |edge| edge.props[:kind] == "control" } &&
|
408
|
+
node.inputs.none? { |edge| edge.props[:name] == "anchor" }
|
374
409
|
|
375
410
|
unless node.props[:hidden]
|
376
411
|
node.props[:hidden] = true
|
@@ -382,23 +417,16 @@ module Seafoam
|
|
382
417
|
end
|
383
418
|
|
384
419
|
# If we see these in the graph properties it's probably a Graal graph.
|
385
|
-
TRIGGERS =
|
386
|
-
HostedGraphBuilderPhase
|
387
|
-
GraalCompiler
|
388
|
-
TruffleCompiler
|
389
|
-
]
|
420
|
+
TRIGGERS = ["HostedGraphBuilderPhase", "GraalCompiler", "TruffleCompiler"]
|
390
421
|
|
391
422
|
# Simple input node classes that may be inlined.
|
392
|
-
SIMPLE_INPUTS =
|
393
|
-
org.graalvm.compiler.nodes.ConstantNode
|
394
|
-
org.graalvm.compiler.nodes.ParameterNode
|
395
|
-
]
|
423
|
+
SIMPLE_INPUTS = ["org.graalvm.compiler.nodes.ConstantNode", "org.graalvm.compiler.nodes.ParameterNode"]
|
396
424
|
|
397
425
|
# Nodes just to maintain frame state.
|
398
|
-
FRAME_STATE_NODES =
|
399
|
-
|
400
|
-
|
401
|
-
]
|
426
|
+
FRAME_STATE_NODES = ["org.graalvm.compiler.nodes.FrameState",
|
427
|
+
"org.graalvm.compiler.virtual.nodes.MaterializedObjectState",]
|
428
|
+
|
429
|
+
BEGIN_END_NODES = ["org.graalvm.compiler.nodes.BeginNode", "org.graalvm.compiler.nodes.EndNode"]
|
402
430
|
end
|
403
431
|
end
|
404
432
|
end
|