seafoam 0.14 → 0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 44f9af9b54052ddbfc03bc99833eb0af6e2e5f2bd0a5612a77ea10e3d30b3fca
4
- data.tar.gz: 7d1613577c3e033c69149eb51845540b88adc0c05bda3327c59a41c700647181
3
+ metadata.gz: 30a5f036d6ae3873ad70b1f113fe00015678efe83e5e2dfdbac8e7a2556e76ec
4
+ data.tar.gz: f8ee8f98c42e1d3a82a47fa58f50867553b5ffe1d532ed4ccebba9224314a4c0
5
5
  SHA512:
6
- metadata.gz: f35b3f93409e92be806e793817461900f66d7d1a8e91e6ae95fc52f66fa61955d7c48f0de1899ad15b35e88fa2b6b4cbb70fed976accb9f20ee7725f201828fe
7
- data.tar.gz: 03d4b654e6f2001128aa711ccddb4cccf09aed480d65578e0e49edb3d59c2acb5b594e3ef4f32b972e9821862aa24b9daa12c4fb7f1cef838a46c43c2c3b4fa9
6
+ metadata.gz: 0bd1f351f0e43737ba6182d156afd405b2d3d69b4b2804c8ef7d556062d857787b7d278a8edfb26462ed65add584a08741968244e9ab47b082a28783a16064a0
7
+ data.tar.gz: 4da1e9d9c3a5d27c94efbd37fb698820d3d44344b27f2eb030223f045b0f4ba358df2df9e0a0d4becb0b50e862700f493f8c6e587a3cf6b38b58df703468bd99
@@ -350,10 +350,20 @@ module Seafoam
350
350
  def describe(name, formatter_module, *args)
351
351
  file, graph_index, *rest = parse_name(name)
352
352
 
353
+ pass_options = DEFAULT_PASS_OPTIONS.dup
354
+ until args.empty?
355
+ arg = args.shift
356
+ case arg
357
+ when "--no-simplify"
358
+ pass_options.merge!(NO_SIMPLIFY_PASS_OPTIONS)
359
+ else
360
+ raise ArgumentError, "unexpected option #{arg}"
361
+ end
362
+ end
363
+
353
364
  if graph_index.nil? || !rest.all?(&:nil?)
354
365
  raise ArgumentError, "describe only works with a graph"
355
366
  end
356
- raise ArgumentError, "describe does not take arguments" unless args.empty?
357
367
 
358
368
  parser = BGV::BGVParser.new(file)
359
369
  parser.read_file_header
@@ -371,26 +381,33 @@ module Seafoam
371
381
  end
372
382
 
373
383
  graph = parser.read_graph
384
+ Passes.apply(graph, pass_options)
385
+
374
386
  description = Seafoam::Graal::GraphDescription.new
375
387
 
376
388
  graph.nodes.each_value do |node|
377
- node_class = node.node_class
389
+ next if node.props[:hidden]
378
390
 
379
- simple_node_class = node_class[/([^.]+)$/, 1]
380
- description.node_counts[simple_node_class] += 1
381
-
382
- case node_class
383
- when "org.graalvm.compiler.nodes.IfNode"
384
- description.branches = true
385
- when "org.graalvm.compiler.nodes.LoopBeginNode"
386
- description.loops = true
387
- when "org.graalvm.compiler.nodes.InvokeNode", "org.graalvm.compiler.nodes.InvokeWithExceptionNode"
388
- description.calls = true
391
+ node_class = node.node_class
392
+ if node_class
393
+ simple_node_class = node_class[/([^.]+)$/, 1]
394
+ description.node_counts[simple_node_class] += 1
395
+
396
+ case node_class
397
+ when "org.graalvm.compiler.nodes.IfNode"
398
+ description.branches = true
399
+ when "org.graalvm.compiler.nodes.LoopBeginNode"
400
+ description.loops = true
401
+ when "org.graalvm.compiler.nodes.InvokeNode", "org.graalvm.compiler.nodes.InvokeWithExceptionNode"
402
+ description.calls = true
403
+ end
404
+ elsif node.props[:synthetic_class]
405
+ description.node_counts["*" + node.props[:synthetic_class]] += 1
389
406
  end
390
- end
391
407
 
392
- description.deopts = graph.nodes[0].outputs.map(&:to)
393
- .all? { |t| t.node_class == "org.graalvm.compiler.nodes.DeoptimizeNode" }
408
+ description.deopts = graph.nodes[0].outputs.map(&:to)
409
+ .all? { |t| t.node_class == "org.graalvm.compiler.nodes.DeoptimizeNode" }
410
+ end
394
411
 
395
412
  formatter = formatter_module::DescribeFormatter.new(graph, description)
396
413
  @out.puts formatter.format
@@ -405,16 +422,7 @@ module Seafoam
405
422
  raise ArgumentError, "render needs at least a graph" unless graph_index
406
423
  raise ArgumentError, "render only works with a graph" unless rest == [nil, nil]
407
424
 
408
- pass_options = {
409
- simplify_truffle_args: true,
410
- hide_frame_state: true,
411
- hide_pi: true,
412
- hide_begin_end: true,
413
- hide_floating: false,
414
- reduce_edges: true,
415
- simplify_alloc: true,
416
- hide_null_fields: true,
417
- }
425
+ pass_options = DEFAULT_PASS_OPTIONS.dup
418
426
  spotlight_nodes = nil
419
427
  args = args.dup
420
428
  out_file = nil
@@ -456,6 +464,8 @@ module Seafoam
456
464
  spotlight_nodes = spotlight_arg.split(",").map { |n| Integer(n) }
457
465
  when "--full-truffle-args"
458
466
  pass_options[:simplify_truffle_args] = false
467
+ when "--show-reachability-fences"
468
+ pass_options[:hide_reachability_fences] = false
459
469
  when "--no-simplify-alloc"
460
470
  pass_options[:simplify_alloc] = false
461
471
  when "--show-null-fields"
@@ -470,6 +480,8 @@ module Seafoam
470
480
  pass_options[:hide_floating] = true
471
481
  when "--no-reduce-edges"
472
482
  pass_options[:reduce_edges] = false
483
+ when "--no-simplify"
484
+ pass_options.merge!(NO_SIMPLIFY_PASS_OPTIONS)
473
485
  when "--draw-blocks"
474
486
  draw_blocks = true
475
487
  when "--option"
@@ -477,7 +489,7 @@ module Seafoam
477
489
  raise ArgumentError, "no key for --option" unless key
478
490
 
479
491
  value = args.shift
480
- raise ArgumentError, "no value for --option #{key}" unless out_file
492
+ raise ArgumentError, "no value for --option #{key}" unless value
481
493
 
482
494
  value = { "true" => true, "false" => "false" }.fetch(key, value)
483
495
  pass_options[key.to_sym] = value
@@ -644,6 +656,7 @@ module Seafoam
644
656
  @out.puts " --show-begin-end"
645
657
  @out.puts " --hide-floating"
646
658
  @out.puts " --no-reduce-edges"
659
+ @out.puts " --no-simplify"
647
660
  @out.puts " --draw-blocks"
648
661
  @out.puts " --option key value"
649
662
  @out.puts " --help"
@@ -693,5 +706,27 @@ module Seafoam
693
706
  end
694
707
  # Don't worry if it fails.
695
708
  end
709
+
710
+ DEFAULT_PASS_OPTIONS = {
711
+ simplify_truffle_args: true,
712
+ hide_reachability_fences: true,
713
+ hide_frame_state: true,
714
+ hide_pi: true,
715
+ hide_begin_end: true,
716
+ hide_floating: false,
717
+ reduce_edges: true,
718
+ simplify_alloc: true,
719
+ hide_null_fields: true,
720
+ }
721
+
722
+ NO_SIMPLIFY_PASS_OPTIONS = {
723
+ simplify_truffle_args: false,
724
+ hide_reachability_fences: false,
725
+ simplify_alloc: false,
726
+ hide_null_fields: false,
727
+ hide_pi: false,
728
+ hide_begin_end: false,
729
+ reduce_edges: false,
730
+ }
696
731
  end
697
732
  end
@@ -9,7 +9,7 @@ module Seafoam
9
9
  class DescribeFormatter < Seafoam::Formatters::Base::DescribeFormatter
10
10
  def format
11
11
  ret = Seafoam::Graal::GraphDescription::ATTRIBUTES.map { |attr| [attr, description.send(attr)] }.to_h
12
- ret[:node_count] = graph.nodes.size
12
+ ret[:node_count] = graph.nodes.values.count { |n| !n.props[:hidden] }
13
13
  ret[:node_counts] = description.sorted_node_counts
14
14
 
15
15
  ret.to_json
@@ -7,9 +7,10 @@ module Seafoam
7
7
  class DescribeFormatter < Seafoam::Formatters::Base::DescribeFormatter
8
8
  def format
9
9
  notes = Seafoam::Graal::GraphDescription::ATTRIBUTES.select { |attr| description.send(attr) }
10
+ unhidden_count = graph.nodes.values.count { |n| !n.props[:hidden] }
10
11
  node_counts = description.sorted_node_counts.map { |node_class, count| "#{node_class}: #{count}" }.join("\n")
11
12
 
12
- ["#{graph.nodes.size} nodes", *notes].join(", ") + "\n#{node_counts}"
13
+ ["#{unhidden_count} nodes", *notes].join(", ") + "\n#{node_counts}"
13
14
  end
14
15
  end
15
16
 
data/lib/seafoam/graph.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "set"
4
+
3
5
  module Seafoam
4
6
  # A graph, with properties, nodes, and edges. We don't encapsulate the graph
5
7
  # too much - be careful.
@@ -87,6 +89,18 @@ module Seafoam
87
89
  def inspect
88
90
  "<Node #{id} #{node_class}>"
89
91
  end
92
+
93
+ def visit(&block)
94
+ block.call(self)
95
+ end
96
+
97
+ def visit_outputs(search_strategy, &block)
98
+ if search_strategy == :bfs
99
+ BFS.new(self).search(&block)
100
+ else
101
+ raise "Unknown search strategy: #{search_strategy}"
102
+ end
103
+ end
90
104
  end
91
105
 
92
106
  # A directed edge, with a node it's from and a node it's going to, and
@@ -16,14 +16,14 @@ module Seafoam
16
16
  graph.nodes.each_value do |node|
17
17
  nodes.push(
18
18
  id: node.id,
19
- props: node.props
19
+ props: node.props,
20
20
  )
21
21
 
22
22
  node.outputs.each do |edge|
23
23
  edges.push(
24
24
  from: edge.from.id,
25
25
  to: edge.to.id,
26
- props: edge.props
26
+ props: edge.props,
27
27
  )
28
28
  end
29
29
  end
@@ -212,9 +212,13 @@ module Seafoam
212
212
  "#{node.props.dig("field", :field_class).split(".").last}.#{node.props.dig("field", :name)}"
213
213
  end
214
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"]}"
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"]}"
218
222
  end
219
223
  string = string.gsub(/\{x#simpleStamp\}/) do |_|
220
224
  stamp = node.props.dig("checkedStamp")
@@ -417,14 +421,16 @@ module Seafoam
417
421
  end
418
422
 
419
423
  # If we see these in the graph properties it's probably a Graal graph.
420
- TRIGGERS = ["HostedGraphBuilderPhase", "GraalCompiler", "TruffleCompiler"]
424
+ TRIGGERS = ["HostedGraphBuilderPhase", "GraalCompiler", "TruffleCompiler", "SubstrateCompilation"]
421
425
 
422
426
  # Simple input node classes that may be inlined.
423
427
  SIMPLE_INPUTS = ["org.graalvm.compiler.nodes.ConstantNode", "org.graalvm.compiler.nodes.ParameterNode"]
424
428
 
425
429
  # Nodes just to maintain frame state.
426
- FRAME_STATE_NODES = ["org.graalvm.compiler.nodes.FrameState",
427
- "org.graalvm.compiler.virtual.nodes.MaterializedObjectState",]
430
+ FRAME_STATE_NODES = [
431
+ "org.graalvm.compiler.nodes.FrameState",
432
+ "org.graalvm.compiler.virtual.nodes.MaterializedObjectState",
433
+ ]
428
434
 
429
435
  BEGIN_END_NODES = ["org.graalvm.compiler.nodes.BeginNode", "org.graalvm.compiler.nodes.EndNode"]
430
436
  end
@@ -17,6 +17,7 @@ module Seafoam
17
17
  def apply(graph)
18
18
  simplify_truffle_args(graph) if @options[:simplify_truffle_args]
19
19
  simplify_alloc(graph) if @options[:simplify_alloc]
20
+ hide_reachability_fences(graph) if @options[:hide_reachability_fences]
20
21
  end
21
22
 
22
23
  private
@@ -35,17 +36,24 @@ module Seafoam
35
36
 
36
37
  node.props[:truffle_arg_load] = true
37
38
 
38
- index = index_node.props["rawvalue"]
39
+ lang_formatter = Seafoam::Passes::TruffleTranslators.get_translator(node)
40
+ index = lang_formatter.translate_argument_load(index_node.props["rawvalue"].to_i)
39
41
 
40
- arg_node = graph.create_node(graph.new_id,
41
- { synthetic: true, inlined: true, label: "T(#{index})", kind: "input" })
42
+ arg_node = graph.create_node(
43
+ graph.new_id,
44
+ { synthetic: true, synthetic_class: "TruffleArgument", inlined: true, label: "T(#{index})", kind: "input" },
45
+ )
46
+
47
+ edges_to_remove = []
42
48
 
43
49
  node.outputs.each do |output|
44
50
  next if output.props[:name] == "next"
45
51
 
46
52
  graph.create_edge(arg_node, output.to, output.props.dup)
47
- graph.remove_edge(output)
53
+ edges_to_remove << output
48
54
  end
55
+
56
+ edges_to_remove.each { |edge| graph.remove_edge(edge) }
49
57
  end
50
58
 
51
59
  graph.nodes.each_value.select { |node| node.props[:truffle_arg_load] }.each do |node|
@@ -78,7 +86,12 @@ module Seafoam
78
86
 
79
87
  virtual_id = m[1].to_i
80
88
 
81
- (m = /^(\w+(?:\[\])?)\[([0-9,]+)\]$/.match(value)) || raise(value)
89
+ m = /^([[:alnum:]$]+(?:\[\])?)\[([0-9,]+)\]$/.match(value)
90
+
91
+ unless m
92
+ raise "Unexpected value in allocation node: '#{value}'"
93
+ end
94
+
82
95
  class_name, values = m.captures
83
96
  values = values.split(",").map(&:to_i)
84
97
  virtual_node = graph.nodes[virtual_id]
@@ -91,7 +104,10 @@ module Seafoam
91
104
  end
92
105
  raise unless fields.size == values.size
93
106
 
94
- new_node = graph.create_node(graph.new_id, { synthetic: true, label: label, kind: "alloc" })
107
+ new_node = graph.create_node(
108
+ graph.new_id,
109
+ { synthetic: true, synthetic_class: "TruffleNew", label: label, kind: "alloc" },
110
+ )
95
111
 
96
112
  object = [new_node, virtual_node, fields, values]
97
113
  objects << object
@@ -108,7 +124,7 @@ module Seafoam
108
124
  usage = virtual_to_object[value_id]
109
125
  b.call(usage) if usage
110
126
  end
111
- end
127
+ end,
112
128
  ).reduce(:concat)
113
129
 
114
130
  prev = control_flow_pred.from
@@ -149,8 +165,24 @@ module Seafoam
149
165
  end
150
166
  end
151
167
 
168
+ # Hide reachability fences - they're just really boring.
169
+ def hide_reachability_fences(graph)
170
+ graph.nodes.each_value do |node|
171
+ next unless node.node_class == "org.graalvm.compiler.nodes.java.ReachabilityFenceNode"
172
+
173
+ pred = node.inputs.find { |edge| edge.props[:name] == "next" }
174
+ succ = node.outputs.find { |edge| edge.props[:name] == "next" }
175
+
176
+ graph.create_edge(pred.from, succ.to, pred.props.merge({ synthetic: true }))
177
+
178
+ node.props[:hidden] = true
179
+ pred.props[:hidden] = true
180
+ succ.props[:hidden] = true
181
+ end
182
+ end
183
+
152
184
  # If we see these in the graph properties it's probably a Truffle graph.
153
- TRIGGERS = ["TruffleCompiler"]
185
+ TRIGGERS = ["TruffleCompiler", "TruffleFinal"]
154
186
  end
155
187
  end
156
188
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Seafoam
4
+ module Passes
5
+ module TruffleTranslators
6
+ class Default
7
+ def translate_argument_load(index)
8
+ index.to_s
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "set"
4
+
5
+ module Seafoam
6
+ module Passes
7
+ module TruffleTranslators
8
+ autoload :Default, "seafoam/passes/truffle_translators/default"
9
+ autoload :TruffleRuby, "seafoam/passes/truffle_translators/truffleruby"
10
+
11
+ TRUFFLE_LANGUAGES = {
12
+ "org.truffleruby" => "TruffleRuby",
13
+ }
14
+
15
+ class << self
16
+ def get_translator(node)
17
+ translator = node.visit_outputs(:bfs) do |entry|
18
+ declaring_class = entry.props["code"] || entry.props.dig("nodeSourcePosition", :method)
19
+
20
+ if declaring_class
21
+ subpackage = declaring_class[:declaring_class].match(/^(\w+\.\w+)\./)[1]
22
+ translator = TRUFFLE_LANGUAGES[subpackage]
23
+
24
+ break const_get(translator).new if translator
25
+ end
26
+ end
27
+
28
+ translator || Default.new
29
+ end
30
+ end
31
+
32
+ class Default
33
+ def translate_argument_load(index)
34
+ index.to_s
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Seafoam
4
+ module Passes
5
+ module TruffleTranslators
6
+ class TruffleRuby < Default
7
+ TRUFFLERUBY_ARGS = [
8
+ "DECLARATION_FRAME",
9
+ "CALLER_SPECIAL_VARIABLES",
10
+ "METHOD",
11
+ "DECLARATION_CONTEXT",
12
+ "FRAME_ON_STACK_MARKER",
13
+ "SELF",
14
+ "BLOCK",
15
+ "DESCRIPTOR",
16
+ ]
17
+
18
+ def translate_argument_load(index)
19
+ index >= TRUFFLERUBY_ARGS.size ? "args[#{index - TRUFFLERUBY_ARGS.size}]" : TRUFFLERUBY_ARGS[index]
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "set"
4
+
5
+ module Seafoam
6
+ class BFS
7
+ attr_reader :root
8
+
9
+ def initialize(root)
10
+ @root = root
11
+ end
12
+
13
+ def search(&block)
14
+ queue = root.outputs.collect(&:to)
15
+ visited = Set.new
16
+
17
+ until queue.empty?
18
+ entry = queue.shift
19
+ visited << entry
20
+
21
+ result = entry.visit(&block)
22
+
23
+ if result
24
+ return result
25
+ else
26
+ entry.outputs.collect(&:to).each do |child|
27
+ queue << child unless visited.include?(child)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Seafoam
4
4
  MAJOR_VERSION = 0
5
- MINOR_VERSION = 14
5
+ MINOR_VERSION = 15
6
6
  VERSION = "#{MAJOR_VERSION}.#{MINOR_VERSION}"
7
7
  end
data/lib/seafoam.rb CHANGED
@@ -9,6 +9,7 @@ require "seafoam/graal/graph_description"
9
9
  require "seafoam/graal/source"
10
10
  require "seafoam/graal/pi"
11
11
  require "seafoam/passes"
12
+ require "seafoam/passes/truffle_translators/translators"
12
13
  require "seafoam/passes/truffle"
13
14
  require "seafoam/passes/graal"
14
15
  require "seafoam/passes/fallback"
@@ -20,3 +21,4 @@ require "seafoam/mermaid_writer"
20
21
  require "seafoam/markdown_writer"
21
22
  require "seafoam/commands"
22
23
  require "seafoam/formatters/formatters"
24
+ require "seafoam/search"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: seafoam
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.14'
4
+ version: '0.15'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Seaton
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-09-02 00:00:00.000000000 Z
11
+ date: 2023-01-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -42,14 +42,14 @@ dependencies:
42
42
  name: rubocop-shopify
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: 2.9.0
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: 2.9.0
55
55
  description:
@@ -86,12 +86,19 @@ files:
86
86
  - lib/seafoam/passes/fallback.rb
87
87
  - lib/seafoam/passes/graal.rb
88
88
  - lib/seafoam/passes/truffle.rb
89
+ - lib/seafoam/passes/truffle_translators/default.rb
90
+ - lib/seafoam/passes/truffle_translators/translators.rb
91
+ - lib/seafoam/passes/truffle_translators/truffleruby.rb
92
+ - lib/seafoam/search.rb
89
93
  - lib/seafoam/spotlight.rb
90
94
  - lib/seafoam/version.rb
91
95
  homepage: https://github.com/Shopify/seafoam
92
96
  licenses:
93
97
  - MIT
94
- metadata: {}
98
+ metadata:
99
+ bug_tracker_uri: https://github.com/Shopify/seafoam/issues
100
+ source_code_uri: https://github.com/Shopify/seafoam
101
+ allowed_push_host: https://rubygems.org
95
102
  post_install_message:
96
103
  rdoc_options: []
97
104
  require_paths:
@@ -107,7 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
107
114
  - !ruby/object:Gem::Version
108
115
  version: '0'
109
116
  requirements: []
110
- rubygems_version: 3.3.7
117
+ rubygems_version: 3.3.3
111
118
  signing_key:
112
119
  specification_version: 4
113
120
  summary: A tool for working with compiler graphs