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.
- checksums.yaml +4 -4
- data/bin/bgv2isabelle +1 -5
- data/bin/bgv2json +1 -5
- data/bin/cfg2asm +1 -5
- data/bin/seafoam +1 -5
- data/lib/seafoam/commands.rb +48 -31
- data/lib/seafoam/graal/pi.rb +18 -0
- data/lib/seafoam/graph.rb +9 -1
- data/lib/seafoam/graphviz_writer.rb +3 -0
- data/lib/seafoam/json_writer.rb +1 -3
- data/lib/seafoam/{annotators → passes}/fallback.rb +4 -4
- data/lib/seafoam/{annotators → passes}/graal.rb +43 -13
- data/lib/seafoam/passes/truffle.rb +58 -0
- data/lib/seafoam/passes.rb +61 -0
- data/lib/seafoam/version.rb +1 -1
- data/lib/seafoam.rb +5 -4
- metadata +23 -60
- data/.github/probots.yml +0 -2
- data/.github/workflows/workflows.yml +0 -40
- data/.gitignore +0 -6
- data/.rubocop.yml +0 -37
- data/.ruby-version +0 -1
- data/.seafoam/config +0 -1
- data/CODE_OF_CONDUCT.md +0 -128
- data/CONTRIBUTING.md +0 -5
- data/Gemfile +0 -2
- data/Gemfile.lock +0 -59
- data/LICENSE.md +0 -7
- data/README.md +0 -378
- data/demos/box-unbox-stats +0 -65
- data/docs/annotators.md +0 -43
- data/docs/bgv.md +0 -294
- data/docs/getting-graphs.md +0 -63
- data/docs/images/igv.png +0 -0
- data/docs/images/seafoam.png +0 -0
- data/docs/images/spotlight-igv.png +0 -0
- data/docs/images/spotlight-seafoam.png +0 -0
- data/docs/json.md +0 -35
- data/examples/Fib.java +0 -24
- data/examples/MatMult.java +0 -39
- data/examples/fib-java.bgv.gz +0 -0
- data/examples/fib.js +0 -15
- data/examples/fib.rb +0 -15
- data/examples/identity.rb +0 -13
- data/examples/java/Irreducible.class +0 -0
- data/examples/java/Irreducible.j +0 -35
- data/examples/java/IrreducibleDecompiled.java +0 -21
- data/examples/java/JavaExamples.java +0 -418
- data/examples/matmult.rb +0 -29
- data/examples/overflow.rb +0 -13
- data/examples/ruby/clamps.rb +0 -20
- data/examples/ruby/graal.patch +0 -15
- data/examples/ruby/ruby_examples.rb +0 -278
- data/lib/seafoam/annotators.rb +0 -54
- data/lib/seafoam/config.rb +0 -34
- data/seafoam.gemspec +0 -22
- data/spec/seafoam/annotators/fallback_spec.rb +0 -69
- data/spec/seafoam/annotators/graal_spec.rb +0 -96
- data/spec/seafoam/annotators_spec.rb +0 -61
- data/spec/seafoam/bgv/bgv_parser_spec.rb +0 -167
- data/spec/seafoam/binary/io_binary_reader_spec.rb +0 -176
- data/spec/seafoam/cfg/cfg_parser_spec.rb +0 -21
- data/spec/seafoam/cfg/disassembler_spec.rb +0 -32
- data/spec/seafoam/command_spec.rb +0 -314
- data/spec/seafoam/graph_spec.rb +0 -172
- data/spec/seafoam/graphviz_writer_spec.rb +0 -63
- data/spec/seafoam/json_writer_spec.rb +0 -14
- data/spec/seafoam/spec_helpers.rb +0 -34
- data/spec/seafoam/spotlight_spec.rb +0 -38
- data/tools/render-all +0 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 49d090779b04322f8c82aae0cf11ea2e39cd4cef1f3d9dc2b51de1f27e565f9c
|
4
|
+
data.tar.gz: 121f1c7bb327c30f1a388960012c43dab49e0f1079d5a420811ab2332de9663b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd13ee2efe4fe4118fc5f6bdb56c55b3c1c5f28b86a3d37ce3cf4fc72bcdcbeb161968260b62626047b9f9f9eedec53cbc743d79512a11bd77b195f054c54262
|
7
|
+
data.tar.gz: 67e06a4e89fdf9e6297e3d68da7f7b0e7d4f1de95a97c9be17c12e6c9114476ee6e747c6306c3bc472e549317f20c19c315c9789d1814c68fdd85501327c432b
|
data/bin/bgv2isabelle
CHANGED
@@ -5,12 +5,8 @@ require 'seafoam'
|
|
5
5
|
# This is the 'bgv2isabelle' command line entry point.
|
6
6
|
|
7
7
|
begin
|
8
|
-
# Load configuraiton.
|
9
|
-
config = Seafoam::Config.new
|
10
|
-
config.load_config
|
11
|
-
|
12
8
|
# Run the command line.
|
13
|
-
commands = Seafoam::Commands.new($stdout
|
9
|
+
commands = Seafoam::Commands.new($stdout)
|
14
10
|
commands.bgv2isabelle(*ARGV)
|
15
11
|
rescue StandardError => e
|
16
12
|
if $DEBUG
|
data/bin/bgv2json
CHANGED
@@ -5,12 +5,8 @@ require 'seafoam'
|
|
5
5
|
# This is the 'bgv2json' command line entry point.
|
6
6
|
|
7
7
|
begin
|
8
|
-
# Load configuraiton.
|
9
|
-
config = Seafoam::Config.new
|
10
|
-
config.load_config
|
11
|
-
|
12
8
|
# Run the command line.
|
13
|
-
commands = Seafoam::Commands.new($stdout
|
9
|
+
commands = Seafoam::Commands.new($stdout)
|
14
10
|
commands.bgv2json(*ARGV)
|
15
11
|
rescue StandardError => e
|
16
12
|
if $DEBUG
|
data/bin/cfg2asm
CHANGED
@@ -5,12 +5,8 @@ require 'seafoam'
|
|
5
5
|
# This is the 'cfg2asm' command line entry point.
|
6
6
|
|
7
7
|
begin
|
8
|
-
# Load configuraiton.
|
9
|
-
config = Seafoam::Config.new
|
10
|
-
config.load_config
|
11
|
-
|
12
8
|
# Run the command line.
|
13
|
-
commands = Seafoam::Commands.new($stdout
|
9
|
+
commands = Seafoam::Commands.new($stdout)
|
14
10
|
commands.cfg2asm(*ARGV)
|
15
11
|
rescue StandardError => e
|
16
12
|
if $DEBUG
|
data/bin/seafoam
CHANGED
@@ -5,12 +5,8 @@ require 'seafoam'
|
|
5
5
|
# This is the 'seafoam' command line entry point.
|
6
6
|
|
7
7
|
begin
|
8
|
-
# Load configuraiton.
|
9
|
-
config = Seafoam::Config.new
|
10
|
-
config.load_config
|
11
|
-
|
12
8
|
# Run the command line.
|
13
|
-
commands = Seafoam::Commands.new($stdout
|
9
|
+
commands = Seafoam::Commands.new($stdout)
|
14
10
|
commands.seafoam(*ARGV)
|
15
11
|
rescue StandardError => e
|
16
12
|
if $DEBUG
|
data/lib/seafoam/commands.rb
CHANGED
@@ -3,9 +3,8 @@ require 'json'
|
|
3
3
|
module Seafoam
|
4
4
|
# Implementations of the command-line commands that you can run in Seafoam.
|
5
5
|
class Commands
|
6
|
-
def initialize(out
|
6
|
+
def initialize(out)
|
7
7
|
@out = out
|
8
|
-
@config = config
|
9
8
|
end
|
10
9
|
|
11
10
|
# Run the general seafoam command.
|
@@ -15,25 +14,7 @@ module Seafoam
|
|
15
14
|
when nil, 'help', '-h', '--help', '-help'
|
16
15
|
raise ArgumentError, "unexpected arguments #{args.join(' ')}" unless args.empty?
|
17
16
|
|
18
|
-
|
19
|
-
@out.puts ' file.bgv list'
|
20
|
-
@out.puts ' file.bgv[:graph][:node[-edge]] search term...'
|
21
|
-
@out.puts ' file.bgv[:graph][:node[-edge]] edges'
|
22
|
-
@out.puts ' file.bgv[:graph][:node[-edge]] props'
|
23
|
-
@out.puts ' file.bgv:graph:node source'
|
24
|
-
@out.puts ' file.bgv:graph render'
|
25
|
-
@out.puts ' --spotlight n,n,n...'
|
26
|
-
@out.puts ' --out graph.pdf'
|
27
|
-
@out.puts ' graph.svg'
|
28
|
-
@out.puts ' graph.png'
|
29
|
-
@out.puts ' graph.dot'
|
30
|
-
@out.puts ' --show-frame-state'
|
31
|
-
@out.puts ' --hide-floating'
|
32
|
-
@out.puts ' --no-reduce-edges'
|
33
|
-
@out.puts ' --draw-blocks'
|
34
|
-
@out.puts ' --option key value'
|
35
|
-
@out.puts ' --help'
|
36
|
-
@out.puts ' --version'
|
17
|
+
help(*args)
|
37
18
|
when 'version', '-v', '-version', '--version'
|
38
19
|
version(*args)
|
39
20
|
else
|
@@ -263,7 +244,7 @@ module Seafoam
|
|
263
244
|
end
|
264
245
|
|
265
246
|
def search_object(tag, object, terms)
|
266
|
-
full_text = JSON.generate(object)
|
247
|
+
full_text = JSON.generate(JSONWriter.prepare_json(object))
|
267
248
|
full_text_down = full_text.downcase
|
268
249
|
start = 0
|
269
250
|
terms.each do |t|
|
@@ -299,7 +280,7 @@ module Seafoam
|
|
299
280
|
parser.read_graph_header
|
300
281
|
graph = parser.read_graph
|
301
282
|
if node_id
|
302
|
-
|
283
|
+
Passes.apply graph
|
303
284
|
node = graph.nodes[node_id]
|
304
285
|
raise ArgumentError, 'node not found' unless node
|
305
286
|
|
@@ -398,8 +379,10 @@ module Seafoam
|
|
398
379
|
raise ArgumentError, 'render needs at least a graph' unless graph_index
|
399
380
|
raise ArgumentError, 'render only works with a graph' unless rest == [nil, nil]
|
400
381
|
|
401
|
-
|
382
|
+
pass_options = {
|
383
|
+
simplify_truffle_args: true,
|
402
384
|
hide_frame_state: true,
|
385
|
+
hide_pi: true,
|
403
386
|
hide_floating: false,
|
404
387
|
reduce_edges: true
|
405
388
|
}
|
@@ -420,12 +403,16 @@ module Seafoam
|
|
420
403
|
raise ArgumentError, 'no list for --spotlight' unless spotlight_arg
|
421
404
|
|
422
405
|
spotlight_nodes = spotlight_arg.split(',').map { |n| Integer(n) }
|
406
|
+
when '--full-truffle-args'
|
407
|
+
pass_options[:simplify_truffle_args] = false
|
423
408
|
when '--show-frame-state'
|
424
|
-
|
409
|
+
pass_options[:hide_frame_state] = false
|
410
|
+
when '--show-pi'
|
411
|
+
pass_options[:hide_pi] = false
|
425
412
|
when '--hide-floating'
|
426
|
-
|
413
|
+
pass_options[:hide_floating] = true
|
427
414
|
when '--no-reduce-edges'
|
428
|
-
|
415
|
+
pass_options[:reduce_edges] = false
|
429
416
|
when '--draw-blocks'
|
430
417
|
draw_blocks = true
|
431
418
|
when '--option'
|
@@ -436,7 +423,7 @@ module Seafoam
|
|
436
423
|
raise ArgumentError, "no value for --option #{key}" unless out_file
|
437
424
|
|
438
425
|
value = { 'true' => true, 'false' => 'false' }.fetch(key, value)
|
439
|
-
|
426
|
+
pass_options[key.to_sym] = value
|
440
427
|
else
|
441
428
|
raise ArgumentError, "unexpected option #{arg}"
|
442
429
|
end
|
@@ -459,7 +446,7 @@ module Seafoam
|
|
459
446
|
with_graph(file, graph_index) do |parser|
|
460
447
|
parser.skip_graph_header
|
461
448
|
graph = parser.read_graph
|
462
|
-
|
449
|
+
Passes.apply graph, pass_options
|
463
450
|
if spotlight_nodes
|
464
451
|
spotlight = Spotlight.new(graph)
|
465
452
|
spotlight_nodes.each do |node_id|
|
@@ -569,6 +556,31 @@ module Seafoam
|
|
569
556
|
raise ArgumentError, 'graph not found' unless graph_found
|
570
557
|
end
|
571
558
|
|
559
|
+
# Prints help.
|
560
|
+
def help(*_args)
|
561
|
+
@out.puts 'seafoam file.bgv info'
|
562
|
+
@out.puts ' file.bgv list'
|
563
|
+
@out.puts ' file.bgv[:graph][:node[-edge]] search term...'
|
564
|
+
@out.puts ' file.bgv[:graph][:node[-edge]] edges'
|
565
|
+
@out.puts ' file.bgv[:graph][:node[-edge]] props'
|
566
|
+
@out.puts ' file.bgv:graph:node source'
|
567
|
+
@out.puts ' file.bgv:graph render'
|
568
|
+
@out.puts ' --spotlight n,n,n...'
|
569
|
+
@out.puts ' --out graph.pdf'
|
570
|
+
@out.puts ' graph.svg'
|
571
|
+
@out.puts ' graph.png'
|
572
|
+
@out.puts ' graph.dot'
|
573
|
+
@out.puts ' --full-truffle-args'
|
574
|
+
@out.puts ' --show-frame-state'
|
575
|
+
@out.puts ' --show-pi'
|
576
|
+
@out.puts ' --hide-floating'
|
577
|
+
@out.puts ' --no-reduce-edges'
|
578
|
+
@out.puts ' --draw-blocks'
|
579
|
+
@out.puts ' --option key value'
|
580
|
+
@out.puts ' --help'
|
581
|
+
@out.puts ' --version'
|
582
|
+
end
|
583
|
+
|
572
584
|
# Prints the version.
|
573
585
|
def version(*args)
|
574
586
|
raise ArgumentError, "unexpected arguments #{args.join(' ')}" unless args.empty?
|
@@ -602,10 +614,15 @@ module Seafoam
|
|
602
614
|
|
603
615
|
# Open a file for the user if possible.
|
604
616
|
def autoopen(file)
|
605
|
-
|
617
|
+
return unless @out.tty?
|
618
|
+
|
619
|
+
case RUBY_PLATFORM
|
620
|
+
when /darwin/
|
606
621
|
system 'open', file
|
607
|
-
|
622
|
+
when /linux/
|
623
|
+
system 'xdg-open', file
|
608
624
|
end
|
625
|
+
# Don't worry if it fails.
|
609
626
|
end
|
610
627
|
end
|
611
628
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Seafoam
|
2
|
+
module Graal
|
3
|
+
# Routines for understanding pi nodes in Graal.
|
4
|
+
module Pi
|
5
|
+
# Find the actual value behind potentially a chain of pi nodes.
|
6
|
+
def self.follow_pi_object(node)
|
7
|
+
node = node.edges.find { |edge| edge.props[:name] == 'object' }.from while PI_NODES.include?(node.props.dig(:node_class, :node_class))
|
8
|
+
node
|
9
|
+
end
|
10
|
+
|
11
|
+
# Pi nodes add type information.
|
12
|
+
PI_NODES = [
|
13
|
+
'org.graalvm.compiler.nodes.PiNode',
|
14
|
+
'org.graalvm.compiler.nodes.PiArrayNode'
|
15
|
+
]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/seafoam/graph.rb
CHANGED
@@ -2,13 +2,14 @@ module Seafoam
|
|
2
2
|
# A graph, with properties, nodes, and edges. We don't encapsulate the graph
|
3
3
|
# too much - be careful.
|
4
4
|
class Graph
|
5
|
-
attr_reader :props, :nodes, :edges, :blocks
|
5
|
+
attr_reader :props, :nodes, :edges, :blocks, :new_id
|
6
6
|
|
7
7
|
def initialize(props = nil)
|
8
8
|
@props = props || {}
|
9
9
|
@nodes = {}
|
10
10
|
@edges = []
|
11
11
|
@blocks = []
|
12
|
+
@new_id = 0
|
12
13
|
end
|
13
14
|
|
14
15
|
# Create a node.
|
@@ -16,6 +17,7 @@ module Seafoam
|
|
16
17
|
props ||= {}
|
17
18
|
node = Node.new(id, props)
|
18
19
|
@nodes[id] = node
|
20
|
+
@new_id = id + 1
|
19
21
|
node
|
20
22
|
end
|
21
23
|
|
@@ -36,6 +38,12 @@ module Seafoam
|
|
36
38
|
@blocks.push block
|
37
39
|
block
|
38
40
|
end
|
41
|
+
|
42
|
+
def remove_edge(edge)
|
43
|
+
edge.from.outputs.delete edge
|
44
|
+
edge.to.inputs.delete edge
|
45
|
+
edges.delete edge
|
46
|
+
end
|
39
47
|
end
|
40
48
|
|
41
49
|
# A node, with properties, input edges, and output edges.
|
@@ -100,6 +100,9 @@ module Seafoam
|
|
100
100
|
# from a shaded node.
|
101
101
|
next if edge.to.props[:hidden] && edge.from.props[:spotlight] != 'shaded'
|
102
102
|
|
103
|
+
# Skip the edge if it's hidden itself
|
104
|
+
next if edge.props[:hidden]
|
105
|
+
|
103
106
|
write_edge inline_attrs, edge
|
104
107
|
end
|
105
108
|
end
|
data/lib/seafoam/json_writer.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
module Seafoam
|
2
|
-
module
|
3
|
-
# The fallback
|
2
|
+
module Passes
|
3
|
+
# The fallback pass always applies, and adds some basic properties.
|
4
4
|
# Works for example with Truffle AST and call graphs, but also means anyone
|
5
5
|
# can emit a graph with 'label' properties and we can do something useful
|
6
6
|
# with it.
|
7
|
-
class
|
7
|
+
class FallbackPass < Pass
|
8
8
|
def self.applies?(_graph)
|
9
9
|
true
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
12
|
+
def apply(graph)
|
13
13
|
graph.nodes.each_value do |node|
|
14
14
|
if node.props[:label].nil? && node.props['label']
|
15
15
|
node.props[:label] = node.props['label']
|
@@ -1,18 +1,19 @@
|
|
1
1
|
module Seafoam
|
2
|
-
module
|
3
|
-
# The Graal
|
2
|
+
module Passes
|
3
|
+
# The Graal pass applies if it looks like it was compiled by Graal or
|
4
4
|
# Truffle.
|
5
|
-
class
|
5
|
+
class GraalPass < Pass
|
6
6
|
def self.applies?(graph)
|
7
7
|
graph.props.values.any? do |v|
|
8
8
|
TRIGGERS.any? { |t| v.to_s.include?(t) }
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
13
|
-
|
14
|
-
|
12
|
+
def apply(graph)
|
13
|
+
apply_nodes graph
|
14
|
+
apply_edges graph
|
15
15
|
hide_frame_state graph if @options[:hide_frame_state]
|
16
|
+
hide_pi graph if @options[:hide_pi]
|
16
17
|
hide_floating graph if @options[:hide_floating]
|
17
18
|
reduce_edges graph if @options[:reduce_edges]
|
18
19
|
hide_unused_nodes graph
|
@@ -21,8 +22,10 @@ module Seafoam
|
|
21
22
|
private
|
22
23
|
|
23
24
|
# Annotate nodes with their label and kind
|
24
|
-
def
|
25
|
+
def apply_nodes(graph)
|
25
26
|
graph.nodes.each_value do |node|
|
27
|
+
next if node.props[:label]
|
28
|
+
|
26
29
|
# The Java class of the node.
|
27
30
|
node_class = node.props.dig(:node_class, :node_class)
|
28
31
|
|
@@ -93,6 +96,11 @@ module Seafoam
|
|
93
96
|
name_template = 'π'
|
94
97
|
end
|
95
98
|
|
99
|
+
# Use a symbol for PiArrayNode.
|
100
|
+
if node_class == 'org.graalvm.compiler.nodes.PiArrayNode'
|
101
|
+
name_template = '[π]'
|
102
|
+
end
|
103
|
+
|
96
104
|
# Use a symbol for PhiNode.
|
97
105
|
if node_class == 'org.graalvm.compiler.nodes.ValuePhiNode'
|
98
106
|
name_template = 'ϕ'
|
@@ -208,7 +216,7 @@ module Seafoam
|
|
208
216
|
end
|
209
217
|
|
210
218
|
# Annotate edges with their label and kind.
|
211
|
-
def
|
219
|
+
def apply_edges(graph)
|
212
220
|
graph.edges.each do |edge|
|
213
221
|
if edge.to.props.dig(:node_class, :node_class) == 'org.graalvm.compiler.nodes.ValuePhiNode' && edge.props[:name] == 'values'
|
214
222
|
merge_node = edge.to.edges.find { |e| e.props[:name] == 'merge' }.from
|
@@ -311,6 +319,24 @@ module Seafoam
|
|
311
319
|
end
|
312
320
|
end
|
313
321
|
|
322
|
+
# Hide pi nodes - they add information for optimisation, but not generally
|
323
|
+
# useful day-to-day for understanding the graph. Connect the user to the
|
324
|
+
# actual object, which may be several steps away.
|
325
|
+
def hide_pi(graph)
|
326
|
+
loop do
|
327
|
+
umodified = true
|
328
|
+
graph.edges.each do |edge|
|
329
|
+
next unless Graal::Pi::PI_NODES.include?(edge.from.props.dig(:node_class, :node_class))
|
330
|
+
|
331
|
+
object = Graal::Pi.follow_pi_object(edge.from)
|
332
|
+
graph.create_edge object, edge.to, edge.props.merge({ synthetic: true })
|
333
|
+
graph.remove_edge edge
|
334
|
+
umodified = false
|
335
|
+
end
|
336
|
+
break if umodified
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
314
340
|
# Hide floating nodes. This highlights just the control flow backbone.
|
315
341
|
def hide_floating(graph)
|
316
342
|
graph.nodes.each_value do |node|
|
@@ -332,15 +358,19 @@ module Seafoam
|
|
332
358
|
end
|
333
359
|
end
|
334
360
|
|
335
|
-
# Hide nodes that have no non-hidden users and no control flow
|
336
|
-
# would display as a node floating unconnected to the rest of
|
337
|
-
# otherwise. An exception is made for node with an anchor edge
|
338
|
-
# as some guards are anchored like this.
|
361
|
+
# Hide nodes that have no non-hidden users or edges and no control flow
|
362
|
+
# in. These would display as a node floating unconnected to the rest of
|
363
|
+
# the graph otherwise. An exception is made for node with an anchor edge
|
364
|
+
# coming in, as some guards are anchored like this.
|
339
365
|
def hide_unused_nodes(graph)
|
340
366
|
loop do
|
341
367
|
modified = false
|
342
368
|
graph.nodes.each_value do |node|
|
343
|
-
|
369
|
+
# Call trees are like Graal graphs but don't have these edges -
|
370
|
+
# don't hide them.
|
371
|
+
next if node.props['truffleCallees']
|
372
|
+
|
373
|
+
next unless node.outputs.all? { |edge| edge.to.props[:hidden] || edge.props[:hidden] } &&
|
344
374
|
node.inputs.none? { |edge| edge.props[:kind] == 'control' } &&
|
345
375
|
node.inputs.none? { |edge| edge.props[:name] == 'anchor' }
|
346
376
|
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Seafoam
|
2
|
+
module Passes
|
3
|
+
# The Truffle pass applies if it looks like it was compiled by Truffle.
|
4
|
+
class TrufflePass < Pass
|
5
|
+
def self.applies?(graph)
|
6
|
+
graph.props.values.any? do |v|
|
7
|
+
TRIGGERS.any? { |t| v.to_s.include?(t) }
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def apply(graph)
|
12
|
+
simplify_truffle_args graph if @options[:simplify_truffle_args]
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
# Simplify a Truffle argument load into a single, inlined, node very much
|
18
|
+
# like a Graal parameter node.
|
19
|
+
def simplify_truffle_args(graph)
|
20
|
+
graph.nodes.dup.each_value do |node|
|
21
|
+
next unless node.props.dig(:node_class, :node_class) == 'org.graalvm.compiler.nodes.java.LoadIndexedNode'
|
22
|
+
|
23
|
+
index_node = node.inputs.find { |edge| edge.props[:name] == 'index' }.from
|
24
|
+
array_node = Graal::Pi.follow_pi_object(node.inputs.find { |edge| edge.props[:name] == 'array' }.from)
|
25
|
+
|
26
|
+
next unless index_node.props.dig(:node_class, :node_class) == 'org.graalvm.compiler.nodes.ConstantNode'
|
27
|
+
next unless array_node.props.dig(:node_class, :node_class) == 'org.graalvm.compiler.nodes.ParameterNode'
|
28
|
+
|
29
|
+
node.props[:truffle_arg_load] = true
|
30
|
+
|
31
|
+
index = index_node.props['rawvalue']
|
32
|
+
|
33
|
+
arg_node = graph.create_node(graph.new_id, { synthetic: true, inlined: true, label: "T(#{index})", kind: 'input' })
|
34
|
+
|
35
|
+
node.outputs.each do |output|
|
36
|
+
next if output.props[:name] == 'next'
|
37
|
+
|
38
|
+
graph.create_edge arg_node, output.to, output.props.dup
|
39
|
+
graph.remove_edge output
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
graph.nodes.each_value.select { |node| node.props[:truffle_arg_load] }.each do |node|
|
44
|
+
control_in = node.inputs.find { |edge| edge.props[:name] == 'next' }
|
45
|
+
control_out = node.outputs.find { |edge| edge.props[:name] == 'next' }
|
46
|
+
graph.create_edge control_in.from, control_out.to, { name: 'next' }
|
47
|
+
graph.remove_edge control_in
|
48
|
+
graph.remove_edge control_out
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# If we see these in the graph properties it's probably a Truffle graph.
|
53
|
+
TRIGGERS = %w[
|
54
|
+
TruffleCompiler
|
55
|
+
]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Seafoam
|
2
|
+
# Passes 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 Passes
|
5
|
+
# Apply all applicable passes to a graph.
|
6
|
+
def self.apply(graph, options = {})
|
7
|
+
passes.each do |pass|
|
8
|
+
next unless pass.applies?(graph)
|
9
|
+
|
10
|
+
# Record for information that the pass was applied this graph.
|
11
|
+
passes_applied = graph.props[:passes_applied] ||= []
|
12
|
+
passes_applied.push pass
|
13
|
+
|
14
|
+
# Run the pass.
|
15
|
+
instance = pass.new(options)
|
16
|
+
instance.apply graph
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Get a list of all passes in the system.
|
21
|
+
def self.passes
|
22
|
+
# We have a defined order for passes to run - these passes at the start.
|
23
|
+
pre_passes = [
|
24
|
+
TrufflePass,
|
25
|
+
GraalPass
|
26
|
+
]
|
27
|
+
|
28
|
+
# The fallback pass runs last.
|
29
|
+
post_passes = [
|
30
|
+
FallbackPass
|
31
|
+
]
|
32
|
+
|
33
|
+
# Any extra passes in the middle.
|
34
|
+
extra_passes = Pass::SUBCLASSES.dup - pre_passes - post_passes
|
35
|
+
|
36
|
+
pre_passes + extra_passes + post_passes
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# The base class for all passes. You must subclass this to be recognized
|
41
|
+
# as an pass.
|
42
|
+
class Pass
|
43
|
+
SUBCLASSES = []
|
44
|
+
|
45
|
+
def initialize(options = {})
|
46
|
+
@options = options
|
47
|
+
end
|
48
|
+
|
49
|
+
def applies?(_graph)
|
50
|
+
raise NotImplementedError
|
51
|
+
end
|
52
|
+
|
53
|
+
def apply(_graph)
|
54
|
+
raise NotImplementedError
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.inherited(pass)
|
58
|
+
SUBCLASSES.push pass
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/seafoam/version.rb
CHANGED
data/lib/seafoam.rb
CHANGED
@@ -6,12 +6,13 @@ require 'seafoam/cfg/disassembler'
|
|
6
6
|
require 'seafoam/colors'
|
7
7
|
require 'seafoam/graph'
|
8
8
|
require 'seafoam/graal/source'
|
9
|
-
require 'seafoam/
|
10
|
-
require 'seafoam/
|
11
|
-
require 'seafoam/
|
9
|
+
require 'seafoam/graal/pi'
|
10
|
+
require 'seafoam/passes'
|
11
|
+
require 'seafoam/passes/truffle'
|
12
|
+
require 'seafoam/passes/graal'
|
13
|
+
require 'seafoam/passes/fallback'
|
12
14
|
require 'seafoam/spotlight'
|
13
15
|
require 'seafoam/isabelle_writer'
|
14
16
|
require 'seafoam/json_writer'
|
15
17
|
require 'seafoam/graphviz_writer'
|
16
|
-
require 'seafoam/config'
|
17
18
|
require 'seafoam/commands'
|