seafoam 0.14 → 0.15

Sign up to get free protection for your applications and to get access to all the features.
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