seafoam 0.8 → 0.9

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