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.
@@ -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,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)?\}}) { |_| 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("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('checkedStamp')
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.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' }
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] = 'data'
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 'ends', 'next', 'trueSuccessor', 'falseSuccessor', 'exceptionEdge'
237
- edge.props[:kind] = 'control'
251
+ when "ends", "next", "trueSuccessor", "falseSuccessor", "exceptionEdge"
252
+ edge.props[:kind] = "control"
238
253
  case edge.props[:name]
239
- when 'trueSuccessor'
254
+ when "trueSuccessor"
240
255
  # Simplify trueSuccessor to T
241
- edge.props[:label] = 'T'
242
- when 'falseSuccessor'
256
+ edge.props[:label] = "T"
257
+ when "falseSuccessor"
243
258
  # Simplify falseSuccessor to F
244
- edge.props[:label] = 'F'
245
- when 'exceptionEdge'
259
+ edge.props[:label] = "F"
260
+ when "exceptionEdge"
246
261
  # Simplify exceptionEdge to unwind
247
- edge.props[:label] = 'unwind'
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 'frameState', 'callTarget', 'stateAfter'
267
+ when "frameState", "callTarget", "stateAfter"
253
268
  edge.props[:label] = nil
254
- edge.props[:kind] = 'info'
269
+ edge.props[:kind] = "info"
255
270
  edge.props[:reverse] = true
256
271
 
257
272
  # Condition for branches, which we label as ?.
258
- when 'condition'
259
- edge.props[:kind] = 'data'
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 'loopBegin'
265
- case edge.to.props.dig(:node_class, :node_class)
266
- when 'org.graalvm.compiler.nodes.LoopEndNode'
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] = 'loop'
283
+ edge.props[:kind] = "loop"
269
284
  edge.props[:reverse] = true
270
- when 'org.graalvm.compiler.nodes.LoopExitNode'
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] = 'info'
288
+ edge.props[:kind] = "info"
274
289
  edge.props[:reverse] = true
275
290
  else
276
- raise EncodingError, 'loopBegin edge not to LoopEnd or LoopExit'
291
+ raise EncodingError, "loopBegin edge not to LoopEnd or LoopExit"
277
292
  end
278
293
 
279
294
  # Merges are info.
280
- when 'merge'
281
- edge.props[:kind] = 'info'
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 'successors'
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['keys'].size
288
- label = 'default'
302
+ label = if edge.props[:index] == edge.from.props["keys"].size
303
+ "default"
289
304
  else
290
- label = "k[#{edge.props[:index]}]"
305
+ "k[#{edge.props[:index]}]"
291
306
  end
292
307
  edge.props[:label] = label
293
- edge.props[:kind] = 'control'
308
+ edge.props[:kind] = "control"
294
309
 
295
310
  # Successors are control from a switch.
296
- when 'arguments'
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] = 'data'
314
+ edge.props[:kind] = "data"
300
315
 
301
316
  # Everything else is data.
302
317
  else
303
- edge.props[:kind] = 'data'
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.props.dig(:node_class, :node_class))
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.props.dig(:node_class, :node_class))
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 object, edge.to, edge.props.merge({ synthetic: true })
331
- graph.remove_edge 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] == 'control' }
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.props.dig(:node_class, :node_class))
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['truffleCallees']
404
+ next if node.props["truffleCallees"]
370
405
 
371
406
  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' }
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 = %w[
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 = %w[
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 = %w[
399
- org.graalvm.compiler.nodes.FrameState
400
- org.graalvm.compiler.virtual.nodes.MaterializedObjectState
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