Skip to content

Commit 6903b43

Browse files
authored
Fix invalidations from extending ==(::Any, ::SomeType) (#35)
1 parent ec40e2b commit 6903b43

File tree

5 files changed

+117
-94
lines changed

5 files changed

+117
-94
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ version = "1.1.2"
77
JuliaInterpreter = "aa1ae85d-cabe-5617-a682-6adf51b2e16a"
88

99
[compat]
10-
JuliaInterpreter = "0.7"
10+
JuliaInterpreter = "0.7.16"
1111
julia = "1"
1212

1313
[extras]

src/LoweredCodeUtils.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ using Base.Meta: isexpr
99
using JuliaInterpreter
1010
using JuliaInterpreter: SSAValue, SlotNumber, Frame
1111
using JuliaInterpreter: @lookup, moduleof, pc_expr, step_expr!, is_global_ref, is_quotenode, whichtt,
12-
next_until!, finish_and_return!, get_return, nstatements, codelocation
12+
next_until!, finish_and_return!, get_return, nstatements, codelocation, linetable
1313

1414
const SSAValues = Union{Core.Compiler.SSAValue, JuliaInterpreter.SSAValue}
1515

src/codeedges.jl

Lines changed: 39 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -590,41 +590,6 @@ end
590590

591591
function lines_required!(isrequired::AbstractVector{Bool}, objs, src::CodeInfo, edges::CodeEdges; exclude_named_typedefs::Bool=false)
592592
# Do a traveral of "numbered" predecessors
593-
function add_preds!(isrequired, idx, edges::CodeEdges, norequire)
594-
changed = false
595-
preds = edges.preds[idx]
596-
for p in preds
597-
isrequired[p] && continue
598-
p norequire && continue
599-
isrequired[p] = true
600-
changed = true
601-
add_preds!(isrequired, p, edges, norequire)
602-
end
603-
return changed
604-
end
605-
function add_succs!(isrequired, idx, edges::CodeEdges, succs, norequire)
606-
changed = false
607-
for p in succs
608-
isrequired[p] && continue
609-
p norequire && continue
610-
isrequired[p] = true
611-
changed = true
612-
add_succs!(isrequired, p, edges, edges.succs[p], norequire)
613-
end
614-
return changed
615-
end
616-
function add_obj!(isrequired, objs, obj, edges::CodeEdges, norequire)
617-
changed = false
618-
for d in edges.byname[obj].assigned
619-
d norequire && continue
620-
isrequired[d] || add_preds!(isrequired, d, edges, norequire)
621-
isrequired[d] = true
622-
changed = true
623-
end
624-
push!(objs, obj)
625-
return changed
626-
end
627-
628593
# We'll mostly use generic graph traversal to discover all the lines we need,
629594
# but structs are in a bit of a different category (especially on Julia 1.5+).
630595
# It's easiest to discover these at the beginning.
@@ -636,7 +601,8 @@ function lines_required!(isrequired::AbstractVector{Bool}, objs, src::CodeInfo,
636601
i = 1
637602
while i <= nstmts
638603
stmt = rhs(src.code[i])
639-
if istypedef(stmt) && !isanonymous_typedef(stmt)
604+
if istypedef(stmt) && !isanonymous_typedef(stmt::Expr)
605+
stmt = stmt::Expr
640606
r = typedef_range(src, i)
641607
push!(typedef_blocks, r)
642608
name = stmt.head === :call ? stmt.args[3] : stmt.args[1]
@@ -665,7 +631,7 @@ function lines_required!(isrequired::AbstractVector{Bool}, objs, src::CodeInfo,
665631
bbs = Core.Compiler.compute_basic_blocks(src.code) # needed for control-flow analysis
666632
nblocks = length(bbs.blocks)
667633

668-
changed = true
634+
changed::Bool = true
669635
iter = 0
670636
while changed
671637
changed = false
@@ -742,7 +708,7 @@ function lines_required!(isrequired::AbstractVector{Bool}, objs, src::CodeInfo,
742708
while i <= length(src.code) && !ismethod3(src.code[i])
743709
i += 1
744710
end
745-
if i <= length(src.code) && src.code[i].args[1] == false
711+
if i <= length(src.code) && (src.code[i]::Expr).args[1] == false
746712
tpreds = terminal_preds(i, edges)
747713
if minimum(tpreds) == idx && i norequire
748714
changed |= !isrequired[i]
@@ -756,6 +722,41 @@ function lines_required!(isrequired::AbstractVector{Bool}, objs, src::CodeInfo,
756722
return isrequired
757723
end
758724

725+
function add_preds!(isrequired, idx, edges::CodeEdges, norequire)
726+
chngd = false
727+
preds = edges.preds[idx]
728+
for p in preds
729+
isrequired[p] && continue
730+
p norequire && continue
731+
isrequired[p] = true
732+
chngd = true
733+
add_preds!(isrequired, p, edges, norequire)
734+
end
735+
return chngd
736+
end
737+
function add_succs!(isrequired, idx, edges::CodeEdges, succs, norequire)
738+
chngd = false
739+
for p in succs
740+
isrequired[p] && continue
741+
p norequire && continue
742+
isrequired[p] = true
743+
chngd = true
744+
add_succs!(isrequired, p, edges, edges.succs[p], norequire)
745+
end
746+
return chngd
747+
end
748+
function add_obj!(isrequired, objs, obj, edges::CodeEdges, norequire)
749+
chngd = false
750+
for d in edges.byname[obj].assigned
751+
d norequire && continue
752+
isrequired[d] || add_preds!(isrequired, d, edges, norequire)
753+
isrequired[d] = true
754+
chngd = true
755+
end
756+
push!(objs, obj)
757+
return chngd
758+
end
759+
759760
"""
760761
selective_eval!([recurse], frame::Frame, isrequired::AbstractVector{Bool}, istoplevel=false)
761762

src/signatures.jl

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ For `f(x::AbstractArray{T}) where T`, the corresponding `sigsv` is constructed a
1515
sig = signature(sigsv)
1616
"""
1717
function signature(sigsv::SimpleVector)
18-
sigp, sigtv = sigsv
18+
sigp::SimpleVector, sigtv::SimpleVector = sigsv
1919
sig = Tuple{sigp...}
2020
for i = length(sigtv):-1:1
2121
sig = UnionAll(sigtv[i], sig)
2222
end
23-
return sig
23+
return sig::Union{DataType,UnionAll}
2424
end
2525

2626
"""
@@ -43,8 +43,8 @@ function signature(@nospecialize(recurse), frame::Frame, @nospecialize(stmt), pc
4343
while !isexpr(stmt, :method, 3) # wait for the 3-arg version
4444
if isanonymous_typedef(stmt)
4545
lastpc = pc = step_through_methoddef(recurse, frame, stmt) # define an anonymous function
46-
elseif isexpr(stmt, :call) && is_quotenode(stmt.args[1], Core.Typeof) &&
47-
(sym = stmt.args[2]; isa(sym, Symbol) && !isdefined(mod, sym))
46+
elseif isexpr(stmt, :call) && (q = (stmt::Expr).args[1]; isa(q, QuoteNode) && q.value === Core.Typeof) &&
47+
(sym = (stmt::Expr).args[2]; isa(sym, Symbol) && !isdefined(mod, sym))
4848
return nothing, pc
4949
else
5050
lastpc = pc
@@ -53,6 +53,7 @@ function signature(@nospecialize(recurse), frame::Frame, @nospecialize(stmt), pc
5353
end
5454
stmt = pc_expr(frame, pc)
5555
end
56+
isa(stmt, Expr) || return nothing, pc
5657
sigsv = @lookup(frame, stmt.args[2])::SimpleVector
5758
sigt = signature(sigsv)
5859
return sigt, lastpc
@@ -105,6 +106,13 @@ mutable struct MethodInfo
105106
end
106107
MethodInfo(start) = MethodInfo(start, -1, Int[])
107108

109+
struct SelfCall
110+
linetop::Int
111+
linebody::Int
112+
callee::Symbol
113+
caller::Union{Symbol,Bool}
114+
end
115+
108116
"""
109117
methodinfos, selfcalls = identify_framemethod_calls(frame)
110118
@@ -122,21 +130,26 @@ which will correspond to a 3-argument `:method` expression containing a `CodeInf
122130
function identify_framemethod_calls(frame)
123131
refs = Pair{Symbol,Int}[]
124132
methodinfos = Dict{Symbol,MethodInfo}()
125-
selfcalls = NamedTuple{(:linetop, :linebody, :callee, :caller),Tuple{Int64,Int64,Symbol,Union{Symbol,Bool}}}[]
133+
selfcalls = SelfCall[]
126134
for (i, stmt) in enumerate(frame.framecode.src.code)
127-
if isexpr(stmt, :global, 1)
128-
key = stmt.args[1]
135+
isa(stmt, Expr) || continue
136+
if stmt.head === :global && length(stmt.args) == 1
137+
key = stmt.args[1]::Symbol
129138
# We don't know for sure if this is a reference to a method, but let's
130139
# tentatively cue it
131140
push!(refs, key=>i)
132-
elseif isexpr(stmt, :thunk, 1) && stmt.args[1] isa CodeInfo
141+
elseif stmt.head === :thunk && stmt.args[1] isa CodeInfo
133142
tsrc = stmt.args[1]::CodeInfo
134143
if length(tsrc.code) == 1
135144
tstmt = tsrc.code[1]
136-
if isexpr(tstmt, :return, 1)
137-
tex = tstmt.args[1]
138-
if isexpr(tex, :method)
139-
push!(refs, tex.args[1]=>i)
145+
if isa(tstmt, Expr)
146+
if tstmt.head === :return && length(tstmt.args) == 1
147+
tex = tstmt.args[1]
148+
if isa(tex, Expr)
149+
if tex.head === :method && (methname = tex.args[1]; isa(methname, Symbol))
150+
push!(refs, methname=>i)
151+
end
152+
end
140153
end
141154
end
142155
end
@@ -158,12 +171,14 @@ function identify_framemethod_calls(frame)
158171
end
159172
msrc = stmt.args[3]
160173
if msrc isa CodeInfo
174+
key = key::Union{Symbol,Bool}
161175
for (j, mstmt) in enumerate(msrc.code)
162-
if isexpr(mstmt, :call)
176+
isa(mstmt, Expr) || continue
177+
if mstmt.head === :call
163178
mkey = mstmt.args[1]
164179
if isa(mkey, Symbol)
165180
# Could be a GlobalRef but then it's outside frame
166-
haskey(methodinfos, mkey) && push!(selfcalls, (linetop=i, linebody=j, callee=mkey, caller=key))
181+
haskey(methodinfos, mkey) && push!(selfcalls, SelfCall(i, j, mkey, key))
167182
elseif is_global_ref(mkey, Core, isdefined(Core, :_apply_iterate) ? :_apply_iterate : :_apply)
168183
ssaref = mstmt.args[end-1]
169184
if isa(ssaref, JuliaInterpreter.SSAValue)
@@ -172,14 +187,16 @@ function identify_framemethod_calls(frame)
172187
end
173188
mkey = mstmt.args[end-2]
174189
if isa(mkey, Symbol)
175-
haskey(methodinfos, mkey) && push!(selfcalls, (linetop=i, linebody=j, callee=mkey, caller=key))
190+
haskey(methodinfos, mkey) && push!(selfcalls, SelfCall(i, j, mkey, key))
176191
end
177192
end
178-
elseif isexpr(mstmt, :meta) && mstmt.args[1] == :generated
193+
elseif mstmt.head === :meta && mstmt.args[1] === :generated
179194
newex = mstmt.args[2]
180-
if isexpr(newex, :new) && length(newex.args) >= 2 && is_global_ref(newex.args[1], Core, :GeneratedFunctionStub)
181-
mkey = newex.args[2]::Symbol
182-
haskey(methodinfos, mkey) && push!(selfcalls, (linetop=i, linebody=j, callee=mkey, caller=key))
195+
if isa(newex, Expr)
196+
if newex.head === :new && length(newex.args) >= 2 && is_global_ref(newex.args[1], Core, :GeneratedFunctionStub)
197+
mkey = newex.args[2]::Symbol
198+
haskey(methodinfos, mkey) && push!(selfcalls, SelfCall(i, j, mkey, key))
199+
end
183200
end
184201
end
185202
end
@@ -261,7 +278,8 @@ function rename_framemethods!(@nospecialize(recurse), frame::Frame, methodinfos,
261278
@warn "skipping callee $callee (called by $caller) due to $err"
262279
end
263280
end
264-
for (linetop, linebody, callee, caller) in selfcalls
281+
for sc in selfcalls
282+
linetop, linebody, callee, caller = sc.linetop, sc.linebody, sc.callee, sc.caller
265283
cname = get(replacements, callee, nothing)
266284
if cname !== nothing && cname !== callee
267285
replacename!((src.code[linetop].args[3])::CodeInfo, callee=>cname)
@@ -315,7 +333,7 @@ function find_corrected_name(@nospecialize(recurse), frame, pc, name, parentname
315333
if stmt.args[1] !== name && isa(body, CodeInfo)
316334
# This might be the GeneratedFunctionStub for a @generated method
317335
for (i, bodystmt) in enumerate(body.code)
318-
if isexpr(bodystmt, :meta) && bodystmt.args[1] === :generated
336+
if isexpr(bodystmt, :meta) && (bodystmt::Expr).args[1] === :generated
319337
return signature_top(frame, stmt, pc), true
320338
end
321339
i >= 5 && break # we should find this early
@@ -351,11 +369,11 @@ function replacename!(args::Vector{Any}, pr)
351369
replacename!(a, pr)
352370
elseif isa(a, CodeInfo)
353371
replacename!(a.code, pr)
354-
elseif isa(a, QuoteNode) && a.value == oldname
372+
elseif isa(a, QuoteNode) && a.value === oldname
355373
args[i] = QuoteNode(newname)
356374
elseif isa(a, Vector{Any})
357375
replacename!(a, pr)
358-
elseif a == oldname
376+
elseif a === oldname
359377
args[i] = newname
360378
end
361379
end
@@ -448,7 +466,7 @@ function methoddef!(@nospecialize(recurse), signatures, frame::Frame, @nospecial
448466
# guard against busted lookup, e.g., https://github.com/JuliaLang/julia/issues/31112
449467
code = framecode.src
450468
codeloc = codelocation(code, pc)
451-
loc = code.linetable[codeloc]
469+
loc = linetable(code, codeloc)
452470
ft = Base.unwrap_unionall(Base.unwrap_unionall(sigt).parameters[1])
453471
if !startswith(String(ft.name.name), "##")
454472
@warn "file $(loc.file), line $(loc.line): no method found for $sigt"
@@ -472,7 +490,7 @@ function methoddef!(@nospecialize(recurse), signatures, frame::Frame, @nospecial
472490
stmt = pc_expr(frame, pc)
473491
end
474492
pc3 = pc
475-
name3 = stmt.args[1]
493+
name3 = (stmt::Expr).args[1]
476494
sigt === nothing && (error("expected a signature"); return next_or_nothing(frame, pc)), pc3
477495
# Methods like f(x::Ref{<:Real}) that use gensymmed typevars will not have the *exact*
478496
# signature of the active method. So let's get the active signature.

0 commit comments

Comments
 (0)