Skip to content

Commit 1ccb067

Browse files
committed
use Vector as bindings
1 parent 48355e1 commit 1ccb067

File tree

2 files changed

+68
-60
lines changed

2 files changed

+68
-60
lines changed

perf/benchmark.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ b = ins.input[1]
120120
@show ins.input |> length
121121
@btime map(x -> Libtask._lookup(tf, x), ins.input)
122122
@btime Libtask._lookup(tf, b)
123-
@btime b.get(tf, b.id)
123+
# @btime b.get(tf, b.id)
124124
@btime tf.bindings[b.id]
125125

126126
println("done")

src/tapedfunction.jl

Lines changed: 67 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,17 @@ function _infer(f, args_type)
1111
return ir0
1212
end
1313

14+
# const Bindings = Dict{Symbol, Any}
15+
const Bindings = Vector{Any}
16+
1417
mutable struct TapedFunction{F, TapeType}
1518
func::F # maybe a function, a constructor, or a callable object
1619
arity::Int
1720
ir::Core.CodeInfo
1821
tape::TapeType
1922
counter::Int
20-
bindings::Dict{Symbol, Any}
21-
retval::Symbol
23+
bindings::Bindings
24+
retval::Int
2225

2326
function TapedFunction{F, T}(f::F, args...; cache=false) where {F, T}
2427
args_type = _accurate_typeof.(args)
@@ -33,7 +36,7 @@ mutable struct TapedFunction{F, TapeType}
3336
ir = _infer(f, args_type)
3437
bindings, tape = translate!(RawTape(), ir)
3538

36-
tf = new{F, T}(f, length(args), ir, tape, 1, bindings, :none)
39+
tf = new{F, T}(f, length(args), ir, tape, 1, bindings, 0)
3740
TRCache[cache_key] = tf # set cache
3841
return tf
3942
end
@@ -43,7 +46,7 @@ mutable struct TapedFunction{F, TapeType}
4346

4447
function TapedFunction{F, T0}(tf::TapedFunction{F, T1}) where {F, T0, T1}
4548
new{F, T0}(tf.func, tf.arity, tf.ir, tf.tape,
46-
tf.counter, tf.bindings, :none)
49+
tf.counter, tf.bindings, 0)
4750
end
4851

4952
TapedFunction(tf::TapedFunction{F, T}) where {F, T} = TapedFunction{F, T}(tf)
@@ -76,19 +79,20 @@ end
7679
end
7780

7881
struct Box{T}
79-
id::Symbol
80-
get::TypedFunction{T, Tuple{TapedFunction, Symbol}}
82+
id::Int
83+
# get::TypedFunction{T, Tuple{TapedFunction, Int}}
8184

82-
function Box{T}(id::Symbol) where T
83-
return new(id, TypedFunction{T, Tuple{TapedFunction, Symbol}}(_inner_getter))
85+
function Box{T}(id::Int) where T
86+
return new(id)
87+
# return new(id, TypedFunction{T, Tuple{TapedFunction, Int}}(_inner_getter))
8488
end
8589
end
8690
Base.show(io::IO, box::Box{T}) where {T} = print(io, "Box{$T}($(box.id))")
8791

88-
@inline _inner_getter(tf::TapedFunction, v::Symbol) = tf.bindings[v]
89-
@inline _lookup(tf::TapedFunction, v::Box{T}) where T = v.get(tf, v.id)
90-
@inline _update_var!(tf::TapedFunction, v::Symbol, c) = (tf.bindings[v] = c; nothing)
91-
@inline _update_var!(tf::TapedFunction, v::Box{T}, c::T) where T = (tf.bindings[v.id] = c; nothing)
92+
@inline _inner_getter(tf::TapedFunction, v::Int) = @inbounds tf.bindings[v]
93+
@inline _lookup(tf::TapedFunction, v::Box{T}) where T = @inbounds tf.bindings[v.id]
94+
# @inline _lookup(tf::TapedFunction, v::Box{T}) where T = v.get(tf, v.id)
95+
@inline _update_var!(tf::TapedFunction, v::Box{T}, c::T) where T = (@inbounds tf.bindings[v.id] = c; nothing)
9296

9397
"""
9498
Instruction
@@ -114,20 +118,19 @@ end
114118

115119
@inline result(t::TapedFunction) = t.bindings[t.retval]
116120

117-
const SLOTS = [Symbol("_", i) for i in 1:100]
118-
119121
function (tf::TapedFunction)(args...; callback=nothing, continuation=false)
120122
if !continuation # reset counter and retval to run from the start
121-
tf.counter = 1;
122-
tf.retval = :none;
123+
tf.counter = 1
124+
tf.retval = 0
123125
end
124126

125127
# set args
126128
if tf.counter <= 1
127-
haskey(tf.bindings, :_1) && _update_var!(tf, :_1, tf.func)
129+
_update_var!(tf, Box{typeof(tf.func)}(1), tf.func)
128130
for i in 1:length(args)
129-
slot = i < length(SLOTS) ? SLOTS[i + 1] : Symbol("_", i + 1)
130-
haskey(tf.bindings, slot) && _update_var!(tf, slot, args[i])
131+
slot = i + 1
132+
b = Box{typeof(args[i])}(slot)
133+
_update_var!(tf, b, args[i])
131134
end
132135
end
133136

@@ -136,7 +139,7 @@ function (tf::TapedFunction)(args...; callback=nothing, continuation=false)
136139
ins = tf.tape[tf.counter]
137140
ins(tf)
138141
callback !== nothing && callback()
139-
tf.retval !== :none && break
142+
tf.retval != 0 && break
140143
end
141144
return result(tf)
142145
end
@@ -205,8 +208,8 @@ end
205208
end
206209

207210
function (instr::GotoInstruction)(tf::TapedFunction)
208-
cond = instr.condition.id === :_true ? true :
209-
instr.condition.id === :_false ? false :
211+
cond = instr.condition.id === -1 ? true :
212+
instr.condition.id === 0 ? false :
210213
_lookup(tf, instr.condition)
211214

212215
if cond
@@ -220,9 +223,7 @@ function (instr::ReturnInstruction)(tf::TapedFunction)
220223
tf.retval = instr.arg.id
221224
end
222225

223-
224226
## internal functions
225-
226227
_accurate_typeof(v) = typeof(v)
227228
_accurate_typeof(::Type{V}) where V = Type{V}
228229
_loose_type(t) = t
@@ -240,33 +241,40 @@ end
240241

241242

242243
## Translation: CodeInfo -> Tape
243-
244-
function bind_var!(var, bindings::Dict{Symbol, Any}, ir::Core.CodeInfo) # for literal constants
245-
id = gensym()
246-
bindings[id] = var
247-
Box{typeof(var)}(id)
248-
end
249-
bind_var!(var::GlobalRef, bindings::Dict{Symbol, Any}, ir::Core.CodeInfo) =
244+
const CNT_SLOT = 20
245+
const CNT_LITE = 100
246+
const OFFSET_VAR = CNT_SLOT + CNT_LITE
247+
248+
function bind_var!(var, bindings::Bindings, ir::Core.CodeInfo) # for literal constants
249+
last_idx = bindings[CNT_SLOT]
250+
idx = last_idx + 1
251+
bindings[CNT_SLOT] = idx
252+
bindings[idx] = var
253+
Box{typeof(var)}(idx)
254+
end
255+
bind_var!(var::GlobalRef, bindings::Bindings, ir::Core.CodeInfo) =
250256
bind_var!(getproperty(var.mod, var.name), bindings, ir)
251-
bind_var!(var::QuoteNode, bindings::Dict{Symbol, Any}, ir::Core.CodeInfo) =
257+
bind_var!(var::QuoteNode, bindings::Bindings, ir::Core.CodeInfo) =
252258
bind_var!(eval(var), bindings, ir)
253-
bind_var!(var::Core.SSAValue, bindings::Dict{Symbol, Any}, ir::Core.CodeInfo) =
254-
bind_var!(Symbol(var.id), bindings, ir.ssavaluetypes[var.id])
255-
bind_var!(var::Core.TypedSlot, bindings::Dict{Symbol, Any}, ir::Core.CodeInfo) =
256-
bind_var!(Symbol(:_, var.id), bindings, ir.slottypes[var.id])
257-
bind_var!(var::Core.SlotNumber, bindings::Dict{Symbol, Any}, ir::Core.CodeInfo) =
258-
bind_var!(Symbol(:_, var.id), bindings, ir.slottypes[var.id])
259-
bind_var!(var::Symbol, boxes::Dict{Symbol, Any}, c::Core.Const) =
259+
bind_var!(var::Core.SSAValue, bindings::Bindings, ir::Core.CodeInfo) =
260+
bind_var!(var.id + OFFSET_VAR, bindings, ir.ssavaluetypes[var.id])
261+
bind_var!(var::Core.TypedSlot, bindings::Bindings, ir::Core.CodeInfo) =
262+
bind_var!(var.id, bindings, ir.slottypes[var.id])
263+
bind_var!(var::Core.SlotNumber, bindings::Bindings, ir::Core.CodeInfo) =
264+
bind_var!(var.id, bindings, ir.slottypes[var.id])
265+
bind_var!(var::Int, boxes::Bindings, c::Core.Const) =
260266
bind_var!(var, boxes, _loose_type(Type{c.val}))
261-
bind_var!(var::Symbol, boxes::Dict{Symbol, Any}, c::Core.PartialStruct) =
267+
bind_var!(var::Int, boxes::Bindings, c::Core.PartialStruct) =
262268
bind_var!(var, boxes, _loose_type(c.typ))
263-
function bind_var!(var::Symbol, bindings::Dict{Symbol, Any}, ::Type{T}) where T
264-
get!(bindings, var, nothing)
269+
function bind_var!(var::Int, bindings::Bindings, ::Type{T}) where T
270+
var > length(bindings) && resize!(bindings, var + 10)
265271
Box{T}(var)
266272
end
267273

268274
function translate!(tape::RawTape, ir::Core.CodeInfo)
269-
bindings = Dict{Symbol, Any}()
275+
bindings = Bindings()
276+
resize!(bindings, OFFSET_VAR + 10)
277+
bindings[CNT_SLOT] = CNT_SLOT
270278

271279
for (idx, line) in enumerate(ir.code)
272280
isa(line, Core.Const) && (line = line.val) # unbox Core.Const
@@ -279,24 +287,24 @@ end
279287

280288
const IRVar = Union{Core.SSAValue, Core.SlotNumber}
281289

282-
function _const_instruction(var::IRVar, v, bindings::Dict{Symbol, Any}, ir)
290+
function _const_instruction(var::IRVar, v, bindings::Bindings, ir)
283291
if isa(var, Core.SSAValue)
284292
box = bind_var!(var, bindings, ir)
285293
bindings[box.id] = v
286-
return GotoInstruction(Box{Bool}(:_true), 0) # NOOP
294+
return GotoInstruction(Box{Bool}(-1), 0) # NOOP
287295
end
288296
return Instruction(identity, (bind_var!(v, bindings, ir),), bind_var!(var, bindings, ir))
289297
end
290298

291299
function translate!!(var::IRVar, line::Core.NewvarNode,
292-
bindings::Dict{Symbol, Any}, isconst::Bool, @nospecialize(ir))
300+
bindings::Bindings, isconst::Bool, @nospecialize(ir))
293301
# use a noop to ensure the 1-to-1 mapping from ir.code to instructions
294302
# on tape. see GotoInstruction.dest.
295-
return GotoInstruction(Box{Bool}(:_true), 0)
303+
return GotoInstruction(Box{Bool}(-1), 0)
296304
end
297305

298306
function translate!!(var::IRVar, line::GlobalRef,
299-
bindings::Dict{Symbol, Any}, isconst::Bool, ir)
307+
bindings::Bindings, isconst::Bool, ir)
300308
if isconst
301309
v = ir.ssavaluetypes[var.id].val
302310
return _const_instruction(var, v, bindings, ir)
@@ -305,7 +313,7 @@ function translate!!(var::IRVar, line::GlobalRef,
305313
end
306314

307315
function translate!!(var::IRVar, line::Core.SlotNumber,
308-
bindings::Dict{Symbol, Any}, isconst::Bool, ir)
316+
bindings::Bindings, isconst::Bool, ir)
309317
if isconst
310318
v = ir.ssavaluetypes[var.id].val
311319
return _const_instruction(var, v, bindings, ir)
@@ -314,35 +322,35 @@ function translate!!(var::IRVar, line::Core.SlotNumber,
314322
end
315323

316324
function translate!!(var::IRVar, line::Core.TypedSlot,
317-
bindings::Dict{Symbol, Any}, isconst::Bool, ir)
325+
bindings::Bindings, isconst::Bool, ir)
318326
input_box = bind_var!(Core.SlotNumber(line.id), bindings, ir)
319327
return Instruction(identity, (input_box,), bind_var!(var, bindings, ir))
320328
end
321329

322330
function translate!!(var::IRVar, line::Core.GotoIfNot,
323-
bindings::Dict{Symbol, Any}, isconst::Bool, ir)
331+
bindings::Bindings, isconst::Bool, ir)
324332
_cond = bind_var!(line.cond, bindings, ir)
325333
cond = if isa(_cond, Bool)
326-
Box{Bool}(_cond ? :_true : :_false)
334+
Box{Bool}(_cond ? -1 : 0)
327335
else
328336
_cond
329337
end
330338
return GotoInstruction(cond, line.dest)
331339
end
332340

333341
function translate!!(var::IRVar, line::Core.GotoNode,
334-
bindings::Dict{Symbol, Any}, isconst::Bool, @nospecialize(ir))
335-
return GotoInstruction(Box{Bool}(:_false), line.label)
342+
bindings::Bindings, isconst::Bool, @nospecialize(ir))
343+
return GotoInstruction(Box{Bool}(0), line.label)
336344
end
337345

338346
function translate!!(var::IRVar, line::Core.ReturnNode,
339-
bindings::Dict{Symbol, Any}, isconst::Bool, ir)
347+
bindings::Bindings, isconst::Bool, ir)
340348
return ReturnInstruction(bind_var!(line.val, bindings, ir))
341349
end
342350

343351
_canbeoptimized(v) = isa(v, DataType) || isprimitivetype(typeof(v))
344352
function translate!!(var::IRVar, line::Expr,
345-
bindings::Dict{Symbol, Any}, isconst::Bool, ir::Core.CodeInfo)
353+
bindings::Bindings, isconst::Bool, ir::Core.CodeInfo)
346354
head = line.head
347355
_bind_fn = (x) -> bind_var!(x, bindings, ir)
348356
if head === :new
@@ -410,10 +418,10 @@ tape_copy(x::Core.Box) = Core.Box(tape_copy(x.contents))
410418
# tape_copy(x::Array) = deepcopy(x)
411419
# tape_copy(x::Dict) = deepcopy(x)
412420

413-
function copy_bindings(old::Dict{Symbol, Any})
421+
function copy_bindings(old::Bindings)
414422
newb = copy(old)
415-
for (k, v) in old
416-
newb[k] = tape_copy(v)
423+
for k in 1:length(old)
424+
isassigned(old, k) && (newb[k] = tape_copy(old[k]))
417425
end
418426
return newb
419427
end

0 commit comments

Comments
 (0)