furnace 0.4.0.beta.1 → 0.4.0.beta.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.
- checksums.yaml +7 -0
- data/.travis.yml +6 -0
- data/INSTRUMENT.md +250 -0
- data/Rakefile +1 -1
- data/lib/furnace.rb +10 -6
- data/lib/furnace/ast/node.rb +15 -1
- data/lib/furnace/awesome_printer.rb +121 -0
- data/lib/furnace/context.rb +0 -0
- data/lib/furnace/ssa.rb +7 -25
- data/lib/furnace/ssa/argument.rb +14 -10
- data/lib/furnace/ssa/basic_block.rb +70 -25
- data/lib/furnace/ssa/builder.rb +11 -7
- data/lib/furnace/ssa/constant.rb +19 -11
- data/lib/furnace/ssa/event_stream.rb +145 -0
- data/lib/furnace/ssa/function.rb +78 -57
- data/lib/furnace/ssa/generic_instruction.rb +12 -5
- data/lib/furnace/ssa/instruction.rb +50 -35
- data/lib/furnace/ssa/instruction_syntax.rb +9 -25
- data/lib/furnace/ssa/instructions/branch.rb +2 -2
- data/lib/furnace/ssa/instructions/phi.rb +12 -10
- data/lib/furnace/ssa/instructions/return.rb +3 -3
- data/lib/furnace/ssa/instructions/return_value.rb +11 -0
- data/lib/furnace/ssa/instrumentation.rb +33 -0
- data/lib/furnace/ssa/module.rb +5 -1
- data/lib/furnace/ssa/named_value.rb +31 -10
- data/lib/furnace/ssa/terminator_instruction.rb +6 -6
- data/lib/furnace/ssa/types/basic_block.rb +4 -8
- data/lib/furnace/ssa/types/function.rb +4 -8
- data/lib/furnace/ssa/user.rb +14 -15
- data/lib/furnace/ssa/value.rb +9 -5
- data/lib/furnace/transform/iterative.rb +20 -4
- data/lib/furnace/type.rb +9 -0
- data/lib/furnace/type/bottom.rb +11 -0
- data/lib/furnace/type/top.rb +72 -0
- data/lib/furnace/type/value.rb +13 -0
- data/lib/furnace/type/variable.rb +61 -0
- data/lib/furnace/version.rb +1 -1
- data/test/{test_helper.rb → helper.rb} +28 -3
- data/test/{ast_test.rb → test_ast.rb} +13 -1
- data/test/test_awesome_printer.rb +148 -0
- data/test/{ssa_test.rb → test_ssa.rb} +276 -315
- data/test/{transform_test.rb → test_transform.rb} +2 -2
- data/test/test_type.rb +138 -0
- metadata +83 -105
- data/lib/furnace/graphviz.rb +0 -49
- data/lib/furnace/ssa/generic_type.rb +0 -16
- data/lib/furnace/ssa/pretty_printer.rb +0 -113
- data/lib/furnace/ssa/type.rb +0 -27
- data/lib/furnace/ssa/types/void.rb +0 -15
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 09c880a785045b6520d037457d92d4c1fb5a5252
|
4
|
+
data.tar.gz: 95fe046fd5ae819eca7bc005230e688c7be97647
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 432ac773720df277c3c0b8d834f9364176d5245cd84027c1d775a39d05f0107aff5b6bdfbd9fde5df8a2a886ef4db7c9a0a9e9a8f530ad9a3b3152b65317b801
|
7
|
+
data.tar.gz: fff823fe2cf09c881a6e827aa160ba8491e25e33d9dc38c4f8053975410290f293020b09d474c3bb9d76875056947e457fe7e886ae72af7b878a95463d336492
|
data/.travis.yml
CHANGED
data/INSTRUMENT.md
ADDED
@@ -0,0 +1,250 @@
|
|
1
|
+
Insturmentation stream format
|
2
|
+
=============================
|
3
|
+
|
4
|
+
Instrumentation data is produced by Foundry as streams of events dumped
|
5
|
+
as JSON. A stream corresponds to one function.
|
6
|
+
|
7
|
+
Within a function, entities have names. Entity names are always unique.
|
8
|
+
Entity names may change; in this case, all subsequent references are to be
|
9
|
+
resolved via updated name.
|
10
|
+
|
11
|
+
Entities may refer to types. Types are identified with a number, which is
|
12
|
+
always unique and does not change.
|
13
|
+
|
14
|
+
The root of the stream contains a Function.
|
15
|
+
|
16
|
+
Type
|
17
|
+
----
|
18
|
+
|
19
|
+
There are several kinds of Types, disambiguated by the field "kind".
|
20
|
+
|
21
|
+
### Void type
|
22
|
+
|
23
|
+
{
|
24
|
+
"event": "type",
|
25
|
+
"id": <number>,
|
26
|
+
"kind": "void",
|
27
|
+
}
|
28
|
+
|
29
|
+
Should render as:
|
30
|
+
|
31
|
+
void
|
32
|
+
|
33
|
+
### Monotypes
|
34
|
+
|
35
|
+
{
|
36
|
+
"event": "type",
|
37
|
+
"id": <number>,
|
38
|
+
"kind": "monotype",
|
39
|
+
"name": <string>
|
40
|
+
}
|
41
|
+
|
42
|
+
Should render as:
|
43
|
+
|
44
|
+
#{name}
|
45
|
+
|
46
|
+
### Parametric types
|
47
|
+
|
48
|
+
{
|
49
|
+
"event": "type",
|
50
|
+
"id": <number>,
|
51
|
+
"kind": "parametric",
|
52
|
+
"name": <string>,
|
53
|
+
"parameters": <array of Type>
|
54
|
+
}
|
55
|
+
|
56
|
+
Should render as:
|
57
|
+
|
58
|
+
#{name}<#{parameters.map(&:render)}>
|
59
|
+
|
60
|
+
Function
|
61
|
+
--------
|
62
|
+
|
63
|
+
{
|
64
|
+
"name": <string>,
|
65
|
+
"present": <Boolean>,
|
66
|
+
"events": <array of Event>
|
67
|
+
}
|
68
|
+
|
69
|
+
### Set arguments
|
70
|
+
|
71
|
+
{
|
72
|
+
"event": "set_arguments",
|
73
|
+
"arguments": <array of Argument>
|
74
|
+
}
|
75
|
+
|
76
|
+
### Set return type
|
77
|
+
|
78
|
+
{
|
79
|
+
"event": "set_return_type",
|
80
|
+
"return_type": <Type>
|
81
|
+
}
|
82
|
+
|
83
|
+
Argument
|
84
|
+
--------
|
85
|
+
|
86
|
+
{
|
87
|
+
"name": <string>,
|
88
|
+
"type": <Type>
|
89
|
+
}
|
90
|
+
|
91
|
+
Should render as:
|
92
|
+
|
93
|
+
#{type} %#{name}
|
94
|
+
|
95
|
+
Basic block
|
96
|
+
-----------
|
97
|
+
|
98
|
+
Should render as:
|
99
|
+
|
100
|
+
#{name}:
|
101
|
+
#{instructions.map(&:render)}
|
102
|
+
|
103
|
+
### Add basic block
|
104
|
+
|
105
|
+
{
|
106
|
+
"event": "add_basic_block",
|
107
|
+
"name": <string>
|
108
|
+
}
|
109
|
+
|
110
|
+
### Remove basic block
|
111
|
+
|
112
|
+
{
|
113
|
+
"event": "remove_basic_block",
|
114
|
+
"name": <string>
|
115
|
+
}
|
116
|
+
|
117
|
+
### Rename basic block
|
118
|
+
|
119
|
+
{
|
120
|
+
"event": "rename_basic_block",
|
121
|
+
"name": <string>,
|
122
|
+
"new_name": <string>
|
123
|
+
}
|
124
|
+
|
125
|
+
Operand
|
126
|
+
-------
|
127
|
+
|
128
|
+
### Constant operand
|
129
|
+
|
130
|
+
{
|
131
|
+
"kind": "constant",
|
132
|
+
"type": <Type>,
|
133
|
+
"value": <string>
|
134
|
+
}
|
135
|
+
|
136
|
+
Should render as:
|
137
|
+
|
138
|
+
#{type} #{value}
|
139
|
+
|
140
|
+
### Argument operand
|
141
|
+
|
142
|
+
{
|
143
|
+
"kind": "argument",
|
144
|
+
"name": <string>
|
145
|
+
}
|
146
|
+
|
147
|
+
Should render as:
|
148
|
+
|
149
|
+
%#{name}
|
150
|
+
|
151
|
+
### Instruction operand
|
152
|
+
|
153
|
+
{
|
154
|
+
"kind": "instruction",
|
155
|
+
"name": <string>
|
156
|
+
}
|
157
|
+
|
158
|
+
Should render as:
|
159
|
+
|
160
|
+
%#{name}
|
161
|
+
|
162
|
+
### Basic block operand
|
163
|
+
|
164
|
+
{
|
165
|
+
"kind": "basic_block",
|
166
|
+
"name": <string>
|
167
|
+
}
|
168
|
+
|
169
|
+
Should render as:
|
170
|
+
|
171
|
+
label %#{name}
|
172
|
+
|
173
|
+
Presence of an operand of this type should create an edge in the graph.
|
174
|
+
|
175
|
+
### Function operand
|
176
|
+
|
177
|
+
{
|
178
|
+
"kind": "function",
|
179
|
+
"name": <string>
|
180
|
+
}
|
181
|
+
|
182
|
+
Should render as:
|
183
|
+
|
184
|
+
function "#{name}"
|
185
|
+
|
186
|
+
Presence of an operand of this type should create a cross-reference link.
|
187
|
+
|
188
|
+
Instruction
|
189
|
+
-----------
|
190
|
+
|
191
|
+
Should render as:
|
192
|
+
|
193
|
+
1. If it has non-void type:
|
194
|
+
|
195
|
+
#{type} %#{name} = #{opcode} #{parameters} #{operands}
|
196
|
+
|
197
|
+
2. If it has void type:
|
198
|
+
|
199
|
+
#{opcode} #{parameters} #{operands}
|
200
|
+
|
201
|
+
If `opcode` is `phi`, render `operands` comma-separated with each operand as:
|
202
|
+
|
203
|
+
#{operand[0]} => #{operand[1]}
|
204
|
+
|
205
|
+
Else, render `operands` as comma-separated operands.
|
206
|
+
|
207
|
+
### Add instruction
|
208
|
+
|
209
|
+
{
|
210
|
+
"event": "add_instruction",
|
211
|
+
"name": <string>,
|
212
|
+
"basic_block": <string>,
|
213
|
+
"position": <number>
|
214
|
+
}
|
215
|
+
|
216
|
+
### Update instruction
|
217
|
+
|
218
|
+
{
|
219
|
+
"event": "update_instruction",
|
220
|
+
"opcode": <string>,
|
221
|
+
"name": <string>
|
222
|
+
"parameters": <string>
|
223
|
+
"operands": <array>
|
224
|
+
"type": <Type>
|
225
|
+
}
|
226
|
+
|
227
|
+
### Remove instruction
|
228
|
+
|
229
|
+
{
|
230
|
+
"event": "remove_instruction",
|
231
|
+
"name": <string>
|
232
|
+
}
|
233
|
+
|
234
|
+
### Rename instruction
|
235
|
+
|
236
|
+
{
|
237
|
+
"event": "rename_instruction",
|
238
|
+
"name": <string>,
|
239
|
+
"new_name": <string>
|
240
|
+
}
|
241
|
+
|
242
|
+
Miscellanea
|
243
|
+
-----------
|
244
|
+
|
245
|
+
### Transformation start
|
246
|
+
|
247
|
+
{
|
248
|
+
"event": "transform_start",
|
249
|
+
"name": <string>
|
250
|
+
}
|
data/Rakefile
CHANGED
data/lib/furnace.rb
CHANGED
@@ -2,22 +2,26 @@
|
|
2
2
|
# static analyzers--any programs which read, manipulate or transform
|
3
3
|
# other programs.
|
4
4
|
#
|
5
|
-
# Currently it provides
|
6
|
-
#
|
5
|
+
# Currently it provides four loosely coupled modules, each operating
|
6
|
+
# upon a single kind of entity:
|
7
7
|
#
|
8
8
|
# * Abstract syntax trees: {AST}
|
9
|
+
# * Parametric types: {Type}
|
9
10
|
# * Static single assignment representation: {SSA}
|
10
11
|
# * Transformations: {Transform}
|
11
12
|
#
|
12
|
-
# Additionally, a
|
13
|
+
# Additionally, a custom pretty printing module {AwesomePrinter} is
|
14
|
+
# provided which has built-in knowledge of {Type}s.
|
15
|
+
#
|
13
16
|
module Furnace
|
14
17
|
require "furnace/version"
|
15
18
|
|
19
|
+
require "furnace/awesome_printer"
|
20
|
+
|
16
21
|
require "furnace/ast"
|
22
|
+
require "furnace/type"
|
17
23
|
require "furnace/ssa"
|
18
24
|
|
19
25
|
require "furnace/transform/pipeline"
|
20
26
|
require "furnace/transform/iterative"
|
21
|
-
|
22
|
-
require "furnace/graphviz"
|
23
|
-
end
|
27
|
+
end
|
data/lib/furnace/ast/node.rb
CHANGED
@@ -123,6 +123,20 @@ module Furnace::AST
|
|
123
123
|
end
|
124
124
|
end
|
125
125
|
|
126
|
+
# Concatenates `array` with `children` and returns the resulting node.
|
127
|
+
#
|
128
|
+
# @return [AST::Node]
|
129
|
+
def +(array)
|
130
|
+
updated(nil, @children + array.to_a)
|
131
|
+
end
|
132
|
+
|
133
|
+
# Appends `element` to `children` and returns the resulting node.
|
134
|
+
#
|
135
|
+
# @return [AST::Node]
|
136
|
+
def <<(element)
|
137
|
+
updated(nil, @children + [element])
|
138
|
+
end
|
139
|
+
|
126
140
|
# Converts `self` to a concise s-expression, omitting any children.
|
127
141
|
#
|
128
142
|
# @return [String]
|
@@ -198,4 +212,4 @@ module Furnace::AST
|
|
198
212
|
@type.to_s.gsub('_', '-')
|
199
213
|
end
|
200
214
|
end
|
201
|
-
end
|
215
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'ansi'
|
2
|
+
|
3
|
+
module Furnace
|
4
|
+
class AwesomePrinter
|
5
|
+
@colorize = true
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_accessor :colorize
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(colorize=self.class.colorize,
|
12
|
+
annotator=Type::Variable::Annotator.new)
|
13
|
+
@colorize = colorize
|
14
|
+
@annotator = annotator
|
15
|
+
|
16
|
+
@buffer = ""
|
17
|
+
@need_space = false
|
18
|
+
|
19
|
+
yield self if block_given?
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
@buffer
|
24
|
+
end
|
25
|
+
|
26
|
+
alias to_str to_s
|
27
|
+
|
28
|
+
def ==(other)
|
29
|
+
to_s == other
|
30
|
+
end
|
31
|
+
|
32
|
+
def =~(other)
|
33
|
+
to_s =~ other
|
34
|
+
end
|
35
|
+
|
36
|
+
def append(what)
|
37
|
+
@need_space = false
|
38
|
+
@buffer << what.to_s
|
39
|
+
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
def text(what)
|
44
|
+
ensure_space { append what }
|
45
|
+
end
|
46
|
+
|
47
|
+
def newline
|
48
|
+
append "\n"
|
49
|
+
end
|
50
|
+
|
51
|
+
def nest(what, &block)
|
52
|
+
if what
|
53
|
+
if what.respond_to? :awesome_print
|
54
|
+
what.awesome_print(self)
|
55
|
+
else
|
56
|
+
text what.to_s
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
self
|
61
|
+
end
|
62
|
+
|
63
|
+
def name(what)
|
64
|
+
text "%#{what}"
|
65
|
+
end
|
66
|
+
|
67
|
+
def type(what)
|
68
|
+
text with_ansi(:green) { what }
|
69
|
+
end
|
70
|
+
|
71
|
+
def type_variable(what)
|
72
|
+
text with_ansi(:bright, :magenta) { "~#{@annotator.annotate(what)}" }
|
73
|
+
end
|
74
|
+
|
75
|
+
def keyword(what)
|
76
|
+
text with_ansi(:bright, :white) { what }
|
77
|
+
end
|
78
|
+
|
79
|
+
def collection(left='', separator='', right='', what, &block)
|
80
|
+
return self if what.empty?
|
81
|
+
|
82
|
+
ensure_space do
|
83
|
+
append left
|
84
|
+
|
85
|
+
what.each.with_index do |element, index|
|
86
|
+
if index > 0
|
87
|
+
append separator
|
88
|
+
end
|
89
|
+
|
90
|
+
if block_given?
|
91
|
+
yield element
|
92
|
+
else
|
93
|
+
nest element
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
append right
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
protected
|
102
|
+
|
103
|
+
def with_ansi(*colors)
|
104
|
+
if @colorize
|
105
|
+
ANSI::Code.ansi(yield.to_s, *colors)
|
106
|
+
else
|
107
|
+
yield
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def ensure_space
|
112
|
+
append " " if @need_space
|
113
|
+
|
114
|
+
yield
|
115
|
+
|
116
|
+
@need_space = true
|
117
|
+
|
118
|
+
self
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|