seafoam 0.8 → 0.9

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/commands.rb +48 -31
  7. data/lib/seafoam/graal/pi.rb +18 -0
  8. data/lib/seafoam/graph.rb +9 -1
  9. data/lib/seafoam/graphviz_writer.rb +3 -0
  10. data/lib/seafoam/json_writer.rb +1 -3
  11. data/lib/seafoam/{annotators → passes}/fallback.rb +4 -4
  12. data/lib/seafoam/{annotators → passes}/graal.rb +43 -13
  13. data/lib/seafoam/passes/truffle.rb +58 -0
  14. data/lib/seafoam/passes.rb +61 -0
  15. data/lib/seafoam/version.rb +1 -1
  16. data/lib/seafoam.rb +5 -4
  17. metadata +23 -60
  18. data/.github/probots.yml +0 -2
  19. data/.github/workflows/workflows.yml +0 -40
  20. data/.gitignore +0 -6
  21. data/.rubocop.yml +0 -37
  22. data/.ruby-version +0 -1
  23. data/.seafoam/config +0 -1
  24. data/CODE_OF_CONDUCT.md +0 -128
  25. data/CONTRIBUTING.md +0 -5
  26. data/Gemfile +0 -2
  27. data/Gemfile.lock +0 -59
  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 -294
  33. data/docs/getting-graphs.md +0 -63
  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 -22
  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 -167
  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 -314
  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: 6f5cdd6b29d9c25bc7db525b2f49d6937fb996bc108a7bf18ddf0364575e6999
4
- data.tar.gz: 510608b5d784ef4c58768aafb42372bdd33aad226a6123e9ad72ea77845a8050
3
+ metadata.gz: 49d090779b04322f8c82aae0cf11ea2e39cd4cef1f3d9dc2b51de1f27e565f9c
4
+ data.tar.gz: 121f1c7bb327c30f1a388960012c43dab49e0f1079d5a420811ab2332de9663b
5
5
  SHA512:
6
- metadata.gz: 125d9c14699c1a9a72bc1311b2673cf24d725af3c4da38eac1c2c89ebce4d6157c3e08ad7cc7b8769f8c755227cd04da4b9a6f53ae30f0f3ce38e7a1cf12d4b2
7
- data.tar.gz: 2430c0b5f04378767c5bbbb51274900deae22291fd905831f4a5d5847edd5e7497e3df94a434ab803689ee4f9b3f6cd5d6740bdc28dbf96d7da329c8610ac6e5
6
+ metadata.gz: dd13ee2efe4fe4118fc5f6bdb56c55b3c1c5f28b86a3d37ce3cf4fc72bcdcbeb161968260b62626047b9f9f9eedec53cbc743d79512a11bd77b195f054c54262
7
+ data.tar.gz: 67e06a4e89fdf9e6297e3d68da7f7b0e7d4f1de95a97c9be17c12e6c9114476ee6e747c6306c3bc472e549317f20c19c315c9789d1814c68fdd85501327c432b
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
@@ -3,9 +3,8 @@ require 'json'
3
3
  module Seafoam
4
4
  # Implementations of the command-line commands that you can run in Seafoam.
5
5
  class Commands
6
- def initialize(out, config)
6
+ def initialize(out)
7
7
  @out = out
8
- @config = config
9
8
  end
10
9
 
11
10
  # Run the general seafoam command.
@@ -15,25 +14,7 @@ module Seafoam
15
14
  when nil, 'help', '-h', '--help', '-help'
16
15
  raise ArgumentError, "unexpected arguments #{args.join(' ')}" unless args.empty?
17
16
 
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 ' --draw-blocks'
34
- @out.puts ' --option key value'
35
- @out.puts ' --help'
36
- @out.puts ' --version'
17
+ help(*args)
37
18
  when 'version', '-v', '-version', '--version'
38
19
  version(*args)
39
20
  else
@@ -263,7 +244,7 @@ module Seafoam
263
244
  end
264
245
 
265
246
  def search_object(tag, object, terms)
266
- full_text = JSON.generate(object)
247
+ full_text = JSON.generate(JSONWriter.prepare_json(object))
267
248
  full_text_down = full_text.downcase
268
249
  start = 0
269
250
  terms.each do |t|
@@ -299,7 +280,7 @@ module Seafoam
299
280
  parser.read_graph_header
300
281
  graph = parser.read_graph
301
282
  if node_id
302
- Annotators.apply graph
283
+ Passes.apply graph
303
284
  node = graph.nodes[node_id]
304
285
  raise ArgumentError, 'node not found' unless node
305
286
 
@@ -398,8 +379,10 @@ module Seafoam
398
379
  raise ArgumentError, 'render needs at least a graph' unless graph_index
399
380
  raise ArgumentError, 'render only works with a graph' unless rest == [nil, nil]
400
381
 
401
- annotator_options = {
382
+ pass_options = {
383
+ simplify_truffle_args: true,
402
384
  hide_frame_state: true,
385
+ hide_pi: true,
403
386
  hide_floating: false,
404
387
  reduce_edges: true
405
388
  }
@@ -420,12 +403,16 @@ module Seafoam
420
403
  raise ArgumentError, 'no list for --spotlight' unless spotlight_arg
421
404
 
422
405
  spotlight_nodes = spotlight_arg.split(',').map { |n| Integer(n) }
406
+ when '--full-truffle-args'
407
+ pass_options[:simplify_truffle_args] = false
423
408
  when '--show-frame-state'
424
- annotator_options[:hide_frame_state] = false
409
+ pass_options[:hide_frame_state] = false
410
+ when '--show-pi'
411
+ pass_options[:hide_pi] = false
425
412
  when '--hide-floating'
426
- annotator_options[:hide_floating] = true
413
+ pass_options[:hide_floating] = true
427
414
  when '--no-reduce-edges'
428
- annotator_options[:reduce_edges] = false
415
+ pass_options[:reduce_edges] = false
429
416
  when '--draw-blocks'
430
417
  draw_blocks = true
431
418
  when '--option'
@@ -436,7 +423,7 @@ module Seafoam
436
423
  raise ArgumentError, "no value for --option #{key}" unless out_file
437
424
 
438
425
  value = { 'true' => true, 'false' => 'false' }.fetch(key, value)
439
- annotator_options[key.to_sym] = value
426
+ pass_options[key.to_sym] = value
440
427
  else
441
428
  raise ArgumentError, "unexpected option #{arg}"
442
429
  end
@@ -459,7 +446,7 @@ module Seafoam
459
446
  with_graph(file, graph_index) do |parser|
460
447
  parser.skip_graph_header
461
448
  graph = parser.read_graph
462
- Annotators.apply graph, annotator_options
449
+ Passes.apply graph, pass_options
463
450
  if spotlight_nodes
464
451
  spotlight = Spotlight.new(graph)
465
452
  spotlight_nodes.each do |node_id|
@@ -569,6 +556,31 @@ module Seafoam
569
556
  raise ArgumentError, 'graph not found' unless graph_found
570
557
  end
571
558
 
559
+ # Prints help.
560
+ def help(*_args)
561
+ @out.puts 'seafoam file.bgv info'
562
+ @out.puts ' file.bgv list'
563
+ @out.puts ' file.bgv[:graph][:node[-edge]] search term...'
564
+ @out.puts ' file.bgv[:graph][:node[-edge]] edges'
565
+ @out.puts ' file.bgv[:graph][:node[-edge]] props'
566
+ @out.puts ' file.bgv:graph:node source'
567
+ @out.puts ' file.bgv:graph render'
568
+ @out.puts ' --spotlight n,n,n...'
569
+ @out.puts ' --out graph.pdf'
570
+ @out.puts ' graph.svg'
571
+ @out.puts ' graph.png'
572
+ @out.puts ' graph.dot'
573
+ @out.puts ' --full-truffle-args'
574
+ @out.puts ' --show-frame-state'
575
+ @out.puts ' --show-pi'
576
+ @out.puts ' --hide-floating'
577
+ @out.puts ' --no-reduce-edges'
578
+ @out.puts ' --draw-blocks'
579
+ @out.puts ' --option key value'
580
+ @out.puts ' --help'
581
+ @out.puts ' --version'
582
+ end
583
+
572
584
  # Prints the version.
573
585
  def version(*args)
574
586
  raise ArgumentError, "unexpected arguments #{args.join(' ')}" unless args.empty?
@@ -602,10 +614,15 @@ module Seafoam
602
614
 
603
615
  # Open a file for the user if possible.
604
616
  def autoopen(file)
605
- if RUBY_PLATFORM.include?('darwin') && @out.tty?
617
+ return unless @out.tty?
618
+
619
+ case RUBY_PLATFORM
620
+ when /darwin/
606
621
  system 'open', file
607
- # Don't worry if it fails.
622
+ when /linux/
623
+ system 'xdg-open', file
608
624
  end
625
+ # Don't worry if it fails.
609
626
  end
610
627
  end
611
628
  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,13 +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, :blocks
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
11
  @blocks = []
12
+ @new_id = 0
12
13
  end
13
14
 
14
15
  # Create a node.
@@ -16,6 +17,7 @@ module Seafoam
16
17
  props ||= {}
17
18
  node = Node.new(id, props)
18
19
  @nodes[id] = node
20
+ @new_id = id + 1
19
21
  node
20
22
  end
21
23
 
@@ -36,6 +38,12 @@ module Seafoam
36
38
  @blocks.push block
37
39
  block
38
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
39
47
  end
40
48
 
41
49
  # A node, with properties, input edges, and output edges.
@@ -100,6 +100,9 @@ module Seafoam
100
100
  # from a shaded node.
101
101
  next if edge.to.props[:hidden] && edge.from.props[:spotlight] != 'shaded'
102
102
 
103
+ # Skip the edge if it's hidden itself
104
+ next if edge.props[:hidden]
105
+
103
106
  write_edge inline_attrs, edge
104
107
  end
105
108
  end
@@ -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
@@ -311,6 +319,24 @@ module Seafoam
311
319
  end
312
320
  end
313
321
 
322
+ # Hide pi nodes - they add information for optimisation, but not generally
323
+ # useful day-to-day for understanding the graph. Connect the user to the
324
+ # actual object, which may be several steps away.
325
+ def hide_pi(graph)
326
+ loop do
327
+ umodified = true
328
+ graph.edges.each do |edge|
329
+ next unless Graal::Pi::PI_NODES.include?(edge.from.props.dig(:node_class, :node_class))
330
+
331
+ object = Graal::Pi.follow_pi_object(edge.from)
332
+ graph.create_edge object, edge.to, edge.props.merge({ synthetic: true })
333
+ graph.remove_edge edge
334
+ umodified = false
335
+ end
336
+ break if umodified
337
+ end
338
+ end
339
+
314
340
  # Hide floating nodes. This highlights just the control flow backbone.
315
341
  def hide_floating(graph)
316
342
  graph.nodes.each_value do |node|
@@ -332,15 +358,19 @@ module Seafoam
332
358
  end
333
359
  end
334
360
 
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.
361
+ # Hide nodes that have no non-hidden users or edges and no control flow
362
+ # in. These would display as a node floating unconnected to the rest of
363
+ # the graph otherwise. An exception is made for node with an anchor edge
364
+ # coming in, as some guards are anchored like this.
339
365
  def hide_unused_nodes(graph)
340
366
  loop do
341
367
  modified = false
342
368
  graph.nodes.each_value do |node|
343
- next unless node.outputs.all? { |edge| edge.to.props[:hidden] } &&
369
+ # Call trees are like Graal graphs but don't have these edges -
370
+ # don't hide them.
371
+ next if node.props['truffleCallees']
372
+
373
+ next unless node.outputs.all? { |edge| edge.to.props[:hidden] || edge.props[:hidden] } &&
344
374
  node.inputs.none? { |edge| edge.props[:kind] == 'control' } &&
345
375
  node.inputs.none? { |edge| edge.props[:name] == 'anchor' }
346
376
 
@@ -0,0 +1,58 @@
1
+ module Seafoam
2
+ module Passes
3
+ # The Truffle pass applies if it looks like it was compiled by Truffle.
4
+ class TrufflePass < Pass
5
+ def self.applies?(graph)
6
+ graph.props.values.any? do |v|
7
+ TRIGGERS.any? { |t| v.to_s.include?(t) }
8
+ end
9
+ end
10
+
11
+ def apply(graph)
12
+ simplify_truffle_args graph if @options[:simplify_truffle_args]
13
+ end
14
+
15
+ private
16
+
17
+ # Simplify a Truffle argument load into a single, inlined, node very much
18
+ # like a Graal parameter node.
19
+ def simplify_truffle_args(graph)
20
+ graph.nodes.dup.each_value do |node|
21
+ next unless node.props.dig(:node_class, :node_class) == 'org.graalvm.compiler.nodes.java.LoadIndexedNode'
22
+
23
+ index_node = node.inputs.find { |edge| edge.props[:name] == 'index' }.from
24
+ array_node = Graal::Pi.follow_pi_object(node.inputs.find { |edge| edge.props[:name] == 'array' }.from)
25
+
26
+ next unless index_node.props.dig(:node_class, :node_class) == 'org.graalvm.compiler.nodes.ConstantNode'
27
+ next unless array_node.props.dig(:node_class, :node_class) == 'org.graalvm.compiler.nodes.ParameterNode'
28
+
29
+ node.props[:truffle_arg_load] = true
30
+
31
+ index = index_node.props['rawvalue']
32
+
33
+ arg_node = graph.create_node(graph.new_id, { synthetic: true, inlined: true, label: "T(#{index})", kind: 'input' })
34
+
35
+ node.outputs.each do |output|
36
+ next if output.props[:name] == 'next'
37
+
38
+ graph.create_edge arg_node, output.to, output.props.dup
39
+ graph.remove_edge output
40
+ end
41
+ end
42
+
43
+ graph.nodes.each_value.select { |node| node.props[:truffle_arg_load] }.each do |node|
44
+ control_in = node.inputs.find { |edge| edge.props[:name] == 'next' }
45
+ control_out = node.outputs.find { |edge| edge.props[:name] == 'next' }
46
+ graph.create_edge control_in.from, control_out.to, { name: 'next' }
47
+ graph.remove_edge control_in
48
+ graph.remove_edge control_out
49
+ end
50
+ end
51
+
52
+ # If we see these in the graph properties it's probably a Truffle graph.
53
+ TRIGGERS = %w[
54
+ TruffleCompiler
55
+ ]
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,61 @@
1
+ module Seafoam
2
+ # Passes are routines to read the graph and apply properties which tools,
3
+ # such as the render command, can use to show more understandable output.
4
+ module Passes
5
+ # Apply all applicable passes to a graph.
6
+ def self.apply(graph, options = {})
7
+ passes.each do |pass|
8
+ next unless pass.applies?(graph)
9
+
10
+ # Record for information that the pass was applied this graph.
11
+ passes_applied = graph.props[:passes_applied] ||= []
12
+ passes_applied.push pass
13
+
14
+ # Run the pass.
15
+ instance = pass.new(options)
16
+ instance.apply graph
17
+ end
18
+ end
19
+
20
+ # Get a list of all passes in the system.
21
+ def self.passes
22
+ # We have a defined order for passes to run - these passes at the start.
23
+ pre_passes = [
24
+ TrufflePass,
25
+ GraalPass
26
+ ]
27
+
28
+ # The fallback pass runs last.
29
+ post_passes = [
30
+ FallbackPass
31
+ ]
32
+
33
+ # Any extra passes in the middle.
34
+ extra_passes = Pass::SUBCLASSES.dup - pre_passes - post_passes
35
+
36
+ pre_passes + extra_passes + post_passes
37
+ end
38
+ end
39
+
40
+ # The base class for all passes. You must subclass this to be recognized
41
+ # as an pass.
42
+ class Pass
43
+ SUBCLASSES = []
44
+
45
+ def initialize(options = {})
46
+ @options = options
47
+ end
48
+
49
+ def applies?(_graph)
50
+ raise NotImplementedError
51
+ end
52
+
53
+ def apply(_graph)
54
+ raise NotImplementedError
55
+ end
56
+
57
+ def self.inherited(pass)
58
+ SUBCLASSES.push pass
59
+ end
60
+ end
61
+ end
@@ -1,5 +1,5 @@
1
1
  module Seafoam
2
2
  MAJOR_VERSION = 0
3
- MINOR_VERSION = 8
3
+ MINOR_VERSION = 9
4
4
  VERSION = "#{MAJOR_VERSION}.#{MINOR_VERSION}"
5
5
  end
data/lib/seafoam.rb CHANGED
@@ -6,12 +6,13 @@ require 'seafoam/cfg/disassembler'
6
6
  require 'seafoam/colors'
7
7
  require 'seafoam/graph'
8
8
  require 'seafoam/graal/source'
9
- require 'seafoam/annotators'
10
- require 'seafoam/annotators/graal'
11
- require 'seafoam/annotators/fallback'
9
+ require 'seafoam/graal/pi'
10
+ require 'seafoam/passes'
11
+ require 'seafoam/passes/truffle'
12
+ require 'seafoam/passes/graal'
13
+ require 'seafoam/passes/fallback'
12
14
  require 'seafoam/spotlight'
13
15
  require 'seafoam/isabelle_writer'
14
16
  require 'seafoam/json_writer'
15
17
  require 'seafoam/graphviz_writer'
16
- require 'seafoam/config'
17
18
  require 'seafoam/commands'