seafoam 0.2

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 (147) hide show
  1. checksums.yaml +7 -0
  2. data/.github/probots.yml +2 -0
  3. data/.github/workflows/rubocop.yml +10 -0
  4. data/.github/workflows/specs.yml +19 -0
  5. data/.gitignore +7 -0
  6. data/.rubocop.yml +34 -0
  7. data/.ruby-version +1 -0
  8. data/.seafoam/config +1 -0
  9. data/CODE_OF_CONDUCT.md +128 -0
  10. data/CONTRIBUTING.md +5 -0
  11. data/Gemfile +2 -0
  12. data/LICENSE.md +7 -0
  13. data/README.md +298 -0
  14. data/bin/bgv2isabelle +53 -0
  15. data/bin/bgv2json +42 -0
  16. data/bin/seafoam +24 -0
  17. data/docs/annotators.md +43 -0
  18. data/docs/bgv.md +284 -0
  19. data/docs/getting-graphs.md +47 -0
  20. data/examples/Fib.java +24 -0
  21. data/examples/MatMult.java +39 -0
  22. data/examples/fib-java.bgv +0 -0
  23. data/examples/fib-js.bgv +0 -0
  24. data/examples/fib-ruby.bgv +0 -0
  25. data/examples/fib.js +15 -0
  26. data/examples/fib.rb +15 -0
  27. data/examples/identity.bgv +0 -0
  28. data/examples/identity.rb +13 -0
  29. data/examples/java/Irreducible.j +35 -0
  30. data/examples/java/IrreducibleDecompiled.java +21 -0
  31. data/examples/java/JavaExamples.java +418 -0
  32. data/examples/java/exampleArithOperator.bgv +0 -0
  33. data/examples/java/exampleArithOperator.cfg +925 -0
  34. data/examples/java/exampleArrayAllocation.bgv +0 -0
  35. data/examples/java/exampleArrayAllocation.cfg +5268 -0
  36. data/examples/java/exampleArrayRead.bgv +0 -0
  37. data/examples/java/exampleArrayRead.cfg +2263 -0
  38. data/examples/java/exampleArrayWrite.bgv +0 -0
  39. data/examples/java/exampleArrayWrite.cfg +2315 -0
  40. data/examples/java/exampleCatch.bgv +0 -0
  41. data/examples/java/exampleCatch.cfg +4150 -0
  42. data/examples/java/exampleCompareOperator.bgv +0 -0
  43. data/examples/java/exampleCompareOperator.cfg +1109 -0
  44. data/examples/java/exampleDoubleSynchronized.bgv +0 -0
  45. data/examples/java/exampleDoubleSynchronized.cfg +26497 -0
  46. data/examples/java/exampleExactArith.bgv +0 -0
  47. data/examples/java/exampleExactArith.cfg +1888 -0
  48. data/examples/java/exampleFieldRead.bgv +0 -0
  49. data/examples/java/exampleFieldRead.cfg +1228 -0
  50. data/examples/java/exampleFieldWrite.bgv +0 -0
  51. data/examples/java/exampleFieldWrite.cfg +1102 -0
  52. data/examples/java/exampleFor.bgv +0 -0
  53. data/examples/java/exampleFor.cfg +3936 -0
  54. data/examples/java/exampleFullEscape.bgv +0 -0
  55. data/examples/java/exampleFullEscape.cfg +5893 -0
  56. data/examples/java/exampleIf.bgv +0 -0
  57. data/examples/java/exampleIf.cfg +2462 -0
  58. data/examples/java/exampleIfNeverTaken.bgv +0 -0
  59. data/examples/java/exampleIfNeverTaken.cfg +2476 -0
  60. data/examples/java/exampleInstanceOfManyImpls.bgv +0 -0
  61. data/examples/java/exampleInstanceOfManyImpls.cfg +6391 -0
  62. data/examples/java/exampleInstanceOfOneImpl.bgv +0 -0
  63. data/examples/java/exampleInstanceOfOneImpl.cfg +2604 -0
  64. data/examples/java/exampleIntSwitch.bgv +0 -0
  65. data/examples/java/exampleIntSwitch.cfg +3121 -0
  66. data/examples/java/exampleInterfaceCallManyImpls.bgv +0 -0
  67. data/examples/java/exampleInterfaceCallManyImpls.cfg +1358 -0
  68. data/examples/java/exampleInterfaceCallOneImpl.bgv +0 -0
  69. data/examples/java/exampleInterfaceCallOneImpl.cfg +3859 -0
  70. data/examples/java/exampleLocalInstanceOf.bgv +0 -0
  71. data/examples/java/exampleLocalInstanceOf.cfg +5276 -0
  72. data/examples/java/exampleLocalSynchronized.bgv +0 -0
  73. data/examples/java/exampleLocalSynchronized.cfg +1364 -0
  74. data/examples/java/exampleLocalVariables.bgv +0 -0
  75. data/examples/java/exampleLocalVariables.cfg +1195 -0
  76. data/examples/java/exampleLocalVariablesState.bgv +0 -0
  77. data/examples/java/exampleLocalVariablesState.cfg +1673 -0
  78. data/examples/java/exampleNestedWhile.bgv +0 -0
  79. data/examples/java/exampleNestedWhile.cfg +15499 -0
  80. data/examples/java/exampleNestedWhileBreak.bgv +0 -0
  81. data/examples/java/exampleNestedWhileBreak.cfg +11162 -0
  82. data/examples/java/exampleNoEscape.bgv +0 -0
  83. data/examples/java/exampleNoEscape.cfg +974 -0
  84. data/examples/java/exampleObjectAllocation.bgv +0 -0
  85. data/examples/java/exampleObjectAllocation.cfg +5287 -0
  86. data/examples/java/examplePartialEscape.bgv +0 -0
  87. data/examples/java/examplePartialEscape.cfg +7042 -0
  88. data/examples/java/examplePhi.bgv +0 -0
  89. data/examples/java/examplePhi.cfg +3227 -0
  90. data/examples/java/exampleReducible.bgv +0 -0
  91. data/examples/java/exampleReducible.cfg +5578 -0
  92. data/examples/java/exampleSimpleCall.bgv +0 -0
  93. data/examples/java/exampleSimpleCall.cfg +1435 -0
  94. data/examples/java/exampleStamp.bgv +0 -0
  95. data/examples/java/exampleStamp.cfg +913 -0
  96. data/examples/java/exampleStaticCall.bgv +0 -0
  97. data/examples/java/exampleStaticCall.cfg +1154 -0
  98. data/examples/java/exampleStringSwitch.bgv +0 -0
  99. data/examples/java/exampleStringSwitch.cfg +15377 -0
  100. data/examples/java/exampleSynchronized.bgv +0 -0
  101. data/examples/java/exampleSynchronized.cfg +26027 -0
  102. data/examples/java/exampleThrow.bgv +0 -0
  103. data/examples/java/exampleThrow.cfg +780 -0
  104. data/examples/java/exampleThrowCatch.bgv +0 -0
  105. data/examples/java/exampleThrowCatch.cfg +744 -0
  106. data/examples/java/exampleUnsafeRead.bgv +0 -0
  107. data/examples/java/exampleUnsafeRead.cfg +912 -0
  108. data/examples/java/exampleUnsafeWrite.bgv +0 -0
  109. data/examples/java/exampleUnsafeWrite.cfg +962 -0
  110. data/examples/java/exampleWhile.bgv +0 -0
  111. data/examples/java/exampleWhile.cfg +3936 -0
  112. data/examples/java/exampleWhileBreak.bgv +0 -0
  113. data/examples/java/exampleWhileBreak.cfg +5963 -0
  114. data/examples/matmult-java.bgv +0 -0
  115. data/examples/matmult-ruby.bgv +0 -0
  116. data/examples/matmult.rb +29 -0
  117. data/examples/overflow.bgv +0 -0
  118. data/examples/overflow.rb +13 -0
  119. data/lib/seafoam.rb +13 -0
  120. data/lib/seafoam/annotators.rb +54 -0
  121. data/lib/seafoam/annotators/fallback.rb +27 -0
  122. data/lib/seafoam/annotators/graal.rb +376 -0
  123. data/lib/seafoam/bgv/bgv_parser.rb +602 -0
  124. data/lib/seafoam/binary/binary_reader.rb +21 -0
  125. data/lib/seafoam/binary/io_binary_reader.rb +88 -0
  126. data/lib/seafoam/colors.rb +18 -0
  127. data/lib/seafoam/commands.rb +447 -0
  128. data/lib/seafoam/config.rb +34 -0
  129. data/lib/seafoam/graph.rb +91 -0
  130. data/lib/seafoam/graphviz_writer.rb +213 -0
  131. data/lib/seafoam/spotlight.rb +28 -0
  132. data/lib/seafoam/version.rb +5 -0
  133. data/seafoam.gemspec +20 -0
  134. data/spec/seafoam/annotators/fallback_spec.rb +69 -0
  135. data/spec/seafoam/annotators/graal_spec.rb +96 -0
  136. data/spec/seafoam/annotators_spec.rb +61 -0
  137. data/spec/seafoam/bgv/bgv_parser_spec.rb +144 -0
  138. data/spec/seafoam/bgv/fixtures/not.bgv +1 -0
  139. data/spec/seafoam/bgv/fixtures/unsupported.bgv +1 -0
  140. data/spec/seafoam/binary/io_binary_reader_spec.rb +176 -0
  141. data/spec/seafoam/command_spec.rb +252 -0
  142. data/spec/seafoam/graph_spec.rb +172 -0
  143. data/spec/seafoam/graphviz_writer_spec.rb +63 -0
  144. data/spec/seafoam/spec_helpers.rb +30 -0
  145. data/spec/seafoam/spotlight_spec.rb +38 -0
  146. data/tools/render-all +36 -0
  147. metadata +238 -0
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'seafoam'
4
+
5
+ # definition eg_short_cut_or1 :: IRGraph where
6
+ # "eg_short_cut_or1 =
7
+ # (add_node 14 ReturnNode [13] []
8
+ # (add_node 13 PhiNode [10, 11, 12] []
9
+ # (add_node 12 (ConstantNode 0) [] []
10
+ # (add_node 11 (ConstantNode 42) [] []
11
+ # (add_node 10 MergeNode [7, 9] [14]
12
+ # (add_node 9 EndNode [] []
13
+ # (add_node 8 BeginNode [] [9]
14
+ # (add_node 7 EndNode [] []
15
+ # (add_node 6 BeginNode [] [7]
16
+ # (add_node 5 IfNode [3] [6, 8]
17
+ # (add_node 3 (ShortCircuitOrNode False False) [1, 2] []
18
+ # (add_node 2 (ParameterNode 1) [] []
19
+ # (add_node 1 (ParameterNode 0) [] []
20
+ # (add_node 0 StartNode [] [5]
21
+ # empty_graph))))))))))))))"
22
+
23
+ ARGV.each do |file|
24
+ parser = Seafoam::BGV::BGVParser.new(File.new(file))
25
+ parser.read_file_header
26
+ parser.skip_document_props
27
+
28
+ loop do
29
+ index, = parser.read_graph_preheader
30
+ break unless index
31
+
32
+ graph_header = parser.read_graph_header
33
+ graph = parser.read_graph
34
+
35
+ puts "graph#{index} = # #{parser.graph_name(graph_header)}"
36
+
37
+ graph.nodes.each_value do |node|
38
+ node_class = node.props[:node_class][:node_class]
39
+ case node_class
40
+ when 'org.graalvm.compiler.nodes.ConstantNode'
41
+ desc = "(ConstantNode #{node.props['rawvalue']})"
42
+ when 'org.graalvm.compiler.nodes.ParameterNode'
43
+ desc = "(ParameterNode #{node.props['index']})"
44
+ else
45
+ desc = node_class.split('.').last
46
+ end
47
+ inputs = node.inputs.map(&:from).map(&:id)
48
+ outputs = node.outputs.map(&:to).map(&:id)
49
+ puts " (add_node #{node.id} #{desc} #{inputs.inspect} #{outputs.inspect}"
50
+ end
51
+ puts ' empty_graph' + (')' * graph.nodes.size)
52
+ end
53
+ end
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'seafoam'
4
+ require 'json'
5
+
6
+ ARGV.each do |file|
7
+ parser = Seafoam::BGV::BGVParser.new(File.new(file))
8
+ parser.read_file_header
9
+ parser.skip_document_props
10
+
11
+ loop do
12
+ index, = parser.read_graph_preheader
13
+ break unless index
14
+
15
+ graph_header = parser.read_graph_header
16
+
17
+ graph = parser.read_graph
18
+ Seafoam::Annotators.apply graph
19
+
20
+ name = parser.graph_name(graph_header)
21
+
22
+ nodes = []
23
+ edges = []
24
+
25
+ graph.nodes.each_value do |node|
26
+ nodes.push({
27
+ id: node.id,
28
+ props: node.props
29
+ })
30
+
31
+ node.outputs.each do |edge|
32
+ edges.push({
33
+ from: edge.from.id,
34
+ to: edge.to.id,
35
+ props: edge.props
36
+ })
37
+ end
38
+ end
39
+
40
+ puts JSON.generate({name: name, props: graph.props, nodes: nodes, edges: edges})
41
+ end
42
+ end
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'seafoam'
4
+
5
+ # This is the 'seafoam' command line entry point.
6
+
7
+ begin
8
+ # Load configuraiton.
9
+ config = Seafoam::Config.new
10
+ config.load_config
11
+
12
+ # Run the command line.
13
+ commands = Seafoam::Commands.new($stdout, config)
14
+ commands.run(*ARGV)
15
+ rescue StandardError => e
16
+ if $DEBUG
17
+ # Re-raise the exception so the user sees it, it debugging is
18
+ # enabled (ruby -d).
19
+ raise e
20
+ else
21
+ # Otherwise, just print the message.
22
+ warn "seafoam: #{e.message}"
23
+ end
24
+ end
@@ -0,0 +1,43 @@
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`.
@@ -0,0 +1,284 @@
1
+ # BGV File Format
2
+
3
+ The BGV (*binary graph*, sometimes also called *BIGV*) file format is dumped by
4
+ Graal graphs.
5
+
6
+ The BGV parser was implemented from the [open-source writer code][graph-protocol]
7
+ in the GraalVM compiler.
8
+
9
+ [graph-protocol]: https://github.com/oracle/graal/blob/master/compiler/src/org.graalvm.graphio/src/org/graalvm/graphio/GraphProtocol.java
10
+
11
+ ## Format
12
+
13
+ Seafoam supports BGV versions:
14
+
15
+ * 7.0 (GraalVM 20.1.0 and up)
16
+ * 6.1 (GraalVM 1.0.0-rc16 and up)
17
+
18
+ The BGV file format is network-endian.
19
+
20
+ ```c
21
+ BGV {
22
+ char[4] = 'BIGV'
23
+ sint8 major
24
+ sint8 minor
25
+ GroupOrGraph*
26
+ }
27
+
28
+ GroupOrGraph {
29
+ BeginGroup GroupOrGraph* CloseGroup | Graph
30
+ }
31
+
32
+ BeginGroup {
33
+ sint8 token = BEGIN_GROUP
34
+ PoolObject name
35
+ PoolObject method
36
+ sint32 bci
37
+ Props props
38
+ }
39
+
40
+ Graph {
41
+ sint8 token = BEGIN_GRAPH
42
+ String format
43
+ Args args
44
+ GraphBody body
45
+ }
46
+
47
+ GraphBody {
48
+ Props props
49
+ sint32 nodes_count
50
+ Node[nodes_count] nodes
51
+ Blocks blocks
52
+ }
53
+
54
+ Node {
55
+ sint32 id
56
+ PoolObject node_class
57
+ bool has_predecessor
58
+ Pops props
59
+ Edge[node_class.inputs.size] edges_in
60
+ Edge[node_class.outputs.size] edges_out
61
+ }
62
+
63
+ Edge {
64
+ sint32[inputs_count] nodes
65
+ }
66
+
67
+ Blocks {
68
+ sint32 id
69
+ sint32 nodes_count
70
+ sint32[nodes_count] nodes
71
+ sint32 followers_count
72
+ sint32[followers_count] followers
73
+ }
74
+
75
+ CloseGroup {
76
+ sint8 token = CLOSE_GROUP
77
+ }
78
+
79
+ Props {
80
+ sint16 props_count
81
+ Prop[props_count] props
82
+ }
83
+
84
+ Prop {
85
+ PoolObject key
86
+ PropObject value
87
+ }
88
+
89
+ PropObject {
90
+ union {
91
+ struct {
92
+ sint8 PROPERTY_POOL
93
+ PoolObject object
94
+ }
95
+ struct {
96
+ sint8 PROPERTY_INT
97
+ sint32 value
98
+ }
99
+ struct {
100
+ sint8 PROPERTY_LONG
101
+ sint64 value
102
+ }
103
+ struct {
104
+ sint8 PROPERTY_DOUBLE
105
+ float64 value
106
+ }
107
+ struct {
108
+ sint8 PROPERTY_FLOAT
109
+ float32 value
110
+ }
111
+ struct {
112
+ sint8 PROPERTY_TRUE
113
+ }
114
+ struct {
115
+ sint8 PROPERTY_FALSE
116
+ }
117
+ struct {
118
+ sint8 PROPERTY_ARRAY
119
+ union {
120
+ struct {
121
+ sint8 PROPERTY_POOL
122
+ sint32 times
123
+ PoolObject[times] values
124
+ }
125
+ }
126
+ }
127
+ struct {
128
+ sint8 PROPERTY_SUBGRAPH
129
+ GraphBody graph
130
+ }
131
+ }
132
+ }
133
+
134
+ PoolObject {
135
+ union {
136
+ POOL_NULL
137
+ struct {
138
+ sint8 token = POOL_NEW
139
+ uint16 id
140
+ union {
141
+ struct {
142
+ sint8 type = POOL_STRING
143
+ String string
144
+ }
145
+ struct {
146
+ sint8 type = POOL_ENUM
147
+ PoolObject enum_class
148
+ sint32 enum_ordinal
149
+ }
150
+ struct {
151
+ sint8 type = POOL_CLASS
152
+ String type_name
153
+ union {
154
+ struct {
155
+ sint8 type = ENUM_KLASS
156
+ sint32 values_count
157
+ PoolObject values[values_count]
158
+ }
159
+ struct {
160
+ sint8 type = KLASS
161
+ }
162
+ }
163
+ }
164
+ struct {
165
+ sint8 type = POOL_METHOD
166
+ PoolObject declaring_class
167
+ PoolObject method_name
168
+ PoolObject signature
169
+ sint32 modifiers
170
+ sint32 bytes_length
171
+ uint8[bytes_length] bytes
172
+ }
173
+ struct {
174
+ sint8 type = POOL_NODE_CLASS
175
+ PoolObject node_class
176
+ String name_template
177
+ sint16 input_count
178
+ InputEdgeInfo inputs[input_count]
179
+ sint16 output_count
180
+ OutputEdgeInfo outputs[output_count]
181
+ }
182
+ struct {
183
+ sint8 type = POOL_FIELD
184
+ PoolObject field_class
185
+ PoolObject name
186
+ PoolObject type_name
187
+ sint32 modifiers
188
+ }
189
+ struct {
190
+ sint8 type = POOL_NODE_SIGNATURE
191
+ sint16 args_count
192
+ PoolObject args[args_count]
193
+ }
194
+ struct {
195
+ sint8 type = POOL_NODE_SOURCE_POSITION
196
+ PoolObject method
197
+ sint32 bci
198
+ SourcePosition source_positions[...until SourcePosition.uri = null]
199
+ PoolObject caller
200
+ }
201
+ struct {
202
+ sint8 type = POOL_NODE
203
+ sint32 node_id
204
+ PoolObject node_class
205
+ }
206
+ }
207
+ }
208
+ struct {
209
+ sint8 token = POOL_STRING | POOL_ENUM | POOL_CLASS | POOL_METHOD | POOL_NODE_CLASS | POOL_FIELD | POOL_SIGNATURE | POOL_NODE_SOURCE_POSITION | POOL_NODE
210
+ uint16 pool_id
211
+ }
212
+ }
213
+ }
214
+
215
+ InputEdgeInfo {
216
+ sint8 indirect
217
+ PoolObject name
218
+ PoolObject type
219
+ }
220
+
221
+ OutputEdgeInfo {
222
+ sint8 indirect
223
+ PoolObject name
224
+ }
225
+
226
+ SourcePosition {
227
+ PoolObject uri
228
+ String location
229
+ sint32 line
230
+ sint32 start
231
+ sint32 end
232
+ }
233
+
234
+ String {
235
+ sint32 length
236
+ char[length] chars
237
+ }
238
+
239
+ BEGIN_GROUP = 0x00
240
+ BEGIN_GRAPH = 0x01
241
+ CLOSE_GROUP = 0x02
242
+ BEGIN_DOCUMENT = 0x03
243
+
244
+ POOL_NEW = 0x00
245
+ POOL_STRING = 0x01
246
+ POOL_ENUM = 0x02
247
+ POOL_CLASS = 0x03
248
+ POOL_METHOD = 0x04
249
+ POOL_NULL = 0x05
250
+ POOL_NODE_CLASS = 0x06
251
+ POOL_FIELD = 0x07
252
+ POOL_SIGNATURE = 0x08
253
+ POOL_NODE_SOURCE_POSITION = 0x09
254
+ POOL_NODE = 0x0a
255
+
256
+ PROPERTY_POOL = 0x00
257
+ PROPERTY_INT = 0x01
258
+ PROPERTY_LONG = 0x02
259
+ PROPERTY_DOUBLE = 0x03
260
+ PROPERTY_FLOAT = 0x04
261
+ PROPERTY_TRUE = 0x05
262
+ PROPERTY_FALSE = 0x06
263
+ PROPERTY_ARRAY = 0x07
264
+ PROPERTY_SUBGRAPH = 0x08
265
+
266
+ KLASS = 0x00
267
+ ENUM_KLASS = 0x01
268
+ ```
269
+
270
+ ## Seeking
271
+
272
+ The BGV format is not particularly amenable to seeking. You must read each prior
273
+ graph in order to read any subsequent graph, the length of nodes and edges
274
+ depends on values within them, and there is an object pool that is incrementally
275
+ built.
276
+
277
+ In order to 'seek' BGV files we have two code paths for reading the file, one
278
+ with loads the data and one which loads as little as possible to know just how
279
+ much further to advance in the file.
280
+
281
+ ## Other information
282
+
283
+ `seafoam file.bgv debug` checks that a file can be parsed and prints information
284
+ as it does so.