-
-
Couldn't load subscription status.
- Fork 5.7k
change compiler to be stackless #55575
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -251,6 +251,7 @@ mutable struct InferenceState | |
| stmt_info::Vector{CallInfo} | ||
|
|
||
| #= intermediate states for interprocedural abstract interpretation =# | ||
| tasks::Vector{WorkThunk} | ||
| pclimitations::IdSet{InferenceState} # causes of precision restrictions (LimitedAccuracy) on currpc ssavalue | ||
| limitations::IdSet{InferenceState} # causes of precision restrictions (LimitedAccuracy) on return | ||
| cycle_backedges::Vector{Tuple{InferenceState, Int}} # call-graph backedges connecting from callee to caller | ||
|
|
@@ -328,6 +329,7 @@ mutable struct InferenceState | |
| limitations = IdSet{InferenceState}() | ||
| cycle_backedges = Vector{Tuple{InferenceState,Int}}() | ||
| callstack = AbsIntState[] | ||
| tasks = WorkThunk[] | ||
|
|
||
| valid_worlds = WorldRange(1, get_world_counter()) | ||
| bestguess = Bottom | ||
|
|
@@ -351,7 +353,7 @@ mutable struct InferenceState | |
| this = new( | ||
| mi, world, mod, sptypes, slottypes, src, cfg, method_info, | ||
| currbb, currpc, ip, handler_info, ssavalue_uses, bb_vartables, ssavaluetypes, stmt_edges, stmt_info, | ||
| pclimitations, limitations, cycle_backedges, callstack, 0, 0, 0, | ||
| tasks, pclimitations, limitations, cycle_backedges, callstack, 0, 0, 0, | ||
| result, unreachable, valid_worlds, bestguess, exc_bestguess, ipo_effects, | ||
| restrict_abstract_call_sites, cache_mode, insert_coverage, | ||
| interp) | ||
|
|
@@ -800,6 +802,7 @@ mutable struct IRInterpretationState | |
| const ssa_refined::BitSet | ||
| const lazyreachability::LazyCFGReachability | ||
| valid_worlds::WorldRange | ||
| const tasks::Vector{WorkThunk} | ||
| const edges::Vector{Any} | ||
| callstack #::Vector{AbsIntState} | ||
| frameid::Int | ||
|
|
@@ -825,10 +828,11 @@ mutable struct IRInterpretationState | |
| ssa_refined = BitSet() | ||
| lazyreachability = LazyCFGReachability(ir) | ||
| valid_worlds = WorldRange(min_world, max_world == typemax(UInt) ? get_world_counter() : max_world) | ||
| tasks = WorkThunk[] | ||
| edges = Any[] | ||
| callstack = AbsIntState[] | ||
| return new(method_info, ir, mi, world, curridx, argtypes_refined, ir.sptypes, tpdum, | ||
| ssa_refined, lazyreachability, valid_worlds, edges, callstack, 0, 0) | ||
| ssa_refined, lazyreachability, valid_worlds, tasks, edges, callstack, 0, 0) | ||
| end | ||
| end | ||
|
|
||
|
|
@@ -870,6 +874,7 @@ function print_callstack(frame::AbsIntState) | |
| print(frame_instance(sv)) | ||
| is_cached(sv) || print(" [uncached]") | ||
| sv.parentid == idx - 1 || print(" [parent=", sv.parentid, "]") | ||
| isempty(callers_in_cycle(sv)) || print(" [cycle=", sv.cycleid, "]") | ||
| println() | ||
| @assert sv.frameid == idx | ||
| end | ||
|
|
@@ -994,7 +999,10 @@ of the same cycle, only if it is part of a cycle with multiple frames. | |
| function callers_in_cycle(sv::InferenceState) | ||
| callstack = sv.callstack::Vector{AbsIntState} | ||
| cycletop = cycleid = sv.cycleid | ||
| while cycletop < length(callstack) && (callstack[cycletop + 1]::InferenceState).cycleid == cycleid | ||
| while cycletop < length(callstack) | ||
| frame = callstack[cycletop + 1] | ||
| frame isa InferenceState || break | ||
| frame.cycleid == cycleid || break | ||
| cycletop += 1 | ||
| end | ||
| return AbsIntCycle(callstack, cycletop == cycleid ? 0 : cycleid, cycletop) | ||
|
|
@@ -1054,6 +1062,7 @@ function merge_effects!(::AbstractInterpreter, caller::InferenceState, effects:: | |
| effects = Effects(effects; effect_free=ALWAYS_TRUE) | ||
| end | ||
| caller.ipo_effects = merge_effects(caller.ipo_effects, effects) | ||
| nothing | ||
| end | ||
| merge_effects!(::AbstractInterpreter, ::IRInterpretationState, ::Effects) = return | ||
|
|
||
|
|
@@ -1116,3 +1125,90 @@ function get_max_methods_for_module(mod::Module) | |
| max_methods < 0 && return nothing | ||
| return max_methods | ||
| end | ||
|
|
||
| """ | ||
| Future{T} | ||
|
|
||
| Delayed return value for a value of type `T`, similar to RefValue{T}, but | ||
| explicitly represents completed as a `Bool` rather than as `isdefined`. | ||
| Set once with `f[] = v` and accessed with `f[]` afterwards. | ||
|
|
||
| Can also be constructed with the `completed` flag value and a closure to | ||
| produce `x`, as well as the additional arguments to avoid always capturing the | ||
| same couple of values. | ||
|
Comment on lines
+1136
to
+1138
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like this feature isn't implemented? Or we could refactor the constructor that takes There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is implemented. The additional arguments are |
||
| """ | ||
| struct Future{T} | ||
| later::Union{Nothing,RefValue{T}} | ||
| now::Union{Nothing,T} | ||
| Future{T}() where {T} = new{T}(RefValue{T}(), nothing) | ||
| Future{T}(x) where {T} = new{T}(nothing, x) | ||
| Future(x::T) where {T} = new{T}(nothing, x) | ||
| end | ||
| isready(f::Future) = f.later === nothing | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems weird to me that |
||
| getindex(f::Future{T}) where {T} = (later = f.later; later === nothing ? f.now::T : later[]) | ||
| setindex!(f::Future, v) = something(f.later)[] = v | ||
| convert(::Type{Future{T}}, x) where {T} = Future{T}(x) # support return type conversion | ||
| convert(::Type{Future{T}}, x::Future) where {T} = x::Future{T} | ||
|
Comment on lines
+1150
to
+1151
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Before merging this PR, I'd like to make sure the code works without this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
| function Future{T}(f, immediate::Bool, interp::AbstractInterpreter, sv::AbsIntState) where {T} | ||
| if immediate | ||
| return Future{T}(f(interp, sv)) | ||
| else | ||
| @assert applicable(f, interp, sv) | ||
| result = Future{T}() | ||
| push!(sv.tasks, function (interp, sv) | ||
| result[] = f(interp, sv) | ||
| return true | ||
| end) | ||
| return result | ||
| end | ||
| end | ||
| function Future{T}(f, prev::Future{S}, interp::AbstractInterpreter, sv::AbsIntState) where {T, S} | ||
| later = prev.later | ||
| if later === nothing | ||
| return Future{T}(f(prev[], interp, sv)) | ||
| else | ||
| @assert Core._hasmethod(Tuple{Core.Typeof(f), S, typeof(interp), typeof(sv)}) | ||
| result = Future{T}() | ||
| push!(sv.tasks, function (interp, sv) | ||
| result[] = f(later[], interp, sv) # capture just later, instead of all of prev | ||
| return true | ||
| end) | ||
| return result | ||
| end | ||
| end | ||
|
|
||
|
|
||
| """ | ||
| doworkloop(args...) | ||
|
|
||
| Run a tasks inside the abstract interpreter, returning false if there are none. | ||
| Tasks will be run in DFS post-order tree order, such that all child tasks will | ||
| be run in the order scheduled, prior to running any subsequent tasks. This | ||
| allows tasks to generate more child tasks, which will be run before anything else. | ||
| Each task will be run repeatedly when returning `false`, until it returns `true`. | ||
| """ | ||
| function doworkloop(interp::AbstractInterpreter, sv::AbsIntState) | ||
| tasks = sv.tasks | ||
| prev = length(tasks) | ||
| prev == 0 && return false | ||
| task = pop!(tasks) | ||
| completed = task(interp, sv) | ||
| tasks = sv.tasks # allow dropping gc root over the previous call | ||
| completed isa Bool || throw(TypeError(:return, "", Bool, task)) # print the task on failure as part of the error message, instead of just "@ workloop:line" | ||
| completed || push!(tasks, task) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't seem like it guarantees convergence. I understand that the below requires child tasks to complete before it's run again, but what if a dependency is earlier in the task list - we will never run this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The list is always post-dom sorted: dependencies are later by construction There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe add a comment to that effect? |
||
| # efficient post-order visitor: items pushed are executed in reverse post order such | ||
vtjnash marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| # that later items are executed before earlier ones, but are fully executed | ||
| # (including any dependencies scheduled by them) before going on to the next item | ||
| reverse!(tasks, #=start=#prev) | ||
| return true | ||
| end | ||
|
|
||
|
|
||
| #macro workthunk(name::Symbol, body) | ||
| # name = esc(name) | ||
| # body = esc(body) | ||
| # return replace_linenums!( | ||
| # :(function $name($(esc(interp)), $(esc(sv))) | ||
| # $body | ||
| # end), __source__) | ||
| #end | ||
Uh oh!
There was an error while loading. Please reload this page.