Skip to content

Commit 4d713f1

Browse files
committed
Merge branch 'master' of github.com:JuliaDebug/LoweredCodeUtils.jl into support-external-methodtables
2 parents 6d3e785 + c3ee610 commit 4d713f1

File tree

7 files changed

+161
-102
lines changed

7 files changed

+161
-102
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "LoweredCodeUtils"
22
uuid = "6f1432cf-f94c-5a45-995e-cdbf5db27b0b"
33
authors = ["Tim Holy <[email protected]>"]
4-
version = "3.1.0"
4+
version = "3.2.1"
55

66
[deps]
77
JuliaInterpreter = "aa1ae85d-cabe-5617-a682-6adf51b2e16a"

src/LoweredCodeUtils.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ module LoweredCodeUtils
1111

1212
using JuliaInterpreter
1313
using JuliaInterpreter: SSAValue, SlotNumber, Frame
14-
using JuliaInterpreter: @lookup, moduleof, pc_expr, step_expr!, is_global_ref, is_quotenode_egal, whichtt,
14+
using JuliaInterpreter: @lookup, moduleof, pc_expr, step_expr!, is_global_ref, is_global_ref_egal, is_quotenode_egal, whichtt,
1515
next_until!, finish_and_return!, get_return, nstatements, codelocation, linetable,
1616
is_return, lookup_return, extract_method_table
1717

src/codeedges.jl

Lines changed: 85 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,58 @@ 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+
# Required by Revise, but otherwise deprecated
196+
# The depwarn is currently disabled because Revise's tests check for empty warning logs
197+
function is_assignment_like(@nospecialize stmt)
198+
# Base.depwarn("is_assignment_like is deprecated, switch to `LoweredCodeUtils.get_lhs_rhs`", :is_assignment_like)
199+
return isexpr(stmt, :(=)) || isexpr(stmt, :const, 2)
200+
end
201+
202+
function get_lhs_rhs(@nospecialize stmt)
203+
if isexpr(stmt, :(=))
204+
return Pair{Any,Any}(stmt.args[1], stmt.args[2])
205+
elseif isexpr(stmt, :const) && length(stmt.args) == 2
206+
return Pair{Any,Any}(stmt.args[1], stmt.args[2])
207+
elseif isexpr(stmt, :call) && length(stmt.args) == 4
208+
f = stmt.args[1]
209+
if is_global_ref_egal(f, :setglobal!, Core.setglobal!)
210+
mod = stmt.args[2]
211+
mod isa Module || return nothing
212+
name = stmt.args[3]
213+
if name isa QuoteNode
214+
name = name.value
215+
end
216+
name isa Symbol || return nothing
217+
lhs = GlobalRef(mod, name)
218+
return Pair{Any,Any}(lhs, stmt.args[4])
219+
end
220+
end
221+
return nothing
222+
end
195223

196224
function direct_links!(cl::CodeLinks, src::CodeInfo)
197225
# Utility for when a stmt itself contains a CodeInfo
198226
function add_inner!(cl::CodeLinks, icl::CodeLinks, idx)
199227
for (name, _) in icl.nameassigns
200-
assigns = get(cl.nameassigns, name, nothing)
201-
if assigns === nothing
202-
cl.nameassigns[name] = assigns = Int[]
203-
end
228+
assigns = get!(Vector{Int}, cl.nameassigns, name)
204229
push!(assigns, idx)
205230
end
206231
for (name, _) in icl.namesuccs
207-
succs = get(cl.namesuccs, name, nothing)
208-
if succs === nothing
209-
cl.namesuccs[name] = succs = Links()
210-
end
232+
succs = get!(Links, cl.namesuccs, name)
211233
push!(succs.ssas, idx)
212234
end
213235
end
214236

215237
P = Pair{Union{SSAValue,SlotNumber,GlobalRef},Links}
216238

217239
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])
240+
if isexpr(stmt, :thunk) && (arg1 = stmt.args[1]; arg1 isa CodeInfo)
241+
icl = CodeLinks(cl.thismod, arg1)
220242
add_inner!(cl, icl, i)
221243
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])
244+
elseif isexpr(stmt, :method)
245+
if length(stmt.args) === 3 && (arg3 = stmt.args[3]; arg3 isa CodeInfo)
246+
icl = CodeLinks(cl.thismod, arg3)
225247
add_inner!(cl, icl, i)
226248
end
227249
name = stmt.args[1]
@@ -234,10 +256,7 @@ function direct_links!(cl::CodeLinks, src::CodeInfo)
234256
cl.nameassigns[name] = assign = Int[]
235257
end
236258
push!(assign, i)
237-
targetstore = get(cl.namepreds, name, nothing)
238-
if targetstore === nothing
239-
cl.namepreds[name] = targetstore = Links()
240-
end
259+
targetstore = get!(Links, cl.namepreds, name)
241260
target = P(name, targetstore)
242261
add_links!(target, stmt, cl)
243262
elseif name in (nothing, false)
@@ -247,10 +266,10 @@ function direct_links!(cl::CodeLinks, src::CodeInfo)
247266
end
248267
rhs = stmt
249268
target = P(SSAValue(i), cl.ssapreds[i])
250-
elseif is_assignment_like(stmt)
269+
elseif (lhs_rhs = get_lhs_rhs(stmt); lhs_rhs !== nothing)
251270
# An assignment
252271
stmt = stmt::Expr
253-
lhs, rhs = stmt.args[1], stmt.args[2]
272+
lhs, rhs = lhs_rhs
254273
if @issslotnum(lhs)
255274
lhs = lhs::AnySlotNumber
256275
id = lhs.id
@@ -260,10 +279,7 @@ function direct_links!(cl::CodeLinks, src::CodeInfo)
260279
if isa(lhs, Symbol)
261280
lhs = GlobalRef(cl.thismod, lhs)
262281
end
263-
targetstore = get(cl.namepreds, lhs, nothing)
264-
if targetstore === nothing
265-
cl.namepreds[lhs] = targetstore = Links()
266-
end
282+
targetstore = get!(Links, cl.namepreds, lhs)
267283
target = P(lhs, targetstore)
268284
assign = get(cl.nameassigns, lhs, nothing)
269285
if assign === nothing
@@ -299,23 +315,35 @@ function add_links!(target::Pair{Union{SSAValue,SlotNumber,GlobalRef},Links}, @n
299315
stmt = GlobalRef(cl.thismod, stmt)
300316
end
301317
push!(targetstore, stmt)
302-
namestore = get(cl.namesuccs, stmt, nothing)
303-
if namestore === nothing
304-
cl.namesuccs[stmt] = namestore = Links()
305-
end
318+
namestore = get!(Links, cl.namesuccs, stmt)
306319
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)
320+
elseif isa(stmt, Expr)
321+
if stmt.head === :globaldecl
322+
for i = 1:length(stmt.args)
323+
a = stmt.args[i]
324+
if a isa GlobalRef
325+
namestore = get!(Links, cl.namepreds, a) # TODO should this information be tracked in the separate `cl.namedecls` store?
326+
push!(namestore, targetid)
327+
if targetid isa SSAValue
328+
push!(namestore, SSAValue(targetid.id+1)) # +1 for :latestworld
329+
end
330+
else
331+
add_links!(target, a, cl)
332+
end
333+
end
334+
elseif stmt.head !== :copyast
335+
stmt = stmt::Expr
336+
arng = 1:length(stmt.args)
337+
if stmt.head === :call
338+
f = stmt.args[1]
339+
if !@isssa(f) && !@issslotnum(f)
340+
# Avoid putting named callees on the namestore
341+
arng = 2:length(stmt.args)
342+
end
343+
end
344+
for i in arng
345+
add_links!(target, stmt.args[i], cl)
315346
end
316-
end
317-
for i in arng
318-
add_links!(target, stmt.args[i], cl)
319347
end
320348
elseif stmt isa Core.GotoIfNot
321349
add_links!(target, stmt.cond, cl)
@@ -362,7 +390,6 @@ struct Variable
362390
preds::Vector{Int}
363391
succs::Vector{Int}
364392
end
365-
Variable() = Variable(Int[], Int[], Int[])
366393

367394
function Base.show(io::IO, v::Variable)
368395
print(io, "assigned on ", showempty(v.assigned))
@@ -423,9 +450,9 @@ function CodeEdges(src::CodeInfo, cl::CodeLinks)
423450
emptylist = Int[]
424451
for (i, stmt) in enumerate(src.code)
425452
# Identify line predecents for slots and named variables
426-
if is_assignment_like(stmt)
453+
if (lhs_rhs = get_lhs_rhs(stmt); lhs_rhs !== nothing)
427454
stmt = stmt::Expr
428-
lhs = stmt.args[1]
455+
lhs, _ = lhs_rhs
429456
# Mark predecessors and successors of this line by following ssas & named assignments
430457
if @issslotnum(lhs)
431458
lhs = lhs::AnySlotNumber
@@ -611,7 +638,7 @@ function exclude_named_typedefs(src::CodeInfo, edges::CodeEdges)
611638
i = 1
612639
nstmts = length(src.code)
613640
while i <= nstmts
614-
stmt = rhs(src.code[i])
641+
stmt = getrhs(src.code[i])
615642
if istypedef(stmt) && !isanonymous_typedef(stmt::Expr)
616643
r = typedef_range(src, i)
617644
pushall!(norequire, r)
@@ -715,10 +742,17 @@ function add_succs!(isrequired, idx, edges::CodeEdges, succs, norequire)
715742
end
716743
return chngd
717744
end
718-
function add_obj!(isrequired, objs, obj, edges::CodeEdges, norequire)
745+
function add_obj!(isrequired, objs, obj::GlobalRef, edges::CodeEdges, norequire)
719746
chngd = false
747+
for p in edges.byname[obj].preds
748+
p norequire && continue
749+
isrequired[p] && continue
750+
isrequired[p] = true
751+
chngd = true
752+
end
720753
for d in edges.byname[obj].assigned
721754
d norequire && continue
755+
isrequired[d] && continue
722756
isrequired[d] || add_preds!(isrequired, d, edges, norequire)
723757
isrequired[d] = true
724758
chngd = true
@@ -871,7 +905,7 @@ function find_typedefs(src::CodeInfo)
871905
i = 1
872906
nstmts = length(src.code)
873907
while i <= nstmts
874-
stmt = rhs(src.code[i])
908+
stmt = getrhs(src.code[i])
875909
if istypedef(stmt) && !isanonymous_typedef(stmt::Expr)
876910
stmt = stmt::Expr
877911
r = typedef_range(src, i)
@@ -972,8 +1006,8 @@ function add_inplace!(isrequired, src, edges, norequire)
9721006
for k in edges.preds[j]
9731007
isrequired[k] || continue
9741008
predstmt = src.code[k]
975-
if is_assignment_like(predstmt)
976-
lhs = predstmt.args[1]
1009+
if (lhs_rhs = get_lhs_rhs(predstmt); lhs_rhs !== nothing)
1010+
lhs, _ = lhs_rhs
9771011
if @issslotnum(lhs) && lhs.id == id
9781012
changed |= mark_if_inplace(stmt, j)
9791013
break
@@ -1056,7 +1090,7 @@ function print_with_code(io::IO, src::CodeInfo, isrequired::AbstractVector{Bool}
10561090
preprint(::IO) = nothing
10571091
preprint(io::IO, idx::Int) = (c = isrequired[idx]; printstyled(io, lpad(idx, nd), ' ', c ? "t " : "f "; color = c ? :cyan : :plain))
10581092
postprint(::IO) = nothing
1059-
postprint(io::IO, idx::Int, bbchanged::Bool) = nothing
1093+
postprint(::IO, idx::Int, bbchanged::Bool) = nothing
10601094

10611095
print_with_code(preprint, postprint, io, src)
10621096
end

src/packagedef.jl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
Base.Experimental.@optlevel 1
22

3-
using Core: SimpleVector
4-
using Core.IR
3+
using Core: SimpleVector, MethodTable
4+
using Core.IR: CodeInfo, GotoIfNot, GotoNode, IR, MethodInstance, ReturnNode
5+
@static if isdefined(Core.IR, :EnterNode)
6+
using Core.IR: EnterNode
7+
end
58
using Core.Compiler: construct_domtree, construct_postdomtree, nearest_common_dominator,
69
postdominates
710
using Base.Meta: isexpr
811

912
const SSAValues = Union{Core.Compiler.SSAValue, JuliaInterpreter.SSAValue}
1013

11-
const trackedheads = (:method,)
14+
const trackedheads = (:method,) # Revise uses this (for now), don't delete; also update test/hastrackedexpr if this list gets expanded
1215
const structdecls = (:_structtype, :_abstracttype, :_primitivetype)
1316

1417
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)