Skip to content

Commit 69a0886

Browse files
committed
Eliminating allocation of ccall root in simple cases
1 parent d9e253d commit 69a0886

File tree

2 files changed

+63
-4
lines changed

2 files changed

+63
-4
lines changed

base/inference.jl

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5217,6 +5217,21 @@ function occurs_outside_getfield(e::ANY, sym::ANY,
52175217
if head === :(=)
52185218
return occurs_outside_getfield(e.args[2], sym, sv,
52195219
field_count, field_names)
5220+
elseif head === :foreigncall
5221+
args = e.args
5222+
nccallargs = args[5]::Int
5223+
# Only arguments escape, GC root arguments do not escape.
5224+
for i in 1:length(args)
5225+
a = args[i]
5226+
if i > 5 + nccallargs && symequal(a, sym)
5227+
# No need to verify indices, uninitialized members can be
5228+
# ignored in root slot.
5229+
continue
5230+
end
5231+
if occurs_outside_getfield(a, sym, sv, field_count, field_names)
5232+
return true
5233+
end
5234+
end
52205235
else
52215236
if (head === :block && isa(sym, Slot) &&
52225237
sv.src.slotflags[slot_id(sym)] & Slot_UsedUndef == 0)
@@ -5800,8 +5815,11 @@ end
58005815
function replace_getfield!(e::Expr, tupname, vals, field_names, sv::InferenceState)
58015816
for i = 1:length(e.args)
58025817
a = e.args[i]
5803-
if isa(a,Expr) && is_known_call(a, getfield, sv.src, sv.mod) &&
5804-
symequal(a.args[2],tupname)
5818+
if !isa(a, Expr)
5819+
continue
5820+
end
5821+
a = a::Expr
5822+
if is_known_call(a, getfield, sv.src, sv.mod) && symequal(a.args[2], tupname)
58055823
idx = if isa(a.args[3], Int)
58065824
a.args[3]
58075825
else
@@ -5830,8 +5848,22 @@ function replace_getfield!(e::Expr, tupname, vals, field_names, sv::InferenceSta
58305848
end
58315849
end
58325850
e.args[i] = val
5833-
elseif isa(a, Expr)
5834-
replace_getfield!(a::Expr, tupname, vals, field_names, sv)
5851+
else
5852+
if a.head === :foreigncall
5853+
args = a.args
5854+
nccallargs = args[5]::Int
5855+
le = length(args)
5856+
next_i = 6 + nccallargs
5857+
while next_i <= le
5858+
i = next_i
5859+
next_i += 1
5860+
5861+
symequal(args[i], tupname) || continue
5862+
splice!(args, i, vals)
5863+
next_i += length(vals) - 1
5864+
end
5865+
end
5866+
replace_getfield!(a, tupname, vals, field_names, sv)
58355867
end
58365868
end
58375869
end

test/codegen.jl

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,37 @@ function compare_large_struct(a)
128128
end
129129
end
130130

131+
mutable struct MutableStruct
132+
a::Int
133+
MutableStruct() = new()
134+
end
135+
136+
breakpoint_mutable(a::MutableStruct) = ccall(:jl_breakpoint, Void, (Ref{MutableStruct},), a)
137+
138+
# Allocation with uninitialized field as gcroot
139+
mutable struct BadRef
140+
x::MutableStruct
141+
y::MutableStruct
142+
BadRef(x) = new(x)
143+
end
144+
Base.cconvert(::Type{Ptr{BadRef}}, a::MutableStruct) = BadRef(a)
145+
Base.unsafe_convert(::Type{Ptr{BadRef}}, ar::BadRef) = Ptr{BadRef}(pointer_from_objref(ar.x))
146+
147+
breakpoint_badref(a::MutableStruct) = ccall(:jl_breakpoint, Void, (Ptr{BadRef},), a)
148+
131149
if opt_level > 0
132150
@test !contains(get_llvm(isequal, Tuple{Nullable{BigFloat}, Nullable{BigFloat}}), "%gcframe")
133151
@test !contains(get_llvm(pointer_not_safepoint, Tuple{}), "%gcframe")
134152
compare_large_struct_ir = get_llvm(compare_large_struct, Tuple{typeof(create_ref_struct())})
135153
@test contains(compare_large_struct_ir, "call i32 @memcmp")
136154
@test !contains(compare_large_struct_ir, "%gcframe")
155+
156+
@test contains(get_llvm(MutableStruct, Tuple{}), "jl_gc_pool_alloc")
157+
breakpoint_mutable_ir = get_llvm(breakpoint_mutable, Tuple{MutableStruct})
158+
@test !contains(breakpoint_mutable_ir, "%gcframe")
159+
@test !contains(breakpoint_mutable_ir, "jl_gc_pool_alloc")
160+
161+
breakpoint_badref_ir = get_llvm(breakpoint_badref, Tuple{MutableStruct})
162+
@test !contains(breakpoint_badref_ir, "%gcframe")
163+
@test !contains(breakpoint_badref_ir, "jl_gc_pool_alloc")
137164
end

0 commit comments

Comments
 (0)