furnace 0.1.2 → 0.2.0
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.
- data/lib/furnace/ast/matcher.rb +2 -0
- data/lib/furnace/ast.rb +1 -1
- data/lib/furnace/cfg/graph.rb +5 -0
- data/lib/furnace/cfg.rb +1 -1
- data/lib/furnace/code.rb +1 -1
- data/lib/furnace/graphviz.rb +1 -1
- data/lib/furnace/version.rb +1 -1
- data/lib/furnace.rb +5 -14
- metadata +4 -14
- data/.rvmrc +0 -61
- data/bin/furnace +0 -22
- data/lib/furnace/base.rb +0 -5
- data/lib/furnace/transform/generic/cfg_build.rb +0 -89
- data/lib/furnace/transform/generic/cfg_normalize.rb +0 -41
- data/lib/furnace/transform/generic/label_normalize.rb +0 -60
- data/lib/furnace/transform/optimizing/fold_constants.rb +0 -19
- data/lib/furnace/transform/rubinius/ast_build.rb +0 -53
- data/lib/furnace/transform/rubinius/ast_normalize.rb +0 -170
- data/lib/furnace/transform.rb +0 -13
data/lib/furnace/ast/matcher.rb
CHANGED
data/lib/furnace/ast.rb
CHANGED
data/lib/furnace/cfg/graph.rb
CHANGED
@@ -58,6 +58,11 @@ module Furnace::CFG
|
|
58
58
|
target = node.targets[0]
|
59
59
|
next if target == @exit
|
60
60
|
|
61
|
+
# Skip explicitly non-redundant nodes
|
62
|
+
if node.cti && node.cti.metadata[:keep]
|
63
|
+
next
|
64
|
+
end
|
65
|
+
|
61
66
|
if node.targets.count == 1 &&
|
62
67
|
target.sources.count == 1 &&
|
63
68
|
node.exception == target.exception
|
data/lib/furnace/cfg.rb
CHANGED
data/lib/furnace/code.rb
CHANGED
data/lib/furnace/graphviz.rb
CHANGED
data/lib/furnace/version.rb
CHANGED
data/lib/furnace.rb
CHANGED
@@ -1,21 +1,12 @@
|
|
1
|
+
module Furnace
|
2
|
+
end
|
3
|
+
|
1
4
|
require "furnace/version"
|
2
5
|
|
3
6
|
require "furnace/ast"
|
4
7
|
require "furnace/cfg"
|
5
8
|
require "furnace/code"
|
6
9
|
|
7
|
-
require "furnace/
|
8
|
-
require "furnace/anf/edge"
|
9
|
-
require "furnace/anf/let_node"
|
10
|
-
require "furnace/anf/in_node"
|
11
|
-
require "furnace/anf/if_node"
|
12
|
-
require "furnace/anf/return_node"
|
13
|
-
require "furnace/anf/graph"
|
14
|
-
|
15
|
-
require "furnace/transform"
|
16
|
-
|
17
|
-
require "furnace/graphviz"
|
10
|
+
require "furnace/transform/pipeline"
|
18
11
|
|
19
|
-
|
20
|
-
raise "Sorry, Furnace only works on Rubinius."
|
21
|
-
end
|
12
|
+
require "furnace/graphviz"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: furnace
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,23 +9,20 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-06-10 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Furnace is a static code analysis framework for dynamic languages, aimed
|
15
15
|
at efficient type and behavior inference.
|
16
16
|
email:
|
17
17
|
- whitequark@whitequark.org
|
18
|
-
executables:
|
19
|
-
- furnace
|
18
|
+
executables: []
|
20
19
|
extensions: []
|
21
20
|
extra_rdoc_files: []
|
22
21
|
files:
|
23
22
|
- .gitignore
|
24
|
-
- .rvmrc
|
25
23
|
- Gemfile
|
26
24
|
- LICENSE
|
27
25
|
- Rakefile
|
28
|
-
- bin/furnace
|
29
26
|
- furnace.gemspec
|
30
27
|
- lib/furnace.rb
|
31
28
|
- lib/furnace/ast.rb
|
@@ -35,7 +32,6 @@ files:
|
|
35
32
|
- lib/furnace/ast/node.rb
|
36
33
|
- lib/furnace/ast/symbolic_node.rb
|
37
34
|
- lib/furnace/ast/visitor.rb
|
38
|
-
- lib/furnace/base.rb
|
39
35
|
- lib/furnace/cfg.rb
|
40
36
|
- lib/furnace/cfg/graph.rb
|
41
37
|
- lib/furnace/cfg/node.rb
|
@@ -47,14 +43,7 @@ files:
|
|
47
43
|
- lib/furnace/code/terminal_token.rb
|
48
44
|
- lib/furnace/code/token.rb
|
49
45
|
- lib/furnace/graphviz.rb
|
50
|
-
- lib/furnace/transform.rb
|
51
|
-
- lib/furnace/transform/generic/cfg_build.rb
|
52
|
-
- lib/furnace/transform/generic/cfg_normalize.rb
|
53
|
-
- lib/furnace/transform/generic/label_normalize.rb
|
54
|
-
- lib/furnace/transform/optimizing/fold_constants.rb
|
55
46
|
- lib/furnace/transform/pipeline.rb
|
56
|
-
- lib/furnace/transform/rubinius/ast_build.rb
|
57
|
-
- lib/furnace/transform/rubinius/ast_normalize.rb
|
58
47
|
- lib/furnace/version.rb
|
59
48
|
homepage: http://github.com/whitequark/furnace
|
60
49
|
licenses: []
|
@@ -81,3 +70,4 @@ signing_key:
|
|
81
70
|
specification_version: 3
|
82
71
|
summary: A static code analysis framework
|
83
72
|
test_files: []
|
73
|
+
has_rdoc:
|
data/.rvmrc
DELETED
@@ -1,61 +0,0 @@
|
|
1
|
-
#!/usr/bin/env bash
|
2
|
-
|
3
|
-
# This is an RVM Project .rvmrc file, used to automatically load the ruby
|
4
|
-
# development environment upon cd'ing into the directory
|
5
|
-
|
6
|
-
# First we specify our desired <ruby>[@<gemset>], the @gemset name is optional.
|
7
|
-
environment_id="rbx-head@furnace"
|
8
|
-
|
9
|
-
#
|
10
|
-
# Uncomment following line if you want options to be set only for given project.
|
11
|
-
#
|
12
|
-
# PROJECT_JRUBY_OPTS=( --1.9 )
|
13
|
-
|
14
|
-
#
|
15
|
-
# First we attempt to load the desired environment directly from the environment
|
16
|
-
# file. This is very fast and efficient compared to running through the entire
|
17
|
-
# CLI and selector. If you want feedback on which environment was used then
|
18
|
-
# insert the word 'use' after --create as this triggers verbose mode.
|
19
|
-
#
|
20
|
-
if [[ -d "${rvm_path:-$HOME/.rvm}/environments" \
|
21
|
-
&& -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
|
22
|
-
then
|
23
|
-
\. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
|
24
|
-
|
25
|
-
if [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]]
|
26
|
-
then
|
27
|
-
. "${rvm_path:-$HOME/.rvm}/hooks/after_use"
|
28
|
-
fi
|
29
|
-
else
|
30
|
-
# If the environment file has not yet been created, use the RVM CLI to select.
|
31
|
-
if ! rvm --create "$environment_id"
|
32
|
-
then
|
33
|
-
echo "Failed to create RVM environment '${environment_id}'."
|
34
|
-
return 1
|
35
|
-
fi
|
36
|
-
fi
|
37
|
-
|
38
|
-
#
|
39
|
-
# If you use an RVM gemset file to install a list of gems (*.gems), you can have
|
40
|
-
# it be automatically loaded. Uncomment the following and adjust the filename if
|
41
|
-
# necessary.
|
42
|
-
#
|
43
|
-
# filename=".gems"
|
44
|
-
# if [[ -s "$filename" ]]
|
45
|
-
# then
|
46
|
-
# rvm gemset import "$filename" | grep -v already | grep -v listed | grep -v complete | sed '/^$/d'
|
47
|
-
# fi
|
48
|
-
|
49
|
-
# If you use bundler, this might be useful to you:
|
50
|
-
# if command -v bundle && [[ -s Gemfile ]]
|
51
|
-
# then
|
52
|
-
# bundle install
|
53
|
-
# fi
|
54
|
-
|
55
|
-
if [[ $- == *i* ]] # check for interactive shells
|
56
|
-
then
|
57
|
-
echo "Using: $(tput setaf 2)$GEM_HOME$(tput sgr0)" # show the user the ruby and gemset they are using in green
|
58
|
-
else
|
59
|
-
echo "Using: $GEM_HOME" # don't use colors in interactive shells
|
60
|
-
fi
|
61
|
-
|
data/bin/furnace
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'furnace'
|
4
|
-
|
5
|
-
load ARGV[0]
|
6
|
-
|
7
|
-
pipeline = Furnace::Transform::Pipeline.new(*[
|
8
|
-
Furnace::Transform::Rubinius::ASTBuild.new,
|
9
|
-
Furnace::Transform::Rubinius::ASTNormalize.new,
|
10
|
-
|
11
|
-
Furnace::Transform::Generic::LabelNormalize.new,
|
12
|
-
Furnace::Transform::Generic::CFGBuild.new,
|
13
|
-
Furnace::Transform::Generic::CFGNormalize.new,
|
14
|
-
|
15
|
-
Furnace::Transform::Generic::ANFBuild.new,
|
16
|
-
|
17
|
-
Furnace::Transform::Optimizing::FoldConstants.new,
|
18
|
-
])
|
19
|
-
|
20
|
-
cfg, = pipeline.run(method(:main).executable)
|
21
|
-
|
22
|
-
puts cfg.to_graphviz
|
data/lib/furnace/base.rb
DELETED
@@ -1,89 +0,0 @@
|
|
1
|
-
module Furnace
|
2
|
-
module Transform
|
3
|
-
module Generic
|
4
|
-
class VariableTracer
|
5
|
-
include AST::Visitor
|
6
|
-
|
7
|
-
attr_reader :read_set, :write_set
|
8
|
-
|
9
|
-
def initialize
|
10
|
-
@read_set = Set.new
|
11
|
-
@write_set = Set.new
|
12
|
-
@conflict = false
|
13
|
-
end
|
14
|
-
|
15
|
-
def reset
|
16
|
-
@read_set.clear
|
17
|
-
@write_set.clear
|
18
|
-
@conflict = false
|
19
|
-
end
|
20
|
-
|
21
|
-
def conflict?
|
22
|
-
@conflict
|
23
|
-
end
|
24
|
-
|
25
|
-
def on_set_lvar(node)
|
26
|
-
var = node.children.first
|
27
|
-
|
28
|
-
@write_set.add var
|
29
|
-
@conflict ||= @read_set.include?(var)
|
30
|
-
end
|
31
|
-
|
32
|
-
def on_get_lvar(node)
|
33
|
-
var = node.children.first
|
34
|
-
|
35
|
-
@read_set.add var
|
36
|
-
@conflict ||= @write_set.include?(var)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
class CFGBuild
|
41
|
-
def transform(ast, target_map, method)
|
42
|
-
cfg = CFG::Graph.new
|
43
|
-
|
44
|
-
tracer = VariableTracer.new
|
45
|
-
|
46
|
-
ast.children.each do |child|
|
47
|
-
label = child.metadata[:label]
|
48
|
-
|
49
|
-
# Transfer control to the next operation directly if this
|
50
|
-
# is a jump target.
|
51
|
-
if target_map.include? label
|
52
|
-
cfg.transfer({ nil => label })
|
53
|
-
end
|
54
|
-
|
55
|
-
# Our CFG must also be easily convertible to ANF/SSA.
|
56
|
-
# Split blocks if a non-SSA variable operation is encountered.
|
57
|
-
tracer.visit child
|
58
|
-
|
59
|
-
if tracer.conflict?
|
60
|
-
cfg.transfer({ nil => child.metadata[:label] })
|
61
|
-
end
|
62
|
-
|
63
|
-
# Expand current operation.
|
64
|
-
cfg.expand label, child
|
65
|
-
|
66
|
-
# Transfer control non-sequentaly if needed.
|
67
|
-
if child.type == :jump
|
68
|
-
cfg.transfer({ label => child.children[0] })
|
69
|
-
elsif child.type == :jump_if
|
70
|
-
cfg.transfer({ label => child.children[0],
|
71
|
-
nil => child.next.metadata[:label] })
|
72
|
-
elsif child.type == :return
|
73
|
-
cfg.transfer({ })
|
74
|
-
elsif tracer.conflict?
|
75
|
-
# Reset tracer below.
|
76
|
-
else
|
77
|
-
next
|
78
|
-
end
|
79
|
-
|
80
|
-
# There was a conflict or a control transfer. Reset the tracer.
|
81
|
-
tracer.reset
|
82
|
-
end
|
83
|
-
|
84
|
-
[ cfg, method ]
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
module Furnace
|
2
|
-
module Transform
|
3
|
-
module Generic
|
4
|
-
class CFGNormalize
|
5
|
-
def transform(cfg, method)
|
6
|
-
cfg.nodes.each do |node|
|
7
|
-
# If a last operation is an unconditional jump, optimize it out.
|
8
|
-
last = node.operations.last
|
9
|
-
if last.type == :jump
|
10
|
-
edge = node.leaving_edge(last.metadata[:label])
|
11
|
-
|
12
|
-
node.operations.delete last
|
13
|
-
|
14
|
-
cfg.edges.delete edge
|
15
|
-
cfg.edges.add CFG::Edge.new(cfg, nil, node.label, edge.target.label)
|
16
|
-
end
|
17
|
-
|
18
|
-
# Remove no-ops.
|
19
|
-
node.operations.delete_if { |op| op.type == :nop }
|
20
|
-
end
|
21
|
-
|
22
|
-
# Remove empty nodes.
|
23
|
-
cfg.nodes.delete_if do |node|
|
24
|
-
if node.operations.empty?
|
25
|
-
node.entering_edges.each do |edge|
|
26
|
-
edge.target = node.default_leaving_edge.target
|
27
|
-
end
|
28
|
-
cfg.edges.subtract node.leaving_edges
|
29
|
-
|
30
|
-
true
|
31
|
-
else
|
32
|
-
false
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
[ cfg, method ]
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
@@ -1,60 +0,0 @@
|
|
1
|
-
module Furnace
|
2
|
-
module Transform
|
3
|
-
module Generic
|
4
|
-
class LabelNormalize
|
5
|
-
include AST::Visitor
|
6
|
-
|
7
|
-
def transform(ast, method)
|
8
|
-
# Find the minimal label in each operation sub-tree.
|
9
|
-
# It's the operation entry point.
|
10
|
-
visit ast
|
11
|
-
|
12
|
-
# Traverse operations in reverse order and bypass all jump_target's,
|
13
|
-
# recording the forwarded address in label_map.
|
14
|
-
label_map = {}
|
15
|
-
|
16
|
-
last_real_operation = nil
|
17
|
-
ast.children.reverse.each do |child|
|
18
|
-
if child.type == :jump_target
|
19
|
-
label = last_real_operation
|
20
|
-
else
|
21
|
-
label = child.metadata[:label]
|
22
|
-
last_real_operation = label
|
23
|
-
end
|
24
|
-
|
25
|
-
label_map[child.metadata[:label]] = label
|
26
|
-
end
|
27
|
-
|
28
|
-
# Remove jump_target's.
|
29
|
-
ast.children.reject! { |c| c.type == :jump_target }
|
30
|
-
|
31
|
-
# Find all jumpable labels and substitute the addresses to forward
|
32
|
-
# through jump_target's.
|
33
|
-
target_map = []
|
34
|
-
|
35
|
-
ast.children.each do |child|
|
36
|
-
if child.type == :jump || child.type == :jump_if
|
37
|
-
forwarded_target = label_map[child.children[0]]
|
38
|
-
child.children[0] = forwarded_target
|
39
|
-
|
40
|
-
target_map << forwarded_target
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
[ ast, target_map, method ]
|
45
|
-
end
|
46
|
-
|
47
|
-
def on_any(node)
|
48
|
-
return if node.type == :root
|
49
|
-
|
50
|
-
child_nodes = node.children.select { |c| c.is_a? AST::Node }
|
51
|
-
|
52
|
-
new_label = child_nodes.map { |c| c.metadata[:label] }.compact.min
|
53
|
-
node.metadata[:label] = new_label if new_label
|
54
|
-
|
55
|
-
child_nodes.each { |c| c.metadata.delete :label }
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
module Furnace
|
2
|
-
module Transform
|
3
|
-
module Optimizing
|
4
|
-
class FoldConstants
|
5
|
-
def transform(anf, method)
|
6
|
-
anf.nodes.each do |node|
|
7
|
-
if node.is_a? ANF::LetNode
|
8
|
-
node.try_propagate
|
9
|
-
node.try_eliminate
|
10
|
-
end
|
11
|
-
end
|
12
|
-
anf.eliminate_dead_code
|
13
|
-
|
14
|
-
[ anf, method ]
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
module Furnace
|
2
|
-
module Transform
|
3
|
-
module Rubinius
|
4
|
-
class ASTBuild
|
5
|
-
def transform(method)
|
6
|
-
stack = []
|
7
|
-
map = {}
|
8
|
-
serial = 0
|
9
|
-
|
10
|
-
ast = AST::Node.new(:root)
|
11
|
-
|
12
|
-
method.decode.each do |opcode|
|
13
|
-
ins = opcode.instruction
|
14
|
-
|
15
|
-
node = AST::Node.new("rbx_#{ins.opcode}")
|
16
|
-
node.metadata[:label] = opcode.ip
|
17
|
-
node.children += opcode.args
|
18
|
-
|
19
|
-
# Compute the real value of consumed values.
|
20
|
-
case ins.stack_consumed
|
21
|
-
when Fixnum
|
22
|
-
consumed = ins.stack_consumed
|
23
|
-
when Array
|
24
|
-
#p ins.stack_consumed, opcode.args
|
25
|
-
consumed = ins.stack_consumed[0] + opcode.args.last
|
26
|
-
end
|
27
|
-
|
28
|
-
# Pop consumed values and attach to current node.
|
29
|
-
consumed.times.map { map[stack.pop] }.reverse.each do |child|
|
30
|
-
child.parent = node
|
31
|
-
node.children << child
|
32
|
-
end
|
33
|
-
|
34
|
-
# Push back and map the results.
|
35
|
-
if ins.stack_produced == 0 || ins.opcode == :ret
|
36
|
-
node.parent = ast
|
37
|
-
ast.children << node
|
38
|
-
elsif ins.stack_produced == 1
|
39
|
-
map[serial] = node
|
40
|
-
stack.push serial
|
41
|
-
|
42
|
-
serial += 1
|
43
|
-
else
|
44
|
-
raise RuntimeError, "don't know what to do with opcode #{opcode.inspect}"
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
[ ast, method ]
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
@@ -1,170 +0,0 @@
|
|
1
|
-
module Furnace
|
2
|
-
module Transform
|
3
|
-
module Rubinius
|
4
|
-
class ASTNormalize
|
5
|
-
include AST::Visitor
|
6
|
-
|
7
|
-
def transform(ast, method)
|
8
|
-
@locals = method.local_names
|
9
|
-
@literals = method.literals
|
10
|
-
|
11
|
-
visit ast
|
12
|
-
|
13
|
-
[ ast, method ]
|
14
|
-
end
|
15
|
-
|
16
|
-
# (rbx-meta-push-0) -> 0
|
17
|
-
def on_rbx_meta_push_0(node)
|
18
|
-
node.update(:fixnum, [0], :constant => true)
|
19
|
-
end
|
20
|
-
|
21
|
-
# (rbx-meta-push-1) -> 1
|
22
|
-
def on_rbx_meta_push_1(node)
|
23
|
-
node.update(:fixnum, [1], :constant => true)
|
24
|
-
end
|
25
|
-
|
26
|
-
# (rbx-meta-push-2) -> 2
|
27
|
-
def on_rbx_meta_push_2(node)
|
28
|
-
node.update(:fixnum, [2], :constant => true)
|
29
|
-
end
|
30
|
-
|
31
|
-
# (rbx-push-int f) -> f
|
32
|
-
def on_rbx_push_int(node)
|
33
|
-
node.update(:fixnum, nil, :constant => true)
|
34
|
-
end
|
35
|
-
|
36
|
-
# (rbx-push-literal l) -> l
|
37
|
-
def on_rbx_push_literal(node)
|
38
|
-
node.update(:literal, nil, :constant => true)
|
39
|
-
end
|
40
|
-
|
41
|
-
# (rbx-push-nil) -> (nil)
|
42
|
-
def on_rbx_push_nil(node)
|
43
|
-
node.update(:nil, nil, :constant => true)
|
44
|
-
end
|
45
|
-
|
46
|
-
# (rbx-string-dup s) -> (dup s)
|
47
|
-
def on_rbx_string_dup(node)
|
48
|
-
node.update(:dup)
|
49
|
-
end
|
50
|
-
|
51
|
-
# (rbx-pop x) -> x
|
52
|
-
def on_rbx_pop(node)
|
53
|
-
child = node.children.first
|
54
|
-
child.update(:nop) if child.metadata[:constant]
|
55
|
-
|
56
|
-
node.update(:expand, [
|
57
|
-
child,
|
58
|
-
AST::Node.new(:jump_target, [], node.metadata)
|
59
|
-
], nil)
|
60
|
-
end
|
61
|
-
|
62
|
-
# (rbx-*) -> .
|
63
|
-
def make_jump_target(node)
|
64
|
-
node.update(:jump_target)
|
65
|
-
end
|
66
|
-
alias :on_rbx_check_interrupts :make_jump_target
|
67
|
-
alias :on_rbx_allow_private :make_jump_target
|
68
|
-
|
69
|
-
# (rbx-push-self) -> (self)
|
70
|
-
def on_rbx_push_self(node)
|
71
|
-
node.update(:self)
|
72
|
-
end
|
73
|
-
|
74
|
-
# (rbx-push-local n) -> (get-local n)
|
75
|
-
def on_rbx_push_local(node)
|
76
|
-
node.update(:get_lvar, [ @locals[node.children.first] ])
|
77
|
-
end
|
78
|
-
|
79
|
-
# (rbx-set-local n v) -> (set-local n v)
|
80
|
-
def on_rbx_set_local(node)
|
81
|
-
node.update(:set_lvar, [ @locals[node.children.first], node.children.last ])
|
82
|
-
end
|
83
|
-
|
84
|
-
# (rbx-push-ivar n) -> (get-ivar n)
|
85
|
-
def on_rbx_push_ivar(node)
|
86
|
-
node.update(:get_ivar, [ @literals[node.children.first] ])
|
87
|
-
end
|
88
|
-
|
89
|
-
# (rbx-set-ivar n v) -> (set-ivar n v)
|
90
|
-
def on_rbx_set_ivar(node)
|
91
|
-
node.update(:set_ivar, [ @literals[node.children.first], node.children.last ])
|
92
|
-
end
|
93
|
-
|
94
|
-
# (rbx-push-const-fast n x) -> (const n)
|
95
|
-
def on_rbx_push_const_fast(node)
|
96
|
-
node.update(:const, [ node.children.first ])
|
97
|
-
end
|
98
|
-
|
99
|
-
# (rbx-find-const n c) -> (const n c)
|
100
|
-
def on_rbx_find_const(node)
|
101
|
-
node.update(:const, [ @literals[node.children.first], node.children.last ])
|
102
|
-
end
|
103
|
-
|
104
|
-
# (rbx-ret x) -> (return x)
|
105
|
-
def on_rbx_ret(node)
|
106
|
-
node.update(:return)
|
107
|
-
end
|
108
|
-
|
109
|
-
# (rbx-send-method msg receiver) -> (send msg receiver)
|
110
|
-
def on_rbx_send_method(node)
|
111
|
-
node.update(:send, [
|
112
|
-
AST::MethodName.new(node.children[0]),
|
113
|
-
node.children[1]
|
114
|
-
])
|
115
|
-
end
|
116
|
-
|
117
|
-
# (rbx-send-stack msg count receiver args...) -> (send msg receiver args...)
|
118
|
-
def on_rbx_send_stack(node)
|
119
|
-
node.update(:send, [
|
120
|
-
AST::MethodName.new(node.children[0]), # message
|
121
|
-
node.children[2], # receiver
|
122
|
-
*node.children[3..-1] # args
|
123
|
-
])
|
124
|
-
end
|
125
|
-
|
126
|
-
# (rbx-send-stack-with-block msg count receiver args... block) -> (send-with-block msg receiver args... block)
|
127
|
-
def on_rbx_send_stack_with_block(node)
|
128
|
-
node.update(:send_with_block, [
|
129
|
-
AST::MethodName.new(node.children[0]), # message
|
130
|
-
node.children[2], # receiver
|
131
|
-
*node.children[3..-1] # args
|
132
|
-
])
|
133
|
-
end
|
134
|
-
|
135
|
-
# (rbx-create-block block) -> (lambda block)
|
136
|
-
def on_rbx_create_block(node)
|
137
|
-
$block = node.children.first
|
138
|
-
node.update(:lambda, [ "FAIL" ])
|
139
|
-
end
|
140
|
-
|
141
|
-
# (rbx-meta-* op receiver arg) -> (send op receiver arg)
|
142
|
-
def on_rbx_send_op_any(node)
|
143
|
-
node.update(:send, [
|
144
|
-
AST::MethodName.new(node.children[0]),
|
145
|
-
*node.children[1..-1]
|
146
|
-
])
|
147
|
-
end
|
148
|
-
alias :on_rbx_meta_send_op_plus :on_rbx_send_op_any
|
149
|
-
alias :on_rbx_meta_send_op_minus :on_rbx_send_op_any
|
150
|
-
alias :on_rbx_meta_send_op_gt :on_rbx_send_op_any
|
151
|
-
alias :on_rbx_meta_send_op_lt :on_rbx_send_op_any
|
152
|
-
alias :on_rbx_meta_to_s :on_rbx_send_op_any
|
153
|
-
|
154
|
-
# (rbx-goto-if-* block condition) -> (jump-if block value condition)
|
155
|
-
def on_rbx_goto_if_false(node)
|
156
|
-
node.update(:jump_if, [ node.children[0], false, node.children[1] ])
|
157
|
-
end
|
158
|
-
|
159
|
-
def on_rbx_goto_if_true(node)
|
160
|
-
node.update(:jump_if, [ node.children[0], true, node.children[1] ])
|
161
|
-
end
|
162
|
-
|
163
|
-
# (rbx-goto block) -> (jump block)
|
164
|
-
def on_rbx_goto(node)
|
165
|
-
node.update(:jump)
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|
170
|
-
end
|
data/lib/furnace/transform.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
module Furnace::Transform
|
2
|
-
end
|
3
|
-
|
4
|
-
require "furnace/transform/pipeline"
|
5
|
-
|
6
|
-
require "furnace/transform/rubinius/ast_build"
|
7
|
-
require "furnace/transform/rubinius/ast_normalize"
|
8
|
-
|
9
|
-
require "furnace/transform/generic/label_normalize"
|
10
|
-
require "furnace/transform/generic/cfg_build"
|
11
|
-
require "furnace/transform/generic/cfg_normalize"
|
12
|
-
|
13
|
-
require "furnace/transform/optimizing/fold_constants"
|