furnace 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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"
|