seafoam 0.6 → 0.10

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.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/bin/bgv2isabelle +1 -5
  3. data/bin/bgv2json +1 -5
  4. data/bin/cfg2asm +1 -5
  5. data/bin/seafoam +1 -5
  6. data/lib/seafoam/bgv/bgv_parser.rb +10 -2
  7. data/lib/seafoam/commands.rb +107 -32
  8. data/lib/seafoam/graal/pi.rb +18 -0
  9. data/lib/seafoam/graph.rb +33 -1
  10. data/lib/seafoam/graphviz_writer.rb +24 -2
  11. data/lib/seafoam/json_writer.rb +1 -3
  12. data/lib/seafoam/{annotators → passes}/fallback.rb +4 -4
  13. data/lib/seafoam/{annotators → passes}/graal.rb +43 -15
  14. data/lib/seafoam/passes/truffle.rb +58 -0
  15. data/lib/seafoam/passes.rb +61 -0
  16. data/lib/seafoam/version.rb +1 -1
  17. data/lib/seafoam.rb +5 -4
  18. metadata +26 -62
  19. data/.github/probots.yml +0 -2
  20. data/.github/workflows/workflows.yml +0 -39
  21. data/.gitignore +0 -7
  22. data/.rubocop.yml +0 -37
  23. data/.ruby-version +0 -1
  24. data/.seafoam/config +0 -1
  25. data/CODE_OF_CONDUCT.md +0 -128
  26. data/CONTRIBUTING.md +0 -5
  27. data/Gemfile +0 -2
  28. data/LICENSE.md +0 -7
  29. data/README.md +0 -378
  30. data/demos/box-unbox-stats +0 -65
  31. data/docs/annotators.md +0 -43
  32. data/docs/bgv.md +0 -293
  33. data/docs/getting-graphs.md +0 -59
  34. data/docs/images/igv.png +0 -0
  35. data/docs/images/seafoam.png +0 -0
  36. data/docs/images/spotlight-igv.png +0 -0
  37. data/docs/images/spotlight-seafoam.png +0 -0
  38. data/docs/json.md +0 -35
  39. data/examples/Fib.java +0 -24
  40. data/examples/MatMult.java +0 -39
  41. data/examples/fib-java.bgv.gz +0 -0
  42. data/examples/fib.js +0 -15
  43. data/examples/fib.rb +0 -15
  44. data/examples/identity.rb +0 -13
  45. data/examples/java/Irreducible.class +0 -0
  46. data/examples/java/Irreducible.j +0 -35
  47. data/examples/java/IrreducibleDecompiled.java +0 -21
  48. data/examples/java/JavaExamples.java +0 -418
  49. data/examples/matmult.rb +0 -29
  50. data/examples/overflow.rb +0 -13
  51. data/examples/ruby/clamps.rb +0 -20
  52. data/examples/ruby/graal.patch +0 -15
  53. data/examples/ruby/ruby_examples.rb +0 -278
  54. data/lib/seafoam/annotators.rb +0 -54
  55. data/lib/seafoam/config.rb +0 -34
  56. data/seafoam.gemspec +0 -21
  57. data/spec/seafoam/annotators/fallback_spec.rb +0 -69
  58. data/spec/seafoam/annotators/graal_spec.rb +0 -96
  59. data/spec/seafoam/annotators_spec.rb +0 -61
  60. data/spec/seafoam/bgv/bgv_parser_spec.rb +0 -157
  61. data/spec/seafoam/binary/io_binary_reader_spec.rb +0 -176
  62. data/spec/seafoam/cfg/cfg_parser_spec.rb +0 -21
  63. data/spec/seafoam/cfg/disassembler_spec.rb +0 -32
  64. data/spec/seafoam/command_spec.rb +0 -316
  65. data/spec/seafoam/graph_spec.rb +0 -172
  66. data/spec/seafoam/graphviz_writer_spec.rb +0 -63
  67. data/spec/seafoam/json_writer_spec.rb +0 -14
  68. data/spec/seafoam/spec_helpers.rb +0 -34
  69. data/spec/seafoam/spotlight_spec.rb +0 -38
  70. data/tools/render-all +0 -36
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 69f3387c345f401ca95791c9f5b69d57b1ab123e60abcb31b9160b8734b5507e
4
- data.tar.gz: 154f61a73ddb2ff1cf271c8d57fbf9422ddbb46fa3e0dc6d1256d1f4c2c0addc
3
+ metadata.gz: f8665fe768d4900820ca676269cd25028306e8253c2109c71ff4cb31dd7c6e44
4
+ data.tar.gz: fd8c52e5cf3daafa9b2673265067b743cc644755c3772c02904c2b815b3a93d2
5
5
  SHA512:
6
- metadata.gz: 29067885733970836583c0060a933ad13ec78ba35a01c6462ea0af4ac7df2137f8d0202dcdb7f57078aab0aba30c2da08973c9f31415191c9229f0a7adaf816b
7
- data.tar.gz: 69b2872db8937ed1bd73eefee880139055ee9a40b3a3cd50c041f3c623307780ff5e72d3ad2eaf9882d4234b58b9668021270f768c767229e930d12613483f8d
6
+ metadata.gz: 815e7031027718cea7a933b7fc5ad822f754f05e3ae5bdc2066775183a9ca98c841b54e682a148c4437a29b1f95c4ede5833a2a1f2995d2c55296a800e71b269
7
+ data.tar.gz: 462aaad5134c8b6cce229e8456742151354333c5e7c02283e2e90917fa7ad238f3f4f71770519357117f42b1579928ddb0bba3f04b31ddef68d7e41e92f8c016
data/bin/bgv2isabelle CHANGED
@@ -5,12 +5,8 @@ require 'seafoam'
5
5
  # This is the 'bgv2isabelle' command line entry point.
6
6
 
7
7
  begin
8
- # Load configuraiton.
9
- config = Seafoam::Config.new
10
- config.load_config
11
-
12
8
  # Run the command line.
13
- commands = Seafoam::Commands.new($stdout, config)
9
+ commands = Seafoam::Commands.new($stdout)
14
10
  commands.bgv2isabelle(*ARGV)
15
11
  rescue StandardError => e
16
12
  if $DEBUG
data/bin/bgv2json CHANGED
@@ -5,12 +5,8 @@ require 'seafoam'
5
5
  # This is the 'bgv2json' command line entry point.
6
6
 
7
7
  begin
8
- # Load configuraiton.
9
- config = Seafoam::Config.new
10
- config.load_config
11
-
12
8
  # Run the command line.
13
- commands = Seafoam::Commands.new($stdout, config)
9
+ commands = Seafoam::Commands.new($stdout)
14
10
  commands.bgv2json(*ARGV)
15
11
  rescue StandardError => e
16
12
  if $DEBUG
data/bin/cfg2asm CHANGED
@@ -5,12 +5,8 @@ require 'seafoam'
5
5
  # This is the 'cfg2asm' command line entry point.
6
6
 
7
7
  begin
8
- # Load configuraiton.
9
- config = Seafoam::Config.new
10
- config.load_config
11
-
12
8
  # Run the command line.
13
- commands = Seafoam::Commands.new($stdout, config)
9
+ commands = Seafoam::Commands.new($stdout)
14
10
  commands.cfg2asm(*ARGV)
15
11
  rescue StandardError => e
16
12
  if $DEBUG
data/bin/seafoam CHANGED
@@ -5,12 +5,8 @@ require 'seafoam'
5
5
  # This is the 'seafoam' command line entry point.
6
6
 
7
7
  begin
8
- # Load configuraiton.
9
- config = Seafoam::Config.new
10
- config.load_config
11
-
12
8
  # Run the command line.
13
- commands = Seafoam::Commands.new($stdout, config)
9
+ commands = Seafoam::Commands.new($stdout)
14
10
  commands.seafoam(*ARGV)
15
11
  rescue StandardError => e
16
12
  if $DEBUG
@@ -127,13 +127,21 @@ module Seafoam
127
127
  end
128
128
  end
129
129
  end
130
- skip_blocks
130
+
131
+ # Read block information.
132
+ @reader.read_sint32.times do
133
+ block_id = @reader.read_sint32
134
+ block_nodes = @reader.read_sint32.times.map { @reader.read_sint32 }
135
+ # Followers aren't used but could be.
136
+ @reader.read_sint32.times.map { @reader.read_sint32 }
137
+ graph.create_block block_id, block_nodes
138
+ end
131
139
  graph
132
140
  end
133
141
 
134
142
  # Skip over a graph, having read or skipped its headers.
135
143
  def skip_graph
136
- # Already read BEGIN_GRAPH, id, format, args, and props
144
+ # Already read BEGIN_GRAPH, id, format, args, and props.
137
145
  @reader.read_sint32.times do
138
146
  @reader.skip_int32
139
147
  node_class = read_pool_object
@@ -1,11 +1,11 @@
1
1
  require 'json'
2
+ require 'set'
2
3
 
3
4
  module Seafoam
4
5
  # Implementations of the command-line commands that you can run in Seafoam.
5
6
  class Commands
6
- def initialize(out, config)
7
+ def initialize(out)
7
8
  @out = out
8
- @config = config
9
9
  end
10
10
 
11
11
  # Run the general seafoam command.
@@ -15,24 +15,7 @@ module Seafoam
15
15
  when nil, 'help', '-h', '--help', '-help'
16
16
  raise ArgumentError, "unexpected arguments #{args.join(' ')}" unless args.empty?
17
17
 
18
- @out.puts 'seafoam file.bgv info'
19
- @out.puts ' file.bgv list'
20
- @out.puts ' file.bgv[:graph][:node[-edge]] search term...'
21
- @out.puts ' file.bgv[:graph][:node[-edge]] edges'
22
- @out.puts ' file.bgv[:graph][:node[-edge]] props'
23
- @out.puts ' file.bgv:graph:node source'
24
- @out.puts ' file.bgv:graph render'
25
- @out.puts ' --spotlight n,n,n...'
26
- @out.puts ' --out graph.pdf'
27
- @out.puts ' graph.svg'
28
- @out.puts ' graph.png'
29
- @out.puts ' graph.dot'
30
- @out.puts ' --show-frame-state'
31
- @out.puts ' --hide-floating'
32
- @out.puts ' --no-reduce-edges'
33
- @out.puts ' --option key value'
34
- @out.puts ' --help'
35
- @out.puts ' --version'
18
+ help(*args)
36
19
  when 'version', '-v', '-version', '--version'
37
20
  version(*args)
38
21
  else
@@ -57,6 +40,8 @@ module Seafoam
57
40
  render name, *args
58
41
  when 'debug'
59
42
  debug name, *args
43
+ when 'describe'
44
+ describe name, *args
60
45
  else
61
46
  raise ArgumentError, "unknown command #{command}"
62
47
  end
@@ -262,7 +247,7 @@ module Seafoam
262
247
  end
263
248
 
264
249
  def search_object(tag, object, terms)
265
- full_text = JSON.generate(object)
250
+ full_text = JSON.generate(JSONWriter.prepare_json(object))
266
251
  full_text_down = full_text.downcase
267
252
  start = 0
268
253
  terms.each do |t|
@@ -298,7 +283,7 @@ module Seafoam
298
283
  parser.read_graph_header
299
284
  graph = parser.read_graph
300
285
  if node_id
301
- Annotators.apply graph
286
+ Passes.apply graph
302
287
  node = graph.nodes[node_id]
303
288
  raise ArgumentError, 'node not found' unless node
304
289
 
@@ -391,14 +376,66 @@ module Seafoam
391
376
  end
392
377
  end
393
378
 
379
+ # seafoam file.bgv:n describe
380
+ def describe(name, *args)
381
+ file, graph_index, *rest = parse_name(name)
382
+
383
+ if graph_index.nil? || !rest.all?(&:nil?)
384
+ raise ArgumentError, 'describe only works with a graph'
385
+ end
386
+ raise ArgumentError, 'describe does not take arguments' unless args.empty?
387
+
388
+ parser = BGV::BGVParser.new(file)
389
+ parser.read_file_header
390
+ parser.skip_document_props
391
+
392
+ loop do
393
+ index, = parser.read_graph_preheader
394
+ break unless index
395
+
396
+ parser.skip_graph_header
397
+
398
+ if index != graph_index
399
+ parser.skip_graph
400
+ next
401
+ end
402
+
403
+ graph = parser.read_graph
404
+ notes = Set.new
405
+
406
+ graph.nodes.each_value do |node|
407
+ node_class = node.props.dig(:node_class, :node_class)
408
+ case node_class
409
+ when 'org.graalvm.compiler.nodes.IfNode'
410
+ notes.add 'branches'
411
+ when 'org.graalvm.compiler.nodes.LoopBeginNode'
412
+ notes.add 'loops'
413
+ when 'org.graalvm.compiler.nodes.InvokeNode', 'org.graalvm.compiler.nodes.InvokeWithExceptionNode'
414
+ notes.add 'calls'
415
+ end
416
+ end
417
+
418
+ notes.add 'deopts' if graph.nodes[0].outputs.map(&:to)
419
+ .all? { |t| t.props.dig(:node_class, :node_class) == 'org.graalvm.compiler.nodes.DeoptimizeNode' }
420
+
421
+ notes.add 'linear' unless notes.include?('branches') || notes.include?('loops')
422
+
423
+ @out.puts ["#{graph.nodes.size} nodes", *notes].join(', ')
424
+
425
+ break
426
+ end
427
+ end
428
+
394
429
  # seafoam file.bgv:n render options...
395
430
  def render(name, *args)
396
431
  file, graph_index, *rest = parse_name(name)
397
432
  raise ArgumentError, 'render needs at least a graph' unless graph_index
398
433
  raise ArgumentError, 'render only works with a graph' unless rest == [nil, nil]
399
434
 
400
- annotator_options = {
435
+ pass_options = {
436
+ simplify_truffle_args: true,
401
437
  hide_frame_state: true,
438
+ hide_pi: true,
402
439
  hide_floating: false,
403
440
  reduce_edges: true
404
441
  }
@@ -406,6 +443,7 @@ module Seafoam
406
443
  args = args.dup
407
444
  out_file = nil
408
445
  explicit_out_file = false
446
+ draw_blocks = false
409
447
  until args.empty?
410
448
  arg = args.shift
411
449
  case arg
@@ -418,12 +456,18 @@ module Seafoam
418
456
  raise ArgumentError, 'no list for --spotlight' unless spotlight_arg
419
457
 
420
458
  spotlight_nodes = spotlight_arg.split(',').map { |n| Integer(n) }
459
+ when '--full-truffle-args'
460
+ pass_options[:simplify_truffle_args] = false
421
461
  when '--show-frame-state'
422
- annotator_options[:hide_frame_state] = false
462
+ pass_options[:hide_frame_state] = false
463
+ when '--show-pi'
464
+ pass_options[:hide_pi] = false
423
465
  when '--hide-floating'
424
- annotator_options[:hide_floating] = true
466
+ pass_options[:hide_floating] = true
425
467
  when '--no-reduce-edges'
426
- annotator_options[:reduce_edges] = false
468
+ pass_options[:reduce_edges] = false
469
+ when '--draw-blocks'
470
+ draw_blocks = true
427
471
  when '--option'
428
472
  key = args.shift
429
473
  raise ArgumentError, 'no key for --option' unless key
@@ -432,7 +476,7 @@ module Seafoam
432
476
  raise ArgumentError, "no value for --option #{key}" unless out_file
433
477
 
434
478
  value = { 'true' => true, 'false' => 'false' }.fetch(key, value)
435
- annotator_options[key.to_sym] = value
479
+ pass_options[key.to_sym] = value
436
480
  else
437
481
  raise ArgumentError, "unexpected option #{arg}"
438
482
  end
@@ -455,7 +499,7 @@ module Seafoam
455
499
  with_graph(file, graph_index) do |parser|
456
500
  parser.skip_graph_header
457
501
  graph = parser.read_graph
458
- Annotators.apply graph, annotator_options
502
+ Passes.apply graph, pass_options
459
503
  if spotlight_nodes
460
504
  spotlight = Spotlight.new(graph)
461
505
  spotlight_nodes.each do |node_id|
@@ -469,14 +513,14 @@ module Seafoam
469
513
  if out_format == :dot
470
514
  File.open(out_file, 'w') do |stream|
471
515
  writer = GraphvizWriter.new(stream)
472
- writer.write_graph graph
516
+ writer.write_graph graph, false, draw_blocks
473
517
  end
474
518
  else
475
519
  begin
476
520
  IO.popen(['dot', "-T#{out_format}", '-o', out_file], 'w') do |stream|
477
521
  writer = GraphvizWriter.new(stream)
478
522
  hidpi = out_format == :png
479
- writer.write_graph graph, hidpi
523
+ writer.write_graph graph, hidpi, draw_blocks
480
524
  end
481
525
  rescue Errno::ENOENT
482
526
  raise 'Could not run Graphviz - is it installed?'
@@ -565,6 +609,32 @@ module Seafoam
565
609
  raise ArgumentError, 'graph not found' unless graph_found
566
610
  end
567
611
 
612
+ # Prints help.
613
+ def help(*_args)
614
+ @out.puts 'seafoam file.bgv info'
615
+ @out.puts ' file.bgv list'
616
+ @out.puts ' file.bgv[:graph][:node[-edge]] search term...'
617
+ @out.puts ' file.bgv[:graph][:node[-edge]] edges'
618
+ @out.puts ' file.bgv[:graph][:node[-edge]] props'
619
+ @out.puts ' file.bgv:graph:node source'
620
+ @out.puts ' file.bgv:graph describe'
621
+ @out.puts ' file.bgv:graph render'
622
+ @out.puts ' --spotlight n,n,n...'
623
+ @out.puts ' --out graph.pdf'
624
+ @out.puts ' graph.svg'
625
+ @out.puts ' graph.png'
626
+ @out.puts ' graph.dot'
627
+ @out.puts ' --full-truffle-args'
628
+ @out.puts ' --show-frame-state'
629
+ @out.puts ' --show-pi'
630
+ @out.puts ' --hide-floating'
631
+ @out.puts ' --no-reduce-edges'
632
+ @out.puts ' --draw-blocks'
633
+ @out.puts ' --option key value'
634
+ @out.puts ' --help'
635
+ @out.puts ' --version'
636
+ end
637
+
568
638
  # Prints the version.
569
639
  def version(*args)
570
640
  raise ArgumentError, "unexpected arguments #{args.join(' ')}" unless args.empty?
@@ -598,10 +668,15 @@ module Seafoam
598
668
 
599
669
  # Open a file for the user if possible.
600
670
  def autoopen(file)
601
- if RUBY_PLATFORM.include?('darwin') && @out.tty?
671
+ return unless @out.tty?
672
+
673
+ case RUBY_PLATFORM
674
+ when /darwin/
602
675
  system 'open', file
603
- # Don't worry if it fails.
676
+ when /linux/
677
+ system 'xdg-open', file
604
678
  end
679
+ # Don't worry if it fails.
605
680
  end
606
681
  end
607
682
  end
@@ -0,0 +1,18 @@
1
+ module Seafoam
2
+ module Graal
3
+ # Routines for understanding pi nodes in Graal.
4
+ module Pi
5
+ # Find the actual value behind potentially a chain of pi nodes.
6
+ def self.follow_pi_object(node)
7
+ node = node.edges.find { |edge| edge.props[:name] == 'object' }.from while PI_NODES.include?(node.props.dig(:node_class, :node_class))
8
+ node
9
+ end
10
+
11
+ # Pi nodes add type information.
12
+ PI_NODES = [
13
+ 'org.graalvm.compiler.nodes.PiNode',
14
+ 'org.graalvm.compiler.nodes.PiArrayNode'
15
+ ]
16
+ end
17
+ end
18
+ end
data/lib/seafoam/graph.rb CHANGED
@@ -2,12 +2,14 @@ module Seafoam
2
2
  # A graph, with properties, nodes, and edges. We don't encapsulate the graph
3
3
  # too much - be careful.
4
4
  class Graph
5
- attr_reader :props, :nodes, :edges
5
+ attr_reader :props, :nodes, :edges, :blocks, :new_id
6
6
 
7
7
  def initialize(props = nil)
8
8
  @props = props || {}
9
9
  @nodes = {}
10
10
  @edges = []
11
+ @blocks = []
12
+ @new_id = 0
11
13
  end
12
14
 
13
15
  # Create a node.
@@ -15,6 +17,7 @@ module Seafoam
15
17
  props ||= {}
16
18
  node = Node.new(id, props)
17
19
  @nodes[id] = node
20
+ @new_id = id + 1
18
21
  node
19
22
  end
20
23
 
@@ -27,6 +30,20 @@ module Seafoam
27
30
  to.inputs.push edge
28
31
  edge
29
32
  end
33
+
34
+ # Add a new basic block with given id and node id list.
35
+ def create_block(id, node_ids)
36
+ nodes = node_ids.select { |n| @nodes.key? n }.map { |n| @nodes[n] }
37
+ block = Block.new(id, nodes)
38
+ @blocks.push block
39
+ block
40
+ end
41
+
42
+ def remove_edge(edge)
43
+ edge.from.outputs.delete edge
44
+ edge.to.inputs.delete edge
45
+ edges.delete edge
46
+ end
30
47
  end
31
48
 
32
49
  # A node, with properties, input edges, and output edges.
@@ -88,4 +105,19 @@ module Seafoam
88
105
  "<Edge #{from.id} -> #{to.id}>"
89
106
  end
90
107
  end
108
+
109
+ # A control-flow basic block
110
+ class Block
111
+ attr_reader :id, :nodes
112
+
113
+ def initialize(id, nodes)
114
+ @id = id
115
+ @nodes = nodes
116
+ end
117
+
118
+ # Inspect.
119
+ def inspect
120
+ "<Block #{id}>"
121
+ end
122
+ end
91
123
  end
@@ -7,15 +7,16 @@ module Seafoam
7
7
  end
8
8
 
9
9
  # Write a graph.
10
- def write_graph(graph, hidpi = false)
10
+ def write_graph(graph, hidpi = false, draw_blocks = false)
11
11
  inline_attrs = {}
12
12
  attrs = {}
13
13
  attrs[:dpi] = 200 if hidpi
14
- attrs[:bgcolor] = 'transparent'
14
+ attrs[:bgcolor] = 'white'
15
15
  @stream.puts 'digraph G {'
16
16
  @stream.puts " graph #{write_attrs(attrs)};"
17
17
  write_nodes inline_attrs, graph
18
18
  write_edges inline_attrs, graph
19
+ write_blocks graph if draw_blocks
19
20
  @stream.puts '}'
20
21
  end
21
22
 
@@ -99,6 +100,9 @@ module Seafoam
99
100
  # from a shaded node.
100
101
  next if edge.to.props[:hidden] && edge.from.props[:spotlight] != 'shaded'
101
102
 
103
+ # Skip the edge if it's hidden itself
104
+ next if edge.props[:hidden]
105
+
102
106
  write_edge inline_attrs, edge
103
107
  end
104
108
  end
@@ -166,6 +170,24 @@ module Seafoam
166
170
  end
167
171
  end
168
172
 
173
+ # Write basic block outlines.
174
+ def write_blocks(graph)
175
+ graph.blocks.each do |block|
176
+ @stream.puts " subgraph cluster_block#{block.id} {"
177
+ @stream.puts ' fontname = "Arial";'
178
+ @stream.puts " label = \"B#{block.id}\";"
179
+ @stream.puts ' style=dotted;'
180
+
181
+ block.nodes.each do |node|
182
+ next if node.props[:hidden] || node.props[:inlined]
183
+
184
+ @stream.puts " node#{node.id};"
185
+ end
186
+
187
+ @stream.puts ' }'
188
+ end
189
+ end
190
+
169
191
  # Return attributes for a node or edge modified to 'shade' them in terms
170
192
  # the spotlight functionality - so basically make them light grey.
171
193
  def shade(attrs)
@@ -36,9 +36,7 @@ module Seafoam
36
36
  @out.puts JSON.pretty_generate(prepare_json(object))
37
37
  end
38
38
 
39
- private
40
-
41
- def prepare_json(object)
39
+ def self.prepare_json(object)
42
40
  case object
43
41
  when Float
44
42
  if object.nan?
@@ -1,15 +1,15 @@
1
1
  module Seafoam
2
- module Annotators
3
- # The fallback annotator always applies, and adds some basic annotations.
2
+ module Passes
3
+ # The fallback pass always applies, and adds some basic properties.
4
4
  # Works for example with Truffle AST and call graphs, but also means anyone
5
5
  # can emit a graph with 'label' properties and we can do something useful
6
6
  # with it.
7
- class FallbackAnnotator < Annotator
7
+ class FallbackPass < Pass
8
8
  def self.applies?(_graph)
9
9
  true
10
10
  end
11
11
 
12
- def annotate(graph)
12
+ def apply(graph)
13
13
  graph.nodes.each_value do |node|
14
14
  if node.props[:label].nil? && node.props['label']
15
15
  node.props[:label] = node.props['label']
@@ -1,18 +1,19 @@
1
1
  module Seafoam
2
- module Annotators
3
- # The Graal annotator applies if it looks like it was compiled by Graal or
2
+ module Passes
3
+ # The Graal pass applies if it looks like it was compiled by Graal or
4
4
  # Truffle.
5
- class GraalAnnotator < Annotator
5
+ class GraalPass < Pass
6
6
  def self.applies?(graph)
7
7
  graph.props.values.any? do |v|
8
8
  TRIGGERS.any? { |t| v.to_s.include?(t) }
9
9
  end
10
10
  end
11
11
 
12
- def annotate(graph)
13
- annotate_nodes graph
14
- annotate_edges graph
12
+ def apply(graph)
13
+ apply_nodes graph
14
+ apply_edges graph
15
15
  hide_frame_state graph if @options[:hide_frame_state]
16
+ hide_pi graph if @options[:hide_pi]
16
17
  hide_floating graph if @options[:hide_floating]
17
18
  reduce_edges graph if @options[:reduce_edges]
18
19
  hide_unused_nodes graph
@@ -21,8 +22,10 @@ module Seafoam
21
22
  private
22
23
 
23
24
  # Annotate nodes with their label and kind
24
- def annotate_nodes(graph)
25
+ def apply_nodes(graph)
25
26
  graph.nodes.each_value do |node|
27
+ next if node.props[:label]
28
+
26
29
  # The Java class of the node.
27
30
  node_class = node.props.dig(:node_class, :node_class)
28
31
 
@@ -93,6 +96,11 @@ module Seafoam
93
96
  name_template = 'π'
94
97
  end
95
98
 
99
+ # Use a symbol for PiArrayNode.
100
+ if node_class == 'org.graalvm.compiler.nodes.PiArrayNode'
101
+ name_template = '[π]'
102
+ end
103
+
96
104
  # Use a symbol for PhiNode.
97
105
  if node_class == 'org.graalvm.compiler.nodes.ValuePhiNode'
98
106
  name_template = 'ϕ'
@@ -208,7 +216,7 @@ module Seafoam
208
216
  end
209
217
 
210
218
  # Annotate edges with their label and kind.
211
- def annotate_edges(graph)
219
+ def apply_edges(graph)
212
220
  graph.edges.each do |edge|
213
221
  if edge.to.props.dig(:node_class, :node_class) == 'org.graalvm.compiler.nodes.ValuePhiNode' && edge.props[:name] == 'values'
214
222
  merge_node = edge.to.edges.find { |e| e.props[:name] == 'merge' }.from
@@ -254,8 +262,6 @@ module Seafoam
254
262
  # loopBegin edges point from LoopEndNode (continue) and LoopExitNode
255
263
  # (break) to the LoopBeginNode. Both are drawn reversed.
256
264
  when 'loopBegin'
257
- edge.props[:hidden] = true
258
-
259
265
  case edge.to.props.dig(:node_class, :node_class)
260
266
  when 'org.graalvm.compiler.nodes.LoopEndNode'
261
267
  # If it's from the LoopEnd then it's the control edge to follow.
@@ -311,6 +317,24 @@ module Seafoam
311
317
  end
312
318
  end
313
319
 
320
+ # Hide pi nodes - they add information for optimisation, but not generally
321
+ # useful day-to-day for understanding the graph. Connect the user to the
322
+ # actual object, which may be several steps away.
323
+ def hide_pi(graph)
324
+ loop do
325
+ umodified = true
326
+ graph.edges.each do |edge|
327
+ next unless Graal::Pi::PI_NODES.include?(edge.from.props.dig(:node_class, :node_class))
328
+
329
+ 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
332
+ umodified = false
333
+ end
334
+ break if umodified
335
+ end
336
+ end
337
+
314
338
  # Hide floating nodes. This highlights just the control flow backbone.
315
339
  def hide_floating(graph)
316
340
  graph.nodes.each_value do |node|
@@ -332,15 +356,19 @@ module Seafoam
332
356
  end
333
357
  end
334
358
 
335
- # Hide nodes that have no non-hidden users and no control flow in. These
336
- # would display as a node floating unconnected to the rest of the graph
337
- # otherwise. An exception is made for node with an anchor edge coming in,
338
- # as some guards are anchored like this.
359
+ # Hide nodes that have no non-hidden users or edges and no control flow
360
+ # in. These would display as a node floating unconnected to the rest of
361
+ # the graph otherwise. An exception is made for node with an anchor edge
362
+ # coming in, as some guards are anchored like this.
339
363
  def hide_unused_nodes(graph)
340
364
  loop do
341
365
  modified = false
342
366
  graph.nodes.each_value do |node|
343
- next unless node.outputs.all? { |edge| edge.to.props[:hidden] } &&
367
+ # Call trees are like Graal graphs but don't have these edges -
368
+ # don't hide them.
369
+ next if node.props['truffleCallees']
370
+
371
+ next unless node.outputs.all? { |edge| edge.to.props[:hidden] || edge.props[:hidden] } &&
344
372
  node.inputs.none? { |edge| edge.props[:kind] == 'control' } &&
345
373
  node.inputs.none? { |edge| edge.props[:name] == 'anchor' }
346
374