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.
- checksums.yaml +4 -4
- data/bin/bgv2isabelle +3 -2
- data/bin/bgv2json +3 -2
- data/bin/seafoam +3 -2
- data/lib/seafoam/bgv/bgv_parser.rb +58 -50
- data/lib/seafoam/binary/io_binary_reader.rb +19 -17
- data/lib/seafoam/colors.rb +17 -11
- data/lib/seafoam/commands.rb +177 -153
- data/lib/seafoam/formatters/base.rb +2 -0
- data/lib/seafoam/formatters/formatters.rb +5 -3
- data/lib/seafoam/formatters/json.rb +8 -5
- data/lib/seafoam/formatters/text.rb +7 -4
- data/lib/seafoam/graal/graph_description.rb +9 -1
- data/lib/seafoam/graal/pi.rb +10 -6
- data/lib/seafoam/graal/source.rb +13 -9
- data/lib/seafoam/graph.rb +15 -9
- data/lib/seafoam/graphviz_writer.rb +129 -99
- data/lib/seafoam/isabelle_writer.rb +9 -7
- data/lib/seafoam/json_writer.rb +17 -13
- data/lib/seafoam/markdown_writer.rb +5 -3
- data/lib/seafoam/mermaid_writer.rb +36 -24
- data/lib/seafoam/passes/fallback.rb +10 -6
- data/lib/seafoam/passes/graal.rb +189 -161
- data/lib/seafoam/passes/truffle.rb +120 -22
- data/lib/seafoam/passes.rb +36 -29
- data/lib/seafoam/spotlight.rb +4 -2
- data/lib/seafoam/version.rb +3 -1
- data/lib/seafoam.rb +22 -20
- metadata +12 -12
@@ -1,15 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "tsort"
|
4
|
+
|
1
5
|
module Seafoam
|
2
6
|
module Passes
|
3
7
|
# The Truffle pass applies if it looks like it was compiled by Truffle.
|
4
8
|
class TrufflePass < Pass
|
5
|
-
|
6
|
-
graph
|
7
|
-
|
9
|
+
class << self
|
10
|
+
def applies?(graph)
|
11
|
+
graph.props.values.any? do |v|
|
12
|
+
TRIGGERS.any? { |t| v.to_s.include?(t) }
|
13
|
+
end
|
8
14
|
end
|
9
15
|
end
|
10
16
|
|
11
17
|
def apply(graph)
|
12
|
-
simplify_truffle_args
|
18
|
+
simplify_truffle_args(graph) if @options[:simplify_truffle_args]
|
19
|
+
simplify_alloc(graph) if @options[:simplify_alloc]
|
13
20
|
end
|
14
21
|
|
15
22
|
private
|
@@ -18,41 +25,132 @@ module Seafoam
|
|
18
25
|
# like a Graal parameter node.
|
19
26
|
def simplify_truffle_args(graph)
|
20
27
|
graph.nodes.dup.each_value do |node|
|
21
|
-
next unless node.
|
28
|
+
next unless node.node_class == "org.graalvm.compiler.nodes.java.LoadIndexedNode"
|
22
29
|
|
23
|
-
index_node = node.inputs.find { |edge| edge.props[:name] ==
|
24
|
-
array_node = Graal::Pi.follow_pi_object(node.inputs.find { |edge| edge.props[:name] ==
|
30
|
+
index_node = node.inputs.find { |edge| edge.props[:name] == "index" }.from
|
31
|
+
array_node = Graal::Pi.follow_pi_object(node.inputs.find { |edge| edge.props[:name] == "array" }.from)
|
25
32
|
|
26
|
-
next unless index_node.
|
27
|
-
next unless array_node.
|
33
|
+
next unless index_node.node_class == "org.graalvm.compiler.nodes.ConstantNode"
|
34
|
+
next unless array_node.node_class == "org.graalvm.compiler.nodes.ParameterNode"
|
28
35
|
|
29
36
|
node.props[:truffle_arg_load] = true
|
30
37
|
|
31
|
-
index = index_node.props[
|
38
|
+
index = index_node.props["rawvalue"]
|
32
39
|
|
33
|
-
arg_node = graph.create_node(graph.new_id,
|
40
|
+
arg_node = graph.create_node(graph.new_id,
|
41
|
+
{ synthetic: true, inlined: true, label: "T(#{index})", kind: "input" })
|
34
42
|
|
35
43
|
node.outputs.each do |output|
|
36
|
-
next if output.props[:name] ==
|
44
|
+
next if output.props[:name] == "next"
|
37
45
|
|
38
|
-
graph.create_edge
|
39
|
-
graph.remove_edge
|
46
|
+
graph.create_edge(arg_node, output.to, output.props.dup)
|
47
|
+
graph.remove_edge(output)
|
40
48
|
end
|
41
49
|
end
|
42
50
|
|
43
51
|
graph.nodes.each_value.select { |node| node.props[:truffle_arg_load] }.each do |node|
|
44
|
-
control_in = node.inputs.find { |edge| edge.props[:name] ==
|
45
|
-
control_out = node.outputs.find { |edge| edge.props[:name] ==
|
46
|
-
graph.create_edge
|
47
|
-
graph.remove_edge
|
48
|
-
graph.remove_edge
|
52
|
+
control_in = node.inputs.find { |edge| edge.props[:name] == "next" }
|
53
|
+
control_out = node.outputs.find { |edge| edge.props[:name] == "next" }
|
54
|
+
graph.create_edge(control_in.from, control_out.to, { name: "next" })
|
55
|
+
graph.remove_edge(control_in)
|
56
|
+
graph.remove_edge(control_out)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Hide nodes that are uninteresting inputs to an allocation node. These
|
61
|
+
# are constants that are null or 0.
|
62
|
+
def simplify_alloc(graph)
|
63
|
+
commit_allocation_nodes = graph.nodes.each_value.select do |node|
|
64
|
+
node.node_class == "org.graalvm.compiler.nodes.virtual.CommitAllocationNode"
|
65
|
+
end
|
66
|
+
|
67
|
+
commit_allocation_nodes.each do |commit_allocation_node|
|
68
|
+
control_flow_pred = commit_allocation_node.inputs.first
|
69
|
+
control_flow_next = commit_allocation_node.outputs.first
|
70
|
+
|
71
|
+
objects = []
|
72
|
+
virtual_to_object = {}
|
73
|
+
|
74
|
+
# First step to fill virtual_to_object and avoid ordering issues
|
75
|
+
commit_allocation_node.props.each_pair do |key, value|
|
76
|
+
m = /^object\((\d+)\)$/.match(key)
|
77
|
+
next unless m
|
78
|
+
|
79
|
+
virtual_id = m[1].to_i
|
80
|
+
|
81
|
+
(m = /^(\w+(?:\[\])?)\[([0-9,]+)\]$/.match(value)) || raise(value)
|
82
|
+
class_name, values = m.captures
|
83
|
+
values = values.split(",").map(&:to_i)
|
84
|
+
virtual_node = graph.nodes[virtual_id]
|
85
|
+
if virtual_node.node_class == "org.graalvm.compiler.nodes.virtual.VirtualArrayNode"
|
86
|
+
label = "New #{class_name[0...-1]}#{virtual_node.props["length"]}]"
|
87
|
+
fields = values.size.times.to_a
|
88
|
+
else
|
89
|
+
label = "New #{class_name}"
|
90
|
+
fields = virtual_node.props["fields"].map { |field| field[:name] }
|
91
|
+
end
|
92
|
+
raise unless fields.size == values.size
|
93
|
+
|
94
|
+
new_node = graph.create_node(graph.new_id, { synthetic: true, label: label, kind: "alloc" })
|
95
|
+
|
96
|
+
object = [new_node, virtual_node, fields, values]
|
97
|
+
objects << object
|
98
|
+
virtual_to_object[virtual_id] = object
|
99
|
+
end
|
100
|
+
|
101
|
+
# Topological sort of the new nodes in the control flow according to data dependencies
|
102
|
+
# There can be cycles (e.g., instances referring one another),
|
103
|
+
# so we use TSort.strongly_connected_components instead of TSort.tsort.
|
104
|
+
objects = TSort.strongly_connected_components(
|
105
|
+
objects.method(:each),
|
106
|
+
lambda do |(_new_node, _virtual_node, _fields, values), &b|
|
107
|
+
values.each do |value_id|
|
108
|
+
usage = virtual_to_object[value_id]
|
109
|
+
b.call(usage) if usage
|
110
|
+
end
|
111
|
+
end
|
112
|
+
).reduce(:concat)
|
113
|
+
|
114
|
+
prev = control_flow_pred.from
|
115
|
+
objects.each do |new_node, virtual_node, fields, values|
|
116
|
+
graph.create_edge(prev, new_node, control_flow_pred.props)
|
117
|
+
|
118
|
+
allocated_object_node = virtual_node.outputs.find do |output|
|
119
|
+
output.to.node_class == "org.graalvm.compiler.nodes.virtual.AllocatedObjectNode"
|
120
|
+
end
|
121
|
+
if allocated_object_node
|
122
|
+
allocated_object_node = allocated_object_node.to
|
123
|
+
|
124
|
+
allocated_object_node.outputs.each do |edge|
|
125
|
+
graph.create_edge(new_node, edge.to, edge.props)
|
126
|
+
end
|
127
|
+
|
128
|
+
allocated_object_node.props[:hidden] = true
|
129
|
+
end
|
130
|
+
|
131
|
+
fields.zip(values) do |field, value_id|
|
132
|
+
value_node = virtual_to_object[value_id]&.first || graph.nodes[value_id]
|
133
|
+
if @options[:hide_null_fields] &&
|
134
|
+
(value_node.node_class == "org.graalvm.compiler.nodes.ConstantNode") &&
|
135
|
+
["Object[null]", "0"].include?(value_node.props["rawvalue"])
|
136
|
+
value_node.props[:hidden] = true
|
137
|
+
else
|
138
|
+
graph.create_edge(value_node, new_node, { name: field })
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
virtual_node.props[:hidden] = true
|
143
|
+
|
144
|
+
prev = new_node
|
145
|
+
end
|
146
|
+
graph.create_edge(prev, control_flow_next.to, control_flow_next.props)
|
147
|
+
|
148
|
+
commit_allocation_node.props[:hidden] = true
|
49
149
|
end
|
50
150
|
end
|
51
151
|
|
52
152
|
# If we see these in the graph properties it's probably a Truffle graph.
|
53
|
-
TRIGGERS =
|
54
|
-
TruffleCompiler
|
55
|
-
]
|
153
|
+
TRIGGERS = ["TruffleCompiler"]
|
56
154
|
end
|
57
155
|
end
|
58
156
|
end
|
data/lib/seafoam/passes.rb
CHANGED
@@ -1,39 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Seafoam
|
2
4
|
# Passes are routines to read the graph and apply properties which tools,
|
3
5
|
# such as the render command, can use to show more understandable output.
|
4
6
|
module Passes
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
7
|
+
class << self
|
8
|
+
# Apply all applicable passes to a graph.
|
9
|
+
def apply(graph, options = {})
|
10
|
+
passes.each do |pass|
|
11
|
+
next unless pass.applies?(graph)
|
12
|
+
|
13
|
+
# Record for information that the pass was applied this graph.
|
14
|
+
passes_applied = graph.props[:passes_applied] ||= []
|
15
|
+
passes_applied.push(pass)
|
16
|
+
|
17
|
+
# Run the pass.
|
18
|
+
instance = pass.new(options)
|
19
|
+
instance.apply(graph)
|
20
|
+
end
|
17
21
|
end
|
18
|
-
end
|
19
22
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
# Get a list of all passes in the system.
|
24
|
+
def passes
|
25
|
+
# We have a defined order for passes to run - these passes at the start.
|
26
|
+
pre_passes = [
|
27
|
+
TrufflePass,
|
28
|
+
GraalPass,
|
29
|
+
]
|
27
30
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
31
|
+
# The fallback pass runs last.
|
32
|
+
post_passes = [
|
33
|
+
FallbackPass,
|
34
|
+
]
|
32
35
|
|
33
|
-
|
34
|
-
|
36
|
+
# Any extra passes in the middle.
|
37
|
+
extra_passes = Pass::SUBCLASSES.dup - pre_passes - post_passes
|
35
38
|
|
36
|
-
|
39
|
+
pre_passes + extra_passes + post_passes
|
40
|
+
end
|
37
41
|
end
|
38
42
|
end
|
39
43
|
|
@@ -54,8 +58,11 @@ module Seafoam
|
|
54
58
|
raise NotImplementedError
|
55
59
|
end
|
56
60
|
|
57
|
-
|
58
|
-
|
61
|
+
class << self
|
62
|
+
def inherited(pass)
|
63
|
+
super
|
64
|
+
SUBCLASSES.push(pass)
|
65
|
+
end
|
59
66
|
end
|
60
67
|
end
|
61
68
|
end
|
data/lib/seafoam/spotlight.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Seafoam
|
2
4
|
# Spotlight can *light* nodes, which makes them visible, their adjacent nodes
|
3
5
|
# visible by grey, and other nodes invisible. Multiple nodes can be *lit*.
|
@@ -9,11 +11,11 @@ module Seafoam
|
|
9
11
|
# Mark a node as lit by the spotlight.
|
10
12
|
def light(node)
|
11
13
|
# This node is lit.
|
12
|
-
node.props[:spotlight] =
|
14
|
+
node.props[:spotlight] = "lit"
|
13
15
|
|
14
16
|
# Adjacent nodes are shaded, if they haven't be lit themselvs.
|
15
17
|
node.adjacent.each do |adjacent|
|
16
|
-
adjacent.props[:spotlight] ||=
|
18
|
+
adjacent.props[:spotlight] ||= "shaded"
|
17
19
|
end
|
18
20
|
end
|
19
21
|
|
data/lib/seafoam/version.rb
CHANGED
data/lib/seafoam.rb
CHANGED
@@ -1,20 +1,22 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
13
|
-
require
|
14
|
-
require
|
15
|
-
require
|
16
|
-
require
|
17
|
-
require
|
18
|
-
require
|
19
|
-
require
|
20
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "seafoam/version"
|
4
|
+
require "seafoam/binary/io_binary_reader"
|
5
|
+
require "seafoam/bgv/bgv_parser"
|
6
|
+
require "seafoam/colors"
|
7
|
+
require "seafoam/graph"
|
8
|
+
require "seafoam/graal/graph_description"
|
9
|
+
require "seafoam/graal/source"
|
10
|
+
require "seafoam/graal/pi"
|
11
|
+
require "seafoam/passes"
|
12
|
+
require "seafoam/passes/truffle"
|
13
|
+
require "seafoam/passes/graal"
|
14
|
+
require "seafoam/passes/fallback"
|
15
|
+
require "seafoam/spotlight"
|
16
|
+
require "seafoam/isabelle_writer"
|
17
|
+
require "seafoam/json_writer"
|
18
|
+
require "seafoam/graphviz_writer"
|
19
|
+
require "seafoam/mermaid_writer"
|
20
|
+
require "seafoam/markdown_writer"
|
21
|
+
require "seafoam/commands"
|
22
|
+
require "seafoam/formatters/formatters"
|
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.
|
4
|
+
version: '0.14'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Seaton
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-02
|
11
|
+
date: 2022-09-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -39,21 +39,21 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '3.8'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name: rubocop
|
42
|
+
name: rubocop-shopify
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
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
|
-
version:
|
55
|
-
description:
|
56
|
-
email:
|
54
|
+
version: 2.9.0
|
55
|
+
description:
|
56
|
+
email:
|
57
57
|
executables:
|
58
58
|
- seafoam
|
59
59
|
- bgv2json
|
@@ -92,7 +92,7 @@ homepage: https://github.com/Shopify/seafoam
|
|
92
92
|
licenses:
|
93
93
|
- MIT
|
94
94
|
metadata: {}
|
95
|
-
post_install_message:
|
95
|
+
post_install_message:
|
96
96
|
rdoc_options: []
|
97
97
|
require_paths:
|
98
98
|
- lib
|
@@ -100,15 +100,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
100
100
|
requirements:
|
101
101
|
- - ">="
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: 2.
|
103
|
+
version: 2.7.0
|
104
104
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
105
|
requirements:
|
106
106
|
- - ">="
|
107
107
|
- !ruby/object:Gem::Version
|
108
108
|
version: '0'
|
109
109
|
requirements: []
|
110
|
-
rubygems_version: 3.3.
|
111
|
-
signing_key:
|
110
|
+
rubygems_version: 3.3.7
|
111
|
+
signing_key:
|
112
112
|
specification_version: 4
|
113
113
|
summary: A tool for working with compiler graphs
|
114
114
|
test_files: []
|