seafoam 0.13 → 0.15

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- def self.applies?(graph)
7
- graph.props.values.any? do |v|
8
- TRIGGERS.any? { |t| v.to_s.include?(t) }
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 graph
14
- apply_edges graph
15
- hide_frame_state graph if @options[:hide_frame_state]
16
- hide_pi graph if @options[:hide_pi]
17
- hide_floating graph if @options[:hide_floating]
18
- reduce_edges graph if @options[:reduce_edges]
19
- hide_unused_nodes graph
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.props.dig(:node_class, :node_class)
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 == 'org.graalvm.compiler.nodes.ConstantNode'
41
- if node.props['value'] =~ /Object\[Instance<(\w+\.)+(\w*)>\]/
42
- node.props['rawvalue'] = "instance:#{Regexp.last_match(2)}"
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 = 'C({p#rawvalue})'
49
+ name_template = "C({p#rawvalue})"
45
50
  end
46
51
 
47
52
  # The template for FixedGuardNode could be simpler.
48
- if %w[
49
- org.graalvm.compiler.nodes.FixedGuardNode
50
- org.graalvm.compiler.nodes.GuardNode
51
- ].include?(node_class)
52
- name_template = if node.props['negated']
53
- 'Guard not, else {p#reason/s}'
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 == 'org.graalvm.compiler.nodes.InvokeNode'
61
- name_template = 'Call {p#targetMethod/s}'
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 == 'org.graalvm.compiler.nodes.InvokeWithExceptionNode'
66
- name_template = 'Call {p#targetMethod/s} !'
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 == 'org.graalvm.compiler.nodes.virtual.CommitAllocationNode'
71
- name_template = 'Alloc'
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 includes an ID that we don't normally need.
75
- if node_class == 'org.graalvm.compiler.nodes.virtual.VirtualArrayNode'
76
- name_template = 'VirtualArray {p#componentType/s}[{p#length}]'
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 == 'org.graalvm.compiler.nodes.java.LoadFieldNode'
81
- name_template = 'LoadField {x#field}'
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 == 'org.graalvm.compiler.nodes.java.StoreFieldNode'
86
- name_template = 'StoreField {x#field}'
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 == 'org.graalvm.compiler.nodes.extended.IntegerSwitchNode'
91
- name_template = 'IntegerSwitch {p#keys}'
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 == 'org.graalvm.compiler.nodes.PiNode'
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 == 'org.graalvm.compiler.nodes.PiArrayNode'
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 == 'org.graalvm.compiler.nodes.ValuePhiNode'
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 == 'org.graalvm.compiler.nodes.FrameState'
111
- name_template = 'FrameState {x#state}'
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 == 'org.graalvm.compiler.nodes.java.InstanceOfNode'
116
- name_template = 'InstanceOf {x#simpleStamp}'
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('.').last
123
- short_name = short_name.slice(0, short_name.size - 'Node'.size) if short_name.end_with?('Node')
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['stamp'] =~ /(\[\d+ \- \d+\])/
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?('org.graalvm.compiler.nodes.calc.') ||
140
- node_class.start_with?('org.graalvm.compiler.replacements.nodes.arithmetic.')
141
- kind = 'calc'
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
- kind = NODE_KIND_MAP[node_class] || 'other'
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
- 'org.graalvm.compiler.nodes.BeginNode' => 'control',
152
- 'org.graalvm.compiler.nodes.ConstantNode' => 'input',
153
- 'org.graalvm.compiler.nodes.DeoptimizeNode' => 'effect',
154
- 'org.graalvm.compiler.nodes.EndNode' => 'control',
155
- 'org.graalvm.compiler.nodes.extended.IntegerSwitchNode' => 'control',
156
- 'org.graalvm.compiler.nodes.extended.UnsafeMemoryLoadNode' => 'effect',
157
- 'org.graalvm.compiler.nodes.extended.UnsafeMemoryStoreNode' => 'effect',
158
- 'org.graalvm.compiler.nodes.FixedGuardNode' => 'guard',
159
- 'org.graalvm.compiler.nodes.FrameState' => 'info',
160
- 'org.graalvm.compiler.nodes.GuardNode' => 'guard',
161
- 'org.graalvm.compiler.nodes.IfNode' => 'control',
162
- 'org.graalvm.compiler.nodes.InvokeNode' => 'effect',
163
- 'org.graalvm.compiler.nodes.InvokeWithExceptionNode' => 'effect',
164
- 'org.graalvm.compiler.nodes.java.ArrayLengthNode' => 'effect',
165
- 'org.graalvm.compiler.nodes.java.LoadFieldNode' => 'effect',
166
- 'org.graalvm.compiler.nodes.java.LoadIndexedNode' => 'effect',
167
- 'org.graalvm.compiler.nodes.java.MonitorEnterNode' => 'effect',
168
- 'org.graalvm.compiler.nodes.java.MonitorExitNode' => 'effect',
169
- 'org.graalvm.compiler.nodes.java.NewArrayNode' => 'effect',
170
- 'org.graalvm.compiler.nodes.java.NewInstanceNode' => 'effect',
171
- 'org.graalvm.compiler.nodes.java.RawMonitorEnterNode' => 'effect',
172
- 'org.graalvm.compiler.nodes.java.StoreFieldNode' => 'effect',
173
- 'org.graalvm.compiler.nodes.java.StoreIndexedNode' => 'effect',
174
- 'org.graalvm.compiler.nodes.KillingBeginNode' => 'control',
175
- 'org.graalvm.compiler.nodes.LoopBeginNode' => 'control',
176
- 'org.graalvm.compiler.nodes.LoopEndNode' => 'control',
177
- 'org.graalvm.compiler.nodes.LoopExitNode' => 'control',
178
- 'org.graalvm.compiler.nodes.memory.ReadNode' => 'effect',
179
- 'org.graalvm.compiler.nodes.memory.WriteNode' => 'effect',
180
- 'org.graalvm.compiler.nodes.MergeNode' => 'control',
181
- 'org.graalvm.compiler.nodes.ParameterNode' => 'input',
182
- 'org.graalvm.compiler.nodes.PrefetchAllocateNode' => 'effect',
183
- 'org.graalvm.compiler.nodes.ReturnNode' => 'control',
184
- 'org.graalvm.compiler.nodes.StartNode' => 'control',
185
- 'org.graalvm.compiler.nodes.UnwindNode' => 'effect',
186
- 'org.graalvm.compiler.nodes.virtual.AllocatedObjectNode' => 'virtual',
187
- 'org.graalvm.compiler.nodes.virtual.CommitAllocationNode' => 'effect',
188
- 'org.graalvm.compiler.nodes.virtual.VirtualArrayNode' => 'virtual',
189
- 'org.graalvm.compiler.nodes.VirtualObjectState' => 'info',
190
- 'org.graalvm.compiler.replacements.nodes.ArrayEqualsNode' => 'effect',
191
- 'org.graalvm.compiler.replacements.nodes.ReadRegisterNode' => 'effect',
192
- 'org.graalvm.compiler.replacements.nodes.WriteRegisterNode' => 'effect'
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,25 @@ 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)?\}}) { |_| node.inputs.select { |e| e.props[:name] == Regexp.last_match(1) }.map { |e| e.from.id }.join(', ') }
205
- string = string.gsub(/\{x#field\}/) { |_| "#{node.props.dig('field', :field_class).split('.').last}.#{node.props.dig('field', :name)}" }
206
- string = string.gsub(/\{x#state\}/) { |_| "#{node.props.dig('code', :declaring_class)}##{node.props.dig('code', :method_name)} #{node.props['sourceFile']}:#{node.props['sourceLine']}" }
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(
216
+ "code",
217
+ :declaring_class,
218
+ )}##{node.props.dig(
219
+ "code",
220
+ :method_name,
221
+ )} #{node.props["sourceFile"]}:#{node.props["sourceLine"]}"
222
+ end
207
223
  string = string.gsub(/\{x#simpleStamp\}/) do |_|
208
- stamp = node.props.dig('checkedStamp')
224
+ stamp = node.props.dig("checkedStamp")
209
225
  if stamp =~ /a!?# L(.*);/
210
226
  Regexp.last_match(1)
211
227
  else
@@ -218,14 +234,17 @@ module Seafoam
218
234
  # Annotate edges with their label and kind.
219
235
  def apply_edges(graph)
220
236
  graph.edges.each do |edge|
221
- if edge.to.props.dig(:node_class, :node_class) == 'org.graalvm.compiler.nodes.ValuePhiNode' && edge.props[:name] == 'values'
222
- merge_node = edge.to.edges.find { |e| e.props[:name] == 'merge' }.from
223
- control_into_merge = %w[ends loopBegin]
224
- merge_node_control_edges_in = merge_node.edges.select { |e| control_into_merge.include?(e.props[:name]) && e.to.props.dig(:node_class, :node_class) != 'org.graalvm.compiler.nodes.LoopExitNode' }
237
+ if edge.to.node_class == "org.graalvm.compiler.nodes.ValuePhiNode" && edge.props[:name] == "values"
238
+ merge_node = edge.to.edges.find { |e| e.props[:name] == "merge" }.from
239
+ control_into_merge = ["ends", "loopBegin"]
240
+ merge_node_control_edges_in = merge_node.edges.select do |e|
241
+ exit_node = "org.graalvm.compiler.nodes.LoopExitNode"
242
+ control_into_merge.include?(e.props[:name]) && e.to.node_class != exit_node
243
+ end
225
244
  matching_control_edge = merge_node_control_edges_in[edge.props[:index]]
226
245
  control_in_node = matching_control_edge.nodes.find { |n| n != merge_node }
227
246
  edge.props[:label] = "from #{control_in_node.id}"
228
- edge.props[:kind] = 'data'
247
+ edge.props[:kind] = "data"
229
248
  next
230
249
  end
231
250
 
@@ -233,74 +252,74 @@ module Seafoam
233
252
  case edge.props[:name]
234
253
 
235
254
  # Control edges.
236
- when 'ends', 'next', 'trueSuccessor', 'falseSuccessor', 'exceptionEdge'
237
- edge.props[:kind] = 'control'
255
+ when "ends", "next", "trueSuccessor", "falseSuccessor", "exceptionEdge"
256
+ edge.props[:kind] = "control"
238
257
  case edge.props[:name]
239
- when 'trueSuccessor'
258
+ when "trueSuccessor"
240
259
  # Simplify trueSuccessor to T
241
- edge.props[:label] = 'T'
242
- when 'falseSuccessor'
260
+ edge.props[:label] = "T"
261
+ when "falseSuccessor"
243
262
  # Simplify falseSuccessor to F
244
- edge.props[:label] = 'F'
245
- when 'exceptionEdge'
263
+ edge.props[:label] = "F"
264
+ when "exceptionEdge"
246
265
  # Simplify exceptionEdge to unwind
247
- edge.props[:label] = 'unwind'
266
+ edge.props[:label] = "unwind"
248
267
  end
249
268
 
250
269
  # Info edges, which are drawn reversed as they point from the user
251
270
  # to the info.
252
- when 'frameState', 'callTarget', 'stateAfter'
271
+ when "frameState", "callTarget", "stateAfter"
253
272
  edge.props[:label] = nil
254
- edge.props[:kind] = 'info'
273
+ edge.props[:kind] = "info"
255
274
  edge.props[:reverse] = true
256
275
 
257
276
  # Condition for branches, which we label as ?.
258
- when 'condition'
259
- edge.props[:kind] = 'data'
260
- edge.props[:label] = '?'
277
+ when "condition"
278
+ edge.props[:kind] = "data"
279
+ edge.props[:label] = "?"
261
280
 
262
281
  # loopBegin edges point from LoopEndNode (continue) and LoopExitNode
263
282
  # (break) to the LoopBeginNode. Both are drawn reversed.
264
- when 'loopBegin'
265
- case edge.to.props.dig(:node_class, :node_class)
266
- when 'org.graalvm.compiler.nodes.LoopEndNode'
283
+ when "loopBegin"
284
+ case edge.to.node_class
285
+ when "org.graalvm.compiler.nodes.LoopEndNode"
267
286
  # If it's from the LoopEnd then it's the control edge to follow.
268
- edge.props[:kind] = 'loop'
287
+ edge.props[:kind] = "loop"
269
288
  edge.props[:reverse] = true
270
- when 'org.graalvm.compiler.nodes.LoopExitNode'
289
+ when "org.graalvm.compiler.nodes.LoopExitNode"
271
290
  # If it's from the LoopExit then it's just for information - it's
272
291
  # not control flow to follow.
273
- edge.props[:kind] = 'info'
292
+ edge.props[:kind] = "info"
274
293
  edge.props[:reverse] = true
275
294
  else
276
- raise EncodingError, 'loopBegin edge not to LoopEnd or LoopExit'
295
+ raise EncodingError, "loopBegin edge not to LoopEnd or LoopExit"
277
296
  end
278
297
 
279
298
  # Merges are info.
280
- when 'merge'
281
- edge.props[:kind] = 'info'
299
+ when "merge"
300
+ edge.props[:kind] = "info"
282
301
  edge.props[:reverse] = true
283
302
 
284
303
  # Successors are control from a switch.
285
- when 'successors'
304
+ when "successors"
286
305
  # We want to label the edges with the corresponding index of the key.
287
- if edge.props[:index] == edge.from.props['keys'].size
288
- label = 'default'
306
+ label = if edge.props[:index] == edge.from.props["keys"].size
307
+ "default"
289
308
  else
290
- label = "k[#{edge.props[:index]}]"
309
+ "k[#{edge.props[:index]}]"
291
310
  end
292
311
  edge.props[:label] = label
293
- edge.props[:kind] = 'control'
312
+ edge.props[:kind] = "control"
294
313
 
295
314
  # Successors are control from a switch.
296
- when 'arguments'
315
+ when "arguments"
297
316
  # We want to label the edges with their corresponding argument index.
298
317
  edge.props[:label] = "arg[#{edge.props[:index]}]"
299
- edge.props[:kind] = 'data'
318
+ edge.props[:kind] = "data"
300
319
 
301
320
  # Everything else is data.
302
321
  else
303
- edge.props[:kind] = 'data'
322
+ edge.props[:kind] = "data"
304
323
  edge.props[:label] = edge.props[:name]
305
324
 
306
325
  end
@@ -311,7 +330,7 @@ module Seafoam
311
330
  # useful to look at, and severely clutter the graph.
312
331
  def hide_frame_state(graph)
313
332
  graph.nodes.each_value do |node|
314
- if FRAME_STATE_NODES.include?(node.props.dig(:node_class, :node_class))
333
+ if FRAME_STATE_NODES.include?(node.node_class)
315
334
  node.props[:hidden] = true
316
335
  end
317
336
  end
@@ -324,21 +343,41 @@ module Seafoam
324
343
  loop do
325
344
  umodified = true
326
345
  graph.edges.each do |edge|
327
- next unless Graal::Pi::PI_NODES.include?(edge.from.props.dig(:node_class, :node_class))
346
+ next unless Graal::Pi::PI_NODES.include?(edge.from.node_class)
328
347
 
329
348
  object = Graal::Pi.follow_pi_object(edge.from)
330
- graph.create_edge object, edge.to, edge.props.merge({ synthetic: true })
331
- graph.remove_edge edge
349
+ graph.create_edge(object, edge.to, edge.props.merge({ synthetic: true }))
350
+ graph.remove_edge(edge)
332
351
  umodified = false
333
352
  end
334
353
  break if umodified
335
354
  end
336
355
  end
337
356
 
357
+ def hide_begin_end(graph)
358
+ graph.nodes.each_value do |node|
359
+ node_class = node.node_class
360
+ next unless BEGIN_END_NODES.include?(node_class)
361
+
362
+ # In mid tier, a BeginNode can have multiple input edges, leave those in the graph
363
+ next unless (node.inputs.size == 1) && (node.outputs.size == 1)
364
+
365
+ input_edge = node.inputs[0]
366
+ output_edge = node.outputs[0]
367
+ # The edge above the BeginNode is the interesting one, the edges
368
+ # after the Begin or before/after the EndNode are pure control flow
369
+ # and have no extra information
370
+ preserved_props = input_edge.props
371
+ graph.create_edge(input_edge.from, output_edge.to, preserved_props)
372
+ graph.remove_edge(input_edge)
373
+ graph.remove_edge(output_edge)
374
+ end
375
+ end
376
+
338
377
  # Hide floating nodes. This highlights just the control flow backbone.
339
378
  def hide_floating(graph)
340
379
  graph.nodes.each_value do |node|
341
- if node.edges.none? { |e| e.props[:kind] == 'control' }
380
+ if node.edges.none? { |e| e.props[:kind] == "control" }
342
381
  node.props[:hidden] = true
343
382
  end
344
383
  end
@@ -350,7 +389,7 @@ module Seafoam
350
389
  # nodes that are 'simple', like parameters and constants.
351
390
  def reduce_edges(graph)
352
391
  graph.nodes.each_value do |node|
353
- if SIMPLE_INPUTS.include?(node.props.dig(:node_class, :node_class))
392
+ if SIMPLE_INPUTS.include?(node.node_class)
354
393
  node.props[:inlined] = true
355
394
  end
356
395
  end
@@ -366,11 +405,11 @@ module Seafoam
366
405
  graph.nodes.each_value do |node|
367
406
  # Call trees are like Graal graphs but don't have these edges -
368
407
  # don't hide them.
369
- next if node.props['truffleCallees']
408
+ next if node.props["truffleCallees"]
370
409
 
371
410
  next unless node.outputs.all? { |edge| edge.to.props[:hidden] || edge.props[:hidden] } &&
372
- node.inputs.none? { |edge| edge.props[:kind] == 'control' } &&
373
- node.inputs.none? { |edge| edge.props[:name] == 'anchor' }
411
+ node.inputs.none? { |edge| edge.props[:kind] == "control" } &&
412
+ node.inputs.none? { |edge| edge.props[:name] == "anchor" }
374
413
 
375
414
  unless node.props[:hidden]
376
415
  node.props[:hidden] = true
@@ -382,23 +421,18 @@ module Seafoam
382
421
  end
383
422
 
384
423
  # If we see these in the graph properties it's probably a Graal graph.
385
- TRIGGERS = %w[
386
- HostedGraphBuilderPhase
387
- GraalCompiler
388
- TruffleCompiler
389
- ]
424
+ TRIGGERS = ["HostedGraphBuilderPhase", "GraalCompiler", "TruffleCompiler", "SubstrateCompilation"]
390
425
 
391
426
  # Simple input node classes that may be inlined.
392
- SIMPLE_INPUTS = %w[
393
- org.graalvm.compiler.nodes.ConstantNode
394
- org.graalvm.compiler.nodes.ParameterNode
395
- ]
427
+ SIMPLE_INPUTS = ["org.graalvm.compiler.nodes.ConstantNode", "org.graalvm.compiler.nodes.ParameterNode"]
396
428
 
397
429
  # Nodes just to maintain frame state.
398
- FRAME_STATE_NODES = %w[
399
- org.graalvm.compiler.nodes.FrameState
400
- org.graalvm.compiler.virtual.nodes.MaterializedObjectState
430
+ FRAME_STATE_NODES = [
431
+ "org.graalvm.compiler.nodes.FrameState",
432
+ "org.graalvm.compiler.virtual.nodes.MaterializedObjectState",
401
433
  ]
434
+
435
+ BEGIN_END_NODES = ["org.graalvm.compiler.nodes.BeginNode", "org.graalvm.compiler.nodes.EndNode"]
402
436
  end
403
437
  end
404
438
  end