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
@@ -1,278 +0,0 @@
1
- # truffleruby_primitives: true
2
-
3
- # We're using Graal with graal.patch, to disable some inlining.
4
-
5
- # % ruby --jvm --experimental-options --engine.OSR=false --engine.MultiTier=false --engine.TraceCompilation --vm.Dgraal.Dump=Truffle:1 ruby_examples.rb
6
-
7
- RANDOM = Random.new
8
- EXCEPTION = Exception.new
9
-
10
- def example_local_variables(x, y)
11
- a = x + y
12
- a * 2 + a
13
- end
14
-
15
- def example_local_variables_state(x, y)
16
- a = x + y
17
- opaque_call
18
- a * 2 + a
19
- end
20
-
21
- def example_arith_operator(x, y)
22
- x + y
23
- end
24
-
25
- def example_compare_operator(x, y)
26
- x <= y
27
- end
28
-
29
- def example_phi(condition, x)
30
- if condition
31
- a = opaque_call_a
32
- else
33
- a = opaque_call_b
34
- end
35
- a + x
36
- end
37
-
38
- def example_simple_call(object, x)
39
- object.instance_call(x)
40
- end
41
-
42
- def example_stamp(x)
43
- x & 0x1234
44
- end
45
-
46
- def example_full_escape(x)
47
- a = [x]
48
- Primitive.blackhole a
49
- a[0]
50
- end
51
-
52
- def example_no_escape(x)
53
- a = [x]
54
- a[0]
55
- end
56
-
57
- def example_partial_escape(condition, x)
58
- a = [x]
59
- if condition
60
- Primitive.blackhole a
61
- a[0]
62
- else
63
- a[0]
64
- end
65
- end
66
-
67
- def example_if(condition, x, y)
68
- if condition
69
- Primitive.blackhole x
70
- a = x
71
- else
72
- Primitive.blackhole y
73
- a = y
74
- end
75
- a
76
- end
77
-
78
- def example_if_never_taken(condition, x, y)
79
- if condition
80
- Primitive.blackhole x
81
- a = x
82
- else
83
- Primitive.blackhole y
84
- a = y
85
- end
86
- a
87
- end
88
-
89
- def example_int_switch(value, x, y, z)
90
- case value
91
- when 0
92
- Primitive.blackhole x
93
- a = x
94
- when 1
95
- Primitive.blackhole y
96
- a = y
97
- else
98
- Primitive.blackhole z
99
- a = z
100
- end
101
- a
102
- end
103
-
104
- def example_string_switch(value, x, y, z)
105
- case value
106
- when 'foo'
107
- Primitive.blackhole x
108
- a = x
109
- when 'bar'
110
- Primitive.blackhole y
111
- a = y
112
- else
113
- Primitive.blackhole z
114
- a = z
115
- end
116
- a
117
- end
118
-
119
- def example_while(count)
120
- a = count
121
- while a > 0
122
- Primitive.blackhole a
123
- a -= 1
124
- end
125
- count
126
- end
127
-
128
- def example_for(count)
129
- count.times do |a|
130
- Primitive.blackhole a
131
- end
132
- end
133
-
134
- def example_nested_while(count)
135
- a = count
136
- while (a > 0)
137
- y = count
138
- while (y > 0)
139
- Primitive.blackhole a
140
- y -= 1
141
- end
142
- a -= 1
143
- end
144
- count
145
- end
146
-
147
- def example_while_break(count)
148
- a = count
149
- while a > 0
150
- if a == 4
151
- break
152
- end
153
- Primitive.blackhole a
154
- a -= 1
155
- end
156
- count
157
- end
158
-
159
- def example_raise
160
- raise EXCEPTION
161
- end
162
-
163
- def example_rescue
164
- begin
165
- opaque_raise
166
- rescue Exception => e
167
- Primitive.blackhole e
168
- end
169
- end
170
-
171
- def example_raise_rescue
172
- begin
173
- raise EXCEPTION
174
- rescue Exception => e
175
- Primitive.blackhole e
176
- end
177
- end
178
-
179
- def example_object_allocation(x)
180
- ExampleObject.new(x)
181
- end
182
-
183
- def example_array_allocation(x, y)
184
- [x, y]
185
- end
186
-
187
- def example_field_write(object, x)
188
- object.x = x
189
- end
190
-
191
- def example_field_read(object)
192
- object.x
193
- end
194
-
195
- def example_array_write(array, n, x)
196
- array[n] = x
197
- end
198
-
199
- def example_array_read(array, n)
200
- array[n]
201
- end
202
-
203
- def example_instance_of(x)
204
- x.is_a?(ExampleObject)
205
- end
206
-
207
- # no inline
208
- def opaque_call
209
- RANDOM.rand(1000)
210
- end
211
-
212
- # no inline
213
- def opaque_call_a
214
- opaque_call
215
- end
216
-
217
- # no inline
218
- def opaque_call_b
219
- opaque_call
220
- end
221
-
222
- # no inline
223
- def opaque_raise
224
- raise EXCEPTION
225
- end
226
-
227
- # no inline
228
- def static_call(x)
229
- x
230
- end
231
-
232
- class ExampleObject
233
- attr_accessor :x
234
-
235
- def initialize(x)
236
- @x = x
237
- end
238
-
239
- # no inline
240
- def instance_call(y)
241
- @x + y
242
- end
243
- end
244
-
245
- loop do
246
- example_local_variables RANDOM.rand(1000), RANDOM.rand(1000)
247
- example_local_variables_state RANDOM.rand(1000), RANDOM.rand(1000)
248
- example_arith_operator RANDOM.rand(1000), RANDOM.rand(1000)
249
- example_compare_operator RANDOM.rand(1000), RANDOM.rand(1000)
250
- example_phi [true, false].sample, RANDOM.rand(1000)
251
- example_simple_call ExampleObject.new(RANDOM.rand(1000)), RANDOM.rand(1000)
252
- example_stamp RANDOM.rand(1000)
253
- example_full_escape RANDOM.rand(1000)
254
- example_no_escape RANDOM.rand(1000)
255
- example_partial_escape [true, false].sample, RANDOM.rand(1000)
256
- example_if [true, false].sample, RANDOM.rand(1000), RANDOM.rand(1000)
257
- example_if_never_taken false, RANDOM.rand(1000), RANDOM.rand(1000)
258
- example_int_switch RANDOM.rand(3), RANDOM.rand(1000), RANDOM.rand(1000), RANDOM.rand(1000)
259
- example_string_switch ['foo', 'bar', 'baz'].sample, RANDOM.rand(1000), RANDOM.rand(1000), RANDOM.rand(1000)
260
- example_while RANDOM.rand(10)
261
- example_for RANDOM.rand(10)
262
- example_nested_while RANDOM.rand(10)
263
- example_while_break RANDOM.rand(10)
264
- begin
265
- example_raise
266
- rescue Exception => e
267
- #
268
- end
269
- example_rescue
270
- example_raise_rescue
271
- example_object_allocation RANDOM.rand(1000)
272
- example_array_allocation RANDOM.rand(1000), RANDOM.rand(1000)
273
- example_field_write ExampleObject.new(RANDOM.rand(1000)), RANDOM.rand(1000)
274
- example_field_read ExampleObject.new(RANDOM.rand(1000))
275
- example_array_write [RANDOM.rand(1000), RANDOM.rand(1000), RANDOM.rand(1000)], RANDOM.rand(3), RANDOM.rand(1000)
276
- example_array_read [RANDOM.rand(1000), RANDOM.rand(1000), RANDOM.rand(1000)], RANDOM.rand(3)
277
- example_instance_of [Object.new, ExampleObject.new(0)].sample
278
- end
@@ -1,54 +0,0 @@
1
- module Seafoam
2
- # Annotators 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 Annotators
5
- # Apply all applicable annotators to a graph.
6
- def self.apply(graph, options = {})
7
- annotators.each do |annotator|
8
- next unless annotator.applies?(graph)
9
-
10
- # Record for information that the annotator annotated this graph.
11
- annotated_by = graph.props[:annotated_by] ||= []
12
- annotated_by.push annotator
13
-
14
- # Run the annotator.
15
- instance = annotator.new(options)
16
- instance.annotate graph
17
- end
18
- end
19
-
20
- # Get a list of all annotators in the system.
21
- def self.annotators
22
- # Get all subclasses of Annotator.
23
- annotators = Annotator::SUBCLASSES.dup
24
-
25
- # We want the FallbackAnnotator to run last.
26
- annotators.delete FallbackAnnotator
27
- annotators.push FallbackAnnotator
28
-
29
- annotators
30
- end
31
- end
32
-
33
- # The base class for all annotators. You must subclass this to be recognized
34
- # as an annotator.
35
- class Annotator
36
- SUBCLASSES = []
37
-
38
- def initialize(options = {})
39
- @options = options
40
- end
41
-
42
- def applies?(_graph)
43
- raise NotImplementedError
44
- end
45
-
46
- def annotate(_graph)
47
- raise NotImplementedError
48
- end
49
-
50
- def self.inherited(annotator)
51
- SUBCLASSES.push annotator
52
- end
53
- end
54
- end
@@ -1,34 +0,0 @@
1
- module Seafoam
2
- # Finds and loads configuration.
3
- class Config
4
- def initialize
5
- @dot_dir = find_dot_dir
6
- end
7
-
8
- # Load the configuration.
9
- def load_config
10
- config_file = File.expand_path('config', @dot_dir)
11
- if File.exist?(config_file)
12
- puts "loading config #{config_file}" if $DEBUG
13
- load config_file
14
- end
15
- end
16
-
17
- private
18
-
19
- # Walk up the directory chain from the current directory to root, looking
20
- # for .seafoam.
21
- def find_dot_dir
22
- dir = Dir.getwd
23
- loop do
24
- dot_dir = File.expand_path('.seafoam', dir)
25
- return dot_dir if Dir.exist?(dot_dir)
26
-
27
- new_dir = File.expand_path('..', dir)
28
- break if new_dir == dir
29
-
30
- dir = new_dir
31
- end
32
- end
33
- end
34
- end
data/seafoam.gemspec DELETED
@@ -1,22 +0,0 @@
1
- require_relative 'lib/seafoam/version'
2
-
3
- Gem::Specification.new do |spec|
4
- spec.name = 'seafoam'
5
- spec.version = Seafoam::VERSION
6
- spec.summary = 'A tool for working with compiler graphs'
7
- spec.authors = ['Chris Seaton']
8
- spec.homepage = 'https://github.com/Shopify/seafoam'
9
- spec.license = 'MIT'
10
-
11
- spec.files = `git ls-files`.split("\n").reject { |f| f.end_with?('.bgv') || f.end_with?('.cfg') }
12
- spec.bindir = 'bin'
13
- spec.executables = %w[seafoam bgv2json bgv2isabelle cfg2asm]
14
-
15
- spec.required_ruby_version = '>= 2.5.8'
16
-
17
- spec.add_dependency 'crabstone', '~> 4.0'
18
-
19
- spec.add_development_dependency 'benchmark-ips', '~> 2.7'
20
- spec.add_development_dependency 'rspec', '~> 3.8'
21
- spec.add_development_dependency 'rubocop', '~> 0.74'
22
- end
@@ -1,69 +0,0 @@
1
- require 'seafoam'
2
-
3
- require 'rspec'
4
-
5
- describe Seafoam::Annotators::FallbackAnnotator do
6
- it 'always applies' do
7
- expect(Seafoam::Annotators::FallbackAnnotator.applies?(Seafoam::Graph.new)).to be true
8
- end
9
-
10
- it 'adds a label annotation when there is a label property' do
11
- graph = Seafoam::Graph.new
12
- node = graph.create_node(0, 'label' => 'foo')
13
- annotator = Seafoam::Annotators::FallbackAnnotator.new
14
- annotator.annotate graph
15
- expect(node.props[:label]).to eq 'foo'
16
- end
17
-
18
- it 'does not overwrite an existing label annotation' do
19
- graph = Seafoam::Graph.new
20
- node = graph.create_node(0, 'label' => 'foo', :label => 'bar')
21
- annotator = Seafoam::Annotators::FallbackAnnotator.new
22
- annotator.annotate graph
23
- expect(node.props[:label]).to eq 'bar'
24
- end
25
-
26
- it 'adds nothing when there is no label property' do
27
- graph = Seafoam::Graph.new
28
- node = graph.create_node(0, 'xlabel' => 'foo')
29
- annotator = Seafoam::Annotators::FallbackAnnotator.new
30
- annotator.annotate graph
31
- expect(node.props[:label]).to be nil
32
- end
33
-
34
- it 'sets node kind to other when there is no kind' do
35
- graph = Seafoam::Graph.new
36
- node = graph.create_node(0)
37
- annotator = Seafoam::Annotators::FallbackAnnotator.new
38
- annotator.annotate graph
39
- expect(node.props[:kind]).to eq 'other'
40
- end
41
-
42
- it 'does not overwrite an existing node kind annotations' do
43
- graph = Seafoam::Graph.new
44
- node = graph.create_node(0, kind: 'control')
45
- annotator = Seafoam::Annotators::FallbackAnnotator.new
46
- annotator.annotate graph
47
- expect(node.props[:kind]).to eq 'control'
48
- end
49
-
50
- it 'sets edge kind to other when there is no kind' do
51
- graph = Seafoam::Graph.new
52
- node_a = graph.create_node(0)
53
- node_b = graph.create_node(1)
54
- edge = graph.create_edge(node_a, node_b)
55
- annotator = Seafoam::Annotators::FallbackAnnotator.new
56
- annotator.annotate graph
57
- expect(edge.props[:kind]).to eq 'other'
58
- end
59
-
60
- it 'does not overwrite an existing edge kind annotations' do
61
- graph = Seafoam::Graph.new
62
- node_a = graph.create_node(0)
63
- node_b = graph.create_node(1)
64
- edge = graph.create_edge(node_a, node_b, kind: 'control')
65
- annotator = Seafoam::Annotators::FallbackAnnotator.new
66
- annotator.annotate graph
67
- expect(edge.props[:kind]).to eq 'control'
68
- end
69
- end
@@ -1,96 +0,0 @@
1
- require 'seafoam'
2
-
3
- require 'rspec'
4
-
5
- require_relative '../spec_helpers'
6
-
7
- describe Seafoam::Annotators::GraalAnnotator do
8
- it 'applies to Graal graphs' do
9
- expect(Seafoam::Annotators::GraalAnnotator.applies?(Seafoam::SpecHelpers.example_graph('fib-java', 0))).to be true
10
- end
11
-
12
- it 'does not apply to Truffle trees' do
13
- expect(Seafoam::Annotators::GraalAnnotator.applies?(Seafoam::SpecHelpers.example_graph('fib-js', 0))).to be false
14
- end
15
-
16
- it 'applies to Truffle graphs' do
17
- expect(Seafoam::Annotators::GraalAnnotator.applies?(Seafoam::SpecHelpers.example_graph('fib-js', 2))).to be true
18
- end
19
-
20
- describe 'when run' do
21
- describe 'without options' do
22
- before :all do
23
- @graph = Seafoam::SpecHelpers.example_graph('matmult-ruby', 8)
24
- annotator = Seafoam::Annotators::GraalAnnotator.new({})
25
- annotator.annotate @graph
26
- end
27
-
28
- it 'annotates all nodes with a kind' do
29
- expect(@graph.nodes.values.any? { |n| n.props[:kind].nil? }).to be_falsey
30
- end
31
-
32
- it 'annotates all nodes with a label' do
33
- expect(@graph.nodes.values.any? { |n| n.props[:label].nil? }).to be_falsey
34
- end
35
-
36
- it 'annotates all edges with a kind' do
37
- expect(@graph.edges.any? { |e| e.props[:kind].nil? }).to be_falsey
38
- end
39
-
40
- it 'annotates not negated GuardNodes with "Guard, else ..."' do
41
- expect(@graph.nodes[7101].props['negated']).to be false
42
- expect(@graph.nodes[7101].props[:label]).to start_with 'Guard, else'
43
- end
44
-
45
- it 'annotates negated GuardNodes with "Guard not, else ..."' do
46
- expect(@graph.nodes[7102].props['negated']).to be true
47
- expect(@graph.nodes[7102].props[:label]).to start_with 'Guard not, else'
48
- end
49
- end
50
-
51
- describe 'with :hide_frame_state' do
52
- before :all do
53
- @graph = Seafoam::SpecHelpers.example_graph('matmult-ruby', 2)
54
- annotator = Seafoam::Annotators::GraalAnnotator.new(hide_frame_state: true)
55
- annotator.annotate @graph
56
- end
57
-
58
- it 'sets the hidden property on all frame state nodes' do
59
- frame_state_nodes = @graph.nodes.values.select do |n|
60
- Seafoam::Annotators::GraalAnnotator::FRAME_STATE_NODES.include?(n.props.dig(:node_class, :node_class))
61
- end
62
- expect(frame_state_nodes.all? { |n| n.props[:hidden] }).to be_truthy
63
- end
64
- end
65
-
66
- describe 'with :hide_floating' do
67
- before :all do
68
- @graph = Seafoam::SpecHelpers.example_graph('matmult-ruby', 2)
69
- annotator = Seafoam::Annotators::GraalAnnotator.new(hide_floating: true)
70
- annotator.annotate @graph
71
- end
72
-
73
- it 'sets the hidden property on all nodes without a control edge' do
74
- nodes_without_control_edge = @graph.nodes.values.select do |n|
75
- n.edges.none? { |e| e.props[:kind] == 'control' }
76
- end
77
- expect(nodes_without_control_edge.all? { |n| n.props[:hidden] }).to be_truthy
78
- end
79
- end
80
-
81
- describe 'with :reduce_edges' do
82
- before :all do
83
- @graph = Seafoam::SpecHelpers.example_graph('matmult-ruby', 2)
84
- annotator = Seafoam::Annotators::GraalAnnotator.new(reduce_edges: true)
85
- annotator.annotate @graph
86
- end
87
-
88
- it 'inlines all constant nodes' do
89
- constant_nodes = @graph.nodes.values.select do |n|
90
- Seafoam::Annotators::GraalAnnotator::SIMPLE_INPUTS.include?(n.props.dig(:node_class, :node_class))
91
- end
92
- expect(constant_nodes.all? { |n| n.props[:inlined] }).to be_truthy
93
- end
94
- end
95
- end
96
- end
@@ -1,61 +0,0 @@
1
- require 'seafoam'
2
-
3
- require 'rspec'
4
-
5
- describe Seafoam::Annotators do
6
- describe '#annotate' do
7
- it 'asks annotators if they apply' do
8
- check_applied = false
9
-
10
- Class.new(Seafoam::Annotator) do
11
- singleton_class.define_method(:applies?) do |_graph|
12
- check_applied = true
13
- false
14
- end
15
- end
16
-
17
- Seafoam::Annotators.apply(Seafoam::Graph.new)
18
- expect(check_applied).to be true
19
- end
20
-
21
- it 'runs annotators that apply' do
22
- check_annotated = false
23
-
24
- Class.new(Seafoam::Annotator) do
25
- singleton_class.define_method(:applies?) do |_graph|
26
- true
27
- end
28
-
29
- define_method(:annotate) do |_graph|
30
- check_annotated = true
31
- end
32
- end
33
-
34
- Seafoam::Annotators.apply(Seafoam::Graph.new)
35
- expect(check_annotated).to be true
36
- end
37
- end
38
-
39
- describe '#annotators' do
40
- it 'returns the standard annotators' do
41
- annotators = Seafoam::Annotators.annotators
42
- expect(annotators).to include Seafoam::Annotators::FallbackAnnotator
43
- expect(annotators).to include Seafoam::Annotators::GraalAnnotator
44
- end
45
-
46
- it 'returns custom annotators' do
47
- custom_annotator = Class.new(Seafoam::Annotator) do
48
- def self.applies?(_graph)
49
- false
50
- end
51
- end
52
- annotators = Seafoam::Annotators.annotators
53
- expect(annotators).to include custom_annotator
54
- end
55
-
56
- it 'returns the FallbackAnnotator annotator last' do
57
- annotators = Seafoam::Annotators.annotators
58
- expect(annotators.last).to eq Seafoam::Annotators::FallbackAnnotator
59
- end
60
- end
61
- end