Skip to content

Commit

Permalink
step through invokes (#182)
Browse files Browse the repository at this point in the history
  • Loading branch information
KristofferC authored and timholy committed Mar 18, 2019
1 parent 0ee85ae commit 87314a4
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 38 deletions.
13 changes: 12 additions & 1 deletion src/generate_builtins.jl
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,22 @@ function maybe_evaluate_builtin(frame, call_expr, expand::Bool)
$head f === Core._apply
argswrapped = getargs(args, frame)
if !expand
return Some{Any}(Core._apply(getargs(args, frame)...))
return Some{Any}(Core._apply(argswrapped...))
end
argsflat = Base.append_any((argswrapped[1],), argswrapped[2:end]...)
new_expr = Expr(:call, map(x->isa(x, Symbol) || isa(x, Expr) || isa(x, QuoteNode) ? QuoteNode(x) : x, argsflat)...)
return new_expr
""")
continue
elseif f === Core.invoke
print(io,
"""
$head f === invoke
argswrapped = getargs(args, frame)
if !expand
return Some{Any}(invoke(argswrapped...))
end
return Expr(:call, invoke, argswrapped...)
""")
continue
end
Expand Down
22 changes: 16 additions & 6 deletions src/interpret.jl
Original file line number Diff line number Diff line change
Expand Up @@ -208,13 +208,23 @@ function evaluate_call_recurse!(@nospecialize(recurse), frame::Frame, call_expr:
err = length(fargs) > 1 ? fargs[2] : frame.framedata.last_exception[]
throw(err)
end
framecode, lenv = get_call_framecode(fargs, frame.framecode, frame.pc; enter_generated=enter_generated)
if lenv === nothing
if isa(framecode, Compiled)
popfirst!(fargs) # now it's really just `args`
return f(fargs...)
if fargs[1] === Core.invoke # invoke needs special handling
f_invoked = which(fargs[2], fargs[3])
sig = Tuple{_Typeof.(fargs)...}
ret = prepare_framecode(f_invoked, sig; enter_generated=enter_generated)
isa(ret, Compiled) && invoke(fargs[2:end]...)
framecode, lenv = ret
fargs = [fargs[2]; fargs[4:end]]
lenv === nothing && return framecode # this was a Builtin
else
framecode, lenv = get_call_framecode(fargs, frame.framecode, frame.pc; enter_generated=enter_generated)
if lenv === nothing
if isa(framecode, Compiled)
popfirst!(fargs) # now it's really just `args`
return f(fargs...)
end
return framecode # this was a Builtin
end
return framecode # this was a Builtin
end
newframe = prepare_frame_caller(frame, framecode, fargs, lenv)
npc = newframe.pc
Expand Down
74 changes: 43 additions & 31 deletions test/debug.jl
Original file line number Diff line number Diff line change
Expand Up @@ -295,39 +295,51 @@ struct B{T} end
finally
break_off(:error)
end
end

@testset "breakpoints" begin
# In source breakpoints
function f_bp(x)
#=1=# i = 1
#=2=# @label foo
#=3=# @bp
#=4=# repr("foo")
#=5=# i += 1
#=6=# i > 3 && return x
#=7=# @goto foo
end
ln = @__LINE__
method_start = ln - 9
fr = enter_call(f_bp, 2)
@test JuliaInterpreter.linenumber(fr) == method_start + 1
fr, pc = JuliaInterpreter.debug_command(fr, :c)
# Hit the breakpoint x1
@test JuliaInterpreter.linenumber(fr) == method_start + 3
@test pc isa BreakpointRef
fr, pc = JuliaInterpreter.debug_command(fr, :n)
@test JuliaInterpreter.linenumber(fr) == method_start + 4
fr, pc = JuliaInterpreter.debug_command(fr, :c)
# Hit the breakpoint again x2
@test pc isa BreakpointRef
@test JuliaInterpreter.linenumber(fr) == method_start + 3
fr, pc = JuliaInterpreter.debug_command(fr, :c)
# Hit the breakpoint for the last time x3
@test pc isa BreakpointRef
@test JuliaInterpreter.linenumber(fr) == method_start + 3
JuliaInterpreter.debug_command(fr, :c)
@test get_return(fr) == 2
@testset "breakpoints" begin
# In source breakpoints
function f_bp(x)
#=1=# i = 1
#=2=# @label foo
#=3=# @bp
#=4=# repr("foo")
#=5=# i += 1
#=6=# i > 3 && return x
#=7=# @goto foo
end
ln = @__LINE__
method_start = ln - 9
fr = enter_call(f_bp, 2)
@test JuliaInterpreter.linenumber(fr) == method_start + 1
fr, pc = JuliaInterpreter.debug_command(fr, :c)
# Hit the breakpoint x1
@test JuliaInterpreter.linenumber(fr) == method_start + 3
@test pc isa BreakpointRef
fr, pc = JuliaInterpreter.debug_command(fr, :n)
@test JuliaInterpreter.linenumber(fr) == method_start + 4
fr, pc = JuliaInterpreter.debug_command(fr, :c)
# Hit the breakpoint again x2
@test pc isa BreakpointRef
@test JuliaInterpreter.linenumber(fr) == method_start + 3
fr, pc = JuliaInterpreter.debug_command(fr, :c)
# Hit the breakpoint for the last time x3
@test pc isa BreakpointRef
@test JuliaInterpreter.linenumber(fr) == method_start + 3
JuliaInterpreter.debug_command(fr, :c)
@test get_return(fr) == 2
end

f_inv(x::Real) = x^2;
f_inv(x::Integer) = 1 + invoke(f_inv, Tuple{Real}, x)
@testset "invoke" begin
fr = JuliaInterpreter.enter_call(f_inv, 2)
fr, pc = JuliaInterpreter.debug_command(fr, :s) # apply_type
frame, pc = JuliaInterpreter.debug_command(fr, :s) # step into invoke
@test frame.framecode.scope.sig == Tuple{typeof(f_inv),Real}
JuliaInterpreter.debug_command(frame, :c)
frame = root(frame)
@test get_return(frame) == f_inv(2)
end

@testset "Issue #178" begin
Expand Down

0 comments on commit 87314a4

Please sign in to comment.