Skip to content

Commit 3ded02f

Browse files
authored
add support for in-source breakpoints (#133)
* add support for in source breakpoints * ssa fixes * simpler implementation
1 parent 1c2c2fb commit 3ded02f

File tree

6 files changed

+67
-2
lines changed

6 files changed

+67
-2
lines changed

docs/src/dev_reference.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ JuliaInterpreter.debug_command
5555

5656
```@docs
5757
@breakpoint
58+
@bp
5859
breakpoint
5960
enable
6061
disable

src/JuliaInterpreter.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ using CodeTracking
1414

1515
export @interpret, Compiled, Frame, root, leaf,
1616
BreakpointRef, breakpoint, @breakpoint, breakpoints, enable, disable, remove,
17-
debug_command
17+
debug_command, @bp
1818

1919
module CompiledCalls
2020
# This module is for handling intrinsics that must be compiled (llvmcall)

src/breakpoints.jl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,3 +286,14 @@ macro breakpoint(call_expr, args...)
286286
end
287287
end
288288
end
289+
290+
const __BREAKPOINT_MARKER__ = nothing
291+
292+
"""
293+
@bp
294+
295+
Insert a breakpoint at a location in the source code.
296+
"""
297+
macro bp()
298+
return esc(:($(JuliaInterpreter).__BREAKPOINT_MARKER__))
299+
end

src/types.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ struct FrameCode
6464
generator::Bool # true if this is for the expression-generator of a @generated function
6565
end
6666

67+
const BREAKPOINT_EXPR = :($(QuoteNode(getproperty))($JuliaInterpreter, :__BREAKPOINT_MARKER__))
6768
function FrameCode(scope, src::CodeInfo; generator=false, optimize=true)
6869
if optimize
6970
src, methodtables = optimize!(copy_codeinfo(src), moduleof(scope))
@@ -72,6 +73,12 @@ function FrameCode(scope, src::CodeInfo; generator=false, optimize=true)
7273
methodtables = Vector{Union{Compiled,TypeMapEntry}}(undef, length(src.code))
7374
end
7475
breakpoints = Vector{BreakpointState}(undef, length(src.code))
76+
for (i, pc_expr) in enumerate(src.code)
77+
if pc_expr == BREAKPOINT_EXPR
78+
breakpoints[i] = BreakpointState()
79+
src.code[i] = nothing
80+
end
81+
end
7582
used = find_used(src)
7683
return FrameCode(scope, src, methodtables, breakpoints, used, generator)
7784
end

test/breakpoints.jl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,20 @@ end
173173
bp = JuliaInterpreter.BreakpointRef(frame.framecode, 1, ArgumentError("whoops"))
174174
show(io, bp)
175175
@test String(take!(io)) == "breakpoint(loop_radius2(n) in $(@__MODULE__) at $(@__FILE__):3, line 3, ArgumentError(\"whoops\"))"
176+
177+
# In source breakpointing
178+
f_outer_bp(x) = g_inner_bp(x)
179+
function g_inner_bp(x)
180+
sin(x)
181+
@bp
182+
@bp
183+
@bp
184+
x = 3
185+
return 2
186+
end
187+
fr, bp = @interpret f_outer_bp(3)
188+
@test leaf(fr).framecode.scope.name == :g_inner_bp
189+
@test bp.stmtidx == 3
176190
end
177191

178192
if tmppath != ""

test/debug.jl

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,38 @@ struct B{T} end
232232
finally
233233
JuliaInterpreter.break_on_error[] = false
234234
end
235-
end
236235

236+
@testset "breakpoints" begin
237+
# In source breakpoints
238+
function f_bp(x)
239+
#=1=# i = 1
240+
#=2=# @label foo
241+
#=3=# @bp
242+
#=4=# repr("foo")
243+
#=5=# i += 1
244+
#=6=# i > 3 && return x
245+
#=7=# @goto foo
246+
end
247+
ln = @__LINE__
248+
method_start = ln - 9
249+
fr = enter_call(f_bp, 2)
250+
@test JuliaInterpreter.linenumber(fr) == method_start + 1
251+
fr, pc = JuliaInterpreter.debug_command(fr, "c")
252+
# Hit the breakpoint x1
253+
@test JuliaInterpreter.linenumber(fr) == method_start + 3
254+
@test pc isa BreakpointRef
255+
fr, pc = JuliaInterpreter.debug_command(fr, "n")
256+
@test JuliaInterpreter.linenumber(fr) == method_start + 4
257+
fr, pc = JuliaInterpreter.debug_command(fr, "c")
258+
# Hit the breakpoint again x2
259+
@test pc isa BreakpointRef
260+
@test JuliaInterpreter.linenumber(fr) == method_start + 3
261+
fr, pc = JuliaInterpreter.debug_command(fr, "c")
262+
# Hit the breakpoint for the last time x3
263+
@test pc isa BreakpointRef
264+
@test JuliaInterpreter.linenumber(fr) == method_start + 3
265+
JuliaInterpreter.debug_command(fr, "c")
266+
@test get_return(fr) == 2
267+
end
268+
end
237269
# end

0 commit comments

Comments
 (0)