Skip to content

Commit

Permalink
add closed over variables to locals and fix code evaluation on them (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
KristofferC authored May 9, 2020
1 parent 3868bcc commit 939c0d7
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 3 deletions.
7 changes: 6 additions & 1 deletion src/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -263,15 +263,20 @@ Important fields:
- `value::Any`: the value of the local variable.
- `name::Symbol`: the name of the variable as given in the source code.
- `isparam::Bool`: if the variable is a type parameter, for example `T` in `f(x::T) where {T} = x`.
- `is_captured_closure::Bool`: if the variable has been captured by a closure
"""
struct Variable
value::Any
name::Symbol
isparam::Bool
is_captured_closure::Bool
end
Variable(value, name) = Variable(value, name, false, false)
Variable(value, name, isparam) = Variable(value, name, isparam, false)
Base.show(io::IO, var::Variable) = (print(io, var.name, " = "); show(io,var.value))
Base.isequal(var1::Variable, var2::Variable) =
var1.value == var2.value && var1.name == var2.name && var1.isparam == var2.isparam
var1.value == var2.value && var1.name == var2.name && var1.isparam == var2.isparam &&
var1.is_captured_closure == var2.is_captured_closure

# A type that is unique to this package for which there are no valid operations
struct Unassigned end
Expand Down
18 changes: 17 additions & 1 deletion src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ function locals(frame::Frame)
slotnames = code.src.slotnames::SlotNamesType
for (sym, counter, val) in zip(slotnames, data.last_reference, data.locals)
counter == 0 && continue
var = Variable(something(val), sym, false)
var = Variable(something(val), sym)
idx = get(varlookup, sym, 0)
if idx > 0
if counter > var_counter[idx]
Expand All @@ -392,6 +392,13 @@ function locals(frame::Frame)
end
end
end
for var in vars
if var.name == Symbol("#self#")
for field in fieldnames(typeof(var.value))
push!(vars, Variable(getfield(var.value, field), field, false, true))
end
end
end
return vars
end

Expand Down Expand Up @@ -484,6 +491,15 @@ function eval_code(frame::Frame, expr)
if v.isparam
data.sparams[j] = res[i]
j += 1
elseif v.is_captured_closure
selfidx = findfirst(v -> v.name === Symbol("#self#"), vars)
@assert selfidx !== nothing
self = vars[selfidx].value
closed_over_var = getfield(self, v.name)
if closed_over_var isa Core.Box
setfield!(closed_over_var, :contents, res[i])
end
# We cannot rebind closed over variables that the frontend identified as constant
else
slot_indices = code.slotnamelists[v.name]
idx = argmax(data.last_reference[slot_indices])
Expand Down
19 changes: 18 additions & 1 deletion test/eval_code.jl
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,21 @@ JuliaInterpreter.step_expr!(frame)
eval_code(frame, "x = 3")
@test eval_code(frame, "x") == 3
JuliaInterpreter.finish!(frame)
@test JuliaInterpreter.get_return(frame) == 2
@test JuliaInterpreter.get_return(frame) == 2

function debugfun(non_accessible_variable)
garbage = ones(10)
map(1:10) do i
1+1
a = 5
@bp
garbage[i] + non_accessible_variable[i]
non_accessible_variable = 2
end
end
fr = JuliaInterpreter.enter_call(debugfun, [1,2])
fr, bp = debug_command(fr, :c)
@test eval_code(fr, "non_accessible_variable") == [1,2]
@test eval_code(fr, "garbage") == ones(10)
eval_code(fr, "non_accessible_variable = 5.0")
@test eval_code(fr, "non_accessible_variable") == 5.0

0 comments on commit 939c0d7

Please sign in to comment.