Skip to content

Commit

Permalink
get rid of O(n^2) behavior in stacklength when enabling break_on(:err…
Browse files Browse the repository at this point in the history
…or) (#212)
  • Loading branch information
KristofferC authored Mar 25, 2019
1 parent 77fc178 commit 1ddbf55
Show file tree
Hide file tree
Showing 3 changed files with 9 additions and 18 deletions.
11 changes: 6 additions & 5 deletions src/construct.jl
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ function prepare_call(@nospecialize(f), allargs; enter_generated = false)
return framecode, args, lenv, argtypes
end

function prepare_framedata(framecode, argvals::Vector{Any})
function prepare_framedata(framecode, argvals::Vector{Any}, caller_will_catch_err::Bool=false)
if isa(framecode.scope, Method)
meth, src = framecode.scope::Method, framecode.src
ssavt = src.ssavaluetypes
Expand Down Expand Up @@ -283,7 +283,7 @@ function prepare_framedata(framecode, argvals::Vector{Any})
callargs = Any[]
last_exception = Ref{Any}(nothing)
end
FrameData(locals, ssavalues, sparams, exception_frames, last_exception, last_reference, callargs)
FrameData(locals, ssavalues, sparams, exception_frames, last_exception, caller_will_catch_err, last_reference, callargs)
end

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

function prepare_frame_caller(caller::Frame, framecode::FrameCode, args::Vector{Any}, lenv::SimpleVector)
caller.callee = frame = prepare_frame(framecode, args, lenv)
caller_will_catch_err = !isempty(caller.framedata.exception_frames) || caller.framedata.caller_will_catch_err
caller.callee = frame = prepare_frame(framecode, args, lenv, caller_will_catch_err)
frame.caller = caller
return frame
end
Expand Down
15 changes: 2 additions & 13 deletions src/interpret.jl
Original file line number Diff line number Diff line change
Expand Up @@ -551,26 +551,15 @@ behaviors:
- otherwise, `err` gets rethrown.
"""
function handle_err(@nospecialize(recurse), frame, err)
data = frame.framedata
if break_on_error[]
# See if the current frame or a frame in the stack will catch this exception,
# otherwise this exception would have been thrown to the user and we should
# return a breakpoint
# Note: this is potentially O(N^2) in the stack depth. Consider storing `exception_caught`
# in the caller frames.
exception_caught = false
fr = frame
while fr !== nothing
if !isempty(fr.framedata.exception_frames)
exception_caught = true
break
end
fr = caller(fr)
end
if !exception_caught
if isempty(data.exception_frames) && !data.caller_will_catch_err
return BreakpointRef(frame.framecode, frame.pc, err)
end
end
data = frame.framedata
if isempty(data.exception_frames)
if frame.caller !== nothing
frame.caller.callee = nothing
Expand Down
1 change: 1 addition & 0 deletions src/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ struct FrameData
sparams::Vector{Any}
exception_frames::Vector{Int}
last_exception::Base.RefValue{Any}
caller_will_catch_err::Bool
# A vector from names to the slotnumber of that name
# for which a reference was last encountered.
last_reference::Dict{Symbol,Int}
Expand Down

0 comments on commit 1ddbf55

Please sign in to comment.