seafoam 0.6 → 0.10

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/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`.