seafoam 0.6 → 0.10

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/bgv/bgv_parser.rb +10 -2
  7. data/lib/seafoam/commands.rb +107 -32
  8. data/lib/seafoam/graal/pi.rb +18 -0
  9. data/lib/seafoam/graph.rb +33 -1
  10. data/lib/seafoam/graphviz_writer.rb +24 -2
  11. data/lib/seafoam/json_writer.rb +1 -3
  12. data/lib/seafoam/{annotators → passes}/fallback.rb +4 -4
  13. data/lib/seafoam/{annotators → passes}/graal.rb +43 -15
  14. data/lib/seafoam/passes/truffle.rb +58 -0
  15. data/lib/seafoam/passes.rb +61 -0
  16. data/lib/seafoam/version.rb +1 -1
  17. data/lib/seafoam.rb +5 -4
  18. metadata +26 -62
  19. data/.github/probots.yml +0 -2
  20. data/.github/workflows/workflows.yml +0 -39
  21. data/.gitignore +0 -7
  22. data/.rubocop.yml +0 -37
  23. data/.ruby-version +0 -1
  24. data/.seafoam/config +0 -1
  25. data/CODE_OF_CONDUCT.md +0 -128
  26. data/CONTRIBUTING.md +0 -5
  27. data/Gemfile +0 -2
  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 -293
  33. data/docs/getting-graphs.md +0 -59
  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 -21
  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 -157
  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 -316
  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
data/README.md DELETED
@@ -1,378 +0,0 @@
1
- # Seafoam
2
-
3
- *Seafoam* is a tool for working with compiler graphs. It's designed primarily
4
- for working with the graph files dumped by the GraalVM compiler, such as in
5
- TruffleRuby, but it could be used with other compilers and graph dump file
6
- formats.
7
-
8
- The *Ideal Graph Visualizer*, or *IGV*, is the tool usually used to work with
9
- GraalVM compiler graphs. Seafoam aims to solve several problems with IGV. Unlike
10
- IGV, Seafoam:
11
-
12
- * is open source and can be used according to the MIT license
13
- * supports gzip-compressed BGV files
14
- * is able to some extent seek BGV files to load specific graphs without loading the rest of the file
15
- * has a command-line interface
16
- * can be used as a library
17
- * has easy PDF, SVG, PNG and JSON output
18
- * is designed for accessibility
19
- * looks prettier, in our opinion
20
-
21
- Additionally, Seafoam adds:
22
-
23
- * support for disassembling CFG files
24
-
25
- Admittedly, Seafoam does not yet have:
26
-
27
- * an interactive user interface
28
- * diffing of graphs
29
- * visualization of basic blocks
30
- * breaking of edges for very congested graphs
31
- * the same speed in rendering big graphs - Seafoam is best suited for looking at graphs before lowering, which is what language developers are usually doing, or use spotlight
32
-
33
- ## Seafoam compared to IGV
34
-
35
- <p>
36
- <img src="docs/images/seafoam.png" width="350">
37
- <img src="docs/images/igv.png" width="350">
38
- </p>
39
-
40
- ## Installation
41
-
42
- ### macOS
43
-
44
- ```
45
- % brew install graphviz
46
- % gem install seafoam
47
- % seafoam --version
48
- seafoam 0.1
49
- ```
50
-
51
- ### Ubuntu
52
-
53
- ```
54
- % sudo apt-get install ruby graphviz
55
- % gem install seafoam
56
- % seafoam --version
57
- seafoam 0.1
58
- ```
59
-
60
- ### RedHat
61
-
62
- ```
63
- % sudo yum install ruby graphviz
64
- % gem install seafoam
65
- % seafoam --version
66
- seafoam 0.1
67
- ```
68
-
69
- ### Capstone
70
-
71
- To use the `cfg2asm` disassembler, you'll then need to install Capstone.
72
-
73
- ```
74
- % brew install capstone # macOS
75
- % sudo apt-get install libcapstone3 # Ubuntu
76
- ```
77
-
78
- ## Quick-start demo
79
-
80
- ```
81
- % seafoam examples/fib-java.bgv:0 render
82
- ```
83
-
84
- ## Getting compiler graphs
85
-
86
- If you are just experimenting, there are example graphs such as
87
- `examples/fib-java.bgv`.
88
-
89
- This is just a quick summary - see more information on
90
- [getting graphs out of compilers](docs/getting-graphs.md).
91
-
92
- ### GraalVM for Java
93
-
94
- ```
95
- % javac Fib.java
96
- % java -XX:CompileOnly=::fib -Dgraal.Dump=:2 Fib 14
97
- ```
98
-
99
- ### GraalVM Native Image
100
-
101
- ```
102
- % native-image -H:Dump=:2 -H:MethodFilter=fib Fib
103
- ```
104
-
105
- ### TruffleRuby and other Truffle languages
106
-
107
- ```
108
- % ruby --experimental-options --engine.CompileOnly=fib --engine.Inlining=false --engine.OSR=false --vm.Dgraal.Dump=Truffle:2 fib.rb 14
109
- ```
110
-
111
- You will usually want to look at the *After TruffleTier* graph.
112
-
113
- ## Name syntax
114
-
115
- When using a command-line interface, Seafoam refers to
116
- `file.bgv[:graph][:node[-edge]]`, where `file.bgv` is a file, `graph` is a graph
117
- index, `node` is a node index, and `to` is another node index to form an edge
118
- from `node` to another node `edge`.
119
-
120
- Note that a *graph ID* is an ID found in BGV files, but is not unique. A
121
- *graph index* is what we use in names, and is unique.
122
-
123
- ## Use cases
124
-
125
- #### Print information about a file
126
-
127
- ```
128
- % seafoam examples/fib-java.bgv info
129
- BGV 6.1
130
- ```
131
-
132
- #### List graphs in a file
133
-
134
- ```
135
- % seafoam examples/fib-java.bgv list
136
- examples/fib-java.bgv:0 2:Fib.fib(int)/After phase org.graalvm.compiler.java.GraphBuilderPhase
137
- examples/fib-java.bgv:1 2:Fib.fib(int)/After phase org.graalvm.compiler.phases.PhaseSuite
138
- examples/fib-java.bgv:2 2:Fib.fib(int)/After phase org.graalvm.compiler.phases.common.DeadCodeEliminationPhase
139
- examples/fib-java.bgv:3 2:Fib.fib(int)/After parsing
140
- examples/fib-java.bgv:4 2:Fib.fib(int)/After phase org.graalvm.compiler.phases.common.CanonicalizerPhase
141
- examples/fib-java.bgv:5 2:Fib.fib(int)/After phase org.graalvm.compiler.phases.common.inlining.InliningPhase
142
- ...
143
- ```
144
-
145
- #### Search for strings in a graph, or node or edge within a graph
146
-
147
- ```
148
- % seafoam examples/fib-java.bgv:0 search Start
149
- examples/fib-java.bgv:0:0 ...node_class":"org.graalvm.compiler.nodes.StartNode","name_template":"Start","inputs":[...
150
- examples/fib-java.bgv:0:0 ...piler.nodes.StartNode","name_template":"Start","inputs":[{"direct":true,"name":"state...
151
- ```
152
-
153
- #### Print edges of a graph, or node or edge within a graph
154
-
155
- ```
156
- % seafoam examples/fib-java.bgv:0 edges
157
- 22 nodes, 30 edges
158
- % seafoam examples/fib-java.bgv:0:13 edges
159
- Input:
160
- 13 (Call Fib.fib) <-() 6 (Begin)
161
- 13 (Call Fib.fib) <-() 14 (@{:declaring_class=>"Fib", :method_name=>"fib", :signature=>{:args=>["I"], :ret=>"I"}, :modifiers=>9}:13)
162
- 13 (Call Fib.fib) <-() 12 (MethodCallTarget)
163
- Output:
164
- 13 (Call Fib.fib) ->() 18 (Call Fib.fib)
165
- 13 (Call Fib.fib) ->(values) 14 (@{:declaring_class=>"Fib", :method_name=>"fib", :signature=>{:args=>["I"], :ret=>"I"}, :modifiers=>9}:13)
166
- 13 (Call Fib.fib) ->(values) 19 (@{:declaring_class=>"Fib", :method_name=>"fib", :signature=>{:args=>["I"], :ret=>"I"}, :modifiers=>9}:19)
167
- 13 (Call Fib.fib) ->(x) 20 (+)
168
- % seafoam examples/fib-java.bgv:0:13-20 edges
169
- 13 (Call Fib.fib) ->(x) 20 (+)
170
- ```
171
-
172
- #### Print properties of a file, graph, or node or edge within a graph
173
-
174
- ```
175
- % seafoam examples/fib-java.bgv:0 props
176
- {
177
- "group": [
178
- {
179
- "name": "2:Fib.fib(int)",
180
- "short_name": "2:Fib.fib(int)",
181
- "method": null,
182
- ...
183
- % seafoam examples/fib-java.bgv:0:13 props
184
- {
185
- "nodeSourcePosition": {
186
- "method": {
187
- "declaring_class": "Fib",
188
- "method_name": "fib",
189
- "signature": {
190
- ...
191
- % seafoam examples/fib-java.bgv:0:13-20 props
192
- {
193
- "direct": true,
194
- "name": "x",
195
- "type": "Value"
196
- }
197
- ```
198
-
199
- #### Print node source information
200
-
201
- ```
202
- % seafoam examples/fib-ruby.bgv:8:2443 source
203
- java.lang.Math#addExact
204
- org.truffleruby.core.numeric.IntegerNodes$AddNode#add
205
- org.truffleruby.core.numeric.IntegerNodesFactory$AddNodeFactory$AddNodeGen#executeAdd
206
- org.truffleruby.core.inlined.InlinedAddNode#intAdd
207
- org.truffleruby.core.inlined.InlinedAddNodeGen#execute
208
- org.truffleruby.language.control.IfElseNode#execute
209
- org.truffleruby.language.control.SequenceNode#execute
210
- org.truffleruby.language.arguments.CheckArityNode#execute
211
- org.truffleruby.language.control.SequenceNode#execute
212
- org.truffleruby.language.methods.CatchForMethodNode#execute
213
- org.truffleruby.language.methods.ExceptionTranslatingNode#execute
214
- org.truffleruby.language.RubyRootNode#execute
215
- org.graalvm.compiler.truffle.runtime.OptimizedCallTarget#executeRootNode
216
- org.graalvm.compiler.truffle.runtime.OptimizedCallTarget#profiledPERoot
217
- ```
218
-
219
- #### Render a graph
220
-
221
- Render a graph as a PDF image and have it opened automatically.
222
-
223
- ```
224
- % seafoam examples/fib-java.bgv:0 render
225
- ```
226
-
227
- Render a graph showing just a few nodes and those surrounding them, similar to
228
- the IGV feature of gradually revealing nodes.
229
-
230
- ```
231
- % seafoam examples/fib-java.bgv:0 render --spotlight 13,20
232
- ```
233
-
234
- <p>
235
- <img src="docs/images/spotlight-seafoam.png" width="200">
236
- <img src="docs/images/spotlight-igv.png" width="350">
237
- </p>
238
-
239
- `render` supports these options:
240
-
241
- * `--out filename.pdf` or `.pdf`, `.svg`, `.png`, `.dot`
242
- * `--option key value` for custom annotators
243
-
244
- #### Convert a file
245
-
246
- Convert a BGV file to the Isabelle graph format.
247
-
248
- ```
249
- % bgv2isabelle examples/fib-java.bgv
250
- graph0 = # 2:Fib.fib(int)/After phase org.graalvm.compiler.java.GraphBuilderPhase
251
- (add_node 0 StartNode [2] [8]
252
- (add_node 1 (ParameterNode 0) [] [2, 5, 9, 11, 14, 16]
253
- (add_node 2 FrameState [1] [0]
254
- (add_node 3 (ConstantNode 1) [] []
255
- (add_node 4 (ConstantNode 2) [] [5]
256
- (add_node 5 IntegerLessThanNode [1, 4] [8]
257
- (add_node 6 BeginNode [8] [13]
258
- (add_node 7 BeginNode [8] [9]
259
- (add_node 8 IfNode [0, 5] [7, 6]
260
- ...
261
- ```
262
-
263
- Convert a BGV file to JSON.
264
-
265
- ```
266
- % bgv2json examples/fib-java.bgv
267
- graph0 = # 2:Fib.fib(int)/After phase org.graalvm.compiler.java.GraphBuilderPhase
268
- (add_node 0 StartNode [2] [8]
269
- (add_node 1 (ParameterNode 0) [] [2, 5, 9, 11, 14, 16]
270
- (add_node 2 FrameState [1] [0]
271
- (add_node 3 (ConstantNode 1) [] []
272
- (add_node 4 (ConstantNode 2) [] [5]
273
- (add_node 5 IntegerLessThanNode [1, 4] [8]
274
- (add_node 6 BeginNode [8] [13]
275
- (add_node 7 BeginNode [8] [9]
276
- (add_node 8 IfNode [0, 5] [7, 6]
277
- ...
278
- ```
279
-
280
- #### Disassembling
281
-
282
- ```
283
- % cfg2asm examples/java/exampleArithOperator.cfg
284
- [examples/java/exampleArithOperator.cfg]
285
- ;Comment 0: 3
286
- ;Comment 0: 1
287
- 0x112e2f660: nop dword ptr [rax + rax]
288
- ;Comment 5: block B0 null
289
- ;Comment 5: 0 [rsi|DWORD, rdx|DWORD, rbp|QWORD] = LABEL numbPhis: 0 align: false label: ?
290
- ;Comment 5: 4 [] = HOTSPOTLOCKSTACK frameMapBuilder: org.graalvm.compiler.lir.amd64.AMD64FrameMapBuilder@143082de0 slotKind: QWORD
291
- ;Comment 5: 10 rsi|DWORD = ADD (x: rsi|DWORD, y: rdx|DWORD) size: DWORD
292
- 0x112e2f665: add esi, edx
293
- ;Comment 7: 12 rax|DWORD = MOVE rsi|DWORD moveKind: DWORD
294
- 0x112e2f667: mov eax, esi
295
- ;Comment 9: 14 RETURN (savedRbp: rbp|QWORD, value: rax|DWORD) isStub: false requiresReservedStackAccessCheck: false thread: r15 scratchForSafepointOnReturn: rcx config: org.graalvm.compiler.hotspot.GraalHotSpotVMConfig@137f187d8
296
- ;Comment 9: 12
297
- 0x112e2f669: test dword ptr [rip - 0x46c4669], eax
298
- 0x112e2f66f: vzeroupper
299
- 0x112e2f672: ret
300
- ...
301
- ```
302
-
303
- ## Options for GraalVM graphs
304
-
305
- * `--show-frame-state` shows frame state nodes, which are hidden by default
306
- * `--hide-floating` hides nodes that aren't fixed by control flow
307
- * `--no-reduce-edges` turns off the option to reduce the number of edges by inlining simple nodes above their users
308
-
309
- ## Configuration
310
-
311
- Seafoam loads and runs a Ruby script called `~/.seafoam/config` in the first
312
- directory it finds starting with the current working directory and moving up.
313
- You can require or configure extra [annotators](docs/annotators.md) in this
314
- file.
315
-
316
- ## Debugging
317
-
318
- Exception backtraces are printed if `$DEBUG` (`-d`) is set.
319
-
320
- Use `seafoam file.bgv debug` to debug file parsing.
321
-
322
- ## More documentation
323
-
324
- * [Graph annotators](docs/annotators.md)
325
- * [Details of the BGV file format](docs/bgv.md)
326
- * [How to get graphs from various compilers](docs/getting-graphs.md)
327
-
328
- ## Frequently asked questions
329
-
330
- #### Why is it called *Seafoam*?
331
-
332
- GraalVM graphs are *seas of nodes*. Seafoam is a shade of green, and Seafoam was
333
- written at Shopify, which has green as a brand colour. Graphs can sometimes be
334
- very complicated, appearing like a foam without any structure - Seafoam tries to
335
- help you make sense of it all.
336
-
337
- #### What do you mean by *graphs*, and *seas* or *soups* of nodes?
338
-
339
- Graphs, as in edges and nodes, are the data structure some compilers use to
340
- represent your program while they're compiling it. It's a form of *intermediate
341
- representation*. Graphs are how the compiler understands the programs and if the
342
- compiler isn't doing what you want you need to look at the graph and make sense
343
- of it. Some graphs are loosely structured and large, making them like a sea or
344
- soup of nodes.
345
-
346
- #### Doesn't *reduce edges* actually introduce more edges?
347
-
348
- Yes, but they're shorter edges, and it achieves the intended effect of less
349
- edges crossing over the graph.
350
-
351
- ## Related work
352
-
353
- The graph layout algorithm we use, via Graphviz, is
354
-
355
- * E. R. Gansner, et al, [*A Technique for Drawing Directed Graphs*](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.3.8982), IEEE Transactions on Software Engineering, 1993
356
-
357
- IGV is the existing tool for working with Graal graphs. It uses a *hierarchical*
358
- layout algorithm, rather than the *force directed* algorithm we use when we use
359
- Graphviz. It's based on the NetBeans IDE platform. It's related to the *C1
360
- Visualiser*, for control-flow graphs. The C1 Visualiser can also be used with
361
- Graal as the backend of Graal is similar enough to C1. IGV is closed-source and
362
- available under a proprietary licence.
363
-
364
- * T. Würthinger, [*Visualization of Program Dependence Graphs*](http://www.ssw.uni-linz.ac.at/Research/Papers/Wuerthinger07Master/), Master Thesis, Linz 2007
365
- * T. Würthinger, [*Visualization of Java Control Flow Graphs*](http://www.ssw.uni-linz.ac.at/General/Staff/TW/Wuerthinger06Bachelor.pdf), Bachelor Thesis, Linz 2006
366
-
367
- [*Turbolizer*][turbolizer] is a similar tool for the intermediate representation
368
- in the V8 JavaScript compiler.
369
-
370
- [turbolizer]: https://github.com/v8/v8/blob/4b9b23521e6fd42373ebbcb20ebe03bf445494f9/tools/turbolizer
371
-
372
- ## Author
373
-
374
- Seafoam was written by Chris Seaton at Shopify, chris.seaton@shopify.com.
375
-
376
- ## License
377
-
378
- MIT
@@ -1,65 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- # This demo analyses a directory full of graphs and looks for how many box nodes
4
- # take their value directly from an unbox node.
5
-
6
- require 'seafoam'
7
-
8
- box_nodes_count = 0
9
- box_nodes_from_unbox_count = 0
10
-
11
- graph_count = 0
12
- graph_match_count = 0
13
-
14
- ARGV.each do |dir|
15
- Dir.glob(['*.bgv', '*.bgv.gz'], base: dir) do |file|
16
- parser = Seafoam::BGV::BGVParser.new(File.join(dir, file))
17
- parser.read_file_header
18
- parser.skip_document_props
19
-
20
- loop do
21
- index, = parser.read_graph_preheader
22
- break unless index
23
-
24
- parser.skip_graph_header
25
- graph = parser.read_graph
26
-
27
- contains_box_unbox = false
28
-
29
- graph.nodes.each_value do |node|
30
- next unless node.props.dig(:node_class, :node_class).start_with?('org.graalvm.compiler.nodes.extended.BoxNode')
31
-
32
- box_node = node
33
- box_nodes_count += 1
34
- value_edge = node.edges.find { |e| e.props[:name] == 'value' }
35
- raise unless value_edge
36
-
37
- value_node = value_edge.from
38
- next unless value_node.props.dig(:node_class, :node_class).start_with?('org.graalvm.compiler.nodes.extended.UnboxNode')
39
-
40
- unbox_node = value_node
41
- box_nodes_from_unbox_count += 1
42
- contains_box_unbox = true
43
- puts "seafoam '#{File.join(dir, file)}:#{index}' render --spotlight #{box_node.id},#{unbox_node.id}"
44
- end
45
-
46
- graph_count += 1
47
- graph_match_count += 1 if contains_box_unbox
48
- end
49
- end
50
- end
51
-
52
- if box_nodes_count.positive?
53
- box_nodes_percent = (box_nodes_from_unbox_count / box_nodes_count.to_f) * 100
54
- else
55
- box_nodes_percent = 0.0
56
- end
57
-
58
- if graph_count.positive?
59
- graph_percent = (graph_match_count / graph_count.to_f) * 100
60
- else
61
- graph_percent = 0.0
62
- end
63
-
64
- puts " How many boxes take a value from an unbox? #{box_nodes_percent.round(1)}%"
65
- puts "How many graphs contain at least one box-unbox? #{graph_percent.round(1)}%"
data/docs/annotators.md DELETED
@@ -1,43 +0,0 @@
1
- # Annotators
2
-
3
- The model of Seafoam is that it is a directed graph, with nodes annotated with a
4
- bag of key-value properties. When graphs are read they'll have some initial
5
- properties. Seafoam may add more properties. The output routines then draw the
6
- graph using the graph structure itself and also the properties.
7
-
8
- *Annotators* are routines that add extra properties to graphs to help the user
9
- understand them. They usually have knowledge of how the graph is structured, and
10
- use this to make the graph easier to read or to make important information in
11
- them stand out.
12
-
13
- We call properties with symbol keys *annotations*, as they're added by the
14
- annotators.
15
-
16
- Annotators are similar to filters in IGV.
17
-
18
- Appropriate annotators are automatically selected and applied to graphs.
19
-
20
- The rendering commands recognize these annotations, so annotators will probably
21
- want to add them:
22
-
23
- * `:label` on nodes and edges
24
- * `:out_annotation` on nodes
25
- * `:hidden` on nodes only, to not show them (*remove frame state* for example in IGV terminology)
26
- * `:inlined` on nodes only, to indicate the node should be shown immediately above each node using it (*reduce edges* in IGV terminology)
27
- * `:kind` on nodes only, which can be `info`, `input`, `control`, `effect`, `virtual`, `calc`, `guard`, or `other`
28
- * `:kind` on edges only, which can be `info`, `control`, `loop`, or `data`
29
- * `:reverse` on edges only
30
- * `:spotlight` for nodes as part of spotlighting (`lit` are shown, `shaded` are shown but greyed out, and edges from `shaded` to `:hidden` nodes are also shown greyed out)
31
-
32
- Seafoam ships with an annotator for generic GraalVM graphs. If you work with a
33
- different compiler you'll probably want to write your own annotators - subclass
34
- `Seafoam::Annotator` and implement `#annotate(graph)`. You can add custom
35
- annotators by requiring them in your `.seafoam/config`. All subclasses of
36
- `Annotator` will be found, so you just need to define the subclass.
37
-
38
- A fallback annotator, run after all others, just labels the node with the
39
- `'label'` property if there is one.
40
-
41
- Options for annotations can be set on the command line with `--option key
42
- value`. Some options are built into Seafoam commands, like `--show-frame-state`,
43
- but they're doing the same thing as `--option hide_frame_state false`.