Skip to content

Commit 5ac43d4

Browse files
committed
opt: remove box
1 parent f4e64d5 commit 5ac43d4

File tree

1 file changed

+52
-69
lines changed

1 file changed

+52
-69
lines changed

src/tapedfunction.jl

Lines changed: 52 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,3 @@
1-
mutable struct Box{T}
2-
id::Symbol
3-
val::T
4-
end
5-
6-
## methods for Box
7-
Box(x) = Box(gensym(), x)
8-
Box{T}(x) where {T} = Box{T}(gensym(), x)
9-
Base.show(io::IO, box::Box) = print(io, "Box(", box.id, ")")
10-
111
## Instruction and TapedFunction
122

133
abstract type AbstractInstruction end
@@ -41,7 +31,7 @@ mutable struct TapedFunction{F}
4131
ir::Core.CodeInfo
4232
tape::RawTape
4333
counter::Int
44-
bindings::Dict{Symbol, Box{<:Any}}
34+
bindings::Dict{Symbol, Any}
4535
retval::Symbol
4636

4737
function TapedFunction(f::F, args...; cache=false) where {F}
@@ -56,12 +46,10 @@ mutable struct TapedFunction{F}
5646
end
5747

5848
ir = CodeInfoTools.code_inferred(f, args_type...)
59-
tf = new{F}() # leave some fields to be undef
60-
tf.func, tf.arity, tf.ir = f, length(args), ir
61-
tf.tape = RawTape()
62-
tf.counter = 1
49+
tape = RawTape()
50+
bindings = translate!(tape, ir)
6351

64-
translate!(tf, ir)
52+
tf = new{F}(f, length(args), ir, tape, 1, bindings, :none)
6553
TRCache[cache_key] = tf # set cache
6654
return tf
6755
end
@@ -75,9 +63,6 @@ end
7563
const TRCache = LRU{Tuple, TapedFunction}(maxsize=10)
7664

7765
val(x) = x
78-
val(x::Box) = x.val
79-
val(x::Box{GlobalRef}) = val(x.val)
80-
val(x::Box{QuoteNode}) = val(x.val)
8166
val(x::GlobalRef) = getproperty(x.mod, x.name)
8267
val(x::QuoteNode) = eval(x)
8368
val(x::TapedFunction) = x.func
@@ -86,10 +71,10 @@ result(t::TapedFunction) = val(t.bindings[t.retval])
8671
function (tf::TapedFunction)(args...; callback=nothing)
8772
# set args
8873
if tf.counter <= 1
89-
haskey(tf.bindings, :_1) && (tf.bindings[:_1].val = tf.func)
74+
haskey(tf.bindings, :_1) && _update_var!(tf, :_1, tf.func)
9075
for i in 1:length(args)
9176
slot = Symbol("_", i + 1)
92-
haskey(tf.bindings, slot) && (tf.bindings[slot].val = args[i])
77+
haskey(tf.bindings, slot) && _update_var!(tf, slot, args[i])
9378
end
9479
end
9580

@@ -148,15 +133,15 @@ end
148133

149134
_lookup(tf::TapedFunction, v) = v
150135
_lookup(tf::TapedFunction, v::Symbol) = tf.bindings[v]
136+
_update_var!(tf::TapedFunction, v::Symbol, c) = tf.bindings[v] = c
151137

152138
function (instr::Instruction{F})(tf::TapedFunction) where F
153139
# catch run-time exceptions / errors.
154140
try
155141
func = val(_lookup(tf, instr.func))
156142
inputs = map(x -> val(_lookup(tf, x)), instr.input)
157143
output = func(inputs...)
158-
output_box = _lookup(tf, instr.output)
159-
output_box.val = output
144+
_update_var!(tf, instr.output, output)
160145
tf.counter += 1
161146
catch e
162147
println("counter=", tf.counter)
@@ -201,60 +186,60 @@ end
201186

202187
## Translation: CodeInfo -> Tape
203188

204-
function var_boxer(var, boxes::Dict{Symbol, Box{<:Any}}) # for literal constants
205-
box = Box(var)
206-
boxes[box.id] = box
207-
return box.id
189+
function bind_var!(var, bindings::Dict{Symbol, Any}) # for literal constants
190+
id = gensym()
191+
bindings[id] = var
192+
return id
193+
end
194+
bind_var!(var::Core.SSAValue, bindings::Dict{Symbol, Any}) = bind_var!(Symbol(var.id), bindings)
195+
bind_var!(var::Core.TypedSlot, bindings::Dict{Symbol, Any}) =
196+
bind_var!(Symbol(:_, var.id), bindings)
197+
bind_var!(var::Core.SlotNumber, bindings::Dict{Symbol, Any}) =
198+
bind_var!(Symbol(:_, var.id), bindings)
199+
function bind_var!(var::Symbol, bindings::Dict{Symbol, Any})
200+
get!(bindings, var, nothing)
201+
return var
208202
end
209-
var_boxer(var::Core.SSAValue, boxes::Dict{Symbol, Box{<:Any}}) = var_boxer(Symbol(var.id), boxes)
210-
var_boxer(var::Core.TypedSlot, boxes::Dict{Symbol, Box{<:Any}}) =
211-
var_boxer(Symbol(:_, var.id), boxes)
212-
var_boxer(var::Core.SlotNumber, boxes::Dict{Symbol, Box{<:Any}}) =
213-
var_boxer(Symbol(:_, var.id), boxes)
214-
var_boxer(var::Symbol, boxes::Dict{Symbol, Box{<:Any}}) =
215-
get!(boxes, var, Box{Any}(var, nothing)).id
216-
217-
function translate!(tf::TapedFunction, ir::Core.CodeInfo)
218-
tape = tf.tape
219-
boxes = Dict{Symbol, Box{<:Any}}()
203+
204+
function translate!(tape::RawTape, ir::Core.CodeInfo)
205+
bindings = Dict{Symbol, Any}()
220206

221207
for (idx, line) in enumerate(ir.code)
222208
isa(line, Core.Const) && (line = line.val) # unbox Core.Const
223-
ins = translate!!(Core.SSAValue(idx), line, boxes, ir)
209+
ins = translate!!(Core.SSAValue(idx), line, bindings, ir)
224210
push!(tape, ins)
225211
end
226-
227-
tf.bindings = boxes
212+
return bindings
228213
end
229214

230215
const IRVar = Union{Core.SSAValue, Core.SlotNumber}
231216

232217
function translate!!(var::IRVar, line::Core.NewvarNode,
233-
boxes::Dict{Symbol, Box{<:Any}}, @nospecialize(ir))
218+
bindings::Dict{Symbol, Any}, @nospecialize(ir))
234219
# use a noop to ensure the 1-to-1 mapping from ir.code to instructions
235220
# on tape. see GotoInstruction.dest.
236221
return GotoInstruction(:_true, 0)
237222
end
238223

239224
function translate!!(var::IRVar, line::GlobalRef,
240-
boxes::Dict{Symbol, Box{<:Any}}, @nospecialize(ir))
241-
return Instruction(() -> val(line), (), var_boxer(var, boxes))
225+
bindings::Dict{Symbol, Any}, @nospecialize(ir))
226+
return Instruction(() -> val(line), (), bind_var!(var, bindings))
242227
end
243228

244229
function translate!!(var::IRVar, line::Core.SlotNumber,
245-
boxes::Dict{Symbol, Box{<:Any}}, @nospecialize(ir))
246-
return Instruction(identity, (var_boxer(line, boxes),), var_boxer(var, boxes))
230+
bindings::Dict{Symbol, Any}, @nospecialize(ir))
231+
return Instruction(identity, (bind_var!(line, bindings),), bind_var!(var, bindings))
247232
end
248233

249234
function translate!!(var::IRVar, line::Core.TypedSlot,
250-
boxes::Dict{Symbol, Box{<:Any}}, @nospecialize(ir))
251-
input_box = var_boxer(Core.SlotNumber(line.id), boxes)
252-
return Instruction(identity, (input_box,), var_boxer(var, boxes))
235+
bindings::Dict{Symbol, Any}, @nospecialize(ir))
236+
input_box = bind_var!(Core.SlotNumber(line.id), bindings)
237+
return Instruction(identity, (input_box,), bind_var!(var, bindings))
253238
end
254239

255240
function translate!!(var::IRVar, line::Core.GotoIfNot,
256-
boxes::Dict{Symbol, Box{<:Any}}, @nospecialize(ir))
257-
_cond = var_boxer(line.cond, boxes)
241+
bindings::Dict{Symbol, Any}, @nospecialize(ir))
242+
_cond = bind_var!(line.cond, bindings)
258243
cond = if isa(_cond, Bool)
259244
_cond ? :_true : :_false
260245
else
@@ -264,53 +249,53 @@ function translate!!(var::IRVar, line::Core.GotoIfNot,
264249
end
265250

266251
function translate!!(var::IRVar, line::Core.GotoNode,
267-
boxes::Dict{Symbol, Box{<:Any}}, @nospecialize(ir))
252+
bindings::Dict{Symbol, Any}, @nospecialize(ir))
268253
return GotoInstruction(:_false, line.label)
269254
end
270255

271256
function translate!!(var::IRVar, line::Core.ReturnNode,
272-
boxes::Dict{Symbol, Box{<:Any}}, @nospecialize(ir))
273-
return ReturnInstruction(var_boxer(line.val, boxes))
257+
bindings::Dict{Symbol, Any}, @nospecialize(ir))
258+
return ReturnInstruction(bind_var!(line.val, bindings))
274259
end
275260

276261
function translate!!(var::IRVar, line::Expr,
277-
boxes::Dict{Symbol, Box{<:Any}}, ir::Core.CodeInfo)
262+
bindings::Dict{Symbol, Any}, ir::Core.CodeInfo)
278263
head = line.head
279-
_box_fn = (x) -> var_boxer(x, boxes)
264+
_bind_fn = (x) -> bind_var!(x, bindings)
280265
if head === :new
281-
args = map(_box_fn, line.args)
282-
return Instruction(__new__, args |> Tuple, var_boxer(var, boxes))
266+
args = map(_bind_fn, line.args)
267+
return Instruction(__new__, args |> Tuple, bind_var!(var, bindings))
283268
elseif head === :call
284-
args = map(_box_fn, line.args)
269+
args = map(_bind_fn, line.args)
285270
# args[1] is the function
286271
func = line.args[1]
287272
if Meta.isexpr(func, :static_parameter) # func is a type parameter
288273
func = ir.parent.sparam_vals[func.args[1]]
289274
else # isa(func, GlobalRef) or a var?
290275
func = args[1] # a var(box)
291276
end
292-
return Instruction(func, args[2:end] |> Tuple, var_boxer(var, boxes))
277+
return Instruction(func, args[2:end] |> Tuple, bind_var!(var, bindings))
293278
elseif head === :(=)
294279
# line.args[1] (the left hand side) is a SlotNumber, and it should be the output
295280
lhs = line.args[1]
296281
rhs = line.args[2] # the right hand side, maybe a Expr, or a var, or ...
297282
if Meta.isexpr(rhs, (:new, :call))
298-
return translate!!(lhs, rhs, boxes, ir)
283+
return translate!!(lhs, rhs, bindings, ir)
299284
else # rhs is a single value
300-
return Instruction(identity, (_box_fn(rhs),), _box_fn(lhs))
285+
return Instruction(identity, (_bind_fn(rhs),), _bind_fn(lhs))
301286
end
302287
else
303288
@error "Unknown Expression: " typeof(var) var typeof(line) line
304289
throw(ErrorException("Unknown Expression"))
305290
end
306291
end
307292

308-
function translate!!(var, line, boxes, ir)
293+
function translate!!(var, line, bindings, ir)
309294
@error "Unknown IR code: " typeof(var) var typeof(line) line
310295
throw(ErrorException("Unknown IR code"))
311296
end
312297

313-
## copy Box, TapedFunction
298+
## copy Bindings, TapedFunction
314299

315300
"""
316301
tape_copy(x)
@@ -329,12 +314,10 @@ tape_copy(x::Core.Box) = Core.Box(tape_copy(x.contents))
329314
# tape_copy(x::Array) = deepcopy(x)
330315
# tape_copy(x::Dict) = deepcopy(x)
331316

332-
Base.copy(box::Box{T}) where T = Box{T}(box.id, tape_copy(box.val))
333-
334-
function copy_bindings(old::Dict{Symbol, Box{<:Any}})
335-
newb = Dict{Symbol, Box{<:Any}}()
317+
function copy_bindings(old::Dict{Symbol, Any})
318+
newb = Dict{Symbol, Any}()
336319
for (k, v) in old
337-
newb[k] = copy(v)
320+
newb[k] = tape_copy(v)
338321
end
339322
return newb
340323
end

0 commit comments

Comments
 (0)