Skip to content

Commit cea0537

Browse files
authored
adjustments to v1.12 (#124)
* adjustments to v1.12 There have been changes to type definitions and global variable assignments to v1.12, and this commit tries to adjust the code base to it. There might be some missing pieces still, this allow us to reduce the failures in the test suite. * fix up * more fix * rm `trackedheads` On recent Julia versions we can just pattern match against `:method` expressions. * simplify `targetstore` creation * Update src/codeedges.jl
1 parent c7d1b30 commit cea0537

File tree

5 files changed

+146
-98
lines changed

5 files changed

+146
-98
lines changed

src/codeedges.jl

Lines changed: 78 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,10 @@ function postprint_linelinks(io::IO, idx::Int, src::CodeInfo, cl::CodeLinks, bbc
163163
printstyled(io, bbchanged ? " " : "", color=:light_black)
164164
printstyled(io, " # ", color=:yellow)
165165
stmt = src.code[idx]
166-
if is_assignment_like(stmt)
167-
lhs = normalize_defsig(stmt.args[1], cl.thismod)
166+
lhs_rhs = get_lhs_rhs(stmt)
167+
if lhs_rhs !== nothing
168+
lhs, _ = lhs_rhs
169+
lhs = normalize_defsig(lhs, cl.thismod)
168170
if @issslotnum(lhs)
169171
# id = lhs.id
170172
# preds, succs = cl.slotpreds[id], cl.slotsuccs[id]
@@ -190,38 +192,51 @@ function namedkeys(cl::CodeLinks)
190192
return ukeys
191193
end
192194

193-
is_assignment_like(stmt::Expr) = isexpr(stmt, :(=)) || (isexpr(stmt, :const) && length(stmt.args) == 2)
194-
is_assignment_like(@nospecialize stmt) = false
195+
function get_lhs_rhs(@nospecialize stmt)
196+
if isexpr(stmt, :(=))
197+
return Pair{Any,Any}(stmt.args[1], stmt.args[2])
198+
elseif isexpr(stmt, :const) && length(stmt.args) == 2
199+
return Pair{Any,Any}(stmt.args[1], stmt.args[2])
200+
elseif isexpr(stmt, :call) && length(stmt.args) == 4
201+
f = stmt.args[1]
202+
if isa(f, GlobalRef) && f.name === :setglobal!
203+
mod = stmt.args[2]
204+
mod isa Module || return nothing
205+
name = stmt.args[3]
206+
if name isa QuoteNode
207+
name = name.value
208+
end
209+
name isa Symbol || return nothing
210+
lhs = GlobalRef(mod, name)
211+
return Pair{Any,Any}(lhs, stmt.args[4])
212+
end
213+
end
214+
return nothing
215+
end
195216

196217
function direct_links!(cl::CodeLinks, src::CodeInfo)
197218
# Utility for when a stmt itself contains a CodeInfo
198219
function add_inner!(cl::CodeLinks, icl::CodeLinks, idx)
199220
for (name, _) in icl.nameassigns
200-
assigns = get(cl.nameassigns, name, nothing)
201-
if assigns === nothing
202-
cl.nameassigns[name] = assigns = Int[]
203-
end
221+
assigns = get!(Vector{Int}, cl.nameassigns, name)
204222
push!(assigns, idx)
205223
end
206224
for (name, _) in icl.namesuccs
207-
succs = get(cl.namesuccs, name, nothing)
208-
if succs === nothing
209-
cl.namesuccs[name] = succs = Links()
210-
end
225+
succs = get!(Links, cl.namesuccs, name)
211226
push!(succs.ssas, idx)
212227
end
213228
end
214229

215230
P = Pair{Union{SSAValue,SlotNumber,GlobalRef},Links}
216231

217232
for (i, stmt) in enumerate(src.code)
218-
if isexpr(stmt, :thunk) && isa(stmt.args[1], CodeInfo)
219-
icl = CodeLinks(cl.thismod, stmt.args[1])
233+
if isexpr(stmt, :thunk) && (arg1 = stmt.args[1]; arg1 isa CodeInfo)
234+
icl = CodeLinks(cl.thismod, arg1)
220235
add_inner!(cl, icl, i)
221236
continue
222-
elseif isa(stmt, Expr) && stmt.head trackedheads
223-
if stmt.head === :method && length(stmt.args) === 3 && isa(stmt.args[3], CodeInfo)
224-
icl = CodeLinks(cl.thismod, stmt.args[3])
237+
elseif isexpr(stmt, :method)
238+
if length(stmt.args) === 3 && (arg3 = stmt.args[3]; arg3 isa CodeInfo)
239+
icl = CodeLinks(cl.thismod, arg3)
225240
add_inner!(cl, icl, i)
226241
end
227242
name = stmt.args[1]
@@ -234,10 +249,7 @@ function direct_links!(cl::CodeLinks, src::CodeInfo)
234249
cl.nameassigns[name] = assign = Int[]
235250
end
236251
push!(assign, i)
237-
targetstore = get(cl.namepreds, name, nothing)
238-
if targetstore === nothing
239-
cl.namepreds[name] = targetstore = Links()
240-
end
252+
targetstore = get!(Links, cl.namepreds, name)
241253
target = P(name, targetstore)
242254
add_links!(target, stmt, cl)
243255
elseif name in (nothing, false)
@@ -247,10 +259,10 @@ function direct_links!(cl::CodeLinks, src::CodeInfo)
247259
end
248260
rhs = stmt
249261
target = P(SSAValue(i), cl.ssapreds[i])
250-
elseif is_assignment_like(stmt)
262+
elseif (lhs_rhs = get_lhs_rhs(stmt); lhs_rhs !== nothing)
251263
# An assignment
252264
stmt = stmt::Expr
253-
lhs, rhs = stmt.args[1], stmt.args[2]
265+
lhs, rhs = lhs_rhs
254266
if @issslotnum(lhs)
255267
lhs = lhs::AnySlotNumber
256268
id = lhs.id
@@ -260,10 +272,7 @@ function direct_links!(cl::CodeLinks, src::CodeInfo)
260272
if isa(lhs, Symbol)
261273
lhs = GlobalRef(cl.thismod, lhs)
262274
end
263-
targetstore = get(cl.namepreds, lhs, nothing)
264-
if targetstore === nothing
265-
cl.namepreds[lhs] = targetstore = Links()
266-
end
275+
targetstore = get!(Links, cl.namepreds, lhs)
267276
target = P(lhs, targetstore)
268277
assign = get(cl.nameassigns, lhs, nothing)
269278
if assign === nothing
@@ -299,23 +308,35 @@ function add_links!(target::Pair{Union{SSAValue,SlotNumber,GlobalRef},Links}, @n
299308
stmt = GlobalRef(cl.thismod, stmt)
300309
end
301310
push!(targetstore, stmt)
302-
namestore = get(cl.namesuccs, stmt, nothing)
303-
if namestore === nothing
304-
cl.namesuccs[stmt] = namestore = Links()
305-
end
311+
namestore = get!(Links, cl.namesuccs, stmt)
306312
push!(namestore, targetid)
307-
elseif isa(stmt, Expr) && stmt.head !== :copyast
308-
stmt = stmt::Expr
309-
arng = 1:length(stmt.args)
310-
if stmt.head === :call
311-
f = stmt.args[1]
312-
if !@isssa(f) && !@issslotnum(f)
313-
# Avoid putting named callees on the namestore
314-
arng = 2:length(stmt.args)
313+
elseif isa(stmt, Expr)
314+
if stmt.head === :globaldecl
315+
for i = 1:length(stmt.args)
316+
a = stmt.args[i]
317+
if a isa GlobalRef
318+
namestore = get!(Links, cl.namepreds, a) # TODO should this information be tracked in the separate `cl.namedecls` store?
319+
push!(namestore, targetid)
320+
if targetid isa SSAValue
321+
push!(namestore, SSAValue(targetid.id+1)) # +1 for :latestworld
322+
end
323+
else
324+
add_links!(target, a, cl)
325+
end
326+
end
327+
elseif stmt.head !== :copyast
328+
stmt = stmt::Expr
329+
arng = 1:length(stmt.args)
330+
if stmt.head === :call
331+
f = stmt.args[1]
332+
if !@isssa(f) && !@issslotnum(f)
333+
# Avoid putting named callees on the namestore
334+
arng = 2:length(stmt.args)
335+
end
336+
end
337+
for i in arng
338+
add_links!(target, stmt.args[i], cl)
315339
end
316-
end
317-
for i in arng
318-
add_links!(target, stmt.args[i], cl)
319340
end
320341
elseif stmt isa Core.GotoIfNot
321342
add_links!(target, stmt.cond, cl)
@@ -362,7 +383,6 @@ struct Variable
362383
preds::Vector{Int}
363384
succs::Vector{Int}
364385
end
365-
Variable() = Variable(Int[], Int[], Int[])
366386

367387
function Base.show(io::IO, v::Variable)
368388
print(io, "assigned on ", showempty(v.assigned))
@@ -423,9 +443,9 @@ function CodeEdges(src::CodeInfo, cl::CodeLinks)
423443
emptylist = Int[]
424444
for (i, stmt) in enumerate(src.code)
425445
# Identify line predecents for slots and named variables
426-
if is_assignment_like(stmt)
446+
if (lhs_rhs = get_lhs_rhs(stmt); lhs_rhs !== nothing)
427447
stmt = stmt::Expr
428-
lhs = stmt.args[1]
448+
lhs, _ = lhs_rhs
429449
# Mark predecessors and successors of this line by following ssas & named assignments
430450
if @issslotnum(lhs)
431451
lhs = lhs::AnySlotNumber
@@ -611,7 +631,7 @@ function exclude_named_typedefs(src::CodeInfo, edges::CodeEdges)
611631
i = 1
612632
nstmts = length(src.code)
613633
while i <= nstmts
614-
stmt = rhs(src.code[i])
634+
stmt = getrhs(src.code[i])
615635
if istypedef(stmt) && !isanonymous_typedef(stmt::Expr)
616636
r = typedef_range(src, i)
617637
pushall!(norequire, r)
@@ -715,10 +735,17 @@ function add_succs!(isrequired, idx, edges::CodeEdges, succs, norequire)
715735
end
716736
return chngd
717737
end
718-
function add_obj!(isrequired, objs, obj, edges::CodeEdges, norequire)
738+
function add_obj!(isrequired, objs, obj::GlobalRef, edges::CodeEdges, norequire)
719739
chngd = false
740+
for p in edges.byname[obj].preds
741+
p norequire && continue
742+
isrequired[p] && continue
743+
isrequired[p] = true
744+
chngd = true
745+
end
720746
for d in edges.byname[obj].assigned
721747
d norequire && continue
748+
isrequired[d] && continue
722749
isrequired[d] || add_preds!(isrequired, d, edges, norequire)
723750
isrequired[d] = true
724751
chngd = true
@@ -871,7 +898,7 @@ function find_typedefs(src::CodeInfo)
871898
i = 1
872899
nstmts = length(src.code)
873900
while i <= nstmts
874-
stmt = rhs(src.code[i])
901+
stmt = getrhs(src.code[i])
875902
if istypedef(stmt) && !isanonymous_typedef(stmt::Expr)
876903
stmt = stmt::Expr
877904
r = typedef_range(src, i)
@@ -972,8 +999,8 @@ function add_inplace!(isrequired, src, edges, norequire)
972999
for k in edges.preds[j]
9731000
isrequired[k] || continue
9741001
predstmt = src.code[k]
975-
if is_assignment_like(predstmt)
976-
lhs = predstmt.args[1]
1002+
if (lhs_rhs = get_lhs_rhs(predstmt); lhs_rhs !== nothing)
1003+
lhs, _ = lhs_rhs
9771004
if @issslotnum(lhs) && lhs.id == id
9781005
changed |= mark_if_inplace(stmt, j)
9791006
break
@@ -1056,7 +1083,7 @@ function print_with_code(io::IO, src::CodeInfo, isrequired::AbstractVector{Bool}
10561083
preprint(::IO) = nothing
10571084
preprint(io::IO, idx::Int) = (c = isrequired[idx]; printstyled(io, lpad(idx, nd), ' ', c ? "t " : "f "; color = c ? :cyan : :plain))
10581085
postprint(::IO) = nothing
1059-
postprint(io::IO, idx::Int, bbchanged::Bool) = nothing
1086+
postprint(::IO, idx::Int, bbchanged::Bool) = nothing
10601087

10611088
print_with_code(preprint, postprint, io, src)
10621089
end

src/packagedef.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ using Base.Meta: isexpr
88

99
const SSAValues = Union{Core.Compiler.SSAValue, JuliaInterpreter.SSAValue}
1010

11-
const trackedheads = (:method,)
1211
const structdecls = (:_structtype, :_abstracttype, :_primitivetype)
1312

1413
export signature, rename_framemethods!, methoddef!, methoddefs!, bodymethod

src/utils.jl

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ function callee_matches(f, mod, sym)
5858
return false
5959
end
6060

61-
function rhs(stmt)
62-
is_assignment_like(stmt) && return (stmt::Expr).args[2]
63-
return stmt
61+
function getrhs(@nospecialize(stmt))
62+
lhs_rhs = get_lhs_rhs(stmt)
63+
return lhs_rhs === nothing ? stmt : lhs_rhs[2]
6464
end
6565

6666
ismethod(frame::Frame) = ismethod(pc_expr(frame))
@@ -107,7 +107,7 @@ function ismethod_with_name(src, stmt, target::AbstractString; reentrant::Bool=f
107107
end
108108

109109
# anonymous function types are defined in a :thunk expr with a characteristic CodeInfo
110-
function isanonymous_typedef(stmt)
110+
function isanonymous_typedef(@nospecialize stmt)
111111
if isa(stmt, Expr)
112112
stmt.head === :thunk || return false
113113
stmt = stmt.args[1]
@@ -119,21 +119,22 @@ function isanonymous_typedef(stmt)
119119
isexpr(stmt, :call) || return false
120120
is_global_ref(stmt.args[1], Core, :_typebody!) || return false
121121
stmt = isa(stmt.args[3], Core.SSAValue) ? src.code[end-3] : src.code[end-2]
122-
is_assignment_like(stmt) || return false
123-
name = stmt.args[1]
124-
if isa(name, GlobalRef)
125-
name = name.name
122+
lhs_rhs = get_lhs_rhs(stmt)
123+
lhs_rhs === nothing && return false
124+
lhs, _ = lhs_rhs
125+
if isa(lhs, GlobalRef)
126+
lhs = lhs.name
126127
else
127-
isa(name, Symbol) || return false
128+
isa(lhs, Symbol) || return false
128129
end
129-
return startswith(String(name), "#")
130+
return startswith(String(lhs), "#")
130131
end
131132
return false
132133
end
133134

134135
function istypedef(stmt)
135136
isa(stmt, Expr) || return false
136-
stmt = rhs(stmt)
137+
stmt = getrhs(stmt)
137138
isa(stmt, Expr) || return false
138139
@static if all(s->isdefined(Core,s), structdecls)
139140
if stmt.head === :call
@@ -162,6 +163,7 @@ function typedef_range(src::CodeInfo, idx)
162163
istart = idx
163164
while istart >= 1
164165
isexpr(src.code[istart], :global) && break
166+
isexpr(src.code[istart], :latestworld) && break
165167
istart -= 1
166168
end
167169
istart >= 1 || error("no initial :global found")
@@ -171,6 +173,7 @@ function typedef_range(src::CodeInfo, idx)
171173
stmt = src.code[iend]
172174
if isa(stmt, Expr)
173175
stmt.head === :global && break
176+
stmt.head === :latestworld && break
174177
if stmt.head === :call
175178
if (is_global_ref(stmt.args[1], Core, :_typebody!) || is_quotenode_egal(stmt.args[1], Core._typebody!))
176179
have_typebody = true
@@ -179,7 +182,7 @@ function typedef_range(src::CodeInfo, idx)
179182
# Advance to the type-assignment
180183
while iend <= n
181184
stmt = src.code[iend]
182-
is_assignment_like(stmt) && break
185+
get_lhs_rhs(stmt) !== nothing && break
183186
iend += 1
184187
end
185188
end

0 commit comments

Comments
 (0)