Skip to content

Commit 1ddbf55

Browse files
authored
get rid of O(n^2) behavior in stacklength when enabling break_on(:error) (#212)
1 parent 77fc178 commit 1ddbf55

File tree

3 files changed

+9
-18
lines changed

3 files changed

+9
-18
lines changed

src/construct.jl

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ function prepare_call(@nospecialize(f), allargs; enter_generated = false)
231231
return framecode, args, lenv, argtypes
232232
end
233233

234-
function prepare_framedata(framecode, argvals::Vector{Any})
234+
function prepare_framedata(framecode, argvals::Vector{Any}, caller_will_catch_err::Bool=false)
235235
if isa(framecode.scope, Method)
236236
meth, src = framecode.scope::Method, framecode.src
237237
ssavt = src.ssavaluetypes
@@ -283,7 +283,7 @@ function prepare_framedata(framecode, argvals::Vector{Any})
283283
callargs = Any[]
284284
last_exception = Ref{Any}(nothing)
285285
end
286-
FrameData(locals, ssavalues, sparams, exception_frames, last_exception, last_reference, callargs)
286+
FrameData(locals, ssavalues, sparams, exception_frames, last_exception, caller_will_catch_err, last_reference, callargs)
287287
end
288288

289289
"""
@@ -292,8 +292,8 @@ end
292292
Construct a new `Frame` for `framecode`, given lowered-code arguments `frameargs` and
293293
static parameters `lenv`. See [`JuliaInterpreter.prepare_call`](@ref) for information about how to prepare the inputs.
294294
"""
295-
function prepare_frame(framecode::FrameCode, args::Vector{Any}, lenv::SimpleVector)
296-
framedata = prepare_framedata(framecode, args)
295+
function prepare_frame(framecode::FrameCode, args::Vector{Any}, lenv::SimpleVector, caller_will_catch_err::Bool=false)
296+
framedata = prepare_framedata(framecode, args, caller_will_catch_err)
297297
resize!(framedata.sparams, length(lenv))
298298
# Add static parameters to environment
299299
for i = 1:length(lenv)
@@ -305,7 +305,8 @@ function prepare_frame(framecode::FrameCode, args::Vector{Any}, lenv::SimpleVect
305305
end
306306

307307
function prepare_frame_caller(caller::Frame, framecode::FrameCode, args::Vector{Any}, lenv::SimpleVector)
308-
caller.callee = frame = prepare_frame(framecode, args, lenv)
308+
caller_will_catch_err = !isempty(caller.framedata.exception_frames) || caller.framedata.caller_will_catch_err
309+
caller.callee = frame = prepare_frame(framecode, args, lenv, caller_will_catch_err)
309310
frame.caller = caller
310311
return frame
311312
end

src/interpret.jl

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -551,26 +551,15 @@ behaviors:
551551
- otherwise, `err` gets rethrown.
552552
"""
553553
function handle_err(@nospecialize(recurse), frame, err)
554+
data = frame.framedata
554555
if break_on_error[]
555556
# See if the current frame or a frame in the stack will catch this exception,
556557
# otherwise this exception would have been thrown to the user and we should
557558
# return a breakpoint
558-
# Note: this is potentially O(N^2) in the stack depth. Consider storing `exception_caught`
559-
# in the caller frames.
560-
exception_caught = false
561-
fr = frame
562-
while fr !== nothing
563-
if !isempty(fr.framedata.exception_frames)
564-
exception_caught = true
565-
break
566-
end
567-
fr = caller(fr)
568-
end
569-
if !exception_caught
559+
if isempty(data.exception_frames) && !data.caller_will_catch_err
570560
return BreakpointRef(frame.framecode, frame.pc, err)
571561
end
572562
end
573-
data = frame.framedata
574563
if isempty(data.exception_frames)
575564
if frame.caller !== nothing
576565
frame.caller.callee = nothing

src/types.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ struct FrameData
126126
sparams::Vector{Any}
127127
exception_frames::Vector{Int}
128128
last_exception::Base.RefValue{Any}
129+
caller_will_catch_err::Bool
129130
# A vector from names to the slotnumber of that name
130131
# for which a reference was last encountered.
131132
last_reference::Dict{Symbol,Int}

0 commit comments

Comments
 (0)