Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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