1
1
abstract type AbstractInstruction end
2
-
3
- mutable struct Tape
4
- tape:: Vector{<:AbstractInstruction}
5
- counter:: Int
6
- owner
7
- end
2
+ abstract type Taped end
3
+ const RawTape = Vector{AbstractInstruction}
8
4
9
5
"""
10
6
Instruction
11
7
12
8
An `Instruction` stands for a function call
13
9
"""
14
- mutable struct Instruction{F} <: AbstractInstruction
15
- fun :: F
10
+ mutable struct Instruction{F, T <: Taped } <: AbstractInstruction
11
+ func :: F
16
12
input:: Tuple
17
13
output
18
- tape:: Tape
14
+ tape:: T
19
15
end
20
16
21
- Tape () = Tape (Vector {AbstractInstruction} (), 1 , nothing )
22
- Tape (owner) = Tape (Vector {AbstractInstruction} (), 1 , owner)
23
- MacroTools. @forward Tape. tape Base. iterate, Base. length
24
- MacroTools. @forward Tape. tape Base. push!, Base. getindex, Base. lastindex
25
- const NULL_TAPE = Tape ()
26
-
27
- function setowner! (tape:: Tape , owner)
28
- tape. owner = owner
29
- return tape
17
+ mutable struct TapedFunction{F} <: Taped
18
+ func:: F # maybe a function or a callable obejct
19
+ arity:: Int
20
+ ir:: Union{Nothing, IRTools.IR}
21
+ tape:: RawTape
22
+ counter:: Int
23
+ owner
24
+ function TapedFunction (f:: F ; arity:: Int = - 1 ) where {F}
25
+ new {F} (f, arity, nothing , RawTape (), 1 , nothing )
26
+ end
30
27
end
31
28
32
29
mutable struct Box{T}
33
30
val:: T
34
31
end
35
32
33
+ # # methods for Box
36
34
val (x) = x
37
35
val (x:: Box ) = x. val
36
+ val (x:: TapedFunction ) = x. func
38
37
box (x) = Box (x)
39
38
box (x:: Box ) = x
39
+ Base. show (io:: IO , box:: Box ) = print (io, " Box(" , box. val, " )" )
40
40
41
- gettape (x) = nothing
42
- gettape (x:: Instruction ) = x. tape
43
- function gettape (x:: Tuple )
44
- for i in x
45
- gettape (i) != nothing && return gettape (i)
46
- end
41
+ # # methods for RawTape and Taped
42
+ MacroTools. @forward TapedFunction. tape Base. iterate, Base. length
43
+ MacroTools. @forward TapedFunction. tape Base. push!, Base. getindex, Base. lastindex
44
+
45
+ result (t:: RawTape ) = isempty (t) ? nothing : val (t[end ]. output)
46
+ result (t:: TapedFunction ) = result (t. tape)
47
+
48
+ function increase_counter! (t:: TapedFunction )
49
+ t. counter > length (t) && return
50
+ # instr = t[t.counter]
51
+ t. counter += 1
52
+ return t
47
53
end
48
- result (t:: Tape ) = isempty (t) ? nothing : val (t[end ]. output)
49
54
50
- function Base. show (io:: IO , box:: Box )
51
- println (io, " Box($(box. val) )" )
55
+ function reset! (tf:: TapedFunction , ir:: IRTools.IR , tape:: RawTape )
56
+ tf. ir = ir
57
+ tf. tape = tape
58
+ return tf
52
59
end
53
60
54
- function Base. show (io:: IO , instruction:: AbstractInstruction )
55
- println (io, " A $(typeof (instruction)) " )
61
+ function (tf:: TapedFunction )(args... )
62
+ if isempty (tf. tape)
63
+ ir = IRTools. @code_ir tf. func (args... )
64
+ ir = intercept (ir; recorder= :track! )
65
+ tf. ir = ir
66
+ tf. tape = RawTape ()
67
+ tf2 = IRTools. evalir (ir, tf, args... )
68
+ @assert tf === tf2
69
+ else
70
+ # run the raw tape
71
+ if length (args) > 0
72
+ input = map (box, args)
73
+ tf. tape[1 ]. input = input
74
+ end
75
+ for instruction in tf. tape
76
+ instruction ()
77
+ end
78
+ end
79
+ return result (tf)
56
80
end
57
81
58
- function Base. show (io:: IO , instruction:: Instruction )
59
- fun = instruction. fun
60
- tape = instruction. tape
61
- println (io, " Instruction($(fun)$(map (val, instruction. input)) , tape=$(objectid (tape)) )" )
82
+ function Base. show (io:: IO , tf:: TapedFunction )
83
+ buf = IOBuffer ()
84
+ println (buf, " TapedFunction:" )
85
+ println (buf, " * .func => $(tf. func) " )
86
+ println (buf, " * .ir =>" )
87
+ println (buf, " ------------------" )
88
+ println (buf, tf. ir)
89
+ println (buf, " ------------------" )
90
+ println (buf, " * .tape =>" )
91
+ println (buf, " ------------------" )
92
+ println (buf, tf. tape)
93
+ println (buf, " ------------------" )
94
+ print (io, String (take! (buf)))
62
95
end
63
96
64
- function Base. show (io:: IO , tp:: Tape )
97
+ function Base. show (io:: IO , tp:: RawTape )
65
98
# we use an extra IOBuffer to collect all the data and then
66
99
# output it once to avoid output interrupt during task context
67
100
# switching
68
101
buf = IOBuffer ()
69
- print (buf, " $(length (tp)) -element Tape " )
102
+ print (buf, " $(length (tp)) -element RawTape " )
70
103
isempty (tp) || println (buf, " :" )
71
104
i = 1
72
105
for instruction in tp
@@ -77,10 +110,19 @@ function Base.show(io::IO, tp::Tape)
77
110
print (io, String (take! (buf)))
78
111
end
79
112
113
+ # # methods for Instruction
114
+ Base. show (io:: IO , instruction:: AbstractInstruction ) = print (io, " A " , typeof (instruction))
115
+
116
+ function Base. show (io:: IO , instruction:: Instruction )
117
+ func = instruction. func
118
+ tape = instruction. tape
119
+ println (io, " Instruction($(func)$(map (val, instruction. input)) , tape=$(objectid (tape)) )" )
120
+ end
121
+
80
122
function (instr:: Instruction{F} )() where F
81
123
# catch run-time exceptions / errors.
82
124
try
83
- output = instr. fun (map (val, instr. input)... )
125
+ output = instr. func (map (val, instr. input)... )
84
126
instr. output. val = output
85
127
catch e
86
128
println (e, catch_backtrace ());
@@ -101,26 +143,9 @@ function (instr::Instruction{typeof(_new)})()
101
143
end
102
144
end
103
145
146
+ # # internal functions
104
147
105
- function increase_counter! (t:: Tape )
106
- t. counter > length (t) && return
107
- # instr = t[t.counter]
108
- t. counter += 1
109
- return t
110
- end
111
-
112
- function run (tape:: Tape , args... )
113
- if length (args) > 0
114
- input = map (box, args)
115
- tape[1 ]. input = input
116
- end
117
- for instruction in tape
118
- instruction ()
119
- increase_counter! (tape)
120
- end
121
- end
122
-
123
- function run_and_record! (tape:: Tape , f, args... )
148
+ function track! (tape:: Taped , f, args... )
124
149
f = val (f) # f maybe a Boxed closure
125
150
output = try
126
151
box (f (map (val, args)... ))
@@ -133,7 +158,7 @@ function run_and_record!(tape::Tape, f, args...)
133
158
return output
134
159
end
135
160
136
- function run_and_record ! (tape:: Tape , :: typeof (_new), args... )
161
+ function track ! (tape:: Taped , :: typeof (_new), args... )
137
162
output = try
138
163
expr = Expr (:new , map (val, args)... )
139
164
box (eval (expr))
@@ -171,9 +196,11 @@ function _replace_args(args, pairs::Dict)
171
196
end
172
197
end
173
198
174
- function intercept (ir; recorder= :run_and_record ! )
199
+ function intercept (ir; recorder= :track ! )
175
200
ir == nothing && return
176
- tape = pushfirst! (ir, IRTools. xcall (@__MODULE__ , :Tape ))
201
+ # we use tf instead of the original function as the first argument
202
+ # get the TapedFunction
203
+ tape = pushfirst! (ir, IRTools. xcall (Base, :identity , IRTools. arguments (ir)[1 ]))
177
204
178
205
# box the args
179
206
first_blk = IRTools. blocks (ir)[1 ]
@@ -229,51 +256,3 @@ function intercept(ir; recorder=:run_and_record!)
229
256
unbox_condition (ir)
230
257
return ir
231
258
end
232
-
233
- mutable struct TapedFunction
234
- func # ::Function # maybe a callable obejct
235
- arity:: Int
236
- ir:: Union{Nothing, IRTools.IR}
237
- tape:: Tape
238
- owner
239
- function TapedFunction (f; arity:: Int = - 1 )
240
- new (f, arity, nothing , NULL_TAPE, nothing )
241
- end
242
- end
243
-
244
- function reset! (tf:: TapedFunction , ir:: IRTools.IR , tape:: Tape )
245
- tf. ir = ir
246
- tf. tape = tape
247
- setowner! (tape, tf)
248
- return tf
249
- end
250
-
251
- function (tf:: TapedFunction )(args... )
252
- if isempty (tf. tape)
253
- ir = IRTools. @code_ir tf. func (args... )
254
- ir = intercept (ir; recorder= :run_and_record! )
255
- tape = IRTools. evalir (ir, tf. func, args... )
256
- tf. ir = ir
257
- tf. tape = tape
258
- setowner! (tape, tf)
259
- return result (tape)
260
- end
261
- # TODO : use cache
262
- run (tf. tape, args... )
263
- return result (tf. tape)
264
- end
265
-
266
- function Base. show (io:: IO , tf:: TapedFunction )
267
- buf = IOBuffer ()
268
- println (buf, " TapedFunction:" )
269
- println (buf, " * .func => $(tf. func) " )
270
- println (buf, " * .ir =>" )
271
- println (buf, " ------------------" )
272
- println (buf, tf. ir)
273
- println (buf, " ------------------" )
274
- println (buf, " * .tape =>" )
275
- println (buf, " ------------------" )
276
- println (buf, tf. tape)
277
- println (buf, " ------------------" )
278
- print (io, String (take! (buf)))
279
- end
0 commit comments