@@ -3687,6 +3687,10 @@ function substitute!(@nospecialize(e), na::Int, argexprs::Vector{Any}, @nospecia
3687
3687
for argt
3688
3688
in e. args[3 ] ]
3689
3689
e. args[3 ] = svec (argtuple... )
3690
+ elseif i == 4
3691
+ @assert isa ((e. args[4 ]:: QuoteNode ). value, Symbol)
3692
+ elseif i == 5
3693
+ @assert isa (e. args[5 ], Int)
3690
3694
else
3691
3695
e. args[i] = substitute! (e. args[i], na, argexprs, spsig, spvals, offset)
3692
3696
end
@@ -4766,16 +4770,16 @@ function inlining_pass(e::Expr, sv::InferenceState, stmts, ins)
4766
4770
# by the interpreter and inlining might put in something it can't handle,
4767
4771
# like another ccall (or try to move the variables out into the function)
4768
4772
if e. head === :foreigncall
4769
- # 3 is rewritten to 1 below to handle the callee.
4770
- i0 = 3
4773
+ # 5 is rewritten to 1 below to handle the callee.
4774
+ i0 = 5
4771
4775
isccall = true
4772
4776
elseif is_known_call (e, Core. Intrinsics. llvmcall, sv. src, sv. mod)
4773
4777
i0 = 5
4774
4778
end
4775
4779
has_stmts = false # needed to preserve order-of-execution
4776
4780
prev_stmts_length = length (stmts)
4777
4781
for _i = length (eargs): - 1 : i0
4778
- if isccall && _i == 3
4782
+ if isccall && _i == 5
4779
4783
i = 1
4780
4784
isccallee = true
4781
4785
else
@@ -4830,10 +4834,21 @@ function inlining_pass(e::Expr, sv::InferenceState, stmts, ins)
4830
4834
end
4831
4835
if isccall
4832
4836
le = length (eargs)
4833
- for i = 4 : 2 : (le - 1 )
4834
- if eargs[i] === eargs[i + 1 ]
4835
- eargs[i + 1 ] = 0
4837
+ nccallargs = eargs[5 ]:: Int
4838
+ ccallargs = ObjectIdDict ()
4839
+ for i in 6 : (5 + nccallargs)
4840
+ ccallargs[eargs[i]] = nothing
4841
+ end
4842
+ i = 6 + nccallargs
4843
+ while i <= le
4844
+ rootarg = eargs[i]
4845
+ if haskey (ccallargs, rootarg)
4846
+ deleteat! (eargs, i)
4847
+ le -= 1
4848
+ elseif i < le
4849
+ ccallargs[rootarg] = nothing
4836
4850
end
4851
+ i += 1
4837
4852
end
4838
4853
end
4839
4854
if e. head != = :call
@@ -5216,6 +5231,27 @@ function occurs_outside_getfield(@nospecialize(e), @nospecialize(sym),
5216
5231
if head === :(= )
5217
5232
return occurs_outside_getfield (e. args[2 ], sym, sv,
5218
5233
field_count, field_names)
5234
+ elseif head === :foreigncall
5235
+ args = e. args
5236
+ nccallargs = args[5 ]:: Int
5237
+ # Only arguments escape the structure/layout of the object,
5238
+ # GC root arguments do not.
5239
+ # Also note that only being used in the root slot for this ccall itself
5240
+ # does **not** mean that the object is not needed during the ccall.
5241
+ # However, if its address is never taken
5242
+ # and the object is never used in a way that escapes its layout, we can be sure
5243
+ # that there's no way the user code can rely on the heap allocation of this object.
5244
+ for i in 1 : length (args)
5245
+ a = args[i]
5246
+ if i > 5 + nccallargs && symequal (a, sym)
5247
+ # No need to verify indices, uninitialized members can be
5248
+ # ignored in root slot.
5249
+ continue
5250
+ end
5251
+ if occurs_outside_getfield (a, sym, sv, field_count, field_names)
5252
+ return true
5253
+ end
5254
+ end
5219
5255
else
5220
5256
if (head === :block && isa (sym, Slot) &&
5221
5257
sv. src. slotflags[slot_id (sym)] & Slot_UsedUndef == 0 )
@@ -5799,8 +5835,11 @@ end
5799
5835
function replace_getfield! (e:: Expr , tupname, vals, field_names, sv:: InferenceState )
5800
5836
for i = 1 : length (e. args)
5801
5837
a = e. args[i]
5802
- if isa (a,Expr) && is_known_call (a, getfield, sv. src, sv. mod) &&
5803
- symequal (a. args[2 ],tupname)
5838
+ if ! isa (a, Expr)
5839
+ continue
5840
+ end
5841
+ a = a:: Expr
5842
+ if is_known_call (a, getfield, sv. src, sv. mod) && symequal (a. args[2 ], tupname)
5804
5843
idx = if isa (a. args[3 ], Int)
5805
5844
a. args[3 ]
5806
5845
else
@@ -5829,8 +5868,23 @@ function replace_getfield!(e::Expr, tupname, vals, field_names, sv::InferenceSta
5829
5868
end
5830
5869
end
5831
5870
e. args[i] = val
5832
- elseif isa (a, Expr)
5833
- replace_getfield! (a:: Expr , tupname, vals, field_names, sv)
5871
+ else
5872
+ if a. head === :foreigncall
5873
+ args = a. args
5874
+ nccallargs = args[5 ]:: Int
5875
+ le = length (args)
5876
+ next_i = 6 + nccallargs
5877
+ while next_i <= le
5878
+ i = next_i
5879
+ next_i += 1
5880
+
5881
+ symequal (args[i], tupname) || continue
5882
+ # Replace the gc root argument with its fields
5883
+ splice! (args, i, vals)
5884
+ next_i += length (vals) - 1
5885
+ end
5886
+ end
5887
+ replace_getfield! (a, tupname, vals, field_names, sv)
5834
5888
end
5835
5889
end
5836
5890
end
0 commit comments